@zhushanwen/pi-subagent-workflow 8.6.0 → 8.7.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 (347) hide show
  1. package/package.json +9 -13
  2. package/relay/relay.mjs +1 -1
  3. package/src/host/__tests__/pi-host.test.ts +214 -0
  4. package/src/host/pi-host.ts +109 -0
  5. package/src/index.ts +89 -32
  6. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  7. package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
  8. package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
  9. package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
  10. package/src/injectors/engine-awareness.ts +123 -0
  11. package/src/injectors/model-list-injector.ts +1 -1
  12. package/src/injectors/subagent-list-injector.ts +8 -8
  13. package/src/injectors/workflow-list-injector.ts +8 -8
  14. package/src/interface/__tests__/detectors.test.ts +3 -3
  15. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +2 -2
  16. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  17. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  18. package/src/interface/bg-notify-render.ts +4 -4
  19. package/src/interface/commands.ts +3 -3
  20. package/src/interface/format.ts +2 -2
  21. package/src/interface/helpers.ts +1 -1
  22. package/src/interface/list-component.ts +4 -4
  23. package/src/interface/list-shared.ts +2 -2
  24. package/src/interface/list-view.ts +2 -2
  25. package/src/interface/subagent-actions.ts +263 -11
  26. package/src/interface/subagent-tool-schema.ts +20 -13
  27. package/src/interface/subagent-tool.ts +11 -6
  28. package/src/interface/subagents.ts +3 -3
  29. package/src/interface/tool-render.ts +34 -2
  30. package/src/interface/tool-workflow-script.ts +4 -4
  31. package/src/interface/tool-workflow.ts +6 -6
  32. package/src/interface/views/WorkflowsView.ts +5 -5
  33. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  34. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  35. package/src/interface/views/detail-content.ts +4 -4
  36. package/src/interface/views/format.ts +4 -4
  37. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +11 -11
  38. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  39. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  40. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  41. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  42. package/src/execution/__tests__/alive-store.test.ts +0 -147
  43. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  44. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  45. package/src/execution/__tests__/bg-notify-render.test.ts +0 -329
  46. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  47. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -601
  48. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  49. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  50. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  51. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  52. package/src/execution/__tests__/config.test.ts +0 -110
  53. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  54. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  55. package/src/execution/__tests__/delivery-methods.test.ts +0 -422
  56. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  57. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  58. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  59. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  60. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  61. package/src/execution/__tests__/execution-record.test.ts +0 -1394
  62. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +0 -171
  63. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  64. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  65. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -169
  66. package/src/execution/__tests__/format.test.ts +0 -458
  67. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  68. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  69. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  70. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  71. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -242
  72. package/src/execution/__tests__/host-mode.test.ts +0 -87
  73. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  74. package/src/execution/__tests__/index-session-start.test.ts +0 -672
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -383
  77. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  78. package/src/execution/__tests__/list-component.test.ts +0 -401
  79. package/src/execution/__tests__/list-fields.test.ts +0 -140
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -465
  82. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  83. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  84. package/src/execution/__tests__/notifier-flush.test.ts +0 -612
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/notify-ledger.test.ts +0 -826
  87. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  88. package/src/execution/__tests__/output-collector.test.ts +0 -358
  89. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  90. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  91. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  92. package/src/execution/__tests__/record-store.test.ts +0 -1057
  93. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  94. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  95. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  96. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  97. package/src/execution/__tests__/relay-env.test.ts +0 -42
  98. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  99. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  100. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  101. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  102. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -687
  103. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  104. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  105. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  106. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -199
  107. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  108. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  109. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  110. package/src/execution/__tests__/session-pending.test.ts +0 -197
  111. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  112. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  113. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -350
  114. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  115. package/src/execution/__tests__/spawn-args.test.ts +0 -445
  116. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  117. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  118. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  119. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  120. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  121. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  122. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  123. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  124. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  125. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  126. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  127. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  128. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  129. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  130. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -599
  131. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  132. package/src/execution/__tests__/timeout-integration.test.ts +0 -615
  133. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  134. package/src/execution/__tests__/tool-action.test.ts +0 -476
  135. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  136. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  137. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  138. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  139. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  140. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  141. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  142. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  143. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  144. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  145. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  146. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  147. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  148. package/src/execution/agent-registry.ts +0 -199
  149. package/src/execution/agent-result-mapper.ts +0 -90
  150. package/src/execution/alive-store.ts +0 -92
  151. package/src/execution/argv-mirror.ts +0 -113
  152. package/src/execution/best-effort.ts +0 -38
  153. package/src/execution/channel-registry-access.ts +0 -144
  154. package/src/execution/concurrency-pool.ts +0 -116
  155. package/src/execution/config.ts +0 -96
  156. package/src/execution/dialog-queue.ts +0 -330
  157. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  158. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  159. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  160. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  161. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  162. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  163. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  164. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  165. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  166. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  167. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  168. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  169. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  170. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  171. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  172. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  173. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  174. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  175. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  176. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  177. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  178. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  179. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  180. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  181. package/src/execution/engine/common/data-dir.ts +0 -62
  182. package/src/execution/engine/common/errors.ts +0 -183
  183. package/src/execution/engine/common/event-journal.ts +0 -254
  184. package/src/execution/engine/common/journal-replay.ts +0 -62
  185. package/src/execution/engine/common/kill-chain.ts +0 -221
  186. package/src/execution/engine/common/nesting-guard.ts +0 -50
  187. package/src/execution/engine/common/persona-router.ts +0 -108
  188. package/src/execution/engine/common/pool-manager.ts +0 -226
  189. package/src/execution/engine/common/schema-emulation.ts +0 -189
  190. package/src/execution/engine/common/session-view-projection.ts +0 -51
  191. package/src/execution/engine/engine-discovery.ts +0 -65
  192. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  193. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  194. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  195. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  196. package/src/execution/engine/engines/pi/reader.ts +0 -48
  197. package/src/execution/engine/engines/pi/registration.ts +0 -35
  198. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  199. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  200. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  201. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  202. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  203. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  204. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  207. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  208. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  209. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  210. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  211. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  212. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  213. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  214. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -658
  215. package/src/execution/engine/host-task-spec.ts +0 -47
  216. package/src/execution/engine/model-prompt.ts +0 -59
  217. package/src/execution/engine/paths.ts +0 -42
  218. package/src/execution/engine/port.ts +0 -153
  219. package/src/execution/engine/registry.ts +0 -123
  220. package/src/execution/engine/routing.ts +0 -218
  221. package/src/execution/engine/types.ts +0 -309
  222. package/src/execution/execute-options-mapper.ts +0 -112
  223. package/src/execution/execution-record.ts +0 -965
  224. package/src/execution/finalize-record.ts +0 -251
  225. package/src/execution/finalized-marker.ts +0 -51
  226. package/src/execution/get-state-handshake.ts +0 -104
  227. package/src/execution/host-mode.ts +0 -56
  228. package/src/execution/idle-gc.ts +0 -47
  229. package/src/execution/lifecycle-manager.ts +0 -513
  230. package/src/execution/lifecycle-predicates.ts +0 -65
  231. package/src/execution/manifest-store.ts +0 -256
  232. package/src/execution/model-config-service.ts +0 -219
  233. package/src/execution/model-resolver.ts +0 -248
  234. package/src/execution/notifier.ts +0 -330
  235. package/src/execution/notify-ledger.ts +0 -580
  236. package/src/execution/output-collector.ts +0 -228
  237. package/src/execution/path-encoding.ts +0 -60
  238. package/src/execution/pi-invocation.ts +0 -120
  239. package/src/execution/record-entry.ts +0 -132
  240. package/src/execution/record-store.ts +0 -1234
  241. package/src/execution/relay-env.ts +0 -37
  242. package/src/execution/session-context-resolver.ts +0 -64
  243. package/src/execution/session-file-gc.ts +0 -120
  244. package/src/execution/session-pending.ts +0 -164
  245. package/src/execution/session-reconstructor.ts +0 -678
  246. package/src/execution/session-runner.ts +0 -1781
  247. package/src/execution/sessions-index.ts +0 -304
  248. package/src/execution/spawn-event-adapter.ts +0 -363
  249. package/src/execution/stdin-writer.ts +0 -198
  250. package/src/execution/stream-sink.ts +0 -126
  251. package/src/execution/subagent-service.ts +0 -2141
  252. package/src/execution/subprocess-agent-runner.ts +0 -317
  253. package/src/execution/temp-prompt.ts +0 -62
  254. package/src/execution/tombstone-store.ts +0 -72
  255. package/src/execution/turn-limiter.ts +0 -102
  256. package/src/execution/types.ts +0 -973
  257. package/src/execution/ui-channels.ts +0 -216
  258. package/src/execution/ui-interaction-model.ts +0 -48
  259. package/src/execution/ui-request-handler-factory.ts +0 -212
  260. package/src/execution/ui-request-observability.ts +0 -81
  261. package/src/execution/ui-request-queue.ts +0 -184
  262. package/src/execution/worktree-manager.ts +0 -688
  263. package/src/execution/worktree-registry.ts +0 -222
  264. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -349
  265. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -202
  266. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -152
  267. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  268. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  269. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -809
  270. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  271. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  272. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  273. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -451
  274. package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +0 -150
  275. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  276. package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +0 -202
  277. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  278. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -600
  279. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  280. package/src/orchestration/__tests__/lifecycle.test.ts +0 -659
  281. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +0 -95
  282. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -2025
  283. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  284. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -201
  285. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  286. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +0 -368
  287. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  288. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  289. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -563
  290. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  291. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -129
  292. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  293. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  294. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  295. package/src/orchestration/agent-opts-resolver.ts +0 -174
  296. package/src/orchestration/args-validator.ts +0 -127
  297. package/src/orchestration/config-loader.ts +0 -315
  298. package/src/orchestration/error-recovery.ts +0 -1018
  299. package/src/orchestration/execute-agent-call.ts +0 -256
  300. package/src/orchestration/launcher.ts +0 -455
  301. package/src/orchestration/lifecycle.ts +0 -399
  302. package/src/orchestration/models/__tests__/budget.test.ts +0 -307
  303. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  304. package/src/orchestration/models/agent-call.ts +0 -83
  305. package/src/orchestration/models/budget.ts +0 -118
  306. package/src/orchestration/models/ports.ts +0 -164
  307. package/src/orchestration/models/run-runtime.ts +0 -104
  308. package/src/orchestration/models/run-spec.ts +0 -83
  309. package/src/orchestration/models/run-state.ts +0 -44
  310. package/src/orchestration/models/trace.ts +0 -183
  311. package/src/orchestration/models/types.ts +0 -301
  312. package/src/orchestration/models/workflow-run.ts +0 -254
  313. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  314. package/src/orchestration/models/workflow-script.ts +0 -117
  315. package/src/orchestration/script-lint.ts +0 -766
  316. package/src/orchestration/skill-discovery.ts +0 -115
  317. package/src/orchestration/worker-handle.ts +0 -115
  318. package/src/orchestration/worker-host.ts +0 -98
  319. package/src/orchestration/worker-script-builder.ts +0 -421
  320. package/src/orchestration/workflow-files.ts +0 -85
  321. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  322. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  323. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  324. package/src/shared/__tests__/model-ref.test.ts +0 -306
  325. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  326. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  327. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  328. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  329. package/src/shared/__tests__/timer-delay.test.ts +0 -61
  330. package/src/shared/agent-event.ts +0 -13
  331. package/src/shared/agent-ref.ts +0 -57
  332. package/src/shared/meta-parser.ts +0 -261
  333. package/src/shared/model-ref.ts +0 -286
  334. package/src/shared/resource-discovery.ts +0 -811
  335. package/src/shared/resource-meta.ts +0 -65
  336. package/src/shared/schema-env.ts +0 -44
  337. package/src/shared/schema-jsonify.ts +0 -58
  338. package/src/shared/timer-delay.ts +0 -54
  339. package/src/shared/xml-injection.ts +0 -35
  340. package/workflows/README.md +0 -81
  341. package/workflows/_shared/agent-refs.cjs +0 -40
  342. package/workflows/chain.js +0 -131
  343. package/workflows/map-reduce.js +0 -174
  344. package/workflows/parallel.js +0 -148
  345. package/workflows/review-fix-loop-utils.cjs +0 -1309
  346. package/workflows/review-fix-loop.js +0 -1404
  347. package/workflows/scatter-gather.js +0 -178
