@paperclipai/server 2026.824.0 → 2026.825.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/builtin-adapter-types.d.ts.map +1 -1
- package/dist/adapters/builtin-adapter-types.js +1 -0
- package/dist/adapters/builtin-adapter-types.js.map +1 -1
- package/dist/adapters/plugin-loader.d.ts +1 -0
- package/dist/adapters/plugin-loader.d.ts.map +1 -1
- package/dist/adapters/plugin-loader.js +12 -1
- package/dist/adapters/plugin-loader.js.map +1 -1
- package/dist/adapters/plugin-loader.test.d.ts +2 -0
- package/dist/adapters/plugin-loader.test.d.ts.map +1 -0
- package/dist/adapters/plugin-loader.test.js +37 -0
- package/dist/adapters/plugin-loader.test.js.map +1 -0
- package/dist/adapters/registry.d.ts.map +1 -1
- package/dist/adapters/registry.js +68 -5
- package/dist/adapters/registry.js.map +1 -1
- package/dist/adapters/registry.test.d.ts +2 -0
- package/dist/adapters/registry.test.d.ts.map +1 -0
- package/dist/adapters/registry.test.js +35 -0
- package/dist/adapters/registry.test.js.map +1 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +5 -7
- package/dist/app.js.map +1 -1
- package/dist/auth/better-auth.d.ts +10 -0
- package/dist/auth/better-auth.d.ts.map +1 -1
- package/dist/auth/better-auth.js +47 -0
- package/dist/auth/better-auth.js.map +1 -1
- package/dist/auth/workspace-login-handoff-exchange.d.ts +75 -0
- package/dist/auth/workspace-login-handoff-exchange.d.ts.map +1 -0
- package/dist/auth/workspace-login-handoff-exchange.js +73 -0
- package/dist/auth/workspace-login-handoff-exchange.js.map +1 -0
- package/dist/auth/workspace-login-handoff-plugin.d.ts +40 -0
- package/dist/auth/workspace-login-handoff-plugin.d.ts.map +1 -0
- package/dist/auth/workspace-login-handoff-plugin.js +140 -0
- package/dist/auth/workspace-login-handoff-plugin.js.map +1 -0
- package/dist/auth/workspace-login-handoff.d.ts +189 -0
- package/dist/auth/workspace-login-handoff.d.ts.map +1 -0
- package/dist/auth/workspace-login-handoff.js +319 -0
- package/dist/auth/workspace-login-handoff.js.map +1 -0
- package/dist/build-info.json +3 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -0
- package/dist/config.js.map +1 -1
- package/dist/dev-runner-worktree.d.ts.map +1 -1
- package/dist/dev-runner-worktree.js +5 -0
- package/dist/dev-runner-worktree.js.map +1 -1
- package/dist/duplex-aggregate-ceiling-env.d.ts +21 -0
- package/dist/duplex-aggregate-ceiling-env.d.ts.map +1 -0
- package/dist/duplex-aggregate-ceiling-env.js +23 -0
- package/dist/duplex-aggregate-ceiling-env.js.map +1 -0
- package/dist/embedded-postgres-supervisor.d.ts +27 -0
- package/dist/embedded-postgres-supervisor.d.ts.map +1 -0
- package/dist/embedded-postgres-supervisor.js +72 -0
- package/dist/embedded-postgres-supervisor.js.map +1 -0
- package/dist/errors.d.ts +2 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -7
- package/dist/index.js.map +1 -1
- package/dist/instrumentation.d.ts +33 -0
- package/dist/instrumentation.d.ts.map +1 -1
- package/dist/instrumentation.js +68 -1
- package/dist/instrumentation.js.map +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +35 -10
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/error-handler.js +8 -1
- package/dist/middleware/error-handler.js.map +1 -1
- package/dist/middleware/logger.d.ts.map +1 -1
- package/dist/middleware/logger.js +5 -2
- package/dist/middleware/logger.js.map +1 -1
- package/dist/middleware/redact-sensitive.d.ts.map +1 -1
- package/dist/middleware/redact-sensitive.js +4 -0
- package/dist/middleware/redact-sensitive.js.map +1 -1
- package/dist/middleware/validate.d.ts +3 -1
- package/dist/middleware/validate.d.ts.map +1 -1
- package/dist/middleware/validate.js +37 -0
- package/dist/middleware/validate.js.map +1 -1
- package/dist/routes/access.d.ts.map +1 -1
- package/dist/routes/access.js +20 -0
- package/dist/routes/access.js.map +1 -1
- package/dist/routes/activity.js +4 -4
- package/dist/routes/activity.js.map +1 -1
- package/dist/routes/adapter-login-route-spine.d.ts +81 -0
- package/dist/routes/adapter-login-route-spine.d.ts.map +1 -0
- package/dist/routes/adapter-login-route-spine.js +40 -0
- package/dist/routes/adapter-login-route-spine.js.map +1 -0
- package/dist/routes/adapters.d.ts +33 -0
- package/dist/routes/adapters.d.ts.map +1 -1
- package/dist/routes/adapters.js +35 -1
- package/dist/routes/adapters.js.map +1 -1
- package/dist/routes/adapters.test.d.ts +2 -0
- package/dist/routes/adapters.test.d.ts.map +1 -0
- package/dist/routes/adapters.test.js +58 -0
- package/dist/routes/adapters.test.js.map +1 -0
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +281 -91
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/cases.d.ts +11 -22
- package/dist/routes/cases.d.ts.map +1 -1
- package/dist/routes/cases.js +13 -13
- package/dist/routes/companies.js +3 -3
- package/dist/routes/decision-training.js +6 -6
- package/dist/routes/decisions.js +4 -4
- package/dist/routes/decisions.js.map +1 -1
- package/dist/routes/environments.d.ts.map +1 -1
- package/dist/routes/environments.js +79 -6
- package/dist/routes/environments.js.map +1 -1
- package/dist/routes/execution-workspaces.d.ts.map +1 -1
- package/dist/routes/execution-workspaces.js +384 -16
- package/dist/routes/execution-workspaces.js.map +1 -1
- package/dist/routes/file-resources.js +2 -2
- package/dist/routes/health.d.ts.map +1 -1
- package/dist/routes/health.js +58 -4
- package/dist/routes/health.js.map +1 -1
- package/dist/routes/instance-settings.d.ts.map +1 -1
- package/dist/routes/instance-settings.js +40 -0
- package/dist/routes/instance-settings.js.map +1 -1
- package/dist/routes/issues.d.ts +10 -0
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +495 -65
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/openapi.d.ts.map +1 -1
- package/dist/routes/openapi.js +241 -122
- package/dist/routes/openapi.js.map +1 -1
- package/dist/routes/pipelines.js +19 -19
- package/dist/routes/plugins.d.ts.map +1 -1
- package/dist/routes/plugins.js +22 -0
- package/dist/routes/plugins.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +2 -0
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/routines.js +2 -2
- package/dist/routes/routines.js.map +1 -1
- package/dist/routes/secrets.d.ts +1 -1
- package/dist/routes/secrets.d.ts.map +1 -1
- package/dist/routes/secrets.js +39 -50
- package/dist/routes/secrets.js.map +1 -1
- package/dist/routes/setup-token-route.test.js +50 -3
- package/dist/routes/setup-token-route.test.js.map +1 -1
- package/dist/services/adapter-login-lease.d.ts +50 -0
- package/dist/services/adapter-login-lease.d.ts.map +1 -0
- package/dist/services/adapter-login-lease.js +26 -0
- package/dist/services/adapter-login-lease.js.map +1 -0
- package/dist/services/adapter-login-lease.test.d.ts +2 -0
- package/dist/services/adapter-login-lease.test.d.ts.map +1 -0
- package/dist/services/adapter-login-lease.test.js +68 -0
- package/dist/services/adapter-login-lease.test.js.map +1 -0
- package/dist/services/agent-action-audit.js +1 -1
- package/dist/services/agent-secret-bindings.d.ts +15 -0
- package/dist/services/agent-secret-bindings.d.ts.map +1 -1
- package/dist/services/agent-secret-bindings.js +2 -2
- package/dist/services/agent-secret-bindings.js.map +1 -1
- package/dist/services/agents.d.ts +13 -13
- package/dist/services/agents.d.ts.map +1 -1
- package/dist/services/agents.js +46 -5
- package/dist/services/agents.js.map +1 -1
- package/dist/services/artifact-review-documents.d.ts +34 -0
- package/dist/services/artifact-review-documents.d.ts.map +1 -0
- package/dist/services/artifact-review-documents.js +196 -0
- package/dist/services/artifact-review-documents.js.map +1 -0
- package/dist/services/assets.d.ts +1 -1
- package/dist/services/codex-device-login-credential-read.d.ts +58 -0
- package/dist/services/codex-device-login-credential-read.d.ts.map +1 -0
- package/dist/services/codex-device-login-credential-read.js +118 -0
- package/dist/services/codex-device-login-credential-read.js.map +1 -0
- package/dist/services/codex-device-login-reaper.d.ts.map +1 -1
- package/dist/services/codex-device-login-reaper.js +8 -5
- package/dist/services/codex-device-login-reaper.js.map +1 -1
- package/dist/services/codex-device-login-service.d.ts +127 -36
- package/dist/services/codex-device-login-service.d.ts.map +1 -1
- package/dist/services/codex-device-login-service.js +204 -84
- package/dist/services/codex-device-login-service.js.map +1 -1
- package/dist/services/company-portability.d.ts +3 -1
- package/dist/services/company-portability.d.ts.map +1 -1
- package/dist/services/company-portability.js +76 -20
- package/dist/services/company-portability.js.map +1 -1
- package/dist/services/company-skill-policy.d.ts +1 -1
- package/dist/services/costs.d.ts +1 -1
- package/dist/services/decisions.d.ts +6 -6
- package/dist/services/duplex-observability-recorder.d.ts +62 -0
- package/dist/services/duplex-observability-recorder.d.ts.map +1 -0
- package/dist/services/duplex-observability-recorder.js +54 -0
- package/dist/services/duplex-observability-recorder.js.map +1 -0
- package/dist/services/environment-config.js +5 -5
- package/dist/services/environment-config.js.map +1 -1
- package/dist/services/environment-custom-image-runtime.d.ts +116 -0
- package/dist/services/environment-custom-image-runtime.d.ts.map +1 -1
- package/dist/services/environment-custom-image-runtime.js +255 -1
- package/dist/services/environment-custom-image-runtime.js.map +1 -1
- package/dist/services/environment-custom-images.d.ts +39 -0
- package/dist/services/environment-custom-images.d.ts.map +1 -1
- package/dist/services/environment-custom-images.js +219 -17
- package/dist/services/environment-custom-images.js.map +1 -1
- package/dist/services/environment-driver-traits.d.ts +109 -0
- package/dist/services/environment-driver-traits.d.ts.map +1 -0
- package/dist/services/environment-driver-traits.js +102 -0
- package/dist/services/environment-driver-traits.js.map +1 -0
- package/dist/services/environment-execution-target.d.ts +4 -0
- package/dist/services/environment-execution-target.d.ts.map +1 -1
- package/dist/services/environment-execution-target.js +63 -7
- package/dist/services/environment-execution-target.js.map +1 -1
- package/dist/services/environment-run-orchestrator.d.ts +27 -1
- package/dist/services/environment-run-orchestrator.d.ts.map +1 -1
- package/dist/services/environment-run-orchestrator.js +24 -4
- package/dist/services/environment-run-orchestrator.js.map +1 -1
- package/dist/services/environment-runtime.d.ts +118 -20
- package/dist/services/environment-runtime.d.ts.map +1 -1
- package/dist/services/environment-runtime.js +436 -91
- package/dist/services/environment-runtime.js.map +1 -1
- package/dist/services/environments.d.ts.map +1 -1
- package/dist/services/environments.js +20 -2
- package/dist/services/environments.js.map +1 -1
- package/dist/services/execution-workspace-branch-ownership.d.ts +4 -0
- package/dist/services/execution-workspace-branch-ownership.d.ts.map +1 -0
- package/dist/services/execution-workspace-branch-ownership.js +9 -0
- package/dist/services/execution-workspace-branch-ownership.js.map +1 -0
- package/dist/services/execution-workspace-policy.d.ts.map +1 -1
- package/dist/services/execution-workspace-policy.js +3 -0
- package/dist/services/execution-workspace-policy.js.map +1 -1
- package/dist/services/execution-workspaces.d.ts +2 -0
- package/dist/services/execution-workspaces.d.ts.map +1 -1
- package/dist/services/execution-workspaces.js +90 -2
- package/dist/services/execution-workspaces.js.map +1 -1
- package/dist/services/external-objects.d.ts +19 -19
- package/dist/services/finance.d.ts +1 -1
- package/dist/services/goals.d.ts +2 -2
- package/dist/services/heartbeat-policy.d.ts +3 -0
- package/dist/services/heartbeat-policy.d.ts.map +1 -0
- package/dist/services/heartbeat-policy.js +10 -0
- package/dist/services/heartbeat-policy.js.map +1 -0
- package/dist/services/heartbeat-run-runtime-status.test.js +1 -1
- package/dist/services/heartbeat-run-runtime-status.test.js.map +1 -1
- package/dist/services/heartbeat.d.ts +23 -1
- package/dist/services/heartbeat.d.ts.map +1 -1
- package/dist/services/heartbeat.js +192 -11
- package/dist/services/heartbeat.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +1 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/instance-settings.d.ts.map +1 -1
- package/dist/services/instance-settings.js +2 -0
- package/dist/services/instance-settings.js.map +1 -1
- package/dist/services/issue-dependency-wakeups.d.ts +57 -9
- package/dist/services/issue-dependency-wakeups.d.ts.map +1 -1
- package/dist/services/issue-dependency-wakeups.js +146 -14
- package/dist/services/issue-dependency-wakeups.js.map +1 -1
- package/dist/services/issue-dependency-wakeups.test.d.ts +2 -0
- package/dist/services/issue-dependency-wakeups.test.d.ts.map +1 -0
- package/dist/services/issue-dependency-wakeups.test.js +183 -0
- package/dist/services/issue-dependency-wakeups.test.js.map +1 -0
- package/dist/services/issue-recovery-actions.d.ts +6 -1
- package/dist/services/issue-recovery-actions.d.ts.map +1 -1
- package/dist/services/issue-recovery-actions.js +123 -44
- package/dist/services/issue-recovery-actions.js.map +1 -1
- package/dist/services/issue-thread-interactions.d.ts +8 -0
- package/dist/services/issue-thread-interactions.d.ts.map +1 -1
- package/dist/services/issue-thread-interactions.js +220 -10
- package/dist/services/issue-thread-interactions.js.map +1 -1
- package/dist/services/issues.d.ts +8 -7
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.js +84 -12
- package/dist/services/issues.js.map +1 -1
- package/dist/services/local-service-supervisor.d.ts +61 -1
- package/dist/services/local-service-supervisor.d.ts.map +1 -1
- package/dist/services/local-service-supervisor.js +221 -25
- package/dist/services/local-service-supervisor.js.map +1 -1
- package/dist/services/login-command.d.ts +46 -0
- package/dist/services/login-command.d.ts.map +1 -0
- package/dist/services/login-command.js +87 -0
- package/dist/services/login-command.js.map +1 -0
- package/dist/services/login-command.test.d.ts +2 -0
- package/dist/services/login-command.test.d.ts.map +1 -0
- package/dist/services/login-command.test.js +71 -0
- package/dist/services/login-command.test.js.map +1 -0
- package/dist/services/managed-workspace-identity.d.ts +140 -0
- package/dist/services/managed-workspace-identity.d.ts.map +1 -0
- package/dist/services/managed-workspace-identity.js +277 -0
- package/dist/services/managed-workspace-identity.js.map +1 -0
- package/dist/services/plugin-environment-driver.d.ts +15 -1
- package/dist/services/plugin-environment-driver.d.ts.map +1 -1
- package/dist/services/plugin-environment-driver.js +23 -1
- package/dist/services/plugin-environment-driver.js.map +1 -1
- package/dist/services/plugin-host-services.d.ts +3 -2
- package/dist/services/plugin-host-services.d.ts.map +1 -1
- package/dist/services/plugin-host-services.js +11 -2
- package/dist/services/plugin-host-services.js.map +1 -1
- package/dist/services/plugin-loader.d.ts.map +1 -1
- package/dist/services/plugin-loader.js +39 -8
- package/dist/services/plugin-loader.js.map +1 -1
- package/dist/services/plugin-managed-agents.d.ts.map +1 -1
- package/dist/services/plugin-managed-agents.js +50 -5
- package/dist/services/plugin-managed-agents.js.map +1 -1
- package/dist/services/plugin-manifest-validator.d.ts.map +1 -1
- package/dist/services/plugin-manifest-validator.js +5 -2
- package/dist/services/plugin-manifest-validator.js.map +1 -1
- package/dist/services/plugin-registry.d.ts +5 -5
- package/dist/services/plugin-worker-manager.d.ts +158 -11
- package/dist/services/plugin-worker-manager.d.ts.map +1 -1
- package/dist/services/plugin-worker-manager.js +1139 -79
- package/dist/services/plugin-worker-manager.js.map +1 -1
- package/dist/services/projects.d.ts +1 -1
- package/dist/services/recovery/disposition-repair.d.ts +24 -0
- package/dist/services/recovery/disposition-repair.d.ts.map +1 -0
- package/dist/services/recovery/disposition-repair.js +125 -0
- package/dist/services/recovery/disposition-repair.js.map +1 -0
- package/dist/services/recovery/service.d.ts +6 -6
- package/dist/services/recovery/service.d.ts.map +1 -1
- package/dist/services/recovery/service.js +856 -384
- package/dist/services/recovery/service.js.map +1 -1
- package/dist/services/recovery/stranded-notice.js +4 -4
- package/dist/services/recovery/stranded-notice.js.map +1 -1
- package/dist/services/recovery/stranded-notice.test.js +1 -1
- package/dist/services/recovery/stranded-notice.test.js.map +1 -1
- package/dist/services/recovery/successful-run-handoff.d.ts +1 -1
- package/dist/services/recovery/successful-run-handoff.d.ts.map +1 -1
- package/dist/services/recovery/successful-run-handoff.js +6 -4
- package/dist/services/recovery/successful-run-handoff.js.map +1 -1
- package/dist/services/recovery/successful-run-handoff.test.js +1 -1
- package/dist/services/recovery/successful-run-handoff.test.js.map +1 -1
- package/dist/services/recovery-observability.d.ts +1 -1
- package/dist/services/recovery-observability.d.ts.map +1 -1
- package/dist/services/recovery-observability.js +4 -1
- package/dist/services/recovery-observability.js.map +1 -1
- package/dist/services/routines.d.ts.map +1 -1
- package/dist/services/routines.js +86 -1
- package/dist/services/routines.js.map +1 -1
- package/dist/services/runtime-exposure/loopback-listener.js +1 -1
- package/dist/services/runtime-exposure/loopback-listener.js.map +1 -1
- package/dist/services/runtime-exposure/loopback-listener.test.js +1 -1
- package/dist/services/runtime-exposure/loopback-listener.test.js.map +1 -1
- package/dist/services/scripts/codex-auth-read.cjs +93 -0
- package/dist/services/secret-proposal-authorization.d.ts +15 -0
- package/dist/services/secret-proposal-authorization.d.ts.map +1 -0
- package/dist/services/secret-proposal-authorization.js +29 -0
- package/dist/services/secret-proposal-authorization.js.map +1 -0
- package/dist/services/secret-proposal-notifications.d.ts +18 -0
- package/dist/services/secret-proposal-notifications.d.ts.map +1 -0
- package/dist/services/secret-proposal-notifications.js +37 -0
- package/dist/services/secret-proposal-notifications.js.map +1 -0
- package/dist/services/secret-proposals.d.ts +20 -10
- package/dist/services/secret-proposals.d.ts.map +1 -1
- package/dist/services/secret-proposals.js +205 -14
- package/dist/services/secret-proposals.js.map +1 -1
- package/dist/services/secrets.d.ts +3 -3
- package/dist/services/settings-visibility.d.ts +17 -0
- package/dist/services/settings-visibility.d.ts.map +1 -0
- package/dist/services/settings-visibility.js +29 -0
- package/dist/services/settings-visibility.js.map +1 -0
- package/dist/services/setup-token-reaper.d.ts +36 -0
- package/dist/services/setup-token-reaper.d.ts.map +1 -0
- package/dist/services/setup-token-reaper.js +38 -0
- package/dist/services/setup-token-reaper.js.map +1 -0
- package/dist/services/setup-token-reaper.test.d.ts +2 -0
- package/dist/services/setup-token-reaper.test.d.ts.map +1 -0
- package/dist/services/setup-token-reaper.test.js +123 -0
- package/dist/services/setup-token-reaper.test.js.map +1 -0
- package/dist/services/setup-token-session.d.ts +57 -45
- package/dist/services/setup-token-session.d.ts.map +1 -1
- package/dist/services/setup-token-session.js +118 -110
- package/dist/services/setup-token-session.js.map +1 -1
- package/dist/services/setup-token-session.test.js +88 -47
- package/dist/services/setup-token-session.test.js.map +1 -1
- package/dist/services/setup-token-transport-binding.d.ts +20 -12
- package/dist/services/setup-token-transport-binding.d.ts.map +1 -1
- package/dist/services/setup-token-transport-binding.js +59 -32
- package/dist/services/setup-token-transport-binding.js.map +1 -1
- package/dist/services/setup-token-transport-binding.test.js +50 -17
- package/dist/services/setup-token-transport-binding.test.js.map +1 -1
- package/dist/services/smoke-lab.d.ts +1 -1
- package/dist/services/stalled-review-decisions.d.ts +1 -1
- package/dist/services/status-cards.d.ts +168 -168
- package/dist/services/tool-access-policy.d.ts +2 -2
- package/dist/services/tool-gateway.d.ts +1 -1
- package/dist/services/work-products.d.ts +19 -0
- package/dist/services/work-products.d.ts.map +1 -1
- package/dist/services/work-products.js +50 -3
- package/dist/services/work-products.js.map +1 -1
- package/dist/services/workspace-git-operation-scheduler.test.js +10 -3
- package/dist/services/workspace-git-operation-scheduler.test.js.map +1 -1
- package/dist/services/workspace-instance-cleanup.d.ts +9 -0
- package/dist/services/workspace-instance-cleanup.d.ts.map +1 -1
- package/dist/services/workspace-instance-cleanup.js +29 -3
- package/dist/services/workspace-instance-cleanup.js.map +1 -1
- package/dist/services/workspace-login-handoff-issuer.d.ts +95 -0
- package/dist/services/workspace-login-handoff-issuer.d.ts.map +1 -0
- package/dist/services/workspace-login-handoff-issuer.js +147 -0
- package/dist/services/workspace-login-handoff-issuer.js.map +1 -0
- package/dist/services/workspace-operations.d.ts +4 -1
- package/dist/services/workspace-operations.d.ts.map +1 -1
- package/dist/services/workspace-operations.js +29 -15
- package/dist/services/workspace-operations.js.map +1 -1
- package/dist/services/workspace-readiness.d.ts +56 -0
- package/dist/services/workspace-readiness.d.ts.map +1 -0
- package/dist/services/workspace-readiness.js +250 -0
- package/dist/services/workspace-readiness.js.map +1 -0
- package/dist/services/workspace-realization.d.ts.map +1 -1
- package/dist/services/workspace-realization.js +5 -33
- package/dist/services/workspace-realization.js.map +1 -1
- package/dist/services/workspace-runtime-exposure.test.js +321 -12
- package/dist/services/workspace-runtime-exposure.test.js.map +1 -1
- package/dist/services/workspace-runtime-leases.d.ts.map +1 -1
- package/dist/services/workspace-runtime-leases.js +1 -1
- package/dist/services/workspace-runtime-leases.js.map +1 -1
- package/dist/services/workspace-runtime-read-model.d.ts +8 -8
- package/dist/services/workspace-runtime-read-model.test.js +20 -0
- package/dist/services/workspace-runtime-read-model.test.js.map +1 -1
- package/dist/services/workspace-runtime-ready-comment.test.js +1 -0
- package/dist/services/workspace-runtime-ready-comment.test.js.map +1 -1
- package/dist/services/workspace-runtime.d.ts +77 -4
- package/dist/services/workspace-runtime.d.ts.map +1 -1
- package/dist/services/workspace-runtime.js +1020 -126
- package/dist/services/workspace-runtime.js.map +1 -1
- package/dist/worktree-config.d.ts.map +1 -1
- package/dist/worktree-config.js +3 -76
- package/dist/worktree-config.js.map +1 -1
- package/dist/worktree-seed-manifest.d.ts +8 -0
- package/dist/worktree-seed-manifest.d.ts.map +1 -0
- package/dist/worktree-seed-manifest.js +47 -0
- package/dist/worktree-seed-manifest.js.map +1 -0
- package/package.json +34 -30
- package/skills/paperclip/SKILL.md +2 -0
- package/skills/paperclip/references/api-reference.md +44 -2
- package/ui-dist/assets/CompanyExport-DnEsO-St.js +4 -0
- package/ui-dist/assets/{abnfDiagram-N423BO3Z-BvgoV-u5.js → abnfDiagram-N423BO3Z-2ff8TsQ0.js} +1 -1
- package/ui-dist/assets/{arc-BInnUBUU.js → arc-B2AXsH34.js} +1 -1
- package/ui-dist/assets/architectureDiagram-T3A2C74G-BDxtKMxk.js +36 -0
- package/ui-dist/assets/{blockDiagram-VBNYF7ZC-D9kzAkLN.js → blockDiagram-VBNYF7ZC-BB8T5Mj5.js} +1 -1
- package/ui-dist/assets/{c4Diagram-5PPSVZJV-BwzsgV_0.js → c4Diagram-5PPSVZJV-lMo8qk-x.js} +1 -1
- package/ui-dist/assets/channel-DCTVZpyq.js +1 -0
- package/ui-dist/assets/{chunk-2GRJ4B5K-D2EQ9vrl.js → chunk-2GRJ4B5K-CsS7EB3G.js} +1 -1
- package/ui-dist/assets/{chunk-2Q5K7J3B-DOA_8fSd.js → chunk-2Q5K7J3B-DFyQPjoR.js} +1 -1
- package/ui-dist/assets/{chunk-5RXB4S5H-CT5ukRiT.js → chunk-5RXB4S5H-No2SHOQR.js} +1 -1
- package/ui-dist/assets/{chunk-5VM5RSS4-D2gOlkyB.js → chunk-5VM5RSS4-DdxQO7V9.js} +1 -1
- package/ui-dist/assets/{chunk-6Q2QTUOP-DUb6aG8c.js → chunk-6Q2QTUOP-gbHjh-aK.js} +1 -1
- package/ui-dist/assets/{chunk-GF5L2VYU-BPabG3Cx.js → chunk-GF5L2VYU-h-BBl6NY.js} +1 -1
- package/ui-dist/assets/{chunk-JWPE2WC7-scNfhlZz.js → chunk-JWPE2WC7-Q3pJdTz5.js} +1 -1
- package/ui-dist/assets/{chunk-KBJHAD2P-BcRAzRpq.js → chunk-KBJHAD2P-Ba8LGLSx.js} +1 -1
- package/ui-dist/assets/{chunk-RYQCIY6F-BiZ0-EGh.js → chunk-RYQCIY6F-9VcvykBo.js} +1 -1
- package/ui-dist/assets/{chunk-XXDRQBXY-lJULxFIE.js → chunk-XXDRQBXY-NVbjDH4W.js} +1 -1
- package/ui-dist/assets/classDiagram-JCYQIIEL-CzJ88u6h.js +1 -0
- package/ui-dist/assets/classDiagram-v2-OCEON4UE-CzJ88u6h.js +1 -0
- package/ui-dist/assets/cose-bilkent-JH36ORCC-Cdz4wtUh.js +1 -0
- package/ui-dist/assets/{cynefin-VYW2F7L2-B34jJY1x.js → cynefin-VYW2F7L2-MpzJkW5s.js} +1 -1
- package/ui-dist/assets/{cynefinDiagram-MW4NZA55-DQ8QK8JK.js → cynefinDiagram-MW4NZA55-_Nx8av7i.js} +1 -1
- package/ui-dist/assets/{dagre-VZM6K2ZE-B7lSKgxH.js → dagre-VZM6K2ZE-DcZTQ4Oh.js} +1 -1
- package/ui-dist/assets/{diagram-7IWD3JNH-B3hLAFGE.js → diagram-7IWD3JNH-UyLi2mee.js} +1 -1
- package/ui-dist/assets/{diagram-B4RE2ZJO-CH9Ro9e0.js → diagram-B4RE2ZJO-B6p0Ivqg.js} +1 -1
- package/ui-dist/assets/{diagram-LBJQPF4R-DdPVMii7.js → diagram-LBJQPF4R-C8u6pa97.js} +1 -1
- package/ui-dist/assets/{diagram-Q27KOJAE-f5VXswjc.js → diagram-Q27KOJAE-DbwyagW0.js} +1 -1
- package/ui-dist/assets/{diagram-UB23O5K3-DGqxixsR.js → diagram-UB23O5K3-Cn5BMEH7.js} +1 -1
- package/ui-dist/assets/{ebnfDiagram-BXEA7PRR-C-1klg_w.js → ebnfDiagram-BXEA7PRR-vE0IZma9.js} +1 -1
- package/ui-dist/assets/{erDiagram-JOGREHBK-Dt4qK4gv.js → erDiagram-JOGREHBK-3OZVIlVG.js} +1 -1
- package/ui-dist/assets/{flowDiagram-UKHOOZJN-9ZlrTuET.js → flowDiagram-UKHOOZJN-C94FiPyr.js} +1 -1
- package/ui-dist/assets/ganttDiagram-PKOTCBZU-DMVaPmF-.js +292 -0
- package/ui-dist/assets/{gitGraphDiagram-DS77QQ5N-HH2fSgad.js → gitGraphDiagram-DS77QQ5N-yeFtJ689.js} +1 -1
- package/ui-dist/assets/{index-Cm6iEYPt.js → index-B4ZF3vY8.js} +288 -224
- package/ui-dist/assets/{index-CHXG4GPL.js → index-Bi_vqkcQ.js} +1 -1
- package/ui-dist/assets/{index-Bc9g6q63.js → index-BjDGQg9-.js} +1 -1
- package/ui-dist/assets/{index-FHzrJ7iQ.js → index-BnpyUMTb.js} +1 -1
- package/ui-dist/assets/{index-C1mpWCcn.js → index-BoqQTVMA.js} +1 -1
- package/ui-dist/assets/index-Bq-Mr-4x.js +1 -0
- package/ui-dist/assets/{index-DceuCrr8.js → index-Brb2U7N4.js} +1 -1
- package/ui-dist/assets/{index-DQIrrn2L.js → index-BsBybVwH.js} +1 -1
- package/ui-dist/assets/{index-CQhaM6qd.js → index-C2iv4Wgu.js} +1 -1
- package/ui-dist/assets/{index-DV2FOgyD.js → index-CKxIu7uO.js} +1 -1
- package/ui-dist/assets/{index-DU4U1fuv.js → index-Cb4VGIwp.js} +1 -1
- package/ui-dist/assets/{index-B61ORkIb.js → index-ChpszwcO.js} +1 -1
- package/ui-dist/assets/{index-DlVBBF8o.js → index-CoQFdT8N.js} +1 -1
- package/ui-dist/assets/index-D6P8_f0W.css +1 -0
- package/ui-dist/assets/index-DKdmghUG.js +1 -0
- package/ui-dist/assets/{index-CVTL3aAL.js → index-DaBci7Bx.js} +1 -1
- package/ui-dist/assets/{index-diFs0CNC.js → index-DjYaNiXZ.js} +1 -1
- package/ui-dist/assets/{index-Bf7tyGxE.js → index-DxTBJl4h.js} +1 -1
- package/ui-dist/assets/{index-DsdVneqe.js → index-Dz3E8nn0.js} +1 -1
- package/ui-dist/assets/{index-DvFUXI-Q.js → index-J7dz_hap.js} +1 -1
- package/ui-dist/assets/{index-CLu3Tfpv.js → index-JMp2Gpnz.js} +1 -1
- package/ui-dist/assets/{index-CcRTJ93J.js → index-Kp6wavQt.js} +1 -1
- package/ui-dist/assets/{index-BvFx-4KW.js → index-LBhYZ0L4.js} +1 -1
- package/ui-dist/assets/{index-BbAhzCq8.js → index-c3C0P6l8.js} +4 -4
- package/ui-dist/assets/{index-BY5ITKmG.js → index-pBEPheTW.js} +1 -1
- package/ui-dist/assets/{infoDiagram-6WML65LV-2jai2fw-.js → infoDiagram-6WML65LV-BiL7jKLA.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-WSZJBQD7-CUmGhmEb.js → ishikawaDiagram-WSZJBQD7-DYcQy41D.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-NVQOT4AX-CGQuPDO1.js → journeyDiagram-NVQOT4AX-Bxva6JgA.js} +1 -1
- package/ui-dist/assets/{kanban-definition-27J2QSJJ-zgEPcbHl.js → kanban-definition-27J2QSJJ-B2HpN34Q.js} +1 -1
- package/ui-dist/assets/{linear-BVf5VtLS.js → linear-Dq8qSESw.js} +1 -1
- package/ui-dist/assets/{mermaid.core-D2TFkGfI.js → mermaid.core-Ikay8Cpl.js} +35 -35
- package/ui-dist/assets/{mindmap-definition-FAOFIHXS-xoAQ0Lb_.js → mindmap-definition-FAOFIHXS-C-SIdYSY.js} +1 -1
- package/ui-dist/assets/{pegDiagram-VL7TDLO6-CBR1PWLr.js → pegDiagram-VL7TDLO6-C7rIJ_13.js} +1 -1
- package/ui-dist/assets/{pieDiagram-7S7Q4E2Y-BMPnzK_e.js → pieDiagram-7S7Q4E2Y-3gx0a0ve.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-CIZ2JOQS-CPtVUPkR.js → quadrantDiagram-CIZ2JOQS-BiwM9QGv.js} +1 -1
- package/ui-dist/assets/{railroadDiagram-AXF67PYL-DC0lsZV1.js → railroadDiagram-AXF67PYL-rFS8XcFA.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-LRYGKXZP-BF6k05SB.js → requirementDiagram-LRYGKXZP-CEAUDUTQ.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-W5VNT64P-CRN0ibiP.js → sankeyDiagram-W5VNT64P-B7anpjlM.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-SI44F4Z6-CQtTiPWm.js → sequenceDiagram-SI44F4Z6-CJEdJvm_.js} +1 -1
- package/ui-dist/assets/{sizeCapture-X5ZJPWSS-BdjuGZd1.js → sizeCapture-X5ZJPWSS-CU1Vm6c1.js} +1 -1
- package/ui-dist/assets/{stateDiagram-OKZ733FA-B99onxyh.js → stateDiagram-OKZ733FA-wxVV9WIi.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-UEYNNEHI-BIFLqlqR.js +1 -0
- package/ui-dist/assets/{swimlanes-SLNWSIFB-BIByPbrL.js → swimlanes-SLNWSIFB-Cd-C1Z_k.js} +2 -2
- package/ui-dist/assets/swimlanesDiagram-ULZ7WXOC-CoBROkkd.js +8 -0
- package/ui-dist/assets/{timeline-definition-Z64GVDOM-I1NgOcn9.js → timeline-definition-Z64GVDOM-SWngk4aR.js} +1 -1
- package/ui-dist/assets/{vennDiagram-T6HMQDX7-D6t2Njcl.js → vennDiagram-T6HMQDX7-DFdPUr36.js} +1 -1
- package/ui-dist/assets/{wardleyDiagram-T6FBY63Y-BiYKm9gh.js → wardleyDiagram-T6FBY63Y-C6IlrZ7t.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-ELKLHX3M-BhwXKWIa.js → xychartDiagram-ELKLHX3M-BNm6hHGl.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/architectureDiagram-T3A2C74G-Dg4MziOm.js +0 -36
- package/ui-dist/assets/channel-qoSYbCn0.js +0 -1
- package/ui-dist/assets/classDiagram-JCYQIIEL-B24u1REs.js +0 -1
- package/ui-dist/assets/classDiagram-v2-OCEON4UE-B24u1REs.js +0 -1
- package/ui-dist/assets/cose-bilkent-JH36ORCC-Do8pe8JB.js +0 -1
- package/ui-dist/assets/ganttDiagram-PKOTCBZU-CE3lyvFq.js +0 -292
- package/ui-dist/assets/index-BHiUiToL.css +0 -1
- package/ui-dist/assets/index-hkanj4t6.js +0 -1
- package/ui-dist/assets/index-yRJnh4vx.js +0 -1
- package/ui-dist/assets/stateDiagram-v2-UEYNNEHI-bzFlYBZ1.js +0 -1
- package/ui-dist/assets/swimlanesDiagram-ULZ7WXOC-DgdkBnuK.js +0 -8
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import { and, eq, inArray } from "drizzle-orm";
|
|
3
|
-
import { companySecrets, companySecretVersions, environmentLeases } from "@paperclipai/db";
|
|
2
|
+
import { and, eq, inArray, sql } from "drizzle-orm";
|
|
3
|
+
import { companySecrets, companySecretVersions, environmentLeases, heartbeatRuns } from "@paperclipai/db";
|
|
4
4
|
import { resolveDeclaredSandboxCapabilities } from "@paperclipai/shared";
|
|
5
5
|
import { ensureSshWorkspaceReady } from "@paperclipai/adapter-utils/ssh";
|
|
6
6
|
import { getActiveStepContext, runWithRuntimeParent, } from "@paperclipai/adapter-utils/acpx-engine/startup-timing";
|
|
7
7
|
import { environmentService } from "./environments.js";
|
|
8
|
+
import { instanceSettingsService } from "./instance-settings.js";
|
|
8
9
|
import { collectEnvironmentSecretRefs, parseEnvironmentDriverConfig, resolveEnvironmentDriverConfigForRuntime, resolveSandboxCleanupConfigSecrets, stripSandboxProviderEnvelope, } from "./environment-config.js";
|
|
9
10
|
import { createEffectiveRunConfigFingerprints, } from "./effective-run-config-fingerprints.js";
|
|
10
11
|
import { acquireSandboxProviderLease, destroySandboxProviderLease, findReusableSandboxProviderLeaseId, getSandboxProvider as getBuiltinSandboxProvider, isBuiltinSandboxProvider, releaseSandboxProviderLease, sandboxConfigFromLeaseMetadata, sandboxConfigFromLeaseMetadataLoose, } from "./sandbox-provider-runtime.js";
|
|
@@ -19,6 +20,10 @@ import { logger } from "../middleware/logger.js";
|
|
|
19
20
|
// credential in its name, code, message, cause, or stack. So the log records
|
|
20
21
|
// this constant and the plain provider identifiers only.
|
|
21
22
|
const SANDBOX_ORPHAN_CLEANUP_WRITE_ERROR_KIND = "sandbox_orphan_cleanup_write_failed";
|
|
23
|
+
// The fixed non-secret refusal a duplex channel open returns when the lease does
|
|
24
|
+
// not grant the opt-in `duplexCommandStream` capability. The service resolves the
|
|
25
|
+
// exact lease capability snapshot and throws this before it reaches any driver.
|
|
26
|
+
const DUPLEX_CHANNEL_CAPABILITY_DENIED = "Sandbox lease does not grant the duplex command stream capability.";
|
|
22
27
|
// ---------------------------------------------------------------------------
|
|
23
28
|
// Sandbox capability contract — one normalizer for both branches
|
|
24
29
|
// ---------------------------------------------------------------------------
|
|
@@ -29,6 +34,8 @@ export const SANDBOX_CAPABILITY_KEYS = [
|
|
|
29
34
|
"persistentProcessSessions",
|
|
30
35
|
"independentControlCommands",
|
|
31
36
|
"incrementalSessionOutput",
|
|
37
|
+
"concurrentSyncOperations",
|
|
38
|
+
"duplexCommandStream",
|
|
32
39
|
];
|
|
33
40
|
/**
|
|
34
41
|
* Opt-in capability keys. Most capabilities are a worker property: an absent
|
|
@@ -41,6 +48,8 @@ export const SANDBOX_CAPABILITY_KEYS = [
|
|
|
41
48
|
*/
|
|
42
49
|
const SANDBOX_CAPABILITY_OPT_IN_KEYS = new Set([
|
|
43
50
|
"incrementalSessionOutput",
|
|
51
|
+
"concurrentSyncOperations",
|
|
52
|
+
"duplexCommandStream",
|
|
44
53
|
]);
|
|
45
54
|
/**
|
|
46
55
|
* Verified prerequisite mapping: the worker methods each capability requires.
|
|
@@ -70,6 +79,17 @@ const SANDBOX_CAPABILITY_OPT_IN_KEYS = new Set([
|
|
|
70
79
|
* provider tails the session log through it. The verified verb is necessary
|
|
71
80
|
* but not sufficient: this key is opt-in, so the declaration is the real gate
|
|
72
81
|
* (see {@link SANDBOX_CAPABILITY_OPT_IN_KEYS}).
|
|
82
|
+
* - `concurrentSyncOperations` requires BOTH sync verbs, because parallel
|
|
83
|
+
* bidirectional transfer runs an inbound and an outbound transfer at the same
|
|
84
|
+
* time. The two verbs are separate required groups, so a provider that
|
|
85
|
+
* verifies only one direction cannot get the capability. The verbs are
|
|
86
|
+
* necessary but not sufficient: this key is opt-in, so the declaration is the
|
|
87
|
+
* real gate (see {@link SANDBOX_CAPABILITY_OPT_IN_KEYS}).
|
|
88
|
+
* - `duplexCommandStream` requires `duplexChannelOpen`, the worker verb that
|
|
89
|
+
* opens the persistent duplex channel. The verified verb is necessary but not
|
|
90
|
+
* sufficient: this key is opt-in, so the declaration is the real gate. A
|
|
91
|
+
* provider that does not implement the duplex open verb resolves `false` and
|
|
92
|
+
* keeps the file bridge.
|
|
73
93
|
*/
|
|
74
94
|
const SANDBOX_CAPABILITY_PREREQUISITE_METHODS = {
|
|
75
95
|
// Reusable leases require ALL reuse verbs. Each verb is its own required
|
|
@@ -83,6 +103,8 @@ const SANDBOX_CAPABILITY_PREREQUISITE_METHODS = {
|
|
|
83
103
|
persistentProcessSessions: [["environmentExecute"]],
|
|
84
104
|
independentControlCommands: [["environmentExecute"]],
|
|
85
105
|
incrementalSessionOutput: [["environmentExecute"]],
|
|
106
|
+
concurrentSyncOperations: [["environmentSyncIn"], ["environmentSyncOut"]],
|
|
107
|
+
duplexCommandStream: [["duplexChannelOpen"]],
|
|
86
108
|
};
|
|
87
109
|
function capabilityIsVerified(key, verifiedMethods) {
|
|
88
110
|
return SANDBOX_CAPABILITY_PREREQUISITE_METHODS[key].every((group) => group.some((verb) => verifiedMethods.has(verb)));
|
|
@@ -108,28 +130,49 @@ export function builtinSandboxProviderVerifiedMethods(provider) {
|
|
|
108
130
|
}
|
|
109
131
|
return methods;
|
|
110
132
|
}
|
|
133
|
+
// `EnvironmentDriverCapabilitySupport` and `ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT`
|
|
134
|
+
// now live in the dependency-leaf module `environment-driver-traits.ts`, next to
|
|
135
|
+
// the other static per-driver traits. Re-export both names here so an existing
|
|
136
|
+
// import of this module keeps resolving.
|
|
137
|
+
export { ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT, } from "./environment-driver-traits.js";
|
|
138
|
+
import { ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT } from "./environment-driver-traits.js";
|
|
111
139
|
/**
|
|
112
|
-
* The one
|
|
113
|
-
*
|
|
140
|
+
* The one general capability classifier. It resolves each of the eight effective
|
|
141
|
+
* capabilities as static support ∩ verified ∩ declared ∩ narrowing, and returns
|
|
142
|
+
* the read-only eight-field snapshot. Every driver reads the same classifier, so
|
|
143
|
+
* the runtime no longer branches on the driver name.
|
|
114
144
|
*
|
|
145
|
+
* - `supportedCapabilities` is the driver's static support definition (see
|
|
146
|
+
* {@link ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT}). A capability not in the set
|
|
147
|
+
* resolves `false` regardless of the other inputs. An absent set applies no
|
|
148
|
+
* static gate, so the classifier behaves as the pure declaration ∩ verified ∩
|
|
149
|
+
* narrowing normalizer.
|
|
115
150
|
* - `verifiedMethods` is the runtime's verified worker verb list (the plug-in
|
|
116
151
|
* worker's `supportedMethods`, or a built-in provider mapped through
|
|
117
152
|
* {@link builtinSandboxProviderVerifiedMethods}). A missing or empty list
|
|
118
153
|
* verifies nothing, so every capability resolves `false` (fail closed).
|
|
119
154
|
* - `declared` is the provider's declaration. An absent flag defers to the
|
|
120
|
-
* verified discovery baseline
|
|
121
|
-
* can only remove a
|
|
122
|
-
* - `narrowing` is the per-target restriction from the config or lease. An
|
|
123
|
-
*
|
|
155
|
+
* verified discovery baseline for a worker-property capability; it never grants
|
|
156
|
+
* an opt-in capability. A present flag can only remove a capability.
|
|
157
|
+
* - `narrowing` is the per-target restriction from the config or lease. An absent
|
|
158
|
+
* key applies no restriction; a `false` value removes the capability.
|
|
124
159
|
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
160
|
+
* The two default rules stay intact. An absent declaration defers to the
|
|
161
|
+
* verified baseline for a worker-property capability. The three opt-in
|
|
162
|
+
* capabilities deny by default (see {@link SANDBOX_CAPABILITY_OPT_IN_KEYS}). A
|
|
163
|
+
* declaration never grants a capability the runtime did not verify.
|
|
127
164
|
*/
|
|
128
|
-
export function
|
|
165
|
+
export function classifyEnvironmentCapabilities(input) {
|
|
129
166
|
const verifiedMethods = new Set(input.verifiedMethods ?? []);
|
|
130
167
|
const declared = input.declared ?? {};
|
|
131
168
|
const narrowing = input.narrowing ?? {};
|
|
169
|
+
const supportedCapabilities = input.supportedCapabilities ?? null;
|
|
132
170
|
const resolve = (key) => {
|
|
171
|
+
// The static support definition is the first gate. A capability the driver
|
|
172
|
+
// family cannot support resolves false, whatever the other inputs say. An
|
|
173
|
+
// absent set applies no static gate.
|
|
174
|
+
if (supportedCapabilities && !supportedCapabilities.has(key))
|
|
175
|
+
return false;
|
|
133
176
|
const verified = capabilityIsVerified(key, verifiedMethods);
|
|
134
177
|
// An absent declaration defers to the verified baseline for a worker-property
|
|
135
178
|
// capability (true = no extra restriction), but denies an opt-in capability
|
|
@@ -147,6 +190,8 @@ export function resolveEffectiveSandboxCapabilities(input) {
|
|
|
147
190
|
persistentProcessSessions: resolve("persistentProcessSessions"),
|
|
148
191
|
independentControlCommands: resolve("independentControlCommands"),
|
|
149
192
|
incrementalSessionOutput: resolve("incrementalSessionOutput"),
|
|
193
|
+
concurrentSyncOperations: resolve("concurrentSyncOperations"),
|
|
194
|
+
duplexCommandStream: resolve("duplexCommandStream"),
|
|
150
195
|
};
|
|
151
196
|
}
|
|
152
197
|
/**
|
|
@@ -160,9 +205,9 @@ export function resolveEffectiveSandboxCapabilities(input) {
|
|
|
160
205
|
* which falls back for a `job` backend or a `nativeFileSyncUnsupported` lease).
|
|
161
206
|
* - `configResolutionFailed` marks that the runtime could not resolve the
|
|
162
207
|
* provider config. A provider whose config cannot be resolved is untrusted, so
|
|
163
|
-
* the runtime fails closed and narrows `persistentProcessSessions
|
|
164
|
-
* `incrementalSessionOutput` to false. An empty
|
|
165
|
-
* closed; only a resolution error does.
|
|
208
|
+
* the runtime fails closed and narrows `persistentProcessSessions`,
|
|
209
|
+
* `incrementalSessionOutput`, and `duplexCommandStream` to false. An empty
|
|
210
|
+
* config alone does not fail closed; only a resolution error does.
|
|
166
211
|
*/
|
|
167
212
|
export function buildSandboxCapabilityNarrowing(input) {
|
|
168
213
|
const narrowing = {};
|
|
@@ -174,11 +219,15 @@ export function buildSandboxCapabilityNarrowing(input) {
|
|
|
174
219
|
}
|
|
175
220
|
if (input.configResolutionFailed === true) {
|
|
176
221
|
// The runtime could not resolve the provider config, so it fails closed and
|
|
177
|
-
// denies persistent process sessions
|
|
178
|
-
// session-output streaming gate reads
|
|
179
|
-
// narrow with the persistent-session
|
|
222
|
+
// denies persistent process sessions, incremental session output, and the
|
|
223
|
+
// duplex command stream. The session-output streaming gate reads
|
|
224
|
+
// `incrementalSessionOutput`, so it must narrow with the persistent-session
|
|
225
|
+
// gate to keep the fail-closed behavior. The duplex command stream opens a
|
|
226
|
+
// host-owned bidirectional channel, so an untrusted provider must not keep
|
|
227
|
+
// it either.
|
|
180
228
|
narrowing.persistentProcessSessions = false;
|
|
181
229
|
narrowing.incrementalSessionOutput = false;
|
|
230
|
+
narrowing.duplexCommandStream = false;
|
|
182
231
|
}
|
|
183
232
|
return narrowing;
|
|
184
233
|
}
|
|
@@ -188,6 +237,14 @@ export function buildEnvironmentLeaseContext(input) {
|
|
|
188
237
|
executionWorkspaceMode: input.persistedExecutionWorkspace?.mode ?? null,
|
|
189
238
|
};
|
|
190
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* Map the experimental instance setting `enableSandboxDuplexBridge` into the
|
|
242
|
+
* per-run duplex bridge input. The setting is the kill switch. It defaults off,
|
|
243
|
+
* so an absent or false setting keeps the file bridge.
|
|
244
|
+
*/
|
|
245
|
+
export function resolveSandboxDuplexBridgeInput(experimental) {
|
|
246
|
+
return { enableDuplexBridge: experimental.enableSandboxDuplexBridge === true };
|
|
247
|
+
}
|
|
191
248
|
function stripSecretRefValuesFromPluginLeaseMetadata(input) {
|
|
192
249
|
const sanitized = structuredClone(input.metadata ?? {});
|
|
193
250
|
for (const path of collectSecretRefPaths(input.schema)) {
|
|
@@ -537,6 +594,15 @@ function createLocalEnvironmentDriver(db) {
|
|
|
537
594
|
},
|
|
538
595
|
};
|
|
539
596
|
},
|
|
597
|
+
async resolveCapabilities() {
|
|
598
|
+
// The local driver runs commands on the host file system with no
|
|
599
|
+
// provider capability model, so its static support definition names
|
|
600
|
+
// none of the eight capabilities. The classifier resolves every field
|
|
601
|
+
// `false` regardless of the other inputs, so this method needs none.
|
|
602
|
+
return classifyEnvironmentCapabilities({
|
|
603
|
+
supportedCapabilities: ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT.local.supportedCapabilities,
|
|
604
|
+
});
|
|
605
|
+
},
|
|
540
606
|
};
|
|
541
607
|
}
|
|
542
608
|
function createSshEnvironmentDriver(db) {
|
|
@@ -593,6 +659,45 @@ function createSshEnvironmentDriver(db) {
|
|
|
593
659
|
},
|
|
594
660
|
};
|
|
595
661
|
},
|
|
662
|
+
async resolveCapabilities() {
|
|
663
|
+
// The SSH driver runs commands on a remote host through the SSH
|
|
664
|
+
// transport with no provider capability model, so it supports none of
|
|
665
|
+
// the eight capabilities either.
|
|
666
|
+
return classifyEnvironmentCapabilities({
|
|
667
|
+
supportedCapabilities: ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT.ssh.supportedCapabilities,
|
|
668
|
+
});
|
|
669
|
+
},
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Adapt the worker manager's duplex host session to the cross-layer channel. The
|
|
674
|
+
* two shapes differ in the exit and stop members: the host session resolves the
|
|
675
|
+
* exit one time from `wait()`, so the channel bridges it to a one-time `onExit`
|
|
676
|
+
* listener; `kill()` maps to `stop()`. The `write`, `onData`, and `close`
|
|
677
|
+
* members map one to one.
|
|
678
|
+
*/
|
|
679
|
+
function adaptDuplexChannelHostSession(session) {
|
|
680
|
+
return {
|
|
681
|
+
write(data) {
|
|
682
|
+
session.write(data);
|
|
683
|
+
},
|
|
684
|
+
onData(listener) {
|
|
685
|
+
session.onData(listener);
|
|
686
|
+
},
|
|
687
|
+
onExit(listener) {
|
|
688
|
+
// `wait()` resolves one time with the exit and never rejects, so a single
|
|
689
|
+
// `then` bridges it to the one-time exit listener. The exit carries
|
|
690
|
+
// `transportClosed`, so the broker tells a real exit from a transport close.
|
|
691
|
+
void session.wait().then((exit) => {
|
|
692
|
+
listener(exit);
|
|
693
|
+
});
|
|
694
|
+
},
|
|
695
|
+
stop() {
|
|
696
|
+
session.kill();
|
|
697
|
+
},
|
|
698
|
+
close() {
|
|
699
|
+
return session.close();
|
|
700
|
+
},
|
|
596
701
|
};
|
|
597
702
|
}
|
|
598
703
|
function createSandboxEnvironmentDriver(db, options = {}) {
|
|
@@ -1794,80 +1899,36 @@ function createSandboxEnvironmentDriver(db, options = {}) {
|
|
|
1794
1899
|
async syncOut(input) {
|
|
1795
1900
|
return await callPluginEnvironmentSync("environmentSyncOut", input);
|
|
1796
1901
|
},
|
|
1797
|
-
async
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
return resolveEffectiveSandboxCapabilities({ verifiedMethods: [], declared: null, narrowing: null });
|
|
1805
|
-
}
|
|
1806
|
-
let declared = null;
|
|
1807
|
-
let verifiedMethods = [];
|
|
1808
|
-
let configResolutionFailed = false;
|
|
1809
|
-
if (metadata.sandboxProviderPlugin) {
|
|
1810
|
-
const pluginId = readString(metadata.pluginId);
|
|
1811
|
-
// Read the declaration from the exact plugin that acquired the lease,
|
|
1812
|
-
// not the first installed plugin with this driver key. A driver key is
|
|
1813
|
-
// only unique inside one manifest, so two plugins can share it. The
|
|
1814
|
-
// by-key resolver could intersect this lease's verified methods with a
|
|
1815
|
-
// different plugin's declaration. This resolver fails closed: it returns
|
|
1816
|
-
// null when the pinned plugin id is absent, or when that exact plugin no
|
|
1817
|
-
// longer declares this provider key with the `sandbox_provider` kind.
|
|
1818
|
-
const resolvedDriver = pluginId
|
|
1819
|
-
? await resolvePluginSandboxProviderDriverById({
|
|
1820
|
-
db,
|
|
1821
|
-
pluginId,
|
|
1822
|
-
driverKey: providerKey,
|
|
1823
|
-
})
|
|
1824
|
-
: null;
|
|
1825
|
-
if (!pluginId || !resolvedDriver) {
|
|
1826
|
-
// Exact-plugin identity failure. The lease pins a plugin id, but the
|
|
1827
|
-
// id is missing, that plugin is absent, or it no longer declares this
|
|
1828
|
-
// provider key. Fail closed: resolve every effective capability to
|
|
1829
|
-
// false, no matter what methods a stale or running worker still
|
|
1830
|
-
// advertises. Do not read the worker methods here; passing them would
|
|
1831
|
-
// let an identity-less lease keep a verified baseline. This differs
|
|
1832
|
-
// from a valid plugin whose manifest merely omits
|
|
1833
|
-
// `sandboxCapabilities`: that case keeps `declared` null below and
|
|
1834
|
-
// defers to verified worker discovery.
|
|
1835
|
-
return resolveEffectiveSandboxCapabilities({
|
|
1836
|
-
verifiedMethods: [],
|
|
1837
|
-
declared: null,
|
|
1838
|
-
narrowing: null,
|
|
1839
|
-
});
|
|
1840
|
-
}
|
|
1841
|
-
verifiedMethods = pluginWorkerManager?.getWorker(pluginId)?.supportedMethods ?? [];
|
|
1842
|
-
declared = resolveDeclaredSandboxCapabilities(resolvedDriver.driver);
|
|
1843
|
-
try {
|
|
1844
|
-
// Resolve the provider config to confirm it is readable. A provider
|
|
1845
|
-
// whose config cannot be resolved is untrusted, so a resolution error
|
|
1846
|
-
// fails closed on persistent process sessions below. The resolved
|
|
1847
|
-
// value itself is no longer read for the narrowing decision.
|
|
1848
|
-
await resolvePluginSandboxRuntimeConfig({
|
|
1849
|
-
environment: input.environment,
|
|
1850
|
-
lease: input.lease,
|
|
1851
|
-
provider: providerKey,
|
|
1852
|
-
});
|
|
1853
|
-
}
|
|
1854
|
-
catch {
|
|
1855
|
-
configResolutionFailed = true;
|
|
1856
|
-
}
|
|
1902
|
+
async openDuplexChannel(input) {
|
|
1903
|
+
// Plugin-backed sandbox providers only: open the host-owned duplex route on
|
|
1904
|
+
// the plugin worker. The lease scope mirrors the sandbox execute path — the
|
|
1905
|
+
// provider driver key, the company, the environment, and the provider lease
|
|
1906
|
+
// id — so the route binds to the same worker session the runner streams.
|
|
1907
|
+
if (!input.lease.metadata?.sandboxProviderPlugin || !pluginWorkerManager) {
|
|
1908
|
+
throw new Error("Sandbox driver does not support duplex channels for this lease.");
|
|
1857
1909
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
});
|
|
1910
|
+
const pluginId = readString(input.lease.metadata?.pluginId);
|
|
1911
|
+
const providerKey = readString(input.lease.metadata?.provider);
|
|
1912
|
+
const providerLeaseId = readString(input.lease.providerLeaseId);
|
|
1913
|
+
if (!pluginId || !providerKey || !providerLeaseId) {
|
|
1914
|
+
throw new Error("Sandbox duplex channel needs a plugin id, a provider key, and a provider lease id on the lease.");
|
|
1864
1915
|
}
|
|
1865
|
-
const
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1916
|
+
const worker = pluginWorkerManager.getWorker(pluginId);
|
|
1917
|
+
if (!worker) {
|
|
1918
|
+
throw new Error(`Plugin worker "${pluginId}" is not running for the duplex channel.`);
|
|
1919
|
+
}
|
|
1920
|
+
const managerInput = {
|
|
1921
|
+
driverKey: providerKey,
|
|
1922
|
+
companyId: input.lease.companyId,
|
|
1923
|
+
environmentId: input.environment.id,
|
|
1924
|
+
providerLeaseId,
|
|
1925
|
+
command: input.command,
|
|
1926
|
+
};
|
|
1927
|
+
const session = await worker.openDuplexChannel(managerInput);
|
|
1928
|
+
return adaptDuplexChannelHostSession(session);
|
|
1929
|
+
},
|
|
1930
|
+
async resolveCapabilities(input) {
|
|
1931
|
+
return await resolveSandboxCapabilitiesForLease(input);
|
|
1871
1932
|
},
|
|
1872
1933
|
async destroyRunLease(input) {
|
|
1873
1934
|
return await destroyReusableSandboxLease({
|
|
@@ -1877,6 +1938,102 @@ function createSandboxEnvironmentDriver(db, options = {}) {
|
|
|
1877
1938
|
});
|
|
1878
1939
|
},
|
|
1879
1940
|
};
|
|
1941
|
+
/**
|
|
1942
|
+
* Resolve the effective capability snapshot for one sandbox lease. This is
|
|
1943
|
+
* the sandbox driver's implementation of the general capability-resolution
|
|
1944
|
+
* method: it gates through {@link ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT}'s
|
|
1945
|
+
* `sandbox` support (the whole set, so this gate adds no restriction beyond
|
|
1946
|
+
* declaration, verification, and narrowing), then reads the per-lease
|
|
1947
|
+
* declaration, the live verified worker methods, and the per-lease
|
|
1948
|
+
* narrowing, exactly as the runtime resolved them before this method
|
|
1949
|
+
* existed.
|
|
1950
|
+
*/
|
|
1951
|
+
async function resolveSandboxCapabilitiesForLease(input) {
|
|
1952
|
+
const metadata = input.lease.metadata ?? {};
|
|
1953
|
+
const providerKey = readString(metadata.provider) ??
|
|
1954
|
+
(input.environment.driver === "sandbox"
|
|
1955
|
+
? readString(parseEnvironmentDriverConfig(input.environment).config.provider)
|
|
1956
|
+
: null);
|
|
1957
|
+
if (!providerKey) {
|
|
1958
|
+
return classifyEnvironmentCapabilities({
|
|
1959
|
+
verifiedMethods: [],
|
|
1960
|
+
declared: null,
|
|
1961
|
+
narrowing: null,
|
|
1962
|
+
supportedCapabilities: ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT.sandbox.supportedCapabilities,
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
let declared = null;
|
|
1966
|
+
let verifiedMethods = [];
|
|
1967
|
+
let configResolutionFailed = false;
|
|
1968
|
+
if (metadata.sandboxProviderPlugin) {
|
|
1969
|
+
const pluginId = readString(metadata.pluginId);
|
|
1970
|
+
// Read the declaration from the exact plugin that acquired the lease,
|
|
1971
|
+
// not the first installed plugin with this driver key. A driver key is
|
|
1972
|
+
// only unique inside one manifest, so two plugins can share it. The
|
|
1973
|
+
// by-key resolver could intersect this lease's verified methods with a
|
|
1974
|
+
// different plugin's declaration. This resolver fails closed: it returns
|
|
1975
|
+
// null when the pinned plugin id is absent, or when that exact plugin no
|
|
1976
|
+
// longer declares this provider key with the `sandbox_provider` kind.
|
|
1977
|
+
const resolvedDriver = pluginId
|
|
1978
|
+
? await resolvePluginSandboxProviderDriverById({
|
|
1979
|
+
db,
|
|
1980
|
+
pluginId,
|
|
1981
|
+
driverKey: providerKey,
|
|
1982
|
+
})
|
|
1983
|
+
: null;
|
|
1984
|
+
if (!pluginId || !resolvedDriver) {
|
|
1985
|
+
// Exact-plugin identity failure. The lease pins a plugin id, but the
|
|
1986
|
+
// id is missing, that plugin is absent, or it no longer declares this
|
|
1987
|
+
// provider key. Fail closed: resolve every effective capability to
|
|
1988
|
+
// false, no matter what methods a stale or running worker still
|
|
1989
|
+
// advertises. Do not read the worker methods here; passing them would
|
|
1990
|
+
// let an identity-less lease keep a verified baseline. This differs
|
|
1991
|
+
// from a valid plugin whose manifest merely omits
|
|
1992
|
+
// `sandboxCapabilities`: that case keeps `declared` null below and
|
|
1993
|
+
// defers to verified worker discovery.
|
|
1994
|
+
return classifyEnvironmentCapabilities({
|
|
1995
|
+
verifiedMethods: [],
|
|
1996
|
+
declared: null,
|
|
1997
|
+
narrowing: null,
|
|
1998
|
+
supportedCapabilities: ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT.sandbox.supportedCapabilities,
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
verifiedMethods = pluginWorkerManager?.getWorker(pluginId)?.supportedMethods ?? [];
|
|
2002
|
+
declared = resolveDeclaredSandboxCapabilities(resolvedDriver.driver);
|
|
2003
|
+
try {
|
|
2004
|
+
// Resolve the provider config to confirm it is readable. A provider
|
|
2005
|
+
// whose config cannot be resolved is untrusted, so a resolution error
|
|
2006
|
+
// fails closed on persistent process sessions below. The resolved
|
|
2007
|
+
// value itself is no longer read for the narrowing decision.
|
|
2008
|
+
await resolvePluginSandboxRuntimeConfig({
|
|
2009
|
+
environment: input.environment,
|
|
2010
|
+
lease: input.lease,
|
|
2011
|
+
provider: providerKey,
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
catch {
|
|
2015
|
+
configResolutionFailed = true;
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
else {
|
|
2019
|
+
const builtin = getBuiltinSandboxProvider(providerKey);
|
|
2020
|
+
verifiedMethods = builtinSandboxProviderVerifiedMethods(builtin);
|
|
2021
|
+
declared = resolveDeclaredSandboxCapabilities({
|
|
2022
|
+
supportsReusableLeases: builtin?.supportsReusableLeases,
|
|
2023
|
+
});
|
|
2024
|
+
}
|
|
2025
|
+
const narrowing = buildSandboxCapabilityNarrowing({
|
|
2026
|
+
leasePolicy: input.lease.leasePolicy,
|
|
2027
|
+
leaseMetadata: metadata,
|
|
2028
|
+
configResolutionFailed,
|
|
2029
|
+
});
|
|
2030
|
+
return classifyEnvironmentCapabilities({
|
|
2031
|
+
verifiedMethods,
|
|
2032
|
+
declared,
|
|
2033
|
+
narrowing,
|
|
2034
|
+
supportedCapabilities: ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT.sandbox.supportedCapabilities,
|
|
2035
|
+
});
|
|
2036
|
+
}
|
|
1880
2037
|
/**
|
|
1881
2038
|
* Verify that the live plugin worker still advertises a reusable-lease
|
|
1882
2039
|
* lifecycle method before the runtime dispatches that RPC. The worker reports
|
|
@@ -2326,6 +2483,50 @@ function createPluginEnvironmentDriver(db, workerManager) {
|
|
|
2326
2483
|
},
|
|
2327
2484
|
});
|
|
2328
2485
|
},
|
|
2486
|
+
async resolveCapabilities(input) {
|
|
2487
|
+
const metadata = input.lease.metadata ?? {};
|
|
2488
|
+
const pluginId = readString(metadata.pluginId);
|
|
2489
|
+
const driverKey = readString(metadata.driverKey);
|
|
2490
|
+
const noCapabilities = () => classifyEnvironmentCapabilities({
|
|
2491
|
+
verifiedMethods: [],
|
|
2492
|
+
declared: null,
|
|
2493
|
+
narrowing: null,
|
|
2494
|
+
supportedCapabilities: ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT.plugin.supportedCapabilities,
|
|
2495
|
+
});
|
|
2496
|
+
if (!pluginId || !driverKey) {
|
|
2497
|
+
// The lease carries no plugin pin, so there is no exact plugin to read
|
|
2498
|
+
// the declaration or the live worker methods from. Fail closed: resolve
|
|
2499
|
+
// every capability false.
|
|
2500
|
+
return noCapabilities();
|
|
2501
|
+
}
|
|
2502
|
+
// Read the declaration from the exact plugin that acquired the lease, not
|
|
2503
|
+
// the plugin the environment's current config names. A plugin uninstall,
|
|
2504
|
+
// a manifest change, or a config edit between the acquire and this call
|
|
2505
|
+
// must not let a stale declaration or a different plugin's worker grant a
|
|
2506
|
+
// capability this lease never verified.
|
|
2507
|
+
const plugin = await pluginRegistry.getById(pluginId);
|
|
2508
|
+
const declaredDriver = plugin && plugin.status === "ready"
|
|
2509
|
+
? plugin.manifestJson.environmentDrivers?.find((candidate) => candidate.driverKey === driverKey)
|
|
2510
|
+
: undefined;
|
|
2511
|
+
if (!plugin || plugin.status !== "ready" || !declaredDriver) {
|
|
2512
|
+
return noCapabilities();
|
|
2513
|
+
}
|
|
2514
|
+
// Read the live worker method list fresh on every call. A worker restart
|
|
2515
|
+
// can drop or add a method between the acquire and this call, so the
|
|
2516
|
+
// runtime never trusts a cached method list for a capability grant.
|
|
2517
|
+
const verifiedMethods = workerManager.getWorker(plugin.id)?.supportedMethods ?? [];
|
|
2518
|
+
const declared = resolveDeclaredSandboxCapabilities(declaredDriver);
|
|
2519
|
+
const narrowing = buildSandboxCapabilityNarrowing({
|
|
2520
|
+
leasePolicy: input.lease.leasePolicy,
|
|
2521
|
+
leaseMetadata: metadata,
|
|
2522
|
+
});
|
|
2523
|
+
return classifyEnvironmentCapabilities({
|
|
2524
|
+
verifiedMethods,
|
|
2525
|
+
declared,
|
|
2526
|
+
narrowing,
|
|
2527
|
+
supportedCapabilities: ENVIRONMENT_DRIVER_CAPABILITY_SUPPORT.plugin.supportedCapabilities,
|
|
2528
|
+
});
|
|
2529
|
+
},
|
|
2329
2530
|
};
|
|
2330
2531
|
}
|
|
2331
2532
|
export function environmentRuntimeService(db, options = {}) {
|
|
@@ -2370,6 +2571,16 @@ export function environmentRuntimeService(db, options = {}) {
|
|
|
2370
2571
|
}
|
|
2371
2572
|
return {
|
|
2372
2573
|
getDriver,
|
|
2574
|
+
/**
|
|
2575
|
+
* Read the sandbox duplex bridge kill switch for a new run. The host calls it
|
|
2576
|
+
* per run before it selects the callback bridge transport. It reads the
|
|
2577
|
+
* experimental instance setting `enableSandboxDuplexBridge` and maps it into
|
|
2578
|
+
* the resolved bridge input. The default-off setting keeps the file bridge.
|
|
2579
|
+
*/
|
|
2580
|
+
async readSandboxDuplexBridgeInput() {
|
|
2581
|
+
const experimental = await instanceSettingsService(db).getExperimental();
|
|
2582
|
+
return resolveSandboxDuplexBridgeInput(experimental);
|
|
2583
|
+
},
|
|
2373
2584
|
async acquireRunLease(input) {
|
|
2374
2585
|
if (input.environment.status !== "active") {
|
|
2375
2586
|
throw new Error(`Environment "${input.environment.name}" is not active.`);
|
|
@@ -2530,6 +2741,113 @@ export function environmentRuntimeService(db, options = {}) {
|
|
|
2530
2741
|
}
|
|
2531
2742
|
return destroyed;
|
|
2532
2743
|
},
|
|
2744
|
+
/**
|
|
2745
|
+
* Destroy every reusable sandbox lease still owned by one environment, so a
|
|
2746
|
+
* consented environment delete can proceed. This must run while the
|
|
2747
|
+
* environment row still exists: the driver resolves provider credentials
|
|
2748
|
+
* from the environment config, and after the delete the normal destroy path
|
|
2749
|
+
* has no context left. A per-lease failure is contained — the driver routes
|
|
2750
|
+
* a failed teardown to `pending_cleanup` for the sweep, and an unexpected
|
|
2751
|
+
* throw leaves the lease in place — so the caller re-checks the blast
|
|
2752
|
+
* radius instead of trusting these counts for the delete decision.
|
|
2753
|
+
*/
|
|
2754
|
+
async destroyReusableSandboxLeasesForEnvironment(input) {
|
|
2755
|
+
const environment = await environmentsSvc.getById(input.environmentId);
|
|
2756
|
+
if (!environment)
|
|
2757
|
+
return { destroyed: 0, failed: 0, skippedLiveRun: 0 };
|
|
2758
|
+
const leaseRows = await db
|
|
2759
|
+
.select()
|
|
2760
|
+
.from(environmentLeases)
|
|
2761
|
+
.where(and(eq(environmentLeases.environmentId, input.environmentId), eq(environmentLeases.leasePolicy, "reuse_by_environment"), inArray(environmentLeases.status, ["active", "released", "retained"])));
|
|
2762
|
+
// A lease whose holding run is still in flight keeps its sandbox: the
|
|
2763
|
+
// consented delete must not tear a live run's environment out from under
|
|
2764
|
+
// it. The skipped lease keeps blocking the delete, so the caller's
|
|
2765
|
+
// blast-radius re-check rejects and the operator retries after the run
|
|
2766
|
+
// finishes. A lease pointing at a finished run — or at no run — is a
|
|
2767
|
+
// stale reservation and destroys normally.
|
|
2768
|
+
const holdingRunIds = leaseRows
|
|
2769
|
+
.map((row) => row.heartbeatRunId)
|
|
2770
|
+
.filter((runId) => Boolean(runId));
|
|
2771
|
+
const liveRunIds = new Set();
|
|
2772
|
+
if (holdingRunIds.length > 0) {
|
|
2773
|
+
const liveRuns = await db
|
|
2774
|
+
.select({ id: heartbeatRuns.id })
|
|
2775
|
+
.from(heartbeatRuns)
|
|
2776
|
+
.where(and(inArray(heartbeatRuns.id, holdingRunIds), inArray(heartbeatRuns.status, ["queued", "scheduled_retry", "running"])));
|
|
2777
|
+
for (const run of liveRuns)
|
|
2778
|
+
liveRunIds.add(run.id);
|
|
2779
|
+
}
|
|
2780
|
+
let destroyed = 0;
|
|
2781
|
+
let failed = 0;
|
|
2782
|
+
let skippedLiveRun = 0;
|
|
2783
|
+
const failureReason = input.failureReason ?? "environment_delete_requested";
|
|
2784
|
+
const now = new Date();
|
|
2785
|
+
for (const leaseRow of leaseRows) {
|
|
2786
|
+
if (leaseRow.heartbeatRunId && liveRunIds.has(leaseRow.heartbeatRunId)) {
|
|
2787
|
+
skippedLiveRun += 1;
|
|
2788
|
+
continue;
|
|
2789
|
+
}
|
|
2790
|
+
// Claim the row BEFORE the provider call, mirroring the inline-teardown
|
|
2791
|
+
// invariant used elsewhere in this file: no provider destroy without a
|
|
2792
|
+
// durable `pending_cleanup` reference already on disk. The claim is one
|
|
2793
|
+
// conditional UPDATE, so it is the fence against a racing resume: a
|
|
2794
|
+
// resume that re-activates the lease first makes the status predicate
|
|
2795
|
+
// (or the run-liveness predicate) fail and the claim loses — the live
|
|
2796
|
+
// run keeps its sandbox. A claim that wins parks the lease where the
|
|
2797
|
+
// cleanup sweep owns it, so a crash or thrown destroy after this point
|
|
2798
|
+
// is recovered by the sweep's idempotent teardown, and a double write
|
|
2799
|
+
// failure cannot strand the lease in a reusable status.
|
|
2800
|
+
const claimedRow = await db
|
|
2801
|
+
.update(environmentLeases)
|
|
2802
|
+
.set({
|
|
2803
|
+
status: "pending_cleanup",
|
|
2804
|
+
failureReason,
|
|
2805
|
+
cleanupStatus: "failed",
|
|
2806
|
+
releasedAt: now,
|
|
2807
|
+
lastUsedAt: now,
|
|
2808
|
+
updatedAt: now,
|
|
2809
|
+
})
|
|
2810
|
+
.where(and(eq(environmentLeases.id, leaseRow.id), inArray(environmentLeases.status, ["active", "released", "retained"]), sql `NOT EXISTS (
|
|
2811
|
+
SELECT 1 FROM ${heartbeatRuns}
|
|
2812
|
+
WHERE ${heartbeatRuns.id} = ${environmentLeases.heartbeatRunId}
|
|
2813
|
+
AND ${heartbeatRuns.status} IN ('queued', 'scheduled_retry', 'running')
|
|
2814
|
+
)`))
|
|
2815
|
+
.returning()
|
|
2816
|
+
.then((rows) => rows[0] ?? null);
|
|
2817
|
+
if (!claimedRow) {
|
|
2818
|
+
// Lost to a racing resume or a concurrent terminal transition — the
|
|
2819
|
+
// lease is no longer ours to destroy.
|
|
2820
|
+
skippedLiveRun += 1;
|
|
2821
|
+
continue;
|
|
2822
|
+
}
|
|
2823
|
+
const leaseSnapshot = toEnvironmentLeaseSnapshot(claimedRow);
|
|
2824
|
+
try {
|
|
2825
|
+
const driver = getDriver(getLeaseDriverKey(leaseSnapshot, environment));
|
|
2826
|
+
if (!driver?.destroyRunLease) {
|
|
2827
|
+
// No driver available: the claim already parked the lease for the
|
|
2828
|
+
// sweep, which retries once the driver's plugin is back.
|
|
2829
|
+
failed += 1;
|
|
2830
|
+
continue;
|
|
2831
|
+
}
|
|
2832
|
+
const lease = await driver.destroyRunLease({
|
|
2833
|
+
environment,
|
|
2834
|
+
lease: leaseSnapshot,
|
|
2835
|
+
failureReason,
|
|
2836
|
+
});
|
|
2837
|
+
if (lease && lease.status !== "pending_cleanup")
|
|
2838
|
+
destroyed += 1;
|
|
2839
|
+
else
|
|
2840
|
+
failed += 1;
|
|
2841
|
+
}
|
|
2842
|
+
catch {
|
|
2843
|
+
// The claim above already parked the lease in `pending_cleanup`, so
|
|
2844
|
+
// the sweep owns the retry; its teardown is idempotent, so a destroy
|
|
2845
|
+
// that reached the provider before the throw resolves as success.
|
|
2846
|
+
failed += 1;
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
return { destroyed, failed, skippedLiveRun };
|
|
2850
|
+
},
|
|
2533
2851
|
async resumeRunLease(input) {
|
|
2534
2852
|
const driver = requireDriverKey(getLeaseDriverKey(input.lease, input.environment));
|
|
2535
2853
|
if (!driver.resumeRunLease) {
|
|
@@ -2562,9 +2880,18 @@ export function environmentRuntimeService(db, options = {}) {
|
|
|
2562
2880
|
const driver = getDriver(getLeaseDriverKey(input.lease, input.environment));
|
|
2563
2881
|
return driver?.supportsSync?.(input) ?? false;
|
|
2564
2882
|
},
|
|
2565
|
-
|
|
2883
|
+
/**
|
|
2884
|
+
* Resolve the general per-lease capability snapshot through the driver's
|
|
2885
|
+
* {@link EnvironmentRuntimeDriver.resolveCapabilities}. Every registered
|
|
2886
|
+
* driver implements this method, so it returns a full snapshot for any
|
|
2887
|
+
* registered driver. It returns `null` only when the lease's driver is
|
|
2888
|
+
* not registered — never as a stand-in for "every capability denied".
|
|
2889
|
+
*/
|
|
2890
|
+
async resolveCapabilities(input) {
|
|
2566
2891
|
const driver = getDriver(getLeaseDriverKey(input.lease, input.environment));
|
|
2567
|
-
|
|
2892
|
+
if (!driver)
|
|
2893
|
+
return null;
|
|
2894
|
+
return await driver.resolveCapabilities(input);
|
|
2568
2895
|
},
|
|
2569
2896
|
async syncIn(input) {
|
|
2570
2897
|
const driver = requireDriverKey(getLeaseDriverKey(input.lease, input.environment));
|
|
@@ -2580,6 +2907,24 @@ export function environmentRuntimeService(db, options = {}) {
|
|
|
2580
2907
|
}
|
|
2581
2908
|
return await driver.syncOut(input);
|
|
2582
2909
|
},
|
|
2910
|
+
async openDuplexChannel(input) {
|
|
2911
|
+
const driver = requireDriverKey(getLeaseDriverKey(input.lease, input.environment));
|
|
2912
|
+
if (!driver.openDuplexChannel) {
|
|
2913
|
+
throw new Error(`Environment driver "${driver.driver}" does not support duplex channels.`);
|
|
2914
|
+
}
|
|
2915
|
+
// Centralize the duplex channel authorization here. Resolve the exact lease
|
|
2916
|
+
// capability snapshot through the general resolver and refuse unless the
|
|
2917
|
+
// effective snapshot grants the opt-in `duplexCommandStream` capability.
|
|
2918
|
+
// This gate runs before the driver call, so an unauthorized lease never
|
|
2919
|
+
// reaches the worker. The execution-target member gate stays as defense
|
|
2920
|
+
// in depth. A driver that cannot resolve the snapshot fails closed with
|
|
2921
|
+
// the fixed refusal.
|
|
2922
|
+
const effective = await driver.resolveCapabilities(input);
|
|
2923
|
+
if (effective.duplexCommandStream !== true) {
|
|
2924
|
+
throw new Error(DUPLEX_CHANNEL_CAPABILITY_DENIED);
|
|
2925
|
+
}
|
|
2926
|
+
return await driver.openDuplexChannel(input);
|
|
2927
|
+
},
|
|
2583
2928
|
};
|
|
2584
2929
|
}
|
|
2585
2930
|
//# sourceMappingURL=environment-runtime.js.map
|