@icebreakers/monorepo-templates 2.0.1 → 2.0.3

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.
Files changed (34) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/assets/.agents/skills/repoctl/SKILL.md +9 -4
  4. package/assets/.agents/skills/repoctl/references/commands.md +2 -1
  5. package/assets/.github/ISSUE_TEMPLATE/config.yml +1 -1
  6. package/assets/.github/workflows/ci.yml +4 -0
  7. package/assets/.github/workflows/release.yml +3 -0
  8. package/assets/AGENTS.md +16 -1
  9. package/assets/CLAUDE.md +8 -2
  10. package/assets/CONTRIBUTING.md +1 -1
  11. package/assets/SECURITY.md +1 -1
  12. package/assets/npmrc +20 -0
  13. package/assets/package.json +7 -7
  14. package/assets/pnpm-workspace.yaml +2 -1
  15. package/assets/renovate.json +3 -0
  16. package/dist/cli.mjs +1 -1
  17. package/dist/index.d.mts +4 -0
  18. package/dist/index.mjs +73 -5
  19. package/dist/{prepare-zIcRa4-K.mjs → prepare-OpBpZD1d.mjs} +22 -6
  20. package/package.json +3 -3
  21. package/templates/cli/package.json +2 -2
  22. package/templates/client/package.json +7 -7
  23. package/templates/server/package.json +4 -4
  24. package/templates/tsdown/package.json +2 -2
  25. package/templates/vitepress/.vitepress/config.ts +3 -3
  26. package/templates/vitepress/.vitepress/seo.ts +2 -2
  27. package/templates/vitepress/ai/create.md +8 -4
  28. package/templates/vitepress/ai/index.md +2 -2
  29. package/templates/vitepress/package.json +3 -3
  30. package/templates/vitepress/zh/ai/create.md +7 -4
  31. package/templates/vitepress/zh/ai/index.md +1 -1
  32. package/templates/vitepress/zh/learn/packages/modern/bundlers.md +3 -3
  33. package/templates/vitepress/zh/learn/packages/modern/index.md +1 -1
  34. package/templates/vue-lib/package.json +4 -4
package/README.md CHANGED
@@ -26,5 +26,5 @@ The source workspaces under the repository's `templates/` directory are private.
26
26
  ## Project links
27
27
 
28
28
  - Documentation: https://repoctl.icebreaker.top
29
- - Repository: https://github.com/sonofmagic/repoctl/tree/main/packages/monorepo-templates
30
- - Issues: https://github.com/sonofmagic/repoctl/issues
29
+ - Repository: https://github.com/icelib/repoctl/tree/main/packages/monorepo-templates
30
+ - Issues: https://github.com/icelib/repoctl/issues
package/README.zh-CN.md CHANGED
@@ -18,5 +18,5 @@ const vitepress = getTemplateDefinition('vitepress')
18
18
  ## 项目链接
19
19
 
20
20
  - 文档:https://repoctl.icebreaker.top
21
- - 仓库:https://github.com/sonofmagic/repoctl/tree/main/packages/monorepo-templates
22
- - 问题反馈:https://github.com/sonofmagic/repoctl/issues
21
+ - 仓库:https://github.com/icelib/repoctl/tree/main/packages/monorepo-templates
22
+ - 问题反馈:https://github.com/icelib/repoctl/issues
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: repoctl
3
- description: Create and maintain pnpm/Turborepo workspaces with repoctl. Use when the user says 使用 repoctl 创建项目, create a monorepo, pnpm create repoctl, scaffold Vue/Hono/tsdown/vitepress, or run repo init/doctor/new/check.
3
+ description: Create and maintain pnpm/Turborepo workspaces with repoctl. Use when the user says 使用 repoctl 创建项目, create a monorepo, pnpm create repoctl@latest, scaffold Vue/Hono/tsdown/vitepress, or run repo init/doctor/new/check.
4
4
  ---
5
5
 
6
6
  # repoctl
@@ -9,17 +9,22 @@ The package name is `repoctl`. The command is `repo`.
9
9
 
10
10
  ## Empty directory
11
11
 
12
- Do not prompt. Map the request to template keys, then:
12
+ Create into a new or empty directory outside the repoctl source workspace. Do
13
+ not add a business project under the source checkout, and do not point the
14
+ create command at a non-empty directory unless the user explicitly asks to
15
+ replace it with `--force`. Do not prompt. Map the request to template keys,
16
+ then:
13
17
 
14
18
  ```bash
15
- pnpm create repoctl <dir> -- --yes --templates <keys>
19
+ pnpm create repoctl@latest <dir> -- --yes --templates <keys>
16
20
  cd <dir>
21
+ corepack enable
17
22
  pnpm install
18
23
  pnpm exec repo init
19
24
  pnpm exec repo doctor
20
25
  ```
21
26
 
22
- `npm create` and `pnpm create` need the extra `--` before flags. `npx create-repoctl <dir> --yes --templates <keys>` does not.
27
+ `npm create` and `pnpm create` need the extra `--` before flags. `npx create-repoctl@latest <dir> --yes --templates <keys>` does not.
23
28
 
24
29
  | User intent | `--templates` key |
25
30
  | ------------------------ | ------------------ |
@@ -193,7 +193,8 @@ Usage:
193
193
 
194
194
  ## skills sync
195
195
 
196
- Purpose: sync the `repoctl` skill into global agent skill directories.
196
+ Purpose: sync the `repoctl` skill into global agent skill directories. Use
197
+ `--all` when all supported agents should receive the same skill version.
197
198
  Usage:
198
199
 
199
200
  - pnpm exec repo skills sync
@@ -1,7 +1,7 @@
1
1
  blank_issues_enabled: false
2
2
  contact_links:
3
3
  - name: Feature Request
4
- url: https://github.com/sonofmagic/repoctl/discussions
4
+ url: https://github.com/icelib/repoctl/discussions
5
5
  about: Suggest new features for consideration
6
6
  # - name: Discord Chat
7
7
  # url: https://chat.vuejs.org
