@zhushanwen/pi-subagent-workflow 8.6.0 → 8.8.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 (364) hide show
  1. package/README.md +5 -11
  2. package/package.json +13 -20
  3. package/relay/relay.mjs +1 -1
  4. package/skills/workflow-script-format/SKILL.md +32 -13
  5. package/src/host/__tests__/pi-host.test.ts +235 -0
  6. package/src/host/pi-host.ts +163 -0
  7. package/src/index.ts +141 -138
  8. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  9. package/src/injectors/__tests__/engine-section-stability.test.ts +343 -0
  10. package/src/injectors/__tests__/model-list-injector.test.ts +18 -21
  11. package/src/injectors/__tests__/subagent-list-injector.test.ts +59 -19
  12. package/src/injectors/__tests__/workflow-list-injector.test.ts +31 -17
  13. package/src/injectors/engine-awareness.ts +119 -0
  14. package/src/injectors/model-list-injector.ts +15 -58
  15. package/src/injectors/subagent-list-injector.ts +56 -114
  16. package/src/injectors/workflow-list-injector.ts +37 -70
  17. package/src/interface/__tests__/detectors.test.ts +48 -37
  18. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +2 -2
  19. package/src/interface/__tests__/subagent-tool-prompt.test.ts +6 -3
  20. package/src/interface/__tests__/tool-workflow-run-builtin-name.test.ts +216 -0
  21. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +17 -6
  22. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +38 -2
  23. package/src/interface/bg-notify-render.ts +7 -17
  24. package/src/interface/command-actions.ts +5 -15
  25. package/src/interface/commands.ts +4 -4
  26. package/src/interface/format.ts +17 -6
  27. package/src/interface/gui-mappers.ts +18 -22
  28. package/src/interface/helpers.ts +9 -130
  29. package/src/interface/list-component.ts +5 -5
  30. package/src/interface/list-shared.ts +3 -3
  31. package/src/interface/list-view.ts +3 -3
  32. package/src/interface/subagent-actions.ts +66 -439
  33. package/src/interface/subagent-tool-schema.ts +21 -17
  34. package/src/interface/subagent-tool.ts +12 -7
  35. package/src/interface/subagents.ts +4 -4
  36. package/src/interface/tool-render.ts +37 -15
  37. package/src/interface/tool-workflow-script.ts +34 -76
  38. package/src/interface/tool-workflow.ts +57 -94
  39. package/src/interface/views/WorkflowsView.ts +8 -16
  40. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  41. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  42. package/src/interface/views/detail-content.ts +4 -4
  43. package/src/interface/views/format.ts +23 -62
  44. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +137 -225
  45. package/agents/analyst.md +0 -61
  46. package/agents/coder.md +0 -70
  47. package/agents/debugger.md +0 -67
  48. package/agents/doc-reviewer.md +0 -50
  49. package/agents/explorer.md +0 -64
  50. package/agents/general-purpose.md +0 -32
  51. package/agents/orchestrator.md +0 -63
  52. package/agents/planner.md +0 -54
  53. package/agents/researcher.md +0 -65
  54. package/agents/reviewer.md +0 -74
  55. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  56. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  57. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  58. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  59. package/src/execution/__tests__/alive-store.test.ts +0 -147
  60. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  61. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  62. package/src/execution/__tests__/bg-notify-render.test.ts +0 -329
  63. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  64. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -601
  65. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  66. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  67. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  68. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  69. package/src/execution/__tests__/config.test.ts +0 -110
  70. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  71. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  72. package/src/execution/__tests__/delivery-methods.test.ts +0 -422
  73. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  74. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  75. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  76. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  77. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  78. package/src/execution/__tests__/execution-record.test.ts +0 -1394
  79. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +0 -171
  80. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  81. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  82. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -169
  83. package/src/execution/__tests__/format.test.ts +0 -458
  84. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  85. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  86. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  87. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  88. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -242
  89. package/src/execution/__tests__/host-mode.test.ts +0 -87
  90. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  91. package/src/execution/__tests__/index-session-start.test.ts +0 -672
  92. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  93. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -383
  94. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  95. package/src/execution/__tests__/list-component.test.ts +0 -401
  96. package/src/execution/__tests__/list-fields.test.ts +0 -140
  97. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  98. package/src/execution/__tests__/model-resolver.test.ts +0 -465
  99. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  100. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  101. package/src/execution/__tests__/notifier-flush.test.ts +0 -612
  102. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  103. package/src/execution/__tests__/notify-ledger.test.ts +0 -826
  104. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  105. package/src/execution/__tests__/output-collector.test.ts +0 -358
  106. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  107. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  108. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  109. package/src/execution/__tests__/record-store.test.ts +0 -1057
  110. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  111. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  112. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  113. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  114. package/src/execution/__tests__/relay-env.test.ts +0 -42
  115. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  116. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  117. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  118. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  119. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -687
  120. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  121. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  122. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  123. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -199
  124. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  125. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  126. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  127. package/src/execution/__tests__/session-pending.test.ts +0 -197
  128. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  129. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  130. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -350
  131. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  132. package/src/execution/__tests__/spawn-args.test.ts +0 -445
  133. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  134. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  135. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  136. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  137. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  138. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  139. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  140. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  141. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  142. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  143. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  144. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  145. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  146. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  147. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -599
  148. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  149. package/src/execution/__tests__/timeout-integration.test.ts +0 -615
  150. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  151. package/src/execution/__tests__/tool-action.test.ts +0 -476
  152. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  153. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  154. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  155. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  156. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  157. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  158. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  159. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  160. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  161. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  162. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  163. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  164. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  165. package/src/execution/agent-registry.ts +0 -199
  166. package/src/execution/agent-result-mapper.ts +0 -90
  167. package/src/execution/alive-store.ts +0 -92
  168. package/src/execution/argv-mirror.ts +0 -113
  169. package/src/execution/best-effort.ts +0 -38
  170. package/src/execution/channel-registry-access.ts +0 -144
  171. package/src/execution/concurrency-pool.ts +0 -116
  172. package/src/execution/config.ts +0 -96
  173. package/src/execution/dialog-queue.ts +0 -330
  174. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  175. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  176. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  177. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  178. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  179. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  180. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  181. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  182. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  183. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  184. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  185. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  186. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  187. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  188. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  189. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  190. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  191. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  192. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  193. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  194. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  195. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  196. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  197. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  198. package/src/execution/engine/common/data-dir.ts +0 -62
  199. package/src/execution/engine/common/errors.ts +0 -183
  200. package/src/execution/engine/common/event-journal.ts +0 -254
  201. package/src/execution/engine/common/journal-replay.ts +0 -62
  202. package/src/execution/engine/common/kill-chain.ts +0 -221
  203. package/src/execution/engine/common/nesting-guard.ts +0 -50
  204. package/src/execution/engine/common/persona-router.ts +0 -108
  205. package/src/execution/engine/common/pool-manager.ts +0 -226
  206. package/src/execution/engine/common/schema-emulation.ts +0 -189
  207. package/src/execution/engine/common/session-view-projection.ts +0 -51
  208. package/src/execution/engine/engine-discovery.ts +0 -65
  209. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  210. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  211. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  212. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  213. package/src/execution/engine/engines/pi/reader.ts +0 -48
  214. package/src/execution/engine/engines/pi/registration.ts +0 -35
  215. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  216. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  217. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  218. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  219. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  220. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  221. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  222. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  223. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  224. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  225. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  226. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  227. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  228. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  229. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  230. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  231. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -658
  232. package/src/execution/engine/host-task-spec.ts +0 -47
  233. package/src/execution/engine/model-prompt.ts +0 -59
  234. package/src/execution/engine/paths.ts +0 -42
  235. package/src/execution/engine/port.ts +0 -153
  236. package/src/execution/engine/registry.ts +0 -123
  237. package/src/execution/engine/routing.ts +0 -218
  238. package/src/execution/engine/types.ts +0 -309
  239. package/src/execution/execute-options-mapper.ts +0 -112
  240. package/src/execution/execution-record.ts +0 -965
  241. package/src/execution/finalize-record.ts +0 -251
  242. package/src/execution/finalized-marker.ts +0 -51
  243. package/src/execution/get-state-handshake.ts +0 -104
  244. package/src/execution/host-mode.ts +0 -56
  245. package/src/execution/idle-gc.ts +0 -47
  246. package/src/execution/lifecycle-manager.ts +0 -513
  247. package/src/execution/lifecycle-predicates.ts +0 -65
  248. package/src/execution/manifest-store.ts +0 -256
  249. package/src/execution/model-config-service.ts +0 -219
  250. package/src/execution/model-resolver.ts +0 -248
  251. package/src/execution/notifier.ts +0 -330
  252. package/src/execution/notify-ledger.ts +0 -580
  253. package/src/execution/output-collector.ts +0 -228
  254. package/src/execution/path-encoding.ts +0 -60
  255. package/src/execution/pi-invocation.ts +0 -120
  256. package/src/execution/record-entry.ts +0 -132
  257. package/src/execution/record-store.ts +0 -1234
  258. package/src/execution/relay-env.ts +0 -37
  259. package/src/execution/session-context-resolver.ts +0 -64
  260. package/src/execution/session-file-gc.ts +0 -120
  261. package/src/execution/session-pending.ts +0 -164
  262. package/src/execution/session-reconstructor.ts +0 -678
  263. package/src/execution/session-runner.ts +0 -1781
  264. package/src/execution/sessions-index.ts +0 -304
  265. package/src/execution/spawn-event-adapter.ts +0 -363
  266. package/src/execution/stdin-writer.ts +0 -198
  267. package/src/execution/stream-sink.ts +0 -126
  268. package/src/execution/subagent-service.ts +0 -2141
  269. package/src/execution/subprocess-agent-runner.ts +0 -317
  270. package/src/execution/temp-prompt.ts +0 -62
  271. package/src/execution/tombstone-store.ts +0 -72
  272. package/src/execution/turn-limiter.ts +0 -102
  273. package/src/execution/types.ts +0 -973
  274. package/src/execution/ui-channels.ts +0 -216
  275. package/src/execution/ui-interaction-model.ts +0 -48
  276. package/src/execution/ui-request-handler-factory.ts +0 -212
  277. package/src/execution/ui-request-observability.ts +0 -81
  278. package/src/execution/ui-request-queue.ts +0 -184
  279. package/src/execution/worktree-manager.ts +0 -688
  280. package/src/execution/worktree-registry.ts +0 -222
  281. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -349
  282. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -202
  283. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -152
  284. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  285. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  286. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -809
  287. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  288. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  289. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  290. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -451
  291. package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +0 -150
  292. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  293. package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +0 -202
  294. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  295. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -600
  296. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  297. package/src/orchestration/__tests__/lifecycle.test.ts +0 -659
  298. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +0 -95
  299. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -2025
  300. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  301. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -201
  302. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  303. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +0 -368
  304. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  305. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  306. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -563
  307. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  308. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -129
  309. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  310. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  311. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  312. package/src/orchestration/agent-opts-resolver.ts +0 -174
  313. package/src/orchestration/args-validator.ts +0 -127
  314. package/src/orchestration/config-loader.ts +0 -315
  315. package/src/orchestration/error-recovery.ts +0 -1018
  316. package/src/orchestration/execute-agent-call.ts +0 -256
  317. package/src/orchestration/launcher.ts +0 -455
  318. package/src/orchestration/lifecycle.ts +0 -399
  319. package/src/orchestration/models/__tests__/budget.test.ts +0 -307
  320. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  321. package/src/orchestration/models/agent-call.ts +0 -83
  322. package/src/orchestration/models/budget.ts +0 -118
  323. package/src/orchestration/models/ports.ts +0 -164
  324. package/src/orchestration/models/run-runtime.ts +0 -104
  325. package/src/orchestration/models/run-spec.ts +0 -83
  326. package/src/orchestration/models/run-state.ts +0 -44
  327. package/src/orchestration/models/trace.ts +0 -183
  328. package/src/orchestration/models/types.ts +0 -301
  329. package/src/orchestration/models/workflow-run.ts +0 -254
  330. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  331. package/src/orchestration/models/workflow-script.ts +0 -117
  332. package/src/orchestration/script-lint.ts +0 -766
  333. package/src/orchestration/skill-discovery.ts +0 -115
  334. package/src/orchestration/worker-handle.ts +0 -115
  335. package/src/orchestration/worker-host.ts +0 -98
  336. package/src/orchestration/worker-script-builder.ts +0 -421
  337. package/src/orchestration/workflow-files.ts +0 -85
  338. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  339. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  340. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  341. package/src/shared/__tests__/model-ref.test.ts +0 -306
  342. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  343. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  344. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  345. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  346. package/src/shared/__tests__/timer-delay.test.ts +0 -61
  347. package/src/shared/agent-event.ts +0 -13
  348. package/src/shared/agent-ref.ts +0 -57
  349. package/src/shared/meta-parser.ts +0 -261
  350. package/src/shared/model-ref.ts +0 -286
  351. package/src/shared/resource-discovery.ts +0 -811
  352. package/src/shared/resource-meta.ts +0 -65
  353. package/src/shared/schema-env.ts +0 -44
  354. package/src/shared/schema-jsonify.ts +0 -58
  355. package/src/shared/timer-delay.ts +0 -54
  356. package/src/shared/xml-injection.ts +0 -35
  357. package/workflows/README.md +0 -81
  358. package/workflows/_shared/agent-refs.cjs +0 -40
  359. package/workflows/chain.js +0 -131
  360. package/workflows/map-reduce.js +0 -174
  361. package/workflows/parallel.js +0 -148
  362. package/workflows/review-fix-loop-utils.cjs +0 -1309
  363. package/workflows/review-fix-loop.js +0 -1404
  364. 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",对齐包内 AbortError 错误语义约定(消费方按 err.name 判别)
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
- });