@zhushanwen/subagent-core 0.2.0 → 0.5.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.
Files changed (347) hide show
  1. package/README.md +45 -2
  2. package/agents/analyst.md +60 -0
  3. package/agents/coder.md +69 -0
  4. package/agents/debugger.md +66 -0
  5. package/agents/doc-reviewer.md +49 -0
  6. package/agents/explorer.md +63 -0
  7. package/agents/general-purpose.md +32 -0
  8. package/agents/orchestrator.md +61 -0
  9. package/agents/planner.md +53 -0
  10. package/agents/researcher.md +67 -0
  11. package/agents/reviewer.md +73 -0
  12. package/dist/chunk-43ONBFZX.js +240 -0
  13. package/dist/chunk-APZY4IME.js +27 -0
  14. package/dist/chunk-V3VHZ2VX.js +59 -0
  15. package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
  16. package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
  17. package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
  18. package/dist/execution/engine/engines/zcode/constants.js +39 -7
  19. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  20. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  21. package/dist/execution/engine/engines/zcode/reader.js +4 -234
  22. package/dist/execution/engine/paths.js +7 -19
  23. package/dist/index.cjs +18234 -1277
  24. package/dist/index.d.cts +5646 -673
  25. package/dist/index.d.ts +5646 -673
  26. package/dist/index.js +17828 -1277
  27. package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
  28. package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
  29. package/package.json +7 -4
  30. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  31. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  32. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  33. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  34. package/src/__tests__/manifest-store.test.ts +10 -9
  35. package/src/__tests__/record-store-cache.test.ts +0 -2
  36. package/src/__tests__/record-store-index.test.ts +1 -2
  37. package/src/__tests__/review-fix-loop-script.test.ts +93 -3
  38. package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
  39. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  40. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  41. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  42. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  43. package/src/__tests__/session-runner.test.ts +1 -1
  44. package/src/__tests__/smoke.test.ts +9 -2
  45. package/src/core/__tests__/host-services.test.ts +2 -2
  46. package/src/core/__tests__/logger.test.ts +1 -1
  47. package/src/core/error-message.ts +9 -0
  48. package/src/core/host-services.ts +21 -5
  49. package/src/core/notify-ports.ts +18 -5
  50. package/src/execution/__tests__/agent-profile.test.ts +232 -0
  51. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  52. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  53. package/src/execution/__tests__/agents-assembly.test.ts +219 -0
  54. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  55. package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
  56. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
  57. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  58. package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
  59. package/src/execution/__tests__/delivery-methods.test.ts +77 -62
  60. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  61. package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
  62. package/src/execution/__tests__/dialog-queue.test.ts +199 -1
  63. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  64. package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
  65. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  66. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  67. package/src/execution/__tests__/execution-record.test.ts +217 -60
  68. package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
  69. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
  70. package/src/execution/__tests__/finalize-record.test.ts +278 -16
  71. package/src/execution/__tests__/gc-timer.test.ts +57 -2
  72. package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
  73. package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
  74. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  75. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  76. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  77. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  78. package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
  79. package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
  80. package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  83. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  84. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
  85. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
  86. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  87. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  88. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  89. package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
  90. package/src/execution/__tests__/output-collector.test.ts +117 -6
  91. package/src/execution/__tests__/pi-invocation.test.ts +1 -1
  92. package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
  93. package/src/execution/__tests__/record-store.test.ts +89 -5
  94. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  95. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  96. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  97. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  98. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  105. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
  106. package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
  107. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  108. package/src/execution/__tests__/session-file-gc.test.ts +35 -0
  109. package/src/execution/__tests__/session-pending.test.ts +471 -0
  110. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  111. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
  112. package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
  113. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  114. package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
  115. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
  116. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  117. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  118. package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
  119. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  120. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  121. package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
  122. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  123. package/src/execution/__tests__/spawned-children.test.ts +155 -11
  124. package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
  125. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  126. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  127. package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
  128. package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
  129. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
  130. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
  131. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
  132. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
  133. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  134. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  135. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  136. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  137. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  138. package/src/execution/__tests__/timeout-integration.test.ts +13 -12
  139. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  140. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  141. package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
  142. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  143. package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
  144. package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
  145. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  146. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  147. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
  148. package/src/execution/agent-registry.ts +298 -30
  149. package/src/execution/agent-result-mapper.ts +3 -0
  150. package/src/execution/agents-assembly.ts +88 -0
  151. package/src/execution/cold-resurrect.ts +199 -0
  152. package/src/execution/concurrency-pool.ts +71 -9
  153. package/src/execution/dialog-queue.ts +101 -3
  154. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  155. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  156. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  158. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  159. package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
  160. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  161. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  162. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
  163. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
  168. package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
  169. package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
  170. package/src/execution/engine/__tests__/registry.test.ts +94 -3
  171. package/src/execution/engine/__tests__/routing.test.ts +115 -6
  172. package/src/execution/engine/common/capability-gate.ts +92 -0
  173. package/src/execution/engine/common/journal-wiring.ts +97 -0
  174. package/src/execution/engine/common/kill-chain.ts +42 -10
  175. package/src/execution/engine/common/nesting-guard.ts +66 -0
  176. package/src/execution/engine/common/persona-router.ts +18 -8
  177. package/src/execution/engine/common/pool-manager.ts +332 -78
  178. package/src/execution/engine/common/session-view-service.ts +506 -0
  179. package/src/execution/engine/common/session-view-types.ts +125 -0
  180. package/src/execution/engine/engine-discovery.ts +12 -16
  181. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
  182. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  183. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  184. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
  185. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  186. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  187. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  188. package/src/execution/engine/engines/pi/reader.ts +11 -0
  189. package/src/execution/engine/engines/pi/registration.ts +4 -2
  190. package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
  191. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  192. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  193. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  194. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  195. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
  197. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  198. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
  199. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  200. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  202. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  203. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  209. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  210. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
  211. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  212. package/src/execution/engine/engines/zcode/connection.ts +598 -0
  213. package/src/execution/engine/engines/zcode/constants.ts +147 -14
  214. package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
  215. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  216. package/src/execution/engine/engines/zcode/preparer.ts +22 -150
  217. package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
  218. package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
  219. package/src/execution/engine/host-task-spec.ts +32 -36
  220. package/src/execution/engine/model-validation.ts +177 -0
  221. package/src/execution/engine/port.ts +65 -7
  222. package/src/execution/engine/registry.ts +53 -0
  223. package/src/execution/engine/routing.ts +75 -1
  224. package/src/execution/engine/types.ts +30 -103
  225. package/src/execution/execution-record.ts +222 -144
  226. package/src/execution/finalize-record.ts +181 -85
  227. package/src/execution/idle-gc.ts +28 -0
  228. package/src/execution/lifecycle-manager.ts +27 -3
  229. package/src/execution/lifecycle-predicates.ts +1 -1
  230. package/src/execution/manifest-store.ts +53 -62
  231. package/src/execution/notifier.ts +10 -10
  232. package/src/execution/notify-host.ts +212 -0
  233. package/src/execution/notify-ledger.ts +117 -16
  234. package/src/execution/record-entry.ts +8 -2
  235. package/src/execution/record-store.ts +148 -88
  236. package/src/execution/round-settlement.ts +93 -0
  237. package/src/execution/session-file-gc.ts +96 -62
  238. package/src/execution/session-pending.ts +213 -62
  239. package/src/execution/session-reconstructor.ts +256 -143
  240. package/src/execution/sessions-index.ts +127 -102
  241. package/src/execution/settled-watchdog.ts +311 -0
  242. package/src/execution/subagent-actions-core.ts +686 -0
  243. package/src/execution/subagent-service.ts +1106 -907
  244. package/src/execution/subprocess-agent-runner.ts +144 -97
  245. package/src/execution/types.ts +9 -0
  246. package/src/execution/ui-request-handler-factory.ts +126 -75
  247. package/src/execution/ui-request-queue.ts +50 -19
  248. package/src/execution/worktree-git-ops.ts +397 -0
  249. package/src/execution/worktree-manager.ts +72 -10
  250. package/src/execution/worktree-registry.ts +6 -12
  251. package/src/index.ts +542 -9
  252. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
  253. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
  254. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  255. package/src/orchestration/__tests__/args-meta.test.ts +358 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  257. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
  258. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
  259. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  260. package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
  261. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
  262. package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
  263. package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
  264. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
  265. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
  266. package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
  267. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  268. package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
  269. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  270. package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
  271. package/src/orchestration/__tests__/script-generate.test.ts +314 -0
  272. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  273. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  274. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  275. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  276. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
  277. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  278. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  279. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  280. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
  281. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
  282. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  283. package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
  284. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  285. package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
  286. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
  287. package/src/orchestration/agent-opts-resolver.ts +8 -8
  288. package/src/orchestration/args-meta.ts +198 -0
  289. package/src/orchestration/args-validator.ts +53 -31
  290. package/src/orchestration/execute-agent-call.ts +25 -79
  291. package/src/orchestration/file-run-store.ts +327 -0
  292. package/src/orchestration/launcher.ts +160 -104
  293. package/src/orchestration/lifecycle.ts +371 -97
  294. package/src/orchestration/models/agent-call.ts +7 -7
  295. package/src/orchestration/models/budget.ts +5 -5
  296. package/src/orchestration/models/ports.ts +4 -4
  297. package/src/orchestration/models/run-runtime.ts +15 -15
  298. package/src/orchestration/models/trace.ts +9 -9
  299. package/src/orchestration/models/types.ts +111 -22
  300. package/src/orchestration/models/workflow-run.ts +28 -28
  301. package/src/orchestration/models/workflow-script.ts +4 -4
  302. package/src/orchestration/run-snapshot.ts +266 -0
  303. package/src/orchestration/script-generate.ts +154 -0
  304. package/src/orchestration/script-lint.ts +123 -90
  305. package/src/orchestration/worker-handle.ts +10 -10
  306. package/src/orchestration/worker-host.ts +10 -10
  307. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
  308. package/src/orchestration/worker-script-builder.ts +401 -346
  309. package/src/orchestration/workflow-files.ts +37 -11
  310. package/src/orchestration/workflow-run-summary.ts +69 -0
  311. package/src/orchestration/workflow-script-registry-impl.ts +31 -9
  312. package/src/shared/__tests__/agent-ref.test.ts +209 -2
  313. package/src/shared/__tests__/atomic-write.test.ts +267 -0
  314. package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
  315. package/src/shared/__tests__/injection-render.test.ts +518 -0
  316. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  317. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
  318. package/src/shared/__tests__/resource-discovery.test.ts +261 -217
  319. package/src/shared/agent-ref.ts +143 -2
  320. package/src/shared/atomic-write.ts +323 -0
  321. package/src/shared/bounded-serialize.ts +154 -0
  322. package/src/shared/injection-render.ts +279 -0
  323. package/src/shared/meta-parser.ts +182 -68
  324. package/src/shared/model-ref.ts +15 -2
  325. package/src/shared/resource-discovery.ts +97 -204
  326. package/src/shared/resource-meta.ts +14 -0
  327. package/src/shared/schema-jsonify.ts +1 -1
  328. package/src/shared/xml-injection.ts +9 -9
  329. package/workflows/README.md +9 -9
  330. package/workflows/chain.js +4 -2
  331. package/workflows/map-reduce.js +5 -3
  332. package/workflows/parallel.js +5 -3
  333. package/workflows/review-fix-loop-utils.cjs +165 -92
  334. package/workflows/review-fix-loop-utils.d.cts +287 -0
  335. package/workflows/review-fix-loop.js +18 -7
  336. package/workflows/scatter-gather.js +4 -2
  337. package/dist/chunk-3VOERJPJ.js +0 -22
  338. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  339. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  340. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  341. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  342. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  343. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  344. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  345. package/src/execution/execute-options-mapper.ts +0 -115
  346. package/src/execution/session-runner.ts +0 -1789
  347. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -1,7 +1,7 @@