@@ -1,132 +0,0 @@
1
- // errors.test.ts —— 引擎层错误 SSOT 的结构锁定。
2
- //
3
- // 三视角:①构建者——11 条 code 与设计 §3.3.3 全表一致;②使用者——错误消息
4
- // code 前缀格式可被字符串匹配分流;③观察者——每条错误必有非空恢复指引(可操作)。
5
-
6
- import { describe, expect, it } from "vitest";
7
-
8
- import {
9
- DEFAULT_RECOVERY_HINTS,
10
- ENGINE_ERROR_CODES,
11
- EngineError,
12
- engineRunFailedDetail,
13
- engineTimeoutDetail,
14
- isEngineErrorCode,
15
- nestedSpawnRejectedError,
16
- promptTooLargeError,
17
- schemaEmulationFailedDetail,
18
- STDOUT_TAIL_ECHO_CHARS,
19
- } from "../../common/errors.ts";
20
-
21
- describe("ENGINE_ERROR_CODES(§3.3.3 全表)", () => {
22
- it("11 条错误码与设计文档错误规格表逐条一致", () => {
23
- expect([...ENGINE_ERROR_CODES]).toEqual([
24
- "engine_not_found",
25
- "engine_probe_failed",
26
- "engine_credential_missing",
27
- "nested_spawn_rejected",
28
- "schema_emulation_failed",
29
- "engine_timeout",
30
- "engine_capability_unsupported",
31
- "engine_session_not_resumable",
32
- "model_not_available",
33
- "prompt_too_large",
34
- "engine_run_failed",
35
- ]);
36
- });
37
-
38
- it("isEngineErrorCode 收窄:表内 code 为 true,表外/非字符串为 false", () => {
39
- expect(isEngineErrorCode("engine_timeout")).toBe(true);
40
- expect(isEngineErrorCode("engine_not_found")).toBe(true);
41
- expect(isEngineErrorCode("engine_oops")).toBe(false);
42
- expect(isEngineErrorCode(42)).toBe(false);
43
- expect(isEngineErrorCode(undefined)).toBe(false);
44
- });
45
- });
46
-
47
- describe("DEFAULT_RECOVERY_HINTS(恢复指引全集)", () => {
48
- it("11 条 code 每条都有非空恢复指引(可操作,非安慰性文案)", () => {
49
- for (const code of ENGINE_ERROR_CODES) {
50
- const hint = DEFAULT_RECOVERY_HINTS[code];
51
- expect(hint, `recovery hint for ${code}`).toMatch(/\S/);
52
- expect(hint.length).toBeGreaterThan(20);
53
- }
54
- });
55
-
56
- it("关键恢复动作在指引中(抽查三条错误规格的载体系数)", () => {
57
- expect(DEFAULT_RECOVERY_HINTS.engine_timeout).toMatch(/stdout tail/i);
58
- expect(DEFAULT_RECOVERY_HINTS.prompt_too_large).toMatch(/stdin/);
59
- expect(DEFAULT_RECOVERY_HINTS.nested_spawn_rejected).toMatch(/inside the current task/);
60
- });
61
- });
62
-
63
- describe("EngineError", () => {
64
- it("message 为 <code>: <detail> 前缀格式(outcome.error 分流依据)", () => {
65
- const err = new EngineError("engine_timeout", "chain exhausted", "retry with pi");
66
- expect(err.message).toBe("engine_timeout: chain exhausted");
67
- expect(err.code).toBe("engine_timeout");
68
- expect(err.recovery).toBe("retry with pi");
69
- expect(err.name).toBe("EngineError");
70
- });
71
-
72
- it("toStructured 投影 code/message/recovery 三字段", () => {
73
- const structured = new EngineError("model_not_available", "no such model", "pick another").toStructured();
74
- expect(structured).toEqual({
75
- code: "model_not_available",
76
- message: "model_not_available: no such model",
77
- recovery: "pick another",
78
- });
79
- });
80
- });
81
-
82
- describe("具名构造器", () => {
83
- it("promptTooLargeError:detail 含实际/上限字节数,recovery 含三条恢复建议", () => {
84
- const err = promptTooLargeError(200_000, 131_072);
85
- expect(err.code).toBe("prompt_too_large");
86
- expect(err.message).toContain("200000");
87
- expect(err.message).toContain("131072");
88
- expect(err.recovery).toMatch(/shorten the task/i);
89
- expect(err.recovery).toMatch(/file channel/);
90
- expect(err.recovery).toMatch(/stdin/);
91
- });
92
-
93
- it("nestedSpawnRejectedError:说明防护规则 + 指向 task 内自行完成", () => {
94
- const err = nestedSpawnRejectedError();
95
- expect(err.code).toBe("nested_spawn_rejected");
96
- expect(err.message).toContain("XYZ_AGENT_SUBAGENT");
97
- expect(err.recovery).toMatch(/inside the current task/);
98
- });
99
-
100
- it("engineTimeoutDetail:含 stdout 尾部 + engine: pi 重跑建议", () => {
101
- const detail = engineTimeoutDetail("partial stdout output");
102
- expect(detail).toContain("partial stdout output");
103
- expect(detail).toMatch(/SIGTERM/);
104
- expect(detail).toMatch(/SIGKILL/);
105
- expect(detail).toMatch(/`engine: pi`/);
106
- });
107
-
108
- it(`engineTimeoutDetail:stdout 尾部截断到 ${STDOUT_TAIL_ECHO_CHARS} 字符`, () => {
109
- const longTail = "x".repeat(STDOUT_TAIL_ECHO_CHARS + 500);
110
- const detail = engineTimeoutDetail(longTail);
111
- // 截断后含省略号标记,总长有界(不含前后固定文案不超过 2000 + 常量开销)
112
- expect(detail).toContain("...");
113
- expect(detail.length).toBeLessThan(STDOUT_TAIL_ECHO_CHARS + 600);
114
- });
115
-
116
- it("engineRunFailedDetail:含 reason / exit code / 尾部 / 恢复指引", () => {
117
- const detail = engineRunFailedDetail("stdout parse failed", 3, "some output");
118
- expect(detail).toContain("stdout parse failed");
119
- expect(detail).toContain("exit code 3");
120
- expect(detail).toContain("some output");
121
- expect(detail).toMatch(/probe/);
122
- // exitCode=null(被信号杀死)的形态
123
- expect(engineRunFailedDetail("crash", null, "t")).toContain("killed by signal");
124
- });
125
-
126
- it("schemaEmulationFailedDetail:含错误明细 + 原始输出尾部 + 重试一次语义", () => {
127
- const detail = schemaEmulationFailedDetail("Schema validation failed: /a must be number", '{"a":"x"}');
128
- expect(detail).toContain("Schema validation failed");
129
- expect(detail).toContain('{"a":"x"}');
130
- expect(detail).toMatch(/retry once/i);
131
- });
132
- });
@@ -1,177 +0,0 @@
1
- // event-journal.test.ts —— JournalWriter 写入-重放往返一致 + 中立格式字段断言。
2
- //
3
- // 三视角:①构建者——行格式 v/ts/taskId/engineId/seq/event 逐字段、seq 单调;②使用者
4
- // ——replayJournal 重放即得事件流(read 第②级),文件不存在/坏行不 throw;③观察者
5
- // ——写失败 warn 留痕且 close 不抛(journal 是尽力而为的②级数据源)。
6
-
7
- import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync, existsSync } from "node:fs";
8
- import { tmpdir } from "node:os";
9
- import { dirname, join } from "node:path";
10
-
11
- import { afterEach, describe, expect, it } from "vitest";
12
-
13
- import { JournalWriter, replayJournal } from "../../common/event-journal.ts";
14
- import type { JournalFsDeps } from "../../common/event-journal.ts";
15
- import type { AgentEvent } from "../../../types.ts";
16
-
17
- let tmpRoot: string | undefined;
18
-
19
- function tmpPath(name: string): string {
20
- tmpRoot ??= mkdtempSync(join(tmpdir(), "engine-journal-test-"));
21
- const path = join(tmpRoot, name);
22
- mkdirSync(dirname(path), { recursive: true });
23
- return path;
24
- }
25
-
26
- afterEach(() => {
27
- if (tmpRoot !== undefined) {
28
- rmSync(tmpRoot, { recursive: true, force: true });
29
- tmpRoot = undefined;
30
- }
31
- });
32
-
33
- const EVENTS: AgentEvent[] = [
34
- { type: "text_delta", delta: "hello " },
35
- { type: "text_delta", delta: "world" },
36
- { type: "tool_start", toolName: "bash", args: { cmd: "ls" } },
37
- { type: "tool_end", toolName: "bash", isError: false },
38
- { type: "turn_end" },
39
- ];
40
-
41
- describe("JournalWriter 写入 + replayJournal 重放", () => {
42
- it("写入-重放往返一致:append N 事件 → close → replay 深等事件流", async () => {
43
- const path = tmpPath("roundtrip/journal-bg-1.jsonl");
44
- const writer = new JournalWriter({ path, taskId: "bg-1", engineId: "zcode" });
45
- for (const ev of EVENTS) writer.append(ev);
46
- await writer.close();
47
-
48
- expect(replayJournal(path)).toEqual(EVENTS);
49
- });
50
-
51
- it("中立格式字段断言:每行 {v:1, ts, taskId, engineId, seq, event},seq 单调递增", async () => {
52
- const path = tmpPath("format/journal-bg-2.jsonl");
53
- const writer = new JournalWriter({ path, taskId: "bg-2", engineId: "pi" });
54
- const before = Date.now();
55
- for (const ev of EVENTS) writer.append(ev);
56
- await writer.close();
57
-
58
- const lines = readFileSync(path, "utf8").trim().split("\n");
59
- expect(lines.length).toBe(EVENTS.length);
60
- const parsed = lines.map((l) => JSON.parse(l) as Record<string, unknown>);
61
- let prevSeq = -1;
62
- for (const [i, row] of parsed.entries()) {
63
- expect(row.v).toBe(1);
64
- expect(typeof row.ts).toBe("number");
65
- expect(row.ts).toBeGreaterThanOrEqual(before);
66
- expect(row.taskId).toBe("bg-2");
67
- expect(row.engineId).toBe("pi");
68
- expect(row.seq).toBe(i);
69
- expect((row.seq as number) > prevSeq).toBe(true);
70
- prevSeq = row.seq as number;
71
- expect(row.event).toEqual(EVENTS[i]);
72
- }
73
- });
74
-
75
- it("close 幂等(二次 close 不追加不抛错);close 后 append 丢弃", async () => {
76
- const path = tmpPath("idempotent/journal-bg-3.jsonl");
77
- const writer = new JournalWriter({ path, taskId: "bg-3", engineId: "pi" });
78
- writer.append({ type: "turn_end" });
79
- await writer.close();
80
- writer.append({ type: "error", message: "late" });
81
- await writer.close();
82
- expect(replayJournal(path)).toEqual([{ type: "turn_end" }]);
83
- });
84
-
85
- it("无事件任务不产生空 journal 文件(惰性创建)", async () => {
86
- const path = tmpPath("empty/journal-bg-4.jsonl");
87
- const writer = new JournalWriter({ path, taskId: "bg-4", engineId: "pi" });
88
- await writer.close();
89
- expect(existsSync(path)).toBe(false);
90
- expect(replayJournal(path)).toEqual([]);
91
- });
92
- });
93
-
94
- describe("JournalWriter 写失败(尽力而为语义)", () => {
95
- function failingFs(): { fs: JournalFsDeps; warnings: string[] } {
96
- const warnings: string[] = [];
97
- const fs: JournalFsDeps = {
98
- mkdir: async () => undefined,
99
- appendFile: async () => {
100
- throw new Error("disk full");
101
- },
102
- open: async () => {
103
- throw new Error("unreachable in failed path");
104
- },
105
- };
106
- return { fs, warnings };
107
- }
108
-
109
- it("appendFile 失败 → warn 留痕 + failed,close 不抛,后续 append 丢弃", async () => {
110
- const path = tmpPath("failing/journal-bg-5.jsonl");
111
- const { fs } = failingFs();
112
- const warnings: string[] = [];
113
- const writer = new JournalWriter(
114
- { path, taskId: "bg-5", engineId: "zcode" },
115
- fs,
116
- (msg) => warnings.push(msg),
117
- );
118
- writer.append({ type: "turn_end" });
119
- await writer.flush();
120
- expect(writer.isFailed).toBe(true);
121
- expect(warnings.length).toBe(1);
122
- expect(warnings[0]).toContain("bg-5");
123
- expect(warnings[0]).toContain("disk full");
124
-
125
- writer.append({ type: "error", message: "dropped" });
126
- await writer.close(); // 不抛
127
- expect(existsSync(path)).toBe(false);
128
- });
129
- });
130
-
131
- describe("replayJournal 容错", () => {
132
- it("文件不存在 → [](②级不可达不算错误,降级链语义)", () => {
133
- expect(replayJournal(tmpPath("missing/journal-none.jsonl"))).toEqual([]);
134
- });
135
-
136
- it("损坏行跳过(追加写末行可能截断),好行保留", () => {
137
- const path = tmpPath("corrupt/journal-bg-6.jsonl");
138
- const good = JSON.stringify({
139
- v: 1, ts: 1, taskId: "bg-6", engineId: "pi", seq: 0, event: { type: "turn_end" },
140
- });
141
- writeFileSync(path, `${good}\n{"v":1,"truncated...\n`, "utf8");
142
- expect(replayJournal(path)).toEqual([{ type: "turn_end" }]);
143
- });
144
-
145
- it("行序乱 → 按 seq 稳定排序返回(重放顺序权威是 seq)", () => {
146
- const path = tmpPath("unordered/journal-bg-7.jsonl");
147
- const line = (seq: number, delta: string): string =>
148
- JSON.stringify({ v: 1, ts: seq, taskId: "bg-7", engineId: "pi", seq, event: { type: "text_delta", delta } });
149
- writeFileSync(path, `${line(2, "c")}\n${line(0, "a")}\n${line(1, "b")}\n`, "utf8");
150
- expect(replayJournal(path)).toEqual([
151
- { type: "text_delta", delta: "a" },
152
- { type: "text_delta", delta: "b" },
153
- { type: "text_delta", delta: "c" },
154
- ]);
155
- });
156
-
157
- it("空文件 → []", () => {
158
- const path = tmpPath("blank/journal-bg-8.jsonl");
159
- writeFileSync(path, "\n\n", "utf8");
160
- expect(replayJournal(path)).toEqual([]);
161
- });
162
-
163
- it("结构不符的行(缺 event / v≠1)跳过", () => {
164
- const path = tmpPath("shape/journal-bg-9.jsonl");
165
- writeFileSync(
166
- path,
167
- [
168
- JSON.stringify({ v: 1, ts: 1, taskId: "t", engineId: "pi", seq: 0, event: { type: "compaction" } }),
169
- JSON.stringify({ v: 1, ts: 2, taskId: "t", engineId: "pi", seq: 1 }), // 无 event
170
- JSON.stringify({ v: 2, ts: 3, taskId: "t", engineId: "pi", seq: 2, event: { type: "turn_end" } }), // v≠1
171
- JSON.stringify({ v: 1, ts: 4, taskId: "t", engineId: "pi", seq: 3, event: "not-an-object" }),
172
- ].join("\n") + "\n",
173
- "utf8",
174
- );
175
- expect(replayJournal(path)).toEqual([{ type: "compaction" }]);
176
- });
177
- });
@@ -1,192 +0,0 @@
1
- // kill-chain.test.ts —— 杀链两分支 + 超时终态合成 + abort 两级编排(fake timers)。
2
- //
3
- // 三视角:①构建者——SIGTERM 优雅 / 超时 SIGKILL 两分支的信号序列正确;②使用者——
4
- // abortWithFallback 对 CLI-only 与 native-interrupt 引擎都收敛不悬挂;③观察者——
5
- // 合成终态的 error 含 stdout 尾部与 exitCode=null(被信号杀死判据)。
6
-
7
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
8
-
9
- import {
10
- abortWithFallback,
11
- killChain,
12
- synthesizeTimeoutOutcome,
13
- } from "../../common/kill-chain.ts";
14
- import type { KillableChild } from "../../common/kill-chain.ts";
15
-
16
- /** fake 子进程:记录 kill 信号序列,emitExit 模拟退出(置退出态 + 触发 exit listener)。 */
17
- function makeFakeChild(): {
18
- child: KillableChild;
19
- signals: string[];
20
- emitExit(code: number | null, signal: NodeJS.Signals | null): void;
21
- } {
22
- const listeners: Array<(code: number | null, signal: NodeJS.Signals | null) => void> = [];
23
- const signals: string[] = [];
24
- const child: KillableChild = {
25
- exitCode: null,
26
- signalCode: null,
27
- kill(signal?: NodeJS.Signals | number): boolean {
28
- signals.push(String(signal ?? "SIGTERM"));
29
- return true;
30
- },
31
- once(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): KillableChild {
32
- if (event === "exit") listeners.push(listener);
33
- return child;
34
- },
35
- };
36
- return {
37
- child,
38
- signals,
39
- emitExit(code, signal) {
40
- child.exitCode = code;
41
- child.signalCode = signal;
42
- for (const l of listeners.splice(0)) l(code, signal);
43
- },
44
- };
45
- }
46
-
47
- beforeEach(() => {
48
- vi.useFakeTimers();
49
- });
50
-
51
- afterEach(() => {
52
- vi.useRealTimers();
53
- });
54
-
55
- describe("killChain", () => {
56
- it("SIGTERM 后进程优雅退出 → 'terminated',无 SIGKILL", async () => {
57
- const { child, signals, emitExit } = makeFakeChild();
58
- const p = killChain(child, { graceMs: 5_000 });
59
- emitExit(0, null); // SIGTERM 被 trap 后正常退出
60
- expect(await p).toBe("terminated");
61
- expect(signals).toEqual(["SIGTERM"]);
62
- });
63
-
64
- it("SIGTERM 超时未退 → SIGKILL 兜底 → 'killed'(fake timers 推进两级窗口)", async () => {
65
- const { child, signals } = makeFakeChild();
66
- const p = killChain(child, { graceMs: 5_000 });
67
- expect(signals).toEqual(["SIGTERM"]); // kill 同步发出
68
- await vi.advanceTimersByTimeAsync(5_000); // grace 窗口走完,进程仍活
69
- expect(signals).toEqual(["SIGTERM", "SIGKILL"]);
70
- await vi.advanceTimersByTimeAsync(10_000); // SIGKILL 收尸窗口(进程不退也返回)
71
- expect(await p).toBe("killed");
72
- });
73
-
74
- it("进程已退出(调用前)→ 不发任何信号,'terminated'", async () => {
75
- const { child, signals, emitExit } = makeFakeChild();
76
- emitExit(1, null);
77
- expect(await killChain(child, { graceMs: 5_000 })).toBe("terminated");
78
- expect(signals).toEqual([]);
79
- });
80
-
81
- it("grace 窗口内恰在超时前一毫秒退出 → 复核退出态,不误发 SIGKILL", async () => {
82
- const { child, signals, emitExit } = makeFakeChild();
83
- const p = killChain(child, { graceMs: 5_000 });
84
- emitExit(null, "SIGTERM"); // 被 SIGTERM 杀死(signalCode 形态)
85
- await vi.advanceTimersByTimeAsync(5_000);
86
- expect(await p).toBe("terminated");
87
- expect(signals).toEqual(["SIGTERM"]);
88
- });
89
- });
90
-
91
- describe("synthesizeTimeoutOutcome", () => {
92
- it("合成 engine_timeout 终态:error 含 slug + stdout 尾部 + engine: pi 重跑建议;exitCode=null", () => {
93
- const outcome = synthesizeTimeoutOutcome(
94
- { task: "review files", slug: "review-files" },
95
- "last stdout lines...",
96
- );
97
- expect(outcome.error).toContain("engine_timeout");
98
- expect(outcome.error).toContain("review-files");
99
- expect(outcome.error).toContain("last stdout lines...");
100
- expect(outcome.error).toMatch(/`engine: pi`/);
101
- expect(outcome.exitCode).toBe(null);
102
- expect(outcome.content).toBe("");
103
- expect(outcome.engineId).toBe("pi");
104
- });
105
-
106
- it("stdout 尾部超 2000 字截断;engineId 可指定", () => {
107
- const outcome = synthesizeTimeoutOutcome(
108
- { task: "t", slug: "s" },
109
- "y".repeat(3_000),
110
- "zcode",
111
- );
112
- expect(outcome.engineId).toBe("zcode");
113
- expect(outcome.error).toContain("...");
114
- expect(outcome.error.length).toBeLessThan(3_000);
115
- });
116
- });
117
-
118
- describe("abortWithFallback", () => {
119
- it("CLI-only 引擎(无原生中断):abort → 直接杀链,SIGTERM 退 → 'terminated'", async () => {
120
- const { child, signals, emitExit } = makeFakeChild();
121
- const controller = new AbortController();
122
- const p = abortWithFallback(child, controller.signal);
123
- controller.abort();
124
- emitExit(0, null); // SIGTERM 生效
125
- expect(await p).toBe("terminated");
126
- expect(signals).toEqual(["SIGTERM"]);
127
- });
128
-
129
- it("原生中断生效:abort → native interrupt → 进程退出,不走杀链(零 kill 信号)", async () => {
130
- const { child, signals, emitExit } = makeFakeChild();
131
- const controller = new AbortController();
132
- const interrupt = vi.fn(async () => {
133
- emitExit(0, null); // 引擎原生中断让进程优雅退出
134
- });
135
- const p = abortWithFallback(child, controller.signal, interrupt);
136
- controller.abort();
137
- expect(await p).toBe("terminated");
138
- expect(interrupt).toHaveBeenCalledTimes(1);
139
- expect(signals).toEqual([]); // 从未发信号——原生中断足量
140
- });
141
-
142
- it("原生中断无效(进程未停)→ 宽限窗口后落杀链 SIGKILL → 'killed'", async () => {
143
- const { child, signals } = makeFakeChild();
144
- const controller = new AbortController();
145
- const interrupt = vi.fn(async () => undefined); // 中断送达但进程不退
146
- const p = abortWithFallback(child, controller.signal, interrupt, {
147
- nativeGraceMs: 3_000,
148
- graceMs: 5_000,
149
- });
150
- controller.abort();
151
- expect(interrupt).toHaveBeenCalledTimes(1);
152
- await vi.advanceTimersByTimeAsync(3_000); // native 宽限窗口走完
153
- expect(signals).toEqual(["SIGTERM"]);
154
- await vi.advanceTimersByTimeAsync(5_000); // 杀链 grace 窗口走完
155
- expect(signals).toEqual(["SIGTERM", "SIGKILL"]);
156
- await vi.advanceTimersByTimeAsync(10_000);
157
- expect(await p).toBe("killed");
158
- });
159
-
160
- it("原生中断 throw(协议错)→ 不阻断兜底,继续杀链", async () => {
161
- const { child, signals, emitExit } = makeFakeChild();
162
- const controller = new AbortController();
163
- const interrupt = vi.fn(async () => {
164
- throw new Error("rpc broken");
165
- });
166
- const p = abortWithFallback(child, controller.signal, interrupt, { nativeGraceMs: 100, graceMs: 5_000 });
167
- controller.abort();
168
- await vi.advanceTimersByTimeAsync(100);
169
- emitExit(0, null); // 后续 SIGTERM 生效
170
- expect(await p).toBe("terminated");
171
- expect(signals).toEqual(["SIGTERM"]);
172
- });
173
-
174
- it("进程自然退出(signal 从未 abort)→ 'terminated',promise 不悬挂", async () => {
175
- const { child, signals, emitExit } = makeFakeChild();
176
- const controller = new AbortController();
177
- const p = abortWithFallback(child, controller.signal);
178
- emitExit(0, null);
179
- expect(await p).toBe("terminated");
180
- expect(signals).toEqual([]);
181
- });
182
-
183
- it("signal 已 abort 的场景(先 abort 后接线)→ 立即执行两级中断", async () => {
184
- const { child, signals, emitExit } = makeFakeChild();
185
- const controller = new AbortController();
186
- controller.abort(); // 先 abort
187
- const p = abortWithFallback(child, controller.signal);
188
- emitExit(0, null);
189
- expect(await p).toBe("terminated");
190
- expect(signals).toEqual(["SIGTERM"]);
191
- });
192
- });
@@ -1,81 +0,0 @@
1
- // nesting-guard.test.ts —— 嵌套标记注入与原生标记剥离(D8 双层防护)。
2
- //
3
- // 三视角:①构建者——三引擎原生标记(PI_SUBAGENT_* / CLAUDECODE / ZSW_NESTED)全部
4
- // 剥离且其余 env 保留;②使用者——子代理进程内 assertNotNestedSpawn 同步拒绝且文案
5
- // 可操作;③观察者——产出的 env 是新对象(不污染入参)。
6
-
7
- import { describe, expect, it } from "vitest";
8
-
9
- import {
10
- assertNotNestedSpawn,
11
- buildNestedSpawnEnv,
12
- NESTED_SPAWN_ENV,
13
- } from "../../common/nesting-guard.ts";
14
- import { EngineError } from "../../common/errors.ts";
15
-
16
- describe("buildNestedSpawnEnv", () => {
17
- it("注入统一标记 XYZ_AGENT_SUBAGENT=1", () => {
18
- const env = buildNestedSpawnEnv({ PATH: "/usr/bin" });
19
- expect(env[NESTED_SPAWN_ENV]).toBe("1");
20
- expect(env.PATH).toBe("/usr/bin");
21
- });
22
-
23
- it("剥离 pi 原生标记 PI_SUBAGENT_*(任意后缀)", () => {
24
- const env = buildNestedSpawnEnv({
25
- PI_SUBAGENT_ID: "bg-1",
26
- PI_SUBAGENT_CWD: "/tmp/x",
27
- PI_SUBAGENT_SESSION: "abc",
28
- KEEP_ME: "yes",
29
- });
30
- expect("PI_SUBAGENT_ID" in env).toBe(false);
31
- expect("PI_SUBAGENT_CWD" in env).toBe(false);
32
- expect("PI_SUBAGENT_SESSION" in env).toBe(false);
33
- expect(env.KEEP_ME).toBe("yes");
34
- });
35
-
36
- it("剥离 CC 与 zsub 的原生标记(CLAUDECODE / ZSW_NESTED)", () => {
37
- const env = buildNestedSpawnEnv({
38
- CLAUDECODE: "1",
39
- ZSW_NESTED: "1",
40
- CLAUDE_UNRELATED: "keep", // 非嵌套标记的 CLAUDE_ 前缀不受影响
41
- });
42
- expect("CLAUDECODE" in env).toBe(false);
43
- expect("ZSW_NESTED" in env).toBe(false);
44
- expect(env.CLAUDE_UNRELATED).toBe("keep");
45
- });
46
-
47
- it("返回新对象,不 mutate 入参(spawn env 组装链安全)", () => {
48
- const base = { PATH: "/usr/bin", PI_SUBAGENT_ID: "x" };
49
- const env = buildNestedSpawnEnv(base);
50
- expect(base.PI_SUBAGENT_ID).toBe("x");
51
- expect("XYZ_AGENT_SUBAGENT" in base).toBe(false);
52
- expect(env).not.toBe(base);
53
- });
54
-
55
- it("空白 env 也能产出仅含标记的最小 env", () => {
56
- const env = buildNestedSpawnEnv({});
57
- expect(env).toEqual({ [NESTED_SPAWN_ENV]: "1" });
58
- });
59
- });
60
-
61
- describe("assertNotNestedSpawn", () => {
62
- it("检测到统一标记(本进程已是 subagent)→ 抛 nested_spawn_rejected", () => {
63
- expect(() => assertNotNestedSpawn({ [NESTED_SPAWN_ENV]: "1" })).toThrowError(EngineError);
64
- try {
65
- assertNotNestedSpawn({ [NESTED_SPAWN_ENV]: "1" });
66
- expect.unreachable("should throw");
67
- } catch (err) {
68
- const e = err as EngineError;
69
- expect(e.code).toBe("nested_spawn_rejected");
70
- // 文案说明防护规则(标记名)+ 指向 task 内自行完成
71
- expect(e.message).toContain("XYZ_AGENT_SUBAGENT");
72
- expect(e.recovery).toMatch(/inside the current task/);
73
- }
74
- });
75
-
76
- it("无标记 / 值非 '1' → 不抛(顶层进程正常派发)", () => {
77
- expect(() => assertNotNestedSpawn({})).not.toThrow();
78
- expect(() => assertNotNestedSpawn({ [NESTED_SPAWN_ENV]: "0" })).not.toThrow();
79
- expect(() => assertNotNestedSpawn({ [NESTED_SPAWN_ENV]: undefined })).not.toThrow();
80
- });
81
- });