@@ -78,6 +78,10 @@ jobs:
78
78
  - name: Test
79
79
  run: pnpm test
80
80
 
81
+ - name: Check packaged monorepo creation
82
+ if: ${{ matrix.os == 'ubuntu-latest' && matrix.node-version == 22 }}
83
+ run: pnpm test:packaged-create
84
+
81
85
  - name: Upload coverage reports to Codecov
82
86
  uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1
83
87
  env:
@@ -69,6 +69,9 @@ jobs:
69
69
  cache: pnpm
70
70
  registry-url: https://registry.npmjs.org
71
71
 
72
+ - name: Install npm with trusted publishing support
73
+ run: npm install --global npm@11.16.0 --registry=https://registry.npmjs.org
74
+
72
75
  - name: Install Dependencies
73
76
  run: pnpm install --frozen-lockfile
74
77
 
package/assets/AGENTS.md CHANGED
@@ -22,6 +22,21 @@ pnpm exec repo new <name> --template <key>
22
22
 
23
23
  Preview without writing files: `pnpm exec repo new <name> --template <key> --dry-run`.
24
24
 
25
+ ## Create a new project
26
+
27
+ If the user asks you to create a new business project, do not add it inside an
28
+ existing unrelated repository. Use a new or empty directory outside the repoctl
29
+ source checkout. Start a new workspace with:
30
+
31
+ ```bash
32
+ pnpm create repoctl@latest <dir> -- --yes --templates <keys>
33
+ cd <dir>
34
+ corepack enable
35
+ pnpm install
36
+ pnpm exec repo init
37
+ pnpm exec repo doctor
38
+ ```
39
+
25
40
  ## Verify
26
41
 
27
42
  ```bash
@@ -38,5 +53,5 @@ pnpm exec repo check
38
53
  ## Requirements
39
54
 
40
55
  - Node.js 22.13 or newer
41
- - pnpm
56
+ - pnpm (run `corepack enable` so the declared workspace version is used)
42
57
  - CLI output is English by default; `--lang zh-CN` or `REPOCTL_LANG=zh-CN` selects Simplified Chinese
package/assets/CLAUDE.md CHANGED
@@ -7,8 +7,14 @@ Follow `AGENTS.md` in the workspace root. Create packages with
7
7
  `pnpm exec repo doctor` and `pnpm exec repo check`.
8
8
 
9
9
  If you were asked to create a new business project, do not add it inside an
10
- existing unrelated repository. Use:
10
+ existing unrelated repository. Use a new or empty directory outside the repoctl
11
+ source checkout:
11
12
 
12
13
  ```bash
