@wnlen/agent-execution-template 0.8.17 → 0.8.18
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 +14 -0
- package/README.zh-CN.md +11 -0
- package/bin/agent-execution-template.js +44 -3
- package/docs/SPEC.md +2 -2
- package/package.json +3 -2
- package/template/en/ai/README.md +2 -19
- package/template/en/ai/template/VERSION +1 -1
- package/template/zh/ai/README.md +2 -19
- package/template/zh/ai/template/VERSION +1 -1
- package/test/check-release.js +94 -0
- package/test/selftest.js +13 -0
package/README.md
CHANGED
|
@@ -444,11 +444,25 @@ Run the self-test:
|
|
|
444
444
|
npm test
|
|
445
445
|
```
|
|
446
446
|
|
|
447
|
+
Run the release consistency check:
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
npm run check:release
|
|
451
|
+
```
|
|
452
|
+
|
|
447
453
|
The test suite verifies the core CLI contract:
|
|
448
454
|
|
|
449
455
|
- `init` creates the expected protocol and project files.
|
|
450
456
|
- `update` does not overwrite `ai/project/**`.
|
|
451
457
|
- `doctor` reports missing and empty required files correctly.
|
|
458
|
+
- `check:release` verifies versions, template shape, installed protocol state,
|
|
459
|
+
and the spec's package version.
|
|
460
|
+
|
|
461
|
+
When maintaining this npm package source checkout, test the local CLI with
|
|
462
|
+
`node bin/agent-execution-template.js <command>`. Use
|
|
463
|
+
`npx -y @wnlen/agent-execution-template <command>` in user projects only.
|
|
464
|
+
Maintainer-local `ai/project/**` bootstrap content should not be committed as
|
|
465
|
+
product changes.
|
|
452
466
|
|
|
453
467
|
## Contributing
|
|
454
468
|
|
package/README.zh-CN.md
CHANGED
|
@@ -449,11 +449,22 @@ License: MIT
|
|
|
449
449
|
npm test
|
|
450
450
|
```
|
|
451
451
|
|
|
452
|
+
发布前检查:
|
|
453
|
+
|
|
454
|
+
```bash
|
|
455
|
+
npm run check:release
|
|
456
|
+
```
|
|
457
|
+
|
|
452
458
|
测试会验证核心 CLI 契约:
|
|
453
459
|
|
|
454
460
|
- `init` 创建预期的协议和项目文件。
|
|
455
461
|
- `update` 不覆盖 `ai/project/**`。
|
|
456
462
|
- `doctor` 正确报告缺失文件和空的必要文件。
|
|
463
|
+
- `check:release` 验证版本号、模板结构、安装态协议和规格文档一致。
|
|
464
|
+
|
|
465
|
+
维护这个 npm 包源码仓库时,用 `node bin/agent-execution-template.js <command>`
|
|
466
|
+
测试当前 checkout;用户项目才使用 `npx -y @wnlen/agent-execution-template <command>`。
|
|
467
|
+
维护者本地 `ai/project/**` 初始化内容不应作为产品改动提交。
|
|
457
468
|
|
|
458
469
|
## 贡献
|
|
459
470
|
|
|
@@ -155,6 +155,10 @@ const TEXT = {
|
|
|
155
155
|
nextReviewProposal: "已有方向修订提案。先审查提案;确认后对 AI 说:",
|
|
156
156
|
nextContinuePrompt: "继续推进这个项目。执行前先拆 L1 任务;若 L1 >= 2,自动启用边界内连续执行;只有 Red 风险停下来确认。",
|
|
157
157
|
repairHint: "缺失的 project 推荐文件可通过重新运行 init 安全补齐;已有 ai/project/** 不会被覆盖。",
|
|
158
|
+
sourceCheckoutNotice: `维护者提示: 当前目录看起来是 @wnlen/agent-execution-template 源码仓库。
|
|
159
|
+
源码仓库内调试请使用: node bin/agent-execution-template.js <command>
|
|
160
|
+
用户项目中安装才使用: npx -y @wnlen/agent-execution-template <command>
|
|
161
|
+
不要把维护者本地初始化产生的 ai/project/** 当成产品改动提交。`,
|
|
158
162
|
permissionDenied: "无法写入目标路径",
|
|
159
163
|
permissionHint: `请检查 ai/** 的归属和权限。常见修复:
|
|
160
164
|
sudo chown -R "$(id -un):$(id -gn)" ai
|
|
@@ -260,6 +264,10 @@ Usage:
|
|
|
260
264
|
nextReviewProposal: "A direction amendment proposal exists. Review it first; after confirmation, tell the AI:",
|
|
261
265
|
nextContinuePrompt: "Continue this project. Before execution, decompose L1 tasks; if L1 >= 2, automatically use bounded continuous execution; only Red risk stops for confirmation.",
|
|
262
266
|
repairHint: "Missing recommended project files can be safely added by running init again; existing ai/project/** files are not overwritten.",
|
|
267
|
+
sourceCheckoutNotice: `Maintainer note: this directory looks like the @wnlen/agent-execution-template source checkout.
|
|
268
|
+
In the source repository, test with: node bin/agent-execution-template.js <command>
|
|
269
|
+
In user projects, install with: npx -y @wnlen/agent-execution-template <command>
|
|
270
|
+
Do not commit maintainer-local ai/project/** bootstrap content as product changes.`,
|
|
263
271
|
permissionDenied: "Cannot write target path",
|
|
264
272
|
permissionHint: `Check ownership and permissions under ai/**. Common fix:
|
|
265
273
|
sudo chown -R "$(id -un):$(id -gn)" ai
|
|
@@ -291,6 +299,17 @@ function readPackageVersion() {
|
|
|
291
299
|
}
|
|
292
300
|
}
|
|
293
301
|
|
|
302
|
+
function readTargetPackageName() {
|
|
303
|
+
const packageFile = path.join(process.cwd(), "package.json");
|
|
304
|
+
if (!fs.existsSync(packageFile)) return null;
|
|
305
|
+
try {
|
|
306
|
+
const pkg = JSON.parse(fs.readFileSync(packageFile, "utf8"));
|
|
307
|
+
return pkg.name || null;
|
|
308
|
+
} catch {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
294
313
|
function readInstalledLang() {
|
|
295
314
|
const langFile = path.join(TARGET_AI, "template", "LANG");
|
|
296
315
|
if (!fs.existsSync(langFile)) return DEFAULT_LANG;
|
|
@@ -298,6 +317,24 @@ function readInstalledLang() {
|
|
|
298
317
|
return SUPPORTED_LANGS.has(lang) ? lang : DEFAULT_LANG;
|
|
299
318
|
}
|
|
300
319
|
|
|
320
|
+
function isSourceCheckout() {
|
|
321
|
+
return process.cwd() === PACKAGE_ROOT &&
|
|
322
|
+
readTargetPackageName() === "@wnlen/agent-execution-template";
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function commandHint(command) {
|
|
326
|
+
if (isSourceCheckout()) {
|
|
327
|
+
return `node bin/agent-execution-template.js ${command}`;
|
|
328
|
+
}
|
|
329
|
+
return `npx -y @wnlen/agent-execution-template ${command}`;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function printSourceCheckoutNotice(lang) {
|
|
333
|
+
if (isSourceCheckout()) {
|
|
334
|
+
console.log(`${getText(lang).sourceCheckoutNotice}\n`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
301
338
|
function parseLang(args, fallback = DEFAULT_LANG) {
|
|
302
339
|
let lang = fallback;
|
|
303
340
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -487,12 +524,14 @@ function init({ lang = DEFAULT_LANG, verbose = false, quiet = false } = {}) {
|
|
|
487
524
|
.map((change) => ({ ...change, path: path.join("ai/project", change.path) })));
|
|
488
525
|
|
|
489
526
|
if (!quiet) {
|
|
527
|
+
const sourceNotice = isSourceCheckout() ? `${text.sourceCheckoutNotice}\n\n` : "";
|
|
490
528
|
console.log(`${text.ready}
|
|
491
529
|
|
|
492
530
|
${text.initGuide}
|
|
493
531
|
|
|
532
|
+
${sourceNotice}
|
|
494
533
|
${text.files}: ${summarizeChanges(changes, lang)}
|
|
495
|
-
${text.check}:
|
|
534
|
+
${text.check}: ${commandHint("doctor")}
|
|
496
535
|
`);
|
|
497
536
|
|
|
498
537
|
if (verbose) {
|
|
@@ -546,12 +585,13 @@ function next({ lang = readInstalledLang() } = {}) {
|
|
|
546
585
|
}
|
|
547
586
|
|
|
548
587
|
console.log(`${text.nextTitle}\n`);
|
|
588
|
+
printSourceCheckoutNotice(lang);
|
|
549
589
|
|
|
550
590
|
const templatePath = path.join(TARGET_AI, "template");
|
|
551
591
|
const projectPath = path.join(TARGET_AI, "project");
|
|
552
592
|
if (!fs.existsSync(templatePath) || !fs.existsSync(projectPath)) {
|
|
553
593
|
console.log(`${text.nextRunInit}
|
|
554
|
-
|
|
594
|
+
${commandHint("init")}
|
|
555
595
|
`);
|
|
556
596
|
return;
|
|
557
597
|
}
|
|
@@ -678,6 +718,7 @@ function doctor() {
|
|
|
678
718
|
const lang = readInstalledLang();
|
|
679
719
|
const text = getText(lang);
|
|
680
720
|
console.log(`${text.doctorTitle}\n`);
|
|
721
|
+
printSourceCheckoutNotice(lang);
|
|
681
722
|
console.log(`${text.templateVersion}: ${readVersion(path.join(TARGET_AI, "template")) || text.unknown}`);
|
|
682
723
|
console.log(`${text.templateLang}: ${lang}\n`);
|
|
683
724
|
|
|
@@ -748,7 +789,7 @@ function doctor() {
|
|
|
748
789
|
}
|
|
749
790
|
|
|
750
791
|
if (missing > 0) {
|
|
751
|
-
console.log(`\n[${text.fail}] ${
|
|
792
|
+
console.log(`\n[${text.fail}] ${commandHint("init")}`);
|
|
752
793
|
process.exitCode = 1;
|
|
753
794
|
} else if (warnings > 0) {
|
|
754
795
|
console.log(`\n[${text.pass}] ${text.readyWithWarnings}`);
|
package/docs/SPEC.md
CHANGED
|
@@ -22,7 +22,7 @@ npx 安装协议 -> AI 整理项目上下文 -> 人类确认 -> AI 生成任务
|
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
24
|
Protocol: v0.8
|
|
25
|
-
Package: @wnlen/agent-execution-template@0.8.
|
|
25
|
+
Package: @wnlen/agent-execution-template@0.8.18
|
|
26
26
|
中文安装: npx -y @wnlen/agent-execution-template init
|
|
27
27
|
英文安装: npx -y @wnlen/agent-execution-template init --lang en
|
|
28
28
|
```
|
|
@@ -392,7 +392,7 @@ npx -y @wnlen/agent-execution-template doctor
|
|
|
392
392
|
```text
|
|
393
393
|
Agent Execution Template 检查
|
|
394
394
|
|
|
395
|
-
模板版本: 0.8.
|
|
395
|
+
模板版本: 0.8.18
|
|
396
396
|
模板语言: zh
|
|
397
397
|
|
|
398
398
|
[通过] ai/template/LANG
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wnlen/agent-execution-template",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.18",
|
|
4
4
|
"description": "Low-friction AI execution protocol template for coding agents.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"agent-execution-template": "bin/agent-execution-template.js"
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
16
|
"doctor": "node bin/agent-execution-template.js doctor",
|
|
17
|
-
"
|
|
17
|
+
"check:release": "node test/check-release.js",
|
|
18
|
+
"test": "node test/selftest.js && node test/check-release.js"
|
|
18
19
|
},
|
|
19
20
|
"keywords": [
|
|
20
21
|
"ai",
|
package/template/en/ai/README.md
CHANGED
|
@@ -114,22 +114,5 @@ From a real project back into the template repo:
|
|
|
114
114
|
- Return only `ai/template/**`.
|
|
115
115
|
- Never return `ai/project/**`.
|
|
116
116
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
- The human provides intent, hard constraints, and final acceptance.
|
|
120
|
-
- The agent drafts `project/project.md` and relevant `project/refs/*` from existing docs, manifests, refs, and project files.
|
|
121
|
-
- The agent drafts `project/task.md` after the human provides the current task goal.
|
|
122
|
-
- The human reviews and confirms project and task drafts before execution.
|
|
123
|
-
- Bootstrap may write only project context files, plus `project/task.md` when a current task is provided.
|
|
124
|
-
- Bootstrap must not edit source code, tests, configuration, dependency files, generated files, runtime files, result files, or metrics files.
|
|
125
|
-
- Ask at most 3 clarification questions.
|
|
126
|
-
- Ask only when the answer changes scope, risk, permission, or acceptance.
|
|
127
|
-
- Repeated assumptions should become `project/runtime.md` update proposals.
|
|
128
|
-
|
|
129
|
-
## Model Division Protocol
|
|
130
|
-
|
|
131
|
-
- Model policy lives in `project/task.md.model_policy`.
|
|
132
|
-
- Use `cheap` by default for routine execution.
|
|
133
|
-
- Use `standard` for moderate implementation complexity.
|
|
134
|
-
- Use `strong` only for planning, risk judgment, architecture review, failure review, or acceptance judgment.
|
|
135
|
-
- Record actual tier, trigger, role, and escalation reason in `project/metrics.json`.
|
|
117
|
+
Detailed execution rules live in `template/protocol.md`,
|
|
118
|
+
`template/bootstrap.md`, `template/execution-policy.md`, and `template/rules/`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.8.
|
|
1
|
+
0.8.18
|
package/template/zh/ai/README.md
CHANGED
|
@@ -112,22 +112,5 @@ ai/project/inbox/ideas/
|
|
|
112
112
|
- 只回流 `ai/template/**`。
|
|
113
113
|
- 永远不要回流 `ai/project/**`。
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- 人类提供意图、硬约束和最终验收。
|
|
118
|
-
- Agent 从现有文档、清单、引用和项目文件中起草 `project/project.md` 和相关 `project/refs/*`。
|
|
119
|
-
- 人类提供当前任务目标后,Agent 起草 `project/task.md`。
|
|
120
|
-
- 人类在执行前检查并确认项目和任务草稿。
|
|
121
|
-
- 引导只能写项目上下文文件;当提供当前任务时,也可以写 `project/task.md`。
|
|
122
|
-
- 引导不得编辑源码、测试、配置、依赖文件、生成文件、运行时文件、结果文件或指标文件。
|
|
123
|
-
- 最多问 3 个澄清问题。
|
|
124
|
-
- 只在答案会改变范围、风险、权限或验收时提问。
|
|
125
|
-
- 重复出现的假设应变成 `project/runtime.md` 更新建议。
|
|
126
|
-
|
|
127
|
-
## 模型分工协议
|
|
128
|
-
|
|
129
|
-
- 模型策略位于 `project/task.md.model_policy`。
|
|
130
|
-
- 常规执行默认使用 `cheap`。
|
|
131
|
-
- 中等实现复杂度使用 `standard`。
|
|
132
|
-
- 只有规划、风险判断、架构复核、失败复盘或验收判断才使用 `strong`。
|
|
133
|
-
- 在 `project/metrics.json` 中记录实际档位、触发条件、角色和升级原因。
|
|
115
|
+
详细执行规则见 `template/protocol.md`、`template/bootstrap.md`、
|
|
116
|
+
`template/execution-policy.md` 和 `template/rules/`。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.8.
|
|
1
|
+
0.8.18
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
const repoRoot = path.resolve(__dirname, "..");
|
|
7
|
+
const packagePath = path.join(repoRoot, "package.json");
|
|
8
|
+
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf8"));
|
|
9
|
+
|
|
10
|
+
function fail(message) {
|
|
11
|
+
throw new Error(message);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function read(relativePath) {
|
|
15
|
+
return fs.readFileSync(path.join(repoRoot, relativePath), "utf8");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function listFiles(relativeDir) {
|
|
19
|
+
const root = path.join(repoRoot, relativeDir);
|
|
20
|
+
const files = [];
|
|
21
|
+
|
|
22
|
+
function walk(dir) {
|
|
23
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
24
|
+
const fullPath = path.join(dir, entry.name);
|
|
25
|
+
if (entry.isDirectory()) {
|
|
26
|
+
walk(fullPath);
|
|
27
|
+
} else if (entry.isFile()) {
|
|
28
|
+
files.push(path.relative(root, fullPath).split(path.sep).join("/"));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
walk(root);
|
|
34
|
+
return files.sort();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function assertEqual(actual, expected, message) {
|
|
38
|
+
if (actual !== expected) {
|
|
39
|
+
fail(`${message}\nExpected: ${expected}\nActual: ${actual}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function assertIncludes(content, expected, message) {
|
|
44
|
+
if (!content.includes(expected)) {
|
|
45
|
+
fail(`${message}\nMissing: ${expected}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function assertFileListsMatch(leftDir, rightDir, message) {
|
|
50
|
+
const left = listFiles(leftDir).join("\n");
|
|
51
|
+
const right = listFiles(rightDir).join("\n");
|
|
52
|
+
assertEqual(left, right, message);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function assertTreesMatch(leftDir, rightDir, message) {
|
|
56
|
+
const leftFiles = listFiles(leftDir);
|
|
57
|
+
const rightFiles = listFiles(rightDir);
|
|
58
|
+
assertEqual(leftFiles.join("\n"), rightFiles.join("\n"), `${message}: file list differs`);
|
|
59
|
+
|
|
60
|
+
for (const file of leftFiles) {
|
|
61
|
+
const left = read(path.join(leftDir, file));
|
|
62
|
+
const right = read(path.join(rightDir, file));
|
|
63
|
+
assertEqual(left, right, `${message}: ${file} differs`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function main() {
|
|
68
|
+
const version = packageJson.version;
|
|
69
|
+
assertEqual(packageJson.name, "@wnlen/agent-execution-template", "package name changed unexpectedly");
|
|
70
|
+
assertEqual(
|
|
71
|
+
packageJson.bin && packageJson.bin["agent-execution-template"],
|
|
72
|
+
"bin/agent-execution-template.js",
|
|
73
|
+
"package bin entry should point to the CLI"
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
assertEqual(read("template/zh/ai/template/VERSION").trim(), version, "zh template version must match package version");
|
|
77
|
+
assertEqual(read("template/en/ai/template/VERSION").trim(), version, "en template version must match package version");
|
|
78
|
+
assertEqual(read("ai/template/VERSION").trim(), version, "installed zh template version must match package version");
|
|
79
|
+
|
|
80
|
+
assertFileListsMatch("template/zh/ai", "template/en/ai", "zh and en templates must expose the same file layout");
|
|
81
|
+
assertTreesMatch("template/zh/ai/template", "ai/template", "installed ai/template must mirror template/zh/ai/template");
|
|
82
|
+
assertEqual(read("template/zh/ai/README.md"), read("ai/README.md"), "installed ai/README.md must mirror template/zh/ai/README.md");
|
|
83
|
+
|
|
84
|
+
const spec = read("docs/SPEC.md");
|
|
85
|
+
assertIncludes(spec, `Package: @wnlen/agent-execution-template@${version}`, "SPEC package version must match package.json");
|
|
86
|
+
|
|
87
|
+
const scripts = packageJson.scripts || {};
|
|
88
|
+
assertIncludes(scripts.test || "", "test/selftest.js", "npm test should run the CLI selftest");
|
|
89
|
+
assertIncludes(scripts.test || "", "test/check-release.js", "npm test should run release consistency checks");
|
|
90
|
+
|
|
91
|
+
console.log("release check ok");
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
main();
|
package/test/selftest.js
CHANGED
|
@@ -122,6 +122,7 @@ function testInitUpdateDoctor() {
|
|
|
122
122
|
assert(initOutput.includes("把 ai/project/inbox/ideas/ 里的新灵感生成方向修订提案"), "init output should provide natural strategy prompt");
|
|
123
123
|
assert(initOutput.includes("agent-execution-template next"), "init output should tell users how to recover the next step");
|
|
124
124
|
assert(initOutput.includes("文件:"), "init output should summarize file changes");
|
|
125
|
+
assert(!initOutput.includes("维护者提示"), "init output should not show source checkout guidance in user projects");
|
|
125
126
|
assert(!initOutput.includes("[已更新]"), "init output should hide detailed file changes by default");
|
|
126
127
|
assert(!initOutput.includes("Read ai/template/bootstrap.md"), "init output should not use weak Read bootstrap command");
|
|
127
128
|
assert(run(["init", "--verbose"], cwd).includes("[已更新] ai/template/VERSION"), "init --verbose should show detailed file changes");
|
|
@@ -202,6 +203,7 @@ function testEnglishInitUpdateDoctor() {
|
|
|
202
203
|
assert(initOutput.includes("Generate a direction amendment proposal from ai/project/inbox/ideas/"), "English init output should provide natural strategy prompt");
|
|
203
204
|
assert(initOutput.includes("agent-execution-template next"), "English init output should tell users how to recover the next step");
|
|
204
205
|
assert(initOutput.includes("Files:"), "English init output should summarize file changes");
|
|
206
|
+
assert(!initOutput.includes("Maintainer note"), "English init output should not show source checkout guidance in user projects");
|
|
205
207
|
assert(!initOutput.includes("[UPDATED]"), "English init output should hide detailed file changes by default");
|
|
206
208
|
assert(run(["init", "--lang=en", "--verbose"], cwd).includes("[UPDATED] ai/template/VERSION"), "English init --verbose should show detailed file changes");
|
|
207
209
|
|
|
@@ -338,6 +340,16 @@ function testPermissionErrorIsActionable() {
|
|
|
338
340
|
}
|
|
339
341
|
}
|
|
340
342
|
|
|
343
|
+
function testSourceCheckoutNotice() {
|
|
344
|
+
const doctorOutput = run(["doctor"], repoRoot);
|
|
345
|
+
assert(doctorOutput.includes("维护者提示"), "doctor should warn when run in the package source checkout");
|
|
346
|
+
assert(doctorOutput.includes("node bin/agent-execution-template.js <command>"), "source checkout notice should show local node command");
|
|
347
|
+
assert(doctorOutput.includes("不要把维护者本地初始化产生的 ai/project/** 当成产品改动提交"), "source checkout notice should warn against committing local bootstrap context");
|
|
348
|
+
|
|
349
|
+
const nextOutput = run(["next"], repoRoot);
|
|
350
|
+
assert(nextOutput.includes("维护者提示"), "next should warn when run in the package source checkout");
|
|
351
|
+
}
|
|
352
|
+
|
|
341
353
|
function main() {
|
|
342
354
|
testInitUpdateDoctor();
|
|
343
355
|
testEnglishInitUpdateDoctor();
|
|
@@ -345,6 +357,7 @@ function main() {
|
|
|
345
357
|
testRefreshBacksUpAndImportsOldProject();
|
|
346
358
|
testNextCommandRoutesByProjectState();
|
|
347
359
|
testPermissionErrorIsActionable();
|
|
360
|
+
testSourceCheckoutNotice();
|
|
348
361
|
console.log("selftest ok");
|
|
349
362
|
}
|
|
350
363
|
|