@zhushanwen/pi-subagent-workflow 8.6.0 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (347) hide show
  1. package/package.json +9 -13
  2. package/relay/relay.mjs +1 -1
  3. package/src/host/__tests__/pi-host.test.ts +214 -0
  4. package/src/host/pi-host.ts +109 -0
  5. package/src/index.ts +89 -32
  6. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  7. package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
  8. package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
  9. package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
  10. package/src/injectors/engine-awareness.ts +123 -0
  11. package/src/injectors/model-list-injector.ts +1 -1
  12. package/src/injectors/subagent-list-injector.ts +8 -8
  13. package/src/injectors/workflow-list-injector.ts +8 -8
  14. package/src/interface/__tests__/detectors.test.ts +3 -3
  15. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +2 -2
  16. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  17. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  18. package/src/interface/bg-notify-render.ts +4 -4
  19. package/src/interface/commands.ts +3 -3
  20. package/src/interface/format.ts +2 -2
  21. package/src/interface/helpers.ts +1 -1
  22. package/src/interface/list-component.ts +4 -4
  23. package/src/interface/list-shared.ts +2 -2
  24. package/src/interface/list-view.ts +2 -2
  25. package/src/interface/subagent-actions.ts +263 -11
  26. package/src/interface/subagent-tool-schema.ts +20 -13
  27. package/src/interface/subagent-tool.ts +11 -6
  28. package/src/interface/subagents.ts +3 -3
  29. package/src/interface/tool-render.ts +34 -2
  30. package/src/interface/tool-workflow-script.ts +4 -4
  31. package/src/interface/tool-workflow.ts +6 -6
  32. package/src/interface/views/WorkflowsView.ts +5 -5
  33. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  34. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  35. package/src/interface/views/detail-content.ts +4 -4
  36. package/src/interface/views/format.ts +4 -4
  37. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +11 -11
  38. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  39. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  40. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  41. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  42. package/src/execution/__tests__/alive-store.test.ts +0 -147
  43. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  44. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  45. package/src/execution/__tests__/bg-notify-render.test.ts +0 -329
  46. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  47. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -601
  48. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  49. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  50. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  51. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  52. package/src/execution/__tests__/config.test.ts +0 -110
  53. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  54. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  55. package/src/execution/__tests__/delivery-methods.test.ts +0 -422
  56. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  57. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  58. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  59. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  60. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
  61. package/src/execution/__tests__/execution-record.test.ts +0 -1394
  62. package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +0 -171
  63. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  64. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  65. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -169
  66. package/src/execution/__tests__/format.test.ts +0 -458
  67. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  68. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  69. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  70. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  71. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -242
  72. package/src/execution/__tests__/host-mode.test.ts +0 -87
  73. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  74. package/src/execution/__tests__/index-session-start.test.ts +0 -672
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -383
  77. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  78. package/src/execution/__tests__/list-component.test.ts +0 -401
  79. package/src/execution/__tests__/list-fields.test.ts +0 -140
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -465
  82. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  83. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  84. package/src/execution/__tests__/notifier-flush.test.ts +0 -612
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/notify-ledger.test.ts +0 -826
  87. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  88. package/src/execution/__tests__/output-collector.test.ts +0 -358
  89. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  90. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  91. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  92. package/src/execution/__tests__/record-store.test.ts +0 -1057
  93. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  94. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  95. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  96. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  97. package/src/execution/__tests__/relay-env.test.ts +0 -42
  98. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  99. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  100. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  101. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  102. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -687
  103. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  104. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  105. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  106. package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -199
  107. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  108. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  109. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  110. package/src/execution/__tests__/session-pending.test.ts +0 -197
  111. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  112. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  113. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -350
  114. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  115. package/src/execution/__tests__/spawn-args.test.ts +0 -445
  116. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  117. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  118. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  119. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  120. package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
  121. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  122. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  123. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  124. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  125. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  126. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  127. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  128. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  129. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  130. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -599
  131. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  132. package/src/execution/__tests__/timeout-integration.test.ts +0 -615
  133. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  134. package/src/execution/__tests__/tool-action.test.ts +0 -476
  135. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  136. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  137. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  138. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  139. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  140. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  141. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  142. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  143. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  144. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  145. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  146. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  147. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  148. package/src/execution/agent-registry.ts +0 -199
  149. package/src/execution/agent-result-mapper.ts +0 -90
  150. package/src/execution/alive-store.ts +0 -92
  151. package/src/execution/argv-mirror.ts +0 -113
  152. package/src/execution/best-effort.ts +0 -38
  153. package/src/execution/channel-registry-access.ts +0 -144
  154. package/src/execution/concurrency-pool.ts +0 -116
  155. package/src/execution/config.ts +0 -96
  156. package/src/execution/dialog-queue.ts +0 -330
  157. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  158. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  159. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  160. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  161. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  162. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  163. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  164. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  165. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  166. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  167. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  168. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  169. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  170. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  171. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  172. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  173. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  174. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  175. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  176. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  177. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  178. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  179. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  180. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  181. package/src/execution/engine/common/data-dir.ts +0 -62
  182. package/src/execution/engine/common/errors.ts +0 -183
  183. package/src/execution/engine/common/event-journal.ts +0 -254
  184. package/src/execution/engine/common/journal-replay.ts +0 -62
  185. package/src/execution/engine/common/kill-chain.ts +0 -221
  186. package/src/execution/engine/common/nesting-guard.ts +0 -50
  187. package/src/execution/engine/common/persona-router.ts +0 -108
  188. package/src/execution/engine/common/pool-manager.ts +0 -226
  189. package/src/execution/engine/common/schema-emulation.ts +0 -189
  190. package/src/execution/engine/common/session-view-projection.ts +0 -51
  191. package/src/execution/engine/engine-discovery.ts +0 -65
  192. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  193. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  194. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  195. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  196. package/src/execution/engine/engines/pi/reader.ts +0 -48
  197. package/src/execution/engine/engines/pi/registration.ts +0 -35
  198. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  199. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  200. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  201. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  202. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  203. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  204. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  205. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  206. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
  207. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  208. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  209. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  210. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  211. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  212. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  213. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  214. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -658
  215. package/src/execution/engine/host-task-spec.ts +0 -47
  216. package/src/execution/engine/model-prompt.ts +0 -59
  217. package/src/execution/engine/paths.ts +0 -42
  218. package/src/execution/engine/port.ts +0 -153
  219. package/src/execution/engine/registry.ts +0 -123
  220. package/src/execution/engine/routing.ts +0 -218
  221. package/src/execution/engine/types.ts +0 -309
  222. package/src/execution/execute-options-mapper.ts +0 -112
  223. package/src/execution/execution-record.ts +0 -965
  224. package/src/execution/finalize-record.ts +0 -251
  225. package/src/execution/finalized-marker.ts +0 -51
  226. package/src/execution/get-state-handshake.ts +0 -104
  227. package/src/execution/host-mode.ts +0 -56
  228. package/src/execution/idle-gc.ts +0 -47
  229. package/src/execution/lifecycle-manager.ts +0 -513
  230. package/src/execution/lifecycle-predicates.ts +0 -65
  231. package/src/execution/manifest-store.ts +0 -256
  232. package/src/execution/model-config-service.ts +0 -219
  233. package/src/execution/model-resolver.ts +0 -248
  234. package/src/execution/notifier.ts +0 -330
  235. package/src/execution/notify-ledger.ts +0 -580
  236. package/src/execution/output-collector.ts +0 -228
  237. package/src/execution/path-encoding.ts +0 -60
  238. package/src/execution/pi-invocation.ts +0 -120
  239. package/src/execution/record-entry.ts +0 -132
  240. package/src/execution/record-store.ts +0 -1234
  241. package/src/execution/relay-env.ts +0 -37
  242. package/src/execution/session-context-resolver.ts +0 -64
  243. package/src/execution/session-file-gc.ts +0 -120
  244. package/src/execution/session-pending.ts +0 -164
  245. package/src/execution/session-reconstructor.ts +0 -678
  246. package/src/execution/session-runner.ts +0 -1781
  247. package/src/execution/sessions-index.ts +0 -304
  248. package/src/execution/spawn-event-adapter.ts +0 -363
  249. package/src/execution/stdin-writer.ts +0 -198
  250. package/src/execution/stream-sink.ts +0 -126
  251. package/src/execution/subagent-service.ts +0 -2141
  252. package/src/execution/subprocess-agent-runner.ts +0 -317
  253. package/src/execution/temp-prompt.ts +0 -62
  254. package/src/execution/tombstone-store.ts +0 -72
  255. package/src/execution/turn-limiter.ts +0 -102
  256. package/src/execution/types.ts +0 -973
  257. package/src/execution/ui-channels.ts +0 -216
  258. package/src/execution/ui-interaction-model.ts +0 -48
  259. package/src/execution/ui-request-handler-factory.ts +0 -212
  260. package/src/execution/ui-request-observability.ts +0 -81
  261. package/src/execution/ui-request-queue.ts +0 -184
  262. package/src/execution/worktree-manager.ts +0 -688
  263. package/src/execution/worktree-registry.ts +0 -222
  264. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -349
  265. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -202
  266. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -152
  267. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  268. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  269. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -809
  270. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  271. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  272. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  273. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -451
  274. package/src/orchestration/__tests__/jsonl-run-store-corrupt-entry.test.ts +0 -150
  275. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  276. package/src/orchestration/__tests__/jsonl-run-store-retention.test.ts +0 -202
  277. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  278. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -600
  279. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  280. package/src/orchestration/__tests__/lifecycle.test.ts +0 -659
  281. package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +0 -95
  282. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -2025
  283. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  284. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -201
  285. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  286. package/src/orchestration/__tests__/worker-exit-without-result.test.ts +0 -368
  287. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  288. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  289. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -563
  290. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  291. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -129
  292. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  293. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  294. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  295. package/src/orchestration/agent-opts-resolver.ts +0 -174
  296. package/src/orchestration/args-validator.ts +0 -127
  297. package/src/orchestration/config-loader.ts +0 -315
  298. package/src/orchestration/error-recovery.ts +0 -1018
  299. package/src/orchestration/execute-agent-call.ts +0 -256
  300. package/src/orchestration/launcher.ts +0 -455
  301. package/src/orchestration/lifecycle.ts +0 -399
  302. package/src/orchestration/models/__tests__/budget.test.ts +0 -307
  303. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  304. package/src/orchestration/models/agent-call.ts +0 -83
  305. package/src/orchestration/models/budget.ts +0 -118
  306. package/src/orchestration/models/ports.ts +0 -164
  307. package/src/orchestration/models/run-runtime.ts +0 -104
  308. package/src/orchestration/models/run-spec.ts +0 -83
  309. package/src/orchestration/models/run-state.ts +0 -44
  310. package/src/orchestration/models/trace.ts +0 -183
  311. package/src/orchestration/models/types.ts +0 -301
  312. package/src/orchestration/models/workflow-run.ts +0 -254
  313. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  314. package/src/orchestration/models/workflow-script.ts +0 -117
  315. package/src/orchestration/script-lint.ts +0 -766
  316. package/src/orchestration/skill-discovery.ts +0 -115
  317. package/src/orchestration/worker-handle.ts +0 -115
  318. package/src/orchestration/worker-host.ts +0 -98
  319. package/src/orchestration/worker-script-builder.ts +0 -421
  320. package/src/orchestration/workflow-files.ts +0 -85
  321. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  322. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  323. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  324. package/src/shared/__tests__/model-ref.test.ts +0 -306
  325. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  326. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  327. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  328. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  329. package/src/shared/__tests__/timer-delay.test.ts +0 -61
  330. package/src/shared/agent-event.ts +0 -13
  331. package/src/shared/agent-ref.ts +0 -57
  332. package/src/shared/meta-parser.ts +0 -261
  333. package/src/shared/model-ref.ts +0 -286
  334. package/src/shared/resource-discovery.ts +0 -811
  335. package/src/shared/resource-meta.ts +0 -65
  336. package/src/shared/schema-env.ts +0 -44
  337. package/src/shared/schema-jsonify.ts +0 -58
  338. package/src/shared/timer-delay.ts +0 -54
  339. package/src/shared/xml-injection.ts +0 -35
  340. package/workflows/README.md +0 -81
  341. package/workflows/_shared/agent-refs.cjs +0 -40
  342. package/workflows/chain.js +0 -131
  343. package/workflows/map-reduce.js +0 -174
  344. package/workflows/parallel.js +0 -148
  345. package/workflows/review-fix-loop-utils.cjs +0 -1309
  346. package/workflows/review-fix-loop.js +0 -1404
  347. package/workflows/scatter-gather.js +0 -178