1
1
  // review-fix-loop-utils.cjs — review-fix-loop.js 的可测纯函数模块
2
2
  //
3
3
  // workflow 编排逻辑的纯函数抽到独立 .cjs,
4
- // 供 vitest 单测直接 require(extensions/universal/subagent-workflow/src/__tests__/review-fix-loop-utils.test.ts)
4
+ // 供 vitest 单测直接 require(packages/subagent-core/src/__tests__/review-fix-loop-utils.test.ts)
5
5
  // 与 worker 运行时共用(review-fix-loop.js 经 workerData.scriptPath 定位本文件)。
6
6
  //
7
7
  // 本文件不依赖 workflow 全局($ARGS/agent/parallel/phase/log),所有需要报错的函数
@@ -310,10 +310,16 @@ function normIssueId(s) {
310
310
  * fix 阶段(fix-attempted/deferred 标记)与 ES3 校验共用——精确键查表会把
311
311
  * "mf-1"/"MF-1 (fixed)" 等漂移 ID 判为未追踪,导致 fix-attempted → fixed/regressed
312
312
  * → needs-redesign 状态链静默失效;deferred 侧漂移则创建幽灵条目(原条目仍 open 阻塞收敛)。
313
+ *
314
+ * 首查必须 Object.hasOwn(上收 zsw 侧同款修复):truthy 查表(issues[issueId])会让
315
+ * 原型链键("__proto__"/"toString"/"constructor")误命中——ID 来自 LLM 产出,攻击面
316
+ * 真实存在;误命中会把非 own 键当台账键返回,后续 issues[key].severity 读取原型
317
+ * 成员(undefined 或函数)污染 fix 对账。归一化回退段的 Object.keys 只枚举 own 键,
318
+ * 本就无此问题。
313
319
  */
314
320
  function findIssueKey(issues, issueId) {
315
321
  if (!issues || typeof issueId !== "string" || !issueId) return undefined;
316
- if (issues[issueId]) return issueId;
322
+ if (Object.hasOwn(issues, issueId)) return issueId;
317
323
  const norm = normIssueId(issueId);
318
324
  if (!norm) return undefined;
319
325
  for (const key of Object.keys(issues)) {
@@ -322,6 +328,64 @@ function findIssueKey(issues, issueId) {
322
328
  return undefined;
323
329
  }
324
330
 
331
+ /**
332
+ * deferred 条目的有效 severity(m9 交叉核对):自报 severity 可被单边绕过(fix agent
333
+ * 与审核方同一 LLM,有少干活动机,把 must-fix 标 minor 塞进 deferred 即过旧校验)——
334
+ * 与追踪表交叉核对:trackedIssues 中能找到的 ID 以其追踪 severity 为准;追踪表无此 ID
335
+ * 采信自报。仅认真实 severity 等级(critical/major/minor/trivial);"unknown"(reconcile
336
+ * 新 ID 默认)等非等级值不覆盖自报,避免误伤合法 minor deferral。
337
+ */
338
+ function resolveDeferredEffectiveSeverity(d, trackedIssues, idMap) {
339
+ const sev = typeof d.severity === "string" ? d.severity.toLowerCase() : "";
340
+ let effectiveSev = sev;
341
+ if (trackedIssues && typeof d.issue_id === "string" && d.issue_id) {
342
+ const trackedKey = findIssueKey(trackedIssues, translateId(idMap, d.issue_id, trackedIssues));
343
+ const trackedSev = trackedKey ? trackedIssues[trackedKey].severity : undefined;
344
+ const ts = typeof trackedSev === "string" ? trackedSev.toLowerCase() : "";
345
+ if (ts === "critical" || ts === "major" || ts === "minor" || ts === "trivial") {
346
+ effectiveSev = ts;
347
+ }
348
+ }
349
+ return effectiveSev;
350
+ }
351
+
352
+ /** deferred 违规收集(TC3):有效 severity 非 minor/trivial 即违规;falsy 条目跳过。 */
353
+ function collectDeferredViolations(result, trackedIssues, idMap) {
354
+ const violations = [];
355
+ for (const d of result.deferred || []) {
356
+ if (!d) continue;
357
+ const effectiveSev = resolveDeferredEffectiveSeverity(d, trackedIssues, idMap);
358
+ if (effectiveSev && effectiveSev !== "minor" && effectiveSev !== "trivial") {
359
+ violations.push({ issue_id: d.issue_id || "(unnamed)", severity: effectiveSev });
360
+ }
361
+ }
362
+ return violations;
363
+ }
364
+
365
+ /** must-fix 申报 ID 归一化:string 直接归一;对象形态取 .id 归一;其余空串。 */
366
+ function normMustFixEntryId(id) {
367
+ if (typeof id === "string") return normIssueId(id);
368
+ return id && typeof id.id === "string" ? normIssueId(id.id) : "";
369
+ }
370
+
371
+ /**
372
+ * must-fix 漏修违规收集(m3):ID 归一化比较——大小写 + 尾部括号尾注(如 "(fixed)")
373
+ * 漂移不误杀:严格 trim 比较会把 "mf-1"/"MF-1 (fixed)" 判漏修,整轮 fix-failure 误杀。
374
+ */
375
+ function collectMustFixNotFixedViolations(result, mustFixIds) {
376
+ const violations = [];
377
+ const fixedIds = new Set((result.fixes || [])
378
+ .map((f) => (f && typeof f.issue_id === "string" ? normIssueId(f.issue_id) : ""))
379
+ .filter(Boolean));
380
+ for (const id of mustFixIds) {
381
+ const norm = normMustFixEntryId(id);
382
+ if (norm && !fixedIds.has(norm)) {
383
+ violations.push({ issue_id: norm, severity: "must-fix-not-fixed" });
384
+ }
385
+ }
386
+ return violations;
387
+ }
388
+
325
389
  /**
326
390
  * ES3 硬校验(5.3-P1 红线):(1) deferred 只允许 minor/trivial;(2) must-fix 必须全进
327
391
  * fixes[]——mustFixIds 中未修复且未显式处理的 ID 判 violation(漏修)。mustFixIds
@@ -335,40 +399,9 @@ function findIssueKey(issues, issueId) {
335
399
  * 翻译任一侧都会制造假失配(must-fix-not-fixed 误杀整 run)。
336
400
  */
337
401
  function validateFixResult(result, mustFixIds, trackedIssues, idMap) {
338
- const violations = [];
339
- for (const d of result.deferred || []) {
340
- if (!d) continue;
341
- const sev = typeof d.severity === "string" ? d.severity.toLowerCase() : "";
342
- // m9: 自报 severity 可被单边绕过(fix agent 与审核方同一 LLM,有少干活动机,
343
- // 把 must-fix 标 minor 塞进 deferred 即过旧校验)——与追踪表交叉核对:
344
- // trackedIssues 中能找到的 ID 以其追踪 severity 为准;追踪表无此 ID 采信自报。
345
- let effectiveSev = sev;
346
- if (trackedIssues && typeof d.issue_id === "string" && d.issue_id) {
347
- const trackedKey = findIssueKey(trackedIssues, translateId(idMap, d.issue_id, trackedIssues));
348
- const trackedSev = trackedKey ? trackedIssues[trackedKey].severity : undefined;
349
- const ts = typeof trackedSev === "string" ? trackedSev.toLowerCase() : "";
350
- // 仅认真实 severity 等级(critical/major/minor/trivial);"unknown"(reconcile 新
351
- // ID 默认)等非等级值不覆盖自报,避免误伤合法 minor deferral
352
- if (ts === "critical" || ts === "major" || ts === "minor" || ts === "trivial") {
353
- effectiveSev = ts;
354
- }
355
- }
356
- if (effectiveSev && effectiveSev !== "minor" && effectiveSev !== "trivial") {
357
- violations.push({ issue_id: d.issue_id || "(unnamed)", severity: effectiveSev });
358
- }
359
- }
402
+ const violations = collectDeferredViolations(result, trackedIssues, idMap);
360
403
  if (Array.isArray(mustFixIds) && mustFixIds.length > 0) {
361
- // m3: ID 归一化比较——大小写 + 尾部括号尾注(如 "(fixed)")漂移不误杀:
362
- // 严格 trim 比较会把 "mf-1"/"MF-1 (fixed)" 判漏修,整轮 fix-failure 误杀
363
- const fixedIds = new Set((result.fixes || [])
364
- .map((f) => (f && typeof f.issue_id === "string" ? normIssueId(f.issue_id) : ""))
365
- .filter(Boolean));
366
- for (const id of mustFixIds) {
367
- const norm = typeof id === "string" ? normIssueId(id) : (id && typeof id.id === "string" ? normIssueId(id.id) : "");
368
- if (norm && !fixedIds.has(norm)) {
369
- violations.push({ issue_id: norm, severity: "must-fix-not-fixed" });
370
- }
371
- }
404
+ violations.push(...collectMustFixNotFixedViolations(result, mustFixIds));
372
405
  }
373
406
  return violations;
374
407
  }
@@ -785,7 +818,9 @@ function resolveIssueIdentity(entry, { issues, dormant }) {
785
818
  */
786
819
  function translateId(idMap, id, issues) {
787
820
  if (typeof id !== "string" || !id) return id;
788
- if (issues && issues[id]) return id;
821
+ // Object.hasOwn:truthy 查表会让原型链键("__proto__"/"toString")误判为台账键
822
+ // 直接返回,跳过 idMap 翻译(与 findIssueKey 同款加固,nextFreeId 键空间同理)。
823
+ if (issues && Object.hasOwn(issues, id)) return id;
789
824
  if (idMap && Object.prototype.hasOwnProperty.call(idMap, id)) return idMap[id];
790
825
  return id;
791
826
  }
@@ -821,6 +856,88 @@ function translateReconSets(reconSeen, reconEscalate, reconFixed, idMap, issues)
821
856
  * 未知 ID(不在 prevIssues 中)按新发现处理;stuckThreshold 复用 stuckThreshold 参数。
822
857
  * @returns { issues, stuck, stuckIds, knownRemaining }
823
858
  */
859
+ /** 条目克隆:浅拷贝 + history 复制——reconcile 不修改入参条目,转换落在新条目上。 */
860
+ function cloneTrackedIssue(issue) {
861
+ return { ...issue, history: [...(issue.history || [])] };
862
+ }
863
+
864
+ /**
865
+ * 5.1-5 显式升级:reconciliation 声明 escalate → 重新 open(保留历史与 fixAttempts),
866
+ * 进入修复循环;未升级的 deferred 留 known-remaining,不参与判定。
867
+ */
868
+ function escalateDeferredIssue(entry, id, escalated, round) {
869
+ if (!escalated.has(id)) return;
870
+ entry.status = "open";
871
+ entry.openStreak = 0;
872
+ entry.history.push({ round, status: "escalated" });
873
+ }
874
+
875
+ /**
876
+ * open/regressed + 声明 fixed(verify-first)→ 清账,命中返回 true(调用方跳过后续
877
+ * 转换)。与"fix result claiming fixed is NOT evidence"原则不冲突:这里的 fixed 声明
878
+ * 来自 reviewer 亲自读目标后的申报(evidence 非空由调用方过滤),正是该原则认可的
879
+ * 证据形态——此前它被收集侧整体丢弃,open 条目无消除通道。
880
+ */
881
+ function applyReconciledFix(entry, id, fixedDeclared, round) {
882
+ if (!((entry.status === "open" || entry.status === "regressed") && fixedDeclared.has(id))) return false;
883
+ entry.status = "fixed";
884
+ entry.openStreak = 0;
885
+ entry.history.push({ round, status: "fixed", via: "reconciliation" });
886
+ return true;
887
+ }
888
+
889
+ /**
890
+ * fix-attempted 判定:未再现(未 seen)→ fixed;再现 → regressed(fixAttempts+1)。
891
+ */
892
+ function applyFixAttemptedOutcome(entry, statusNow, id, seen, round) {
893
+ if (statusNow !== "fix-attempted") return;
894
+ if (!seen.has(id)) {
895
+ entry.status = "fixed";
896
+ entry.openStreak = 0;
897
+ entry.history.push({ round, status: "fixed" });
898
+ } else {
899
+ entry.status = "regressed";
900
+ // fixAttempts 语义 = 修复失败次数:初始 0,每次 regressed +1(RC-7「经 2 次修复
901
+ // 仍未收敛」= 第 2 次 regressed 后触发,修复见 findNeedsRedesign 阈值)。
902
+ entry.fixAttempts = (entry.fixAttempts || 0) + 1;
903
+ entry.history.push({ round, status: "regressed" });
904
+ }
905
+ }
906
+
907
+ /**
908
+ * MF-2: fixed 条目再次被报告(seen)→ 回归:转 regressed + fixAttempts+1(已确认修复
909
+ * 的问题复发同样计修复失败,needs-redesign 可达);openStreak 由统一 if 累计
910
+ * (首轮回归 1)。未 seen → 保持 fixed(漏报不误转)。修复前此处无转换——fixed 条目
911
+ * 复发时 fixAttempts/openStreak 均不增长,与收敛终止组合后默认配置下 R3 即以
912
+ * converged 提前终止而 must-fix 仍活跃(MF-2)。
913
+ */
914
+ function applyFixedRegression(entry, statusNow, id, seen, round) {
915
+ if (!(statusNow === "fixed" && seen.has(id))) return;
916
+ entry.status = "regressed";
917
+ entry.fixAttempts = (entry.fixAttempts || 0) + 1;
918
+ entry.history.push({ round, status: "regressed" });
919
+ }
920
+
921
+ // open/regressed 且本轮仍在(seen)→ openStreak +1(跨轮字段);漏报(未 seen)不增长(保守)。
922
+ // status 读 entry 当前值——fix-attempted/fixed 分支本轮转出的 regressed 同样累计(原语义)。
923
+ function accrueOpenStreak(entry, id, seen, stuckThreshold, stuckIds) {
924
+ if (seen.has(id) && (entry.status === "open" || entry.status === "regressed")) {
925
+ entry.openStreak = (entry.openStreak || 0) + 1;
926
+ if (entry.openStreak >= stuckThreshold) stuckIds.push(id);
927
+ }
928
+ }
929
+
930
+ // 新 ID(reviewer 声明的新发现)→ open。新 ID 首现 openStreak=1:统一判定语义
931
+ // openStreak >= stuckThreshold(与既有条目分支一致)。边界:stuckThreshold=1 时新 ID
932
+ // 首现即 stuck(语义自洽:阈值为 1 表示「任何未解决条目出现即视为卡住」,属显式配置而非 bug)。
933
+ function registerNewFinding(issues, id, round, stuckThreshold, stuckIds) {
934
+ issues[id] = {
935
+ firstSeen: round, severity: "unknown", status: "open", openStreak: 1,
936
+ history: [{ round, status: "open" }], fixAttempts: 0,
937
+ };
938
+ if (issues[id].openStreak >= stuckThreshold) stuckIds.push(id);
939
+ }
940
+
824
941
  function reconcileIssues(prevIssues, { seenIds, escalateIds, fixedIds, round, stuckThreshold }) {
825
942
  const issues = {};
826
943
  const seen = new Set(seenIds || []);
@@ -828,67 +945,20 @@ function reconcileIssues(prevIssues, { seenIds, escalateIds, fixedIds, round, st
828
945
  const fixedDeclared = new Set(fixedIds || []);
829
946
  const stuckIds = [];
830
947
  for (const [id, issue] of Object.entries(prevIssues || {})) {
831
- issues[id] = { ...issue, history: [...(issue.history || [])] };
948
+ const entry = cloneTrackedIssue(issue);
949
+ issues[id] = entry;
832
950
  if (issue.status === "deferred") {
833
- // 5.1-5 显式升级:reconciliation 声明 escalate → 重新 open(保留历史与 fixAttempts),
834
- // 进入修复循环;未升级的 deferred 留 known-remaining,不参与判定。
835
- if (escalated.has(id)) {
836
- issues[id].status = "open";
837
- issues[id].openStreak = 0;
838
- issues[id].history.push({ round, status: "escalated" });
839
- }
840
- continue;
841
- }
842
- // open/regressed + 声明 fixed(verify-first)→ 清账。与"fix result claiming fixed
843
- // is NOT evidence"原则不冲突:这里的 fixed 声明来自 reviewer 亲自读目标后的申报
844
- // (evidence 非空由调用方过滤),正是该原则认可的证据形态——此前它被收集侧
845
- // 整体丢弃,open 条目无消除通道。
846
- if ((issues[id].status === "open" || issues[id].status === "regressed") && fixedDeclared.has(id)) {
847
- issues[id].status = "fixed";
848
- issues[id].openStreak = 0;
849
- issues[id].history.push({ round, status: "fixed", via: "reconciliation" });
951
+ escalateDeferredIssue(entry, id, escalated, round);
850
952
  continue;
851
953
  }
852
- if (issue.status === "fix-attempted") {
853
- if (!seen.has(id)) {
854
- issues[id].status = "fixed";
855
- issues[id].openStreak = 0;
856
- issues[id].history.push({ round, status: "fixed" });
857
- } else {
858
- issues[id].status = "regressed";
859
- // fixAttempts 语义 = 修复失败次数:初始 0,每次 regressed +1(RC-7「经 2 次修复
860
- // 仍未收敛」= 第 2 次 regressed 后触发,修复见 findNeedsRedesign 阈值)。
861
- issues[id].fixAttempts = (issue.fixAttempts || 0) + 1;
862
- issues[id].history.push({ round, status: "regressed" });
863
- }
864
- }
865
- // MF-2: fixed 条目再次被报告(seen)→ 回归:转 regressed + fixAttempts+1(已确认修复
866
- // 的问题复发同样计修复失败,needs-redesign 可达);openStreak 由下方统一 if 累计
867
- // (首轮回归 1)。未 seen → 保持 fixed(漏报不误转)。修复前此处无转换——fixed 条目
868
- // 复发时 fixAttempts/openStreak 均不增长,与收敛终止组合后默认配置下 R3 即以
869
- // converged 提前终止而 must-fix 仍活跃(MF-2)。
870
- if (issue.status === "fixed" && seen.has(id)) {
871
- issues[id].status = "regressed";
872
- issues[id].fixAttempts = (issue.fixAttempts || 0) + 1;
873
- issues[id].history.push({ round, status: "regressed" });
874
- }
875
- // open/regressed 且本轮仍在(seen)→ openStreak +1(跨轮字段);漏报(未 seen)不增长(保守)
876
- if (seen.has(id) && (issues[id].status === "open" || issues[id].status === "regressed")) {
877
- issues[id].openStreak = (issues[id].openStreak || 0) + 1;
878
- if (issues[id].openStreak >= stuckThreshold) stuckIds.push(id);
879
- }
954
+ if (applyReconciledFix(entry, id, fixedDeclared, round)) continue;
955
+ applyFixAttemptedOutcome(entry, issue.status, id, seen, round);
956
+ applyFixedRegression(entry, issue.status, id, seen, round);
957
+ accrueOpenStreak(entry, id, seen, stuckThreshold, stuckIds);
880
958
  }
881
- // 新 ID(reviewer 声明的新发现)→ open
882
959
  for (const id of seen) {
883
960
  if (issues[id]) continue;
884
- issues[id] = {
885
- firstSeen: round, severity: "unknown", status: "open", openStreak: 1,
886
- history: [{ round, status: "open" }], fixAttempts: 0,
887
- };
888
- // 新 ID 首现 openStreak=1:统一判定语义 openStreak >= stuckThreshold(与下方既有
889
- // 条目分支一致)。边界:stuckThreshold=1 时新 ID 首现即 stuck(语义自洽:阈值为 1
890
- // 表示「任何未解决条目出现即视为卡住」,属显式配置而非 bug)。
891
- if (issues[id].openStreak >= stuckThreshold) stuckIds.push(id);
961
+ registerNewFinding(issues, id, round, stuckThreshold, stuckIds);
892
962
  }
893
963
  const knownRemaining = computeKnownRemaining(issues);
894
964
  return { issues, stuck: stuckIds.length > 0, stuckIds, knownRemaining };
@@ -1417,7 +1487,10 @@ const FALLOW_DEF = { name: "fallow-scan", title: "FALLOW STATIC ANALYSIS", repor
1417
1487
  *
1418
1488
  * - def 只含标识(path/name/report/title),**不读文件**——agent 内容的加载与 systemPrompt
1419
1489
  * 注入由主线程 resolveAgentOpts(agent-call 按 path 加载)统一完成
1420
- * - `fallow-scan` 是脚本内部保留字(fallowScan 参数前置插入的首批),非用户参数值域
1490
+ * - `fallow-scan` 是脚本内部保留字(fallowScan 参数前置插入的首批),非用户参数值域:
1491
+ * 本函数对字面值仍静默映射 FALLOW_DEF(fallowScan 前置批与 batchN 兼容形态依赖此
1492
+ * 映射),用户参数侧的拒收在脚本层——fixAgent=fallow-scan 由 review-fix-loop.js
1493
+ * 在调用本函数前 fail-fast(RX2-F2),防 fix 派发静默退化为通用 subagent
1421
1494
  * @param batchNames 批内 agentRef 路径数组
1422
1495
  */
1423
1496
  function resolveAgentDefs(batchNames) {
@@ -0,0 +1,287 @@
1
+ // review-fix-loop-utils.cjs 的消费面类型声明(test-only 类型基建:src/__tests__/
2
+ // review-fix-loop-utils.test.ts 顶层 import 本模块;tsc 纳入测试后需要声明锚点)。
3
+ // 与 .cjs 同名同目录的 .d.cts 会被 TS 自动关联(相对路径导入解析)。
4
+ // 仅声明测试消费的导出——未来消费新导出时在编译期报缺并在此补充。
5
+ // 参数对象字段全可选(cjs 侧对缺省字段有兜底/容忍 undefined 的拼接语义)。
6
+
7
+ /** fail 回调(测试侧实现为抛错终止,签名兼容 (msg: string) => void)。 */
8
+ export type FailFn = (msg: string) => void;
9
+
10
+ /** 评分条目(landScores/backfillFixRegression 的 scores 元素形态)。 */
11
+ export interface ScoreEntry {
12
+ round?: number;
13
+ targetKind?: string;
14
+ targetName?: string;
15
+ batch?: number;
16
+ dimensions: Record<string, unknown>;
17
+ total?: number | null;
18
+ note?: string;
19
+ [key: string]: unknown;
20
+ }
21
+
22
+ /** workflow 跨轮状态(applyCleanRoundBackfill 的 state 形态)。 */
23
+ export interface AgentState {
24
+ issues: Record<string, IssueEntry>;
25
+ knownRemaining: string[];
26
+ scores: ScoreEntry[];
27
+ fixResults?: unknown[];
28
+ dormant?: Array<{ id: string; reason?: string; detail?: string; round?: number; revived?: boolean; [key: string]: unknown }>;
29
+ idMap?: { round?: number; map?: Record<string, string> };
30
+ [key: string]: unknown;
31
+ }
32
+
33
+ /** issue 记录(issues map 值形态,测试按用例裁剪字段)。 */
34
+ export interface IssueEntry {
35
+ id?: string;
36
+ issue_id?: string;
37
+ title?: string;
38
+ status?: string;
39
+ severity?: string;
40
+ description?: string;
41
+ reason?: string;
42
+ fixAttempts?: number;
43
+ openStreak?: number;
44
+ firstSeen?: number;
45
+ history?: Array<{ round?: number; status?: string; [key: string]: unknown }>;
46
+ deferredReason?: string;
47
+ [key: string]: unknown;
48
+ }
49
+
50
+ export declare function parseBatches(args: Record<string, unknown>, fail: FailFn): string[][];
51
+ export declare function resolveBatchNames(
52
+ rawBatchNames: string[] | undefined,
53
+ batches: string[][],
54
+ fail: FailFn,
55
+ ): string[];
56
+ export declare function buildReviewInstruction(targetType: string, target: string): string;
57
+ export declare function lockReviewBase(
58
+ targetType: string,
59
+ target: string,
60
+ run?: (cmd: string) => string,
61
+ ): { base: string; hash: string };
62
+ export declare function buildScopedRecheckPrompt(args: {
63
+ header?: string;
64
+ round?: number;
65
+ max?: number;
66
+ roundDir?: string;
67
+ reportFile?: string;
68
+ modifiedFiles?: string[];
69
+ affectedFiles?: string[];
70
+ aggPath?: string;
71
+ fixResult?: Record<string, unknown> | null;
72
+ aggRound?: number;
73
+ fixRound?: number;
74
+ reviewPrompt?: string;
75
+ reviewInstruction?: string;
76
+ }): string;
77
+ export declare function wrapUntrusted(content: string, tag: string): string;
78
+ export declare function buildFixPrompt(args: {
79
+ header?: string;
80
+ reportContent?: string;
81
+ fixPrompt?: string;
82
+ commitInstr?: string;
83
+ caution?: string[];
84
+ guidance?: Array<{ id?: string; guidance?: string; [key: string]: unknown }>;
85
+ }): string;
86
+ export declare function buildAggregatorPrompt(args: {
87
+ header?: string;
88
+ round?: number;
89
+ max?: number;
90
+ roundDir?: string;
91
+ reviewResults?: unknown;
92
+ prevFixResult?: unknown;
93
+ prevTitles?: unknown;
94
+ }): string;
95
+ export declare function resolveReviewReportPath(
96
+ parsed: { report_content?: string; report_file?: string; [key: string]: unknown },
97
+ roundDir: string,
98
+ reportName: string,
99
+ ): { reportFile?: string; reportContent: string; [key: string]: unknown };
100
+ export declare function normalizeFixResult(raw: unknown): {
101
+ fixed_count: number;
102
+ fixes: Array<{ issue_id: string; description?: string; [key: string]: unknown }>;
103
+ deferred: Array<{ issue_id: string; reason?: string; severity?: string; [key: string]: unknown }>;
104
+ [key: string]: unknown;
105
+ };
106
+ export declare function normIssueId(s: string | null | undefined): string;
107
+ export declare function findIssueKey(
108
+ issues: Record<string, unknown> | null | undefined,
109
+ issueId: string,
110
+ ): string | undefined;
111
+ export declare function hasOpenResidue(issues: Record<string, unknown> | undefined): boolean;
112
+ export declare function normTitle(s: string | undefined): string;
113
+ export declare function matchByTitle(
114
+ title: string,
115
+ issues: Record<string, unknown>,
116
+ dormant: unknown,
117
+ ): { kind: string; id?: string; [key: string]: unknown };
118
+ export declare function nextFreeId(existingIds: string[]): string;
119
+ export declare function resolveIssueIdentity(
120
+ entry: { id?: string; title?: string; [key: string]: unknown },
121
+ ctx: { issues: Record<string, unknown>; dormant: unknown[] },
122
+ ): { kind: string; id: string; [key: string]: unknown };
123
+ export declare function translateId(
124
+ idMap: Record<string, string> | null | undefined,
125
+ id: string,
126
+ issues: Record<string, unknown>,
127
+ ): string;
128
+ export declare function translateReconSets(
129
+ reconSeen: Set<unknown>,
130
+ reconEscalate: Set<unknown>,
131
+ reconFixed: Set<unknown>,
132
+ idMap: Record<string, string>,
133
+ issues: Record<string, unknown>,
134
+ ): { seen: Set<string>; escalate: Set<string>; fixed: Set<string> };
135
+ export declare function validateFixResult(
136
+ result: unknown,
137
+ mustFixIds?: string[],
138
+ trackedIssues?: Record<string, unknown>,
139
+ idMap?: Record<string, string>,
140
+ ): Array<Record<string, unknown>>;
141
+ export declare function reconcileIssues(
142
+ prevIssues: Record<string, unknown>,
143
+ opts: {
144
+ seenIds: Set<string> | string[];
145
+ escalateIds?: Set<string> | string[];
146
+ fixedIds?: Set<string> | string[];
147
+ round: number;
148
+ stuckThreshold: number;
149
+ },
150
+ ): { issues: Record<string, IssueEntry>; stuck: boolean; knownRemaining: string[]; [key: string]: unknown };
151
+ export declare function normalizeReviewResult(raw: unknown): {
152
+ report_file?: string;
153
+ report_content?: string;
154
+ [key: string]: unknown;
155
+ };
156
+ export declare function checkConvergence(opts: {
157
+ prevStreak?: number;
158
+ newFindings?: number;
159
+ newFindingsCritical?: number;
160
+ convergeNewIssues?: number;
161
+ convergeRounds?: number;
162
+ }): { converged: boolean; streak: number; [key: string]: unknown };
163
+ export declare function findNeedsRedesign(
164
+ issues: Record<string, unknown>,
165
+ maxFixAttempts: number,
166
+ ): Array<{ issue_id: string; [key: string]: unknown }>;
167
+ export declare function parseResult(raw: unknown): Record<string, unknown>;
168
+ export declare function normalizeAggregatorResult(raw: unknown): {
169
+ must_fix: number;
170
+ suggestion: number;
171
+ must_fix_ids: Array<{ id?: string; issue_id?: string; severity?: string; [key: string]: unknown }>;
172
+ scores?: ScoreEntry[];
173
+ [key: string]: unknown;
174
+ };
175
+ export declare function parseAggregatedMd(content: string): {
176
+ must_fix: number;
177
+ suggestion: number;
178
+ [key: string]: unknown;
179
+ };
180
+ export declare function resolveRunRoot(opts: {
181
+ runId?: string;
182
+ cwd?: string;
183
+ homeDir?: string;
184
+ tmpDir?: string;
185
+ exec?: (cmd: string) => string;
186
+ mkdir?: (p: string) => void;
187
+ }): { root: string; slug: string; degraded: boolean; [key: string]: unknown };
188
+ export declare function computeOrigin(
189
+ entry: { [key: string]: unknown },
190
+ opts: { lastModifiedFiles?: string[]; fixImpactFiles?: string[] },
191
+ ): { origin: string; evidence?: unknown; [key: string]: unknown };
192
+ export declare function recordDormant(
193
+ dormant: unknown[],
194
+ entries: unknown[],
195
+ round: number,
196
+ excludeIds?: unknown[] | Set<unknown>,
197
+ ): Array<{ id: string; [key: string]: unknown }>;
198
+ export declare function filterActiveIds(
199
+ entries: Array<{ id?: string; adjudication?: string; [key: string]: unknown }>,
200
+ ): string[];
201
+ export declare function filterDormantFromRecon(
202
+ reconSeen: Set<string>,
203
+ reconEscalate: Set<string>,
204
+ dormant: Array<{ id?: string; [key: string]: unknown }>,
205
+ ): { seen: Set<string>; escalate: Set<string> };
206
+ export declare function landScores(
207
+ existingScores?: ScoreEntry[] | null,
208
+ rawScores?: Array<Record<string, unknown> | null> | null,
209
+ batchIndex?: number,
210
+ ): { scores: ScoreEntry[]; landed: number; malformed: number };
211
+ export declare function countMissingFields(entries: unknown[]): {
212
+ active: number;
213
+ missingGuidance: number;
214
+ missingEvidence: number;
215
+ };
216
+ export declare function backfillFixRegression(opts: {
217
+ scores?: ScoreEntry[];
218
+ fixResult?: Record<string, unknown> | null;
219
+ issues?: Record<string, unknown>;
220
+ round?: number;
221
+ batch?: number;
222
+ cleanRound?: boolean;
223
+ mode?: string;
224
+ }): ScoreEntry[];
225
+ export declare function applyCleanRoundBackfill(
226
+ state: Omit<AgentState, "issues"> & { issues: Record<string, unknown> | Record<string, IssueEntry> },
227
+ opts: {
228
+ reconSeen: Set<string> | string[];
229
+ reconEscalate: Set<string> | string[];
230
+ reconFixed?: Set<string> | string[];
231
+ round: number;
232
+ stuckThreshold: number;
233
+ batch?: number;
234
+ },
235
+ ): { state: AgentState; stuck: boolean; [key: string]: unknown };
236
+ export declare function resolveAggregatorModel(raw: string | undefined, fallback: string | string | undefined): string;
237
+ export declare function resolveAgentDefs(batchNames: string[]): Array<Record<string, unknown>>;
238
+ export declare function recordAgentClean(
239
+ state: { agentStatus: Record<string, unknown>; fixCount?: number },
240
+ agentName: string,
241
+ batchIndex: number,
242
+ ): void;
243
+ export declare function recordAgentDirty(
244
+ state: { agentStatus: Record<string, unknown>; fixCount?: number },
245
+ agentName: string,
246
+ mustFix: number,
247
+ batchIndex: number,
248
+ ): void;
249
+ export declare function shouldSkipAgent(status: unknown, fixCount: number, batchIndex: number): boolean;
250
+ export declare function updateStuckState(
251
+ prevMustFix: number,
252
+ stuckCount: number,
253
+ mustFix: number,
254
+ stuckThreshold: number,
255
+ ): { prevMustFix: number; stuckCount: number; [key: string]: unknown };
256
+ export declare function resolveBatchTerminated(
257
+ batchClean: boolean,
258
+ terminated: string | undefined,
259
+ ): string | undefined;
260
+
261
+ export declare const TARGET_TYPES: string[];
262
+ export declare const VALID_ARG_KEYS: Set<string>;
263
+ export declare const ROUND_CONTEXT_MARKER: string;
264
+ export declare function buildR1ReviewPrompt(args: {
265
+ header?: string;
266
+ roundDir?: string;
267
+ reportFile?: string;
268
+ prevBatchesHint?: string;
269
+ reviewPrompt?: string;
270
+ reviewInstruction?: string;
271
+ }): string;
272
+ export declare function buildR2ReviewPrompt(args: {
273
+ header?: string;
274
+ round?: number;
275
+ max?: number;
276
+ roundDir?: string;
277
+ reportFile?: string;
278
+ aggPath?: string;
279
+ fixResult?: Record<string, unknown> | null;
280
+ aggRound?: number;
281
+ fixRound?: number;
282
+ knownRemaining?: string[];
283
+ dormant?: unknown[];
284
+ openIssues?: unknown[];
285
+ reviewPrompt?: string;
286
+ reviewInstruction?: string;
287
+ }): string;
@@ -22,9 +22,10 @@
22
22
  //
23
23
  // 用法:
24
24
  // workflow run review-fix-loop --args targetType=git-diff target=main \
25
- // batch1="/path/reviewer-a.md,/path/reviewer-b.md" autoCommit=true
25
+ // batch1="/path/reviewer-a.md,/path/reviewer-b.md" autoCommit=true(pi 宿主语法)
26
26
  // workflow run review-fix-loop --args targetType=file target=/path/to/doc.md \
27
- // batch1="/path/doc-reviewer.md" autoCommit=false
27
+ // batch1="/path/doc-reviewer.md" autoCommit=false(pi 宿主语法)
28
+ // zsw workflow --workflow review-fix-loop --task "<任务书>" --workdir <绝对路径>(zsw 宿主直参语法;`zsw` 为 CLI 简写,实际执行以 SessionStart 注入段的 node "<绝对路径>/bin/zsw.js" 形态为准;per-workflow 参数用 zsw 专属 flag --target-type/--target/--batch1 等,语义见 @pi-meta parameters)
28
29
  //
29
30
  // S4 路径统一:batch1..batchN/fixAgent 值 = agentRef(.md 绝对路径,<available_subagents> 的
30
31
  // <location>);fallowScan=true 独立参数前置插入静态分析批次(不占 batchN)。
@@ -75,7 +76,8 @@ usage: |
75
76
  - batch1..batchN 与 agents 互斥(至少传一个 batchN);值 = agentRef(.md 绝对路径,<available_subagents> 的 <location>)
76
77
  - fixAgent:fix 阶段执行者(agentRef),缺省用通用 subagent + 内联 fixPrompt
77
78
  - fallowScan=true 仅 targetType=git-diff 合法(前置静态分析批次,不占 batchN)
78
- - 示例:workflow run review-fix-loop --args targetType=git-diff target=main batch1="/path/fallow-agent.md,/path/reviewer.md" autoCommit=true
79
+ - 示例(pi 宿主语法):workflow run review-fix-loop --args targetType=git-diff target=main batch1="/path/fallow-agent.md,/path/reviewer.md" autoCommit=true
80
+ - 示例(zsw 宿主直参语法;`zsw` 为 CLI 简写,实际以注入段 node "<绝对路径>/bin/zsw.js" 形态为准):zsw workflow --workflow review-fix-loop --task "<任务书>" --workdir <绝对路径>(per-workflow 参数用 zsw 专属 flag --target-type/--target/--batch1 等,语义见 @pi-meta parameters)
79
81
  */
80
82
 
81
83
  // ── 参数解析 + 白名单校验(fail-fast) ────────────────────────────
@@ -187,11 +189,18 @@ const skipCleanAgents = coerceBool($ARGS.skipCleanAgents, true);
187
189
  // RC-5(fix 后全批全量重审放大 token)在默认场景消失。传 true 启用可选强回归模式:fix 后重派
188
190
  // 全批,clean agent 走限定 prompt(buildScopedRecheckPrompt,只审 modifiedFiles,5.5)。
189
191
  const recheckAfterFix = coerceBool($ARGS.recheckAfterFix, false);
190
- // fixAgent(5.3):值语义同 batchN 的 agent 项(内置名 / agent.md 路径),解析复用
191
- // resolveAgentDefs 白名单与加载逻辑。传入时 fix 阶段用 agent({agent: ...}) 派发(代码场景
192
- // verify 命令写在该 agent.md 内);未传保持现状(通用 subagent + 内联 prompt)。
192
+ // fixAgent(5.3):值 = .md 绝对路径(同 batchN 的 agent 项值域);`fallow-scan`
193
+ // fallowScan 参数的内部保留字,显式拒收(RX2-F2)——resolveAgentDefs 对它会静默映射
194
+ // 为内置工具型 FALLOW_DEF(无 path),fix 派发即退化为通用 subagent + 内联 prompt
195
+ // 与「不属于 fixAgent 值域」相悖,故在解析前 fail-fast。其余合法值解析复用
196
+ // resolveAgentDefs 白名单与加载逻辑:传入时 fix 阶段用 agent({agent: ...}) 派发
197
+ // (代码场景的 verify 命令写在该 agent.md 内);未传保持现状(通用 subagent + 内联 prompt)。
193
198
  const FIX_AGENT_RAW = typeof $ARGS.fixAgent === "string" && $ARGS.fixAgent.trim()
194
199
  ? $ARGS.fixAgent.trim() : undefined;
200
+ if (FIX_AGENT_RAW === "fallow-scan") {
201
+ fail("fixAgent=fallow-scan 是内部保留字:fallow-scan 是 fallowScan 前置批次的内部标记,不属于 fixAgent 值域。" +
202
+ "要跑 fallow 静态分析前置批请用参数 fallowScan=true(需 targetType=git-diff);要指定 fix 执行者请传 agent .md 绝对路径。");
203
+ }
195
204
  const FIX_DEF = FIX_AGENT_RAW ? resolveAgentDefs([FIX_AGENT_RAW])[0] : null;
196
205
  // 5.7 收敛终止参数:maxFixAttempts(needs-redesign 阈值,RC-7)/ convergeNewIssues +
197
206
  // convergeRounds(新发现率收敛阈值)
@@ -1039,7 +1048,9 @@ for (let batchIndex = 1; batchIndex <= BATCHES.length; batchIndex++) {
1039
1048
  const r1IdMap = {};
1040
1049
  for (const entry of agg.must_fix_ids) {
1041
1050
  const id = typeof entry === "string" ? entry : entry && entry.id;
1042
- if (!id || state.issues[id]) continue;
1051
+ // Object.hasOwn:truthy 查表会让原型链键("__proto__"/"toString")误判已登记
1052
+ // 而 continue 跳过真实条目(与 utils findIssueKey 同款加固;id 来自 LLM 产出)。
1053
+ if (!id || Object.hasOwn(state.issues, id)) continue;
1043
1054
  if (!activeIds.has(id)) continue;
1044
1055
  const resolved = resolveIssueIdentity(
1045
1056
  typeof entry === "string" ? { id } : entry,