@zhushanwen/subagent-core 0.2.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 (330) hide show
  1. package/README.md +114 -0
  2. package/dist/chunk-3VOERJPJ.js +22 -0
  3. package/dist/chunk-A4IVZWVX.js +31 -0
  4. package/dist/execution/engine/engines/zcode/constants.cjs +54 -0
  5. package/dist/execution/engine/engines/zcode/constants.d.cts +31 -0
  6. package/dist/execution/engine/engines/zcode/constants.d.ts +31 -0
  7. package/dist/execution/engine/engines/zcode/constants.js +22 -0
  8. package/dist/execution/engine/engines/zcode/reader.cjs +276 -0
  9. package/dist/execution/engine/engines/zcode/reader.d.cts +20 -0
  10. package/dist/execution/engine/engines/zcode/reader.d.ts +20 -0
  11. package/dist/execution/engine/engines/zcode/reader.js +239 -0
  12. package/dist/execution/engine/paths.cjs +55 -0
  13. package/dist/execution/engine/paths.d.cts +8 -0
  14. package/dist/execution/engine/paths.d.ts +8 -0
  15. package/dist/execution/engine/paths.js +26 -0
  16. package/dist/execution/relay-env.cjs +62 -0
  17. package/dist/execution/relay-env.d.cts +33 -0
  18. package/dist/execution/relay-env.d.ts +33 -0
  19. package/dist/execution/relay-env.js +20 -0
  20. package/dist/index.cjs +1852 -0
  21. package/dist/index.d.cts +1184 -0
  22. package/dist/index.d.ts +1184 -0
  23. package/dist/index.js +1810 -0
  24. package/dist/types-BxyAidGf.d.cts +875 -0
  25. package/dist/types-BxyAidGf.d.ts +875 -0
  26. package/package.json +99 -0
  27. package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +142 -0
  28. package/src/__tests__/append-system-prompt-assembly.test.ts +242 -0
  29. package/src/__tests__/builtin-workflows-structure.test.ts +180 -0
  30. package/src/__tests__/derive-closed-display-parity.test.ts +93 -0
  31. package/src/__tests__/fr4-get-state-handshake.test.ts +125 -0
  32. package/src/__tests__/fr8-orphan-recovery.test.ts +259 -0
  33. package/src/__tests__/m2-append-content-probe.test.ts +73 -0
  34. package/src/__tests__/manifest-store.test.ts +368 -0
  35. package/src/__tests__/record-store-cache.test.ts +335 -0
  36. package/src/__tests__/record-store-index.test.ts +560 -0
  37. package/src/__tests__/record-store-last-line.test.ts +129 -0
  38. package/src/__tests__/review-fix-loop-script.test.ts +288 -0
  39. package/src/__tests__/review-fix-loop-utils.test.ts +2377 -0
  40. package/src/__tests__/robustness-low-batch1.test.ts +286 -0
  41. package/src/__tests__/robustness-medium-batch1.test.ts +69 -0
  42. package/src/__tests__/robustness-medium-batch2.test.ts +65 -0
  43. package/src/__tests__/robustness-medium-batch3.test.ts +30 -0
  44. package/src/__tests__/robustness-medium-batch4.test.ts +358 -0
  45. package/src/__tests__/session-runner.test.ts +69 -0
  46. package/src/__tests__/smoke.test.ts +9 -0
  47. package/src/__tests__/stream-sink.test.ts +203 -0
  48. package/src/core/__tests__/host-services.test.ts +144 -0
  49. package/src/core/__tests__/logger.test.ts +78 -0
  50. package/src/core/__tests__/notify-ports.test.ts +104 -0
  51. package/src/core/host-services.ts +97 -0
  52. package/src/core/logger.ts +47 -0
  53. package/src/core/notify-ports.ts +126 -0
  54. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +53 -0
  55. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +1 -0
  56. package/src/execution/__tests__/agent-result-mapper.test.ts +150 -0
  57. package/src/execution/__tests__/alive-store.test.ts +147 -0
  58. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +490 -0
  59. package/src/execution/__tests__/channel-registry-handshake.test.ts +242 -0
  60. package/src/execution/__tests__/chat-engine-routing.test.ts +610 -0
  61. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +190 -0
  62. package/src/execution/__tests__/concurrency-pool.test.ts +250 -0
  63. package/src/execution/__tests__/config.test.ts +302 -0
  64. package/src/execution/__tests__/delivery-methods.test.ts +424 -0
  65. package/src/execution/__tests__/dialog-queue.test.ts +299 -0
  66. package/src/execution/__tests__/epipe-fallback.test.ts +241 -0
  67. package/src/execution/__tests__/execute-and-await-worktree.test.ts +243 -0
  68. package/src/execution/__tests__/execute-nesting.test.ts +323 -0
  69. package/src/execution/__tests__/execute-options-mapper.test.ts +200 -0
  70. package/src/execution/__tests__/execution-record.test.ts +1394 -0
  71. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
  72. package/src/execution/__tests__/finalize-record.test.ts +367 -0
  73. package/src/execution/__tests__/finalized-marker.test.ts +104 -0
  74. package/src/execution/__tests__/format-schema-instruction.test.ts +169 -0
  75. package/src/execution/__tests__/gc-timer.test.ts +184 -0
  76. package/src/execution/__tests__/get-record-for-action-restart.test.ts +254 -0
  77. package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
  78. package/src/execution/__tests__/helpers/spawn-mock.ts +242 -0
  79. package/src/execution/__tests__/host-mode.test.ts +87 -0
  80. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +211 -0
  81. package/src/execution/__tests__/lifecycle-manager.test.ts +383 -0
  82. package/src/execution/__tests__/lifecycle-predicates.test.ts +116 -0
  83. package/src/execution/__tests__/manifest-parentid.test.ts +117 -0
  84. package/src/execution/__tests__/model-resolver.test.ts +465 -0
  85. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +287 -0
  86. package/src/execution/__tests__/nested-visibility.test.ts +325 -0
  87. package/src/execution/__tests__/output-collector.test.ts +358 -0
  88. package/src/execution/__tests__/path-encoding.test.ts +104 -0
  89. package/src/execution/__tests__/pi-invocation.test.ts +134 -0
  90. package/src/execution/__tests__/record-store.test.ts +1057 -0
  91. package/src/execution/__tests__/records-cwd-isolation.test.ts +91 -0
  92. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +339 -0
  93. package/src/execution/__tests__/recursive-visibility-env.test.ts +273 -0
  94. package/src/execution/__tests__/relay-env.test.ts +42 -0
  95. package/src/execution/__tests__/resource-policy.test.ts +109 -0
  96. package/src/execution/__tests__/rpc-mode.test.ts +89 -0
  97. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +267 -0
  98. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +253 -0
  99. package/src/execution/__tests__/run-spawn-edges.test.ts +687 -0
  100. package/src/execution/__tests__/run-spawn-integration.test.ts +933 -0
  101. package/src/execution/__tests__/run-spawn-resume.test.ts +322 -0
  102. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +196 -0
  103. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
  104. package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
  105. package/src/execution/__tests__/session-file-gc.test.ts +293 -0
  106. package/src/execution/__tests__/session-reconstructor.test.ts +379 -0
  107. package/src/execution/__tests__/session-runner-epipe.test.ts +178 -0
  108. package/src/execution/__tests__/session-runner-schema-env.test.ts +350 -0
  109. package/src/execution/__tests__/spawn-args.test.ts +445 -0
  110. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +189 -0
  111. package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
  112. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +207 -0
  113. package/src/execution/__tests__/spawned-children.test.ts +92 -0
  114. package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
  115. package/src/execution/__tests__/stdin-writer.test.ts +462 -0
  116. package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
  117. package/src/execution/__tests__/subagent-service-abort.test.ts +60 -0
  118. package/src/execution/__tests__/subagent-service-message-close.test.ts +629 -0
  119. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +180 -0
  120. package/src/execution/__tests__/subagent-service.test.ts +788 -0
  121. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
  122. package/src/execution/__tests__/subprocess-agent-runner.test.ts +612 -0
  123. package/src/execution/__tests__/temp-prompt.test.ts +53 -0
  124. package/src/execution/__tests__/timeout-integration.test.ts +615 -0
  125. package/src/execution/__tests__/tombstone-store.test.ts +73 -0
  126. package/src/execution/__tests__/turn-limiter-semantics.test.ts +194 -0
  127. package/src/execution/__tests__/turn-limiter.test.ts +65 -0
  128. package/src/execution/__tests__/ui-channels.test.ts +187 -0
  129. package/src/execution/__tests__/ui-interaction-model.test.ts +67 -0
  130. package/src/execution/__tests__/ui-request-handler-factory.test.ts +369 -0
  131. package/src/execution/__tests__/ui-request-handler.test.ts +204 -0
  132. package/src/execution/__tests__/ui-request-observability.test.ts +113 -0
  133. package/src/execution/__tests__/ui-request-queue.test.ts +133 -0
  134. package/src/execution/__tests__/worktree-manager.test.ts +633 -0
  135. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +229 -0
  136. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +181 -0
  137. package/src/execution/__tests__/worktree-registry.test.ts +199 -0
  138. package/src/execution/agent-registry.ts +199 -0
  139. package/src/execution/agent-result-mapper.ts +90 -0
  140. package/src/execution/alive-store.ts +119 -0
  141. package/src/execution/argv-mirror.ts +113 -0
  142. package/src/execution/best-effort.ts +38 -0
  143. package/src/execution/channel-registry-access.ts +144 -0
  144. package/src/execution/concurrency-pool.ts +116 -0
  145. package/src/execution/config.ts +165 -0
  146. package/src/execution/dialog-queue.ts +330 -0
  147. package/src/execution/engine/__tests__/common/data-dir.test.ts +78 -0
  148. package/src/execution/engine/__tests__/common/errors.test.ts +132 -0
  149. package/src/execution/engine/__tests__/common/event-journal.test.ts +177 -0
  150. package/src/execution/engine/__tests__/common/kill-chain.test.ts +192 -0
  151. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +81 -0
  152. package/src/execution/engine/__tests__/common/persona-router.test.ts +123 -0
  153. package/src/execution/engine/__tests__/common/pool-manager.test.ts +154 -0
  154. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +128 -0
  155. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +28 -0
  156. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +141 -0
  157. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +109 -0
  158. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +101 -0
  159. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +77 -0
  160. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +104 -0
  161. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +201 -0
  162. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +76 -0
  163. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +79 -0
  164. package/src/execution/engine/__tests__/engine-discovery.test.ts +87 -0
  165. package/src/execution/engine/__tests__/model-prompt.test.ts +197 -0
  166. package/src/execution/engine/__tests__/paths.test.ts +39 -0
  167. package/src/execution/engine/__tests__/registry.test.ts +120 -0
  168. package/src/execution/engine/__tests__/routing.test.ts +231 -0
  169. package/src/execution/engine/common/data-dir.ts +66 -0
  170. package/src/execution/engine/common/errors.ts +183 -0
  171. package/src/execution/engine/common/event-journal.ts +254 -0
  172. package/src/execution/engine/common/journal-replay.ts +62 -0
  173. package/src/execution/engine/common/kill-chain.ts +221 -0
  174. package/src/execution/engine/common/nesting-guard.ts +50 -0
  175. package/src/execution/engine/common/persona-router.ts +108 -0
  176. package/src/execution/engine/common/pool-manager.ts +226 -0
  177. package/src/execution/engine/common/schema-emulation.ts +189 -0
  178. package/src/execution/engine/common/session-view-projection.ts +51 -0
  179. package/src/execution/engine/engine-discovery.ts +65 -0
  180. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +469 -0
  181. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +155 -0
  182. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +164 -0
  183. package/src/execution/engine/engines/pi/pi-engine.ts +415 -0
  184. package/src/execution/engine/engines/pi/reader.ts +48 -0
  185. package/src/execution/engine/engines/pi/registration.ts +35 -0
  186. package/src/execution/engine/engines/pi/task-spec-mapper.ts +100 -0
  187. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +39 -0
  188. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +150 -0
  189. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +246 -0
  190. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +228 -0
  191. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +210 -0
  192. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +71 -0
  193. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +127 -0
  194. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +580 -0
  195. package/src/execution/engine/engines/zcode/constants.ts +43 -0
  196. package/src/execution/engine/engines/zcode/golden-sample.ts +39 -0
  197. package/src/execution/engine/engines/zcode/launcher.ts +161 -0
  198. package/src/execution/engine/engines/zcode/parser.ts +436 -0
  199. package/src/execution/engine/engines/zcode/preparer.ts +363 -0
  200. package/src/execution/engine/engines/zcode/reader.ts +381 -0
  201. package/src/execution/engine/engines/zcode/registration.ts +37 -0
  202. package/src/execution/engine/engines/zcode/zcode-engine.ts +658 -0
  203. package/src/execution/engine/host-task-spec.ts +47 -0
  204. package/src/execution/engine/model-prompt.ts +158 -0
  205. package/src/execution/engine/paths.ts +42 -0
  206. package/src/execution/engine/port.ts +153 -0
  207. package/src/execution/engine/registry.ts +133 -0
  208. package/src/execution/engine/routing.ts +218 -0
  209. package/src/execution/engine/types.ts +309 -0
  210. package/src/execution/execute-options-mapper.ts +115 -0
  211. package/src/execution/execution-record.ts +984 -0
  212. package/src/execution/finalize-record.ts +254 -0
  213. package/src/execution/finalized-marker.ts +70 -0
  214. package/src/execution/get-state-handshake.ts +104 -0
  215. package/src/execution/host-mode.ts +56 -0
  216. package/src/execution/idle-gc.ts +47 -0
  217. package/src/execution/lifecycle-manager.ts +513 -0
  218. package/src/execution/lifecycle-predicates.ts +65 -0
  219. package/src/execution/manifest-store.ts +256 -0
  220. package/src/execution/model-config-service.ts +250 -0
  221. package/src/execution/model-resolver.ts +248 -0
  222. package/src/execution/notifier.ts +372 -0
  223. package/src/execution/notify-ledger.ts +580 -0
  224. package/src/execution/output-collector.ts +228 -0
  225. package/src/execution/path-encoding.ts +60 -0
  226. package/src/execution/pi-invocation.ts +120 -0
  227. package/src/execution/record-entry.ts +132 -0
  228. package/src/execution/record-store.ts +1265 -0
  229. package/src/execution/relay-env.ts +37 -0
  230. package/src/execution/session-context-resolver.ts +64 -0
  231. package/src/execution/session-file-gc.ts +120 -0
  232. package/src/execution/session-pending.ts +170 -0
  233. package/src/execution/session-reconstructor.ts +678 -0
  234. package/src/execution/session-runner.ts +1789 -0
  235. package/src/execution/sessions-index.ts +304 -0
  236. package/src/execution/spawn-event-adapter.ts +363 -0
  237. package/src/execution/stdin-writer.ts +198 -0
  238. package/src/execution/stream-sink.ts +126 -0
  239. package/src/execution/subagent-service.ts +2268 -0
  240. package/src/execution/subprocess-agent-runner.ts +317 -0
  241. package/src/execution/temp-prompt.ts +62 -0
  242. package/src/execution/tombstone-store.ts +72 -0
  243. package/src/execution/turn-limiter.ts +102 -0
  244. package/src/execution/types.ts +1023 -0
  245. package/src/execution/ui-channels.ts +216 -0
  246. package/src/execution/ui-interaction-model.ts +48 -0
  247. package/src/execution/ui-request-handler-factory.ts +243 -0
  248. package/src/execution/ui-request-observability.ts +81 -0
  249. package/src/execution/ui-request-queue.ts +184 -0
  250. package/src/execution/worktree-manager.ts +688 -0
  251. package/src/execution/worktree-registry.ts +279 -0
  252. package/src/index.ts +87 -0
  253. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +349 -0
  254. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +202 -0
  255. package/src/orchestration/__tests__/agent-call-stream.test.ts +152 -0
  256. package/src/orchestration/__tests__/args-validator.test.ts +143 -0
  257. package/src/orchestration/__tests__/config-loader.test.ts +503 -0
  258. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +809 -0
  259. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +404 -0
  260. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +56 -0
  261. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
  262. package/src/orchestration/__tests__/execute-agent-call.test.ts +451 -0
  263. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +600 -0
  264. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +96 -0
  265. package/src/orchestration/__tests__/lifecycle.test.ts +659 -0
  266. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
  267. package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +183 -0
  268. package/src/orchestration/__tests__/script-lint.test.ts +831 -0
  269. package/src/orchestration/__tests__/skill-discovery.test.ts +210 -0
  270. package/src/orchestration/__tests__/test-mocks.ts +197 -0
  271. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
  272. package/src/orchestration/__tests__/worker-host.test.ts +120 -0
  273. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +164 -0
  274. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +563 -0
  275. package/src/orchestration/__tests__/worker-script-builder.test.ts +309 -0
  276. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +129 -0
  277. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +317 -0
  278. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +110 -0
  279. package/src/orchestration/agent-opts-resolver.ts +174 -0
  280. package/src/orchestration/args-validator.ts +127 -0
  281. package/src/orchestration/config-loader.ts +316 -0
  282. package/src/orchestration/error-recovery.ts +1018 -0
  283. package/src/orchestration/execute-agent-call.ts +256 -0
  284. package/src/orchestration/launcher.ts +455 -0
  285. package/src/orchestration/lifecycle.ts +399 -0
  286. package/src/orchestration/models/__tests__/budget.test.ts +307 -0
  287. package/src/orchestration/models/agent-call.ts +83 -0
  288. package/src/orchestration/models/budget.ts +118 -0
  289. package/src/orchestration/models/ports.ts +164 -0
  290. package/src/orchestration/models/run-runtime.ts +104 -0
  291. package/src/orchestration/models/run-spec.ts +83 -0
  292. package/src/orchestration/models/run-state.ts +44 -0
  293. package/src/orchestration/models/trace.ts +183 -0
  294. package/src/orchestration/models/types.ts +301 -0
  295. package/src/orchestration/models/workflow-run.ts +254 -0
  296. package/src/orchestration/models/workflow-script-registry.ts +35 -0
  297. package/src/orchestration/models/workflow-script.ts +117 -0
  298. package/src/orchestration/script-lint.ts +766 -0
  299. package/src/orchestration/skill-discovery.ts +135 -0
  300. package/src/orchestration/worker-handle.ts +115 -0
  301. package/src/orchestration/worker-host.ts +98 -0
  302. package/src/orchestration/worker-script-builder.ts +421 -0
  303. package/src/orchestration/workflow-files.ts +85 -0
  304. package/src/orchestration/workflow-script-registry-impl.ts +133 -0
  305. package/src/shared/__tests__/agent-ref.test.ts +34 -0
  306. package/src/shared/__tests__/meta-parser.test.ts +304 -0
  307. package/src/shared/__tests__/model-ref.test.ts +306 -0
  308. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +288 -0
  309. package/src/shared/__tests__/resource-discovery.test.ts +749 -0
  310. package/src/shared/__tests__/resource-meta.test.ts +51 -0
  311. package/src/shared/__tests__/schema-jsonify.test.ts +81 -0
  312. package/src/shared/__tests__/timer-delay.test.ts +61 -0
  313. package/src/shared/agent-event.ts +13 -0
  314. package/src/shared/agent-ref.ts +57 -0
  315. package/src/shared/meta-parser.ts +261 -0
  316. package/src/shared/model-ref.ts +286 -0
  317. package/src/shared/resource-discovery.ts +835 -0
  318. package/src/shared/resource-meta.ts +65 -0
  319. package/src/shared/schema-env.ts +44 -0
  320. package/src/shared/schema-jsonify.ts +58 -0
  321. package/src/shared/timer-delay.ts +54 -0
  322. package/src/shared/xml-injection.ts +35 -0
  323. package/workflows/README.md +81 -0
  324. package/workflows/_shared/agent-refs.cjs +40 -0
  325. package/workflows/chain.js +137 -0
  326. package/workflows/map-reduce.js +180 -0
  327. package/workflows/parallel.js +154 -0
  328. package/workflows/review-fix-loop-utils.cjs +1542 -0
  329. package/workflows/review-fix-loop.js +1605 -0
  330. package/workflows/scatter-gather.js +184 -0
