@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
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 历史:saveWorkflow 曾有两套实现——commands.ts 用 renameSync 仅 project scope,
|
|
5
5
|
* WorkflowsView.ts 用 copyFileSync 支持 user scope。本次统一为 rename + 仅 project
|
|
6
|
-
* scope(决策 2):tmp
|
|
6
|
+
* scope(决策 2):tmp 文件保存后自动消失,保存位置缺省 DEFAULT_WORKFLOW_SAVED_DIR
|
|
7
|
+
* (pi 布局;W4/D-6 参数化后宿主经 WorkflowDirOptions 注入自有布局)。
|
|
7
8
|
*
|
|
8
9
|
* 代价:TUI 失去 user scope Tab 切换(功能倒退,已接受);
|
|
9
10
|
* Windows/跨设备 rename 可能失败(已知风险,接受)。
|
|
@@ -12,35 +13,58 @@
|
|
|
12
13
|
import { existsSync, mkdirSync, renameSync, unlinkSync } from "node:fs";
|
|
13
14
|
import { resolve } from "node:path";
|
|
14
15
|
|
|
16
|
+
// ── 目录参数化(D-6:.pi 硬编码 → 宿主注入)──────────────────
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 缺省目录(pi 生态布局)。相对路径,调用时 resolve(相对当前 cwd)——与 pi
|
|
20
|
+
* 宿主现行为一致;宿主注入绝对目录(如 zsw 的自有 workflows 布局)即脱离
|
|
21
|
+
* pi 目录。全文件唯一的 .pi 路径来源即这两个缺省常量。
|
|
22
|
+
*/
|
|
23
|
+
export const DEFAULT_WORKFLOW_TMP_DIR = ".pi/workflows/.tmp";
|
|
24
|
+
export const DEFAULT_WORKFLOW_SAVED_DIR = ".pi/workflows";
|
|
25
|
+
|
|
26
|
+
/** 落盘目录注入参数:宿主覆盖缺省 pi 布局(两目录独立可选注入)。 */
|
|
27
|
+
export interface WorkflowDirOptions {
|
|
28
|
+
/** 临时脚本目录(generate 产物落盘处);缺省 DEFAULT_WORKFLOW_TMP_DIR */
|
|
29
|
+
tmpDir?: string;
|
|
30
|
+
/** 固化脚本目录(save 目标);缺省 DEFAULT_WORKFLOW_SAVED_DIR */
|
|
31
|
+
savedDir?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
15
34
|
// ── Path helpers (computed at call time to respect cwd changes in tests) ──
|
|
16
35
|
|
|
17
|
-
function getTmpDir(): string {
|
|
18
|
-
return resolve(
|
|
36
|
+
function getTmpDir(options?: WorkflowDirOptions): string {
|
|
37
|
+
return resolve(options?.tmpDir ?? DEFAULT_WORKFLOW_TMP_DIR);
|
|
19
38
|
}
|
|
20
39
|
|
|
21
|
-
function getSavedDir(): string {
|
|
22
|
-
return resolve(
|
|
40
|
+
function getSavedDir(options?: WorkflowDirOptions): string {
|
|
41
|
+
return resolve(options?.savedDir ?? DEFAULT_WORKFLOW_SAVED_DIR);
|
|
23
42
|
}
|
|
24
43
|
|
|
25
44
|
// ── Save ──────────────────────────────────────────────────────
|
|
26
45
|
|
|
27
46
|
/**
|
|
28
|
-
* 保存临时 workflow
|
|
47
|
+
* 保存临时 workflow:{tmpDir}/{tmpName}.js → {savedDir}/{newName||tmpName}.js
|
|
29
48
|
* 用 rename(tmp 文件保存后消失)。仅 project scope。
|
|
30
49
|
*
|
|
31
50
|
* 直接按路径查找 tmp 文件,不调 config-loader 全扫——save 只需知道 tmp 文件
|
|
32
51
|
* 的路径,不需要 meta 提取或跨目录去重。
|
|
33
52
|
*
|
|
53
|
+
* @param options 目录注入(缺省 pi 布局;pi 现两参调用形态行为不变,W4 向后兼容)
|
|
34
54
|
* @throws 若 tmp workflow 不存在、目标已存在、或 rename 失败
|
|
35
55
|
*/
|
|
36
|
-
export async function saveWorkflow(
|
|
37
|
-
|
|
56
|
+
export async function saveWorkflow(
|
|
57
|
+
tmpName: string,
|
|
58
|
+
newName?: string,
|
|
59
|
+
options?: WorkflowDirOptions,
|
|
60
|
+
): Promise<string> {
|
|
61
|
+
const srcPath = resolve(getTmpDir(options), `${tmpName}.js`);
|
|
38
62
|
if (!existsSync(srcPath)) {
|
|
39
63
|
throw new Error(`Temporary workflow '${tmpName}' not found`);
|
|
40
64
|
}
|
|
41
65
|
|
|
42
66
|
const destName = newName ?? tmpName;
|
|
43
|
-
const savedDir = getSavedDir();
|
|
67
|
+
const savedDir = getSavedDir(options);
|
|
44
68
|
const destPath = resolve(savedDir, `${destName}.js`);
|
|
45
69
|
|
|
46
70
|
if (existsSync(destPath)) {
|
|
@@ -57,18 +81,20 @@ export async function saveWorkflow(tmpName: string, newName?: string): Promise<s
|
|
|
57
81
|
/**
|
|
58
82
|
* 删除 workflow 脚本文件(tmp 或 saved)。
|
|
59
83
|
* @param isRunning 回调,判断某 name 是否正在运行(运行中拒绝删除)
|
|
84
|
+
* @param options 目录注入(缺省 pi 布局;pi 现两参调用形态行为不变,W4 向后兼容)
|
|
60
85
|
* @throws 若正在运行、或文件不存在
|
|
61
86
|
*/
|
|
62
87
|
export function deleteWorkflow(
|
|
63
88
|
name: string,
|
|
64
89
|
isRunning: (name: string) => boolean,
|
|
90
|
+
options?: WorkflowDirOptions,
|
|
65
91
|
): string {
|
|
66
92
|
if (isRunning(name)) {
|
|
67
93
|
throw new Error(`Cannot delete '${name}': workflow is currently running. Abort it first.`);
|
|
68
94
|
}
|
|
69
95
|
|
|
70
|
-
const tmpDir = getTmpDir();
|
|
71
|
-
const savedDir = getSavedDir();
|
|
96
|
+
const tmpDir = getTmpDir(options);
|
|
97
|
+
const savedDir = getSavedDir(options);
|
|
72
98
|
const candidates = [
|
|
73
99
|
resolve(tmpDir, `${name}.js`),
|
|
74
100
|
resolve(savedDir, `${name}.js`),
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkflowRun 摘要投影(设计 D8/B5 —— U7)。
|
|
3
|
+
*
|
|
4
|
+
* 「宿主各写一遍」域的收口:pi tool-workflow.toRunSummary 与 zsw
|
|
5
|
+
* orchestration-host 投影的字段集已实锤分叉(workflow vs name),本模块以 core
|
|
6
|
+
* WorkflowRun 为准提供单一投影,宿主可在此基础上扩展自己的投影字段
|
|
7
|
+
* (如 pi 版的 stateFile 需要 RunStore,归宿主扩展——core 不依赖具体 store 实例)。
|
|
8
|
+
*
|
|
9
|
+
* 层归属:Engine(纯投影,零 IO、零依赖)。字段名对齐 pi 版(name = scriptName)。
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { RunStatus, DoneReason } from "./models/types.ts";
|
|
13
|
+
import type { WorkflowRun } from "./models/workflow-run.ts";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* WorkflowRun 的可序列化摘要(status action / 列表渲染用)。
|
|
17
|
+
*
|
|
18
|
+
* 字段与 pi tool-workflow.toRunSummary 一致(去除依赖 RunStore 的 stateFile——
|
|
19
|
+
* 宿主可扩展投影自行追加)。slug 旧持久化 run 可能缺失(undefined 保真透传)。
|
|
20
|
+
*/
|
|
21
|
+
export interface WorkflowRunSummary {
|
|
22
|
+
runId: string;
|
|
23
|
+
/** 脚本身份名(spec.scriptName)。 */
|
|
24
|
+
name: string;
|
|
25
|
+
/** run 级简短标签(可选,旧持久化 run 缺失)。 */
|
|
26
|
+
slug?: string;
|
|
27
|
+
status: RunStatus;
|
|
28
|
+
reason?: DoneReason;
|
|
29
|
+
/** ISO 时间戳,run 创建/启动时刻。 */
|
|
30
|
+
startedAt: string;
|
|
31
|
+
/** ISO 时间戳,transition("done") 时设置;running run 为 undefined。 */
|
|
32
|
+
completedAt?: string;
|
|
33
|
+
/** 失败/中止原因(state.error)。 */
|
|
34
|
+
error?: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* WorkflowRun → 摘要投影。纯函数,不读 store、不发事件。
|
|
39
|
+
*
|
|
40
|
+
* @param run 聚合根(running 或 done 均可投影)
|
|
41
|
+
*/
|
|
42
|
+
export function runSummary(run: WorkflowRun): WorkflowRunSummary {
|
|
43
|
+
return {
|
|
44
|
+
runId: run.runId,
|
|
45
|
+
name: run.spec.scriptName,
|
|
46
|
+
slug: run.spec.slug,
|
|
47
|
+
status: run.state.status,
|
|
48
|
+
reason: run.state.reason,
|
|
49
|
+
startedAt: run.meta.startedAt,
|
|
50
|
+
completedAt: run.meta.completedAt,
|
|
51
|
+
error: run.state.error,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 判断是否存在指定名字、仍在 running 的 workflow script。
|
|
57
|
+
*
|
|
58
|
+
* pi 版遍历全部 session 的 runs(两层循环);core 版收口为单 runs Map——
|
|
59
|
+
* per-session 隔离由调用方(宿主逐 session 调用或传入聚合 Map)负责。
|
|
60
|
+
*
|
|
61
|
+
* @param runs run 注册表(runId → WorkflowRun)
|
|
62
|
+
* @param name script 名(按 spec.scriptName 精确匹配)
|
|
63
|
+
*/
|
|
64
|
+
export function isScriptRunning(runs: Map<string, WorkflowRun>, name: string): boolean {
|
|
65
|
+
for (const run of runs.values()) {
|
|
66
|
+
if (run.spec.scriptName === name && run.state.status === "running") return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
@@ -29,6 +29,28 @@ import {
|
|
|
29
29
|
type WorkflowScanConfig,
|
|
30
30
|
} from "./config-loader.ts";
|
|
31
31
|
|
|
32
|
+
// ── barrel 导出面(sink 设计 U1:WorkflowScript 实体 + 按路径加载工厂)──
|
|
33
|
+
|
|
34
|
+
// WorkflowScript 类(实体:sourceCode/validate/toExecutable 收敛)导出给 barrel
|
|
35
|
+
// re-export——第三宿主仅凭导出面即可消费实体(G3),不再鸭子复刻整类(§2.2 A2)。
|
|
36
|
+
export { WorkflowScript };
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 按绝对路径加载单个 workflow 脚本的自由函数工厂(U1)。
|
|
40
|
+
*
|
|
41
|
+
* 与 `new WorkflowScriptRegistryImpl().getPath(path)` 等价的无状态形态:barrel
|
|
42
|
+
* 消费面(zsw vendor / 第三宿主)不暴露 registry 实例时的一次性加载入口。底层走
|
|
43
|
+
* getWorkflowByPath 的 60s TTL 缓存与 m5 mtime 缓存层,重复调用不重复读盘。
|
|
44
|
+
*
|
|
45
|
+
* 返回 undefined:引用非法(相对路径 / 非 .js / 含 `..` 段——normalizeRef 拒绝)。
|
|
46
|
+
* 返回 available=false 的 stub:文件不可读或 meta 提取失败(loader never throws)。
|
|
47
|
+
*/
|
|
48
|
+
export async function loadWorkflowScriptByPath(
|
|
49
|
+
path: string,
|
|
50
|
+
): Promise<WorkflowScript | undefined> {
|
|
51
|
+
return new WorkflowScriptRegistryImpl().getPath(path);
|
|
52
|
+
}
|
|
53
|
+
|
|
32
54
|
// ── WorkflowScriptRegistryImpl ───────────────────────────────
|
|
33
55
|
|
|
34
56
|
/**
|
|
@@ -40,7 +62,7 @@ import {
|
|
|
40
62
|
export class WorkflowScriptRegistryImpl implements WorkflowScriptRegistry {
|
|
41
63
|
constructor(private readonly config?: WorkflowScanConfig) {}
|
|
42
64
|
|
|
43
|
-
|
|
65
|
+
/**
|
|
44
66
|
* 扫描所有 workflow 脚本(project + user + tmp),按 tmp>project>user 优先级
|
|
45
67
|
* 去重,返回 WorkflowScript 实体数组(含 available=false 的解析失败项)。
|
|
46
68
|
*
|
|
@@ -53,7 +75,7 @@ export class WorkflowScriptRegistryImpl implements WorkflowScriptRegistry {
|
|
|
53
75
|
return metas.map((m) => this.toScript(m));
|
|
54
76
|
}
|
|
55
77
|
|
|
56
|
-
|
|
78
|
+
/**
|
|
57
79
|
* 按名查单个脚本。精确匹配。
|
|
58
80
|
* 返回 undefined 当 name 不存在。
|
|
59
81
|
*
|
|
@@ -70,7 +92,7 @@ export class WorkflowScriptRegistryImpl implements WorkflowScriptRegistry {
|
|
|
70
92
|
return meta ? this.toScript(meta) : undefined;
|
|
71
93
|
}
|
|
72
94
|
|
|
73
|
-
|
|
95
|
+
/**
|
|
74
96
|
* 按绝对路径加载单个脚本(S2 路径统一)。任意路径(不限扫描源)。
|
|
75
97
|
* 供 workflow tool 的 run/info(name 参数 = workflowRef)。
|
|
76
98
|
*/
|
|
@@ -79,12 +101,12 @@ export class WorkflowScriptRegistryImpl implements WorkflowScriptRegistry {
|
|
|
79
101
|
return meta ? this.toScript(meta) : undefined;
|
|
80
102
|
}
|
|
81
103
|
|
|
82
|
-
|
|
104
|
+
/** 失效缓存——下次 loadAll/get 重新扫描文件系统。 */
|
|
83
105
|
invalidate(): void {
|
|
84
106
|
invalidateCache();
|
|
85
107
|
}
|
|
86
108
|
|
|
87
|
-
|
|
109
|
+
/**
|
|
88
110
|
* 把 CachedWorkflowMeta 转换为 WorkflowScript 实体。
|
|
89
111
|
*
|
|
90
112
|
* m2:整对象透传——m 已是 WorkflowMeta(CachedWorkflowMeta extends WorkflowMeta),
|
|
@@ -95,8 +117,8 @@ export class WorkflowScriptRegistryImpl implements WorkflowScriptRegistry {
|
|
|
95
117
|
* available:meta 提取失败或文件不可读时为 false。
|
|
96
118
|
*/
|
|
97
119
|
private toScript(m: CachedWorkflowMeta): WorkflowScript {
|
|
98
|
-
|
|
99
|
-
|
|
120
|
+
// FR-2: registry 是唯一读文件处。readFileSync 填 sourceCode —— 这样 launcher/tool
|
|
121
|
+
// 直接调 toExecutable/validate 即可,无需各自 readFile(避免重复读,60s TTL 缓存生效)。
|
|
100
122
|
let sourceCode = "";
|
|
101
123
|
let available = m.available;
|
|
102
124
|
if (available) {
|
|
@@ -111,8 +133,8 @@ export class WorkflowScriptRegistryImpl implements WorkflowScriptRegistry {
|
|
|
111
133
|
sourceCode = cachedContent;
|
|
112
134
|
}
|
|
113
135
|
} catch {
|
|
114
|
-
|
|
115
|
-
|
|
136
|
+
// 文件不可读(race condition 删除、权限等)——标 available=false,
|
|
137
|
+
// 与 meta 提取失败的现有语义一致(loader "never throws")。
|
|
116
138
|
sourceCode = "";
|
|
117
139
|
available = false;
|
|
118
140
|
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* agent-ref 测试:displayAgentName 短名投影 + normalizeRef `..` 段拒绝(⛔2 样本集)
|
|
3
|
+
* + invalidAgentRefMessage 文案工厂 + normalizeWorkflowRef 三分裁决(sink 设计 U1)。
|
|
3
4
|
*
|
|
4
5
|
* 数据层不变式(displayAgentName 只服务显示出口):非路径值原样返回。
|
|
5
6
|
*/
|
|
7
|
+
import { homedir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
6
9
|
import { describe, expect, it } from "vitest";
|
|
7
10
|
|
|
8
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
displayAgentName,
|
|
13
|
+
invalidAgentRefMessage,
|
|
14
|
+
normalizeRef,
|
|
15
|
+
normalizeWorkflowRef,
|
|
16
|
+
} from "../agent-ref.ts";
|
|
9
17
|
|
|
10
18
|
describe("displayAgentName", () => {
|
|
11
19
|
it("mac/linux 绝对路径取 basename 并去 .md", () => {
|
|
@@ -32,3 +40,202 @@ describe("displayAgentName", () => {
|
|
|
32
40
|
expect(displayAgentName("worker.md")).toBe("worker");
|
|
33
41
|
});
|
|
34
42
|
});
|
|
43
|
+
|
|
44
|
+
// ── ⛔2:`..` 段拒绝(sink 设计声明行为变更——现状两宿主均放行,收紧为安全修复)──
|
|
45
|
+
|
|
46
|
+
describe("normalizeRef `..` 段拒绝(⛔2 样本集)", () => {
|
|
47
|
+
it("agent .md 面:/x/../y.md 拒绝", () => {
|
|
48
|
+
expect(normalizeRef("/x/../y.md", ".md")).toBeNull();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("workflow .js 面:/x/../y.js 拒绝(normalizeRef 为 agent/workflow 双消费面)", () => {
|
|
52
|
+
expect(normalizeRef("/x/../y.js", ".js")).toBeNull();
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("~/ 开头合法路径不误伤(展开后无 .. 段照常通过)", () => {
|
|
56
|
+
expect(normalizeRef("~/agents/worker.md", ".md")).toBe(join(homedir(), "agents/worker.md"));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("~/ 展开后含 .. 段同样拒绝(收紧的一致延伸,显式声明)", () => {
|
|
60
|
+
expect(normalizeRef("~/../x.md", ".md")).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("无扩展名校验面同样拒绝(收紧在 ext 校验之前)", () => {
|
|
64
|
+
expect(normalizeRef("/x/../y.md")).toBeNull();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("中段/尾段/多段 .. 均拒绝", () => {
|
|
68
|
+
expect(normalizeRef("/a/../b/c.md", ".md")).toBeNull();
|
|
69
|
+
expect(normalizeRef("/a/b/..", ".md")).toBeNull();
|
|
70
|
+
expect(normalizeRef("/a/../b/../c.md", ".md")).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("windows 反斜杠分隔的 .. 段同样拒绝", () => {
|
|
74
|
+
expect(normalizeRef("C:\\x\\..\\y.md", ".md")).toBeNull();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it(". 段与 .. 前缀文件名不误伤(最小收紧:只拒 .. 路径段)", () => {
|
|
78
|
+
expect(normalizeRef("/x/./y.md", ".md")).toBe("/x/./y.md");
|
|
79
|
+
expect(normalizeRef("/x/..foo.md", ".md")).toBe("/x/..foo.md");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("既有行为保持:空/相对路径/扩展名不符仍 null,普通绝对路径通过", () => {
|
|
83
|
+
expect(normalizeRef("", ".md")).toBeNull();
|
|
84
|
+
expect(normalizeRef("worker.md", ".md")).toBeNull();
|
|
85
|
+
expect(normalizeRef("/x/y.js", ".md")).toBeNull();
|
|
86
|
+
expect(normalizeRef("/x/y.md", ".md")).toBe("/x/y.md");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// ── 报错文案工厂(sink 设计 U1:口径收敛单点)──
|
|
91
|
+
|
|
92
|
+
describe("invalidAgentRefMessage", () => {
|
|
93
|
+
it("非 .. 形态:与 AgentRegistry.loadByPath 既有 throw 文案逐字一致(基准口径)", () => {
|
|
94
|
+
expect(invalidAgentRefMessage("worker")).toBe(
|
|
95
|
+
"Invalid agent ref: worker. Agent refs must be absolute paths to .md files (use <location> from <available_subagents>).",
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it(".. 形态:附纠正指引(含 .. 段说明与注入段 location 指引)", () => {
|
|
100
|
+
const msg = invalidAgentRefMessage("/x/../y.md");
|
|
101
|
+
expect(msg).toMatch(/^Invalid agent ref: \/x\/\.\.\/y\.md\./);
|
|
102
|
+
expect(msg).toContain('without ".." path segments');
|
|
103
|
+
expect(msg).toContain("<location> from <available_subagents>");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("howToList 注入:第三宿主清单段名替换缺省 <available_subagents>", () => {
|
|
107
|
+
expect(invalidAgentRefMessage("worker", { howToList: "<available_agents>" })).toContain(
|
|
108
|
+
"use <location> from <available_agents>",
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// ── workflow ref 原语(sink 设计 U1:名/路径二分 + 保留字裁决 + 内置名优先)──
|
|
114
|
+
|
|
115
|
+
describe("normalizeWorkflowRef 三分裁决", () => {
|
|
116
|
+
const knownNames = ["review-fix-loop", "chain", "my-user-wf"];
|
|
117
|
+
|
|
118
|
+
it("裸名分支:命中 knownNames → name(内置名优先——命中即用,不猜路径)", () => {
|
|
119
|
+
expect(normalizeWorkflowRef("review-fix-loop", { knownNames })).toEqual({
|
|
120
|
+
kind: "name",
|
|
121
|
+
name: "review-fix-loop",
|
|
122
|
+
});
|
|
123
|
+
expect(normalizeWorkflowRef("my-user-wf", { knownNames })).toEqual({
|
|
124
|
+
kind: "name",
|
|
125
|
+
name: "my-user-wf",
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("裸名分支:未命中 knownNames → invalid/unknown_name", () => {
|
|
130
|
+
expect(normalizeWorkflowRef("no-such-wf", { knownNames })).toEqual({
|
|
131
|
+
kind: "invalid",
|
|
132
|
+
ref: "no-such-wf",
|
|
133
|
+
reason: "unknown_name",
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("裸名分支:缺省 knownNames → 无已知名,全部裸名 unknown_name", () => {
|
|
138
|
+
expect(normalizeWorkflowRef("review-fix-loop")).toEqual({
|
|
139
|
+
kind: "invalid",
|
|
140
|
+
ref: "review-fix-loop",
|
|
141
|
+
reason: "unknown_name",
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("保留字裁决:. 与 .. 拒绝(reserved)", () => {
|
|
146
|
+
expect(normalizeWorkflowRef(".", { knownNames })).toEqual({
|
|
147
|
+
kind: "invalid",
|
|
148
|
+
ref: ".",
|
|
149
|
+
reason: "reserved",
|
|
150
|
+
});
|
|
151
|
+
expect(normalizeWorkflowRef("..", { knownNames })).toEqual({
|
|
152
|
+
kind: "invalid",
|
|
153
|
+
ref: "..",
|
|
154
|
+
reason: "reserved",
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("保留字优先于 knownNames(宿主清单异常含保留字也不放行)", () => {
|
|
159
|
+
expect(normalizeWorkflowRef("..", { knownNames: ["chain", ".."] })).toEqual({
|
|
160
|
+
kind: "invalid",
|
|
161
|
+
ref: "..",
|
|
162
|
+
reason: "reserved",
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("空引用:empty(首尾空白 trim 后同判)", () => {
|
|
167
|
+
expect(normalizeWorkflowRef("")).toEqual({ kind: "invalid", ref: "", reason: "empty" });
|
|
168
|
+
expect(normalizeWorkflowRef(" ")).toEqual({ kind: "invalid", ref: " ", reason: "empty" });
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("路径分支:绝对 .js 路径 → path", () => {
|
|
172
|
+
expect(normalizeWorkflowRef("/proj/wf.js", { knownNames })).toEqual({
|
|
173
|
+
kind: "path",
|
|
174
|
+
path: "/proj/wf.js",
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("路径分支:~/ 前缀展开为 homedir 绝对路径", () => {
|
|
179
|
+
expect(normalizeWorkflowRef("~/wf.js", { knownNames })).toEqual({
|
|
180
|
+
kind: "path",
|
|
181
|
+
path: join(homedir(), "wf.js"),
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("路径分支:.. 段拒绝(⛔2 同面——路径域收紧对 workflow 原语生效)", () => {
|
|
186
|
+
expect(normalizeWorkflowRef("/x/../y.js", { knownNames })).toEqual({
|
|
187
|
+
kind: "invalid",
|
|
188
|
+
ref: "/x/../y.js",
|
|
189
|
+
reason: "parent_segment",
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it("路径分支:相对路径 not_absolute、非 .js 扩展名 bad_ext", () => {
|
|
194
|
+
// "wf.js" 无分隔符是合法裸名形态(workflow 名可含点号)→ 走名分支不猜路径
|
|
195
|
+
expect(normalizeWorkflowRef("wf.js", { knownNames })).toEqual({
|
|
196
|
+
kind: "invalid",
|
|
197
|
+
ref: "wf.js",
|
|
198
|
+
reason: "unknown_name",
|
|
199
|
+
});
|
|
200
|
+
// 显式相对路径形态(含分隔符)→ 路径分支
|
|
201
|
+
expect(normalizeWorkflowRef("./wf.js", { knownNames })).toEqual({
|
|
202
|
+
kind: "invalid",
|
|
203
|
+
ref: "./wf.js",
|
|
204
|
+
reason: "not_absolute",
|
|
205
|
+
});
|
|
206
|
+
expect(normalizeWorkflowRef("/proj/wf.txt", { knownNames })).toEqual({
|
|
207
|
+
kind: "invalid",
|
|
208
|
+
ref: "/proj/wf.txt",
|
|
209
|
+
reason: "bad_ext",
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("路径分支失败原因优先级:.. 段先于扩展名判定", () => {
|
|
214
|
+
expect(normalizeWorkflowRef("/x/../y.txt")).toEqual({
|
|
215
|
+
kind: "invalid",
|
|
216
|
+
ref: "/x/../y.txt",
|
|
217
|
+
reason: "parent_segment",
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("路径分支失败原因优先级:.. 段先于绝对路径判定(重放顺序对齐 normalizeRef 判序)", () => {
|
|
222
|
+
// 相对路径 + 含 .. 段:normalizeRef 实际因 parent_segment 先判拒绝,归因
|
|
223
|
+
// 不得误报 not_absolute(否则指引改绝对路径后仍被 .. 段拒绝——两步误导)
|
|
224
|
+
expect(normalizeWorkflowRef("a/../b.js")).toEqual({
|
|
225
|
+
kind: "invalid",
|
|
226
|
+
ref: "a/../b.js",
|
|
227
|
+
reason: "parent_segment",
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("裸名与路径天然二分:名字是简单标识符,含分隔符即归路径分支(对齐 pi 现行为)", () => {
|
|
232
|
+
// 名字不撞路径:knownNames 命中不受路径分支影响
|
|
233
|
+
expect(normalizeWorkflowRef("chain", { knownNames: ["chain"] }).kind).toBe("name");
|
|
234
|
+
// 同串含分隔符后不再是名引用(绝对路径形态但缺 .js 后缀 → bad_ext)
|
|
235
|
+
expect(normalizeWorkflowRef("/chain", { knownNames: ["chain"] })).toEqual({
|
|
236
|
+
kind: "invalid",
|
|
237
|
+
ref: "/chain",
|
|
238
|
+
reason: "bad_ext",
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
});
|