@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,7 +1,12 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { accessSync, constants as fsConstants, existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
1
4
|
import { and, eq } from "drizzle-orm";
|
|
2
5
|
import { Router } from "express";
|
|
3
6
|
import { issues, projects, projectWorkspaces } from "@paperclipai/db";
|
|
4
7
|
import { findWorkspaceCommandDefinition, matchWorkspaceRuntimeServiceToCommand, reconcileExecutionWorkspaceBranchSchema, updateExecutionWorkspaceSchema, workspaceOverviewQuerySchema, workspaceRuntimeControlTargetSchema, } from "@paperclipai/shared";
|
|
8
|
+
import { baseWorkspaceDeclaresInstanceConfig, resolveCanonicalWorktreeSeedSource, } from "@paperclipai/shared/worktree-seed-source";
|
|
9
|
+
import { resolvePaperclipConfigPath } from "../paths.js";
|
|
5
10
|
import { validate } from "../middleware/validate.js";
|
|
6
11
|
import { accessService, executionWorkspaceService, heartbeatService, logActivity, workspaceOperationService, workspaceRuntimeLeaseService, LEASED_WORKSPACE_RUNTIME_ACTIONS, } from "../services/index.js";
|
|
7
12
|
import { mergeExecutionWorkspaceConfig, readExecutionWorkspaceConfig } from "../services/execution-workspaces.js";
|
|
@@ -15,7 +20,29 @@ import { assertCanManageExecutionWorkspaceRuntimeServices } from "./workspace-ru
|
|
|
15
20
|
import { appendWithCap } from "../adapters/utils.js";
|
|
16
21
|
import { environmentRuntimeService } from "../services/environment-runtime.js";
|
|
17
22
|
import { runExclusiveWorkspaceRuntimeControl } from "../services/workspace-operations.js";
|
|
23
|
+
import { resolveManagedWorkspaceInstanceId } from "../services/managed-workspace-identity.js";
|
|
24
|
+
import { isVerifiedWorktreeSeedManifest } from "../worktree-seed-manifest.js";
|
|
25
|
+
import { issueWorkspaceLoginHandoff, workspaceLoginHandoffFailureStatus, } from "../services/workspace-login-handoff-issuer.js";
|
|
26
|
+
import { conflict, unprocessable } from "../errors.js";
|
|
18
27
|
const WORKSPACE_CONTROL_OUTPUT_MAX_CHARS = 256 * 1024;
|
|
28
|
+
function isReadableFile(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
accessSync(filePath, fsConstants.R_OK);
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The control plane's own instance config, named as the seed source only when the base
|
|
39
|
+
* project workspace is a plain checkout carrying no instance config of its own. A base
|
|
40
|
+
* workspace that has one stays authoritative, so an operator's mismatched source is
|
|
41
|
+
* still rejected.
|
|
42
|
+
*/
|
|
43
|
+
function resolveFallbackSeedSourceConfigPath(baseWorkspaceCwd) {
|
|
44
|
+
return baseWorkspaceDeclaresInstanceConfig(baseWorkspaceCwd) ? null : resolvePaperclipConfigPath();
|
|
45
|
+
}
|
|
19
46
|
export function executionWorkspaceRoutes(db, opts = {}) {
|
|
20
47
|
const router = Router();
|
|
21
48
|
const svc = executionWorkspaceService(db);
|
|
@@ -106,6 +133,81 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
106
133
|
}
|
|
107
134
|
res.json(readiness);
|
|
108
135
|
});
|
|
136
|
+
/**
|
|
137
|
+
* Mint a single-use workspace login handoff for the calling board user.
|
|
138
|
+
*
|
|
139
|
+
* Board-only: the ticket carries a user identity, so an agent key — which has
|
|
140
|
+
* no user to sign in — must never be able to mint one. Nothing in the request
|
|
141
|
+
* body influences what the ticket is bound to; only the landing path is taken
|
|
142
|
+
* from the caller, and it is reduced to a same-origin path before signing.
|
|
143
|
+
*/
|
|
144
|
+
router.post("/execution-workspaces/:id/login-handoff", async (req, res) => {
|
|
145
|
+
const id = req.params.id;
|
|
146
|
+
assertBoard(req);
|
|
147
|
+
const workspace = await getAccessibleResource(req, res, svc.getById(id), "Execution workspace not found");
|
|
148
|
+
if (!workspace)
|
|
149
|
+
return;
|
|
150
|
+
// Opening a workspace board is a runtime-control-grade action: it hands the
|
|
151
|
+
// caller an authenticated session inside the cloned instance.
|
|
152
|
+
if (!(await assertRuntimeManageAllowed(req, res, workspace.companyId)))
|
|
153
|
+
return;
|
|
154
|
+
const requestedNext = typeof req.body?.next === "string"
|
|
155
|
+
? req.body.next
|
|
156
|
+
: null;
|
|
157
|
+
const result = await issueWorkspaceLoginHandoff({
|
|
158
|
+
db,
|
|
159
|
+
companyId: workspace.companyId,
|
|
160
|
+
executionWorkspace: { id: workspace.id, cwd: workspace.cwd },
|
|
161
|
+
actor: {
|
|
162
|
+
userId: req.actor.userId ?? null,
|
|
163
|
+
userEmail: req.actor.userEmail ?? null,
|
|
164
|
+
source: req.actor.source ?? null,
|
|
165
|
+
},
|
|
166
|
+
next: requestedNext,
|
|
167
|
+
});
|
|
168
|
+
if (!result.ok) {
|
|
169
|
+
logger.warn({
|
|
170
|
+
executionWorkspaceId: workspace.id,
|
|
171
|
+
reason: result.failure.reason,
|
|
172
|
+
detail: "detail" in result.failure ? result.failure.detail : null,
|
|
173
|
+
}, "workspace login handoff was not issued");
|
|
174
|
+
res.status(workspaceLoginHandoffFailureStatus(result.failure)).json({
|
|
175
|
+
error: "workspace_login_handoff_unavailable",
|
|
176
|
+
// The UI turns this into the labeled snapshot-local credential fallback
|
|
177
|
+
// or a repair prompt, so the machine reason has to survive the boundary.
|
|
178
|
+
reason: result.failure.reason,
|
|
179
|
+
mode: "credentials",
|
|
180
|
+
...("detail" in result.failure ? { detail: result.failure.detail } : {}),
|
|
181
|
+
...("readiness" in result.failure ? { readiness: result.failure.readiness } : {}),
|
|
182
|
+
});
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
await logActivity(db, {
|
|
186
|
+
companyId: workspace.companyId,
|
|
187
|
+
// Auditing issuance is a requirement of the handoff design: the nonce ties
|
|
188
|
+
// this record to the guest's own accept/reject record. The ticket itself is
|
|
189
|
+
// never recorded.
|
|
190
|
+
action: "workspace_login_handoff_issued",
|
|
191
|
+
entityType: "execution_workspace",
|
|
192
|
+
entityId: workspace.id,
|
|
193
|
+
actorType: "user",
|
|
194
|
+
actorId: result.issuance.userId,
|
|
195
|
+
details: {
|
|
196
|
+
nonce: result.issuance.nonce,
|
|
197
|
+
instanceId: result.issuance.instanceId,
|
|
198
|
+
origin: result.issuance.origin,
|
|
199
|
+
expiresAt: result.issuance.expiresAt,
|
|
200
|
+
},
|
|
201
|
+
}).catch((error) => {
|
|
202
|
+
logger.warn({ err: error, executionWorkspaceId: workspace.id }, "failed to audit workspace login handoff");
|
|
203
|
+
});
|
|
204
|
+
res.setHeader("Cache-Control", "no-store");
|
|
205
|
+
res.status(201).json({
|
|
206
|
+
url: result.issuance.url,
|
|
207
|
+
expiresAt: result.issuance.expiresAt,
|
|
208
|
+
mode: "handoff",
|
|
209
|
+
});
|
|
210
|
+
});
|
|
109
211
|
router.get("/execution-workspaces/:id/workspace-operations", async (req, res) => {
|
|
110
212
|
const id = req.params.id;
|
|
111
213
|
const workspace = await getAccessibleResource(req, res, svc.getById(id), "Execution workspace not found");
|
|
@@ -119,7 +221,7 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
119
221
|
async function handleExecutionWorkspaceRuntimeCommand(req, res) {
|
|
120
222
|
const id = req.params.id;
|
|
121
223
|
const action = String(req.params.action ?? "").trim().toLowerCase();
|
|
122
|
-
if (action !== "start" && action !== "stop" && action !== "restart" && action !== "run") {
|
|
224
|
+
if (action !== "start" && action !== "stop" && action !== "restart" && action !== "repair" && action !== "run") {
|
|
123
225
|
res.status(404).json({ error: "Workspace command action not found" });
|
|
124
226
|
return;
|
|
125
227
|
}
|
|
@@ -133,13 +235,6 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
133
235
|
executionWorkspaceId: existing.id,
|
|
134
236
|
sourceIssueId: existing.sourceIssueId,
|
|
135
237
|
});
|
|
136
|
-
// Recover any managed runtime-control operation this workspace was stranded with, then
|
|
137
|
-
// refuse only if one is genuinely still live. Authorization above still gates the caller,
|
|
138
|
-
// so recovery never widens who may control the workspace.
|
|
139
|
-
await workspaceOperationsSvc.assertRuntimeControlAvailable({
|
|
140
|
-
executionWorkspaceId: existing.id,
|
|
141
|
-
action,
|
|
142
|
-
});
|
|
143
238
|
const workspaceCwd = existing.cwd;
|
|
144
239
|
if (!workspaceCwd) {
|
|
145
240
|
res.status(422).json({ error: "Execution workspace needs a local path before Paperclip can run workspace commands" });
|
|
@@ -156,7 +251,7 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
156
251
|
metadata: projectWorkspaces.metadata,
|
|
157
252
|
})
|
|
158
253
|
.from(projectWorkspaces)
|
|
159
|
-
.where(and(eq(projectWorkspaces.id, existing.projectWorkspaceId), eq(projectWorkspaces.companyId, existing.companyId)))
|
|
254
|
+
.where(and(eq(projectWorkspaces.id, existing.projectWorkspaceId), eq(projectWorkspaces.companyId, existing.companyId), eq(projectWorkspaces.projectId, existing.projectId)))
|
|
160
255
|
.then((rows) => rows[0] ?? null)
|
|
161
256
|
: null;
|
|
162
257
|
const projectWorkspaceRuntime = readProjectWorkspaceRuntimeConfig(projectWorkspace?.metadata ?? null)?.workspaceRuntime ?? null;
|
|
@@ -174,6 +269,7 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
174
269
|
const configuredServices = effectiveRuntimeConfig
|
|
175
270
|
? listConfiguredRuntimeServiceEntries({ workspaceRuntime: effectiveRuntimeConfig })
|
|
176
271
|
: [];
|
|
272
|
+
const repairRestartsRuntimeServices = action === "repair" && configuredServices.length > 0;
|
|
177
273
|
const workspaceCommand = effectiveRuntimeConfig
|
|
178
274
|
? findWorkspaceCommandDefinition(effectiveRuntimeConfig, target.workspaceCommandId ?? null)
|
|
179
275
|
: null;
|
|
@@ -214,6 +310,70 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
214
310
|
res.status(422).json({ error: "Execution workspace has no workspace command configuration or inherited project workspace default" });
|
|
215
311
|
return;
|
|
216
312
|
}
|
|
313
|
+
let repairSeedSource = null;
|
|
314
|
+
let repairPreviousAttemptId = null;
|
|
315
|
+
let repairCliArgs = null;
|
|
316
|
+
if (action === "repair") {
|
|
317
|
+
const manifestPath = path.join(workspaceCwd, ".paperclip", "seed-manifest.json");
|
|
318
|
+
let manifest;
|
|
319
|
+
try {
|
|
320
|
+
manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
throw unprocessable("Workspace seed manifest is malformed; repair source identity cannot be trusted.", {
|
|
324
|
+
code: "workspace_repair_precondition_failed",
|
|
325
|
+
reason: "seed_manifest_malformed",
|
|
326
|
+
repairPhase: "precondition_validation",
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
if (!projectWorkspace?.cwd) {
|
|
331
|
+
throw new Error("Workspace repair requires a registered base project workspace.");
|
|
332
|
+
}
|
|
333
|
+
const expectedTargetInstanceId = resolveManagedWorkspaceInstanceId(workspaceCwd);
|
|
334
|
+
if (!expectedTargetInstanceId) {
|
|
335
|
+
throw new Error("Workspace repair cannot resolve the registered target instance.");
|
|
336
|
+
}
|
|
337
|
+
repairSeedSource = resolveCanonicalWorktreeSeedSource({
|
|
338
|
+
registeredBaseWorkspaceCwd: projectWorkspace.cwd,
|
|
339
|
+
explicitSourceConfigPath: resolveFallbackSeedSourceConfigPath(projectWorkspace.cwd),
|
|
340
|
+
targetConfigPath: path.join(workspaceCwd, ".paperclip", "config.json"),
|
|
341
|
+
expectedTargetInstanceId,
|
|
342
|
+
manifestSource: manifest.source,
|
|
343
|
+
manifestTargetInstanceId: manifest.targetInstanceId,
|
|
344
|
+
});
|
|
345
|
+
repairPreviousAttemptId = typeof manifest.attemptId === "string" ? manifest.attemptId : null;
|
|
346
|
+
const baseWorkspaceCwd = repairSeedSource.baseWorkspaceCwd;
|
|
347
|
+
if (!baseWorkspaceCwd) {
|
|
348
|
+
throw new Error("Workspace repair source is not bound to a registered base project workspace.");
|
|
349
|
+
}
|
|
350
|
+
const cliRunner = path.join(baseWorkspaceCwd, "cli", "node_modules", "tsx", "dist", "cli.mjs");
|
|
351
|
+
const cliEntry = path.join(baseWorkspaceCwd, "cli", "src", "index.ts");
|
|
352
|
+
const cliDist = path.join(baseWorkspaceCwd, "cli", "dist", "index.js");
|
|
353
|
+
repairCliArgs = isReadableFile(cliRunner) && isReadableFile(cliEntry)
|
|
354
|
+
? [cliRunner, cliEntry]
|
|
355
|
+
: isReadableFile(cliDist)
|
|
356
|
+
? [cliDist]
|
|
357
|
+
: null;
|
|
358
|
+
if (!repairCliArgs) {
|
|
359
|
+
throw new Error("Workspace repair cannot find a runnable Paperclip CLI in the base workspace.");
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
throw unprocessable(error instanceof Error ? error.message : "Workspace repair source validation failed.", {
|
|
364
|
+
code: "workspace_repair_precondition_failed",
|
|
365
|
+
reason: "source_registration_invalid",
|
|
366
|
+
repairPhase: "precondition_validation",
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// This check can reconcile a stale operation row, so repair source validation must
|
|
371
|
+
// precede it. Invalid manifest diagnostics must fail before any operation or service
|
|
372
|
+
// mutation, not merely before the reseed child process is spawned.
|
|
373
|
+
await workspaceOperationsSvc.assertRuntimeControlAvailable({
|
|
374
|
+
executionWorkspaceId: existing.id,
|
|
375
|
+
action,
|
|
376
|
+
});
|
|
217
377
|
const actor = getActorInfo(req);
|
|
218
378
|
const recorder = workspaceOperationsSvc.createRecorder({
|
|
219
379
|
companyId: existing.companyId,
|
|
@@ -268,7 +428,11 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
268
428
|
}
|
|
269
429
|
}
|
|
270
430
|
const recordRuntimeControlOperation = () => recorder.recordOperation({
|
|
271
|
-
phase: action === "stop"
|
|
431
|
+
phase: action === "stop"
|
|
432
|
+
? "workspace_teardown"
|
|
433
|
+
: action === "repair"
|
|
434
|
+
? "workspace_repair"
|
|
435
|
+
: "workspace_provision",
|
|
272
436
|
command: workspaceCommand?.command ?? `workspace command ${action}`,
|
|
273
437
|
cwd: existing.cwd,
|
|
274
438
|
metadata: {
|
|
@@ -280,7 +444,7 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
280
444
|
runtimeServiceId: selectedRuntimeServiceId,
|
|
281
445
|
serviceIndex: selectedServiceIndex,
|
|
282
446
|
},
|
|
283
|
-
run: async () => {
|
|
447
|
+
run: async (reportProgress) => {
|
|
284
448
|
const ensureWorkspaceAvailable = async () => await ensurePersistedExecutionWorkspaceAvailable({
|
|
285
449
|
base: {
|
|
286
450
|
baseCwd: projectWorkspace?.cwd ?? workspaceCwd,
|
|
@@ -367,7 +531,203 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
367
531
|
else
|
|
368
532
|
stderr = appendWithCap(stderr, chunk, WORKSPACE_CONTROL_OUTPUT_MAX_CHARS);
|
|
369
533
|
};
|
|
370
|
-
if (action === "
|
|
534
|
+
if (action === "repair") {
|
|
535
|
+
const repairDiagnostics = [];
|
|
536
|
+
let repairPhase = "managed_stop";
|
|
537
|
+
const repairPreconditionError = (status, reason, message) => {
|
|
538
|
+
const details = {
|
|
539
|
+
code: "workspace_repair_precondition_failed",
|
|
540
|
+
reason,
|
|
541
|
+
repairPhase,
|
|
542
|
+
};
|
|
543
|
+
return status === 409
|
|
544
|
+
? conflict(message, details)
|
|
545
|
+
: unprocessable(message, details);
|
|
546
|
+
};
|
|
547
|
+
const reportRepairPhase = async (phase, status) => {
|
|
548
|
+
repairPhase = phase;
|
|
549
|
+
repairDiagnostics.push({ phase, status, at: new Date().toISOString() });
|
|
550
|
+
if (repairDiagnostics.length > 32)
|
|
551
|
+
repairDiagnostics.splice(0, repairDiagnostics.length - 32);
|
|
552
|
+
await reportProgress({
|
|
553
|
+
metadata: {
|
|
554
|
+
repairPhase,
|
|
555
|
+
repairDiagnostics: [...repairDiagnostics],
|
|
556
|
+
databaseOnly: true,
|
|
557
|
+
worktreePreserved: true,
|
|
558
|
+
},
|
|
559
|
+
system: `Workspace repair ${phase}: ${status}.\n`,
|
|
560
|
+
});
|
|
561
|
+
};
|
|
562
|
+
try {
|
|
563
|
+
await reportRepairPhase("managed_stop", "started");
|
|
564
|
+
await stopRuntimeServicesForExecutionWorkspace({
|
|
565
|
+
db,
|
|
566
|
+
executionWorkspaceId: existing.id,
|
|
567
|
+
workspaceCwd,
|
|
568
|
+
});
|
|
569
|
+
await reportRepairPhase("managed_stop", "succeeded");
|
|
570
|
+
if (!repairSeedSource?.baseWorkspaceCwd || !repairCliArgs) {
|
|
571
|
+
throw new Error("Workspace repair source preflight did not complete.");
|
|
572
|
+
}
|
|
573
|
+
const manifestPath = path.join(workspaceCwd, ".paperclip", "seed-manifest.json");
|
|
574
|
+
const sourceConfigPath = repairSeedSource.configPath;
|
|
575
|
+
const baseWorkspaceCwd = repairSeedSource.baseWorkspaceCwd;
|
|
576
|
+
await reportRepairPhase("target_backup", "started");
|
|
577
|
+
const child = spawn(process.execPath, [
|
|
578
|
+
...repairCliArgs,
|
|
579
|
+
"worktree",
|
|
580
|
+
"reseed",
|
|
581
|
+
"--from-config",
|
|
582
|
+
sourceConfigPath,
|
|
583
|
+
"--to",
|
|
584
|
+
workspaceCwd,
|
|
585
|
+
"--seed-mode",
|
|
586
|
+
"full",
|
|
587
|
+
"--yes",
|
|
588
|
+
"--backup-target",
|
|
589
|
+
], {
|
|
590
|
+
cwd: baseWorkspaceCwd,
|
|
591
|
+
env: {
|
|
592
|
+
...process.env,
|
|
593
|
+
PAPERCLIP_SEED_EXPECTED_COMPANY_ID: existing.companyId,
|
|
594
|
+
PAPERCLIP_WORKSPACE_BASE_CWD: baseWorkspaceCwd,
|
|
595
|
+
PAPERCLIP_PROJECT_WORKSPACE_ID: existing.projectWorkspaceId ?? "",
|
|
596
|
+
},
|
|
597
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
598
|
+
});
|
|
599
|
+
child.stdout?.on("data", (chunk) => {
|
|
600
|
+
void onLog("stdout", chunk.toString("utf8"));
|
|
601
|
+
});
|
|
602
|
+
child.stderr?.on("data", (chunk) => {
|
|
603
|
+
void onLog("stderr", chunk.toString("utf8"));
|
|
604
|
+
});
|
|
605
|
+
let repairCommandTimedOut = false;
|
|
606
|
+
let repairCommandForceTimeout = null;
|
|
607
|
+
const repairCommandTimeout = setTimeout(() => {
|
|
608
|
+
repairCommandTimedOut = true;
|
|
609
|
+
child.kill("SIGTERM");
|
|
610
|
+
repairCommandForceTimeout = setTimeout(() => child.kill("SIGKILL"), 5_000);
|
|
611
|
+
repairCommandForceTimeout.unref?.();
|
|
612
|
+
}, 20 * 60_000);
|
|
613
|
+
repairCommandTimeout.unref?.();
|
|
614
|
+
let reseedObserved = false;
|
|
615
|
+
const manifestPoll = setInterval(() => {
|
|
616
|
+
if (reseedObserved || !existsSync(manifestPath))
|
|
617
|
+
return;
|
|
618
|
+
try {
|
|
619
|
+
const current = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
620
|
+
if (typeof current.attemptId === "string"
|
|
621
|
+
&& current.attemptId !== repairPreviousAttemptId
|
|
622
|
+
&& (current.state === "pending" || current.state === "running" || current.state === "failed")) {
|
|
623
|
+
reseedObserved = true;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
catch {
|
|
627
|
+
// The atomic manifest writer makes this unlikely; the terminal
|
|
628
|
+
// read below remains authoritative.
|
|
629
|
+
}
|
|
630
|
+
}, 100);
|
|
631
|
+
manifestPoll.unref?.();
|
|
632
|
+
const exitCode = await new Promise((resolve, reject) => {
|
|
633
|
+
child.once("error", reject);
|
|
634
|
+
child.once("exit", (code) => resolve(code ?? 1));
|
|
635
|
+
}).finally(() => {
|
|
636
|
+
clearInterval(manifestPoll);
|
|
637
|
+
clearTimeout(repairCommandTimeout);
|
|
638
|
+
if (repairCommandForceTimeout)
|
|
639
|
+
clearTimeout(repairCommandForceTimeout);
|
|
640
|
+
});
|
|
641
|
+
if (reseedObserved) {
|
|
642
|
+
await reportRepairPhase("target_backup", "succeeded");
|
|
643
|
+
await reportRepairPhase("full_reseed", "started");
|
|
644
|
+
}
|
|
645
|
+
if (exitCode !== 0) {
|
|
646
|
+
let seedFailurePhase = null;
|
|
647
|
+
try {
|
|
648
|
+
const failedManifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
649
|
+
seedFailurePhase = failedManifest.state === "failed" && typeof failedManifest.phase === "string"
|
|
650
|
+
? failedManifest.phase
|
|
651
|
+
: null;
|
|
652
|
+
}
|
|
653
|
+
catch {
|
|
654
|
+
// The outer repair phase remains exact when no seed phase was persisted.
|
|
655
|
+
}
|
|
656
|
+
await reportProgress({
|
|
657
|
+
metadata: { seedFailurePhase },
|
|
658
|
+
system: seedFailurePhase ? `Workspace seed failed during ${seedFailurePhase}.\n` : null,
|
|
659
|
+
});
|
|
660
|
+
throw new Error(repairCommandTimedOut
|
|
661
|
+
? `Workspace database repair command timed out during ${repairPhase}.`
|
|
662
|
+
: `Workspace database repair command failed during ${repairPhase}.`);
|
|
663
|
+
}
|
|
664
|
+
if (!reseedObserved) {
|
|
665
|
+
await reportRepairPhase("target_backup", "succeeded");
|
|
666
|
+
await reportRepairPhase("full_reseed", "started");
|
|
667
|
+
}
|
|
668
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
669
|
+
if (!isVerifiedWorktreeSeedManifest(manifest)) {
|
|
670
|
+
throw new Error("Workspace reseed returned without a verified terminal manifest.");
|
|
671
|
+
}
|
|
672
|
+
const expectedInstanceId = resolveManagedWorkspaceInstanceId(workspaceCwd);
|
|
673
|
+
if (manifest.targetInstanceId !== expectedInstanceId) {
|
|
674
|
+
throw repairPreconditionError(422, "seed_manifest_instance_mismatch", "Verified seed manifest belongs to a different workspace instance.");
|
|
675
|
+
}
|
|
676
|
+
resolveCanonicalWorktreeSeedSource({
|
|
677
|
+
registeredBaseWorkspaceCwd: baseWorkspaceCwd,
|
|
678
|
+
explicitSourceConfigPath: resolveFallbackSeedSourceConfigPath(baseWorkspaceCwd),
|
|
679
|
+
targetConfigPath: path.join(workspaceCwd, ".paperclip", "config.json"),
|
|
680
|
+
expectedTargetInstanceId: repairSeedSource.targetInstanceId,
|
|
681
|
+
manifestSource: manifest.source,
|
|
682
|
+
manifestTargetInstanceId: manifest.targetInstanceId,
|
|
683
|
+
});
|
|
684
|
+
await reportRepairPhase("full_reseed", "succeeded");
|
|
685
|
+
await reportRepairPhase("managed_restart", "started");
|
|
686
|
+
let startedServices = [];
|
|
687
|
+
if (repairRestartsRuntimeServices) {
|
|
688
|
+
const availableWorkspace = await ensureWorkspaceAvailable();
|
|
689
|
+
if (!availableWorkspace) {
|
|
690
|
+
throw new Error("Execution workspace needs a local path before Paperclip can restart it.");
|
|
691
|
+
}
|
|
692
|
+
startedServices = await startRuntimeServicesForWorkspaceControl({
|
|
693
|
+
db,
|
|
694
|
+
actor: {
|
|
695
|
+
id: actor.agentId ?? null,
|
|
696
|
+
name: actor.actorType === "user" ? "Board" : "Agent",
|
|
697
|
+
companyId: existing.companyId,
|
|
698
|
+
},
|
|
699
|
+
issue: existing.sourceIssueId
|
|
700
|
+
? { id: existing.sourceIssueId, identifier: null, title: existing.name }
|
|
701
|
+
: null,
|
|
702
|
+
workspace: availableWorkspace,
|
|
703
|
+
executionWorkspaceId: existing.id,
|
|
704
|
+
config: {
|
|
705
|
+
workspaceRuntime: effectiveRuntimeConfig,
|
|
706
|
+
runtimeProvisionCommand: existing.config?.runtimeProvisionCommand
|
|
707
|
+
?? projectPolicy?.workspaceStrategy?.runtimeProvisionCommand
|
|
708
|
+
?? null,
|
|
709
|
+
},
|
|
710
|
+
adapterEnv: {},
|
|
711
|
+
onLog,
|
|
712
|
+
recorder,
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
runtimeServiceCount = startedServices.length;
|
|
716
|
+
await reportRepairPhase("managed_restart", "succeeded");
|
|
717
|
+
await reportRepairPhase("readiness_validation", "started");
|
|
718
|
+
if (repairRestartsRuntimeServices
|
|
719
|
+
&& (startedServices.length === 0
|
|
720
|
+
|| startedServices.some((service) => service.status !== "running" || service.healthStatus !== "healthy"))) {
|
|
721
|
+
throw new Error("Managed restart did not produce healthy runtime services.");
|
|
722
|
+
}
|
|
723
|
+
await reportRepairPhase("readiness_validation", "succeeded");
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
await reportRepairPhase(repairPhase, "failed");
|
|
727
|
+
throw error;
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
else if (action === "stop" || action === "restart") {
|
|
371
731
|
await stopRuntimeServicesForExecutionWorkspace({
|
|
372
732
|
db,
|
|
373
733
|
executionWorkspaceId: existing.id,
|
|
@@ -419,7 +779,7 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
419
779
|
}
|
|
420
780
|
runtimeServiceCount = startedServices.length;
|
|
421
781
|
}
|
|
422
|
-
else {
|
|
782
|
+
else if (action !== "repair") {
|
|
423
783
|
runtimeServiceCount = selectedRuntimeServiceId ? Math.max(0, (existing.runtimeServices?.length ?? 1) - 1) : 0;
|
|
424
784
|
}
|
|
425
785
|
const currentDesiredState = existing.config?.desiredState
|
|
@@ -435,7 +795,9 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
435
795
|
config: { workspaceRuntime: effectiveRuntimeConfig },
|
|
436
796
|
currentDesiredState,
|
|
437
797
|
currentServiceStates: existing.config?.serviceStates ?? null,
|
|
438
|
-
action
|
|
798
|
+
action: action === "repair"
|
|
799
|
+
? repairRestartsRuntimeServices ? "start" : "stop"
|
|
800
|
+
: action,
|
|
439
801
|
serviceIndex: selectedServiceIndex,
|
|
440
802
|
});
|
|
441
803
|
const metadata = mergeExecutionWorkspaceConfig(existing.metadata, {
|
|
@@ -451,12 +813,17 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
451
813
|
? "Stopped execution workspace runtime services.\n"
|
|
452
814
|
: action === "restart"
|
|
453
815
|
? "Restarted execution workspace runtime services.\n"
|
|
454
|
-
:
|
|
816
|
+
: action === "repair"
|
|
817
|
+
? repairRestartsRuntimeServices
|
|
818
|
+
? "Repaired the isolated workspace database and restarted healthy runtime services.\n"
|
|
819
|
+
: "Repaired the isolated workspace database; no managed runtime services were configured to restart.\n"
|
|
820
|
+
: "Started execution workspace runtime services.\n",
|
|
455
821
|
metadata: {
|
|
456
822
|
runtimeServiceCount,
|
|
457
823
|
workspaceCommandId: workspaceCommand?.id ?? target.workspaceCommandId ?? null,
|
|
458
824
|
runtimeServiceId: selectedRuntimeServiceId,
|
|
459
825
|
serviceIndex: selectedServiceIndex,
|
|
826
|
+
runtimeRestarted: action === "repair" ? repairRestartsRuntimeServices : undefined,
|
|
460
827
|
},
|
|
461
828
|
};
|
|
462
829
|
},
|
|
@@ -494,8 +861,9 @@ export function executionWorkspaceRoutes(db, opts = {}) {
|
|
|
494
861
|
// The operation is already terminal here. This also catches the recorder's own time
|
|
495
862
|
// budget expiring on a start that never settles, which is the one failure the inner
|
|
496
863
|
// handler cannot see — reconcile there too so no listener or desired state is left over.
|
|
497
|
-
if (action === "start" || action === "restart")
|
|
864
|
+
if (action === "start" || action === "restart" || action === "repair") {
|
|
498
865
|
await reconcileFailedRuntimeStart(error);
|
|
866
|
+
}
|
|
499
867
|
throw error;
|
|
500
868
|
}
|
|
501
869
|
},
|