@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/execution/engine/engines/pi/spawn-event-adapter.ts
|
|
2
2
|
//
|
|
3
3
|
// pi 子进程 stdout JSON 事件流的解析器。Core 叶子原语(仅依赖 types.ts)。
|
|
4
4
|
//
|
|
@@ -20,7 +20,8 @@
|
|
|
20
20
|
import * as fs from "node:fs";
|
|
21
21
|
import * as path from "node:path";
|
|
22
22
|
|
|
23
|
-
import type { SdkEvent } from "
|
|
23
|
+
import type { SdkEvent } from "../../../types.ts";
|
|
24
|
+
import { toErrorMessage } from "../../../../core/error-message.ts";
|
|
24
25
|
|
|
25
26
|
/** pi stdout header 行(session 元信息)。type 固定为 "session"。 */
|
|
26
27
|
export interface SpawnSessionHeader {
|
|
@@ -158,6 +159,56 @@ function isExtensionUiRequest(obj: unknown): obj is ExtensionUiRequestEnvelope {
|
|
|
158
159
|
);
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
/** 必填 string 字段提取:类型不符降级空串(字段容错——仍归类已知 method,不丢 method 信息)。 */
|
|
163
|
+
function reqStr(r: Record<string, unknown>, key: string): string {
|
|
164
|
+
const v = r[key];
|
|
165
|
+
return typeof v === "string" ? v : "";
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/** string[] 字段提取:数组剔除非字符串元素;非数组降级 onMissing(options 传 [],
|
|
169
|
+
* widgetLines 传 undefined——两者对缺失值的载荷语义不同:前者恒挂键,后者键挂值 undefined)。 */
|
|
170
|
+
function strArrayField<T extends string[] | undefined>(
|
|
171
|
+
r: Record<string, unknown>,
|
|
172
|
+
key: string,
|
|
173
|
+
onMissing: T,
|
|
174
|
+
): string[] | T {
|
|
175
|
+
const v = r[key];
|
|
176
|
+
return Array.isArray(v)
|
|
177
|
+
? v.filter((x): x is string => typeof x === "string")
|
|
178
|
+
: onMissing;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** timeout 条件展开:非 number 不挂键(timeout?: number 的字段省略语义)。 */
|
|
182
|
+
function optTimeout(r: Record<string, unknown>): { timeout?: number } {
|
|
183
|
+
return typeof r.timeout === "number" ? { timeout: r.timeout } : {};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** placeholder 条件展开:非 string 不挂键。 */
|
|
187
|
+
function optPlaceholder(r: Record<string, unknown>): { placeholder?: string } {
|
|
188
|
+
return typeof r.placeholder === "string" ? { placeholder: r.placeholder } : {};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** prefill 条件展开:非 string 不挂键。 */
|
|
192
|
+
function optPrefill(r: Record<string, unknown>): { prefill?: string } {
|
|
193
|
+
return typeof r.prefill === "string" ? { prefill: r.prefill } : {};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** notifyType 条件展开:仅接受三种已知枚举值,其余不挂键。 */
|
|
197
|
+
function optNotifyType(
|
|
198
|
+
r: Record<string, unknown>
|
|
199
|
+
): { notifyType?: "info" | "warning" | "error" } {
|
|
200
|
+
const v = r.notifyType;
|
|
201
|
+
return v === "info" || v === "warning" || v === "error" ? { notifyType: v } : {};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** widgetPlacement 条件展开:仅接受两种已知枚举值,其余不挂键。 */
|
|
205
|
+
function optWidgetPlacement(
|
|
206
|
+
r: Record<string, unknown>
|
|
207
|
+
): { widgetPlacement?: "aboveEditor" | "belowEditor" } {
|
|
208
|
+
const v = r.widgetPlacement;
|
|
209
|
+
return v === "aboveEditor" || v === "belowEditor" ? { widgetPlacement: v } : {};
|
|
210
|
+
}
|
|
211
|
+
|
|
161
212
|
/**
|
|
162
213
|
* 从已通过 isExtensionUiRequest 守卫的 envelope 构造 ExtensionUiRequest 变体。
|
|
163
214
|
*
|
|
@@ -166,6 +217,7 @@ function isExtensionUiRequest(obj: unknown): obj is ExtensionUiRequestEnvelope {
|
|
|
166
217
|
*
|
|
167
218
|
* 字段类型容错:协议字段类型不符(如 options 非数组)时,该字段降级为空数组/undefined
|
|
168
219
|
*(数组类字段做元素类型过滤,剔除非字符串元素),仍归类为已知 method(不丢 method 信息)。
|
|
220
|
+
* 字段级提取/条件展开由上方字段 helper 承担,本函数只做 method 分发。
|
|
169
221
|
*/
|
|
170
222
|
function buildExtensionUiRequest(env: ExtensionUiRequestEnvelope): ExtensionUiRequest {
|
|
171
223
|
const r: Record<string, unknown> = env;
|
|
@@ -173,69 +225,58 @@ function buildExtensionUiRequest(env: ExtensionUiRequestEnvelope): ExtensionUiRe
|
|
|
173
225
|
case "select":
|
|
174
226
|
return {
|
|
175
227
|
method: "select",
|
|
176
|
-
title:
|
|
177
|
-
options:
|
|
178
|
-
|
|
179
|
-
: [],
|
|
180
|
-
...(typeof r.timeout === "number" ? { timeout: r.timeout } : {}),
|
|
228
|
+
title: reqStr(r, "title"),
|
|
229
|
+
options: strArrayField(r, "options", []),
|
|
230
|
+
...optTimeout(r),
|
|
181
231
|
};
|
|
182
232
|
case "confirm":
|
|
183
233
|
return {
|
|
184
234
|
method: "confirm",
|
|
185
|
-
title:
|
|
186
|
-
message:
|
|
187
|
-
...(
|
|
235
|
+
title: reqStr(r, "title"),
|
|
236
|
+
message: reqStr(r, "message"),
|
|
237
|
+
...optTimeout(r),
|
|
188
238
|
};
|
|
189
239
|
case "input":
|
|
190
240
|
return {
|
|
191
241
|
method: "input",
|
|
192
|
-
title:
|
|
193
|
-
...(
|
|
194
|
-
...(
|
|
242
|
+
title: reqStr(r, "title"),
|
|
243
|
+
...optPlaceholder(r),
|
|
244
|
+
...optTimeout(r),
|
|
195
245
|
};
|
|
196
246
|
case "editor":
|
|
197
247
|
return {
|
|
198
248
|
method: "editor",
|
|
199
|
-
title:
|
|
200
|
-
...(
|
|
249
|
+
title: reqStr(r, "title"),
|
|
250
|
+
...optPrefill(r),
|
|
201
251
|
};
|
|
202
252
|
case "notify":
|
|
203
253
|
return {
|
|
204
254
|
method: "notify",
|
|
205
|
-
message:
|
|
206
|
-
...(r
|
|
207
|
-
? { notifyType: r.notifyType }
|
|
208
|
-
: {}),
|
|
255
|
+
message: reqStr(r, "message"),
|
|
256
|
+
...optNotifyType(r),
|
|
209
257
|
};
|
|
210
258
|
case "setStatus":
|
|
211
259
|
return {
|
|
212
260
|
method: "setStatus",
|
|
213
|
-
statusKey:
|
|
261
|
+
statusKey: reqStr(r, "statusKey"),
|
|
214
262
|
statusText: typeof r.statusText === "string" ? r.statusText : undefined,
|
|
215
263
|
};
|
|
216
|
-
case "setWidget":
|
|
217
|
-
const placement = r.widgetPlacement;
|
|
218
|
-
const widgetLines = Array.isArray(r.widgetLines)
|
|
219
|
-
? r.widgetLines.filter((x): x is string => typeof x === "string")
|
|
220
|
-
: undefined;
|
|
264
|
+
case "setWidget":
|
|
221
265
|
return {
|
|
222
266
|
method: "setWidget",
|
|
223
|
-
widgetKey:
|
|
224
|
-
widgetLines,
|
|
225
|
-
...(
|
|
226
|
-
? { widgetPlacement: placement }
|
|
227
|
-
: {}),
|
|
267
|
+
widgetKey: reqStr(r, "widgetKey"),
|
|
268
|
+
widgetLines: strArrayField(r, "widgetLines", undefined),
|
|
269
|
+
...optWidgetPlacement(r),
|
|
228
270
|
};
|
|
229
|
-
}
|
|
230
271
|
case "setTitle":
|
|
231
272
|
return {
|
|
232
273
|
method: "setTitle",
|
|
233
|
-
title:
|
|
274
|
+
title: reqStr(r, "title"),
|
|
234
275
|
};
|
|
235
276
|
case "set_editor_text":
|
|
236
277
|
return {
|
|
237
278
|
method: "set_editor_text",
|
|
238
|
-
text:
|
|
279
|
+
text: reqStr(r, "text"),
|
|
239
280
|
};
|
|
240
281
|
default:
|
|
241
282
|
// 未知 method:保留全部原始字段,避免协议演进时丢信息
|
|
@@ -273,7 +314,7 @@ export function parseSpawnLine(line: string): ParsedSpawnLine | null {
|
|
|
273
314
|
return {
|
|
274
315
|
kind: "invalid",
|
|
275
316
|
raw: trimmed,
|
|
276
|
-
error:
|
|
317
|
+
error: toErrorMessage(err),
|
|
277
318
|
};
|
|
278
319
|
}
|
|
279
320
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/execution/stdin-writer.ts
|
|
1
|
+
// src/execution/engine/engines/pi/stdin-writer.ts
|
|
2
2
|
//
|
|
3
3
|
// 向 rpc 子进程 stdin 写入命令的 helper 集合。
|
|
4
4
|
//
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
import type { ChildProcess } from "node:child_process";
|
|
11
11
|
import * as crypto from "node:crypto";
|
|
12
12
|
|
|
13
|
-
import { getLogger } from "
|
|
13
|
+
import { getLogger } from "../../../../core/logger.ts";
|
|
14
14
|
|
|
15
|
-
import type { UiResponse } from "
|
|
15
|
+
import type { UiResponse } from "../../../dialog-queue.ts";
|
|
16
|
+
import { toErrorMessage } from "../../../../core/error-message.ts";
|
|
16
17
|
|
|
17
18
|
const logger = getLogger("subagents");
|
|
18
19
|
|
|
@@ -25,7 +26,7 @@ const logger = getLogger("subagents");
|
|
|
25
26
|
* 是 stdin 域中立模块,epipe 计数属 stdin 错误域,职责合理。
|
|
26
27
|
*
|
|
27
28
|
* 错误处理两半面共用本计数器(合并计数,防 spawn→EPIPE→resume 死循环):
|
|
28
|
-
* ① 同步 write 抛错(writeStdinLine throw →
|
|
29
|
+
* ① 同步 write 抛错(writeStdinLine throw → PiEngine.deliverPrompt catch 递增)
|
|
29
30
|
* ② 异步 stream 'error' event(session-runner.ts child.stdin.on('error') 递增)
|
|
30
31
|
*/
|
|
31
32
|
const epipeConsecutiveFailures = new Map<string, number>();
|
|
@@ -79,7 +80,7 @@ export function respond(child: ChildProcess, id: string, out: UiResponse, signal
|
|
|
79
80
|
} catch (err) {
|
|
80
81
|
// [R2] out.value 含循环引用/BigInt 等不可序列化结构——降级 cancelled,避免父进程崩溃。
|
|
81
82
|
logger.warn(`[subagents] JSON.stringify failed for ui response ${id}, degrading to cancelled`, {
|
|
82
|
-
detail:
|
|
83
|
+
detail: toErrorMessage(err),
|
|
83
84
|
});
|
|
84
85
|
line = JSON.stringify({ type: "extension_ui_response", id, cancelled: true });
|
|
85
86
|
}
|
|
@@ -158,7 +159,7 @@ export function sendGetStateCommand(child: ChildProcess): string {
|
|
|
158
159
|
*
|
|
159
160
|
* [R1] write 返回 false 时记 warn(不阻塞,内核缓冲会随后排空)。
|
|
160
161
|
* [R3] write 抛 EPIPE / ERR_STREAM_DESTROYED 时 throw 含 EPIPE 关键词的 Error,
|
|
161
|
-
* 让上层(
|
|
162
|
+
* 让上层(PiEngine.deliverPrompt)能捕获并自动转冷路径 resume。
|
|
162
163
|
* stdin 已关闭/销毁时跳过——respond 已检查 signal,sendPromptCommand 已检查 destroyed。
|
|
163
164
|
*
|
|
164
165
|
* @param child 子进程
|
|
@@ -173,11 +174,11 @@ function writeStdinLine(child: ChildProcess, line: string, warnTag: string): voi
|
|
|
173
174
|
if (!ok) logger.warn(`[subagents] stdin backpressure on ${warnTag}`);
|
|
174
175
|
} catch (err) {
|
|
175
176
|
// [R3] EPIPE / ERR_STREAM_DESTROYED:stdin 管道已断,子进程已退出或 stdin 被销毁。
|
|
176
|
-
// [v4 A-1] 错误处理两半面:① 同步 write 抛错(本 catch
|
|
177
|
+
// [v4 A-1] 错误处理两半面:① 同步 write 抛错(本 catch)——上层(PiEngine.deliverPrompt)捕获后
|
|
177
178
|
// 调 recordEpipeFailure 递增计数;② 异步 stream 'error' event(session-runner.ts 的
|
|
178
179
|
// child.stdin.on('error') listener)。两者共用本模块 export 的 recordEpipeFailure
|
|
179
180
|
// helper 合并计数(防 spawn→EPIPE→resume 死循环)。
|
|
180
|
-
// throw 让上层(
|
|
181
|
+
// throw 让上层(PiEngine.deliverPrompt)捕获并自动转冷路径 resume + 消息重放。
|
|
181
182
|
if (
|
|
182
183
|
err !== null &&
|
|
183
184
|
typeof err === "object" &&
|
|
@@ -192,7 +193,7 @@ function writeStdinLine(child: ChildProcess, line: string, warnTag: string): voi
|
|
|
192
193
|
}
|
|
193
194
|
// 非 EPIPE 错误(不应发生,但兜底降级为 warn 不崩溃)
|
|
194
195
|
logger.warn(`[subagents] unexpected stdin write error on ${warnTag}`, {
|
|
195
|
-
detail:
|
|
196
|
+
detail: toErrorMessage(err),
|
|
196
197
|
});
|
|
197
198
|
}
|
|
198
199
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/execution/engine/engines/pi/temp-prompt.ts
|
|
2
2
|
//
|
|
3
3
|
// 将 agent systemPrompt 写入临时文件,供 pi CLI --append-system-prompt 使用。
|
|
4
4
|
// Core 叶子原语(node 内置 + 同目录 bestEffort 清理 helper)。注意 bestEffort
|
|
@@ -14,7 +14,7 @@ import * as fs from "node:fs";
|
|
|
14
14
|
import * as os from "node:os";
|
|
15
15
|
import * as path from "node:path";
|
|
16
16
|
|
|
17
|
-
import { bestEffort } from "
|
|
17
|
+
import { bestEffort } from "../../../best-effort.ts";
|
|
18
18
|
|
|
19
19
|
/** 临时 prompt 文件创建结果。dir 供调用方清理。 */
|
|
20
20
|
export interface TempPromptFile {
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fake app-server(R2 连接层测试专用,绝不 spawn 真 zcode.cjs)。
|
|
3
|
+
*
|
|
4
|
+
* 移植改造自 zsw 仓 84b63a0^ z-subagent-workflow/fixtures/fake-appserver.js 的测试
|
|
5
|
+
* 模式(该仓只读参照),vitest 子进程形态(ESM——本仓 eslint 禁 require,CJS 形态
|
|
6
|
+
* 被 no-require-imports 拦截):启动方式与真协议对齐——由被测 AppServerConnection
|
|
7
|
+
* 以 `node <本文件> app-server --cwd <dir>` spawn(argv 解析后记录进流水,不消费)。
|
|
8
|
+
* stdio NDJSON,帧形态对齐设计附录 A.1(无 jsonrpc 字段)。
|
|
9
|
+
*
|
|
10
|
+
* 测试断言面 = FAKE_STATE_FILE 事件流水(append JSONL):
|
|
11
|
+
* boot / env / recv(收到的每个客户端帧)/ reverse-answer(反向请求收到的我方应答)
|
|
12
|
+
* / unparseable-from-client。env 开关随 spawn env 固化:
|
|
13
|
+
* FAKE_STATE_FILE 流水文件路径(未设则不记流水)
|
|
14
|
+
* FAKE_STDERR=1 启动时往 stderr 写两行(tee 落盘断言取证)
|
|
15
|
+
* FAKE_EXTRA_KEYS=1 我方应答/推送帧携带未知键(客户端宽容解析断言)
|
|
16
|
+
* FAKE_PROTOCOL_PUSH=1 协议自报走 {method:'protocol'} 推送形态(缺省走 A.1 首帧
|
|
17
|
+
* {protocol:{...}} 形态)
|
|
18
|
+
*
|
|
19
|
+
* 内置方法(可编程注入四帧型的全部形态):
|
|
20
|
+
* test/echo 应答 {id, result: params}(原样回显——并发 id 关联断言依据)
|
|
21
|
+
* test/delay-echo delayMs 后应答回显(制造在途请求)
|
|
22
|
+
* test/fail 应答 {id, error:{code,message,data}}(params 指定)
|
|
23
|
+
* test/push 先推一帧 {method: pushMethod, params: pushParams} 再应答
|
|
24
|
+
* test/reverse 发一个反向请求(method=params.reverseMethod)并等客户端
|
|
25
|
+
* 应答,流水记录后回 {id, result:{answered:true}}
|
|
26
|
+
* test/malformed-first 先写一行非 JSON 再正常应答(坏行跳过不断流断言)
|
|
27
|
+
* test/suicide stderr 写 600 字符噪声 + 标记后 exit(1)(崩溃收割断言)
|
|
28
|
+
* session/create 真实协议语义(A.2):先发反向请求 session/requestRuntime
|
|
29
|
+
* Preferences 并等客户端应答(D9 常量表断言依据),流水记录
|
|
30
|
+
* 后回 {session:{sessionId}}
|
|
31
|
+
* session/subscribe 应答 {subscribed:true}(R3;真实应答形状未知——会话层不校验)
|
|
32
|
+
* session/send 按 FAKE_SESSION_SCENARIO 推送帧序列后应答(缺省 {accepted:true})
|
|
33
|
+
* session/read 按 FAKE_SESSION_SCENARIO 应答(缺省 {messages:[]})
|
|
34
|
+
* session/close 应答 {closed:true}
|
|
35
|
+
* 其余方法 应答 -32601(method not found)
|
|
36
|
+
*
|
|
37
|
+
* 会话场景注入(R3 会话层测试;不设 = 各方法走缺省行为,R2 连接层测试不受影响):
|
|
38
|
+
* FAKE_SESSION_SCENARIO=<path> 启动时读取一次的 JSON 文件:
|
|
39
|
+
* {
|
|
40
|
+
* createResult?: object 覆盖 create 应答(golden create 应答注入)
|
|
41
|
+
* createError?: {code,message,data} create 应答 error 帧(-32602/-32601 注入)
|
|
42
|
+
* sendError?: {code,message,data} send 应答 error 帧(-32010/-32602 注入)
|
|
43
|
+
* sendPushes?: [frame, ...] send 应答前逐帧推送(推送流 + 终态帧全显式
|
|
44
|
+
* 逐字回放,不经 withExtra 改写)
|
|
45
|
+
* sendResult?: object 缺省 {accepted:true}
|
|
46
|
+
* crashAfterSendMs?: number [P0-1 U4] send 应答后 N ms 自杀 exit(1)(连接
|
|
47
|
+
* 崩溃收割注入——onClose → failAllTurns 在途
|
|
48
|
+
* turn 收割;进程死 → 下次 request 惰性重建
|
|
49
|
+
* boot 新代重读 scenario,重试轮/下一任务形态
|
|
50
|
+
* 切换经测试侧 rewriteScenario)
|
|
51
|
+
* rebootSendPushes?: [frame, ...] [P0-1 U4] 非首代进程(本 fake 启动时 state 流水
|
|
52
|
+
* 已有 boot 记录——崩溃/杀链后的重建代)的 send
|
|
53
|
+
* 推送序列,替代 sendPushes:崩溃后惰性重建的
|
|
54
|
+
* 重试轮拿到不同行为(如完整终态流)——首轮挂起
|
|
55
|
+
* + 重试轮成功的静态注入通道(同任务重试轮无法
|
|
56
|
+
* 经测试侧 rewriteScenario 插手,run 整体 await)
|
|
57
|
+
* readError?: {code,message,data} read 应答 error 帧(read 兜底降级链断言)
|
|
58
|
+
* readResult?: object 覆盖 read 应答
|
|
59
|
+
* stopBehavior?: 'terminal'|'none'|'hang'
|
|
60
|
+
* session/stop 的行为(R4 abort 链断言面):
|
|
61
|
+
* 'terminal'(缺省)= stop 时推送该会话的
|
|
62
|
+
* turn.terminal 终态帧(stop 优雅生效——不杀
|
|
63
|
+
* 进程的 abort 路径);'none' = 只应答不推终态
|
|
64
|
+
* (grace 窗口耗尽 → killChain 兜底路径);
|
|
65
|
+
* 'hang' = 连应答都不给(P0-1 U2 超时入口态③——
|
|
66
|
+
* 控制面假死注入,stop 3s 超时 → 连接级失败判据)
|
|
67
|
+
* stopError?: {code,message,data} stop 应答 error 帧(P0-1 U2 超时入口态②——
|
|
68
|
+
* 协议性 error(如会话已回收)注入,断言不升级杀链)
|
|
69
|
+
* }
|
|
70
|
+
*
|
|
71
|
+
* 多会话支持(R4 引擎接线 / RA3 双会话地基):
|
|
72
|
+
* FAKE_STAMP_SESSION=1 session/send 的推送帧回放时把 params.sessionId 统一改写
|
|
73
|
+
* 为「当前 send 的目标会话」,telemetry 帧(无 sid)补记
|
|
74
|
+
* sessionId——并发两会话各自收到归因正确的推送流,不串线。
|
|
75
|
+
* (缺省关:R2/R3 单会话用例的字节级行为不变。)
|
|
76
|
+
* session/stop 应答 {stopped:true};按 scenario.stopBehavior 决定是否
|
|
77
|
+
* 推送终态帧(见上)。stopTerminal 推送同样受 STAMP 改写。
|
|
78
|
+
*/
|
|
79
|
+
import fs from 'node:fs';
|
|
80
|
+
import readline from 'node:readline';
|
|
81
|
+
|
|
82
|
+
const STATE_FILE = process.env.FAKE_STATE_FILE;
|
|
83
|
+
const EXTRA_KEYS = process.env.FAKE_EXTRA_KEYS === '1';
|
|
84
|
+
const PROTOCOL_AS_PUSH = process.env.FAKE_PROTOCOL_PUSH === '1';
|
|
85
|
+
// [R4] 多会话推送改写开关(见文件头注释)
|
|
86
|
+
const STAMP_SESSION = process.env.FAKE_STAMP_SESSION === '1';
|
|
87
|
+
|
|
88
|
+
// 会话场景(R3):启动时读取一次(env 固化语义与其他 FAKE_ 开关一致)
|
|
89
|
+
let SCENARIO = null;
|
|
90
|
+
if (process.env.FAKE_SESSION_SCENARIO) {
|
|
91
|
+
try {
|
|
92
|
+
SCENARIO = JSON.parse(fs.readFileSync(process.env.FAKE_SESSION_SCENARIO, 'utf8'));
|
|
93
|
+
} catch (err) {
|
|
94
|
+
log('scenario-load-failed', { message: String(err && err.message) });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// [P0-1 U4] 本进程代数(state 流水已有 boot 记录数 + 1):崩溃/杀链后的惰性重建代
|
|
99
|
+
// ≥2——rebootSendPushes 仅对重建代生效(重试轮拿到与首轮不同的推送序列)
|
|
100
|
+
let BOOT_GEN = 1;
|
|
101
|
+
if (STATE_FILE && SCENARIO && SCENARIO.rebootSendPushes) {
|
|
102
|
+
try {
|
|
103
|
+
const priorBoots = fs
|
|
104
|
+
.readFileSync(STATE_FILE, 'utf8')
|
|
105
|
+
.split('\n')
|
|
106
|
+
.filter((l) => l.includes('"ev":"boot"')).length;
|
|
107
|
+
BOOT_GEN = priorBoots + 1;
|
|
108
|
+
} catch { /* 流水读失败按首代处理 */ }
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let seq = 0;
|
|
112
|
+
function log(ev, data = {}) {
|
|
113
|
+
if (!STATE_FILE) return;
|
|
114
|
+
try {
|
|
115
|
+
fs.appendFileSync(STATE_FILE, JSON.stringify({ seq: ++seq, ev, ...data }) + '\n');
|
|
116
|
+
} catch { /* 流水写失败不影响协议行为 */ }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const out = (frame) => process.stdout.write(`${JSON.stringify(frame)}\n`);
|
|
120
|
+
const withExtra = (frame) => (EXTRA_KEYS ? { ...frame, unknownServerKey: 'lenient' } : frame);
|
|
121
|
+
const reply = (id, result) => out(withExtra({ id, result }));
|
|
122
|
+
const replyErr = (id, code, message, data) =>
|
|
123
|
+
out({ id, error: { code, message, ...(data !== undefined ? { data } : {}) } });
|
|
124
|
+
|
|
125
|
+
// 协议自报(A.1:首帧 {protocol:{...}};推送形态显式开关——两种到达形态都要被忽略)
|
|
126
|
+
if (PROTOCOL_AS_PUSH) out({ method: 'protocol', params: { name: 'ZCode Protocol', version: 1 } });
|
|
127
|
+
else out({ protocol: { name: 'ZCode Protocol', version: 1 } });
|
|
128
|
+
|
|
129
|
+
// SIGTERM 优雅窗口:默认终止会丢弃「已写入管道但尚未读到」的帧——延迟退出让
|
|
130
|
+
// stdin 排空后收尾(dispose 的 close-帧-先于-SIGTERM 顺序在本侧可观测:
|
|
131
|
+
// killChain 的 grace 远大于本窗口,不会升级 SIGKILL)
|
|
132
|
+
process.on('SIGTERM', () => {
|
|
133
|
+
setTimeout(() => process.exit(0), 100);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// env 快照 + boot 流水(惰性启动 / argv 形态 / env 惯例断言的数据源)
|
|
137
|
+
log('env', {
|
|
138
|
+
pid: process.pid,
|
|
139
|
+
home: process.env.HOME,
|
|
140
|
+
telemetry: process.env.ZCODE_MODEL_TELEMETRY_ENABLED,
|
|
141
|
+
nested: process.env.ZSW_NESTED,
|
|
142
|
+
unifiedNested: process.env.XYZ_AGENT_SUBAGENT,
|
|
143
|
+
});
|
|
144
|
+
log('boot', { pid: process.pid, argv: process.argv.slice(2) });
|
|
145
|
+
if (process.env.FAKE_STDERR === '1') {
|
|
146
|
+
process.stderr.write('fake-appserver stderr line A\nfake-appserver stderr line B\n');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// 反向请求记账:id -> 客户端应答到达时 resolve
|
|
150
|
+
let reqSeq = 0;
|
|
151
|
+
const pendingReverse = new Map();
|
|
152
|
+
|
|
153
|
+
function sendReverse(method, params) {
|
|
154
|
+
return new Promise((resolve) => {
|
|
155
|
+
const id = `srv-${++reqSeq}`;
|
|
156
|
+
pendingReverse.set(id, resolve);
|
|
157
|
+
out({ id, method, ...(params !== undefined ? { params } : {}) });
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function onClientAnswer(frame) {
|
|
162
|
+
const settle = pendingReverse.get(frame.id);
|
|
163
|
+
if (settle) {
|
|
164
|
+
pendingReverse.delete(frame.id);
|
|
165
|
+
settle({ id: frame.id, result: frame.result, error: frame.error });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// 推送帧回放(scenario 帧即 golden 语料/注入形态本身,不走 withExtra)。STAMP_SESSION
|
|
170
|
+
// 开启时统一改写/补记 params.sessionId 为目标会话(RA3 双会话地基:并发两会话各自
|
|
171
|
+
// 收到归因正确的推送流——真服务端推送本就按会话归因,telemetry 帧不带 sid 属协议
|
|
172
|
+
// 实测形态,stamp 是 fake 侧的确定性等价物)。
|
|
173
|
+
function pushFrames(frames, targetSessionId) {
|
|
174
|
+
for (const frame of frames || []) {
|
|
175
|
+
if (!STAMP_SESSION || !targetSessionId) {
|
|
176
|
+
out(frame);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
const stamped = JSON.parse(JSON.stringify(frame));
|
|
180
|
+
if (stamped && typeof stamped.params === 'object' && stamped.params !== null) {
|
|
181
|
+
stamped.params.sessionId = targetSessionId;
|
|
182
|
+
}
|
|
183
|
+
out(stamped);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// [R4] stop 触发的终态推送(stopBehavior 缺省 'terminal'——abort 优雅生效路径)
|
|
188
|
+
const TURN_TERMINAL_FRAME = {
|
|
189
|
+
method: 'v4/telemetry/event',
|
|
190
|
+
params: { kind: 'turn.terminal', status: 'success' },
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
async function handleRequest(f) {
|
|
194
|
+
const { id, method } = f;
|
|
195
|
+
const params = f.params ?? {};
|
|
196
|
+
switch (method) {
|
|
197
|
+
case 'test/echo':
|
|
198
|
+
return reply(id, params);
|
|
199
|
+
case 'test/delay-echo': {
|
|
200
|
+
const delay = Number(params.delayMs) || 50;
|
|
201
|
+
setTimeout(() => reply(id, params), delay);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
case 'test/fail':
|
|
205
|
+
return replyErr(id, Number(params.code) || -32603, String(params.message || 'fake failure'), params.data);
|
|
206
|
+
case 'test/push': {
|
|
207
|
+
const pushMethod = String(params.pushMethod || 'test/notification');
|
|
208
|
+
out(withExtra({ method: pushMethod, ...(params.pushParams !== undefined ? { params: params.pushParams } : {}) }));
|
|
209
|
+
return reply(id, { pushed: true });
|
|
210
|
+
}
|
|
211
|
+
case 'test/reverse': {
|
|
212
|
+
const answer = await sendReverse(String(params.reverseMethod || 'permission/request'), params.reverseParams);
|
|
213
|
+
log('reverse-answer', { requested: params.reverseMethod, answer });
|
|
214
|
+
return reply(id, { answered: true });
|
|
215
|
+
}
|
|
216
|
+
case 'test/malformed-first':
|
|
217
|
+
process.stdout.write('this is not json {{{\n');
|
|
218
|
+
return reply(id, { survived: true });
|
|
219
|
+
case 'test/suicide':
|
|
220
|
+
process.stderr.write('A'.repeat(600) + 'CRASH-MARK-TAIL');
|
|
221
|
+
process.exit(1);
|
|
222
|
+
return; // 不可达(exit 先行),保持 switch 完整
|
|
223
|
+
case 'session/create': {
|
|
224
|
+
if (SCENARIO && SCENARIO.createError) {
|
|
225
|
+
return replyErr(id, SCENARIO.createError.code, SCENARIO.createError.message, SCENARIO.createError.data);
|
|
226
|
+
}
|
|
227
|
+
const answer = await sendReverse('session/requestRuntimePreferences');
|
|
228
|
+
log('reverse-answer', { requested: 'session/requestRuntimePreferences', answer });
|
|
229
|
+
if (SCENARIO && SCENARIO.createResult) return reply(id, SCENARIO.createResult);
|
|
230
|
+
return reply(id, { session: { sessionId: `sess_${id}` } });
|
|
231
|
+
}
|
|
232
|
+
case 'session/subscribe':
|
|
233
|
+
return reply(id, (SCENARIO && SCENARIO.subscribeResult) || { subscribed: true });
|
|
234
|
+
case 'session/send': {
|
|
235
|
+
if (SCENARIO && SCENARIO.sendError) {
|
|
236
|
+
return replyErr(id, SCENARIO.sendError.code, SCENARIO.sendError.message, SCENARIO.sendError.data);
|
|
237
|
+
}
|
|
238
|
+
// 推送帧逐字回放(STAMP_SESSION 时按目标会话归因改写);重建代走 rebootSendPushes
|
|
239
|
+
// (U4:重试轮的不同行为通道)
|
|
240
|
+
const pushes =
|
|
241
|
+
BOOT_GEN > 1 && SCENARIO && SCENARIO.rebootSendPushes
|
|
242
|
+
? SCENARIO.rebootSendPushes
|
|
243
|
+
: SCENARIO && SCENARIO.sendPushes;
|
|
244
|
+
pushFrames(pushes, String(params.sessionId || ''));
|
|
245
|
+
// [P0-1 U4] 崩溃收割注入:应答后 N ms 自杀(onClose → failAllTurns 在途 turn
|
|
246
|
+
// 收割的确定性触发面;exit(1) 非零码与 test/suicide 同形态)
|
|
247
|
+
const crashAfterSendMs = SCENARIO && SCENARIO.crashAfterSendMs;
|
|
248
|
+
if (typeof crashAfterSendMs === 'number' && crashAfterSendMs >= 0) {
|
|
249
|
+
setTimeout(() => {
|
|
250
|
+
log('crash-injected', { afterMs: crashAfterSendMs });
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}, crashAfterSendMs).unref();
|
|
253
|
+
}
|
|
254
|
+
return reply(id, (SCENARIO && SCENARIO.sendResult) || { accepted: true });
|
|
255
|
+
}
|
|
256
|
+
case 'session/stop': {
|
|
257
|
+
// [R4] abort 链断言面:缺省推终态(stop 优雅生效);stopBehavior:'none' 只应答;
|
|
258
|
+
// stopError 注入协议性 error 应答帧(P0-1 U2 态②——不升级杀链判据);
|
|
259
|
+
// stopBehavior:'hang' 永不应答(态③——stop 3s 超时 = 连接级失败判据)
|
|
260
|
+
const behavior = (SCENARIO && SCENARIO.stopBehavior) || 'terminal';
|
|
261
|
+
if (behavior === 'hang') return;
|
|
262
|
+
if (SCENARIO && SCENARIO.stopError) {
|
|
263
|
+
return replyErr(id, SCENARIO.stopError.code, SCENARIO.stopError.message, SCENARIO.stopError.data);
|
|
264
|
+
}
|
|
265
|
+
if (behavior === 'terminal') {
|
|
266
|
+
pushFrames([TURN_TERMINAL_FRAME], String(params.sessionId || ''));
|
|
267
|
+
}
|
|
268
|
+
return reply(id, { stopped: true });
|
|
269
|
+
}
|
|
270
|
+
case 'session/read': {
|
|
271
|
+
if (SCENARIO && SCENARIO.readError) {
|
|
272
|
+
return replyErr(id, SCENARIO.readError.code, SCENARIO.readError.message, SCENARIO.readError.data);
|
|
273
|
+
}
|
|
274
|
+
return reply(id, (SCENARIO && SCENARIO.readResult) || { messages: [] });
|
|
275
|
+
}
|
|
276
|
+
case 'session/close':
|
|
277
|
+
return reply(id, { closed: true });
|
|
278
|
+
default:
|
|
279
|
+
return replyErr(id, -32601, `method not found: ${method}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const rl = readline.createInterface({ input: process.stdin });
|
|
284
|
+
rl.on('line', (line) => {
|
|
285
|
+
const text = String(line).trim();
|
|
286
|
+
if (!text) return;
|
|
287
|
+
let f;
|
|
288
|
+
try {
|
|
289
|
+
f = JSON.parse(text);
|
|
290
|
+
} catch {
|
|
291
|
+
log('unparseable-from-client', { line: text.slice(0, 100) });
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
log('recv', { frame: f });
|
|
295
|
+
if (f && f.id != null && typeof f.method === 'string') {
|
|
296
|
+
void handleRequest(f);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (f && f.id != null) onClientAnswer(f); // 我方反向请求的客户端应答
|
|
300
|
+
});
|
|
301
|
+
rl.on('close', () => process.exit(0));
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_meta": {
|
|
3
|
+
"description": "zcode app-server 常驻通道 golden 帧序列语料(R3)。四类样本:create 应答 / 推送流 / 终态帧 / read 应答(NDJSON 逐行,附录 A.2 任务生命周期帧序)",
|
|
4
|
+
"source": "synthesized-from-A2-protocol-authority",
|
|
5
|
+
"synthesisNote": "非真机实录——按设计附录 A.2(协议权威,zcode.cjs 0.16.5 二进制字符串级验证命中)+ 旧 zsw 实现真机抓包形态(zsw 仓 84b63a0^ runner-appserver.js 实测注释)合成。真机冒烟(RA 跨仓段)后应替换为实录并同步双副本。telemetry 帧不带 sessionId(A.2 未标)——归因走唯一在途兜底;session/event 帧带 sessionId",
|
|
6
|
+
"engineVersion": "0.16.5 (app-server)",
|
|
7
|
+
"protocolVersion": 1,
|
|
8
|
+
"recordedAt": "2026-08-30",
|
|
9
|
+
"invariants": {
|
|
10
|
+
"textIdentity": "pushStream 中 payload.delta 拼接 === terminal 收尾帧 payload.response === readResponse 最后 assistant 消息 text parts 拼接('你好,任务完成')——不变量 1 双来源",
|
|
11
|
+
"usage": "收尾帧 usage {inputTokens:12599, outputTokens:17} 与 spawn golden(zcode-golden-spawn.json)同值——漂移对照锚点"
|
|
12
|
+
},
|
|
13
|
+
"frames": {
|
|
14
|
+
"createResponse": "session/create 应答帧(NDJSON 单行)。projection.sessionId 恒 \"unknown\"(勿用),权威位置 session.sessionId",
|
|
15
|
+
"pushStream": "推送流帧(A.2 ④ 逐行):state.updated 进入 running / v4 telemetry stream.chunk(无文本,chunkLength 遥测)/ session/event payload.delta(实时文本增量)",
|
|
16
|
+
"terminal": "终态帧(A.2 ⑤ 逐行):v4 telemetry turn.terminal(终态权威,status 枚举)+ session/event 收尾帧(全文 + usage)",
|
|
17
|
+
"readResponse": "session/read 应答帧(NDJSON 单行,A.2 ⑥):messages[].info.role + parts[](text 全文 / step-finish tokens——tokens 结构属 A.5 未确认项,宽容解析)"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"frames": {
|
|
21
|
+
"createResponse": "{\"session\":{\"sessionId\":\"sess_golden_r3_01\"},\"projection\":{\"sessionId\":\"unknown\",\"status\":\"idle\",\"turnCount\":0,\"totalTokenCount\":0,\"contextUsed\":0,\"contextWindow\":1000000}}",
|
|
22
|
+
"pushStream": [
|
|
23
|
+
"{\"method\":\"state.updated\",\"params\":{\"sessionId\":\"sess_golden_r3_01\",\"patch\":{\"status\":\"running\"},\"reason\":\"prompt_started\"}}",
|
|
24
|
+
"{\"method\":\"v4/telemetry/event\",\"params\":{\"kind\":\"stream.chunk\",\"channel\":\"text\",\"chunkLength\":6,\"firstChunk\":true,\"assistantMessageId\":\"msg_golden_r3_01\"}}",
|
|
25
|
+
"{\"method\":\"session/event\",\"params\":{\"sessionId\":\"sess_golden_r3_01\",\"payload\":{\"delta\":\"你好\",\"assistantMessageId\":\"msg_golden_r3_01\"}}}",
|
|
26
|
+
"{\"method\":\"v4/telemetry/event\",\"params\":{\"kind\":\"stream.chunk\",\"channel\":\"text\",\"chunkLength\":1,\"firstChunk\":false,\"assistantMessageId\":\"msg_golden_r3_01\"}}",
|
|
27
|
+
"{\"method\":\"session/event\",\"params\":{\"sessionId\":\"sess_golden_r3_01\",\"payload\":{\"delta\":\",\",\"assistantMessageId\":\"msg_golden_r3_01\"}}}",
|
|
28
|
+
"{\"method\":\"session/event\",\"params\":{\"sessionId\":\"sess_golden_r3_01\",\"payload\":{\"delta\":\"任务完成\",\"assistantMessageId\":\"msg_golden_r3_01\"}}}"
|
|
29
|
+
],
|
|
30
|
+
"terminal": [
|
|
31
|
+
"{\"method\":\"v4/telemetry/event\",\"params\":{\"kind\":\"turn.terminal\",\"status\":\"success\"}}",
|
|
32
|
+
"{\"method\":\"session/event\",\"params\":{\"sessionId\":\"sess_golden_r3_01\",\"payload\":{\"response\":\"你好,任务完成\",\"usage\":{\"inputTokens\":12599,\"outputTokens\":17}}}}"
|
|
33
|
+
],
|
|
34
|
+
"readResponse": "{\"messages\":[{\"info\":{\"role\":\"user\"},\"parts\":[{\"type\":\"text\",\"text\":\"做点什么\"}]},{\"info\":{\"role\":\"assistant\"},\"parts\":[{\"type\":\"text\",\"text\":\"你好\"},{\"type\":\"text\",\"text\":\",任务完成\"},{\"type\":\"step-finish\",\"tokens\":{\"input\":12599,\"output\":17,\"reasoning\":0,\"cache\":512,\"total\":12616}}]}]}"
|
|
35
|
+
}
|
|
36
|
+
}
|