@zhushanwen/pi-subagent-workflow 8.5.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 (336) hide show
  1. package/package.json +13 -16
  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 +142 -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 +157 -0
  16. package/src/interface/__tests__/subagent-tool-prompt.test.ts +12 -0
  17. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  18. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  19. package/src/interface/bg-notify-render.ts +34 -13
  20. package/src/interface/commands.ts +3 -3
  21. package/src/interface/format.ts +2 -2
  22. package/src/interface/helpers.ts +3 -3
  23. package/src/interface/list-component.ts +4 -4
  24. package/src/interface/list-shared.ts +2 -2
  25. package/src/interface/list-view.ts +2 -2
  26. package/src/interface/subagent-actions.ts +288 -19
  27. package/src/interface/subagent-tool-schema.ts +163 -0
  28. package/src/interface/subagent-tool.ts +65 -129
  29. package/src/interface/subagents.ts +5 -5
  30. package/src/interface/tool-render.ts +34 -2
  31. package/src/interface/tool-workflow-script.ts +4 -4
  32. package/src/interface/tool-workflow.ts +6 -6
  33. package/src/interface/views/WorkflowsView.ts +5 -5
  34. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  35. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  36. package/src/interface/views/detail-content.ts +4 -4
  37. package/src/interface/views/format.ts +4 -4
  38. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +132 -18
  39. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  40. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  41. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  42. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  43. package/src/execution/__tests__/alive-store.test.ts +0 -147
  44. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  45. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  46. package/src/execution/__tests__/bg-notify-render.test.ts +0 -256
  47. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  48. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -597
  49. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  50. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  51. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  52. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  53. package/src/execution/__tests__/config.test.ts +0 -110
  54. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  55. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  56. package/src/execution/__tests__/delivery-methods.test.ts +0 -385
  57. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  58. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  59. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  60. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  61. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -189
  62. package/src/execution/__tests__/execution-record.test.ts +0 -1284
  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 -138
  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 -238
  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 -593
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -337
  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 -109
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -413
  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 -574
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  87. package/src/execution/__tests__/output-collector.test.ts +0 -61
  88. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  89. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  90. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  91. package/src/execution/__tests__/record-store.test.ts +0 -1057
  92. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  93. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  94. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  95. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  96. package/src/execution/__tests__/relay-env.test.ts +0 -42
  97. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  98. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -644
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  105. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  106. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  107. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  108. package/src/execution/__tests__/session-pending.test.ts +0 -197
  109. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  110. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -311
  112. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  113. package/src/execution/__tests__/spawn-args.test.ts +0 -434
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  117. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  118. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  119. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  120. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  122. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  124. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  125. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  126. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  127. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -506
  128. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  129. package/src/execution/__tests__/timeout-integration.test.ts +0 -397
  130. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  131. package/src/execution/__tests__/tool-action.test.ts +0 -385
  132. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  133. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  134. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  135. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  136. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  137. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  138. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  139. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  140. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  141. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  142. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  143. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  144. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  145. package/src/execution/agent-registry.ts +0 -193
  146. package/src/execution/agent-result-mapper.ts +0 -90
  147. package/src/execution/alive-store.ts +0 -92
  148. package/src/execution/argv-mirror.ts +0 -109
  149. package/src/execution/best-effort.ts +0 -38
  150. package/src/execution/channel-registry-access.ts +0 -144
  151. package/src/execution/concurrency-pool.ts +0 -116
  152. package/src/execution/config.ts +0 -96
  153. package/src/execution/dialog-queue.ts +0 -330
  154. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  155. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  156. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  158. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  159. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  160. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  161. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  162. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  163. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  164. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  165. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  166. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  167. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  168. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  169. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  170. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  171. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  172. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  173. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  174. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  175. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  176. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  177. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  178. package/src/execution/engine/common/data-dir.ts +0 -62
  179. package/src/execution/engine/common/errors.ts +0 -183
  180. package/src/execution/engine/common/event-journal.ts +0 -254
  181. package/src/execution/engine/common/journal-replay.ts +0 -62
  182. package/src/execution/engine/common/kill-chain.ts +0 -221
  183. package/src/execution/engine/common/nesting-guard.ts +0 -50
  184. package/src/execution/engine/common/persona-router.ts +0 -108
  185. package/src/execution/engine/common/pool-manager.ts +0 -226
  186. package/src/execution/engine/common/schema-emulation.ts +0 -189
  187. package/src/execution/engine/common/session-view-projection.ts +0 -51
  188. package/src/execution/engine/engine-discovery.ts +0 -65
  189. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  190. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  191. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  192. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  193. package/src/execution/engine/engines/pi/reader.ts +0 -48
  194. package/src/execution/engine/engines/pi/registration.ts +0 -35
  195. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  197. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  198. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  199. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  200. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  201. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -567
  204. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  205. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  206. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  207. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  208. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  209. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  210. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  211. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -648
  212. package/src/execution/engine/host-task-spec.ts +0 -47
  213. package/src/execution/engine/model-prompt.ts +0 -59
  214. package/src/execution/engine/paths.ts +0 -42
  215. package/src/execution/engine/port.ts +0 -153
  216. package/src/execution/engine/registry.ts +0 -123
  217. package/src/execution/engine/routing.ts +0 -218
  218. package/src/execution/engine/types.ts +0 -304
  219. package/src/execution/execute-options-mapper.ts +0 -111
  220. package/src/execution/execution-record.ts +0 -906
  221. package/src/execution/finalize-record.ts +0 -251
  222. package/src/execution/finalized-marker.ts +0 -51
  223. package/src/execution/get-state-handshake.ts +0 -104
  224. package/src/execution/host-mode.ts +0 -56
  225. package/src/execution/idle-gc.ts +0 -47
  226. package/src/execution/lifecycle-manager.ts +0 -491
  227. package/src/execution/lifecycle-predicates.ts +0 -65
  228. package/src/execution/manifest-store.ts +0 -256
  229. package/src/execution/model-config-service.ts +0 -204
  230. package/src/execution/model-resolver.ts +0 -276
  231. package/src/execution/notifier.ts +0 -260
  232. package/src/execution/output-collector.ts +0 -88
  233. package/src/execution/path-encoding.ts +0 -60
  234. package/src/execution/pi-invocation.ts +0 -120
  235. package/src/execution/record-entry.ts +0 -132
  236. package/src/execution/record-store.ts +0 -1234
  237. package/src/execution/relay-env.ts +0 -37
  238. package/src/execution/session-context-resolver.ts +0 -64
  239. package/src/execution/session-file-gc.ts +0 -120
  240. package/src/execution/session-pending.ts +0 -164
  241. package/src/execution/session-reconstructor.ts +0 -678
  242. package/src/execution/session-runner.ts +0 -1548
  243. package/src/execution/sessions-index.ts +0 -304
  244. package/src/execution/spawn-event-adapter.ts +0 -363
  245. package/src/execution/stdin-writer.ts +0 -198
  246. package/src/execution/stream-sink.ts +0 -126
  247. package/src/execution/subagent-service.ts +0 -2119
  248. package/src/execution/subprocess-agent-runner.ts +0 -303
  249. package/src/execution/temp-prompt.ts +0 -62
  250. package/src/execution/tombstone-store.ts +0 -72
  251. package/src/execution/turn-limiter.ts +0 -102
  252. package/src/execution/types.ts +0 -910
  253. package/src/execution/ui-channels.ts +0 -216
  254. package/src/execution/ui-interaction-model.ts +0 -48
  255. package/src/execution/ui-request-handler-factory.ts +0 -212
  256. package/src/execution/ui-request-observability.ts +0 -81
  257. package/src/execution/ui-request-queue.ts +0 -174
  258. package/src/execution/worktree-manager.ts +0 -688
  259. package/src/execution/worktree-registry.ts +0 -222
  260. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -336
  261. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -208
  262. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -157
  263. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  264. package/src/orchestration/__tests__/concurrency-gate.test.ts +0 -125
  265. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  266. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -724
  267. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  268. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  269. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  270. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -314
  271. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  272. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  273. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -277
  274. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  275. package/src/orchestration/__tests__/lifecycle.test.ts +0 -625
  276. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -1971
  277. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  278. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -157
  279. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  280. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  281. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  282. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -520
  283. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  284. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -110
  285. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  286. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  287. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  288. package/src/orchestration/agent-opts-resolver.ts +0 -93
  289. package/src/orchestration/args-validator.ts +0 -127
  290. package/src/orchestration/concurrency-gate.ts +0 -69
  291. package/src/orchestration/config-loader.ts +0 -315
  292. package/src/orchestration/error-recovery.ts +0 -862
  293. package/src/orchestration/execute-agent-call.ts +0 -217
  294. package/src/orchestration/launcher.ts +0 -410
  295. package/src/orchestration/lifecycle.ts +0 -396
  296. package/src/orchestration/models/__tests__/budget.test.ts +0 -367
  297. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  298. package/src/orchestration/models/agent-call.ts +0 -83
  299. package/src/orchestration/models/budget.ts +0 -148
  300. package/src/orchestration/models/ports.ts +0 -164
  301. package/src/orchestration/models/run-runtime.ts +0 -89
  302. package/src/orchestration/models/run-spec.ts +0 -83
  303. package/src/orchestration/models/run-state.ts +0 -44
  304. package/src/orchestration/models/trace.ts +0 -183
  305. package/src/orchestration/models/types.ts +0 -292
  306. package/src/orchestration/models/workflow-run.ts +0 -254
  307. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  308. package/src/orchestration/models/workflow-script.ts +0 -117
  309. package/src/orchestration/script-lint.ts +0 -766
  310. package/src/orchestration/skill-discovery.ts +0 -92
  311. package/src/orchestration/worker-handle.ts +0 -115
  312. package/src/orchestration/worker-host.ts +0 -98
  313. package/src/orchestration/worker-script-builder.ts +0 -408
  314. package/src/orchestration/workflow-files.ts +0 -85
  315. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  316. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  317. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  318. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  319. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  320. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  321. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  322. package/src/shared/agent-event.ts +0 -13
  323. package/src/shared/agent-ref.ts +0 -57
  324. package/src/shared/meta-parser.ts +0 -261
  325. package/src/shared/resource-discovery.ts +0 -811
  326. package/src/shared/resource-meta.ts +0 -65
  327. package/src/shared/schema-jsonify.ts +0 -56
  328. package/src/shared/xml-injection.ts +0 -35
  329. package/workflows/README.md +0 -81
  330. package/workflows/_shared/agent-refs.cjs +0 -40
  331. package/workflows/chain.js +0 -131
  332. package/workflows/map-reduce.js +0 -174
  333. package/workflows/parallel.js +0 -148
  334. package/workflows/review-fix-loop-utils.cjs +0 -1307
  335. package/workflows/review-fix-loop.js +0 -1396
  336. package/workflows/scatter-gather.js +0 -178