13
- pnpm create repoctl <dir> -- --yes --templates <keys>
14
+ pnpm create repoctl@latest <dir> -- --yes --templates <keys>
15
+ cd <dir>
16
+ corepack enable
17
+ pnpm install
18
+ pnpm exec repo init
19
+ pnpm exec repo doctor
14
20
  ```
@@ -31,4 +31,4 @@ The repository includes repoctl's CLI and monorepo engine, template assets, shar
31
31
 
32
32
  When changing templates or managed root assets, update their source first and refresh packaged copies with `pnpm --filter @icebreakers/monorepo-templates sync:assets`.
33
33
 
34
- Report bugs at https://github.com/sonofmagic/repoctl/issues and use discussions for design questions that do not yet have a concrete implementation.
34
+ Report bugs at https://github.com/icelib/repoctl/issues and use discussions for design questions that do not yet have a concrete implementation.
@@ -10,7 +10,7 @@ Security fixes are provided for the latest stable major release of `repoctl` and
10
10
 
11
11
  Do not open a public issue for a suspected vulnerability. Use GitHub's private vulnerability reporting for `sonofmagic/repoctl`:
12
12
 
13
- https://github.com/sonofmagic/repoctl/security/advisories/new
13
+ https://github.com/icelib/repoctl/security/advisories/new
14
14
 
15
15
  Include the affected version, environment, impact, reproduction steps, and any suggested mitigation. Maintainers will acknowledge a complete report as soon as practical and coordinate validation, remediation, and disclosure with the reporter.
16
16
 
package/assets/npmrc ADDED
@@ -0,0 +1,20 @@
1
+ # 文档地址: https://pnpm.io/npmrc
2
+ ## 默认地址
3
+ registry=https://registry.npmjs.org/
4
+ ## 可使用国内镜像地址
5
+ # registry=http://registry.npmmirror.com/
6
+
7
+ ## Git 配置
8
+ git-checks=false
9
+
10
+ ## 包管理器配置
11
+ package-manager-strict=true
12
+ package-manager-strict-version=true
13
+
14
+ ## 依赖处理
15
+ auto-install-peers=true
16
+ strict-peer-dependencies=false
17
+ resolution-mode=highest
18
+
19
+ ## 部分场景可能需要开启此配置
20
+ # shamefully-hoist=true
@@ -3,17 +3,17 @@
3
3
  "type": "module",
4
4
  "version": "0.0.0",
5
5
  "private": true,
6
- "packageManager": "pnpm@12.4.2",
6
+ "packageManager": "pnpm@12.6.0",
7
7
  "description": "Source workspace for repoctl and Icebreaker's shared development packages",
8
8
  "author": "ice breaker <hi@sonofmagic.top>",
9
9
  "license": "MIT",
10
10
  "homepage": "https://repoctl.icebreaker.top",
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "git+https://github.com/sonofmagic/repoctl.git"
13
+ "url": "git+https://github.com/icelib/repoctl.git"
14
14
  },
15
15
  "bugs": {
16
- "url": "https://github.com/sonofmagic/repoctl/issues"
16
+ "url": "https://github.com/icelib/repoctl/issues"
17
17
  },
18
18
  "keywords": [
19
19
  "repoctl",
@@ -71,15 +71,15 @@
71
71
  "--------": "----------------"
72
72
  },
73
73
  "devDependencies": {
74
- "@commitlint/cli": "^21.2.2",
74
+ "@commitlint/cli": "^21.2.3",
75
75
  "@eslint/config-inspector": "^3.5.0",
76
76
  "@icebreakers/commitlint-config": "workspace:*",
77
77
  "@icebreakers/eslint-config": "workspace:*",
78
78
  "@icebreakers/monorepo": "workspace:*",
79
79
  "@icebreakers/stylelint-config": "workspace:*",
80
- "@types/node": "^26.6.1",
80
+ "@types/node": "^26.6.2",
81
81
  "@vitest/coverage-v8": "~5.0.1",
82
- "eslint": "^10.10.0",
82
+ "eslint": "^10.11.0",
83
83
  "execa": "^10.0.1",
84
84
  "husky": "^9.1.7",
85
85
  "lint-staged": "^17.5.1",
@@ -89,7 +89,7 @@
89
89
  "tailwindcss": "^4.3.3",
90
90
  "tsd": "^0.33.0",
91
91
  "tsdown": "0.23.0",
92
- "turbo": "^2.10.13",
92
+ "turbo": "^2.11.3",
93
93
  "typescript": "^6.0.3",
94
94
  "vitest": "~5.0.1",
95
95
  "yaml": "^2.9.1"
@@ -4,6 +4,7 @@ packages:
4
4
  - templates/*
5
5
  - "!**/test/**"
6
6
  minimumReleaseAge: 0
7
+ pmOnFail: error
7
8
  versioning:
8
9
  changelog:
9
10
  storage: repository
@@ -15,7 +16,7 @@ allowBuilds:
15
16
  vue-demi: true
16
17
  workerd: true
17
18
  overrides:
18
- prettier: 3.9.7
19
+ prettier: 3.9.9
19
20
  typescript: 6.0.3
20
21
  vite: 8.3.0
21
22
  postcss: 8.5.28
@@ -6,6 +6,9 @@
6
6
  ":semanticCommitTypeAll(chore)"
7
7
  ],
8
8
  "rangeStrategy": "bump",
9
+ "gitIgnoredAuthors": [
10
+ "41898282+github-actions[bot]@users.noreply.github.com"
11
+ ],
9
12
  "npm": {
10
13
  "commitMessageTopic": "{{prettyDepType}} {{depName}}"
11
14
  },
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as prepareAssets } from "./prepare-zIcRa4-K.mjs";
1
+ import { t as prepareAssets } from "./prepare-OpBpZD1d.mjs";
2
2
  import process from "node:process";
3
3
  //#region src/cli.ts
4
4
  async function main() {
package/dist/index.d.mts CHANGED
@@ -23,6 +23,9 @@ interface SuggestTemplateKeyOptions extends GetTemplateChoicesOptions {
23
23
  keys?: readonly string[];
24
24
  }
25
25
  //#endregion
26
+ //#region src/package-manager/index.d.ts
27
+ export declare function getWorkspacePackageManager(): Promise<string>;
28
+ //#endregion
26
29
  //#region src/paths.d.ts
27
30
  export declare const packageDir: string;
28
31
  export declare const templatesDir: string;
@@ -76,6 +79,7 @@ export declare function execaCommand(command: string, options?: RunCommandOption
76
79
  //#region src/utils/gitignore.d.ts
77
80
  export declare function toPublishGitignorePath(input: string): string;
78
81
  export declare function toWorkspaceGitignorePath(input: string): string;
82
+ export declare function toWorkspaceAssetPath(input: string): string;
79
83
  export declare function isGitignoreFile(name: string): boolean;
80
84
  //#endregion
81
85
  //#region src/utils/template-filter.d.ts
package/dist/index.mjs CHANGED
@@ -1,11 +1,22 @@
1
- import { a as toPublishGitignorePath, c as assetsDir, d as templatesDir, f as assetTargets$1, i as isGitignoreFile, l as packageDir, n as createTemplateCopyFilter, o as toWorkspaceGitignorePath, p as getAssetTargets$1, r as shouldSkipTemplatePath, s as templateChoices$1, t as prepareAssets, u as skeletonDir } from "./prepare-zIcRa4-K.mjs";
1
+ import { a as isGitignoreFile, c as toWorkspaceGitignorePath, d as packageDir, f as skeletonDir, h as getAssetTargets$1, i as shouldSkipTemplatePath, l as templateChoices$1, m as assetTargets$1, n as sanitizePublishedWorkspaceContent, o as toPublishGitignorePath, p as templatesDir, r as createTemplateCopyFilter, s as toWorkspaceAssetPath, t as prepareAssets, u as assetsDir } from "./prepare-OpBpZD1d.mjs";
2
2
  import path from "node:path";
3
- import fs, { access, open, rm } from "node:fs/promises";
3
+ import fs, { access, open, readFile, rm } from "node:fs/promises";
4
4
  import exec from "nanoexec";
5
5
  import checkbox from "@inquirer/checkbox";
6
6
  import input from "@inquirer/input";
7
7
  import select from "@inquirer/select";
8
8
  import { Command, program } from "commander";
9
+ //#region src/package-manager/read.ts
10
+ const packageManagerPattern = /^pnpm@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/u;
11
+ function validateWorkspacePackageManager(value, source) {
12
+ if (typeof value !== "string" || !packageManagerPattern.test(value)) throw new Error(`Invalid packageManager in ${source}; expected a pnpm version such as pnpm@12.5.1.`);
13
+ return value;
14
+ }
15
+ async function readPackageManagerFromManifest(manifestPath) {
16
+ const raw = await fs.readFile(manifestPath, "utf8");
17
+ return validateWorkspacePackageManager(JSON.parse(raw)?.packageManager, manifestPath);
18
+ }
19
+ //#endregion
9
20
  //#region src/runtime-assets.ts
10
21
  const lockFileName = ".prepare-assets.lock";
11
22
  const lockPollIntervalMs = 200;
@@ -33,7 +44,55 @@ async function isPrepared() {
33
44
  path.join(assetsDir, "LICENSE"),
34
45
  path.join(templatesDir, "tsdown")
35
46
  ];
36
- return (await Promise.all(checks.map(pathExists))).every(Boolean);
47
+ if (!(await Promise.all(checks.map(pathExists))).every(Boolean)) return false;
48
+ const sourceRoot = path.resolve(packageDir, "..", "..");
49
+ const sourceManifest = path.join(sourceRoot, "package.json");
50
+ let sourcePackage;
51
+ try {
52
+ sourcePackage = JSON.parse(await readFile(sourceManifest, "utf8"));
53
+ } catch (error) {
54
+ if (error.code === "ENOENT") return true;
55
+ throw error;
56
+ }
57
+ if (sourcePackage.name !== "repoctl-workspace") return true;
58
+ const [sourcePackageManager, sourceNpmrc, sourceWorkspace] = await Promise.all([
59
+ readPackageManagerFromManifest(sourceManifest),
60
+ readFile(path.join(sourceRoot, ".npmrc"), "utf8"),
61
+ readFile(path.join(sourceRoot, "pnpm-workspace.yaml"), "utf8")
62
+ ]);
63
+ let preparedPackageManager;
64
+ let preparedNpmrc;
65
+ let preparedWorkspace;
66
+ let sourceAgentContent;
67
+ let preparedAgentContent;
68
+ let sourceSkillContent;
69
+ let preparedSkillContent;
70
+ try {
71
+ const sourceAgentFiles = ["AGENTS.md", "CLAUDE.md"];
72
+ const [prepared, sourceAgents, preparedAgents, sourceSkill, preparedSkill] = await Promise.all([
73
+ Promise.all([
74
+ readPackageManagerFromManifest(path.join(assetsDir, "package.json")),
75
+ readFile(path.join(assetsDir, "npmrc"), "utf8"),
76
+ readFile(path.join(assetsDir, "pnpm-workspace.yaml"), "utf8")
77
+ ]),
78
+ Promise.all(sourceAgentFiles.map((filename) => readFile(path.join(sourceRoot, "packages/monorepo/assets", filename), "utf8"))),
79
+ Promise.all(sourceAgentFiles.map((filename) => readFile(path.join(assetsDir, filename), "utf8"))),
80
+ readFile(path.join(sourceRoot, "packages/monorepo/resources/skills/repoctl/SKILL.md"), "utf8"),
81
+ readFile(path.join(assetsDir, ".agents/skills/repoctl/SKILL.md"), "utf8")
82
+ ]);
83
+ preparedPackageManager = prepared[0];
84
+ preparedNpmrc = prepared[1];
85
+ preparedWorkspace = prepared[2];
86
+ sourceAgentContent = sourceAgents;
87
+ preparedAgentContent = preparedAgents;
88
+ sourceSkillContent = sourceSkill;
89
+ preparedSkillContent = preparedSkill;
90
+ } catch (error) {
91
+ if (error.code === "ENOENT" || error instanceof SyntaxError) return false;
92
+ if (error instanceof Error && error.message.startsWith("Invalid packageManager in ")) return false;
93
+ throw error;
94
+ }
95
+ return sourcePackageManager === preparedPackageManager && sourceNpmrc === preparedNpmrc && sanitizePublishedWorkspaceContent(sourceWorkspace) === preparedWorkspace && sourceAgentContent.every((content, index) => content === preparedAgentContent[index]) && sourceSkillContent === preparedSkillContent;
37
96
  }
38
97
  async function waitForPrepared() {
39
98
  const deadline = Date.now() + lockTimeoutMs;
@@ -69,6 +128,12 @@ async function ensureTemplateAssetsPrepared() {
69
128
  await ensurePromise;
70
129
  }
71
130
  //#endregion
131
+ //#region src/package-manager/index.ts
132
+ async function getWorkspacePackageManager() {
133
+ await ensureTemplateAssetsPrepared();
134
+ return readPackageManagerFromManifest(path.join(assetsDir, "package.json"));
135
+ }
136
+ //#endregion
72
137
  //#region src/scaffold.ts
73
138
  async function isEmptyDir(dir) {
74
139
  try {
@@ -141,7 +206,10 @@ async function scaffoldWorkspace(options) {
141
206
  if (includeAssets && path.resolve(assetsDir$1) === path.resolve(assetsDir) || templateKeys.length > 0 && path.resolve(templatesDir$1) === path.resolve(templatesDir)) await ensureTemplateAssetsPrepared();
142
207
  if (targetMode === "prepare") await prepareTargetDir(targetDir, { force });
143
208
  else if (targetMode === "ensure") await fs.mkdir(targetDir, { recursive: true });
144
- if (includeAssets) await copyDirContents(assetsDir$1, targetDir, { rootDir: assetsDir$1 });
209
+ if (includeAssets) await copyDirContents(assetsDir$1, targetDir, {
210
+ rootDir: assetsDir$1,
211
+ renameEntry: toWorkspaceAssetPath
212
+ });
145
213
  if (!templateKeys.length) return;
146
214
  const selections = new Set(templateKeys);
147
215
  for (const template of templateChoices$1) {
@@ -258,4 +326,4 @@ const templateSourceMap = Object.fromEntries(templateChoices.map((item) => [item
258
326
  const templateTargetMap = Object.fromEntries(templateChoices.map((item) => [item.key, item.target]));
259
327
  const templateMap = templateSourceMap;
260
328
  //#endregion
261
- export { Command, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, getTemplateChoice, getTemplateChoices, getTemplateDefinition, getTemplateKeys, getTemplateSource, getTemplateTarget, input, isGitignoreFile, isTemplateCategory, isTemplateKey, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, suggestTemplateKey, templateCategories, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceGitignorePath };
329
+ export { Command, assetTargets, assetsDir, checkbox, createTemplateCopyFilter, ensureTemplateAssetsPrepared, execaCommand, getAssetTargets, getTemplateChoice, getTemplateChoices, getTemplateDefinition, getTemplateKeys, getTemplateSource, getTemplateTarget, getWorkspacePackageManager, input, isGitignoreFile, isTemplateCategory, isTemplateKey, packageDir, prepareAssets, program, runCommand, scaffoldTemplate, scaffoldWorkspace, select, shouldSkipTemplatePath, skeletonDir, suggestTemplateKey, templateCategories, templateChoices, templateMap, templateSourceMap, templateTargetMap, templatesDir, toPublishGitignorePath, toWorkspaceAssetPath, toWorkspaceGitignorePath };
@@ -128,6 +128,9 @@ function toPublishGitignorePath(input) {
128
128
  function toWorkspaceGitignorePath(input) {
129
129
  return replaceBasename(input, publishBasename, workspaceBasename);
130
130
  }
131
+ function toWorkspaceAssetPath(input) {
132
+ return replaceBasename(toWorkspaceGitignorePath(input), "npmrc", ".npmrc");
133
+ }
131
134
  function isGitignoreFile(name) {
132
135
  return toPublishGitignorePath(name) !== name || toWorkspaceGitignorePath(name) !== name;
133
136
  }
@@ -201,6 +204,9 @@ const publishedToolingConfigs = {
201
204
  ].join("\n")
202
205
  };
203
206
  const sourceRepoReleaseToolingBuildStepPattern = /\r?\n\s+- name: Build Release Tooling\r?\n\s+run: pnpm run tooling:build\r?\n/g;
207
+ function toPublishedAssetPath(target) {
208
+ return target === ".npmrc" ? "npmrc" : toPublishGitignorePath(target);
209
+ }
204
210
  function removeSourceRepoReleaseToolingBuildStepContent(content) {
205
211
  return content.replaceAll(sourceRepoReleaseToolingBuildStepPattern, "\n");
206
212
  }
@@ -294,9 +300,17 @@ async function copyAssets(repoRoot, overwriteExisting) {
294
300
  const repoAsset = path$1.join(repoRoot, target);
295
301
  const from = publishedAgentSourceFiles.has(target) || !await pathExists(repoAsset) ? packageAsset : repoAsset;
296
302
  if (!await pathExists(from)) continue;
297
- const to = path$1.join(assetsDir, toPublishGitignorePath(target));
303
+ const to = path$1.join(assetsDir, toPublishedAssetPath(target));
298
304
  const stats = await fs.stat(from);
299
- await copyEntry(from, to, overwriteExisting, target === ".husky" ? (src) => !huskySkippedEntryPattern.test(src) : void 0);
305
+ const filter = target === ".husky" ? (src) => !huskySkippedEntryPattern.test(src) : void 0;
306
+ const refreshManagedMetadata = [
307
+ "package.json",
308
+ ".npmrc",
309
+ "pnpm-workspace.yaml",
310
+ "AGENTS.md",
311
+ "CLAUDE.md"
312
+ ].includes(target);
313
+ await copyEntry(from, to, overwriteExisting || refreshManagedMetadata, filter);
300
314
  if (target === "tsconfig.json") await fs.writeFile(to, `${JSON.stringify({
301
315
  extends: "repoctl/tsconfig.json",
302
316
  files: []
@@ -310,10 +324,10 @@ async function writePublishedToolingConfigs() {
310
324
  if (await pathExists(targetPath)) await fs.writeFile(targetPath, content);
311
325
  }));
312
326
  }
