Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ export const docsContentConfig = {
},
sections: {
showcase: { layout: 'content' },
examples: {
layout: 'docs',
sidebar: [
{
type: 'group',
label: { en: 'Examples', zh: '使用示例' },
items: [
{ type: 'item', href: '/examples/variants', label: { en: 'Template variants', zh: '同一模板,不同版本' } },
{ type: 'item', href: '/examples/skills', label: { en: 'Shared skills', zh: '复用常用 Skills' } },
{ type: 'item', href: '/examples/monorepo', label: { en: 'Extract from a monorepo', zh: '提取 monorepo 子项目' } },
{ type: 'item', href: '/examples/file-changes', label: { en: 'Edit files during creation', zh: '创建时调整文件' } },
],
},
],
},
guide: {
layout: 'docs',
sidebar: [
Expand Down
6 changes: 4 additions & 2 deletions docs/docs.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { PresetFooter } from './src/site/footer'
import { DocsSiteLink } from './src/site/docs-link'
import { headerNavigation } from './src/site/navigation'
import { ShowcaseProject } from './src/showcase/showcase-project'
import { ExampleExplorer } from './src/examples/example-explorer'

export const docsConfig = defineDocsConfig({
content: docsContentConfig,
Expand All @@ -26,8 +27,8 @@ export const docsConfig = defineDocsConfig({
eyebrow: false,
title: 'Create Preset',
description: {
en: 'Provides the ability to quickly create preset projects.',
zh: '提供快速创建预设项目模板的能力。',
en: 'Similar templates. Still maintaining separate copies?',
zh: '模板相似,却要维护多份?',
},
primaryAction: {
href: '/guide/getting-started',
Expand All @@ -40,6 +41,7 @@ export const docsConfig = defineDocsConfig({
FadePreview: DocsFadePreview,
PackageManagerCommands,
ShowcaseProject,
ExampleExplorer,
},
},
theme: {
Expand Down
2 changes: 2 additions & 0 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
"dependencies": {
"@bassist/utils": "^0.17.0",
"@blackwork/docs": "^0.6.0",
"@blackwork/machine": "0.2.2",
"@blackwork/search": "^0.1.1",
"blackwork": "^0.14.0",
"clsx": "^2.1.1",
"lucide-react": "^1.31.0",
"next": "^16.3.8",
"react": "^19.2.8",
"react-dom": "^19.2.8",
"shiki": "^4.4.3",
"tailwind-merge": "^3.6.0"
},
"devDependencies": {
Expand Down
6 changes: 6 additions & 0 deletions docs/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions docs/src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@
background-color: hsl(var(--foreground) / 0.35);
}

/* File examples need room for both paths and code inside the shared docs shell. */
@media (width >= 64rem) {
[data-docs-region='docs-shell']:has([data-preset-example]) {
column-gap: 3rem;
}

[data-docs-region='docs-shell']:has([data-preset-example]) [data-docs-region='sidebar'] {
width: 14rem;
}

[data-docs-region='docs-shell']:has([data-preset-example]) [data-docs-region='toc'] {
display: none;
}
}

/* Keep shared header controls reachable on phones, including docs pages. */
@media (width < 40rem) {
[data-docs-region='header'] > div {
Expand Down
30 changes: 30 additions & 0 deletions docs/src/contents/en/examples/file-changes.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: Edit files during project creation
description: Remove demo files, update the README, and change defaults while creating a project.
order: 4
---

# Edit files during project creation

After cloning a service starter, there are often demo files to remove, a README to rewrite, defaults to change, and a demo command to delete from `package.json`. When the edits are the same each time, put them in a preset.

<ExampleExplorer example="file-changes" />

## Operation order

1. `exclude` skips `demo.js` during copying, leaving it out of the new project.
2. `write` rewrites `README.md`, with each entry in `lines` becoming one line in the file.
3. `replace` changes `APP_LABEL=Starter` to `APP_LABEL=Team` in `.env.example`.
4. `json` edits `package.json`. Setting `scripts.demo` to `null` removes that command and keeps `scripts.start`.

## Preview the creation plan

Save the config as `presets/service.json`, then add `--dry-run` to see the planned operations:

```bash
pnpm create preset init my-service --from ./presets/service.json --dry-run
```

This step does not download the repository, so it cannot check whether the original text in `replace` exists. After checking the plan, remove `--dry-run` to create the project and inspect the files.

See [Preset Configs](/guide/preset-configs) for other fields.
27 changes: 27 additions & 0 deletions docs/src/contents/en/examples/monorepo.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: Extract a project from a monorepo
description: Copy the needed directory and handle test files and workspace dependencies during creation.
order: 3
---

# Extract a project from a monorepo

The docs starter lives in `apps/docs` and the component library in `packages/ui`. A new docs site only needs the starter, but copying that directory still leaves test files to remove and `workspace:` dependencies to fix.

The config below handles those steps together: take files from `apps/docs`, exclude `src/__tests__`, and set the component library dependency to a specific version.

<ExampleExplorer example="monorepo" />

## Subdirectory and file exclusions

With `source.directory` set to `apps/docs`, that directory's contents become the new project's root files. Neither `packages/ui` nor the repository's root `pnpm-workspace.yaml` is copied.

Paths in `exclude` start from the selected directory too. Use `src/__tests__`, without the `apps/docs` prefix.

## Workspace dependency conversion

Enable `packageJson.resolveWorkspace` and set `@example/ui` to `1.2.3` in `workspaceVersions`. The generated `package.json` uses that version in place of `workspace:*`, with no registry lookup for this package.

`@example/ui` is an example name. Use a published package and version that the environment can install. This changes the dependency version; it does not copy or bundle the component source from `packages/ui`.

Without a specified version, the CLI queries `npm view` using the current npm registry settings. See [Resolve workspace dependencies](/guide/preset-configs#resolve-workspace-dependencies) for the full rules.
31 changes: 31 additions & 0 deletions docs/src/contents/en/examples/skills.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: Reuse skills across projects
description: Maintain common skills together and select the ones each project needs.
order: 2
---

# Reuse skills across projects

Code review, documentation, and testing often use the same skills across projects. Keeping them in one shared repository saves finding and copying each folder whenever a new project needs them.

This example keeps three skills in the `skills` directory of `team-resources`. One config includes all three. The other uses `exclude` to leave out `testing` when it is not needed.

<ExampleExplorer example="skills" />

## Target directory

Run the example command from the project root with a new or empty `.agents/skills` directory as the target. For example, `skills/code-review/SKILL.md` in the repository becomes `.agents/skills/code-review/SKILL.md` in the project.

If the agent reads skills from another location, change the target path in the command. Several projects can use this repository without an npm package for distribution.

## Existing skills

**For a nonempty target, the CLI asks to replace the entire directory. It does not merge individual skills.** Generate into a new temporary directory first:

```bash
pnpm create preset init skills-preview --from ./presets/skills.json
```

Check the files, then copy the skill folders needed into the project. Compare same-name files before overwriting them. Later updates can be fetched and compared the same way. Create Preset does not sync updates automatically or link skills into other agents' directories.

Each preset reads one source repository. Skills from several repositories need collecting in one repository before this config can distribute them together.
32 changes: 32 additions & 0 deletions docs/src/contents/en/examples/variants.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: One template, different editions
description: Maintain shared code once and configure the differences between basic and team editions.
order: 1
---

# One template, different editions

The basic edition does not need analytics; the team edition does. Everything else is the same. With a separate template for each, every shared bug needs fixing twice.

Keep the complete source, including analytics, and add a config that removes it for the basic edition. Below, `basic.json` removes the analytics file and its references in the entry point. `team.json` keeps them.

<ExampleExplorer example="variants" />

## Template differences

Both configs take files from `starter`. The basic edition adds two steps:

- `exclude` leaves out `src/analytics.ts`.
- `replace` removes the import and call from `src/main.ts`, so the entry point no longer refers to the deleted file.

The team edition keeps both files. In each edition, the generated `package.json` name matches the target directory: `my-basic-app` or `my-team-app`.

Shared fixes go into the source repository once. New projects use the selected preset when created; projects already generated need updating separately.

## Text replacement rules

`replace` matches exact text. After editing the entry point, check the config's `from` value too. Creation fails if that text can no longer be found.

This works for small, explicit file differences. Any references that need removing must be listed in the config. The CLI does not analyze module references or convert TypeScript automatically.

See [Preset Configs](/guide/preset-configs) for more operations.
4 changes: 4 additions & 0 deletions docs/src/contents/en/guide/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ order: 1

# Getting Started

The [examples](/examples/variants) include configs, source files, and output for template variants, shared skills, and monorepo projects.

If a template author already provides a creation command, run it directly. There is no need to write a JSON config first.

Run Create Preset with a package manager:

<PackageManagerCommands />
Expand Down
30 changes: 30 additions & 0 deletions docs/src/contents/zh/examples/file-changes.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: 创建时调整文件和配置
description: 删演示文件、改 README、调整默认配置,创建项目时一起完成。
order: 4
---

# 创建时调整文件和配置

服务模板中的演示文件、README 和默认配置通常需要在创建项目后调整。示例将这些固定操作写入 Preset,在创建时删除 `demo.js`、重写 README、替换环境变量,并移除 `package.json` 中的演示命令。

<ExampleExplorer example="file-changes" locale="zh" />

## 文件处理顺序

1. `exclude`:复制时跳过 `demo.js`,新项目里就不会有这个文件。
2. `write`:重写 `README.md`,`lines` 中的每一项对应文件中的一行。
3. `replace`:把 `.env.example` 中的 `APP_LABEL=Starter` 换成 `APP_LABEL=Team`。
4. `json`:修改 `package.json`,把 `scripts.demo` 设为 `null` 就能删掉这条命令,`scripts.start` 会保留。

## 预览创建计划

配置保存为 `presets/service.json` 后,可以加上 `--dry-run` 查看准备执行的操作:

```bash
pnpm create preset init my-service --from ./presets/service.json --dry-run
```

这一步不会下载仓库,因此也不会检查 `replace` 中的原文能否找到。确认计划后,去掉 `--dry-run` 创建项目,再检查生成的文件。

其他字段的用法见[Preset 配置](/zh/guide/preset-configs)。
27 changes: 27 additions & 0 deletions docs/src/contents/zh/examples/monorepo.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: 从 monorepo 提取子项目
description: 提取子目录,排除测试文件,并转换 workspace 依赖。
order: 3
---

# 从 monorepo 提取子项目

文档模板位于 `apps/docs`,依赖同一仓库中 `packages/ui` 提供的组件库。将文档模板用于独立项目时,需要排除内部测试文件,并将 `workspace:` 依赖换成已发布的版本。

示例配置选取 `apps/docs`,排除 `src/__tests__`,并指定组件库的依赖版本。

<ExampleExplorer example="monorepo" locale="zh" />

## 子目录与文件排除

`source.directory` 设为 `apps/docs` 后,该目录的内容会复制到新项目根目录。`packages/ui` 和仓库根目录的 `pnpm-workspace.yaml` 不会复制。

`exclude` 中的路径相对于选中的目录,因此测试目录配置为 `src/__tests__`,不包含 `apps/docs` 前缀。

## workspace 依赖转换

开启 `packageJson.resolveWorkspace`,再在 `workspaceVersions` 中指定 `@example/ui` 的版本为 `1.2.3`。生成后的 `package.json` 就会用这个版本替换 `workspace:*`,也无需为这个包查询 registry。

`@example/ui` 只是示例名称,实际使用时要换成已发布、且当前环境能安装的包和版本。这里处理的是依赖版本,`packages/ui` 中的组件源码不会一起复制或打包。

没有指定版本时,CLI 会通过 `npm view` 查询,使用 npm 当前的 registry 配置。详细规则见[处理 workspace 依赖](/zh/guide/preset-configs#处理-workspace-依赖)。
31 changes: 31 additions & 0 deletions docs/src/contents/zh/examples/skills.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: 在多个项目中复用 Skills
description: 集中维护常用 Skills,通过配置选取并引入项目。
order: 2
---

# 在多个项目中复用 Skills

代码审查、文档写作和测试约定等 Skills 可以在多个项目中复用。将它们集中保存在一个仓库,通过 Preset 选取目录,可以减少逐个复制文件的操作。

示例仓库 `team-resources` 的 `skills` 目录包含三个 Skill。两份配置分别用于引入全部 Skills,以及通过 `exclude` 排除 `testing` 目录。

<ExampleExplorer example="skills" locale="zh" />

## 目标目录

示例命令从项目根目录运行,目标是新建或空的 `.agents/skills` 目录。例如,仓库里的 `skills/code-review/SKILL.md` 会放到 `.agents/skills/code-review/SKILL.md`。

目标路径需要与所用 agent 的 Skills 目录一致,可以在命令中修改。同一个仓库可以供多个项目使用,不必为了分发再发布 npm 包。

## 已有 Skills 的处理

**目标目录已有文件时,CLI 会询问是否替换整个目录,不会逐个合并 Skill。** 为保留项目中的现有内容,可以先生成到一个新的临时目录:

```bash
pnpm create preset init skills-preview --from ./presets/skills.json
```

检查生成内容后,将需要的 Skill 文件夹复制到项目中;同名文件需要比较后再决定是否覆盖。源仓库更新后,也可以通过临时目录比较新旧文件。Create Preset 不会自动同步更新,也不会把 Skills 链接到其他 agent 的目录。

一份 Preset 只读取一个源仓库。如果常用 Skills 分散在多个仓库,需要先整理到同一个仓库,再用这份配置分发。
32 changes: 32 additions & 0 deletions docs/src/contents/zh/examples/variants.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: 同一模板,生成不同版本
description: 公共代码只维护一份,基础版和团队版的区别交给配置处理。
order: 1
---

# 同一模板,生成不同版本

基础版和团队版共用同一套代码,区别在于是否包含统计模块。分别维护模板时,公共代码的修改需要同步到两份源码。

示例保留一份完整源码,通过两份 Preset 生成不同版本:`basic.json` 排除统计文件并删除入口中的相关代码,`team.json` 保留统计功能。

<ExampleExplorer example="variants" locale="zh" />

## 模板差异配置

两份配置都从 `starter` 目录取文件。基础版多做两步:

- 用 `exclude` 排除 `src/analytics.ts`。
- 用 `replace` 删除 `src/main.ts` 中的导入和调用,避免入口继续引用已删除的文件。

团队版保留这两个文件。两个版本的 `package.json` 都会按目标目录更新 `name`,分别变成 `my-basic-app` 和 `my-team-app`。

公共代码在源仓库中维护,创建项目时应用对应配置。已经生成的项目需要自行更新。

## 文本替换规则

`replace` 按原文精确匹配。入口代码修改后,需要同步检查配置中的 `from`;找不到对应文本时,创建会报错。

这类配置适合少量、明确的文件差异。删除文件后,相关引用也需要通过配置移除。CLI 不会自动分析引用关系或转换 TypeScript。

更多操作见[Preset 配置](/zh/guide/preset-configs)。
4 changes: 4 additions & 0 deletions docs/src/contents/zh/guide/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ order: 1

# 快速开始

[使用示例](/zh/examples/variants)提供模板复用、Skills 分发和 monorepo 子项目提取的配置,以及对应的源文件和生成结果。

如果模板作者已经提供创建命令,直接运行即可,无需自己编写 JSON。

使用包管理器运行 Create Preset:

<PackageManagerCommands locale="zh" />
Expand Down
21 changes: 21 additions & 0 deletions docs/src/examples/changes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { describe, expect, test } from 'vitest'
import { changedLines, sourceChange } from './changes'

describe('example change annotations', () => {
test('does not mark retained lines after a removed import', () => {
expect(changedLines("import './analytics'\nstart()\n", 'start()\n')).toEqual({ before: [0], after: [] })
})

test('matches repeated lines in order when content is inserted', () => {
expect(changedLines('a\nb\na\n', 'a\nx\nb\na\n')).toEqual({ before: [], after: [1] })
})

test('highlights the two sides of a replacement', () => {
expect(changedLines('APP=Starter\n', 'APP=Team\n')).toEqual({ before: [0], after: [0] })
})

test('distinguishes excluded files from files outside the selected directory', () => {
expect(sourceChange('apps/docs/test.ts', 'test()\n', 'apps/docs', {})).toEqual({ kind: 'removed', lines: [0] })
expect(sourceChange('apps/docs-other/test.ts', 'test()\n', 'apps/docs', {})).toEqual({ kind: 'outside', lines: [] })
})
})
Loading
Loading