@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
package/dist/routes/issues.js
CHANGED
|
@@ -4,13 +4,15 @@ import multer from "multer";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { and, asc, desc, eq, inArray, isNull, notInArray } from "drizzle-orm";
|
|
6
6
|
import { activityLog, agents, approvals, companyMemberships, documents, executionWorkspaces, heartbeatRuns, issueApprovals, issueComments, issueDocuments, issueExecutionDecisions, issueRelations, issueThreadInteractions, issues as issueRows, issueWorkProducts, pipelineCaseIssueLinks, pipelineCases, pipelineStages, pipelines, projectWorkspaces, } from "@paperclipai/db";
|
|
7
|
-
import { addIssueCommentSchema, acceptIssueThreadInteractionSchema, attachmentArtifactWorkProductMetadataSchema, cancelIssueThreadInteractionSchema, withdrawIssueThreadInteractionSchema, companySearchExtractQuerySchema, companySearchQuerySchema, createIssueAttachmentMetadataSchema, createIssueThreadInteractionSchema, createIssueWorkProductSchema, createIssueLabelSchema, createAcceptedPlanDecompositionSchema, checkoutIssueSchema, createDocumentAnnotationCommentSchema, createDocumentAnnotationThreadSchema, createChildIssueSchema, createIssueSchema, resolveCreateIssueStatusDefault, resolveIssueRecoveryActionSchema, feedbackTargetTypeSchema, feedbackTraceStatusSchema, feedbackVoteValueSchema, upsertIssueFeedbackVoteSchema, upsertIssueWatchdogSchema, linkIssueApprovalSchema, issueDocumentKeySchema, ISSUE_CONTINUATION_SUMMARY_DOCUMENT_KEY, ISSUE_WATCHDOG_DISCOVERY_KINDS, TASK_WATCHDOG_PRODUCT_BUG_ORIGIN_KIND, ONBOARDING_FIRST_TASK_ORIGIN_KIND, rejectIssueThreadInteractionSchema, restoreIssueDocumentRevisionSchema, respondIssueThreadInteractionSchema, stalledReviewDecisionSchema, submitIssueThreadInteractionVerdictsSchema, updateIssueWorkProductSchema, updateDocumentAnnotationThreadSchema, upsertIssueDocumentSchema, updateIssueSchema, isClosedIsolatedExecutionWorkspace, isUuidLike, normalizeIssueIdentifier as normalizeIssueReferenceIdentifier, issueWriteDenialCodeForResponsibleUserDenial, issueWriteDenialResponse, } from "@paperclipai/shared";
|
|
7
|
+
import { addIssueCommentSchema, acceptIssueThreadInteractionSchema, attachmentArtifactWorkProductMetadataSchema, cancelIssueThreadInteractionSchema, withdrawIssueThreadInteractionSchema, companySearchExtractQuerySchema, companySearchQuerySchema, createIssueAttachmentMetadataSchema, createIssueThreadInteractionSchema, createIssueWorkProductSchema, createIssueLabelSchema, createAcceptedPlanDecompositionSchema, checkoutIssueSchema, createDocumentAnnotationCommentSchema, createDocumentAnnotationThreadSchema, createChildIssueSchema, createIssueSchema, resolveCreateIssueStatusDefault, resolveIssueRecoveryActionSchema, feedbackTargetTypeSchema, feedbackTraceStatusSchema, feedbackVoteValueSchema, upsertIssueFeedbackVoteSchema, upsertIssueWatchdogSchema, linkIssueApprovalSchema, issueDocumentKeySchema, ISSUE_CONTINUATION_SUMMARY_DOCUMENT_KEY, ISSUE_WATCHDOG_DISCOVERY_KINDS, TASK_WATCHDOG_PRODUCT_BUG_ORIGIN_KIND, ONBOARDING_FIRST_TASK_ORIGIN_KIND, rejectIssueThreadInteractionSchema, restoreIssueDocumentRevisionSchema, respondIssueThreadInteractionSchema, stalledReviewDecisionSchema, submitIssueThreadInteractionVerdictsSchema, updateIssueWorkProductSchema, updateDocumentAnnotationThreadSchema, upsertIssueDocumentSchema, updateIssueSchema, isClosedIsolatedExecutionWorkspace, isMarkdownArtifactWorkProduct, isMarkdownAttachmentContent, isUuidLike, normalizeIssueIdentifier as normalizeIssueReferenceIdentifier, issueWriteDenialCodeForResponsibleUserDenial, issueWriteDenialResponse, } from "@paperclipai/shared";
|
|
8
8
|
import { trackAgentTaskCompleted } from "@paperclipai/shared/telemetry";
|
|
9
9
|
import { getTelemetryClient } from "../telemetry.js";
|
|
10
10
|
import { isUniqueViolation } from "../db-errors.js";
|
|
11
|
-
import { validate } from "../middleware/validate.js";
|
|
11
|
+
import { validate, validateIssueMutationBody } from "../middleware/validate.js";
|
|
12
12
|
import * as serviceIndex from "../services/index.js";
|
|
13
|
-
import { accessService, agentService, companySkillService, companyService, companySearchService, goalService, heartbeatService, issueApprovalService, issueRecoveryActionService, issueThreadInteractionService, ISSUE_LIST_DEFAULT_LIMIT, ISSUE_LIST_MAX_LIMIT, issueReferenceService, issueService, clampIssueListLimit, documentService, documentAnnotationService, logActivity, publishActivity, projectService, routineService, workProductService, } from "../services/index.js";
|
|
13
|
+
import { accessService, agentService, budgetService, companySkillService, companyService, companySearchService, goalService, heartbeatService, issueApprovalService, issueRecoveryActionService, issueThreadInteractionService, ISSUE_LIST_DEFAULT_LIMIT, ISSUE_LIST_MAX_LIMIT, issueReferenceService, issueService, clampIssueListLimit, documentService, documentAnnotationService, logActivity, publishActivity, projectService, routineService, workProductService, } from "../services/index.js";
|
|
14
|
+
import { artifactReviewDocumentService } from "../services/artifact-review-documents.js";
|
|
15
|
+
import { assertCanResolveProposal } from "../services/secret-proposal-authorization.js";
|
|
14
16
|
import { buildDocumentReviewContext, buildPlanReviewContext } from "../services/plan-review-context.js";
|
|
15
17
|
import { decideIssueReviewPathRecovery, ISSUE_REVIEW_PATH_LOST_WAKE_REASON, isReviewPathRecoveryIdempotencyConflict, REVIEW_PATH_RECOVERY_INSTRUCTION, } from "../services/recovery/review-path-recovery.js";
|
|
16
18
|
import { hydrateSuccessfulRunHandoffLiveness } from "../services/successful-run-handoff-state.js";
|
|
@@ -24,8 +26,10 @@ import { assertNoAgentHostWorkspaceCommandMutation, collectIssueWorkspaceCommand
|
|
|
24
26
|
import { shouldWakeAssigneeOnCheckout } from "./issues-checkout-wakeup.js";
|
|
25
27
|
import { GENERIC_ATTACHMENT_CONTENT_TYPES, isInlineAttachmentContentType, normalizeIssueAttachmentMaxBytes, normalizeContentType, normalizeUploadAttachmentContentType, SVG_CONTENT_TYPE, } from "../attachment-types.js";
|
|
26
28
|
import { queueIssueAssignmentWakeup } from "../services/issue-assignment-wakeup.js";
|
|
29
|
+
import { createSecretProposalsService } from "../services/secret-proposals.js";
|
|
30
|
+
import { notifySecretProposalResolution } from "../services/secret-proposal-notifications.js";
|
|
27
31
|
import { buildOnboardingGreeting, ONBOARDING_GREETING_AUTHORIZATION_REASON, } from "../services/onboarding-greeting.js";
|
|
28
|
-
import { ISSUE_BLOCKERS_RESOLVED_WAKE_REASON,
|
|
32
|
+
import { ISSUE_BLOCKERS_RESOLVED_WAKE_REASON, buildIssueBlockersResolvedWakeStateKey, findExistingIssueBlockersResolvedWakeForReadyState, } from "../services/issue-dependency-wakeups.js";
|
|
29
33
|
import { assertEnvironmentSelectionForCompany } from "./environment-selection.js";
|
|
30
34
|
import { executionWorkspaceService as executionWorkspaceServiceDirect, STALE_REOPEN_PENDING_CONSUMPTION_GRACE_MS, } from "../services/execution-workspaces.js";
|
|
31
35
|
import { decisionTrainingService } from "../services/decision-training.js";
|
|
@@ -59,17 +63,17 @@ function prefersMinimalIssueUpdateResponse(req) {
|
|
|
59
63
|
.some((preference) => preference.trim().toLowerCase() === "return=minimal");
|
|
60
64
|
}
|
|
61
65
|
const refreshExternalObjectsSchema = z.object({
|
|
62
|
-
objectIds: z.array(z.string().
|
|
66
|
+
objectIds: z.array(z.string().guid()).max(50).optional(),
|
|
63
67
|
}).strict();
|
|
64
68
|
const inboxArchiveBodySchema = z.object({
|
|
65
69
|
userId: z.string().trim().min(1).optional(),
|
|
66
70
|
}).strict().default({});
|
|
67
71
|
const externalObjectSummariesSchema = z.object({
|
|
68
|
-
issueIds: z.array(z.string().
|
|
72
|
+
issueIds: z.array(z.string().guid()).max(1000),
|
|
69
73
|
}).strict();
|
|
70
74
|
const promoteLowTrustOutputSchema = z.object({
|
|
71
75
|
sourceArtifactKind: z.enum(["comment", "document", "work_product", "issue"]),
|
|
72
|
-
sourceArtifactId: z.string().
|
|
76
|
+
sourceArtifactId: z.string().guid(),
|
|
73
77
|
title: z.string().trim().min(1).max(200),
|
|
74
78
|
summary: z.string().trim().min(1).max(8_000),
|
|
75
79
|
});
|
|
@@ -189,7 +193,7 @@ function requiresPaperclipAttachmentMetadata(input, fallback) {
|
|
|
189
193
|
return type === "artifact" && provider === "paperclip";
|
|
190
194
|
}
|
|
191
195
|
const attachmentArtifactMetadataInputSchema = z.object({
|
|
192
|
-
attachmentId: z.string().
|
|
196
|
+
attachmentId: z.string().guid(),
|
|
193
197
|
}).passthrough();
|
|
194
198
|
function buildCreateIssueActivityStatusDetails(issue, res) {
|
|
195
199
|
const statusDefault = res.locals.createIssueStatusDefault;
|
|
@@ -1211,6 +1215,13 @@ function readToolActionExecutionStatus(value) {
|
|
|
1211
1215
|
? value
|
|
1212
1216
|
: null;
|
|
1213
1217
|
}
|
|
1218
|
+
function secretProposalExecutionErrorCode(error) {
|
|
1219
|
+
if (error instanceof HttpError) {
|
|
1220
|
+
const details = readObject(error.details);
|
|
1221
|
+
return readNonEmptyString(details.code) ?? `http_${error.status}`;
|
|
1222
|
+
}
|
|
1223
|
+
return "secret_proposal_execution_failed";
|
|
1224
|
+
}
|
|
1214
1225
|
function readToolActionContinuationContext(interaction) {
|
|
1215
1226
|
const payload = readObject(interaction.payload);
|
|
1216
1227
|
const toolActionPayload = readObject(payload.toolAction);
|
|
@@ -1269,6 +1280,49 @@ function readToolActionContinuationContext(interaction) {
|
|
|
1269
1280
|
instructions: `the approved ${toolName} action is ${executionStatus}; do not call the tool again while this approval is being processed.`,
|
|
1270
1281
|
};
|
|
1271
1282
|
}
|
|
1283
|
+
function readSecretProposalContinuationContext(interaction) {
|
|
1284
|
+
const payload = readObject(interaction.payload);
|
|
1285
|
+
const proposal = readObject(payload.secretProposal);
|
|
1286
|
+
const proposalId = readNonEmptyString(proposal.proposalId);
|
|
1287
|
+
const configPath = readNonEmptyString(proposal.configPath);
|
|
1288
|
+
if (!proposalId || !configPath)
|
|
1289
|
+
return null;
|
|
1290
|
+
const result = readObject(interaction.result);
|
|
1291
|
+
const execution = readObject(result.secretProposal);
|
|
1292
|
+
const executionStatus = readNonEmptyString(execution.status);
|
|
1293
|
+
const errorCode = readNonEmptyString(execution.errorCode);
|
|
1294
|
+
const sourceSecretLabel = readNonEmptyString(proposal.sourceSecretLabel);
|
|
1295
|
+
if (interaction.status === "rejected") {
|
|
1296
|
+
return {
|
|
1297
|
+
proposalId,
|
|
1298
|
+
configPath,
|
|
1299
|
+
decision: "rejected",
|
|
1300
|
+
executionStatus: "rejected",
|
|
1301
|
+
instructions: "the secret binding proposal was rejected; do not assume the alias exists.",
|
|
1302
|
+
};
|
|
1303
|
+
}
|
|
1304
|
+
if (interaction.status !== "accepted" || (executionStatus !== "executed" && executionStatus !== "failed")) {
|
|
1305
|
+
return null;
|
|
1306
|
+
}
|
|
1307
|
+
if (executionStatus === "executed") {
|
|
1308
|
+
return {
|
|
1309
|
+
proposalId,
|
|
1310
|
+
configPath,
|
|
1311
|
+
decision: "accepted",
|
|
1312
|
+
executionStatus,
|
|
1313
|
+
...(sourceSecretLabel ? { sourceSecretLabel } : {}),
|
|
1314
|
+
instructions: `the binding was created at ${configPath}; verify it with GET /api/agents/me/secrets before using it.`,
|
|
1315
|
+
};
|
|
1316
|
+
}
|
|
1317
|
+
return {
|
|
1318
|
+
proposalId,
|
|
1319
|
+
configPath,
|
|
1320
|
+
decision: "accepted",
|
|
1321
|
+
executionStatus,
|
|
1322
|
+
...(errorCode ? { errorCode } : {}),
|
|
1323
|
+
instructions: "the binding was not created; inspect the failure comment and submit a fresh proposal after fixing the cause.",
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1272
1326
|
const REQUEST_ITEM_VERDICTS_WAKE_COALESCE_WINDOW_MS = 2_000;
|
|
1273
1327
|
function buildRequestItemVerdictsWakeIdempotencyKey(args) {
|
|
1274
1328
|
const now = args.at ?? new Date();
|
|
@@ -1306,6 +1360,7 @@ async function queueResolvedInteractionContinuationWakeup(input) {
|
|
|
1306
1360
|
const interactionResult = readConfirmationResultForWake(input.interaction.result);
|
|
1307
1361
|
const checkboxSelection = readCheckboxSelectionForWake(input.interaction);
|
|
1308
1362
|
const toolAction = readToolActionContinuationContext(input.interaction);
|
|
1363
|
+
const secretProposal = readSecretProposalContinuationContext(input.interaction);
|
|
1309
1364
|
const newlyResolvedItemIds = input.newlyResolvedItemIds?.filter((value) => value.length > 0) ?? [];
|
|
1310
1365
|
const itemVerdicts = newlyResolvedItemIds.length > 0
|
|
1311
1366
|
? {
|
|
@@ -1337,6 +1392,7 @@ async function queueResolvedInteractionContinuationWakeup(input) {
|
|
|
1337
1392
|
...(planReviewInteraction ? { planReviewInteraction } : {}),
|
|
1338
1393
|
...(checkboxSelection ? { checkboxSelection } : {}),
|
|
1339
1394
|
...(toolAction ? { toolAction } : {}),
|
|
1395
|
+
...(secretProposal ? { secretProposal } : {}),
|
|
1340
1396
|
...(itemVerdicts ? { itemVerdicts, newlyResolvedItemIds } : {}),
|
|
1341
1397
|
...(reviewPathContext ?? {}),
|
|
1342
1398
|
mutation: "interaction",
|
|
@@ -1355,6 +1411,7 @@ async function queueResolvedInteractionContinuationWakeup(input) {
|
|
|
1355
1411
|
...(planReviewInteraction ? { planReviewInteraction } : {}),
|
|
1356
1412
|
...(checkboxSelection ? { checkboxSelection } : {}),
|
|
1357
1413
|
...(toolAction ? { toolAction } : {}),
|
|
1414
|
+
...(secretProposal ? { secretProposal } : {}),
|
|
1358
1415
|
...(itemVerdicts ? { itemVerdicts, newlyResolvedItemIds } : {}),
|
|
1359
1416
|
...(reviewPathContext ?? {}),
|
|
1360
1417
|
wakeReason: "issue_commented",
|
|
@@ -1835,6 +1892,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
1835
1892
|
const svc = issueService(db);
|
|
1836
1893
|
const runRedactions = createRunSecretRedactionRegistry(db);
|
|
1837
1894
|
const access = accessService(db);
|
|
1895
|
+
const secretProposals = createSecretProposalsService(db);
|
|
1838
1896
|
const heartbeat = heartbeatService(db, {
|
|
1839
1897
|
pluginWorkerManager: opts.pluginWorkerManager,
|
|
1840
1898
|
});
|
|
@@ -1857,6 +1915,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
1857
1915
|
const executionWorkspacesSvc = executionWorkspaceServiceDirect(db);
|
|
1858
1916
|
const workProductsSvc = workProductService(db);
|
|
1859
1917
|
const documentsSvc = documentService(db);
|
|
1918
|
+
const artifactReviewDocumentsSvc = artifactReviewDocumentService(db, storage);
|
|
1860
1919
|
const companySkillsSvc = companySkillService(db);
|
|
1861
1920
|
const documentAnnotationsSvc = documentAnnotationService(db);
|
|
1862
1921
|
const decisionTrainingSvc = decisionTrainingService(db);
|
|
@@ -2408,8 +2467,8 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
2408
2467
|
&& !(interaction.kind === "request_confirmation"
|
|
2409
2468
|
&& interaction.payload
|
|
2410
2469
|
&& typeof interaction.payload === "object"
|
|
2411
|
-
&& "toolAction" in interaction.payload
|
|
2412
|
-
|
|
2470
|
+
&& (("toolAction" in interaction.payload && interaction.payload.toolAction !== undefined)
|
|
2471
|
+
|| ("secretProposal" in interaction.payload && interaction.payload.secretProposal !== undefined))));
|
|
2413
2472
|
if (!designatedReviewConfirmation) {
|
|
2414
2473
|
const creatorDescription = input.actorType === "agent"
|
|
2415
2474
|
? "this agent run"
|
|
@@ -3066,7 +3125,8 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
3066
3125
|
: { type: "user", userId: actor.actorId },
|
|
3067
3126
|
interaction,
|
|
3068
3127
|
additionalRestriction: resolverPolicyRestriction,
|
|
3069
|
-
governedAction: interaction.kind === "request_confirmation"
|
|
3128
|
+
governedAction: interaction.kind === "request_confirmation"
|
|
3129
|
+
&& (payload?.toolAction !== undefined || payload?.secretProposal !== undefined),
|
|
3070
3130
|
});
|
|
3071
3131
|
if (!decision.allowed) {
|
|
3072
3132
|
return denyIssueThreadInteractionResolution(res, {
|
|
@@ -3688,15 +3748,14 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
3688
3748
|
});
|
|
3689
3749
|
return false;
|
|
3690
3750
|
}
|
|
3691
|
-
async function
|
|
3751
|
+
async function requireRecoveryActionAuthority(req, issue, activeRecoveryAction, input) {
|
|
3692
3752
|
if (req.actor.type !== "agent")
|
|
3693
3753
|
return true;
|
|
3694
3754
|
if (!activeRecoveryAction)
|
|
3695
3755
|
return true;
|
|
3696
3756
|
const actorAgentId = req.actor.agentId;
|
|
3697
3757
|
if (!actorAgentId) {
|
|
3698
|
-
|
|
3699
|
-
return false;
|
|
3758
|
+
throw forbidden("Agent authentication required");
|
|
3700
3759
|
}
|
|
3701
3760
|
if (issue.assigneeAgentId === actorAgentId)
|
|
3702
3761
|
return true;
|
|
@@ -3710,19 +3769,123 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
3710
3769
|
await hasActiveCheckoutManagementOverride(actorAgentId, issue.companyId, activeRecoveryAction.ownerAgentId)) {
|
|
3711
3770
|
return true;
|
|
3712
3771
|
}
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3772
|
+
throw forbidden("Agent cannot resolve another owner's recovery action", {
|
|
3773
|
+
issueId: issue.id,
|
|
3774
|
+
recoveryActionId: activeRecoveryAction.id,
|
|
3775
|
+
actorAgentId,
|
|
3776
|
+
assigneeAgentId: issue.assigneeAgentId,
|
|
3777
|
+
recoveryOwnerAgentId: activeRecoveryAction.ownerAgentId,
|
|
3778
|
+
source: input.source,
|
|
3779
|
+
securityPrinciples: ["Least Privilege", "Complete Mediation", "Secure Defaults"],
|
|
3780
|
+
});
|
|
3781
|
+
}
|
|
3782
|
+
function activeExecutionParticipantAgentId(issue) {
|
|
3783
|
+
const state = parseIssueExecutionState(issue.executionState);
|
|
3784
|
+
return state?.status === "pending" && state.currentParticipant?.type === "agent"
|
|
3785
|
+
? state.currentParticipant.agentId
|
|
3786
|
+
: null;
|
|
3787
|
+
}
|
|
3788
|
+
async function requireRecoverySourceMutationAuthority(req, issue) {
|
|
3789
|
+
if (req.actor.type !== "agent")
|
|
3790
|
+
return;
|
|
3791
|
+
const actorAgentId = req.actor.agentId;
|
|
3792
|
+
if (!actorAgentId)
|
|
3793
|
+
throw forbidden("Agent authentication required");
|
|
3794
|
+
const isSourceOwner = issue.assigneeAgentId === actorAgentId;
|
|
3795
|
+
const isExecutionParticipant = activeExecutionParticipantAgentId(issue) === actorAgentId;
|
|
3796
|
+
const hasPolicyGrant = Boolean(issue.assigneeAgentId &&
|
|
3797
|
+
await hasActiveCheckoutManagementOverride(actorAgentId, issue.companyId, issue.assigneeAgentId));
|
|
3798
|
+
if (!isSourceOwner && !isExecutionParticipant && !hasPolicyGrant) {
|
|
3799
|
+
throw forbidden("Recovery ownership does not authorize this source issue mutation", {
|
|
3800
|
+
code: "recovery_source_authority_required",
|
|
3716
3801
|
issueId: issue.id,
|
|
3717
|
-
recoveryActionId: activeRecoveryAction.id,
|
|
3718
3802
|
actorAgentId,
|
|
3719
3803
|
assigneeAgentId: issue.assigneeAgentId,
|
|
3720
|
-
|
|
3721
|
-
|
|
3804
|
+
currentExecutionParticipantAgentId: activeExecutionParticipantAgentId(issue),
|
|
3805
|
+
remediation: "Have the source owner, current execution participant, board, or a policy-authorized agent perform the source mutation.",
|
|
3722
3806
|
securityPrinciples: ["Least Privilege", "Complete Mediation", "Secure Defaults"],
|
|
3723
|
-
}
|
|
3724
|
-
}
|
|
3725
|
-
|
|
3807
|
+
});
|
|
3808
|
+
}
|
|
3809
|
+
const actorRunId = req.actor.runId?.trim() || null;
|
|
3810
|
+
const conflictingRunId = [issue.checkoutRunId, issue.executionRunId]
|
|
3811
|
+
.find((runId) => runId && runId !== actorRunId);
|
|
3812
|
+
if (conflictingRunId && !hasPolicyGrant) {
|
|
3813
|
+
throw conflict("Source issue mutation is locked by another active checkout or run", {
|
|
3814
|
+
code: "recovery_source_run_lock",
|
|
3815
|
+
issueId: issue.id,
|
|
3816
|
+
actorAgentId,
|
|
3817
|
+
actorRunId,
|
|
3818
|
+
checkoutRunId: issue.checkoutRunId ?? null,
|
|
3819
|
+
executionRunId: issue.executionRunId ?? null,
|
|
3820
|
+
});
|
|
3821
|
+
}
|
|
3822
|
+
if (isSourceOwner && issue.status === "in_progress" && !actorRunId && !hasPolicyGrant) {
|
|
3823
|
+
throw unauthorized("Agent run id required");
|
|
3824
|
+
}
|
|
3825
|
+
}
|
|
3826
|
+
async function assertSafeRecoveryHandBackGates(input) {
|
|
3827
|
+
const returnOwnerAgentId = input.recoveryAction.returnOwnerAgentId;
|
|
3828
|
+
if (!returnOwnerAgentId || input.issue.assigneeAgentId !== returnOwnerAgentId) {
|
|
3829
|
+
throw forbidden("Safe recovery hand-back requires the recorded original owner to remain assigned", {
|
|
3830
|
+
code: "recovery_safe_hand_back_owner_mismatch",
|
|
3831
|
+
issueId: input.issue.id,
|
|
3832
|
+
assigneeAgentId: input.issue.assigneeAgentId,
|
|
3833
|
+
returnOwnerAgentId,
|
|
3834
|
+
});
|
|
3835
|
+
}
|
|
3836
|
+
const actorRunId = input.req.actor.type === "agent"
|
|
3837
|
+
? input.req.actor.runId?.trim() || null
|
|
3838
|
+
: null;
|
|
3839
|
+
const conflictingRunId = [input.issue.checkoutRunId, input.issue.executionRunId]
|
|
3840
|
+
.find((runId) => runId && runId !== actorRunId);
|
|
3841
|
+
if (conflictingRunId) {
|
|
3842
|
+
throw conflict("Safe recovery hand-back is locked by another active checkout or run", {
|
|
3843
|
+
code: "recovery_source_run_lock",
|
|
3844
|
+
issueId: input.issue.id,
|
|
3845
|
+
actorRunId,
|
|
3846
|
+
checkoutRunId: input.issue.checkoutRunId ?? null,
|
|
3847
|
+
executionRunId: input.issue.executionRunId ?? null,
|
|
3848
|
+
});
|
|
3849
|
+
}
|
|
3850
|
+
if (parseIssueExecutionState(input.issue.executionState)?.status === "pending") {
|
|
3851
|
+
throw conflict("Safe recovery hand-back cannot bypass a pending execution review or approval stage", {
|
|
3852
|
+
code: "recovery_governed_stage_pending",
|
|
3853
|
+
issueId: input.issue.id,
|
|
3854
|
+
});
|
|
3855
|
+
}
|
|
3856
|
+
const activePauseHold = await treeControlSvc.getActivePauseHoldGate(input.issue.companyId, input.issue.id);
|
|
3857
|
+
if (activePauseHold) {
|
|
3858
|
+
throw conflict("Safe recovery hand-back blocked by active subtree pause hold", {
|
|
3859
|
+
issueId: input.issue.id,
|
|
3860
|
+
holdId: activePauseHold.holdId,
|
|
3861
|
+
rootIssueId: activePauseHold.rootIssueId,
|
|
3862
|
+
mode: activePauseHold.mode,
|
|
3863
|
+
});
|
|
3864
|
+
}
|
|
3865
|
+
if (input.issue.projectId) {
|
|
3866
|
+
const project = await projectsSvc.getById(input.issue.projectId);
|
|
3867
|
+
if (project?.pausedAt) {
|
|
3868
|
+
throw conflict(project.pauseReason === "budget"
|
|
3869
|
+
? "Project is paused because its budget hard-stop was reached"
|
|
3870
|
+
: "Project is paused");
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
const approvals = await issueApprovalsSvc.listApprovalsForIssue(input.issue.id);
|
|
3874
|
+
if (approvals.some((approval) => ACTIVE_REVIEW_APPROVAL_STATUSES.has(String(approval.status)))) {
|
|
3875
|
+
throw conflict("Safe recovery hand-back cannot bypass a pending governed approval", {
|
|
3876
|
+
code: "recovery_governed_approval_pending",
|
|
3877
|
+
issueId: input.issue.id,
|
|
3878
|
+
});
|
|
3879
|
+
}
|
|
3880
|
+
const budgetBlock = await budgetService(db).getInvocationBlock(input.issue.companyId, returnOwnerAgentId, { issueId: input.issue.id, projectId: input.issue.projectId });
|
|
3881
|
+
if (budgetBlock) {
|
|
3882
|
+
throw conflict("Safe recovery hand-back is blocked by the source owner's budget or pause gate", {
|
|
3883
|
+
code: "recovery_safe_hand_back_budget_blocked",
|
|
3884
|
+
issueId: input.issue.id,
|
|
3885
|
+
returnOwnerAgentId,
|
|
3886
|
+
budgetBlock,
|
|
3887
|
+
});
|
|
3888
|
+
}
|
|
3726
3889
|
}
|
|
3727
3890
|
async function resolveActiveIssueRun(issue) {
|
|
3728
3891
|
let runToInterrupt = issue.executionRunId ? await heartbeat.getRun(issue.executionRunId) : null;
|
|
@@ -5089,39 +5252,45 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
5089
5252
|
const existing = await getAccessibleResource(req, res, svc.getById(id), "Issue not found");
|
|
5090
5253
|
if (!existing)
|
|
5091
5254
|
return;
|
|
5092
|
-
if (!(await
|
|
5255
|
+
if (!(await assertIssueReadAllowed(req, res, existing)))
|
|
5093
5256
|
return;
|
|
5094
|
-
|
|
5095
|
-
if (!(await assertRecoveryActionAuthority(req, res, existing, activeRecoveryAction, { source: "recovery_action_resolution" }))) {
|
|
5257
|
+
if (await assertLowTrustControlPlaneDenied(req, res, existing.companyId, existing))
|
|
5096
5258
|
return;
|
|
5259
|
+
if (req.actor.type === "agent") {
|
|
5260
|
+
const boundaryDecision = await decideIssueAccess(req, existing, "issue:mutate");
|
|
5261
|
+
if (!boundaryDecision.allowed) {
|
|
5262
|
+
await denyIssueWrite(req, res, existing, issueWriteDenialCodeForDecision(boundaryDecision));
|
|
5263
|
+
return;
|
|
5264
|
+
}
|
|
5265
|
+
if (!requireAgentRunId(req, res))
|
|
5266
|
+
return;
|
|
5267
|
+
if (!(await assertCrossIssueInfluenceWithinRunCap(req, res, existing, "update")))
|
|
5268
|
+
return;
|
|
5097
5269
|
}
|
|
5098
5270
|
const { actionId, outcome, sourceIssueStatus, resolutionNote } = req.body;
|
|
5099
5271
|
if (outcome === "false_positive" || outcome === "cancelled") {
|
|
5100
5272
|
assertBoard(req);
|
|
5101
5273
|
}
|
|
5102
5274
|
const actor = getActorInfo(req);
|
|
5103
|
-
const handBackAgentId = outcome === "restored" && sourceIssueStatus === "todo"
|
|
5104
|
-
? activeRecoveryAction?.returnOwnerAgentId ?? null
|
|
5105
|
-
: null;
|
|
5106
|
-
const recordedOutcome = handBackAgentId
|
|
5107
|
-
? "handed_back"
|
|
5108
|
-
: outcome === "restored" && sourceIssueStatus === "done"
|
|
5109
|
-
? "owner_completed"
|
|
5110
|
-
: outcome;
|
|
5111
|
-
const updateFields = sourceIssueStatus ? { status: sourceIssueStatus } : {};
|
|
5112
|
-
await assertInReviewReviewPath({
|
|
5113
|
-
existing,
|
|
5114
|
-
updateFields,
|
|
5115
|
-
actorType: actor.actorType,
|
|
5116
|
-
actorId: actor.actorId,
|
|
5117
|
-
actorAgentId: actor.agentId,
|
|
5118
|
-
actorRunId: actor.runId,
|
|
5119
|
-
});
|
|
5120
5275
|
const actionStatus = outcome === "cancelled" ? "cancelled" : "resolved";
|
|
5121
5276
|
const postCommitActivityPublications = [];
|
|
5122
5277
|
const result = await db.transaction(async (tx) => {
|
|
5123
|
-
|
|
5124
|
-
|
|
5278
|
+
const lockedIssue = await tx
|
|
5279
|
+
.select()
|
|
5280
|
+
.from(issueRows)
|
|
5281
|
+
.where(and(eq(issueRows.companyId, existing.companyId), eq(issueRows.id, existing.id)))
|
|
5282
|
+
.for("update")
|
|
5283
|
+
.then((rows) => rows[0] ?? null);
|
|
5284
|
+
if (!lockedIssue)
|
|
5285
|
+
throw notFound("Issue not found");
|
|
5286
|
+
const activeRecoveryAction = await recoveryActionsSvc.getActiveForIssue(lockedIssue.companyId, lockedIssue.id, tx);
|
|
5287
|
+
if (!activeRecoveryAction || (actionId && activeRecoveryAction.id !== actionId)) {
|
|
5288
|
+
throw notFound("Active recovery action not found");
|
|
5289
|
+
}
|
|
5290
|
+
await requireRecoveryActionAuthority(req, lockedIssue, activeRecoveryAction, { source: "recovery_action_resolution" });
|
|
5291
|
+
let issue = lockedIssue;
|
|
5292
|
+
const sourceStatusChanged = sourceIssueStatus !== lockedIssue.status;
|
|
5293
|
+
if (outcome === "blocked" && sourceStatusChanged) {
|
|
5125
5294
|
const unresolvedBlockers = await tx
|
|
5126
5295
|
.select({ id: issueRows.id })
|
|
5127
5296
|
.from(issueRelations)
|
|
@@ -5132,10 +5301,78 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
5132
5301
|
throw unprocessable("Blocked recovery resolution requires an unresolved first-class blocker on the source issue");
|
|
5133
5302
|
}
|
|
5134
5303
|
}
|
|
5135
|
-
if (
|
|
5304
|
+
if (sourceStatusChanged) {
|
|
5305
|
+
const safeHandBack = outcome === "restored" &&
|
|
5306
|
+
sourceIssueStatus === "todo" &&
|
|
5307
|
+
activeRecoveryAction.returnOwnerAgentId != null &&
|
|
5308
|
+
lockedIssue.assigneeAgentId === activeRecoveryAction.returnOwnerAgentId;
|
|
5309
|
+
if (safeHandBack) {
|
|
5310
|
+
await assertSafeRecoveryHandBackGates({
|
|
5311
|
+
req,
|
|
5312
|
+
issue: lockedIssue,
|
|
5313
|
+
recoveryAction: activeRecoveryAction,
|
|
5314
|
+
});
|
|
5315
|
+
}
|
|
5316
|
+
else {
|
|
5317
|
+
await requireRecoverySourceMutationAuthority(req, lockedIssue);
|
|
5318
|
+
}
|
|
5319
|
+
if (lockedIssue.status === "in_review" &&
|
|
5320
|
+
(sourceIssueStatus === "done" || sourceIssueStatus === "cancelled") &&
|
|
5321
|
+
lockedIssue.reviewPolicy != null &&
|
|
5322
|
+
lockedIssue.reviewPolicy !== "anyone") {
|
|
5323
|
+
await assertIssueReviewVerdictActorAllowed(tx, {
|
|
5324
|
+
issue: lockedIssue,
|
|
5325
|
+
actor: { type: actor.actorType, id: actor.actorId },
|
|
5326
|
+
});
|
|
5327
|
+
}
|
|
5328
|
+
const updateFields = { status: sourceIssueStatus };
|
|
5329
|
+
if (!safeHandBack) {
|
|
5330
|
+
await assertInReviewReviewPath({
|
|
5331
|
+
existing: lockedIssue,
|
|
5332
|
+
updateFields,
|
|
5333
|
+
actorType: actor.actorType,
|
|
5334
|
+
actorId: actor.actorId,
|
|
5335
|
+
actorAgentId: actor.agentId,
|
|
5336
|
+
actorRunId: actor.runId,
|
|
5337
|
+
});
|
|
5338
|
+
const executionPolicy = normalizeIssueExecutionPolicy(lockedIssue.executionPolicy ?? null);
|
|
5339
|
+
const transition = applyIssueExecutionPolicyTransition({
|
|
5340
|
+
issue: lockedIssue,
|
|
5341
|
+
policy: executionPolicy,
|
|
5342
|
+
previousPolicy: executionPolicy,
|
|
5343
|
+
requestedStatus: sourceIssueStatus,
|
|
5344
|
+
requestedAssigneePatch: {},
|
|
5345
|
+
actor: {
|
|
5346
|
+
agentId: actor.agentId ?? null,
|
|
5347
|
+
userId: actor.actorType === "user" ? actor.actorId : null,
|
|
5348
|
+
},
|
|
5349
|
+
allowBoardOverride: req.actor.type === "board",
|
|
5350
|
+
commentBody: resolutionNote ?? null,
|
|
5351
|
+
});
|
|
5352
|
+
Object.assign(updateFields, transition.patch);
|
|
5353
|
+
if (transition.decision) {
|
|
5354
|
+
const decisionId = randomUUID();
|
|
5355
|
+
const nextExecutionState = updateFields.executionState;
|
|
5356
|
+
if (!nextExecutionState || typeof nextExecutionState !== "object") {
|
|
5357
|
+
throw new Error("Execution policy decision patch is missing executionState");
|
|
5358
|
+
}
|
|
5359
|
+
updateFields.executionState = { ...nextExecutionState, lastDecisionId: decisionId };
|
|
5360
|
+
await tx.insert(issueExecutionDecisions).values({
|
|
5361
|
+
id: decisionId,
|
|
5362
|
+
companyId: lockedIssue.companyId,
|
|
5363
|
+
issueId: lockedIssue.id,
|
|
5364
|
+
stageId: transition.decision.stageId,
|
|
5365
|
+
stageType: transition.decision.stageType,
|
|
5366
|
+
actorAgentId: actor.agentId ?? null,
|
|
5367
|
+
actorUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
5368
|
+
outcome: transition.decision.outcome,
|
|
5369
|
+
body: transition.decision.body,
|
|
5370
|
+
createdByRunId: actor.runId ?? null,
|
|
5371
|
+
});
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5136
5374
|
const updatedIssue = await svc.update(id, {
|
|
5137
|
-
|
|
5138
|
-
...(handBackAgentId ? { assigneeAgentId: handBackAgentId } : {}),
|
|
5375
|
+
...updateFields,
|
|
5139
5376
|
actorAgentId: actor.agentId ?? null,
|
|
5140
5377
|
actorUserId: actor.actorType === "user" ? actor.actorId : null,
|
|
5141
5378
|
}, tx, postCommitActivityPublications);
|
|
@@ -5143,10 +5380,17 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
5143
5380
|
throw notFound("Issue not found");
|
|
5144
5381
|
issue = updatedIssue;
|
|
5145
5382
|
}
|
|
5383
|
+
const recordedOutcome = outcome === "restored" && issue.status === "todo" &&
|
|
5384
|
+
activeRecoveryAction.returnOwnerAgentId != null &&
|
|
5385
|
+
issue.assigneeAgentId === activeRecoveryAction.returnOwnerAgentId
|
|
5386
|
+
? "handed_back"
|
|
5387
|
+
: outcome === "restored" && issue.status === "done"
|
|
5388
|
+
? "owner_completed"
|
|
5389
|
+
: outcome;
|
|
5146
5390
|
const recoveryAction = await recoveryActionsSvc.resolveActiveForIssue({
|
|
5147
5391
|
companyId: existing.companyId,
|
|
5148
5392
|
sourceIssueId: existing.id,
|
|
5149
|
-
actionId:
|
|
5393
|
+
actionId: activeRecoveryAction.id,
|
|
5150
5394
|
status: actionStatus,
|
|
5151
5395
|
outcome: recordedOutcome,
|
|
5152
5396
|
resolutionNote: resolutionNote ?? null,
|
|
@@ -5974,8 +6218,101 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
5974
6218
|
actor,
|
|
5975
6219
|
workProductChanged: true,
|
|
5976
6220
|
});
|
|
6221
|
+
await materializeArtifactReviewDocumentBestEffort({ issue, workProduct: product, actor });
|
|
5977
6222
|
res.status(201).json(product);
|
|
5978
6223
|
});
|
|
6224
|
+
async function ensureArtifactReviewDocumentForWorkProduct(input) {
|
|
6225
|
+
const { issue, workProduct, actor } = input;
|
|
6226
|
+
const result = await artifactReviewDocumentsSvc.ensureForWorkProduct({
|
|
6227
|
+
issue: { id: issue.id, companyId: issue.companyId },
|
|
6228
|
+
workProduct,
|
|
6229
|
+
});
|
|
6230
|
+
if (!result.revisionChanged)
|
|
6231
|
+
return result;
|
|
6232
|
+
const doc = result.document;
|
|
6233
|
+
await issueReferencesSvc.syncDocument(doc.id);
|
|
6234
|
+
await externalObjectsSvc.syncDocumentSafely(doc.id);
|
|
6235
|
+
await logActivity(db, {
|
|
6236
|
+
companyId: issue.companyId,
|
|
6237
|
+
actorType: actor.actorType,
|
|
6238
|
+
actorId: actor.actorId,
|
|
6239
|
+
agentId: actor.agentId,
|
|
6240
|
+
runId: actor.runId,
|
|
6241
|
+
agentApiKeyId: actor.agentApiKeyId,
|
|
6242
|
+
action: result.created ? "issue.document_created" : "issue.document_updated",
|
|
6243
|
+
entityType: "issue",
|
|
6244
|
+
entityId: issue.id,
|
|
6245
|
+
details: {
|
|
6246
|
+
key: doc.key,
|
|
6247
|
+
documentId: doc.id,
|
|
6248
|
+
title: doc.title,
|
|
6249
|
+
format: doc.format,
|
|
6250
|
+
revisionNumber: doc.latestRevisionNumber,
|
|
6251
|
+
workProductId: workProduct.id,
|
|
6252
|
+
artifactReviewDocument: true,
|
|
6253
|
+
},
|
|
6254
|
+
});
|
|
6255
|
+
for (const remap of result.remappedAnnotations) {
|
|
6256
|
+
await logActivity(db, {
|
|
6257
|
+
companyId: issue.companyId,
|
|
6258
|
+
actorType: actor.actorType,
|
|
6259
|
+
actorId: actor.actorId,
|
|
6260
|
+
agentId: actor.agentId,
|
|
6261
|
+
runId: actor.runId,
|
|
6262
|
+
agentApiKeyId: actor.agentApiKeyId,
|
|
6263
|
+
action: "issue.document_annotation_remapped",
|
|
6264
|
+
entityType: "issue",
|
|
6265
|
+
entityId: issue.id,
|
|
6266
|
+
details: {
|
|
6267
|
+
key: doc.key,
|
|
6268
|
+
documentId: doc.id,
|
|
6269
|
+
threadId: remap.thread.id,
|
|
6270
|
+
revisionNumber: doc.latestRevisionNumber,
|
|
6271
|
+
anchorState: remap.thread.anchorState,
|
|
6272
|
+
anchorConfidence: remap.thread.anchorConfidence,
|
|
6273
|
+
snapshotId: remap.snapshot.id,
|
|
6274
|
+
},
|
|
6275
|
+
});
|
|
6276
|
+
}
|
|
6277
|
+
await revalidateActiveSourceRecoveryAfterCommittedWrite({
|
|
6278
|
+
issue,
|
|
6279
|
+
trigger: "document",
|
|
6280
|
+
actor,
|
|
6281
|
+
documentChanged: true,
|
|
6282
|
+
});
|
|
6283
|
+
return result;
|
|
6284
|
+
}
|
|
6285
|
+
async function materializeArtifactReviewDocumentBestEffort(input) {
|
|
6286
|
+
if (!isMarkdownArtifactWorkProduct(input.workProduct))
|
|
6287
|
+
return;
|
|
6288
|
+
try {
|
|
6289
|
+
await ensureArtifactReviewDocumentForWorkProduct(input);
|
|
6290
|
+
}
|
|
6291
|
+
catch (error) {
|
|
6292
|
+
// Work-product writes stay fail-open: raw open and download remain
|
|
6293
|
+
// available, and the explicit review-document endpoint is the retry path.
|
|
6294
|
+
logger.warn({ err: error, issueId: input.issue.id, workProductId: input.workProduct.id }, "markdown work product review-document materialization failed");
|
|
6295
|
+
}
|
|
6296
|
+
}
|
|
6297
|
+
router.post("/issues/:id/work-products/:workProductId/review-document", async (req, res) => {
|
|
6298
|
+
const id = req.params.id;
|
|
6299
|
+
const workProductId = req.params.workProductId;
|
|
6300
|
+
const issue = await getAccessibleResource(req, res, svc.getById(id), "Issue not found");
|
|
6301
|
+
if (!issue)
|
|
6302
|
+
return;
|
|
6303
|
+
if (!(await assertAgentIssueMutationAllowed(req, res, issue)))
|
|
6304
|
+
return;
|
|
6305
|
+
if (!(await assertDeliverableMutationAllowedByRunContext(req, res, issue)))
|
|
6306
|
+
return;
|
|
6307
|
+
const workProduct = await workProductsSvc.getById(workProductId);
|
|
6308
|
+
if (!workProduct || workProduct.issueId !== issue.id || workProduct.companyId !== issue.companyId) {
|
|
6309
|
+
res.status(404).json({ error: "Work product not found" });
|
|
6310
|
+
return;
|
|
6311
|
+
}
|
|
6312
|
+
const actor = getActorInfo(req);
|
|
6313
|
+
const result = await ensureArtifactReviewDocumentForWorkProduct({ issue, workProduct, actor });
|
|
6314
|
+
res.status(result.created ? 201 : 200).json(result.document);
|
|
6315
|
+
});
|
|
5979
6316
|
router.post("/issues/:id/low-trust/promotions", validate(promoteLowTrustOutputSchema), async (req, res) => {
|
|
5980
6317
|
const id = req.params.id;
|
|
5981
6318
|
const issue = await getAccessibleResource(req, res, svc.getById(id), "Issue not found");
|
|
@@ -6164,6 +6501,11 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
6164
6501
|
actor,
|
|
6165
6502
|
workProductChanged: true,
|
|
6166
6503
|
});
|
|
6504
|
+
const reviewDocumentInputChanged = ["type", "provider", "metadata", "title", "createdByRunId"]
|
|
6505
|
+
.some((key) => Object.prototype.hasOwnProperty.call(patch, key));
|
|
6506
|
+
if (reviewDocumentInputChanged || sourceTrust) {
|
|
6507
|
+
await materializeArtifactReviewDocumentBestEffort({ issue, workProduct: product, actor });
|
|
6508
|
+
}
|
|
6167
6509
|
res.json(product);
|
|
6168
6510
|
});
|
|
6169
6511
|
router.delete("/work-products/:id", async (req, res) => {
|
|
@@ -6434,7 +6776,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
6434
6776
|
});
|
|
6435
6777
|
res.json({ ok: true });
|
|
6436
6778
|
});
|
|
6437
|
-
router.post("/companies/:companyId/issues", applyCreateIssueStatusDefault,
|
|
6779
|
+
router.post("/companies/:companyId/issues", applyCreateIssueStatusDefault, validateIssueMutationBody(createIssueSchema), async (req, res) => {
|
|
6438
6780
|
const companyId = req.params.companyId;
|
|
6439
6781
|
assertCompanyAccess(req, companyId);
|
|
6440
6782
|
if (isSkillTestScopedActor(req)) {
|
|
@@ -6742,7 +7084,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
6742
7084
|
referencedIssueIdentifiers: referenceSummary.outbound.map((item) => item.issue.identifier ?? item.issue.id),
|
|
6743
7085
|
});
|
|
6744
7086
|
});
|
|
6745
|
-
router.post("/issues/:id/children", applyCreateIssueStatusDefault,
|
|
7087
|
+
router.post("/issues/:id/children", applyCreateIssueStatusDefault, validateIssueMutationBody(createChildIssueSchema), async (req, res) => {
|
|
6746
7088
|
const parentId = req.params.id;
|
|
6747
7089
|
const parent = await getAccessibleResource(req, res, svc.getById(parentId), "Parent issue not found");
|
|
6748
7090
|
if (!parent)
|
|
@@ -6916,7 +7258,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
6916
7258
|
const decompositions = await svc.listAcceptedPlanDecompositions(sourceIssue.id);
|
|
6917
7259
|
res.json(decompositions);
|
|
6918
7260
|
});
|
|
6919
|
-
router.post("/issues/:id/accepted-plan-decompositions",
|
|
7261
|
+
router.post("/issues/:id/accepted-plan-decompositions", validateIssueMutationBody(createAcceptedPlanDecompositionSchema), async (req, res) => {
|
|
6920
7262
|
const sourceIssueId = req.params.id;
|
|
6921
7263
|
const sourceIssue = await getAccessibleResource(req, res, svc.getById(sourceIssueId), "Issue not found");
|
|
6922
7264
|
if (!sourceIssue)
|
|
@@ -7251,7 +7593,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
7251
7593
|
wakeQueued,
|
|
7252
7594
|
});
|
|
7253
7595
|
});
|
|
7254
|
-
router.patch("/issues/:id",
|
|
7596
|
+
router.patch("/issues/:id", validateIssueMutationBody(updateIssueRouteSchema), async (req, res) => {
|
|
7255
7597
|
const id = req.params.id;
|
|
7256
7598
|
const existing = await getAccessibleResource(req, res, svc.getById(id), "Issue not found");
|
|
7257
7599
|
if (!existing)
|
|
@@ -7335,9 +7677,19 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
7335
7677
|
const activeRecoveryActionBeforeUpdate = recoveryRelevantSourceMutationRequested
|
|
7336
7678
|
? await recoveryActionsSvc.getActiveForIssue(existing.companyId, existing.id)
|
|
7337
7679
|
: null;
|
|
7338
|
-
if (recoveryRelevantSourceMutationRequested
|
|
7339
|
-
|
|
7340
|
-
|
|
7680
|
+
if (recoveryRelevantSourceMutationRequested) {
|
|
7681
|
+
await requireRecoveryActionAuthority(req, existing, activeRecoveryActionBeforeUpdate, { source: "issue_update" });
|
|
7682
|
+
const recoveryRestrictedSourceMutationRequested = activeRecoveryActionBeforeUpdate != null &&
|
|
7683
|
+
(updateFields.status === "done" ||
|
|
7684
|
+
updateFields.status === "cancelled" ||
|
|
7685
|
+
normalizedAssigneeAgentId !== undefined ||
|
|
7686
|
+
req.body.assigneeUserId !== undefined ||
|
|
7687
|
+
(activeExecutionParticipantAgentId(existing) != null &&
|
|
7688
|
+
typeof updateFields.status === "string" &&
|
|
7689
|
+
updateFields.status !== existing.status));
|
|
7690
|
+
if (recoveryRestrictedSourceMutationRequested) {
|
|
7691
|
+
await requireRecoverySourceMutationAuthority(req, existing);
|
|
7692
|
+
}
|
|
7341
7693
|
}
|
|
7342
7694
|
if (resumeRequested !== true &&
|
|
7343
7695
|
agentStatusTransitionRequiresResumeAuthority &&
|
|
@@ -8259,14 +8611,17 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
8259
8611
|
wakeups.set(`${agentId}:${wakeIssueId}`, { agentId, wakeup });
|
|
8260
8612
|
};
|
|
8261
8613
|
const addDependencyResolvedWakeup = async (input) => {
|
|
8262
|
-
const idempotencyKey =
|
|
8614
|
+
const idempotencyKey = buildIssueBlockersResolvedWakeStateKey({
|
|
8263
8615
|
dependentIssueId: input.dependentIssueId,
|
|
8264
|
-
|
|
8616
|
+
blockerIssueIds: input.blockerIssueIds,
|
|
8617
|
+
blockedTransitionAt: input.blockedTransitionAt,
|
|
8265
8618
|
});
|
|
8266
8619
|
try {
|
|
8267
|
-
const existingWake = await
|
|
8620
|
+
const existingWake = await findExistingIssueBlockersResolvedWakeForReadyState(db, {
|
|
8268
8621
|
companyId: issue.companyId,
|
|
8269
|
-
|
|
8622
|
+
dependentIssueId: input.dependentIssueId,
|
|
8623
|
+
blockerIssueIds: input.blockerIssueIds,
|
|
8624
|
+
blockedTransitionAt: input.blockedTransitionAt,
|
|
8270
8625
|
});
|
|
8271
8626
|
if (existingWake)
|
|
8272
8627
|
return;
|
|
@@ -8442,6 +8797,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
8442
8797
|
dependentIssueId: dependent.id,
|
|
8443
8798
|
resolvedBlockerIssueId: issue.id,
|
|
8444
8799
|
blockerIssueIds: dependent.blockerIssueIds,
|
|
8800
|
+
blockedTransitionAt: dependent.blockedTransitionAt,
|
|
8445
8801
|
source: "issue.blockers_resolved",
|
|
8446
8802
|
mutation: "blocker_done",
|
|
8447
8803
|
});
|
|
@@ -8463,6 +8819,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
8463
8819
|
dependentIssueId: issue.id,
|
|
8464
8820
|
resolvedBlockerIssueId,
|
|
8465
8821
|
blockerIssueIds: readiness.blockerIssueIds,
|
|
8822
|
+
blockedTransitionAt: issue.blockedTransitionAt,
|
|
8466
8823
|
source: "issue.blockers_restored",
|
|
8467
8824
|
mutation: "blocked_dependency_restored",
|
|
8468
8825
|
});
|
|
@@ -8882,6 +9239,9 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
8882
9239
|
if (req.body.kind === "request_confirmation" && req.body.payload?.toolAction !== undefined) {
|
|
8883
9240
|
throw unprocessable("payload.toolAction is server-owned metadata and cannot be supplied when creating an interaction");
|
|
8884
9241
|
}
|
|
9242
|
+
if (req.body.kind === "request_confirmation" && req.body.payload?.secretProposal !== undefined) {
|
|
9243
|
+
throw unprocessable("payload.secretProposal is server-owned metadata and cannot be supplied when creating an interaction");
|
|
9244
|
+
}
|
|
8885
9245
|
// Plan-document confirmation targets are validated authoritatively inside
|
|
8886
9246
|
// issueThreadInteractionService.create, which re-reads the plan document's
|
|
8887
9247
|
// latest revision and rejects a stale/missing target under the same insert
|
|
@@ -8987,6 +9347,9 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
8987
9347
|
const toolAction = interaction.payload && typeof interaction.payload === "object"
|
|
8988
9348
|
? interaction.payload.toolAction
|
|
8989
9349
|
: null;
|
|
9350
|
+
const secretProposal = interaction.payload && typeof interaction.payload === "object"
|
|
9351
|
+
? interaction.payload.secretProposal
|
|
9352
|
+
: null;
|
|
8990
9353
|
let continuationInteraction = interaction;
|
|
8991
9354
|
if (interaction.kind === "request_confirmation"
|
|
8992
9355
|
&& interaction.status === "accepted"
|
|
@@ -9021,6 +9384,63 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
9021
9384
|
};
|
|
9022
9385
|
}
|
|
9023
9386
|
}
|
|
9387
|
+
if (interaction.kind === "request_confirmation"
|
|
9388
|
+
&& interaction.status === "accepted"
|
|
9389
|
+
&& typeof secretProposal?.proposalId === "string") {
|
|
9390
|
+
const resolvedByUserId = actor.actorType === "user" ? actor.actorId : "board";
|
|
9391
|
+
try {
|
|
9392
|
+
if (opts.approveSecretProposal) {
|
|
9393
|
+
await opts.approveSecretProposal({
|
|
9394
|
+
companyId: issue.companyId,
|
|
9395
|
+
issueId: issue.id,
|
|
9396
|
+
interactionId: interaction.id,
|
|
9397
|
+
proposalId: secretProposal.proposalId,
|
|
9398
|
+
actor: { agentId: actor.agentId, userId: actor.actorType === "user" ? actor.actorId : null },
|
|
9399
|
+
});
|
|
9400
|
+
}
|
|
9401
|
+
else {
|
|
9402
|
+
const proposal = await secretProposals.getById(issue.companyId, secretProposal.proposalId);
|
|
9403
|
+
if (!proposal
|
|
9404
|
+
|| proposal.kind !== "binding"
|
|
9405
|
+
|| proposal.originIssueId !== issue.id
|
|
9406
|
+
|| proposal.interactionId !== interaction.id) {
|
|
9407
|
+
throw notFound("Secret proposal not found");
|
|
9408
|
+
}
|
|
9409
|
+
await secretProposals.approve(issue.companyId, proposal.id, {
|
|
9410
|
+
resolvedByUserId,
|
|
9411
|
+
assertCanResolve: (lockedProposal, txDb) => assertCanResolveProposal({
|
|
9412
|
+
db: txDb,
|
|
9413
|
+
actor: req.actor,
|
|
9414
|
+
companyId: issue.companyId,
|
|
9415
|
+
proposal: lockedProposal,
|
|
9416
|
+
}),
|
|
9417
|
+
});
|
|
9418
|
+
await notifySecretProposalResolution({
|
|
9419
|
+
proposal,
|
|
9420
|
+
status: "approved",
|
|
9421
|
+
userId: resolvedByUserId,
|
|
9422
|
+
issues: svc,
|
|
9423
|
+
heartbeat,
|
|
9424
|
+
});
|
|
9425
|
+
}
|
|
9426
|
+
continuationInteraction = await interactionSvc.recordSecretProposalExecutionResult(issue, interaction.id, secretProposal.proposalId, { status: "executed" });
|
|
9427
|
+
}
|
|
9428
|
+
catch (error) {
|
|
9429
|
+
const errorCode = secretProposalExecutionErrorCode(error);
|
|
9430
|
+
continuationInteraction = await interactionSvc.recordSecretProposalExecutionResult(issue, interaction.id, secretProposal.proposalId, { status: "failed", errorCode });
|
|
9431
|
+
const recordedResult = readObject(continuationInteraction.result);
|
|
9432
|
+
const recordedSecretProposal = readObject(recordedResult.secretProposal);
|
|
9433
|
+
if (recordedSecretProposal.status !== "executed") {
|
|
9434
|
+
const configPath = typeof secretProposal.configPath === "string" ? secretProposal.configPath : "unknown";
|
|
9435
|
+
try {
|
|
9436
|
+
await svc.addComment(issue.id, `Secret binding execution failed\n\n- Config path: \`${configPath}\`\n- Error code: \`${errorCode}\`\n- Binding created: **no**`, { userId: resolvedByUserId });
|
|
9437
|
+
}
|
|
9438
|
+
catch (commentError) {
|
|
9439
|
+
logger.warn({ err: commentError, issueId: issue.id, interactionId: interaction.id, errorCode }, "failed to post secret proposal execution failure comment");
|
|
9440
|
+
}
|
|
9441
|
+
}
|
|
9442
|
+
}
|
|
9443
|
+
}
|
|
9024
9444
|
const continuationWakeIssue = continuationIssue ?? issue;
|
|
9025
9445
|
await logActivity(db, {
|
|
9026
9446
|
companyId: issue.companyId,
|
|
@@ -10022,14 +10442,17 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
10022
10442
|
wakeups.set(key, { agentId, wakeup });
|
|
10023
10443
|
};
|
|
10024
10444
|
const addDependencyResolvedWakeup = async (input) => {
|
|
10025
|
-
const idempotencyKey =
|
|
10445
|
+
const idempotencyKey = buildIssueBlockersResolvedWakeStateKey({
|
|
10026
10446
|
dependentIssueId: input.dependentIssueId,
|
|
10027
|
-
|
|
10447
|
+
blockerIssueIds: input.blockerIssueIds,
|
|
10448
|
+
blockedTransitionAt: input.blockedTransitionAt,
|
|
10028
10449
|
});
|
|
10029
10450
|
try {
|
|
10030
|
-
const existingWake = await
|
|
10451
|
+
const existingWake = await findExistingIssueBlockersResolvedWakeForReadyState(db, {
|
|
10031
10452
|
companyId: currentIssue.companyId,
|
|
10032
|
-
|
|
10453
|
+
dependentIssueId: input.dependentIssueId,
|
|
10454
|
+
blockerIssueIds: input.blockerIssueIds,
|
|
10455
|
+
blockedTransitionAt: input.blockedTransitionAt,
|
|
10033
10456
|
});
|
|
10034
10457
|
if (existingWake)
|
|
10035
10458
|
return;
|
|
@@ -10187,6 +10610,7 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
10187
10610
|
dependentIssueId: dependent.id,
|
|
10188
10611
|
resolvedBlockerIssueId: currentIssue.id,
|
|
10189
10612
|
blockerIssueIds: dependent.blockerIssueIds,
|
|
10613
|
+
blockedTransitionAt: dependent.blockedTransitionAt,
|
|
10190
10614
|
});
|
|
10191
10615
|
}
|
|
10192
10616
|
}
|
|
@@ -10484,7 +10908,13 @@ export function issueRoutes(db, storage, opts = {}) {
|
|
|
10484
10908
|
objectContentType: object.contentType,
|
|
10485
10909
|
originalFilename: attachment.originalFilename,
|
|
10486
10910
|
});
|
|
10487
|
-
|
|
10911
|
+
// Markdown bodies are stored as UTF-8; declare the charset so inline
|
|
10912
|
+
// (raw) views do not mojibake. SVG/inline checks below stay on the bare type.
|
|
10913
|
+
const isMarkdownResponse = isMarkdownAttachmentContent({
|
|
10914
|
+
contentType: responseContentType,
|
|
10915
|
+
originalFilename: attachment.originalFilename,
|
|
10916
|
+
});
|
|
10917
|
+
res.setHeader("Content-Type", isMarkdownResponse ? `${responseContentType}; charset=utf-8` : responseContentType);
|
|
10488
10918
|
res.setHeader("Cache-Control", "private, max-age=60");
|
|
10489
10919
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
10490
10920
|
if (responseContentType === SVG_CONTENT_TYPE) {
|