@@ -0,0 +1,190 @@
1
+ // src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts
2
+ //
3
+ // [V2 决策 2] chatMode 首轮闭环——runSpawn resolve 时机(Step 4a 改动 1)。
4
+ //
5
+ // 改动 1:chatMode agent_settled 时提前 resolve runSpawn 的 exitCode promise(exit code 0),
6
+ // 让 runAndFinalize 拿到首轮 result,进程仍保活(idle timer armed)。非 chatMode 不变
7
+ //(agent_end kill → close resolve)。
8
+ //
9
+ // 本文件验证 resolve 时机(run-spawn-chatmode-settled.test.ts 验证 idle timer + 回调挂载点,
10
+ // 收尾靠 emit close 让 resolve——隐含 agent_settled 不 resolve;本文件显式断言 agent_settled
11
+ // 即 resolve,且进程未 close)。
12
+ //
13
+ // mock 结构与 run-spawn-chatmode-settled.test.ts 一致(FakeChild + session-pending count=0)。
14
+
15
+ import { spawn } from "node:child_process";
16
+ import * as fs from "node:fs";
17
+
18
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
19
+
20
+ vi.mock("node:child_process", async () => {
21
+ const { FakeChild } = await import("./helpers/spawn-mock.ts");
22
+ return {
23
+ spawn: vi.fn(() => new FakeChild()),
24
+ // buildEnvBlock 的 git branch 调用(execFile 异步):默认 err-first 兜底 → catch → branch=""
25
+ execFile: vi.fn(
26
+ (
27
+ _cmd: string,
28
+ _args: readonly string[],
29
+ _opts: unknown,
30
+ cb: (err: Error | null, stdout?: string, stderr?: string) => void,
31
+ ) => cb(new Error("execFile not configured in this test")),
32
+ ),
33
+ };
34
+ });
35
+
36
+ vi.mock("node:fs", async () => {
37
+ const actual = await import("node:fs");
38
+ return {
39
+ default: {
40
+ ...actual,
41
+ mkdirSync: vi.fn(),
42
+ existsSync: vi.fn(() => false),
43
+ appendFileSync: vi.fn(),
44
+ writeFileSync: vi.fn(),
45
+ readdirSync: vi.fn(() => []),
46
+ },
47
+ mkdirSync: vi.fn(),
48
+ existsSync: vi.fn(() => false),
49
+ appendFileSync: vi.fn(),
50
+ writeFileSync: vi.fn(),
51
+ readdirSync: vi.fn(() => []),
52
+ promises: actual.promises,
53
+ };
54
+ });
55
+
56
+ vi.mock("../alive-store.ts", () => ({ writeAliveMarker: vi.fn() }));
57
+
58
+ // chatMode agent_end 早返回(continue),不读 session-pending;统一 count=0 防干扰。
59
+ vi.mock("../session-pending.ts", () => ({
60
+ readActivePendingFromSessionFile: vi.fn(() => ({ count: 0 })),
61
+ }));
62
+
63
+ vi.mock("../temp-prompt.ts", () => ({
64
+ writePromptToTempFile: vi.fn(async (agent: string) => {
65
+ const safeName = agent.replace(/[^\w.-]+/g, "_");
66
+ return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
67
+ }),
68
+ cleanupTempPrompt: vi.fn(async () => {}),
69
+ }));
70
+
71
+ import { runSpawn } from "../session-runner.ts";
72
+ import type { SessionRunnerContext } from "../session-runner.ts";
73
+ import { _resetLifecycleState } from "../lifecycle-manager.ts";
74
+ import { createRecord } from "../execution-record.ts";
75
+ import type { ExecutionRecord } from "../types.ts";
76
+ import {
77
+ emitStdoutLine,
78
+ type FakeChild,
79
+ lastSpawnedChild as lastSpawnedChildOf,
80
+ makeCtx,
81
+ makeOpts,
82
+ makeRecord,
83
+ sessionHeader,
84
+ waitForSpawn as waitForSpawnOf,
85
+ } from "./helpers/spawn-mock.ts";
86
+
87
+ const mockSpawn = vi.mocked(spawn);
88
+
89
+ const lastSpawnedChild = (): FakeChild => lastSpawnedChildOf(mockSpawn);
90
+ const waitForSpawn = (timeoutMs = 1000): Promise<void> => waitForSpawnOf(mockSpawn, timeoutMs);
91
+
92
+ /** 构造 chatMode record(spawn-mock.makeRecord 默认非 chatMode,此处显式开启)。 */
93
+ function makeChatModeRecord(id = "sa-chat"): ExecutionRecord {
94
+ return createRecord(id, {
95
+ agent: "general-purpose",
96
+ model: "test-model",
97
+ mode: "sync",
98
+ task: "chat task",
99
+ slug: "chat",
100
+ startedAt: 1_000_000,
101
+ rootSessionId: "root-session",
102
+ parentRecordId: undefined,
103
+ depth: 0,
104
+ chatMode: true,
105
+ });
106
+ }
107
+
108
+ /** 用 race 探测 promise 是否在指定时间内 settle(resolve 或 reject)。 */
109
+ async function settlesWithin(p: Promise<unknown>, ms: number): Promise<boolean> {
110
+ return Promise.race([
111
+ p.then(
112
+ () => true,
113
+ () => true,
114
+ ),
115
+ new Promise<boolean>((r) => setTimeout(() => r(false), ms)),
116
+ ]);
117
+ }
118
+
119
+ describe("[V2 决策 2] chatMode 首轮闭环:runSpawn resolve 时机(改动 1)", () => {
120
+ beforeEach(() => {
121
+ vi.clearAllMocks();
122
+ _resetLifecycleState();
123
+ });
124
+
125
+ afterEach(() => {
126
+ vi.restoreAllMocks();
127
+ vi.useRealTimers();
128
+ _resetLifecycleState();
129
+ });
130
+
131
+ it("chatMode agent_settled → runSpawn 提前 resolve(不等 close),进程仍保活", async () => {
132
+ const record = makeChatModeRecord("sa-first-resolve");
133
+ const promise = runSpawn(record, "Task: first-round", makeOpts(), makeCtx());
134
+
135
+ await waitForSpawn();
136
+ const child = lastSpawnedChild();
137
+
138
+ emitStdoutLine(child, sessionHeader());
139
+ emitStdoutLine(child, { type: "agent_end", willRetry: false });
140
+ // 让 stdout flush 处理 agent_end(chatMode 分支 continue,不 kill)
141
+ await new Promise((r) => setTimeout(r, 10));
142
+ emitStdoutLine(child, { type: "agent_settled" });
143
+
144
+ // [改动 1 核心] agent_settled 后 runSpawn 立即 resolve(resolveRun(0)),不等 close。
145
+ // 若改动 1 未生效,promise 会 hang 等 close,settlesWithin 返回 false。
146
+ expect(await settlesWithin(promise, 500)).toBe(true);
147
+ const result = await promise;
148
+ expect(result.success).toBe(true);
149
+ expect(result.sessionId).toBe("sess-abc");
150
+
151
+ // 进程仍保活:agent_settled 只 resolve promise,未 kill、未 emit close。
152
+ // idle timer(5min 真实 setTimeout)armed 但未到期。
153
+ expect(child.killed).toBe(false);
154
+
155
+ // 收尾:手动 close(模拟后续 idle timer 超时 kill / 外部终止)。
156
+ // close handler 的 cleanup 仍执行(resolve(code) 是 no-op,Promise 已 resolve)。
157
+ child.stdout.end();
158
+ child.stderr.end();
159
+ child.emit("close", 0);
160
+ });
161
+
162
+ it("非 chatMode runSpawn 仍在 close resolve(agent_settled 不触发 resolve)", async () => {
163
+ // makeRecord 默认非 chatMode
164
+ const record = makeRecord("sa-nonchat-resolve");
165
+ const promise = runSpawn(record, "Task: nonchat", makeOpts(), makeCtx());
166
+
167
+ await waitForSpawn();
168
+ const child = lastSpawnedChild();
169
+
170
+ emitStdoutLine(child, sessionHeader());
171
+ emitStdoutLine(child, { type: "agent_end", willRetry: false });
172
+ // 非 chatMode agent_end → count=0 → SIGTERM kill
173
+ await new Promise((r) => setTimeout(r, 10));
174
+ expect(child.killed).toBe(true);
175
+
176
+ // agent_settled 在非 chatMode 下被忽略(handler 直接 return,不调 resolveRun)
177
+ emitStdoutLine(child, { type: "agent_settled" });
178
+ await new Promise((r) => setTimeout(r, 20));
179
+
180
+ // [回归防护] agent_settled 不 resolve 非 chatMode runSpawn——promise 仍 pending(等 close)。
181
+ expect(await settlesWithin(promise, 200)).toBe(false);
182
+
183
+ // emit close 才 resolve(现有行为,改动 1 不影响非 chatMode)
184
+ child.stdout.end();
185
+ child.stderr.end();
186
+ child.emit("close", 143);
187
+ const result = await promise;
188
+ expect(result.success).toBe(true); // 信号终止(143 ≥ threshold)视为正常完成
189
+ });
190
+ });
@@ -0,0 +1,250 @@
1
+ // src/__tests__/concurrency-pool.test.ts
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import { DefaultConcurrencyPool } from "../concurrency-pool.ts";
5
+
6
+ describe("DefaultConcurrencyPool", () => {
7
+ it("allows up to maxConcurrent concurrent tasks", async () => {
8
+ const pool = new DefaultConcurrencyPool(2);
9
+ await pool.acquire(0);
10
+ await pool.acquire(0);
11
+ // 第三个 acquire 应阻塞
12
+ let thirdAcquired = false;
13
+ const third = pool.acquire(0).then(() => { thirdAcquired = true; });
14
+ await new Promise((r) => setTimeout(r, 5));
15
+ expect(thirdAcquired).toBe(false);
16
+ expect(pool.active).toBe(2);
17
+
18
+ pool.release();
19
+ await third;
20
+ expect(thirdAcquired).toBe(true);
21
+ expect(pool.active).toBe(2);
22
+
23
+ pool.release();
24
+ pool.release();
25
+ await new Promise((r) => setTimeout(r, 5));
26
+ expect(pool.active).toBe(0);
27
+ });
28
+
29
+ it("higher priority acquires the pool first", async () => {
30
+ const pool = new DefaultConcurrencyPool(1);
31
+ await pool.acquire(0); // 占满
32
+
33
+ let lowAcquired = false;
34
+ let highAcquired = false;
35
+ const low = pool.acquire(10).then(() => { lowAcquired = true; });
36
+ const high = pool.acquire(0).then(() => { highAcquired = true; });
37
+
38
+ await new Promise((r) => setTimeout(r, 5));
39
+ pool.release();
40
+ await Promise.race([low, high, new Promise((r) => setTimeout(r, 20))]);
41
+
42
+ expect(highAcquired).toBe(true);
43
+ expect(lowAcquired).toBe(false);
44
+ pool.release();
45
+ });
46
+
47
+ it("same-priority tasks wake in FIFO (seq) order", async () => {
48
+ const pool = new DefaultConcurrencyPool(1);
49
+ await pool.acquire(0); // fill slot
50
+
51
+ const order: number[] = [];
52
+ // Enqueue 3 tasks with same priority — they should resolve in enqueue order
53
+ const p1 = pool.acquire(0).then(() => { order.push(1); pool.release(); });
54
+ const p2 = pool.acquire(0).then(() => { order.push(2); pool.release(); });
55
+ const p3 = pool.acquire(0).then(() => { order.push(3); pool.release(); });
56
+
57
+ pool.release(); // kick off the chain
58
+ await Promise.allSettled([p1, p2, p3]);
59
+
60
+ expect(order).toEqual([1, 2, 3]);
61
+ });
62
+
63
+ it("extra release() does not make active negative", () => {
64
+ const pool = new DefaultConcurrencyPool(2);
65
+ pool.release(); // no acquires yet
66
+ pool.release();
67
+ pool.release();
68
+ expect(pool.active).toBe(0);
69
+ });
70
+
71
+ it("active never exceeds maxConcurrent", async () => {
72
+ const pool = new DefaultConcurrencyPool(2);
73
+ const acquires: Array<Promise<void>> = [];
74
+ let peak = 0;
75
+ for (let i = 0; i < 6; i++) {
76
+ acquires.push(pool.acquire(0).then(() => {
77
+ peak = Math.max(peak, pool.active);
78
+ }));
79
+ }
80
+ // Drain: release one at a time so we can observe peak
81
+ for (let i = 0; i < 6; i++) {
82
+ pool.release();
83
+ await new Promise((r) => setTimeout(r, 2));
84
+ }
85
+ await Promise.allSettled(acquires);
86
+ expect(peak).toBeLessThanOrEqual(2);
87
+ });
88
+
89
+ it("clamps maxConcurrent=0 to 1 (no deadlock, C3 fix)", async () => {
90
+ const pool = new DefaultConcurrencyPool(0);
91
+ // 不会死锁——clamp 到 1,acquire 立即返回
92
+ await pool.acquire(0);
93
+ expect(pool.active).toBe(1);
94
+ pool.release();
95
+ expect(pool.active).toBe(0);
96
+ });
97
+
98
+ it("clamps negative maxConcurrent to 1", async () => {
99
+ const pool = new DefaultConcurrencyPool(-5);
100
+ await pool.acquire(0);
101
+ expect(pool.active).toBe(1);
102
+ });
103
+
104
+ it("priority 0 (sync) preempts priority 1000 (background)", async () => {
105
+ const pool = new DefaultConcurrencyPool(1);
106
+ await pool.acquire(1000); // background 占满
107
+
108
+ let bgAcquired = false;
109
+ let syncAcquired = false;
110
+ const bg = pool.acquire(1000).then(() => { bgAcquired = true; });
111
+ const sync = pool.acquire(0).then(() => { syncAcquired = true; });
112
+
113
+ await new Promise((r) => setTimeout(r, 5));
114
+ pool.release();
115
+ await Promise.race([bg, sync, new Promise((r) => setTimeout(r, 20))]);
116
+
117
+ expect(syncAcquired).toBe(true);
118
+ expect(bgAcquired).toBe(false);
119
+ pool.release();
120
+ });
121
+
122
+ // ============================================================
123
+ // 分层配额:effectiveMaxConcurrent 参数控制放行上限 (T-A1~T-A4)
124
+ // ============================================================
125
+ //
126
+ // [背景] T2 Wave 0 给 acquire 增加可选 effectiveMaxConcurrent 参数,让调用方
127
+ // 传 max(1, maxConcurrent - depth) 实现分层配额(嵌套越深有效并发越小)。
128
+ // 该参数覆盖实例级 maxConcurrent 的本次调用上限,不改实例状态。
129
+ // 这组测试锁定该参数的语义。
130
+
131
+ describe("分层配额 effectiveMaxConcurrent (T-A1~T-A4)", () => {
132
+ it("T-A1: effectiveMaxConcurrent 限制本次调用放行数(小于实例级 maxConcurrent)", async () => {
133
+ // 实例配额 5,但本次调用 effective=2 → 第 3 个应阻塞
134
+ const pool = new DefaultConcurrencyPool(5);
135
+ await pool.acquire(0, 2);
136
+ await pool.acquire(0, 2);
137
+ expect(pool.active).toBe(2);
138
+
139
+ let thirdAcquired = false;
140
+ const third = pool.acquire(0, 2).then(() => { thirdAcquired = true; });
141
+ await new Promise((r) => setTimeout(r, 5));
142
+
143
+ expect(thirdAcquired).toBe(false);
144
+ expect(pool.active).toBe(2);
145
+
146
+ pool.release();
147
+ await third;
148
+ expect(thirdAcquired).toBe(true);
149
+ pool.release();
150
+ pool.release();
151
+ });
152
+
153
+ it("T-A2: 同一 pool 实例不同 effectiveMaxConcurrent 控制不同调用放行数", async () => {
154
+ // 同一 pool(实例级 maxConcurrent=5)
155
+ const pool = new DefaultConcurrencyPool(5);
156
+ // 前 3 个用 effective=3,全放行(active 0→1→2→3,每次 < 3)
157
+ await pool.acquire(0, 3);
158
+ await pool.acquire(0, 3);
159
+ await pool.acquire(0, 3);
160
+ expect(pool.active).toBe(3);
161
+
162
+ // 第 4 个用 effective=3 → 阻塞(active 3 >= 3)
163
+ let blockedAcquired = false;
164
+ const blocked = pool.acquire(0, 3).then(() => { blockedAcquired = true; });
165
+ await new Promise((r) => setTimeout(r, 5));
166
+ expect(blockedAcquired).toBe(false);
167
+
168
+ // 换 effective=5 放行(active 3 < 5)
169
+ let wideAcquired = false;
170
+ const wide = pool.acquire(0, 5).then(() => { wideAcquired = true; });
171
+ await new Promise((r) => setTimeout(r, 5));
172
+ expect(wideAcquired).toBe(true);
173
+ expect(pool.active).toBe(4);
174
+
175
+ // wide release 后 blocked 仍等(active 3 >= 3 不变直到再 release)
176
+ pool.release(); // wide 释放
177
+ await new Promise((r) => setTimeout(r, 5));
178
+ expect(blockedAcquired).toBe(true);
179
+
180
+ // 清理
181
+ pool.release();
182
+ pool.release();
183
+ pool.release();
184
+ pool.release();
185
+ await Promise.allSettled([blocked, wide]);
186
+ });
187
+
188
+ it("T-A3: effectiveMaxConcurrent=1 只放行 1 个(保底)", async () => {
189
+ const pool = new DefaultConcurrencyPool(5);
190
+ await pool.acquire(0, 1);
191
+ expect(pool.active).toBe(1);
192
+
193
+ let secondAcquired = false;
194
+ const second = pool.acquire(0, 1).then(() => { secondAcquired = true; });
195
+ await new Promise((r) => setTimeout(r, 5));
196
+ expect(secondAcquired).toBe(false);
197
+ expect(pool.active).toBe(1);
198
+
199
+ pool.release();
200
+ await second;
201
+ expect(secondAcquired).toBe(true);
202
+ pool.release();
203
+ });
204
+
205
+ it("T-A4: maxConcurrent readonly 属性可读且等于构造值", () => {
206
+ const pool = new DefaultConcurrencyPool(4);
207
+ expect(pool.maxConcurrent).toBe(4);
208
+
209
+ // clamp 路径也通过该属性暴露
210
+ const clamped = new DefaultConcurrencyPool(0);
211
+ expect(clamped.maxConcurrent).toBe(1);
212
+
213
+ const negative = new DefaultConcurrencyPool(-3);
214
+ expect(negative.maxConcurrent).toBe(1);
215
+ });
216
+ });
217
+
218
+ // ============================================================
219
+ // H2: acquire 支持 AbortSignal — abort 时排队条目 reject
220
+ // ============================================================
221
+ describe("H2 abort support for acquire", () => {
222
+ it("abort signal rejects queued acquire with AbortError", async () => {
223
+ const pool = new DefaultConcurrencyPool(1);
224
+ await pool.acquire(0); // 占满
225
+
226
+ const controller = new AbortController();
227
+ const queued = pool.acquire(0, undefined, controller.signal);
228
+
229
+ await new Promise((r) => setTimeout(r, 5));
230
+ expect(pool.active).toBe(1); // 仍在排队
231
+
232
+ controller.abort();
233
+
234
+ await expect(queued).rejects.toThrow("aborted");
235
+ });
236
+
237
+ it("non-aborted acquire still resolves normally after release", async () => {
238
+ const pool = new DefaultConcurrencyPool(1);
239
+ await pool.acquire(0); // 占满
240
+
241
+ const controller = new AbortController();
242
+ const queued = pool.acquire(0, undefined, controller.signal);
243
+
244
+ pool.release(); // 释放 → queued 应被 resolve
245
+ await queued; // 不应 reject
246
+ expect(pool.active).toBe(1);
247
+ pool.release();
248
+ });
249
+ });
250
+ });