313
- async function writePublishedAgentSkill(repoRoot, overwriteExisting) {
327
+ async function writePublishedAgentSkill(repoRoot) {
314
328
  const skillFrom = path$1.join(repoRoot, "packages/monorepo/resources/skills/repoctl");
315
329
  if (!await pathExists(skillFrom)) return;
316
- await copyEntry(skillFrom, path$1.join(assetsDir, ".agents", "skills", "repoctl"), overwriteExisting);
330
+ await copyEntry(skillFrom, path$1.join(assetsDir, ".agents", "skills", "repoctl"), true);
317
331
  }
318
332
  async function sanitizePublishedWorkspace() {
319
333
  const workspacePath = path$1.join(assetsDir, "pnpm-workspace.yaml");
@@ -341,6 +355,7 @@ async function removeSourceRepoWorkerTypeChecks() {
341
355
  if (await pathExists(manifestPath)) {
342
356
  const manifest = JSON.parse(await fs.readFile(manifestPath, "utf8"));
343
357
  delete manifest.scripts?.["test:worker-types"];
358
+ delete manifest.scripts?.["test:packaged-create"];
344
359
  await fs.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
345
360
  }
346
361
  }
@@ -360,14 +375,15 @@ async function prepareAssets(options = {}) {
360
375
  if (!await pathExists(path$1.join(repoRoot, "templates"))) return;
361
376
  await resetDir(assetsDir, overwriteExisting);
362
377
  await resetDir(templatesDir, overwriteExisting);
378
+ await fs.rm(path$1.join(assetsDir, ".npmrc"), { force: true });
363
379
  await copyAssets(repoRoot, overwriteExisting);
364
380
  await sanitizePublishedWorkspace();
365
381
  await removePublishedReleaseState();
366
382
  await writePublishedToolingConfigs();
367
- await writePublishedAgentSkill(repoRoot, overwriteExisting);
383
+ await writePublishedAgentSkill(repoRoot);
368
384
  await removeSourceRepoReleaseToolingBuildStep();
369
385
  await removeSourceRepoWorkerTypeChecks();
370
386
  await copyTemplates(repoRoot, overwriteExisting);
371
387
  }
372
388
  //#endregion
373
- export { toPublishGitignorePath as a, assetsDir as c, templatesDir as d, assetTargets as f, isGitignoreFile as i, packageDir as l, createTemplateCopyFilter as n, toWorkspaceGitignorePath as o, getAssetTargets as p, shouldSkipTemplatePath as r, templateChoices as s, prepareAssets as t, skeletonDir as u };
389
+ export { isGitignoreFile as a, toWorkspaceGitignorePath as c, packageDir as d, skeletonDir as f, getAssetTargets as h, shouldSkipTemplatePath as i, templateChoices as l, assetTargets as m, sanitizePublishedWorkspaceContent as n, toPublishGitignorePath as o, templatesDir as p, createTemplateCopyFilter as r, toWorkspaceAssetPath as s, prepareAssets as t, assetsDir as u };
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@icebreakers/monorepo-templates",
3
3
  "type": "module",
4
- "version": "2.0.1",
4
+ "version": "2.0.3",
5
5
  "description": "Built-in project templates and managed workspace assets for repoctl",
6
6
  "author": "ice breaker <hi@sonofmagic.top>",
7
7
  "license": "MIT",
8
8
  "homepage": "https://repoctl.icebreaker.top",
9
9
  "repository": {
10
10
  "type": "git",
11
- "url": "git+https://github.com/sonofmagic/repoctl.git",
11
+ "url": "git+https://github.com/icelib/repoctl.git",
12
12
  "directory": "packages/monorepo-templates"
13
13
  },
14
14
  "bugs": {
15
- "url": "https://github.com/sonofmagic/repoctl/issues"
15
+ "url": "https://github.com/icelib/repoctl/issues"
16
16
  },
17
17
  "keywords": [
18
18
  "repoctl",
@@ -9,11 +9,11 @@
9
9
  "homepage": "https://repoctl.icebreaker.top",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/sonofmagic/repoctl.git",
12
+ "url": "git+https://github.com/icelib/repoctl.git",
13
13
  "directory": "templates/cli"
14
14
  },
15
15
  "bugs": {
16
- "url": "https://github.com/sonofmagic/repoctl/issues"
16
+ "url": "https://github.com/icelib/repoctl/issues"
17
17
  },
18
18
  "keywords": [
19
19
  "repoctl",
@@ -9,11 +9,11 @@
9
9
  "homepage": "https://repoctl.icebreaker.top",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/sonofmagic/repoctl.git",
12
+ "url": "git+https://github.com/icelib/repoctl.git",
13
13
  "directory": "templates/client"
14
14
  },
15
15
  "bugs": {
16
- "url": "https://github.com/sonofmagic/repoctl/issues"
16
+ "url": "https://github.com/icelib/repoctl/issues"
17
17
  },
18
18
  "keywords": [
19
19
  "repoctl",
@@ -37,8 +37,8 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@faker-js/faker": "^10.6.0",
40
- "@tanstack/vue-query": "^5.103.1",
41
- "@tanstack/vue-query-devtools": "^6.2.1",
40
+ "@tanstack/vue-query": "^5.103.2",
41
+ "@tanstack/vue-query-devtools": "^6.2.4",
42
42
  "@tanstack/vue-table": "^9.2.4",
43
43
  "@tanstack/vue-virtual": "^3.13.39",
44
44
  "@trpc/client": "^11.19.0",
@@ -51,7 +51,7 @@
51
51
  "vue-router": "^5.3.1"
52
52
  },
53
53
  "devDependencies": {
54
- "@cloudflare/vite-plugin": "^1.54.11",
54
+ "@cloudflare/vite-plugin": "^1.56.0",
55
55
  "@hono/node-server": "^2.1.1",
56
56
  "@hono/trpc-server": "^0.4.2",
57
57
  "@tailwindcss/vite": "^4.3.3",
@@ -60,14 +60,14 @@
60
60
  "@vitejs/plugin-vue-jsx": "^5.1.6",
61
61
  "@vue/tsconfig": "^0.9.1",
62
62
  "consola": "^3.4.2",
63
- "hono": "^4.13.8",
63
+ "hono": "^4.13.9",
64
64
  "tailwindcss": "^4.3.3",
65
65
  "typescript": "~6.0.3",
66
66
  "vite": "^8.3.0",
67
67
  "vite-plugin-vue-devtools": "^8.2.1",
68
68
  "vite-tsconfig-paths": "^6.1.1",
69
69
  "vue-tsc": "3.3.11",
70
- "wrangler": "^4.133.0",
70
+ "wrangler": "^4.135.0",
71
71
  "zod": "^4.6.5"
72
72
  }
73
73
  }
@@ -9,11 +9,11 @@
9
9
  "homepage": "https://repoctl.icebreaker.top",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/sonofmagic/repoctl.git",
12
+ "url": "git+https://github.com/icelib/repoctl.git",
13
13
  "directory": "templates/server"
14
14
  },
