@zhushanwen/subagent-core 0.4.0 → 0.6.0

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 (309) hide show
  1. package/dist/{chunk-4KN4TTG7.js → chunk-43ONBFZX.js} +1 -1
  2. package/dist/{chunk-X7SZ5HLQ.js → chunk-V3VHZ2VX.js} +20 -27
  3. package/dist/execution/engine/engines/zcode/constants.cjs +29 -41
  4. package/dist/execution/engine/engines/zcode/constants.d.cts +65 -53
  5. package/dist/execution/engine/engines/zcode/constants.d.ts +65 -53
  6. package/dist/execution/engine/engines/zcode/constants.js +17 -27
  7. package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
  8. package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
  9. package/dist/execution/engine/engines/zcode/reader.js +2 -2
  10. package/dist/index.cjs +17100 -14082
  11. package/dist/index.d.cts +5336 -4033
  12. package/dist/index.d.ts +5336 -4033
  13. package/dist/index.js +17020 -14055
  14. package/dist/{types-DpUO16pj.d.cts → types-C3fE3R9x.d.cts} +280 -112
  15. package/dist/{types-DpUO16pj.d.ts → types-C3fE3R9x.d.ts} +280 -112
  16. package/dist.bundle/index.cjs +34933 -0
  17. package/package.json +3 -3
  18. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
  19. package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
  20. package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
  21. package/src/__tests__/m2-append-content-probe.test.ts +0 -1
  22. package/src/__tests__/manifest-store.test.ts +10 -9
  23. package/src/__tests__/record-store-cache.test.ts +0 -2
  24. package/src/__tests__/record-store-index.test.ts +1 -2
  25. package/src/__tests__/review-fix-loop-script.test.ts +4 -2
  26. package/src/__tests__/review-fix-loop-utils.test.ts +10 -10
  27. package/src/__tests__/robustness-low-batch1.test.ts +6 -5
  28. package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
  29. package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
  30. package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
  31. package/src/__tests__/session-runner.test.ts +1 -1
  32. package/src/core/__tests__/host-services.test.ts +2 -2
  33. package/src/core/__tests__/logger.test.ts +1 -1
  34. package/src/core/error-message.ts +9 -0
  35. package/src/core/host-services.ts +21 -5
  36. package/src/core/notify-ports.ts +18 -5
  37. package/src/execution/__tests__/agent-profile.test.ts +4 -4
  38. package/src/execution/__tests__/agent-registry.test.ts +370 -0
  39. package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
  40. package/src/execution/__tests__/agents-assembly.test.ts +2 -2
  41. package/src/execution/__tests__/alive-store.test.ts +1 -1
  42. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
  43. package/src/execution/__tests__/chat-engine-routing.test.ts +68 -33
  44. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +4 -4
  45. package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
  46. package/src/execution/__tests__/collect-budget.test.ts +291 -0
  47. package/src/execution/__tests__/collect-coordinator-service.test.ts +327 -0
  48. package/src/execution/__tests__/collect-coordinator.test.ts +371 -0
  49. package/src/execution/__tests__/collect-mixed-dispatch.test.ts +262 -0
  50. package/src/execution/__tests__/config-collect-sync.test.ts +120 -0
  51. package/src/execution/__tests__/config.test.ts +1 -1
  52. package/src/execution/__tests__/delivery-methods.test.ts +75 -62
  53. package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
  54. package/src/execution/__tests__/descendant-sweep.test.ts +6 -6
  55. package/src/execution/__tests__/dialog-queue.test.ts +2 -2
  56. package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
  57. package/src/execution/__tests__/epipe-fallback.test.ts +29 -24
  58. package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
  59. package/src/execution/__tests__/execute-nesting.test.ts +34 -188
  60. package/src/execution/__tests__/execution-record.test.ts +217 -60
  61. package/src/execution/__tests__/execution-runtime-face.test.ts +5 -5
  62. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +4 -4
  63. package/src/execution/__tests__/finalize-record.test.ts +173 -17
  64. package/src/execution/__tests__/finalized-marker.test.ts +1 -1
  65. package/src/execution/__tests__/gc-timer.test.ts +56 -3
  66. package/src/execution/__tests__/get-record-for-action-restart.test.ts +12 -12
  67. package/src/execution/__tests__/get-state-handshake.test.ts +1 -1
  68. package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
  69. package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
  70. package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
  71. package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
  72. package/src/execution/__tests__/keep-alive-no-progress.test.ts +50 -148
  73. package/src/execution/__tests__/kill-all-escalation.test.ts +2 -2
  74. package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
  75. package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
  76. package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +1 -1
  77. package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +1 -1
  78. package/src/execution/__tests__/model-resolver.test.ts +2 -2
  79. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
  80. package/src/execution/__tests__/nested-visibility.test.ts +2 -0
  81. package/src/execution/__tests__/notify-batch.test.ts +500 -0
  82. package/src/execution/__tests__/notify-ledger.test.ts +1000 -18
  83. package/src/execution/__tests__/output-collector.test.ts +117 -6
  84. package/src/execution/__tests__/pi-invocation.test.ts +36 -4
  85. package/src/execution/__tests__/record-entry-collect.test.ts +102 -0
  86. package/src/execution/__tests__/record-store.test.ts +10 -9
  87. package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
  88. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
  89. package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
  90. package/src/execution/__tests__/relay-env.test.ts +12 -1
  91. package/src/execution/__tests__/rpc-mode.test.ts +2 -2
  92. package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
  93. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +15 -9
  94. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +4 -4
  95. package/src/execution/__tests__/run-spawn-edges.test.ts +17 -15
  96. package/src/execution/__tests__/run-spawn-integration.test.ts +2 -2
  97. package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
  98. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
  99. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +4 -4
  100. package/src/execution/__tests__/service-kill-escalation.test.ts +7 -5
  101. package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
  102. package/src/execution/__tests__/session-file-gc.test.ts +36 -1
  103. package/src/execution/__tests__/session-pending.test.ts +257 -14
  104. package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
  105. package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +1 -1
  106. package/src/execution/__tests__/session-runner-close-prune.test.ts +2 -2
  107. package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
  108. package/src/execution/__tests__/session-runner-epipe.test.ts +3 -3
  109. package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +5 -4
  110. package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
  112. package/src/execution/__tests__/settled-watchdog.test.ts +282 -47
  113. package/src/execution/__tests__/spawn-args.test.ts +11 -10
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +3 -3
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
  117. package/src/execution/__tests__/spawned-children.test.ts +2 -1
  118. package/src/execution/__tests__/start-collect-guard.test.ts +255 -0
  119. package/src/execution/__tests__/start-sync-model-guard.test.ts +5 -5
  120. package/src/execution/__tests__/stdin-writer.test.ts +6 -4
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
  122. package/src/execution/__tests__/subagent-actions-core.test.ts +48 -22
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +29 -26
  124. package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +21 -8
  125. package/src/execution/__tests__/subagent-service-notify-gate.test.ts +27 -22
  126. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +30 -29
  127. package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +45 -20
  128. package/src/execution/__tests__/subagent-service.test.ts +37 -30
  129. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
  130. package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
  131. package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
  132. package/src/execution/__tests__/sync-collect-recovery.test.ts +1117 -0
  133. package/src/execution/__tests__/temp-prompt.test.ts +1 -1
  134. package/src/execution/__tests__/timeout-integration.test.ts +6 -5
  135. package/src/execution/__tests__/tombstone-store.test.ts +1 -1
  136. package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
  137. package/src/execution/__tests__/turn-limiter.test.ts +1 -1
  138. package/src/execution/__tests__/ui-request-handler-factory.test.ts +12 -6
  139. package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
  140. package/src/execution/__tests__/ui-request-queue.test.ts +142 -2
  141. package/src/execution/__tests__/worktree-git-ops.test.ts +1 -1
  142. package/src/execution/__tests__/worktree-manager.test.ts +14 -5
  143. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
  144. package/src/execution/__tests__/worktree-reconcile-aging.test.ts +2 -2
  145. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +1 -1
  146. package/src/execution/__tests__/worktree-registry.test.ts +1 -1
  147. package/src/execution/agent-registry.ts +74 -30
  148. package/src/execution/agent-result-mapper.ts +3 -0
  149. package/src/execution/cold-resurrect.ts +199 -0
  150. package/src/execution/collect-coordinator.ts +200 -0
  151. package/src/execution/config.ts +77 -5
  152. package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
  153. package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
  154. package/src/execution/engine/__tests__/common/event-journal.test.ts +1 -1
  155. package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
  156. package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
  157. package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
  158. package/src/execution/engine/__tests__/common/pool-manager.test.ts +213 -53
  159. package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
  160. package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
  161. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +22 -112
  162. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +15 -28
  163. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +1 -1
  164. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +12 -12
  165. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +2 -2
  166. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +21 -82
  167. package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +4 -7
  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 +4 -2
  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/engines/pi/__tests__/pi-engine.test.ts +174 -28
  181. package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
  182. package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
  183. package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +1 -1
  184. package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
  185. package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
  186. package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
  187. package/src/execution/engine/engines/pi/reader.ts +11 -0
  188. package/src/execution/engine/engines/pi/registration.ts +4 -2
  189. package/src/execution/{session-runner.ts → engine/engines/pi/session-runner.ts} +617 -412
  190. package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
  191. package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
  192. package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
  193. package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
  194. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +54 -27
  195. package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
  196. package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +13 -12
  197. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
  198. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
  199. package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
  200. package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
  201. package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +20 -8
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +77 -110
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +26 -320
  204. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
  207. package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
  208. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +48 -148
  209. package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
  210. package/src/execution/engine/engines/zcode/connection.ts +24 -11
  211. package/src/execution/engine/engines/zcode/constants.ts +75 -71
  212. package/src/execution/engine/engines/zcode/golden-sample.ts +8 -46
  213. package/src/execution/engine/engines/zcode/parser.ts +12 -346
  214. package/src/execution/engine/engines/zcode/preparer.ts +12 -143
  215. package/src/execution/engine/engines/zcode/session-channel.ts +351 -39
  216. package/src/execution/engine/engines/zcode/zcode-engine.ts +665 -760
  217. package/src/execution/engine/host-task-spec.ts +32 -36
  218. package/src/execution/engine/model-validation.ts +177 -0
  219. package/src/execution/engine/port.ts +24 -6
  220. package/src/execution/engine/routing.ts +75 -1
  221. package/src/execution/engine/types.ts +30 -103
  222. package/src/execution/execution-record.ts +229 -144
  223. package/src/execution/finalize-record.ts +141 -99
  224. package/src/execution/idle-gc.ts +28 -0
  225. package/src/execution/lifecycle-predicates.ts +1 -1
  226. package/src/execution/notifier.ts +234 -25
  227. package/src/execution/notify-host.ts +232 -0
  228. package/src/execution/record-entry.ts +16 -0
  229. package/src/execution/record-store.ts +280 -103
  230. package/src/execution/round-settlement.ts +93 -0
  231. package/src/execution/session-file-gc.ts +96 -62
  232. package/src/execution/session-reconstructor.ts +256 -143
  233. package/src/execution/sessions-index.ts +117 -47
  234. package/src/execution/settled-watchdog.ts +264 -52
  235. package/src/execution/subagent-actions-core.ts +84 -28
  236. package/src/execution/subagent-service.ts +1225 -964
  237. package/src/execution/subprocess-agent-runner.ts +144 -97
  238. package/src/execution/sync-rebuild.ts +87 -0
  239. package/src/execution/types.ts +72 -0
  240. package/src/execution/ui-request-handler-factory.ts +102 -74
  241. package/src/execution/ui-request-queue.ts +50 -19
  242. package/src/index.ts +442 -316
  243. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +1 -1
  244. package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
  245. package/src/orchestration/__tests__/args-validator.test.ts +14 -0
  246. package/src/orchestration/__tests__/config-loader.test.ts +1 -1
  247. package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +1 -1
  248. package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +11 -9
  249. package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
  250. package/src/orchestration/__tests__/file-run-store-prune.test.ts +1 -1
  251. package/src/orchestration/__tests__/file-run-store-throttle.test.ts +1 -1
  252. package/src/orchestration/__tests__/file-run-store.test.ts +7 -6
  253. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +2 -2
  254. package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +1 -1
  255. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
  256. package/src/orchestration/__tests__/lifecycle.test.ts +7 -5
  257. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
  258. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +1 -1
  259. package/src/orchestration/__tests__/run-snapshot.test.ts +8 -5
  260. package/src/orchestration/__tests__/script-generate.test.ts +5 -5
  261. package/src/orchestration/__tests__/script-lint.test.ts +17 -0
  262. package/src/orchestration/__tests__/skill-discovery.test.ts +2 -2
  263. package/src/orchestration/__tests__/test-mocks.ts +2 -0
  264. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
  265. package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
  266. package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +27 -19
  267. package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
  268. package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
  269. package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
  270. package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +1 -1
  271. package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
  272. package/src/orchestration/__tests__/workflow-files.test.ts +10 -10
  273. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
  274. package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +1 -1
  275. package/src/orchestration/agent-opts-resolver.ts +1 -1
  276. package/src/orchestration/args-validator.ts +53 -31
  277. package/src/orchestration/execute-agent-call.ts +19 -73
  278. package/src/orchestration/launcher.ts +128 -81
  279. package/src/orchestration/lifecycle.ts +43 -45
  280. package/src/orchestration/models/ports.ts +4 -4
  281. package/src/orchestration/models/run-runtime.ts +2 -2
  282. package/src/orchestration/models/trace.ts +1 -1
  283. package/src/orchestration/models/types.ts +111 -22
  284. package/src/orchestration/models/workflow-run.ts +1 -1
  285. package/src/orchestration/script-lint.ts +91 -58
  286. package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +157 -150
  287. package/src/shared/__tests__/atomic-write.test.ts +1 -1
  288. package/src/shared/__tests__/meta-parser.test.ts +151 -0
  289. package/src/shared/__tests__/resource-discovery-host-roots.test.ts +5 -5
  290. package/src/shared/__tests__/resource-discovery.test.ts +258 -215
  291. package/src/shared/atomic-write.ts +12 -9
  292. package/src/shared/meta-parser.ts +158 -84
  293. package/src/shared/model-ref.ts +15 -2
  294. package/src/shared/resource-discovery.ts +9 -183
  295. package/src/shared/schema-jsonify.ts +1 -1
  296. package/workflows/review-fix-loop-utils.cjs +151 -89
  297. package/workflows/review-fix-loop-utils.d.cts +287 -0
  298. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  299. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  300. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  301. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  302. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  303. package/src/execution/engine/engines/zcode/__tests__/preparer-appserver.test.ts +0 -387
  304. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -710
  305. package/src/execution/engine/engines/zcode/appserver-home.ts +0 -442
  306. package/src/execution/engine/engines/zcode/appserver-probe.ts +0 -141
  307. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  308. package/src/execution/execute-options-mapper.ts +0 -115
  309. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * 原子写原语(sink 设计 U6a / B6):tmp+rename 的单一实现。
