@zhushanwen/pi-subagent-workflow 8.5.0 → 8.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/package.json +13 -16
  2. package/relay/relay.mjs +1 -1
  3. package/src/host/__tests__/pi-host.test.ts +214 -0
  4. package/src/host/pi-host.ts +109 -0
  5. package/src/index.ts +142 -32
  6. package/src/injectors/__tests__/engine-awareness.test.ts +292 -0
  7. package/src/injectors/__tests__/engine-section-stability.test.ts +341 -0
  8. package/src/injectors/__tests__/subagent-list-injector.test.ts +5 -5
  9. package/src/injectors/__tests__/workflow-list-injector.test.ts +5 -5
  10. package/src/injectors/engine-awareness.ts +123 -0
  11. package/src/injectors/model-list-injector.ts +1 -1
  12. package/src/injectors/subagent-list-injector.ts +8 -8
  13. package/src/injectors/workflow-list-injector.ts +8 -8
  14. package/src/interface/__tests__/detectors.test.ts +3 -3
  15. package/src/interface/__tests__/subagent-tool-path-guard.test.ts +157 -0
  16. package/src/interface/__tests__/subagent-tool-prompt.test.ts +12 -0
  17. package/src/interface/__tests__/tool-workflow-script-generate.test.ts +2 -2
  18. package/src/interface/__tests__/tool-workflow-throw-paths.test.ts +1 -1
  19. package/src/interface/bg-notify-render.ts +34 -13
  20. package/src/interface/commands.ts +3 -3
  21. package/src/interface/format.ts +2 -2
  22. package/src/interface/helpers.ts +3 -3
  23. package/src/interface/list-component.ts +4 -4
  24. package/src/interface/list-shared.ts +2 -2
  25. package/src/interface/list-view.ts +2 -2
  26. package/src/interface/subagent-actions.ts +288 -19
  27. package/src/interface/subagent-tool-schema.ts +163 -0
  28. package/src/interface/subagent-tool.ts +65 -129
  29. package/src/interface/subagents.ts +5 -5
  30. package/src/interface/tool-render.ts +34 -2
  31. package/src/interface/tool-workflow-script.ts +4 -4
  32. package/src/interface/tool-workflow.ts +6 -6
  33. package/src/interface/views/WorkflowsView.ts +5 -5
  34. package/src/interface/views/__tests__/WorkflowsView-signature.test.ts +3 -3
  35. package/src/interface/views/__tests__/detail-content-session-file.test.ts +2 -2
  36. package/src/interface/views/detail-content.ts +4 -4
  37. package/src/interface/views/format.ts +4 -4
  38. package/src/{orchestration/jsonl-run-store.ts → jsonl-run-store.ts} +132 -18
  39. package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +0 -53
  40. package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +0 -1
  41. package/src/execution/__tests__/agent-registry.test.ts +0 -363
  42. package/src/execution/__tests__/agent-result-mapper.test.ts +0 -150
  43. package/src/execution/__tests__/alive-store.test.ts +0 -147
  44. package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
  45. package/src/execution/__tests__/before-agent-start-injection.test.ts +0 -132
  46. package/src/execution/__tests__/bg-notify-render.test.ts +0 -256
  47. package/src/execution/__tests__/channel-registry-handshake.test.ts +0 -243
  48. package/src/execution/__tests__/chat-engine-routing.test.ts +0 -597
  49. package/src/execution/__tests__/chatmode-first-round-closure-service.test.ts +0 -365
  50. package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -190
  51. package/src/execution/__tests__/chatmode-round-notify-real-chain.test.ts +0 -215
  52. package/src/execution/__tests__/concurrency-pool.test.ts +0 -250
  53. package/src/execution/__tests__/config.test.ts +0 -110
  54. package/src/execution/__tests__/conversation-wiring.test.ts +0 -198
  55. package/src/execution/__tests__/crash-recovery.test.ts +0 -320
  56. package/src/execution/__tests__/delivery-methods.test.ts +0 -385
  57. package/src/execution/__tests__/dialog-queue.test.ts +0 -299
  58. package/src/execution/__tests__/epipe-fallback.test.ts +0 -241
  59. package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -243
  60. package/src/execution/__tests__/execute-nesting.test.ts +0 -323
  61. package/src/execution/__tests__/execute-options-mapper.test.ts +0 -189
  62. package/src/execution/__tests__/execution-record.test.ts +0 -1284
  63. package/src/execution/__tests__/finalize-record.test.ts +0 -368
  64. package/src/execution/__tests__/finalized-marker.test.ts +0 -82
  65. package/src/execution/__tests__/format-schema-instruction.test.ts +0 -138
  66. package/src/execution/__tests__/format.test.ts +0 -458
  67. package/src/execution/__tests__/gc-timer.test.ts +0 -184
  68. package/src/execution/__tests__/get-record-for-action-restart.test.ts +0 -254
  69. package/src/execution/__tests__/gui-mode-dispatch.test.ts +0 -59
  70. package/src/execution/__tests__/helpers/mock-extension-api.ts +0 -30
  71. package/src/execution/__tests__/helpers/spawn-mock.ts +0 -238
  72. package/src/execution/__tests__/host-mode.test.ts +0 -87
  73. package/src/execution/__tests__/index-session-start-identity.test.ts +0 -371
  74. package/src/execution/__tests__/index-session-start.test.ts +0 -593
  75. package/src/execution/__tests__/lifecycle-manager-lock.test.ts +0 -211
  76. package/src/execution/__tests__/lifecycle-manager.test.ts +0 -337
  77. package/src/execution/__tests__/lifecycle-predicates.test.ts +0 -116
  78. package/src/execution/__tests__/list-component.test.ts +0 -401
  79. package/src/execution/__tests__/list-fields.test.ts +0 -109
  80. package/src/execution/__tests__/manifest-parentid.test.ts +0 -117
  81. package/src/execution/__tests__/model-resolver.test.ts +0 -413
  82. package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +0 -287
  83. package/src/execution/__tests__/nested-visibility.test.ts +0 -325
  84. package/src/execution/__tests__/notifier-flush.test.ts +0 -574
  85. package/src/execution/__tests__/notifier-golden-snapshot.test.ts +0 -261
  86. package/src/execution/__tests__/one-shot-upgrade.test.ts +0 -205
  87. package/src/execution/__tests__/output-collector.test.ts +0 -61
  88. package/src/execution/__tests__/parent-child-matrix.test.ts +0 -336
  89. package/src/execution/__tests__/path-encoding.test.ts +0 -104
  90. package/src/execution/__tests__/pi-invocation.test.ts +0 -134
  91. package/src/execution/__tests__/record-store.test.ts +0 -1057
  92. package/src/execution/__tests__/records-cwd-isolation.test.ts +0 -91
  93. package/src/execution/__tests__/recursive-visibility-baseline.test.ts +0 -339
  94. package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -273
  95. package/src/execution/__tests__/relay-agent.test.ts +0 -448
  96. package/src/execution/__tests__/relay-env.test.ts +0 -42
  97. package/src/execution/__tests__/resource-policy.test.ts +0 -109
  98. package/src/execution/__tests__/rpc-mode.test.ts +0 -89
  99. package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -267
  100. package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -253
  101. package/src/execution/__tests__/run-spawn-edges.test.ts +0 -644
  102. package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
  103. package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
  104. package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
  105. package/src/execution/__tests__/sdk-contract.test.ts +0 -273
  106. package/src/execution/__tests__/session-context-resolver.test.ts +0 -167
  107. package/src/execution/__tests__/session-file-gc.test.ts +0 -293
  108. package/src/execution/__tests__/session-pending.test.ts +0 -197
  109. package/src/execution/__tests__/session-reconstructor.test.ts +0 -379
  110. package/src/execution/__tests__/session-runner-epipe.test.ts +0 -178
  111. package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -311
  112. package/src/execution/__tests__/session-start-reaper.test.ts +0 -233
  113. package/src/execution/__tests__/spawn-args.test.ts +0 -434
  114. package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -189
  115. package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
  116. package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -207
  117. package/src/execution/__tests__/spawned-children.test.ts +0 -92
  118. package/src/execution/__tests__/startup-config-declaration.test.ts +0 -35
  119. package/src/execution/__tests__/status-refactor.test.ts +0 -345
  120. package/src/execution/__tests__/stdin-writer.test.ts +0 -463
  121. package/src/execution/__tests__/stream-sink-retirement.test.ts +0 -261
  122. package/src/execution/__tests__/subagent-service-abort.test.ts +0 -60
  123. package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -629
  124. package/src/execution/__tests__/subagent-service-parent-guard.test.ts +0 -180
  125. package/src/execution/__tests__/subagent-service.test.ts +0 -788
  126. package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +0 -310
  127. package/src/execution/__tests__/subprocess-agent-runner.test.ts +0 -506
  128. package/src/execution/__tests__/temp-prompt.test.ts +0 -53
  129. package/src/execution/__tests__/timeout-integration.test.ts +0 -397
  130. package/src/execution/__tests__/tombstone-store.test.ts +0 -73
  131. package/src/execution/__tests__/tool-action.test.ts +0 -385
  132. package/src/execution/__tests__/truncline-snapshot.test.ts +0 -81
  133. package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
  134. package/src/execution/__tests__/turn-limiter.test.ts +0 -65
  135. package/src/execution/__tests__/ui-channels.test.ts +0 -187
  136. package/src/execution/__tests__/ui-interaction-model.test.ts +0 -67
  137. package/src/execution/__tests__/ui-request-handler-factory.test.ts +0 -370
  138. package/src/execution/__tests__/ui-request-handler.test.ts +0 -204
  139. package/src/execution/__tests__/ui-request-observability.test.ts +0 -114
  140. package/src/execution/__tests__/ui-request-queue.test.ts +0 -133
  141. package/src/execution/__tests__/worktree-manager.test.ts +0 -633
  142. package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -229
  143. package/src/execution/__tests__/worktree-reconcile.integration.test.ts +0 -181
  144. package/src/execution/__tests__/worktree-registry.test.ts +0 -199
  145. package/src/execution/agent-registry.ts +0 -193
  146. package/src/execution/agent-result-mapper.ts +0 -90
  147. package/src/execution/alive-store.ts +0 -92
  148. package/src/execution/argv-mirror.ts +0 -109
  149. package/src/execution/best-effort.ts +0 -38
  150. package/src/execution/channel-registry-access.ts +0 -144
  151. package/src/execution/concurrency-pool.ts +0 -116
  152. package/src/execution/config.ts +0 -96
  153. package/src/execution/dialog-queue.ts +0 -330
  154. package/src/execution/engine/__tests__/common/data-dir.test.ts +0 -53
  155. package/src/execution/engine/__tests__/common/errors.test.ts +0 -132
  156. package/src/execution/engine/__tests__/common/event-journal.test.ts +0 -177
  157. package/src/execution/engine/__tests__/common/kill-chain.test.ts +0 -192
  158. package/src/execution/engine/__tests__/common/nesting-guard.test.ts +0 -81
  159. package/src/execution/engine/__tests__/common/persona-router.test.ts +0 -123
  160. package/src/execution/engine/__tests__/common/pool-manager.test.ts +0 -154
  161. package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
  162. package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
  163. package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +0 -141
  164. package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +0 -109
  165. package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +0 -101
  166. package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +0 -77
  167. package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +0 -104
  168. package/src/execution/engine/__tests__/conformance/contract.relay.test.ts +0 -342
  169. package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +0 -201
  170. package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +0 -76
  171. package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +0 -79
  172. package/src/execution/engine/__tests__/engine-discovery.test.ts +0 -87
  173. package/src/execution/engine/__tests__/engines-declaration.test.ts +0 -36
  174. package/src/execution/engine/__tests__/model-prompt.test.ts +0 -85
  175. package/src/execution/engine/__tests__/paths.test.ts +0 -39
  176. package/src/execution/engine/__tests__/registry.test.ts +0 -120
  177. package/src/execution/engine/__tests__/routing.test.ts +0 -231
  178. package/src/execution/engine/common/data-dir.ts +0 -62
  179. package/src/execution/engine/common/errors.ts +0 -183
  180. package/src/execution/engine/common/event-journal.ts +0 -254
  181. package/src/execution/engine/common/journal-replay.ts +0 -62
  182. package/src/execution/engine/common/kill-chain.ts +0 -221
  183. package/src/execution/engine/common/nesting-guard.ts +0 -50
  184. package/src/execution/engine/common/persona-router.ts +0 -108
  185. package/src/execution/engine/common/pool-manager.ts +0 -226
  186. package/src/execution/engine/common/schema-emulation.ts +0 -189
  187. package/src/execution/engine/common/session-view-projection.ts +0 -51
  188. package/src/execution/engine/engine-discovery.ts +0 -65
  189. package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -469
  190. package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
  191. package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
  192. package/src/execution/engine/engines/pi/pi-engine.ts +0 -415
  193. package/src/execution/engine/engines/pi/reader.ts +0 -48
  194. package/src/execution/engine/engines/pi/registration.ts +0 -35
  195. package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
  196. package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
  197. package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
  198. package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -246
  199. package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -228
  200. package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
  201. package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -64
  202. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -127
  203. package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -567
  204. package/src/execution/engine/engines/zcode/constants.ts +0 -43
  205. package/src/execution/engine/engines/zcode/golden-sample.ts +0 -39
  206. package/src/execution/engine/engines/zcode/launcher.ts +0 -161
  207. package/src/execution/engine/engines/zcode/parser.ts +0 -436
  208. package/src/execution/engine/engines/zcode/preparer.ts +0 -363
  209. package/src/execution/engine/engines/zcode/reader.ts +0 -381
  210. package/src/execution/engine/engines/zcode/registration.ts +0 -37
  211. package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -648
  212. package/src/execution/engine/host-task-spec.ts +0 -47
  213. package/src/execution/engine/model-prompt.ts +0 -59
  214. package/src/execution/engine/paths.ts +0 -42
  215. package/src/execution/engine/port.ts +0 -153
  216. package/src/execution/engine/registry.ts +0 -123
  217. package/src/execution/engine/routing.ts +0 -218
  218. package/src/execution/engine/types.ts +0 -304
  219. package/src/execution/execute-options-mapper.ts +0 -111
  220. package/src/execution/execution-record.ts +0 -906
  221. package/src/execution/finalize-record.ts +0 -251
  222. package/src/execution/finalized-marker.ts +0 -51
  223. package/src/execution/get-state-handshake.ts +0 -104
  224. package/src/execution/host-mode.ts +0 -56
  225. package/src/execution/idle-gc.ts +0 -47
  226. package/src/execution/lifecycle-manager.ts +0 -491
  227. package/src/execution/lifecycle-predicates.ts +0 -65
  228. package/src/execution/manifest-store.ts +0 -256
  229. package/src/execution/model-config-service.ts +0 -204
  230. package/src/execution/model-resolver.ts +0 -276
  231. package/src/execution/notifier.ts +0 -260
  232. package/src/execution/output-collector.ts +0 -88
  233. package/src/execution/path-encoding.ts +0 -60
  234. package/src/execution/pi-invocation.ts +0 -120
  235. package/src/execution/record-entry.ts +0 -132
  236. package/src/execution/record-store.ts +0 -1234
  237. package/src/execution/relay-env.ts +0 -37
  238. package/src/execution/session-context-resolver.ts +0 -64
  239. package/src/execution/session-file-gc.ts +0 -120
  240. package/src/execution/session-pending.ts +0 -164
  241. package/src/execution/session-reconstructor.ts +0 -678
  242. package/src/execution/session-runner.ts +0 -1548
  243. package/src/execution/sessions-index.ts +0 -304
  244. package/src/execution/spawn-event-adapter.ts +0 -363
  245. package/src/execution/stdin-writer.ts +0 -198
  246. package/src/execution/stream-sink.ts +0 -126
  247. package/src/execution/subagent-service.ts +0 -2119
  248. package/src/execution/subprocess-agent-runner.ts +0 -303
  249. package/src/execution/temp-prompt.ts +0 -62
  250. package/src/execution/tombstone-store.ts +0 -72
  251. package/src/execution/turn-limiter.ts +0 -102
  252. package/src/execution/types.ts +0 -910
  253. package/src/execution/ui-channels.ts +0 -216
  254. package/src/execution/ui-interaction-model.ts +0 -48
  255. package/src/execution/ui-request-handler-factory.ts +0 -212
  256. package/src/execution/ui-request-observability.ts +0 -81
  257. package/src/execution/ui-request-queue.ts +0 -174
  258. package/src/execution/worktree-manager.ts +0 -688
  259. package/src/execution/worktree-registry.ts +0 -222
  260. package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +0 -336
  261. package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +0 -208
  262. package/src/orchestration/__tests__/agent-call-stream.test.ts +0 -157
  263. package/src/orchestration/__tests__/args-validator.test.ts +0 -143
  264. package/src/orchestration/__tests__/concurrency-gate.test.ts +0 -125
  265. package/src/orchestration/__tests__/config-loader.test.ts +0 -503
  266. package/src/orchestration/__tests__/error-recovery-handlers.test.ts +0 -724
  267. package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +0 -405
  268. package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +0 -56
  269. package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +0 -166
  270. package/src/orchestration/__tests__/execute-agent-call.test.ts +0 -314
  271. package/src/orchestration/__tests__/jsonl-run-store-loadall-sources.test.ts +0 -171
  272. package/src/orchestration/__tests__/jsonl-run-store-session-file.test.ts +0 -1030
  273. package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +0 -277
  274. package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +0 -96
  275. package/src/orchestration/__tests__/lifecycle.test.ts +0 -625
  276. package/src/orchestration/__tests__/review-fix-loop-e2e.test.ts +0 -1971
  277. package/src/orchestration/__tests__/script-lint.test.ts +0 -831
  278. package/src/orchestration/__tests__/skill-discovery.test.ts +0 -157
  279. package/src/orchestration/__tests__/test-mocks.ts +0 -197
  280. package/src/orchestration/__tests__/worker-host.test.ts +0 -120
  281. package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +0 -164
  282. package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +0 -520
  283. package/src/orchestration/__tests__/worker-script-builder.test.ts +0 -309
  284. package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +0 -110
  285. package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +0 -317
  286. package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +0 -110
  287. package/src/orchestration/__tests__/workflows-e2e.test.ts +0 -537
  288. package/src/orchestration/agent-opts-resolver.ts +0 -93
  289. package/src/orchestration/args-validator.ts +0 -127
  290. package/src/orchestration/concurrency-gate.ts +0 -69
  291. package/src/orchestration/config-loader.ts +0 -315
  292. package/src/orchestration/error-recovery.ts +0 -862
  293. package/src/orchestration/execute-agent-call.ts +0 -217
  294. package/src/orchestration/launcher.ts +0 -410
  295. package/src/orchestration/lifecycle.ts +0 -396
  296. package/src/orchestration/models/__tests__/budget.test.ts +0 -367
  297. package/src/orchestration/models/__tests__/trace.test.ts +0 -408
  298. package/src/orchestration/models/agent-call.ts +0 -83
  299. package/src/orchestration/models/budget.ts +0 -148
  300. package/src/orchestration/models/ports.ts +0 -164
  301. package/src/orchestration/models/run-runtime.ts +0 -89
  302. package/src/orchestration/models/run-spec.ts +0 -83
  303. package/src/orchestration/models/run-state.ts +0 -44
  304. package/src/orchestration/models/trace.ts +0 -183
  305. package/src/orchestration/models/types.ts +0 -292
  306. package/src/orchestration/models/workflow-run.ts +0 -254
  307. package/src/orchestration/models/workflow-script-registry.ts +0 -35
  308. package/src/orchestration/models/workflow-script.ts +0 -117
  309. package/src/orchestration/script-lint.ts +0 -766
  310. package/src/orchestration/skill-discovery.ts +0 -92
  311. package/src/orchestration/worker-handle.ts +0 -115
  312. package/src/orchestration/worker-host.ts +0 -98
  313. package/src/orchestration/worker-script-builder.ts +0 -408
  314. package/src/orchestration/workflow-files.ts +0 -85
  315. package/src/orchestration/workflow-script-registry-impl.ts +0 -133
  316. package/src/shared/__tests__/agent-ref.test.ts +0 -34
  317. package/src/shared/__tests__/meta-parser.test.ts +0 -304
  318. package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -280
  319. package/src/shared/__tests__/resource-discovery.test.ts +0 -736
  320. package/src/shared/__tests__/resource-meta.test.ts +0 -51
  321. package/src/shared/__tests__/schema-jsonify.test.ts +0 -81
  322. package/src/shared/agent-event.ts +0 -13
  323. package/src/shared/agent-ref.ts +0 -57
  324. package/src/shared/meta-parser.ts +0 -261
  325. package/src/shared/resource-discovery.ts +0 -811
  326. package/src/shared/resource-meta.ts +0 -65
  327. package/src/shared/schema-jsonify.ts +0 -56
  328. package/src/shared/xml-injection.ts +0 -35
  329. package/workflows/README.md +0 -81
  330. package/workflows/_shared/agent-refs.cjs +0 -40
  331. package/workflows/chain.js +0 -131
  332. package/workflows/map-reduce.js +0 -174
  333. package/workflows/parallel.js +0 -148
  334. package/workflows/review-fix-loop-utils.cjs +0 -1307
  335. package/workflows/review-fix-loop.js +0 -1396
  336. package/workflows/scatter-gather.js +0 -178
@@ -1,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
- });