@zhushanwen/subagent-core 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/chunk-KXVBIVOU.js +16 -0
- package/dist/chunk-T2SYBW3I.js +24 -0
- package/dist/chunk-VURUAGMM.js +2305 -0
- package/dist/{types-Dv4QhSJ_.d.cts → engine-discovery-scan-ocpM8FmI.d.cts} +835 -668
- package/dist/{types-Dv4QhSJ_.d.ts → engine-discovery-scan-ocpM8FmI.d.ts} +835 -668
- package/dist/execution/engine/engine-discovery-scan.cjs +2210 -0
- package/dist/execution/engine/engine-discovery-scan.d.cts +4 -0
- package/dist/execution/engine/engine-discovery-scan.d.ts +4 -0
- package/dist/execution/engine/engine-discovery-scan.js +20 -0
- package/dist/execution/engine/paths.cjs +6 -23
- package/dist/execution/engine/paths.d.cts +1 -8
- package/dist/execution/engine/paths.d.ts +1 -8
- package/dist/execution/engine/paths.js +1 -1
- package/dist/execution/relay-env.cjs +12 -28
- package/dist/execution/relay-env.d.cts +1 -33
- package/dist/execution/relay-env.d.ts +1 -33
- package/dist/execution/relay-env.js +5 -3
- package/dist/index.cjs +14123 -15467
- package/dist/index.d.cts +1179 -1540
- package/dist/index.d.ts +1179 -1540
- package/dist/index.js +7694 -10986
- package/dist.bundle/index.cjs +33485 -0
- package/package.json +20 -26
- package/src/__tests__/record-store-last-line.test.ts +16 -7
- package/src/core/error-message.ts +7 -6
- package/src/core/host-services.ts +8 -2
- package/src/core/notify-ports.ts +17 -2
- package/src/execution/__tests__/agent-registry.test.ts +1 -1
- package/src/execution/__tests__/alive-store.test.ts +1 -1
- package/src/execution/__tests__/chat-engine-routing.test.ts +62 -28
- package/src/execution/__tests__/chat-round-first-round-watchdog.test.ts +255 -0
- package/src/execution/__tests__/collect-budget.test.ts +291 -0
- package/src/execution/__tests__/collect-coordinator-service.test.ts +316 -0
- package/src/execution/__tests__/collect-coordinator.test.ts +371 -0
- package/src/execution/__tests__/collect-mixed-dispatch.test.ts +229 -0
- package/src/execution/__tests__/config-collect-sync.test.ts +120 -0
- package/src/execution/__tests__/config.test.ts +1 -1
- package/src/execution/__tests__/delivery-methods.test.ts +179 -237
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +0 -2
- package/src/execution/__tests__/execute-nesting.test.ts +20 -13
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +21 -34
- package/src/execution/__tests__/finalized-marker.test.ts +1 -1
- package/src/execution/__tests__/gc-timer.test.ts +8 -23
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +20 -10
- package/src/execution/__tests__/helpers/fake-engine-port.ts +187 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +36 -9
- package/src/execution/__tests__/helpers/subagent-service-mocks.ts +1 -1
- package/src/execution/__tests__/idle-gc.test.ts +200 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +26 -21
- package/src/execution/__tests__/manifest-store-tmp-recovery.test.ts +1 -1
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +5 -2
- package/src/execution/__tests__/notify-batch.test.ts +500 -0
- package/src/execution/__tests__/notify-ledger.test.ts +27 -0
- package/src/execution/__tests__/reconcile-sweep.test.ts +200 -0
- package/src/execution/__tests__/record-entry-collect.test.ts +102 -0
- package/src/execution/__tests__/record-store.test.ts +60 -6
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +20 -13
- package/src/execution/__tests__/relay-env.test.ts +12 -1
- package/src/execution/__tests__/round-supervisor.test.ts +293 -0
- package/src/execution/__tests__/session-file-gc.test.ts +1 -1
- package/src/execution/__tests__/session-pending.test.ts +119 -17
- package/src/execution/__tests__/start-collect-guard.test.ts +255 -0
- package/src/execution/__tests__/stream-sink-retirement.test.ts +10 -10
- package/src/execution/__tests__/subagent-actions-core.test.ts +6 -0
- package/src/execution/__tests__/subagent-service-multiproc-guard.test.ts +14 -11
- package/src/execution/__tests__/subagent-service-notify-gate.test.ts +33 -30
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +2 -9
- package/src/execution/__tests__/subagent-service-recovery-bounds.test.ts +59 -129
- package/src/execution/__tests__/subagent-service.test.ts +2 -2
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +109 -7
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +108 -36
- package/src/execution/__tests__/sync-collect-recovery.test.ts +1102 -0
- package/src/execution/__tests__/tombstone-store.test.ts +1 -1
- package/src/execution/__tests__/workflow-state-root.test.ts +232 -0
- package/src/execution/__tests__/worktree-git-ops.test.ts +1 -1
- package/src/execution/__tests__/worktree-reconcile-aging.test.ts +2 -2
- package/src/execution/__tests__/worktree-reconcile.integration.test.ts +1 -1
- package/src/execution/__tests__/worktree-registry.test.ts +1 -1
- package/src/execution/agent-registry.ts +6 -2
- package/src/execution/collect-coordinator.ts +200 -0
- package/src/execution/config.ts +77 -5
- package/src/execution/dialog-queue.ts +6 -73
- package/src/execution/engine/__tests__/common/capability-gate.test.ts +115 -15
- package/src/execution/engine/__tests__/common/errors.test.ts +11 -18
- package/src/execution/engine/__tests__/common/event-journal.test.ts +1 -1
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +7 -0
- package/src/execution/engine/__tests__/common/nesting-guard.test.ts +9 -3
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +2 -2
- package/src/execution/engine/__tests__/common/session-view-service.test.ts +90 -3
- package/src/execution/engine/__tests__/conformance/H9-test-disposition.md +116 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/fake-engine-protocol.mjs +377 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/recorded.fixture.json +331 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/engine-protocol/smoke-run.fixture.json +213 -0
- package/src/execution/engine/__tests__/conformance/chat-round-protocol.test.ts +230 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +69 -42
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +4 -81
- package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +67 -44
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +82 -55
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +133 -70
- package/src/execution/engine/__tests__/conformance/engine-crash.test.ts +143 -0
- package/src/execution/engine/__tests__/conformance/fake-engine-capabilities.ts +19 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +8 -3
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +6 -5
- package/src/execution/engine/__tests__/conformance/protocol-blackbox.test.ts +398 -0
- package/src/execution/engine/__tests__/conformance/registry-fork-filter.test.ts +221 -0
- package/src/execution/engine/__tests__/conformance/round-liveness-supervisor.test.ts +302 -0
- package/src/execution/engine/__tests__/conformance/static-spawn-guard.test.ts +58 -0
- package/src/execution/engine/__tests__/engine-discovery-scan.test.ts +558 -0
- package/src/execution/engine/__tests__/host-task-spec.test.ts +45 -0
- package/src/execution/engine/__tests__/model-ref-split.test.ts +74 -0
- package/src/execution/engine/__tests__/registry.test.ts +206 -1
- package/src/execution/engine/__tests__/routing.test.ts +97 -0
- package/src/execution/engine/__tests__/run-failure-worktree-cleanup.test.ts +97 -0
- package/src/execution/engine/client/__tests__/__fixtures__/fake-engine.mjs +294 -0
- package/src/execution/engine/client/__tests__/engine-client.test.ts +516 -0
- package/src/execution/engine/client/__tests__/mirror.test.ts +67 -0
- package/src/execution/engine/client/__tests__/pid-file.test.ts +257 -0
- package/src/execution/engine/client/__tests__/protocol-closure.test.ts +95 -0
- package/src/execution/engine/client/__tests__/remote-engine.test.ts +457 -0
- package/src/execution/engine/client/client-options.ts +103 -0
- package/src/execution/engine/client/engine-client.ts +687 -0
- package/src/execution/engine/client/mirror.ts +167 -0
- package/src/execution/engine/client/pid-file.ts +392 -0
- package/src/execution/engine/client/reaper.ts +95 -0
- package/src/execution/engine/client/remote-engine.ts +441 -0
- package/src/execution/engine/client/reverse-router.ts +255 -0
- package/src/execution/engine/common/capability-gate.ts +109 -22
- package/src/execution/engine/common/errors.ts +9 -25
- package/src/execution/engine/common/event-journal.ts +4 -50
- package/src/execution/engine/common/journal-replay.ts +3 -1
- package/src/execution/engine/common/kill-chain.ts +18 -251
- package/src/execution/engine/common/nesting-guard.ts +18 -114
- package/src/execution/engine/common/pool-manager.ts +4 -0
- package/src/execution/engine/common/session-view-service.ts +56 -84
- package/src/execution/engine/config.ts +151 -0
- package/src/execution/engine/d8-compat.ts +346 -0
- package/src/execution/engine/engine-discovery-roots.ts +107 -0
- package/src/execution/engine/engine-discovery-scan.ts +269 -0
- package/src/execution/engine/engine-discovery.ts +30 -7
- package/src/execution/engine/engine-inspect-package.ts +282 -0
- package/src/execution/engine/engine-manifest.ts +244 -0
- package/src/execution/engine/host/__tests__/host-askuser-endpoint.test.ts +123 -0
- package/src/execution/engine/host/__tests__/host-bridge.test.ts +135 -0
- package/src/execution/engine/host/__tests__/spawned-children.test.ts +73 -0
- package/src/execution/engine/host/host-bridge.ts +150 -0
- package/src/execution/engine/host/host-ui-endpoint.ts +47 -0
- package/src/execution/engine/host/pi-host-binding.ts +91 -0
- package/src/execution/engine/host/spawned-children.ts +139 -0
- package/src/execution/engine/host-task-spec.ts +29 -2
- package/src/execution/engine/model-validation.ts +55 -2
- package/src/execution/engine/paths.ts +16 -41
- package/src/execution/engine/port.ts +48 -2
- package/src/execution/engine/registry.ts +153 -34
- package/src/execution/engine/routing.ts +225 -52
- package/src/execution/engine/types.ts +25 -200
- package/src/execution/execution-record.ts +7 -0
- package/src/execution/finalize-record.ts +40 -11
- package/src/execution/idle-gc.ts +89 -14
- package/src/execution/lifecycle-manager.ts +10 -7
- package/src/execution/lifecycle-predicates.ts +10 -8
- package/src/execution/notifier.ts +234 -25
- package/src/execution/notify-host.ts +21 -1
- package/src/execution/record-entry.ts +16 -0
- package/src/execution/record-store.ts +189 -31
- package/src/execution/relay-env.ts +19 -36
- package/src/execution/round-supervisor/domain.ts +89 -0
- package/src/execution/round-supervisor/index.ts +33 -0
- package/src/execution/round-supervisor/notify-accounting.ts +87 -0
- package/src/execution/round-supervisor/reconcile-sweep.ts +235 -0
- package/src/execution/round-supervisor/service-binding.test.ts +661 -0
- package/src/execution/round-supervisor/service-binding.ts +273 -0
- package/src/execution/round-supervisor/supervisor.ts +426 -0
- package/src/execution/session-pending.ts +68 -74
- package/src/execution/settled-watchdog.ts +39 -0
- package/src/execution/subagent-actions-core.ts +62 -6
- package/src/execution/subagent-service.ts +1161 -406
- package/src/execution/subprocess-agent-runner.ts +16 -8
- package/src/execution/sync-rebuild.ts +87 -0
- package/src/execution/types.ts +104 -117
- package/src/execution/ui-channels.ts +13 -214
- package/src/execution/ui-request-handler-factory.ts +7 -4
- package/src/execution/ui-request-observability.ts +2 -2
- package/src/execution/workflow-state-root.ts +67 -0
- package/src/execution/worktree-git-ops.ts +5 -0
- package/src/execution/worktree-manager.ts +11 -1
- package/src/index.ts +55 -26
- package/src/orchestration/__tests__/config-loader.test.ts +1 -1
- package/src/orchestration/__tests__/execute-agent-call.test.ts +1 -1
- package/src/orchestration/__tests__/file-run-store-prune.test.ts +1 -1
- package/src/orchestration/__tests__/file-run-store-throttle.test.ts +1 -1
- package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +1 -1
- package/src/orchestration/__tests__/script-generate.test.ts +5 -5
- package/src/orchestration/__tests__/skill-discovery.test.ts +2 -2
- package/src/orchestration/__tests__/workflow-files.test.ts +10 -10
- package/src/orchestration/__tests__/workflow-script-registry-impl.test.ts +1 -1
- package/src/orchestration/execute-agent-call.ts +1 -1
- package/src/orchestration/file-run-store.ts +144 -59
- package/src/orchestration/models/types.ts +43 -42
- package/src/shared/__tests__/atomic-write.test.ts +1 -1
- package/src/shared/__tests__/resource-discovery-host-roots.test.ts +5 -5
- package/src/shared/zcode-model-ref.ts +31 -0
- package/dist/chunk-43ONBFZX.js +0 -240
- package/dist/chunk-A4IVZWVX.js +0 -31
- package/dist/chunk-APZY4IME.js +0 -27
- package/dist/chunk-V3VHZ2VX.js +0 -59
- package/dist/execution/engine/engines/zcode/constants.cjs +0 -107
- package/dist/execution/engine/engines/zcode/constants.d.cts +0 -135
- package/dist/execution/engine/engines/zcode/constants.d.ts +0 -135
- package/dist/execution/engine/engines/zcode/constants.js +0 -54
- package/dist/execution/engine/engines/zcode/reader.cjs +0 -276
- package/dist/execution/engine/engines/zcode/reader.d.cts +0 -21
- package/dist/execution/engine/engines/zcode/reader.d.ts +0 -21
- package/dist/execution/engine/engines/zcode/reader.js +0 -9
- package/src/__tests__/append-system-prompt-assembly.test.ts +0 -243
- package/src/__tests__/fr4-get-state-handshake.test.ts +0 -125
- package/src/__tests__/session-runner.test.ts +0 -69
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +0 -490
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +0 -191
- package/src/execution/__tests__/descendant-sweep-guards.test.ts +0 -220
- package/src/execution/__tests__/descendant-sweep.test.ts +0 -269
- package/src/execution/__tests__/engine-model-validation.test.ts +0 -741
- package/src/execution/__tests__/epipe-fallback.test.ts +0 -248
- package/src/execution/__tests__/execution-runtime-face.test.ts +0 -272
- package/src/execution/__tests__/get-state-handshake.test.ts +0 -127
- package/src/execution/__tests__/helpers/session-runner-mocks.ts +0 -113
- package/src/execution/__tests__/keep-alive-no-progress.test.ts +0 -280
- package/src/execution/__tests__/kill-all-escalation.test.ts +0 -196
- package/src/execution/__tests__/max-turns-to-watchdog-ms.test.ts +0 -113
- package/src/execution/__tests__/output-collector.test.ts +0 -469
- package/src/execution/__tests__/pi-invocation.test.ts +0 -134
- package/src/execution/__tests__/recursive-visibility-env.test.ts +0 -149
- package/src/execution/__tests__/rpc-mode.test.ts +0 -89
- package/src/execution/__tests__/run-and-finalize-anchoring.test.ts +0 -387
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +0 -277
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +0 -254
- package/src/execution/__tests__/run-spawn-edges.test.ts +0 -1079
- package/src/execution/__tests__/run-spawn-integration.test.ts +0 -933
- package/src/execution/__tests__/run-spawn-resume.test.ts +0 -322
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +0 -196
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +0 -207
- package/src/execution/__tests__/service-kill-escalation.test.ts +0 -91
- package/src/execution/__tests__/session-runner-branch-cache-lru.test.ts +0 -110
- package/src/execution/__tests__/session-runner-close-prune.test.ts +0 -181
- package/src/execution/__tests__/session-runner-dispatch.test.ts +0 -489
- package/src/execution/__tests__/session-runner-epipe.test.ts +0 -179
- package/src/execution/__tests__/session-runner-heartbeat-idle-fallback.test.ts +0 -227
- package/src/execution/__tests__/session-runner-lifecycle-helpers.test.ts +0 -290
- package/src/execution/__tests__/session-runner-schema-env.test.ts +0 -352
- package/src/execution/__tests__/settled-watchdog.test.ts +0 -524
- package/src/execution/__tests__/spawn-args.test.ts +0 -446
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +0 -192
- package/src/execution/__tests__/spawn-event-adapter.test.ts +0 -167
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +0 -208
- package/src/execution/__tests__/spawned-children.test.ts +0 -236
- package/src/execution/__tests__/start-sync-model-guard.test.ts +0 -150
- package/src/execution/__tests__/stdin-writer.test.ts +0 -464
- package/src/execution/__tests__/subagent-service-message-close.test.ts +0 -693
- package/src/execution/__tests__/temp-prompt.test.ts +0 -53
- package/src/execution/__tests__/timeout-integration.test.ts +0 -616
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +0 -194
- package/src/execution/__tests__/turn-limiter.test.ts +0 -65
- package/src/execution/__tests__/ui-request-handler.test.ts +0 -205
- package/src/execution/__tests__/ui-request-queue.test.ts +0 -298
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +0 -230
- package/src/execution/engine/__tests__/common/schema-emulation.test.ts +0 -128
- package/src/execution/engine/__tests__/common/session-view-service-zcode-dbpath.test.ts +0 -149
- package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +0 -28
- package/src/execution/engine/__tests__/conformance/zcode-appserver-harness.ts +0 -128
- package/src/execution/engine/__tests__/paths.test.ts +0 -39
- package/src/execution/engine/common/schema-emulation.ts +0 -189
- package/src/execution/engine/common/session-view-projection.ts +0 -51
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +0 -615
- package/src/execution/engine/engines/pi/__tests__/reader.test.ts +0 -155
- package/src/execution/engine/engines/pi/__tests__/spawn-opts-direct.test.ts +0 -257
- package/src/execution/engine/engines/pi/argv-mirror.ts +0 -135
- package/src/execution/engine/engines/pi/get-state-handshake.ts +0 -179
- package/src/execution/engine/engines/pi/output-collector.ts +0 -317
- package/src/execution/engine/engines/pi/pi-engine.ts +0 -811
- package/src/execution/engine/engines/pi/pi-invocation.ts +0 -120
- package/src/execution/engine/engines/pi/reader.ts +0 -59
- package/src/execution/engine/engines/pi/registration.ts +0 -37
- package/src/execution/engine/engines/pi/session-runner.ts +0 -2840
- package/src/execution/engine/engines/pi/spawn-event-adapter.ts +0 -404
- package/src/execution/engine/engines/pi/stdin-writer.ts +0 -199
- package/src/execution/engine/engines/pi/temp-prompt.ts +0 -62
- package/src/execution/engine/engines/pi/turn-limiter.ts +0 -102
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/fake-appserver.mjs +0 -301
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-appserver.json +0 -36
- package/src/execution/engine/engines/zcode/__tests__/appserver-launcher.test.ts +0 -321
- package/src/execution/engine/engines/zcode/__tests__/connection.test.ts +0 -473
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +0 -43
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +0 -124
- package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +0 -210
- package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +0 -71
- package/src/execution/engine/engines/zcode/__tests__/session-channel-dispose-harvest.test.ts +0 -247
- package/src/execution/engine/engines/zcode/__tests__/session-channel-turn-timers.test.ts +0 -451
- package/src/execution/engine/engines/zcode/__tests__/session-channel.test.ts +0 -792
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-appserver.test.ts +0 -782
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-degrade.test.ts +0 -168
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-dispose.test.ts +0 -210
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-retry.test.ts +0 -353
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-status.test.ts +0 -282
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine-timeout.test.ts +0 -372
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +0 -145
- package/src/execution/engine/engines/zcode/appserver-launcher.ts +0 -167
- package/src/execution/engine/engines/zcode/connection.ts +0 -598
- package/src/execution/engine/engines/zcode/constants.ts +0 -176
- package/src/execution/engine/engines/zcode/golden-sample.ts +0 -47
- package/src/execution/engine/engines/zcode/parser.ts +0 -102
- package/src/execution/engine/engines/zcode/preparer.ts +0 -235
- package/src/execution/engine/engines/zcode/reader.ts +0 -381
- package/src/execution/engine/engines/zcode/registration.ts +0 -37
- package/src/execution/engine/engines/zcode/session-channel.ts +0 -968
- package/src/execution/engine/engines/zcode/zcode-engine.ts +0 -1431
- package/src/execution/round-settlement.ts +0 -93
- package/src/execution/ui-request-queue.ts +0 -215
- package/src/shared/schema-env.ts +0 -44
|
@@ -1,253 +1,20 @@
|
|
|
1
1
|
// src/execution/engine/common/kill-chain.ts
|
|
2
2
|
//
|
|
3
|
-
// 超时杀链与 abort
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// 杀链(SIGTERM → grace → SIGKILL)
|
|
22
|
-
// ============================================================
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 可杀子进程的结构形状(Node ChildProcess 的结构子集)。
|
|
26
|
-
* 用结构接口而非 ChildProcess 类型:测试可注入 fake(ChildProcess 全字段构造过重),
|
|
27
|
-
* 且未来 driver host 的常驻进程句柄只要满足此形状即可复用杀链。
|
|
28
|
-
*/
|
|
29
|
-
export interface KillableChild {
|
|
30
|
-
/** 非 null = 进程已退出(自然退出码)。 */
|
|
31
|
-
readonly exitCode: number | null;
|
|
32
|
-
/** 非 null = 进程被信号杀死。exitCode/signalCode 任一非 null 即已退出。 */
|
|
33
|
-
readonly signalCode: string | null;
|
|
34
|
-
/** 发信号。返回 false = 进程已不存在(kill no-op)。 */
|
|
35
|
-
kill(signal?: NodeJS.Signals | number): boolean;
|
|
36
|
-
once(event: "exit", listener: (code: number | null, signal: NodeJS.Signals | null) => void): unknown;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// 毫秒→秒换算(SIGKILL 升级 warn 日志的秒数显示)。文件内私有定义:工程内 MS_PER_SECOND
|
|
40
|
-
// 惯例是各使用文件私有常量(execution-record / lifecycle-manager / session-file-gc /
|
|
41
|
-
// session-runner 四处先例),无共享导出源可 import,保持同惯例不另立导出点。
|
|
42
|
-
const MS_PER_SECOND = 1_000;
|
|
43
|
-
|
|
44
|
-
/** SIGTERM 优雅窗口默认值(ms)。实测校准点:设计 §5 待验证检查点⑤(zcode 对 SIGTERM 的响应时序)。 */
|
|
45
|
-
export const DEFAULT_KILL_GRACE_MS = 5_000;
|
|
46
|
-
|
|
47
|
-
/** SIGKILL 发出后的收尸等待上限(ms)——SIGKILL 后进程必死(D 状态罕见),有界等待防挂死。 */
|
|
48
|
-
const SIGKILL_REAP_TIMEOUT_MS = 10_000;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 宿主超时 abort 的 signal.reason 标记(对齐点④)。mergeTimeoutSignal(SAR 侧超时
|
|
52
|
-
* 合并链)产出;引擎 abort 合成终态时判别「超时 vs 用户 cancel」——超时统一走
|
|
53
|
-
* synthesizeTimeoutOutcome(engine_timeout),cancel 维持中止标记(engine_run_failed)。
|
|
54
|
-
*/
|
|
55
|
-
export const HOST_TIMEOUT_ABORT_REASON = "agent-call-timeout";
|
|
56
|
-
|
|
57
|
-
/** killChain 的参数形状。 */
|
|
58
|
-
export interface KillChainOptions {
|
|
59
|
-
/**
|
|
60
|
-
* SIGTERM 优雅窗口(ms)。grace 窗口按引擎参数化(D3-① 杀链合一):pi 传 30s
|
|
61
|
-
* ([race-F4] 现状值)、zcode 传 5s(ZCODE_KILL_GRACE_MS)——两引擎现状逐字节保持。
|
|
62
|
-
*/
|
|
63
|
-
graceMs: number;
|
|
64
|
-
/**
|
|
65
|
-
* [D3-①] 内部 timer unref。pi 路径现状 = 升级 timer unref(不阻止主进程退出,dispose
|
|
66
|
-
* killAll 兜底);zcode 现状 = ref'd(timer 挂起时进程等待收尸)——各引擎按现状传。
|
|
67
|
-
*/
|
|
68
|
-
unrefTimers?: boolean;
|
|
69
|
-
/**
|
|
70
|
-
* SIGKILL 升级时的 warn 留痕载体(如 `child sa-xxx (source: spawn watchdog)`)。
|
|
71
|
-
* 不传则升级静默(zcode 现状)——pi 侧现状有 warn,由调用方组装完整语境。
|
|
72
|
-
*/
|
|
73
|
-
escalationNote?: string;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* 杀链:SIGTERM → 等待 graceMs → 仍存活则 SIGKILL。
|
|
78
|
-
*
|
|
79
|
-
* @returns 'terminated' = SIGTERM 优雅退出(或进程已自行退出);'killed' = 走了 SIGKILL。
|
|
80
|
-
*/
|
|
81
|
-
export async function killChain(
|
|
82
|
-
child: KillableChild,
|
|
83
|
-
opts: KillChainOptions,
|
|
84
|
-
): Promise<"terminated" | "killed"> {
|
|
85
|
-
// 已退出(自然/已被杀)→ 无需发信号,按优雅终止口径返回
|
|
86
|
-
if (child.exitCode !== null || child.signalCode !== null) return "terminated";
|
|
87
|
-
|
|
88
|
-
const exited = waitForExit(child);
|
|
89
|
-
safeKill(child, "SIGTERM");
|
|
90
|
-
|
|
91
|
-
const graceful = await raceTimeout(exited, opts.graceMs, opts.unrefTimers === true);
|
|
92
|
-
if (graceful === "settled") return "terminated";
|
|
93
|
-
// grace 超时后进程可能恰好在检查前一刻退出——复核退出态,避免误杀已死进程
|
|
94
|
-
if (child.exitCode !== null || child.signalCode !== null) return "terminated";
|
|
95
|
-
|
|
96
|
-
if (opts.escalationNote !== undefined) {
|
|
97
|
-
logger.warn(
|
|
98
|
-
`[kill-chain] ${opts.escalationNote} still alive ${opts.graceMs / MS_PER_SECOND}s after SIGTERM, escalating to SIGKILL`,
|
|
99
|
-
);
|
|
100
|
-
}
|
|
101
|
-
safeKill(child, "SIGKILL");
|
|
102
|
-
// 有界收尸:无论等到与否都返回 'killed'(信号已发出,返回值表达「走了 SIGKILL」)
|
|
103
|
-
await raceTimeout(exited, SIGKILL_REAP_TIMEOUT_MS, opts.unrefTimers === true);
|
|
104
|
-
return "killed";
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* 发信号兜底包裹:进程恰在退出态检查与 kill 之间自退时,ChildProcess.kill 可能抛
|
|
109
|
-
* (zsub 实测经验)——幂等吞掉并 debug 留痕,不阻断杀链语义(对已退进程信号本就是
|
|
110
|
-
* no-op)。收口自 zcode launcher 的内联实现(对齐点②:单一权威)。
|
|
111
|
-
*/
|
|
112
|
-
function safeKill(child: KillableChild, signal: NodeJS.Signals): void {
|
|
113
|
-
try {
|
|
114
|
-
child.kill(signal);
|
|
115
|
-
} catch (err) {
|
|
116
|
-
logger.debug(
|
|
117
|
-
`[kill-chain] ${signal} on exited process: ${toErrorMessage(err)}`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ============================================================
|
|
123
|
-
// 超时终态合成
|
|
124
|
-
// ============================================================
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* 合成 engine_timeout 终态(宿主超时杀链走完后的 AgentOutcome)。
|
|
128
|
-
* 含 stdout 尾部 2000 字 + 「可用 engine: pi 重跑」建议(§3.3.3 第 6 行);
|
|
129
|
-
* exitCode: null = 被信号杀死(AgentOutcome 的杀链判据,§3.3.5)。
|
|
130
|
-
*/
|
|
131
|
-
export function synthesizeTimeoutOutcome(
|
|
132
|
-
task: AgentCallOpts,
|
|
133
|
-
stdoutTail: string,
|
|
134
|
-
engineId: string = DEFAULT_ENGINE_ID,
|
|
135
|
-
): AgentOutcome {
|
|
136
|
-
return {
|
|
137
|
-
content: "",
|
|
138
|
-
// slug 进错误信息:单看 outcome(record 之外)也能定位是哪个任务超时
|
|
139
|
-
error: `engine_timeout: [slug=${task.description ?? "unknown"}] ${engineTimeoutDetail(stdoutTail)}`,
|
|
140
|
-
// 被信号杀死:退出码语义为 null(§3.3.5 AgentOutcome.exitCode 注释)
|
|
141
|
-
exitCode: null,
|
|
142
|
-
engineId,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// ============================================================
|
|
147
|
-
// abort 两级编排
|
|
148
|
-
// ============================================================
|
|
149
|
-
|
|
150
|
-
/** 原生中断后的宽限窗口默认值(ms):中断指令送达 → 引擎自行收尾的等待上限。 */
|
|
151
|
-
export const DEFAULT_NATIVE_INTERRUPT_GRACE_MS = 3_000;
|
|
152
|
-
|
|
153
|
-
/**
|
|
154
|
-
* abort 两级编排 helper(D1 abort 分级的公共实现):
|
|
155
|
-
* signal abort 时 ①先调引擎原生中断(tryNativeInterrupt,若有)并给宽限窗口,
|
|
156
|
-
* 窗口内未停(或无原生中断——CLI-only 引擎)则 ②走杀链兜底。
|
|
157
|
-
*
|
|
158
|
-
* 进程自然退出时以 'terminated' settle(挂在 exit 事件上,杀链对已退进程是 no-op),
|
|
159
|
-
* 调用方可安全 await;signal 永不 abort 且进程已退时也会 settle,不悬挂。
|
|
160
|
-
*/
|
|
161
|
-
export function abortWithFallback(
|
|
162
|
-
child: KillableChild,
|
|
163
|
-
signal: AbortSignal,
|
|
164
|
-
tryNativeInterrupt?: () => Promise<void>,
|
|
165
|
-
opts?: { graceMs?: number; nativeGraceMs?: number },
|
|
166
|
-
): Promise<"terminated" | "killed"> {
|
|
167
|
-
const graceMs = opts?.graceMs ?? DEFAULT_KILL_GRACE_MS;
|
|
168
|
-
const nativeGraceMs = opts?.nativeGraceMs ?? DEFAULT_NATIVE_INTERRUPT_GRACE_MS;
|
|
169
|
-
|
|
170
|
-
return new Promise<"terminated" | "killed">((resolve) => {
|
|
171
|
-
let settled = false;
|
|
172
|
-
// 三个 handler 互相引用(finish 移除 onAbort / onAbort 触发 runChain / runChain
|
|
173
|
-
// 兜底 finish),用函数声明 + 提升消解声明环,避免 use-before-define。
|
|
174
|
-
function finish(result: "terminated" | "killed"): void {
|
|
175
|
-
if (settled) return;
|
|
176
|
-
settled = true;
|
|
177
|
-
signal.removeEventListener("abort", onAbort);
|
|
178
|
-
resolve(result);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function onExit(): void {
|
|
182
|
-
finish("terminated");
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function runChain(): void {
|
|
186
|
-
void (async () => {
|
|
187
|
-
if (tryNativeInterrupt) {
|
|
188
|
-
try {
|
|
189
|
-
await tryNativeInterrupt();
|
|
190
|
-
} catch (err) {
|
|
191
|
-
// 原生中断失败(协议错/管道断)→ 直接落杀链,中断失败不阻断兜底。
|
|
192
|
-
// debug 级留诊断线索:这不是错误终态,只是该引擎优雅中断不可用
|
|
193
|
-
logger.debug(
|
|
194
|
-
`[kill-chain] native interrupt failed, falling back to kill chain: ${
|
|
195
|
-
toErrorMessage(err)
|
|
196
|
-
}`,
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
const stopped = await raceTimeout(waitForExit(child), nativeGraceMs);
|
|
200
|
-
if (stopped === "settled" || settled) return; // 原生中断生效,进程已停
|
|
201
|
-
}
|
|
202
|
-
finish(await killChain(child, { graceMs }));
|
|
203
|
-
})();
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function onAbort(): void {
|
|
207
|
-
runChain();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// 进程自然退出(含原生中断生效)→ 优雅终止口径。
|
|
211
|
-
// once listener 不显式移除:触发时 finish 已幂等,单 child 单 listener 无堆积。
|
|
212
|
-
child.once("exit", onExit);
|
|
213
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
214
|
-
finish("terminated");
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (signal.aborted) runChain();
|
|
219
|
-
else signal.addEventListener("abort", onAbort, { once: true });
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// ── 内部工具 ────────────────────────────────────────────────────
|
|
224
|
-
|
|
225
|
-
/** 等 child 退出(已退出立即 settle;否则挂一次性 exit listener)。 */
|
|
226
|
-
function waitForExit(child: KillableChild): Promise<void> {
|
|
227
|
-
return new Promise<void>((resolve) => {
|
|
228
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
229
|
-
resolve();
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
child.once("exit", () => resolve());
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/** promise vs 超时:超时先到返回 'timeout'(promise 继续但被放弃等待)。unref 见 KillChainOptions。 */
|
|
237
|
-
function raceTimeout(p: Promise<void>, ms: number, unref = false): Promise<"settled" | "timeout"> {
|
|
238
|
-
return new Promise<"settled" | "timeout">((resolve) => {
|
|
239
|
-
const timer = setTimeout(() => resolve("timeout"), ms);
|
|
240
|
-
if (unref) timer.unref();
|
|
241
|
-
p.then(
|
|
242
|
-
() => {
|
|
243
|
-
clearTimeout(timer);
|
|
244
|
-
resolve("settled");
|
|
245
|
-
},
|
|
246
|
-
() => {
|
|
247
|
-
// 被 await 的 exit promise 不会 reject;防御分支保持语义完整(超时口径胜出前出错按 settled 处理)
|
|
248
|
-
clearTimeout(timer);
|
|
249
|
-
resolve("settled");
|
|
250
|
-
},
|
|
251
|
-
);
|
|
252
|
-
});
|
|
253
|
-
}
|
|
3
|
+
// 超时杀链与 abort 两级中断的 re-export shim:实现体单源
|
|
4
|
+
// @zhushanwen/subagent-engine-sdk(自本文件逐字等价移入 SDK,s4-reuse 簇 1;
|
|
5
|
+
// core → SDK 边界正向合法,设计权威源 D1/§3.3.3 注释随实现留在 SDK 侧)。
|
|
6
|
+
// core 内消费方(subprocess-agent-runner 与本目录测试)import 路径保持不变。
|
|
7
|
+
// 唯一签名差异:SDK 版 synthesizeTimeoutOutcome 第 3 参 engineId 必填
|
|
8
|
+
//(core 原缺省 DEFAULT_ENGINE_ID="pi" 的隐式行为随收编删除——core 非测试
|
|
9
|
+
// 代码零调用方,无生产行为影响)。
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
abortWithFallback,
|
|
13
|
+
DEFAULT_KILL_GRACE_MS,
|
|
14
|
+
DEFAULT_NATIVE_INTERRUPT_GRACE_MS,
|
|
15
|
+
HOST_TIMEOUT_ABORT_REASON,
|
|
16
|
+
killChain,
|
|
17
|
+
type KillableChild,
|
|
18
|
+
type KillChainOptions,
|
|
19
|
+
synthesizeTimeoutOutcome,
|
|
20
|
+
} from "@zhushanwen/subagent-engine-sdk";
|
|
@@ -1,116 +1,20 @@
|
|
|
1
1
|
// src/execution/engine/common/nesting-guard.ts
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/** 统一嵌套标记 env 名(D8)。值恒 '1'。 */
|
|
22
|
-
export const NESTED_SPAWN_ENV = "XYZ_AGENT_SUBAGENT";
|
|
23
|
-
|
|
24
|
-
/** 需剥离的引擎原生嵌套标记(精确名)。 */
|
|
25
|
-
const NATIVE_NESTED_KEYS: readonly string[] = ["CLAUDECODE", "ZSW_NESTED"];
|
|
26
|
-
|
|
27
|
-
/** 需剥离的引擎原生嵌套标记前缀(pi 家族)。 */
|
|
28
|
-
const NATIVE_NESTED_PREFIXES: readonly string[] = ["PI_SUBAGENT_"];
|
|
29
|
-
|
|
30
|
-
/** env 对象形状(NodeJS.ProcessEnv 的结构子集,测试可传普通对象)。 */
|
|
31
|
-
export type SpawnEnv = Record<string, string | undefined>;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* 构造子代理 spawn env:注入 XYZ_AGENT_SUBAGENT=1 + 剥离引擎原生嵌套标记。
|
|
35
|
-
* 返回新对象,不改入参(spawn env 组装链中的多层 spread 安全)。
|
|
36
|
-
*/
|
|
37
|
-
export function buildNestedSpawnEnv(baseEnv: SpawnEnv): SpawnEnv {
|
|
38
|
-
const env: SpawnEnv = {};
|
|
39
|
-
for (const [key, value] of Object.entries(baseEnv)) {
|
|
40
|
-
if (NATIVE_NESTED_KEYS.includes(key)) continue;
|
|
41
|
-
if (NATIVE_NESTED_PREFIXES.some((prefix) => key.startsWith(prefix))) continue;
|
|
42
|
-
env[key] = value;
|
|
43
|
-
}
|
|
44
|
-
env[NESTED_SPAWN_ENV] = "1";
|
|
45
|
-
return env;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* 嵌套 spawn 防护断言:检测到统一标记(本进程已是 subagent)抛
|
|
50
|
-
* EngineError(nested_spawn_rejected)——文案说明防护规则、指向 task 内自行完成。
|
|
51
|
-
* 调用点:subagent 工具入口(进程创建前拒绝,D11 处置三级)。
|
|
52
|
-
*/
|
|
53
|
-
export function assertNotNestedSpawn(env: SpawnEnv): void {
|
|
54
|
-
if (env[NESTED_SPAWN_ENV] === "1") {
|
|
55
|
-
throw nestedSpawnRejectedError();
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ============================================================
|
|
60
|
-
// [D3-⑤] 进程内执行嵌套上下文(原 SubagentService.execCtxAls 下沉)
|
|
61
|
-
// ============================================================
|
|
62
|
-
|
|
63
|
-
/** 执行嵌套状态:当前正在跑的 record 身份 + 递归深度(D-033 通用嵌套深度护栏的计数载体)。 */
|
|
64
|
-
export interface ExecutionNestingState {
|
|
65
|
-
recordId: string | undefined;
|
|
66
|
-
depth: number;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* 进程内执行嵌套上下文([D3-⑤] 从 SubagentService 的 execCtxAls 私有字段并入公共层)。
|
|
71
|
-
*
|
|
72
|
-
* 机制(原样迁移,行为零变化):
|
|
73
|
-
* - ALS 按异步调用链传递当前 record 身份:B run() 期间包 this 上下文,B 内创建 C 时
|
|
74
|
-
* 读到 B → C.parentRecordId=B.id、C.depth=B.depth+1;主 session 链上无 store → 顶层。
|
|
75
|
-
* - 进程级基线兜底 [ALS 断裂修复]:pi RPC mode 的 stdin JSONL 是事件回调式
|
|
76
|
-
* (attachJsonlLineReader stream.on("data")),每个命令是独立异步链,enterWith 的
|
|
77
|
-
* store 不会贯穿到后续 tool 调用事件(实测:递归第二层 parentRecordId/depth 丢失
|
|
78
|
-
* 而 rootSessionId 正确)。基线 = 本进程自己的身份(initSession 从 env 读取):
|
|
79
|
-
* 读 ALS store 失败时兜底,保证「本进程派发的 subagent 都是本进程记录的孩子」。
|
|
80
|
-
*
|
|
81
|
-
* 实例归属:per-Service(基线随宿主进程身份而异),Service 构造时创建并持有。
|
|
82
|
-
* 深度上限判据(MAX_FORK_DEPTH)留在调用方——上限常量属 execution 层
|
|
83
|
-
* (session-context-resolver),公共层只提供状态存取单点。
|
|
84
|
-
*/
|
|
85
|
-
export class ExecutionNestingContext {
|
|
86
|
-
private readonly als = new AsyncLocalStorage<ExecutionNestingState>();
|
|
87
|
-
private baselineState: ExecutionNestingState | null = null;
|
|
88
|
-
|
|
89
|
-
/** 建立进程级基线(initSession:有 env 自我标记 → env 身份;根进程 → null 顶层)。 */
|
|
90
|
-
setBaseline(state: ExecutionNestingState | null): void {
|
|
91
|
-
this.baselineState = state;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/** 读当前嵌套状态:ALS store 优先,断裂时基线兜底(顶层 = null)。 */
|
|
95
|
-
current(): ExecutionNestingState | null {
|
|
96
|
-
return this.als.getStore() ?? this.baselineState;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 读进程级基线(与 current() 的差异:不看 ALS store——直接父归属校验等场景要的是
|
|
101
|
-
* 「本进程自己的身份」而非「当前异步链正在跑的 record 身份」)。
|
|
102
|
-
*/
|
|
103
|
-
baseline(): ExecutionNestingState | null {
|
|
104
|
-
return this.baselineState;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/** 包裹执行(B run() 期间挂 B 身份——内层创建 C 时 current() 读到 B)。 */
|
|
108
|
-
run<T>(state: ExecutionNestingState, fn: () => T): T {
|
|
109
|
-
return this.als.run(state, fn);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/** 顶层 enterWith(initSession 建立基线身份后挂入当前异步链)。 */
|
|
113
|
-
enterWith(state: ExecutionNestingState): void {
|
|
114
|
-
this.als.enterWith(state);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
3
|
+
// 嵌套防护(跨进程 env 标记 + 进程内 ALS 深度计数)的 re-export shim:实现体单源
|
|
4
|
+
// @zhushanwen/subagent-engine-sdk(自本文件逐字等价移入 SDK,s4-reuse 簇 2;
|
|
5
|
+
// 设计权威源 D8 / D3-⑤ 注释随实现留在 SDK 侧)。core 内消费方(subagent-service
|
|
6
|
+
// 与本目录测试)import 路径保持不变。唯一行为差异:assertNotNestedSpawn 抛
|
|
7
|
+
// NestedSpawnRejectedError(SDK 形态,code/recovery 文案逐字一致)而非 core
|
|
8
|
+
// EngineError——该函数在 core 非测试代码零调用方,错误类形态差异无生产影响。
|
|
9
|
+
// 错误类随 shim 一并导出(本目录测试断言消费;core barrel 不转发本模块,无对外
|
|
10
|
+
// 导出面影响)。
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
assertNotNestedSpawn,
|
|
14
|
+
buildNestedSpawnEnv,
|
|
15
|
+
ExecutionNestingContext,
|
|
16
|
+
type ExecutionNestingState,
|
|
17
|
+
NestedSpawnRejectedError,
|
|
18
|
+
NESTED_SPAWN_ENV,
|
|
19
|
+
type SpawnEnv,
|
|
20
|
+
} from "@zhushanwen/subagent-engine-sdk";
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
// 2. journal-*.jsonl 不随池删——生命周期跟随 record,release 只删「该 record 自己的」
|
|
16
16
|
// journal(record GC 时联动,避免「池删导致仍存 record 的历史从②级静默跌③级」);
|
|
17
17
|
// 3. 删除失败置 .pool-cleanup-failed 标记文件(可观测不静默),启动期扫描该标记告警。
|
|
18
|
+
// 隔离库边界(2026-09 会话库隔离,设计 docs/design/zcode-session-db-isolation.md D4):
|
|
19
|
+
// zcode 隔离会话库不在池目录内,但 TTL 扫描会枚举 session-db/(engines/<id>/ 下每个
|
|
20
|
+
// 子目录都被当池遍历)——db.sqlite* 不匹配任何删除条件(无 refs.json 早退;孤儿 journal
|
|
21
|
+
// 只匹配 journal-*.jsonl),由 A9 守卫测试(公共 API + 枚举断言)钉死。
|
|
18
22
|
//
|
|
19
23
|
// TTL 兜底(cleanupExpiredPoolRefs):record 主数据的死亡(主 session 文件被 pi 侧
|
|
20
24
|
// 管理)对 core 无触发点,done record 的 journal 因此没有精确回收锚——按 30 天 mtime
|
|
@@ -25,23 +25,28 @@
|
|
|
25
25
|
// pi 分支维持现状(A1 守护):pi 历史走 runtime 自有 JSONL 直读链
|
|
26
26
|
// (session-service.getSubagentHistory),不经本模块;engineId='pi' 的防御分支
|
|
27
27
|
// 返回空数组,与被收敛前的 runtime 实现一致。
|
|
28
|
+
//
|
|
29
|
+
// [W11/H1] 零静态引擎依赖(设计 §3.8 DoD#3):①级 native reader 全部经
|
|
30
|
+
// registerNativeSessionReader 注入——core 不再静态 import engines/zcode 的
|
|
31
|
+
// reader/constants/db-path(zcode sqlite 直读迁引擎进程,宿主经协议 read 消费;
|
|
32
|
+
// dbPath 白名单/池锚定判定随 reader 迁 @zhushanwen/zcode-subagent-cli,A plan
|
|
33
|
+
// 证据面由 zcode 包 e2e 接替,原 svs-zcode-dbpath 守护测试随迁删除)。
|
|
28
34
|
|
|
29
35
|
import { randomUUID } from "node:crypto";
|
|
30
|
-
import { homedir } from "node:os";
|
|
31
36
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
32
37
|
|
|
33
38
|
// 相对 import 用 .js 形态(本文件是双端复用模块,被 xyz-agent runtime import——对齐
|
|
34
|
-
//
|
|
35
|
-
//
|
|
39
|
+
// 先例:runtime tsconfig 无 allowImportingTsExtensions,.ts 形态在 runtime tsc 下报
|
|
40
|
+
// TS5097;.js 后缀经 bundler/ESM 解析器 substitution 到 .ts)。
|
|
41
|
+
// aggregateUsage 单源 SDK(原 ./session-view-projection.js 逐字等价双活副本已删)。
|
|
42
|
+
// 包名 import 在 runtime 编译图可解析(先例:dialog-queue.ts 同式 import SDK barrel)。
|
|
43
|
+
import { aggregateUsage } from "@zhushanwen/subagent-engine-sdk";
|
|
36
44
|
import { getLogger } from "../../../core/logger.js";
|
|
37
45
|
import { createRecord, updateFromEvent } from "../../execution-record.js";
|
|
38
46
|
import type { Turn } from "../../types.js";
|
|
39
|
-
import {
|
|
40
|
-
import { ZCODE_ENGINE_ID, ZCODE_HOST_DB_SUFFIX } from "../engines/zcode/constants.js";
|
|
41
|
-
import { resolveEnginesRoot, resolvePoolDir } from "../paths.js";
|
|
47
|
+
import { resolveEnginesRoot } from "../paths.js";
|
|
42
48
|
import type { SessionView } from "../types.js";
|
|
43
49
|
import { replayJournal } from "./event-journal.js";
|
|
44
|
-
import { aggregateUsage } from "./session-view-projection.js";
|
|
45
50
|
import type {
|
|
46
51
|
EngineHandleView,
|
|
47
52
|
EngineToolCallSource,
|
|
@@ -50,18 +55,27 @@ import type {
|
|
|
50
55
|
SubagentRecordSnapshot,
|
|
51
56
|
} from "./session-view-types.js";
|
|
52
57
|
import { parseEngineHandle } from "./session-view-types.js";
|
|
53
|
-
import { toErrorMessage } from "../../../core/error-message.ts";
|
|
54
58
|
|
|
55
59
|
const logger = getLogger("subagents");
|
|
56
60
|
|
|
57
61
|
/**
|
|
58
62
|
* 缺省引擎 id(与 registry.ts 的 DEFAULT_ENGINE_ID 同值本地锚定——对齐
|
|
59
|
-
*
|
|
63
|
+
* inproc reader(已删) 的 PI_ENGINE_ID 先例:import registry 会连带 port.ts →
|
|
60
64
|
* stream-sink.ts 的 .ts 后缀值 import 链进 runtime tsc 编译图,破坏双端复用闭包
|
|
61
65
|
* 约束;锚定漂移由本包 registry.test / 读取链测试双重守护)。
|
|
62
66
|
*/
|
|
63
67
|
const DEFAULT_ENGINE_ID = "pi";
|
|
64
68
|
|
|
69
|
+
/**
|
|
70
|
+
* ③级 outcome-only 占位 assistant 文案(subagent-nonpi-visibility-followups 设计
|
|
71
|
+
* §3.3 D6 三端锚点)。core 生产代码不 import shared(双端复用约束,见上方 import
|
|
72
|
+
* 注释),故本地同值常量 + 锚定注释:权威值 = packages/shared 的
|
|
73
|
+
* SUBAGENT_OUTCOME_PLACEHOLDER('(no outcome recorded)');同值漂移由 runtime
|
|
74
|
+
* test/subagent-extractor-engine.test.ts 契约钉子用例的行为断言守护(③级投影占位
|
|
75
|
+
* content === shared 常量)——core 改文案即该用例翻红。
|
|
76
|
+
*/
|
|
77
|
+
const OUTCOME_PLACEHOLDER_TEXT = "(no outcome recorded)";
|
|
78
|
+
|
|
65
79
|
// ============================================================
|
|
66
80
|
// 引擎 id 提取(record 路由段)
|
|
67
81
|
// ============================================================
|
|
@@ -83,8 +97,12 @@ export function extractEngineId(record: SubagentRecordSnapshot): string {
|
|
|
83
97
|
/**
|
|
84
98
|
* 引擎原生 reader(①级):handle + dataDir → SessionView。
|
|
85
99
|
* 返回 undefined = 本级不可达/失败(编排层降②级);reader 内部自行留 debug 日志。
|
|
86
|
-
* 双端复用约束(设计 §3.3.7
|
|
87
|
-
*
|
|
100
|
+
* 双端复用约束(设计 §3.3.7):实现必须无状态纯函数、不 import 引擎运行时件。
|
|
101
|
+
*
|
|
102
|
+
* [W11/H1] 本模块零静态引擎依赖:①级 reader 全部经注入面注册——生产调用方 =
|
|
103
|
+
* runtime 协议客户端(W8 subagent-engine-history 把「协议 read」注册为引擎原生
|
|
104
|
+
* reader,引擎 id 动态、zcode sqlite 直读在引擎进程内完成);注册表初始为空,
|
|
105
|
+
* 未注册引擎直接落②级 journal。
|
|
88
106
|
*/
|
|
89
107
|
export type NativeSessionReader = (
|
|
90
108
|
handle: EngineHandleView,
|
|
@@ -102,18 +120,15 @@ function getReaderSlot(): Map<string, NativeSessionReader> {
|
|
|
102
120
|
| undefined;
|
|
103
121
|
if (!slot) {
|
|
104
122
|
slot = new Map();
|
|
105
|
-
// 内置注册:core 自带 reader 的引擎(当前仅 zcode——pi 的历史读取按 D1 范围声明
|
|
106
|
-
// 走 runtime 自有 JSONL 直读链,不注册原生 reader)
|
|
107
|
-
slot.set(ZCODE_ENGINE_ID, readZcodeNativeTier);
|
|
108
123
|
Reflect.set(globalThis, NATIVE_READER_SLOT_KEY, slot);
|
|
109
124
|
}
|
|
110
125
|
return slot;
|
|
111
126
|
}
|
|
112
127
|
|
|
113
128
|
/**
|
|
114
|
-
* 登记引擎原生 reader
|
|
115
|
-
* (幂等,对齐 registerEngine 惯例)。生产调用方 =
|
|
116
|
-
*
|
|
129
|
+
* 登记引擎原生 reader(W11/H1 后的唯①级接入点)。重复注册同 id = 覆盖
|
|
130
|
+
* (幂等,对齐 registerEngine 惯例)。生产调用方 = 宿主协议客户端接线
|
|
131
|
+
* (runtime subagent-engine-history 的 ensureProtocolReaderFor)。
|
|
117
132
|
*/
|
|
118
133
|
export function registerNativeSessionReader(engineId: string, reader: NativeSessionReader): void {
|
|
119
134
|
getReaderSlot().set(engineId, reader);
|
|
@@ -124,65 +139,9 @@ function lookupNativeSessionReader(engineId: string): NativeSessionReader | unde
|
|
|
124
139
|
return getReaderSlot().get(engineId);
|
|
125
140
|
}
|
|
126
141
|
|
|
127
|
-
/**
|
|
142
|
+
/** 清空注册表(测试隔离专用,生产禁用——对齐 clearEngines 惯例)。 */
|
|
128
143
|
export function resetNativeSessionReaders(): void {
|
|
129
|
-
|
|
130
|
-
slot.clear();
|
|
131
|
-
slot.set(ZCODE_ENGINE_ID, readZcodeNativeTier);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ============================================================
|
|
135
|
-
// ①级:zcode sqlite 原生读取(内置注册的 reader)
|
|
136
|
-
// ============================================================
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* zcode ①级 reader:sessionRef 的 dbPath/sessionId 重定位 + 白名单 +
|
|
140
|
-
* readZcodeSessionView(extension/runtime 双端复用的同一份 reader)。
|
|
141
|
-
* 语义复刻被收敛前的 runtime readZcodeNativeTier(含共享宿主 HOME 形态的绝对
|
|
142
|
-
* dbPath 精确白名单):绝对 dbPath 只认宿主 zcode 会话 db(ZCODE_HOST_DB_SUFFIX
|
|
143
|
-
* SSOT 推导,防任意读);相对路径锚池目录 resolve,越界路径(../ 逃逸 / 跨池)
|
|
144
|
-
* 拒绝降②级;读取失败(结构化错误)降②级。
|
|
145
|
-
*/
|
|
146
|
-
async function readZcodeNativeTier(
|
|
147
|
-
handle: EngineHandleView,
|
|
148
|
-
dataDir: string,
|
|
149
|
-
): Promise<SessionView | undefined> {
|
|
150
|
-
const dbPathRaw = handle.sessionRef["dbPath"];
|
|
151
|
-
const sessionId = handle.sessionRef["sessionId"];
|
|
152
|
-
if (typeof dbPathRaw !== "string" || typeof sessionId !== "string") {
|
|
153
|
-
logger.debug("[session-view-service] zcode tier1 skipped: handle missing dbPath/sessionId");
|
|
154
|
-
return undefined;
|
|
155
|
-
}
|
|
156
|
-
let dbPath: string;
|
|
157
|
-
if (dbPathRaw.startsWith("/")) {
|
|
158
|
-
// 共享宿主 HOME 形态(2026-09 起,写侧 zcode-engine 恒绝对路径):唯一合法绝对
|
|
159
|
-
// 路径 = 宿主 zcode 会话 db(record 来自 JSONL 文本不可信,精确匹配 core SSOT
|
|
160
|
-
// 后缀拼出的路径,防任意读)
|
|
161
|
-
if (dbPathRaw !== resolve(homedir(), ...ZCODE_HOST_DB_SUFFIX)) {
|
|
162
|
-
logger.warn(
|
|
163
|
-
`[session-view-service] zcode absolute dbPath not host db, reject tier1: ${dbPathRaw}`,
|
|
164
|
-
);
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
dbPath = dbPathRaw;
|
|
168
|
-
} else {
|
|
169
|
-
// 旧池时代 records(HOME 池化时期):相对路径锚池目录重定位,白名单防逃逸
|
|
170
|
-
const poolDir = resolvePoolDir(dataDir, ZCODE_ENGINE_ID, handle.poolKey);
|
|
171
|
-
dbPath = resolve(poolDir, dbPathRaw);
|
|
172
|
-
if (!isStrictlyUnder(poolDir, dbPath)) {
|
|
173
|
-
logger.warn(`[session-view-service] zcode dbPath escapes pool dir, reject tier1: ${dbPath}`);
|
|
174
|
-
return undefined;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
try {
|
|
178
|
-
return await readZcodeSessionView(dbPath, sessionId);
|
|
179
|
-
} catch (err) {
|
|
180
|
-
logger.debug(
|
|
181
|
-
`[session-view-service] zcode tier1 read failed, degrade to journal tier: ` +
|
|
182
|
-
`${toErrorMessage(err)}`,
|
|
183
|
-
);
|
|
184
|
-
return undefined;
|
|
185
|
-
}
|
|
144
|
+
getReaderSlot().clear();
|
|
186
145
|
}
|
|
187
146
|
|
|
188
147
|
// ============================================================
|
|
@@ -291,7 +250,7 @@ function replayEventsToHistory(
|
|
|
291
250
|
return undefined;
|
|
292
251
|
}
|
|
293
252
|
|
|
294
|
-
function hasTurnContent(turn:
|
|
253
|
+
function hasTurnContent(turn: { text: string; thinking: string; toolCalls: unknown[] }): boolean {
|
|
295
254
|
return turn.text !== "" || turn.thinking !== "" || turn.toolCalls.length > 0;
|
|
296
255
|
}
|
|
297
256
|
|
|
@@ -447,7 +406,7 @@ function outcomeOnlyMessages(record: SubagentRecordSnapshot): HistoryMessage[] {
|
|
|
447
406
|
id: randomUUID(),
|
|
448
407
|
role: "assistant",
|
|
449
408
|
// result 优先(正常轮终文本);error 次之(失败终态);双缺占位(运行中被杀等)
|
|
450
|
-
content: record.result ?? record.error ??
|
|
409
|
+
content: record.result ?? record.error ?? OUTCOME_PLACEHOLDER_TEXT,
|
|
451
410
|
status: isErrorOutcome ? "error" : "complete",
|
|
452
411
|
timestamp: record.endedAt ?? base,
|
|
453
412
|
...(isErrorOutcome && record.error !== undefined ? { error: record.error } : {}),
|
|
@@ -464,8 +423,8 @@ function outcomeOnlyMessages(record: SubagentRecordSnapshot): HistoryMessage[] {
|
|
|
464
423
|
*
|
|
465
424
|
* 降级顺序 ①→②→③ 逐级尝试,每级失败留 debug/warn 日志不抛崩溃(GUI 详情页
|
|
466
425
|
* 永不白屏报错,设计 A8)。engineId='pi' 返回 [](pi 的①级 = 调用方现有 JSONL
|
|
467
|
-
* 直读链,A1 守护)。未注册 reader
|
|
468
|
-
*
|
|
426
|
+
* 直读链,A1 守护)。未注册 reader 的引擎(W11 后 = 宿主未接线协议 reader 的
|
|
427
|
+
* 进程)跳过①级直落②级 journal——record 字段就够,详情页至少有摘要卡。
|
|
469
428
|
*
|
|
470
429
|
* @param record record 快照(engine/engineHandle 为不可信源,内部守卫消费)
|
|
471
430
|
* @param dataDir xyz-agent 数据根(journal/dbPath 白名单经 paths.ts 布局 SSOT 推导)
|
|
@@ -484,16 +443,29 @@ export async function readSubagentHistoryMessages(
|
|
|
484
443
|
);
|
|
485
444
|
return outcomeOnlyMessages(record);
|
|
486
445
|
}
|
|
446
|
+
// [W11/H1] ①级 reader 全经注入:未注册(W11 后注册表初始为空——宿主未接线协议
|
|
447
|
+
// reader 的进程)不可跳过②级——journal 是宿主自有数据,与引擎 reader 无关,
|
|
448
|
+
// 未注册 reader 的引擎仍走②→③(与「reader 失败降②级」同构)。
|
|
487
449
|
const reader = lookupNativeSessionReader(engineId);
|
|
488
|
-
if (reader
|
|
450
|
+
if (reader !== undefined) {
|
|
451
|
+
const native = await reader(handle, dataDir);
|
|
452
|
+
if (native !== undefined) {
|
|
453
|
+
// ①级判空降级(设计 D3):读成功但 turns 无实质内容(text/thinking/toolCalls
|
|
454
|
+
// 全空,与②级 replayEventsToHistory 的 contentTurns 判定同语义)= 本级不可用,
|
|
455
|
+
// 降②级——「仅 task」空壳投影(窗口 B)不再从①级放行。
|
|
456
|
+
if (native.turns.some(hasTurnContent)) return sessionViewToMessages(native, record);
|
|
457
|
+
logger.debug(
|
|
458
|
+
`[session-view-service] tier1 native view has no substantive content ` +
|
|
459
|
+
`(turns=${native.turns.length}), degrade to journal tier ` +
|
|
460
|
+
`(subagentId=${record.subagentId})`,
|
|
461
|
+
);
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
489
464
|
logger.debug(
|
|
490
465
|
`[session-view-service] engine '${engineId}' has no native reader tier, ` +
|
|
491
|
-
`
|
|
466
|
+
`fall through to journal tier (subagentId=${record.subagentId})`,
|
|
492
467
|
);
|
|
493
|
-
return outcomeOnlyMessages(record);
|
|
494
468
|
}
|
|
495
|
-
const native = await reader(handle, dataDir);
|
|
496
|
-
if (native !== undefined) return sessionViewToMessages(native, record);
|
|
497
469
|
const journaled = readJournalTier(record, handle, dataDir);
|
|
498
470
|
if (journaled !== undefined) return journaled;
|
|
499
471
|
return outcomeOnlyMessages(record);
|