@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
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// pidfile 单元测试(W2,impl-plan §2.2「pidfile」+ §7.2 R9-3 / R9-3b)。
|
|
2
|
+
//
|
|
3
|
+
// 测试红线:禁真实数据目录——全部文件操作在 mkdtempSync 自建目录;「杀」一律注入
|
|
4
|
+
// killEngine fake,绝不真杀(真实杀路径的真机验证归 A8④ 场景族)。
|
|
5
|
+
|
|
6
|
+
import { spawn } from "node:child_process";
|
|
7
|
+
import { mkdtempSync, readdirSync, rmSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { tmpdir } from "node:os";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
isProcessAlive,
|
|
14
|
+
pidfilePath,
|
|
15
|
+
readPidfile,
|
|
16
|
+
readProcessStartTime,
|
|
17
|
+
removePidfile,
|
|
18
|
+
sweepStalePidfiles,
|
|
19
|
+
writePidfileAtomic,
|
|
20
|
+
} from "../pid-file.ts";
|
|
21
|
+
|
|
22
|
+
let dataDir: string;
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
dataDir = mkdtempSync(join(tmpdir(), "w2-pidfile-"));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
afterEach(() => {
|
|
29
|
+
rmSync(dataDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 20 });
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
/** 造一个已死的宿主 pid:短命进程跑完即尸。 */
|
|
33
|
+
function spawnDeadProcess(): Promise<number> {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
const child = spawn(process.execPath, ["-e", "process.exit(0)"]);
|
|
36
|
+
child.once("exit", () => resolve(child.pid!));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** 造一个长活进程(返回 stop 函数);cmdline 形态可被 matchesEngineCmdline 命中。 */
|
|
41
|
+
function spawnLongLived(): { pid: number; stop: () => void } {
|
|
42
|
+
const child = spawn(process.execPath, ["-e", "setInterval(() => {}, 1000)"], {
|
|
43
|
+
stdio: "ignore",
|
|
44
|
+
});
|
|
45
|
+
return { pid: child.pid!, stop: () => process.kill(child.pid!, "SIGKILL") };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const longLived: Array<{ stop: () => void }> = [];
|
|
49
|
+
function track<P extends { pid: number; stop: () => void }>(proc: P): P {
|
|
50
|
+
longLived.push(proc);
|
|
51
|
+
return proc;
|
|
52
|
+
}
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
for (const p of longLived.splice(0)) p.stop();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
function writePidfile(engineId: string, hostKind: string, hostPid: number, enginePid: number, engineStartTime: string | null): string {
|
|
58
|
+
const path = pidfilePath(dataDir, engineId, hostKind, hostPid);
|
|
59
|
+
writePidfileAtomic(path, {
|
|
60
|
+
enginePid,
|
|
61
|
+
hostPid,
|
|
62
|
+
engineStartTime,
|
|
63
|
+
engineId,
|
|
64
|
+
hostKind,
|
|
65
|
+
writtenAt: new Date().toISOString(),
|
|
66
|
+
});
|
|
67
|
+
return path;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
describe("pidfile 原子写/读/删", () => {
|
|
71
|
+
it("文件名 = engine.<hostKind>.<hostPid>.pid(实例维度,不共用 engine.pid);内容含三要素", () => {
|
|
72
|
+
const path = writePidfile("zcode", "pi", 111, 222, "Mon Sep 8 21:14:32 2026");
|
|
73
|
+
expect(path.endsWith(join("engines", "zcode", "engine.pi.111.pid"))).toBe(true);
|
|
74
|
+
expect(existsSync(path)).toBe(true);
|
|
75
|
+
expect(readPidfile(path)).toMatchObject({
|
|
76
|
+
enginePid: 222,
|
|
77
|
+
hostPid: 111,
|
|
78
|
+
engineStartTime: "Mon Sep 8 21:14:32 2026",
|
|
79
|
+
engineId: "zcode",
|
|
80
|
+
hostKind: "pi",
|
|
81
|
+
});
|
|
82
|
+
removePidfile(path);
|
|
83
|
+
expect(existsSync(path)).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("坏 JSON / 缺关键字段 → readPidfile undefined(调用方按陈旧处理)", () => {
|
|
87
|
+
const dir = join(dataDir, "engines", "x");
|
|
88
|
+
mkdirSync(dir, { recursive: true });
|
|
89
|
+
const bad = join(dir, "engine.pi.1.pid");
|
|
90
|
+
writeFileSync(bad, "{not json");
|
|
91
|
+
expect(readPidfile(bad)).toBeUndefined();
|
|
92
|
+
const incomplete = join(dir, "engine.pi.2.pid");
|
|
93
|
+
writeFileSync(incomplete, JSON.stringify({ enginePid: 1 }));
|
|
94
|
+
expect(readPidfile(incomplete)).toBeUndefined();
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
describe("pidfile 三条件清扫", () => {
|
|
99
|
+
it("pid 已死(宿主崩溃残留)→ 陈旧文件被 unlink(R9-3 防堆积)", async () => {
|
|
100
|
+
const deadHost = await spawnDeadProcess();
|
|
101
|
+
const path = writePidfile("zcode", "pi", deadHost, 999999, null);
|
|
102
|
+
const result = sweepStalePidfiles({
|
|
103
|
+
engineDataDir: dataDir,
|
|
104
|
+
engineId: "zcode",
|
|
105
|
+
currentHostPid: process.pid,
|
|
106
|
+
matchesEngineCmdline: () => true,
|
|
107
|
+
});
|
|
108
|
+
expect(existsSync(path)).toBe(false);
|
|
109
|
+
expect(result.removed.some((r) => r.file.endsWith(`engine.pi.${deadHost}.pid`))).toBe(true);
|
|
110
|
+
expect(result.killed).toEqual([]);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("三条件全立(pid 活 + cmdline 符合 + engineStartTime 匹配 + 宿主死)→ 杀(注入 fake)+ 删文件", async () => {
|
|
114
|
+
const engine = track(spawnLongLived());
|
|
115
|
+
const deadHost = await spawnDeadProcess();
|
|
116
|
+
// R9-3b 匹配分支:pidfile 记录目标 pid 的真实 OS 启动时间(readProcessStartTime
|
|
117
|
+
// 与清扫内部同一数据源,真值一致)。
|
|
118
|
+
const realStartTime = readProcessStartTime(engine.pid);
|
|
119
|
+
expect(realStartTime).toBeDefined();
|
|
120
|
+
const path = writePidfile("zcode", "pi", deadHost, engine.pid, realStartTime!);
|
|
121
|
+
const killed: number[] = [];
|
|
122
|
+
const result = sweepStalePidfiles({
|
|
123
|
+
engineDataDir: dataDir,
|
|
124
|
+
engineId: "zcode",
|
|
125
|
+
currentHostPid: process.pid,
|
|
126
|
+
matchesEngineCmdline: (cmdline) => cmdline.includes(process.execPath.replace(/\\/g, "")) || cmdline.includes("node"),
|
|
127
|
+
killEngine: (pid) => killed.push(pid),
|
|
128
|
+
});
|
|
129
|
+
expect(killed).toEqual([engine.pid]);
|
|
130
|
+
expect(existsSync(path)).toBe(false);
|
|
131
|
+
expect(result.killed).toEqual([engine.pid]);
|
|
132
|
+
expect(result.removed.some((r) => r.reason.includes("swept after kill"))).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("R9-3b:engineStartTime 不匹配(同 cmdline 的 pid 复用)→ 判定不成立:删文件不杀", async () => {
|
|
136
|
+
const engine = track(spawnLongLived());
|
|
137
|
+
const deadHost = await spawnDeadProcess();
|
|
138
|
+
// 写入一个必然不匹配的假启动时间(真实 lstart 是当天日期,假值取 2000 年)。
|
|
139
|
+
const path = writePidfile("zcode", "pi", deadHost, engine.pid, "Sat Jan 1 00:00:00 2000");
|
|
140
|
+
let killCalled = 0;
|
|
141
|
+
const result = sweepStalePidfiles({
|
|
142
|
+
engineDataDir: dataDir,
|
|
143
|
+
engineId: "zcode",
|
|
144
|
+
currentHostPid: process.pid,
|
|
145
|
+
matchesEngineCmdline: () => true,
|
|
146
|
+
killEngine: () => {
|
|
147
|
+
killCalled += 1;
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
expect(killCalled).toBe(0);
|
|
151
|
+
expect(existsSync(path)).toBe(false);
|
|
152
|
+
expect(
|
|
153
|
+
result.removed.some((r) => r.reason.includes("start-time-mismatch")),
|
|
154
|
+
).toBe(true);
|
|
155
|
+
// 进程未被波及(保守方向:复用识别后只清文件)
|
|
156
|
+
expect(isProcessAlive(engine.pid)).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("cmdline 身份校验不符(pid 被复用给无关进程)→ 判定不成立:删文件不杀(防误杀)", async () => {
|
|
160
|
+
const engine = track(spawnLongLived());
|
|
161
|
+
const deadHost = await spawnDeadProcess();
|
|
162
|
+
const path = writePidfile("zcode", "pi", deadHost, engine.pid, null);
|
|
163
|
+
// 让 engineStartTime 分支在 cmdline 之后短路:cmdline 谓词恒 false。
|
|
164
|
+
let killCalled = 0;
|
|
165
|
+
const result = sweepStalePidfiles({
|
|
166
|
+
engineDataDir: dataDir,
|
|
167
|
+
engineId: "zcode",
|
|
168
|
+
currentHostPid: process.pid,
|
|
169
|
+
matchesEngineCmdline: () => false,
|
|
170
|
+
killEngine: () => {
|
|
171
|
+
killCalled += 1;
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
expect(killCalled).toBe(0);
|
|
175
|
+
expect(existsSync(path)).toBe(false);
|
|
176
|
+
expect(result.removed.some((r) => r.reason.includes("cmdline-mismatch"))).toBe(true);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it("宿主 pid 存活(活实例 / pid 复用疑似)→ 保守跳过不杀 + 保留文件(R9-3)", () => {
|
|
180
|
+
const engine = track(spawnLongLived());
|
|
181
|
+
const path = writePidfile("zcode", "pi", process.pid, engine.pid, null);
|
|
182
|
+
let killCalled = 0;
|
|
183
|
+
const result = sweepStalePidfiles({
|
|
184
|
+
engineDataDir: dataDir,
|
|
185
|
+
engineId: "zcode",
|
|
186
|
+
currentHostPid: process.pid + 1, // 不是自己的文件
|
|
187
|
+
matchesEngineCmdline: () => true,
|
|
188
|
+
killEngine: () => {
|
|
189
|
+
killCalled += 1;
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
expect(killCalled).toBe(0);
|
|
193
|
+
expect(existsSync(path)).toBe(true);
|
|
194
|
+
expect(result.skipped.some((s) => s.reason === "host-pid-alive")).toBe(true);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("自己的 pidfile(hostPid = 当前宿主)→ 跳过", () => {
|
|
198
|
+
const path = writePidfile("zcode", "pi", process.pid, 123456, null);
|
|
199
|
+
const result = sweepStalePidfiles({
|
|
200
|
+
engineDataDir: dataDir,
|
|
201
|
+
engineId: "zcode",
|
|
202
|
+
currentHostPid: process.pid,
|
|
203
|
+
matchesEngineCmdline: () => true,
|
|
204
|
+
killEngine: () => {
|
|
205
|
+
throw new Error("must not kill own pidfile entry");
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
expect(existsSync(path)).toBe(true);
|
|
209
|
+
expect(result.skipped.some((s) => s.reason === "own-pidfile")).toBe(true);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("Windows 平台:不杀只删(无可移植判据,安全方向)", async () => {
|
|
213
|
+
const engine = track(spawnLongLived());
|
|
214
|
+
const deadHost = await spawnDeadProcess();
|
|
215
|
+
const path = writePidfile("zcode", "pi", deadHost, engine.pid, null);
|
|
216
|
+
let killCalled = 0;
|
|
217
|
+
const result = sweepStalePidfiles({
|
|
218
|
+
engineDataDir: dataDir,
|
|
219
|
+
engineId: "zcode",
|
|
220
|
+
currentHostPid: process.pid,
|
|
221
|
+
matchesEngineCmdline: () => true,
|
|
222
|
+
platform: "win32",
|
|
223
|
+
killEngine: () => {
|
|
224
|
+
killCalled += 1;
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
expect(killCalled).toBe(0);
|
|
228
|
+
expect(existsSync(path)).toBe(false);
|
|
229
|
+
expect(result.removed.some((r) => r.reason.includes("win32 never kills"))).toBe(true);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("无数量上限:多个陈旧文件一次全清(宿主崩溃重启 N 次的堆积回收)", async () => {
|
|
233
|
+
const deadHosts: number[] = [];
|
|
234
|
+
for (let i = 0; i < 3; i += 1) {
|
|
235
|
+
deadHosts.push(await spawnDeadProcess());
|
|
236
|
+
writePidfile("zcode", "pi", deadHosts[i], 999999, null);
|
|
237
|
+
}
|
|
238
|
+
const result = sweepStalePidfiles({
|
|
239
|
+
engineDataDir: dataDir,
|
|
240
|
+
engineId: "zcode",
|
|
241
|
+
currentHostPid: process.pid,
|
|
242
|
+
matchesEngineCmdline: () => true,
|
|
243
|
+
});
|
|
244
|
+
expect(result.removed.length).toBe(3);
|
|
245
|
+
expect(readdirSync(join(dataDir, "engines", "zcode")).filter((f) => f.endsWith(".pid"))).toEqual([]);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it("目录不存在(首次启动)→ 空结果不抛错", () => {
|
|
249
|
+
const result = sweepStalePidfiles({
|
|
250
|
+
engineDataDir: dataDir,
|
|
251
|
+
engineId: "never-created",
|
|
252
|
+
currentHostPid: process.pid,
|
|
253
|
+
matchesEngineCmdline: () => true,
|
|
254
|
+
});
|
|
255
|
+
expect(result).toEqual({ killed: [], removed: [], skipped: [] });
|
|
256
|
+
});
|
|
257
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// 协议契约类型双向可赋值断言(W2 挂靠,impl-plan §2.1「core 侧双向可赋值断言」)。
|
|
2
|
+
//
|
|
3
|
+
// SDK 契约类型(@zhushanwen/subagent-engine-sdk,SSOT)与 core 中立类型是结构等价
|
|
4
|
+
// 闭包——任一侧字段漂移(字段缺失 / 可选性漂移 / 联合分支不齐)在本文件编译期报错。
|
|
5
|
+
// 运行时无逻辑;`const _assert: true = <expr>` 形态让断言结果进入类型检查。
|
|
6
|
+
//
|
|
7
|
+
// UiRequest / UiResponse / UiRequestHandler / UiMethod 的 core 侧出口 =
|
|
8
|
+
// execution/dialog-queue.ts 的 SDK 再导出(W7 已切换,SSOT = SDK ui-types)——
|
|
9
|
+
// 本断言的 Core* 别名现在与 Sdk* 同源,保留断言形态防未来回退为本地定义后漂移。
|
|
10
|
+
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
AssertMutuallyAssignable,
|
|
15
|
+
AgentEvent as SdkAgentEvent,
|
|
16
|
+
AgentCallOpts as SdkAgentCallOpts,
|
|
17
|
+
AgentOutcome as SdkAgentOutcome,
|
|
18
|
+
EngineCapabilities as SdkEngineCapabilities,
|
|
19
|
+
EngineHandleData as SdkEngineHandleData,
|
|
20
|
+
InteractAction as SdkInteractAction,
|
|
21
|
+
InteractResult as SdkInteractResult,
|
|
22
|
+
ProbeReport as SdkProbeReport,
|
|
23
|
+
SessionView as SdkSessionView,
|
|
24
|
+
UiRequest as SdkUiRequest,
|
|
25
|
+
UiRequestHandler as SdkUiRequestHandler,
|
|
26
|
+
UiResponse as SdkUiResponse,
|
|
27
|
+
UiMethod as SdkUiMethod,
|
|
28
|
+
WorktreeHandle as SdkWorktreeHandle,
|
|
29
|
+
} from "@zhushanwen/subagent-engine-sdk";
|
|
30
|
+
|
|
31
|
+
import type { AgentCallOpts as CoreAgentCallOpts } from "../../../../orchestration/models/types.ts";
|
|
32
|
+
import type {
|
|
33
|
+
AgentEvent as CoreAgentEvent,
|
|
34
|
+
WorktreeHandle as CoreWorktreeHandle,
|
|
35
|
+
} from "../../../types.ts";
|
|
36
|
+
import type {
|
|
37
|
+
AgentOutcome as CoreAgentOutcome,
|
|
38
|
+
EngineCapabilities as CoreEngineCapabilities,
|
|
39
|
+
EngineHandleData as CoreEngineHandleData,
|
|
40
|
+
InteractAction as CoreInteractAction,
|
|
41
|
+
InteractResult as CoreInteractResult,
|
|
42
|
+
ProbeReport as CoreProbeReport,
|
|
43
|
+
SessionView as CoreSessionView,
|
|
44
|
+
} from "../../types.ts";
|
|
45
|
+
import type {
|
|
46
|
+
UiMethod as CoreUiMethod,
|
|
47
|
+
UiRequest as CoreUiRequest,
|
|
48
|
+
UiRequestHandler as CoreUiRequestHandler,
|
|
49
|
+
UiResponse as CoreUiResponse,
|
|
50
|
+
} from "../../../dialog-queue.ts";
|
|
51
|
+
|
|
52
|
+
// ── 引擎面契约类型(SDK SSOT ↔ core execution/engine/types.ts)──
|
|
53
|
+
type _CoreSdkAgentEvent = AssertMutuallyAssignable<CoreAgentEvent, SdkAgentEvent>;
|
|
54
|
+
type _CoreSdkAgentOutcome = AssertMutuallyAssignable<CoreAgentOutcome, SdkAgentOutcome>;
|
|
55
|
+
type _CoreSdkEngineCapabilities = AssertMutuallyAssignable<CoreEngineCapabilities, SdkEngineCapabilities>;
|
|
56
|
+
type _CoreSdkEngineHandleData = AssertMutuallyAssignable<CoreEngineHandleData, SdkEngineHandleData>;
|
|
57
|
+
type _CoreSdkInteractAction = AssertMutuallyAssignable<CoreInteractAction, SdkInteractAction>;
|
|
58
|
+
type _CoreSdkInteractResult = AssertMutuallyAssignable<CoreInteractResult, SdkInteractResult>;
|
|
59
|
+
type _CoreSdkProbeReport = AssertMutuallyAssignable<CoreProbeReport, SdkProbeReport>;
|
|
60
|
+
type _CoreSdkSessionView = AssertMutuallyAssignable<CoreSessionView, SdkSessionView>;
|
|
61
|
+
type _CoreSdkWorktreeHandle = AssertMutuallyAssignable<CoreWorktreeHandle, SdkWorktreeHandle>;
|
|
62
|
+
|
|
63
|
+
// ── Ui 请求契约三类型 + UiMethod(SDK ui-types ↔ core dialog-queue)──
|
|
64
|
+
type _CoreSdkUiRequest = AssertMutuallyAssignable<CoreUiRequest, SdkUiRequest>;
|
|
65
|
+
type _CoreSdkUiResponse = AssertMutuallyAssignable<CoreUiResponse, SdkUiResponse>;
|
|
66
|
+
type _CoreSdkUiRequestHandler = AssertMutuallyAssignable<CoreUiRequestHandler, SdkUiRequestHandler>;
|
|
67
|
+
type _CoreSdkUiMethod = AssertMutuallyAssignable<CoreUiMethod, SdkUiMethod>;
|
|
68
|
+
|
|
69
|
+
// ── AgentCallOpts:SDK 版是 core 版的引擎面子集(结构互赋——core 多出的宿主自持
|
|
70
|
+
// 可选字段不影响赋值方向;worktree 的 WorktreeHandle 结构副本经上行断言互证)──
|
|
71
|
+
type _CoreSdkAgentCallOpts = AssertMutuallyAssignable<CoreAgentCallOpts, SdkAgentCallOpts>;
|
|
72
|
+
|
|
73
|
+
const _assertions: Array<true> = [
|
|
74
|
+
true as _CoreSdkAgentEvent,
|
|
75
|
+
true as _CoreSdkAgentOutcome,
|
|
76
|
+
true as _CoreSdkEngineCapabilities,
|
|
77
|
+
true as _CoreSdkEngineHandleData,
|
|
78
|
+
true as _CoreSdkInteractAction,
|
|
79
|
+
true as _CoreSdkInteractResult,
|
|
80
|
+
true as _CoreSdkProbeReport,
|
|
81
|
+
true as _CoreSdkSessionView,
|
|
82
|
+
true as _CoreSdkWorktreeHandle,
|
|
83
|
+
true as _CoreSdkUiRequest,
|
|
84
|
+
true as _CoreSdkUiResponse,
|
|
85
|
+
true as _CoreSdkUiRequestHandler,
|
|
86
|
+
true as _CoreSdkUiMethod,
|
|
87
|
+
true as _CoreSdkAgentCallOpts,
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
describe("协议契约类型双向可赋值(编译期断言的运行时锚)", () => {
|
|
91
|
+
it("全部断言成立(漂移会在 tsc --noEmit 报 never → 本文件编译失败)", () => {
|
|
92
|
+
expect(_assertions).toHaveLength(14);
|
|
93
|
+
expect(_assertions.every((v) => v === true)).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
});
|