@caupulican/pi-adaptative 0.81.39 → 0.81.40
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/CHANGELOG.md +52 -0
- package/README.md +2 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +2 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +2 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +3 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +9 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +290 -107
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +357 -122
- package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +2 -2
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +9 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-directory-layout.d.ts +15 -0
- package/dist/core/agent-directory-layout.d.ts.map +1 -0
- package/dist/core/agent-directory-layout.js +72 -0
- package/dist/core/agent-directory-layout.js.map +1 -0
- package/dist/core/agent-paths.d.ts +19 -2
- package/dist/core/agent-paths.d.ts.map +1 -1
- package/dist/core/agent-paths.js +67 -4
- package/dist/core/agent-paths.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +52 -8
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +397 -79
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -0
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +71 -136
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +477 -1318
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/approval-gate.d.ts +3 -2
- package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
- package/dist/core/autonomy/approval-gate.js +6 -28
- package/dist/core/autonomy/approval-gate.js.map +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
- package/dist/core/autonomy/bounded-completion.js +1 -1
- package/dist/core/autonomy/bounded-completion.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +20 -12
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
- package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
- package/dist/core/autonomy/foreground-envelope.js +8 -25
- package/dist/core/autonomy/foreground-envelope.js.map +1 -1
- package/dist/core/autonomy/gates.d.ts.map +1 -1
- package/dist/core/autonomy/gates.js +8 -10
- package/dist/core/autonomy/gates.js.map +1 -1
- package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
- package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
- package/dist/core/autonomy/lane-private-paths.js +16 -0
- package/dist/core/autonomy/lane-private-paths.js.map +1 -0
- package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
- package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tool-surface.js +46 -8
- package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
- package/dist/core/autonomy/lane-tracker.d.ts +14 -0
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +38 -0
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/autonomy/risk-assessment.d.ts +1 -2
- package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
- package/dist/core/autonomy/risk-assessment.js +1 -123
- package/dist/core/autonomy/risk-assessment.js.map +1 -1
- package/dist/core/autonomy/session-lane-record.d.ts +4 -4
- package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
- package/dist/core/autonomy/session-lane-record.js +16 -29
- package/dist/core/autonomy/session-lane-record.js.map +1 -1
- package/dist/core/autonomy/telemetry-events.d.ts +1 -1
- package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
- package/dist/core/autonomy/telemetry-events.js +1 -1
- package/dist/core/autonomy/telemetry-events.js.map +1 -1
- package/dist/core/autonomy-telemetry.d.ts +7 -7
- package/dist/core/autonomy-telemetry.d.ts.map +1 -1
- package/dist/core/autonomy-telemetry.js +9 -9
- package/dist/core/autonomy-telemetry.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +54 -236
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +140 -1273
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/capability-contract.d.ts +4 -0
- package/dist/core/capability-contract.d.ts.map +1 -0
- package/dist/core/capability-contract.js +28 -0
- package/dist/core/capability-contract.js.map +1 -0
- package/dist/core/compaction-controller.d.ts +90 -0
- package/dist/core/compaction-controller.d.ts.map +1 -0
- package/dist/core/compaction-controller.js +452 -0
- package/dist/core/compaction-controller.js.map +1 -0
- package/dist/core/compaction-support.d.ts +12 -11
- package/dist/core/compaction-support.d.ts.map +1 -1
- package/dist/core/compaction-support.js.map +1 -1
- package/dist/core/context/context-artifacts.d.ts +6 -2
- package/dist/core/context/context-artifacts.d.ts.map +1 -1
- package/dist/core/context/context-artifacts.js +34 -2
- package/dist/core/context/context-artifacts.js.map +1 -1
- package/dist/core/context/context-store-retention.d.ts +8 -2
- package/dist/core/context/context-store-retention.d.ts.map +1 -1
- package/dist/core/context/context-store-retention.js +158 -35
- package/dist/core/context/context-store-retention.js.map +1 -1
- package/dist/core/context/okf-memory.d.ts.map +1 -1
- package/dist/core/context/okf-memory.js +9 -11
- package/dist/core/context/okf-memory.js.map +1 -1
- package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
- package/dist/core/context/sqlite-runtime-index.js +6 -8
- package/dist/core/context/sqlite-runtime-index.js.map +1 -1
- package/dist/core/context-gc.d.ts +3 -0
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +10 -5
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +9 -4
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/default-tool-surface.d.ts.map +1 -1
- package/dist/core/default-tool-surface.js +1 -0
- package/dist/core/default-tool-surface.js.map +1 -1
- package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
- package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
- package/dist/core/delegation/managed-lane-controller.js +217 -0
- package/dist/core/delegation/managed-lane-controller.js.map +1 -0
- package/dist/core/delegation/session-worker-claim.d.ts +44 -0
- package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
- package/dist/core/delegation/session-worker-claim.js +98 -0
- package/dist/core/delegation/session-worker-claim.js.map +1 -0
- package/dist/core/delegation/worker-actions.d.ts +7 -5
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +20 -4
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
- package/dist/core/delegation/worker-claim.d.ts.map +1 -0
- package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
- package/dist/core/delegation/worker-claim.js.map +1 -0
- package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
- package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
- package/dist/core/delegation/worker-delegation-controller.js +861 -0
- package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
- package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
- package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
- package/dist/core/delegation/worker-delegation-request.js +2 -0
- package/dist/core/delegation/worker-delegation-request.js.map +1 -0
- package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
- package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
- package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
- package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
- package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
- package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
- package/dist/core/delegation/worker-execution-policy.js +160 -0
- package/dist/core/delegation/worker-execution-policy.js.map +1 -0
- package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
- package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
- package/dist/core/delegation/worker-lane-projection.js +100 -0
- package/dist/core/delegation/worker-lane-projection.js.map +1 -0
- package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
- package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
- package/dist/core/delegation/worker-lifecycle.js +339 -0
- package/dist/core/delegation/worker-lifecycle.js.map +1 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
- package/dist/core/delegation/worker-notification-coordinator.js +90 -0
- package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
- package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
- package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
- package/dist/core/delegation/worker-profile-resolver.js +113 -0
- package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
- package/dist/core/delegation/worker-runner.d.ts +25 -14
- package/dist/core/delegation/worker-runner.d.ts.map +1 -1
- package/dist/core/delegation/worker-runner.js +122 -53
- package/dist/core/delegation/worker-runner.js.map +1 -1
- package/dist/core/delegation/worker-task-label.d.ts +3 -0
- package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
- package/dist/core/delegation/worker-task-label.js +11 -0
- package/dist/core/delegation/worker-task-label.js.map +1 -0
- package/dist/core/doctor.d.ts +8 -0
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +32 -1
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +5 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +50 -15
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/storage.d.ts +8 -0
- package/dist/core/extensions/storage.d.ts.map +1 -0
- package/dist/core/extensions/storage.js +28 -0
- package/dist/core/extensions/storage.js.map +1 -0
- package/dist/core/extensions/types.d.ts +70 -21
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/failure-corpus.d.ts +1 -15
- package/dist/core/failure-corpus.d.ts.map +1 -1
- package/dist/core/failure-corpus.js +9 -37
- package/dist/core/failure-corpus.js.map +1 -1
- package/dist/core/foreground-recovery-controller.d.ts +52 -0
- package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
- package/dist/core/foreground-recovery-controller.js +111 -0
- package/dist/core/foreground-recovery-controller.js.map +1 -0
- package/dist/core/gateways/channel-provider.d.ts +3 -0
- package/dist/core/gateways/channel-provider.d.ts.map +1 -1
- package/dist/core/gateways/channel-provider.js +31 -6
- package/dist/core/gateways/channel-provider.js.map +1 -1
- package/dist/core/goals/goal-acceptance.d.ts +11 -0
- package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
- package/dist/core/goals/goal-acceptance.js +25 -0
- package/dist/core/goals/goal-acceptance.js.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts +27 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.js +93 -0
- package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
- package/dist/core/goals/goal-continuation-controller.d.ts +1 -1
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-controller.js +10 -0
- package/dist/core/goals/goal-continuation-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +6 -6
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/goals/goal-lifecycle.d.ts +20 -0
- package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
- package/dist/core/goals/goal-lifecycle.js +17 -0
- package/dist/core/goals/goal-lifecycle.js.map +1 -0
- package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js +10 -8
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/goal-state.d.ts +1 -0
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +7 -10
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +8 -6
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +11 -41
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +2 -4
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js +10 -33
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/human-input.d.ts +100 -0
- package/dist/core/human-input.d.ts.map +1 -0
- package/dist/core/human-input.js +362 -0
- package/dist/core/human-input.js.map +1 -0
- package/dist/core/index.d.ts +9 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
- package/dist/core/install-telemetry.d.ts.map +1 -0
- package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
- package/dist/core/install-telemetry.js.map +1 -0
- package/dist/core/keybindings.d.ts +17 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +24 -6
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/learning/learning-audit.d.ts +2 -4
- package/dist/core/learning/learning-audit.d.ts.map +1 -1
- package/dist/core/learning/learning-audit.js +9 -29
- package/dist/core/learning/learning-audit.js.map +1 -1
- package/dist/core/learning/learning-gate.d.ts.map +1 -1
- package/dist/core/learning/learning-gate.js +1 -6
- package/dist/core/learning/learning-gate.js.map +1 -1
- package/dist/core/learning/session-learning-decision.d.ts +2 -4
- package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
- package/dist/core/learning/session-learning-decision.js +9 -29
- package/dist/core/learning/session-learning-decision.js.map +1 -1
- package/dist/core/memory-controller.d.ts.map +1 -1
- package/dist/core/memory-controller.js +4 -4
- package/dist/core/memory-controller.js.map +1 -1
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +1 -0
- package/dist/core/model-capability.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +6 -9
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-router/intent-classifier.d.ts +1 -4
- package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
- package/dist/core/model-router/intent-classifier.js +1 -156
- package/dist/core/model-router/intent-classifier.js.map +1 -1
- package/dist/core/model-router-controller.d.ts.map +1 -1
- package/dist/core/model-router-controller.js +2 -2
- package/dist/core/model-router-controller.js.map +1 -1
- package/dist/core/model-selection-controller.d.ts +4 -4
- package/dist/core/model-selection-controller.d.ts.map +1 -1
- package/dist/core/model-selection-controller.js.map +1 -1
- package/dist/core/model-tool-protocol.d.ts +23 -0
- package/dist/core/model-tool-protocol.d.ts.map +1 -0
- package/dist/core/model-tool-protocol.js +43 -0
- package/dist/core/model-tool-protocol.js.map +1 -0
- package/dist/core/models/adaptation-store.d.ts +4 -6
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +95 -83
- package/dist/core/models/adaptation-store.js.map +1 -1
- package/dist/core/models/fitness-store.d.ts +2 -12
- package/dist/core/models/fitness-store.d.ts.map +1 -1
- package/dist/core/models/fitness-store.js +84 -57
- package/dist/core/models/fitness-store.js.map +1 -1
- package/dist/core/models/host-state-store.d.ts +34 -0
- package/dist/core/models/host-state-store.d.ts.map +1 -0
- package/dist/core/models/host-state-store.js +86 -0
- package/dist/core/models/host-state-store.js.map +1 -0
- package/dist/core/orchestration/agent-resume.d.ts +24 -0
- package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
- package/dist/core/orchestration/agent-resume.js +90 -0
- package/dist/core/orchestration/agent-resume.js.map +1 -0
- package/dist/core/orchestration/capability-gateway.d.ts +61 -0
- package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
- package/dist/core/orchestration/capability-gateway.js +152 -0
- package/dist/core/orchestration/capability-gateway.js.map +1 -0
- package/dist/core/orchestration/contracts.d.ts +343 -0
- package/dist/core/orchestration/contracts.d.ts.map +1 -0
- package/dist/core/orchestration/contracts.js +135 -0
- package/dist/core/orchestration/contracts.js.map +1 -0
- package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
- package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
- package/dist/core/orchestration/delegation-ledger.js +197 -0
- package/dist/core/orchestration/delegation-ledger.js.map +1 -0
- package/dist/core/orchestration/event-store.d.ts +83 -0
- package/dist/core/orchestration/event-store.d.ts.map +1 -0
- package/dist/core/orchestration/event-store.js +560 -0
- package/dist/core/orchestration/event-store.js.map +1 -0
- package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
- package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
- package/dist/core/orchestration/lane-tool-manifests.js +37 -0
- package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
- package/dist/core/orchestration/model-binding.d.ts +15 -0
- package/dist/core/orchestration/model-binding.d.ts.map +1 -0
- package/dist/core/orchestration/model-binding.js +29 -0
- package/dist/core/orchestration/model-binding.js.map +1 -0
- package/dist/core/orchestration/policy-compiler.d.ts +49 -0
- package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
- package/dist/core/orchestration/policy-compiler.js +191 -0
- package/dist/core/orchestration/policy-compiler.js.map +1 -0
- package/dist/core/orchestration/policy-gate.d.ts +18 -0
- package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
- package/dist/core/orchestration/policy-gate.js +24 -0
- package/dist/core/orchestration/policy-gate.js.map +1 -0
- package/dist/core/orchestration/profile-registry.d.ts +51 -0
- package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
- package/dist/core/orchestration/profile-registry.js +393 -0
- package/dist/core/orchestration/profile-registry.js.map +1 -0
- package/dist/core/orchestration/profile-store.d.ts +31 -0
- package/dist/core/orchestration/profile-store.d.ts.map +1 -0
- package/dist/core/orchestration/profile-store.js +136 -0
- package/dist/core/orchestration/profile-store.js.map +1 -0
- package/dist/core/orchestration/risk-budget.d.ts +9 -0
- package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
- package/dist/core/orchestration/risk-budget.js +48 -0
- package/dist/core/orchestration/risk-budget.js.map +1 -0
- package/dist/core/orchestration/task-runtime.d.ts +168 -0
- package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
- package/dist/core/orchestration/task-runtime.js +1600 -0
- package/dist/core/orchestration/task-runtime.js.map +1 -0
- package/dist/core/orchestration/work-state-projection.d.ts +32 -0
- package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
- package/dist/core/orchestration/work-state-projection.js +116 -0
- package/dist/core/orchestration/work-state-projection.js.map +1 -0
- package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
- package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
- package/dist/core/orchestration/worker-execution-contract.js +179 -0
- package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
- package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
- package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
- package/dist/core/orchestration/worker-result-adapter.js +109 -0
- package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
- package/dist/core/process-identity.d.ts +11 -0
- package/dist/core/process-identity.d.ts.map +1 -0
- package/dist/core/process-identity.js +26 -0
- package/dist/core/process-identity.js.map +1 -0
- package/dist/core/process-matrix/codes.d.ts +14 -3
- package/dist/core/process-matrix/codes.d.ts.map +1 -1
- package/dist/core/process-matrix/codes.js.map +1 -1
- package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
- package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
- package/dist/core/process-matrix/resume-launcher.js +62 -0
- package/dist/core/process-matrix/resume-launcher.js.map +1 -0
- package/dist/core/process-matrix/runtime.d.ts +37 -22
- package/dist/core/process-matrix/runtime.d.ts.map +1 -1
- package/dist/core/process-matrix/runtime.js +399 -76
- package/dist/core/process-matrix/runtime.js.map +1 -1
- package/dist/core/process-matrix/store.d.ts +5 -2
- package/dist/core/process-matrix/store.d.ts.map +1 -1
- package/dist/core/process-matrix/store.js +123 -14
- package/dist/core/process-matrix/store.js.map +1 -1
- package/dist/core/process-matrix/supervisor.d.ts +10 -7
- package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
- package/dist/core/process-matrix/supervisor.js +45 -14
- package/dist/core/process-matrix/supervisor.js.map +1 -1
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +6 -8
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +4 -4
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +2 -1
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/reload-blockers.d.ts.map +1 -1
- package/dist/core/reload-blockers.js +6 -8
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/research/evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/evidence-bundle.js +1 -6
- package/dist/core/research/evidence-bundle.js.map +1 -1
- package/dist/core/research/lane-model-resolver.d.ts +33 -0
- package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
- package/dist/core/research/lane-model-resolver.js +65 -0
- package/dist/core/research/lane-model-resolver.js.map +1 -0
- package/dist/core/research/model-fitness-controller.d.ts +38 -0
- package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
- package/dist/core/research/model-fitness-controller.js +106 -0
- package/dist/core/research/model-fitness-controller.js.map +1 -0
- package/dist/core/research/model-fitness.d.ts +1 -1
- package/dist/core/research/model-fitness.d.ts.map +1 -1
- package/dist/core/research/model-fitness.js +4 -4
- package/dist/core/research/model-fitness.js.map +1 -1
- package/dist/core/research/research-gate.d.ts.map +1 -1
- package/dist/core/research/research-gate.js +7 -7
- package/dist/core/research/research-gate.js.map +1 -1
- package/dist/core/research/research-lane-controller.d.ts +62 -0
- package/dist/core/research/research-lane-controller.d.ts.map +1 -0
- package/dist/core/research/research-lane-controller.js +292 -0
- package/dist/core/research/research-lane-controller.js.map +1 -0
- package/dist/core/research/session-evidence-bundle.d.ts +2 -4
- package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
- package/dist/core/research/session-evidence-bundle.js +10 -46
- package/dist/core/research/session-evidence-bundle.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +7 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/risk-classifier.d.ts +6 -0
- package/dist/core/risk-classifier.d.ts.map +1 -0
- package/dist/core/risk-classifier.js +225 -0
- package/dist/core/risk-classifier.js.map +1 -0
- package/dist/core/runtime-builder.d.ts +26 -20
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +237 -178
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/sdk.d.ts +6 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +61 -24
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-analytics.d.ts.map +1 -1
- package/dist/core/session-analytics.js +28 -1
- package/dist/core/session-analytics.js.map +1 -1
- package/dist/core/session-image-store.d.ts +33 -0
- package/dist/core/session-image-store.d.ts.map +1 -0
- package/dist/core/session-image-store.js +283 -0
- package/dist/core/session-image-store.js.map +1 -0
- package/dist/core/session-role.d.ts +6 -4
- package/dist/core/session-role.d.ts.map +1 -1
- package/dist/core/session-role.js +10 -4
- package/dist/core/session-role.js.map +1 -1
- package/dist/core/session-snapshot.d.ts +34 -0
- package/dist/core/session-snapshot.d.ts.map +1 -0
- package/dist/core/session-snapshot.js +68 -0
- package/dist/core/session-snapshot.js.map +1 -0
- package/dist/core/session-supervision-runtime.d.ts +31 -0
- package/dist/core/session-supervision-runtime.d.ts.map +1 -0
- package/dist/core/session-supervision-runtime.js +97 -0
- package/dist/core/session-supervision-runtime.js.map +1 -0
- package/dist/core/settings-manager.d.ts +9 -4
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +80 -28
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tasks/session-task-state.d.ts +2 -4
- package/dist/core/tasks/session-task-state.d.ts.map +1 -1
- package/dist/core/tasks/session-task-state.js +10 -28
- package/dist/core/tasks/session-task-state.js.map +1 -1
- package/dist/core/tasks/task-projection.d.ts +20 -0
- package/dist/core/tasks/task-projection.d.ts.map +1 -0
- package/dist/core/tasks/task-projection.js +47 -0
- package/dist/core/tasks/task-projection.js.map +1 -0
- package/dist/core/tasks/task-state.d.ts +4 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -1
- package/dist/core/tasks/task-state.js +28 -11
- package/dist/core/tasks/task-state.js.map +1 -1
- package/dist/core/tool-capability-policy.d.ts +13 -0
- package/dist/core/tool-capability-policy.d.ts.map +1 -0
- package/dist/core/tool-capability-policy.js +85 -0
- package/dist/core/tool-capability-policy.js.map +1 -0
- package/dist/core/tool-protocol-controller.d.ts +91 -0
- package/dist/core/tool-protocol-controller.d.ts.map +1 -0
- package/dist/core/tool-protocol-controller.js +512 -0
- package/dist/core/tool-protocol-controller.js.map +1 -0
- package/dist/core/tool-recovery-log-records.d.ts +2 -3
- package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
- package/dist/core/tool-recovery-log-records.js +9 -35
- package/dist/core/tool-recovery-log-records.js.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
- package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.js +97 -138
- package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
- package/dist/core/tools/ask-question.d.ts +124 -0
- package/dist/core/tools/ask-question.d.ts.map +1 -0
- package/dist/core/tools/ask-question.js +693 -0
- package/dist/core/tools/ask-question.js.map +1 -0
- package/dist/core/tools/delegate-status.d.ts +31 -3
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +149 -29
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +15 -13
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +108 -23
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/extensionify.d.ts.map +1 -1
- package/dist/core/tools/extensionify.js +1 -0
- package/dist/core/tools/extensionify.js.map +1 -1
- package/dist/core/tools/goal.d.ts +5 -5
- package/dist/core/tools/goal.d.ts.map +1 -1
- package/dist/core/tools/goal.js +10 -10
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/core/tools/model-fitness.d.ts.map +1 -1
- package/dist/core/tools/model-fitness.js +2 -2
- package/dist/core/tools/model-fitness.js.map +1 -1
- package/dist/core/tools/orchestration-panel.d.ts +43 -0
- package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
- package/dist/core/tools/orchestration-panel.js +168 -0
- package/dist/core/tools/orchestration-panel.js.map +1 -0
- package/dist/core/tools/run-process.d.ts +26 -0
- package/dist/core/tools/run-process.d.ts.map +1 -0
- package/dist/core/tools/run-process.js +138 -0
- package/dist/core/tools/run-process.js.map +1 -0
- package/dist/core/tools/task-steps.d.ts +2 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -1
- package/dist/core/tools/task-steps.js +102 -0
- package/dist/core/tools/task-steps.js.map +1 -1
- package/dist/core/tools/tmux-dispatch.d.ts +3 -5
- package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
- package/dist/core/tools/tmux-dispatch.js +4 -4
- package/dist/core/tools/tmux-dispatch.js.map +1 -1
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
- package/dist/core/tools/windows-shell-engine.js +4 -6
- package/dist/core/tools/windows-shell-engine.js.map +1 -1
- package/dist/core/util/bounded-jsonl.d.ts +10 -0
- package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
- package/dist/core/util/bounded-jsonl.js +75 -0
- package/dist/core/util/bounded-jsonl.js.map +1 -0
- package/dist/core/util/value-guards.d.ts +5 -0
- package/dist/core/util/value-guards.d.ts.map +1 -0
- package/dist/core/util/value-guards.js +12 -0
- package/dist/core/util/value-guards.js.map +1 -0
- package/dist/core/worktree-sync/store.d.ts +3 -3
- package/dist/core/worktree-sync/store.d.ts.map +1 -1
- package/dist/core/worktree-sync/store.js +10 -5
- package/dist/core/worktree-sync/store.js.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +128 -44
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +4 -6
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +186 -28
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/clipboard-input.d.ts +7 -1
- package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
- package/dist/modes/interactive/clipboard-input.js +44 -6
- package/dist/modes/interactive/clipboard-input.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +2 -2
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/config-backup.d.ts.map +1 -1
- package/dist/modes/interactive/config-backup.js +5 -4
- package/dist/modes/interactive/config-backup.js.map +1 -1
- package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
- package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
- package/dist/modes/interactive/extension-ui-host.js +76 -15
- package/dist/modes/interactive/extension-ui-host.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +63 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/key-handlers.js +1 -1
- package/dist/modes/interactive/key-handlers.js.map +1 -1
- package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
- package/dist/modes/interactive/profile-menu-controller.js +7 -7
- package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
- package/dist/modes/interactive/report-commands.d.ts.map +1 -1
- package/dist/modes/interactive/report-commands.js +21 -0
- package/dist/modes/interactive/report-commands.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts +17 -2
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +50 -17
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-io-commands.js +16 -6
- package/dist/modes/interactive/session-io-commands.js.map +1 -1
- package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
- package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
- package/dist/modes/interactive/session-replacement-errors.js +15 -0
- package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
- package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
- package/dist/modes/interactive/startup-checks.js +1 -1
- package/dist/modes/interactive/startup-checks.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +82 -23
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +15 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js +138 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +2 -13
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard-native.d.ts +1 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -1
- package/dist/utils/clipboard-native.js.map +1 -1
- package/dist/utils/clipboard.d.ts +1 -0
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +52 -1
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/platform.d.ts +3 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +8 -0
- package/dist/utils/platform.js.map +1 -0
- package/dist/utils/work-directory.d.ts +11 -0
- package/dist/utils/work-directory.d.ts.map +1 -1
- package/dist/utils/work-directory.js +30 -9
- package/dist/utils/work-directory.js.map +1 -1
- package/docs/UI_POLISH_ORCHESTRATION.md +44 -0
- package/docs/UI_QUALITY_ORCHESTRATION.md +30 -0
- package/docs/docs.json +4 -0
- package/docs/extensions.md +62 -2
- package/docs/harness-architecture.md +156 -0
- package/docs/keybindings.md +11 -1
- package/docs/process-matrix.md +59 -26
- package/docs/rpc.md +45 -2
- package/docs/sessions.md +15 -0
- package/docs/settings.md +125 -11
- package/docs/task-steps.md +8 -0
- package/docs/telemetry.md +19 -0
- package/docs/tmux-agent-manager.md +10 -3
- package/docs/ui-reference/README.md +9 -0
- package/docs/ui-reference/orchestration-after.txt +7 -0
- package/docs/ui-reference/orchestration-before.txt +7 -0
- package/docs/ui-reference/orchestration-reference.txt +6 -0
- package/docs/usage.md +14 -2
- package/docs/work-directory.md +19 -8
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/question.ts +34 -245
- package/examples/extensions/questionnaire.ts +41 -407
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
- package/dist/core/delegation/session-worker-result.d.ts +0 -46
- package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
- package/dist/core/delegation/session-worker-result.js +0 -113
- package/dist/core/delegation/session-worker-result.js.map +0 -1
- package/dist/core/delegation/worker-result.d.ts.map +0 -1
- package/dist/core/delegation/worker-result.js.map +0 -1
- package/dist/core/telemetry.d.ts.map +0 -1
- package/dist/core/telemetry.js.map +0 -1
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import type { CapabilityEnvelope, GateOutcome,
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function
|
|
4
|
-
export declare function requiresParentReview(
|
|
1
|
+
import type { CapabilityEnvelope, GateOutcome, WorkerClaim, WorkerRequest } from "../autonomy/contracts.ts";
|
|
2
|
+
export declare function cloneWorkerClaimForStorage(claim: WorkerClaim): WorkerClaim;
|
|
3
|
+
export declare function isWorkerClaim(value: unknown): value is WorkerClaim;
|
|
4
|
+
export declare function requiresParentReview(claim: WorkerClaim): boolean;
|
|
5
5
|
/**
|
|
6
|
-
* True iff {@link
|
|
6
|
+
* True iff {@link validateWorkerClaim}'s gate would flag this claim "ask-user" /
|
|
7
7
|
* "parent_review_required" (the two branches at :110 and :178 below) — an otherwise-completed
|
|
8
|
-
*
|
|
9
|
-
* that passed path-scope validation. Reuses `
|
|
8
|
+
* claim the parent must explicitly look at because it reports blockers, or reports file mutations
|
|
9
|
+
* that passed path-scope validation. Reuses `validateWorkerClaim` itself rather than a
|
|
10
10
|
* separately-maintained heuristic, so a persisted review marker can never drift from the
|
|
11
11
|
* gate's actual verdict.
|
|
12
12
|
*/
|
|
13
13
|
export declare function isParentReviewRequired(args: {
|
|
14
14
|
request: WorkerRequest;
|
|
15
|
-
|
|
15
|
+
claim: WorkerClaim;
|
|
16
16
|
cwd?: string;
|
|
17
17
|
}): boolean;
|
|
18
|
-
export declare function
|
|
18
|
+
export declare function validateWorkerClaim(args: {
|
|
19
19
|
request: WorkerRequest;
|
|
20
|
-
|
|
20
|
+
claim: WorkerClaim;
|
|
21
21
|
/**
|
|
22
22
|
* Baseline for relative paths — BOTH the runner's cwd-relative `changedFiles` and the
|
|
23
23
|
* envelope's possibly-relative path scopes resolve against this. Defaults to process.cwd()
|
|
@@ -30,8 +30,8 @@ export declare function validateWorkerResult(args: {
|
|
|
30
30
|
* -- e.g. a tmux worker's own completion report, which (unlike an in-process worker's) never
|
|
31
31
|
* passed through this process's `applyWorkerActions` envelope enforcement before the write
|
|
32
32
|
* happened; the tmux worker's tool loop runs in a separate process this session does not gate.
|
|
33
|
-
* Reuses {@link
|
|
34
|
-
* reimplement path resolution: synthesizes a minimal, always-"completed" request/
|
|
33
|
+
* Reuses {@link validateWorkerClaim}'s exact symlink-safe scope check verbatim -- never
|
|
34
|
+
* reimplement path resolution: synthesizes a minimal, always-"completed" request/claim pair
|
|
35
35
|
* carrying only the reported `changedFiles` and the scope's `allowedPaths`/`deniedPaths`, so the
|
|
36
36
|
* ONLY thing that can vary the verdict is the path-scope branch.
|
|
37
37
|
*
|
|
@@ -53,4 +53,4 @@ export declare function reviewManagedLaneChangedFiles(args: {
|
|
|
53
53
|
reviewRequired: boolean;
|
|
54
54
|
reasonCode: string;
|
|
55
55
|
};
|
|
56
|
-
//# sourceMappingURL=worker-
|
|
56
|
+
//# sourceMappingURL=worker-claim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-claim.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-claim.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK5G,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,WAAW,GAAG,WAAW,CAW1E;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAyClE;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAWhE;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAGlH;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACzC,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,WAAW,CAAC;IACnB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,GAAG,WAAW,CAmHd;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IACnD,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;+FAC2F;IAC3F,QAAQ,EAAE,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,aAAa,CAAC,CAAC;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,GAAG;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAiClD","sourcesContent":["import path from \"node:path\";\nimport type { CapabilityEnvelope, GateOutcome, WorkerClaim, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport { checkPathScope } from \"../autonomy/path-scope.ts\";\nimport { cloneEvidenceBundleForStorage, isEvidenceBundle } from \"../research/evidence-bundle.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\n\nexport function cloneWorkerClaimForStorage(claim: WorkerClaim): WorkerClaim {\n\treturn {\n\t\t...claim,\n\t\t...(claim.outputFormat ? { outputFormat: claim.outputFormat } : {}),\n\t\tchangedFiles: [...claim.changedFiles],\n\t\tblockers: claim.blockers ? [...claim.blockers] : undefined,\n\t\tevidence: claim.evidence ? cloneEvidenceBundleForStorage(claim.evidence) : undefined,\n\t\tverification: claim.verification\n\t\t\t? { ...claim.verification, reasonCodes: [...claim.verification.reasonCodes] }\n\t\t\t: undefined,\n\t};\n}\n\nexport function isWorkerClaim(value: unknown): value is WorkerClaim {\n\tif (!isPlainRecord(value)) return false;\n\tconst obj = value as Record<string, unknown>;\n\n\tif (typeof obj.requestId !== \"string\") return false;\n\tif (typeof obj.status !== \"string\" || ![\"completed\", \"blocked\", \"failed\", \"cancelled\"].includes(obj.status)) {\n\t\treturn false;\n\t}\n\tif (typeof obj.summary !== \"string\") return false;\n\tif (obj.outputFormat !== undefined && obj.outputFormat !== \"structured\" && obj.outputFormat !== \"plain_text\")\n\t\treturn false;\n\n\tif (!Array.isArray(obj.changedFiles) || !obj.changedFiles.every((f) => typeof f === \"string\")) {\n\t\treturn false;\n\t}\n\n\tif (obj.blockers !== undefined) {\n\t\tif (!Array.isArray(obj.blockers) || !obj.blockers.every((b) => typeof b === \"string\")) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (obj.usageReportId !== undefined && typeof obj.usageReportId !== \"string\") return false;\n\tif (obj.createdAt !== undefined && typeof obj.createdAt !== \"string\") return false;\n\tif (obj.parentReviewRequired !== undefined && typeof obj.parentReviewRequired !== \"boolean\") return false;\n\tif (obj.parentReviewedAt !== undefined && typeof obj.parentReviewedAt !== \"string\") return false;\n\tif (obj.verification !== undefined) {\n\t\tif (!isPlainRecord(obj.verification)) return false;\n\t\tif (typeof obj.verification.subjectTaskId !== \"string\" || !obj.verification.subjectTaskId) return false;\n\t\tif (obj.verification.verdict !== \"accepted\" && obj.verification.verdict !== \"rejected\") return false;\n\t\tif (\n\t\t\t!Array.isArray(obj.verification.reasonCodes) ||\n\t\t\t!obj.verification.reasonCodes.every((reasonCode) => typeof reasonCode === \"string\" && reasonCode.length > 0)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (obj.evidence !== undefined && !isEvidenceBundle(obj.evidence)) return false;\n\n\treturn true;\n}\n\nexport function requiresParentReview(claim: WorkerClaim): boolean {\n\tif (claim.status !== \"completed\") {\n\t\treturn true;\n\t}\n\tif (claim.blockers && claim.blockers.length > 0) {\n\t\treturn true;\n\t}\n\tif (claim.changedFiles.length > 0) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * True iff {@link validateWorkerClaim}'s gate would flag this claim \"ask-user\" /\n * \"parent_review_required\" (the two branches at :110 and :178 below) — an otherwise-completed\n * claim the parent must explicitly look at because it reports blockers, or reports file mutations\n * that passed path-scope validation. Reuses `validateWorkerClaim` itself rather than a\n * separately-maintained heuristic, so a persisted review marker can never drift from the\n * gate's actual verdict.\n */\nexport function isParentReviewRequired(args: { request: WorkerRequest; claim: WorkerClaim; cwd?: string }): boolean {\n\tconst acceptance = validateWorkerClaim(args);\n\treturn acceptance.outcome === \"ask-user\" && acceptance.reasonCode === \"parent_review_required\";\n}\n\nexport function validateWorkerClaim(args: {\n\trequest: WorkerRequest;\n\tclaim: WorkerClaim;\n\t/**\n\t * Baseline for relative paths — BOTH the runner's cwd-relative `changedFiles` and the\n\t * envelope's possibly-relative path scopes resolve against this. Defaults to process.cwd()\n\t * for callers whose session cwd is the process cwd.\n\t */\n\tcwd?: string;\n}): GateOutcome {\n\tconst { request, claim } = args;\n\tconst baseDir = args.cwd ?? process.cwd();\n\n\tif (claim.requestId !== request.id) {\n\t\treturn {\n\t\t\toutcome: \"block\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"request_id_mismatch\",\n\t\t\tmessage: `Claim requestId '${claim.requestId}' does not match request id '${request.id}'.`,\n\t\t};\n\t}\n\n\tif (claim.status !== \"completed\") {\n\t\treturn {\n\t\t\toutcome: \"block\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"worker_not_completed\",\n\t\t\tmessage: `Worker finished with status '${claim.status}'.`,\n\t\t\tdetails: claim.blockers && claim.blockers.length > 0 ? { blockers: [...claim.blockers] } : undefined,\n\t\t};\n\t}\n\n\tif (!claim.usageReportId) {\n\t\treturn {\n\t\t\toutcome: \"block\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"missing_usage_report\",\n\t\t\tmessage: \"Completed worker claim is missing usageReportId.\",\n\t\t};\n\t}\n\n\tif (claim.blockers && claim.blockers.length > 0) {\n\t\treturn {\n\t\t\toutcome: \"ask-user\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"parent_review_required\",\n\t\t\tmessage: \"Completed worker claim includes blockers and requires parent review.\",\n\t\t\tdetails: { blockers: [...claim.blockers] },\n\t\t};\n\t}\n\n\tif (claim.changedFiles.length > 0) {\n\t\tif (!request.envelope.allowedPaths || request.envelope.allowedPaths.length === 0) {\n\t\t\treturn {\n\t\t\t\toutcome: \"block\",\n\t\t\t\tgate: \"worker_claim\",\n\t\t\t\treasonCode: \"missing_path_scope\",\n\t\t\t\tmessage: \"Worker changed files but no allowedPaths are configured in the envelope.\",\n\t\t\t};\n\t\t}\n\n\t\t// The runner reports changed files relative to the session cwd — resolve file and scope\n\t\t// roots against the SAME baseline. Resolving per-root double-prefixed nested names and\n\t\t// let a denied subtree slip past the deny rule.\n\t\tconst resolvedAllowed = request.envelope.allowedPaths.map((p) => path.resolve(baseDir, p));\n\t\tconst resolvedDenied = request.envelope.deniedPaths?.map((p) => path.resolve(baseDir, p));\n\t\tfor (const changedFile of claim.changedFiles) {\n\t\t\tlet isInsideAny = false;\n\t\t\tlet isDenied = false;\n\n\t\t\tconst scopedChangedFile = path.resolve(baseDir, changedFile);\n\t\t\tfor (const root of resolvedAllowed) {\n\t\t\t\tconst decision = checkPathScope(\n\t\t\t\t\t{\n\t\t\t\t\t\troot,\n\t\t\t\t\t\tallowedPaths: resolvedAllowed,\n\t\t\t\t\t\tdeniedPaths: resolvedDenied,\n\t\t\t\t\t},\n\t\t\t\t\tscopedChangedFile,\n\t\t\t\t);\n\n\t\t\t\tif (decision.kind === \"denied\") {\n\t\t\t\t\tisDenied = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (decision.kind === \"inside\") {\n\t\t\t\t\tisInsideAny = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isDenied) {\n\t\t\t\treturn {\n\t\t\t\t\toutcome: \"block\",\n\t\t\t\t\tgate: \"worker_claim\",\n\t\t\t\t\treasonCode: \"changed_file_denied\",\n\t\t\t\t\tmessage: `Worker changed file '${changedFile}' which matches a denied path.`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!isInsideAny) {\n\t\t\t\treturn {\n\t\t\t\t\toutcome: \"block\",\n\t\t\t\t\tgate: \"worker_claim\",\n\t\t\t\t\treasonCode: \"changed_file_outside_scope\",\n\t\t\t\t\tmessage: `Worker changed file '${changedFile}' outside allowed scope.`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Files are inside scope, but worker output is untrusted\n\t\treturn {\n\t\t\toutcome: \"ask-user\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"parent_review_required\",\n\t\t\tmessage: \"Worker changed files require parent review.\",\n\t\t};\n\t}\n\n\treturn {\n\t\toutcome: \"allow\",\n\t\tgate: \"worker_claim\",\n\t\treasonCode: \"allowed\",\n\t\tmessage: \"Worker claim is read-only and allowed.\",\n\t};\n}\n\n/**\n * Path-scope-only re-review for a SELF-REPORTED (out-of-process) worker's claimed `changedFiles`\n * -- e.g. a tmux worker's own completion report, which (unlike an in-process worker's) never\n * passed through this process's `applyWorkerActions` envelope enforcement before the write\n * happened; the tmux worker's tool loop runs in a separate process this session does not gate.\n * Reuses {@link validateWorkerClaim}'s exact symlink-safe scope check verbatim -- never\n * reimplement path resolution: synthesizes a minimal, always-\"completed\" request/claim pair\n * carrying only the reported `changedFiles` and the scope's `allowedPaths`/`deniedPaths`, so the\n * ONLY thing that can vary the verdict is the path-scope branch.\n *\n * Deliberately broader than {@link isParentReviewRequired}: that helper only flags the gate's\n * \"ask-user\" branch, which is correct for an in-process worker (a write that would have been\n * \"block\"-worthy was already refused before it could happen, by the SAME envelope, via\n * `applyWorkerActions`). A self-reported claim has no such backstop -- an out-of-scope or denied\n * path already happened on the real filesystem whether or not this gate would allow it, so here\n * ANY non-\"allow\" verdict (in scope, out of scope, or no scope configured at all) means a human\n * must look, not \"the write didn't happen\".\n */\nexport function reviewManagedLaneChangedFiles(args: {\n\tchangedFiles: readonly string[];\n\t/** The scope to validate against -- e.g. the session's active `CapabilityEnvelope`, until a\n\t * per-launch tmux standing grant envelope lands in a later wave (documented follow-up). */\n\tenvelope: Pick<CapabilityEnvelope, \"allowedPaths\" | \"deniedPaths\">;\n\tcwd?: string;\n}): { reviewRequired: boolean; reasonCode: string } {\n\tif (args.changedFiles.length === 0) {\n\t\treturn { reviewRequired: false, reasonCode: \"no_changed_files\" };\n\t}\n\tconst syntheticId = \"managed-lane-review\";\n\tconst acceptance = validateWorkerClaim({\n\t\trequest: {\n\t\t\tid: syntheticId,\n\t\t\tinstructions: \"\",\n\t\t\troute: {\n\t\t\t\ttier: \"cheap\",\n\t\t\t\trisk: \"scoped-write\",\n\t\t\t\tconfidence: 1,\n\t\t\t\treasonCode: \"managed_lane_review\",\n\t\t\t\treasons: [],\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tid: syntheticId,\n\t\t\t\tcapabilities: [\"filesystem.write\"],\n\t\t\t\tallowedPaths: args.envelope.allowedPaths,\n\t\t\t\tdeniedPaths: args.envelope.deniedPaths,\n\t\t\t},\n\t\t},\n\t\tclaim: {\n\t\t\trequestId: syntheticId,\n\t\t\tstatus: \"completed\",\n\t\t\tsummary: \"\",\n\t\t\tchangedFiles: [...args.changedFiles],\n\t\t\tusageReportId: syntheticId,\n\t\t},\n\t\tcwd: args.cwd,\n\t});\n\treturn { reviewRequired: acceptance.outcome !== \"allow\", reasonCode: acceptance.reasonCode };\n}\n"]}
|
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { checkPathScope } from "../autonomy/path-scope.js";
|
|
3
3
|
import { cloneEvidenceBundleForStorage, isEvidenceBundle } from "../research/evidence-bundle.js";
|
|
4
|
-
|
|
4
|
+
import { isPlainRecord } from "../util/value-guards.js";
|
|
5
|
+
export function cloneWorkerClaimForStorage(claim) {
|
|
5
6
|
return {
|
|
6
|
-
...
|
|
7
|
-
...(
|
|
8
|
-
changedFiles: [...
|
|
9
|
-
blockers:
|
|
10
|
-
evidence:
|
|
7
|
+
...claim,
|
|
8
|
+
...(claim.outputFormat ? { outputFormat: claim.outputFormat } : {}),
|
|
9
|
+
changedFiles: [...claim.changedFiles],
|
|
10
|
+
blockers: claim.blockers ? [...claim.blockers] : undefined,
|
|
11
|
+
evidence: claim.evidence ? cloneEvidenceBundleForStorage(claim.evidence) : undefined,
|
|
12
|
+
verification: claim.verification
|
|
13
|
+
? { ...claim.verification, reasonCodes: [...claim.verification.reasonCodes] }
|
|
14
|
+
: undefined,
|
|
11
15
|
};
|
|
12
16
|
}
|
|
13
|
-
function
|
|
14
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
15
|
-
return false;
|
|
16
|
-
const prototype = Object.getPrototypeOf(value);
|
|
17
|
-
return prototype === Object.prototype || prototype === null;
|
|
18
|
-
}
|
|
19
|
-
export function isWorkerResult(value) {
|
|
17
|
+
export function isWorkerClaim(value) {
|
|
20
18
|
if (!isPlainRecord(value))
|
|
21
19
|
return false;
|
|
22
20
|
const obj = value;
|
|
@@ -45,76 +43,88 @@ export function isWorkerResult(value) {
|
|
|
45
43
|
return false;
|
|
46
44
|
if (obj.parentReviewedAt !== undefined && typeof obj.parentReviewedAt !== "string")
|
|
47
45
|
return false;
|
|
46
|
+
if (obj.verification !== undefined) {
|
|
47
|
+
if (!isPlainRecord(obj.verification))
|
|
48
|
+
return false;
|
|
49
|
+
if (typeof obj.verification.subjectTaskId !== "string" || !obj.verification.subjectTaskId)
|
|
50
|
+
return false;
|
|
51
|
+
if (obj.verification.verdict !== "accepted" && obj.verification.verdict !== "rejected")
|
|
52
|
+
return false;
|
|
53
|
+
if (!Array.isArray(obj.verification.reasonCodes) ||
|
|
54
|
+
!obj.verification.reasonCodes.every((reasonCode) => typeof reasonCode === "string" && reasonCode.length > 0)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
48
58
|
if (obj.evidence !== undefined && !isEvidenceBundle(obj.evidence))
|
|
49
59
|
return false;
|
|
50
60
|
return true;
|
|
51
61
|
}
|
|
52
|
-
export function requiresParentReview(
|
|
53
|
-
if (
|
|
62
|
+
export function requiresParentReview(claim) {
|
|
63
|
+
if (claim.status !== "completed") {
|
|
54
64
|
return true;
|
|
55
65
|
}
|
|
56
|
-
if (
|
|
66
|
+
if (claim.blockers && claim.blockers.length > 0) {
|
|
57
67
|
return true;
|
|
58
68
|
}
|
|
59
|
-
if (
|
|
69
|
+
if (claim.changedFiles.length > 0) {
|
|
60
70
|
return true;
|
|
61
71
|
}
|
|
62
72
|
return false;
|
|
63
73
|
}
|
|
64
74
|
/**
|
|
65
|
-
* True iff {@link
|
|
75
|
+
* True iff {@link validateWorkerClaim}'s gate would flag this claim "ask-user" /
|
|
66
76
|
* "parent_review_required" (the two branches at :110 and :178 below) — an otherwise-completed
|
|
67
|
-
*
|
|
68
|
-
* that passed path-scope validation. Reuses `
|
|
77
|
+
* claim the parent must explicitly look at because it reports blockers, or reports file mutations
|
|
78
|
+
* that passed path-scope validation. Reuses `validateWorkerClaim` itself rather than a
|
|
69
79
|
* separately-maintained heuristic, so a persisted review marker can never drift from the
|
|
70
80
|
* gate's actual verdict.
|
|
71
81
|
*/
|
|
72
82
|
export function isParentReviewRequired(args) {
|
|
73
|
-
const acceptance =
|
|
83
|
+
const acceptance = validateWorkerClaim(args);
|
|
74
84
|
return acceptance.outcome === "ask-user" && acceptance.reasonCode === "parent_review_required";
|
|
75
85
|
}
|
|
76
|
-
export function
|
|
77
|
-
const { request,
|
|
86
|
+
export function validateWorkerClaim(args) {
|
|
87
|
+
const { request, claim } = args;
|
|
78
88
|
const baseDir = args.cwd ?? process.cwd();
|
|
79
|
-
if (
|
|
89
|
+
if (claim.requestId !== request.id) {
|
|
80
90
|
return {
|
|
81
91
|
outcome: "block",
|
|
82
|
-
gate: "
|
|
92
|
+
gate: "worker_claim",
|
|
83
93
|
reasonCode: "request_id_mismatch",
|
|
84
|
-
message: `
|
|
94
|
+
message: `Claim requestId '${claim.requestId}' does not match request id '${request.id}'.`,
|
|
85
95
|
};
|
|
86
96
|
}
|
|
87
|
-
if (
|
|
97
|
+
if (claim.status !== "completed") {
|
|
88
98
|
return {
|
|
89
99
|
outcome: "block",
|
|
90
|
-
gate: "
|
|
100
|
+
gate: "worker_claim",
|
|
91
101
|
reasonCode: "worker_not_completed",
|
|
92
|
-
message: `Worker finished with status '${
|
|
93
|
-
details:
|
|
102
|
+
message: `Worker finished with status '${claim.status}'.`,
|
|
103
|
+
details: claim.blockers && claim.blockers.length > 0 ? { blockers: [...claim.blockers] } : undefined,
|
|
94
104
|
};
|
|
95
105
|
}
|
|
96
|
-
if (!
|
|
106
|
+
if (!claim.usageReportId) {
|
|
97
107
|
return {
|
|
98
108
|
outcome: "block",
|
|
99
|
-
gate: "
|
|
109
|
+
gate: "worker_claim",
|
|
100
110
|
reasonCode: "missing_usage_report",
|
|
101
|
-
message: "Completed worker
|
|
111
|
+
message: "Completed worker claim is missing usageReportId.",
|
|
102
112
|
};
|
|
103
113
|
}
|
|
104
|
-
if (
|
|
114
|
+
if (claim.blockers && claim.blockers.length > 0) {
|
|
105
115
|
return {
|
|
106
116
|
outcome: "ask-user",
|
|
107
|
-
gate: "
|
|
117
|
+
gate: "worker_claim",
|
|
108
118
|
reasonCode: "parent_review_required",
|
|
109
|
-
message: "Completed worker
|
|
110
|
-
details: { blockers: [...
|
|
119
|
+
message: "Completed worker claim includes blockers and requires parent review.",
|
|
120
|
+
details: { blockers: [...claim.blockers] },
|
|
111
121
|
};
|
|
112
122
|
}
|
|
113
|
-
if (
|
|
123
|
+
if (claim.changedFiles.length > 0) {
|
|
114
124
|
if (!request.envelope.allowedPaths || request.envelope.allowedPaths.length === 0) {
|
|
115
125
|
return {
|
|
116
126
|
outcome: "block",
|
|
117
|
-
gate: "
|
|
127
|
+
gate: "worker_claim",
|
|
118
128
|
reasonCode: "missing_path_scope",
|
|
119
129
|
message: "Worker changed files but no allowedPaths are configured in the envelope.",
|
|
120
130
|
};
|
|
@@ -124,7 +134,7 @@ export function validateWorkerResult(args) {
|
|
|
124
134
|
// let a denied subtree slip past the deny rule.
|
|
125
135
|
const resolvedAllowed = request.envelope.allowedPaths.map((p) => path.resolve(baseDir, p));
|
|
126
136
|
const resolvedDenied = request.envelope.deniedPaths?.map((p) => path.resolve(baseDir, p));
|
|
127
|
-
for (const changedFile of
|
|
137
|
+
for (const changedFile of claim.changedFiles) {
|
|
128
138
|
let isInsideAny = false;
|
|
129
139
|
let isDenied = false;
|
|
130
140
|
const scopedChangedFile = path.resolve(baseDir, changedFile);
|
|
@@ -145,7 +155,7 @@ export function validateWorkerResult(args) {
|
|
|
145
155
|
if (isDenied) {
|
|
146
156
|
return {
|
|
147
157
|
outcome: "block",
|
|
148
|
-
gate: "
|
|
158
|
+
gate: "worker_claim",
|
|
149
159
|
reasonCode: "changed_file_denied",
|
|
150
160
|
message: `Worker changed file '${changedFile}' which matches a denied path.`,
|
|
151
161
|
};
|
|
@@ -153,7 +163,7 @@ export function validateWorkerResult(args) {
|
|
|
153
163
|
if (!isInsideAny) {
|
|
154
164
|
return {
|
|
155
165
|
outcome: "block",
|
|
156
|
-
gate: "
|
|
166
|
+
gate: "worker_claim",
|
|
157
167
|
reasonCode: "changed_file_outside_scope",
|
|
158
168
|
message: `Worker changed file '${changedFile}' outside allowed scope.`,
|
|
159
169
|
};
|
|
@@ -162,16 +172,16 @@ export function validateWorkerResult(args) {
|
|
|
162
172
|
// Files are inside scope, but worker output is untrusted
|
|
163
173
|
return {
|
|
164
174
|
outcome: "ask-user",
|
|
165
|
-
gate: "
|
|
175
|
+
gate: "worker_claim",
|
|
166
176
|
reasonCode: "parent_review_required",
|
|
167
177
|
message: "Worker changed files require parent review.",
|
|
168
178
|
};
|
|
169
179
|
}
|
|
170
180
|
return {
|
|
171
181
|
outcome: "allow",
|
|
172
|
-
gate: "
|
|
182
|
+
gate: "worker_claim",
|
|
173
183
|
reasonCode: "allowed",
|
|
174
|
-
message: "Worker
|
|
184
|
+
message: "Worker claim is read-only and allowed.",
|
|
175
185
|
};
|
|
176
186
|
}
|
|
177
187
|
/**
|
|
@@ -179,8 +189,8 @@ export function validateWorkerResult(args) {
|
|
|
179
189
|
* -- e.g. a tmux worker's own completion report, which (unlike an in-process worker's) never
|
|
180
190
|
* passed through this process's `applyWorkerActions` envelope enforcement before the write
|
|
181
191
|
* happened; the tmux worker's tool loop runs in a separate process this session does not gate.
|
|
182
|
-
* Reuses {@link
|
|
183
|
-
* reimplement path resolution: synthesizes a minimal, always-"completed" request/
|
|
192
|
+
* Reuses {@link validateWorkerClaim}'s exact symlink-safe scope check verbatim -- never
|
|
193
|
+
* reimplement path resolution: synthesizes a minimal, always-"completed" request/claim pair
|
|
184
194
|
* carrying only the reported `changedFiles` and the scope's `allowedPaths`/`deniedPaths`, so the
|
|
185
195
|
* ONLY thing that can vary the verdict is the path-scope branch.
|
|
186
196
|
*
|
|
@@ -197,7 +207,7 @@ export function reviewManagedLaneChangedFiles(args) {
|
|
|
197
207
|
return { reviewRequired: false, reasonCode: "no_changed_files" };
|
|
198
208
|
}
|
|
199
209
|
const syntheticId = "managed-lane-review";
|
|
200
|
-
const acceptance =
|
|
210
|
+
const acceptance = validateWorkerClaim({
|
|
201
211
|
request: {
|
|
202
212
|
id: syntheticId,
|
|
203
213
|
instructions: "",
|
|
@@ -210,12 +220,12 @@ export function reviewManagedLaneChangedFiles(args) {
|
|
|
210
220
|
},
|
|
211
221
|
envelope: {
|
|
212
222
|
id: syntheticId,
|
|
213
|
-
capabilities: ["
|
|
223
|
+
capabilities: ["filesystem.write"],
|
|
214
224
|
allowedPaths: args.envelope.allowedPaths,
|
|
215
225
|
deniedPaths: args.envelope.deniedPaths,
|
|
216
226
|
},
|
|
217
227
|
},
|
|
218
|
-
|
|
228
|
+
claim: {
|
|
219
229
|
requestId: syntheticId,
|
|
220
230
|
status: "completed",
|
|
221
231
|
summary: "",
|
|
@@ -226,4 +236,4 @@ export function reviewManagedLaneChangedFiles(args) {
|
|
|
226
236
|
});
|
|
227
237
|
return { reviewRequired: acceptance.outcome !== "allow", reasonCode: acceptance.reasonCode };
|
|
228
238
|
}
|
|
229
|
-
//# sourceMappingURL=worker-
|
|
239
|
+
//# sourceMappingURL=worker-claim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-claim.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-claim.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,6BAA6B,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AACjG,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,UAAU,0BAA0B,CAAC,KAAkB,EAAe;IAC3E,OAAO;QACN,GAAG,KAAK;QACR,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,YAAY,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;QACrC,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;QAC1D,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,6BAA6B,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS;QACpF,YAAY,EAAE,KAAK,CAAC,YAAY;YAC/B,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,YAAY,EAAE,WAAW,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE;YAC7E,CAAC,CAAC,SAAS;KACZ,CAAC;AAAA,CACF;AAED,MAAM,UAAU,aAAa,CAAC,KAAc,EAAwB;IACnE,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,GAAG,GAAG,KAAgC,CAAC;IAE7C,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACpD,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC7G,OAAO,KAAK,CAAC;IACd,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClD,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,IAAI,GAAG,CAAC,YAAY,KAAK,YAAY,IAAI,GAAG,CAAC,YAAY,KAAK,YAAY;QAC3G,OAAO,KAAK,CAAC;IAEd,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;QAC/F,OAAO,KAAK,CAAC;IACd,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,EAAE,CAAC;YACvF,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED,IAAI,GAAG,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,aAAa,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3F,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACnF,IAAI,GAAG,CAAC,oBAAoB,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,oBAAoB,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC1G,IAAI,GAAG,CAAC,gBAAgB,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,gBAAgB,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACjG,IAAI,GAAG,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;QACpC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC;YAAE,OAAO,KAAK,CAAC;QACnD,IAAI,OAAO,GAAG,CAAC,YAAY,CAAC,aAAa,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,aAAa;YAAE,OAAO,KAAK,CAAC;QACxG,IAAI,GAAG,CAAC,YAAY,CAAC,OAAO,KAAK,UAAU,IAAI,GAAG,CAAC,YAAY,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QACrG,IACC,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC;YAC5C,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,EAC3G,CAAC;YACF,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAEhF,OAAO,IAAI,CAAC;AAAA,CACZ;AAED,MAAM,UAAU,oBAAoB,CAAC,KAAkB,EAAW;IACjE,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACb,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAkE,EAAW;IACnH,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,UAAU,CAAC,OAAO,KAAK,UAAU,IAAI,UAAU,CAAC,UAAU,KAAK,wBAAwB,CAAC;AAAA,CAC/F;AAED,MAAM,UAAU,mBAAmB,CAAC,IASnC,EAAe;IACf,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAChC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1C,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,EAAE,CAAC;QACpC,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,cAAc;YACpB,UAAU,EAAE,qBAAqB;YACjC,OAAO,EAAE,oBAAoB,KAAK,CAAC,SAAS,gCAAgC,OAAO,CAAC,EAAE,IAAI;SAC1F,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,cAAc;YACpB,UAAU,EAAE,sBAAsB;YAClC,OAAO,EAAE,gCAAgC,KAAK,CAAC,MAAM,IAAI;YACzD,OAAO,EAAE,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;SACpG,CAAC;IACH,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;QAC1B,OAAO;YACN,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,cAAc;YACpB,UAAU,EAAE,sBAAsB;YAClC,OAAO,EAAE,kDAAkD;SAC3D,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO;YACN,OAAO,EAAE,UAAU;YACnB,IAAI,EAAE,cAAc;YACpB,UAAU,EAAE,wBAAwB;YACpC,OAAO,EAAE,sEAAsE;YAC/E,OAAO,EAAE,EAAE,QAAQ,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,EAAE;SAC1C,CAAC;IACH,CAAC;IAED,IAAI,KAAK,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClF,OAAO;gBACN,OAAO,EAAE,OAAO;gBAChB,IAAI,EAAE,cAAc;gBACpB,UAAU,EAAE,oBAAoB;gBAChC,OAAO,EAAE,0EAA0E;aACnF,CAAC;QACH,CAAC;QAED,0FAAwF;QACxF,uFAAuF;QACvF,gDAAgD;QAChD,MAAM,eAAe,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3F,MAAM,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1F,KAAK,MAAM,WAAW,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YAC9C,IAAI,WAAW,GAAG,KAAK,CAAC;YACxB,IAAI,QAAQ,GAAG,KAAK,CAAC;YAErB,MAAM,iBAAiB,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YAC7D,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;gBACpC,MAAM,QAAQ,GAAG,cAAc,CAC9B;oBACC,IAAI;oBACJ,YAAY,EAAE,eAAe;oBAC7B,WAAW,EAAE,cAAc;iBAC3B,EACD,iBAAiB,CACjB,CAAC;gBAEF,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAChC,QAAQ,GAAG,IAAI,CAAC;oBAChB,MAAM;gBACP,CAAC;gBACD,IAAI,QAAQ,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAChC,WAAW,GAAG,IAAI,CAAC;gBACpB,CAAC;YACF,CAAC;YAED,IAAI,QAAQ,EAAE,CAAC;gBACd,OAAO;oBACN,OAAO,EAAE,OAAO;oBAChB,IAAI,EAAE,cAAc;oBACpB,UAAU,EAAE,qBAAqB;oBACjC,OAAO,EAAE,wBAAwB,WAAW,gCAAgC;iBAC5E,CAAC;YACH,CAAC;YAED,IAAI,CAAC,WAAW,EAAE,CAAC;gBAClB,OAAO;oBACN,OAAO,EAAE,OAAO;oBAChB,IAAI,EAAE,cAAc;oBACpB,UAAU,EAAE,4BAA4B;oBACxC,OAAO,EAAE,wBAAwB,WAAW,0BAA0B;iBACtE,CAAC;YACH,CAAC;QACF,CAAC;QAED,yDAAyD;QACzD,OAAO;YACN,OAAO,EAAE,UAAU;YACnB,IAAI,EAAE,cAAc;YACpB,UAAU,EAAE,wBAAwB;YACpC,OAAO,EAAE,6CAA6C;SACtD,CAAC;IACH,CAAC;IAED,OAAO;QACN,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,cAAc;QACpB,UAAU,EAAE,SAAS;QACrB,OAAO,EAAE,wCAAwC;KACjD,CAAC;AAAA,CACF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,6BAA6B,CAAC,IAM7C,EAAmD;IACnD,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;IAClE,CAAC;IACD,MAAM,WAAW,GAAG,qBAAqB,CAAC;IAC1C,MAAM,UAAU,GAAG,mBAAmB,CAAC;QACtC,OAAO,EAAE;YACR,EAAE,EAAE,WAAW;YACf,YAAY,EAAE,EAAE;YAChB,KAAK,EAAE;gBACN,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,cAAc;gBACpB,UAAU,EAAE,CAAC;gBACb,UAAU,EAAE,qBAAqB;gBACjC,OAAO,EAAE,EAAE;aACX;YACD,QAAQ,EAAE;gBACT,EAAE,EAAE,WAAW;gBACf,YAAY,EAAE,CAAC,kBAAkB,CAAC;gBAClC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,YAAY;gBACxC,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW;aACtC;SACD;QACD,KAAK,EAAE;YACN,SAAS,EAAE,WAAW;YACtB,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,EAAE;YACX,YAAY,EAAE,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC;YACpC,aAAa,EAAE,WAAW;SAC1B;QACD,GAAG,EAAE,IAAI,CAAC,GAAG;KACb,CAAC,CAAC;IACH,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC,OAAO,KAAK,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE,CAAC;AAAA,CAC7F","sourcesContent":["import path from \"node:path\";\nimport type { CapabilityEnvelope, GateOutcome, WorkerClaim, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport { checkPathScope } from \"../autonomy/path-scope.ts\";\nimport { cloneEvidenceBundleForStorage, isEvidenceBundle } from \"../research/evidence-bundle.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\n\nexport function cloneWorkerClaimForStorage(claim: WorkerClaim): WorkerClaim {\n\treturn {\n\t\t...claim,\n\t\t...(claim.outputFormat ? { outputFormat: claim.outputFormat } : {}),\n\t\tchangedFiles: [...claim.changedFiles],\n\t\tblockers: claim.blockers ? [...claim.blockers] : undefined,\n\t\tevidence: claim.evidence ? cloneEvidenceBundleForStorage(claim.evidence) : undefined,\n\t\tverification: claim.verification\n\t\t\t? { ...claim.verification, reasonCodes: [...claim.verification.reasonCodes] }\n\t\t\t: undefined,\n\t};\n}\n\nexport function isWorkerClaim(value: unknown): value is WorkerClaim {\n\tif (!isPlainRecord(value)) return false;\n\tconst obj = value as Record<string, unknown>;\n\n\tif (typeof obj.requestId !== \"string\") return false;\n\tif (typeof obj.status !== \"string\" || ![\"completed\", \"blocked\", \"failed\", \"cancelled\"].includes(obj.status)) {\n\t\treturn false;\n\t}\n\tif (typeof obj.summary !== \"string\") return false;\n\tif (obj.outputFormat !== undefined && obj.outputFormat !== \"structured\" && obj.outputFormat !== \"plain_text\")\n\t\treturn false;\n\n\tif (!Array.isArray(obj.changedFiles) || !obj.changedFiles.every((f) => typeof f === \"string\")) {\n\t\treturn false;\n\t}\n\n\tif (obj.blockers !== undefined) {\n\t\tif (!Array.isArray(obj.blockers) || !obj.blockers.every((b) => typeof b === \"string\")) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (obj.usageReportId !== undefined && typeof obj.usageReportId !== \"string\") return false;\n\tif (obj.createdAt !== undefined && typeof obj.createdAt !== \"string\") return false;\n\tif (obj.parentReviewRequired !== undefined && typeof obj.parentReviewRequired !== \"boolean\") return false;\n\tif (obj.parentReviewedAt !== undefined && typeof obj.parentReviewedAt !== \"string\") return false;\n\tif (obj.verification !== undefined) {\n\t\tif (!isPlainRecord(obj.verification)) return false;\n\t\tif (typeof obj.verification.subjectTaskId !== \"string\" || !obj.verification.subjectTaskId) return false;\n\t\tif (obj.verification.verdict !== \"accepted\" && obj.verification.verdict !== \"rejected\") return false;\n\t\tif (\n\t\t\t!Array.isArray(obj.verification.reasonCodes) ||\n\t\t\t!obj.verification.reasonCodes.every((reasonCode) => typeof reasonCode === \"string\" && reasonCode.length > 0)\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (obj.evidence !== undefined && !isEvidenceBundle(obj.evidence)) return false;\n\n\treturn true;\n}\n\nexport function requiresParentReview(claim: WorkerClaim): boolean {\n\tif (claim.status !== \"completed\") {\n\t\treturn true;\n\t}\n\tif (claim.blockers && claim.blockers.length > 0) {\n\t\treturn true;\n\t}\n\tif (claim.changedFiles.length > 0) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * True iff {@link validateWorkerClaim}'s gate would flag this claim \"ask-user\" /\n * \"parent_review_required\" (the two branches at :110 and :178 below) — an otherwise-completed\n * claim the parent must explicitly look at because it reports blockers, or reports file mutations\n * that passed path-scope validation. Reuses `validateWorkerClaim` itself rather than a\n * separately-maintained heuristic, so a persisted review marker can never drift from the\n * gate's actual verdict.\n */\nexport function isParentReviewRequired(args: { request: WorkerRequest; claim: WorkerClaim; cwd?: string }): boolean {\n\tconst acceptance = validateWorkerClaim(args);\n\treturn acceptance.outcome === \"ask-user\" && acceptance.reasonCode === \"parent_review_required\";\n}\n\nexport function validateWorkerClaim(args: {\n\trequest: WorkerRequest;\n\tclaim: WorkerClaim;\n\t/**\n\t * Baseline for relative paths — BOTH the runner's cwd-relative `changedFiles` and the\n\t * envelope's possibly-relative path scopes resolve against this. Defaults to process.cwd()\n\t * for callers whose session cwd is the process cwd.\n\t */\n\tcwd?: string;\n}): GateOutcome {\n\tconst { request, claim } = args;\n\tconst baseDir = args.cwd ?? process.cwd();\n\n\tif (claim.requestId !== request.id) {\n\t\treturn {\n\t\t\toutcome: \"block\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"request_id_mismatch\",\n\t\t\tmessage: `Claim requestId '${claim.requestId}' does not match request id '${request.id}'.`,\n\t\t};\n\t}\n\n\tif (claim.status !== \"completed\") {\n\t\treturn {\n\t\t\toutcome: \"block\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"worker_not_completed\",\n\t\t\tmessage: `Worker finished with status '${claim.status}'.`,\n\t\t\tdetails: claim.blockers && claim.blockers.length > 0 ? { blockers: [...claim.blockers] } : undefined,\n\t\t};\n\t}\n\n\tif (!claim.usageReportId) {\n\t\treturn {\n\t\t\toutcome: \"block\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"missing_usage_report\",\n\t\t\tmessage: \"Completed worker claim is missing usageReportId.\",\n\t\t};\n\t}\n\n\tif (claim.blockers && claim.blockers.length > 0) {\n\t\treturn {\n\t\t\toutcome: \"ask-user\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"parent_review_required\",\n\t\t\tmessage: \"Completed worker claim includes blockers and requires parent review.\",\n\t\t\tdetails: { blockers: [...claim.blockers] },\n\t\t};\n\t}\n\n\tif (claim.changedFiles.length > 0) {\n\t\tif (!request.envelope.allowedPaths || request.envelope.allowedPaths.length === 0) {\n\t\t\treturn {\n\t\t\t\toutcome: \"block\",\n\t\t\t\tgate: \"worker_claim\",\n\t\t\t\treasonCode: \"missing_path_scope\",\n\t\t\t\tmessage: \"Worker changed files but no allowedPaths are configured in the envelope.\",\n\t\t\t};\n\t\t}\n\n\t\t// The runner reports changed files relative to the session cwd — resolve file and scope\n\t\t// roots against the SAME baseline. Resolving per-root double-prefixed nested names and\n\t\t// let a denied subtree slip past the deny rule.\n\t\tconst resolvedAllowed = request.envelope.allowedPaths.map((p) => path.resolve(baseDir, p));\n\t\tconst resolvedDenied = request.envelope.deniedPaths?.map((p) => path.resolve(baseDir, p));\n\t\tfor (const changedFile of claim.changedFiles) {\n\t\t\tlet isInsideAny = false;\n\t\t\tlet isDenied = false;\n\n\t\t\tconst scopedChangedFile = path.resolve(baseDir, changedFile);\n\t\t\tfor (const root of resolvedAllowed) {\n\t\t\t\tconst decision = checkPathScope(\n\t\t\t\t\t{\n\t\t\t\t\t\troot,\n\t\t\t\t\t\tallowedPaths: resolvedAllowed,\n\t\t\t\t\t\tdeniedPaths: resolvedDenied,\n\t\t\t\t\t},\n\t\t\t\t\tscopedChangedFile,\n\t\t\t\t);\n\n\t\t\t\tif (decision.kind === \"denied\") {\n\t\t\t\t\tisDenied = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (decision.kind === \"inside\") {\n\t\t\t\t\tisInsideAny = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isDenied) {\n\t\t\t\treturn {\n\t\t\t\t\toutcome: \"block\",\n\t\t\t\t\tgate: \"worker_claim\",\n\t\t\t\t\treasonCode: \"changed_file_denied\",\n\t\t\t\t\tmessage: `Worker changed file '${changedFile}' which matches a denied path.`,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (!isInsideAny) {\n\t\t\t\treturn {\n\t\t\t\t\toutcome: \"block\",\n\t\t\t\t\tgate: \"worker_claim\",\n\t\t\t\t\treasonCode: \"changed_file_outside_scope\",\n\t\t\t\t\tmessage: `Worker changed file '${changedFile}' outside allowed scope.`,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\t// Files are inside scope, but worker output is untrusted\n\t\treturn {\n\t\t\toutcome: \"ask-user\",\n\t\t\tgate: \"worker_claim\",\n\t\t\treasonCode: \"parent_review_required\",\n\t\t\tmessage: \"Worker changed files require parent review.\",\n\t\t};\n\t}\n\n\treturn {\n\t\toutcome: \"allow\",\n\t\tgate: \"worker_claim\",\n\t\treasonCode: \"allowed\",\n\t\tmessage: \"Worker claim is read-only and allowed.\",\n\t};\n}\n\n/**\n * Path-scope-only re-review for a SELF-REPORTED (out-of-process) worker's claimed `changedFiles`\n * -- e.g. a tmux worker's own completion report, which (unlike an in-process worker's) never\n * passed through this process's `applyWorkerActions` envelope enforcement before the write\n * happened; the tmux worker's tool loop runs in a separate process this session does not gate.\n * Reuses {@link validateWorkerClaim}'s exact symlink-safe scope check verbatim -- never\n * reimplement path resolution: synthesizes a minimal, always-\"completed\" request/claim pair\n * carrying only the reported `changedFiles` and the scope's `allowedPaths`/`deniedPaths`, so the\n * ONLY thing that can vary the verdict is the path-scope branch.\n *\n * Deliberately broader than {@link isParentReviewRequired}: that helper only flags the gate's\n * \"ask-user\" branch, which is correct for an in-process worker (a write that would have been\n * \"block\"-worthy was already refused before it could happen, by the SAME envelope, via\n * `applyWorkerActions`). A self-reported claim has no such backstop -- an out-of-scope or denied\n * path already happened on the real filesystem whether or not this gate would allow it, so here\n * ANY non-\"allow\" verdict (in scope, out of scope, or no scope configured at all) means a human\n * must look, not \"the write didn't happen\".\n */\nexport function reviewManagedLaneChangedFiles(args: {\n\tchangedFiles: readonly string[];\n\t/** The scope to validate against -- e.g. the session's active `CapabilityEnvelope`, until a\n\t * per-launch tmux standing grant envelope lands in a later wave (documented follow-up). */\n\tenvelope: Pick<CapabilityEnvelope, \"allowedPaths\" | \"deniedPaths\">;\n\tcwd?: string;\n}): { reviewRequired: boolean; reasonCode: string } {\n\tif (args.changedFiles.length === 0) {\n\t\treturn { reviewRequired: false, reasonCode: \"no_changed_files\" };\n\t}\n\tconst syntheticId = \"managed-lane-review\";\n\tconst acceptance = validateWorkerClaim({\n\t\trequest: {\n\t\t\tid: syntheticId,\n\t\t\tinstructions: \"\",\n\t\t\troute: {\n\t\t\t\ttier: \"cheap\",\n\t\t\t\trisk: \"scoped-write\",\n\t\t\t\tconfidence: 1,\n\t\t\t\treasonCode: \"managed_lane_review\",\n\t\t\t\treasons: [],\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tid: syntheticId,\n\t\t\t\tcapabilities: [\"filesystem.write\"],\n\t\t\t\tallowedPaths: args.envelope.allowedPaths,\n\t\t\t\tdeniedPaths: args.envelope.deniedPaths,\n\t\t\t},\n\t\t},\n\t\tclaim: {\n\t\t\trequestId: syntheticId,\n\t\t\tstatus: \"completed\",\n\t\t\tsummary: \"\",\n\t\t\tchangedFiles: [...args.changedFiles],\n\t\t\tusageReportId: syntheticId,\n\t\t},\n\t\tcwd: args.cwd,\n\t});\n\treturn { reviewRequired: acceptance.outcome !== \"allow\", reasonCode: acceptance.reasonCode };\n}\n"]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import type { SessionManager } from "@caupulican/pi-agent-core/node";
|
|
2
|
+
import type { Api, Model, Usage } from "@caupulican/pi-ai";
|
|
3
|
+
import type { AgentSessionEvent, IsolatedCompletionOptions, IsolatedCompletionResult, WorkerDelegationRunOutcome } from "../agent-session.ts";
|
|
4
|
+
import type { CapabilityEnvelope, WorkerClaim, WorkerRequest } from "../autonomy/contracts.ts";
|
|
5
|
+
import type { LaneRecord, LaneTerminalStatus } from "../autonomy/lane-tracker.ts";
|
|
6
|
+
import { type AutonomyTelemetryEvent } from "../autonomy/telemetry-events.ts";
|
|
7
|
+
import type { GoalState } from "../goals/goal-state.ts";
|
|
8
|
+
import type { ModelRegistry } from "../model-registry.ts";
|
|
9
|
+
import type { OrchestrationProfile } from "../orchestration/contracts.ts";
|
|
10
|
+
import type { TaskRuntimeProjection } from "../orchestration/task-runtime.ts";
|
|
11
|
+
import type { SettingsManager } from "../settings-manager.ts";
|
|
12
|
+
import type { WorkerDelegationRequest } from "./worker-delegation-request.ts";
|
|
13
|
+
import type { WorkerLifecycle } from "./worker-lifecycle.ts";
|
|
14
|
+
import type { WorkerNotificationCoordinator } from "./worker-notification-coordinator.ts";
|
|
15
|
+
export declare function isLocalExecutionModel(model: Pick<Model<Api>, "provider" | "baseUrl">): boolean;
|
|
16
|
+
export interface WorkerDelegationControllerDeps {
|
|
17
|
+
isDisposed(): boolean;
|
|
18
|
+
getSessionId(): string;
|
|
19
|
+
getCwd(): string;
|
|
20
|
+
getAgentDir(): string;
|
|
21
|
+
getSessionManager(): SessionManager;
|
|
22
|
+
getSettingsManager(): SettingsManager;
|
|
23
|
+
getActiveOrchestrationProfile?(): OrchestrationProfile | undefined;
|
|
24
|
+
getModelRegistry(): ModelRegistry;
|
|
25
|
+
isModelExhausted(model: Model<Api>): boolean;
|
|
26
|
+
getModel(): Model<Api> | undefined;
|
|
27
|
+
isDelegateToolActive(): boolean;
|
|
28
|
+
getCapabilityEnvelope(): CapabilityEnvelope | undefined;
|
|
29
|
+
emit(event: AgentSessionEvent): void;
|
|
30
|
+
notifyWorkerTerminalHandoff(records: readonly {
|
|
31
|
+
laneId: string;
|
|
32
|
+
status: LaneTerminalStatus;
|
|
33
|
+
reasonCode?: string;
|
|
34
|
+
}[]): Promise<void>;
|
|
35
|
+
emitAutonomyTelemetry(event: AutonomyTelemetryEvent): void;
|
|
36
|
+
getGoalStateSnapshot(): GoalState | undefined;
|
|
37
|
+
saveWorkerClaimSnapshot(claim: WorkerClaim, request?: WorkerRequest): string;
|
|
38
|
+
queueWorkerHumanInput(request: {
|
|
39
|
+
workerRequestId: string;
|
|
40
|
+
message: string;
|
|
41
|
+
blockers: readonly string[];
|
|
42
|
+
}): void;
|
|
43
|
+
readMemoryForLane(query: string): Promise<string>;
|
|
44
|
+
addSpawnedUsage(usage: Usage, opts: {
|
|
45
|
+
label?: string;
|
|
46
|
+
sourceSessionId?: string;
|
|
47
|
+
reportId: string;
|
|
48
|
+
}): string | undefined;
|
|
49
|
+
runIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;
|
|
50
|
+
}
|
|
51
|
+
export declare class WorkerDelegationController {
|
|
52
|
+
private readonly deps;
|
|
53
|
+
private readonly workerAbort;
|
|
54
|
+
private readonly lifecycle;
|
|
55
|
+
private profileResolver;
|
|
56
|
+
private queueRecovered;
|
|
57
|
+
private recoveringDurableState;
|
|
58
|
+
private readonly verificationRecoveryFailures;
|
|
59
|
+
private readonly notifications;
|
|
60
|
+
private readonly scheduler;
|
|
61
|
+
private readonly laneAbortControllers;
|
|
62
|
+
private readonly publishedTerminalAttemptIds;
|
|
63
|
+
private readonly inFlightLedgers;
|
|
64
|
+
constructor(deps: WorkerDelegationControllerDeps, notifications: WorkerNotificationCoordinator, lifecycle: WorkerLifecycle);
|
|
65
|
+
private safeWarn;
|
|
66
|
+
recordTerminal(record: LaneRecord): void;
|
|
67
|
+
getRecords(): LaneRecord[];
|
|
68
|
+
/** Process-local worker records for the shared terminal notifier; never triggers durable recovery. */
|
|
69
|
+
getLoadedRecords(): LaneRecord[];
|
|
70
|
+
markNotificationsDelivered(notificationIds: readonly string[]): void;
|
|
71
|
+
abort(): void;
|
|
72
|
+
private getWorkerLifecycle;
|
|
73
|
+
private getWorkerProfileResolver;
|
|
74
|
+
/** Read-only durable worker projection. Undefined means the delegate capability never loaded. */
|
|
75
|
+
getTaskRuntimeSnapshot(): TaskRuntimeProjection | undefined;
|
|
76
|
+
/** Reconcile the session goal into an already-loaded worker runtime without defeating lazy UAC. */
|
|
77
|
+
synchronizeGoalState(goal: GoalState): void;
|
|
78
|
+
private publishGoalTerminalRecords;
|
|
79
|
+
private recoverDurableQueue;
|
|
80
|
+
private laneCapabilityProfile;
|
|
81
|
+
getProfileCatalog(): Array<{
|
|
82
|
+
profileId: string;
|
|
83
|
+
role: string;
|
|
84
|
+
description: string;
|
|
85
|
+
}>;
|
|
86
|
+
private resolveWorkerShipment;
|
|
87
|
+
private resolveRequiredVerifier;
|
|
88
|
+
/** Single admission contract shared by enqueue, scheduler revalidation, and execution. */
|
|
89
|
+
private resolveWorkerAdmission;
|
|
90
|
+
private buildVerifierRequest;
|
|
91
|
+
private publishTerminalRecord;
|
|
92
|
+
private hasWorkerCapacity;
|
|
93
|
+
private workerDispatchAdmission;
|
|
94
|
+
private buildWorkerExecutionPlan;
|
|
95
|
+
/** One durable preparation path for queued, immediate, and recovered execution. */
|
|
96
|
+
private prepareWorkerAttempt;
|
|
97
|
+
start(request: WorkerDelegationRequest): {
|
|
98
|
+
started: false;
|
|
99
|
+
skipReason: string;
|
|
100
|
+
} | {
|
|
101
|
+
started: true;
|
|
102
|
+
record: LaneRecord;
|
|
103
|
+
};
|
|
104
|
+
private startInternal;
|
|
105
|
+
runOnce(request: WorkerDelegationRequest, onStarted?: (record: LaneRecord) => void, existingRecord?: LaneRecord): Promise<WorkerDelegationRunOutcome>;
|
|
106
|
+
private runOnceWithAdmission;
|
|
107
|
+
/** Start every capacity-eligible queued worker at the owner session's foreground-idle boundary. */
|
|
108
|
+
drain(): void;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=worker-delegation-controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-delegation-controller.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-delegation-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"node:path\";\nimport type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Api, Model, Usage } from \"@caupulican/pi-ai\";\nimport type {\n\tAgentSessionEvent,\n\tIsolatedCompletionOptions,\n\tIsolatedCompletionResult,\n\tWorkerDelegationRunOutcome,\n} from \"../agent-session.ts\";\nimport type { CapabilityEnvelope, WorkerClaim, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport { getPrivateLaneDeniedPaths } from \"../autonomy/lane-private-paths.ts\";\nimport { createLaneToolSurface } from \"../autonomy/lane-tool-surface.ts\";\nimport type { LaneRecord, LaneTerminalStatus } from \"../autonomy/lane-tracker.ts\";\nimport { safeRealpathSync } from \"../autonomy/path-scope.ts\";\nimport { appendLaneRecordSnapshot } from \"../autonomy/session-lane-record.ts\";\nimport { composeSubagentSystemPrompt } from \"../autonomy/subagent-prompt.ts\";\nimport { AUTONOMY_TELEMETRY_EVENT_TYPES, type AutonomyTelemetryEvent } from \"../autonomy/telemetry-events.ts\";\nimport type { GoalState } from \"../goals/goal-state.ts\";\nimport { deriveModelCapabilityProfile, type ModelCapabilityProfile } from \"../model-capability.ts\";\nimport type { ModelRegistry } from \"../model-registry.ts\";\nimport type { OrchestrationProfile, WorkerExecutionContract } from \"../orchestration/contracts.ts\";\nimport type { StartedDelegationAttempt } from \"../orchestration/delegation-ledger.ts\";\nimport type { AttemptRuntimeState, TaskRuntimeProjection } from \"../orchestration/task-runtime.ts\";\nimport {\n\tcreateWorkerExecutionContract,\n\tverifierWorkerExecutionContract,\n} from \"../orchestration/worker-execution-contract.ts\";\nimport { createWorkerResultContract } from \"../orchestration/worker-result-adapter.ts\";\nimport { registerInFlightWork } from \"../reload-blockers.ts\";\nimport type { ResolvedWorkerDelegationSettings, SettingsManager } from \"../settings-manager.ts\";\nimport { applyWorkerActions } from \"./worker-actions.ts\";\nimport type { WorkerDelegationRequest } from \"./worker-delegation-request.ts\";\nimport { type WorkerDispatchAdmission, WorkerDispatchScheduler } from \"./worker-dispatch-scheduler.ts\";\nimport {\n\tbuildWorkerExecutionPlan,\n\tcompileWorkerExecutionGrant,\n\tnarrowWorkerExecutionPlan,\n\ttype WorkerExecutionPlan,\n\tworkerExecutionAuthorityFromPlan,\n} from \"./worker-execution-policy.ts\";\nimport type { WorkerLifecycle } from \"./worker-lifecycle.ts\";\nimport type { WorkerNotificationCoordinator } from \"./worker-notification-coordinator.ts\";\nimport { type ResolvedWorkerProfile, WorkerProfileResolver } from \"./worker-profile-resolver.ts\";\nimport { runWorker } from \"./worker-runner.ts\";\n\nexport function isLocalExecutionModel(model: Pick<Model<Api>, \"provider\" | \"baseUrl\">): boolean {\n\tif (model.provider === \"ollama\" || model.provider === \"transformers\" || model.provider === \"llama-cpp\") {\n\t\treturn true;\n\t}\n\ttry {\n\t\tconst hostname = new URL(model.baseUrl).hostname.toLowerCase();\n\t\treturn hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\" || hostname === \"[::1]\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport interface WorkerDelegationControllerDeps {\n\tisDisposed(): boolean;\n\tgetSessionId(): string;\n\tgetCwd(): string;\n\tgetAgentDir(): string;\n\tgetSessionManager(): SessionManager;\n\tgetSettingsManager(): SettingsManager;\n\tgetActiveOrchestrationProfile?(): OrchestrationProfile | undefined;\n\tgetModelRegistry(): ModelRegistry;\n\tisModelExhausted(model: Model<Api>): boolean;\n\tgetModel(): Model<Api> | undefined;\n\tisDelegateToolActive(): boolean;\n\tgetCapabilityEnvelope(): CapabilityEnvelope | undefined;\n\temit(event: AgentSessionEvent): void;\n\tnotifyWorkerTerminalHandoff(\n\t\trecords: readonly { laneId: string; status: LaneTerminalStatus; reasonCode?: string }[],\n\t): Promise<void>;\n\temitAutonomyTelemetry(event: AutonomyTelemetryEvent): void;\n\tgetGoalStateSnapshot(): GoalState | undefined;\n\tsaveWorkerClaimSnapshot(claim: WorkerClaim, request?: WorkerRequest): string;\n\tqueueWorkerHumanInput(request: { workerRequestId: string; message: string; blockers: readonly string[] }): void;\n\treadMemoryForLane(query: string): Promise<string>;\n\taddSpawnedUsage(\n\t\tusage: Usage,\n\t\topts: { label?: string; sourceSessionId?: string; reportId: string },\n\t): string | undefined;\n\trunIsolatedCompletion(opts: IsolatedCompletionOptions): Promise<IsolatedCompletionResult>;\n}\n\ntype WorkerAdmission =\n\t| {\n\t\t\tok: true;\n\t\t\tinstructions: string;\n\t\t\tsettings: ResolvedWorkerDelegationSettings;\n\t\t\tshipment: ResolvedWorkerProfile;\n\t\t\tverifierShipment?: ResolvedWorkerProfile;\n\t\t\texecutionContract: WorkerExecutionContract;\n\t\t\texecutionPlan: WorkerExecutionPlan;\n\t }\n\t| { ok: false; skipReason: string };\n\ninterface PreparedWorkerAttempt {\n\texecutionPlan: WorkerExecutionPlan;\n\tlifecycle: WorkerLifecycle;\n\trecord: LaneRecord;\n\tattempt?: AttemptRuntimeState;\n}\n\nexport class WorkerDelegationController {\n\tprivate readonly deps: WorkerDelegationControllerDeps;\n\tprivate readonly workerAbort = new AbortController();\n\tprivate readonly lifecycle: WorkerLifecycle;\n\tprivate profileResolver: WorkerProfileResolver | undefined;\n\tprivate queueRecovered = false;\n\tprivate recoveringDurableState = false;\n\tprivate readonly verificationRecoveryFailures = new Map<string, string>();\n\tprivate readonly notifications: WorkerNotificationCoordinator;\n\tprivate readonly scheduler: WorkerDispatchScheduler;\n\tprivate readonly laneAbortControllers = new Map<string, AbortController>();\n\tprivate readonly publishedTerminalAttemptIds = new Set<string>();\n\tprivate readonly inFlightLedgers = new Map<\n\t\tstring,\n\t\t{\n\t\t\tchangedFiles: Set<string>;\n\t\t\tgetSpend: () => Usage | undefined;\n\t\t\tgetToolCalls: () => number;\n\t\t\trequest: WorkerRequest;\n\t\t\thandle: StartedDelegationAttempt;\n\t\t\tstartedAt: number;\n\t\t}\n\t>();\n\n\tconstructor(\n\t\tdeps: WorkerDelegationControllerDeps,\n\t\tnotifications: WorkerNotificationCoordinator,\n\t\tlifecycle: WorkerLifecycle,\n\t) {\n\t\tthis.deps = deps;\n\t\tthis.notifications = notifications;\n\t\tthis.lifecycle = lifecycle;\n\t\tthis.scheduler = new WorkerDispatchScheduler({\n\t\t\tagentDir: this.deps.getAgentDir?.() ?? \"\",\n\t\t\tisDisposed: () => this.deps.isDisposed(),\n\t\t\tadmit: (request, record) => this.workerDispatchAdmission(request, record),\n\t\t\tgetRecord: (laneId) => this.getWorkerLifecycle().getRecord(laneId),\n\t\t\trun: (request, record) => this.runOnce(request, undefined, record),\n\t\t\tcancel: (laneId, reasonCode) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst terminal = this.getWorkerLifecycle().cancel(laneId, reasonCode);\n\t\t\t\t\tif (terminal) this.publishTerminalRecord(terminal);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.safeWarn(\n\t\t\t\t\t\t`Failed to cancel durable worker ${laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t},\n\t\t\twarn: (message) => this.safeWarn(message),\n\t\t});\n\t}\n\n\tprivate safeWarn(message: string): void {\n\t\ttry {\n\t\t\tthis.deps.emit({ type: \"warning\", message });\n\t\t} catch {\n\t\t\t// Disposal and recovery diagnostics must never throw.\n\t\t}\n\t}\n\n\trecordTerminal(record: LaneRecord): void {\n\t\tif (record.status === \"queued\" || record.status === \"running\") return;\n\t\tif (record.type === \"worker\") {\n\t\t\tconst notification = this.lifecycle.getTerminalNotification(record.laneId);\n\t\t\tif (notification?.status === \"delivered\") return;\n\t\t\tif (notification) {\n\t\t\t\tthis.notifications.recordTerminal(record, notification.notificationId);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis.notifications.recordTerminal(record);\n\t}\n\n\tgetRecords(): LaneRecord[] {\n\t\tif (this.deps.isDelegateToolActive?.()) this.recoverDurableQueue();\n\t\treturn this.lifecycle.getRecords();\n\t}\n\n\t/** Process-local worker records for the shared terminal notifier; never triggers durable recovery. */\n\tgetLoadedRecords(): LaneRecord[] {\n\t\treturn this.lifecycle.getRecords();\n\t}\n\n\tmarkNotificationsDelivered(notificationIds: readonly string[]): void {\n\t\tthis.lifecycle.markNotificationsDelivered(notificationIds);\n\t}\n\n\tabort(): void {\n\t\tthis.workerAbort.abort();\n\t\tfor (const record of this.lifecycle.getRecords()) {\n\t\t\tif (record.status !== \"queued\" && record.status !== \"running\") continue;\n\t\t\tconst ledger = this.inFlightLedgers.get(record.laneId);\n\t\t\tif (!ledger) {\n\t\t\t\ttry {\n\t\t\t\t\tconst canceled = this.lifecycle.cancel(record.laneId, \"session_disposed\");\n\t\t\t\t\tif (canceled) {\n\t\t\t\t\t\tthis.publishTerminalRecord(canceled);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.safeWarn(\n\t\t\t\t\t\t`Failed to cancel durable queued worker ${record.laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.inFlightLedgers.delete(record.laneId);\n\t\t\ttry {\n\t\t\t\tconst spend = ledger.getSpend();\n\t\t\t\tconst reportId = `worker:${this.deps.getSessionId()}:${record.laneId}`;\n\t\t\t\tconst claim: WorkerClaim = {\n\t\t\t\t\trequestId: ledger.request.id,\n\t\t\t\t\tstatus: \"cancelled\",\n\t\t\t\t\tsummary: \"canceled on session dispose\",\n\t\t\t\t\tchangedFiles: [...ledger.changedFiles],\n\t\t\t\t\tusageReportId: reportId,\n\t\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\t};\n\t\t\t\tconst canceled = this.getWorkerLifecycle().finish(\n\t\t\t\t\tcreateWorkerResultContract({\n\t\t\t\t\t\thandle: ledger.handle,\n\t\t\t\t\t\tclaim,\n\t\t\t\t\t\taccepted: false,\n\t\t\t\t\t\tcostUsd: spend?.cost.total ?? 0,\n\t\t\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\t\t\t...(spend\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tinputTokens: spend.input,\n\t\t\t\t\t\t\t\t\toutputTokens: spend.output,\n\t\t\t\t\t\t\t\t\ttotalTokens: spend.totalTokens,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\twallClockMs: Date.now() - ledger.startedAt,\n\t\t\t\t\t\ttoolCalls: ledger.getToolCalls(),\n\t\t\t\t\t\treasonCode: \"session_disposed\",\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tthis.publishTerminalRecord(canceled);\n\t\t\t\t// Bounded honesty: spend may be incomplete (it lands only when the isolated completion\n\t\t\t\t// returns, which a mid-flight abort preempts) — record what `getSpend()` knows. Same\n\t\t\t\t// deterministic reportId scheme as the normal path, so a later duplicate report (there\n\t\t\t\t// is none in practice here, since the lane is now terminal) stays idempotent.\n\t\t\t\tthis.deps.saveWorkerClaimSnapshot(claim, ledger.request);\n\t\t\t\tif (spend && (spend.cost.total > 0 || spend.totalTokens > 0)) {\n\t\t\t\t\tthis.deps.addSpawnedUsage(spend, { label: \"worker-delegation\", reportId });\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis.safeWarn(\n\t\t\t\t\t`Failed to persist canceled worker claim ${record.laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis.scheduler.cancelQueued();\n\t}\n\n\tprivate getWorkerLifecycle(): WorkerLifecycle {\n\t\treturn this.lifecycle;\n\t}\n\n\tprivate getWorkerProfileResolver(): WorkerProfileResolver {\n\t\tif (this.profileResolver) return this.profileResolver;\n\t\tthis.profileResolver = new WorkerProfileResolver({\n\t\t\tagentDir: this.deps.getAgentDir(),\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\tgetSettingsManager: () => this.deps.getSettingsManager(),\n\t\t\tgetModelRegistry: () => this.deps.getModelRegistry(),\n\t\t\tisModelExhausted: (model) => this.deps.isModelExhausted(model),\n\t\t\tgetActiveOrchestrationProfile: () => this.deps.getActiveOrchestrationProfile?.(),\n\t\t\tonDiagnostic: (message) => this.safeWarn(message),\n\t\t});\n\t\treturn this.profileResolver;\n\t}\n\n\t/** Read-only durable worker projection. Undefined means the delegate capability never loaded. */\n\tgetTaskRuntimeSnapshot(): TaskRuntimeProjection | undefined {\n\t\treturn this.lifecycle.getTaskRuntimeSnapshot();\n\t}\n\n\t/** Reconcile the session goal into an already-loaded worker runtime without defeating lazy UAC. */\n\tsynchronizeGoalState(goal: GoalState): void {\n\t\tthis.publishGoalTerminalRecords(this.lifecycle.synchronizeGoalState(goal));\n\t}\n\n\tprivate publishGoalTerminalRecords(records: readonly LaneRecord[]): void {\n\t\tfor (const record of records) {\n\t\t\tthis.scheduler.dropQueued(record.laneId);\n\t\t\tthis.laneAbortControllers.get(record.laneId)?.abort(\"goal_terminal\");\n\t\t\tthis.publishTerminalRecord(record);\n\t\t}\n\t}\n\n\tprivate recoverDurableQueue(): void {\n\t\tif (this.recoveringDurableState) return;\n\t\tthis.recoveringDurableState = true;\n\t\tconst lifecycle = this.getWorkerLifecycle();\n\t\ttry {\n\t\t\tif (!this.queueRecovered) {\n\t\t\t\tfor (const { attempt, record, verificationOfTaskId } of lifecycle.recoverQueued()) {\n\t\t\t\t\tconst request: WorkerDelegationRequest = {\n\t\t\t\t\t\tinstructions: attempt.dispatch.instructions,\n\t\t\t\t\t\tprofileId: attempt.dispatch.profileId,\n\t\t\t\t\t\t...(verificationOfTaskId ? { verificationOfTaskId } : {}),\n\t\t\t\t\t};\n\t\t\t\t\tthis.scheduler.enqueue(record, request, true, verificationOfTaskId !== undefined);\n\t\t\t\t}\n\t\t\t\tthis.queueRecovered = true;\n\t\t\t}\n\t\t\tfor (const recovery of lifecycle.getPendingVerificationRecoveries()) {\n\t\t\t\tif (recovery.action === \"reconcile\") {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tthis.publishTerminalRecord(lifecycle.reconcileVerification(recovery));\n\t\t\t\t\t\tthis.verificationRecoveryFailures.delete(recovery.subjectTaskId);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis.safeWarn(\n\t\t\t\t\t\t\t`Failed to reconcile recovered verification for ${recovery.subjectTaskId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst legacyImplementation = recovery.verifierExecutionContract\n\t\t\t\t\t? undefined\n\t\t\t\t\t: this.resolveWorkerAdmission({\n\t\t\t\t\t\t\tinstructions: recovery.summary,\n\t\t\t\t\t\t\tprofileId: recovery.implementationProfileId,\n\t\t\t\t\t\t});\n\t\t\t\tconst verifierProfileId =\n\t\t\t\t\trecovery.verifierExecutionContract?.worker.profile.profileId ??\n\t\t\t\t\t(legacyImplementation?.ok ? legacyImplementation.verifierShipment?.profile.profileId : undefined);\n\t\t\t\tconst started = verifierProfileId\n\t\t\t\t\t? this.startInternal(\n\t\t\t\t\t\t\tthis.buildVerifierRequest({\n\t\t\t\t\t\t\t\tsubjectTaskId: recovery.subjectTaskId,\n\t\t\t\t\t\t\t\tverifierProfileId,\n\t\t\t\t\t\t\t\tsummary: recovery.summary,\n\t\t\t\t\t\t\t\tartifactUris: recovery.artifactUris,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\trecovery.verifierExecutionContract,\n\t\t\t\t\t\t)\n\t\t\t\t\t: { started: false as const, skipReason: \"independent_verifier_unavailable\" };\n\t\t\t\tif (started.started) {\n\t\t\t\t\tthis.verificationRecoveryFailures.delete(recovery.subjectTaskId);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (this.verificationRecoveryFailures.get(recovery.subjectTaskId) !== started.skipReason) {\n\t\t\t\t\tthis.verificationRecoveryFailures.set(recovery.subjectTaskId, started.skipReason);\n\t\t\t\t\tthis.safeWarn(\n\t\t\t\t\t\t`Recovered verification for ${recovery.subjectTaskId} did not start: ${started.skipReason}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const notification of lifecycle.getPendingTerminalNotifications()) {\n\t\t\t\tthis.notifications.recordTerminal(notification.record, notification.notificationId);\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.recoveringDurableState = false;\n\t\t}\n\t}\n\n\tprivate laneCapabilityProfile(model: Model<Api>): ModelCapabilityProfile {\n\t\treturn deriveModelCapabilityProfile({\n\t\t\tcontextWindow: model.contextWindow,\n\t\t\tmode: this.deps.getSettingsManager().getModelCapabilitySettings().mode,\n\t\t});\n\t}\n\n\tgetProfileCatalog(): Array<{ profileId: string; role: string; description: string }> {\n\t\treturn this.getWorkerProfileResolver().catalog();\n\t}\n\n\tprivate resolveWorkerShipment(\n\t\trequest: WorkerDelegationRequest,\n\t\tsettings: ResolvedWorkerDelegationSettings,\n\t): { ok: true; shipment: ResolvedWorkerProfile } | { ok: false; skipReason: string } {\n\t\tconst resolved = this.getWorkerProfileResolver().resolve(request, settings.orchestrationProfile);\n\t\treturn resolved.ok ? { ok: true, shipment: resolved.resolved } : { ok: false, skipReason: resolved.reason };\n\t}\n\n\tprivate resolveRequiredVerifier(\n\t\tprofile: OrchestrationProfile,\n\t): { ok: true; shipment?: ResolvedWorkerProfile } | { ok: false; skipReason: string } {\n\t\tif (!profile.requireIndependentVerification) return { ok: true };\n\t\tconst resolved = this.getWorkerProfileResolver().resolveVerifier(profile);\n\t\treturn resolved.ok\n\t\t\t? { ok: true, shipment: resolved.resolved }\n\t\t\t: { ok: false, skipReason: `independent_verifier_unavailable:${resolved.reason}` };\n\t}\n\n\t/** Single admission contract shared by enqueue, scheduler revalidation, and execution. */\n\tprivate resolveWorkerAdmission(\n\t\trequest: WorkerDelegationRequest,\n\t\tpinnedContract?: WorkerExecutionContract,\n\t): WorkerAdmission {\n\t\tif (this.deps.isDisposed()) return { ok: false, skipReason: \"session_disposed\" };\n\t\tconst instructions = request.instructions.trim();\n\t\tif (!instructions) return { ok: false, skipReason: \"missing_instructions\" };\n\t\tif (!this.deps.isDelegateToolActive()) return { ok: false, skipReason: \"delegate_tool_inactive\" };\n\t\tconst settings = this.deps.getSettingsManager().getWorkerDelegationSettings();\n\t\tif (!settings.enabled) return { ok: false, skipReason: \"worker_delegation_disabled\" };\n\t\tif (pinnedContract && request.profileId && request.profileId !== pinnedContract.worker.profile.profileId) {\n\t\t\treturn { ok: false, skipReason: \"orchestration_execution_contract_mismatch\" };\n\t\t}\n\t\tconst resolved = pinnedContract\n\t\t\t? this.getWorkerProfileResolver().resolveContract(pinnedContract.worker)\n\t\t\t: this.resolveWorkerShipment(request, settings);\n\t\tif (!resolved.ok) {\n\t\t\treturn { ok: false, skipReason: \"skipReason\" in resolved ? resolved.skipReason : resolved.reason };\n\t\t}\n\t\tconst shipment = \"shipment\" in resolved ? resolved.shipment : resolved.resolved;\n\t\tif (request.verificationOfTaskId && shipment.profile.role !== \"verifier\") {\n\t\t\treturn { ok: false, skipReason: \"verification_profile_role_mismatch\" };\n\t\t}\n\t\tif (!request.verificationOfTaskId && shipment.profile.role === \"verifier\") {\n\t\t\treturn { ok: false, skipReason: \"verifier_profile_requires_runtime_dispatch\" };\n\t\t}\n\t\tlet verifierShipment: ResolvedWorkerProfile | undefined;\n\t\tif (pinnedContract?.verifier) {\n\t\t\tconst verifier = this.getWorkerProfileResolver().resolveContract(pinnedContract.verifier);\n\t\t\tif (!verifier.ok) {\n\t\t\t\treturn { ok: false, skipReason: `independent_verifier_unavailable:${verifier.reason}` };\n\t\t\t}\n\t\t\tverifierShipment = verifier.resolved;\n\t\t} else {\n\t\t\tconst verifier = this.resolveRequiredVerifier(shipment.profile);\n\t\t\tif (!verifier.ok) return verifier;\n\t\t\tverifierShipment = verifier.shipment;\n\t\t}\n\t\tif (!this.laneCapabilityProfile(shipment.model).backgroundLanesEnabled) {\n\t\t\treturn { ok: false, skipReason: \"model_delegation_unsupported\" };\n\t\t}\n\t\tconst currentExecutionPlan = this.buildWorkerExecutionPlan(shipment.profile, settings);\n\t\tconst executionPlan = pinnedContract\n\t\t\t? narrowWorkerExecutionPlan(pinnedContract.worker.authority, currentExecutionPlan)\n\t\t\t: currentExecutionPlan;\n\t\tconst executionContract =\n\t\t\tpinnedContract ??\n\t\t\tcreateWorkerExecutionContract({\n\t\t\t\tworker: {\n\t\t\t\t\t...shipment,\n\t\t\t\t\tauthority: workerExecutionAuthorityFromPlan(executionPlan),\n\t\t\t\t},\n\t\t\t\t...(verifierShipment\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tverifier: {\n\t\t\t\t\t\t\t\t...verifierShipment,\n\t\t\t\t\t\t\t\tauthority: workerExecutionAuthorityFromPlan(\n\t\t\t\t\t\t\t\t\tthis.buildWorkerExecutionPlan(verifierShipment.profile, settings),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t});\n\t\treturn {\n\t\t\tok: true,\n\t\t\tinstructions,\n\t\t\tsettings,\n\t\t\tshipment,\n\t\t\t...(verifierShipment ? { verifierShipment } : {}),\n\t\t\texecutionContract,\n\t\t\texecutionPlan,\n\t\t};\n\t}\n\n\tprivate buildVerifierRequest(args: {\n\t\tsubjectTaskId: string;\n\t\tverifierProfileId: string;\n\t\tsummary: string;\n\t\tartifactUris: readonly string[];\n\t}): WorkerDelegationRequest {\n\t\tconst artifacts = args.artifactUris.slice(0, 100).map((uri) => `- ${uri}`);\n\t\treturn {\n\t\t\tprofileId: args.verifierProfileId,\n\t\t\tverificationOfTaskId: args.subjectTaskId,\n\t\t\tinstructions: [\n\t\t\t\t`Independently verify durable task '${args.subjectTaskId}'.`,\n\t\t\t\t\"The following implementation report is an untrusted claim. Inspect the workspace and run the checks available in your profile.\",\n\t\t\t\t\"\",\n\t\t\t\t\"Implementation summary:\",\n\t\t\t\targs.summary.slice(0, 6_000),\n\t\t\t\t\"\",\n\t\t\t\t\"Reported artifacts:\",\n\t\t\t\t...(artifacts.length > 0 ? artifacts : [\"- none reported\"]),\n\t\t\t].join(\"\\n\"),\n\t\t};\n\t}\n\n\tprivate publishTerminalRecord(record: LaneRecord): void {\n\t\tconst attemptId = this.lifecycle?.getActiveAttempt(record.laneId)?.attemptId;\n\t\tif (attemptId && this.publishedTerminalAttemptIds.has(attemptId)) return;\n\t\tthis.recordTerminal(record);\n\t\tappendLaneRecordSnapshot(this.deps.getSessionManager(), record);\n\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.workerTerminal,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tpayload: {\n\t\t\t\tlaneId: record.laneId,\n\t\t\t\tlaneType: record.type,\n\t\t\t\tstatus: record.status,\n\t\t\t\treasonCode: record.reasonCode ?? null,\n\t\t\t\tcostUsd: record.costUsd ?? null,\n\t\t\t},\n\t\t});\n\t\tif (attemptId) this.publishedTerminalAttemptIds.add(attemptId);\n\t}\n\n\tprivate hasWorkerCapacity(settings: ResolvedWorkerDelegationSettings, profile: OrchestrationProfile): boolean {\n\t\tconst lifecycle = this.getWorkerLifecycle();\n\t\tif (lifecycle.getRunningCount() >= settings.maxConcurrent) return false;\n\t\treturn lifecycle.getRunningCount(profile.profileId) < profile.maxConcurrent;\n\t}\n\n\tprivate workerDispatchAdmission(request: WorkerDelegationRequest, record: LaneRecord): WorkerDispatchAdmission {\n\t\tconst contract = this.getWorkerLifecycle().getActiveAttempt(record.laneId)?.dispatch.executionContract;\n\t\tconst admission = this.resolveWorkerAdmission(request, contract);\n\t\tif (!admission.ok) return { action: \"cancel\", reasonCode: admission.skipReason };\n\t\treturn this.hasWorkerCapacity(admission.settings, admission.shipment.profile)\n\t\t\t? { action: \"start\" }\n\t\t\t: { action: \"wait\" };\n\t}\n\n\tprivate buildWorkerExecutionPlan(\n\t\tprofile: OrchestrationProfile,\n\t\tsettings: ResolvedWorkerDelegationSettings,\n\t): WorkerExecutionPlan {\n\t\treturn buildWorkerExecutionPlan({\n\t\t\tprofile,\n\t\t\tsettings,\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\tdeniedPaths: getPrivateLaneDeniedPaths(this.deps.getCwd(), this.deps.getAgentDir()),\n\t\t\tforegroundMaxCostUsd: this.deps.getCapabilityEnvelope()?.maxEstimatedUsd,\n\t\t\tmemoryEnabled: this.deps.getSettingsManager().getMemoryRetrievalSettings().enabled,\n\t\t});\n\t}\n\n\t/** One durable preparation path for queued, immediate, and recovered execution. */\n\tprivate prepareWorkerAttempt(\n\t\trequest: WorkerDelegationRequest,\n\t\tadmission: Extract<WorkerAdmission, { ok: true }>,\n\t\texistingRecord?: LaneRecord,\n\t): PreparedWorkerAttempt {\n\t\tconst lifecycle = this.getWorkerLifecycle();\n\t\tif (existingRecord) {\n\t\t\treturn {\n\t\t\t\texecutionPlan: admission.executionPlan,\n\t\t\t\tlifecycle,\n\t\t\t\trecord: existingRecord,\n\t\t\t\tattempt: lifecycle.getActiveAttempt(existingRecord.laneId),\n\t\t\t};\n\t\t}\n\t\tconst goal = this.deps.getGoalStateSnapshot();\n\t\tconst prepared = lifecycle.prepare({\n\t\t\tinstructions: admission.instructions,\n\t\t\texecutionContract: admission.executionContract,\n\t\t\trequiredCapabilities: admission.executionPlan.requiredCapabilities,\n\t\t\t...(request.verificationOfTaskId ? { verificationOfTaskId: request.verificationOfTaskId } : {}),\n\t\t\t...(goal ? { goal } : {}),\n\t\t});\n\t\treturn { executionPlan: admission.executionPlan, lifecycle, ...prepared };\n\t}\n\n\tstart(\n\t\trequest: WorkerDelegationRequest,\n\t): { started: false; skipReason: string } | { started: true; record: LaneRecord } {\n\t\treturn this.startInternal(request);\n\t}\n\n\tprivate startInternal(\n\t\trequest: WorkerDelegationRequest,\n\t\tpinnedContract?: WorkerExecutionContract,\n\t): { started: false; skipReason: string } | { started: true; record: LaneRecord } {\n\t\tconst admission = this.resolveWorkerAdmission(request, pinnedContract);\n\t\tif (!admission.ok) return { started: false, skipReason: admission.skipReason };\n\t\tif (!request.verificationOfTaskId) this.recoverDurableQueue();\n\t\tconst { settings, shipment } = admission;\n\n\t\tconst foreground = this.deps.getModel();\n\t\tconst contendsWithLocalForeground =\n\t\t\tforeground !== undefined && isLocalExecutionModel(foreground) && isLocalExecutionModel(shipment.model);\n\t\tif (contendsWithLocalForeground || !this.hasWorkerCapacity(settings, shipment.profile)) {\n\t\t\t// A mandatory verifier is the continuation of an already admitted implementation, not a\n\t\t\t// new owner request. Reserve its queue admission so a burst of ordinary work cannot strand\n\t\t\t// the subject behind `independent_verification_required` with no terminal handoff.\n\t\t\tif (this.scheduler.queuedCount >= 8 && !request.verificationOfTaskId) {\n\t\t\t\treturn { started: false, skipReason: \"worker_delegation_queue_full\" };\n\t\t\t}\n\t\t\tlet record: LaneRecord;\n\t\t\ttry {\n\t\t\t\trecord = this.prepareWorkerAttempt(request, admission).record;\n\t\t\t} catch (error) {\n\t\t\t\tthis.safeWarn(\n\t\t\t\t\t`Worker dispatch was not persisted: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t\treturn { started: false, skipReason: \"orchestration_ledger_error\" };\n\t\t\t}\n\t\t\tthis.scheduler.enqueue(\n\t\t\t\trecord,\n\t\t\t\t{ ...request, profileId: shipment.profile.profileId },\n\t\t\t\tfalse,\n\t\t\t\trequest.verificationOfTaskId !== undefined,\n\t\t\t);\n\t\t\tthis.notifications.statusChanged();\n\t\t\treturn { started: true, record };\n\t\t}\n\t\tlet startedRecord: LaneRecord | undefined;\n\t\tconst promise = this.runOnceWithAdmission(\n\t\t\trequest,\n\t\t\t(record) => {\n\t\t\t\tstartedRecord = record;\n\t\t\t},\n\t\t\tundefined,\n\t\t\tadmission,\n\t\t);\n\t\tif (!startedRecord) {\n\t\t\t// Preparation is synchronous up to the first isolated completion await. A promise that\n\t\t\t// rejected before producing a lane is still observed below, so it cannot become unhandled.\n\t\t\tvoid promise.catch(() => undefined);\n\t\t\treturn { started: false, skipReason: \"worker_not_started\" };\n\t\t}\n\t\tthis.scheduler.track(startedRecord.laneId, promise);\n\t\treturn { started: true, record: startedRecord };\n\t}\n\n\tasync runOnce(\n\t\trequest: WorkerDelegationRequest,\n\t\tonStarted?: (record: LaneRecord) => void,\n\t\texistingRecord?: LaneRecord,\n\t): Promise<WorkerDelegationRunOutcome> {\n\t\treturn this.runOnceWithAdmission(request, onStarted, existingRecord);\n\t}\n\n\tprivate async runOnceWithAdmission(\n\t\trequest: WorkerDelegationRequest,\n\t\tonStarted?: (record: LaneRecord) => void,\n\t\texistingRecord?: LaneRecord,\n\t\tpreparedAdmission?: Extract<WorkerAdmission, { ok: true }>,\n\t): Promise<WorkerDelegationRunOutcome> {\n\t\tconst pinnedContract = existingRecord\n\t\t\t? this.getWorkerLifecycle().getActiveAttempt(existingRecord.laneId)?.dispatch.executionContract\n\t\t\t: undefined;\n\t\tconst admission = preparedAdmission ?? this.resolveWorkerAdmission(request, pinnedContract);\n\t\tif (!admission.ok) return { started: false, skipReason: admission.skipReason };\n\t\tif (!request.verificationOfTaskId) this.recoverDurableQueue();\n\t\tconst { instructions, settings, verifierShipment } = admission;\n\t\tconst { model, modelBinding, profile: orchestrationProfile, soul } = admission.shipment;\n\t\tif (!this.hasWorkerCapacity(settings, orchestrationProfile)) {\n\t\t\treturn { started: false, skipReason: \"worker_delegation_already_running\" };\n\t\t}\n\t\tconst laneCapability = this.laneCapabilityProfile(model);\n\t\tconst prepared = this.prepareWorkerAttempt(request, admission, existingRecord);\n\t\tconst { executionPlan, lifecycle } = prepared;\n\t\tif (!prepared.attempt) return { started: false, skipReason: \"orchestration_attempt_missing\" };\n\t\tconst durableTask = lifecycle.getTask(prepared.record.laneId);\n\t\tif (!durableTask) return { started: false, skipReason: \"orchestration_task_missing\" };\n\t\tconst compiled = compileWorkerExecutionGrant({\n\t\t\ttarget: {\n\t\t\t\tobjectiveId: durableTask.task.objectiveId,\n\t\t\t\ttaskId: prepared.attempt.taskId,\n\t\t\t\tattemptId: prepared.attempt.attemptId,\n\t\t\t},\n\t\t\tprofile: orchestrationProfile,\n\t\t\tplan: executionPlan,\n\t\t});\n\t\tif (!compiled.ok) {\n\t\t\tlifecycle.cancel(prepared.record.laneId, compiled.reasonCodes.join(\",\"));\n\t\t\treturn { started: false, skipReason: `execution_policy_denied:${compiled.reasonCodes.join(\",\")}` };\n\t\t}\n\t\tlifecycle.bindGrant(prepared.attempt.attemptId, compiled.grant);\n\t\tconst durableHandle = lifecycle.start(prepared.record.laneId, orchestrationProfile.leaseTtlMs);\n\t\tconst startedRecord = lifecycle.getRecord(prepared.record.laneId);\n\t\tif (!startedRecord) return { started: false, skipReason: \"orchestration_projection_missing\" };\n\t\tonStarted?.(startedRecord);\n\t\tconst maxUsd = compiled.grant.budget.maxCostUsd;\n\t\tconst executionPolicy = orchestrationProfile.executionPolicy;\n\t\tconst toolSurface = createLaneToolSurface({\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\treadMemory: executionPlan.readMemory ? (query) => this.deps.readMemoryForLane(query) : undefined,\n\t\t\twriteEnabled: executionPlan.writeEnabled,\n\t\t\twritePaths: executionPlan.writePaths,\n\t\t\t...(executionPlan.processEnabled && executionPolicy ? { executionPolicy } : {}),\n\t\t\tprocessMaxWallClockMs: compiled.grant.budget.maxWallClockMs ?? 0,\n\t\t\tgrant: compiled.grant,\n\t\t\ttoolManifests: executionPlan.toolManifests,\n\t\t});\n\t\tconst writeGranted =\n\t\t\texecutionPlan.writeEnabled &&\n\t\t\ttoolSurface.gateway !== undefined &&\n\t\t\ttoolSurface.allowedTools.some((name) => name === \"write\" || name === \"edit\");\n\t\tconst workerRequest: WorkerRequest = {\n\t\t\tid: startedRecord.laneId,\n\t\t\tinstructions,\n\t\t\troute: {\n\t\t\t\ttier: \"cheap\",\n\t\t\t\trisk: writeGranted ? \"scoped-write\" : \"read-only\",\n\t\t\t\tconfidence: 1,\n\t\t\t\treasonCode: \"profile_worker\",\n\t\t\t\treasons: [writeGranted ? \"Path-scoped worker delegation\" : \"Read-only worker delegation\"],\n\t\t\t},\n\t\t\tenvelope: {\n\t\t\t\tid: `worker-${this.deps.getSessionId()}-${startedRecord.laneId}`,\n\t\t\t\tprofileId: orchestrationProfile.profileId,\n\t\t\t\t// filesystem.write requires BOTH the opt-in AND an explicit non-empty path scope —\n\t\t\t\t// an unscoped write grant is refused here, not discovered at validation time.\n\t\t\t\tcapabilities: [...compiled.grant.capabilities],\n\t\t\t\t...(writeGranted ? { allowedPaths: [...compiled.grant.writePaths] } : {}),\n\t\t\t\tdeniedPaths: [...compiled.grant.deniedPaths],\n\t\t\t\tallowedTools: [...toolSurface.allowedTools],\n\t\t\t\tdeniedTools: [...toolSurface.deniedTools],\n\t\t\t\t...(maxUsd !== undefined ? { maxEstimatedUsd: maxUsd } : {}),\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t},\n\t\t\t...(maxUsd !== undefined ? { maxEstimatedUsd: maxUsd } : {}),\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t};\n\t\t// Worker delegation START. Routing/scope codes + budget only — never the instructions text.\n\t\tthis.deps.emitAutonomyTelemetry({\n\t\t\ttype: AUTONOMY_TELEMETRY_EVENT_TYPES.workerRequest,\n\t\t\ttimestamp: new Date().toISOString(),\n\t\t\tpayload: {\n\t\t\t\tid: workerRequest.id,\n\t\t\t\ttier: workerRequest.route.tier,\n\t\t\t\tcapabilities: [...workerRequest.envelope.capabilities],\n\t\t\t\tmaxEstimatedUsd: workerRequest.maxEstimatedUsd ?? null,\n\t\t\t},\n\t\t});\n\t\tconst usageReportId = `worker:${this.deps.getSessionId()}:${startedRecord.laneId}`;\n\t\tconst laneAbortController = new AbortController();\n\t\tthis.laneAbortControllers.set(startedRecord.laneId, laneAbortController);\n\t\tconst workerSignal = AbortSignal.any([this.workerAbort.signal, laneAbortController.signal]);\n\n\t\t// Registered for the lane's full run so the reload gate waits it out; deregistered in the\n\t\t// finally below no matter how this lane terminates (success, disposal, or a thrown error).\n\t\t// registerInFlightWork is a pure sync map op (cannot throw), so placing it as the last\n\t\t// statement before `try` still guarantees the matching finally always runs.\n\t\tconst deregisterInFlight = registerInFlightWork(\n\t\t\tthis.deps.getAgentDir(),\n\t\t\t\"lane\",\n\t\t\t`worker:${startedRecord.laneId}`,\n\t\t);\n\t\tconst durableStartedAt = Date.now();\n\t\ttry {\n\t\t\tlet spentUsage: Usage | undefined;\n\t\t\tconst toolChangedFiles = new Set<string>();\n\t\t\tconst toolIssues = new Set<string>();\n\t\t\t// Register the live mutation ledger BEFORE the suspend point below so a synchronous\n\t\t\t// disposal cutoff (`abortInFlightLanes`) can read a race-free snapshot of whatever this\n\t\t\t// worker has already applied — the worker is suspended at the `await runWorker(...)` below\n\t\t\t// whenever abort runs, and the abort signal stops further tool calls. Deleted in the\n\t\t\t// `finally` on every exit path (normal completion, throw, or already consumed by abort).\n\t\t\tthis.inFlightLedgers.set(startedRecord.laneId, {\n\t\t\t\tchangedFiles: toolChangedFiles,\n\t\t\t\tgetSpend: () => spentUsage,\n\t\t\t\tgetToolCalls: () => toolSurface.gateway?.getUsage().toolCalls ?? 0,\n\t\t\t\trequest: workerRequest,\n\t\t\t\thandle: durableHandle,\n\t\t\t\tstartedAt: durableStartedAt,\n\t\t\t});\n\t\t\tconst maxToolCalls = compiled.grant.budget.maxToolCalls ?? 0;\n\t\t\tconst rawOutcome = await runWorker({\n\t\t\t\trequest: workerRequest,\n\t\t\t\tmaxUsd,\n\t\t\t\tmaxWallClockMs: compiled.grant.budget.maxWallClockMs ?? 0,\n\t\t\t\tusageReportId,\n\t\t\t\tgetChangedFiles: () => [...toolChangedFiles],\n\t\t\t\tsignal: workerSignal,\n\t\t\t\t// Parent validation must use the same relative-path baseline the runner reports in.\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\tprocessCapable: executionPlan.processEnabled,\n\t\t\t\t...(request.verificationOfTaskId ? { verificationSubjectTaskId: request.verificationOfTaskId } : {}),\n\t\t\t\t// Write lane: runner-side action application through the envelope path scope.\n\t\t\t\tapplyActions: workerRequest.envelope.capabilities.includes(\"filesystem.write\")\n\t\t\t\t\t? (actions) => {\n\t\t\t\t\t\t\treturn applyWorkerActions({\n\t\t\t\t\t\t\t\tactions,\n\t\t\t\t\t\t\t\tgateway: toolSurface.gateway!,\n\t\t\t\t\t\t\t\ttoolManifests: executionPlan.toolManifests,\n\t\t\t\t\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\t\t\t\tcomplete: async ({ systemPrompt, userPrompt, signal }) => {\n\t\t\t\t\tconst completion = await this.deps.runIsolatedCompletion({\n\t\t\t\t\t\t// Level-0 core and owner-authored profile remain authoritative. The delegating\n\t\t\t\t\t\t// model supplies task instructions only; it cannot replace the worker role prompt.\n\t\t\t\t\t\tsystemPrompt: composeSubagentSystemPrompt({\n\t\t\t\t\t\t\tsoul,\n\t\t\t\t\t\t\trolePrompt: systemPrompt,\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tmessages: [{ role: \"user\", content: [{ type: \"text\", text: userPrompt }], timestamp: Date.now() }],\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tthinkingLevel: modelBinding.thinkingLevel,\n\t\t\t\t\t\tmaxTokens: Math.min(\n\t\t\t\t\t\t\tlaneCapability.laneMaxOutputTokens,\n\t\t\t\t\t\t\tcompiled.grant.budget.maxTokens ?? Number.POSITIVE_INFINITY,\n\t\t\t\t\t\t),\n\t\t\t\t\t\ttools: toolSurface.tools,\n\t\t\t\t\t\tmaxTurns: Math.max(1, Math.min(6, maxToolCalls + 1)),\n\t\t\t\t\t\tfinalTextPrompt:\n\t\t\t\t\t\t\t\"The tool-turn budget is exhausted. Do not call more tools. Return the required worker-claim JSON envelope now using only evidence already gathered. If the investigation is incomplete, say so in the summary or blockers instead of omitting the envelope.\",\n\t\t\t\t\t\tbeforeToolCall: async (context, toolSignal) => {\n\t\t\t\t\t\t\tconst decision = await toolSurface.beforeToolCall(context, toolSignal);\n\t\t\t\t\t\t\tif (decision?.block) {\n\t\t\t\t\t\t\t\ttoolIssues.add(`${context.toolCall.name} blocked: ${decision.reason ?? \"capability denied\"}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn decision;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tafterToolCall: async ({ toolCall, args, isError }) => {\n\t\t\t\t\t\t\t// This hook runs only for a validated, gate-approved tool that actually entered\n\t\t\t\t\t\t\t// execution. Record a direct mutation target before inspecting `isError`: write/edit\n\t\t\t\t\t\t\t// may have changed disk and then observed cancellation, timeout, or a late I/O error.\n\t\t\t\t\t\t\t// Pre-gate/profile/path refusals never reach afterToolCall, so they remain unreported.\n\t\t\t\t\t\t\tif (toolCall.name === \"write\" || toolCall.name === \"edit\") {\n\t\t\t\t\t\t\t\tif (args && typeof args === \"object\" && !Array.isArray(args)) {\n\t\t\t\t\t\t\t\t\tconst rawPath = (args as Record<string, unknown>).path;\n\t\t\t\t\t\t\t\t\tif (typeof rawPath === \"string\" && rawPath.length > 0) {\n\t\t\t\t\t\t\t\t\t\tconst absolutePath = path.isAbsolute(rawPath)\n\t\t\t\t\t\t\t\t\t\t\t? path.resolve(rawPath)\n\t\t\t\t\t\t\t\t\t\t\t: path.resolve(this.deps.getCwd(), rawPath);\n\t\t\t\t\t\t\t\t\t\tlet canonicalPath = absolutePath;\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tcanonicalPath = safeRealpathSync(absolutePath);\n\t\t\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t\t\t// Execution was attempted; preserve conservative accounting with the lexical path.\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\ttoolChangedFiles.add(\n\t\t\t\t\t\t\t\t\t\t\tpath.relative(this.deps.getCwd(), canonicalPath).split(path.sep).join(\"/\"),\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (isError) {\n\t\t\t\t\t\t\t\ttoolIssues.add(`${toolCall.name} failed during isolated execution`);\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\t// Core/soul/role are all static per configuration — the provider can cache the prefix.\n\t\t\t\t\t\tcacheRetention: \"short\",\n\t\t\t\t\t\t// Stable per-lane synthetic affinity key so repeat worker-delegation calls route to\n\t\t\t\t\t\t// the same cache-warm backend without carrying the real session id.\n\t\t\t\t\t\tlaneKind: \"worker\",\n\t\t\t\t\t});\n\t\t\t\t\tspentUsage = completion.usage;\n\t\t\t\t\ttoolSurface.gateway?.recordUsage({\n\t\t\t\t\t\tinputTokens: completion.usage.input,\n\t\t\t\t\t\toutputTokens: completion.usage.output,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttext: completion.text,\n\t\t\t\t\t\tcostUsd: completion.usage.cost.total,\n\t\t\t\t\t\tstopReason: String(completion.stopReason),\n\t\t\t\t\t\tchangedFiles: [...toolChangedFiles],\n\t\t\t\t\t\tblockers: [...toolIssues],\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst verificationRequired =\n\t\t\t\torchestrationProfile.requireIndependentVerification &&\n\t\t\t\torchestrationProfile.role !== \"verifier\" &&\n\t\t\t\trawOutcome.claim.status === \"completed\";\n\t\t\tconst outcome = verificationRequired\n\t\t\t\t? {\n\t\t\t\t\t\t...rawOutcome,\n\t\t\t\t\t\taccepted: false,\n\t\t\t\t\t\treasonCode: \"independent_verification_required\",\n\t\t\t\t\t\tacceptance: {\n\t\t\t\t\t\t\toutcome: \"ask-user\" as const,\n\t\t\t\t\t\t\tgate: \"independent_verification\",\n\t\t\t\t\t\t\treasonCode: \"independent_verification_required\",\n\t\t\t\t\t\t\tmessage: \"The owner-authored profile requires an independent verifier before acceptance.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\tclaim: {\n\t\t\t\t\t\t\t...rawOutcome.claim,\n\t\t\t\t\t\t\tparentReviewRequired: true,\n\t\t\t\t\t\t\tblockers: [\n\t\t\t\t\t\t\t\t...(rawOutcome.claim.blockers ?? []),\n\t\t\t\t\t\t\t\t\"independent verification is required before acceptance\",\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t}\n\t\t\t\t: rawOutcome;\n\n\t\t\t// Never persist against a disposed session. When disposal raced this\n\t\t\t// await, `abortInFlightLanes()`'s synchronous cutoff already completed this lane, persisted\n\t\t\t// its durable lane record + bounded WorkerClaim, and consumed (deleted) the ledger —\n\t\t\t// `.complete()` below is then a no-op (the lane is already terminal, so it returns\n\t\t\t// undefined) and no double persistence or duplicate terminal notification can happen here.\n\t\t\tif (this.deps.isDisposed()) {\n\t\t\t\tconst record = lifecycle.getRecord(startedRecord.laneId);\n\t\t\t\treturn { started: true, record, outcome };\n\t\t\t}\n\n\t\t\tconst verificationSubject = request.verificationOfTaskId\n\t\t\t\t? lifecycle.getTask(request.verificationOfTaskId)\n\t\t\t\t: undefined;\n\t\t\tlet record = lifecycle.finish(\n\t\t\t\tcreateWorkerResultContract({\n\t\t\t\t\thandle: durableHandle,\n\t\t\t\t\tclaim: outcome.claim,\n\t\t\t\t\taccepted: outcome.accepted,\n\t\t\t\t\tcostUsd: outcome.costUsd,\n\t\t\t\t\treasonCode: outcome.reasonCode,\n\t\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\t\t...(spentUsage\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tinputTokens: spentUsage.input,\n\t\t\t\t\t\t\t\toutputTokens: spentUsage.output,\n\t\t\t\t\t\t\t\ttotalTokens: spentUsage.totalTokens,\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t\twallClockMs: Date.now() - durableStartedAt,\n\t\t\t\t\ttoolCalls: toolSurface.gateway?.getUsage().toolCalls ?? 0,\n\t\t\t\t\tverificationRequired,\n\t\t\t\t\tverificationCriterionIds: verificationSubject?.task.acceptanceCriterionIds,\n\t\t\t\t}),\n\t\t\t\t{ notify: !verificationRequired },\n\t\t\t);\n\t\t\ttry {\n\t\t\t\tthis.deps.saveWorkerClaimSnapshot(outcome.claim, workerRequest);\n\t\t\t} catch (error) {\n\t\t\t\tthis.safeWarn(\n\t\t\t\t\t`Failed to persist worker claim ${startedRecord.laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (spentUsage && (spentUsage.cost.total > 0 || spentUsage.totalTokens > 0)) {\n\t\t\t\tthis.deps.addSpawnedUsage(spentUsage, { label: \"worker-delegation\", reportId: usageReportId });\n\t\t\t}\n\n\t\t\tconst terminalRecords: LaneRecord[] = [record];\n\t\t\tif (request.verificationOfTaskId) {\n\t\t\t\tconst decision = outcome.accepted ? outcome.claim.verification : undefined;\n\t\t\t\tconst subject = lifecycle.reconcileVerification({\n\t\t\t\t\tsubjectTaskId: request.verificationOfTaskId,\n\t\t\t\t\tverifierTaskId: startedRecord.laneId,\n\t\t\t\t\tverifierAttemptId: durableHandle.attemptId,\n\t\t\t\t\tverdict: decision?.verdict ?? \"inconclusive\",\n\t\t\t\t\treasonCode: decision\n\t\t\t\t\t\t? decision.verdict === \"accepted\"\n\t\t\t\t\t\t\t? \"independent_verification_accepted\"\n\t\t\t\t\t\t\t: `independent_verification_rejected:${decision.reasonCodes.join(\",\")}`\n\t\t\t\t\t\t: `independent_verification_inconclusive:${outcome.reasonCode}`,\n\t\t\t\t});\n\t\t\t\tterminalRecords.push(subject);\n\t\t\t} else if (verificationRequired) {\n\t\t\t\tconst verifierStart = verifierShipment\n\t\t\t\t\t? this.startInternal(\n\t\t\t\t\t\t\tthis.buildVerifierRequest({\n\t\t\t\t\t\t\t\tsubjectTaskId: startedRecord.laneId,\n\t\t\t\t\t\t\t\tverifierProfileId: verifierShipment.profile.profileId,\n\t\t\t\t\t\t\t\tsummary: rawOutcome.claim.summary,\n\t\t\t\t\t\t\t\tartifactUris: rawOutcome.claim.changedFiles,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tverifierWorkerExecutionContract(admission.executionContract),\n\t\t\t\t\t\t)\n\t\t\t\t\t: { started: false as const, skipReason: \"independent_verifier_unavailable\" };\n\t\t\t\tif (verifierStart.started) {\n\t\t\t\t\t// The durable verifier dispatch is now the terminal-work owner. The subject remains\n\t\t\t\t\t// blocked and emits no compatibility terminal snapshot until reconciliation.\n\t\t\t\t\tterminalRecords.length = 0;\n\t\t\t\t\tthis.scheduler.drain();\n\t\t\t\t} else {\n\t\t\t\t\tthis.safeWarn(\n\t\t\t\t\t\t`Independent verifier for ${startedRecord.laneId} did not start: ${verifierStart.skipReason}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (outcome.acceptance.outcome === \"ask-user\" && terminalRecords.length > 0) {\n\t\t\t\tthis.deps.queueWorkerHumanInput({\n\t\t\t\t\tworkerRequestId: startedRecord.laneId,\n\t\t\t\t\tmessage: outcome.acceptance.message ?? \"Worker output requires owner review.\",\n\t\t\t\t\tblockers: outcome.claim.blockers ?? [],\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const terminalRecord of terminalRecords) {\n\t\t\t\tthis.publishTerminalRecord(terminalRecord);\n\t\t\t}\n\t\t\tif (request.verificationOfTaskId) {\n\t\t\t\trecord = lifecycle.getRecord(startedRecord.laneId) ?? record;\n\t\t\t}\n\t\t\treturn { started: true, record, outcome };\n\t\t} catch (error) {\n\t\t\tconst durableState = lifecycle.ledger.runtime.getSnapshot().attempts[durableHandle.attemptId];\n\t\t\tif (durableState?.status === \"cancelled\" && (laneAbortController.signal.aborted || this.deps.isDisposed())) {\n\t\t\t\treturn { started: true, record: lifecycle.getRecord(startedRecord.laneId) };\n\t\t\t}\n\t\t\tif (durableState?.status === \"running\" || durableState?.status === \"leased\") {\n\t\t\t\tconst failureClaim: WorkerClaim = {\n\t\t\t\t\trequestId: startedRecord.laneId,\n\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\tsummary: `Worker delegation failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\tchangedFiles: [],\n\t\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t\t};\n\t\t\t\ttry {\n\t\t\t\t\tlifecycle.finish(\n\t\t\t\t\t\tcreateWorkerResultContract({\n\t\t\t\t\t\t\thandle: durableHandle,\n\t\t\t\t\t\t\tclaim: failureClaim,\n\t\t\t\t\t\t\taccepted: false,\n\t\t\t\t\t\t\tcostUsd: 0,\n\t\t\t\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\t\t\t\twallClockMs: Date.now() - durableStartedAt,\n\t\t\t\t\t\t\ttoolCalls: toolSurface.gateway?.getUsage().toolCalls ?? 0,\n\t\t\t\t\t\t\treasonCode: \"worker_delegation_error\",\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t} catch (persistError) {\n\t\t\t\t\tthis.safeWarn(\n\t\t\t\t\t\t`Failed to persist durable worker failure ${startedRecord.laneId}: ${persistError instanceof Error ? persistError.message : String(persistError)}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet record = lifecycle.getRecord(startedRecord.laneId);\n\t\t\tif (record?.status === \"queued\" || record?.status === \"running\") {\n\t\t\t\trecord = lifecycle.cancel(startedRecord.laneId, \"worker_delegation_error\");\n\t\t\t}\n\t\t\tif (record && !this.deps.isDisposed()) this.publishTerminalRecord(record);\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.deps.emit({ type: \"warning\", message: `Worker delegation failed: ${message}` });\n\t\t\treturn { started: true, record };\n\t\t} finally {\n\t\t\tthis.inFlightLedgers.delete(startedRecord.laneId);\n\t\t\tthis.laneAbortControllers.delete(startedRecord.laneId);\n\t\t\tderegisterInFlight();\n\t\t}\n\t}\n\n\t/** Start every capacity-eligible queued worker at the owner session's foreground-idle boundary. */\n\tdrain(): void {\n\t\tthis.recoverDurableQueue();\n\t\tthis.scheduler.drain();\n\t}\n}\n"]}
|