15
15
  "bugs": {
16
- "url": "https://github.com/sonofmagic/repoctl/issues"
16
+ "url": "https://github.com/icelib/repoctl/issues"
17
17
  },
18
18
  "keywords": [
19
19
  "repoctl",
@@ -66,9 +66,9 @@
66
66
  "devDependencies": {
67
67
  "@hono/node-server": "^2.1.1",
68
68
  "consola": "^3.4.2",
69
- "hono": "^4.13.8",
69
+ "hono": "^4.13.9",
70
70
  "tsdown": "0.23.0",
71
- "wrangler": "^4.133.0",
71
+ "wrangler": "^4.135.0",
72
72
  "zod": "^4.6.5"
73
73
  }
74
74
  }
@@ -9,11 +9,11 @@
9
9
  "homepage": "https://repoctl.icebreaker.top",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/sonofmagic/repoctl.git",
12
+ "url": "git+https://github.com/icelib/repoctl.git",
13
13
  "directory": "templates/tsdown"
14
14
  },
15
15
  "bugs": {
16
- "url": "https://github.com/sonofmagic/repoctl/issues"
16
+ "url": "https://github.com/icelib/repoctl/issues"
17
17
  },
18
18
  "keywords": [
19
19
  "repoctl",
@@ -28,7 +28,7 @@ export default withMermaid(defineConfig({
28
28
  alt: 'repoctl',
29
29
  },
30
30
  search: { provider: 'local' },
31
- socialLinks: [{ icon: 'github', link: 'https://github.com/sonofmagic/repoctl' }],
31
+ socialLinks: [{ icon: 'github', link: 'https://github.com/icelib/repoctl' }],
32
32
  },
33
33
  locales: {
34
34
  root: {
@@ -41,7 +41,7 @@ export default withMermaid(defineConfig({
41
41
  outline: { label: 'On This Page', level: [2, 3] },
42
42
  sidebar: createSidebars('en'),
43
43
  editLink: {
44
- pattern: 'https://github.com/sonofmagic/repoctl/edit/main/templates/vitepress/:path',
44
+ pattern: 'https://github.com/icelib/repoctl/edit/main/templates/vitepress/:path',
45
45
  text: 'Edit this page',
46
46
  },
47
47
  docFooter: { prev: 'Previous page', next: 'Next page' },
@@ -59,7 +59,7 @@ export default withMermaid(defineConfig({
59
59
  outline: { label: '目录', level: [2, 3] },
60
60
  sidebar: createSidebars('zh'),
61
61
  editLink: {
62
- pattern: 'https://github.com/sonofmagic/repoctl/edit/main/templates/vitepress/:path',
62
+ pattern: 'https://github.com/icelib/repoctl/edit/main/templates/vitepress/:path',
63
63
  text: '为此页提供修改建议',
64
64
  },
65
65
  docFooter: { prev: '上一页', next: '下一页' },
@@ -32,8 +32,8 @@ export function createPageHead({ page, title, description }: TransformContext):
32
32
  const jsonLd = {
33
33
  '@context': 'https://schema.org',
34
34
  '@graph': [
35
- { '@type': 'Organization', 'name': 'repoctl', 'url': siteOrigin, 'logo': `${siteOrigin}/brand/repoctl-mark.svg`, 'sameAs': ['https://github.com/sonofmagic/repoctl', 'https://www.npmjs.com/package/repoctl'] },
36
- { '@type': 'SoftwareApplication', 'name': 'repoctl', 'applicationCategory': 'DeveloperApplication', 'operatingSystem': 'macOS, Linux, Windows', 'url': siteOrigin, description, 'sameAs': ['https://github.com/sonofmagic/repoctl', 'https://www.npmjs.com/package/repoctl'], 'offers': { '@type': 'Offer', 'price': '0', 'priceCurrency': 'USD' } },
35
+ { '@type': 'Organization', 'name': 'repoctl', 'url': siteOrigin, 'logo': `${siteOrigin}/brand/repoctl-mark.svg`, 'sameAs': ['https://github.com/icelib/repoctl', 'https://www.npmjs.com/package/repoctl'] },
36
+ { '@type': 'SoftwareApplication', 'name': 'repoctl', 'applicationCategory': 'DeveloperApplication', 'operatingSystem': 'macOS, Linux, Windows', 'url': siteOrigin, description, 'sameAs': ['https://github.com/icelib/repoctl', 'https://www.npmjs.com/package/repoctl'], 'offers': { '@type': 'Offer', 'price': '0', 'priceCurrency': 'USD' } },
37
37
  { '@type': 'WebSite', 'name': 'repoctl', 'url': siteOrigin, 'potentialAction': { '@type': 'SearchAction', 'target': `${siteOrigin}/reference/commands?q={search_term_string}`, 'query-input': 'required name=search_term_string' } },
38
38
  ],
39
39
  }
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Non-interactive recipe for AI agents to create a repoctl workspace with pnpm create repoctl --yes.
2
+ description: Non-interactive recipe for AI agents to create a repoctl workspace with pnpm create repoctl@latest --yes.
3
3
  outline: deep
4
4
  ---
5
5
 
@@ -9,18 +9,22 @@ Use this page when an agent is asked to create a new project with repoctl.
9
9
 
10
10
  ## Empty directory
11
11
 
12
- Do not prompt. Run:
12
+ Use a new or empty directory outside the repoctl source checkout. Do not add a
13
+ business project inside the source workspace, and do not use a non-empty target
14
+ unless the user explicitly asks to replace it with `--force`. Do not prompt.
15
+ Run:
13
16
 
14
17
  ```bash
15
- pnpm create repoctl <dir> -- --yes --templates <keys>
18
+ pnpm create repoctl@latest <dir> -- --yes --templates <keys>
16
19
  cd <dir>
20
+ corepack enable
17
21
  pnpm install
18
22
  pnpm exec repo init
19
23
  pnpm exec repo doctor
20
24
  ```
21
25
 
22
26
  `npm create repoctl@latest <dir> -- --yes --templates <keys>` and
23
- `npx create-repoctl <dir> --yes --templates <keys>` are equivalent.
27
+ `npx create-repoctl@latest <dir> --yes --templates <keys>` are equivalent.
24
28
  `pnpm create` and `npm create` need the extra `--` before flags.
25
29
 
26
30
  ## Template keys
@@ -10,7 +10,7 @@ outline: deep
10
10
  | ------------- | ---------------------------------------------------- |
11
11
  | Product | repoctl, task-first CLI for monorepos |
12
12
  | Official site | https://repoctl.icebreaker.top |
13
- | Source | https://github.com/sonofmagic/repoctl |
13
+ | Source | https://github.com/icelib/repoctl |
14
14
  | npm package | `repoctl` — https://www.npmjs.com/package/repoctl |
15
15
  | Install | `pnpm add -D repoctl` |
16
16
  | Core commands | `repo init`, `repo doctor`, `repo new`, `repo check` |
@@ -23,7 +23,7 @@ repoctl publishes AI-readable documentation alongside the human site.
23
23
  - `/llms.txt`: compact English index and product summary.
24
24
  - `/llms-full.txt`: combined page content when a larger context is appropriate.
25
25
  - `/zh/`: Simplified Chinese documentation.
26
- - [Create a project](./create.md): non-interactive `pnpm create repoctl --yes` recipe.
26
+ - [Create a project](./create.md): non-interactive `pnpm create repoctl@latest --yes` recipe.
27
27
  - [llms.txt Guide](./llms-txt.md): usage and maintenance rules.
28
28
 
29
29
  ## Using It In AI Tools
@@ -9,11 +9,11 @@
9
9
  "homepage": "https://repoctl.icebreaker.top",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/sonofmagic/repoctl.git",
12
+ "url": "git+https://github.com/icelib/repoctl.git",
13
13
  "directory": "templates/vitepress"
14
14
  },
15
15
  "bugs": {
16
- "url": "https://github.com/sonofmagic/repoctl/issues"
16
+ "url": "https://github.com/icelib/repoctl/issues"
17
17
  },
18
18
  "keywords": [
19
19
  "repoctl",
@@ -52,6 +52,6 @@
52
52
  "vitepress-plugin-llms": "^1.14.0",
53
53
  "vitepress-plugin-mermaid": "^2.0.17",
54
54
  "vue-tsc": "^3.3.11",
55
- "wrangler": "^4.133.0"
55
+ "wrangler": "^4.135.0"
56
56
  }
57
57
  }
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: 给 AI 代理用的非交互配方:pnpm create repoctl --yes 创建 repoctl 工作区。
2
+ description: 给 AI 代理用的非交互配方:pnpm create repoctl@latest --yes 创建 repoctl 工作区。
3
3
  outline: deep
4
4
  ---
5
5
 
@@ -9,18 +9,21 @@ outline: deep
9
9
 
10
10
  ## 空目录
11
11
 
12
- 不要提问。直接运行:
12
+ 目标目录应是 repoctl 源仓库之外的新目录或空目录。不要把业务项目放进
13
+ 源仓库,也不要在非空目录上运行,除非用户明确要求使用 `--force` 覆盖。
14
+ 不要提问,直接运行:
13
15
 
14
16
  ```bash
15
- pnpm create repoctl <dir> -- --yes --templates <keys>
17
+ pnpm create repoctl@latest <dir> -- --yes --templates <keys>
16
18
  cd <dir>
19
+ corepack enable
17
20
  pnpm install
18
21
  pnpm exec repo init
19
22
  pnpm exec repo doctor
20
23
  ```
21
24
 
22
25
  等价命令:`npm create repoctl@latest <dir> -- --yes --templates <keys>` 与
23
- `npx create-repoctl <dir> --yes --templates <keys>`。
26
+ `npx create-repoctl@latest <dir> --yes --templates <keys>`。
24
27
  `pnpm create` / `npm create` 的 flag 前必须加 `--`。
25
28
 
26
29
  ## 模板 key
@@ -12,7 +12,7 @@ AI 文档入口用于给 Cursor、Claude Code、Codex 和其他 AI 编程工具
12
12
  | ------------------------------ | ------------------------------------------------ |
13
13
  | `/llms.txt` | 轻量文档索引,适合先交给 AI 工具判断要读哪些页面 |
14
14
  | `/llms-full.txt` | 合并后的完整文档,适合需要一次性提供上下文的场景 |
15
- | [创建项目](./create.md) | 非交互 `pnpm create repoctl --yes` 配方 |
15
+ | [创建项目](./create.md) | 非交互 `pnpm create repoctl@latest --yes` 配方 |
16
16
  | [llms.txt 说明](./llms-txt.md) | 维护约定、访问方式和页面 frontmatter 要求 |
17
17
 
18
18
  ## 2. 在 AI 工具里怎么用
@@ -25,7 +25,7 @@
25
25
 
26
26
  ## tsdown
27
27
 
28
- repoctl 当前的通用类库模板是 [tsdown](https://github.com/sonofmagic/repoctl/tree/main/templates/tsdown)
28
+ repoctl 当前的通用类库模板是 [tsdown](https://github.com/icelib/repoctl/tree/main/templates/tsdown)
29
29
 
30
30
  :::code-group
31
31
 
@@ -45,8 +45,8 @@ export default defineConfig({
45
45
 
46
46
  ## vite
47
47
 
48
- repoctl 的内置模板之一 [vue-lib](https://github.com/sonofmagic/repoctl/tree/main/templates/vue-lib)
48
+ repoctl 的内置模板之一 [vue-lib](https://github.com/icelib/repoctl/tree/main/templates/vue-lib)
49
49
 
50
50
  你可以在 [`vite` 库模式官方文档](https://vite.dev/guide/build.html#library-mode) 来查看打包 `vue` 组件的方式
51
51
 
52
- 这些能力已经配置在 [vue-lib](https://github.com/sonofmagic/repoctl/tree/main/templates/vue-lib) 中
52
+ 这些能力已经配置在 [vue-lib](https://github.com/icelib/repoctl/tree/main/templates/vue-lib) 中
@@ -14,7 +14,7 @@ outline: [2, 4]
14
14
 
15
15
  为此我们需要提升包的质量,具体的手段如下
16
16
 
17
- 此代码的演变用例见 [examples](https://github.com/sonofmagic/repoctl/tree/main/templates/vitepress/learn/packages/examples)
17
+ 此代码的演变用例见 [examples](https://github.com/icelib/repoctl/tree/main/templates/vitepress/learn/packages/examples)
18
18
 
19
19
  ## 确定包的模块入口点
20
20
 
@@ -9,11 +9,11 @@
9
9
  "homepage": "https://repoctl.icebreaker.top",
10
10
  "repository": {
11
11
  "type": "git",
12
- "url": "git+https://github.com/sonofmagic/repoctl.git",
12
+ "url": "git+https://github.com/icelib/repoctl.git",
13
13
  "directory": "templates/vue-lib"
14
14
  },
15
15
  "bugs": {
16
- "url": "https://github.com/sonofmagic/repoctl/issues"
16
+ "url": "https://github.com/icelib/repoctl/issues"
17
17
  },
18
18
  "keywords": [
19
19
  "repoctl",
@@ -62,9 +62,9 @@
62
62
  "@vitejs/plugin-vue": "^6.0.9",
63
63
  "@vue/test-utils": "^2.5.1",
64
64
  "@vue/tsconfig": "^0.9.1",
65
- "jsdom": "^30.1.0",
65
+ "jsdom": "^30.1.1",
66
66
  "vite": "^8.3.0",
67
- "vite-plugin-dts": "^5.1.0",
67
+ "vite-plugin-dts": "^5.1.1",
68
68
  "vue": "^3.5.43",
69
69
  "vue-tsc": "^3.3.11"
70
70
  }