3
3
  *
4
- * 背景:core 内部散布 6-7 份 tmp+rename 写点(manifest-store / sessions-index /
4
+ * 背景:core 内部曾散布 6-7 份 tmp+rename 写点(manifest-store / sessions-index /
5
5
  * worktree-registry / engine-discovery / zcode preparer / zcode appserver-home),
6
6
  * tmp 命名各异(`.tmp.<pid>` / `.tmp_<pid>_<rand>` / `.tmp-<pid>-<ts>`)、失败路径
7
7
  * 清理纪律不齐(worktree-registry 失败时漏清残留 tmp)。本模块给出统一原语供全
8
- * 部写点收敛(调用点迁移归 u-wire 单元,本单元只建原语)。
8
+ * 部写点收敛(调用点迁移归 u-wire 单元,本单元只建原语)。现存消费方 4 处:
9
+ * manifest-store / sessions-index / worktree-registry / engine-discovery——zcode
10
+ * preparer 与 zcode appserver-home 两处写点已随 2026-09 共享宿主 HOME 重构删除。
9
11
  *
10
12
  * **统一 tmp 命名约定**:`<最终路径>.tmp.<pid>.<seq>-<rand>`。
11
13
  * - `.tmp.` 标记向后兼容 manifest-store 既有扫描(`x.json` 的 tmp 名为
@@ -21,8 +23,8 @@
21
23
  *
22
24
  * **两种耐久档位**(对齐现存两族写点的生产模式):
23
25
  * - sync(writeAtomicFileSync):writeFileSync + renameSync,无 fsync——对齐
24
- * worktree-registry / engine-discovery / zcode preparer / appserver-home 四处
25
- * 同步写点现状(prep/注册表类,进程崩溃窗口可容忍);
26
+ * worktree-registry / engine-discovery 两处同步写点现状(注册表/发现缓存类,
27
+ * 进程崩溃窗口可容忍);
26
28
  * - async(writeAtomicFile):fsync 文件 → rename → 尽力 fsync 目录——对齐
27
29
  * manifest-store / sessions-index 的生产耐久模式(掉电也不丢已确认写入)。
28
30
  */
@@ -32,6 +34,7 @@ import * as fsPromises from "node:fs/promises";
32
34
  import * as path from "node:path";
33
35
 
34
36
  import { getLogger } from "../core/logger.ts";
37
+ import { toErrorMessage } from "../core/error-message.ts";
35
38
 
36
39
  const logger = getLogger("subagents");
37
40
 
@@ -111,7 +114,7 @@ function removeTmpBestEffortSync(tmpPath: string): void {
111
114
  } catch (cleanupErr) {
112
115
  // tmp 可能已被 rename 消费或从未创建;原错误由调用方上抛
113
116
  logger.debug("[subagent-core] atomic-write cleanup tmp failed", {
114
- detail: cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr),
117
+ detail: toErrorMessage(cleanupErr),
115
118
  tmpPath,
116
119
  });
117
120
  }
@@ -188,7 +191,7 @@ export async function writeAtomicFile(
188
191
  }
189
192
  } catch (dirSyncErr) {
190
193
  logger.debug("[subagent-core] atomic-write fsync dir failed", {
191
- detail: dirSyncErr instanceof Error ? dirSyncErr.message : String(dirSyncErr),
194
+ detail: toErrorMessage(dirSyncErr),
192
195
  dirPath,
193
196
  });
194
197
  }