@@ -1,336 +0,0 @@
1
- // src/execution/__tests__/parent-child-matrix.test.ts
2
- //
3
- // SP-4: 父子联动测试(真实 SubagentService + index.ts 事件接线)。
4
- //
5
- // [M2/M7 重写] 旧套件在测试内手写 tryTransition/completeRecord/recentlyCascaded 模拟
6
- // (平行复刻生产逻辑),生产代码任何回归恒绿。现改为两层真实驱动:
7
- // Block 1: 真实 SubagentService.onParentFork / onParentNew / disposeAllRecords
8
- // → 断言 record 转 closed + closedReason + archive + pending:unregister
9
- // Block 2: 真实 index.ts factory 注册的 session_before_fork / session_before_switch
10
- // handler 驱动同一真实 Service → 断言事件接线与 reason 门控
11
- //
12
- // 事件语义依据 SDK 0.82.1(core/agent-session-runtime.js + core/agent-session.js):
13
- // /fork → session_before_fork(entryId, position) → teardown("fork")
14
- // /new → session_before_switch(reason:"new") → teardown("new")
15
- // (/new 从不触发 session_before_tree——旧实现误挂即 M2 bug)
16
- // /resume /import → session_before_switch(reason:"resume")
17
- // /tree → session_before_tree(同 session 内分支导航,无 session 替换)
18
- // + session_tree(导航后)——均无级联关闭语义
19
-
20
- import * as fs from "node:fs";
21
- import * as os from "node:os";
22
- import * as path from "node:path";
23
-
24
- import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
25
-
26
- import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
27
-
28
- // mock logger(import 链需要 getLogger 存在;对齐 subagent-service-parent-guard.test.ts。
29
- // setPiHandle 是 index.ts factory 顶层调用(注入 pi handle 给全局 logger),需一并 stub)
30
- const { loggerMock } = vi.hoisted(() => ({
31
- loggerMock: { debug: vi.fn(), warn: vi.fn(), error: vi.fn(), info: vi.fn() },
32
- }));
33
- vi.mock("@zhushanwen/pi-extension-logger", () => ({
34
- getLogger: () => loggerMock,
35
- setPiHandle: vi.fn(),
36
- }));
37
-
38
- // mock session-runner(import 链需要 runSpawn/killAllSpawnedChildren/getChildByRecord;
39
- // 避免真实 kill,且 dispose 收割路径可断言)
40
- const { killAllSpawnedChildrenMock } = vi.hoisted(() => ({
41
- killAllSpawnedChildrenMock: vi.fn(),
42
- }));
43
- vi.mock("../session-runner.ts", () => ({
44
- runSpawn: vi.fn(),
45
- killAllSpawnedChildren: killAllSpawnedChildrenMock,
46
- getChildByRecord: vi.fn(() => undefined),
47
- }));
48
-
49
- import { createRecord } from "../execution-record.ts";
50
- import { ModelConfigService } from "../model-config-service.ts";
51
- import { RecordStore } from "../record-store.ts";
52
- import { SubagentService, setSubagentService } from "../subagent-service.ts";
53
- import type { PiLike } from "../subagent-service.ts";
54
- import type { ExecutionRecord } from "../types.ts";
55
- import subagentsExtension from "../../index.ts";
56
-
57
- // ── helpers ──
58
-
59
- function makeTmpAgentDir(): string {
60
- return fs.mkdtempSync(path.join(os.tmpdir(), "parent-child-matrix-"));
61
- }
62
-
63
- /** 最小 mock PiLike(appendEntry/events.emit/sendMessage 全部可断言)。 */
64
- function makePi(): { pi: PiLike; eventsEmit: ReturnType<typeof vi.fn> } {
65
- const eventsEmit = vi.fn();
66
- const pi = {
67
- appendEntry: vi.fn(),
68
- events: { emit: eventsEmit },
69
- sendMessage: vi.fn(),
70
- } as unknown as PiLike;
71
- return { pi, eventsEmit };
72
- }
73
-
74
- /** 暴露私有字段供测试注入 record(对齐 subagent-service-parent-guard.test.ts 模式)。 */
75
- interface ServiceInternals {
76
- store: RecordStore;
77
- }
78
-
79
- /** 构造一个 running 状态的 ExecutionRecord(内存态,register 进真实 store)。 */
80
- function makeRunningRecord(id: string, overrides: Partial<ExecutionRecord> = {}): ExecutionRecord {
81
- return createRecord(id, {
82
- agent: "general-purpose",
83
- model: "test/model",
84
- mode: "background",
85
- task: `task for ${id}`,
86
- slug: `slug-${id}`,
87
- startedAt: Date.now(),
88
- rootSessionId: "root-session",
89
- controller: new AbortController(),
90
- ...overrides,
91
- });
92
- }
93
-
94
- /** 重置进程级 SubagentService 单例槽(setSubagentService 不接受 null,测试清理用)。
95
- * key 与生产 getServiceSlot 的 SERVICE_SLOT_KEY(subagent-service.ts)一致。 */
96
- function resetServiceSlot(): void {
97
- const slot = Reflect.get(globalThis, Symbol.for("@zhushanwen/pi-subagents.service")) as
98
- | { current: SubagentService | null }
99
- | undefined;
100
- if (slot) slot.current = null;
101
- }
102
-
103
- /** 创建真实 SubagentService(tmp agentDir + mock pi),返回 service 与内部 store。 */
104
- function setupRealService(): { service: SubagentService; store: RecordStore } {
105
- const agentDir = makeTmpAgentDir();
106
- const modelService = new ModelConfigService({ agentDir });
107
- const service = new SubagentService({ cwd: agentDir, modelService });
108
- service.initSession({ pi: makePi().pi, sessionId: "root-session" });
109
- const store = (service as unknown as ServiceInternals).store;
110
- return { service, store, agentDir };
111
- }
112
-
113
- // ============================================================
114
- // Block 1: 真实 SubagentService 级联关闭
115
- // ============================================================
116
-
117
- describe("SP-4 级联关闭(真实 SubagentService)", () => {
118
- let agentDir: string;
119
- let service: SubagentService;
120
- let store: RecordStore;
121
- let eventsEmit: ReturnType<typeof vi.fn>;
122
-
123
- beforeEach(() => {
124
- agentDir = makeTmpAgentDir();
125
- const modelService = new ModelConfigService({ agentDir });
126
- const { pi, eventsEmit: emit } = makePi();
127
- eventsEmit = emit;
128
- service = new SubagentService({ cwd: agentDir, modelService });
129
- service.initSession({ pi, sessionId: "root-session" });
130
- store = (service as unknown as ServiceInternals).store;
131
- });
132
-
133
- afterEach(() => {
134
- service.dispose();
135
- fs.rmSync(agentDir, { recursive: true, force: true });
136
- });
137
-
138
- it("onParentFork:running record 转 closed + closedReason=parent-fork,并从内存归档", () => {
139
- const record = makeRunningRecord("sa-fork-1");
140
- store.register(record);
141
-
142
- const count = service.onParentFork();
143
-
144
- expect(count).toBe(1);
145
- expect(record.status).toBe("closed");
146
- expect(record.closedReason).toBe("parent-fork");
147
- expect(record.endedAt).toBeDefined();
148
- // completeRecord 冻结合成 AgentResult(disposeAllRecords 构造,无在途执行)
149
- expect(record.error).toBe("closed due to parent-fork");
150
- // archive 生效:终态 record 立即从内存移除(读时从 session.jsonl 重建)
151
- expect(store.getMutable("sa-fork-1")).toBeUndefined();
152
- expect(store.listAllActive()).toHaveLength(0);
153
- });
154
-
155
- it("onParentNew:running record 转 closed + closedReason=parent-new", () => {
156
- const record = makeRunningRecord("sa-new-1");
157
- store.register(record);
158
-
159
- const count = service.onParentNew();
160
-
161
- expect(count).toBe(1);
162
- expect(record.status).toBe("closed");
163
- expect(record.closedReason).toBe("parent-new");
164
- expect(store.getMutable("sa-new-1")).toBeUndefined();
165
- });
166
-
167
- it("多个 running record 全部级联关闭,返回 count 与 record 数一致", () => {
168
- const records = [
169
- makeRunningRecord("sa-multi-1"),
170
- makeRunningRecord("sa-multi-2"),
171
- makeRunningRecord("sa-multi-3"),
172
- ];
173
- for (const r of records) store.register(r);
174
-
175
- const count = service.onParentNew();
176
-
177
- expect(count).toBe(3);
178
- for (const r of records) {
179
- expect(r.status).toBe("closed");
180
- expect(r.closedReason).toBe("parent-new");
181
- }
182
- expect(store.listAllActive()).toHaveLength(0);
183
- });
184
-
185
- it("级联关闭对每个被关 record 发 pending:unregister(reason=closed)", () => {
186
- const record = makeRunningRecord("sa-pending-1");
187
- store.register(record);
188
-
189
- service.onParentFork();
190
-
191
- expect(eventsEmit).toHaveBeenCalledWith("pending:unregister", {
192
- id: "sa-pending-1",
193
- reason: "closed",
194
- });
195
- });
196
-
197
- it("幂等:无活跃 record 返回 0;级联后再次调用返回 0(record 已归档)", () => {
198
- expect(service.onParentNew()).toBe(0);
199
-
200
- const record = makeRunningRecord("sa-idem-1");
201
- store.register(record);
202
- expect(service.onParentFork()).toBe(1);
203
- expect(service.onParentFork()).toBe(0); // 已 closed + archived,不重复关
204
- });
205
- });
206
-
207
- // ============================================================
208
- // Block 2: index.ts 事件接线(真实 factory + 真实 Service)
209
- // ============================================================
210
-
211
- describe("SP-4 index.ts 事件接线", () => {
212
- type PiHandler = (...args: unknown[]) => void | Promise<void>;
213
- const registered = new Map<string, PiHandler>();
214
- let processOnSpy: ReturnType<typeof vi.spyOn>;
215
- let agentDir: string;
216
- let service: SubagentService;
217
- let store: RecordStore;
218
-
219
- /** 最小 mock ExtensionAPI:捕获 pi.on 注册的 handler(对齐 process-shutdown-hook.test.ts 模式)。 */
220
- function createMockPi(): ExtensionAPI {
221
- const noop = (): void => {
222
- /* mock */
223
- };
224
- return {
225
- registerTool: vi.fn(),
226
- registerCommand: vi.fn(),
227
- registerMessageRenderer: vi.fn(),
228
- on: (event: string, handler: PiHandler) => {
229
- registered.set(event, handler);
230
- },
231
- appendEntry: vi.fn(),
232
- events: { emit: vi.fn(), on: vi.fn() },
233
- } as unknown as ExtensionAPI;
234
- }
235
-
236
- beforeEach(() => {
237
- // 捕获 process.on 注册(不真实注册,防 listener 跨用例泄漏)——factory 顶层注册
238
- // SIGTERM/SIGINT/beforeExit 三个 process hook(见 process-shutdown-hook.test.ts)。
239
- processOnSpy = vi.spyOn(process, "on").mockImplementation((() => process) as never);
240
-
241
- registered.clear();
242
- killAllSpawnedChildrenMock.mockReset();
243
-
244
- const ctx = setupRealService();
245
- agentDir = ctx.agentDir;
246
- service = ctx.service;
247
- store = ctx.store;
248
- setSubagentService(service);
249
-
250
- subagentsExtension(createMockPi());
251
- });
252
-
253
- afterEach(() => {
254
- processOnSpy.mockRestore();
255
- service.dispose();
256
- fs.rmSync(agentDir, { recursive: true, force: true });
257
- resetServiceSlot();
258
- });
259
-
260
- it("factory 注册 session_before_fork 与 session_before_switch handler", () => {
261
- expect(registered.get("session_before_fork")).toBeTypeOf("function");
262
- expect(registered.get("session_before_switch")).toBeTypeOf("function");
263
- });
264
-
265
- it("[M2] 不注册 session_before_tree——/tree 同 session 分支导航不得级联杀 subagent", () => {
266
- // SDK 中 session_before_tree 只由 navigateTree(/tree)触发,与 /new 无关。
267
- // 旧实现误挂此事件当 /new 级联入口 → 普通 /tree 导航误杀全部活跃 subagent。
268
- // 本断言是 M2 回归守卫:该事件不得再注册级联 handler。
269
- expect(registered.has("session_before_tree")).toBe(false);
270
- });
271
-
272
- it("[M2] session_before_switch(reason:'new') 触发 /new 级联:record 转 closed + parent-new", () => {
273
- const record = makeRunningRecord("sa-wire-new-1");
274
- store.register(record);
275
- const onParentNewSpy = vi.spyOn(service, "onParentNew");
276
-
277
- registered.get("session_before_switch")!(
278
- { type: "session_before_switch", reason: "new" },
279
- undefined,
280
- );
281
-
282
- expect(onParentNewSpy).toHaveBeenCalledTimes(1);
283
- expect(record.status).toBe("closed");
284
- expect(record.closedReason).toBe("parent-new");
285
- expect(store.getMutable("sa-wire-new-1")).toBeUndefined();
286
- });
287
-
288
- it("[M2] session_before_switch(reason:'resume') 不级联:/resume 回到已有 session,record 保持 running", () => {
289
- const record = makeRunningRecord("sa-wire-resume-1");
290
- store.register(record);
291
- const onParentNewSpy = vi.spyOn(service, "onParentNew");
292
-
293
- registered.get("session_before_switch")!(
294
- {
295
- type: "session_before_switch",
296
- reason: "resume",
297
- targetSessionFile: "/tmp/other-session.jsonl",
298
- },
299
- undefined,
300
- );
301
-
302
- expect(onParentNewSpy).not.toHaveBeenCalled();
303
- expect(record.status).toBe("running");
304
- expect(store.getMutable("sa-wire-resume-1")).toBe(record);
305
- });
306
-
307
- it("session_before_fork 触发 /fork 级联:record 转 closed + parent-fork", () => {
308
- const record = makeRunningRecord("sa-wire-fork-1");
309
- store.register(record);
310
- const onParentForkSpy = vi.spyOn(service, "onParentFork");
311
-
312
- registered.get("session_before_fork")!(
313
- { type: "session_before_fork", entryId: "entry-1", position: "before" },
314
- undefined,
315
- );
316
-
317
- expect(onParentForkSpy).toHaveBeenCalledTimes(1);
318
- expect(record.status).toBe("closed");
319
- expect(record.closedReason).toBe("parent-fork");
320
- expect(store.getMutable("sa-wire-fork-1")).toBeUndefined();
321
- });
322
-
323
- it("service 单例未初始化(getSubagentService()=null)时 handler 安全 no-op", () => {
324
- resetServiceSlot();
325
- expect(() => {
326
- registered.get("session_before_switch")!(
327
- { type: "session_before_switch", reason: "new" },
328
- undefined,
329
- );
330
- registered.get("session_before_fork")!(
331
- { type: "session_before_fork", entryId: "e", position: "before" },
332
- undefined,
333
- );
334
- }).not.toThrow();
335
- });
336
- });
@@ -1,104 +0,0 @@
1
- // src/__tests__/path-encoding.test.ts
2
- //
3
- // 锁定 encodeCwd 契约:session-runner 与 session-file-gc 共用此编码,
4
- // 漂移会导致同一 cwd 落到两个不同目录(见 path-encoding.ts 顶部注释)。
5
- import * as path from "node:path";
6
-
7
- import { describe, expect, it } from "vitest";
8
-
9
- import { encodeCwd, getSubagentRecordsDir, getSubagentSessionDir } from "../path-encoding.ts";
10
-
11
- describe("encodeCwd", () => {
12
- it("encodes a normal unix absolute path", () => {
13
- expect(encodeCwd("/Users/x/proj")).toBe("--Users-x-proj--");
14
- });
15
-
16
- it("strips a single leading backslash", () => {
17
- expect(encodeCwd("\\foo")).toBe("--foo--");
18
- });
19
-
20
- it("encodes Windows drive letter (colon + backslash)", () => {
21
- // C:\proj → 去掉无前导分隔符 → C:\proj → : 和 \ 都替换为 - → C--proj
22
- expect(encodeCwd("C:\\proj")).toBe("--C--proj--");
23
- });
24
-
25
- it("encodes empty string to bare delimiter pair", () => {
26
- expect(encodeCwd("")).toBe("----");
27
- });
28
-
29
- it("encodes relative path with no leading separator", () => {
30
- expect(encodeCwd("relative/path")).toBe("--relative-path--");
31
- });
32
-
33
- it("collapses consecutive separators (forward slash)", () => {
34
- expect(encodeCwd("/a//b")).toBe("--a--b--");
35
- });
36
-
37
- it("collapses consecutive separators (backslash)", () => {
38
- expect(encodeCwd("a\\b\\c")).toBe("--a-b-c--");
39
- });
40
-
41
- it("encodes mixed separators and colon", () => {
42
- // /x:y\\z → 去前导 / → x:y\z → : \ → - - → x-y-z
43
- expect(encodeCwd("/x:y\\z")).toBe("--x-y-z--");
44
- });
45
- });
46
-
47
- describe("getSubagentSessionDir", () => {
48
- it("returns agentDir/subagents/<encodedCwd>/sessions", () => {
49
- // [MF#1] 既有布局:subagents/<enc>/sessions/(不改,避免升级用户既有数据 orphan)
50
- const result = getSubagentSessionDir("/home/user/.pi/agent", "/home/user/project");
51
- expect(result).toBe(
52
- path.join("/home/user/.pi/agent", "subagents", "--home-user-project--", "sessions")
53
- );
54
- });
55
-
56
- it("uses mainCwd encoding (not effectiveCwd)", () => {
57
- // D-004: 用主 cwd 编码,保证同一主 cwd 下所有 subagent 存同一目录
58
- const mainCwd = "/Users/zhushanwen/Code/my-project";
59
- const result = getSubagentSessionDir("~/.pi/agent", mainCwd);
60
- const encoded = encodeCwd(mainCwd);
61
- expect(result).toBe(path.join("~/.pi/agent", "subagents", encoded, "sessions"));
62
- });
63
-
64
- it("produces consistent path for same inputs", () => {
65
- const a = getSubagentSessionDir("/agent", "/cwd");
66
- const b = getSubagentSessionDir("/agent", "/cwd");
67
- expect(a).toBe(b);
68
- });
69
-
70
- it("produces different path for different mainCwd", () => {
71
- const a = getSubagentSessionDir("/agent", "/cwd1");
72
- const b = getSubagentSessionDir("/agent", "/cwd2");
73
- expect(a).not.toBe(b);
74
- });
75
- });
76
-
77
- describe("getSubagentRecordsDir", () => {
78
- it("returns agentDir/subagents/<encodedCwd>/records", () => {
79
- const result = getSubagentRecordsDir("/home/user/.pi/agent", "/Users/x/proj");
80
- expect(result).toBe(
81
- path.join("/home/user/.pi/agent", "subagents", "--Users-x-proj--", "records")
82
- );
83
- });
84
-
85
- it("shares the same <enc> segment with getSubagentSessionDir for same cwd", () => {
86
- // F1:records 与 sessions 在同一 <enc> 段下,仅尾段不同(records vs sessions)。
87
- // worktree 场景三者恒等的前提就靠这个共享 enc。
88
- const agentDir = "/home/user/.pi/agent";
89
- const cwd = "/Users/x/proj";
90
- const sessions = getSubagentSessionDir(agentDir, cwd);
91
- const records = getSubagentRecordsDir(agentDir, cwd);
92
- // 共享 enc:去掉尾段后剩同一路径前缀
93
- expect(path.dirname(sessions)).toBe(path.dirname(records));
94
- // 尾段不同
95
- expect(path.basename(sessions)).toBe("sessions");
96
- expect(path.basename(records)).toBe("records");
97
- });
98
-
99
- it("produces different path for different mainCwd", () => {
100
- const a = getSubagentRecordsDir("/agent", "/cwd1");
101
- const b = getSubagentRecordsDir("/agent", "/cwd2");
102
- expect(a).not.toBe(b);
103
- });
104
- });
@@ -1,134 +0,0 @@
1
- // src/__tests__/pi-invocation.test.ts
2
- import * as fs from "node:fs";
3
- import * as os from "node:os";
4
- import * as path from "node:path";
5
-
6
- import { afterEach, describe, expect, it } from "vitest";
7
-
8
- import { getPiInvocation } from "../pi-invocation.ts";
9
- import { RELAY_ENV_NODE, RELAY_ENV_SCRIPT, RELAY_ENV_SOCKET } from "../relay-env.ts";
10
-
11
- describe("getPiInvocation", () => {
12
- const originalArgv = process.argv;
13
- const originalExecPath = process.execPath;
14
- let tmpScript: string;
15
-
16
- afterEach(() => {
17
- Object.defineProperty(process, "argv", { value: originalArgv, configurable: true });
18
- Object.defineProperty(process, "execPath", { value: originalExecPath, configurable: true });
19
- if (tmpScript && fs.existsSync(tmpScript)) fs.unlinkSync(tmpScript);
20
- });
21
-
22
- it("真实脚本路径存在 → node <script> <userArgs>", () => {
23
- // 创建真实临时脚本文件(避免 ESM spy 限制)
24
- tmpScript = path.join(os.tmpdir(), `pi-inv-test-${Date.now()}.mjs`);
25
- fs.writeFileSync(tmpScript, "// test");
26
- Object.defineProperty(process, "argv", { value: ["node", tmpScript], configurable: true });
27
- Object.defineProperty(process, "execPath", { value: "/usr/bin/node", configurable: true });
28
-
29
- const result = getPiInvocation(["--mode", "json", "Task: x"]);
30
- expect(result.command).toBe("/usr/bin/node");
31
- expect(result.args).toEqual([tmpScript, "--mode", "json", "Task: x"]);
32
- });
33
-
34
- it("bun 虚拟脚本(/$bunfs/root/)→ 退化到 pi-in-PATH", () => {
35
- tmpScript = "";
36
- const virtualScript = "/$bunfs/root/pi";
37
- Object.defineProperty(process, "argv", { value: ["bun", virtualScript], configurable: true });
38
- Object.defineProperty(process, "execPath", { value: "/usr/bin/bun", configurable: true });
39
-
40
- const result = getPiInvocation(["--mode", "json"]);
41
- expect(result.command).toBe("pi");
42
- expect(result.args).toEqual(["--mode", "json"]);
43
- });
44
-
45
- it("非通用 runtime(pi standalone binary)→ 直接 execPath", () => {
46
- tmpScript = "";
47
- Object.defineProperty(process, "argv", { value: ["/usr/bin/pi", "/nonexistent"], configurable: true });
48
- Object.defineProperty(process, "execPath", { value: "/usr/local/bin/pi-binary", configurable: true });
49
-
50
- const result = getPiInvocation(["--mode", "json"]);
51
- expect(result.command).toBe("/usr/local/bin/pi-binary");
52
- expect(result.args).toEqual(["--mode", "json"]);
53
- });
54
-
55
- it("node 通用 runtime + 脚本不存在 → pi-in-PATH", () => {
56
- tmpScript = "";
57
- Object.defineProperty(process, "argv", { value: ["node", "/nonexistent"], configurable: true });
58
- Object.defineProperty(process, "execPath", { value: "/usr/bin/node", configurable: true });
59
-
60
- const result = getPiInvocation(["--mode", "json"]);
61
- expect(result.command).toBe("pi");
62
- expect(result.args).toEqual(["--mode", "json"]);
63
- });
64
-
65
- it("空 userArgs 合法(仅 command + 空 args)", () => {
66
- tmpScript = "";
67
- Object.defineProperty(process, "argv", { value: ["node"], configurable: true });
68
- Object.defineProperty(process, "execPath", { value: "/usr/bin/node", configurable: true });
69
-
70
- const result = getPiInvocation([]);
71
- expect(result.command).toBe("pi");
72
- expect(result.args).toEqual([]);
73
- });
74
- });
75
-
76
- describe("getPiInvocation relay 分支(E 方案 §5.1)", () => {
77
- const originalArgv = process.argv;
78
- const originalExecPath = process.execPath;
79
- const RELAY_ENVS = [RELAY_ENV_SOCKET, RELAY_ENV_NODE, RELAY_ENV_SCRIPT] as const;
80
- /** 三 env 齐备的基准值(改 argv/execPath 隔离直连分支,只测 relay 判定本身)。 */
81
- const RELAY_FULL: Record<string, string> = {
82
- [RELAY_ENV_SOCKET]: "/tmp/relay-test.sock",
83
- [RELAY_ENV_NODE]: "/usr/bin/relay-node",
84
- [RELAY_ENV_SCRIPT]: "/opt/relay/relay.mjs",
85
- };
86
-
87
- afterEach(() => {
88
- Object.defineProperty(process, "argv", { value: originalArgv, configurable: true });
89
- Object.defineProperty(process, "execPath", { value: originalExecPath, configurable: true });
90
- for (const key of RELAY_ENVS) delete process.env[key];
91
- });
92
-
93
- /** 形态 1:三 env 齐备 + 默认 opts → relay invocation(command=NODE、args[0]=SCRIPT)。 */
94
- it("三 env 齐备(无 opts)→ 代理形态 <NODE> <SCRIPT> <userArgs>", () => {
95
- Object.assign(process.env, RELAY_FULL);
96
- const result = getPiInvocation(["--mode", "rpc"]);
97
- expect(result.command).toBe(RELAY_FULL[RELAY_ENV_NODE]);
98
- expect(result.args).toEqual([RELAY_FULL[RELAY_ENV_SCRIPT], "--mode", "rpc"]);
99
- });
100
-
101
- /** 形态 1 变体:opts.relay === true 显式开启,行为与缺省一致。 */
102
- it("三 env 齐备 + opts.relay=true → 同缺省(显式开启非必填)", () => {
103
- Object.assign(process.env, RELAY_FULL);
104
- const result = getPiInvocation(["--mode", "rpc"], { relay: true });
105
- expect(result.command).toBe(RELAY_FULL[RELAY_ENV_NODE]);
106
- expect(result.args[0]).toBe(RELAY_FULL[RELAY_ENV_SCRIPT]);
107
- });
108
-
109
- /** 形态 2:三缺一逐个枚举 → 回落现状直连(全有或全无,E-TUI 零回归)。 */
110
- it("三缺一(逐个枚举)→ 现状直连分支", () => {
111
- // 直连分支落到「node + 不存在脚本 → pi-in-PATH」可稳定断言(不依赖测试机 execPath 形态)
112
- Object.defineProperty(process, "argv", { value: ["node", "/nonexistent"], configurable: true });
113
- Object.defineProperty(process, "execPath", { value: "/usr/bin/node", configurable: true });
114
- for (const missing of RELAY_ENVS) {
115
- const partial = { ...RELAY_FULL };
116
- delete partial[missing];
117
- for (const key of RELAY_ENVS) delete process.env[key];
118
- Object.assign(process.env, partial);
119
- const result = getPiInvocation(["--mode", "rpc"]);
120
- expect(result.command).toBe("pi"); // 分支 3:通用 runtime + 脚本不存在 → PATH
121
- expect(result.args).toEqual(["--mode", "rpc"]);
122
- }
123
- });
124
-
125
- /** 形态 3:probe 排除——显式 relay:false 时即便三 env 齐备也直连。 */
126
- it("relay:false 强制直连(probe 语义:探 pi 本体,不探 runtime 健康)", () => {
127
- Object.assign(process.env, RELAY_FULL);
128
- Object.defineProperty(process, "argv", { value: ["node", "/nonexistent"], configurable: true });
129
- Object.defineProperty(process, "execPath", { value: "/usr/bin/node", configurable: true });
130
- const result = getPiInvocation(["--version"], { relay: false });
131
- expect(result.command).toBe("pi");
132
- expect(result.args).toEqual(["--version"]);
133
- });
134
- });