@thincoder/core 0.9.4 → 0.10.1
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/CHANGELOG.md +63 -0
- package/README.md +1 -1
- package/abort-provenance.mjs +10 -10
- package/advisor/citations.mjs +5 -5
- package/advisor/compaction.mjs +16 -15
- package/advisor/loop.mjs +14 -14
- package/advisor/messages.mjs +6 -6
- package/advisor/project-context.mjs +5 -5
- package/advisor/repos.mjs +3 -3
- package/advisor/run.mjs +23 -13
- package/advisor.mjs +4 -4
- package/agent/assemble.mjs +111 -0
- package/agent/chat-call.mjs +68 -0
- package/agent/child-marks.mjs +2 -2
- package/agent/completion.mjs +9 -2
- package/agent/continue-decision.mjs +25 -0
- package/agent/dispatch-gates.mjs +140 -0
- package/agent/dispatch-run.mjs +167 -0
- package/agent/dispatch.mjs +55 -294
- package/agent/family-tools.mjs +11 -11
- package/agent/helpers.mjs +63 -3
- package/agent/live-beat.mjs +49 -0
- package/agent/post-turn.mjs +4 -8
- package/agent/record-results.mjs +23 -20
- package/agent/relay-prefix.mjs +2 -2
- package/agent/run-stages.mjs +19 -15
- package/agent/run-start.mjs +111 -0
- package/agent/setup-reminders.mjs +9 -9
- package/agent/setup.mjs +32 -4
- package/agent/spawn-child.mjs +9 -9
- package/agent/suspension.mjs +90 -30
- package/agent/timers.mjs +113 -0
- package/agent/turn-loop.mjs +244 -0
- package/agent/write-gate.mjs +103 -6
- package/agent-tools/advisor-async.mjs +11 -11
- package/agent-tools/advisor-settle.mjs +17 -17
- package/agent-tools/advisor.mjs +38 -43
- package/agent-tools/async-discard.mjs +44 -1
- package/agent-tools/async-settle.mjs +23 -20
- package/agent-tools/audit-block.mjs +7 -7
- package/agent-tools/bash-async.mjs +281 -0
- package/agent-tools/batch-lifecycle.mjs +65 -34
- package/agent-tools/batch-paths.mjs +186 -0
- package/agent-tools/batch-skeleton.mjs +19 -1
- package/agent-tools/batch.mjs +22 -119
- package/agent-tools/checkpoint.mjs +121 -0
- package/agent-tools/child-permission.mjs +5 -3
- package/agent-tools/consult.mjs +58 -58
- package/agent-tools/context.mjs +4 -20
- package/agent-tools/design-token.mjs +3 -3
- package/agent-tools/digest-budget.mjs +1 -1
- package/agent-tools/eng.mjs +5 -5
- package/agent-tools/escalate-async.mjs +18 -13
- package/agent-tools/goal.mjs +3 -10
- package/agent-tools/panel-blocks.mjs +3 -3
- package/agent-tools/parent-channel.mjs +3 -13
- package/agent-tools/plan.mjs +3 -4
- package/agent-tools/read-history.mjs +12 -28
- package/agent-tools/recent-changes.mjs +4 -5
- package/agent-tools/review-facts.mjs +1 -1
- package/agent-tools/settings.mjs +47 -20
- package/agent-tools/skill.mjs +3 -5
- package/agent-tools/spawn-gates.mjs +3 -3
- package/agent-tools/subagent-actions-query.mjs +270 -0
- package/agent-tools/subagent-actions.mjs +29 -273
- package/agent-tools/subagent-async.mjs +36 -31
- package/agent-tools/subagent-panel.mjs +38 -9
- package/agent-tools/subagent-run.mjs +44 -29
- package/agent-tools/subagent-scheduler.mjs +29 -28
- package/agent-tools/subagent-spawn.mjs +57 -25
- package/agent-tools/subagent.mjs +46 -66
- package/agent-tools/task.mjs +3 -9
- package/agent-tools/timer.mjs +12 -12
- package/agent-tools/verify.mjs +14 -13
- package/agent-tools.mjs +0 -1
- package/agent.mjs +20 -351
- package/attachments.mjs +125 -0
- package/auto-think.mjs +1 -1
- package/config-presets.mjs +12 -7
- package/config-watch.mjs +83 -0
- package/config.mjs +17 -4
- package/context-degrade.mjs +81 -0
- package/context-echo.mjs +88 -0
- package/context-push.mjs +51 -0
- package/context.mjs +8 -187
- package/conventions.mjs +110 -161
- package/declaration.mjs +194 -0
- package/embedding.mjs +3 -1
- package/env-ref.mjs +81 -0
- package/explore-distill.mjs +2 -3
- package/file-links.mjs +53 -0
- package/file-refs.mjs +103 -0
- package/generate-title.mjs +28 -4
- package/git/checkpoint.mjs +4 -8
- package/history-window.mjs +17 -2
- package/i18n.mjs +2 -0
- package/index-discover.mjs +7 -7
- package/ledger-cmd.mjs +34 -126
- package/ledger-db.mjs +35 -7
- package/ledger-migrate.mjs +299 -0
- package/ledger-tools.mjs +188 -0
- package/ledger.mjs +11 -5
- package/log.mjs +12 -7
- package/manifest-discovery.mjs +131 -0
- package/manifest-schema.mjs +166 -0
- package/manifest.mjs +18 -217
- package/mcp.mjs +4 -1
- package/memory/code-search.mjs +149 -0
- package/memory/code-sync.mjs +89 -230
- package/memory/core.mjs +47 -32
- package/memory/docs.mjs +63 -262
- package/memory/file-list.mjs +89 -0
- package/memory/file-walk.mjs +7 -4
- package/memory/memory-tool.mjs +229 -0
- package/memory/schema.mjs +18 -3
- package/memory/sweep.mjs +289 -0
- package/memory/sync-tail.mjs +81 -0
- package/memory-status.mjs +69 -0
- package/memory.mjs +3 -0
- package/model-specs.mjs +131 -66
- package/notify-policy.mjs +51 -0
- package/package.json +1 -1
- package/peer-claims.mjs +263 -0
- package/peer-domains.mjs +100 -71
- package/peer-instances.mjs +9 -10
- package/process-probe-exec.mjs +187 -0
- package/process-probe.mjs +27 -175
- package/prompt-overlays.mjs +11 -10
- package/prompts/advisor-design.md +2 -2
- package/prompts/advisor-round2.md +1 -1
- package/prompts/advisor-round3.md +1 -1
- package/prompts/common.md +19 -7
- package/prompts/discipline-engineering.md +57 -16
- package/prompts/discipline-normal.md +6 -3
- package/prompts/persona-coder.md +0 -1
- package/prompts/persona-eng-coder.md +1 -5
- package/prompts/persona-eng-designer.md +1 -2
- package/prompts/persona-engineering.md +41 -11
- package/prompts/persona-explore.md +0 -1
- package/prompts/persona-normal.md +10 -1
- package/prompts/persona-plan.md +3 -4
- package/prompts/subagent-base.md +14 -0
- package/provider/core.mjs +11 -48
- package/provider/list-models.mjs +3 -0
- package/provider/responses-request.mjs +237 -0
- package/provider/responses.mjs +6 -228
- package/provider-flows.mjs +248 -0
- package/queued.mjs +90 -0
- package/rules.mjs +209 -2
- package/session-gc.mjs +67 -6
- package/session-guard.mjs +27 -7
- package/session-lifecycle.mjs +90 -18
- package/session-rename.mjs +5 -1
- package/session-slot-claims.mjs +230 -0
- package/session-slot-scan.mjs +299 -0
- package/session-slot-verify.mjs +304 -0
- package/session-slot-write.mjs +74 -8
- package/session-slots-manifest.mjs +163 -236
- package/session-slots.mjs +99 -71
- package/session.mjs +30 -10
- package/shell-candidates.mjs +78 -0
- package/text-budget.mjs +2 -2
- package/think-off.mjs +49 -0
- package/token-ttl.mjs +15 -4
- package/tool-args.mjs +73 -0
- package/tool-docs/advisor.md +9 -0
- package/tool-docs/batch.md +1 -0
- package/tool-docs/code_search.md +1 -0
- package/tool-docs/consult_start.md +5 -0
- package/tool-docs/consult_stop.md +3 -0
- package/tool-docs/context.md +7 -0
- package/tool-docs/doc_search.md +1 -0
- package/tool-docs/edit.md +2 -13
- package/tool-docs/eng.md +1 -0
- package/tool-docs/execute.md +1 -9
- package/tool-docs/git.md +25 -51
- package/tool-docs/goal.md +6 -0
- package/tool-docs/ledger_add.md +1 -0
- package/tool-docs/ledger_close.md +1 -0
- package/tool-docs/ledger_count.md +1 -0
- package/tool-docs/ledger_query.md +1 -0
- package/tool-docs/ledger_update.md +1 -0
- package/tool-docs/main_history.md +1 -0
- package/tool-docs/memory.md +10 -0
- package/tool-docs/notify_parent.md +9 -0
- package/tool-docs/peer_instances.md +1 -0
- package/tool-docs/plan.md +5 -0
- package/tool-docs/process.md +7 -3
- package/tool-docs/question.md +1 -0
- package/tool-docs/read_history.md +7 -0
- package/tool-docs/recent_changes.md +1 -0
- package/tool-docs/repo_outline.md +1 -0
- package/tool-docs/settings.md +6 -0
- package/tool-docs/skill.md +5 -0
- package/tool-docs/subagent.md +31 -0
- package/tool-docs/task.md +7 -0
- package/tool-docs/timer.md +6 -0
- package/tool-docs/verify.md +1 -0
- package/tool-docs/wait_for.md +2 -1
- package/tools/bash.mjs +28 -4
- package/tools/edit-batch.mjs +10 -11
- package/tools/edit-diff.mjs +33 -25
- package/tools/exec-run.mjs +102 -4
- package/tools/execute.mjs +5 -2
- package/tools/file.mjs +11 -12
- package/tools/git-run.mjs +1 -1
- package/tools/git.mjs +0 -24
- package/tools/glob-dialect.mjs +3 -3
- package/tools/index.mjs +2 -1
- package/tools/linter.mjs +2 -1
- package/tools/node-child.mjs +21 -0
- package/tools/ops.mjs +50 -13
- package/tools/patch.mjs +4 -2
- package/tools/repomap.mjs +20 -9
- package/tools/search.mjs +2 -2
- package/tools/shared.mjs +9 -7
- package/tools/web.mjs +5 -2
- package/tools/write-path.mjs +1 -1
- package/traces/trace-store.mjs +17 -14
- package/vision-reader.mjs +76 -0
- package/agent-tools/batch-segment.mjs +0 -18
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* process-probe-exec.mjs — 探测执行面(#590① 自 `process-probe.mjs` 外提——CORE-UNIFICATION
|
|
3
|
+
* 行 10 预案兑现;语义逐字零变)。
|
|
4
|
+
*
|
|
5
|
+
* 归本档:双超时常量(`ALIVE_EXEC_TIMEOUT_MS` / `CMDLINE_EXEC_TIMEOUT_MS`)· 模块级测试注入缝
|
|
6
|
+
* (`_testImpl` + 两 setter——唯一读取点 = 本档四批量函数,同档免回引 / 免环)· `uniqPids` ·
|
|
7
|
+
* 输出解析族 · `execFileP` · 四批量探测函数(`batchAlive` / `batchAliveAsync` / `probeCmdlines` /
|
|
8
|
+
* `probeCmdlinesAsync`)。
|
|
9
|
+
* 留 `process-probe.mjs`:身份判据 · 三态判据 · 束 API · 单 pid 兼容面 · 清理面适配——该档对
|
|
10
|
+
* 四批量名与缝名 **import + re-export**(导入面逐字零改;`isProcessAlive` 经 import 取用本档
|
|
11
|
+
* `parseTasklistPids`,并自持 `execFileSync` import——win32 分支直调,不设转口)。
|
|
12
|
+
*
|
|
13
|
+
* 成本纪律与两形态语义(同步 / 异步共用同一解析族与同一注入缝)= `process-probe.mjs` 头注
|
|
14
|
+
* (单源——本档不重述)。
|
|
15
|
+
*/
|
|
16
|
+
import { execFile, execFileSync } from "node:child_process"
|
|
17
|
+
|
|
18
|
+
const ALIVE_EXEC_TIMEOUT_MS = 10_000
|
|
19
|
+
const CMDLINE_EXEC_TIMEOUT_MS = 15_000
|
|
20
|
+
|
|
21
|
+
// 模块级测试注入缝(default null = 生产实现;测试注入 + finally 恢复——见测试文件)
|
|
22
|
+
let _testImpl = null
|
|
23
|
+
|
|
24
|
+
/** 注入测试实现。aliveFn(pids) → Set<pid>|null;cmdlineFn(pids) → Map<pid,cmdline>|null
|
|
25
|
+
* (两缝均**批量**语义——一次调用拿全量)。返回前值便于测试保存恢复;**未传的槽置 null**(传 `{}` = 两槽同清,等价 reset)。 */
|
|
26
|
+
export function _setProcessProbeTestImpl({ aliveFn = undefined, cmdlineFn = undefined } = {}) {
|
|
27
|
+
const prev = _testImpl
|
|
28
|
+
_testImpl = { aliveFn: aliveFn ?? null, cmdlineFn: cmdlineFn ?? null }
|
|
29
|
+
return prev
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function _resetProcessProbeTestImpl() {
|
|
33
|
+
_testImpl = null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** pid 清单归一:去重 + 正整数(两探测共用——空清单调用面零 exec)。 */
|
|
37
|
+
export function uniqPids(pids) {
|
|
38
|
+
return [...new Set(pids.map(Number).filter((n) => Number.isInteger(n) && n > 0))]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ── 输出解析族(同步 / 异步两形态**共用**——单源,防两形态漂移) ─────────────────
|
|
42
|
+
/** Windows tasklist CSV(`"name","pid"…`)→ 全量 PID 集合。 */
|
|
43
|
+
export function parseTasklistPids(out) {
|
|
44
|
+
const alive = new Set()
|
|
45
|
+
for (const line of out.split(/\r?\n/)) {
|
|
46
|
+
const m = line.match(/^"([^"]*)","(\d+)"/)
|
|
47
|
+
if (m) alive.add(Number(m[2]))
|
|
48
|
+
}
|
|
49
|
+
return alive
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Unix `ps -eo pid=` → 全量 PID 集合。 */
|
|
53
|
+
function parsePsPids(out) {
|
|
54
|
+
return new Set(out.split(/\r?\n/).map((l) => Number(l.trim())).filter((n) => Number.isInteger(n)))
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Windows `Get-CimInstance … ConvertTo-Json` → `Map<pid, cmdline>`。 */
|
|
58
|
+
function parseCimCmdlines(out) {
|
|
59
|
+
const rows = JSON.parse(out.trim())
|
|
60
|
+
const map = new Map()
|
|
61
|
+
for (const r of Array.isArray(rows) ? rows : [rows]) {
|
|
62
|
+
if (r && Number.isInteger(r.ProcessId) && typeof r.CommandLine === "string") {
|
|
63
|
+
map.set(Number(r.ProcessId), r.CommandLine)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return map
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Unix `ps -eo pid=,args=` → `Map<pid, cmdline>`。 */
|
|
70
|
+
function parsePsArgs(out) {
|
|
71
|
+
const map = new Map()
|
|
72
|
+
for (const line of out.split(/\r?\n/)) {
|
|
73
|
+
const m = line.match(/^\s*(\d+)\s+(.*)$/)
|
|
74
|
+
if (m) map.set(Number(m[1]), m[2])
|
|
75
|
+
}
|
|
76
|
+
return map
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** execFile → Promise<string>(stdout;exec / 超时失败 ⇒ reject——调用面按「探测失败」降级)。 */
|
|
80
|
+
function execFileP(cmd, args, timeout) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
execFile(cmd, args, { encoding: "utf8", timeout, windowsHide: true }, (err, stdout) => {
|
|
83
|
+
if (err) reject(err); else resolve(stdout)
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 批量判活:单次 tasklist(Windows 全量 CSV)/ ps(Unix)拿全量 PID 集合 → 一次 exec
|
|
90
|
+
* 比对(修复 isProcessAlive 每 pid 一次 execSync 的成本——每回合 N 次 = 贵,探索 §4)。
|
|
91
|
+
* 返回存活 pid 的 Set;exec/解析失败 → null(调用方区分"探测失败"与"全死"——只读面按
|
|
92
|
+
* 无活伴降级;域面(peer-domains 死清理)在 null 时不得执行删除——探测失败 ≠ 死)。
|
|
93
|
+
* **纯存在性**:身份判据不在此层(D-MI11——过滤落点在读面 `peerInstances()` 与清理面
|
|
94
|
+
* `filterDeadOwners`;`peer-domains.mjs` 的域残留清理语义保持零变)。
|
|
95
|
+
*/
|
|
96
|
+
export function batchAlive(pids, { timeoutMs = ALIVE_EXEC_TIMEOUT_MS } = {}) {
|
|
97
|
+
const uniq = uniqPids(pids)
|
|
98
|
+
if (uniq.length === 0) return new Set()
|
|
99
|
+
if (_testImpl?.aliveFn) return _testImpl.aliveFn(uniq)
|
|
100
|
+
try {
|
|
101
|
+
if (process.platform === "win32") {
|
|
102
|
+
const output = execFileSync("tasklist", ["/FO", "CSV", "/NH"], {
|
|
103
|
+
encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"],
|
|
104
|
+
})
|
|
105
|
+
const alive = parseTasklistPids(output)
|
|
106
|
+
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
107
|
+
}
|
|
108
|
+
const output = execFileSync("ps", ["-eo", "pid="], {
|
|
109
|
+
encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"],
|
|
110
|
+
})
|
|
111
|
+
const alive = parsePsPids(output)
|
|
112
|
+
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
113
|
+
} catch {
|
|
114
|
+
return null // 探测失败(区别于全死)——调用方不得据此执行删除/判死副作用
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* 异步对偶(TUI 假死批 · MULTI-INSTANCE-COLLAB §3.1):与 `batchAlive` 同语义(返回集 / null
|
|
120
|
+
* 降级一致),但 `execFile` + Promise 化——**读面**(每回合的 `peerInstances`)不得用同步 exec
|
|
121
|
+
* 占住事件循环。**同一注入缝** `_setProcessProbeTestImpl`(注入值可能是同步函数——经 await
|
|
122
|
+
* 消费);**清理面继续用同步版**(会话起点 / 认领路径,非每回合面——D-MI14 登记)。
|
|
123
|
+
*/
|
|
124
|
+
export async function batchAliveAsync(pids) {
|
|
125
|
+
const uniq = uniqPids(pids)
|
|
126
|
+
if (uniq.length === 0) return new Set()
|
|
127
|
+
if (_testImpl?.aliveFn) return _testImpl.aliveFn(uniq)
|
|
128
|
+
try {
|
|
129
|
+
if (process.platform === "win32") {
|
|
130
|
+
const alive = parseTasklistPids(await execFileP("tasklist", ["/FO", "CSV", "/NH"], ALIVE_EXEC_TIMEOUT_MS))
|
|
131
|
+
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
132
|
+
}
|
|
133
|
+
const alive = parsePsPids(await execFileP("ps", ["-eo", "pid="], ALIVE_EXEC_TIMEOUT_MS))
|
|
134
|
+
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
135
|
+
} catch {
|
|
136
|
+
return null // 探测失败(区别于全死)——只读面按「无活伴」降级
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* 批量 cmdline 探测(决策③ A——一次 exec 拿全部 pid+cmdline):返回 Map<pid, cmdline>
|
|
142
|
+
* 或 null(exec 失败/解析失败)。Windows = 一次 Get-CimInstance(PowerShell);Unix =
|
|
143
|
+
* 一次 ps。仅在 manifest mtime 变化后跑一次(~百 ms 级——设计已接受);清理面同一批量
|
|
144
|
+
* 结果逐条消费(D-MI3 / N-MI3——不做每 pid 一次 exec)。
|
|
145
|
+
*/
|
|
146
|
+
export function probeCmdlines(pids, { timeoutMs = CMDLINE_EXEC_TIMEOUT_MS } = {}) {
|
|
147
|
+
const uniq = uniqPids(pids)
|
|
148
|
+
if (uniq.length === 0) return new Map()
|
|
149
|
+
if (_testImpl?.cmdlineFn) return _testImpl.cmdlineFn(uniq)
|
|
150
|
+
try {
|
|
151
|
+
let out
|
|
152
|
+
if (process.platform === "win32") {
|
|
153
|
+
// 一次 Get-CimInstance 拿全表 → node 侧过滤目标 pid(避免 shell 引号注入面)
|
|
154
|
+
out = execFileSync("powershell.exe",
|
|
155
|
+
["-NoProfile", "-NonInteractive", "-Command",
|
|
156
|
+
"Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"],
|
|
157
|
+
{ encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"] })
|
|
158
|
+
return parseCimCmdlines(out)
|
|
159
|
+
}
|
|
160
|
+
out = execFileSync("ps", ["-eo", "pid=,args="], {
|
|
161
|
+
encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"],
|
|
162
|
+
})
|
|
163
|
+
return parsePsArgs(out)
|
|
164
|
+
} catch {
|
|
165
|
+
return null // 探测失败 → 端字段/身份缺省(调用方降级:保守保留)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** 异步对偶(同 `probeCmdlines` 语义——`execFile` + Promise;同一注入缝;读面在用)。 */
|
|
170
|
+
export async function probeCmdlinesAsync(pids) {
|
|
171
|
+
const uniq = uniqPids(pids)
|
|
172
|
+
if (uniq.length === 0) return new Map()
|
|
173
|
+
if (_testImpl?.cmdlineFn) return _testImpl.cmdlineFn(uniq)
|
|
174
|
+
try {
|
|
175
|
+
if (process.platform === "win32") {
|
|
176
|
+
const out = await execFileP("powershell.exe",
|
|
177
|
+
["-NoProfile", "-NonInteractive", "-Command",
|
|
178
|
+
"Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"],
|
|
179
|
+
CMDLINE_EXEC_TIMEOUT_MS)
|
|
180
|
+
return parseCimCmdlines(out)
|
|
181
|
+
}
|
|
182
|
+
const out = await execFileP("ps", ["-eo", "pid=,args="], CMDLINE_EXEC_TIMEOUT_MS)
|
|
183
|
+
return parsePsArgs(out)
|
|
184
|
+
} catch {
|
|
185
|
+
return null // 探测失败 → 端字段/身份缺省(调用方降级:保守保留)
|
|
186
|
+
}
|
|
187
|
+
}
|
package/process-probe.mjs
CHANGED
|
@@ -20,11 +20,17 @@
|
|
|
20
20
|
* 2 s + 三态)。`filterDeadOwners` = `ownerState` 薄适配(`alive` 三态,缺省 = 未知)。
|
|
21
21
|
* 方向不对称(D-MI10):探测失败(null)/ 该 pid 缺行 ⇒ **保守保留/不删**——误保留 = 噪音,
|
|
22
22
|
* 误删活实例 = 破坏存储隔离(双进程同槽),两者代价不同级。
|
|
23
|
+
*
|
|
24
|
+
* 执行面拆分(#590① · CORE-UNIFICATION 行 10 兑现):注入缝 + 解析族 + 四批量探测函数
|
|
25
|
+
* (`batchAlive` / `batchAliveAsync` / `probeCmdlines` / `probeCmdlinesAsync`)+ `uniqPids`
|
|
26
|
+
* 住拆分件 `process-probe-exec.mjs`(迁移账 = 该档头注);本档 import 自用 + re-export
|
|
27
|
+
* 保导入面逐字零改(VSC `session-io.mjs` 与核七消费档不动)。
|
|
23
28
|
*/
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
import { execFileSync } from "node:child_process"
|
|
30
|
+
import {
|
|
31
|
+
batchAlive, batchAliveAsync, probeCmdlines, probeCmdlinesAsync,
|
|
32
|
+
uniqPids, parseTasklistPids,
|
|
33
|
+
} from "./process-probe-exec.mjs"
|
|
28
34
|
|
|
29
35
|
/** 同步束的**紧界**(F-MI7 · SESSION.md §6.2):同步探测阻塞事件循环 ⇒ 单次 exec ≤ 2 s;
|
|
30
36
|
* 超时 / 失败 ⇒ 未知(三态判据)⇒ 保守保留(D-MI10)。单源常量——调用面不得自行取值。 */
|
|
@@ -40,187 +46,30 @@ const VSC_END_RE = /--extensionDevelopmentPath|--type=extensionHost|extensionHos
|
|
|
40
46
|
* 「误删方向」——消解路径 = 实测出现时补进本族,单源改点仅此一处)。 */
|
|
41
47
|
const CLI_ENTRY_RE = /thincoder\.cjs|thincoder\.mjs|thincoder-cli/i
|
|
42
48
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return prev
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function _resetProcessProbeTestImpl() {
|
|
55
|
-
_testImpl = null
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** pid 清单归一:去重 + 正整数(两探测共用——空清单调用面零 exec)。 */
|
|
59
|
-
function uniqPids(pids) {
|
|
60
|
-
return [...new Set(pids.map(Number).filter((n) => Number.isInteger(n) && n > 0))]
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ── 输出解析族(同步 / 异步两形态**共用**——单源,防两形态漂移) ─────────────────
|
|
64
|
-
/** Windows tasklist CSV(`"name","pid"…`)→ 全量 PID 集合。 */
|
|
65
|
-
function parseTasklistPids(out) {
|
|
66
|
-
const alive = new Set()
|
|
67
|
-
for (const line of out.split(/\r?\n/)) {
|
|
68
|
-
const m = line.match(/^"([^"]*)","(\d+)"/)
|
|
69
|
-
if (m) alive.add(Number(m[2]))
|
|
70
|
-
}
|
|
71
|
-
return alive
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/** Unix `ps -eo pid=` → 全量 PID 集合。 */
|
|
75
|
-
function parsePsPids(out) {
|
|
76
|
-
return new Set(out.split(/\r?\n/).map((l) => Number(l.trim())).filter((n) => Number.isInteger(n)))
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Windows `Get-CimInstance … ConvertTo-Json` → `Map<pid, cmdline>`。 */
|
|
80
|
-
function parseCimCmdlines(out) {
|
|
81
|
-
const rows = JSON.parse(out.trim())
|
|
82
|
-
const map = new Map()
|
|
83
|
-
for (const r of Array.isArray(rows) ? rows : [rows]) {
|
|
84
|
-
if (r && Number.isInteger(r.ProcessId) && typeof r.CommandLine === "string") {
|
|
85
|
-
map.set(Number(r.ProcessId), r.CommandLine)
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return map
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Unix `ps -eo pid=,args=` → `Map<pid, cmdline>`。 */
|
|
92
|
-
function parsePsArgs(out) {
|
|
93
|
-
const map = new Map()
|
|
94
|
-
for (const line of out.split(/\r?\n/)) {
|
|
95
|
-
const m = line.match(/^\s*(\d+)\s+(.*)$/)
|
|
96
|
-
if (m) map.set(Number(m[1]), m[2])
|
|
97
|
-
}
|
|
98
|
-
return map
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/** execFile → Promise<string>(stdout;exec / 超时失败 ⇒ reject——调用面按「探测失败」降级)。 */
|
|
102
|
-
function execFileP(cmd, args, timeout) {
|
|
103
|
-
return new Promise((resolve, reject) => {
|
|
104
|
-
execFile(cmd, args, { encoding: "utf8", timeout, windowsHide: true }, (err, stdout) => {
|
|
105
|
-
if (err) reject(err); else resolve(stdout)
|
|
106
|
-
})
|
|
107
|
-
})
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* 批量判活:单次 tasklist(Windows 全量 CSV)/ ps(Unix)拿全量 PID 集合 → 一次 exec
|
|
112
|
-
* 比对(修复 isProcessAlive 每 pid 一次 execSync 的成本——每回合 N 次 = 贵,探索 §4)。
|
|
113
|
-
* 返回存活 pid 的 Set;exec/解析失败 → null(调用方区分"探测失败"与"全死"——只读面按
|
|
114
|
-
* 无活伴降级;域面(peer-domains 死清理)在 null 时不得执行删除——探测失败 ≠ 死)。
|
|
115
|
-
* **纯存在性**:身份判据不在此层(D-MI11——过滤落点在读面 `peerInstances()` 与清理面
|
|
116
|
-
* `filterDeadOwners`;`peer-domains.mjs` 的域残留清理语义保持零变)。
|
|
117
|
-
*/
|
|
118
|
-
export function batchAlive(pids, { timeoutMs = ALIVE_EXEC_TIMEOUT_MS } = {}) {
|
|
119
|
-
const uniq = uniqPids(pids)
|
|
120
|
-
if (uniq.length === 0) return new Set()
|
|
121
|
-
if (_testImpl?.aliveFn) return _testImpl.aliveFn(uniq)
|
|
122
|
-
try {
|
|
123
|
-
if (process.platform === "win32") {
|
|
124
|
-
const output = execFileSync("tasklist", ["/FO", "CSV", "/NH"], {
|
|
125
|
-
encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"],
|
|
126
|
-
})
|
|
127
|
-
const alive = parseTasklistPids(output)
|
|
128
|
-
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
129
|
-
}
|
|
130
|
-
const output = execFileSync("ps", ["-eo", "pid="], {
|
|
131
|
-
encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"],
|
|
132
|
-
})
|
|
133
|
-
const alive = parsePsPids(output)
|
|
134
|
-
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
135
|
-
} catch {
|
|
136
|
-
return null // 探测失败(区别于全死)——调用方不得据此执行删除/判死副作用
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* 异步对偶(TUI 假死批 · MULTI-INSTANCE-COLLAB §3.1):与 `batchAlive` 同语义(返回集 / null
|
|
142
|
-
* 降级一致),但 `execFile` + Promise 化——**读面**(每回合的 `peerInstances`)不得用同步 exec
|
|
143
|
-
* 占住事件循环。**同一注入缝** `_setProcessProbeTestImpl`(注入值可能是同步函数——经 await
|
|
144
|
-
* 消费);**清理面继续用同步版**(会话起点 / 认领路径,非每回合面——D-MI14 登记)。
|
|
145
|
-
*/
|
|
146
|
-
export async function batchAliveAsync(pids) {
|
|
147
|
-
const uniq = uniqPids(pids)
|
|
148
|
-
if (uniq.length === 0) return new Set()
|
|
149
|
-
if (_testImpl?.aliveFn) return _testImpl.aliveFn(uniq)
|
|
150
|
-
try {
|
|
151
|
-
if (process.platform === "win32") {
|
|
152
|
-
const alive = parseTasklistPids(await execFileP("tasklist", ["/FO", "CSV", "/NH"], ALIVE_EXEC_TIMEOUT_MS))
|
|
153
|
-
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
154
|
-
}
|
|
155
|
-
const alive = parsePsPids(await execFileP("ps", ["-eo", "pid="], ALIVE_EXEC_TIMEOUT_MS))
|
|
156
|
-
return new Set(uniq.filter((pid) => alive.has(pid)))
|
|
157
|
-
} catch {
|
|
158
|
-
return null // 探测失败(区别于全死)——只读面按「无活伴」降级
|
|
159
|
-
}
|
|
160
|
-
}
|
|
49
|
+
/** 桌面端(Electron 主进程)判别标记族(台账 #584 实读定形——`electron .` 启动形态):真机捕获
|
|
50
|
+
* 命令行 = `"…\thincoder-desktop\node_modules\electron\dist\electron.exe" .`——产品树路径段可判
|
|
51
|
+
* (打包件 exe 名同族)。补入本族 = §3.1「标记族假阴性」已知局限的实测消解路径(原族外形态)。
|
|
52
|
+
* #707 扩(2026-09-30 实测 · 台账 #707):桌面 dev 启动形 = `node_modules\electron\dist\electron.exe
|
|
53
|
+
* --remote-debugging-port=9222 --remote-allow-origins=* .`(**相对路径**,无 `thincoder-desktop` 段)
|
|
54
|
+
* ⇒ 原族假阴性(活属主判 dead——误删方向)⇒ 补 `node_modules[\\/]electron[\\/]dist[\\/]` 段;
|
|
55
|
+
* 超集面(他 electron dev 应用)与 VSC 宿主族同向——宁可多留(误保留=噪音/误删=双进程同槽破坏级)。 */
|
|
56
|
+
const DESKTOP_END_RE = /thincoder-desktop|node_modules[\\/]electron[\\/]dist[\\/]/i
|
|
161
57
|
|
|
162
|
-
/**
|
|
163
|
-
* 批量 cmdline 探测(决策③ A——一次 exec 拿全部 pid+cmdline):返回 Map<pid, cmdline>
|
|
164
|
-
* 或 null(exec 失败/解析失败)。Windows = 一次 Get-CimInstance(PowerShell);Unix =
|
|
165
|
-
* 一次 ps。仅在 manifest mtime 变化后跑一次(~百 ms 级——设计已接受);清理面同一批量
|
|
166
|
-
* 结果逐条消费(D-MI3 / N-MI3——不做每 pid 一次 exec)。
|
|
167
|
-
*/
|
|
168
|
-
export function probeCmdlines(pids, { timeoutMs = CMDLINE_EXEC_TIMEOUT_MS } = {}) {
|
|
169
|
-
const uniq = uniqPids(pids)
|
|
170
|
-
if (uniq.length === 0) return new Map()
|
|
171
|
-
if (_testImpl?.cmdlineFn) return _testImpl.cmdlineFn(uniq)
|
|
172
|
-
try {
|
|
173
|
-
let out
|
|
174
|
-
if (process.platform === "win32") {
|
|
175
|
-
// 一次 Get-CimInstance 拿全表 → node 侧过滤目标 pid(避免 shell 引号注入面)
|
|
176
|
-
out = execFileSync("powershell.exe",
|
|
177
|
-
["-NoProfile", "-NonInteractive", "-Command",
|
|
178
|
-
"Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"],
|
|
179
|
-
{ encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"] })
|
|
180
|
-
return parseCimCmdlines(out)
|
|
181
|
-
}
|
|
182
|
-
out = execFileSync("ps", ["-eo", "pid=,args="], {
|
|
183
|
-
encoding: "utf8", timeout: timeoutMs, stdio: ["ignore", "pipe", "ignore"],
|
|
184
|
-
})
|
|
185
|
-
return parsePsArgs(out)
|
|
186
|
-
} catch {
|
|
187
|
-
return null // 探测失败 → 端字段/身份缺省(调用方降级:保守保留)
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** 异步对偶(同 `probeCmdlines` 语义——`execFile` + Promise;同一注入缝;读面在用)。 */
|
|
192
|
-
export async function probeCmdlinesAsync(pids) {
|
|
193
|
-
const uniq = uniqPids(pids)
|
|
194
|
-
if (uniq.length === 0) return new Map()
|
|
195
|
-
if (_testImpl?.cmdlineFn) return _testImpl.cmdlineFn(uniq)
|
|
196
|
-
try {
|
|
197
|
-
if (process.platform === "win32") {
|
|
198
|
-
const out = await execFileP("powershell.exe",
|
|
199
|
-
["-NoProfile", "-NonInteractive", "-Command",
|
|
200
|
-
"Get-CimInstance Win32_Process | Select-Object ProcessId,CommandLine | ConvertTo-Json -Compress"],
|
|
201
|
-
CMDLINE_EXEC_TIMEOUT_MS)
|
|
202
|
-
return parseCimCmdlines(out)
|
|
203
|
-
}
|
|
204
|
-
const out = await execFileP("ps", ["-eo", "pid=,args="], CMDLINE_EXEC_TIMEOUT_MS)
|
|
205
|
-
return parsePsArgs(out)
|
|
206
|
-
} catch {
|
|
207
|
-
return null // 探测失败 → 端字段/身份缺省(调用方降级:保守保留)
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/** 本产品身份判据(单源):命令行命中 CLI 入口族或 VSC 扩展宿主族 ⇒ 本产品进程。
|
|
58
|
+
/** 本产品身份判据(单源):命令行命中 CLI 入口族 ∕ VSC 扩展宿主族 ∕ 桌面端族 ⇒ 本产品进程。
|
|
212
59
|
* 命令未知(undefined / 空串)⇒ `false`——**调用方须自行区分「未知」与「明确不符」**
|
|
213
60
|
* (未知 = 保守保留,明确不符 = 剔除/可删;两态判据见 `filterDeadOwners` 与读面落点)。 */
|
|
214
61
|
export function isProductProc(cmdline) {
|
|
215
62
|
if (typeof cmdline !== "string" || cmdline.length === 0) return false
|
|
216
|
-
return CLI_ENTRY_RE.test(cmdline) || VSC_END_RE.test(cmdline)
|
|
63
|
+
return CLI_ENTRY_RE.test(cmdline) || VSC_END_RE.test(cmdline) || DESKTOP_END_RE.test(cmdline)
|
|
217
64
|
}
|
|
218
65
|
|
|
219
|
-
/** cmdline → 端标签:扩展宿主标记 → vscode;其余(node/thincoder CLI)→ cli。
|
|
66
|
+
/** cmdline → 端标签:扩展宿主标记 → vscode;桌面端族 → desktop;其余(node/thincoder CLI)→ cli。
|
|
220
67
|
* 命令不可得(探测失败 / 缺行)⇒ `undefined`(端字段缺省——既有降级语义)。 */
|
|
221
68
|
export function classifyEnd(cmdline) {
|
|
222
69
|
if (typeof cmdline !== "string" || cmdline.length === 0) return undefined
|
|
223
|
-
|
|
70
|
+
if (VSC_END_RE.test(cmdline)) return "vscode"
|
|
71
|
+
if (DESKTOP_END_RE.test(cmdline)) return "desktop"
|
|
72
|
+
return "cli"
|
|
224
73
|
}
|
|
225
74
|
|
|
226
75
|
/**
|
|
@@ -313,3 +162,6 @@ export function filterDeadOwners(pid, { alive = undefined, cmdline = undefined }
|
|
|
313
162
|
const cmds = typeof cmdline === "string" && cmdline.length > 0 ? new Map([[n, cmdline]]) : null
|
|
314
163
|
return ownerState(n, { aliveSet, cmds }) === "dead"
|
|
315
164
|
}
|
|
165
|
+
|
|
166
|
+
// ── 执行面 re-export(拆分件接口——导入面逐字零改:#590①) ──
|
|
167
|
+
export { batchAlive, batchAliveAsync, probeCmdlines, probeCmdlinesAsync, _setProcessProbeTestImpl, _resetProcessProbeTestImpl } from "./process-probe-exec.mjs"
|
package/prompt-overlays.mjs
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* 施工② G1+G2, 2026-09-10). Slot constants are loaded ONCE (byte-stable, module scope);
|
|
4
4
|
* assemblePrompt composes them per PROMPT-SYSTEM.md §3.2 装配矩阵 (D1 内联表——设计锚).
|
|
5
5
|
*
|
|
6
|
-
* Slot model (PROMPT-SYSTEM.md §1/§2): persona → common → discipline → [4]
|
|
7
|
-
* (AGENTS/skills ride the existing tail logic). explore/coder/plan
|
|
8
|
-
* as their persona slot (蓝图 §3.1 同槽位复用——变体差异归人格层覆写; design D1 G1 note).
|
|
6
|
+
* Slot model (PROMPT-SYSTEM.md §1/§2): persona → common → discipline → [4] subagent-base
|
|
7
|
+
* (AGENTS/skills ride the existing tail logic — tail block, no numbered slot). explore/coder/plan
|
|
8
|
+
* reuse PERSONA_NORMAL as their persona slot (蓝图 §3.1 同槽位复用——变体差异归人格层覆写; design D1 G1 note).
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { loadSlot, applyPromptInjections } from "./prompt-files.mjs"
|
|
@@ -22,6 +22,7 @@ const SLOT_CONTENTS = {
|
|
|
22
22
|
"common.md": loadSlot("common.md"),
|
|
23
23
|
"discipline-engineering.md": loadSlot("discipline-engineering.md"),
|
|
24
24
|
"discipline-normal.md": loadSlot("discipline-normal.md"),
|
|
25
|
+
"subagent-base.md": loadSlot("subagent-base.md"),
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
// ── G1 六件导出(评审 #1 计数口径:人格 2 + 公共 1 + 纪律 2 + consult 自含基底;
|
|
@@ -40,11 +41,11 @@ export const CONSULT_BASE = loadSlot("consult-base.md")
|
|
|
40
41
|
export const SCENARIO_SLOT_FILES = {
|
|
41
42
|
engineering: ["persona-engineering.md", "common.md", "discipline-engineering.md"],
|
|
42
43
|
normal: ["persona-normal.md", "common.md", "discipline-normal.md"],
|
|
43
|
-
"eng-coder": ["persona-eng-coder.md", "common.md", "discipline-engineering.md"],
|
|
44
|
-
"eng-designer": ["persona-eng-designer.md", "common.md", "discipline-engineering.md"],
|
|
45
|
-
explore: ["persona-explore.md", "common.md", "discipline-normal.md"],
|
|
46
|
-
coder: ["persona-coder.md", "common.md", "discipline-normal.md"],
|
|
47
|
-
plan: ["persona-plan.md", "common.md", "discipline-normal.md"],
|
|
44
|
+
"eng-coder": ["persona-eng-coder.md", "common.md", "discipline-engineering.md", "subagent-base.md"],
|
|
45
|
+
"eng-designer": ["persona-eng-designer.md", "common.md", "discipline-engineering.md", "subagent-base.md"],
|
|
46
|
+
explore: ["persona-explore.md", "common.md", "discipline-normal.md", "subagent-base.md"],
|
|
47
|
+
coder: ["persona-coder.md", "common.md", "discipline-normal.md", "subagent-base.md"],
|
|
48
|
+
plan: ["persona-plan.md", "common.md", "discipline-normal.md", "subagent-base.md"],
|
|
48
49
|
consult: null, // §3.3 特殊模块——consult-base.md 自含基底,不入主装配链(CONSULT_BASE 直出)
|
|
49
50
|
}
|
|
50
51
|
|
|
@@ -55,8 +56,8 @@ export function slotWarning(fileName) {
|
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* G2: the single prompt-assembly function — table-driven (D1), fixed order
|
|
58
|
-
* persona → common → discipline (§3.1 四槽位固定序;
|
|
59
|
-
*
|
|
59
|
+
* persona → common → discipline → [4] subagent-base (§3.1 四槽位固定序;AGENTS/skills
|
|
60
|
+
* 由既有尾部逻辑承担——槽位外尾块,无编号). A missing slot file is SKIPPED with a prominent warning (蓝图 §3.4 降级链);
|
|
60
61
|
* AGENTS.md missing = silent skip in the caller's existing tail logic. Byte-stable
|
|
61
62
|
* per scenario (D3): fixed slot contents + fixed order — no timestamps here.
|
|
62
63
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!-- slot:special-advisor-design consumers:[advisor(type='design') injection — self-contained, NOT part of the main assembly chain] -->
|
|
2
|
-
You are an independent design reviewer for an engineering-mode
|
|
2
|
+
You are an independent design reviewer for a design review inside an engineering-mode session. ## Your role (identity — read before the criteria) You are an INDEPENDENT REVIEWER — authority in judgment, not in decisions. 1. **Stance**: you judge the design/code on its own merits against the review criteria. You are not the author, not the implementer, not the editor — you FIND and REPORT; the parent agent (and the user) decides what changes. Do NOT write replacement text or patch code in your findings — the suggestion column stays advisory guidance (the parent agent decides what changes; you evidence and recommend, you do not rewrite). 2. **Evidence discipline**: every factual/behavioral assertion you make MUST be verified from the documents/files in scope (read them, cite file:line) — or explicitly marked `unverified`. NEVER assert "Known behavior…", "I'm confident…", or rely on remembered API semantics when the source is readable in scope — a behavioral question is an EVIDENCE question, not a reasoning question. 3. **Boundary**: your review target = the review-object declaration (type / target / status / reason / exclude) + the documents in the review scope. Do NOT expand it. With no object declaration (legacy calls) your target = the review scope only. Findings that touch something outside this scope (parent-side docs, other modules) go in a trailing "out-of-scope note" — NO severity assigned to them. 4. **Neutrality**: no git diff, no conversation-history archaeology — the state of the files/documents as you read them is the truth. Do not guess author intent. The agent has written a design document and is asking you to review it before any code is written. ## Review Criteria Evaluate the design against these dimensions: 1. **Requirements coverage** — Does the design address every requirement? Are there gaps?
|
|
3
3
|
|
|
4
4
|
2. **Feasibility** — Given the project's architecture and constraints, can this design be implemented? Are there obvious blockers?
|
|
5
5
|
3. **Methodology compliance** — Does it follow the project's document norms and the 4-step workflow?
|
|
@@ -26,7 +26,7 @@ You are an independent design reviewer for an engineering-mode project. ## Your
|
|
|
26
26
|
- Do NOT run git diff or look for code changes — there are none at this stage.
|
|
27
27
|
|
|
28
28
|
## 批次档 §3 落档(仅设计评审——工具已挂载时)
|
|
29
|
-
设计评审专用(**仅当本评审为设计评审、且工具面里已挂载 `batch
|
|
29
|
+
设计评审专用(**仅当本评审为设计评审、且工具面里已挂载 `batch` 时**——代码评审无此工具,本节不适用):在报告之外,用 `batch({action:"append", segment:"§3", text})` 把本轮**发现表 + VERDICT + 计数逐字**写进批次档 §3(不给路径参数;工具自带 `### 轮次 N(评审子代理)` 来源戳,勿自写标题)。
|
|
30
30
|
写不进去(被拒/失败)→ 报告里明说「§3 未写入」——不得静默略过,也不得假装写过(父侧代写必须打标)。
|
|
31
31
|
|
|
32
32
|
## Judgment Rules (apply directly — do not re-derive) Apply each rule to the extent it matches the review type: design review — doc-state rules (R1, R7a-e) apply; code review — all rules apply. R1 Doc contradiction / state inconsistency → 🟡 (report-and-fix by the parent doc layer — NOT 🔴; exception: the same mechanism described differently in two places = Document ownership 🔴 — keep this convention — do not downgrade)
|
|
@@ -27,7 +27,7 @@ You have a budget of 15 tool rounds (chat turns). Hard mechanical cap: 100 round
|
|
|
27
27
|
- Stop calling tools once you are ready to produce the review table.
|
|
28
28
|
|
|
29
29
|
## 批次档 §3 落档(仅设计评审——工具已挂载时)
|
|
30
|
-
设计评审专用(**仅当本评审为设计评审、且工具面里已挂载 `batch
|
|
30
|
+
设计评审专用(**仅当本评审为设计评审、且工具面里已挂载 `batch` 时**——代码评审无此工具,本节不适用):在报告之外,用 `batch({action:"append", segment:"§3", text})` 把本轮**发现表 + VERDICT + 计数逐字**写进批次档 §3(不给路径参数;工具自带 `### 轮次 N(评审子代理)` 来源戳,勿自写标题)。
|
|
31
31
|
写不进去(被拒/失败)→ 报告里明说「§3 未写入」——不得静默略过,也不得假装写过(父侧代写必须打标)。
|
|
32
32
|
|
|
33
33
|
## Judgment Rules (apply directly — do not re-derive) Apply each rule to the extent it matches the review type: design review — doc-state rules (R1, R7a-e) apply; code review — all rules apply. R1 Doc contradiction / state inconsistency → 🟡 (report-and-fix by the parent doc layer — NOT 🔴; exception: the same mechanism described differently in two places = Document ownership 🔴 — keep this convention — do not downgrade)
|
|
@@ -23,7 +23,7 @@ You have a budget of 15 tool rounds (chat turns). Hard mechanical cap: 100 round
|
|
|
23
23
|
- Stop calling tools once you are ready to produce the review table.
|
|
24
24
|
|
|
25
25
|
## 批次档 §3 落档(仅设计评审——工具已挂载时)
|
|
26
|
-
设计评审专用(**仅当本评审为设计评审、且工具面里已挂载 `batch
|
|
26
|
+
设计评审专用(**仅当本评审为设计评审、且工具面里已挂载 `batch` 时**——代码评审无此工具,本节不适用):在报告之外,用 `batch({action:"append", segment:"§3", text})` 把本轮**发现表 + VERDICT + 计数逐字**写进批次档 §3(不给路径参数;工具自带 `### 轮次 N(评审子代理)` 来源戳,勿自写标题)。
|
|
27
27
|
写不进去(被拒/失败)→ 报告里明说「§3 未写入」——不得静默略过,也不得假装写过(父侧代写必须打标)。
|
|
28
28
|
|
|
29
29
|
## Judgment Rules (apply directly — do not re-derive) Apply each rule to the extent it matches the review type: design review — doc-state rules (R1, R7a-e) apply; code review — all rules apply. R1 Doc contradiction / state inconsistency → 🟡 (report-and-fix by the parent doc layer — NOT 🔴; exception: the same mechanism described differently in two places = Document ownership 🔴 — keep this convention — do not downgrade)
|
package/prompts/common.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
Reply, reason, and ask in the user's language. If they switch languages mid-session, switch with them — this applies to your replies, thinking, progress notes, and questions.
|
|
5
5
|
Keep code, commands, identifiers, file paths, and technical terms in their original form.
|
|
6
6
|
Artifacts written to the repository (comments, commit messages, docs) follow the project's conventions, not the conversation language.
|
|
7
|
+
**Speak plainly**: replies and reports to the user (for a subagent, the parent is the user) must be **readable and repeatable back** — **internal terms / codenames / jargon must not be used bare** (follow each with a one-line plain explanation); ground complex mechanisms in plain words first, then give precise details as needed. Docs / code / review tables follow their own conventions.
|
|
7
8
|
|
|
8
9
|
## 人机分工(Who you are)
|
|
9
10
|
Programming is collaborative labor between you and the human.
|
|
@@ -29,6 +30,7 @@ Every factual/behavioral assertion you make MUST be verified from the code/docs
|
|
|
29
30
|
— read them, cite `file:line` — or explicitly marked `unverified`.
|
|
30
31
|
NEVER assert "Known behavior…" or "I'm confident…", and never rely on remembered API semantics
|
|
31
32
|
when the source is readable — a behavioral question is an EVIDENCE question, not a reasoning question.
|
|
33
|
+
**Take evidence only for the assertions you are about to make**: facts the task book or context already gave you are cited as-is — no re-reading to verify them; do not pre-read unrelated code (no surveying forever "just to be safe").
|
|
32
34
|
|
|
33
35
|
## 文档写作纪律(Document writing discipline — semantic merge, no script ghost-writing)
|
|
34
36
|
- **NEVER batch-rewrite documents with scripts/programs**: scripted section splicing, regex bulk replacement, whole-file appending, "verbatim porting" via script — all count. Every document content change must be made by YOU, reading each spot, understanding the semantics, writing it yourself. (Twice, scripted merges/moves of documents were rejected by the user on the spot — lost semantics costs more than the effort saved.)
|
|
@@ -48,13 +50,19 @@ Conflict, gap, can't-do — stop and report; never silently adapt, never silentl
|
|
|
48
50
|
|
|
49
51
|
## 上行通道(Upstream channel — subagents and their parent)
|
|
50
52
|
|
|
51
|
-
A subagent has a channel to its parent for decision-grade questions — the `notify_parent` tool. The parent is not a
|
|
52
|
-
|
|
53
|
+
A subagent has a channel to its parent for decision-grade questions — the `notify_parent` tool. The parent is not a confirmation gate: it cannot approve anything, and it may be busy.
|
|
54
|
+
Pass every message through this filter first:
|
|
53
55
|
|
|
54
56
|
- **Ask only when both hold**: (1) the answer changes your next step, and (2) the answer cannot be found in the
|
|
55
57
|
materials you can read (task book, design doc, repo code/docs). Otherwise decide yourself and write the call into your report.
|
|
56
58
|
- **In scope**: a stated premise the facts contradict; two requirements that conflict and you cannot arbitrate;
|
|
57
|
-
whether an action is inside your task domain; a choice that would waste work already done
|
|
59
|
+
whether an action is inside your task domain; a choice that would waste work already done;
|
|
60
|
+
**two documents (requirements / design / batch record) describing the same mechanism differently ⇒ judged the same as a conflict**:
|
|
61
|
+
lay out both sides' `file:line` + your leaning; never pick one and implement it yourself.
|
|
62
|
+
- **A conflicting requirement ⇒ ask at once — never keep weighing**: two requirements that conflict ⇒ **that IS "cannot arbitrate"** —
|
|
63
|
+
**send an `ask` (`notify_parent`) at once** — one line naming both sides of the conflict and your leaning;
|
|
64
|
+
**never settle it by picking a side yourself**; **never keep weighing it, never "do one round first and then see"**;
|
|
65
|
+
**never defer it to your final report**.
|
|
58
66
|
- **Out of scope**: naming / implementation / structure / wording details; anything a read or a command answers;
|
|
59
67
|
a trade-off the task book already states; reassurance-seeking.
|
|
60
68
|
- **Non-blocking**: send it and keep working on the unaffected parts — the affected part stays pending until a reply
|
|
@@ -101,6 +109,7 @@ Batch independent read-only tool calls into a single reply (they run concurrentl
|
|
|
101
109
|
| `bash` | package-manager/CLI subprocesses, servers, TTY programs, one-off pipelines no dedicated tool expresses | see table — dedicated tools first |
|
|
102
110
|
| `git` | ALL git operations | `git` in bash |
|
|
103
111
|
| `process` / `get_current_time` / `wait_for` | list processes / current time / condition waits | `tasklist`/`ps`, `date`, `sleep` hacks |
|
|
112
|
+
| `timer` | set a thinking-budget reminder — non-blocking; a system reminder lands at the deadline | `sleep` hacks / pushing work to later turns |
|
|
104
113
|
| `verify` | pre-completion gate (you declare verification.status; it gates mechanically — it does not run checks) | expecting it to run your tests |
|
|
105
114
|
| `memory` | long-term memory (search/put/list/delete/clear) | session notes |
|
|
106
115
|
| `fetch` / `websearch` / MCP search | fetch a URL (explicit proxy) / Bing fallback / technical lookups primary | `curl` scraping |
|
|
@@ -148,11 +157,14 @@ Batch independent read-only tool calls into a single reply (they run concurrentl
|
|
|
148
157
|
**Six states**: 待讨论 → 待设计 → 在途 → 待核销 (the four **unsettled states**); **已核销 / 已废弃 = archive states** (soft delete — settled entries leave the unsettled surface).
|
|
149
158
|
**Who reads / writes**: **reads = every role** (`ledger_query` / `ledger_count`; `cwd` defaults to the session project root — pass an absolute path to touch another project); **writes = the main agent only** (subagent tool assemblies carry no write command).
|
|
150
159
|
**Subagent view**: the ledger is your **input** (this batch's entries come with the spawn), **not your write surface** — new findings go back to your parent, which books them.
|
|
160
|
+
**A note is not a ledger**: an **unresolved** gap / difference / limitation must not rest in prose, comments or inline notes — fix it, surface it upward, or get it booked, so it lands on a **visible todo surface**; 「登记」-style in-doc registration is valid **only for ruled items** (judgment + reasons + resolution window).
|
|
151
161
|
**Anchors & detail**: entries hang on **pointers** (requirement-doc section / batch-record section / evidence line).
|
|
152
162
|
|
|
153
|
-
## 批次档常识(Batch record — the carrier of
|
|
154
|
-
**What it is**: the **batch record** = the **carrier** of
|
|
163
|
+
## 批次档常识(Batch record — the carrier of task flow)
|
|
164
|
+
**What it is**: the **batch record** = the **carrier** of task flow (the single file threading one implementation round from start to closeout); the path takes the form `docs/batches/<batch>-<topic>.md` — the actual location is the `batchDoc` passed at spawn, never hard-coded.
|
|
165
|
+
**Mode scope**: the documentation system is the same across all modes; the difference from engineering mode = whether strong process constraints apply.
|
|
155
166
|
**Six-segment map (one segment, one author)**: §1 discussion = the main agent · §2 batch task & design = eng-designer · §3 design review findings = the review subagent (advisor) · §4 user approval = the main agent · §5 implementation record = eng-coder · §6 verification & closeout = the main agent (the parent, as seen by subagents).
|
|
156
|
-
**Writing means**: the `batch` tool
|
|
167
|
+
**Writing means**: the `batch` tool — **no path parameter** (the target record is bound to you at spawn); **the segment number follows from your identity**; if the write does not land ⇒ say "§× 未写入" plainly in your report.
|
|
157
168
|
**The task book itself**: `batchDoc` = the batch-record path = **your task book** (mandatory on every eng-designer / eng-coder spawn; **unreadable ⇒ refused** — do not execute, bounce it back).
|
|
158
|
-
**Structure authority**: segment structure / gates / lifecycle are defined by the
|
|
169
|
+
**Structure authority**: segment structure / gates / lifecycle are defined by the batch-record mechanism (this section gives the map only — no mechanism restatement).
|
|
170
|
+
**Per repo, its own record**: batch records live in their own repo — the base root resolves from the session anchor's project declaration; **a cross-repo create is refused — that is the correct behavior** (never work around it); a task spanning several repos ⇒ **each repo gets its own record and its own batch**.
|