@zhushanwen/subagent-core 0.2.0 → 0.5.1
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.
- package/README.md +45 -2
- package/agents/analyst.md +60 -0
- package/agents/coder.md +69 -0
- package/agents/debugger.md +66 -0
- package/agents/doc-reviewer.md +49 -0
- package/agents/explorer.md +63 -0
- package/agents/general-purpose.md +32 -0
- package/agents/orchestrator.md +61 -0
- package/agents/planner.md +53 -0
- package/agents/researcher.md +67 -0
- package/agents/reviewer.md +73 -0
- package/dist/chunk-43ONBFZX.js +240 -0
- package/dist/chunk-APZY4IME.js +27 -0
- package/dist/chunk-V3VHZ2VX.js +59 -0
- package/dist/execution/engine/engines/zcode/constants.cjs +62 -9
- package/dist/execution/engine/engines/zcode/constants.d.cts +116 -12
- package/dist/execution/engine/engines/zcode/constants.d.ts +116 -12
- package/dist/execution/engine/engines/zcode/constants.js +39 -7
- package/dist/execution/engine/engines/zcode/reader.d.cts +2 -1
- package/dist/execution/engine/engines/zcode/reader.d.ts +2 -1
- package/dist/execution/engine/engines/zcode/reader.js +4 -234
- package/dist/execution/engine/paths.js +7 -19
- package/dist/index.cjs +18234 -1277
- package/dist/index.d.cts +5646 -673
- package/dist/index.d.ts +5646 -673
- package/dist/index.js +17828 -1277
- package/dist/{types-BxyAidGf.d.cts → types-Dv4QhSJ_.d.cts} +678 -112
- package/dist/{types-BxyAidGf.d.ts → types-Dv4QhSJ_.d.ts} +678 -112
- package/package.json +7 -4
- package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +0 -1
- package/src/__tests__/append-system-prompt-assembly.test.ts +8 -7
- package/src/__tests__/fr4-get-state-handshake.test.ts +2 -2
- package/src/__tests__/m2-append-content-probe.test.ts +0 -1
- package/src/__tests__/manifest-store.test.ts +10 -9
- package/src/__tests__/record-store-cache.test.ts +0 -2
- package/src/__tests__/record-store-index.test.ts +1 -2
- package/src/__tests__/review-fix-loop-script.test.ts +93 -3
- package/src/__tests__/review-fix-loop-utils.test.ts +31 -10
- package/src/__tests__/robustness-low-batch1.test.ts +6 -5
- package/src/__tests__/robustness-medium-batch1.test.ts +2 -2
- package/src/__tests__/robustness-medium-batch2.test.ts +17 -6
- package/src/__tests__/robustness-medium-batch4.test.ts +2 -2
- package/src/__tests__/session-runner.test.ts +1 -1
- package/src/__tests__/smoke.test.ts +9 -2
- package/src/core/__tests__/host-services.test.ts +2 -2
- package/src/core/__tests__/logger.test.ts +1 -1
- package/src/core/error-message.ts +9 -0
- package/src/core/host-services.ts +21 -5
- package/src/core/notify-ports.ts +18 -5
- package/src/execution/__tests__/agent-profile.test.ts +232 -0
- package/src/execution/__tests__/agent-registry.test.ts +370 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +18 -2
- package/src/execution/__tests__/agents-assembly.test.ts +219 -0
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +6 -6
- package/src/execution/__tests__/chat-engine-routing.test.ts +136 -30
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +5 -4
- package/src/execution/__tests__/cold-resurrect.test.ts +283 -0
- package/src/execution/__tests__/create-concurrency-pool.test.ts +194 -0
- package/src/execution/__tests__/delivery-methods.test.ts +77 -62
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +220 -0
- package/src/execution/__tests__/descendant-sweep.test.ts +269 -0
- package/src/execution/__tests__/dialog-queue.test.ts +199 -1
- package/src/execution/__tests__/engine-model-validation.test.ts +741 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +31 -24
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +21 -91
- package/src/execution/__tests__/execute-nesting.test.ts +34 -188
- package/src/execution/__tests__/execution-record.test.ts +217 -60
- package/src/execution/__tests__/execution-runtime-face.test.ts +272 -0
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +3 -3
- package/src/execution/__tests__/finalize-record.test.ts +278 -16
- package/src/execution/__tests__/gc-timer.test.ts +57 -2
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +14 -12
- package/src/execution/__tests__/get-state-handshake.test.ts +127 -0
- package/src/execution/__tests__/helpers/mock-extension-api.ts +1 -1
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +113 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +150 -3
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +137 -0
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +280 -0
- package/src/execution/__tests__/kill-all-escalation.test.ts +196 -0
- package/src/execution/__tests__/lifecycle-manager-idle-timer-identity.test.ts +117 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +39 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +1 -2
- package/src/execution/__tests__/manifest-parentid.test.ts +4 -4
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +99 -0
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +113 -0
- package/src/execution/__tests__/model-resolver.test.ts +2 -2
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +23 -121
- package/src/execution/__tests__/nested-visibility.test.ts +2 -0
- package/src/execution/__tests__/notify-ledger.test.ts +1249 -0
- package/src/execution/__tests__/output-collector.test.ts +117 -6
- package/src/execution/__tests__/pi-invocation.test.ts +1 -1
- package/src/execution/__tests__/record-store-orphan-revive.test.ts +159 -0
- package/src/execution/__tests__/record-store.test.ts +89 -5
- package/src/execution/__tests__/records-cwd-isolation.test.ts +2 -2
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +29 -132
- package/src/execution/__tests__/recursive-visibility-env.test.ts +55 -179
- package/src/execution/__tests__/rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +387 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +19 -9
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +5 -4
- package/src/execution/__tests__/run-spawn-edges.test.ts +418 -26
- package/src/execution/__tests__/run-spawn-integration.test.ts +3 -3
- package/src/execution/__tests__/run-spawn-resume.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +2 -2
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +16 -8
- package/src/execution/__tests__/service-kill-escalation.test.ts +91 -0
- package/src/execution/__tests__/session-context-resolver.test.ts +0 -2
- package/src/execution/__tests__/session-file-gc.test.ts +35 -0
- package/src/execution/__tests__/session-pending.test.ts +471 -0
- package/src/execution/__tests__/session-reconstructor.test.ts +366 -15
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +110 -0
- package/src/execution/__tests__/session-runner-close-prune.test.ts +181 -0
- package/src/execution/__tests__/session-runner-dispatch.test.ts +489 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +4 -3
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +227 -0
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +290 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +7 -5
- package/src/execution/__tests__/settled-watchdog.test.ts +524 -0
- package/src/execution/__tests__/spawn-args.test.ts +11 -10
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +26 -23
- package/src/execution/__tests__/spawn-event-adapter.test.ts +1 -1
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +5 -4
- package/src/execution/__tests__/spawned-children.test.ts +155 -11
- package/src/execution/__tests__/start-sync-model-guard.test.ts +4 -4
- package/src/execution/__tests__/stdin-writer.test.ts +6 -4
- package/src/execution/__tests__/stream-sink-retirement.test.ts +6 -6
- package/src/execution/__tests__/subagent-actions-core.test.ts +1017 -0
- package/src/execution/__tests__/subagent-service-message-close.test.ts +99 -35
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +174 -0
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +271 -0
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +33 -29
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +341 -0
- package/src/execution/__tests__/subagent-service.test.ts +37 -30
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +88 -12
- package/src/execution/__tests__/subprocess-agent-runner-timeout.test.ts +75 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +22 -20
- package/src/execution/__tests__/temp-prompt.test.ts +1 -1
- package/src/execution/__tests__/timeout-integration.test.ts +13 -12
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +1 -1
- package/src/execution/__tests__/turn-limiter.test.ts +1 -1
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +107 -7
- package/src/execution/__tests__/ui-request-handler.test.ts +4 -3
- package/src/execution/__tests__/ui-request-queue.test.ts +167 -2
- package/src/execution/__tests__/worktree-git-ops.test.ts +571 -0
- package/src/execution/__tests__/worktree-manager.test.ts +14 -5
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +4 -3
- package/src/execution/__tests__/worktree-reconcile-aging.test.ts +204 -0
- package/src/execution/agent-registry.ts +298 -30
- package/src/execution/agent-result-mapper.ts +3 -0
- package/src/execution/agents-assembly.ts +88 -0
- package/src/execution/cold-resurrect.ts +199 -0
- package/src/execution/concurrency-pool.ts +71 -9
- package/src/execution/dialog-queue.ts +101 -3
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +91 -0
- package/src/execution/engine/__tests__/common/data-dir.test.ts +1 -1
- package/src/execution/engine/__tests__/common/journal-wiring.test.ts +84 -0
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +34 -7
- package/src/execution/engine/__tests__/common/persona-router.test.ts +4 -5
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +211 -51
- package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +149 -0
- package/src/execution/engine/__tests__/common/session-view-service.test.ts +499 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +56 -99
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +88 -15
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +33 -7
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +1 -1
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +75 -54
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +128 -0
- package/src/execution/engine/__tests__/engine-discovery.test.ts +15 -3
- package/src/execution/engine/__tests__/model-prompt.test.ts +15 -3
- package/src/execution/engine/__tests__/registry.test.ts +94 -3
- package/src/execution/engine/__tests__/routing.test.ts +115 -6
- package/src/execution/engine/common/capability-gate.ts +92 -0
- package/src/execution/engine/common/journal-wiring.ts +97 -0
- package/src/execution/engine/common/kill-chain.ts +42 -10
- package/src/execution/engine/common/nesting-guard.ts +66 -0
- package/src/execution/engine/common/persona-router.ts +18 -8
- package/src/execution/engine/common/pool-manager.ts +332 -78
- package/src/execution/engine/common/session-view-service.ts +506 -0
- package/src/execution/engine/common/session-view-types.ts +125 -0
- package/src/execution/engine/engine-discovery.ts +12 -16
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +174 -28
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +257 -0
- package/src/execution/{argv-mirror.ts → engine/engines/pi/argv-mirror.ts} +43 -21
- package/src/execution/{get-state-handshake.ts → engine/engines/pi/get-state-handshake.ts} +86 -11
- package/src/execution/{output-collector.ts → engine/engines/pi/output-collector.ts} +108 -19
- package/src/execution/engine/engines/pi/pi-engine.ts +434 -38
- package/src/execution/{pi-invocation.ts → engine/engines/pi/pi-invocation.ts} +2 -2
- package/src/execution/engine/engines/pi/reader.ts +11 -0
- package/src/execution/engine/engines/pi/registration.ts +4 -2
- package/src/execution/engine/engines/pi/session-runner.ts +2840 -0
- package/src/execution/{spawn-event-adapter.ts → engine/engines/pi/spawn-event-adapter.ts} +75 -34
- package/src/execution/{stdin-writer.ts → engine/engines/pi/stdin-writer.ts} +10 -9
- package/src/execution/{temp-prompt.ts → engine/engines/pi/temp-prompt.ts} +2 -2
- package/src/execution/{turn-limiter.ts → engine/engines/pi/turn-limiter.ts} +1 -1
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +301 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +36 -0
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +321 -0
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +473 -0
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +7 -210
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +6 -110
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +247 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +451 -0
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +792 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +782 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +168 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +353 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +282 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +372 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +65 -47
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +167 -0
- package/src/execution/engine/engines/zcode/connection.ts +598 -0
- package/src/execution/engine/engines/zcode/constants.ts +147 -14
- package/src/execution/engine/engines/zcode/golden-sample.ts +42 -34
- package/src/execution/engine/engines/zcode/parser.ts +12 -346
- package/src/execution/engine/engines/zcode/preparer.ts +22 -150
- package/src/execution/engine/engines/zcode/session-channel.ts +968 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +1023 -250
- package/src/execution/engine/host-task-spec.ts +32 -36
- package/src/execution/engine/model-validation.ts +177 -0
- package/src/execution/engine/port.ts +65 -7
- package/src/execution/engine/registry.ts +53 -0
- package/src/execution/engine/routing.ts +75 -1
- package/src/execution/engine/types.ts +30 -103
- package/src/execution/execution-record.ts +222 -144
- package/src/execution/finalize-record.ts +181 -85
- package/src/execution/idle-gc.ts +28 -0
- package/src/execution/lifecycle-manager.ts +27 -3
- package/src/execution/lifecycle-predicates.ts +1 -1
- package/src/execution/manifest-store.ts +53 -62
- package/src/execution/notifier.ts +10 -10
- package/src/execution/notify-host.ts +212 -0
- package/src/execution/notify-ledger.ts +117 -16
- package/src/execution/record-entry.ts +8 -2
- package/src/execution/record-store.ts +148 -88
- package/src/execution/round-settlement.ts +93 -0
- package/src/execution/session-file-gc.ts +96 -62
- package/src/execution/session-pending.ts +213 -62
- package/src/execution/session-reconstructor.ts +256 -143
- package/src/execution/sessions-index.ts +127 -102
- package/src/execution/settled-watchdog.ts +311 -0
- package/src/execution/subagent-actions-core.ts +686 -0
- package/src/execution/subagent-service.ts +1106 -907
- package/src/execution/subprocess-agent-runner.ts +144 -97
- package/src/execution/types.ts +9 -0
- package/src/execution/ui-request-handler-factory.ts +126 -75
- package/src/execution/ui-request-queue.ts +50 -19
- package/src/execution/worktree-git-ops.ts +397 -0
- package/src/execution/worktree-manager.ts +72 -10
- package/src/execution/worktree-registry.ts +6 -12
- package/src/index.ts +542 -9
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +42 -3
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +3 -5
- package/src/orchestration/__tests__/agent-call-stream.test.ts +2 -2
- package/src/orchestration/__tests__/args-meta.test.ts +358 -0
- package/src/orchestration/__tests__/args-validator.test.ts +14 -0
- package/src/orchestration/__tests__/error-recovery-rebuild-failure.test.ts +312 -0
- package/src/orchestration/__tests__/error-recovery-terminal-hardening.test.ts +384 -0
- package/src/orchestration/__tests__/execute-agent-call.test.ts +151 -11
- package/src/orchestration/__tests__/file-run-store-prune.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store-throttle.test.ts +168 -0
- package/src/orchestration/__tests__/file-run-store.test.ts +390 -0
- package/src/orchestration/__tests__/helpers/flush-microtasks.ts +13 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +34 -0
- package/src/orchestration/__tests__/lifecycle-abort-broadcast-signal.test.ts +357 -0
- package/src/orchestration/__tests__/lifecycle-recover-crashed.test.ts +289 -0
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +3 -3
- package/src/orchestration/__tests__/lifecycle.test.ts +84 -5
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/run-snapshot.test.ts +356 -0
- package/src/orchestration/__tests__/script-generate.test.ts +314 -0
- package/src/orchestration/__tests__/script-lint.test.ts +17 -0
- package/src/orchestration/__tests__/test-mocks.ts +2 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +7 -6
- package/src/orchestration/__tests__/worker-message-pump-finalize-run.test.ts +229 -0
- package/src/orchestration/__tests__/{error-recovery-handlers.test.ts → worker-message-pump-handlers.test.ts} +28 -27
- package/src/orchestration/__tests__/{error-recovery-postmessage-defense.test.ts → worker-message-pump-postmessage-defense.test.ts} +8 -8
- package/src/orchestration/__tests__/{error-recovery-serialize-failed-result.test.ts → worker-message-pump-serialize-failed-result.test.ts} +2 -2
- package/src/orchestration/__tests__/{error-recovery-workflow-call.test.ts → worker-message-pump-workflow-call.test.ts} +1 -1
- package/src/orchestration/__tests__/worker-pending-timeout-abort.test.ts +275 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +78 -1
- package/src/orchestration/__tests__/worker-script-builder.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-files.test.ts +186 -0
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +1 -1
- package/src/orchestration/__tests__/workflow-run-summary.test.ts +119 -0
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +124 -0
- package/src/orchestration/agent-opts-resolver.ts +8 -8
- package/src/orchestration/args-meta.ts +198 -0
- package/src/orchestration/args-validator.ts +53 -31
- package/src/orchestration/execute-agent-call.ts +25 -79
- package/src/orchestration/file-run-store.ts +327 -0
- package/src/orchestration/launcher.ts +160 -104
- package/src/orchestration/lifecycle.ts +371 -97
- package/src/orchestration/models/agent-call.ts +7 -7
- package/src/orchestration/models/budget.ts +5 -5
- package/src/orchestration/models/ports.ts +4 -4
- package/src/orchestration/models/run-runtime.ts +15 -15
- package/src/orchestration/models/trace.ts +9 -9
- package/src/orchestration/models/types.ts +111 -22
- package/src/orchestration/models/workflow-run.ts +28 -28
- package/src/orchestration/models/workflow-script.ts +4 -4
- package/src/orchestration/run-snapshot.ts +266 -0
- package/src/orchestration/script-generate.ts +154 -0
- package/src/orchestration/script-lint.ts +123 -90
- package/src/orchestration/worker-handle.ts +10 -10
- package/src/orchestration/worker-host.ts +10 -10
- package/src/orchestration/{error-recovery.ts → worker-message-pump.ts} +498 -221
- package/src/orchestration/worker-script-builder.ts +401 -346
- package/src/orchestration/workflow-files.ts +37 -11
- package/src/orchestration/workflow-run-summary.ts +69 -0
- package/src/orchestration/workflow-script-registry-impl.ts +31 -9
- package/src/shared/__tests__/agent-ref.test.ts +209 -2
- package/src/shared/__tests__/atomic-write.test.ts +267 -0
- package/src/shared/__tests__/bounded-serialize.test.ts +236 -0
- package/src/shared/__tests__/injection-render.test.ts +518 -0
- package/src/shared/__tests__/meta-parser.test.ts +151 -0
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +474 -0
- package/src/shared/__tests__/resource-discovery.test.ts +261 -217
- package/src/shared/agent-ref.ts +143 -2
- package/src/shared/atomic-write.ts +323 -0
- package/src/shared/bounded-serialize.ts +154 -0
- package/src/shared/injection-render.ts +279 -0
- package/src/shared/meta-parser.ts +182 -68
- package/src/shared/model-ref.ts +15 -2
- package/src/shared/resource-discovery.ts +97 -204
- package/src/shared/resource-meta.ts +14 -0
- package/src/shared/schema-jsonify.ts +1 -1
- package/src/shared/xml-injection.ts +9 -9
- package/workflows/README.md +9 -9
- package/workflows/chain.js +4 -2
- package/workflows/map-reduce.js +5 -3
- package/workflows/parallel.js +5 -3
- package/workflows/review-fix-loop-utils.cjs +165 -92
- package/workflows/review-fix-loop-utils.d.cts +287 -0
- package/workflows/review-fix-loop.js +18 -7
- package/workflows/scatter-gather.js +4 -2
- package/dist/chunk-3VOERJPJ.js +0 -22
- package/src/execution/__tests__/execute-options-mapper.test.ts +0 -200
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +0 -164
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +0 -100
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +0 -39
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +0 -150
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +0 -580
- package/src/execution/engine/engines/zcode/launcher.ts +0 -161
- package/src/execution/execute-options-mapper.ts +0 -115
- package/src/execution/session-runner.ts +0 -1789
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +0 -288
|
@@ -16,102 +16,32 @@
|
|
|
16
16
|
// 4. forkDepth 基线:env PI_SUBAGENT_FORK_DEPTH → fork spawn env 递增
|
|
17
17
|
//
|
|
18
18
|
// mock 策略与 execute-nesting.test.ts 一致(spawn → FakeChild,fs 同步方法 mock,
|
|
19
|
-
// temp-prompt / alive-store / finalized-marker / manifest-store mock
|
|
20
|
-
|
|
21
|
-
import type { PassThrough } from "node:stream";
|
|
19
|
+
// temp-prompt / alive-store / finalized-marker / manifest-store mock;已收敛
|
|
20
|
+
// ./helpers/subagent-service-mocks.ts 四文件共享单源)。
|
|
22
21
|
|
|
23
22
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
stdout = new PassThrough();
|
|
34
|
-
stderr = new PassThrough();
|
|
35
|
-
killed = false;
|
|
36
|
-
killSignal: string | undefined;
|
|
37
|
-
kill(sig?: string): boolean {
|
|
38
|
-
this.killed = true;
|
|
39
|
-
this.killSignal = sig;
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return {
|
|
45
|
-
spawn: vi.fn(() => new FakeChild()),
|
|
46
|
-
// buildEnvBlock 用 execFile 异步取 git branch:默认 err-first 兜底(catch → branch="")
|
|
47
|
-
execFile: vi.fn(
|
|
48
|
-
(
|
|
49
|
-
_cmd: string,
|
|
50
|
-
_args: readonly string[],
|
|
51
|
-
_opts: unknown,
|
|
52
|
-
cb: (err: Error | null, stdout?: string, stderr?: string) => void,
|
|
53
|
-
) => cb(new Error("execFile not configured in this test")),
|
|
54
|
-
),
|
|
55
|
-
};
|
|
56
|
-
});
|
|
24
|
+
import {
|
|
25
|
+
aliveStoreModule,
|
|
26
|
+
childProcessModule,
|
|
27
|
+
finalizedMarkerModule,
|
|
28
|
+
fsSyncModule,
|
|
29
|
+
manifestStoreModule,
|
|
30
|
+
tempPromptModule,
|
|
31
|
+
} from "./helpers/subagent-service-mocks.ts";
|
|
57
32
|
|
|
58
|
-
|
|
59
|
-
const actual = await import("node:fs");
|
|
60
|
-
return {
|
|
61
|
-
default: {
|
|
62
|
-
...actual,
|
|
63
|
-
mkdirSync: vi.fn(),
|
|
64
|
-
existsSync: vi.fn(() => false),
|
|
65
|
-
appendFileSync: vi.fn(),
|
|
66
|
-
writeFileSync: vi.fn(),
|
|
67
|
-
readdirSync: vi.fn(() => []),
|
|
68
|
-
},
|
|
69
|
-
mkdirSync: vi.fn(),
|
|
70
|
-
existsSync: vi.fn(() => false),
|
|
71
|
-
appendFileSync: vi.fn(),
|
|
72
|
-
writeFileSync: vi.fn(),
|
|
73
|
-
readdirSync: vi.fn(() => []),
|
|
74
|
-
promises: actual.promises,
|
|
75
|
-
};
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
vi.mock("../alive-store.ts", async (importOriginal) => {
|
|
79
|
-
const actual = await importOriginal<typeof import("../alive-store.ts")>();
|
|
80
|
-
return {
|
|
81
|
-
...actual,
|
|
82
|
-
writeAliveMarker: vi.fn(),
|
|
83
|
-
removeAliveMarker: vi.fn(),
|
|
84
|
-
};
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
vi.mock("../finalized-marker.ts", () => ({
|
|
88
|
-
writeFinalized: vi.fn(),
|
|
89
|
-
readFinalized: vi.fn(() => false),
|
|
90
|
-
}));
|
|
91
|
-
|
|
92
|
-
vi.mock("../manifest-store.ts", () => {
|
|
93
|
-
class FakeManifestStore {
|
|
94
|
-
writeManifest = vi.fn(async () => {});
|
|
95
|
-
readManifest = vi.fn(async () => null);
|
|
96
|
-
listAllSync = vi.fn(() => []);
|
|
97
|
-
recoverTmpFiles = vi.fn(async () => []);
|
|
98
|
-
}
|
|
99
|
-
// vi.fn 包裹:构造参数(recordsDir)可从 mock.calls 断言([MF-3] 目录统一验证)。
|
|
100
|
-
// 注意用普通 function(箭头函数不能被 new 调用)。
|
|
101
|
-
return { ManifestStore: vi.fn(function (_recordsDir: string) { return new FakeManifestStore(); }) };
|
|
102
|
-
});
|
|
33
|
+
// ── mock modules(同 execute-nesting.test.ts)──
|
|
103
34
|
|
|
104
|
-
vi.mock("
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}));
|
|
35
|
+
vi.mock("node:child_process", () => childProcessModule());
|
|
36
|
+
vi.mock("node:fs", async (importOriginal) => fsSyncModule(await importOriginal<typeof import("node:fs")>()));
|
|
37
|
+
vi.mock("../alive-store.ts", async (importOriginal) => aliveStoreModule(await importOriginal<typeof import("../alive-store.ts")>()));
|
|
38
|
+
vi.mock("../finalized-marker.ts", () => finalizedMarkerModule());
|
|
39
|
+
vi.mock("../manifest-store.ts", () => manifestStoreModule());
|
|
40
|
+
vi.mock("../engine/engines/pi/temp-prompt.ts", () => tempPromptModule());
|
|
111
41
|
|
|
112
42
|
import { spawn } from "node:child_process";
|
|
113
43
|
|
|
114
|
-
import { waitForSpawn } from "./helpers/spawn-mock.ts";
|
|
44
|
+
import { waitForSpawn, lastSpawnedChild } from "./helpers/spawn-mock.ts";
|
|
115
45
|
import { ModelConfigService } from "../model-config-service.ts";
|
|
116
46
|
import type { ModelInfo, ModelRegistryLike } from "../model-resolver.ts";
|
|
117
47
|
import { ManifestStore } from "../manifest-store.ts";
|
|
@@ -128,43 +58,10 @@ const ENV_DEPTH = "PI_SUBAGENT_DEPTH";
|
|
|
128
58
|
const ENV_ROOT_CWD = "PI_SUBAGENT_ROOT_CWD";
|
|
129
59
|
const ENV_FORK_DEPTH = "PI_SUBAGENT_FORK_DEPTH";
|
|
130
60
|
|
|
131
|
-
interface FakeChild {
|
|
132
|
-
pid: number;
|
|
133
|
-
stdout: PassThrough;
|
|
134
|
-
stderr: PassThrough;
|
|
135
|
-
killed: boolean;
|
|
136
|
-
killSignal: string | undefined;
|
|
137
|
-
kill(sig?: string): boolean;
|
|
138
|
-
emit(event: string, ...args: unknown[]): boolean;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function lastSpawnedChild(): FakeChild {
|
|
142
|
-
const result = mockSpawn.mock.results.at(-1);
|
|
143
|
-
if (!result) throw new Error("spawn was not called yet");
|
|
144
|
-
return result.value as FakeChild;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
61
|
function getLastSpawnEnv(): Record<string, string | undefined> {
|
|
148
62
|
return (mockSpawn.mock.calls.at(-1)?.[2]?.env as Record<string, string | undefined>) ?? {};
|
|
149
63
|
}
|
|
150
64
|
|
|
151
|
-
function sessionHeader(id = "baseline-session"): Record<string, unknown> {
|
|
152
|
-
return { type: "session", id, timestamp: "2026-08-11T00-00-00-000Z", cwd: "/tmp/test" };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function emitStdoutLine(child: FakeChild, obj: Record<string, unknown>): void {
|
|
156
|
-
child.stdout.write(`${JSON.stringify(obj)}\n`);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/** 驱动 FakeChild 完成:header + 可选事件 + close(0)(runSpawn 自然 resolve)。 */
|
|
160
|
-
async function driveChildToCompletion(child: FakeChild, events: Record<string, unknown>[] = []): Promise<void> {
|
|
161
|
-
emitStdoutLine(child, sessionHeader());
|
|
162
|
-
for (const e of events) emitStdoutLine(child, e);
|
|
163
|
-
child.stdout.end();
|
|
164
|
-
child.stderr.end();
|
|
165
|
-
child.emit("close", 0);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
65
|
// ── 辅助:service 构造 ──
|
|
169
66
|
|
|
170
67
|
function makeEmptyRegistry(): ModelRegistryLike {
|
|
@@ -177,7 +74,7 @@ function makePi() {
|
|
|
177
74
|
|
|
178
75
|
function setup(env: Record<string, string>): { service: SubagentService; store: RecordStore } {
|
|
179
76
|
const agentDir = "/tmp/baseline-it";
|
|
180
|
-
const modelService = new ModelConfigService({ agentDir });
|
|
77
|
+
const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
|
|
181
78
|
modelService.initModel({
|
|
182
79
|
modelRegistry: makeEmptyRegistry(),
|
|
183
80
|
sessionId: "baseline-it",
|
|
@@ -227,7 +124,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
|
|
|
227
124
|
const { service, store } = setup({});
|
|
228
125
|
|
|
229
126
|
// 不在 execCtxAls.run 内调用(模拟 ALS 断裂:事件回调上下文读不到 store)
|
|
230
|
-
const handle = await service.execute({ task: "child of parent", ctxModel });
|
|
127
|
+
const handle = await service.execute({ task: "child of parent", slug: "test", ctxModel });
|
|
231
128
|
|
|
232
129
|
const rec = store.collectRecords(10, "all", "root-main").find((r) => r.id === handle.subagentId);
|
|
233
130
|
expect(rec).toBeDefined();
|
|
@@ -239,7 +136,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
|
|
|
239
136
|
// 旧实现传 this.sessionId(子进程自己的 session id ≠ ROOT)→ 子进程内列表恒空。
|
|
240
137
|
// 子进程的本进程 sessionId 是 "baseline-it"(initSession 注入),而 record 归属
|
|
241
138
|
// root-main(env 贯穿的真 ROOT)——能查到即证明过滤用的是 sessionRootId。
|
|
242
|
-
const viaService = service.collectRecords(10);
|
|
139
|
+
const viaService = service.queries.collectRecords(10);
|
|
243
140
|
expect(viaService.map((r) => r.id)).toContain(handle.subagentId);
|
|
244
141
|
expect(viaService[0]!.rootSessionId).toBe("root-main");
|
|
245
142
|
});
|
|
@@ -247,7 +144,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
|
|
|
247
144
|
it("[顶层] 无 env(根进程):parentRecordId undefined / depth 0", async () => {
|
|
248
145
|
const { service, store } = setup({});
|
|
249
146
|
|
|
250
|
-
const handle = await service.execute({ task: "top level", ctxModel });
|
|
147
|
+
const handle = await service.execute({ task: "top level", slug: "test", ctxModel });
|
|
251
148
|
|
|
252
149
|
const rec = store.collectRecords(10, "all", "baseline-it").find((r) => r.id === handle.subagentId);
|
|
253
150
|
expect(rec).toBeDefined();
|
|
@@ -261,10 +158,10 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
|
|
|
261
158
|
process.env[ENV_DEPTH] = "0";
|
|
262
159
|
|
|
263
160
|
const { service, store } = setup({});
|
|
264
|
-
const
|
|
161
|
+
const execNesting = Reflect.get(service, "execNesting") as ExecCtxAls;
|
|
265
162
|
|
|
266
|
-
const handle = await
|
|
267
|
-
service.execute({ task: "inline nested", ctxModel }),
|
|
163
|
+
const handle = await execNesting.run({ recordId: "sa-inline-parent", depth: 3 }, () =>
|
|
164
|
+
service.execute({ task: "inline nested", slug: "test", ctxModel }),
|
|
268
165
|
);
|
|
269
166
|
|
|
270
167
|
const rec = store.collectRecords(10, "all", "root-main").find((r) => r.id === handle.subagentId);
|
|
@@ -281,14 +178,14 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
|
|
|
281
178
|
|
|
282
179
|
const { service } = setup({});
|
|
283
180
|
|
|
284
|
-
const execPromise = service.execute({ task: "fork child", ctxModel, fork: true });
|
|
181
|
+
const execPromise = service.execute({ task: "fork child", slug: "test", ctxModel, fork: true });
|
|
285
182
|
await waitForSpawn(mockSpawn);
|
|
286
183
|
const childEnv = getLastSpawnEnv();
|
|
287
184
|
|
|
288
185
|
// 742 行 parentDepth = forkDepthAls.getStore() ?? forkDepthBaseline —— ALS 断裂时基线=1,+1 → 2
|
|
289
186
|
expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBe("2");
|
|
290
187
|
|
|
291
|
-
const child = lastSpawnedChild();
|
|
188
|
+
const child = lastSpawnedChild(mockSpawn);
|
|
292
189
|
child.emit("close", 0);
|
|
293
190
|
await execPromise;
|
|
294
191
|
});
|
|
@@ -303,7 +200,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
|
|
|
303
200
|
// MAX_FORK_DEPTH 至少 > 5 才不会被误拒;这里验证基线参与计数的方式是
|
|
304
201
|
// 用直接深度断言——execute 不抛错说明 nestingDepth=6 未超限,护栏不误伤。
|
|
305
202
|
// (MAX_FORK_DEPTH 具体值由 session-context-resolver 定义,这里不硬编码。)
|
|
306
|
-
await expect(service.execute({ task: "deep but allowed", ctxModel })).resolves.toBeDefined();
|
|
203
|
+
await expect(service.execute({ task: "deep but allowed", slug: "test", ctxModel })).resolves.toBeDefined();
|
|
307
204
|
});
|
|
308
205
|
|
|
309
206
|
it("[MF-3 回归] 有 ENV_ROOT_CWD(worktree 子进程):sessions 与 records 两套目录统一编码在 ROOT cwd 段", () => {
|
|
@@ -314,7 +211,7 @@ describe("进程级基线兜底(ALS 断裂修复,pi 事件回调模型)",
|
|
|
314
211
|
|
|
315
212
|
const agentDir = "/tmp/baseline-it";
|
|
316
213
|
const checkoutPath = "/var/folders/worktree/pi-subagents/--root-project--/branch";
|
|
317
|
-
const modelService = new ModelConfigService({ agentDir });
|
|
214
|
+
const modelService = new ModelConfigService({ agentDir, cwd: agentDir });
|
|
318
215
|
modelService.initModel({
|
|
319
216
|
modelRegistry: makeEmptyRegistry(),
|
|
320
217
|
sessionId: "baseline-it",
|
|
@@ -7,150 +7,46 @@
|
|
|
7
7
|
//
|
|
8
8
|
// 这是场景 1(端到端三层嵌套全树可见)的「env 传递机制」确定性验证——不依赖 LLM 配合,
|
|
9
9
|
// mock spawn 拦截 childEnv 直接断言。端到端可见性由场景 1(真实 pi CLI + recursive-worker agent)覆盖。
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
//
|
|
11
|
+
// mock 块与 fixture 收敛 __tests__/helpers/spawn-mock.ts(vi.mock 工厂 await import 转发,
|
|
12
|
+
// 单源共享);vi.mocked 取回与收尾装配来自 helpers/session-runner-mocks.ts。
|
|
12
13
|
|
|
13
14
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
14
15
|
|
|
15
16
|
import { getSubagentSessionDir } from "../path-encoding.ts";
|
|
16
17
|
|
|
17
|
-
// ── mock modules(同 session-runner-schema-env.test.ts
|
|
18
|
-
|
|
19
|
-
vi.mock("node:child_process", async () =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
vi.mock("node:fs", async () => {
|
|
53
|
-
const actual = await import("node:fs");
|
|
54
|
-
return {
|
|
55
|
-
default: {
|
|
56
|
-
...actual,
|
|
57
|
-
mkdirSync: vi.fn(),
|
|
58
|
-
existsSync: vi.fn(() => false),
|
|
59
|
-
appendFileSync: vi.fn(),
|
|
60
|
-
writeFileSync: vi.fn(),
|
|
61
|
-
readdirSync: vi.fn(() => []),
|
|
62
|
-
},
|
|
63
|
-
mkdirSync: vi.fn(),
|
|
64
|
-
existsSync: vi.fn(() => false),
|
|
65
|
-
appendFileSync: vi.fn(),
|
|
66
|
-
writeFileSync: vi.fn(),
|
|
67
|
-
readdirSync: vi.fn(() => []),
|
|
68
|
-
promises: actual.promises,
|
|
69
|
-
};
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
vi.mock("../alive-store.ts", () => ({
|
|
73
|
-
writeAliveMarker: vi.fn(),
|
|
74
|
-
}));
|
|
75
|
-
|
|
76
|
-
vi.mock("../temp-prompt.ts", () => ({
|
|
77
|
-
writePromptToTempFile: vi.fn(async (agent: string) => {
|
|
78
|
-
const safeName = agent.replace(/[^\w.-]+/g, "_");
|
|
79
|
-
return { dir: `/tmp/fake-${safeName}`, filePath: `/tmp/fake-${safeName}/prompt-${safeName}.md` };
|
|
80
|
-
}),
|
|
81
|
-
cleanupTempPrompt: vi.fn(async () => {}),
|
|
82
|
-
}));
|
|
83
|
-
|
|
84
|
-
import { spawn } from "node:child_process";
|
|
85
|
-
import * as fs from "node:fs";
|
|
86
|
-
|
|
87
|
-
import { waitForSpawn } from "./helpers/spawn-mock.ts";
|
|
88
|
-
import { createRecord } from "../execution-record.ts";
|
|
89
|
-
import { type RunOptions, runSpawn, type SessionRunnerContext } from "../session-runner.ts";
|
|
90
|
-
|
|
91
|
-
const mockSpawn = vi.mocked(spawn);
|
|
92
|
-
const mockExistsSync = vi.mocked(fs.existsSync);
|
|
93
|
-
|
|
94
|
-
interface FakeChild {
|
|
95
|
-
pid: number;
|
|
96
|
-
stdout: PassThrough;
|
|
97
|
-
stderr: PassThrough;
|
|
98
|
-
killed: boolean;
|
|
99
|
-
killSignal: string | undefined;
|
|
100
|
-
kill(sig?: string): boolean;
|
|
101
|
-
emit(event: string, ...args: unknown[]): boolean;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function getLastSpawnedChild(): FakeChild {
|
|
105
|
-
const result = mockSpawn.mock.results.at(-1);
|
|
106
|
-
if (!result) throw new Error("spawn was not called yet");
|
|
107
|
-
return result.value as FakeChild;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function getLastSpawnEnv(): Record<string, string | undefined> {
|
|
111
|
-
return (mockSpawn.mock.calls.at(-1)?.[2]?.env as Record<string, string | undefined>) ?? {};
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// ── fixture ──
|
|
115
|
-
|
|
116
|
-
function makeRecord(overrides: { id?: string; depth?: number } = {}) {
|
|
117
|
-
return createRecord(overrides.id ?? "sa-test-record", {
|
|
118
|
-
agent: "general-purpose",
|
|
119
|
-
model: "test/model",
|
|
120
|
-
mode: "background",
|
|
121
|
-
task: "test task",
|
|
122
|
-
startedAt: Date.now(),
|
|
123
|
-
rootSessionId: "should-be-overridden-by-sessionRootId-source",
|
|
124
|
-
parentRecordId: undefined,
|
|
125
|
-
depth: overrides.depth ?? 0,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function makeRunOpts(overrides: Partial<RunOptions> = {}): RunOptions {
|
|
130
|
-
return {
|
|
131
|
-
resolved: { model: { provider: "test", id: "model" }, thinkingLevel: undefined },
|
|
132
|
-
agentConfig: undefined,
|
|
133
|
-
appendSystemPrompt: undefined,
|
|
134
|
-
skillPath: undefined,
|
|
135
|
-
schema: undefined,
|
|
136
|
-
maxTurns: undefined,
|
|
137
|
-
graceTurns: undefined,
|
|
138
|
-
signal: undefined,
|
|
139
|
-
onEvent: undefined,
|
|
140
|
-
...overrides,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function makeCtx(overrides: Partial<SessionRunnerContext> = {}): SessionRunnerContext {
|
|
145
|
-
return {
|
|
146
|
-
cwd: "/fake/cwd",
|
|
147
|
-
agentDir: "/fake/agent",
|
|
148
|
-
skillDirs: [],
|
|
149
|
-
mainCwd: "/fake/cwd",
|
|
150
|
-
sessionRootId: "root-main-session",
|
|
151
|
-
rootCwd: "/fake/cwd",
|
|
152
|
-
...overrides,
|
|
153
|
-
};
|
|
18
|
+
// ── mock modules(同 session-runner-schema-env.test.ts 模式,工厂单源在 spawn-mock.ts)──
|
|
19
|
+
|
|
20
|
+
vi.mock("node:child_process", async () =>
|
|
21
|
+
(await import("./helpers/spawn-mock.ts")).childProcessModule());
|
|
22
|
+
vi.mock("node:fs", async () => (await import("./helpers/spawn-mock.ts")).fsModule());
|
|
23
|
+
vi.mock("../alive-store.ts", async () =>
|
|
24
|
+
(await import("./helpers/spawn-mock.ts")).aliveStoreModule());
|
|
25
|
+
vi.mock("../engine/engines/pi/temp-prompt.ts", async () =>
|
|
26
|
+
(await import("./helpers/spawn-mock.ts")).tempPromptModule());
|
|
27
|
+
|
|
28
|
+
import { runSpawn } from "../engine/engines/pi/session-runner.ts";
|
|
29
|
+
import {
|
|
30
|
+
getLastSpawnEnv,
|
|
31
|
+
makeRunOpts,
|
|
32
|
+
makeVisibilityCtx,
|
|
33
|
+
makeVisibilityRecord,
|
|
34
|
+
waitForSpawn,
|
|
35
|
+
} from "./helpers/spawn-mock.ts";
|
|
36
|
+
import { closeLastChildAndAwait, takeSessionRunnerMocks } from "./helpers/session-runner-mocks.ts";
|
|
37
|
+
|
|
38
|
+
const { mockSpawn, mockExistsSync } = takeSessionRunnerMocks();
|
|
39
|
+
|
|
40
|
+
/** runSpawn 前奏装配:启动、等 spawn 落位、取回 childEnv(断言留在各用例)。 */
|
|
41
|
+
async function spawnAndCaptureEnv(
|
|
42
|
+
record: ReturnType<typeof makeVisibilityRecord>,
|
|
43
|
+
task: string,
|
|
44
|
+
opts: ReturnType<typeof makeRunOpts>,
|
|
45
|
+
ctx: ReturnType<typeof makeVisibilityCtx>,
|
|
46
|
+
): Promise<{ resultPromise: Promise<unknown>; childEnv: Record<string, string | undefined> }> {
|
|
47
|
+
const resultPromise = runSpawn(record, task, opts, ctx);
|
|
48
|
+
await waitForSpawn(mockSpawn);
|
|
49
|
+
return { resultPromise, childEnv: getLastSpawnEnv(mockSpawn) };
|
|
154
50
|
}
|
|
155
51
|
|
|
156
52
|
// ── runSpawn childEnv 身份 env 注入(场景 1b)──
|
|
@@ -166,13 +62,11 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
|
|
|
166
62
|
});
|
|
167
63
|
|
|
168
64
|
it("非 fork(fork=false/undefined):无条件注入 4 个身份 env(决策 2)", async () => {
|
|
169
|
-
const record =
|
|
170
|
-
const ctx =
|
|
65
|
+
const record = makeVisibilityRecord({ id: "sa-aaa", depth: 0 });
|
|
66
|
+
const ctx = makeVisibilityCtx({ sessionRootId: "root-main" });
|
|
171
67
|
const opts = makeRunOpts({ fork: false });
|
|
172
68
|
|
|
173
|
-
const resultPromise =
|
|
174
|
-
await waitForSpawn(mockSpawn);
|
|
175
|
-
const childEnv = getLastSpawnEnv();
|
|
69
|
+
const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", opts, ctx);
|
|
176
70
|
|
|
177
71
|
expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("root-main");
|
|
178
72
|
expect(childEnv.PI_SUBAGENT_SELF_RECORD_ID).toBe("sa-aaa");
|
|
@@ -182,19 +76,15 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
|
|
|
182
76
|
// fork=false 不注入 fork depth env(与既有行为一致,本测试不改变它)
|
|
183
77
|
expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBeUndefined();
|
|
184
78
|
|
|
185
|
-
|
|
186
|
-
child.emit("close", 0);
|
|
187
|
-
await resultPromise;
|
|
79
|
+
await closeLastChildAndAwait(resultPromise);
|
|
188
80
|
});
|
|
189
81
|
|
|
190
82
|
it("fork=true:4 个身份 env 与 fork depth env 共存(决策 2 无条件注入不依赖 fork)", async () => {
|
|
191
|
-
const record =
|
|
192
|
-
const ctx =
|
|
83
|
+
const record = makeVisibilityRecord({ id: "sa-bbb", depth: 2 });
|
|
84
|
+
const ctx = makeVisibilityCtx({ sessionRootId: "root-main" });
|
|
193
85
|
const opts = makeRunOpts({ fork: true, parentForkDepth: 1 });
|
|
194
86
|
|
|
195
|
-
const resultPromise =
|
|
196
|
-
await waitForSpawn(mockSpawn);
|
|
197
|
-
const childEnv = getLastSpawnEnv();
|
|
87
|
+
const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", opts, ctx);
|
|
198
88
|
|
|
199
89
|
// 身份 env 无条件存在(决策 2)
|
|
200
90
|
expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("root-main");
|
|
@@ -204,46 +94,36 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
|
|
|
204
94
|
// fork depth env 同时存在(fork=true + parentForkDepth=1 → 2)
|
|
205
95
|
expect(childEnv.PI_SUBAGENT_FORK_DEPTH).toBe("2");
|
|
206
96
|
|
|
207
|
-
|
|
208
|
-
child.emit("close", 0);
|
|
209
|
-
await resultPromise;
|
|
97
|
+
await closeLastChildAndAwait(resultPromise);
|
|
210
98
|
});
|
|
211
99
|
|
|
212
100
|
it("深层 record(depth=3):DEPTH env = String(record.depth),正确贯穿嵌套层级", async () => {
|
|
213
|
-
const record =
|
|
214
|
-
const ctx =
|
|
101
|
+
const record = makeVisibilityRecord({ id: "sa-deep", depth: 3 });
|
|
102
|
+
const ctx = makeVisibilityCtx({ sessionRootId: "root-topmost" });
|
|
215
103
|
|
|
216
|
-
const resultPromise =
|
|
217
|
-
await waitForSpawn(mockSpawn);
|
|
218
|
-
const childEnv = getLastSpawnEnv();
|
|
104
|
+
const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", makeRunOpts(), ctx);
|
|
219
105
|
|
|
220
106
|
expect(childEnv.PI_SUBAGENT_DEPTH).toBe("3");
|
|
221
107
|
expect(childEnv.PI_SUBAGENT_SELF_RECORD_ID).toBe("sa-deep");
|
|
222
108
|
expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("root-topmost");
|
|
223
109
|
|
|
224
|
-
|
|
225
|
-
child.emit("close", 0);
|
|
226
|
-
await resultPromise;
|
|
110
|
+
await closeLastChildAndAwait(resultPromise);
|
|
227
111
|
});
|
|
228
112
|
|
|
229
113
|
it("ROOT_SESSION_ID 恒等于 ctx.sessionRootId(贯穿真 ROOT,非 record.rootSessionId)", async () => {
|
|
230
114
|
// record.rootSessionId 是 createRecord 时写入的值(可能来自旧逻辑),但 env 注入用的是
|
|
231
115
|
// ctx.sessionRootId(经 buildSessionRunnerContext 从 this.sessionRootId 透传,贯穿真 ROOT)。
|
|
232
116
|
// 这保证深层 subagent 的子进程仍归顶层 ROOT(设计决策 1/3)。
|
|
233
|
-
const record =
|
|
234
|
-
const ctx =
|
|
117
|
+
const record = makeVisibilityRecord({ id: "sa-ccc" }); // record.rootSessionId = fixture 默认值
|
|
118
|
+
const ctx = makeVisibilityCtx({ sessionRootId: "real-root-session" });
|
|
235
119
|
|
|
236
|
-
const resultPromise =
|
|
237
|
-
await waitForSpawn(mockSpawn);
|
|
238
|
-
const childEnv = getLastSpawnEnv();
|
|
120
|
+
const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", makeRunOpts(), ctx);
|
|
239
121
|
|
|
240
122
|
// env 用 ctx.sessionRootId,不是 record.rootSessionId
|
|
241
123
|
expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).toBe("real-root-session");
|
|
242
124
|
expect(childEnv.PI_SUBAGENT_ROOT_SESSION_ID).not.toBe(record.rootSessionId);
|
|
243
125
|
|
|
244
|
-
|
|
245
|
-
child.emit("close", 0);
|
|
246
|
-
await resultPromise;
|
|
126
|
+
await closeLastChildAndAwait(resultPromise);
|
|
247
127
|
});
|
|
248
128
|
|
|
249
129
|
it("[MF-3 回归] worktree 模式(mainCwd=checkout ≠ rootCwd):sessionDir 用 ROOT cwd 编码,深层 record 落盘到 ROOT 可扫描段", async () => {
|
|
@@ -252,12 +132,10 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
|
|
|
252
132
|
const rootCwd = "/root/project";
|
|
253
133
|
const checkoutPath = "/var/folders/worktree/pi-subagents/--root-project--/branch";
|
|
254
134
|
const agentDir = "/fake/agent";
|
|
255
|
-
const record =
|
|
256
|
-
const ctx =
|
|
135
|
+
const record = makeVisibilityRecord({ id: "sa-deep", depth: 2 });
|
|
136
|
+
const ctx = makeVisibilityCtx({ cwd: checkoutPath, mainCwd: checkoutPath, rootCwd, agentDir });
|
|
257
137
|
|
|
258
|
-
const resultPromise =
|
|
259
|
-
await waitForSpawn(mockSpawn);
|
|
260
|
-
const childEnv = getLastSpawnEnv();
|
|
138
|
+
const { resultPromise, childEnv } = await spawnAndCaptureEnv(record, "test task", makeRunOpts(), ctx);
|
|
261
139
|
const spawnArgs = mockSpawn.mock.calls.at(-1)?.[1] as string[];
|
|
262
140
|
|
|
263
141
|
// 第 4 个 env 贯穿 ROOT cwd
|
|
@@ -266,8 +144,6 @@ describe("runSpawn 跨进程身份 env 注入(递归可见性场景 1b)", ()
|
|
|
266
144
|
expect(spawnArgs).toContain(getSubagentSessionDir(agentDir, rootCwd));
|
|
267
145
|
expect(spawnArgs).not.toContain(getSubagentSessionDir(agentDir, checkoutPath));
|
|
268
146
|
|
|
269
|
-
|
|
270
|
-
child.emit("close", 0);
|
|
271
|
-
await resultPromise;
|
|
147
|
+
await closeLastChildAndAwait(resultPromise);
|
|
272
148
|
});
|
|
273
149
|
});
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
import { describe, expect, it } from "vitest";
|
|
8
8
|
|
|
9
|
-
import { buildSpawnArgs } from "../session-runner.ts";
|
|
10
|
-
import { parseSpawnLine } from "../spawn-event-adapter.ts";
|
|
9
|
+
import { buildSpawnArgs } from "../engine/engines/pi/session-runner.ts";
|
|
10
|
+
import { parseSpawnLine } from "../engine/engines/pi/spawn-event-adapter.ts";
|
|
11
11
|
|
|
12
12
|
describe("buildSpawnArgs - RPC mode", () => {
|
|
13
13
|
const baseParams = {
|