@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
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
|
+
## [0.81.40] - 2026-07-24
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
|
|
5
|
+
- Added one targeted `accept:core-workflows` gate covering active-worker crash/restart fencing, simultaneous durable writers, repeated compaction/reopen cleanup, provider-neutral routing/reasoning/result/retry contracts, and adversarial UAC omission without running the full test suite.
|
|
6
|
+
- Added owner-authored orchestration profiles with pinned model/thinking/tool/resource/budget policy, architect-owned worker allowlists, durable DAG attempts and fenced typed results, exact-session process-worker resume, and a constrained direct-argv `run_process` launcher for execution profiles.
|
|
7
|
+
- Added one event-driven native interaction layer for human questions, task steps, and worker lanes: batched single/multi-select questions with unrestricted custom text, clipboard image attachments, skip/review flows, grouped width-bounded work status, durable human worker labels/profile ids, quiet idle behavior, progressive evidence detail, and host-owned lifecycle across extension reload and session resume. Worker UAC excludes the question tool before construction, and the legacy question examples now adapt this native contract instead of carrying two UI implementations.
|
|
8
|
+
- Added a bounded session image store for clipboard attachments, configurable through `images.clipboardDirectory`, with stable numbered references that survive `/resume` and deterministic latest-image resolution for prompts such as “look at the image.”
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed Windows startup migration of the NTFS `auth.json:Zone.Identifier` alternate data stream so its bytes move into bounded legacy state and the named stream is removed without rewriting the auth file.
|
|
13
|
+
- Persisted one immutable admission-time worker execution contract across queueing, retry, restart recovery, and mandatory verifier recovery, so profile edits cannot silently switch a pending worker's model, thinking level, tools, execution policy, or resource identity; current host policy may still narrow the recorded authority.
|
|
14
|
+
- Rebased durable-runtime startup tails onto a projection snapshot installed during the initial read, preventing a concurrent compaction from replaying post-snapshot events without their prefix.
|
|
15
|
+
- Made durable orchestration replay and append fail closed on missing event ordinals, truncated tails, inaccessible storage, invalid snapshot idempotency data, and missing or changed published snapshots without reparsing an unchanged projection on every append.
|
|
16
|
+
- Fenced process-matrix reconciliation, adoption, cleanup, self-owned heartbeat/exit, resumed-worker PID publication, terminal persistence, and delivery acknowledgement with one shared per-entry conditional-write contract so stale process generations cannot overwrite newer registrations.
|
|
17
|
+
- Made session teardown, activation, and quit failures drain every cleanup step; replacement failures reconstruct and rebind the previous durable session, clean rejected candidate resources/artifacts, remain distinct from post-commit callbacks, and serialize process disposal behind any admitted replacement.
|
|
18
|
+
- Made session replacement transactional through candidate preparation and awaited old-session resource shutdown, moved process/worktree supervision under the active session lifecycle, restored exact session+task workers only after goal activation, persisted late terminal notices for replay to the owning session, denied automatic recovery for mismatched or terminal goals, and bounded process-matrix retention.
|
|
19
|
+
- Fenced overlapping session replacements and RPC prompt/replacement races, and made durable worker terminal notifications acknowledge delivery only after the bounded parent handoff is persisted; owner-question handoffs no longer spend a redundant model turn.
|
|
20
|
+
- Made `/resume`, `--resume`, `--continue`, and exact `--session` restore a blocked goal through the same core persisted transition as `/goal resume`, before worker supervision starts.
|
|
21
|
+
- Bounded durable orchestration persistence with immutable digest-verified projection snapshots, a count/byte-limited append-only event tail, bounded retained idempotency evidence, crash-safe pointer publication, and monotonic ordinals across compaction and concurrent-runtime catch-up.
|
|
22
|
+
- Made owner-input requests crash-safe and transport-neutral: `ask_question` now checkpoints before display, uses the full multi-line editor without an answer-length clamp, RPC exposes the same fail-closed typed question protocol as the TUI, `/resume` replays the original tool-call id, large custom answers remain exact in bounded artifacts, RPC images are retained before checkpoint, client-forged artifact references are rejected, non-vision image submission fails visibly, and worker `ask-user` verdicts create deterministic parent requests instead of relying on prompt compliance.
|
|
23
|
+
- Made the clipboard paste action match platform conventions (`Ctrl+V` on Unix/macOS, `Alt+V` on Windows, both on WSL), preserve ordinary text paste when no image is present, resize image payloads through the shared safety path, and keep default storage out of working directories.
|
|
24
|
+
- Added a zero-write, single-namespace extension storage contract for durable state, rebuildable cache, and automatically released bounded work; extension loading now honors injected agent directories for transform cache and storage, while `pi doctor` reports unexpected root writers through a bounded read-only audit.
|
|
25
|
+
- Contained directory profile overlays and configuration backups under canonical `profiles/` and `state/` namespaces, archived obsolete root scratch/Auto Learn layouts, and added bounded conflict-preserving migration with zero-write legacy reads.
|
|
26
|
+
- Consolidated generated context payloads under one leased, bounded per-session work namespace; context/report inspection and unflushed session creation are now zero-write, recognized legacy stores migrate safely, and empty session namespaces are pruned without applying retention to transcripts.
|
|
27
|
+
- Consolidated fitness, adaptation, and tool-selection host state behind one validated lock-safe atomic store; concurrent sessions no longer overwrite profile or tool evidence, and worker read-only mode remains zero-write.
|
|
28
|
+
- Extracted managed tmux-worker lifecycle and claim review from the background coordinator, made managed and in-process workers share one durable task runtime and terminal outbox without materializing a withheld execution controller, required every managed dispatch to carry its fixed profile, authorization, instruction, provider, turn, lease, tool, path, and budget contract, persisted the full compiled execution grant before process/prompt side effects, rejected scope-changing follow-ups, removed the extension's duplicate parent wake path, removed the research controller's circular dependency on its parent, and renamed raw worker-claim modules so untrusted claims are no longer presented as durable results.
|
|
29
|
+
- Consolidated failure-corpus, tool-recovery, and worktree-audit persistence behind one lock-safe bounded JSONL sink; worktree audit is no longer unbounded, concurrent failure-corpus rotation cannot lose appends, and worker terminal telemetry no longer masquerades as an accepted result.
|
|
30
|
+
- Unified process supervision and durable orchestration on one logical-agent identity, pinned initial tmux workers and exact-session resumes to the same managed lane, and made resume prefer the persisted session file while rejecting divergent lane context.
|
|
31
|
+
- Separated untrusted worker claims from host-fenced durable worker results, removed parallel result adapters, and made session, goal, status, telemetry, and review projections use the claim contract without implying worker self-report is accepted task truth.
|
|
32
|
+
- Unified capability envelopes, profile grants, lane construction, runtime gates, research policy, and worker execution on one canonical capability vocabulary; equivalent grants such as `worktree.read` and `tests.execute` now survive through execution instead of failing a second translated gate.
|
|
33
|
+
- Consolidated foreground envelopes, runtime gates, orchestration profile validation, and lane manifests behind one tool-capability policy catalog; active network, skill, source, verifier, and status tools no longer disappear from capability visibility while separate authorization tables drift.
|
|
34
|
+
- Unified goal and durable-objective acceptance/lifecycle transitions: every satisfied requirement now needs its own trusted proof, goal pause/resume/cancel/complete reconciles already-loaded worker execution without defeating lazy UAC, terminal objectives cancel residual attempts with explicit reasons, and worker terminal publication has one idempotent path.
|
|
35
|
+
- Consolidated goal requirements, foreground task steps, and delegated DAG work behind one identity-based read model; task steps now persist explicit requirement links, legacy text inference has one conservative fallback, and worker dispatch synchronizes durable objective acceptance criteria without treating worker self-report as proof.
|
|
36
|
+
- Consolidated versioned session snapshot persistence, validation, defensive cloning, list reads, latest reads, and branch-ancestry fallback behind one typed codec shared by goal, task, evidence, learning/audit, lane, and worker state; live accessors and review acknowledgements now read one active branch while diagnostics retain explicit whole-session history, and domain validators share explicit plain-record and general record-object guards.
|
|
37
|
+
- Consolidated worker admission, profile/verifier resolution, capability checks, durable attempt preparation, and resumed lane-id allocation so immediate, queued, recovered, and scheduler-revalidated dispatches share one policy contract, durable tasks are the sole identity source, and a lifecycle instantiated before late durable writes cannot reuse an existing lane id.
|
|
38
|
+
- Unified managed-worker identity across dispatch, goal binding, persistence, reload recovery, and terminal reporting; running tmux lanes now restore under the same durable id instead of degrading into indeterminate bindings after `/reload`.
|
|
39
|
+
- Persisted per-check compaction verification score ranges across retry fallback and surfaced them in session analytics and `/usage` diagnostics.
|
|
40
|
+
- Made foreground prompt preparation transactional: routing events stay balanced, failed extension preflight retains pending `nextTurn` context, queued messages cannot reset active-turn cost accounting, and pre-start execution failures release early-painted message identities.
|
|
41
|
+
- Consolidated terminal foreground response handling behind one recovery coordinator with deterministic transient retry, quota failover, retry closeout, compaction, and queued-continuation ordering.
|
|
42
|
+
- Consolidated manual and automatic compaction detection, execution, retry, cancellation, persistence, and extension notification behind one controller with a shared result-application path and provider-neutral policy types.
|
|
43
|
+
- Consolidated foreground model tool-protocol selection, probing, calibration, circuit breaking, repair teaching, and turn-local telemetry into one controller shared by session call sites.
|
|
44
|
+
- Made execution policy a mandatory durable pre-lease gate: approvals and owner notifications now replay, approval never grants authority without a newly compiled grant, paused objectives cannot start or resume work, and workers bind their grant before entering leased/running state.
|
|
45
|
+
- Split goal auto-continuation, autonomous research, model-fitness probing, and shared lane-model resolution into single-owner controllers, leaving the background facade responsible only for composition and the separate managed-lane bridge.
|
|
46
|
+
- Moved durable worker scheduling, execution, recovery, verification, and terminal notification behind one controller; capacity-bound workers now queue consistently across providers, owner-pinned verifier profiles run automatically before acceptance and retry event-driven recovery after temporary admission failures, and dead Pi workers resume the exact persisted session and logical-agent identity with checkpoint/resource handoff.
|
|
47
|
+
- Consolidated worker profile resolution, risk classification, capability grants, execution budgets, lifecycle state, structured-action enforcement, and terminal notifications behind single-owner contracts; removed delegate/settings authority overrides, made undelivered in-process terminal handoffs resume-safe, and enforced trusted acceptance evidence before task/objective completion.
|
|
48
|
+
- Made out-of-process managed workers emit the same bounded event-driven terminal handoff as in-process delegates, taught models to retrieve results once after that handoff instead of polling, and let unprofiled background lanes use the selected model's declared or provider-agnostic reasoning default.
|
|
49
|
+
- Unified foreground startup, background-lane defaults, and isolated-completion clamping through the shared provider-neutral model capability resolver.
|
|
50
|
+
- Made foreground and isolated worker tool routing share the same calibrated text-protocol variant instead of silently forcing subagents onto the default dialect.
|
|
51
|
+
- Classified process-matrix/tmux children as workers from their parent identity, and applied worker/resource-profile UAC before built-in/override tool construction and live extension import, so withheld tools invoke no runtime factory and denied extensions load no module code.
|
|
52
|
+
|
|
1
53
|
## [0.81.39] - 2026-07-20
|
|
2
54
|
|
|
3
55
|
### Added
|
package/README.md
CHANGED
|
@@ -323,6 +323,8 @@ Pi has two separate startup features:
|
|
|
323
323
|
|
|
324
324
|
Use `--offline` or `PI_OFFLINE=1` to disable all startup network operations described here, including update checks, package update checks, and install/update telemetry.
|
|
325
325
|
|
|
326
|
+
Runtime orchestration, recovery, and learning telemetry stays local. See [docs/telemetry.md](docs/telemetry.md) for its trust boundaries, locations, and retention rules.
|
|
327
|
+
|
|
326
328
|
---
|
|
327
329
|
|
|
328
330
|
## Context Files
|
|
@@ -105,6 +105,8 @@ export interface LaunchProfileSource {
|
|
|
105
105
|
*/
|
|
106
106
|
parentPid?: number;
|
|
107
107
|
parentSession?: string;
|
|
108
|
+
/** Stable goal/task identity used to fence process-matrix recovery. */
|
|
109
|
+
taskRef?: string;
|
|
108
110
|
}
|
|
109
111
|
/** A grant-covered launch derives its profile from the grant's envelope. */
|
|
110
112
|
export declare function launchProfileSourceFromGrant(grant: TmuxDispatchGrant): LaunchProfileSource;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-grant.d.ts","sourceRoot":"","sources":["../../../../src/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\n\n/**\n * The STANDING GRANT for approval-gated tmux dispatch (owner authorizes once via `grant_dispatch`;\n * the extension then dispatches unattended WITHIN the grant's bounds). Pure data + pure decode/decision\n * logic only — no session/tmux/filesystem access, so every function here is directly unit-testable.\n * The extension (index.ts) owns reading/writing session custom entries and calls into this module for\n * decoding and authorization decisions.\n *\n * HONEST TRUST BOUNDARY: this grant bounds WHO may be launched, HOW OFTEN, and WITH WHAT launch-time\n * envelope (pushed into the child's own CLI flags) — it never claims to gate the child's in-process\n * tool loop, which is a separate OS process outside this runtime's `beforeToolCall` machinery.\n */\n\nexport type Provider = \"pi\" | \"codex\" | \"agy\" | \"claude\" | \"opencode\" | \"custom\";\n\nexport const GRANT_CUSTOM_TYPE = \"tmux-dispatch-grant\";\nexport const GRANT_USAGE_CUSTOM_TYPE = \"tmux-dispatch-grant-usage\";\n\nexport interface TmuxDispatchGrantEnvelope {\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n}\n\nexport interface TmuxDispatchGrantBudget {\n\tmaxLaunches: number;\n\tmaxWallClockMs?: number;\n\tmaxUsdAdvisory?: number;\n}\n\nexport interface TmuxDispatchGrant {\n\tgrantId: string;\n\tcreatedAt: string;\n\tagent: Provider;\n\tscope: { goalId?: string };\n\tenvelope: TmuxDispatchGrantEnvelope;\n\tbudget: TmuxDispatchGrantBudget;\n\texpiresAt?: string;\n}\n\n/** Appended by `revoke_grant`. Shares `GRANT_CUSTOM_TYPE` so the SAME latest-on-branch read that\n * resolves an active grant also sees a revocation and stops treating any older grant beneath it as\n * active — a tombstone is a hard stop, never skipped over to resurrect an earlier grant. */\nexport interface TmuxDispatchGrantTombstone {\n\ttombstone: true;\n\tgrantId: string;\n\trevokedAt: string;\n}\n\nexport interface TmuxDispatchGrantUsage {\n\tgrantId: string;\n\tjobId: string;\n\tat: string;\n}\n\nconst PROVIDERS: readonly Provider[] = [\"pi\", \"codex\", \"agy\", \"claude\", \"opencode\", \"custom\"];\n\nfunction isProvider(value: unknown): value is Provider {\n\treturn typeof value === \"string\" && (PROVIDERS as readonly string[]).includes(value);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isTmuxDispatchGrantTombstone(value: unknown): value is TmuxDispatchGrantTombstone {\n\tif (!isPlainRecord(value)) return false;\n\treturn value.tombstone === true && typeof value.grantId === \"string\" && typeof value.revokedAt === \"string\";\n}\n\nexport function isTmuxDispatchGrant(value: unknown): value is TmuxDispatchGrant {\n\tif (!isPlainRecord(value) || value.tombstone === true) return false;\n\tif (typeof value.grantId !== \"string\" || typeof value.createdAt !== \"string\" || !isProvider(value.agent))\n\t\treturn false;\n\tif (!isPlainRecord(value.scope) || !isPlainRecord(value.envelope) || !isPlainRecord(value.budget)) return false;\n\treturn typeof value.budget.maxLaunches === \"number\" && Number.isFinite(value.budget.maxLaunches);\n}\n\nexport function isTmuxDispatchGrantUsage(value: unknown): value is TmuxDispatchGrantUsage {\n\tif (!isPlainRecord(value)) return false;\n\treturn typeof value.grantId === \"string\" && typeof value.jobId === \"string\" && typeof value.at === \"string\";\n}\n\nexport function makeGrantId(): string {\n\treturn `grant-${Date.now().toString(36)}-${crypto.randomBytes(4).toString(\"hex\")}`;\n}\n\nexport interface GrantCoverageRequest {\n\tagent: Provider;\n\tgoalId?: string;\n\tnowIso?: string;\n}\n\n/** Whether `grant` authorizes a launch for `request`: same agent, goal-scope match (an UNSCOPED grant\n * covers any goal including none; a goal-SCOPED grant covers ONLY that exact goalId), and the grant is\n * not past `expiresAt`. Budget (maxLaunches) is checked separately via {@link isGrantBudgetExhausted}\n * because counting usages requires the caller's session-entry access. */\nexport function grantCovers(grant: TmuxDispatchGrant, request: GrantCoverageRequest): boolean {\n\tif (grant.agent !== request.agent) return false;\n\tif (grant.scope.goalId && grant.scope.goalId !== request.goalId) return false;\n\tif (grant.expiresAt) {\n\t\tconst now = Date.parse(request.nowIso ?? new Date().toISOString());\n\t\tconst expiry = Date.parse(grant.expiresAt);\n\t\tif (Number.isFinite(expiry) && Number.isFinite(now) && now >= expiry) return false;\n\t}\n\treturn true;\n}\n\n/** Count spend entries for `grantId` among already-decoded custom-entry payloads (the caller walks the\n * session branch and passes the raw `data` values — this stays pure/session-agnostic). */\nexport function countGrantUsages(grantId: string, usageEntries: readonly unknown[]): number {\n\tlet count = 0;\n\tfor (const entry of usageEntries) if (isTmuxDispatchGrantUsage(entry) && entry.grantId === grantId) count++;\n\treturn count;\n}\n\nexport function isGrantBudgetExhausted(grant: TmuxDispatchGrant, usedCount: number): boolean {\n\treturn usedCount >= grant.budget.maxLaunches;\n}\n\nexport function buildGrantUsageEntry(\n\tgrantId: string,\n\tjobId: string,\n\tnowIso = new Date().toISOString(),\n): TmuxDispatchGrantUsage {\n\treturn { grantId, jobId, at: nowIso };\n}\n\nexport function buildTombstone(grantId: string, nowIso = new Date().toISOString()): TmuxDispatchGrantTombstone {\n\treturn { tombstone: true, grantId, revokedAt: nowIso };\n}\n\nexport interface GrantDispatchParams {\n\tagent: Provider;\n\tgoalId?: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\tmaxLaunches: number;\n\texpiresInMinutes?: number;\n\tmaxUsdAdvisory?: number;\n}\n\n/** Build a new grant record from `grant_dispatch` params. Pure — the caller (index.ts) owns the\n * approval gate (ui.confirm / opt-in flag) and the `pi.appendEntry` persistence; this only shapes the\n * data, so it stays independently testable and never itself decides whether creation is authorized. */\nexport function buildGrant(params: GrantDispatchParams, nowIso = new Date().toISOString()): TmuxDispatchGrant {\n\tif (!Number.isFinite(params.maxLaunches) || params.maxLaunches < 1)\n\t\tthrow new Error(\"grant_dispatch requires maxLaunches >= 1\");\n\tconst expiresAt =\n\t\tparams.expiresInMinutes !== undefined\n\t\t\t? new Date(Date.parse(nowIso) + Math.max(1, params.expiresInMinutes) * 60_000).toISOString()\n\t\t\t: undefined;\n\treturn {\n\t\tgrantId: makeGrantId(),\n\t\tcreatedAt: nowIso,\n\t\tagent: params.agent,\n\t\tscope: { goalId: params.goalId },\n\t\tenvelope: {\n\t\t\tallowedTools: params.allowedTools,\n\t\t\tresourceProfile: params.resourceProfile,\n\t\t\twritePaths: params.writePaths,\n\t\t},\n\t\tbudget: {\n\t\t\tmaxLaunches: Math.trunc(params.maxLaunches),\n\t\t\tmaxUsdAdvisory: params.maxUsdAdvisory,\n\t\t},\n\t\texpiresAt,\n\t};\n}\n\nexport function describeGrant(grant: TmuxDispatchGrant): string {\n\treturn [\n\t\t`Grant id: ${grant.grantId}`,\n\t\t`Agent: ${grant.agent}`,\n\t\tgrant.scope.goalId ? `Goal scope: ${grant.scope.goalId}` : \"Goal scope: none (covers any goal)\",\n\t\t`Max launches: ${grant.budget.maxLaunches}`,\n\t\tgrant.expiresAt ? `Expires: ${grant.expiresAt}` : \"Expires: never (until revoke_grant)\",\n\t\tgrant.envelope.allowedTools?.length\n\t\t\t? `Allowed tools: ${grant.envelope.allowedTools.join(\", \")}`\n\t\t\t: `Allowed tools: read-biased safe default (${DEFAULT_READ_BIASED_TOOLS.join(\", \")})`,\n\t\tgrant.envelope.resourceProfile\n\t\t\t? `Resource profile: ${grant.envelope.resourceProfile}`\n\t\t\t: \"Resource profile: none (child launches with --no-extensions --no-skills)\",\n\t\tgrant.envelope.writePaths?.length\n\t\t\t? `Write paths: ${grant.envelope.writePaths.join(\", \")}`\n\t\t\t: \"Write paths: none declared\",\n\t\tgrant.budget.maxUsdAdvisory !== undefined\n\t\t\t? `Advisory USD cap: ${grant.budget.maxUsdAdvisory} (not enforced across the process boundary — advisory only)`\n\t\t\t: undefined,\n\t]\n\t\t.filter((line): line is string => Boolean(line))\n\t\t.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Launch-profile flags: the REAL lever — pushed into the child `pi` CLI's own config.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_READ_BIASED_TOOLS: readonly string[] = [\"read\", \"grep\", \"find\", \"ls\"];\n\nexport interface LaunchProfileSource {\n\t/** Human-readable identity for the scoped system prompt (e.g. \"grant <id>\" or a one-shot label). */\n\tidentity: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\t/**\n\t * Worktree-sync lane key this launch is bound to (per-agent -- see `applyLaunchProfile`'s caller,\n\t * which builds a per-agent `LaunchProfileSource` only when that agent carries `worktreeLane`).\n\t * When present, `buildLaunchProfileFlags` appends `--worktree-lane <key>` (the same CLI flag\n\t * `src/cli/args.ts` already exposes, sugar over the `PI_WORKTREE_LANE` env contract) and\n\t * `buildScopedSystemPrompt` appends one lane-doctrine sentence.\n\t */\n\tworktreeLane?: string;\n\t/**\n\t * Process-matrix parent identity for this launch (see `core/process-matrix/runtime.ts`): the\n\t * dispatching process's own pid/sessionId. When present, `buildLaunchProfileFlags` appends\n\t * `--parent-pid`/`--parent-session` (sugar over `PI_PARENT_PID`/`PI_PARENT_SESSION`) so the\n\t * child self-registers as a worker of this session and winds down gracefully if it disappears.\n\t */\n\tparentPid?: number;\n\tparentSession?: string;\n}\n\n/** A grant-covered launch derives its profile from the grant's envelope. */\nexport function launchProfileSourceFromGrant(grant: TmuxDispatchGrant): LaunchProfileSource {\n\treturn {\n\t\tidentity: `grant ${grant.grantId}`,\n\t\tallowedTools: grant.envelope.allowedTools,\n\t\tresourceProfile: grant.envelope.resourceProfile,\n\t\twritePaths: grant.envelope.writePaths,\n\t};\n}\n\n/** A one-shot interactively-approved launch (no standing grant) still gets the conservative default\n * profile — approving a single launch is not the same as defining an unrestricted envelope. */\nexport const ONE_SHOT_LAUNCH_PROFILE_SOURCE: LaunchProfileSource = {\n\tidentity: \"a one-shot owner-approved tmux dispatch (no standing grant)\",\n};\n\nexport interface LaunchProfileFlag {\n\tflag: string;\n\tvalue?: string;\n}\n\n/** Build the CLI flags to append to a child `pi` invocation so the grant's envelope lives in the\n * child's OWN launch config (verified flag names: --tools, --resource-profile, --no-extensions,\n * --no-skills, --append-system-prompt). Never includes --no-approve: the child must keep gating its\n * own hard stops. */\nexport function buildLaunchProfileFlags(source: LaunchProfileSource): LaunchProfileFlag[] {\n\tconst tools = source.allowedTools?.length ? source.allowedTools : DEFAULT_READ_BIASED_TOOLS;\n\tconst flags: LaunchProfileFlag[] = [{ flag: \"--tools\", value: tools.join(\",\") }];\n\tif (source.resourceProfile) flags.push({ flag: \"--resource-profile\", value: source.resourceProfile });\n\telse flags.push({ flag: \"--no-extensions\" }, { flag: \"--no-skills\" });\n\tif (source.worktreeLane) flags.push({ flag: \"--worktree-lane\", value: source.worktreeLane });\n\tif (source.parentPid !== undefined) flags.push({ flag: \"--parent-pid\", value: String(source.parentPid) });\n\tif (source.parentSession) flags.push({ flag: \"--parent-session\", value: source.parentSession });\n\tflags.push({ flag: \"--append-system-prompt\", value: buildScopedSystemPrompt(source) });\n\treturn flags;\n}\n\nexport function buildScopedSystemPrompt(source: LaunchProfileSource): string {\n\tconst paths = source.writePaths?.length ? source.writePaths.join(\", \") : \"no additional paths granted\";\n\tconst sentences = [\n\t\t`You are a tmux worker dispatched under ${source.identity}.`,\n\t\t`Stay within these write paths: ${paths}.`,\n\t\t\"Hard stops — publishing/npm, git push, tagging a release, changing credentials/auth, or destructive deletion — require returning BLOCKED for owner approval. Never self-approve a hard stop.\",\n\t];\n\tif (source.worktreeLane) {\n\t\tsentences.push(\n\t\t\t`You are bound to worktree-sync lane '${source.worktreeLane}': work only inside this lane's own worktree, integrate exclusively via worktree_sync land, and never touch main directly.`,\n\t\t);\n\t}\n\treturn sentences.join(\" \");\n}\n\n// ---------------------------------------------------------------------------\n// Advisory worker usage claim: budget stays advisory across the process boundary.\n// ---------------------------------------------------------------------------\n\n/** Permissively decode a worker-reported usage CLAIM (a cooperative worker may write this to a\n * well-known sibling file before printing its completion marker). Read-defensive: missing/malformed\n * numeric fields default to 0 rather than throwing — this is untrusted, OPTIONAL, advisory input, never\n * an authoritative billing record. Returns undefined only when `raw` isn't even an object, so the\n * caller can distinguish \"no claim offered\" (skip reporting) from \"a claim was offered\" (report it,\n * however partial). */\nexport function decodeTmuxWorkerUsageClaim(raw: unknown): Usage | undefined {\n\tif (!isPlainRecord(raw)) return undefined;\n\tconst num = (value: unknown): number => (typeof value === \"number\" && Number.isFinite(value) ? value : 0);\n\tconst cost = isPlainRecord(raw.cost) ? raw.cost : {};\n\treturn {\n\t\tinput: num(raw.input),\n\t\toutput: num(raw.output),\n\t\tcacheRead: num(raw.cacheRead),\n\t\tcacheWrite: num(raw.cacheWrite),\n\t\ttotalTokens: num(raw.totalTokens),\n\t\tcost: {\n\t\t\tinput: num(cost.input),\n\t\t\toutput: num(cost.output),\n\t\t\tcacheRead: num(cost.cacheRead),\n\t\t\tcacheWrite: num(cost.cacheWrite),\n\t\t\ttotal: num(cost.total),\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dispatch-grant.d.ts","sourceRoot":"","sources":["../../../../src/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\n\n/**\n * The STANDING GRANT for approval-gated tmux dispatch (owner authorizes once via `grant_dispatch`;\n * the extension then dispatches unattended WITHIN the grant's bounds). Pure data + pure decode/decision\n * logic only — no session/tmux/filesystem access, so every function here is directly unit-testable.\n * The extension (index.ts) owns reading/writing session custom entries and calls into this module for\n * decoding and authorization decisions.\n *\n * HONEST TRUST BOUNDARY: this grant bounds WHO may be launched, HOW OFTEN, and WITH WHAT launch-time\n * envelope (pushed into the child's own CLI flags) — it never claims to gate the child's in-process\n * tool loop, which is a separate OS process outside this runtime's `beforeToolCall` machinery.\n */\n\nexport type Provider = \"pi\" | \"codex\" | \"agy\" | \"claude\" | \"opencode\" | \"custom\";\n\nexport const GRANT_CUSTOM_TYPE = \"tmux-dispatch-grant\";\nexport const GRANT_USAGE_CUSTOM_TYPE = \"tmux-dispatch-grant-usage\";\n\nexport interface TmuxDispatchGrantEnvelope {\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n}\n\nexport interface TmuxDispatchGrantBudget {\n\tmaxLaunches: number;\n\tmaxWallClockMs?: number;\n\tmaxUsdAdvisory?: number;\n}\n\nexport interface TmuxDispatchGrant {\n\tgrantId: string;\n\tcreatedAt: string;\n\tagent: Provider;\n\tscope: { goalId?: string };\n\tenvelope: TmuxDispatchGrantEnvelope;\n\tbudget: TmuxDispatchGrantBudget;\n\texpiresAt?: string;\n}\n\n/** Appended by `revoke_grant`. Shares `GRANT_CUSTOM_TYPE` so the SAME latest-on-branch read that\n * resolves an active grant also sees a revocation and stops treating any older grant beneath it as\n * active — a tombstone is a hard stop, never skipped over to resurrect an earlier grant. */\nexport interface TmuxDispatchGrantTombstone {\n\ttombstone: true;\n\tgrantId: string;\n\trevokedAt: string;\n}\n\nexport interface TmuxDispatchGrantUsage {\n\tgrantId: string;\n\tjobId: string;\n\tat: string;\n}\n\nconst PROVIDERS: readonly Provider[] = [\"pi\", \"codex\", \"agy\", \"claude\", \"opencode\", \"custom\"];\n\nfunction isProvider(value: unknown): value is Provider {\n\treturn typeof value === \"string\" && (PROVIDERS as readonly string[]).includes(value);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isTmuxDispatchGrantTombstone(value: unknown): value is TmuxDispatchGrantTombstone {\n\tif (!isPlainRecord(value)) return false;\n\treturn value.tombstone === true && typeof value.grantId === \"string\" && typeof value.revokedAt === \"string\";\n}\n\nexport function isTmuxDispatchGrant(value: unknown): value is TmuxDispatchGrant {\n\tif (!isPlainRecord(value) || value.tombstone === true) return false;\n\tif (typeof value.grantId !== \"string\" || typeof value.createdAt !== \"string\" || !isProvider(value.agent))\n\t\treturn false;\n\tif (!isPlainRecord(value.scope) || !isPlainRecord(value.envelope) || !isPlainRecord(value.budget)) return false;\n\treturn typeof value.budget.maxLaunches === \"number\" && Number.isFinite(value.budget.maxLaunches);\n}\n\nexport function isTmuxDispatchGrantUsage(value: unknown): value is TmuxDispatchGrantUsage {\n\tif (!isPlainRecord(value)) return false;\n\treturn typeof value.grantId === \"string\" && typeof value.jobId === \"string\" && typeof value.at === \"string\";\n}\n\nexport function makeGrantId(): string {\n\treturn `grant-${Date.now().toString(36)}-${crypto.randomBytes(4).toString(\"hex\")}`;\n}\n\nexport interface GrantCoverageRequest {\n\tagent: Provider;\n\tgoalId?: string;\n\tnowIso?: string;\n}\n\n/** Whether `grant` authorizes a launch for `request`: same agent, goal-scope match (an UNSCOPED grant\n * covers any goal including none; a goal-SCOPED grant covers ONLY that exact goalId), and the grant is\n * not past `expiresAt`. Budget (maxLaunches) is checked separately via {@link isGrantBudgetExhausted}\n * because counting usages requires the caller's session-entry access. */\nexport function grantCovers(grant: TmuxDispatchGrant, request: GrantCoverageRequest): boolean {\n\tif (grant.agent !== request.agent) return false;\n\tif (grant.scope.goalId && grant.scope.goalId !== request.goalId) return false;\n\tif (grant.expiresAt) {\n\t\tconst now = Date.parse(request.nowIso ?? new Date().toISOString());\n\t\tconst expiry = Date.parse(grant.expiresAt);\n\t\tif (Number.isFinite(expiry) && Number.isFinite(now) && now >= expiry) return false;\n\t}\n\treturn true;\n}\n\n/** Count spend entries for `grantId` among already-decoded custom-entry payloads (the caller walks the\n * session branch and passes the raw `data` values — this stays pure/session-agnostic). */\nexport function countGrantUsages(grantId: string, usageEntries: readonly unknown[]): number {\n\tlet count = 0;\n\tfor (const entry of usageEntries) if (isTmuxDispatchGrantUsage(entry) && entry.grantId === grantId) count++;\n\treturn count;\n}\n\nexport function isGrantBudgetExhausted(grant: TmuxDispatchGrant, usedCount: number): boolean {\n\treturn usedCount >= grant.budget.maxLaunches;\n}\n\nexport function buildGrantUsageEntry(\n\tgrantId: string,\n\tjobId: string,\n\tnowIso = new Date().toISOString(),\n): TmuxDispatchGrantUsage {\n\treturn { grantId, jobId, at: nowIso };\n}\n\nexport function buildTombstone(grantId: string, nowIso = new Date().toISOString()): TmuxDispatchGrantTombstone {\n\treturn { tombstone: true, grantId, revokedAt: nowIso };\n}\n\nexport interface GrantDispatchParams {\n\tagent: Provider;\n\tgoalId?: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\tmaxLaunches: number;\n\texpiresInMinutes?: number;\n\tmaxUsdAdvisory?: number;\n}\n\n/** Build a new grant record from `grant_dispatch` params. Pure — the caller (index.ts) owns the\n * approval gate (ui.confirm / opt-in flag) and the `pi.appendEntry` persistence; this only shapes the\n * data, so it stays independently testable and never itself decides whether creation is authorized. */\nexport function buildGrant(params: GrantDispatchParams, nowIso = new Date().toISOString()): TmuxDispatchGrant {\n\tif (!Number.isFinite(params.maxLaunches) || params.maxLaunches < 1)\n\t\tthrow new Error(\"grant_dispatch requires maxLaunches >= 1\");\n\tconst expiresAt =\n\t\tparams.expiresInMinutes !== undefined\n\t\t\t? new Date(Date.parse(nowIso) + Math.max(1, params.expiresInMinutes) * 60_000).toISOString()\n\t\t\t: undefined;\n\treturn {\n\t\tgrantId: makeGrantId(),\n\t\tcreatedAt: nowIso,\n\t\tagent: params.agent,\n\t\tscope: { goalId: params.goalId },\n\t\tenvelope: {\n\t\t\tallowedTools: params.allowedTools,\n\t\t\tresourceProfile: params.resourceProfile,\n\t\t\twritePaths: params.writePaths,\n\t\t},\n\t\tbudget: {\n\t\t\tmaxLaunches: Math.trunc(params.maxLaunches),\n\t\t\tmaxUsdAdvisory: params.maxUsdAdvisory,\n\t\t},\n\t\texpiresAt,\n\t};\n}\n\nexport function describeGrant(grant: TmuxDispatchGrant): string {\n\treturn [\n\t\t`Grant id: ${grant.grantId}`,\n\t\t`Agent: ${grant.agent}`,\n\t\tgrant.scope.goalId ? `Goal scope: ${grant.scope.goalId}` : \"Goal scope: none (covers any goal)\",\n\t\t`Max launches: ${grant.budget.maxLaunches}`,\n\t\tgrant.expiresAt ? `Expires: ${grant.expiresAt}` : \"Expires: never (until revoke_grant)\",\n\t\tgrant.envelope.allowedTools?.length\n\t\t\t? `Allowed tools: ${grant.envelope.allowedTools.join(\", \")}`\n\t\t\t: `Allowed tools: read-biased safe default (${DEFAULT_READ_BIASED_TOOLS.join(\", \")})`,\n\t\tgrant.envelope.resourceProfile\n\t\t\t? `Resource profile: ${grant.envelope.resourceProfile}`\n\t\t\t: \"Resource profile: none (child launches with --no-extensions --no-skills)\",\n\t\tgrant.envelope.writePaths?.length\n\t\t\t? `Write paths: ${grant.envelope.writePaths.join(\", \")}`\n\t\t\t: \"Write paths: none declared\",\n\t\tgrant.budget.maxUsdAdvisory !== undefined\n\t\t\t? `Advisory USD cap: ${grant.budget.maxUsdAdvisory} (not enforced across the process boundary — advisory only)`\n\t\t\t: undefined,\n\t]\n\t\t.filter((line): line is string => Boolean(line))\n\t\t.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Launch-profile flags: the REAL lever — pushed into the child `pi` CLI's own config.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_READ_BIASED_TOOLS: readonly string[] = [\"read\", \"grep\", \"find\", \"ls\"];\n\nexport interface LaunchProfileSource {\n\t/** Human-readable identity for the scoped system prompt (e.g. \"grant <id>\" or a one-shot label). */\n\tidentity: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\t/**\n\t * Worktree-sync lane key this launch is bound to (per-agent -- see `applyLaunchProfile`'s caller,\n\t * which builds a per-agent `LaunchProfileSource` only when that agent carries `worktreeLane`).\n\t * When present, `buildLaunchProfileFlags` appends `--worktree-lane <key>` (the same CLI flag\n\t * `src/cli/args.ts` already exposes, sugar over the `PI_WORKTREE_LANE` env contract) and\n\t * `buildScopedSystemPrompt` appends one lane-doctrine sentence.\n\t */\n\tworktreeLane?: string;\n\t/**\n\t * Process-matrix parent identity for this launch (see `core/process-matrix/runtime.ts`): the\n\t * dispatching process's own pid/sessionId. When present, `buildLaunchProfileFlags` appends\n\t * `--parent-pid`/`--parent-session` (sugar over `PI_PARENT_PID`/`PI_PARENT_SESSION`) so the\n\t * child self-registers as a worker of this session and winds down gracefully if it disappears.\n\t */\n\tparentPid?: number;\n\tparentSession?: string;\n\t/** Stable goal/task identity used to fence process-matrix recovery. */\n\ttaskRef?: string;\n}\n\n/** A grant-covered launch derives its profile from the grant's envelope. */\nexport function launchProfileSourceFromGrant(grant: TmuxDispatchGrant): LaunchProfileSource {\n\treturn {\n\t\tidentity: `grant ${grant.grantId}`,\n\t\tallowedTools: grant.envelope.allowedTools,\n\t\tresourceProfile: grant.envelope.resourceProfile,\n\t\twritePaths: grant.envelope.writePaths,\n\t};\n}\n\n/** A one-shot interactively-approved launch (no standing grant) still gets the conservative default\n * profile — approving a single launch is not the same as defining an unrestricted envelope. */\nexport const ONE_SHOT_LAUNCH_PROFILE_SOURCE: LaunchProfileSource = {\n\tidentity: \"a one-shot owner-approved tmux dispatch (no standing grant)\",\n};\n\nexport interface LaunchProfileFlag {\n\tflag: string;\n\tvalue?: string;\n}\n\n/** Build the CLI flags to append to a child `pi` invocation so the grant's envelope lives in the\n * child's OWN launch config (verified flag names: --tools, --resource-profile, --no-extensions,\n * --no-skills, --append-system-prompt). Never includes --no-approve: the child must keep gating its\n * own hard stops. */\nexport function buildLaunchProfileFlags(source: LaunchProfileSource): LaunchProfileFlag[] {\n\tconst tools = source.allowedTools?.length ? source.allowedTools : DEFAULT_READ_BIASED_TOOLS;\n\tconst flags: LaunchProfileFlag[] = [{ flag: \"--tools\", value: tools.join(\",\") }];\n\tif (source.resourceProfile) flags.push({ flag: \"--resource-profile\", value: source.resourceProfile });\n\telse flags.push({ flag: \"--no-extensions\" }, { flag: \"--no-skills\" });\n\tif (source.worktreeLane) flags.push({ flag: \"--worktree-lane\", value: source.worktreeLane });\n\tif (source.parentPid !== undefined) flags.push({ flag: \"--parent-pid\", value: String(source.parentPid) });\n\tif (source.parentSession) flags.push({ flag: \"--parent-session\", value: source.parentSession });\n\tif (source.taskRef) flags.push({ flag: \"--task-ref\", value: source.taskRef });\n\tflags.push({ flag: \"--append-system-prompt\", value: buildScopedSystemPrompt(source) });\n\treturn flags;\n}\n\nexport function buildScopedSystemPrompt(source: LaunchProfileSource): string {\n\tconst paths = source.writePaths?.length ? source.writePaths.join(\", \") : \"no additional paths granted\";\n\tconst sentences = [\n\t\t`You are a tmux worker dispatched under ${source.identity}.`,\n\t\t`Stay within these write paths: ${paths}.`,\n\t\t\"Hard stops — publishing/npm, git push, tagging a release, changing credentials/auth, or destructive deletion — require returning BLOCKED for owner approval. Never self-approve a hard stop.\",\n\t];\n\tif (source.worktreeLane) {\n\t\tsentences.push(\n\t\t\t`You are bound to worktree-sync lane '${source.worktreeLane}': work only inside this lane's own worktree, integrate exclusively via worktree_sync land, and never touch main directly.`,\n\t\t);\n\t}\n\treturn sentences.join(\" \");\n}\n\n// ---------------------------------------------------------------------------\n// Advisory worker usage claim: budget stays advisory across the process boundary.\n// ---------------------------------------------------------------------------\n\n/** Permissively decode a worker-reported usage CLAIM (a cooperative worker may write this to a\n * well-known sibling file before printing its completion marker). Read-defensive: missing/malformed\n * numeric fields default to 0 rather than throwing — this is untrusted, OPTIONAL, advisory input, never\n * an authoritative billing record. Returns undefined only when `raw` isn't even an object, so the\n * caller can distinguish \"no claim offered\" (skip reporting) from \"a claim was offered\" (report it,\n * however partial). */\nexport function decodeTmuxWorkerUsageClaim(raw: unknown): Usage | undefined {\n\tif (!isPlainRecord(raw)) return undefined;\n\tconst num = (value: unknown): number => (typeof value === \"number\" && Number.isFinite(value) ? value : 0);\n\tconst cost = isPlainRecord(raw.cost) ? raw.cost : {};\n\treturn {\n\t\tinput: num(raw.input),\n\t\toutput: num(raw.output),\n\t\tcacheRead: num(raw.cacheRead),\n\t\tcacheWrite: num(raw.cacheWrite),\n\t\ttotalTokens: num(raw.totalTokens),\n\t\tcost: {\n\t\t\tinput: num(cost.input),\n\t\t\toutput: num(cost.output),\n\t\t\tcacheRead: num(cost.cacheRead),\n\t\t\tcacheWrite: num(cost.cacheWrite),\n\t\t\ttotal: num(cost.total),\n\t\t},\n\t};\n}\n"]}
|
|
@@ -149,6 +149,8 @@ export function buildLaunchProfileFlags(source) {
|
|
|
149
149
|
flags.push({ flag: "--parent-pid", value: String(source.parentPid) });
|
|
150
150
|
if (source.parentSession)
|
|
151
151
|
flags.push({ flag: "--parent-session", value: source.parentSession });
|
|
152
|
+
if (source.taskRef)
|
|
153
|
+
flags.push({ flag: "--task-ref", value: source.taskRef });
|
|
152
154
|
flags.push({ flag: "--append-system-prompt", value: buildScopedSystemPrompt(source) });
|
|
153
155
|
return flags;
|
|
154
156
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatch-grant.js","sourceRoot":"","sources":["../../../../src/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\n\n/**\n * The STANDING GRANT for approval-gated tmux dispatch (owner authorizes once via `grant_dispatch`;\n * the extension then dispatches unattended WITHIN the grant's bounds). Pure data + pure decode/decision\n * logic only — no session/tmux/filesystem access, so every function here is directly unit-testable.\n * The extension (index.ts) owns reading/writing session custom entries and calls into this module for\n * decoding and authorization decisions.\n *\n * HONEST TRUST BOUNDARY: this grant bounds WHO may be launched, HOW OFTEN, and WITH WHAT launch-time\n * envelope (pushed into the child's own CLI flags) — it never claims to gate the child's in-process\n * tool loop, which is a separate OS process outside this runtime's `beforeToolCall` machinery.\n */\n\nexport type Provider = \"pi\" | \"codex\" | \"agy\" | \"claude\" | \"opencode\" | \"custom\";\n\nexport const GRANT_CUSTOM_TYPE = \"tmux-dispatch-grant\";\nexport const GRANT_USAGE_CUSTOM_TYPE = \"tmux-dispatch-grant-usage\";\n\nexport interface TmuxDispatchGrantEnvelope {\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n}\n\nexport interface TmuxDispatchGrantBudget {\n\tmaxLaunches: number;\n\tmaxWallClockMs?: number;\n\tmaxUsdAdvisory?: number;\n}\n\nexport interface TmuxDispatchGrant {\n\tgrantId: string;\n\tcreatedAt: string;\n\tagent: Provider;\n\tscope: { goalId?: string };\n\tenvelope: TmuxDispatchGrantEnvelope;\n\tbudget: TmuxDispatchGrantBudget;\n\texpiresAt?: string;\n}\n\n/** Appended by `revoke_grant`. Shares `GRANT_CUSTOM_TYPE` so the SAME latest-on-branch read that\n * resolves an active grant also sees a revocation and stops treating any older grant beneath it as\n * active — a tombstone is a hard stop, never skipped over to resurrect an earlier grant. */\nexport interface TmuxDispatchGrantTombstone {\n\ttombstone: true;\n\tgrantId: string;\n\trevokedAt: string;\n}\n\nexport interface TmuxDispatchGrantUsage {\n\tgrantId: string;\n\tjobId: string;\n\tat: string;\n}\n\nconst PROVIDERS: readonly Provider[] = [\"pi\", \"codex\", \"agy\", \"claude\", \"opencode\", \"custom\"];\n\nfunction isProvider(value: unknown): value is Provider {\n\treturn typeof value === \"string\" && (PROVIDERS as readonly string[]).includes(value);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isTmuxDispatchGrantTombstone(value: unknown): value is TmuxDispatchGrantTombstone {\n\tif (!isPlainRecord(value)) return false;\n\treturn value.tombstone === true && typeof value.grantId === \"string\" && typeof value.revokedAt === \"string\";\n}\n\nexport function isTmuxDispatchGrant(value: unknown): value is TmuxDispatchGrant {\n\tif (!isPlainRecord(value) || value.tombstone === true) return false;\n\tif (typeof value.grantId !== \"string\" || typeof value.createdAt !== \"string\" || !isProvider(value.agent))\n\t\treturn false;\n\tif (!isPlainRecord(value.scope) || !isPlainRecord(value.envelope) || !isPlainRecord(value.budget)) return false;\n\treturn typeof value.budget.maxLaunches === \"number\" && Number.isFinite(value.budget.maxLaunches);\n}\n\nexport function isTmuxDispatchGrantUsage(value: unknown): value is TmuxDispatchGrantUsage {\n\tif (!isPlainRecord(value)) return false;\n\treturn typeof value.grantId === \"string\" && typeof value.jobId === \"string\" && typeof value.at === \"string\";\n}\n\nexport function makeGrantId(): string {\n\treturn `grant-${Date.now().toString(36)}-${crypto.randomBytes(4).toString(\"hex\")}`;\n}\n\nexport interface GrantCoverageRequest {\n\tagent: Provider;\n\tgoalId?: string;\n\tnowIso?: string;\n}\n\n/** Whether `grant` authorizes a launch for `request`: same agent, goal-scope match (an UNSCOPED grant\n * covers any goal including none; a goal-SCOPED grant covers ONLY that exact goalId), and the grant is\n * not past `expiresAt`. Budget (maxLaunches) is checked separately via {@link isGrantBudgetExhausted}\n * because counting usages requires the caller's session-entry access. */\nexport function grantCovers(grant: TmuxDispatchGrant, request: GrantCoverageRequest): boolean {\n\tif (grant.agent !== request.agent) return false;\n\tif (grant.scope.goalId && grant.scope.goalId !== request.goalId) return false;\n\tif (grant.expiresAt) {\n\t\tconst now = Date.parse(request.nowIso ?? new Date().toISOString());\n\t\tconst expiry = Date.parse(grant.expiresAt);\n\t\tif (Number.isFinite(expiry) && Number.isFinite(now) && now >= expiry) return false;\n\t}\n\treturn true;\n}\n\n/** Count spend entries for `grantId` among already-decoded custom-entry payloads (the caller walks the\n * session branch and passes the raw `data` values — this stays pure/session-agnostic). */\nexport function countGrantUsages(grantId: string, usageEntries: readonly unknown[]): number {\n\tlet count = 0;\n\tfor (const entry of usageEntries) if (isTmuxDispatchGrantUsage(entry) && entry.grantId === grantId) count++;\n\treturn count;\n}\n\nexport function isGrantBudgetExhausted(grant: TmuxDispatchGrant, usedCount: number): boolean {\n\treturn usedCount >= grant.budget.maxLaunches;\n}\n\nexport function buildGrantUsageEntry(\n\tgrantId: string,\n\tjobId: string,\n\tnowIso = new Date().toISOString(),\n): TmuxDispatchGrantUsage {\n\treturn { grantId, jobId, at: nowIso };\n}\n\nexport function buildTombstone(grantId: string, nowIso = new Date().toISOString()): TmuxDispatchGrantTombstone {\n\treturn { tombstone: true, grantId, revokedAt: nowIso };\n}\n\nexport interface GrantDispatchParams {\n\tagent: Provider;\n\tgoalId?: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\tmaxLaunches: number;\n\texpiresInMinutes?: number;\n\tmaxUsdAdvisory?: number;\n}\n\n/** Build a new grant record from `grant_dispatch` params. Pure — the caller (index.ts) owns the\n * approval gate (ui.confirm / opt-in flag) and the `pi.appendEntry` persistence; this only shapes the\n * data, so it stays independently testable and never itself decides whether creation is authorized. */\nexport function buildGrant(params: GrantDispatchParams, nowIso = new Date().toISOString()): TmuxDispatchGrant {\n\tif (!Number.isFinite(params.maxLaunches) || params.maxLaunches < 1)\n\t\tthrow new Error(\"grant_dispatch requires maxLaunches >= 1\");\n\tconst expiresAt =\n\t\tparams.expiresInMinutes !== undefined\n\t\t\t? new Date(Date.parse(nowIso) + Math.max(1, params.expiresInMinutes) * 60_000).toISOString()\n\t\t\t: undefined;\n\treturn {\n\t\tgrantId: makeGrantId(),\n\t\tcreatedAt: nowIso,\n\t\tagent: params.agent,\n\t\tscope: { goalId: params.goalId },\n\t\tenvelope: {\n\t\t\tallowedTools: params.allowedTools,\n\t\t\tresourceProfile: params.resourceProfile,\n\t\t\twritePaths: params.writePaths,\n\t\t},\n\t\tbudget: {\n\t\t\tmaxLaunches: Math.trunc(params.maxLaunches),\n\t\t\tmaxUsdAdvisory: params.maxUsdAdvisory,\n\t\t},\n\t\texpiresAt,\n\t};\n}\n\nexport function describeGrant(grant: TmuxDispatchGrant): string {\n\treturn [\n\t\t`Grant id: ${grant.grantId}`,\n\t\t`Agent: ${grant.agent}`,\n\t\tgrant.scope.goalId ? `Goal scope: ${grant.scope.goalId}` : \"Goal scope: none (covers any goal)\",\n\t\t`Max launches: ${grant.budget.maxLaunches}`,\n\t\tgrant.expiresAt ? `Expires: ${grant.expiresAt}` : \"Expires: never (until revoke_grant)\",\n\t\tgrant.envelope.allowedTools?.length\n\t\t\t? `Allowed tools: ${grant.envelope.allowedTools.join(\", \")}`\n\t\t\t: `Allowed tools: read-biased safe default (${DEFAULT_READ_BIASED_TOOLS.join(\", \")})`,\n\t\tgrant.envelope.resourceProfile\n\t\t\t? `Resource profile: ${grant.envelope.resourceProfile}`\n\t\t\t: \"Resource profile: none (child launches with --no-extensions --no-skills)\",\n\t\tgrant.envelope.writePaths?.length\n\t\t\t? `Write paths: ${grant.envelope.writePaths.join(\", \")}`\n\t\t\t: \"Write paths: none declared\",\n\t\tgrant.budget.maxUsdAdvisory !== undefined\n\t\t\t? `Advisory USD cap: ${grant.budget.maxUsdAdvisory} (not enforced across the process boundary — advisory only)`\n\t\t\t: undefined,\n\t]\n\t\t.filter((line): line is string => Boolean(line))\n\t\t.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Launch-profile flags: the REAL lever — pushed into the child `pi` CLI's own config.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_READ_BIASED_TOOLS: readonly string[] = [\"read\", \"grep\", \"find\", \"ls\"];\n\nexport interface LaunchProfileSource {\n\t/** Human-readable identity for the scoped system prompt (e.g. \"grant <id>\" or a one-shot label). */\n\tidentity: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\t/**\n\t * Worktree-sync lane key this launch is bound to (per-agent -- see `applyLaunchProfile`'s caller,\n\t * which builds a per-agent `LaunchProfileSource` only when that agent carries `worktreeLane`).\n\t * When present, `buildLaunchProfileFlags` appends `--worktree-lane <key>` (the same CLI flag\n\t * `src/cli/args.ts` already exposes, sugar over the `PI_WORKTREE_LANE` env contract) and\n\t * `buildScopedSystemPrompt` appends one lane-doctrine sentence.\n\t */\n\tworktreeLane?: string;\n\t/**\n\t * Process-matrix parent identity for this launch (see `core/process-matrix/runtime.ts`): the\n\t * dispatching process's own pid/sessionId. When present, `buildLaunchProfileFlags` appends\n\t * `--parent-pid`/`--parent-session` (sugar over `PI_PARENT_PID`/`PI_PARENT_SESSION`) so the\n\t * child self-registers as a worker of this session and winds down gracefully if it disappears.\n\t */\n\tparentPid?: number;\n\tparentSession?: string;\n}\n\n/** A grant-covered launch derives its profile from the grant's envelope. */\nexport function launchProfileSourceFromGrant(grant: TmuxDispatchGrant): LaunchProfileSource {\n\treturn {\n\t\tidentity: `grant ${grant.grantId}`,\n\t\tallowedTools: grant.envelope.allowedTools,\n\t\tresourceProfile: grant.envelope.resourceProfile,\n\t\twritePaths: grant.envelope.writePaths,\n\t};\n}\n\n/** A one-shot interactively-approved launch (no standing grant) still gets the conservative default\n * profile — approving a single launch is not the same as defining an unrestricted envelope. */\nexport const ONE_SHOT_LAUNCH_PROFILE_SOURCE: LaunchProfileSource = {\n\tidentity: \"a one-shot owner-approved tmux dispatch (no standing grant)\",\n};\n\nexport interface LaunchProfileFlag {\n\tflag: string;\n\tvalue?: string;\n}\n\n/** Build the CLI flags to append to a child `pi` invocation so the grant's envelope lives in the\n * child's OWN launch config (verified flag names: --tools, --resource-profile, --no-extensions,\n * --no-skills, --append-system-prompt). Never includes --no-approve: the child must keep gating its\n * own hard stops. */\nexport function buildLaunchProfileFlags(source: LaunchProfileSource): LaunchProfileFlag[] {\n\tconst tools = source.allowedTools?.length ? source.allowedTools : DEFAULT_READ_BIASED_TOOLS;\n\tconst flags: LaunchProfileFlag[] = [{ flag: \"--tools\", value: tools.join(\",\") }];\n\tif (source.resourceProfile) flags.push({ flag: \"--resource-profile\", value: source.resourceProfile });\n\telse flags.push({ flag: \"--no-extensions\" }, { flag: \"--no-skills\" });\n\tif (source.worktreeLane) flags.push({ flag: \"--worktree-lane\", value: source.worktreeLane });\n\tif (source.parentPid !== undefined) flags.push({ flag: \"--parent-pid\", value: String(source.parentPid) });\n\tif (source.parentSession) flags.push({ flag: \"--parent-session\", value: source.parentSession });\n\tflags.push({ flag: \"--append-system-prompt\", value: buildScopedSystemPrompt(source) });\n\treturn flags;\n}\n\nexport function buildScopedSystemPrompt(source: LaunchProfileSource): string {\n\tconst paths = source.writePaths?.length ? source.writePaths.join(\", \") : \"no additional paths granted\";\n\tconst sentences = [\n\t\t`You are a tmux worker dispatched under ${source.identity}.`,\n\t\t`Stay within these write paths: ${paths}.`,\n\t\t\"Hard stops — publishing/npm, git push, tagging a release, changing credentials/auth, or destructive deletion — require returning BLOCKED for owner approval. Never self-approve a hard stop.\",\n\t];\n\tif (source.worktreeLane) {\n\t\tsentences.push(\n\t\t\t`You are bound to worktree-sync lane '${source.worktreeLane}': work only inside this lane's own worktree, integrate exclusively via worktree_sync land, and never touch main directly.`,\n\t\t);\n\t}\n\treturn sentences.join(\" \");\n}\n\n// ---------------------------------------------------------------------------\n// Advisory worker usage claim: budget stays advisory across the process boundary.\n// ---------------------------------------------------------------------------\n\n/** Permissively decode a worker-reported usage CLAIM (a cooperative worker may write this to a\n * well-known sibling file before printing its completion marker). Read-defensive: missing/malformed\n * numeric fields default to 0 rather than throwing — this is untrusted, OPTIONAL, advisory input, never\n * an authoritative billing record. Returns undefined only when `raw` isn't even an object, so the\n * caller can distinguish \"no claim offered\" (skip reporting) from \"a claim was offered\" (report it,\n * however partial). */\nexport function decodeTmuxWorkerUsageClaim(raw: unknown): Usage | undefined {\n\tif (!isPlainRecord(raw)) return undefined;\n\tconst num = (value: unknown): number => (typeof value === \"number\" && Number.isFinite(value) ? value : 0);\n\tconst cost = isPlainRecord(raw.cost) ? raw.cost : {};\n\treturn {\n\t\tinput: num(raw.input),\n\t\toutput: num(raw.output),\n\t\tcacheRead: num(raw.cacheRead),\n\t\tcacheWrite: num(raw.cacheWrite),\n\t\ttotalTokens: num(raw.totalTokens),\n\t\tcost: {\n\t\t\tinput: num(cost.input),\n\t\t\toutput: num(cost.output),\n\t\t\tcacheRead: num(cost.cacheRead),\n\t\t\tcacheWrite: num(cost.cacheWrite),\n\t\t\ttotal: num(cost.total),\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dispatch-grant.js","sourceRoot":"","sources":["../../../../src/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts"],"names":[],"mappings":"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","sourcesContent":["import * as crypto from \"node:crypto\";\nimport type { Usage } from \"@caupulican/pi-ai\";\n\n/**\n * The STANDING GRANT for approval-gated tmux dispatch (owner authorizes once via `grant_dispatch`;\n * the extension then dispatches unattended WITHIN the grant's bounds). Pure data + pure decode/decision\n * logic only — no session/tmux/filesystem access, so every function here is directly unit-testable.\n * The extension (index.ts) owns reading/writing session custom entries and calls into this module for\n * decoding and authorization decisions.\n *\n * HONEST TRUST BOUNDARY: this grant bounds WHO may be launched, HOW OFTEN, and WITH WHAT launch-time\n * envelope (pushed into the child's own CLI flags) — it never claims to gate the child's in-process\n * tool loop, which is a separate OS process outside this runtime's `beforeToolCall` machinery.\n */\n\nexport type Provider = \"pi\" | \"codex\" | \"agy\" | \"claude\" | \"opencode\" | \"custom\";\n\nexport const GRANT_CUSTOM_TYPE = \"tmux-dispatch-grant\";\nexport const GRANT_USAGE_CUSTOM_TYPE = \"tmux-dispatch-grant-usage\";\n\nexport interface TmuxDispatchGrantEnvelope {\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n}\n\nexport interface TmuxDispatchGrantBudget {\n\tmaxLaunches: number;\n\tmaxWallClockMs?: number;\n\tmaxUsdAdvisory?: number;\n}\n\nexport interface TmuxDispatchGrant {\n\tgrantId: string;\n\tcreatedAt: string;\n\tagent: Provider;\n\tscope: { goalId?: string };\n\tenvelope: TmuxDispatchGrantEnvelope;\n\tbudget: TmuxDispatchGrantBudget;\n\texpiresAt?: string;\n}\n\n/** Appended by `revoke_grant`. Shares `GRANT_CUSTOM_TYPE` so the SAME latest-on-branch read that\n * resolves an active grant also sees a revocation and stops treating any older grant beneath it as\n * active — a tombstone is a hard stop, never skipped over to resurrect an earlier grant. */\nexport interface TmuxDispatchGrantTombstone {\n\ttombstone: true;\n\tgrantId: string;\n\trevokedAt: string;\n}\n\nexport interface TmuxDispatchGrantUsage {\n\tgrantId: string;\n\tjobId: string;\n\tat: string;\n}\n\nconst PROVIDERS: readonly Provider[] = [\"pi\", \"codex\", \"agy\", \"claude\", \"opencode\", \"custom\"];\n\nfunction isProvider(value: unknown): value is Provider {\n\treturn typeof value === \"string\" && (PROVIDERS as readonly string[]).includes(value);\n}\n\nfunction isPlainRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isTmuxDispatchGrantTombstone(value: unknown): value is TmuxDispatchGrantTombstone {\n\tif (!isPlainRecord(value)) return false;\n\treturn value.tombstone === true && typeof value.grantId === \"string\" && typeof value.revokedAt === \"string\";\n}\n\nexport function isTmuxDispatchGrant(value: unknown): value is TmuxDispatchGrant {\n\tif (!isPlainRecord(value) || value.tombstone === true) return false;\n\tif (typeof value.grantId !== \"string\" || typeof value.createdAt !== \"string\" || !isProvider(value.agent))\n\t\treturn false;\n\tif (!isPlainRecord(value.scope) || !isPlainRecord(value.envelope) || !isPlainRecord(value.budget)) return false;\n\treturn typeof value.budget.maxLaunches === \"number\" && Number.isFinite(value.budget.maxLaunches);\n}\n\nexport function isTmuxDispatchGrantUsage(value: unknown): value is TmuxDispatchGrantUsage {\n\tif (!isPlainRecord(value)) return false;\n\treturn typeof value.grantId === \"string\" && typeof value.jobId === \"string\" && typeof value.at === \"string\";\n}\n\nexport function makeGrantId(): string {\n\treturn `grant-${Date.now().toString(36)}-${crypto.randomBytes(4).toString(\"hex\")}`;\n}\n\nexport interface GrantCoverageRequest {\n\tagent: Provider;\n\tgoalId?: string;\n\tnowIso?: string;\n}\n\n/** Whether `grant` authorizes a launch for `request`: same agent, goal-scope match (an UNSCOPED grant\n * covers any goal including none; a goal-SCOPED grant covers ONLY that exact goalId), and the grant is\n * not past `expiresAt`. Budget (maxLaunches) is checked separately via {@link isGrantBudgetExhausted}\n * because counting usages requires the caller's session-entry access. */\nexport function grantCovers(grant: TmuxDispatchGrant, request: GrantCoverageRequest): boolean {\n\tif (grant.agent !== request.agent) return false;\n\tif (grant.scope.goalId && grant.scope.goalId !== request.goalId) return false;\n\tif (grant.expiresAt) {\n\t\tconst now = Date.parse(request.nowIso ?? new Date().toISOString());\n\t\tconst expiry = Date.parse(grant.expiresAt);\n\t\tif (Number.isFinite(expiry) && Number.isFinite(now) && now >= expiry) return false;\n\t}\n\treturn true;\n}\n\n/** Count spend entries for `grantId` among already-decoded custom-entry payloads (the caller walks the\n * session branch and passes the raw `data` values — this stays pure/session-agnostic). */\nexport function countGrantUsages(grantId: string, usageEntries: readonly unknown[]): number {\n\tlet count = 0;\n\tfor (const entry of usageEntries) if (isTmuxDispatchGrantUsage(entry) && entry.grantId === grantId) count++;\n\treturn count;\n}\n\nexport function isGrantBudgetExhausted(grant: TmuxDispatchGrant, usedCount: number): boolean {\n\treturn usedCount >= grant.budget.maxLaunches;\n}\n\nexport function buildGrantUsageEntry(\n\tgrantId: string,\n\tjobId: string,\n\tnowIso = new Date().toISOString(),\n): TmuxDispatchGrantUsage {\n\treturn { grantId, jobId, at: nowIso };\n}\n\nexport function buildTombstone(grantId: string, nowIso = new Date().toISOString()): TmuxDispatchGrantTombstone {\n\treturn { tombstone: true, grantId, revokedAt: nowIso };\n}\n\nexport interface GrantDispatchParams {\n\tagent: Provider;\n\tgoalId?: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\tmaxLaunches: number;\n\texpiresInMinutes?: number;\n\tmaxUsdAdvisory?: number;\n}\n\n/** Build a new grant record from `grant_dispatch` params. Pure — the caller (index.ts) owns the\n * approval gate (ui.confirm / opt-in flag) and the `pi.appendEntry` persistence; this only shapes the\n * data, so it stays independently testable and never itself decides whether creation is authorized. */\nexport function buildGrant(params: GrantDispatchParams, nowIso = new Date().toISOString()): TmuxDispatchGrant {\n\tif (!Number.isFinite(params.maxLaunches) || params.maxLaunches < 1)\n\t\tthrow new Error(\"grant_dispatch requires maxLaunches >= 1\");\n\tconst expiresAt =\n\t\tparams.expiresInMinutes !== undefined\n\t\t\t? new Date(Date.parse(nowIso) + Math.max(1, params.expiresInMinutes) * 60_000).toISOString()\n\t\t\t: undefined;\n\treturn {\n\t\tgrantId: makeGrantId(),\n\t\tcreatedAt: nowIso,\n\t\tagent: params.agent,\n\t\tscope: { goalId: params.goalId },\n\t\tenvelope: {\n\t\t\tallowedTools: params.allowedTools,\n\t\t\tresourceProfile: params.resourceProfile,\n\t\t\twritePaths: params.writePaths,\n\t\t},\n\t\tbudget: {\n\t\t\tmaxLaunches: Math.trunc(params.maxLaunches),\n\t\t\tmaxUsdAdvisory: params.maxUsdAdvisory,\n\t\t},\n\t\texpiresAt,\n\t};\n}\n\nexport function describeGrant(grant: TmuxDispatchGrant): string {\n\treturn [\n\t\t`Grant id: ${grant.grantId}`,\n\t\t`Agent: ${grant.agent}`,\n\t\tgrant.scope.goalId ? `Goal scope: ${grant.scope.goalId}` : \"Goal scope: none (covers any goal)\",\n\t\t`Max launches: ${grant.budget.maxLaunches}`,\n\t\tgrant.expiresAt ? `Expires: ${grant.expiresAt}` : \"Expires: never (until revoke_grant)\",\n\t\tgrant.envelope.allowedTools?.length\n\t\t\t? `Allowed tools: ${grant.envelope.allowedTools.join(\", \")}`\n\t\t\t: `Allowed tools: read-biased safe default (${DEFAULT_READ_BIASED_TOOLS.join(\", \")})`,\n\t\tgrant.envelope.resourceProfile\n\t\t\t? `Resource profile: ${grant.envelope.resourceProfile}`\n\t\t\t: \"Resource profile: none (child launches with --no-extensions --no-skills)\",\n\t\tgrant.envelope.writePaths?.length\n\t\t\t? `Write paths: ${grant.envelope.writePaths.join(\", \")}`\n\t\t\t: \"Write paths: none declared\",\n\t\tgrant.budget.maxUsdAdvisory !== undefined\n\t\t\t? `Advisory USD cap: ${grant.budget.maxUsdAdvisory} (not enforced across the process boundary — advisory only)`\n\t\t\t: undefined,\n\t]\n\t\t.filter((line): line is string => Boolean(line))\n\t\t.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Launch-profile flags: the REAL lever — pushed into the child `pi` CLI's own config.\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_READ_BIASED_TOOLS: readonly string[] = [\"read\", \"grep\", \"find\", \"ls\"];\n\nexport interface LaunchProfileSource {\n\t/** Human-readable identity for the scoped system prompt (e.g. \"grant <id>\" or a one-shot label). */\n\tidentity: string;\n\tallowedTools?: string[];\n\tresourceProfile?: string;\n\twritePaths?: string[];\n\t/**\n\t * Worktree-sync lane key this launch is bound to (per-agent -- see `applyLaunchProfile`'s caller,\n\t * which builds a per-agent `LaunchProfileSource` only when that agent carries `worktreeLane`).\n\t * When present, `buildLaunchProfileFlags` appends `--worktree-lane <key>` (the same CLI flag\n\t * `src/cli/args.ts` already exposes, sugar over the `PI_WORKTREE_LANE` env contract) and\n\t * `buildScopedSystemPrompt` appends one lane-doctrine sentence.\n\t */\n\tworktreeLane?: string;\n\t/**\n\t * Process-matrix parent identity for this launch (see `core/process-matrix/runtime.ts`): the\n\t * dispatching process's own pid/sessionId. When present, `buildLaunchProfileFlags` appends\n\t * `--parent-pid`/`--parent-session` (sugar over `PI_PARENT_PID`/`PI_PARENT_SESSION`) so the\n\t * child self-registers as a worker of this session and winds down gracefully if it disappears.\n\t */\n\tparentPid?: number;\n\tparentSession?: string;\n\t/** Stable goal/task identity used to fence process-matrix recovery. */\n\ttaskRef?: string;\n}\n\n/** A grant-covered launch derives its profile from the grant's envelope. */\nexport function launchProfileSourceFromGrant(grant: TmuxDispatchGrant): LaunchProfileSource {\n\treturn {\n\t\tidentity: `grant ${grant.grantId}`,\n\t\tallowedTools: grant.envelope.allowedTools,\n\t\tresourceProfile: grant.envelope.resourceProfile,\n\t\twritePaths: grant.envelope.writePaths,\n\t};\n}\n\n/** A one-shot interactively-approved launch (no standing grant) still gets the conservative default\n * profile — approving a single launch is not the same as defining an unrestricted envelope. */\nexport const ONE_SHOT_LAUNCH_PROFILE_SOURCE: LaunchProfileSource = {\n\tidentity: \"a one-shot owner-approved tmux dispatch (no standing grant)\",\n};\n\nexport interface LaunchProfileFlag {\n\tflag: string;\n\tvalue?: string;\n}\n\n/** Build the CLI flags to append to a child `pi` invocation so the grant's envelope lives in the\n * child's OWN launch config (verified flag names: --tools, --resource-profile, --no-extensions,\n * --no-skills, --append-system-prompt). Never includes --no-approve: the child must keep gating its\n * own hard stops. */\nexport function buildLaunchProfileFlags(source: LaunchProfileSource): LaunchProfileFlag[] {\n\tconst tools = source.allowedTools?.length ? source.allowedTools : DEFAULT_READ_BIASED_TOOLS;\n\tconst flags: LaunchProfileFlag[] = [{ flag: \"--tools\", value: tools.join(\",\") }];\n\tif (source.resourceProfile) flags.push({ flag: \"--resource-profile\", value: source.resourceProfile });\n\telse flags.push({ flag: \"--no-extensions\" }, { flag: \"--no-skills\" });\n\tif (source.worktreeLane) flags.push({ flag: \"--worktree-lane\", value: source.worktreeLane });\n\tif (source.parentPid !== undefined) flags.push({ flag: \"--parent-pid\", value: String(source.parentPid) });\n\tif (source.parentSession) flags.push({ flag: \"--parent-session\", value: source.parentSession });\n\tif (source.taskRef) flags.push({ flag: \"--task-ref\", value: source.taskRef });\n\tflags.push({ flag: \"--append-system-prompt\", value: buildScopedSystemPrompt(source) });\n\treturn flags;\n}\n\nexport function buildScopedSystemPrompt(source: LaunchProfileSource): string {\n\tconst paths = source.writePaths?.length ? source.writePaths.join(\", \") : \"no additional paths granted\";\n\tconst sentences = [\n\t\t`You are a tmux worker dispatched under ${source.identity}.`,\n\t\t`Stay within these write paths: ${paths}.`,\n\t\t\"Hard stops — publishing/npm, git push, tagging a release, changing credentials/auth, or destructive deletion — require returning BLOCKED for owner approval. Never self-approve a hard stop.\",\n\t];\n\tif (source.worktreeLane) {\n\t\tsentences.push(\n\t\t\t`You are bound to worktree-sync lane '${source.worktreeLane}': work only inside this lane's own worktree, integrate exclusively via worktree_sync land, and never touch main directly.`,\n\t\t);\n\t}\n\treturn sentences.join(\" \");\n}\n\n// ---------------------------------------------------------------------------\n// Advisory worker usage claim: budget stays advisory across the process boundary.\n// ---------------------------------------------------------------------------\n\n/** Permissively decode a worker-reported usage CLAIM (a cooperative worker may write this to a\n * well-known sibling file before printing its completion marker). Read-defensive: missing/malformed\n * numeric fields default to 0 rather than throwing — this is untrusted, OPTIONAL, advisory input, never\n * an authoritative billing record. Returns undefined only when `raw` isn't even an object, so the\n * caller can distinguish \"no claim offered\" (skip reporting) from \"a claim was offered\" (report it,\n * however partial). */\nexport function decodeTmuxWorkerUsageClaim(raw: unknown): Usage | undefined {\n\tif (!isPlainRecord(raw)) return undefined;\n\tconst num = (value: unknown): number => (typeof value === \"number\" && Number.isFinite(value) ? value : 0);\n\tconst cost = isPlainRecord(raw.cost) ? raw.cost : {};\n\treturn {\n\t\tinput: num(raw.input),\n\t\toutput: num(raw.output),\n\t\tcacheRead: num(raw.cacheRead),\n\t\tcacheWrite: num(raw.cacheWrite),\n\t\ttotalTokens: num(raw.totalTokens),\n\t\tcost: {\n\t\t\tinput: num(cost.input),\n\t\t\toutput: num(cost.output),\n\t\t\tcacheRead: num(cost.cacheRead),\n\t\t\tcacheWrite: num(cost.cacheWrite),\n\t\t\ttotal: num(cost.total),\n\t\t},\n\t};\n}\n"]}
|
|
@@ -223,6 +223,8 @@ export interface LaunchProfileSource {
|
|
|
223
223
|
*/
|
|
224
224
|
parentPid?: number;
|
|
225
225
|
parentSession?: string;
|
|
226
|
+
/** Stable goal/task identity used to fence process-matrix recovery. */
|
|
227
|
+
taskRef?: string;
|
|
226
228
|
}
|
|
227
229
|
|
|
228
230
|
/** A grant-covered launch derives its profile from the grant's envelope. */
|
|
@@ -258,6 +260,7 @@ export function buildLaunchProfileFlags(source: LaunchProfileSource): LaunchProf
|
|
|
258
260
|
if (source.worktreeLane) flags.push({ flag: "--worktree-lane", value: source.worktreeLane });
|
|
259
261
|
if (source.parentPid !== undefined) flags.push({ flag: "--parent-pid", value: String(source.parentPid) });
|
|
260
262
|
if (source.parentSession) flags.push({ flag: "--parent-session", value: source.parentSession });
|
|
263
|
+
if (source.taskRef) flags.push({ flag: "--task-ref", value: source.taskRef });
|
|
261
264
|
flags.push({ flag: "--append-system-prompt", value: buildScopedSystemPrompt(source) });
|
|
262
265
|
return flags;
|
|
263
266
|
}
|
|
@@ -36,6 +36,15 @@ type FireAgentPlan = {
|
|
|
36
36
|
/** Mirrors `AgentSpec.worktreeLane` -- carried onto the plan so `applyLaunchProfile` (per-agent
|
|
37
37
|
* flags) and the dispatch-phase `reportManagedLane` call can both read it after `buildFireTaskPlan`. */
|
|
38
38
|
worktreeLane?: string;
|
|
39
|
+
/** Durable host-lifecycle metadata for the current turn. */
|
|
40
|
+
dispatchAuthorizationId?: string;
|
|
41
|
+
dispatchAuthorizationKind?: "standing-grant" | "one-shot-owner-approval" | "legacy-recovery";
|
|
42
|
+
dispatchAllowedTools?: string[];
|
|
43
|
+
dispatchWritePaths?: string[];
|
|
44
|
+
dispatchMaxCostUsd?: number;
|
|
45
|
+
dispatchInstructions?: string;
|
|
46
|
+
dispatchGoalId?: string;
|
|
47
|
+
dispatchLeaseTtlMs?: number;
|
|
39
48
|
};
|
|
40
49
|
type FireTaskPlan = {
|
|
41
50
|
id: string;
|