@icebreakers/monorepo-templates 2.0.2 → 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.
- package/assets/.agents/skills/repoctl/SKILL.md +9 -4
- package/assets/.agents/skills/repoctl/references/commands.md +2 -1
- package/assets/.github/workflows/ci.yml +4 -0
- package/assets/AGENTS.md +16 -1
- package/assets/CLAUDE.md +8 -2
- package/assets/npmrc +20 -0
- package/assets/package.json +1 -1
- package/assets/pnpm-workspace.yaml +1 -0
- package/dist/cli.mjs +1 -1
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +73 -5
- package/dist/{prepare-zIcRa4-K.mjs → prepare-OpBpZD1d.mjs} +22 -6
- package/package.json +1 -1
- package/templates/client/package.json +1 -1
- package/templates/server/package.json +1 -1
- package/templates/vitepress/ai/create.md +8 -4
- package/templates/vitepress/ai/index.md +1 -1
- package/templates/vitepress/zh/ai/create.md +7 -4
- package/templates/vitepress/zh/ai/index.md +1 -1
|
@@ -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
|
-
|
|
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
|
|
@@ -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:
|
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
|
```
|
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
|
package/assets/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"type": "module",
|
|
4
4
|
"version": "0.0.0",
|
|
5
5
|
"private": true,
|
|
6
|
-
"packageManager": "pnpm@12.
|
|
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",
|
package/dist/cli.mjs
CHANGED
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
|
|
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
|
-
|
|
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, {
|
|
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,
|
|
303
|
+
const to = path$1.join(assetsDir, toPublishedAssetPath(target));
|
|
298
304
|
const stats = await fs.stat(from);
|
|
299
|
-
|
|
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
|
|
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"),
|
|
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
|
|
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 {
|
|
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,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
|
|
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
|
|
@@ -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
|
|
@@ -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 工具里怎么用
|