@@ -1,116 +0,0 @@
1
- // src/core/concurrency-pool.ts
2
- //
3
- // 并发控制 + 优先级排队。background=1000(单一优先级,保留 priority 机制供未来扩展)。
4
-
5
- /** 队列条目:优先级 + resolver + rejecter + 入队序号(同优先级 FIFO)。 */
6
- interface QueueEntry {
7
- priority: number;
8
- resolve: () => void;
9
- reject: (err: Error) => void;
10
- seq: number;
11
- /** abort listener(用于 resolve/abort 时清理)。 */
12
- onAbort?: () => void;
13
- /** 关联的 signal(用于 resolve 时 removeEventListener)。 */
14
- signal?: AbortSignal;
15
- }
16
-
17
- /** 并发池接口(可注入,便于测试 mock)。 */
18
- export interface ConcurrencyPool {
19
- /** 按优先级排队获取槽位(0=最高)。可选 effectiveMaxConcurrent 覆盖实例级默认配额。可选 AbortSignal 在 abort 时 reject 排队条目。 */
20
- acquire(priority: number, effectiveMaxConcurrent?: number, signal?: AbortSignal): Promise<void>;
21
- /** 归还槽位。必须无条件执行(finally)。 */
22
- release(): void;
23
- /** 当前已占用槽位数(诊断/widget 用)。 */
24
- readonly active: number;
25
- /** 实例级最大并发配额。调用方可据此计算分层配额(max(1, maxConcurrent - depth))。 */
26
- readonly maxConcurrent: number;
27
- }
28
-
29
- /**
30
- * 默认实现:maxConcurrent 槽位 + 优先级队列。
31
- *
32
- * acquire(priority, effectiveMaxConcurrent?):
33
- * effective = effectiveMaxConcurrent ?? maxConcurrent
34
- * active < effective → active++, resolve
35
- * 否则 → 入队 { priority, resolve, seq }, 队列按 priority 升序 + seq FIFO
36
- *
37
- * release():
38
- * queue 非空 → 出队最高优先级 resolve(active 不变)
39
- * queue 空 → active--(防下溢)
40
- */
41
- export class DefaultConcurrencyPool implements ConcurrencyPool {
42
- private _active = 0;
43
- private readonly queue: QueueEntry[] = [];
44
- private seqCounter = 0;
45
-
46
- /** 下限 1——maxConcurrent=0 会让 acquire 永久排队死锁(C3 修复)。 */
47
- readonly maxConcurrent: number;
48
-
49
- constructor(maxConcurrent: number) {
50
- this.maxConcurrent = Math.max(1, maxConcurrent);
51
- }
52
-
53
- acquire(priority: number, effectiveMaxConcurrent?: number, signal?: AbortSignal): Promise<void> {
54
- // effectiveMaxConcurrent 覆盖实例级默认配额(分层配额:调用方传 max(1, maxConcurrent - depth))。
55
- // 不修改实例级 maxConcurrent——实例配额是全局共享上限,分层配额是本次 acquire 的局部上限。
56
- const effective = effectiveMaxConcurrent ?? this.maxConcurrent;
57
- if (this._active < effective) {
58
- this._active += 1;
59
- return Promise.resolve();
60
- }
61
- return new Promise<void>((resolve, reject) => {
62
- const entry: QueueEntry = { priority, resolve, reject, seq: this.seqCounter++ };
63
- // H2: abort 时 reject 排队条目并从 queue 移除,防止永久挂起
64
- if (signal) {
65
- if (signal.aborted) {
66
- // S1: abort reject 需带 name="AbortError",对齐 concurrency-gate.ts 的 AbortError 语义
67
- const err = new Error("acquire aborted");
68
- err.name = "AbortError";
69
- reject(err);
70
- return;
71
- }
72
- entry.signal = signal;
73
- entry.onAbort = (): void => {
74
- const idx = this.queue.indexOf(entry);
75
- if (idx >= 0) {
76
- this.queue.splice(idx, 1);
77
- // S1: abort reject 需带 name="AbortError",与 pre-aborted 分支一致
78
- const err = new Error("acquire aborted");
79
- err.name = "AbortError";
80
- reject(err);
81
- }
82
- };
83
- signal.addEventListener("abort", entry.onAbort, { once: true });
84
- }
85
- this.queue.push(entry);
86
- });
87
- }
88
-
89
- release(): void {
90
- if (this.queue.length > 0) {
91
- // 取优先级最高(priority 最小)的;同优先级 FIFO(seq 最小)
92
- let bestIdx = 0;
93
- for (let i = 1; i < this.queue.length; i++) {
94
- const cur = this.queue[i];
95
- const best = this.queue[bestIdx];
96
- if (cur.priority < best.priority || (cur.priority === best.priority && cur.seq < best.seq)) {
97
- bestIdx = i;
98
- }
99
- }
100
- const next = this.queue.splice(bestIdx, 1)[0];
101
- // H2: 条目已获槽位——移除 abort listener(防 listener 泄漏到长生命周期 signal)
102
- if (next.onAbort && next.signal) {
103
- next.signal.removeEventListener("abort", next.onAbort);
104
- }
105
- next.resolve();
106
- // active 不变(一个离开队列立即进入活跃)
107
- } else if (this._active > 0) {
108
- // 防御性下界:release 调用次数多于 acquire 时不让 active 为负
109
- this._active -= 1;
110
- }
111
- }
112
-
113
- get active(): number {
114
- return this._active;
115
- }
116
- }
@@ -1,96 +0,0 @@
1
- // src/runtime/config/config.ts
2
- //
3
- // 全局配置(~/.pi/agent/subagents/config.json)。
4
- // 仅保留 maxConcurrent(pool 大小)。模型解析已退化为「主 agent model 优先」,
5
- // 不再有 category/fallback/session 级覆盖——相关字段读取时忽略。
6
-
7
- import * as fs from "node:fs";
8
- import * as path from "node:path";
9
-
10
- import type { SubagentsGlobalConfig } from "./types.ts";
11
-
12
- // ============================================================
13
- // 常量
14
- // ============================================================
15
-
16
- /**
17
- * 开箱默认配置(单一真相源,内联在代码里)。
18
- *
19
- * 历史教训 [HISTORICAL]:曾用包内 config.json(与 src/ 同级)作为默认值源,
20
- * 但 config.json 被 .gitignore 排除且不应随 npm 包分发用户私有配置——导致
21
- * npm pack 后读不到文件,catch 兜底用空字段,pi install 后首次执行抛错。
22
- * 修复:默认值内联在代码里,不依赖任何包内文件。
23
- *
24
- * export 供守护测试断言 package.json startupConfig 声明与此深相等(防漂移)。
25
- */
26
- export const DEFAULT_CONFIG: SubagentsGlobalConfig = {
27
- version: 1,
28
- maxConcurrent: 6,
29
- };
30
-
31
- /** 默认 maxConcurrent(DEFAULT_CONFIG 的镜像,sanitize 用)。 */
32
- const DEFAULT_MAX_CONCURRENT = 6;
33
- // ============================================================
34
- // 路径
35
- // ============================================================
36
-
37
- /**
38
- * 配置文件路径(<agentDir>/subagents/config.json)。
39
- * agentDir 由 Pi 核心 getAgentDir() 决定(读 PI_CODING_AGENT_DIR,默认 ~/.pi/agent),
40
- * 与 Pi 主进程的目录约定完全一致——支持宿主经环境变量整体重定向。
41
- */
42
- export function getGlobalConfigPath(agentDir: string): string {
43
- return path.join(agentDir, "subagents", "config.json");
44
- }
45
-
46
- // ============================================================
47
- // 全局配置加载
48
- // ============================================================
49
-
50
- /**
51
- * 加载全局配置。文件不存在 / JSON 解析失败 / 字段缺失时返回默认配置。
52
- * 旧 config.json 中的 categories/fallback/yoloByDefault 等字段读取时忽略
53
- * (模型解析已退化为「主 agent model 优先」)。
54
- */
55
- export function loadGlobalConfig(agentDir: string): SubagentsGlobalConfig {
56
- const configPath = getGlobalConfigPath(agentDir);
57
- try {
58
- const raw = fs.readFileSync(configPath, "utf-8");
59
- const parsed = JSON.parse(raw) as Partial<SubagentsGlobalConfig>;
60
- // P4 引擎路由(D9):全局默认引擎 + strict 模式。非法值静默回缺省('pi' /
61
- // false)——config.json 是用户手编文件,坏值不炸启动(与 maxConcurrent 同判)
62
- const defaultEngine = sanitizeDefaultEngine(parsed.defaultEngine);
63
- const engineRouting = sanitizeEngineRouting(parsed.engineRouting);
64
- return {
65
- version: parsed.version ?? DEFAULT_CONFIG.version,
66
- maxConcurrent: sanitizeMaxConcurrent(parsed.maxConcurrent),
67
- ...(defaultEngine !== undefined ? { defaultEngine } : {}),
68
- ...(engineRouting !== undefined ? { engineRouting } : {}),
69
- };
70
- } catch {
71
- return { ...DEFAULT_CONFIG };
72
- }
73
- }
74
-
75
- /** maxConcurrent 校验:正整数,否则默认。 */
76
- function sanitizeMaxConcurrent(value: unknown): number {
77
- return typeof value === "number" && Number.isInteger(value) && value > 0
78
- ? value
79
- : DEFAULT_MAX_CONCURRENT;
80
- }
81
-
82
- /**
83
- * defaultEngine 校验:非空字符串透传,其余 undefined(缺省引擎由路由层落 'pi')。
84
- * 为什么不在加载期对注册表校验 hasEngine:加载早于组合根注册(agentDir 解析在
85
- * session_start),注册表此刻可能为空——校验归路由层(getEngine 抛 EngineNotFoundError)。
86
- */
87
- function sanitizeDefaultEngine(value: unknown): string | undefined {
88
- return typeof value === "string" && value.trim() !== "" ? value : undefined;
89
- }
90
-
91
- /** engineRouting 校验:仅认 strict 布尔,其余键忽略(向前兼容追加)。 */
92
- function sanitizeEngineRouting(value: unknown): { strict: boolean } | undefined {
93
- if (typeof value !== "object" || value === null) return undefined;
94
- const strict = (value as Record<string, unknown>).strict;
95
- return typeof strict === "boolean" ? { strict } : undefined;
96
- }
@@ -1,330 +0,0 @@
1
- // src/execution/dialog-queue.ts
2
- //
3
- // L2 跨子进程全局 dialog 串行队列。
4
- //
5
- // 进程单例语义:跨所有子进程共享,串行所有 dialog 类 UI 请求
6
- //(isDialogMethod(method)===true,即 select/confirm/input/editor)。
7
- //
8
- // 设计动机(.fix-plans/00-master-summary.md §一 冲突 3):
9
- // - L1 per-child 队列(session-runner.createUiRequestQueue)只解决同一子进程内的串行,
10
- // 多个并行子进程仍可同时把 dialog 请求涌向父 UI(争输入焦点)。
11
- // - L2 全局队列在主 agent handler 入口前再串行一次,保证同一时刻主 agent 只呈现一个 dialog。
12
- // - 排队绑定 method 交互模型(dialog 才排队),不绑定 channel——排队是 Pi 协议固有属性。
13
- //
14
- // SR-4(child close reject):入队项带 child 引用,child close 时把该 child 的 pending dialog
15
- // 全部 resolve 为 {cancelled:true},防 Promise 永挂 + 内存泄漏。
16
- //
17
- // handler 抛错兜底:catch → 回 {cancelled:true} → 继续处理下一个。不能让一个失败卡死队列。
18
- //
19
- // 调用方约定:只对 dialog 类(isDialogMethod===true)调 enqueue;fire-and-forget 由调用方
20
- // 直接调 handler(见 ui-request-handler-factory.ts),不经过本队列。enqueue 内仍防御性兼容
21
- // fire-and-forget(万一调用方未判):直接调 handler 返回,不入队串行。调用方不应依赖此防御。
22
-
23
- import { isDialogMethod } from "./ui-interaction-model.ts";
24
-
25
- // ── 类型定义(本模块是 UiRequest/UiResponse/UiRequestHandler 的规范来源) ──
26
- // session-runner.ts 和 ui-channels.ts 复用这些类型(session-runner 再导出供测试 import)。
27
-
28
- /** Pi extension_ui_request 的方法枚举(dialog + fire-and-forget 两类)。
29
- * dialog 类:select/confirm/input/editor(占输入焦点,等响应)。
30
- * fire-and-forget 类:notify/setStatus/setWidget/setTitle/set_editor_text(纯展示/写入)。
31
- * (string & {}) 兜底:Pi 未来新增 method 或未知 method 走字符串字面量类型。 */
32
- export type UiMethod =
33
- | "select"
34
- | "confirm"
35
- | "input"
36
- | "editor"
37
- | "notify"
38
- | "setStatus"
39
- | "setWidget"
40
- | "setTitle"
41
- | "set_editor_text"
42
- | (string & {});
43
-
44
- /** UI 请求(session-runner 构造后传给 handler)。
45
- *
46
- * method 是判别字段,决定排队策略(dialog 排队)和业务路由(channel 分发)。
47
- * method 特定字段按 method 可选出现(与 ExtensionUiRequest 1:1,由 session-runner 从
48
- * ExtensionUiRequest 平铺构造)。channel/channelPayload 由 parseChannel 填充。
49
- *
50
- * 契约来源:.fix-plans/00-master-summary.md §二 2.2。 */
51
- export interface UiRequest {
52
- /** Pi rpc-types.ts 的 method(select/confirm/input/editor 为 dialog 类)。 */
53
- method: UiMethod;
54
- /** 请求 id(从 extension_ui_request envelope 顶层提取,用于 response 关联)。 */
55
- id: string;
56
- // method 特定字段(按 method 可选,与 ExtensionUiRequest 1:1)
57
- title?: string;
58
- options?: string[];
59
- message?: string;
60
- placeholder?: string;
61
- prefill?: string;
62
- notifyType?: string;
63
- statusKey?: string;
64
- statusText?: string | undefined;
65
- widgetKey?: string;
66
- widgetLines?: string[] | undefined;
67
- widgetPlacement?: "aboveEditor" | "belowEditor";
68
- text?: string;
69
- timeout?: number;
70
- /** channel 名(从 method 对应字段的 NUL 前缀解析)。
71
- * select → 从 title 解析;setWidget → 从 widgetLines[0] 解析;其他 → undefined。
72
- * 已知值:"ask_user"(select)、"gui_widget"(setWidget)。handler 按 channel 分发。 */
73
- channel?: string;
74
- /** channel 解析后的结构化 payload(已 JSON.parse)。
75
- * ask_user: {questions, allowCancel};gui_widget: {component};无 channel: undefined。 */
76
- channelPayload?: unknown;
77
- /** 内部元数据字段:发起该 UI 请求的子进程 pid(由 session-runner.handleUiRequest 从
78
- * child.pid 填入)。L2 队列据此关联 rejectChildDialogs(child close 时批量 reject)。
79
- * 下划线前缀表示内部字段,非 Pi 协议字段,不参与 stdin 回写。 */
80
- _childPid?: number;
81
- }
82
-
83
- /** UI 响应(handler 返回,session-runner 按 shape 回写 stdin)。
84
- * - {value}: select/input/editor 的答案
85
- * - {confirmed}: confirm 的答案
86
- * - {cancelled}: 取消(child close / handler 抛错 / 用户取消)
87
- * - {ack}: fire-and-forget(当前不透传到 TUI,留作协议完整) */
88
- export type UiResponse =
89
- | { value: string }
90
- | { confirmed: boolean }
91
- | { cancelled: true }
92
- | { ack: true };
93
-
94
- /** UI 请求 handler 签名(单函数,按 req.method 内部路由)。
95
- * 实现方负责:channel 业务路由(ask_user → AskUserComponent)+ 默认转发(ctx.ui.*)。
96
- * 抛错由调用方(DialogGlobalQueue / session-runner)兜底为 {cancelled:true}。 */
97
- export type UiRequestHandler = (req: UiRequest) => Promise<UiResponse>;
98
-
99
- // ── DialogGlobalQueue 实现 ──
100
-
101
- /** 入队项的 child 引用形状(只取 pid 用于 rejectChildDialogs 匹配)。 */
102
- export interface DialogChildRef {
103
- pid: number;
104
- }
105
-
106
- /** enqueue 的可选项。child 用于 rejectChildDialogs 关联(child close 时批量 reject)。 */
107
- export interface EnqueueOptions {
108
- child?: DialogChildRef;
109
- }
110
-
111
- /** 队列内一项:请求 + handler + resolve + 所属 child。
112
- * pending 状态持有 resolve,handler 完成 / rejectChildDialogs 时调它 settle Promise。
113
- * settled 标志保证只 settle 一次(rejectChildDialogs 与 handler 完成可能竞争)。 */
114
- interface QueueItem {
115
- req: UiRequest;
116
- handler: UiRequestHandler;
117
- resolve: (resp: UiResponse) => void;
118
- childPid: number | undefined;
119
- /** 是否已 settle(防 handler 完成 / rejectChildDialogs 重复 resolve)。 */
120
- settled: boolean;
121
- }
122
-
123
- /**
124
- * L2 跨子进程全局 dialog 串行队列(进程单例)。
125
- *
126
- * 用法(createUiRequestHandlerForMode 返回的总 handler 内):
127
- * ```ts
128
- * const dialogQueue = new DialogGlobalQueue();
129
- * return async (req: UiRequest) => {
130
- * // 调用方负责判断:dialog 入队,fire-and-forget 直接调 realHandler
131
- * if (isDialogMethod(req.method)) return dialogQueue.enqueue(req, realHandler);
132
- * return realHandler(req);
133
- * };
134
- * ```
135
- *
136
- * 语义保证:
137
- * - FIFO 串行:前一个 handler settle 后才处理下一个
138
- * - SR-4:rejectChildDialogs(child) 把该 child 的 pending 全部 resolve 为 {cancelled:true}
139
- * - handler 抛错兜底:catch → {cancelled:true} → 继续下一个(队列不卡死)
140
- * - 调用方约定只对 dialog 类调 enqueue;fire-and-forget 由调用方直接调 handler 不入队
141
- *(enqueue 内仍防御性兼容 fire-and-forget,但不保证行为)
142
- *
143
- * 线程模型:纯 Promise + 微任务驱动,无锁。Node 单线程 event loop 保证队列状态一致。
144
- *
145
- * 单 session 假设(M-2,与 index.ts lastSessionId 同源):本队列是进程级单例(实例挂在
146
- * globalThis[Symbol.for("@zhushanwen/pi-subagents.dialogQueue")],见 getOrCreateDialogQueue)。
147
- * rejectAll() 清空所有 pending dialog——无 per-session 隔离。Pi 当前架构保证单进程
148
- * 单 session 串行(同进程不会并发多个 session),故 session_shutdown 调 rejectAll() 只会清掉
149
- * 当前 session 的 pending。若未来 Pi 支持同进程多 session 并发,session A 退出会误清 session B
150
- * 的 pending dialog——届时需改为 per-session 隔离(入队项 QueueItem 带 sessionId,rejectAll
151
- * 改 rejectAllForSession(sessionId),session_shutdown 只清当前 session)。
152
- */
153
- export class DialogGlobalQueue {
154
- /** 等待处理的队列(FIFO)。正在处理的项从 queue shift 出后由 current 持有。 */
155
- private queue: QueueItem[] = [];
156
- /** 正在处理的项(handler 已调、未 settle)。用于 rejectChildDialogs 取消占位中的 dialog。 */
157
- private current: QueueItem | undefined;
158
- private processing = false;
159
-
160
- /**
161
- * 入队一个 UI 请求,返回 Promise<UiResponse>。
162
- *
163
- * 调用方约定:只对 dialog 类(isDialogMethod===true)调 enqueue。fire-and-forget 由
164
- * 调用方(ui-request-handler-factory.ts)在 enqueue 前判 isDialogMethod 后直接调 handler,
165
- * 不经过本队列。enqueue 内仍防御性兼容 fire-and-forget(万一调用方未判):直接调 handler 返回,
166
- * 不入队串行,但调用方不应依赖此防御行为。
167
- *
168
- * dialog 项处理(TC-E4 case 1):进队列 FIFO 串行,等前一个 settle 后才调 handler
169
- *(争输入焦点,防并发弹窗)。
170
- *
171
- * handler 抛错兜底:catch → 回 {cancelled:true}(dialog 路径,队列不卡死)。
172
- * SR-4:opts.child 用于 rejectChildDialogs 关联(dialog 项会被批量 reject,含 current)。
173
- *
174
- * @param req UI 请求(约定只传 dialog 类;fire-and-forget 防御性兼容)
175
- * @param handler 真正执行请求的 handler(TUI/GUI 模式分流后的 realHandler)
176
- * @param opts 可选 child 引用(用于 rejectChildDialogs 关联)
177
- * @returns handler 的响应;dialog 抛错时回 {cancelled:true};child close 时回 {cancelled:true}
178
- */
179
- enqueue(
180
- req: UiRequest,
181
- handler: UiRequestHandler,
182
- opts?: EnqueueOptions,
183
- ): Promise<UiResponse> {
184
- // 防御性兼容 fire-and-forget:调用方约定不应传此类 req 进 enqueue(factory 层已判
185
- // isDialogMethod 直接调 handler),但万一调用方未判,这里直接调 handler 不入队,避免阻塞。
186
- // 直接返回 handler 真实结果(不做兜底形变为 cancelled——fire-and-forget 无串行语义)。
187
- if (!isDialogMethod(req.method)) {
188
- return handler(req);
189
- }
190
- // dialog:入队 FIFO 串行
191
- return new Promise<UiResponse>((resolve) => {
192
- this.queue.push({
193
- req,
194
- handler,
195
- resolve,
196
- childPid: opts?.child?.pid,
197
- settled: false,
198
- });
199
- void this.processNext();
200
- });
201
- }
202
-
203
- /**
204
- * settle 一个 item(幂等)。handler 完成 / rejectChildDialogs / rejectAll 都通过本方法,
205
- * settled 标志保证只 settle 一次(防竞争)。
206
- *
207
- * #19 单一推进点:本方法 settle Promise + 清状态后,**唯一**调 processNext 推进队列。
208
- * processNext 尾部不再调 processNext(旧代码双重推进,虽靠 processing 标志幂等,但语义混乱)。
209
- * 为什么推进必须在 settleItem 而非 processNext 尾部:rejectChildDialogs 取消一个永不 settle
210
- * 的 current(handler 等用户输入卡死)时,processNext 的 `await item.handler` 永不 resume,
211
- * 尾部不会执行;只有 settleItem 里的 processNext 才能打破死锁,推进下一个。
212
- */
213
- private settleItem(item: QueueItem, resp: UiResponse): void {
214
- if (item.settled) return;
215
- item.settled = true;
216
- item.resolve(resp);
217
- // 若是正在处理的项,清空 current/processing 并推进队列(唯一推进点)。
218
- // 非当前项(队列中被 reject)只 settle Promise,不影响 current/推进。
219
- if (this.current === item) {
220
- this.current = undefined;
221
- this.processing = false;
222
- void this.processNext();
223
- }
224
- }
225
-
226
- /**
227
- * SR-4:把指定 child 的所有 pending dialog resolve 为 {cancelled:true}。
228
- *
229
- * 触发场景:子进程 close(用户取消 / crash / 超时 kill)时,其 pending dialog 的 handler
230
- * 可能永不 settle(等用户输入),导致 Promise 永挂 + 内存泄漏。本方法批量清理。
231
- *
232
- * 处理范围(TC-E4 case 2):
233
- * - 正在处理中(current)的该 child 项:settle {cancelled:true},解阻塞队列推进下一个
234
- * (关键:handler 可能永不 settle,必须由这里打破死锁)
235
- * - 队列中等待处理的该 child 项:settle {cancelled:true} 并移除
236
- *
237
- * 不影响其他 child 的 pending dialog(TC-E4 case 2 子测试 2)。
238
- */
239
- rejectChildDialogs(child: DialogChildRef): void {
240
- // 先处理正在处理的项(可能永不 settle,必须由这里解阻塞)
241
- if (this.current && this.current.childPid === child.pid) {
242
- this.settleItem(this.current, { cancelled: true });
243
- }
244
- // 再处理队列中等待的项
245
- if (this.queue.length === 0) return;
246
- const remaining: QueueItem[] = [];
247
- for (const item of this.queue) {
248
- if (item.childPid === child.pid) {
249
- // settle 该 child 的 pending Promise 为 cancelled
250
- this.settleItem(item, { cancelled: true });
251
- } else {
252
- remaining.push(item);
253
- }
254
- }
255
- this.queue = remaining;
256
- }
257
-
258
- /**
259
- * 处理队列下一项(FIFO)。
260
- *
261
- * processing 标志保证串行:handler 运行期间 processing=true,新的 processNext 调用直接返回;
262
- * handler settle 后由 settleItem 清 processing=false 并推进下一项(#19 单一推进点)。
263
- *
264
- * handler 抛错兜底(TC-E4 case 3):catch → settle {cancelled:true} → 继续。
265
- * 不能让一个失败卡死队列(processing 永远 true)。
266
- */
267
- private async processNext(): Promise<void> {
268
- if (this.processing) return;
269
- if (this.queue.length === 0) return;
270
- this.processing = true;
271
- const item = this.queue.shift()!;
272
- this.current = item;
273
- try {
274
- const resp = await item.handler(item.req);
275
- // handler 完成:settle(若已被 rejectChildDialogs 抢先 settle 则 noop)。
276
- // settleItem 内会清 current/processing 并推进队列(#19 单一推进点)。
277
- this.settleItem(item, resp);
278
- } catch {
279
- // handler 抛错兜底:回 cancelled,不向上抛(队列不能卡死)
280
- this.settleItem(item, { cancelled: true });
281
- }
282
- // #19:不在尾部再调 processNext——推进统一由 settleItem 负责(避免双重推进)。
283
- }
284
-
285
- /**
286
- * #10:把所有 pending dialog(queue + current)全部 settle 为 {cancelled:true},
287
- * 并清空 queue/current/processing 状态。session_shutdown 调用,保证不留永挂 Promise。
288
- *
289
- * 约定签名:rejectAll(): void(无参,返 void)。Group C 的 index.ts session_shutdown 依赖此契约。
290
- *
291
- * 幂等:依赖 settleItem 的 settled 标志——重复调用只会对已 settled 项 noop。
292
- * 顺序敏感(#19 推进点在 settleItem):必须先清空 queue 数组再 settle current,
293
- * 否则 settleItem(current) 同步触发的 processNext 会从旧 queue 抢占下一项作为新 current,
294
- * 避开本方法的 cancel 语义。清空后 processNext 看到空队列直接返回,新 current 不会被抢占。
295
- *
296
- * 单 session 假设(M-2):见类注释。本方法清空所有 pending 不分 session——依赖 Pi 单进程
297
- * 单 session 串行保证。session_shutdown handler(index.ts)调用本方法时,进程内只会有当前
298
- * session 的 pending dialog。多 session 并发场景的迁移策略(rejectAllForSession)见类注释。
299
- */
300
- rejectAll(): void {
301
- // 先捕获并清空队列——防 settleItem(current) 触发的 processNext 抢占同队列下一项
302
- const items = this.queue;
303
- this.queue = [];
304
- // 再 settle current(processNext 此时看到空队列,不会抢占)
305
- if (this.current) {
306
- this.settleItem(this.current, { cancelled: true });
307
- }
308
- // settle 所有原队列项(Promise 必须 resolve,不能挂)
309
- for (const item of items) {
310
- this.settleItem(item, { cancelled: true });
311
- }
312
- // 状态清理(幂等:settleItem(current) 可能已清)
313
- this.current = undefined;
314
- this.processing = false;
315
- }
316
-
317
- /** 清空队列状态(仅在 rejectAll 之后调用)。pending Promise 必须先由 rejectAll settle。
318
- * 不 settle Promise 的纯状态重置——单独调用会导致 Promise 永挂(footgun),故设为 private。
319
- * 外部调用方应使用 rejectAll()(它 settle 所有 pending + 重置状态,是原子操作)。 */
320
- private resetState(): void {
321
- this.queue = [];
322
- this.current = undefined;
323
- this.processing = false;
324
- }
325
-
326
- /** 当前队列长度(测试/诊断用)。含等待处理项(不含 current)。 */
327
- get size(): number {
328
- return this.queue.length;
329
- }
330
- }
@@ -1,53 +0,0 @@
1
- // data-dir.test.ts —— dataDir 通道解析(XYZ_AGENT_DATA_DIR 权威通道 + piAgentDir 回退)。
2
- //
3
- // 三视角:①构建者——两级解析顺序正确;②使用者——独立 pi 用户(无 xyz env)拿到
4
- // piAgentDir 作根;③观察者——回退路径 warn 一次(不留静默漂移),不刷屏。
5
- //
6
- // 注意:getAgentDir 在 vitest 下 alias 到 mocks/pi-coding-agent.ts(返回
7
- // /home/user/.pi/agent)——本测试只断言两级解析顺序与 warn 行为,不测 pi SDK 内部。
8
-
9
- import { beforeEach, describe, expect, it } from "vitest";
10
-
11
- import { getEngineDataDir, resetDataDirWarnForTests, XYZ_DATA_DIR_ENV } from "../../common/data-dir.ts";
12
-
13
- beforeEach(() => {
14
- resetDataDirWarnForTests();
15
- });
16
-
17
- describe("getEngineDataDir", () => {
18
- it("XYZ_AGENT_DATA_DIR 存在 → 权威通道直取,不 warn", () => {
19
- const warnings: string[] = [];
20
- const dir = getEngineDataDir({ [XYZ_DATA_DIR_ENV]: "/data/xyz-agent" }, (m) => warnings.push(m));
21
- expect(dir).toBe("/data/xyz-agent");
22
- expect(warnings).toEqual([]);
23
- });
24
-
25
- it("空串/空白串视为缺失(truthy 语义与 shared getDataDir 的 || 归一对齐)", () => {
26
- const warnings: string[] = [];
27
- const dir = getEngineDataDir({ [XYZ_DATA_DIR_ENV]: " " }, (m) => warnings.push(m));
28
- expect(dir).not.toBe(" ");
29
- expect(warnings.length).toBe(1);
30
- });
31
-
32
- it("缺 env → 回退 piAgentDir(getAgentDir(),mock 值)并 warn 一次", () => {
33
- const warnings: string[] = [];
34
- const warn = (m: string): void => warnings.push(m);
35
- const dir1 = getEngineDataDir({}, warn);
36
- expect(dir1).toBe("/home/user/.pi/agent"); // vitest mock 的 getAgentDir
37
- expect(warnings.length).toBe(1);
38
- expect(warnings[0]).toContain("XYZ_AGENT_DATA_DIR");
39
-
40
- // warn once:第二次调用不再刷
41
- const dir2 = getEngineDataDir({}, warn);
42
- expect(dir2).toBe(dir1);
43
- expect(warnings.length).toBe(1);
44
- });
45
-
46
- it("reset 后再次回退会重新 warn(测试隔离钩子可用)", () => {
47
- const warnings: string[] = [];
48
- getEngineDataDir({}, (m) => warnings.push(m));
49
- resetDataDirWarnForTests();
50
- getEngineDataDir({}, (m) => warnings.push(m));
51
- expect(warnings.length).toBe(2);
52
- });
53
- });