@brawnen/agent-harness-cli 0.1.0 → 0.1.2
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 +59 -7
- package/README.zh-CN.md +16 -4
- package/package.json +12 -4
- package/src/commands/docs.js +19 -13
- package/src/commands/gate.js +1 -1
- package/src/commands/hook.js +43 -0
- package/src/commands/init.js +83 -8
- package/src/commands/report.js +4 -4
- package/src/commands/state.js +10 -2
- package/src/commands/status.js +169 -11
- package/src/commands/sync.js +88 -0
- package/src/index.js +15 -3
- package/src/lib/claude-hooks.js +49 -0
- package/src/lib/codex-hooks.js +48 -0
- package/src/lib/gemini-hooks.js +76 -0
- package/src/lib/hook-core.js +639 -0
- package/src/lib/hook-io/claude.js +23 -0
- package/src/lib/hook-io/codex.js +23 -0
- package/src/lib/hook-io/gemini.js +130 -0
- package/src/lib/hook-io/shared.js +52 -0
- package/src/lib/host-layout.js +1384 -0
- package/src/lib/output-policy.js +6 -6
- package/src/lib/runtime-paths.js +39 -0
- package/src/lib/task-core.js +104 -20
- package/src/runtime-host/index.js +57 -0
package/README.md
CHANGED
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
[中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
`@brawnen/agent-harness-cli` is the
|
|
5
|
+
`@brawnen/agent-harness-cli` is the compatibility CLI for `agent-harness`.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Its focus is no longer to be the long-term product center. It is the compatibility layer for:
|
|
8
8
|
|
|
9
9
|
- initialization
|
|
10
|
+
- host/runtime bootstrap
|
|
11
|
+
- status inspection
|
|
12
|
+
- manual fallback commands
|
|
10
13
|
- task state
|
|
11
14
|
- verification
|
|
12
15
|
- reports
|
|
@@ -15,6 +18,10 @@ It is the runtime layer that turns protocol rules into a working task loop with:
|
|
|
15
18
|
- delivery
|
|
16
19
|
- documentation scaffolding
|
|
17
20
|
|
|
21
|
+
The repo-local host runtime is becoming the primary execution surface. The CLI remains for initialization, diagnostics, and explicit manual operations.
|
|
22
|
+
|
|
23
|
+
This package is now in maintenance mode. It remains publishable and usable, but it is no longer intended to grow into the long-term product center.
|
|
24
|
+
|
|
18
25
|
## Current Coverage
|
|
19
26
|
|
|
20
27
|
The CLI currently includes these commands:
|
|
@@ -37,10 +44,12 @@ The current implementation also covers:
|
|
|
37
44
|
- host rule injection
|
|
38
45
|
- base project config generation
|
|
39
46
|
- minimal `.codex/hooks.json` integration
|
|
47
|
+
- `.claude/settings.json` hook integration
|
|
48
|
+
- `.gemini/settings.json` hook integration
|
|
40
49
|
|
|
41
50
|
## Current Boundaries
|
|
42
51
|
|
|
43
|
-
The CLI is already usable, but it
|
|
52
|
+
The CLI is already usable, but it should now be treated as a bounded compatibility layer rather than an expanding surface.
|
|
44
53
|
|
|
45
54
|
It currently does not try to provide:
|
|
46
55
|
|
|
@@ -49,6 +58,12 @@ It currently does not try to provide:
|
|
|
49
58
|
- automatic `git push`
|
|
50
59
|
- a deep upgrader / migration system
|
|
51
60
|
|
|
61
|
+
Maintenance-mode interpretation:
|
|
62
|
+
|
|
63
|
+
- keep it usable for bootstrap, diagnostics, and manual fallback
|
|
64
|
+
- accept bug fixes, compatibility fixes, and documentation clarification
|
|
65
|
+
- do not keep expanding host-specific wrapper behavior
|
|
66
|
+
|
|
52
67
|
## What The CLI Does Today
|
|
53
68
|
|
|
54
69
|
### `init`
|
|
@@ -144,7 +159,7 @@ Current responsibilities:
|
|
|
144
159
|
- `docs scaffold --type design-note|adr`
|
|
145
160
|
- generate minimal Markdown skeletons from task context
|
|
146
161
|
|
|
147
|
-
##
|
|
162
|
+
## Host Support
|
|
148
163
|
|
|
149
164
|
The current repository has the most complete host integration for `Codex`.
|
|
150
165
|
|
|
@@ -152,16 +167,44 @@ Current Codex coverage includes:
|
|
|
152
167
|
|
|
153
168
|
- `SessionStart`
|
|
154
169
|
- `UserPromptSubmit`
|
|
170
|
+
|
|
171
|
+
Currently disabled by default:
|
|
172
|
+
|
|
155
173
|
- `PreToolUse`
|
|
156
174
|
- `PostToolUse`
|
|
157
175
|
|
|
158
176
|
Highlights:
|
|
159
177
|
|
|
160
178
|
- automatic intake / continue / clarify
|
|
161
|
-
- pre-tool gating
|
|
162
|
-
- automatic evidence capture
|
|
163
179
|
- active task restore
|
|
164
180
|
|
|
181
|
+
Current Codex boundary:
|
|
182
|
+
|
|
183
|
+
- tool-level hooks remain implemented but are not enabled by default because of host visibility noise
|
|
184
|
+
|
|
185
|
+
Current Gemini CLI coverage includes:
|
|
186
|
+
|
|
187
|
+
- `SessionStart`
|
|
188
|
+
- `BeforeAgent`
|
|
189
|
+
- `BeforeTool`
|
|
190
|
+
- `AfterTool`
|
|
191
|
+
- `AfterAgent`
|
|
192
|
+
|
|
193
|
+
Highlights:
|
|
194
|
+
|
|
195
|
+
- automatic intake / continue / clarify
|
|
196
|
+
- before-tool gating for supported Gemini tools
|
|
197
|
+
- shell evidence capture through `AfterTool`
|
|
198
|
+
- completion gating through `AfterAgent`
|
|
199
|
+
|
|
200
|
+
Current Claude Code coverage includes:
|
|
201
|
+
|
|
202
|
+
- `SessionStart`
|
|
203
|
+
- `UserPromptSubmit`
|
|
204
|
+
- `PreToolUse`
|
|
205
|
+
- `PostToolUse`
|
|
206
|
+
- `Stop`
|
|
207
|
+
|
|
165
208
|
### Current `PreToolUse` Coverage For `Bash`
|
|
166
209
|
|
|
167
210
|
`Bash` currently supports high-confidence path inference for common write commands such as:
|
|
@@ -196,6 +239,8 @@ Useful local checks:
|
|
|
196
239
|
```bash
|
|
197
240
|
npm --prefix packages/cli run verify:task-core
|
|
198
241
|
npm --prefix packages/cli run verify:codex-e2e
|
|
242
|
+
npm --prefix packages/cli run verify:host-hooks
|
|
243
|
+
npm --prefix packages/cli run verify:init-status
|
|
199
244
|
```
|
|
200
245
|
|
|
201
246
|
From the repository root:
|
|
@@ -203,8 +248,14 @@ From the repository root:
|
|
|
203
248
|
```bash
|
|
204
249
|
npm run codex:hooks:check
|
|
205
250
|
npm run codex:e2e
|
|
251
|
+
npm run runtime:host-hooks
|
|
252
|
+
npm run runtime:init-status
|
|
253
|
+
npm run runtime:p1:check
|
|
254
|
+
node packages/cli/bin/agent-harness.js sync --check
|
|
206
255
|
```
|
|
207
256
|
|
|
257
|
+
`codex:hooks:check` validates the source-of-truth hook files under `.harness/hosts/codex/hooks/`, not the generated root `.codex/` shell.
|
|
258
|
+
|
|
208
259
|
## Local Invocation Note
|
|
209
260
|
|
|
210
261
|
If your current working directory is not the repository root, prefer calling the CLI with an absolute path, for example:
|
|
@@ -221,4 +272,5 @@ Do not assume `node packages/cli/bin/agent-harness.js ...` will work from an arb
|
|
|
221
272
|
- installing `@brawnen/agent-harness-cli` from npm should automatically pull `@brawnen/agent-harness-protocol`
|
|
222
273
|
- the protocol must not depend on the CLI
|
|
223
274
|
- the default npm entrypoint is `npx @brawnen/agent-harness-cli init`
|
|
224
|
-
- this repository
|
|
275
|
+
- this repository now treats the Node.js CLI as the compatibility layer of `Agent Harness Runtime`
|
|
276
|
+
- repo-local hooks should now consume the stable runtime entry `@brawnen/agent-harness-cli/runtime-host`
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md)
|
|
4
4
|
|
|
5
|
-
这是 `agent-harness`
|
|
5
|
+
这是 `agent-harness` 的兼容 CLI。
|
|
6
|
+
|
|
7
|
+
当前产品方向已经明确:宿主运行时逐步前移到 repo-local hooks,`CLI` 主要负责初始化、状态检查、人工 fallback 和显式交付动作。
|
|
8
|
+
这个包现在已经进入维护态:保持可用、可发布、可诊断,但不再继续向长期主产品方向扩张。
|
|
6
9
|
|
|
7
10
|
当前已完成:
|
|
8
11
|
|
|
@@ -22,9 +25,11 @@
|
|
|
22
25
|
- 基础项目配置生成
|
|
23
26
|
- `.codex/hooks.json` 最小方案
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
当前边界:
|
|
26
29
|
|
|
27
|
-
-
|
|
30
|
+
- 继续支持初始化、状态检查、验证、报告和人工 fallback
|
|
31
|
+
- 接受必要的 bug fix、兼容修复和文档澄清
|
|
32
|
+
- 不再继续扩大宿主专属 wrapper 行为
|
|
28
33
|
|
|
29
34
|
`init` MVP 当前负责:
|
|
30
35
|
|
|
@@ -218,7 +223,13 @@ node /abs/path/to/agent-harness/packages/cli/bin/agent-harness.js audit read --t
|
|
|
218
223
|
Codex E2E 回归:
|
|
219
224
|
|
|
220
225
|
- 可执行 `npm --prefix packages/cli run verify:codex-e2e`
|
|
226
|
+
- 可执行 `npm --prefix packages/cli run verify:host-hooks`
|
|
227
|
+
- 可执行 `npm --prefix packages/cli run verify:init-status`
|
|
228
|
+
- 可执行 `npm --prefix packages/cli run verify:status-compat`
|
|
221
229
|
- 或在仓库根目录执行 `npm run codex:e2e`
|
|
230
|
+
- 或在仓库根目录执行 `npm run runtime:host-hooks`
|
|
231
|
+
- 或在仓库根目录执行 `npm run runtime:init-status`
|
|
232
|
+
- 或在仓库根目录执行 `npm run runtime:p1:check`
|
|
222
233
|
- 当前最小回归覆盖:新任务自动 intake、follow-up 不误切、高风险确认链路、hook 降级提示
|
|
223
234
|
- 当前回归采用“真实 `codex exec` smoke + hook 主链路回归”混合方式,优先验证我们自己的接入链路
|
|
224
235
|
- 当前脚本会在**当前 trusted 仓库**里执行真实 Codex 回归,并清理自己创建的 task/audit/report 文件
|
|
@@ -229,4 +240,5 @@ Codex E2E 回归:
|
|
|
229
240
|
- CLI 依赖 `@brawnen/agent-harness-protocol`
|
|
230
241
|
- 从 npm 安装 `@brawnen/agent-harness-cli` 时,应自动带上 `@brawnen/agent-harness-protocol`
|
|
231
242
|
- 默认 npm 入口是 `npx @brawnen/agent-harness-cli init`
|
|
232
|
-
-
|
|
243
|
+
- 当前仓库将 Node.js CLI 视为 `Agent Harness Runtime` 的 compatibility layer
|
|
244
|
+
- repo-local hooks 当前应通过 `@brawnen/agent-harness-cli/runtime-host` 这一稳定入口接入 runtime
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brawnen/agent-harness-cli",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "CLI for
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Compatibility CLI for bootstrap, status, and manual fallback in agent-harness projects.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
7
7
|
"agent-harness": "./bin/agent-harness.js"
|
|
8
8
|
},
|
|
9
|
+
"exports": {
|
|
10
|
+
"./runtime-host": "./src/runtime-host/index.js"
|
|
11
|
+
},
|
|
9
12
|
"type": "module",
|
|
10
13
|
"files": [
|
|
11
14
|
"bin",
|
|
@@ -35,10 +38,15 @@
|
|
|
35
38
|
"access": "public"
|
|
36
39
|
},
|
|
37
40
|
"dependencies": {
|
|
38
|
-
"@brawnen/agent-harness-protocol": "^0.1.
|
|
41
|
+
"@brawnen/agent-harness-protocol": "^0.1.2"
|
|
39
42
|
},
|
|
40
43
|
"scripts": {
|
|
41
|
-
"start": "node ./bin/agent-harness.js --help"
|
|
44
|
+
"start": "node ./bin/agent-harness.js --help",
|
|
45
|
+
"verify:codex-e2e": "node ./scripts/verify-codex-e2e.js",
|
|
46
|
+
"verify:host-hooks": "node ./scripts/verify-host-hooks-smoke.js",
|
|
47
|
+
"verify:init-status": "node ./scripts/verify-host-init-status.js",
|
|
48
|
+
"verify:status-compat": "node ./scripts/verify-sync-status-compat.js",
|
|
49
|
+
"verify:task-core": "node ./scripts/verify-task-core-classification.js"
|
|
42
50
|
},
|
|
43
51
|
"engines": {
|
|
44
52
|
"node": ">=18"
|
package/src/commands/docs.js
CHANGED
|
@@ -154,31 +154,33 @@ function buildDesignNoteTemplate(title, context) {
|
|
|
154
154
|
return [
|
|
155
155
|
`# ${title}`,
|
|
156
156
|
"",
|
|
157
|
-
"##
|
|
157
|
+
"## 决策摘要",
|
|
158
158
|
"",
|
|
159
159
|
`- task_id: \`${context.task_id}\``,
|
|
160
160
|
`- intent: \`${context.intent}\``,
|
|
161
161
|
`- risk_level: \`${context.risk_level}\``,
|
|
162
|
+
context.goal ? `- goal: ${context.goal}` : "- goal: 待补充",
|
|
162
163
|
"",
|
|
163
|
-
"##
|
|
164
|
+
"## 要解决的问题",
|
|
164
165
|
"",
|
|
165
|
-
|
|
166
|
+
"- 问题:待补充",
|
|
166
167
|
"",
|
|
167
|
-
"##
|
|
168
|
+
"## 采用方案",
|
|
168
169
|
"",
|
|
169
|
-
|
|
170
|
+
"- 方案:待补充",
|
|
170
171
|
"",
|
|
171
|
-
"##
|
|
172
|
+
"## 为什么选这个方案",
|
|
172
173
|
"",
|
|
173
|
-
"-
|
|
174
|
+
"- 原因:待补充",
|
|
174
175
|
"",
|
|
175
|
-
"##
|
|
176
|
+
"## 边界与风险",
|
|
176
177
|
"",
|
|
177
|
-
|
|
178
|
+
...toBulletLines(context.scope),
|
|
179
|
+
"- 风险与权衡:待补充",
|
|
178
180
|
"",
|
|
179
|
-
"##
|
|
181
|
+
"## 验证",
|
|
180
182
|
"",
|
|
181
|
-
"-
|
|
183
|
+
"- 验证方式:待补充",
|
|
182
184
|
""
|
|
183
185
|
].join("\n");
|
|
184
186
|
}
|
|
@@ -200,9 +202,13 @@ function buildAdrTemplate(title, context) {
|
|
|
200
202
|
"",
|
|
201
203
|
"## 决策",
|
|
202
204
|
"",
|
|
203
|
-
"-
|
|
205
|
+
"- 决策内容:待补充",
|
|
206
|
+
"",
|
|
207
|
+
"## 备选方案",
|
|
208
|
+
"",
|
|
209
|
+
"- 备选方案及放弃原因:待补充",
|
|
204
210
|
"",
|
|
205
|
-
"##
|
|
211
|
+
"## 代价与后果",
|
|
206
212
|
"",
|
|
207
213
|
"- 正面影响:待补充",
|
|
208
214
|
"- 代价与风险:待补充",
|
package/src/commands/gate.js
CHANGED
|
@@ -67,7 +67,7 @@ function parseBeforeToolArgs(argv) {
|
|
|
67
67
|
return { ok: true, options };
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
function beforeTool(cwd, options) {
|
|
70
|
+
export function beforeTool(cwd, options) {
|
|
71
71
|
const taskId = options.taskId ?? resolveActiveTaskId(cwd);
|
|
72
72
|
const taskState = taskId ? getTaskState(cwd, taskId) : null;
|
|
73
73
|
const config = loadProjectConfig(cwd);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { runClaudeHook, readHookPayload } from "../lib/claude-hooks.js";
|
|
2
|
+
import { runCodexHook } from "../lib/codex-hooks.js";
|
|
3
|
+
import { runGeminiHook } from "../lib/gemini-hooks.js";
|
|
4
|
+
|
|
5
|
+
export function runHook(argv) {
|
|
6
|
+
const [host, event] = argv;
|
|
7
|
+
|
|
8
|
+
if (!host || !event) {
|
|
9
|
+
console.error("用法: hook <claude|codex|gemini> <event>");
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!["claude", "claude-code", "codex", "gemini", "gemini-cli"].includes(host)) {
|
|
14
|
+
console.error(`未知 hook 宿主: ${host}`);
|
|
15
|
+
return 1;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const payload = readHookPayload();
|
|
20
|
+
const result = runHostHook(host, event, payload);
|
|
21
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
22
|
+
return 0;
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error(error.message);
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function runHostHook(host, event, payload) {
|
|
30
|
+
if (host === "claude" || host === "claude-code") {
|
|
31
|
+
return runClaudeHook(event, payload);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (host === "codex") {
|
|
35
|
+
return runCodexHook(event, payload);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (host === "gemini" || host === "gemini-cli") {
|
|
39
|
+
return runGeminiHook(event, payload);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
throw new Error(`未知 hook 宿主: ${host}`);
|
|
43
|
+
}
|
package/src/commands/init.js
CHANGED
|
@@ -3,9 +3,10 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
|
|
6
|
+
import { collectHostLayoutWrites } from "../lib/host-layout.js";
|
|
6
7
|
import { DEFAULT_RUNTIME_DIR, defaultRuntimeRelativePath } from "../lib/runtime-paths.js";
|
|
7
8
|
|
|
8
|
-
const CLI_VERSION = "0.1.
|
|
9
|
+
const CLI_VERSION = "0.1.2";
|
|
9
10
|
const RULE_MODES = new Set(["base", "full"]);
|
|
10
11
|
const HOSTS = new Set(["auto", "claude-code", "codex", "gemini-cli"]);
|
|
11
12
|
const MODES = new Set(["delivery", "explore", "poc"]);
|
|
@@ -36,16 +37,19 @@ export function runInit(argv) {
|
|
|
36
37
|
const project = detectProject(cwd);
|
|
37
38
|
const hosts = resolveHosts(cwd, parsed.options.host);
|
|
38
39
|
const actions = [];
|
|
40
|
+
const warnings = [];
|
|
39
41
|
|
|
40
42
|
queueInitActions({
|
|
41
43
|
cwd,
|
|
42
44
|
project,
|
|
43
45
|
hosts,
|
|
44
46
|
options: parsed.options,
|
|
45
|
-
actions
|
|
47
|
+
actions,
|
|
48
|
+
warnings
|
|
46
49
|
});
|
|
47
50
|
|
|
48
51
|
printPlan(actions, parsed.options.dryRun, cwd, project, hosts);
|
|
52
|
+
printWarnings(warnings);
|
|
49
53
|
|
|
50
54
|
if (parsed.options.dryRun) {
|
|
51
55
|
return 0;
|
|
@@ -277,8 +281,7 @@ function resolveHosts(cwd, explicitHost) {
|
|
|
277
281
|
}
|
|
278
282
|
|
|
279
283
|
function queueInitActions(context) {
|
|
280
|
-
const { actions, cwd, hosts, options, project } = context;
|
|
281
|
-
const ruleText = readText(path.join(PROTOCOL_ROOT, "rules", `${options.rules}.md`));
|
|
284
|
+
const { actions, cwd, hosts, options, project, warnings } = context;
|
|
282
285
|
|
|
283
286
|
queueWriteAction({
|
|
284
287
|
actions,
|
|
@@ -288,13 +291,34 @@ function queueInitActions(context) {
|
|
|
288
291
|
});
|
|
289
292
|
|
|
290
293
|
queueProtocolTemplates(actions, cwd, options.force);
|
|
291
|
-
|
|
294
|
+
queueHostLayoutActions(actions, warnings, cwd, hosts, options);
|
|
292
295
|
|
|
293
296
|
if (!options.protocolOnly) {
|
|
294
297
|
queueRuntimeFiles(actions, cwd);
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function queueHostLayoutActions(actions, warnings, cwd, hosts, options) {
|
|
302
|
+
const layout = collectHostLayoutWrites(cwd, {
|
|
303
|
+
hosts,
|
|
304
|
+
includeConfigs: !options.protocolOnly,
|
|
305
|
+
includeRules: true,
|
|
306
|
+
rewrite: options.force,
|
|
307
|
+
seedMissing: true
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
warnings.push(...layout.warnings);
|
|
311
|
+
|
|
312
|
+
for (const write of layout.writes) {
|
|
313
|
+
actions.push({
|
|
314
|
+
description: describeHostLayoutWrite(write),
|
|
315
|
+
relativePath: path.relative(cwd, write.targetPath),
|
|
316
|
+
run: () => {
|
|
317
|
+
ensureDirectory(path.dirname(write.targetPath));
|
|
318
|
+
fs.writeFileSync(write.targetPath, write.content, "utf8");
|
|
319
|
+
},
|
|
320
|
+
skip: false
|
|
321
|
+
});
|
|
298
322
|
}
|
|
299
323
|
}
|
|
300
324
|
|
|
@@ -361,6 +385,25 @@ function queueClaudeSettingsMerge(actions, cwd) {
|
|
|
361
385
|
});
|
|
362
386
|
}
|
|
363
387
|
|
|
388
|
+
function queueGeminiSettingsMerge(actions, cwd) {
|
|
389
|
+
const targetPath = path.join(cwd, ".gemini", "settings.json");
|
|
390
|
+
const templatePath = path.join(PROTOCOL_ROOT, "adapters", "gemini-cli", "hooks.json");
|
|
391
|
+
const template = JSON.parse(readText(templatePath));
|
|
392
|
+
const existing = fs.existsSync(targetPath) ? readJson(targetPath) : {};
|
|
393
|
+
const merged = mergeClaudeSettings(existing, template);
|
|
394
|
+
const content = `${JSON.stringify(merged, null, 2)}\n`;
|
|
395
|
+
|
|
396
|
+
actions.push({
|
|
397
|
+
description: fs.existsSync(targetPath) ? "合并 Gemini CLI hooks" : "创建 Gemini CLI hooks 配置",
|
|
398
|
+
relativePath: path.relative(cwd, targetPath),
|
|
399
|
+
run: () => {
|
|
400
|
+
ensureDirectory(path.dirname(targetPath));
|
|
401
|
+
fs.writeFileSync(targetPath, content, "utf8");
|
|
402
|
+
},
|
|
403
|
+
skip: false
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
364
407
|
function queueRuntimeFiles(actions, cwd) {
|
|
365
408
|
const runtimeReadme = path.join(cwd, DEFAULT_RUNTIME_DIR, "README.md");
|
|
366
409
|
queueWriteAction({
|
|
@@ -666,6 +709,38 @@ function printPlan(actions, dryRun, cwd, project, hosts) {
|
|
|
666
709
|
}
|
|
667
710
|
}
|
|
668
711
|
|
|
712
|
+
function printWarnings(warnings) {
|
|
713
|
+
if (!Array.isArray(warnings) || warnings.length === 0) {
|
|
714
|
+
return;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
console.log("");
|
|
718
|
+
console.log("提示:");
|
|
719
|
+
for (const warning of warnings) {
|
|
720
|
+
console.log(` - ${warning}`);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function describeHostLayoutWrite(write) {
|
|
725
|
+
if (write.type === "source") {
|
|
726
|
+
return "写入收敛布局源文件";
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (write.type === "host") {
|
|
730
|
+
return "生成宿主薄壳配置";
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
if (write.type === "rule") {
|
|
734
|
+
return "生成宿主规则文件";
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
if (write.type === "generated") {
|
|
738
|
+
return "生成布局清单";
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
return "写入布局文件";
|
|
742
|
+
}
|
|
743
|
+
|
|
669
744
|
function readText(filePath) {
|
|
670
745
|
return fs.readFileSync(filePath, "utf8");
|
|
671
746
|
}
|
package/src/commands/report.js
CHANGED
|
@@ -256,15 +256,15 @@ function buildMissingArtifactsMessage(taskId, error, outputPolicy) {
|
|
|
256
256
|
|
|
257
257
|
if (artifact === "design_note") {
|
|
258
258
|
const suggestedPath = path.posix.join(outputPolicy.design_note.directory, `${taskId}-design-note.md`);
|
|
259
|
-
lines.push(`- design_note:
|
|
260
|
-
lines.push(`
|
|
259
|
+
lines.push(`- design_note: 当前任务命中 design note 条件。若尚未沉淀设计决策,可执行 \`node packages/cli/bin/agent-harness.js docs scaffold --type design-note --task-id ${taskId} --path ${suggestedPath}\``);
|
|
260
|
+
lines.push(` 完成后在 report 中补上 \`--design-note ${suggestedPath}\``);
|
|
261
261
|
continue;
|
|
262
262
|
}
|
|
263
263
|
|
|
264
264
|
if (artifact === "adr") {
|
|
265
265
|
const suggestedPath = path.posix.join(outputPolicy.adr.directory, `${taskId}-adr.md`);
|
|
266
|
-
lines.push(`- adr:
|
|
267
|
-
lines.push(`
|
|
266
|
+
lines.push(`- adr: 当前任务命中 ADR 条件。若尚未记录正式决策,可执行 \`node packages/cli/bin/agent-harness.js docs scaffold --type adr --task-id ${taskId} --path ${suggestedPath}\``);
|
|
267
|
+
lines.push(` 完成后在 report 中补上 \`--adr ${suggestedPath}\``);
|
|
268
268
|
}
|
|
269
269
|
}
|
|
270
270
|
|
package/src/commands/state.js
CHANGED
|
@@ -110,7 +110,9 @@ function runStateUpdate(argv) {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
const result = updateTaskState(process.cwd(), taskId, changes);
|
|
113
|
-
|
|
113
|
+
if (parsed.options.verbose) {
|
|
114
|
+
printJson(result);
|
|
115
|
+
}
|
|
114
116
|
return 0;
|
|
115
117
|
} catch (error) {
|
|
116
118
|
console.error(error.message);
|
|
@@ -208,7 +210,8 @@ function parseStateUpdateArgs(argv) {
|
|
|
208
210
|
phase: null,
|
|
209
211
|
state: null,
|
|
210
212
|
taskId: null,
|
|
211
|
-
tool: null
|
|
213
|
+
tool: null,
|
|
214
|
+
verbose: false
|
|
212
215
|
};
|
|
213
216
|
|
|
214
217
|
for (let index = 0; index < argv.length; index += 1) {
|
|
@@ -251,6 +254,11 @@ function parseStateUpdateArgs(argv) {
|
|
|
251
254
|
continue;
|
|
252
255
|
}
|
|
253
256
|
|
|
257
|
+
if (arg === "--verbose") {
|
|
258
|
+
options.verbose = true;
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
|
|
254
262
|
return { ok: false, error: `未知参数: ${arg}` };
|
|
255
263
|
}
|
|
256
264
|
|