@caupulican/pi-adaptative 0.81.39 → 0.81.41
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 +77 -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 +3 -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 +4 -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 +4 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +31 -1
- 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 +25 -2
- package/dist/core/agent-paths.d.ts.map +1 -1
- package/dist/core/agent-paths.js +79 -4
- package/dist/core/agent-paths.js.map +1 -1
- package/dist/core/agent-session-contracts.d.ts +293 -0
- package/dist/core/agent-session-contracts.d.ts.map +1 -0
- package/dist/core/agent-session-contracts.js +26 -0
- package/dist/core/agent-session-contracts.js.map +1 -0
- 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 +400 -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 +74 -518
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +370 -1432
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +3 -1
- package/dist/core/auth-storage.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 +48 -9
- 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 +56 -236
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +141 -1273
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/bedrock-sso-login.d.ts +16 -0
- package/dist/core/bedrock-sso-login.d.ts.map +1 -0
- package/dist/core/bedrock-sso-login.js +98 -0
- package/dist/core/bedrock-sso-login.js.map +1 -0
- 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 +13 -17
- package/dist/core/compaction-support.d.ts.map +1 -1
- package/dist/core/compaction-support.js +3 -3
- 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 +1 -1
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +16 -37
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/cost/cost-summary.d.ts.map +1 -1
- package/dist/core/cost/cost-summary.js +5 -3
- package/dist/core/cost/cost-summary.js.map +1 -1
- package/dist/core/cost/daily-usage.d.ts.map +1 -1
- package/dist/core/cost/daily-usage.js +4 -5
- package/dist/core/cost/daily-usage.js.map +1 -1
- package/dist/core/default-tool-surface.d.ts.map +1 -1
- package/dist/core/default-tool-surface.js +2 -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/extension-import-authority.d.ts +6 -0
- package/dist/core/extension-import-authority.d.ts.map +1 -0
- package/dist/core/extension-import-authority.js +10 -0
- package/dist/core/extension-import-authority.js.map +1 -0
- 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 +52 -18
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +20 -5
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/stale-context.d.ts +2 -0
- package/dist/core/extensions/stale-context.d.ts.map +1 -0
- package/dist/core/extensions/stale-context.js +2 -0
- package/dist/core/extensions/stale-context.js.map +1 -0
- 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 +78 -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 +53 -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/goal-loop-controller.d.ts +14 -9
- package/dist/core/goal-loop-controller.d.ts.map +1 -1
- package/dist/core/goal-loop-controller.js +47 -75
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/compact-goal-context.d.ts +11 -0
- package/dist/core/goals/compact-goal-context.d.ts.map +1 -0
- package/dist/core/goals/compact-goal-context.js +59 -0
- package/dist/core/goals/compact-goal-context.js.map +1 -0
- 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 +27 -0
- package/dist/core/goals/goal-acceptance.js.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts +28 -0
- package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-auto-continue-controller.js +90 -0
- package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
- package/dist/core/goals/goal-continuation-controller.d.ts +2 -2
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-controller.js +52 -11
- package/dist/core/goals/goal-continuation-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.d.ts +4 -29
- package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.js +4 -32
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts +8 -18
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +9 -179
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/goals/goal-lifecycle.d.ts +43 -0
- package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
- package/dist/core/goals/goal-lifecycle.js +102 -0
- package/dist/core/goals/goal-lifecycle.js.map +1 -0
- package/dist/core/goals/goal-record.d.ts +17 -0
- package/dist/core/goals/goal-record.d.ts.map +1 -0
- package/dist/core/goals/goal-record.js +31 -0
- package/dist/core/goals/goal-record.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-session-controller.d.ts +42 -0
- package/dist/core/goals/goal-session-controller.d.ts.map +1 -0
- package/dist/core/goals/goal-session-controller.js +128 -0
- package/dist/core/goals/goal-session-controller.js.map +1 -0
- package/dist/core/goals/goal-state.d.ts +46 -25
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +91 -24
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +9 -10
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +60 -75
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +20 -12
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js +133 -33
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/human-input-controller.d.ts +47 -0
- package/dist/core/human-input-controller.d.ts.map +1 -0
- package/dist/core/human-input-controller.js +181 -0
- package/dist/core/human-input-controller.js.map +1 -0
- 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/local-runtime-controller.d.ts +1 -1
- package/dist/core/local-runtime-controller.d.ts.map +1 -1
- package/dist/core/local-runtime-controller.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 +0 -19
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +1 -19
- package/dist/core/model-capability.js.map +1 -1
- package/dist/core/model-registry.d.ts +6 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +13 -5
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +17 -2
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +38 -25
- 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 +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 +5 -5
- 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 +200 -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/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +20 -3
- package/dist/core/package-manager.js.map +1 -1
- 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-filter-controller.d.ts +8 -1
- package/dist/core/profile-filter-controller.d.ts.map +1 -1
- package/dist/core/profile-filter-controller.js +23 -5
- package/dist/core/profile-filter-controller.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/prompt-templates.d.ts +1 -0
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +18 -29
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +5 -5
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +5 -2
- 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/request-auth.d.ts +7 -0
- package/dist/core/request-auth.d.ts.map +1 -0
- package/dist/core/request-auth.js +8 -0
- package/dist/core/request-auth.js.map +1 -0
- 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 +23 -8
- 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 +233 -0
- package/dist/core/risk-classifier.js.map +1 -0
- package/dist/core/runtime-builder.d.ts +41 -23
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +365 -253
- 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 +68 -25
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/secrets/credential-exposure-guard.d.ts +9 -0
- package/dist/core/secrets/credential-exposure-guard.d.ts.map +1 -0
- package/dist/core/secrets/credential-exposure-guard.js +241 -0
- package/dist/core/secrets/credential-exposure-guard.js.map +1 -0
- package/dist/core/secrets/secret-dotenv.d.ts +27 -0
- package/dist/core/secrets/secret-dotenv.d.ts.map +1 -0
- package/dist/core/secrets/secret-dotenv.js +183 -0
- package/dist/core/secrets/secret-dotenv.js.map +1 -0
- package/dist/core/secrets/secret-vault-format.d.ts +112 -0
- package/dist/core/secrets/secret-vault-format.d.ts.map +1 -0
- package/dist/core/secrets/secret-vault-format.js +397 -0
- package/dist/core/secrets/secret-vault-format.js.map +1 -0
- package/dist/core/secrets/secret-vault.d.ts +72 -0
- package/dist/core/secrets/secret-vault.d.ts.map +1 -0
- package/dist/core/secrets/secret-vault.js +671 -0
- package/dist/core/secrets/secret-vault.js.map +1 -0
- package/dist/core/session-analytics.d.ts +4 -23
- package/dist/core/session-analytics.d.ts.map +1 -1
- package/dist/core/session-analytics.js +67 -70
- 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 +11 -4
- package/dist/core/session-role.d.ts.map +1 -1
- package/dist/core/session-role.js +24 -5
- 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/session-tree-navigator.d.ts +4 -6
- package/dist/core/session-tree-navigator.d.ts.map +1 -1
- package/dist/core/session-tree-navigator.js +4 -1
- package/dist/core/session-tree-navigator.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -5
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +81 -29
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +2 -2
- package/dist/core/slash-commands.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 +86 -0
- package/dist/core/tool-capability-policy.js.map +1 -0
- package/dist/core/tool-gate-controller.d.ts.map +1 -1
- package/dist/core/tool-gate-controller.js +8 -2
- package/dist/core/tool-gate-controller.js.map +1 -1
- package/dist/core/tool-protocol-controller.d.ts +89 -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-recovery-stats.d.ts +21 -1
- package/dist/core/tool-recovery-stats.d.ts.map +1 -1
- package/dist/core/tool-recovery-stats.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/bash.d.ts +5 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +59 -5
- package/dist/core/tools/bash.js.map +1 -1
- 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 +148 -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 +106 -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/git-filter.d.ts +1 -8
- package/dist/core/tools/git-filter.d.ts.map +1 -1
- package/dist/core/tools/git-filter.js +2 -63
- package/dist/core/tools/git-filter.js.map +1 -1
- package/dist/core/tools/goal.d.ts +10 -8
- package/dist/core/tools/goal.d.ts.map +1 -1
- package/dist/core/tools/goal.js +106 -28
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/core/tools/index.d.ts +1 -0
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js +1 -0
- package/dist/core/tools/index.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 +40 -0
- package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
- package/dist/core/tools/orchestration-panel.js +124 -0
- package/dist/core/tools/orchestration-panel.js.map +1 -0
- package/dist/core/tools/output-accumulator.d.ts +11 -0
- package/dist/core/tools/output-accumulator.d.ts.map +1 -1
- package/dist/core/tools/output-accumulator.js +36 -3
- package/dist/core/tools/output-accumulator.js.map +1 -1
- package/dist/core/tools/python.d.ts +2 -0
- package/dist/core/tools/python.d.ts.map +1 -1
- package/dist/core/tools/python.js +3 -1
- package/dist/core/tools/python.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +1 -1
- package/dist/core/tools/read.js.map +1 -1
- 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/search-command-guard.d.ts +14 -0
- package/dist/core/tools/search-command-guard.d.ts.map +1 -0
- package/dist/core/tools/search-command-guard.js +333 -0
- package/dist/core/tools/search-command-guard.js.map +1 -0
- package/dist/core/tools/secret-store.d.ts +38 -0
- package/dist/core/tools/secret-store.d.ts.map +1 -0
- package/dist/core/tools/secret-store.js +412 -0
- package/dist/core/tools/secret-store.js.map +1 -0
- package/dist/core/tools/shell-command-parser.d.ts +16 -0
- package/dist/core/tools/shell-command-parser.d.ts.map +1 -0
- package/dist/core/tools/shell-command-parser.js +113 -0
- package/dist/core/tools/shell-command-parser.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 +99 -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/atomic-file.d.ts +6 -2
- package/dist/core/util/atomic-file.d.ts.map +1 -1
- package/dist/core/util/atomic-file.js +4 -4
- package/dist/core/util/atomic-file.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 +15 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +149 -51
- 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/auth-dialogs-controller.d.ts +4 -0
- package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
- package/dist/modes/interactive/auth-dialogs-controller.js +60 -1
- package/dist/modes/interactive/auth-dialogs-controller.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/activity-lane.d.ts +55 -0
- package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -0
- package/dist/modes/interactive/components/activity-lane.js +304 -0
- package/dist/modes/interactive/components/activity-lane.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +19 -10
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/expandable-text.d.ts +12 -0
- package/dist/modes/interactive/components/expandable-text.d.ts.map +1 -0
- package/dist/modes/interactive/components/expandable-text.js +17 -0
- package/dist/modes/interactive/components/expandable-text.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +15 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +30 -21
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/extension-input.d.ts +1 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-input.js +6 -1
- package/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +23 -14
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +6 -6
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +19 -11
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +53 -20
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-group.js +3 -0
- package/dist/modes/interactive/components/tool-group.js.map +1 -1
- package/dist/modes/interactive/components/usage-action-selector.d.ts +16 -0
- package/dist/modes/interactive/components/usage-action-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/usage-action-selector.js +46 -0
- package/dist/modes/interactive/components/usage-action-selector.js.map +1 -0
- 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 +77 -15
- package/dist/modes/interactive/extension-ui-host.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +15 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -1
- package/dist/modes/interactive/external-editor.js +27 -19
- package/dist/modes/interactive/external-editor.js.map +1 -1
- package/dist/modes/interactive/history-reload-math.d.ts +6 -2
- package/dist/modes/interactive/history-reload-math.d.ts.map +1 -1
- package/dist/modes/interactive/history-reload-math.js +10 -5
- package/dist/modes/interactive/history-reload-math.js.map +1 -1
- package/dist/modes/interactive/interactive-event-controller.d.ts +74 -0
- package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-event-controller.js +328 -0
- package/dist/modes/interactive/interactive-event-controller.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +22 -24
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +245 -595
- 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/loaded-resources-view.d.ts +20 -0
- package/dist/modes/interactive/loaded-resources-view.d.ts.map +1 -0
- package/dist/modes/interactive/loaded-resources-view.js +147 -0
- package/dist/modes/interactive/loaded-resources-view.js.map +1 -0
- 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/resource-display.d.ts.map +1 -1
- package/dist/modes/interactive/resource-display.js +8 -2
- package/dist/modes/interactive/resource-display.js.map +1 -1
- package/dist/modes/interactive/resource-shell-commands.d.ts +1 -5
- package/dist/modes/interactive/resource-shell-commands.d.ts.map +1 -1
- package/dist/modes/interactive/resource-shell-commands.js +0 -5
- package/dist/modes/interactive/resource-shell-commands.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts +27 -8
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +150 -64
- 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/interactive/usage-commands.d.ts +34 -0
- package/dist/modes/interactive/usage-commands.d.ts.map +1 -0
- package/dist/modes/interactive/usage-commands.js +225 -0
- package/dist/modes/interactive/usage-commands.js.map +1 -0
- 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/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +5 -3
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +3 -1
- package/dist/utils/version-check.js.map +1 -1
- 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 +38 -0
- package/docs/UI_QUALITY_ORCHESTRATION.md +28 -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/providers.md +9 -1
- 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 +14 -0
- package/docs/ui-reference/orchestration-before.txt +13 -0
- package/docs/ui-reference/orchestration-reference.txt +16 -0
- package/docs/usage.md +22 -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 +13 -13
- 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/dist/utils/shell.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { delimiter } from \"node:path\";\nimport { spawnSync } from \"child_process\";\nimport { getBinDir } from \"../config.ts\";\n\nexport type PlatformShellToolName = \"bash\" | \"powershell\";\n\nexport interface ShellConfig {\n\tshell: string;\n\targs: string[];\n}\n\nexport const POWERSHELL_UTF8_PREFIX = \"try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\\n\";\n\nconst POWERSHELL_ARGS = [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\"];\n\nexport function getPlatformShellToolName(platform: NodeJS.Platform = process.platform): PlatformShellToolName {\n\treturn platform === \"win32\" ? \"powershell\" : \"bash\";\n}\n\nexport function prefixPowerShellCommand(command: string): string {\n\treturn command.trimStart().startsWith(POWERSHELL_UTF8_PREFIX) ? command : `${POWERSHELL_UTF8_PREFIX}${command}`;\n}\n\nfunction findExecutableOnPath(executable: string): string | null {\n\tconst locator = process.platform === \"win32\" ? \"where\" : \"which\";\n\ttry {\n\t\tconst result = spawnSync(locator, [executable], {\n\t\t\tencoding: \"utf-8\",\n\t\t\ttimeout: 5_000,\n\t\t\twindowsHide: true,\n\t\t});\n\t\tif (result.status === 0 && result.stdout) {\n\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\tif (firstMatch && (process.platform !== \"win32\" || existsSync(firstMatch))) return firstMatch;\n\t\t}\n\t} catch {\n\t\t// Resolution falls through to known paths or the platform fallback.\n\t}\n\treturn null;\n}\n\nfunction isPowerShellExecutableAvailable(executable: string): boolean {\n\ttry {\n\t\treturn (\n\t\t\tspawnSync(executable, [...POWERSHELL_ARGS, \"Write-Output ok\"], {\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\ttimeout: 5_000,\n\t\t\t\twindowsHide: true,\n\t\t\t}).status === 0\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction getPowerShellConfig(): ShellConfig {\n\tconst pwshOnPath = findExecutableOnPath(process.platform === \"win32\" ? \"pwsh.exe\" : \"pwsh\");\n\tif (pwshOnPath && isPowerShellExecutableAvailable(pwshOnPath)) {\n\t\treturn { shell: pwshOnPath, args: [...POWERSHELL_ARGS] };\n\t}\n\n\tconst knownPaths: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) knownPaths.push(`${programFiles}\\\\PowerShell\\\\7\\\\pwsh.exe`);\n\tconst systemRoot = process.env.SystemRoot;\n\tif (systemRoot) knownPaths.push(`${systemRoot}\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe`);\n\tfor (const path of knownPaths) {\n\t\tif (existsSync(path) && isPowerShellExecutableAvailable(path)) {\n\t\t\treturn { shell: path, args: [...POWERSHELL_ARGS] };\n\t\t}\n\t}\n\n\tconst windowsPowerShellOnPath = findExecutableOnPath(\"powershell.exe\");\n\tif (windowsPowerShellOnPath && isPowerShellExecutableAvailable(windowsPowerShellOnPath)) {\n\t\treturn { shell: windowsPowerShellOnPath, args: [...POWERSHELL_ARGS] };\n\t}\n\tthrow new Error(\n\t\t\"No PowerShell executable found. Install PowerShell 7 (pwsh), restore Windows PowerShell, or set shellPath in settings.json.\",\n\t);\n}\n\nfunction getBashConfig(): ShellConfig {\n\tif (process.platform === \"win32\") {\n\t\tconst knownPaths: string[] = [];\n\t\tconst programFiles = process.env.ProgramFiles;\n\t\tif (programFiles) knownPaths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\t\tif (programFilesX86) knownPaths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tfor (const path of knownPaths) {\n\t\t\tif (existsSync(path)) return { shell: path, args: [\"-c\"] };\n\t\t}\n\t\tconst bashOnPath = findExecutableOnPath(\"bash.exe\");\n\t\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\t\tthrow new Error(\"No Bash executable found. Install Git Bash or set shellPath in settings.json.\");\n\t}\n\tif (existsSync(\"/bin/bash\")) return { shell: \"/bin/bash\", args: [\"-c\"] };\n\tconst bashOnPath = findExecutableOnPath(\"bash\");\n\treturn bashOnPath ? { shell: bashOnPath, args: [\"-c\"] } : { shell: \"sh\", args: [\"-c\"] };\n}\n\n// Platform shell resolution spawns probe processes (`where`/`which`, plus a full PowerShell\n// boot on Windows) and is a process-lifetime invariant, so successful resolutions are cached.\n// Failures are not cached: the user can install a shell and retry without restarting.\nconst resolvedPlatformShellConfigs = new Map<PlatformShellToolName, ShellConfig>();\n\n/** Resolve the requested shell. Runtime callers omit shellName to select PowerShell on Windows and Bash elsewhere. */\nexport function getShellConfig(\n\tcustomShellPath?: string,\n\tshellName: PlatformShellToolName = getPlatformShellToolName(),\n): ShellConfig {\n\tif (customShellPath) {\n\t\tif (!existsSync(customShellPath)) throw new Error(`Custom shell path not found: ${customShellPath}`);\n\t\treturn {\n\t\t\tshell: customShellPath,\n\t\t\targs: shellName === \"powershell\" ? [...POWERSHELL_ARGS] : [\"-c\"],\n\t\t};\n\t}\n\tlet resolved = resolvedPlatformShellConfigs.get(shellName);\n\tif (!resolved) {\n\t\tresolved = shellName === \"powershell\" ? getPowerShellConfig() : getBashConfig();\n\t\tresolvedPlatformShellConfigs.set(shellName, resolved);\n\t}\n\treturn { shell: resolved.shell, args: [...resolved.args] };\n}\n\nexport function getShellEnv(): NodeJS.ProcessEnv {\n\tconst binDir = getBinDir();\n\tconst pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n\tconst currentPath = process.env[pathKey] ?? \"\";\n\tconst pathEntries = currentPath.split(delimiter).filter(Boolean);\n\tconst hasBinDir = pathEntries.includes(binDir);\n\tconst updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n\n\treturn {\n\t\t...process.env,\n\t\t[pathKey]: updatedPath,\n\t};\n}\n\n/**\n * Detached child processes must be tracked so they can be killed on parent\n * shutdown signals (SIGHUP/SIGTERM).\n */\nconst trackedDetachedChildPids = new Set<number>();\n\nexport function trackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.add(pid);\n}\n\nexport function untrackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.delete(pid);\n}\n\nexport function killTrackedDetachedChildren(): void {\n\tfor (const pid of trackedDetachedChildPids) {\n\t\tkillProcessTree(pid);\n\t}\n\ttrackedDetachedChildPids.clear();\n}\n\n/**\n * Kill a process and all its children (cross-platform).\n *\n * Windows uses `spawnSync` (not `spawn`) deliberately: callers rely on this function returning\n * only once the tree is actually gone (e.g. before removing a directory that was the killed\n * process's cwd — a directory Windows keeps locked until every handle into it, including a\n * live process's cwd handle, is released). A fire-and-forget async `taskkill` would return before\n * termination completed, leaving a race where the directory is still locked.\n */\nexport function killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\t// Use taskkill on Windows to kill process tree; spawnSync blocks until taskkill itself\n\t\t// (and therefore the termination it requested) has finished.\n\t\ttry {\n\t\t\tspawnSync(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors if taskkill fails\n\t\t}\n\t} else {\n\t\t// Use SIGKILL on Unix/Linux/Mac\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Fallback to killing just the child if process group kill fails\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { delimiter } from \"node:path\";\nimport { spawnSync } from \"child_process\";\nimport { getBinDir } from \"../config.ts\";\nimport { normalizePath } from \"./paths.ts\";\n\nexport type PlatformShellToolName = \"bash\" | \"powershell\";\n\nexport interface ShellConfig {\n\tshell: string;\n\targs: string[];\n}\n\nexport const POWERSHELL_UTF8_PREFIX = \"try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\\n\";\n\nconst POWERSHELL_ARGS = [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\"];\n\nexport function getPlatformShellToolName(platform: NodeJS.Platform = process.platform): PlatformShellToolName {\n\treturn platform === \"win32\" ? \"powershell\" : \"bash\";\n}\n\nexport function prefixPowerShellCommand(command: string): string {\n\treturn command.trimStart().startsWith(POWERSHELL_UTF8_PREFIX) ? command : `${POWERSHELL_UTF8_PREFIX}${command}`;\n}\n\nfunction findExecutableOnPath(executable: string): string | null {\n\tconst locator = process.platform === \"win32\" ? \"where\" : \"which\";\n\ttry {\n\t\tconst result = spawnSync(locator, [executable], {\n\t\t\tencoding: \"utf-8\",\n\t\t\ttimeout: 5_000,\n\t\t\twindowsHide: true,\n\t\t});\n\t\tif (result.status === 0 && result.stdout) {\n\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\tif (firstMatch && (process.platform !== \"win32\" || existsSync(firstMatch))) return firstMatch;\n\t\t}\n\t} catch {\n\t\t// Resolution falls through to known paths or the platform fallback.\n\t}\n\treturn null;\n}\n\nfunction isPowerShellExecutableAvailable(executable: string): boolean {\n\ttry {\n\t\treturn (\n\t\t\tspawnSync(executable, [...POWERSHELL_ARGS, \"Write-Output ok\"], {\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\ttimeout: 5_000,\n\t\t\t\twindowsHide: true,\n\t\t\t}).status === 0\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction getPowerShellConfig(): ShellConfig {\n\tconst pwshOnPath = findExecutableOnPath(process.platform === \"win32\" ? \"pwsh.exe\" : \"pwsh\");\n\tif (pwshOnPath && isPowerShellExecutableAvailable(pwshOnPath)) {\n\t\treturn { shell: pwshOnPath, args: [...POWERSHELL_ARGS] };\n\t}\n\n\tconst knownPaths: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) knownPaths.push(`${programFiles}\\\\PowerShell\\\\7\\\\pwsh.exe`);\n\tconst systemRoot = process.env.SystemRoot;\n\tif (systemRoot) knownPaths.push(`${systemRoot}\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe`);\n\tfor (const path of knownPaths) {\n\t\tif (existsSync(path) && isPowerShellExecutableAvailable(path)) {\n\t\t\treturn { shell: path, args: [...POWERSHELL_ARGS] };\n\t\t}\n\t}\n\n\tconst windowsPowerShellOnPath = findExecutableOnPath(\"powershell.exe\");\n\tif (windowsPowerShellOnPath && isPowerShellExecutableAvailable(windowsPowerShellOnPath)) {\n\t\treturn { shell: windowsPowerShellOnPath, args: [...POWERSHELL_ARGS] };\n\t}\n\tthrow new Error(\n\t\t\"No PowerShell executable found. Install PowerShell 7 (pwsh), restore Windows PowerShell, or set shellPath in settings.json.\",\n\t);\n}\n\nfunction getBashConfig(): ShellConfig {\n\tif (process.platform === \"win32\") {\n\t\tconst knownPaths: string[] = [];\n\t\tconst programFiles = process.env.ProgramFiles;\n\t\tif (programFiles) knownPaths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\t\tif (programFilesX86) knownPaths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tfor (const path of knownPaths) {\n\t\t\tif (existsSync(path)) return { shell: path, args: [\"-c\"] };\n\t\t}\n\t\tconst bashOnPath = findExecutableOnPath(\"bash.exe\");\n\t\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\t\tthrow new Error(\"No Bash executable found. Install Git Bash or set shellPath in settings.json.\");\n\t}\n\tif (existsSync(\"/bin/bash\")) return { shell: \"/bin/bash\", args: [\"-c\"] };\n\tconst bashOnPath = findExecutableOnPath(\"bash\");\n\treturn bashOnPath ? { shell: bashOnPath, args: [\"-c\"] } : { shell: \"sh\", args: [\"-c\"] };\n}\n\n// Platform shell resolution spawns probe processes (`where`/`which`, plus a full PowerShell\n// boot on Windows) and is a process-lifetime invariant, so successful resolutions are cached.\n// Failures are not cached: the user can install a shell and retry without restarting.\nconst resolvedPlatformShellConfigs = new Map<PlatformShellToolName, ShellConfig>();\n\n/** Resolve the requested shell. Runtime callers omit shellName to select PowerShell on Windows and Bash elsewhere. */\nexport function getShellConfig(\n\tcustomShellPath?: string,\n\tshellName: PlatformShellToolName = getPlatformShellToolName(),\n): ShellConfig {\n\tif (customShellPath) {\n\t\tconst resolvedShellPath = normalizePath(customShellPath);\n\t\tif (!existsSync(resolvedShellPath)) throw new Error(`Custom shell path not found: ${resolvedShellPath}`);\n\t\treturn {\n\t\t\tshell: resolvedShellPath,\n\t\t\targs: shellName === \"powershell\" ? [...POWERSHELL_ARGS] : [\"-c\"],\n\t\t};\n\t}\n\tlet resolved = resolvedPlatformShellConfigs.get(shellName);\n\tif (!resolved) {\n\t\tresolved = shellName === \"powershell\" ? getPowerShellConfig() : getBashConfig();\n\t\tresolvedPlatformShellConfigs.set(shellName, resolved);\n\t}\n\treturn { shell: resolved.shell, args: [...resolved.args] };\n}\n\nexport function getShellEnv(): NodeJS.ProcessEnv {\n\tconst binDir = getBinDir();\n\tconst pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n\tconst currentPath = process.env[pathKey] ?? \"\";\n\tconst pathEntries = currentPath.split(delimiter).filter(Boolean);\n\tconst hasBinDir = pathEntries.includes(binDir);\n\tconst updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n\n\treturn {\n\t\t...process.env,\n\t\t[pathKey]: updatedPath,\n\t};\n}\n\n/**\n * Detached child processes must be tracked so they can be killed on parent\n * shutdown signals (SIGHUP/SIGTERM).\n */\nconst trackedDetachedChildPids = new Set<number>();\n\nexport function trackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.add(pid);\n}\n\nexport function untrackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.delete(pid);\n}\n\nexport function killTrackedDetachedChildren(): void {\n\tfor (const pid of trackedDetachedChildPids) {\n\t\tkillProcessTree(pid);\n\t}\n\ttrackedDetachedChildPids.clear();\n}\n\n/**\n * Kill a process and all its children (cross-platform).\n *\n * Windows uses `spawnSync` (not `spawn`) deliberately: callers rely on this function returning\n * only once the tree is actually gone (e.g. before removing a directory that was the killed\n * process's cwd — a directory Windows keeps locked until every handle into it, including a\n * live process's cwd handle, is released). A fire-and-forget async `taskkill` would return before\n * termination completed, leaving a race where the directory is still locked.\n */\nexport function killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\t// Use taskkill on Windows to kill process tree; spawnSync blocks until taskkill itself\n\t\t// (and therefore the termination it requested) has finished.\n\t\ttry {\n\t\t\tspawnSync(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors if taskkill fails\n\t\t}\n\t} else {\n\t\t// Use SIGKILL on Unix/Linux/Mac\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Fallback to killing just the child if process group kill fails\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAsBD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAiCtC;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,
|
|
1
|
+
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAsBD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAiCtC;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GAClC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAYvG","sourcesContent":["import { getPiUserAgent } from \"./pi-user-agent.ts\";\n\nconst LATEST_VERSION_URL = \"https://registry.npmjs.org/@caupulican%2fpi-adaptative/latest\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn left.prerelease.localeCompare(right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_OFFLINE) return undefined;\n\n\tconst response = await fetch(LATEST_VERSION_URL, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tname?: unknown;\n\t\tpackageName?: unknown;\n\t\tversion?: unknown;\n\t\tnote?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.packageName === \"string\" && data.packageName.trim()\n\t\t\t? data.packageName.trim()\n\t\t\t: typeof data.name === \"string\" && data.name.trim()\n\t\t\t\t? data.name.trim()\n\t\t\t\t: undefined;\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\tpackageName,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestPiRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -41,7 +41,7 @@ export function isNewerPackageVersion(candidateVersion, currentVersion) {
|
|
|
41
41
|
return candidateVersion.trim() !== currentVersion.trim();
|
|
42
42
|
}
|
|
43
43
|
export async function getLatestPiRelease(currentVersion, options = {}) {
|
|
44
|
-
if (process.env.
|
|
44
|
+
if (process.env.PI_OFFLINE)
|
|
45
45
|
return undefined;
|
|
46
46
|
const response = await fetch(LATEST_VERSION_URL, {
|
|
47
47
|
headers: {
|
|
@@ -72,6 +72,8 @@ export async function getLatestPiVersion(currentVersion, options = {}) {
|
|
|
72
72
|
return (await getLatestPiRelease(currentVersion, options))?.version;
|
|
73
73
|
}
|
|
74
74
|
export async function checkForNewPiVersion(currentVersion) {
|
|
75
|
+
if (process.env.PI_SKIP_VERSION_CHECK)
|
|
76
|
+
return undefined;
|
|
75
77
|
try {
|
|
76
78
|
const latestRelease = await getLatestPiRelease(currentVersion);
|
|
77
79
|
if (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,kBAAkB,GAAG,+DAA+D,CAAC;AAC3F,MAAM,gCAAgC,GAAG,KAAK,CAAC;AAe/C,SAAS,mBAAmB,CAAC,OAAe,EAA6B;IACxE,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC7F,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO;QACN,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACpC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACpC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACpC,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;KACpB,CAAC;AAAA,CACF;AAED,MAAM,UAAU,sBAAsB,CAAC,WAAmB,EAAE,YAAoB,EAAsB;IACrG,MAAM,IAAI,GAAG,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,mBAAmB,CAAC,YAAY,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAChE,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAChE,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAChE,IAAI,IAAI,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU;QAAE,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC,IAAI,CAAC,UAAU;QAAE,OAAO,CAAC,CAAC;IAC/B,IAAI,CAAC,KAAK,CAAC,UAAU;QAAE,OAAO,CAAC,CAAC,CAAC;IACjC,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AAAA,CACvD;AAED,MAAM,UAAU,qBAAqB,CAAC,gBAAwB,EAAE,cAAsB,EAAW;IAChG,MAAM,UAAU,GAAG,sBAAsB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;IAC5E,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,UAAU,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAK,cAAc,CAAC,IAAI,EAAE,CAAC;AAAA,CACzD;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,cAAsB,EACtB,OAAO,GAA2B,EAAE,EACG;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { getPiUserAgent } from \"./pi-user-agent.ts\";\n\nconst LATEST_VERSION_URL = \"https://registry.npmjs.org/@caupulican%2fpi-adaptative/latest\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn left.prerelease.localeCompare(right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_OFFLINE) return undefined;\n\n\tconst response = await fetch(LATEST_VERSION_URL, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tname?: unknown;\n\t\tpackageName?: unknown;\n\t\tversion?: unknown;\n\t\tnote?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.packageName === \"string\" && data.packageName.trim()\n\t\t\t? data.packageName.trim()\n\t\t\t: typeof data.name === \"string\" && data.name.trim()\n\t\t\t\t? data.name.trim()\n\t\t\t\t: undefined;\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\tpackageName,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestPiRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -10,6 +10,11 @@ export interface WorkRetentionOptions {
|
|
|
10
10
|
maxScannedRuns?: number;
|
|
11
11
|
now?: number;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Clamp caller-selected retention to the harness ceiling. Consumers may retain less, but cannot turn
|
|
15
|
+
* a managed work tenant into an unbounded artifact store by raising or disabling these limits.
|
|
16
|
+
*/
|
|
17
|
+
export declare function boundedWorkRetention(options?: WorkRetentionOptions): WorkRetentionOptions;
|
|
13
18
|
export interface AcquireWorkRunOptions {
|
|
14
19
|
agentDir: string;
|
|
15
20
|
category: string;
|
|
@@ -26,6 +31,12 @@ export interface WorkRunLease {
|
|
|
26
31
|
touch(): void;
|
|
27
32
|
release(): void;
|
|
28
33
|
}
|
|
34
|
+
export declare function assertPortablePathSegment(label: string, value: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Report whether a managed run is leased or being cleaned. Stale local markers are removed as part
|
|
37
|
+
* of the check; malformed or foreign-host markers remain fail-closed and count as active.
|
|
38
|
+
*/
|
|
39
|
+
export declare function hasActiveWorkRunLease(runDir: string): boolean;
|
|
29
40
|
export declare function getWorkRoot(agentDir: string): string;
|
|
30
41
|
export declare function getWorkTenantDir(agentDir: string, category: string, tenant: string): string;
|
|
31
42
|
export declare function getWorkRunDir(agentDir: string, category: string, tenant: string, runId: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-directory.d.ts","sourceRoot":"","sources":["../../src/utils/work-directory.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAC/C,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAgD1D,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,oBAAoB,GAAG,KAAK,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CAChB;AAyOD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI3F;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAKvG;AAED,wBAAgB,eAAe,CAAC,GAAG,SAAa,GAAG,MAAM,CAExD;AAED,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB,GAChC,MAAM,EAAE,CA0DV;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAOlH;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,YAAY,CA2F3E","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n\ttype Dir,\n\texistsSync,\n\tlstatSync,\n\tmkdirSync,\n\topendirSync,\n\treadFileSync,\n\trmdirSync,\n\trmSync,\n\tunlinkSync,\n\tutimesSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const PI_WORK_ROOT_ENV = \"PI_WORK_ROOT\";\nexport const WORK_RUN_MANIFEST_FILE = \".pi-work-run.json\";\n\nconst LEASES_DIRECTORY = \".leases\";\nconst CLEANUP_MARKER_FILE = \".cleanup.json\";\nconst MAX_METADATA_BYTES = 4 * 1024;\nconst MAX_LEASE_MARKERS = 256;\nconst MAX_DIRECTORY_DEPTH = 64;\nconst DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_MAX_RUNS = 64;\nconst DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst DEFAULT_MAX_SCANNED_ENTRIES = 100_000;\nconst DEFAULT_MAX_SCANNED_RUNS = 10_000;\nconst SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst WINDOWS_RESERVED_NAMES = new Set([\n\t\"aux\",\n\t\"clock$\",\n\t\"con\",\n\t\"nul\",\n\t\"prn\",\n\t...Array.from({ length: 9 }, (_, index) => `com${index + 1}`),\n\t...Array.from({ length: 9 }, (_, index) => `lpt${index + 1}`),\n]);\n\ninterface WorkRunManifest {\n\tversion: 1;\n\tcategory: string;\n\ttenant: string;\n\trunId: string;\n\tcreatedAt: number;\n}\n\ninterface WorkMarker {\n\tversion: 1;\n\thostname: string;\n\tpid: number;\n\tcreatedAt: number;\n}\n\ninterface InspectedRun {\n\tpath: string;\n\tmtimeMs: number;\n\tbytes: number;\n}\n\ninterface ScanBudget {\n\tremaining: number;\n}\n\nexport interface WorkRetentionOptions {\n\tmaxAgeMs?: number;\n\tmaxRuns?: number;\n\tmaxTotalBytes?: number;\n\t/** Fixed tenant-wide cap for recursive file entries inspected during one prune. */\n\tmaxScannedEntries?: number;\n\t/** Fixed cap for run directories inspected during one prune. */\n\tmaxScannedRuns?: number;\n\tnow?: number;\n}\n\nexport interface AcquireWorkRunOptions {\n\tagentDir: string;\n\tcategory: string;\n\ttenant: string;\n\trunId?: string;\n\tretention?: WorkRetentionOptions | false;\n\tnow?: number;\n}\n\nexport interface WorkRunLease {\n\treadonly path: string;\n\treadonly category: string;\n\treadonly tenant: string;\n\treadonly runId: string;\n\ttouch(): void;\n\trelease(): void;\n}\n\nconst processWorkRuns = new Map<string, WorkRunLease>();\n\nfunction nonNegativeLimit(value: number | undefined, fallback: number): number {\n\treturn value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;\n}\n\nfunction assertPortableSegment(label: string, value: string): void {\n\tif (!SEGMENT_PATTERN.test(value) || value.endsWith(\".\")) {\n\t\tthrow new Error(`${label} must be a lowercase portable path segment (1-64 characters)`);\n\t}\n\tconst stem = value.split(\".\", 1)[0];\n\tif (stem && WINDOWS_RESERVED_NAMES.has(stem)) {\n\t\tthrow new Error(`${label} uses a Windows-reserved path name: ${value}`);\n\t}\n}\n\nfunction ensureDirectory(path: string): void {\n\ttry {\n\t\tmkdirSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t}\n\tconst stats = lstatSync(path);\n\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\tthrow new Error(`Work path is not a real directory: ${path}`);\n\t}\n}\n\nfunction ensureTenantDirectory(agentDir: string, category: string, tenant: string): string {\n\tmkdirSync(agentDir, { recursive: true });\n\tconst workRoot = getWorkRoot(agentDir);\n\tensureDirectory(workRoot);\n\tconst categoryDir = join(workRoot, category);\n\tensureDirectory(categoryDir);\n\tconst tenantDir = join(categoryDir, tenant);\n\tensureDirectory(tenantDir);\n\treturn tenantDir;\n}\n\nfunction readSmallJson(path: string): unknown {\n\tconst stats = lstatSync(path);\n\tif (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_METADATA_BYTES) {\n\t\tthrow new Error(`Invalid work metadata file: ${path}`);\n\t}\n\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n}\n\nfunction isManifest(value: unknown, category: string, tenant: string, runId: string): value is WorkRunManifest {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst manifest = value as Partial<WorkRunManifest>;\n\treturn (\n\t\tmanifest.version === 1 &&\n\t\tmanifest.category === category &&\n\t\tmanifest.tenant === tenant &&\n\t\tmanifest.runId === runId &&\n\t\ttypeof manifest.createdAt === \"number\" &&\n\t\tNumber.isFinite(manifest.createdAt)\n\t);\n}\n\nfunction isMarker(value: unknown): value is WorkMarker {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst marker = value as Partial<WorkMarker>;\n\treturn (\n\t\tmarker.version === 1 &&\n\t\ttypeof marker.hostname === \"string\" &&\n\t\ttypeof marker.pid === \"number\" &&\n\t\tNumber.isSafeInteger(marker.pid) &&\n\t\tmarker.pid > 0 &&\n\t\ttypeof marker.createdAt === \"number\" &&\n\t\tNumber.isFinite(marker.createdAt)\n\t);\n}\n\nfunction markerState(path: string): \"active\" | \"stale\" | \"unknown\" {\n\ttry {\n\t\tconst value = readSmallJson(path);\n\t\tif (!isMarker(value)) return \"unknown\";\n\t\tif (value.hostname !== hostname()) return \"active\";\n\t\ttry {\n\t\t\tprocess.kill(value.pid, 0);\n\t\t\treturn \"active\";\n\t\t} catch (error) {\n\t\t\treturn (error as NodeJS.ErrnoException).code === \"EPERM\" ? \"active\" : \"stale\";\n\t\t}\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === \"ENOENT\" ? \"stale\" : \"unknown\";\n\t}\n}\n\nfunction removeFile(path: string): void {\n\ttry {\n\t\tunlinkSync(path);\n\t} catch {}\n}\n\nfunction cleanupMarkerBlocksAcquisition(runDir: string): boolean {\n\tconst markerPath = join(runDir, CLEANUP_MARKER_FILE);\n\tif (!existsSync(markerPath)) return false;\n\tconst state = markerState(markerPath);\n\tif (state !== \"stale\") return true;\n\tremoveFile(markerPath);\n\treturn existsSync(markerPath);\n}\n\nfunction hasActiveLease(runDir: string): boolean {\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tif (!existsSync(leasesDir)) return false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(leasesDir);\n\t\tlet scanned = 0;\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tscanned++;\n\t\t\tif (scanned > MAX_LEASE_MARKERS) return true;\n\t\t\tif (!entry.isFile()) return true;\n\t\t\tconst markerPath = join(leasesDir, entry.name);\n\t\t\tconst state = markerState(markerPath);\n\t\t\tif (state === \"active\" || state === \"unknown\") return true;\n\t\t\tremoveFile(markerPath);\n\t\t}\n\t} catch {\n\t\treturn true;\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\ttry {\n\t\trmdirSync(leasesDir);\n\t} catch {}\n\treturn false;\n}\n\nfunction measureDirectory(path: string, budget: ScanBudget, depth = 0): { bytes: number; complete: boolean } {\n\tif (depth > MAX_DIRECTORY_DEPTH || budget.remaining <= 0) return { bytes: 0, complete: false };\n\tlet bytes = 0;\n\tlet complete = true;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(path);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (budget.remaining <= 0) return { bytes, complete: false };\n\t\t\tbudget.remaining--;\n\t\t\tconst childPath = join(path, entry.name);\n\t\t\ttry {\n\t\t\t\tconst stats = lstatSync(childPath);\n\t\t\t\tif (stats.isDirectory() && !stats.isSymbolicLink()) {\n\t\t\t\t\tconst child = measureDirectory(childPath, budget, depth + 1);\n\t\t\t\t\tbytes += child.bytes;\n\t\t\t\t\tcomplete = complete && child.complete;\n\t\t\t\t} else {\n\t\t\t\t\tbytes += stats.size;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tcomplete = false;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { bytes, complete: false };\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\treturn { bytes, complete };\n}\n\nfunction inspectRun(\n\trunPath: string,\n\tcategory: string,\n\ttenant: string,\n\trunId: string,\n\tbudget: ScanBudget,\n\tunknownBytes: number,\n): InspectedRun | undefined {\n\ttry {\n\t\tconst stats = lstatSync(runPath);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return undefined;\n\t\tconst manifest = readSmallJson(join(runPath, WORK_RUN_MANIFEST_FILE));\n\t\tif (!isManifest(manifest, category, tenant, runId)) return undefined;\n\t\tconst measured = measureDirectory(runPath, budget);\n\t\treturn {\n\t\t\tpath: runPath,\n\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\tbytes: measured.complete ? measured.bytes : unknownBytes,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction createCleanupMarker(runDir: string, now: number): string | undefined {\n\tconst path = join(runDir, CLEANUP_MARKER_FILE);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\ttry {\n\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\treturn path;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") return undefined;\n\t\tif (markerState(path) !== \"stale\") return undefined;\n\t\tremoveFile(path);\n\t\ttry {\n\t\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\t\treturn path;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n\nfunction removeRunIfInactive(runPath: string, now: number): boolean {\n\tconst cleanupMarker = createCleanupMarker(runPath, now);\n\tif (!cleanupMarker) return false;\n\tif (hasActiveLease(runPath)) {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n\ttry {\n\t\trmSync(runPath, { recursive: true, force: true });\n\t\treturn !existsSync(runPath);\n\t} catch {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n}\n\nexport function getWorkRoot(agentDir: string): string {\n\treturn join(agentDir, \"work\");\n}\n\nexport function getWorkTenantDir(agentDir: string, category: string, tenant: string): string {\n\tassertPortableSegment(\"Work category\", category);\n\tassertPortableSegment(\"Work tenant\", tenant);\n\treturn join(getWorkRoot(agentDir), category, tenant);\n}\n\nexport function getWorkRunDir(agentDir: string, category: string, tenant: string, runId: string): string {\n\tassertPortableSegment(\"Work category\", category);\n\tassertPortableSegment(\"Work tenant\", tenant);\n\tassertPortableSegment(\"Work run id\", runId);\n\treturn join(getWorkRoot(agentDir), category, tenant, runId);\n}\n\nexport function createWorkRunId(now = Date.now()): string {\n\treturn `run-${now.toString(36)}-${process.pid.toString(36)}-${randomUUID().slice(0, 12)}`;\n}\n\nexport function pruneWorkTenant(\n\tagentDir: string,\n\tcategory: string,\n\ttenant: string,\n\toptions: WorkRetentionOptions = {},\n): string[] {\n\tconst tenantDir = getWorkTenantDir(agentDir, category, tenant);\n\tif (!existsSync(tenantDir)) return [];\n\ttry {\n\t\tconst stats = lstatSync(tenantDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return [];\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst now = options.now ?? Date.now();\n\tconst maxAgeMs = nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS);\n\tconst maxRuns = nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS);\n\tconst maxTotalBytes = nonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);\n\tconst maxScannedRuns = nonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS);\n\tconst budget: ScanBudget = {\n\t\tremaining: nonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),\n\t};\n\tconst unknownBytes = Math.max(1, maxTotalBytes + 1);\n\tconst runs: InspectedRun[] = [];\n\tlet truncated = false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(tenantDir);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (runs.length >= maxScannedRuns) {\n\t\t\t\ttruncated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!entry.isDirectory() || entry.isSymbolicLink()) continue;\n\t\t\tconst inspected = inspectRun(join(tenantDir, entry.name), category, tenant, entry.name, budget, unknownBytes);\n\t\t\tif (inspected) runs.push(inspected);\n\t\t}\n\t} catch {\n\t\treturn [];\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\n\tconst removed: string[] = [];\n\tlet retainedCount = runs.length + (truncated ? maxRuns + 1 : 0);\n\tlet retainedBytes = runs.reduce((sum, run) => sum + run.bytes, 0);\n\tfor (const run of runs.sort((left, right) => left.mtimeMs - right.mtimeMs)) {\n\t\tconst expired = now - run.mtimeMs > maxAgeMs;\n\t\tconst overCount = retainedCount > maxRuns;\n\t\tconst overBytes = retainedBytes > maxTotalBytes;\n\t\tif (!expired && !overCount && !overBytes) continue;\n\t\tif (!removeRunIfInactive(run.path, now)) continue;\n\t\tremoved.push(run.path);\n\t\tretainedCount--;\n\t\tretainedBytes -= run.bytes;\n\t}\n\treturn removed;\n}\n\nexport function getProcessWorkRun(agentDir: string, category: string, tenant: string, runId?: string): WorkRunLease {\n\tconst key = `${agentDir}\\0${category}\\0${tenant}\\0${runId ?? \"\"}`;\n\tconst existing = processWorkRuns.get(key);\n\tif (existing && existsSync(existing.path)) return existing;\n\tconst acquired = acquireWorkRun({ agentDir, category, tenant, runId });\n\tprocessWorkRuns.set(key, acquired);\n\treturn acquired;\n}\n\nexport function acquireWorkRun(options: AcquireWorkRunOptions): WorkRunLease {\n\tconst now = options.now ?? Date.now();\n\tconst runId = options.runId ?? createWorkRunId(now);\n\tassertPortableSegment(\"Work category\", options.category);\n\tassertPortableSegment(\"Work tenant\", options.tenant);\n\tassertPortableSegment(\"Work run id\", runId);\n\tconst tenantDir = ensureTenantDirectory(options.agentDir, options.category, options.tenant);\n\tconst runDir = join(tenantDir, runId);\n\tlet created = false;\n\ttry {\n\t\tmkdirSync(runDir);\n\t\tcreated = true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t\tconst stats = lstatSync(runDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\t\tthrow new Error(`Work run path is not a real directory: ${runDir}`);\n\t\t}\n\t}\n\n\tconst manifestPath = join(runDir, WORK_RUN_MANIFEST_FILE);\n\tif (created) {\n\t\tconst manifest: WorkRunManifest = {\n\t\t\tversion: 1,\n\t\t\tcategory: options.category,\n\t\t\ttenant: options.tenant,\n\t\t\trunId,\n\t\t\tcreatedAt: now,\n\t\t};\n\t\twriteFileSync(manifestPath, JSON.stringify(manifest), { encoding: \"utf8\", flag: \"wx\" });\n\t} else {\n\t\tlet manifest: unknown;\n\t\ttry {\n\t\t\tmanifest = readSmallJson(manifestPath);\n\t\t} catch {\n\t\t\tthrow new Error(`Refusing to adopt unowned work directory: ${runDir}`);\n\t\t}\n\t\tif (!isManifest(manifest, options.category, options.tenant, runId)) {\n\t\t\tthrow new Error(`Work directory manifest does not match its path: ${runDir}`);\n\t\t}\n\t}\n\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tthrow new Error(`Work run is being cleaned: ${runDir}`);\n\t}\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tensureDirectory(leasesDir);\n\tconst markerPath = join(leasesDir, `active-${process.pid}-${randomUUID()}.json`);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\twriteFileSync(markerPath, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tremoveFile(markerPath);\n\t\tthrow new Error(`Work run entered cleanup while it was being acquired: ${runDir}`);\n\t}\n\ttry {\n\t\tutimesSync(runDir, new Date(now), new Date(now));\n\t} catch {}\n\n\tif (options.retention !== false) {\n\t\ttry {\n\t\t\tpruneWorkTenant(options.agentDir, options.category, options.tenant, options.retention);\n\t\t} catch {}\n\t}\n\n\tlet released = false;\n\treturn {\n\t\tpath: runDir,\n\t\tcategory: options.category,\n\t\ttenant: options.tenant,\n\t\trunId,\n\t\ttouch(): void {\n\t\t\tif (released) return;\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(markerPath, touchedAt, touchedAt);\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t\trelease(): void {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tremoveFile(markerPath);\n\t\t\ttry {\n\t\t\t\trmdirSync(leasesDir);\n\t\t\t} catch {}\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"work-directory.d.ts","sourceRoot":"","sources":["../../src/utils/work-directory.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gBAAgB,iBAAiB,CAAC;AAC/C,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAgD1D,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,oBAAyB,GAAG,oBAAoB,CAkB7F;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,oBAAoB,GAAG,KAAK,CAAC;IACzC,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CAChB;AAQD,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAQ5E;AA0HD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAiGD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI3F;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAKvG;AAED,wBAAgB,eAAe,CAAC,GAAG,SAAa,GAAG,MAAM,CAExD;AAED,wBAAgB,eAAe,CAC9B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB,GAChC,MAAM,EAAE,CA0DV;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,YAAY,CAOlH;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,YAAY,CA2F3E","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n\ttype Dir,\n\texistsSync,\n\tlstatSync,\n\tmkdirSync,\n\topendirSync,\n\treadFileSync,\n\trmdirSync,\n\trmSync,\n\tunlinkSync,\n\tutimesSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const PI_WORK_ROOT_ENV = \"PI_WORK_ROOT\";\nexport const WORK_RUN_MANIFEST_FILE = \".pi-work-run.json\";\n\nconst LEASES_DIRECTORY = \".leases\";\nconst CLEANUP_MARKER_FILE = \".cleanup.json\";\nconst MAX_METADATA_BYTES = 4 * 1024;\nconst MAX_LEASE_MARKERS = 256;\nconst MAX_DIRECTORY_DEPTH = 64;\nconst DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_MAX_RUNS = 64;\nconst DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst DEFAULT_MAX_SCANNED_ENTRIES = 100_000;\nconst DEFAULT_MAX_SCANNED_RUNS = 10_000;\nconst SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst WINDOWS_RESERVED_NAMES = new Set([\n\t\"aux\",\n\t\"clock$\",\n\t\"con\",\n\t\"nul\",\n\t\"prn\",\n\t...Array.from({ length: 9 }, (_, index) => `com${index + 1}`),\n\t...Array.from({ length: 9 }, (_, index) => `lpt${index + 1}`),\n]);\n\ninterface WorkRunManifest {\n\tversion: 1;\n\tcategory: string;\n\ttenant: string;\n\trunId: string;\n\tcreatedAt: number;\n}\n\ninterface WorkMarker {\n\tversion: 1;\n\thostname: string;\n\tpid: number;\n\tcreatedAt: number;\n}\n\ninterface InspectedRun {\n\tpath: string;\n\tmtimeMs: number;\n\tbytes: number;\n}\n\ninterface ScanBudget {\n\tremaining: number;\n}\n\nexport interface WorkRetentionOptions {\n\tmaxAgeMs?: number;\n\tmaxRuns?: number;\n\tmaxTotalBytes?: number;\n\t/** Fixed tenant-wide cap for recursive file entries inspected during one prune. */\n\tmaxScannedEntries?: number;\n\t/** Fixed cap for run directories inspected during one prune. */\n\tmaxScannedRuns?: number;\n\tnow?: number;\n}\n\n/**\n * Clamp caller-selected retention to the harness ceiling. Consumers may retain less, but cannot turn\n * a managed work tenant into an unbounded artifact store by raising or disabling these limits.\n */\nexport function boundedWorkRetention(options: WorkRetentionOptions = {}): WorkRetentionOptions {\n\treturn {\n\t\tmaxAgeMs: Math.min(nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS), DEFAULT_MAX_AGE_MS),\n\t\tmaxRuns: Math.min(nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS), DEFAULT_MAX_RUNS),\n\t\tmaxTotalBytes: Math.min(\n\t\t\tnonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES),\n\t\t\tDEFAULT_MAX_TOTAL_BYTES,\n\t\t),\n\t\tmaxScannedEntries: Math.min(\n\t\t\tnonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),\n\t\t\tDEFAULT_MAX_SCANNED_ENTRIES,\n\t\t),\n\t\tmaxScannedRuns: Math.min(\n\t\t\tnonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS),\n\t\t\tDEFAULT_MAX_SCANNED_RUNS,\n\t\t),\n\t\tnow: options.now,\n\t};\n}\n\nexport interface AcquireWorkRunOptions {\n\tagentDir: string;\n\tcategory: string;\n\ttenant: string;\n\trunId?: string;\n\tretention?: WorkRetentionOptions | false;\n\tnow?: number;\n}\n\nexport interface WorkRunLease {\n\treadonly path: string;\n\treadonly category: string;\n\treadonly tenant: string;\n\treadonly runId: string;\n\ttouch(): void;\n\trelease(): void;\n}\n\nconst processWorkRuns = new Map<string, WorkRunLease>();\n\nfunction nonNegativeLimit(value: number | undefined, fallback: number): number {\n\treturn value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;\n}\n\nexport function assertPortablePathSegment(label: string, value: string): void {\n\tif (!SEGMENT_PATTERN.test(value) || value.endsWith(\".\")) {\n\t\tthrow new Error(`${label} must be a lowercase portable path segment (1-64 characters)`);\n\t}\n\tconst stem = value.split(\".\", 1)[0];\n\tif (stem && WINDOWS_RESERVED_NAMES.has(stem)) {\n\t\tthrow new Error(`${label} uses a Windows-reserved path name: ${value}`);\n\t}\n}\n\nfunction ensureDirectory(path: string): void {\n\ttry {\n\t\tmkdirSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t}\n\tconst stats = lstatSync(path);\n\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\tthrow new Error(`Work path is not a real directory: ${path}`);\n\t}\n}\n\nfunction ensureTenantDirectory(agentDir: string, category: string, tenant: string): string {\n\tmkdirSync(agentDir, { recursive: true });\n\tconst workRoot = getWorkRoot(agentDir);\n\tensureDirectory(workRoot);\n\tconst categoryDir = join(workRoot, category);\n\tensureDirectory(categoryDir);\n\tconst tenantDir = join(categoryDir, tenant);\n\tensureDirectory(tenantDir);\n\treturn tenantDir;\n}\n\nfunction readSmallJson(path: string): unknown {\n\tconst stats = lstatSync(path);\n\tif (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_METADATA_BYTES) {\n\t\tthrow new Error(`Invalid work metadata file: ${path}`);\n\t}\n\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n}\n\nfunction isManifest(value: unknown, category: string, tenant: string, runId: string): value is WorkRunManifest {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst manifest = value as Partial<WorkRunManifest>;\n\treturn (\n\t\tmanifest.version === 1 &&\n\t\tmanifest.category === category &&\n\t\tmanifest.tenant === tenant &&\n\t\tmanifest.runId === runId &&\n\t\ttypeof manifest.createdAt === \"number\" &&\n\t\tNumber.isFinite(manifest.createdAt)\n\t);\n}\n\nfunction isMarker(value: unknown): value is WorkMarker {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst marker = value as Partial<WorkMarker>;\n\treturn (\n\t\tmarker.version === 1 &&\n\t\ttypeof marker.hostname === \"string\" &&\n\t\ttypeof marker.pid === \"number\" &&\n\t\tNumber.isSafeInteger(marker.pid) &&\n\t\tmarker.pid > 0 &&\n\t\ttypeof marker.createdAt === \"number\" &&\n\t\tNumber.isFinite(marker.createdAt)\n\t);\n}\n\nfunction markerState(path: string): \"active\" | \"stale\" | \"unknown\" {\n\ttry {\n\t\tconst value = readSmallJson(path);\n\t\tif (!isMarker(value)) return \"unknown\";\n\t\tif (value.hostname !== hostname()) return \"active\";\n\t\ttry {\n\t\t\tprocess.kill(value.pid, 0);\n\t\t\treturn \"active\";\n\t\t} catch (error) {\n\t\t\treturn (error as NodeJS.ErrnoException).code === \"EPERM\" ? \"active\" : \"stale\";\n\t\t}\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === \"ENOENT\" ? \"stale\" : \"unknown\";\n\t}\n}\n\nfunction removeFile(path: string): void {\n\ttry {\n\t\tunlinkSync(path);\n\t} catch {}\n}\n\nfunction cleanupMarkerBlocksAcquisition(runDir: string): boolean {\n\tconst markerPath = join(runDir, CLEANUP_MARKER_FILE);\n\tif (!existsSync(markerPath)) return false;\n\tconst state = markerState(markerPath);\n\tif (state !== \"stale\") return true;\n\tremoveFile(markerPath);\n\treturn existsSync(markerPath);\n}\n\nfunction hasActiveLease(runDir: string): boolean {\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tif (!existsSync(leasesDir)) return false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(leasesDir);\n\t\tlet scanned = 0;\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tscanned++;\n\t\t\tif (scanned > MAX_LEASE_MARKERS) return true;\n\t\t\tif (!entry.isFile()) return true;\n\t\t\tconst markerPath = join(leasesDir, entry.name);\n\t\t\tconst state = markerState(markerPath);\n\t\t\tif (state === \"active\" || state === \"unknown\") return true;\n\t\t\tremoveFile(markerPath);\n\t\t}\n\t} catch {\n\t\treturn true;\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\ttry {\n\t\trmdirSync(leasesDir);\n\t} catch {}\n\treturn false;\n}\n\n/**\n * Report whether a managed run is leased or being cleaned. Stale local markers are removed as part\n * of the check; malformed or foreign-host markers remain fail-closed and count as active.\n */\nexport function hasActiveWorkRunLease(runDir: string): boolean {\n\treturn cleanupMarkerBlocksAcquisition(runDir) || hasActiveLease(runDir);\n}\n\nfunction measureDirectory(path: string, budget: ScanBudget, depth = 0): { bytes: number; complete: boolean } {\n\tif (depth > MAX_DIRECTORY_DEPTH || budget.remaining <= 0) return { bytes: 0, complete: false };\n\tlet bytes = 0;\n\tlet complete = true;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(path);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (budget.remaining <= 0) return { bytes, complete: false };\n\t\t\tbudget.remaining--;\n\t\t\tconst childPath = join(path, entry.name);\n\t\t\ttry {\n\t\t\t\tconst stats = lstatSync(childPath);\n\t\t\t\tif (stats.isDirectory() && !stats.isSymbolicLink()) {\n\t\t\t\t\tconst child = measureDirectory(childPath, budget, depth + 1);\n\t\t\t\t\tbytes += child.bytes;\n\t\t\t\t\tcomplete = complete && child.complete;\n\t\t\t\t} else {\n\t\t\t\t\tbytes += stats.size;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tcomplete = false;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { bytes, complete: false };\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\treturn { bytes, complete };\n}\n\nfunction inspectRun(\n\trunPath: string,\n\tcategory: string,\n\ttenant: string,\n\trunId: string,\n\tbudget: ScanBudget,\n\tunknownBytes: number,\n): InspectedRun | undefined {\n\ttry {\n\t\tconst stats = lstatSync(runPath);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return undefined;\n\t\tconst manifest = readSmallJson(join(runPath, WORK_RUN_MANIFEST_FILE));\n\t\tif (!isManifest(manifest, category, tenant, runId)) return undefined;\n\t\tconst measured = measureDirectory(runPath, budget);\n\t\treturn {\n\t\t\tpath: runPath,\n\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\tbytes: measured.complete ? measured.bytes : unknownBytes,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction createCleanupMarker(runDir: string, now: number): string | undefined {\n\tconst path = join(runDir, CLEANUP_MARKER_FILE);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\ttry {\n\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\treturn path;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") return undefined;\n\t\tif (markerState(path) !== \"stale\") return undefined;\n\t\tremoveFile(path);\n\t\ttry {\n\t\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\t\treturn path;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n\nfunction removeRunIfInactive(runPath: string, now: number): boolean {\n\tconst cleanupMarker = createCleanupMarker(runPath, now);\n\tif (!cleanupMarker) return false;\n\tif (hasActiveLease(runPath)) {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n\ttry {\n\t\trmSync(runPath, { recursive: true, force: true });\n\t\treturn !existsSync(runPath);\n\t} catch {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n}\n\nexport function getWorkRoot(agentDir: string): string {\n\treturn join(agentDir, \"work\");\n}\n\nexport function getWorkTenantDir(agentDir: string, category: string, tenant: string): string {\n\tassertPortablePathSegment(\"Work category\", category);\n\tassertPortablePathSegment(\"Work tenant\", tenant);\n\treturn join(getWorkRoot(agentDir), category, tenant);\n}\n\nexport function getWorkRunDir(agentDir: string, category: string, tenant: string, runId: string): string {\n\tassertPortablePathSegment(\"Work category\", category);\n\tassertPortablePathSegment(\"Work tenant\", tenant);\n\tassertPortablePathSegment(\"Work run id\", runId);\n\treturn join(getWorkRoot(agentDir), category, tenant, runId);\n}\n\nexport function createWorkRunId(now = Date.now()): string {\n\treturn `run-${now.toString(36)}-${process.pid.toString(36)}-${randomUUID().slice(0, 12)}`;\n}\n\nexport function pruneWorkTenant(\n\tagentDir: string,\n\tcategory: string,\n\ttenant: string,\n\toptions: WorkRetentionOptions = {},\n): string[] {\n\tconst tenantDir = getWorkTenantDir(agentDir, category, tenant);\n\tif (!existsSync(tenantDir)) return [];\n\ttry {\n\t\tconst stats = lstatSync(tenantDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return [];\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst now = options.now ?? Date.now();\n\tconst maxAgeMs = nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS);\n\tconst maxRuns = nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS);\n\tconst maxTotalBytes = nonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);\n\tconst maxScannedRuns = nonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS);\n\tconst budget: ScanBudget = {\n\t\tremaining: nonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),\n\t};\n\tconst unknownBytes = Math.max(1, maxTotalBytes + 1);\n\tconst runs: InspectedRun[] = [];\n\tlet truncated = false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(tenantDir);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (runs.length >= maxScannedRuns) {\n\t\t\t\ttruncated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!entry.isDirectory() || entry.isSymbolicLink()) continue;\n\t\t\tconst inspected = inspectRun(join(tenantDir, entry.name), category, tenant, entry.name, budget, unknownBytes);\n\t\t\tif (inspected) runs.push(inspected);\n\t\t}\n\t} catch {\n\t\treturn [];\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\n\tconst removed: string[] = [];\n\tlet retainedCount = runs.length + (truncated ? maxRuns + 1 : 0);\n\tlet retainedBytes = runs.reduce((sum, run) => sum + run.bytes, 0);\n\tfor (const run of runs.sort((left, right) => left.mtimeMs - right.mtimeMs)) {\n\t\tconst expired = now - run.mtimeMs > maxAgeMs;\n\t\tconst overCount = retainedCount > maxRuns;\n\t\tconst overBytes = retainedBytes > maxTotalBytes;\n\t\tif (!expired && !overCount && !overBytes) continue;\n\t\tif (!removeRunIfInactive(run.path, now)) continue;\n\t\tremoved.push(run.path);\n\t\tretainedCount--;\n\t\tretainedBytes -= run.bytes;\n\t}\n\treturn removed;\n}\n\nexport function getProcessWorkRun(agentDir: string, category: string, tenant: string, runId?: string): WorkRunLease {\n\tconst key = `${agentDir}\\0${category}\\0${tenant}\\0${runId ?? \"\"}`;\n\tconst existing = processWorkRuns.get(key);\n\tif (existing && existsSync(existing.path)) return existing;\n\tconst acquired = acquireWorkRun({ agentDir, category, tenant, runId });\n\tprocessWorkRuns.set(key, acquired);\n\treturn acquired;\n}\n\nexport function acquireWorkRun(options: AcquireWorkRunOptions): WorkRunLease {\n\tconst now = options.now ?? Date.now();\n\tconst runId = options.runId ?? createWorkRunId(now);\n\tassertPortablePathSegment(\"Work category\", options.category);\n\tassertPortablePathSegment(\"Work tenant\", options.tenant);\n\tassertPortablePathSegment(\"Work run id\", runId);\n\tconst tenantDir = ensureTenantDirectory(options.agentDir, options.category, options.tenant);\n\tconst runDir = join(tenantDir, runId);\n\tlet created = false;\n\ttry {\n\t\tmkdirSync(runDir);\n\t\tcreated = true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t\tconst stats = lstatSync(runDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\t\tthrow new Error(`Work run path is not a real directory: ${runDir}`);\n\t\t}\n\t}\n\n\tconst manifestPath = join(runDir, WORK_RUN_MANIFEST_FILE);\n\tif (created) {\n\t\tconst manifest: WorkRunManifest = {\n\t\t\tversion: 1,\n\t\t\tcategory: options.category,\n\t\t\ttenant: options.tenant,\n\t\t\trunId,\n\t\t\tcreatedAt: now,\n\t\t};\n\t\twriteFileSync(manifestPath, JSON.stringify(manifest), { encoding: \"utf8\", flag: \"wx\" });\n\t} else {\n\t\tlet manifest: unknown;\n\t\ttry {\n\t\t\tmanifest = readSmallJson(manifestPath);\n\t\t} catch {\n\t\t\tthrow new Error(`Refusing to adopt unowned work directory: ${runDir}`);\n\t\t}\n\t\tif (!isManifest(manifest, options.category, options.tenant, runId)) {\n\t\t\tthrow new Error(`Work directory manifest does not match its path: ${runDir}`);\n\t\t}\n\t}\n\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tthrow new Error(`Work run is being cleaned: ${runDir}`);\n\t}\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tensureDirectory(leasesDir);\n\tconst markerPath = join(leasesDir, `active-${process.pid}-${randomUUID()}.json`);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\twriteFileSync(markerPath, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tremoveFile(markerPath);\n\t\tthrow new Error(`Work run entered cleanup while it was being acquired: ${runDir}`);\n\t}\n\ttry {\n\t\tutimesSync(runDir, new Date(now), new Date(now));\n\t} catch {}\n\n\tif (options.retention !== false) {\n\t\ttry {\n\t\t\tpruneWorkTenant(options.agentDir, options.category, options.tenant, options.retention);\n\t\t} catch {}\n\t}\n\n\tlet released = false;\n\treturn {\n\t\tpath: runDir,\n\t\tcategory: options.category,\n\t\ttenant: options.tenant,\n\t\trunId,\n\t\ttouch(): void {\n\t\t\tif (released) return;\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(markerPath, touchedAt, touchedAt);\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t\trelease(): void {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tremoveFile(markerPath);\n\t\t\ttry {\n\t\t\t\trmdirSync(leasesDir);\n\t\t\t} catch {}\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t};\n}\n"]}
|
|
@@ -24,11 +24,25 @@ const WINDOWS_RESERVED_NAMES = new Set([
|
|
|
24
24
|
...Array.from({ length: 9 }, (_, index) => `com${index + 1}`),
|
|
25
25
|
...Array.from({ length: 9 }, (_, index) => `lpt${index + 1}`),
|
|
26
26
|
]);
|
|
27
|
+
/**
|
|
28
|
+
* Clamp caller-selected retention to the harness ceiling. Consumers may retain less, but cannot turn
|
|
29
|
+
* a managed work tenant into an unbounded artifact store by raising or disabling these limits.
|
|
30
|
+
*/
|
|
31
|
+
export function boundedWorkRetention(options = {}) {
|
|
32
|
+
return {
|
|
33
|
+
maxAgeMs: Math.min(nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS), DEFAULT_MAX_AGE_MS),
|
|
34
|
+
maxRuns: Math.min(nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS), DEFAULT_MAX_RUNS),
|
|
35
|
+
maxTotalBytes: Math.min(nonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES), DEFAULT_MAX_TOTAL_BYTES),
|
|
36
|
+
maxScannedEntries: Math.min(nonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES), DEFAULT_MAX_SCANNED_ENTRIES),
|
|
37
|
+
maxScannedRuns: Math.min(nonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS), DEFAULT_MAX_SCANNED_RUNS),
|
|
38
|
+
now: options.now,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
27
41
|
const processWorkRuns = new Map();
|
|
28
42
|
function nonNegativeLimit(value, fallback) {
|
|
29
43
|
return value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;
|
|
30
44
|
}
|
|
31
|
-
function
|
|
45
|
+
export function assertPortablePathSegment(label, value) {
|
|
32
46
|
if (!SEGMENT_PATTERN.test(value) || value.endsWith(".")) {
|
|
33
47
|
throw new Error(`${label} must be a lowercase portable path segment (1-64 characters)`);
|
|
34
48
|
}
|
|
@@ -164,6 +178,13 @@ function hasActiveLease(runDir) {
|
|
|
164
178
|
catch { }
|
|
165
179
|
return false;
|
|
166
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Report whether a managed run is leased or being cleaned. Stale local markers are removed as part
|
|
183
|
+
* of the check; malformed or foreign-host markers remain fail-closed and count as active.
|
|
184
|
+
*/
|
|
185
|
+
export function hasActiveWorkRunLease(runDir) {
|
|
186
|
+
return cleanupMarkerBlocksAcquisition(runDir) || hasActiveLease(runDir);
|
|
187
|
+
}
|
|
167
188
|
function measureDirectory(path, budget, depth = 0) {
|
|
168
189
|
if (depth > MAX_DIRECTORY_DEPTH || budget.remaining <= 0)
|
|
169
190
|
return { bytes: 0, complete: false };
|
|
@@ -269,14 +290,14 @@ export function getWorkRoot(agentDir) {
|
|
|
269
290
|
return join(agentDir, "work");
|
|
270
291
|
}
|
|
271
292
|
export function getWorkTenantDir(agentDir, category, tenant) {
|
|
272
|
-
|
|
273
|
-
|
|
293
|
+
assertPortablePathSegment("Work category", category);
|
|
294
|
+
assertPortablePathSegment("Work tenant", tenant);
|
|
274
295
|
return join(getWorkRoot(agentDir), category, tenant);
|
|
275
296
|
}
|
|
276
297
|
export function getWorkRunDir(agentDir, category, tenant, runId) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
298
|
+
assertPortablePathSegment("Work category", category);
|
|
299
|
+
assertPortablePathSegment("Work tenant", tenant);
|
|
300
|
+
assertPortablePathSegment("Work run id", runId);
|
|
280
301
|
return join(getWorkRoot(agentDir), category, tenant, runId);
|
|
281
302
|
}
|
|
282
303
|
export function createWorkRunId(now = Date.now()) {
|
|
@@ -363,9 +384,9 @@ export function getProcessWorkRun(agentDir, category, tenant, runId) {
|
|
|
363
384
|
export function acquireWorkRun(options) {
|
|
364
385
|
const now = options.now ?? Date.now();
|
|
365
386
|
const runId = options.runId ?? createWorkRunId(now);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
387
|
+
assertPortablePathSegment("Work category", options.category);
|
|
388
|
+
assertPortablePathSegment("Work tenant", options.tenant);
|
|
389
|
+
assertPortablePathSegment("Work run id", runId);
|
|
369
390
|
const tenantDir = ensureTenantDirectory(options.agentDir, options.category, options.tenant);
|
|
370
391
|
const runDir = join(tenantDir, runId);
|
|
371
392
|
let created = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-directory.js","sourceRoot":"","sources":["../../src/utils/work-directory.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n\ttype Dir,\n\texistsSync,\n\tlstatSync,\n\tmkdirSync,\n\topendirSync,\n\treadFileSync,\n\trmdirSync,\n\trmSync,\n\tunlinkSync,\n\tutimesSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const PI_WORK_ROOT_ENV = \"PI_WORK_ROOT\";\nexport const WORK_RUN_MANIFEST_FILE = \".pi-work-run.json\";\n\nconst LEASES_DIRECTORY = \".leases\";\nconst CLEANUP_MARKER_FILE = \".cleanup.json\";\nconst MAX_METADATA_BYTES = 4 * 1024;\nconst MAX_LEASE_MARKERS = 256;\nconst MAX_DIRECTORY_DEPTH = 64;\nconst DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_MAX_RUNS = 64;\nconst DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst DEFAULT_MAX_SCANNED_ENTRIES = 100_000;\nconst DEFAULT_MAX_SCANNED_RUNS = 10_000;\nconst SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst WINDOWS_RESERVED_NAMES = new Set([\n\t\"aux\",\n\t\"clock$\",\n\t\"con\",\n\t\"nul\",\n\t\"prn\",\n\t...Array.from({ length: 9 }, (_, index) => `com${index + 1}`),\n\t...Array.from({ length: 9 }, (_, index) => `lpt${index + 1}`),\n]);\n\ninterface WorkRunManifest {\n\tversion: 1;\n\tcategory: string;\n\ttenant: string;\n\trunId: string;\n\tcreatedAt: number;\n}\n\ninterface WorkMarker {\n\tversion: 1;\n\thostname: string;\n\tpid: number;\n\tcreatedAt: number;\n}\n\ninterface InspectedRun {\n\tpath: string;\n\tmtimeMs: number;\n\tbytes: number;\n}\n\ninterface ScanBudget {\n\tremaining: number;\n}\n\nexport interface WorkRetentionOptions {\n\tmaxAgeMs?: number;\n\tmaxRuns?: number;\n\tmaxTotalBytes?: number;\n\t/** Fixed tenant-wide cap for recursive file entries inspected during one prune. */\n\tmaxScannedEntries?: number;\n\t/** Fixed cap for run directories inspected during one prune. */\n\tmaxScannedRuns?: number;\n\tnow?: number;\n}\n\nexport interface AcquireWorkRunOptions {\n\tagentDir: string;\n\tcategory: string;\n\ttenant: string;\n\trunId?: string;\n\tretention?: WorkRetentionOptions | false;\n\tnow?: number;\n}\n\nexport interface WorkRunLease {\n\treadonly path: string;\n\treadonly category: string;\n\treadonly tenant: string;\n\treadonly runId: string;\n\ttouch(): void;\n\trelease(): void;\n}\n\nconst processWorkRuns = new Map<string, WorkRunLease>();\n\nfunction nonNegativeLimit(value: number | undefined, fallback: number): number {\n\treturn value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;\n}\n\nfunction assertPortableSegment(label: string, value: string): void {\n\tif (!SEGMENT_PATTERN.test(value) || value.endsWith(\".\")) {\n\t\tthrow new Error(`${label} must be a lowercase portable path segment (1-64 characters)`);\n\t}\n\tconst stem = value.split(\".\", 1)[0];\n\tif (stem && WINDOWS_RESERVED_NAMES.has(stem)) {\n\t\tthrow new Error(`${label} uses a Windows-reserved path name: ${value}`);\n\t}\n}\n\nfunction ensureDirectory(path: string): void {\n\ttry {\n\t\tmkdirSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t}\n\tconst stats = lstatSync(path);\n\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\tthrow new Error(`Work path is not a real directory: ${path}`);\n\t}\n}\n\nfunction ensureTenantDirectory(agentDir: string, category: string, tenant: string): string {\n\tmkdirSync(agentDir, { recursive: true });\n\tconst workRoot = getWorkRoot(agentDir);\n\tensureDirectory(workRoot);\n\tconst categoryDir = join(workRoot, category);\n\tensureDirectory(categoryDir);\n\tconst tenantDir = join(categoryDir, tenant);\n\tensureDirectory(tenantDir);\n\treturn tenantDir;\n}\n\nfunction readSmallJson(path: string): unknown {\n\tconst stats = lstatSync(path);\n\tif (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_METADATA_BYTES) {\n\t\tthrow new Error(`Invalid work metadata file: ${path}`);\n\t}\n\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n}\n\nfunction isManifest(value: unknown, category: string, tenant: string, runId: string): value is WorkRunManifest {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst manifest = value as Partial<WorkRunManifest>;\n\treturn (\n\t\tmanifest.version === 1 &&\n\t\tmanifest.category === category &&\n\t\tmanifest.tenant === tenant &&\n\t\tmanifest.runId === runId &&\n\t\ttypeof manifest.createdAt === \"number\" &&\n\t\tNumber.isFinite(manifest.createdAt)\n\t);\n}\n\nfunction isMarker(value: unknown): value is WorkMarker {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst marker = value as Partial<WorkMarker>;\n\treturn (\n\t\tmarker.version === 1 &&\n\t\ttypeof marker.hostname === \"string\" &&\n\t\ttypeof marker.pid === \"number\" &&\n\t\tNumber.isSafeInteger(marker.pid) &&\n\t\tmarker.pid > 0 &&\n\t\ttypeof marker.createdAt === \"number\" &&\n\t\tNumber.isFinite(marker.createdAt)\n\t);\n}\n\nfunction markerState(path: string): \"active\" | \"stale\" | \"unknown\" {\n\ttry {\n\t\tconst value = readSmallJson(path);\n\t\tif (!isMarker(value)) return \"unknown\";\n\t\tif (value.hostname !== hostname()) return \"active\";\n\t\ttry {\n\t\t\tprocess.kill(value.pid, 0);\n\t\t\treturn \"active\";\n\t\t} catch (error) {\n\t\t\treturn (error as NodeJS.ErrnoException).code === \"EPERM\" ? \"active\" : \"stale\";\n\t\t}\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === \"ENOENT\" ? \"stale\" : \"unknown\";\n\t}\n}\n\nfunction removeFile(path: string): void {\n\ttry {\n\t\tunlinkSync(path);\n\t} catch {}\n}\n\nfunction cleanupMarkerBlocksAcquisition(runDir: string): boolean {\n\tconst markerPath = join(runDir, CLEANUP_MARKER_FILE);\n\tif (!existsSync(markerPath)) return false;\n\tconst state = markerState(markerPath);\n\tif (state !== \"stale\") return true;\n\tremoveFile(markerPath);\n\treturn existsSync(markerPath);\n}\n\nfunction hasActiveLease(runDir: string): boolean {\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tif (!existsSync(leasesDir)) return false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(leasesDir);\n\t\tlet scanned = 0;\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tscanned++;\n\t\t\tif (scanned > MAX_LEASE_MARKERS) return true;\n\t\t\tif (!entry.isFile()) return true;\n\t\t\tconst markerPath = join(leasesDir, entry.name);\n\t\t\tconst state = markerState(markerPath);\n\t\t\tif (state === \"active\" || state === \"unknown\") return true;\n\t\t\tremoveFile(markerPath);\n\t\t}\n\t} catch {\n\t\treturn true;\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\ttry {\n\t\trmdirSync(leasesDir);\n\t} catch {}\n\treturn false;\n}\n\nfunction measureDirectory(path: string, budget: ScanBudget, depth = 0): { bytes: number; complete: boolean } {\n\tif (depth > MAX_DIRECTORY_DEPTH || budget.remaining <= 0) return { bytes: 0, complete: false };\n\tlet bytes = 0;\n\tlet complete = true;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(path);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (budget.remaining <= 0) return { bytes, complete: false };\n\t\t\tbudget.remaining--;\n\t\t\tconst childPath = join(path, entry.name);\n\t\t\ttry {\n\t\t\t\tconst stats = lstatSync(childPath);\n\t\t\t\tif (stats.isDirectory() && !stats.isSymbolicLink()) {\n\t\t\t\t\tconst child = measureDirectory(childPath, budget, depth + 1);\n\t\t\t\t\tbytes += child.bytes;\n\t\t\t\t\tcomplete = complete && child.complete;\n\t\t\t\t} else {\n\t\t\t\t\tbytes += stats.size;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tcomplete = false;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { bytes, complete: false };\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\treturn { bytes, complete };\n}\n\nfunction inspectRun(\n\trunPath: string,\n\tcategory: string,\n\ttenant: string,\n\trunId: string,\n\tbudget: ScanBudget,\n\tunknownBytes: number,\n): InspectedRun | undefined {\n\ttry {\n\t\tconst stats = lstatSync(runPath);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return undefined;\n\t\tconst manifest = readSmallJson(join(runPath, WORK_RUN_MANIFEST_FILE));\n\t\tif (!isManifest(manifest, category, tenant, runId)) return undefined;\n\t\tconst measured = measureDirectory(runPath, budget);\n\t\treturn {\n\t\t\tpath: runPath,\n\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\tbytes: measured.complete ? measured.bytes : unknownBytes,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction createCleanupMarker(runDir: string, now: number): string | undefined {\n\tconst path = join(runDir, CLEANUP_MARKER_FILE);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\ttry {\n\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\treturn path;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") return undefined;\n\t\tif (markerState(path) !== \"stale\") return undefined;\n\t\tremoveFile(path);\n\t\ttry {\n\t\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\t\treturn path;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n\nfunction removeRunIfInactive(runPath: string, now: number): boolean {\n\tconst cleanupMarker = createCleanupMarker(runPath, now);\n\tif (!cleanupMarker) return false;\n\tif (hasActiveLease(runPath)) {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n\ttry {\n\t\trmSync(runPath, { recursive: true, force: true });\n\t\treturn !existsSync(runPath);\n\t} catch {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n}\n\nexport function getWorkRoot(agentDir: string): string {\n\treturn join(agentDir, \"work\");\n}\n\nexport function getWorkTenantDir(agentDir: string, category: string, tenant: string): string {\n\tassertPortableSegment(\"Work category\", category);\n\tassertPortableSegment(\"Work tenant\", tenant);\n\treturn join(getWorkRoot(agentDir), category, tenant);\n}\n\nexport function getWorkRunDir(agentDir: string, category: string, tenant: string, runId: string): string {\n\tassertPortableSegment(\"Work category\", category);\n\tassertPortableSegment(\"Work tenant\", tenant);\n\tassertPortableSegment(\"Work run id\", runId);\n\treturn join(getWorkRoot(agentDir), category, tenant, runId);\n}\n\nexport function createWorkRunId(now = Date.now()): string {\n\treturn `run-${now.toString(36)}-${process.pid.toString(36)}-${randomUUID().slice(0, 12)}`;\n}\n\nexport function pruneWorkTenant(\n\tagentDir: string,\n\tcategory: string,\n\ttenant: string,\n\toptions: WorkRetentionOptions = {},\n): string[] {\n\tconst tenantDir = getWorkTenantDir(agentDir, category, tenant);\n\tif (!existsSync(tenantDir)) return [];\n\ttry {\n\t\tconst stats = lstatSync(tenantDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return [];\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst now = options.now ?? Date.now();\n\tconst maxAgeMs = nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS);\n\tconst maxRuns = nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS);\n\tconst maxTotalBytes = nonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);\n\tconst maxScannedRuns = nonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS);\n\tconst budget: ScanBudget = {\n\t\tremaining: nonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),\n\t};\n\tconst unknownBytes = Math.max(1, maxTotalBytes + 1);\n\tconst runs: InspectedRun[] = [];\n\tlet truncated = false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(tenantDir);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (runs.length >= maxScannedRuns) {\n\t\t\t\ttruncated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!entry.isDirectory() || entry.isSymbolicLink()) continue;\n\t\t\tconst inspected = inspectRun(join(tenantDir, entry.name), category, tenant, entry.name, budget, unknownBytes);\n\t\t\tif (inspected) runs.push(inspected);\n\t\t}\n\t} catch {\n\t\treturn [];\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\n\tconst removed: string[] = [];\n\tlet retainedCount = runs.length + (truncated ? maxRuns + 1 : 0);\n\tlet retainedBytes = runs.reduce((sum, run) => sum + run.bytes, 0);\n\tfor (const run of runs.sort((left, right) => left.mtimeMs - right.mtimeMs)) {\n\t\tconst expired = now - run.mtimeMs > maxAgeMs;\n\t\tconst overCount = retainedCount > maxRuns;\n\t\tconst overBytes = retainedBytes > maxTotalBytes;\n\t\tif (!expired && !overCount && !overBytes) continue;\n\t\tif (!removeRunIfInactive(run.path, now)) continue;\n\t\tremoved.push(run.path);\n\t\tretainedCount--;\n\t\tretainedBytes -= run.bytes;\n\t}\n\treturn removed;\n}\n\nexport function getProcessWorkRun(agentDir: string, category: string, tenant: string, runId?: string): WorkRunLease {\n\tconst key = `${agentDir}\\0${category}\\0${tenant}\\0${runId ?? \"\"}`;\n\tconst existing = processWorkRuns.get(key);\n\tif (existing && existsSync(existing.path)) return existing;\n\tconst acquired = acquireWorkRun({ agentDir, category, tenant, runId });\n\tprocessWorkRuns.set(key, acquired);\n\treturn acquired;\n}\n\nexport function acquireWorkRun(options: AcquireWorkRunOptions): WorkRunLease {\n\tconst now = options.now ?? Date.now();\n\tconst runId = options.runId ?? createWorkRunId(now);\n\tassertPortableSegment(\"Work category\", options.category);\n\tassertPortableSegment(\"Work tenant\", options.tenant);\n\tassertPortableSegment(\"Work run id\", runId);\n\tconst tenantDir = ensureTenantDirectory(options.agentDir, options.category, options.tenant);\n\tconst runDir = join(tenantDir, runId);\n\tlet created = false;\n\ttry {\n\t\tmkdirSync(runDir);\n\t\tcreated = true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t\tconst stats = lstatSync(runDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\t\tthrow new Error(`Work run path is not a real directory: ${runDir}`);\n\t\t}\n\t}\n\n\tconst manifestPath = join(runDir, WORK_RUN_MANIFEST_FILE);\n\tif (created) {\n\t\tconst manifest: WorkRunManifest = {\n\t\t\tversion: 1,\n\t\t\tcategory: options.category,\n\t\t\ttenant: options.tenant,\n\t\t\trunId,\n\t\t\tcreatedAt: now,\n\t\t};\n\t\twriteFileSync(manifestPath, JSON.stringify(manifest), { encoding: \"utf8\", flag: \"wx\" });\n\t} else {\n\t\tlet manifest: unknown;\n\t\ttry {\n\t\t\tmanifest = readSmallJson(manifestPath);\n\t\t} catch {\n\t\t\tthrow new Error(`Refusing to adopt unowned work directory: ${runDir}`);\n\t\t}\n\t\tif (!isManifest(manifest, options.category, options.tenant, runId)) {\n\t\t\tthrow new Error(`Work directory manifest does not match its path: ${runDir}`);\n\t\t}\n\t}\n\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tthrow new Error(`Work run is being cleaned: ${runDir}`);\n\t}\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tensureDirectory(leasesDir);\n\tconst markerPath = join(leasesDir, `active-${process.pid}-${randomUUID()}.json`);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\twriteFileSync(markerPath, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tremoveFile(markerPath);\n\t\tthrow new Error(`Work run entered cleanup while it was being acquired: ${runDir}`);\n\t}\n\ttry {\n\t\tutimesSync(runDir, new Date(now), new Date(now));\n\t} catch {}\n\n\tif (options.retention !== false) {\n\t\ttry {\n\t\t\tpruneWorkTenant(options.agentDir, options.category, options.tenant, options.retention);\n\t\t} catch {}\n\t}\n\n\tlet released = false;\n\treturn {\n\t\tpath: runDir,\n\t\tcategory: options.category,\n\t\ttenant: options.tenant,\n\t\trunId,\n\t\ttouch(): void {\n\t\t\tif (released) return;\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(markerPath, touchedAt, touchedAt);\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t\trelease(): void {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tremoveFile(markerPath);\n\t\t\ttry {\n\t\t\t\trmdirSync(leasesDir);\n\t\t\t} catch {}\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"work-directory.js","sourceRoot":"","sources":["../../src/utils/work-directory.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n\ttype Dir,\n\texistsSync,\n\tlstatSync,\n\tmkdirSync,\n\topendirSync,\n\treadFileSync,\n\trmdirSync,\n\trmSync,\n\tunlinkSync,\n\tutimesSync,\n\twriteFileSync,\n} from \"node:fs\";\nimport { hostname } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const PI_WORK_ROOT_ENV = \"PI_WORK_ROOT\";\nexport const WORK_RUN_MANIFEST_FILE = \".pi-work-run.json\";\n\nconst LEASES_DIRECTORY = \".leases\";\nconst CLEANUP_MARKER_FILE = \".cleanup.json\";\nconst MAX_METADATA_BYTES = 4 * 1024;\nconst MAX_LEASE_MARKERS = 256;\nconst MAX_DIRECTORY_DEPTH = 64;\nconst DEFAULT_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst DEFAULT_MAX_RUNS = 64;\nconst DEFAULT_MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst DEFAULT_MAX_SCANNED_ENTRIES = 100_000;\nconst DEFAULT_MAX_SCANNED_RUNS = 10_000;\nconst SEGMENT_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;\nconst WINDOWS_RESERVED_NAMES = new Set([\n\t\"aux\",\n\t\"clock$\",\n\t\"con\",\n\t\"nul\",\n\t\"prn\",\n\t...Array.from({ length: 9 }, (_, index) => `com${index + 1}`),\n\t...Array.from({ length: 9 }, (_, index) => `lpt${index + 1}`),\n]);\n\ninterface WorkRunManifest {\n\tversion: 1;\n\tcategory: string;\n\ttenant: string;\n\trunId: string;\n\tcreatedAt: number;\n}\n\ninterface WorkMarker {\n\tversion: 1;\n\thostname: string;\n\tpid: number;\n\tcreatedAt: number;\n}\n\ninterface InspectedRun {\n\tpath: string;\n\tmtimeMs: number;\n\tbytes: number;\n}\n\ninterface ScanBudget {\n\tremaining: number;\n}\n\nexport interface WorkRetentionOptions {\n\tmaxAgeMs?: number;\n\tmaxRuns?: number;\n\tmaxTotalBytes?: number;\n\t/** Fixed tenant-wide cap for recursive file entries inspected during one prune. */\n\tmaxScannedEntries?: number;\n\t/** Fixed cap for run directories inspected during one prune. */\n\tmaxScannedRuns?: number;\n\tnow?: number;\n}\n\n/**\n * Clamp caller-selected retention to the harness ceiling. Consumers may retain less, but cannot turn\n * a managed work tenant into an unbounded artifact store by raising or disabling these limits.\n */\nexport function boundedWorkRetention(options: WorkRetentionOptions = {}): WorkRetentionOptions {\n\treturn {\n\t\tmaxAgeMs: Math.min(nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS), DEFAULT_MAX_AGE_MS),\n\t\tmaxRuns: Math.min(nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS), DEFAULT_MAX_RUNS),\n\t\tmaxTotalBytes: Math.min(\n\t\t\tnonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES),\n\t\t\tDEFAULT_MAX_TOTAL_BYTES,\n\t\t),\n\t\tmaxScannedEntries: Math.min(\n\t\t\tnonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),\n\t\t\tDEFAULT_MAX_SCANNED_ENTRIES,\n\t\t),\n\t\tmaxScannedRuns: Math.min(\n\t\t\tnonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS),\n\t\t\tDEFAULT_MAX_SCANNED_RUNS,\n\t\t),\n\t\tnow: options.now,\n\t};\n}\n\nexport interface AcquireWorkRunOptions {\n\tagentDir: string;\n\tcategory: string;\n\ttenant: string;\n\trunId?: string;\n\tretention?: WorkRetentionOptions | false;\n\tnow?: number;\n}\n\nexport interface WorkRunLease {\n\treadonly path: string;\n\treadonly category: string;\n\treadonly tenant: string;\n\treadonly runId: string;\n\ttouch(): void;\n\trelease(): void;\n}\n\nconst processWorkRuns = new Map<string, WorkRunLease>();\n\nfunction nonNegativeLimit(value: number | undefined, fallback: number): number {\n\treturn value !== undefined && Number.isFinite(value) && value >= 0 ? Math.floor(value) : fallback;\n}\n\nexport function assertPortablePathSegment(label: string, value: string): void {\n\tif (!SEGMENT_PATTERN.test(value) || value.endsWith(\".\")) {\n\t\tthrow new Error(`${label} must be a lowercase portable path segment (1-64 characters)`);\n\t}\n\tconst stem = value.split(\".\", 1)[0];\n\tif (stem && WINDOWS_RESERVED_NAMES.has(stem)) {\n\t\tthrow new Error(`${label} uses a Windows-reserved path name: ${value}`);\n\t}\n}\n\nfunction ensureDirectory(path: string): void {\n\ttry {\n\t\tmkdirSync(path);\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t}\n\tconst stats = lstatSync(path);\n\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\tthrow new Error(`Work path is not a real directory: ${path}`);\n\t}\n}\n\nfunction ensureTenantDirectory(agentDir: string, category: string, tenant: string): string {\n\tmkdirSync(agentDir, { recursive: true });\n\tconst workRoot = getWorkRoot(agentDir);\n\tensureDirectory(workRoot);\n\tconst categoryDir = join(workRoot, category);\n\tensureDirectory(categoryDir);\n\tconst tenantDir = join(categoryDir, tenant);\n\tensureDirectory(tenantDir);\n\treturn tenantDir;\n}\n\nfunction readSmallJson(path: string): unknown {\n\tconst stats = lstatSync(path);\n\tif (!stats.isFile() || stats.isSymbolicLink() || stats.size > MAX_METADATA_BYTES) {\n\t\tthrow new Error(`Invalid work metadata file: ${path}`);\n\t}\n\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n}\n\nfunction isManifest(value: unknown, category: string, tenant: string, runId: string): value is WorkRunManifest {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst manifest = value as Partial<WorkRunManifest>;\n\treturn (\n\t\tmanifest.version === 1 &&\n\t\tmanifest.category === category &&\n\t\tmanifest.tenant === tenant &&\n\t\tmanifest.runId === runId &&\n\t\ttypeof manifest.createdAt === \"number\" &&\n\t\tNumber.isFinite(manifest.createdAt)\n\t);\n}\n\nfunction isMarker(value: unknown): value is WorkMarker {\n\tif (!value || typeof value !== \"object\") return false;\n\tconst marker = value as Partial<WorkMarker>;\n\treturn (\n\t\tmarker.version === 1 &&\n\t\ttypeof marker.hostname === \"string\" &&\n\t\ttypeof marker.pid === \"number\" &&\n\t\tNumber.isSafeInteger(marker.pid) &&\n\t\tmarker.pid > 0 &&\n\t\ttypeof marker.createdAt === \"number\" &&\n\t\tNumber.isFinite(marker.createdAt)\n\t);\n}\n\nfunction markerState(path: string): \"active\" | \"stale\" | \"unknown\" {\n\ttry {\n\t\tconst value = readSmallJson(path);\n\t\tif (!isMarker(value)) return \"unknown\";\n\t\tif (value.hostname !== hostname()) return \"active\";\n\t\ttry {\n\t\t\tprocess.kill(value.pid, 0);\n\t\t\treturn \"active\";\n\t\t} catch (error) {\n\t\t\treturn (error as NodeJS.ErrnoException).code === \"EPERM\" ? \"active\" : \"stale\";\n\t\t}\n\t} catch (error) {\n\t\treturn (error as NodeJS.ErrnoException).code === \"ENOENT\" ? \"stale\" : \"unknown\";\n\t}\n}\n\nfunction removeFile(path: string): void {\n\ttry {\n\t\tunlinkSync(path);\n\t} catch {}\n}\n\nfunction cleanupMarkerBlocksAcquisition(runDir: string): boolean {\n\tconst markerPath = join(runDir, CLEANUP_MARKER_FILE);\n\tif (!existsSync(markerPath)) return false;\n\tconst state = markerState(markerPath);\n\tif (state !== \"stale\") return true;\n\tremoveFile(markerPath);\n\treturn existsSync(markerPath);\n}\n\nfunction hasActiveLease(runDir: string): boolean {\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tif (!existsSync(leasesDir)) return false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(leasesDir);\n\t\tlet scanned = 0;\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tscanned++;\n\t\t\tif (scanned > MAX_LEASE_MARKERS) return true;\n\t\t\tif (!entry.isFile()) return true;\n\t\t\tconst markerPath = join(leasesDir, entry.name);\n\t\t\tconst state = markerState(markerPath);\n\t\t\tif (state === \"active\" || state === \"unknown\") return true;\n\t\t\tremoveFile(markerPath);\n\t\t}\n\t} catch {\n\t\treturn true;\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\ttry {\n\t\trmdirSync(leasesDir);\n\t} catch {}\n\treturn false;\n}\n\n/**\n * Report whether a managed run is leased or being cleaned. Stale local markers are removed as part\n * of the check; malformed or foreign-host markers remain fail-closed and count as active.\n */\nexport function hasActiveWorkRunLease(runDir: string): boolean {\n\treturn cleanupMarkerBlocksAcquisition(runDir) || hasActiveLease(runDir);\n}\n\nfunction measureDirectory(path: string, budget: ScanBudget, depth = 0): { bytes: number; complete: boolean } {\n\tif (depth > MAX_DIRECTORY_DEPTH || budget.remaining <= 0) return { bytes: 0, complete: false };\n\tlet bytes = 0;\n\tlet complete = true;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(path);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (budget.remaining <= 0) return { bytes, complete: false };\n\t\t\tbudget.remaining--;\n\t\t\tconst childPath = join(path, entry.name);\n\t\t\ttry {\n\t\t\t\tconst stats = lstatSync(childPath);\n\t\t\t\tif (stats.isDirectory() && !stats.isSymbolicLink()) {\n\t\t\t\t\tconst child = measureDirectory(childPath, budget, depth + 1);\n\t\t\t\t\tbytes += child.bytes;\n\t\t\t\t\tcomplete = complete && child.complete;\n\t\t\t\t} else {\n\t\t\t\t\tbytes += stats.size;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\tcomplete = false;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn { bytes, complete: false };\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\treturn { bytes, complete };\n}\n\nfunction inspectRun(\n\trunPath: string,\n\tcategory: string,\n\ttenant: string,\n\trunId: string,\n\tbudget: ScanBudget,\n\tunknownBytes: number,\n): InspectedRun | undefined {\n\ttry {\n\t\tconst stats = lstatSync(runPath);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return undefined;\n\t\tconst manifest = readSmallJson(join(runPath, WORK_RUN_MANIFEST_FILE));\n\t\tif (!isManifest(manifest, category, tenant, runId)) return undefined;\n\t\tconst measured = measureDirectory(runPath, budget);\n\t\treturn {\n\t\t\tpath: runPath,\n\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\tbytes: measured.complete ? measured.bytes : unknownBytes,\n\t\t};\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction createCleanupMarker(runDir: string, now: number): string | undefined {\n\tconst path = join(runDir, CLEANUP_MARKER_FILE);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\ttry {\n\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\treturn path;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") return undefined;\n\t\tif (markerState(path) !== \"stale\") return undefined;\n\t\tremoveFile(path);\n\t\ttry {\n\t\t\twriteFileSync(path, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\t\t\treturn path;\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n}\n\nfunction removeRunIfInactive(runPath: string, now: number): boolean {\n\tconst cleanupMarker = createCleanupMarker(runPath, now);\n\tif (!cleanupMarker) return false;\n\tif (hasActiveLease(runPath)) {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n\ttry {\n\t\trmSync(runPath, { recursive: true, force: true });\n\t\treturn !existsSync(runPath);\n\t} catch {\n\t\tremoveFile(cleanupMarker);\n\t\treturn false;\n\t}\n}\n\nexport function getWorkRoot(agentDir: string): string {\n\treturn join(agentDir, \"work\");\n}\n\nexport function getWorkTenantDir(agentDir: string, category: string, tenant: string): string {\n\tassertPortablePathSegment(\"Work category\", category);\n\tassertPortablePathSegment(\"Work tenant\", tenant);\n\treturn join(getWorkRoot(agentDir), category, tenant);\n}\n\nexport function getWorkRunDir(agentDir: string, category: string, tenant: string, runId: string): string {\n\tassertPortablePathSegment(\"Work category\", category);\n\tassertPortablePathSegment(\"Work tenant\", tenant);\n\tassertPortablePathSegment(\"Work run id\", runId);\n\treturn join(getWorkRoot(agentDir), category, tenant, runId);\n}\n\nexport function createWorkRunId(now = Date.now()): string {\n\treturn `run-${now.toString(36)}-${process.pid.toString(36)}-${randomUUID().slice(0, 12)}`;\n}\n\nexport function pruneWorkTenant(\n\tagentDir: string,\n\tcategory: string,\n\ttenant: string,\n\toptions: WorkRetentionOptions = {},\n): string[] {\n\tconst tenantDir = getWorkTenantDir(agentDir, category, tenant);\n\tif (!existsSync(tenantDir)) return [];\n\ttry {\n\t\tconst stats = lstatSync(tenantDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) return [];\n\t} catch {\n\t\treturn [];\n\t}\n\n\tconst now = options.now ?? Date.now();\n\tconst maxAgeMs = nonNegativeLimit(options.maxAgeMs, DEFAULT_MAX_AGE_MS);\n\tconst maxRuns = nonNegativeLimit(options.maxRuns, DEFAULT_MAX_RUNS);\n\tconst maxTotalBytes = nonNegativeLimit(options.maxTotalBytes, DEFAULT_MAX_TOTAL_BYTES);\n\tconst maxScannedRuns = nonNegativeLimit(options.maxScannedRuns, DEFAULT_MAX_SCANNED_RUNS);\n\tconst budget: ScanBudget = {\n\t\tremaining: nonNegativeLimit(options.maxScannedEntries, DEFAULT_MAX_SCANNED_ENTRIES),\n\t};\n\tconst unknownBytes = Math.max(1, maxTotalBytes + 1);\n\tconst runs: InspectedRun[] = [];\n\tlet truncated = false;\n\tlet handle: Dir | undefined;\n\ttry {\n\t\thandle = opendirSync(tenantDir);\n\t\twhile (true) {\n\t\t\tconst entry = handle.readSync();\n\t\t\tif (!entry) break;\n\t\t\tif (entry.name.startsWith(\".\")) continue;\n\t\t\tif (runs.length >= maxScannedRuns) {\n\t\t\t\ttruncated = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!entry.isDirectory() || entry.isSymbolicLink()) continue;\n\t\t\tconst inspected = inspectRun(join(tenantDir, entry.name), category, tenant, entry.name, budget, unknownBytes);\n\t\t\tif (inspected) runs.push(inspected);\n\t\t}\n\t} catch {\n\t\treturn [];\n\t} finally {\n\t\ttry {\n\t\t\thandle?.closeSync();\n\t\t} catch {}\n\t}\n\n\tconst removed: string[] = [];\n\tlet retainedCount = runs.length + (truncated ? maxRuns + 1 : 0);\n\tlet retainedBytes = runs.reduce((sum, run) => sum + run.bytes, 0);\n\tfor (const run of runs.sort((left, right) => left.mtimeMs - right.mtimeMs)) {\n\t\tconst expired = now - run.mtimeMs > maxAgeMs;\n\t\tconst overCount = retainedCount > maxRuns;\n\t\tconst overBytes = retainedBytes > maxTotalBytes;\n\t\tif (!expired && !overCount && !overBytes) continue;\n\t\tif (!removeRunIfInactive(run.path, now)) continue;\n\t\tremoved.push(run.path);\n\t\tretainedCount--;\n\t\tretainedBytes -= run.bytes;\n\t}\n\treturn removed;\n}\n\nexport function getProcessWorkRun(agentDir: string, category: string, tenant: string, runId?: string): WorkRunLease {\n\tconst key = `${agentDir}\\0${category}\\0${tenant}\\0${runId ?? \"\"}`;\n\tconst existing = processWorkRuns.get(key);\n\tif (existing && existsSync(existing.path)) return existing;\n\tconst acquired = acquireWorkRun({ agentDir, category, tenant, runId });\n\tprocessWorkRuns.set(key, acquired);\n\treturn acquired;\n}\n\nexport function acquireWorkRun(options: AcquireWorkRunOptions): WorkRunLease {\n\tconst now = options.now ?? Date.now();\n\tconst runId = options.runId ?? createWorkRunId(now);\n\tassertPortablePathSegment(\"Work category\", options.category);\n\tassertPortablePathSegment(\"Work tenant\", options.tenant);\n\tassertPortablePathSegment(\"Work run id\", runId);\n\tconst tenantDir = ensureTenantDirectory(options.agentDir, options.category, options.tenant);\n\tconst runDir = join(tenantDir, runId);\n\tlet created = false;\n\ttry {\n\t\tmkdirSync(runDir);\n\t\tcreated = true;\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t\tconst stats = lstatSync(runDir);\n\t\tif (!stats.isDirectory() || stats.isSymbolicLink()) {\n\t\t\tthrow new Error(`Work run path is not a real directory: ${runDir}`);\n\t\t}\n\t}\n\n\tconst manifestPath = join(runDir, WORK_RUN_MANIFEST_FILE);\n\tif (created) {\n\t\tconst manifest: WorkRunManifest = {\n\t\t\tversion: 1,\n\t\t\tcategory: options.category,\n\t\t\ttenant: options.tenant,\n\t\t\trunId,\n\t\t\tcreatedAt: now,\n\t\t};\n\t\twriteFileSync(manifestPath, JSON.stringify(manifest), { encoding: \"utf8\", flag: \"wx\" });\n\t} else {\n\t\tlet manifest: unknown;\n\t\ttry {\n\t\t\tmanifest = readSmallJson(manifestPath);\n\t\t} catch {\n\t\t\tthrow new Error(`Refusing to adopt unowned work directory: ${runDir}`);\n\t\t}\n\t\tif (!isManifest(manifest, options.category, options.tenant, runId)) {\n\t\t\tthrow new Error(`Work directory manifest does not match its path: ${runDir}`);\n\t\t}\n\t}\n\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tthrow new Error(`Work run is being cleaned: ${runDir}`);\n\t}\n\tconst leasesDir = join(runDir, LEASES_DIRECTORY);\n\tensureDirectory(leasesDir);\n\tconst markerPath = join(leasesDir, `active-${process.pid}-${randomUUID()}.json`);\n\tconst marker: WorkMarker = { version: 1, hostname: hostname(), pid: process.pid, createdAt: now };\n\twriteFileSync(markerPath, JSON.stringify(marker), { encoding: \"utf8\", flag: \"wx\" });\n\tif (cleanupMarkerBlocksAcquisition(runDir)) {\n\t\tremoveFile(markerPath);\n\t\tthrow new Error(`Work run entered cleanup while it was being acquired: ${runDir}`);\n\t}\n\ttry {\n\t\tutimesSync(runDir, new Date(now), new Date(now));\n\t} catch {}\n\n\tif (options.retention !== false) {\n\t\ttry {\n\t\t\tpruneWorkTenant(options.agentDir, options.category, options.tenant, options.retention);\n\t\t} catch {}\n\t}\n\n\tlet released = false;\n\treturn {\n\t\tpath: runDir,\n\t\tcategory: options.category,\n\t\ttenant: options.tenant,\n\t\trunId,\n\t\ttouch(): void {\n\t\t\tif (released) return;\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(markerPath, touchedAt, touchedAt);\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t\trelease(): void {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tremoveFile(markerPath);\n\t\t\ttry {\n\t\t\t\trmdirSync(leasesDir);\n\t\t\t} catch {}\n\t\t\tconst touchedAt = new Date();\n\t\t\ttry {\n\t\t\t\tutimesSync(runDir, touchedAt, touchedAt);\n\t\t\t} catch {}\n\t\t},\n\t};\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# UI polish — activity lane
|
|
2
|
+
|
|
3
|
+
UI type: dense keyboard-first terminal tool. Phase: transient-status consolidation. Comparison sources: Codex `20dafe201d91d4405eef05ecd1db0257f13a9ac8`, Claude Code 2.1.219 (`7006c4c3acac98e554d3997baeda6a7fa4d1ff7c`), and the owner's Pi Teams/task-steps extensions. Only information choreography and lifecycle mechanics were extracted; no branding, frame geometry, source text, or identity was copied.
|
|
4
|
+
|
|
5
|
+
## Ranked findings
|
|
6
|
+
|
|
7
|
+
1. Task, goal, worker, routing, retry, compaction, queue, and tool progress used separate transcript, footer, widget, and loader paths. This duplicated truth and polluted scrollback. They now project into one event-driven horizontal line immediately above the editor.
|
|
8
|
+
2. Completed work needed feedback without becoming permanent history. The lane uses a muted active dot, holds green/red terminal feedback for two seconds, then removes it by timer event.
|
|
9
|
+
3. Resumed state could replay old terminal work as new. Session replacement primes terminal identities without displaying them; only later transitions flash.
|
|
10
|
+
4. Successful orchestration bookkeeping still produced empty or multiline tool cards. Collapsed successful task, goal, and worker tools now render nothing; explicit tool expansion retains the structured detail.
|
|
11
|
+
5. A terminal process did not prove a human was watching. `--session-mode user|worker` feeds the authoritative session-role contract; unattended workers do not receive approval UI, extension TUI context, widgets, footer, loaders, or activity-lane routing.
|
|
12
|
+
6. Loading session history still invoked collapsed tool-result renderers and image conversion. Retained results now stay behind their existing payload accessor until expansion; one expansion materializes once, and collapse releases the display cache.
|
|
13
|
+
|
|
14
|
+
## Acceptance battery
|
|
15
|
+
|
|
16
|
+
| Check | Verdict | Evidence |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| One status owner | PASS | One `ActivityLaneComponent`; the prior native orchestration widget and delegate footer fragment were removed. |
|
|
19
|
+
| Width and density | PASS | One line, display-cell truncation, bounded labels, and `+N` overflow. |
|
|
20
|
+
| State clarity | PASS | Glyph plus text plus semantic theme color; status is never color-only. |
|
|
21
|
+
| Completion lifecycle | PASS | Event/timer driven; success/failure disappears after a bounded hold. |
|
|
22
|
+
| Resume correctness | PASS | Existing terminal identities are primed and do not replay. |
|
|
23
|
+
| History cleanliness | PASS | Successful orchestration calls are absent while collapsed; retained tool-result payloads are not read or rendered until the existing expansion key is used. |
|
|
24
|
+
| Failure honesty | PASS | Tool errors, compaction failures, and final retry failures remain textual and actionable. |
|
|
25
|
+
| Audience isolation | PASS | Worker role disables human UI capability and does not mount transient visual surfaces. |
|
|
26
|
+
| Focus and interruption | PASS | The lane never captures focus; cancellation remains on the existing interrupt binding. |
|
|
27
|
+
|
|
28
|
+
Accessibility gate: PASS. The lane uses text and glyphs in addition to color, has no decorative motion, preserves editor focus, and stays within measured terminal width.
|
|
29
|
+
|
|
30
|
+
## Mechanism merge
|
|
31
|
+
|
|
32
|
+
- From Codex: one live task/status row owned by the composer area, updated by events, absent when idle.
|
|
33
|
+
- From Claude: active-form task wording, bounded horizontal activity, and short-lived completion feedback.
|
|
34
|
+
- From Pi: canonical goal/task/lane state, semantic theme tokens, explicit expansion, durable resume identity, and least-privilege session role.
|
|
35
|
+
|
|
36
|
+
The resulting UI is a Pi-native projection, not an incumbent clone.
|
|
37
|
+
|
|
38
|
+
Controlled 100-column smoke with an isolated agent directory and no provider request: `/task add` rendered one `Next 1/1` line, `/task start step-1` replaced it with `Step 1/1`, `/task done step-1` rendered `Completed` briefly, and the lane then returned to zero height. The temporary agent directory was removed.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# UI quality — activity lane
|
|
2
|
+
|
|
3
|
+
Milestone: transient orchestration consolidation. Mode: REMEDIATE. UI type: dense terminal pro-tool. Reference evidence is indexed under `docs/ui-reference/`.
|
|
4
|
+
|
|
5
|
+
## Seven-dimension score
|
|
6
|
+
|
|
7
|
+
| Dimension | Score | Evidence |
|
|
8
|
+
|---|---:|---|
|
|
9
|
+
| Color and tone balance | 3/3 | Muted active state; restrained semantic colors for task, worker, goal, success, warning, and failure. |
|
|
10
|
+
| Depth and softness | 2/3 | Space and tone establish hierarchy without a box or separator wall. |
|
|
11
|
+
| Spatial rhythm | 3/3 | One-cell inset, one horizontal separator grammar, no persistent multiline status block. |
|
|
12
|
+
| Typographic feel | 2/3 | Short active-form labels and dim overflow metadata fit terminal typography. |
|
|
13
|
+
| Motion and effects | 3/3 | Only state transition and bounded completion hold; no decorative animation. |
|
|
14
|
+
| Drive-feel | 3/3 | Routing, tool, task, worker, compaction, retry, and queue events update immediately. |
|
|
15
|
+
| Coherence and finish | 3/3 | One projection and lifecycle replace the old widget/footer/loader/status-message split. |
|
|
16
|
+
|
|
17
|
+
Accessibility gate: PASS. Status is not color-only, focus remains in the editor, narrow widths are bounded, and details remain keyboard-expandable.
|
|
18
|
+
|
|
19
|
+
## Reality gate
|
|
20
|
+
|
|
21
|
+
- Active task prefers `activeForm`, then blocked, then pending work.
|
|
22
|
+
- Concurrent workers and goals share one line and collapse behind `+N` at narrow widths.
|
|
23
|
+
- Green/red terminal feedback expires after two seconds.
|
|
24
|
+
- Resume does not replay old completions.
|
|
25
|
+
- Idle state occupies zero rows.
|
|
26
|
+
- Worker terminals explicitly run without human-facing UI routing.
|
|
27
|
+
- Actionable failures remain in history; successful bookkeeping does not.
|
|
28
|
+
- Collapsed retained tool results do not hydrate payloads, construct result renderers, or convert images before expansion.
|