@icebreakers/monorepo-templates 2.0.6 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/assets/.agents/skills/repoctl/SKILL.md +2 -2
- package/assets/.agents/skills/repoctl/references/templates.md +3 -2
- package/assets/.github/workflows/ci.yml +0 -4
- package/assets/.github/workflows/release.yml +5 -0
- package/assets/package.json +3 -7
- package/assets/pnpm-workspace.yaml +2 -0
- package/assets/turbo.json +11 -4
- package/dist/cli.mjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{prepare-BapI8ioj.mjs → prepare-2VvFwYDz.mjs} +23 -3
- package/package.json +1 -1
- package/template-data.mjs +8 -0
- package/templates/client/package.json +1 -1
- package/templates/nimbus/AGENTS.md +12 -0
- package/templates/nimbus/LICENSE +21 -0
- package/templates/nimbus/README.md +17 -0
- package/templates/nimbus/UPSTREAM.md +16 -0
- package/templates/nimbus/astro.config.ts +28 -0
- package/templates/nimbus/eslint.config.js +25 -0
- package/templates/nimbus/gitignore +5 -0
- package/templates/nimbus/nimbus.json +4 -0
- package/templates/nimbus/package.json +34 -0
- package/templates/nimbus/public/favicon.svg +1 -0
- package/templates/nimbus/scripts/check-locales.mjs +11 -0
- package/templates/nimbus/src/components/aside.astro +9 -0
- package/templates/nimbus/src/components/head.astro +43 -0
- package/templates/nimbus/src/components/search/client.ts +62 -0
- package/templates/nimbus/src/components/search/index.astro +26 -0
- package/templates/nimbus/src/components/sidebar.astro +26 -0
- package/templates/nimbus/src/components.ts +3 -0
- package/templates/nimbus/src/content/docs/get-started.mdx +36 -0
- package/templates/nimbus/src/content/docs/index.mdx +16 -0
- package/templates/nimbus/src/content/docs/writing.mdx +35 -0
- package/templates/nimbus/src/content/docs/zh/get-started.mdx +36 -0
- package/templates/nimbus/src/content/docs/zh/index.mdx +16 -0
- package/templates/nimbus/src/content/docs/zh/writing.mdx +35 -0
- package/templates/nimbus/src/content.config.ts +6 -0
- package/templates/nimbus/src/env.d.ts +6 -0
- package/templates/nimbus/src/layouts/docs.astro +70 -0
- package/templates/nimbus/src/lib/locale.ts +50 -0
- package/templates/nimbus/src/pages/[...slug]/index.md.ts +4 -0
- package/templates/nimbus/src/pages/[...slug]/index.mdx.ts +4 -0
- package/templates/nimbus/src/pages/[...slug].astro +36 -0
- package/templates/nimbus/src/pages/[section]/llms.txt.ts +4 -0
- package/templates/nimbus/src/pages/llms-full.txt.ts +4 -0
- package/templates/nimbus/src/pages/llms.txt.ts +4 -0
- package/templates/nimbus/src/pages/robots.txt.ts +18 -0
- package/templates/nimbus/src/styles/base.css +121 -0
- package/templates/nimbus/src/styles/site.css +186 -0
- package/templates/nimbus/stylelint.config.js +3 -0
- package/templates/nimbus/tsconfig.json +10 -0
- package/templates/server/package.json +1 -1
- package/templates/vitepress/.vitepress/config.ts +4 -5
- package/templates/vitepress/.vitepress/home/content.ts +2 -2
- package/templates/vitepress/.vitepress/home/faq.ts +16 -0
- package/templates/vitepress/.vitepress/mermaid/markdown.ts +18 -0
- package/templates/vitepress/.vitepress/mermaid/mermaid.vue +66 -0
- package/templates/vitepress/.vitepress/mermaid/render.ts +37 -0
- package/templates/vitepress/.vitepress/seo.ts +12 -1
- package/templates/vitepress/.vitepress/theme/components/HomePage.vue +2 -16
- package/templates/vitepress/.vitepress/theme/index.ts +3 -1
- package/templates/vitepress/ai/create.md +1 -1
- package/templates/vitepress/package.json +4 -8
- package/templates/vitepress/reference/commands.md +3 -3
- package/templates/vitepress/reference/template-assets.md +1 -1
- package/templates/vitepress/reference/templates.md +13 -9
- package/templates/vitepress/tasks/index.md +1 -1
- package/templates/vitepress/tasks/release.md +18 -0
- package/templates/vitepress/test/mermaid.test.ts +39 -0
- package/templates/vitepress/test/render.test.ts +48 -0
- package/templates/vitepress/test/seo.test.ts +19 -0
- package/templates/vitepress/tsconfig.json +8 -8
- package/templates/vitepress/vitest.config.ts +8 -0
- package/templates/vitepress/zh/ai/create.md +1 -1
- package/templates/vitepress/zh/learn/monorepo/manage.md +1 -1
- package/templates/vitepress/zh/reference/commands.md +3 -3
- package/templates/vitepress/zh/reference/execution-model.md +1 -1
- package/templates/vitepress/zh/reference/template-assets.md +3 -2
- package/templates/vitepress/zh/reference/templates.md +13 -9
- package/templates/vitepress/zh/tasks/index.md +1 -1
- package/templates/vitepress/zh/tasks/release.md +18 -0
- package/templates/vitepress/zh/tasks/reports.md +1 -1
- package/assets/.changeset/wicked-ravens-wonder.md +0 -5
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createMarkdownRenderer } from 'vitepress'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import { mermaidMarkdown } from '../.vitepress/mermaid/markdown'
|
|
4
|
+
import { resolveMermaidTheme } from '../.vitepress/mermaid/render'
|
|
5
|
+
|
|
6
|
+
describe('Mermaid Markdown integration', () => {
|
|
7
|
+
it('round-trips diagram text without injecting attributes or Vue expressions', async () => {
|
|
8
|
+
const md = await createMarkdownRenderer(process.cwd(), { config: mermaidMarkdown })
|
|
9
|
+
const source = 'flowchart LR\n A["引号 & <tag> {{ value }}"] --> B["it\'s fine"]\n'
|
|
10
|
+
const html = await md.renderAsync(`\`\`\`mermaid\n${source}\`\`\``)
|
|
11
|
+
const graph = html.match(/graph="([^"]+)"/)![1]!
|
|
12
|
+
expect(decodeURIComponent(graph)).toBe(source)
|
|
13
|
+
expect(html).not.toContain('<tag>')
|
|
14
|
+
expect(html).not.toContain('{{ value }}')
|
|
15
|
+
expect(html).toContain('<Mermaid ')
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('keeps normal fences and the mmd source-code escape hatch highlighted', async () => {
|
|
19
|
+
const md = await createMarkdownRenderer(process.cwd(), { config: mermaidMarkdown })
|
|
20
|
+
const html = await md.renderAsync('```ts\nconst answer = 42\n```\n\n```mmd\nflowchart LR\n A --> B\n```')
|
|
21
|
+
expect(html).toContain('language-ts')
|
|
22
|
+
expect(html).toContain('language-mermaid')
|
|
23
|
+
expect(html).not.toContain('<Mermaid ')
|
|
24
|
+
expect(html).toContain('shiki')
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('renders multiple independent component instances', async () => {
|
|
28
|
+
const md = await createMarkdownRenderer(process.cwd(), { config: mermaidMarkdown })
|
|
29
|
+
const html = await md.renderAsync('```mermaid\nflowchart LR\n A --> B\n```\n\n```mermaid\nsequenceDiagram\n A->>B: Hello\n```')
|
|
30
|
+
expect(html.match(/<Mermaid /g)).toHaveLength(2)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('validates page themes and lets dark mode take precedence', () => {
|
|
34
|
+
expect(resolveMermaidTheme(false, 'forest')).toBe('forest')
|
|
35
|
+
expect(resolveMermaidTheme(true, 'forest')).toBe('dark')
|
|
36
|
+
expect(resolveMermaidTheme(false, { theme: 'forest' })).toBe('default')
|
|
37
|
+
expect(resolveMermaidTheme(false, undefined)).toBe('default')
|
|
38
|
+
})
|
|
39
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
const engine = vi.hoisted(() => ({ initialize: vi.fn(), render: vi.fn() }))
|
|
4
|
+
vi.mock('mermaid', () => ({ default: engine }))
|
|
5
|
+
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
vi.unstubAllGlobals()
|
|
8
|
+
vi.resetAllMocks()
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
describe('Mermaid rendering queue', () => {
|
|
12
|
+
it('serializes theme configuration with rendering and cleans up failed diagrams', async () => {
|
|
13
|
+
const containers: { remove: ReturnType<typeof vi.fn> }[] = []
|
|
14
|
+
vi.stubGlobal('document', {
|
|
15
|
+
createElement: () => {
|
|
16
|
+
const container = { style: {}, setAttribute: vi.fn(), remove: vi.fn() }
|
|
17
|
+
containers.push(container)
|
|
18
|
+
return container
|
|
19
|
+
},
|
|
20
|
+
body: { append: vi.fn() },
|
|
21
|
+
})
|
|
22
|
+
const { renderMermaid } = await import('../.vitepress/mermaid/render')
|
|
23
|
+
const first = Promise.withResolvers<{ svg: string }>()
|
|
24
|
+
const started = Promise.withResolvers<void>()
|
|
25
|
+
engine.render.mockImplementationOnce(() => {
|
|
26
|
+
started.resolve()
|
|
27
|
+
return first.promise
|
|
28
|
+
}).mockRejectedValueOnce(new Error('Invalid diagram')).mockResolvedValueOnce({ svg: '<svg />' })
|
|
29
|
+
|
|
30
|
+
const one = renderMermaid('flowchart LR; A-->B', 'forest')
|
|
31
|
+
const two = renderMermaid('invalid', 'dark')
|
|
32
|
+
const failure = expect(two).rejects.toThrow('Invalid diagram')
|
|
33
|
+
const three = renderMermaid('flowchart LR; B-->C', 'neutral')
|
|
34
|
+
await started.promise
|
|
35
|
+
expect(engine.initialize).toHaveBeenCalledTimes(1)
|
|
36
|
+
expect(engine.initialize).toHaveBeenLastCalledWith(expect.objectContaining({ theme: 'forest' }))
|
|
37
|
+
first.resolve({ svg: '<svg />' })
|
|
38
|
+
await one
|
|
39
|
+
await failure
|
|
40
|
+
await expect(three).resolves.toEqual({ svg: '<svg />' })
|
|
41
|
+
expect(engine.initialize.mock.calls.map(([config]) => config.theme)).toEqual(['forest', 'dark', 'neutral'])
|
|
42
|
+
expect(new Set(engine.render.mock.calls.map(([id]) => id)).size).toBe(3)
|
|
43
|
+
expect(containers).toHaveLength(3)
|
|
44
|
+
for (const container of containers) {
|
|
45
|
+
expect(container.remove).toHaveBeenCalledOnce()
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TransformContext } from 'vitepress'
|
|
2
|
+
import { expect, it } from 'vitest'
|
|
3
|
+
import { faqContent } from '../.vitepress/home/faq'
|
|
4
|
+
import { createPageHead } from '../.vitepress/seo'
|
|
5
|
+
|
|
6
|
+
it.each([['index.md', 'en'], ['zh/index.md', 'zh']] as const)('renders valid FAQ structured data for %s', (page, locale) => {
|
|
7
|
+
const head = createPageHead({ page, title: 'repoctl', description: 'A </script> description' } as TransformContext)
|
|
8
|
+
const script = head.find(([tag, attrs]) => tag === 'script' && attrs.type === 'application/ld+json')!
|
|
9
|
+
const content = script[2]!
|
|
10
|
+
expect(content).not.toContain('</script>')
|
|
11
|
+
const schema = JSON.parse(content)
|
|
12
|
+
const faq = schema['@graph'].find((item: { '@type': string }) => item['@type'] === 'FAQPage')
|
|
13
|
+
expect(faq.mainEntity.map((item: { name: string, acceptedAnswer: { text: string } }) => [item.name, item.acceptedAnswer.text])).toEqual(faqContent[locale])
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('keeps homepage FAQ data off documentation pages', () => {
|
|
17
|
+
const head = createPageHead({ page: 'reference/commands.md', title: 'Commands', description: 'Commands' } as TransformContext)
|
|
18
|
+
expect(head.find(([tag]) => tag === 'script')![2]).not.toContain('FAQPage')
|
|
19
|
+
})
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
"skipLibCheck": true
|
|
11
11
|
},
|
|
12
12
|
"include": [
|
|
13
|
-
".vitepress
|
|
14
|
-
".vitepress
|
|
15
|
-
".vitepress/seo.ts",
|
|
16
|
-
".vitepress/theme/**/*.ts",
|
|
17
|
-
".vitepress/theme/**/*.vue",
|
|
18
|
-
".vitepress/env.d.ts",
|
|
13
|
+
".vitepress/**/*.ts",
|
|
14
|
+
".vitepress/**/*.vue",
|
|
19
15
|
"scripts/**/*.ts",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
16
|
+
"test/**/*.ts",
|
|
17
|
+
"vitest.config.ts"
|
|
18
|
+
],
|
|
19
|
+
"exclude": [
|
|
20
|
+
".vitepress/dist",
|
|
21
|
+
".vitepress/cache"
|
|
22
22
|
]
|
|
23
23
|
}
|
|
@@ -79,9 +79,9 @@ repo templates --markdown --out docs/templates.md
|
|
|
79
79
|
```bash
|
|
80
80
|
repo new
|
|
81
81
|
repo new sdk --template tsdown
|
|
82
|
-
repo new docs --template
|
|
83
|
-
repo new docs --template
|
|
84
|
-
repo new docs --template
|
|
82
|
+
repo new docs --template nimbus
|
|
83
|
+
repo new docs --template nimbus --dry-run
|
|
84
|
+
repo new docs --template nimbus --json --out plans/docs.json
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
用途:
|
|
@@ -61,7 +61,7 @@ repoctl 的失败状态遵循阻塞优先:
|
|
|
61
61
|
如果只是想知道会发生什么,先加 `--dry-run` 或输出计划:
|
|
62
62
|
|
|
63
63
|
```bash
|
|
64
|
-
repo new docs --template
|
|
64
|
+
repo new docs --template nimbus --json --out plans/docs.json
|
|
65
65
|
repo check --markdown --out reports/check-plan.md
|
|
66
66
|
```
|
|
67
67
|
|
|
@@ -15,6 +15,7 @@ repoctl 的模板能力不只是复制目录。它会把模板元数据、默认
|
|
|
15
15
|
| `hono-server` | `templates/server` | `apps/server` | Hono service |
|
|
16
16
|
| `vue-hono` | `templates/client` | `apps/client` | Vue + Hono app |
|
|
17
17
|
| `vitepress` | `templates/vitepress` | `apps/website` | docs site |
|
|
18
|
+
| `nimbus` | `templates/nimbus` | `apps/docs` | default docs site |
|
|
18
19
|
| `cli` | `templates/cli` | `apps/cli` | command line tool |
|
|
19
20
|
|
|
20
21
|
查看实际可用模板:
|
|
@@ -42,8 +43,8 @@ repo templates --markdown --out docs/templates.md
|
|
|
42
43
|
预览创建:
|
|
43
44
|
|
|
44
45
|
```bash
|
|
45
|
-
repo new docs --template
|
|
46
|
-
repo new docs --template
|
|
46
|
+
repo new docs --template nimbus --dry-run
|
|
47
|
+
repo new docs --template nimbus --json --out plans/docs.json
|
|
47
48
|
```
|
|
48
49
|
|
|
49
50
|
`--json` 和 `--out` 都隐含 `--dry-run`,不会写入文件。
|
|
@@ -6,14 +6,17 @@ repoctl 的模板由 `@icebreakers/monorepo-templates` 维护。CLI、脚手架
|
|
|
6
6
|
|
|
7
7
|
## 内置模板
|
|
8
8
|
|
|
9
|
-
| Key | Category | 默认目录 | 适合场景
|
|
10
|
-
| ------------- | -------- | ------------------ |
|
|
11
|
-
| `tsdown` | library | `packages/tsdown` | TypeScript 库包
|
|
12
|
-
| `vue-lib` | library | `packages/vue-lib` | Vue 3 组件库
|
|
13
|
-
| `vue-hono` | app | `apps/client` | Vue 3 + Hono 前后端一体应用
|
|
14
|
-
| `hono-server` | service | `apps/server` | Hono API 服务
|
|
15
|
-
| `vitepress` | docs | `apps/website` | VitePress 文档站
|
|
16
|
-
| `
|
|
9
|
+
| Key | Category | 默认目录 | 适合场景 |
|
|
10
|
+
| ------------- | -------- | ------------------ | -------------------------------- |
|
|
11
|
+
| `tsdown` | library | `packages/tsdown` | TypeScript 库包 |
|
|
12
|
+
| `vue-lib` | library | `packages/vue-lib` | Vue 3 组件库 |
|
|
13
|
+
| `vue-hono` | app | `apps/client` | Vue 3 + Hono 前后端一体应用 |
|
|
14
|
+
| `hono-server` | service | `apps/server` | Hono API 服务 |
|
|
15
|
+
| `vitepress` | docs | `apps/website` | VitePress 文档站 |
|
|
16
|
+
| `nimbus` | docs | `apps/docs` | Nimbus + Astro,默认中英双语文档 |
|
|
17
|
+
| `cli` | tool | `apps/cli` | TypeScript 命令行工具 |
|
|
18
|
+
|
|
19
|
+
Nimbus 是新建文档站点(`Docs Site`)的默认模板,提供英文 `/`、中文 `/zh/`、搜索和 AI 文档入口。VitePress 仍可显式选择,两者分别生成到 `apps/docs` 和 `apps/website`,可以同时使用。通用创建命令仍默认使用 `tsdown`;项目名称 `docs` 不会隐式改变模板。非交互调用请显式指定 `--template nimbus`。
|
|
17
20
|
|
|
18
21
|
## 查看模板
|
|
19
22
|
|
|
@@ -31,6 +34,7 @@ repo templates --markdown --out docs/templates.md
|
|
|
31
34
|
repo new sdk --template tsdown
|
|
32
35
|
repo new ui --template vue-lib
|
|
33
36
|
repo new api --template hono-server
|
|
37
|
+
repo new docs --template nimbus
|
|
34
38
|
repo new website --template vitepress
|
|
35
39
|
repo new toolbox --template cli
|
|
36
40
|
```
|
|
@@ -87,7 +91,7 @@ repo new api --template hono-server
|
|
|
87
91
|
### 要创建文档站
|
|
88
92
|
|
|
89
93
|
```bash
|
|
90
|
-
repo new docs --template
|
|
94
|
+
repo new docs --template nimbus
|
|
91
95
|
```
|
|
92
96
|
|
|
93
97
|
生成后先检查:
|
|
@@ -36,7 +36,7 @@ pnpm exec repo doctor --markdown --redact --out reports/doctor-after.md
|
|
|
36
36
|
```bash
|
|
37
37
|
pnpm exec repo templates
|
|
38
38
|
pnpm exec repo new sdk --template tsdown
|
|
39
|
-
pnpm exec repo new docs --template
|
|
39
|
+
pnpm exec repo new docs --template nimbus --dry-run
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
如果只是日常开发,根脚本也可以:
|
|
@@ -70,6 +70,24 @@ const hook = { script: 'publish:extension', idempotent: true }
|
|
|
70
70
|
|
|
71
71
|
程序化注入的旧 `GitHubOperations` adapter 保留原行为;要启用跨 runner 恢复,需要实现 `readReleaseState`、`writeReleaseState`、`listReleases`、`ensureTag`,并建议提供 `readTagTarget`。写入必须校验 revision,查询错误必须抛出。仅有本地 summary 不能代替远端检查点。
|
|
72
72
|
|
|
73
|
+
## 无需发布的记录与原提交恢复
|
|
74
|
+
|
|
75
|
+
仅包含 `none` 或空 frontmatter 的 intent 表示无需发布。它不会创建版本 PR,也不阻断已经准备好的版本发布。合并后重新出现、但 ledger 已记录消费的 intent 不会再次升级版本;pnpm 会在下一次有效版本操作中清理这些文件。
|
|
76
|
+
|
|
77
|
+
版本 PR 以 pnpm 返回的实际发布包列表为依据,不再把任意 Git 改动视为版本变化。新包首次发布可以保留初始版本号,但仍会列入发布说明。仅清理记录不会创建发布 PR。
|
|
78
|
+
|
|
79
|
+
已有版本尚未完成发布时,新的版本准备会在消费 intent 前失败,并给出原始提交和恢复命令。先恢复旧发布,再准备新版本:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
repo release ci --mode publish --source-sha <完整的-main-提交-SHA> --dry-run
|
|
83
|
+
repo release ci --mode publish --source-sha <完整的-main-提交-SHA>
|
|
84
|
+
repo release ci --mode prepare
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
受管 Release 工作流为 `publish` 和 `publish-unpublished` 提供相同的 `source-sha` 输入。当前工具会在独立目录检出原提交,按照其锁文件安装、构建和验证,恢复该提交 manifest 或 ledger 新增的整批版本,包括依赖传播升级的包。package/version 输入只校验是否属于该批发布,不拆分原发布批次。SHA 必须属于 `origin/main` 历史。dry-run 只检查源码与远端状态,不安装、不上传、不运行 hook、不写检查点。后续变更保留到下一版本;恢复过程中不修改版本号。
|
|
88
|
+
|
|
89
|
+
恢复保留 GitHub 工作流环境,供可信发布和 provenance 使用:签名身份对应运行工作流的提交;独立检出的源码、发布检查点、Git tag 和 Release 目标则对应 `source-sha`。不要通过覆盖 `GITHUB_SHA` 恢复旧源码,npm 会拒绝与工作流签名身份不一致的 provenance。
|
|
90
|
+
|
|
73
91
|
## 下一步
|
|
74
92
|
|
|
75
93
|
阅读[发包与变更日志](/zh/learn/monorepo/publish),再查看[报告与输出](/zh/tasks/reports)了解 CI 产物。
|
|
@@ -94,7 +94,7 @@ JSON 适合机器判断,不适合人工长时间阅读:
|
|
|
94
94
|
```bash
|
|
95
95
|
repo doctor --json --out reports/doctor.json
|
|
96
96
|
repo templates --check --json --out reports/templates.json
|
|
97
|
-
repo new docs --template
|
|
97
|
+
repo new docs --template nimbus --json --out plans/docs.json
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
常见消费方式:
|