@zhushanwen/subagent-core 0.2.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 +114 -0
- package/dist/chunk-3VOERJPJ.js +22 -0
- package/dist/chunk-A4IVZWVX.js +31 -0
- package/dist/execution/engine/engines/zcode/constants.cjs +54 -0
- package/dist/execution/engine/engines/zcode/constants.d.cts +31 -0
- package/dist/execution/engine/engines/zcode/constants.d.ts +31 -0
- package/dist/execution/engine/engines/zcode/constants.js +22 -0
- package/dist/execution/engine/engines/zcode/reader.cjs +276 -0
- package/dist/execution/engine/engines/zcode/reader.d.cts +20 -0
- package/dist/execution/engine/engines/zcode/reader.d.ts +20 -0
- package/dist/execution/engine/engines/zcode/reader.js +239 -0
- package/dist/execution/engine/paths.cjs +55 -0
- package/dist/execution/engine/paths.d.cts +8 -0
- package/dist/execution/engine/paths.d.ts +8 -0
- package/dist/execution/engine/paths.js +26 -0
- package/dist/execution/relay-env.cjs +62 -0
- package/dist/execution/relay-env.d.cts +33 -0
- package/dist/execution/relay-env.d.ts +33 -0
- package/dist/execution/relay-env.js +20 -0
- package/dist/index.cjs +1852 -0
- package/dist/index.d.cts +1184 -0
- package/dist/index.d.ts +1184 -0
- package/dist/index.js +1810 -0
- package/dist/types-BxyAidGf.d.cts +875 -0
- package/dist/types-BxyAidGf.d.ts +875 -0
- package/package.json +99 -0
- package/src/__tests__/agent-opts-resolver-schema-prompt.test.ts +142 -0
- package/src/__tests__/append-system-prompt-assembly.test.ts +242 -0
- package/src/__tests__/builtin-workflows-structure.test.ts +180 -0
- package/src/__tests__/derive-closed-display-parity.test.ts +93 -0
- package/src/__tests__/fr4-get-state-handshake.test.ts +125 -0
- package/src/__tests__/fr8-orphan-recovery.test.ts +259 -0
- package/src/__tests__/m2-append-content-probe.test.ts +73 -0
- package/src/__tests__/manifest-store.test.ts +368 -0
- package/src/__tests__/record-store-cache.test.ts +335 -0
- package/src/__tests__/record-store-index.test.ts +560 -0
- package/src/__tests__/record-store-last-line.test.ts +129 -0
- package/src/__tests__/review-fix-loop-script.test.ts +288 -0
- package/src/__tests__/review-fix-loop-utils.test.ts +2377 -0
- package/src/__tests__/robustness-low-batch1.test.ts +286 -0
- package/src/__tests__/robustness-medium-batch1.test.ts +69 -0
- package/src/__tests__/robustness-medium-batch2.test.ts +65 -0
- package/src/__tests__/robustness-medium-batch3.test.ts +30 -0
- package/src/__tests__/robustness-medium-batch4.test.ts +358 -0
- package/src/__tests__/session-runner.test.ts +69 -0
- package/src/__tests__/smoke.test.ts +9 -0
- package/src/__tests__/stream-sink.test.ts +203 -0
- package/src/core/__tests__/host-services.test.ts +144 -0
- package/src/core/__tests__/logger.test.ts +78 -0
- package/src/core/__tests__/notify-ports.test.ts +104 -0
- package/src/core/host-services.ts +97 -0
- package/src/core/logger.ts +47 -0
- package/src/core/notify-ports.ts +126 -0
- package/src/execution/__tests__/__fixtures__/notifier-golden-snapshots.json +53 -0
- package/src/execution/__tests__/__fixtures__/truncline.snapshot.json +1 -0
- package/src/execution/__tests__/agent-result-mapper.test.ts +150 -0
- package/src/execution/__tests__/alive-store.test.ts +147 -0
- package/src/execution/__tests__/ask-user-transit-e2e.test.ts +490 -0
- package/src/execution/__tests__/channel-registry-handshake.test.ts +242 -0
- package/src/execution/__tests__/chat-engine-routing.test.ts +610 -0
- package/src/execution/__tests__/chatmode-first-round-closure-spawn.test.ts +190 -0
- package/src/execution/__tests__/concurrency-pool.test.ts +250 -0
- package/src/execution/__tests__/config.test.ts +302 -0
- package/src/execution/__tests__/delivery-methods.test.ts +424 -0
- package/src/execution/__tests__/dialog-queue.test.ts +299 -0
- package/src/execution/__tests__/epipe-fallback.test.ts +241 -0
- package/src/execution/__tests__/execute-and-await-worktree.test.ts +243 -0
- package/src/execution/__tests__/execute-nesting.test.ts +323 -0
- package/src/execution/__tests__/execute-options-mapper.test.ts +200 -0
- package/src/execution/__tests__/execution-record.test.ts +1394 -0
- package/src/execution/__tests__/explicit-agent-ref-guard.test.ts +171 -0
- package/src/execution/__tests__/finalize-record.test.ts +367 -0
- package/src/execution/__tests__/finalized-marker.test.ts +104 -0
- package/src/execution/__tests__/format-schema-instruction.test.ts +169 -0
- package/src/execution/__tests__/gc-timer.test.ts +184 -0
- package/src/execution/__tests__/get-record-for-action-restart.test.ts +254 -0
- package/src/execution/__tests__/helpers/mock-extension-api.ts +30 -0
- package/src/execution/__tests__/helpers/spawn-mock.ts +242 -0
- package/src/execution/__tests__/host-mode.test.ts +87 -0
- package/src/execution/__tests__/lifecycle-manager-lock.test.ts +211 -0
- package/src/execution/__tests__/lifecycle-manager.test.ts +383 -0
- package/src/execution/__tests__/lifecycle-predicates.test.ts +116 -0
- package/src/execution/__tests__/manifest-parentid.test.ts +117 -0
- package/src/execution/__tests__/model-resolver.test.ts +465 -0
- package/src/execution/__tests__/nested-visibility-env-propagation.test.ts +287 -0
- package/src/execution/__tests__/nested-visibility.test.ts +325 -0
- package/src/execution/__tests__/output-collector.test.ts +358 -0
- package/src/execution/__tests__/path-encoding.test.ts +104 -0
- package/src/execution/__tests__/pi-invocation.test.ts +134 -0
- package/src/execution/__tests__/record-store.test.ts +1057 -0
- package/src/execution/__tests__/records-cwd-isolation.test.ts +91 -0
- package/src/execution/__tests__/recursive-visibility-baseline.test.ts +339 -0
- package/src/execution/__tests__/recursive-visibility-env.test.ts +273 -0
- package/src/execution/__tests__/relay-env.test.ts +42 -0
- package/src/execution/__tests__/resource-policy.test.ts +109 -0
- package/src/execution/__tests__/rpc-mode.test.ts +89 -0
- package/src/execution/__tests__/run-and-finalize-chatmode.test.ts +267 -0
- package/src/execution/__tests__/run-spawn-chatmode-settled.test.ts +253 -0
- package/src/execution/__tests__/run-spawn-edges.test.ts +687 -0
- package/src/execution/__tests__/run-spawn-integration.test.ts +933 -0
- package/src/execution/__tests__/run-spawn-resume.test.ts +322 -0
- package/src/execution/__tests__/run-spawn-rpc-mode.test.ts +196 -0
- package/src/execution/__tests__/run-spawn-stdout-callback-throw.test.ts +199 -0
- package/src/execution/__tests__/session-context-resolver.test.ts +167 -0
- package/src/execution/__tests__/session-file-gc.test.ts +293 -0
- package/src/execution/__tests__/session-reconstructor.test.ts +379 -0
- package/src/execution/__tests__/session-runner-epipe.test.ts +178 -0
- package/src/execution/__tests__/session-runner-schema-env.test.ts +350 -0
- package/src/execution/__tests__/spawn-args.test.ts +445 -0
- package/src/execution/__tests__/spawn-event-adapter-rpc.test.ts +189 -0
- package/src/execution/__tests__/spawn-event-adapter.test.ts +167 -0
- package/src/execution/__tests__/spawn-worktree-guidance.test.ts +207 -0
- package/src/execution/__tests__/spawned-children.test.ts +92 -0
- package/src/execution/__tests__/start-sync-model-guard.test.ts +150 -0
- package/src/execution/__tests__/stdin-writer.test.ts +462 -0
- package/src/execution/__tests__/stream-sink-retirement.test.ts +261 -0
- package/src/execution/__tests__/subagent-service-abort.test.ts +60 -0
- package/src/execution/__tests__/subagent-service-message-close.test.ts +629 -0
- package/src/execution/__tests__/subagent-service-parent-guard.test.ts +180 -0
- package/src/execution/__tests__/subagent-service.test.ts +788 -0
- package/src/execution/__tests__/subprocess-agent-runner-routing.test.ts +310 -0
- package/src/execution/__tests__/subprocess-agent-runner.test.ts +612 -0
- package/src/execution/__tests__/temp-prompt.test.ts +53 -0
- package/src/execution/__tests__/timeout-integration.test.ts +615 -0
- package/src/execution/__tests__/tombstone-store.test.ts +73 -0
- package/src/execution/__tests__/turn-limiter-semantics.test.ts +194 -0
- package/src/execution/__tests__/turn-limiter.test.ts +65 -0
- package/src/execution/__tests__/ui-channels.test.ts +187 -0
- package/src/execution/__tests__/ui-interaction-model.test.ts +67 -0
- package/src/execution/__tests__/ui-request-handler-factory.test.ts +369 -0
- package/src/execution/__tests__/ui-request-handler.test.ts +204 -0
- package/src/execution/__tests__/ui-request-observability.test.ts +113 -0
- package/src/execution/__tests__/ui-request-queue.test.ts +133 -0
- package/src/execution/__tests__/worktree-manager.test.ts +633 -0
- package/src/execution/__tests__/worktree-pid-registration.integration.test.ts +229 -0
- package/src/execution/__tests__/worktree-reconcile.integration.test.ts +181 -0
- package/src/execution/__tests__/worktree-registry.test.ts +199 -0
- package/src/execution/agent-registry.ts +199 -0
- package/src/execution/agent-result-mapper.ts +90 -0
- package/src/execution/alive-store.ts +119 -0
- package/src/execution/argv-mirror.ts +113 -0
- package/src/execution/best-effort.ts +38 -0
- package/src/execution/channel-registry-access.ts +144 -0
- package/src/execution/concurrency-pool.ts +116 -0
- package/src/execution/config.ts +165 -0
- package/src/execution/dialog-queue.ts +330 -0
- package/src/execution/engine/__tests__/common/data-dir.test.ts +78 -0
- package/src/execution/engine/__tests__/common/errors.test.ts +132 -0
- package/src/execution/engine/__tests__/common/event-journal.test.ts +177 -0
- package/src/execution/engine/__tests__/common/kill-chain.test.ts +192 -0
- package/src/execution/engine/__tests__/common/nesting-guard.test.ts +81 -0
- package/src/execution/engine/__tests__/common/persona-router.test.ts +123 -0
- package/src/execution/engine/__tests__/common/pool-manager.test.ts +154 -0
- package/src/execution/engine/__tests__/common/schema-emulation.test.ts +128 -0
- package/src/execution/engine/__tests__/conformance/__fixtures__/pi-golden-events.json +28 -0
- package/src/execution/engine/__tests__/conformance/agent-event-invariants.ts +141 -0
- package/src/execution/engine/__tests__/conformance/contract.abort.test.ts +109 -0
- package/src/execution/engine/__tests__/conformance/contract.agent-events.test.ts +101 -0
- package/src/execution/engine/__tests__/conformance/contract.probe.test.ts +77 -0
- package/src/execution/engine/__tests__/conformance/contract.read-degradation.test.ts +104 -0
- package/src/execution/engine/__tests__/conformance/engine-conformance.live.test.ts +201 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.pi.test.ts +76 -0
- package/src/execution/engine/__tests__/conformance/golden-replay.zcode.test.ts +79 -0
- package/src/execution/engine/__tests__/engine-discovery.test.ts +87 -0
- package/src/execution/engine/__tests__/model-prompt.test.ts +197 -0
- package/src/execution/engine/__tests__/paths.test.ts +39 -0
- package/src/execution/engine/__tests__/registry.test.ts +120 -0
- package/src/execution/engine/__tests__/routing.test.ts +231 -0
- package/src/execution/engine/common/data-dir.ts +66 -0
- package/src/execution/engine/common/errors.ts +183 -0
- package/src/execution/engine/common/event-journal.ts +254 -0
- package/src/execution/engine/common/journal-replay.ts +62 -0
- package/src/execution/engine/common/kill-chain.ts +221 -0
- package/src/execution/engine/common/nesting-guard.ts +50 -0
- package/src/execution/engine/common/persona-router.ts +108 -0
- package/src/execution/engine/common/pool-manager.ts +226 -0
- package/src/execution/engine/common/schema-emulation.ts +189 -0
- package/src/execution/engine/common/session-view-projection.ts +51 -0
- package/src/execution/engine/engine-discovery.ts +65 -0
- package/src/execution/engine/engines/pi/__tests__/pi-engine.test.ts +469 -0
- package/src/execution/engine/engines/pi/__tests__/reader.test.ts +155 -0
- package/src/execution/engine/engines/pi/__tests__/task-spec-mapper.test.ts +164 -0
- package/src/execution/engine/engines/pi/pi-engine.ts +415 -0
- package/src/execution/engine/engines/pi/reader.ts +48 -0
- package/src/execution/engine/engines/pi/registration.ts +35 -0
- package/src/execution/engine/engines/pi/task-spec-mapper.ts +100 -0
- package/src/execution/engine/engines/zcode/__tests__/__fixtures__/zcode-golden-spawn.json +39 -0
- package/src/execution/engine/engines/zcode/__tests__/launcher.test.ts +150 -0
- package/src/execution/engine/engines/zcode/__tests__/parser.test.ts +246 -0
- package/src/execution/engine/engines/zcode/__tests__/preparer.test.ts +228 -0
- package/src/execution/engine/engines/zcode/__tests__/reader.test.ts +210 -0
- package/src/execution/engine/engines/zcode/__tests__/registration.test.ts +71 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.live.test.ts +127 -0
- package/src/execution/engine/engines/zcode/__tests__/zcode-engine.test.ts +580 -0
- package/src/execution/engine/engines/zcode/constants.ts +43 -0
- package/src/execution/engine/engines/zcode/golden-sample.ts +39 -0
- package/src/execution/engine/engines/zcode/launcher.ts +161 -0
- package/src/execution/engine/engines/zcode/parser.ts +436 -0
- package/src/execution/engine/engines/zcode/preparer.ts +363 -0
- package/src/execution/engine/engines/zcode/reader.ts +381 -0
- package/src/execution/engine/engines/zcode/registration.ts +37 -0
- package/src/execution/engine/engines/zcode/zcode-engine.ts +658 -0
- package/src/execution/engine/host-task-spec.ts +47 -0
- package/src/execution/engine/model-prompt.ts +158 -0
- package/src/execution/engine/paths.ts +42 -0
- package/src/execution/engine/port.ts +153 -0
- package/src/execution/engine/registry.ts +133 -0
- package/src/execution/engine/routing.ts +218 -0
- package/src/execution/engine/types.ts +309 -0
- package/src/execution/execute-options-mapper.ts +115 -0
- package/src/execution/execution-record.ts +984 -0
- package/src/execution/finalize-record.ts +254 -0
- package/src/execution/finalized-marker.ts +70 -0
- package/src/execution/get-state-handshake.ts +104 -0
- package/src/execution/host-mode.ts +56 -0
- package/src/execution/idle-gc.ts +47 -0
- package/src/execution/lifecycle-manager.ts +513 -0
- package/src/execution/lifecycle-predicates.ts +65 -0
- package/src/execution/manifest-store.ts +256 -0
- package/src/execution/model-config-service.ts +250 -0
- package/src/execution/model-resolver.ts +248 -0
- package/src/execution/notifier.ts +372 -0
- package/src/execution/notify-ledger.ts +580 -0
- package/src/execution/output-collector.ts +228 -0
- package/src/execution/path-encoding.ts +60 -0
- package/src/execution/pi-invocation.ts +120 -0
- package/src/execution/record-entry.ts +132 -0
- package/src/execution/record-store.ts +1265 -0
- package/src/execution/relay-env.ts +37 -0
- package/src/execution/session-context-resolver.ts +64 -0
- package/src/execution/session-file-gc.ts +120 -0
- package/src/execution/session-pending.ts +170 -0
- package/src/execution/session-reconstructor.ts +678 -0
- package/src/execution/session-runner.ts +1789 -0
- package/src/execution/sessions-index.ts +304 -0
- package/src/execution/spawn-event-adapter.ts +363 -0
- package/src/execution/stdin-writer.ts +198 -0
- package/src/execution/stream-sink.ts +126 -0
- package/src/execution/subagent-service.ts +2268 -0
- package/src/execution/subprocess-agent-runner.ts +317 -0
- package/src/execution/temp-prompt.ts +62 -0
- package/src/execution/tombstone-store.ts +72 -0
- package/src/execution/turn-limiter.ts +102 -0
- package/src/execution/types.ts +1023 -0
- package/src/execution/ui-channels.ts +216 -0
- package/src/execution/ui-interaction-model.ts +48 -0
- package/src/execution/ui-request-handler-factory.ts +243 -0
- package/src/execution/ui-request-observability.ts +81 -0
- package/src/execution/ui-request-queue.ts +184 -0
- package/src/execution/worktree-manager.ts +688 -0
- package/src/execution/worktree-registry.ts +279 -0
- package/src/index.ts +87 -0
- package/src/orchestration/__tests__/__fixtures__/worker-template.snapshot.txt +349 -0
- package/src/orchestration/__tests__/agent-call-catch-fallback.test.ts +202 -0
- package/src/orchestration/__tests__/agent-call-stream.test.ts +152 -0
- package/src/orchestration/__tests__/args-validator.test.ts +143 -0
- package/src/orchestration/__tests__/config-loader.test.ts +503 -0
- package/src/orchestration/__tests__/error-recovery-handlers.test.ts +809 -0
- package/src/orchestration/__tests__/error-recovery-postmessage-defense.test.ts +404 -0
- package/src/orchestration/__tests__/error-recovery-serialize-failed-result.test.ts +56 -0
- package/src/orchestration/__tests__/error-recovery-workflow-call.test.ts +166 -0
- package/src/orchestration/__tests__/execute-agent-call.test.ts +451 -0
- package/src/orchestration/__tests__/launcher-nested-workflow.test.ts +600 -0
- package/src/orchestration/__tests__/lifecycle-runid-injection.test.ts +96 -0
- package/src/orchestration/__tests__/lifecycle.test.ts +659 -0
- package/src/orchestration/__tests__/non-cloneable-return-e2e.test.ts +95 -0
- package/src/orchestration/__tests__/review-fix-loop-scriptpath-failfast.test.ts +183 -0
- package/src/orchestration/__tests__/script-lint.test.ts +831 -0
- package/src/orchestration/__tests__/skill-discovery.test.ts +210 -0
- package/src/orchestration/__tests__/test-mocks.ts +197 -0
- package/src/orchestration/__tests__/worker-exit-without-result.test.ts +368 -0
- package/src/orchestration/__tests__/worker-host.test.ts +120 -0
- package/src/orchestration/__tests__/worker-returnmeta-passthrough.test.ts +164 -0
- package/src/orchestration/__tests__/worker-script-builder-runtime.test.ts +563 -0
- package/src/orchestration/__tests__/worker-script-builder.test.ts +309 -0
- package/src/orchestration/__tests__/worker-script-template-snapshot.test.ts +129 -0
- package/src/orchestration/__tests__/workflow-nesting-e2e.test.ts +317 -0
- package/src/orchestration/__tests__/workflow-script-lint-memo.test.ts +110 -0
- package/src/orchestration/agent-opts-resolver.ts +174 -0
- package/src/orchestration/args-validator.ts +127 -0
- package/src/orchestration/config-loader.ts +316 -0
- package/src/orchestration/error-recovery.ts +1018 -0
- package/src/orchestration/execute-agent-call.ts +256 -0
- package/src/orchestration/launcher.ts +455 -0
- package/src/orchestration/lifecycle.ts +399 -0
- package/src/orchestration/models/__tests__/budget.test.ts +307 -0
- package/src/orchestration/models/agent-call.ts +83 -0
- package/src/orchestration/models/budget.ts +118 -0
- package/src/orchestration/models/ports.ts +164 -0
- package/src/orchestration/models/run-runtime.ts +104 -0
- package/src/orchestration/models/run-spec.ts +83 -0
- package/src/orchestration/models/run-state.ts +44 -0
- package/src/orchestration/models/trace.ts +183 -0
- package/src/orchestration/models/types.ts +301 -0
- package/src/orchestration/models/workflow-run.ts +254 -0
- package/src/orchestration/models/workflow-script-registry.ts +35 -0
- package/src/orchestration/models/workflow-script.ts +117 -0
- package/src/orchestration/script-lint.ts +766 -0
- package/src/orchestration/skill-discovery.ts +135 -0
- package/src/orchestration/worker-handle.ts +115 -0
- package/src/orchestration/worker-host.ts +98 -0
- package/src/orchestration/worker-script-builder.ts +421 -0
- package/src/orchestration/workflow-files.ts +85 -0
- package/src/orchestration/workflow-script-registry-impl.ts +133 -0
- package/src/shared/__tests__/agent-ref.test.ts +34 -0
- package/src/shared/__tests__/meta-parser.test.ts +304 -0
- package/src/shared/__tests__/model-ref.test.ts +306 -0
- package/src/shared/__tests__/resource-discovery-manifest-cache.test.ts +288 -0
- package/src/shared/__tests__/resource-discovery.test.ts +749 -0
- package/src/shared/__tests__/resource-meta.test.ts +51 -0
- package/src/shared/__tests__/schema-jsonify.test.ts +81 -0
- package/src/shared/__tests__/timer-delay.test.ts +61 -0
- package/src/shared/agent-event.ts +13 -0
- package/src/shared/agent-ref.ts +57 -0
- package/src/shared/meta-parser.ts +261 -0
- package/src/shared/model-ref.ts +286 -0
- package/src/shared/resource-discovery.ts +835 -0
- package/src/shared/resource-meta.ts +65 -0
- package/src/shared/schema-env.ts +44 -0
- package/src/shared/schema-jsonify.ts +58 -0
- package/src/shared/timer-delay.ts +54 -0
- package/src/shared/xml-injection.ts +35 -0
- package/workflows/README.md +81 -0
- package/workflows/_shared/agent-refs.cjs +40 -0
- package/workflows/chain.js +137 -0
- package/workflows/map-reduce.js +180 -0
- package/workflows/parallel.js +154 -0
- package/workflows/review-fix-loop-utils.cjs +1542 -0
- package/workflows/review-fix-loop.js +1605 -0
- package/workflows/scatter-gather.js +184 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// src/execution/agent-registry.ts
|
|
2
|
+
//
|
|
3
|
+
// agent .md 文件发现与解析。
|
|
4
|
+
//
|
|
5
|
+
// 发现逻辑统一走 shared/resource-discovery(ADR-031),与 workflow 共享同一套
|
|
6
|
+
// 扫描源前缀 + manifest 校验。hot-reload:每次调用重扫(mtime 缓存跳过未变文件)。
|
|
7
|
+
//
|
|
8
|
+
// builtin agent(包内 agents/*.md)走 pi.agents manifest(与 npm 包内发现规则一致)。
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
|
|
13
|
+
import { getLogger } from "../core/logger.ts";
|
|
14
|
+
|
|
15
|
+
import {
|
|
16
|
+
getCachedFile,
|
|
17
|
+
} from "../shared/resource-discovery.ts";
|
|
18
|
+
import { normalizeRef, AGENT_REF_EXT } from "../shared/agent-ref.ts";
|
|
19
|
+
import { parseResourceMeta } from "../shared/meta-parser.ts";
|
|
20
|
+
import { lintAgentMeta } from "../orchestration/script-lint.ts";
|
|
21
|
+
import type { AgentMeta } from "../shared/resource-meta.ts";
|
|
22
|
+
import type { AgentConfig } from "./model-resolver.ts";
|
|
23
|
+
import { hasEngine, listEngines, EngineNotFoundError } from "./engine/registry.ts";
|
|
24
|
+
|
|
25
|
+
const logger = getLogger("subagents");
|
|
26
|
+
|
|
27
|
+
/** mtime 缓存条目(跨 loadByPath 保留,靠 mtime 判失效)。 */
|
|
28
|
+
interface FileCacheEntry {
|
|
29
|
+
mtimeMs: number;
|
|
30
|
+
config: AgentConfig;
|
|
31
|
+
/** AgentMeta(W4 lint 用——cache-miss 时 lint 一次,warn 随 mtime 变化刷)。 */
|
|
32
|
+
meta: AgentMeta | null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ============================================================
|
|
36
|
+
// frontmatter 解析
|
|
37
|
+
// ============================================================
|
|
38
|
+
|
|
39
|
+
/** frontmatter 分隔符。 */
|
|
40
|
+
const FM_DELIM = "---";
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 解析 .md frontmatter(name/tools/model/thinkingLevel/defaultBackground)+ body(systemPrompt)。
|
|
44
|
+
* 兼容简单 YAML(key: value 单行格式)。body 作为 systemPrompt。
|
|
45
|
+
*/
|
|
46
|
+
export function parseAgentFrontmatter(filePath: string, content: string): AgentConfig {
|
|
47
|
+
return parseAgentWithMeta(filePath, content).config;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 解析 agent .md → { config, meta } 二元组(m5 T2:W4 lint 需要 AgentMeta——
|
|
52
|
+
* AgentConfig 投影时 examples 被丢弃,meta 供 lintAgentMeta 使用)。
|
|
53
|
+
*/
|
|
54
|
+
export function parseAgentWithMeta(
|
|
55
|
+
filePath: string,
|
|
56
|
+
content: string,
|
|
57
|
+
): { config: AgentConfig; meta: AgentMeta | null } {
|
|
58
|
+
const name = path.basename(filePath, ".md");
|
|
59
|
+
|
|
60
|
+
// 无 frontmatter → 整个内容作为 systemPrompt
|
|
61
|
+
if (!content.startsWith(FM_DELIM)) {
|
|
62
|
+
return { config: { name, systemPrompt: content.trim() }, meta: null };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const closeIdx = content.indexOf(FM_DELIM, FM_DELIM.length);
|
|
66
|
+
if (closeIdx === -1) {
|
|
67
|
+
// 未闭合 frontmatter:提取 name,其余作为 systemPrompt
|
|
68
|
+
const yamlBlock = content.slice(FM_DELIM.length);
|
|
69
|
+
return {
|
|
70
|
+
config: {
|
|
71
|
+
name: extractYamlField(yamlBlock, "name") ?? name,
|
|
72
|
+
systemPrompt: content.trim(),
|
|
73
|
+
},
|
|
74
|
+
meta: null,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const yamlBlock = content.slice(FM_DELIM.length, closeIdx);
|
|
79
|
+
const body = content.slice(closeIdx + FM_DELIM.length).trim();
|
|
80
|
+
|
|
81
|
+
// m2:结构化路由字段(name/model/tools)经 IF1 parseResourceMeta(统一 parser),
|
|
82
|
+
// 消灭本地 frontmatter parser 与 subagent-list-injector 的重复。thinkingLevel/defaultBackground
|
|
83
|
+
// 是执行配置(非 AgentMeta 路由字段),仍用 extractYamlField 取。
|
|
84
|
+
const meta = parseResourceMeta(content, "agent");
|
|
85
|
+
const agentMeta = meta?.kind === "agent" ? meta : null;
|
|
86
|
+
// MF-3 regression fix:agentMeta=null(IF1 要求 name/description 必填,缺则 parseResourceMeta
|
|
87
|
+
// 返 null)时,model/tools 不能静默丢失——fallback 用 extractYamlField 取(保留重构前行为)。
|
|
88
|
+
// 注入路由可见性由 discovery/injector 按 available 标志决定,与本处(direct-path loadByPath)无关。
|
|
89
|
+
const modelFallback = extractYamlField(yamlBlock, "model");
|
|
90
|
+
const toolsFallbackRaw = extractYamlField(yamlBlock, "tools");
|
|
91
|
+
const toolsFallback = toolsFallbackRaw
|
|
92
|
+
? toolsFallbackRaw.split(",").map((s) => s.trim()).filter(Boolean)
|
|
93
|
+
: undefined;
|
|
94
|
+
if (!agentMeta && /^model:|^tools:/m.test(yamlBlock)) {
|
|
95
|
+
// m2 exec-review MINOR-2 + MF-3:IF1 未通过(缺 name/description)→ model/tools 经 legacy
|
|
96
|
+
// fallback 取(direct-path loadByPath 不丢配置,与重构前一致);但结构化路由注入不可见,
|
|
97
|
+
// 建议 agent 作者补 description 以满足 IF1。
|
|
98
|
+
logger.warn(
|
|
99
|
+
`[agent-registry] ${filePath}: agent frontmatter 缺 name/description(IF1 必填),` +
|
|
100
|
+
"model/tools 经 legacy fallback 生效(直接路径不丢配置),但结构化路由不可见——请补充 description",
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
const defaultBackgroundRaw = extractYamlField(yamlBlock, "defaultBackground");
|
|
104
|
+
// engine 字段(D9):结构化优先(IF1),legacy fallback 与 model/tools 同判——
|
|
105
|
+
// agentMeta 未通过 IF1 时配置不丢
|
|
106
|
+
const engine = agentMeta?.engine ?? extractYamlField(yamlBlock, "engine");
|
|
107
|
+
// 解析期校验(D9:未注册 id 前置暴露,不留到运行时神秘失败)。为什么在解析期而非
|
|
108
|
+
// 路由期:配置错误的根源在 .md 文件,越早报错定位越准(错误含文件路径 + 注册清单)
|
|
109
|
+
if (engine !== undefined && !hasEngine(engine)) {
|
|
110
|
+
throw new EngineNotFoundError(engine, listEngines(), filePath);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
config: {
|
|
115
|
+
name: agentMeta?.name ?? name,
|
|
116
|
+
systemPrompt: body,
|
|
117
|
+
model: agentMeta?.model ?? modelFallback ?? undefined,
|
|
118
|
+
thinkingLevel: extractYamlField(yamlBlock, "thinkingLevel") ?? undefined,
|
|
119
|
+
...(engine !== undefined ? { engine } : {}),
|
|
120
|
+
tools: agentMeta?.tools && agentMeta.tools.length > 0
|
|
121
|
+
? agentMeta.tools
|
|
122
|
+
: (toolsFallback && toolsFallback.length > 0 ? toolsFallback : undefined),
|
|
123
|
+
defaultBackground: defaultBackgroundRaw === "true" ? true : undefined,
|
|
124
|
+
},
|
|
125
|
+
meta: agentMeta,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** 提取简单 `key: value` 字段,剥离引号。 */
|
|
130
|
+
function extractYamlField(yaml: string, key: string): string | undefined {
|
|
131
|
+
const regex = new RegExp(`^${key}:\\s*(.+)$`, "m");
|
|
132
|
+
const match = yaml.match(regex);
|
|
133
|
+
if (!match) return undefined;
|
|
134
|
+
let value = match[1].trim();
|
|
135
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
136
|
+
value = value.slice(1, -1);
|
|
137
|
+
}
|
|
138
|
+
return value || undefined;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ============================================================
|
|
142
|
+
// AgentRegistry
|
|
143
|
+
// ============================================================
|
|
144
|
+
|
|
145
|
+
export class AgentRegistry {
|
|
146
|
+
/** 文件级 mtime 缓存(key=绝对路径,跨 loadByPath 保留)。 */
|
|
147
|
+
private readonly fileCache = new Map<string, FileCacheEntry>();
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* 按绝对路径加载 agent(agentRef 统一解析入口——S2 路径统一)。
|
|
151
|
+
*
|
|
152
|
+
* - ~/ 前缀展开;相对路径/非 .md 引用返回 undefined(引用唯一形态 = 绝对路径)
|
|
153
|
+
* - 文件不可读/不存在 → 驱逐缓存 + 返回 undefined(调用方给错误指引)
|
|
154
|
+
* - mtime 未变复用 config 缓存;cache-miss 时 W4 lint 一次
|
|
155
|
+
*
|
|
156
|
+
* require 语义:require:true 时上述两类失败改为 throw(错误文案含
|
|
157
|
+
* <available_subagents> 恢复指引),供「用户显式点名 agent」的调用点使用——
|
|
158
|
+
* 显式 ref 失败是配置错误,必须显式报错而非静默降级(三通道对称审查)。
|
|
159
|
+
*/
|
|
160
|
+
loadByPath(ref: string, require: true): AgentConfig;
|
|
161
|
+
loadByPath(ref: string, require?: boolean): AgentConfig | undefined;
|
|
162
|
+
loadByPath(ref: string, require?: boolean): AgentConfig | undefined {
|
|
163
|
+
const filePath = normalizeRef(ref, AGENT_REF_EXT);
|
|
164
|
+
if (filePath === null) {
|
|
165
|
+
if (require) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
`Invalid agent ref: ${ref}. Agent refs must be absolute paths to .md files (use <location> from <available_subagents>).`,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const file = getCachedFile(filePath);
|
|
174
|
+
if (file === null) {
|
|
175
|
+
// ENOENT/不可读 → 驱逐(mtime 缓存下文件删除不自愈的修复)
|
|
176
|
+
this.fileCache.delete(filePath);
|
|
177
|
+
if (require) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Agent file not found or unreadable: ${filePath}. Use an absolute path from <available_subagents> <location>.`,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const cached = this.fileCache.get(filePath);
|
|
186
|
+
if (cached && cached.mtimeMs === file.mtimeMs) {
|
|
187
|
+
return cached.config;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const { config, meta } = parseAgentWithMeta(filePath, file.content);
|
|
191
|
+
// W4 lint:cache-miss(parse 时一次)——warn 只随 mtime 变化刷
|
|
192
|
+
const lintFindings = meta ? lintAgentMeta(meta) : [];
|
|
193
|
+
for (const finding of lintFindings) {
|
|
194
|
+
logger.warn(`[agent-registry] ${filePath}: ${finding.message}`);
|
|
195
|
+
}
|
|
196
|
+
this.fileCache.set(filePath, { mtimeMs: file.mtimeMs, config, meta });
|
|
197
|
+
return config;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// src/execution/agent-result-mapper.ts
|
|
2
|
+
//
|
|
3
|
+
// D-A10: subagents AgentResult → workflow AgentResult 映射。
|
|
4
|
+
// 纯 DTO 映射函数——executeAndAwait 出口调,SAR 不感知形状差异。
|
|
5
|
+
//
|
|
6
|
+
// 接线层级:[模块内直调] —— SubagentService.executeAndAwait 出口调。
|
|
7
|
+
|
|
8
|
+
import type { AgentResult as WorkflowAgentResult, AgentUsage as WorkflowAgentUsage, ToolCallEntry } from "../orchestration/models/types.ts";
|
|
9
|
+
import type { AgentResult as SubagentsAgentResult, AgentUsageTotal, ToolCall } from "./types.ts";
|
|
10
|
+
|
|
11
|
+
/** safeStringify 的 JSON 截断长度(字符),防大对象拼进 toolCalls 挤爆 trace。 */
|
|
12
|
+
const TOOL_ARGS_JSON_MAX_CHARS = 500;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* D-A10: subagents AgentResult → workflow AgentResult 映射。
|
|
16
|
+
*
|
|
17
|
+
* 字段映射表:
|
|
18
|
+
* subagents → workflow
|
|
19
|
+
* ─────────────────────────────────────────────
|
|
20
|
+
* text → content
|
|
21
|
+
* parsedOutput → parsedOutput(structured-output 契约,BC-8)
|
|
22
|
+
* !success && error → error(失败时填,成功时 undefined)
|
|
23
|
+
* !success && !error → error fallback(abort 路径:session-runner 设 success=false,error=undefined,
|
|
24
|
+
* 若直接透传 undefined 则 executeAgentCall 的 `error===undefined` 误判 completed。H4 修复:synthesize fallback)
|
|
25
|
+
* durationMs → durationMs
|
|
26
|
+
* sessionId → sessionId
|
|
27
|
+
* usage (AgentUsageTotal) → usage (AgentUsage: input/output/cacheRead/cacheWrite/cost/contextTokens/turns)
|
|
28
|
+
* toolCalls (ToolCall[]) → toolCalls (ToolCallEntry[]: name/input)
|
|
29
|
+
*
|
|
30
|
+
* @param r subagents 管道产出的 AgentResult(runSpawn/collectResult 出口形状)
|
|
31
|
+
* @returns workflow 编排层消费的 AgentResult(executeAgentCall/finalizeCall 入参形状)
|
|
32
|
+
*/
|
|
33
|
+
export function mapToWorkflowAgentResult(
|
|
34
|
+
r: SubagentsAgentResult,
|
|
35
|
+
): WorkflowAgentResult {
|
|
36
|
+
return {
|
|
37
|
+
content: r.text,
|
|
38
|
+
parsedOutput: r.parsedOutput,
|
|
39
|
+
error: r.success ? undefined : (r.error || "Agent call failed (aborted or unknown error)"),
|
|
40
|
+
durationMs: r.durationMs,
|
|
41
|
+
sessionId: r.sessionId,
|
|
42
|
+
sessionFile: r.sessionFile,
|
|
43
|
+
usage: r.usage ? mapUsage(r.usage, r.turns) : undefined,
|
|
44
|
+
toolCalls: r.toolCalls ? mapToolCalls(r.toolCalls) : undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* AgentUsageTotal(subagents)→ AgentUsage(workflow)映射。
|
|
50
|
+
*
|
|
51
|
+
* subagents AgentUsageTotal: { input, output, cacheRead, cacheWrite, total, cost }
|
|
52
|
+
* workflow AgentUsage: { input, output, cacheRead, cacheWrite, cost, contextTokens, turns }
|
|
53
|
+
*
|
|
54
|
+
* contextTokens ≈ total(subagents 的四项之和,近似上下文 token 量)。
|
|
55
|
+
* turns 来自 AgentResult.turns(非 usage 内字段)。
|
|
56
|
+
*/
|
|
57
|
+
function mapUsage(u: AgentUsageTotal, turns: number): WorkflowAgentUsage {
|
|
58
|
+
return {
|
|
59
|
+
input: u.input,
|
|
60
|
+
output: u.output,
|
|
61
|
+
cacheRead: u.cacheRead,
|
|
62
|
+
cacheWrite: u.cacheWrite,
|
|
63
|
+
cost: u.cost,
|
|
64
|
+
contextTokens: u.total,
|
|
65
|
+
turns,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* ToolCall(subagents)→ ToolCallEntry(workflow)映射。
|
|
71
|
+
*
|
|
72
|
+
* subagents ToolCall: { toolName, args?, result?, isError? }
|
|
73
|
+
* workflow ToolCallEntry: { name, input }
|
|
74
|
+
*/
|
|
75
|
+
function mapToolCalls(calls: ToolCall[]): ToolCallEntry[] {
|
|
76
|
+
return calls.map((c) => ({
|
|
77
|
+
name: c.toolName,
|
|
78
|
+
input: c.args === undefined ? "" : safeStringify(c.args),
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** 安全序列化(args 可能含循环引用或大对象,截断防 OOM)。 */
|
|
83
|
+
function safeStringify(value: unknown): string {
|
|
84
|
+
try {
|
|
85
|
+
const s = JSON.stringify(value);
|
|
86
|
+
return s.length > TOOL_ARGS_JSON_MAX_CHARS ? `${s.slice(0, TOOL_ARGS_JSON_MAX_CHARS)}...` : s;
|
|
87
|
+
} catch {
|
|
88
|
+
return String(value);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// src/runtime/execution/alive-store.ts
|
|
2
|
+
//
|
|
3
|
+
// .alive sidecar 生产者 + pid 探活。
|
|
4
|
+
//
|
|
5
|
+
// 子进程启动时写 .alive(pid+id+startedAt),心跳检测时读它 + isProcessAlive
|
|
6
|
+
// 判活。finalize/cancel 收尾时 remove。与 .cancelled/.finalized 构成三件套。
|
|
7
|
+
//
|
|
8
|
+
// 设计对齐 tombstone-store:单文件 sidecar、best-effort I/O、无全局 index。
|
|
9
|
+
|
|
10
|
+
import * as fs from "node:fs";
|
|
11
|
+
|
|
12
|
+
import type { AliveMarker } from "./types.ts";
|
|
13
|
+
|
|
14
|
+
// ============================================================
|
|
15
|
+
// 常量
|
|
16
|
+
// ============================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* .alive marker 的软超时(1h,自 record-store.ts 迁移为共享常量):超过此时长的
|
|
20
|
+
* alive 视为陈旧——pid 复用窗口有限([防] 缩短窗口降误判),且长时间 marker 多半
|
|
21
|
+
* 是异常退出后的残留。v8.5 D 透明重生的异进程探针复用同一判据(findForeignLiveInstance)。
|
|
22
|
+
*/
|
|
23
|
+
export const ALIVE_SOFT_TIMEOUT_MS = 3_600_000;
|
|
24
|
+
|
|
25
|
+
// ============================================================
|
|
26
|
+
// 公开函数
|
|
27
|
+
// ============================================================
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 在 sessionFile 旁写 .alive sidecar(单行 JSON)。
|
|
31
|
+
* 覆盖写——同一 sessionFile 只有最后一个 alive marker 有意义。
|
|
32
|
+
*/
|
|
33
|
+
export function writeAliveMarker(sessionFile: string, marker: AliveMarker): void {
|
|
34
|
+
const alivePath = `${sessionFile}.alive`;
|
|
35
|
+
fs.writeFileSync(alivePath, `${JSON.stringify(marker)}\n`, "utf-8");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* 读 sessionFile 旁的 .alive sidecar。
|
|
40
|
+
* 返回 undefined:不存在 / 损坏 / 解析失败。
|
|
41
|
+
*/
|
|
42
|
+
export function readAliveMarker(sessionFile: string): AliveMarker | undefined {
|
|
43
|
+
let raw: string;
|
|
44
|
+
try {
|
|
45
|
+
raw = fs.readFileSync(`${sessionFile}.alive`, "utf-8");
|
|
46
|
+
} catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(raw) as Partial<AliveMarker>;
|
|
51
|
+
if (
|
|
52
|
+
typeof parsed.pid === "number" &&
|
|
53
|
+
typeof parsed.id === "string" &&
|
|
54
|
+
typeof parsed.startedAt === "number"
|
|
55
|
+
) {
|
|
56
|
+
return parsed as AliveMarker;
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
} catch {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 删除 sessionFile 旁的 .alive sidecar。
|
|
66
|
+
* best-effort:不存在不抛(finalize/cancel 收尾调,sidecar 可能已被清理)。
|
|
67
|
+
*/
|
|
68
|
+
export function removeAliveMarker(sessionFile: string): void {
|
|
69
|
+
try {
|
|
70
|
+
fs.unlinkSync(`${sessionFile}.alive`);
|
|
71
|
+
} catch {
|
|
72
|
+
void 0; // best-effort
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 检测 pid 是否存活。
|
|
78
|
+
*
|
|
79
|
+
* process.kill(pid, 0) 语义:不发信号,仅检查进程是否存在。
|
|
80
|
+
* - 无异常 → 存活
|
|
81
|
+
* - ESRCH(No such process)→ 死
|
|
82
|
+
* - EPERM(Process exists but no permission)→ 存活(保守)
|
|
83
|
+
* - 其他异常 → 保守判死 false,避免误删活进程
|
|
84
|
+
*/
|
|
85
|
+
export function isProcessAlive(pid: number): boolean {
|
|
86
|
+
try {
|
|
87
|
+
process.kill(pid, 0);
|
|
88
|
+
return true;
|
|
89
|
+
} catch (err: unknown) {
|
|
90
|
+
if (isErrnoException(err) && err.code === "EPERM") {
|
|
91
|
+
return true; // 存在但无权限发信号 → 判活
|
|
92
|
+
}
|
|
93
|
+
return false; // ESRCH 或其他异常 → 保守判死
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* [v8.5 D] 异进程活实例探针:sessionFile 是否仍有「另一进程」的活跃实例。
|
|
99
|
+
*
|
|
100
|
+
* 三判据与 record-store buildRecord 分支 3 同源(readAliveMarker + isProcessAlive +
|
|
101
|
+
* 软超时):marker 存在 && pid 存活 && 未超软超时才返回 marker;其余返回 undefined
|
|
102
|
+
* (视为确死/陈旧,允许透明重生)。调用方在 resurrect 前必须经此确认源进程确死,
|
|
103
|
+
* 防双写同一 session jsonl。
|
|
104
|
+
*/
|
|
105
|
+
export function findForeignLiveInstance(sessionFile: string, now: number = Date.now()): AliveMarker | undefined {
|
|
106
|
+
const marker = readAliveMarker(sessionFile);
|
|
107
|
+
if (!marker) return undefined;
|
|
108
|
+
if (!isProcessAlive(marker.pid)) return undefined;
|
|
109
|
+
if (now - marker.startedAt >= ALIVE_SOFT_TIMEOUT_MS) return undefined;
|
|
110
|
+
return marker;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ============================================================
|
|
114
|
+
// 内部工具
|
|
115
|
+
// ============================================================
|
|
116
|
+
|
|
117
|
+
function isErrnoException(err: unknown): err is NodeJS.ErrnoException {
|
|
118
|
+
return err instanceof Error && "code" in err;
|
|
119
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从主进程 argv 解析可镜像给子进程的 flag。
|
|
3
|
+
*
|
|
4
|
+
* 独立模块:argv 解析是独立职责,从 session-runner.ts 拆出避免该文件超行数上限。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 镜像 flag 集合:从主进程 argv 解析出的可透传给子进程的 flag。
|
|
9
|
+
* 面向 buildSpawnArgs 的入参形态(解析后)。undefined 字段语义与解析为空一致。
|
|
10
|
+
*/
|
|
11
|
+
export interface MirrorFlags {
|
|
12
|
+
noExtensions: boolean;
|
|
13
|
+
approve: boolean;
|
|
14
|
+
extensionPaths: string[];
|
|
15
|
+
noContextFiles: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 有值 flag 的解析规则表:成员是「后跟一个值」的 flag 名(含长短形式)。
|
|
20
|
+
* 用于 mirrorMainProcessFlags 跳过其他 flag 的值时不误吃。
|
|
21
|
+
*/
|
|
22
|
+
const VALUED_FLAGS = new Set<string>([
|
|
23
|
+
"--extension", "-e",
|
|
24
|
+
"--skill",
|
|
25
|
+
"--model", "--system-prompt", "--append-system-prompt",
|
|
26
|
+
"--tools", "-t", "--exclude-tools", "-xt",
|
|
27
|
+
"--fork", "--session-dir", "--mode",
|
|
28
|
+
"--thinking", "--models",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
/** argv 中 flag 的起始索引:argv[0]=runtime, argv[1]=binary 路径。 */
|
|
32
|
+
const ARGV_FLAG_START = 2;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 从主进程 argv 解析可镜像的 flag(--no-extensions/--approve/--extension/--no-context-files)。
|
|
36
|
+
*
|
|
37
|
+
* 数据源是主 pi 进程的 process.argv:子进程 spawn 的父就是主进程,
|
|
38
|
+
* 主进程 argv 完整保留启动时收到的全部 flag(已运行时验证)。这让子进程
|
|
39
|
+
* extension/approve 加载行为与主进程一致,且对任意 pi 宿主通用(不止 xyz-agent)。
|
|
40
|
+
*
|
|
41
|
+
* 解析规则:
|
|
42
|
+
* - --no-extensions / -ne、--approve / -a:布尔 flag
|
|
43
|
+
* - --no-context-files / -nc:布尔 flag(镜像理由:--extension 镜像会把
|
|
44
|
+
* @zhushanwen/pi-system-prompt 带进每个 subagent,该扩展靠子进程自己的
|
|
45
|
+
* argv 检测此 flag 决定是否注入全局 AGENTS.md——不镜像则用户 opt-out
|
|
46
|
+
* 在 subagent 路径失效)
|
|
47
|
+
* - --extension / -e:支持 `--extension <path>`(空格)与 `--extension=<path>`(等号)
|
|
48
|
+
* - 其他 flag(在 VALUED_FLAGS 中)的值不被误当 extension 路径
|
|
49
|
+
* - positional 参数被忽略
|
|
50
|
+
* - argv[0]/argv[1] 是 bun/pi binary 路径,从 argv[2:] 开始扫
|
|
51
|
+
*/
|
|
52
|
+
// [perf] 进程内 process.argv 引用恒定(唯一调用点 session-runner 每次 spawn 传同一引用),
|
|
53
|
+
// 解析结果按 argv 引用相等 memo——每次 spawn 免重复扫描/正则。测试传新数组引用不命中。
|
|
54
|
+
let memoArgv: readonly string[] | undefined;
|
|
55
|
+
let memoResult: MirrorFlags | undefined;
|
|
56
|
+
|
|
57
|
+
export function mirrorMainProcessFlags(argv: readonly string[]): MirrorFlags {
|
|
58
|
+
if (memoResult !== undefined && memoArgv === argv) return memoResult;
|
|
59
|
+
let hasNoExtensions = false;
|
|
60
|
+
let hasApprove = false;
|
|
61
|
+
let hasNoContextFiles = false;
|
|
62
|
+
const extensionPaths: string[] = [];
|
|
63
|
+
|
|
64
|
+
// argv[0]=runtime(bun), argv[1]=pi binary 路径;flag 从 argv[2] 起
|
|
65
|
+
const flagArgs = argv.length > ARGV_FLAG_START ? argv.slice(ARGV_FLAG_START) : [];
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < flagArgs.length; i++) {
|
|
68
|
+
const tok = flagArgs[i];
|
|
69
|
+
if (tok === "--no-extensions" || tok === "-ne") {
|
|
70
|
+
hasNoExtensions = true;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (tok === "--approve" || tok === "-a") {
|
|
74
|
+
hasApprove = true;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (tok === "--no-context-files" || tok === "-nc") {
|
|
78
|
+
hasNoContextFiles = true;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// 等号形式 --extension=path / -e=path
|
|
82
|
+
const eqMatch = /^(--extension|-e)=(.*)$/.exec(tok);
|
|
83
|
+
if (eqMatch) {
|
|
84
|
+
const val = eqMatch[2];
|
|
85
|
+
if (val) extensionPaths.push(val);
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
// 空格形式 --extension <path> / -e <path>:值在下一个 token
|
|
89
|
+
// [MF-7a] flag 判定收窄为 startsWith("--"):守卫原为 !startsWith("-"),把以单个
|
|
90
|
+
// - 开头的合法路径(如相对路径 -weird-dir/x.md)误判为 flag 跳过——extension 路径
|
|
91
|
+
// 静默丢失。pi CLI 的多字符长 flag 一律 -- 前缀,单 - 只接单字符短 flag(-e 本身),
|
|
92
|
+
// 故「-- 开头才算 flag」不误吃真 flag 且放行 - 开头路径。
|
|
93
|
+
if (tok === "--extension" || tok === "-e") {
|
|
94
|
+
const next = flagArgs[i + 1];
|
|
95
|
+
if (next !== undefined && !next.startsWith("--") && next.length > 0) {
|
|
96
|
+
extensionPaths.push(next);
|
|
97
|
+
i++; // 跳过值
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
// 其他有值 flag:跳过其值,避免误吃(如 --skill /a 的 /a)
|
|
102
|
+
if (VALUED_FLAGS.has(tok)) {
|
|
103
|
+
i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
// 其他情况(未知 flag、--flag=val 形式、positional)忽略
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const result = { noExtensions: hasNoExtensions, approve: hasApprove, extensionPaths, noContextFiles: hasNoContextFiles };
|
|
110
|
+
memoArgv = argv;
|
|
111
|
+
memoResult = result;
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// src/utils/best-effort.ts
|
|
2
|
+
//
|
|
3
|
+
// best-effort IO 清理的错误吞咽 helper。
|
|
4
|
+
//
|
|
5
|
+
// 用途:sidecar 写入 / worktree remove / alive marker 删除等次要 IO,失败不影响
|
|
6
|
+
// 主流程(session 已完成或正在收尾)。这类 catch 故意吞错——但 taste/no-silent-catch
|
|
7
|
+
// 规则禁止空 catch 或仅 console 的 catch。本 helper 提供一条「实质调用语句」让
|
|
8
|
+
// catch 合规,同时把错误记录到 debug/error 便于排查。
|
|
9
|
+
//
|
|
10
|
+
// 规则绕过原理:taste/no-silent-catch 仅检查 CatchClause 直接 body 是否为空或仅
|
|
11
|
+
// console 调用。本 helper 是普通函数调用(ExpressionStatement),既非空也非仅
|
|
12
|
+
// console,故合规。helper 函数体内部经共享 logger 路由(不裸 console)。
|
|
13
|
+
|
|
14
|
+
import { getLogger } from "../core/logger.ts";
|
|
15
|
+
|
|
16
|
+
const logger = getLogger("subagents");
|
|
17
|
+
|
|
18
|
+
/** 错误日志级别。debug = 次要清理(默认);error = 关键步骤但需继续后续清理。 */
|
|
19
|
+
export type BestEffortLevel = "debug" | "error";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 吞咽 best-effort IO 的错误,按 level 经共享 logger 记录。
|
|
23
|
+
*
|
|
24
|
+
* - debug(默认):次要清理(sidecar/worktree/alive marker),失败属预期路径
|
|
25
|
+
* - error:关键步骤抛错但需继续后续清理(如 finalizeRecord 的 B9 链:completeRecord
|
|
26
|
+
* 抛错后仍要执行 finalized/cleanup,错误需可见但不阻断)
|
|
27
|
+
*
|
|
28
|
+
* 错误对象优先取 message(避免打印巨大堆栈/对象),其他类型原样传入。
|
|
29
|
+
*/
|
|
30
|
+
export function bestEffort(err: unknown, context: string, level: BestEffortLevel = "debug"): void {
|
|
31
|
+
const detail = err instanceof Error ? err.message : err;
|
|
32
|
+
const msg = `[subagents] best-effort ${context} failed`;
|
|
33
|
+
if (level === "error") {
|
|
34
|
+
logger.error(msg, { detail });
|
|
35
|
+
} else {
|
|
36
|
+
logger.debug(msg, { detail });
|
|
37
|
+
}
|
|
38
|
+
}
|