@@ -200,7 +203,7 @@ export async function writeAtomicFile(
200
203
  await fsPromises.unlink(tmpPath);
201
204
  } catch (cleanupErr) {
202
205
  logger.debug("[subagent-core] atomic-write cleanup tmp failed", {
203
- detail: cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr),
206
+ detail: toErrorMessage(cleanupErr),
204
207
  tmpPath,
205
208
  });
206
209
  }
@@ -293,7 +296,7 @@ export function cleanupStaleTmpFiles(
293
296
  continue;
294
297
  }
295
298
  logger.debug("[subagent-core] cleanupStaleTmpFiles stat failed", {
296
- detail: statErr instanceof Error ? statErr.message : String(statErr),
299
+ detail: toErrorMessage(statErr),
297
300
  tmpPath: ref.tmpPath,
298
301
  });
299
302
  result.failed.push(ref.tmpPath);
@@ -309,7 +312,7 @@ export function cleanupStaleTmpFiles(
309
312
  result.removed.push(ref.tmpPath);
310
313
  } else {
311
314
  logger.debug("[subagent-core] cleanupStaleTmpFiles unlink failed", {
312
- detail: unlinkErr instanceof Error ? unlinkErr.message : String(unlinkErr),
315
+ detail: toErrorMessage(unlinkErr),
313
316
  tmpPath: ref.tmpPath,
314
317
  });
315
318
  result.failed.push(ref.tmpPath);
@@ -75,6 +75,10 @@ function isPlainObject(v: unknown): v is Record<string, unknown> {
75
75
  * 把 parseYaml 结果(unknown)校验为类型化 ResourceMeta,失败返 null(语义非法,非语法错)。
76
76
  * 严格化(exec-review minor-2..5):kind 专属字段不可串类、description 必填、
77
77
  * phase detail 非字符串/parameters 非对象均 reject(消除「静默丢弃非法字段」)。
78
+ *
79
+ * 结构(行为保持提取,主函数只留公共校验 + kind 分派;各分支校验顺序不可调换):
80
+ * workflow → typecheckWorkflowMeta(串类 → phases → parameters);
81
+ * agent → typecheckAgentMeta(串类 → examples → tools → model/engine → maxTurns → disallowedTools → skills)。
78
82
  */
79
83
  function typecheckMeta(raw: unknown, kind: ResourceKind): ResourceMeta | null {
80
84
  if (!isPlainObject(raw)) return null;
@@ -87,99 +91,140 @@ function typecheckMeta(raw: unknown, kind: ResourceKind): ResourceMeta | null {
87
91
  const notFor = isString(o.notFor) ? o.notFor : undefined;
88
92
 
89
93
  if (kind === "workflow") {
90
- // minor-2:agent 专属字段不可出现在 workflow(串类 reject)
91
- if (
92
- o.examples !== undefined || o.tools !== undefined || o.model !== undefined
93
- || o.engine !== undefined || o.maxTurns !== undefined
94
- || o.disallowedTools !== undefined || o.skills !== undefined
95
- ) {
96
- return null;
97
- }
98
- // phases 必填数组,元素为 string | {title:string, detail?:string}
99
- if (!Array.isArray(o.phases)) return null;
100
- const phases: WorkflowMeta["phases"] = [];
101
- for (const p of o.phases) {
102
- if (isString(p)) {
103
- phases.push(p);
104
- } else if (isPlainObject(p) && isNonEmptyString(p.title)) {
105
- // minor-4:detail 存在但非字符串 → reject(不再静默丢弃)
106
- if (p.detail !== undefined && !isString(p.detail)) return null;
107
- phases.push(isString(p.detail) ? { title: p.title, detail: p.detail } : { title: p.title });
108
- } else {
109
- return null;
110
- }
111
- }
112
- // minor-5:parameters 存在但非 plain object → reject(不再静默当 undefined)
113
- const parameters = o.parameters;
114
- if (parameters !== undefined && !isPlainObject(parameters)) return null;
115
- const usage = isString(o.usage) ? o.usage : undefined;
116
-
117
- const meta: WorkflowMeta = {
118
- kind: "workflow",
119
- name: o.name,
120
- description: o.description,
121
- phases,
122
- ...(parameters !== undefined ? { parameters: parameters as Record<string, unknown> } : {}),
123
- ...(usage !== undefined ? { usage } : {}),
124
- ...(when !== undefined ? { when } : {}),
125
- ...(notFor !== undefined ? { notFor } : {}),
126
- };
127
- return meta;
94
+ return typecheckWorkflowMeta(o, o.name, o.description, when, notFor);
128
95
  }
96
+ return typecheckAgentMeta(o, o.name, o.description, when, notFor);
97
+ }
129
98
 
130
- // kind === "agent"
131
- // minor-2:workflow 专属字段不可出现在 agent(串类 reject)
132
- if (o.phases !== undefined || o.parameters !== undefined || o.usage !== undefined) return null;
133
- let examples: RoutingExample[] | undefined;
134
- if (o.examples !== undefined) {
135
- if (!Array.isArray(o.examples)) return null;
136
- const exs: RoutingExample[] = [];
137
- for (const e of o.examples) {
138
- if (
139
- isPlainObject(e) &&
140
- isString(e.match) &&
141
- isString(e.action) &&
142
- typeof e.positive === "boolean"
143
- ) {
144
- exs.push({ match: e.match, action: e.action, positive: e.positive });
145
- } else {
146
- return null;
147
- }
99
+ /** minor-2 串类守卫(workflow 分支):agent 专属字段任一出现 → reject。 */
100
+ function hasAgentOnlyFields(o: Record<string, unknown>): boolean {
101
+ return (
102
+ o.examples !== undefined || o.tools !== undefined || o.model !== undefined
103
+ || o.engine !== undefined || o.maxTurns !== undefined
104
+ || o.disallowedTools !== undefined || o.skills !== undefined
105
+ );
106
+ }
107
+
108
+ /** minor-2 串类守卫(agent 分支):workflow 专属字段任一出现 → reject。 */
109
+ function hasWorkflowOnlyFields(o: Record<string, unknown>): boolean {
110
+ return o.phases !== undefined || o.parameters !== undefined || o.usage !== undefined;
111
+ }
112
+
113
+ /**
114
+ * phases 元素校验(string | {title:string, detail?:string}):合法元素逐个投影,
115
+ * 任一非法 → null
116
+ * minor-4:detail 存在但非字符串 → reject(不再静默丢弃)。
117
+ */
118
+ function typecheckPhases(rawPhases: unknown[]): WorkflowMeta["phases"] | null {
119
+ const phases: WorkflowMeta["phases"] = [];
120
+ for (const p of rawPhases) {
121
+ if (isString(p)) {
122
+ phases.push(p);
123
+ } else if (isPlainObject(p) && isNonEmptyString(p.title)) {
124
+ if (p.detail !== undefined && !isString(p.detail)) return null;
125
+ phases.push(isString(p.detail) ? { title: p.title, detail: p.detail } : { title: p.title });
126
+ } else {
127
+ return null;
148
128
  }
149
- examples = exs;
150
129
  }
151
- let tools: string[] | undefined;
152
- if (o.tools !== undefined) {
153
- if (Array.isArray(o.tools)) {
154
- if (!o.tools.every(isString)) return null;
155
- tools = o.tools as string[];
156
- } else if (isString(o.tools)) {
157
- // 兼容 agent .md 的逗号分隔字符串约定(如 `tools: read, bash, grep`)
158
- const parts = o.tools.split(",").map((s) => s.trim()).filter(Boolean);
159
- tools = parts.length > 0 ? parts : undefined;
130
+ return phases;
131
+ }
132
+
133
+ /** workflow meta 组装(校验全过后的纯投影——可选字段缺席不进键)。 */
134
+ function buildWorkflowMeta(
135
+ name: string,
136
+ description: string,
137
+ phases: WorkflowMeta["phases"],
138
+ parameters: Record<string, unknown> | undefined,
139
+ usage: string | undefined,
140
+ when: string | undefined,
141
+ notFor: string | undefined,
142
+ ): WorkflowMeta {
143
+ return {
144
+ kind: "workflow",
145
+ name,
146
+ description,
147
+ phases,
148
+ ...(parameters !== undefined ? { parameters } : {}),
149
+ ...(usage !== undefined ? { usage } : {}),
150
+ ...(when !== undefined ? { when } : {}),
151
+ ...(notFor !== undefined ? { notFor } : {}),
152
+ };
153
+ }
154
+
155
+ /** workflow 分支校验(顺序 = 串类 → phases → parameters;usage 宽容投影)。 */
156
+ function typecheckWorkflowMeta(
157
+ o: Record<string, unknown>,
158
+ name: string,
159
+ description: string,
160
+ when: string | undefined,
161
+ notFor: string | undefined,
162
+ ): WorkflowMeta | null {
163
+ // minor-2:agent 专属字段不可出现在 workflow(串类 reject)
164
+ if (hasAgentOnlyFields(o)) return null;
165
+ // phases 必填数组,元素为 string | {title:string, detail?:string}
166
+ const rawPhases = o.phases;
167
+ if (!Array.isArray(rawPhases)) return null;
168
+ const phases = typecheckPhases(rawPhases);
169
+ if (phases === null) return null;
170
+ // minor-5:parameters 存在但非 plain object → reject(不再静默当 undefined)
171
+ const parameters = o.parameters;
172
+ if (parameters !== undefined && !isPlainObject(parameters)) return null;
173
+ const usage = isString(o.usage) ? o.usage : undefined;
174
+ return buildWorkflowMeta(name, description, phases, parameters, usage, when, notFor);
175
+ }
176
+
177
+ /**
178
+ * examples 校验三态:undefined → 缺席(不进 meta);非数组 → null;
179
+ * 元素须为 {match: string, action: string, positive: boolean},任一非法 → null。
180
+ */
181
+ function typecheckExamples(raw: unknown): RoutingExample[] | null | undefined {
182
+ if (raw === undefined) return undefined;
183
+ if (!Array.isArray(raw)) return null;
184
+ const exs: RoutingExample[] = [];
185
+ for (const e of raw) {
186
+ if (
187
+ isPlainObject(e) &&
188
+ isString(e.match) &&
189
+ isString(e.action) &&
190
+ typeof e.positive === "boolean"
191
+ ) {
192
+ exs.push({ match: e.match, action: e.action, positive: e.positive });
160
193
  } else {
161
194
  return null;
162
195
  }
163
196
  }
164
- const model = isString(o.model) ? o.model : undefined;
165
- const engine = isString(o.engine) ? o.engine : undefined;
166
- // D3 可选执行字段(maxTurns/disallowedTools/skills):与 tools 同风格投影
167
- // (空数组 [] 同 tools 保留键——列表字段族空列表语义一致)。严格层对非法类型
168
- // reject(minor-2..5 既有精神:不静默丢弃非法字段)——宽容降级是
169
- // parseAgentProfile(agent-registry)的职责,不在本严格层。
170
- if (o.maxTurns !== undefined && (typeof o.maxTurns !== "number" || !Number.isFinite(o.maxTurns))) {
171
- return null;
172
- }
173
- const maxTurns = typeof o.maxTurns === "number" ? o.maxTurns : undefined;
174
- const disallowedTools = parseStringListField(o.disallowedTools);
175
- if (disallowedTools === null) return null;
176
- const skills = parseStringListField(o.skills);
177
- if (skills === null) return null;
197
+ return exs;
198
+ }
199
+
200
+ /**
201
+ * maxTurns 校验三态:undefined → 缺席;非 number 或非有限值(NaN/Infinity)→ null;
202
+ * 合法 number 原样投影。
203
+ */
204
+ function typecheckMaxTurns(raw: unknown): number | null | undefined {
205
+ if (raw === undefined) return undefined;
206
+ if (typeof raw !== "number" || !Number.isFinite(raw)) return null;
207
+ return raw;
208
+ }
178
209
 
179
- const meta: AgentMeta = {
210
+ /** agent meta 组装(校验全过后的纯投影——可选字段缺席不进键)。 */
211
+ function buildAgentMeta(
212
+ name: string,
213
+ description: string,
214
+ examples: RoutingExample[] | undefined,
215
+ tools: string[] | undefined,
216
+ model: string | undefined,
217
+ engine: string | undefined,
218
+ maxTurns: number | undefined,
219
+ disallowedTools: string[] | undefined,
220
+ skills: string[] | undefined,
221
+ when: string | undefined,
222
+ notFor: string | undefined,
223
+ ): AgentMeta {
224
+ return {
180
225
  kind: "agent",
181
- name: o.name,
182
- description: o.description,
226
+ name,
227
+ description,
183
228
  ...(examples !== undefined ? { examples } : {}),
184
229
  ...(tools !== undefined ? { tools } : {}),
185
230
  ...(model !== undefined ? { model } : {}),
@@ -190,7 +235,36 @@ function typecheckMeta(raw: unknown, kind: ResourceKind): ResourceMeta | null {
190
235
  ...(when !== undefined ? { when } : {}),
191
236
  ...(notFor !== undefined ? { notFor } : {}),
192
237
  };
193
- return meta;
238
+ }
239
+
240
+ /** agent 分支校验(顺序 = 串类 → examples → tools → model/engine → maxTurns → disallowedTools → skills)。 */
241
+ function typecheckAgentMeta(
242
+ o: Record<string, unknown>,
243
+ name: string,
244
+ description: string,
245
+ when: string | undefined,
246
+ notFor: string | undefined,
247
+ ): AgentMeta | null {
248
+ // minor-2:workflow 专属字段不可出现在 agent(串类 reject)
249
+ if (hasWorkflowOnlyFields(o)) return null;
250
+ const examples = typecheckExamples(o.examples);
251
+ if (examples === null) return null;
252
+ // tools 三态经 parseStringListField(数组逐元素 string / 逗号分隔字符串 / 非法形态 → null)
253
+ const tools = parseStringListField(o.tools);
254
+ if (tools === null) return null;
255
+ const model = isString(o.model) ? o.model : undefined;
256
+ const engine = isString(o.engine) ? o.engine : undefined;
257
+ // D3 可选执行字段(maxTurns/disallowedTools/skills):与 tools 同风格投影
258
+ // (空数组 [] 同 tools 保留键——列表字段族空列表语义一致)。严格层对非法类型
259
+ // reject(minor-2..5 既有精神:不静默丢弃非法字段)——宽容降级是
260
+ // parseAgentProfile(agent-registry)的职责,不在本严格层。
261
+ const maxTurns = typecheckMaxTurns(o.maxTurns);
262
+ if (maxTurns === null) return null;
263
+ const disallowedTools = parseStringListField(o.disallowedTools);
264
+ if (disallowedTools === null) return null;
265
+ const skills = parseStringListField(o.skills);
266
+ if (skills === null) return null;
267
+ return buildAgentMeta(name, description, examples, tools, model, engine, maxTurns, disallowedTools, skills, when, notFor);
194
268
  }
195
269
 
196
270
  /**
@@ -188,6 +188,16 @@ function findSimilarSuggestions(
188
188
  .slice(0, MODEL_LIST_LIMIT);
189
189
  }
190
190
 
191
+ /**
192
+ * [u-h2 D2-4] notFoundError 的结构化标记:编排层(pi 未命中跨引擎反查)据此区分
193
+ * 「pi registry 未命中」与孪生歧义/auth 等其他裁决失败——只有未命中形态做反查。
194
+ */
195
+ interface NotFoundMarker {
196
+ refNotFound: true;
197
+ /** 裁决的原始输入串(strip thinking 后缀前的原样值),跨引擎反查的匹配源。 */
198
+ refInput: string;
199
+ }
200
+
191
201
  /** 规则⑤未命中错误:问句候选 + 合法串全集(无候选时)+ 继承指引。 */
192
202
  function notFoundError(
193
203
  input: string,
@@ -195,7 +205,7 @@ function notFoundError(
195
205
  provider: string,
196
206
  id: string,
197
207
  source: ModelRefSource,
198
- ): Error {
208
+ ): Error & NotFoundMarker {
199
209
  const lines = [
200
210
  `Model "${input}"${prefix} is not a registry entry. ` +
201
211
  `Registry match is case-sensitive — the string must equal a registry entry exactly, including letter case.`,
@@ -230,7 +240,10 @@ function notFoundError(
230
240
  }
231
241
 
232
242
  lines.push(`Or omit the \`model\` param to inherit the main agent model.`);
233
- return new Error(lines.join("\n"));
243
+ const err = new Error(lines.join("\n")) as Error & NotFoundMarker;
244
+ err.refNotFound = true;
245
+ err.refInput = input;
246
+ return err;
234
247
  }
235
248
 
236
249
  // ============================================================
@@ -132,8 +132,8 @@ function isDirectChildOfWorkspaceRoot(dir: string, workspaceRoot: string): boole
132
132
  // ── 统一 mtime 缓存层(m5 IF10)────────────────────────────────────
133
133
  //
134
134
  // 模块级 Map<path, { mtimeMs, content }>:mtime 判变缓存文件内容。
135
- // - sync 实现(statSync/readFileSync):agent-registry discoverAll 是同步路径,
136
- // async 缓存无法被 await(m5 design-review A1 探针实证约束)
135
+ // - sync 实现(statSync/readFileSync):getCachedFile 同步返回,供 async 发现流程
136
+ // agent-registry loadByPath 在流程内同步读缓存
137
137
  // - stat 失败/ENOENT → 驱逐条目(mtime 缓存下文件删除不自愈——A3 修复)
138
138
  // - 已知局限(C3 记录):内容变 mtime 未变(cp -p/rsync -t 保留源 mtime、
139
139
  // 2s 粒度文件系统)→ 漏判,invalidateCache/clearFileCache 兜底;
@@ -383,7 +383,7 @@ async function scanDirectory(dirPath: string, kind: ResourceKind): Promise<strin
383
383
  /**
384
384
  * 读取 package.json 的 pi.{kind} manifest(pi.agents / pi.workflows)。
385
385
  * 返回 undefined 表示无 manifest 声明(无 pi / pi[kind] 非数组 / 解析失败)。
386
- * 内部走 manifestCache(与 readPackageManifestSync 共享同一 Map,失败语义见声明处)。
386
+ * 内部走 manifestCache(失败语义见声明处)。
387
387
  */
388
388
  async function readPackageManifest(pkgDir: string, kind: ResourceKind): Promise<string[] | undefined> {
389
389
  const pkgJsonPath = resolve(pkgDir, "package.json");
@@ -477,9 +477,9 @@ async function scanNpmDir(
477
477
  }
478
478
 
479
479
  // [perf] 包级并行(swf-perf-impl cleanup TC2/IF2):entries.map + Promise.all,
480
- // perEntry.flat() 按原 readdir 序 concat——输出序与串行逐包 push 等价。
480
+ // perEntry.flat() 按原 readdir 序 concat——输出序与 readdir 包序一致。
481
481
  // 不加新增 catch:每包失败面由 processPackage 内部既有 catch 承担,未捕获异常
482
- // 传播语义与串行版一致(Promise.all 整体 reject ↔ 串行版向上抛)。
482
+ // Promise.all 以首个 reject 整体向上抛。
483
483
  const perEntry = await Promise.all(
484
484
  entries.map(async (entry): Promise<DiscoveredResource[]> => {
485
485
  const entryPath = resolve(nodeModulesDir, entry);
@@ -624,7 +624,7 @@ function buildScanTargets(config: ScanConfig): ScanTarget[] {
624
624
  * 原 path,属预期失败不抛。
625
625
  *
626
626
  * Throws on unrecoverable scan errors——未捕获异常向上抛(Promise.all 首个 reject
627
- * 即整体拒绝,与串行版 discoverResourcesSync 的传播语义一致,见实现内 [perf] 注释)。
627
+ * 即整体拒绝,见实现内 [perf] 注释)。
628
628
  * 预期失败不抛:目录不存在/不可读返回空列表,manifest 声明路径缺失以 available=false 返回。
629
629
  *
630
630
  * @returns 去重后的资源列表(按优先级合并,高优先级覆盖低优先级同名)
@@ -634,11 +634,10 @@ export async function discoverResources(config: ScanConfig): Promise<DiscoveredR
634
634
 
635
635
  // [perf] 源级并行(swf-perf-impl cleanup TC2/IF2):targets.map + Promise.all,
636
636
  // Promise.all 对 map 数组保序——allBySource 顺序 = targets 优先级序(低→高),
637
- // 与串行逐源 push 完全一致 → 下方合并去重逻辑零改动、输出逐字节等价。
637
+ // 下方合并去重按该顺序 last-writer-wins。
638
638
  // 不加新增 catch:每源预期失败路径由内部既有 catch 面承担(scanDirectory access
639
- // catch / scanNpmDir readdir catch / processPackage 全链 catch),未捕获异常
640
- // 传播语义与串行版等价(ES2:串行版 target k 抛错中断后续源,并行版全部源已并发
641
- // 启动、以首个 reject 拒绝——两版对调用方同为 discoverResources 抛出,各源只读无副作用)。
639
+ // catch / scanNpmDir readdir catch / processPackage 全链 catch);未捕获异常经
640
+ // Promise.all 以首个 reject 整体向上拒绝(各源只读无副作用)。
642
641
  const allBySource: Array<{ source: ResourceSource; resources: DiscoveredResource[] }> = await Promise.all(
643
642
  targets.map(async (target) => {
644
643
  if (target.source === "npm" || target.source === "npm-dev") {
@@ -727,176 +726,3 @@ export async function discoverResources(config: ScanConfig): Promise<DiscoveredR
727
726
  return Array.from(merged.values());
728
727
  }
729
728
 
730
- /**
731
- * 同步版:扫描单个目录下的资源文件路径。
732
- *
733
- * 消费关系(W2⑤ 漂移修正):当前无非测试调用方——agent-registry 只 import
734
- * getCachedFile(mtime 缓存),不消费 sync 扫描。保留作 async scanDirectory 的
735
- * 对称 API / 测试用;生产 agent/workflow 发现统一走 async discoverResources
736
- * (红线 4:修对生产面)。npm/dev 包内发现仍需 async(scanNpmDir)。
737
- */
738
- export function scanDirectorySync(dirPath: string, kind: ResourceKind): string[] {
739
- try {
740
- fsSync.accessSync(dirPath);
741
- } catch {
742
- return [];
743
- }
744
-
745
- let entries: string[];
746
- try {
747
- entries = fsSync.readdirSync(dirPath);
748
- } catch {
749
- return [];
750
- }
751
-
752
- const files: string[] = [];
753
- for (const entry of entries) {
754
- if (!isTargetFile(entry, kind)) continue;
755
- files.push(resolve(dirPath, entry));
756
- }
757
- return files;
758
- }
759
-
760
- /**
761
- * 同步版:读取 package.json 的 pi.{kind} manifest。
762
- * 当前无非测试调用方(W2⑤ 漂移修正,保留作对称 API/测试用)。与 async 版
763
- * 共享 manifestCache(双读者同一 Map)。
764
- */
765
- export function readPackageManifestSync(pkgDir: string, kind: ResourceKind): string[] | undefined {
766
- const pkgJsonPath = resolve(pkgDir, "package.json");
767
- let mtimeMs: number;
768
- try {
769
- mtimeMs = fsSync.statSync(pkgJsonPath).mtimeMs;
770
- } catch {
771
- // stat 失败:文件不存在/不可 stat → 驱逐条目(对齐 getCachedFile 语义)
772
- manifestCache.delete(pkgJsonPath);
773
- return undefined;
774
- }
775
- const entry = manifestCache.get(pkgJsonPath);
776
- if (entry && entry.mtimeMs === mtimeMs) return piToManifest(entry.pi, kind);
777
- let pi: Record<string, unknown> | undefined;
778
- try {
779
- const content = fsSync.readFileSync(pkgJsonPath, "utf-8");
780
- pi = parsePiField(content);
781
- } catch {
782
- // read 失败或坏 JSON → 不缓存不驱逐已有好条目,下次调用重试
783
- return undefined;
784
- }
785
- manifestCache.set(pkgJsonPath, { mtimeMs, pi });
786
- return piToManifest(pi, kind);
787
- }
788
-
789
- /**
790
- * 同步版:处理单个 npm/dev 包。
791
- * 当前无非测试调用方(W2⑤ 漂移修正,保留作对称 API/测试用)。
792
- */
793
- export function processPackageSync(pkgDir: string, kind: ResourceKind): DiscoveredResource[] {
794
- const manifestPaths = readPackageManifestSync(pkgDir, kind);
795
-
796
- if (manifestPaths && manifestPaths.length > 0) {
797
- const results: DiscoveredResource[] = [];
798
-
799
- for (const relPath of manifestPaths) {
800
- const absPath = resolve(pkgDir, relPath);
801
- let fileStat: fsSync.Stats | null;
802
- try {
803
- fileStat = fsSync.statSync(absPath);
804
- } catch {
805
- fileStat = null;
806
- }
807
- if (!fileStat) {
808
- results.push({ path: absPath, source: "npm", available: false });
809
- continue;
810
- }
811
-
812
- if (fileStat.isDirectory()) {
813
- const files = scanDirectorySync(absPath, kind);
814
- for (const f of files) {
815
- results.push({ path: f, source: "npm", available: true });
816
- }
817
- } else if (fileStat.isFile()) {
818
- results.push({ path: absPath, source: "npm", available: true });
819
- }
820
- }
821
-
822
- return results;
823
- }
824
-
825
- // 无 manifest:扫约定目录
826
- const conventionDir = resolve(pkgDir, kind);
827
- const files = scanDirectorySync(conventionDir, kind);
828
- return files.map((f) => ({ path: f, source: "npm", available: true }));
829
- }
830
-
831
- /**
832
- * 同步版:扫描 npm node_modules 目录。
833
- * 当前无非测试调用方(W2⑤ 漂移修正,保留作对称 API/测试用)。
834
- */
835
- export function scanNpmDirSync(nodeModulesDir: string, kind: ResourceKind): DiscoveredResource[] {
836
- let entries: string[];
837
- try {
838
- entries = fsSync.readdirSync(nodeModulesDir);
839
- } catch {
840
- return [];
841
- }
842
-
843
- const results: DiscoveredResource[] = [];
844
- for (const entry of entries) {
845
- const entryPath = resolve(nodeModulesDir, entry);
846
-
847
- if (entry.startsWith("@")) {
848
- let scopedEntries: string[];
849
- try {
850
- scopedEntries = fsSync.readdirSync(entryPath);
851
- } catch {
852
- continue;
853
- }
854
- for (const scopedPkg of scopedEntries) {
855
- const scopedPkgDir = resolve(entryPath, scopedPkg);
856
- results.push(...processPackageSync(scopedPkgDir, kind));
857
- }
858
- } else {
859
- results.push(...processPackageSync(entryPath, kind));
860
- }
861
- }
862
- return results;
863
- }
864
-
865
- /**
866
- * 同步版:发现所有资源。
867
- *
868
- * 当前无非测试调用方(W2⑤ 漂移修正:agent-registry 只 import getCachedFile,
869
- * 不消费本族;保留作 async discoverResources 的对照实现/测试用——两版输出等价
870
- * 由既有快照用例锁定)。
871
- *
872
- * 与 discoverResources 对应的同步实现,扫描相同的源,同 stem last-writer-wins
873
- * 合并(不含 async 链的 realpath 去重——sync 链无非测试调用方,勿扩面,红线 4)。
874
- */
875
- export function discoverResourcesSync(config: ScanConfig): DiscoveredResource[] {
876
- const targets = buildScanTargets(config);
877
- const all: DiscoveredResource[] = [];
878
-
879
- for (const target of targets) {
880
- if (target.source === "npm" || target.source === "npm-dev") {
881
- const resources = scanNpmDirSync(target.dir, config.kind);
882
- all.push(...resources.map((r) => ({ ...r, source: target.source })));
883
- } else if (target.source === "user-extension-paths") {
884
- // XYZ_EXTENSION_PATHS(dev-link):每个 dir 是单个包目录
885
- const resources = processPackageSync(target.dir, config.kind);
886
- all.push(...resources.map((r) => ({ ...r, source: target.source })));
887
- } else {
888
- const files = scanDirectorySync(target.dir, config.kind);
889
- all.push(...files.map((f) => ({ path: f, source: target.source, available: true })));
890
- }
891
- }
892
-
893
- // 按优先级合并(targets 顺序 = 优先级低→高)
894
- const merged = new Map<string, DiscoveredResource>();
895
- for (const r of all) {
896
- const key = stem(r.path);
897
- if (!r.available && merged.has(key)) continue;
898
- merged.set(key, r);
899
- }
900
-
901
- return Array.from(merged.values());
902
- }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * 同一 schema 对象引用的重复 JSON.stringify 消除:resolver(compact,instruction
5
5
  * 与 schemaEnv 复用同串,formatSchemaInstruction 现居 resolver)在单次 agent call
6
- * 内对同一 schema 对象各 stringify 一次;error-recovery 重试路径再加一次。本
6
+ * 内对同一 schema 对象各 stringify 一次;worker-message-pump 重试路径再加一次。本
7
7
  * helper 用 WeakMap 按对象引用缓存两种格式,命中返回缓存串。
8
8
  *
9
9
  * 返回值与直接 JSON.stringify 逐字节一致(compact = JSON.stringify(x)、