@taskforcehq/taskforce 0.3.329 → 0.3.330

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.
Files changed (321) hide show
  1. package/dist/Taskforce.module.css +290 -45
  2. package/dist/components/features/AiProfilesModule.js +3 -5
  3. package/dist/components/features/TaskSettings.js +70 -14
  4. package/dist/components/features/TaskforceAgentsModule.d.ts +1 -2
  5. package/dist/components/features/TaskforceAgentsModule.js +586 -116
  6. package/dist/components/features/agentConnections/AgentConnectionControl.d.ts +15 -0
  7. package/dist/components/features/agentConnections/AgentConnectionControl.js +125 -0
  8. package/dist/components/features/agentConnections/ModelConnectionsPanel.d.ts +18 -0
  9. package/dist/components/features/agentConnections/ModelConnectionsPanel.js +393 -0
  10. package/dist/components/features/agentConnections/modelConnectionsApi.d.ts +65 -0
  11. package/dist/components/features/agentConnections/modelConnectionsApi.js +129 -0
  12. package/dist/components/features/taskforceAgentAssignments/AgentBehaviorAssignments.js +15 -24
  13. package/dist/components/features/taskforceAgentEditorModel.d.ts +2 -1
  14. package/dist/components/features/taskforceAgentEditorModel.js +3 -1
  15. package/dist/components/features/workflowManager/workflowManagerApi.d.ts +1 -1
  16. package/dist/components/features/workflowManager/workflowManagerApi.js +3 -0
  17. package/dist/components/task/TaskWorkflowAssignmentField.js +68 -10
  18. package/dist/components/views/StandaloneLayout.js +27 -26
  19. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +4 -3
  20. package/dist/components/views/standalone/modals/SyncStatusModal.js +33 -38
  21. package/dist/config/envSchema.js +48 -1
  22. package/dist/core/McpTokenService.d.ts +23 -1
  23. package/dist/core/McpTokenService.js +93 -10
  24. package/dist/core/TaskChecklistCommandService.d.ts +27 -0
  25. package/dist/core/TaskChecklistCommandService.js +83 -5
  26. package/dist/core/TaskLifecycleCommandService.d.ts +3 -1
  27. package/dist/core/TaskLifecycleCommandService.js +6 -2
  28. package/dist/core/Taskforce.d.ts +32 -0
  29. package/dist/core/Taskforce.js +125 -4
  30. package/dist/core/types.d.ts +8 -0
  31. package/dist/documentReviews/commandService.d.ts +2 -1
  32. package/dist/documentReviews/commandService.js +6 -3
  33. package/dist/hooks/sync/orchestratorShared.d.ts +1 -0
  34. package/dist/hooks/sync/orchestratorShared.js +2 -0
  35. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.d.ts +3 -0
  36. package/dist/hooks/sync/useLocalSyncCoordinatorSnapshot.js +85 -9
  37. package/dist/hooks/sync/useSyncStatusControls.d.ts +4 -1
  38. package/dist/hooks/sync/useSyncStatusControls.js +47 -11
  39. package/dist/hooks/useSyncOrchestrator.d.ts +3 -0
  40. package/dist/hooks/useSyncOrchestrator.js +111 -2
  41. package/dist/hooks/useTaskData.d.ts +31 -1
  42. package/dist/hooks/useTaskData.js +29 -7
  43. package/dist/hooks/useTaskMutations.d.ts +3 -1
  44. package/dist/hooks/useTaskMutations.js +46 -12
  45. package/dist/hooks/useTaskforce.d.ts +2 -0
  46. package/dist/hooks/useTaskforce.js +11 -2
  47. package/dist/mcp/clientRegistry.d.ts +2 -2
  48. package/dist/mcp/clientRegistry.js +1 -1
  49. package/dist/mcp/documentAssetRegistrar.js +9 -6
  50. package/dist/mcp/durableTaskMutationRouter.d.ts +4 -1
  51. package/dist/mcp/durableTaskMutationRouter.js +10 -0
  52. package/dist/mcp/durableTaskRelationshipMutationRouter.js +4 -0
  53. package/dist/mcp/httpProtocolRouting.d.ts +10 -0
  54. package/dist/mcp/httpProtocolRouting.js +19 -0
  55. package/dist/mcp/localCliHealth.d.ts +2 -2
  56. package/dist/mcp/localCliHealth.js +2 -2
  57. package/dist/mcp/localServiceProxy.d.ts +1 -0
  58. package/dist/mcp/localServiceProxy.js +530 -68
  59. package/dist/mcp/planningAttachmentCommandAdapter.d.ts +3 -1
  60. package/dist/mcp/planningAttachmentCommandAdapter.js +20 -2
  61. package/dist/mcp/runtime.d.ts +54 -79
  62. package/dist/mcp/runtime.js +384 -97
  63. package/dist/mcp/taskPlanningRegistrar.js +23 -4
  64. package/dist/mcp/toolProfiles.d.ts +2 -0
  65. package/dist/mcp/toolProfiles.js +10 -0
  66. package/dist/mcp/toolRegistry.d.ts +1 -0
  67. package/dist/mcp/toolRegistry.js +1 -0
  68. package/dist/mcp/workflowExecutionRegistrar.js +4 -4
  69. package/dist/migrations/taskSchemaMigrations.d.ts +5 -0
  70. package/dist/migrations/taskSchemaMigrations.js +415 -0
  71. package/dist/runtime/appGates.d.ts +2 -1
  72. package/dist/runtime/appGates.js +7 -0
  73. package/dist/server/index.d.ts +3 -0
  74. package/dist/server/index.js +108 -11
  75. package/dist/server/localDatabaseIdentity.js +4 -1
  76. package/dist/server/localServiceLease.js +2 -1
  77. package/dist/server/localServiceSessions.d.ts +14 -17
  78. package/dist/server/localServiceSessions.js +308 -94
  79. package/dist/server/localWorkspaceSyncServerRuntime.js +12 -14
  80. package/dist/server/routes/admin.d.ts +4 -0
  81. package/dist/server/routes/admin.js +112 -3
  82. package/dist/server/routes/agents.d.ts +7 -0
  83. package/dist/server/routes/agents.js +277 -24
  84. package/dist/server/routes/billing.js +5 -1
  85. package/dist/server/routes/durableTaskHttpRouters.d.ts +2 -0
  86. package/dist/server/routes/executorPhaseAApprovals.d.ts +19 -0
  87. package/dist/server/routes/executorPhaseAApprovals.js +140 -0
  88. package/dist/server/routes/executorPhaseAIssuerRedemptions.d.ts +11 -0
  89. package/dist/server/routes/executorPhaseAIssuerRedemptions.js +24 -0
  90. package/dist/server/routes/githubReviewEvidence.d.ts +19 -0
  91. package/dist/server/routes/githubReviewEvidence.js +116 -0
  92. package/dist/server/routes/localService.d.ts +15 -4
  93. package/dist/server/routes/localService.js +136 -40
  94. package/dist/server/routes/modelConnections.d.ts +24 -0
  95. package/dist/server/routes/modelConnections.js +205 -0
  96. package/dist/server/routes/shared.d.ts +19 -0
  97. package/dist/server/routes/shared.js +95 -19
  98. package/dist/server/routes/sync.js +1 -0
  99. package/dist/server/routes/syncAuxRoutes.js +5 -1
  100. package/dist/server/routes/syncPushRoutes.d.ts +1 -0
  101. package/dist/server/routes/syncPushRoutes.js +1 -0
  102. package/dist/server/routes/syncV3FeedRoutes.js +10 -1
  103. package/dist/server/routes/syncV3OperationRoutes.js +35 -9
  104. package/dist/server/routes/tasks.js +21 -2
  105. package/dist/server/routes/workflows.js +9 -1
  106. package/dist/server/routes.js +59 -0
  107. package/dist/services/codexAppServerModelGateway.d.ts +54 -5
  108. package/dist/services/codexAppServerModelGateway.js +246 -21
  109. package/dist/services/codexDeviceCodeLoginManager.d.ts +39 -0
  110. package/dist/services/codexDeviceCodeLoginManager.js +265 -0
  111. package/dist/services/codexModelProviderConnectionLifecycle.d.ts +8 -0
  112. package/dist/services/codexModelProviderConnectionLifecycle.js +73 -0
  113. package/dist/services/executorPhaseAApprovalRuntime.d.ts +14 -0
  114. package/dist/services/executorPhaseAApprovalRuntime.js +24 -0
  115. package/dist/services/executorPhaseAApprovalService.d.ts +40 -0
  116. package/dist/services/executorPhaseAApprovalService.js +609 -0
  117. package/dist/services/executorPhaseADriftEvaluator.d.ts +78 -0
  118. package/dist/services/executorPhaseADriftEvaluator.js +93 -0
  119. package/dist/services/executorPhaseAIssuerCore.d.ts +126 -0
  120. package/dist/services/executorPhaseAIssuerCore.js +295 -0
  121. package/dist/services/executorPhaseAIssuerRedemptionService.d.ts +34 -0
  122. package/dist/services/executorPhaseAIssuerRedemptionService.js +158 -0
  123. package/dist/services/githubReviewEvidenceRuntime.d.ts +14 -0
  124. package/dist/services/githubReviewEvidenceRuntime.js +30 -0
  125. package/dist/services/githubReviewEvidenceService.d.ts +93 -0
  126. package/dist/services/githubReviewEvidenceService.js +336 -0
  127. package/dist/services/modelGateway.d.ts +7 -0
  128. package/dist/services/modelProviderConnectionService.d.ts +71 -0
  129. package/dist/services/modelProviderConnectionService.js +279 -0
  130. package/dist/services/modelProviderCredentialHome.d.ts +32 -0
  131. package/dist/services/modelProviderCredentialHome.js +271 -0
  132. package/dist/services/ownerScopedModelConnectionGateway.d.ts +12 -0
  133. package/dist/services/ownerScopedModelConnectionGateway.js +30 -0
  134. package/dist/services/taskforceAgentConnectionBindingService.d.ts +66 -0
  135. package/dist/services/taskforceAgentConnectionBindingService.js +185 -0
  136. package/dist/services/taskforceAgentMcpBridge.d.ts +1 -1
  137. package/dist/services/taskforceAgentMcpBridge.js +7 -24
  138. package/dist/shared/adminEdgeProxy.d.ts +5 -0
  139. package/dist/shared/adminEdgeProxy.js +94 -0
  140. package/dist/shared/adminProxySessionCookies.d.ts +16 -0
  141. package/dist/shared/adminProxySessionCookies.js +86 -0
  142. package/dist/shared/aiProfileColors.d.ts +31 -1
  143. package/dist/shared/aiProfileColors.js +14 -6
  144. package/dist/shared/executorPhaseAApprovalGoldenVector.json +269 -0
  145. package/dist/shared/executorPhaseAApprovalReceipt.d.ts +112 -0
  146. package/dist/shared/executorPhaseAApprovalReceipt.js +58 -0
  147. package/dist/shared/executorPhaseAApprovalTrustPolicy.json +10 -0
  148. package/dist/shared/executorPhaseADriftContracts.d.ts +37 -0
  149. package/dist/shared/executorPhaseADriftContracts.js +63 -0
  150. package/dist/shared/executorPhaseAIssuerContracts.d.ts +75 -0
  151. package/dist/shared/executorPhaseAIssuerContracts.js +90 -0
  152. package/dist/shared/executorPhaseARunAuthorization.d.ts +120 -0
  153. package/dist/shared/executorPhaseARunAuthorization.js +232 -0
  154. package/dist/shared/executorPhaseASchemaValidation.d.ts +7 -0
  155. package/dist/shared/executorPhaseASchemaValidation.js +53 -0
  156. package/dist/shared/executorPhaseASchemas/approval-receipt.schema.json +106 -0
  157. package/dist/shared/executorPhaseASchemas/drift-attestation.schema.json +54 -0
  158. package/dist/shared/executorPhaseASchemas/drift-request.schema.json +47 -0
  159. package/dist/shared/executorPhaseASchemas/foundation-manifest.schema.json +29 -0
  160. package/dist/shared/executorPhaseASchemas/issuer-audit-record.schema.json +24 -0
  161. package/dist/shared/executorPhaseASchemas/issuer-proof.schema.json +43 -0
  162. package/dist/shared/executorPhaseASchemas/issuer-redemption-request.schema.json +18 -0
  163. package/dist/shared/executorPhaseASchemas/issuer-redemption-response.schema.json +39 -0
  164. package/dist/shared/executorPhaseASchemas/logical-envelope.schema.json +149 -0
  165. package/dist/shared/executorPhaseASchemas/preflight-report.schema.json +216 -0
  166. package/dist/shared/executorPhaseASchemas/run-capability.schema.json +111 -0
  167. package/dist/shared/executorPhaseASchemas/sender-proof.schema.json +37 -0
  168. package/dist/shared/executorPhaseASchemas/workload-grant.schema.json +68 -0
  169. package/dist/shared/executorPhaseASchemas/workload-jwt-claims.schema.json +67 -0
  170. package/dist/shared/executorPhaseATiming.d.ts +1 -0
  171. package/dist/shared/executorPhaseATiming.js +1 -0
  172. package/dist/shared/planningIdentity.js +1 -1
  173. package/dist/shared/productLogoKeys.d.ts +2 -0
  174. package/dist/shared/productLogoKeys.js +18 -0
  175. package/dist/shared/taskforceAgentDefinition.d.ts +0 -1
  176. package/dist/shared/taskforceAgentDefinition.js +6 -9
  177. package/dist/shared/taskforceAgentModels.js +7 -3
  178. package/dist/shared/userFeatureGrants.d.ts +4 -0
  179. package/dist/shared/userFeatureGrants.js +7 -0
  180. package/dist/storage/executorPhaseAApprovalReceiptStore.d.ts +37 -0
  181. package/dist/storage/executorPhaseAApprovalReceiptStore.js +81 -0
  182. package/dist/storage/executorPhaseARunAuthorizationStore.d.ts +103 -0
  183. package/dist/storage/executorPhaseARunAuthorizationStore.js +492 -0
  184. package/dist/storage/githubReviewEvidenceInstallationStore.d.ts +26 -0
  185. package/dist/storage/githubReviewEvidenceInstallationStore.js +89 -0
  186. package/dist/storage/modelProviderConnectionStore.d.ts +99 -0
  187. package/dist/storage/modelProviderConnectionStore.js +446 -0
  188. package/dist/storage/postgresAdapter.d.ts +4 -0
  189. package/dist/storage/postgresAdapter.js +11 -0
  190. package/dist/storage/postgresWorker.js +9 -1
  191. package/dist/storage/postgresWorkerProtocol.d.ts +1 -0
  192. package/dist/storage/taskforceAgentConnectionBindingStore.d.ts +31 -0
  193. package/dist/storage/taskforceAgentConnectionBindingStore.js +84 -0
  194. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +60 -29
  195. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.d.ts +10 -0
  196. package/dist/sync/coordinator/localWorkspaceSyncPendingV2PushProgress.js +29 -0
  197. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.d.ts +15 -1
  198. package/dist/sync/coordinator/localWorkspaceSyncRunnerState.js +99 -2
  199. package/dist/sync/coordinator/workspaceSyncCredentialBroker.d.ts +1 -0
  200. package/dist/sync/coordinator/workspaceSyncCredentialBroker.js +33 -4
  201. package/dist/sync/engine/workspaceSyncContentLifecycleAdapter.d.ts +2 -1
  202. package/dist/sync/engine/workspaceSyncContentVersionStore.d.ts +38 -0
  203. package/dist/sync/engine/workspaceSyncContentVersionStore.js +50 -1
  204. package/dist/sync/engine/workspaceSyncEngineLifecyclePolicy.js +6 -6
  205. package/dist/sync/engine/workspaceSyncEnginePushCompletion.d.ts +14 -0
  206. package/dist/sync/engine/workspaceSyncEnginePushCompletion.js +84 -0
  207. package/dist/sync/engine/workspaceSyncEngineRecovery.js +1 -0
  208. package/dist/sync/engine/workspaceSyncEngineRuntime.d.ts +1 -0
  209. package/dist/sync/engine/workspaceSyncEngineRuntime.js +1 -0
  210. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +112 -38
  211. package/dist/sync/engine/workspaceSyncEngineServerSnapshotReader.js +6 -0
  212. package/dist/sync/engine/workspaceSyncEngineTransfers.js +3 -1
  213. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.d.ts +1 -0
  214. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +29 -0
  215. package/dist/sync/syncApplyHandlers.d.ts +2 -0
  216. package/dist/sync/syncApplyHandlers.js +10 -1
  217. package/dist/sync/syncService.d.ts +15 -0
  218. package/dist/sync/syncService.js +83 -18
  219. package/dist/sync/taskforceAgentSyncAuthorization.d.ts +16 -0
  220. package/dist/sync/taskforceAgentSyncAuthorization.js +20 -0
  221. package/dist/sync/v3/combinedFeedCapability.js +4 -0
  222. package/dist/sync/v3/durableInitiativeMutationRouter.js +18 -10
  223. package/dist/sync/v3/durableOperationReplay.d.ts +14 -0
  224. package/dist/sync/v3/durableOperationReplay.js +18 -0
  225. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +3 -0
  226. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -1
  227. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +58 -15
  228. package/dist/sync/v3/durableTaskCommentMutationRouter.js +3 -0
  229. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +1 -1
  230. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +10 -0
  231. package/dist/sync/v3/durableTaxonomyMutationRouter.js +5 -0
  232. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.d.ts +11 -0
  233. package/dist/sync/v3/durableWorkflowRuntimeMutationRouter.js +39 -10
  234. package/dist/sync/v3/durableWorkstreamMutationRouter.js +18 -10
  235. package/dist/sync/v3/durableWorkstreamTaskOrderMutationRouter.js +16 -5
  236. package/dist/sync/v3/localOutboxDispatchRuntime.js +2 -2
  237. package/dist/sync/v3/localTaskChecklistOutboxHandler.js +16 -2
  238. package/dist/sync/v3/localTaskChecklistOutboxService.d.ts +4 -0
  239. package/dist/sync/v3/localTaskChecklistOutboxService.js +14 -1
  240. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +8 -0
  241. package/dist/sync/v3/localTaskStatusOutboxService.js +219 -12
  242. package/dist/sync/v3/syncDurabilityStore.d.ts +34 -0
  243. package/dist/sync/v3/syncDurabilityStore.js +168 -2
  244. package/dist/sync/v3/taskChecklistMutationService.d.ts +11 -0
  245. package/dist/sync/v3/taskChecklistMutationService.js +44 -1
  246. package/dist/sync/v3/taskStatusMutationService.d.ts +29 -1
  247. package/dist/sync/v3/taskStatusMutationService.js +119 -3
  248. package/dist/sync/v3/workflowAssignmentSync.d.ts +5 -0
  249. package/dist/sync/v3/workflowAssignmentSync.js +27 -0
  250. package/dist/sync/v3/workspaceSyncJournalReader.js +1 -1
  251. package/dist/sync/v3/workspaceSyncOperationRetentionService.d.ts +16 -0
  252. package/dist/sync/v3/workspaceSyncOperationRetentionService.js +83 -0
  253. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.d.ts +1 -0
  254. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +9 -2
  255. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +7 -0
  256. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +44 -32
  257. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +9 -5
  258. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +54 -38
  259. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
  260. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +70 -31
  261. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +2 -1
  262. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +16 -0
  263. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
  264. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
  265. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +5 -0
  266. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +36 -2
  267. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.d.ts +17 -0
  268. package/dist/sync/v3/workspaceSyncV3RepairSnapshotRetentionService.js +64 -0
  269. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.d.ts +7 -0
  270. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverCoverage.js +33 -0
  271. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.d.ts +7 -0
  272. package/dist/sync/v3/workspaceSyncV3WorkflowTaskCoverWireContract.js +8 -0
  273. package/dist/sync/workspaceRepair.d.ts +5 -2
  274. package/dist/sync/workspaceRepair.js +161 -6
  275. package/dist/sync/workspaceSyncModel.d.ts +21 -0
  276. package/dist/sync/workspaceSyncModel.js +35 -7
  277. package/dist/sync/workspaceSyncState.d.ts +1 -0
  278. package/dist/sync/workspaceSyncV2SnapshotBuilder.d.ts +6 -0
  279. package/dist/sync/workspaceSyncV2SnapshotBuilder.js +5 -0
  280. package/dist/ui/assets/AiIdentityRosterCard-OcSz1PkK.js +1 -0
  281. package/dist/ui/assets/AiProfilesModule-ByhYW5Xi.js +1 -0
  282. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-B68Wg-RV.js → AnnotatedAttachmentWorkspace-BTM6nIg_.js} +1 -1
  283. package/dist/ui/assets/{AssetTraySortControl-C8Rztyal.js → AssetTraySortControl-DabEG8L4.js} +1 -1
  284. package/dist/ui/assets/{ContextAttachmentManager-Cj3c7X9y.js → ContextAttachmentManager-Coa8yVGM.js} +1 -1
  285. package/dist/ui/assets/{DocumentWorkspace-B5uvzems.js → DocumentWorkspace-BB0qhdix.js} +1 -1
  286. package/dist/ui/assets/{EntityActivityTimeline-BVFvCB5R.js → EntityActivityTimeline-CZ8x4UJE.js} +1 -1
  287. package/dist/ui/assets/{PlanningModule-B5DWQOGz.js → PlanningModule-pRPjR7v5.js} +1 -1
  288. package/dist/ui/assets/{PlansPage-AY4cGWco.js → PlansPage-D86pZSSl.js} +1 -1
  289. package/dist/ui/assets/{TaskContextUpload-DZxTVesW.js → TaskContextUpload-BVIkU9yT.js} +1 -1
  290. package/dist/ui/assets/TaskSettings-Cv1mNhv_.js +12 -0
  291. package/dist/ui/assets/TaskforceAgentsModule-b-8R25cJ.css +1 -0
  292. package/dist/ui/assets/TaskforceAgentsModule-gmH-PD2q.js +24 -0
  293. package/dist/ui/assets/{WorkflowManagerModule-DEr5di_r.js → WorkflowManagerModule-DbfnHJ-f.js} +1 -1
  294. package/dist/ui/assets/index-BZ-hdZSk.css +1 -0
  295. package/dist/ui/assets/index-CTsDBaef.js +7 -0
  296. package/dist/ui/assets/{vendor-icons-D9Lpw-j4.js → vendor-icons-Bsq-mcEn.js} +1 -1
  297. package/dist/ui/branding/logos/letterhead_dark.png +0 -0
  298. package/dist/ui/branding/logos/letterhead_light.png +0 -0
  299. package/dist/ui/branding/logos/signature_dark.png +0 -0
  300. package/dist/ui/branding/logos/signature_light.png +0 -0
  301. package/dist/ui/index.html +3 -3
  302. package/dist/utils/aiProfileDefaultLogo.js +16 -48
  303. package/dist/utils/httpSetCookie.d.ts +1 -0
  304. package/dist/utils/httpSetCookie.js +4 -1
  305. package/dist/utils/localRuntimeUrl.d.ts +1 -0
  306. package/dist/utils/localRuntimeUrl.js +14 -0
  307. package/dist/utils/productLogoRegistry.d.ts +2 -0
  308. package/dist/utils/productLogoRegistry.js +36 -0
  309. package/dist/utils/syncStatusPresentation.d.ts +4 -0
  310. package/dist/utils/syncStatusPresentation.js +17 -0
  311. package/dist/utils/taskEvents.d.ts +2 -0
  312. package/dist/utils/workspaceSyncPresentation.d.ts +1 -1
  313. package/dist/utils/workspaceSyncPresentation.js +23 -17
  314. package/package.json +22 -4
  315. package/dist/ui/assets/AiIdentityRosterCard-BZM4aQnM.js +0 -1
  316. package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +0 -1
  317. package/dist/ui/assets/TaskSettings-BeWAuyZj.js +0 -12
  318. package/dist/ui/assets/TaskforceAgentsModule-BifCYtjR.js +0 -21
  319. package/dist/ui/assets/TaskforceAgentsModule-D6IC0S7Q.css +0 -1
  320. package/dist/ui/assets/index-I5zhdtgt.js +0 -7
  321. package/dist/ui/assets/index-VRFsx3wz.css +0 -1
@@ -0,0 +1,492 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { canonicalizeExecutorPhaseAJson } from '../shared/executorPhaseAApprovalReceipt.js';
3
+ import { EXECUTOR_PHASE_A_CLEANUP_CAPABILITY_TTL_MS, EXECUTOR_PHASE_A_MAIN_CAPABILITY_TTL_MS, } from '../shared/executorPhaseARunAuthorization.js';
4
+ const verifiedCapabilityRecordBrand = Symbol('verifiedExecutorPhaseACapabilityRecord');
5
+ const verifiedGrantRecordBrand = Symbol('verifiedExecutorPhaseAGrantRecord');
6
+ function sha256(value) {
7
+ return createHash('sha256').update(canonicalizeExecutorPhaseAJson(value)).digest('hex');
8
+ }
9
+ export function executorPhaseACapabilityRecordFromVerified(artifact) {
10
+ const payload = artifact.payload;
11
+ return {
12
+ capabilityId: payload.capabilityId,
13
+ workspaceId: payload.workspaceId,
14
+ taskId: payload.taskId,
15
+ runId: payload.runId,
16
+ receiptId: payload.receiptId,
17
+ receiptSha256: payload.receiptSha256,
18
+ capabilityKind: payload.capabilityKind,
19
+ originalCapabilityId: payload.originalCapabilityId,
20
+ residualInventorySha256: payload.residualInventorySha256,
21
+ actorUserId: payload.actorUserId,
22
+ accountId: payload.accountId,
23
+ region: payload.region,
24
+ availabilityZone: payload.availabilityZone,
25
+ readPrincipalArn: payload.readPrincipalArn,
26
+ brokerKeyFingerprint: payload.brokerKeyFingerprint,
27
+ capabilitySha256: sha256(artifact),
28
+ preflightSha256: payload.preflightSha256,
29
+ logicalEnvelopeSha256: payload.logicalEnvelopeSha256,
30
+ sourceCommit: payload.sourceCommit,
31
+ roleMapSha256: payload.roleMapSha256,
32
+ oidcAudienceSha256: sha256(payload.oidcAudience),
33
+ issuedAt: payload.issuedAt,
34
+ expiresAt: payload.expiresAt,
35
+ mutationDeadline: payload.mutationDeadline,
36
+ cleanupDeadline: payload.cleanupDeadline,
37
+ status: 'active',
38
+ hardStoppedAt: null,
39
+ createdAt: payload.issuedAt,
40
+ updatedAt: payload.issuedAt,
41
+ [verifiedCapabilityRecordBrand]: true,
42
+ };
43
+ }
44
+ export function executorPhaseAGrantRecordFromVerified(bundle, tokenId) {
45
+ const payload = bundle.grant.payload;
46
+ if (!/^token-[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/.test(tokenId)) {
47
+ throw new ExecutorPhaseARunAuthorizationError('The workload token ID is invalid.');
48
+ }
49
+ return {
50
+ grantId: payload.grantId,
51
+ capabilityId: payload.capabilityId,
52
+ workspaceId: payload.workspaceId,
53
+ taskId: payload.taskId,
54
+ runId: payload.runId,
55
+ receiptId: payload.receiptId,
56
+ phase: payload.phase,
57
+ roleArn: payload.roleArn,
58
+ grantSha256: bundle.grantSha256,
59
+ tokenId,
60
+ nonceId: payload.nonceId,
61
+ senderProofSha256: bundle.senderProofSha256,
62
+ brokerKeyFingerprint: payload.brokerKeyFingerprint,
63
+ sourceIdentity: payload.sourceIdentity,
64
+ sessionTagsSha256: sha256(payload.sessionTags),
65
+ policySha256: payload.policySha256,
66
+ issuedAt: payload.issuedAt,
67
+ expiresAt: payload.expiresAt,
68
+ usedAt: null,
69
+ status: 'issued',
70
+ createdAt: payload.issuedAt,
71
+ updatedAt: payload.issuedAt,
72
+ [verifiedGrantRecordBrand]: true,
73
+ };
74
+ }
75
+ export class ExecutorPhaseARunAuthorizationError extends Error {
76
+ code = 'executor_phase_a_run_authorization_invalid';
77
+ constructor(message) {
78
+ super(message);
79
+ this.name = 'ExecutorPhaseARunAuthorizationError';
80
+ }
81
+ }
82
+ function timestamp(value, field) {
83
+ const parsed = Date.parse(value);
84
+ if (!Number.isFinite(parsed))
85
+ throw new ExecutorPhaseARunAuthorizationError(`${field} is invalid.`);
86
+ return parsed;
87
+ }
88
+ function isUniqueConstraintError(error) {
89
+ const code = error && typeof error === 'object' && typeof error.code === 'string'
90
+ ? String(error.code)
91
+ : '';
92
+ return code === '23505'
93
+ || code === 'SQLITE_CONSTRAINT_UNIQUE'
94
+ || code === 'SQLITE_CONSTRAINT_PRIMARYKEY';
95
+ }
96
+ function capabilityFromRow(row) {
97
+ return {
98
+ capabilityId: String(row.capability_id),
99
+ workspaceId: String(row.workspace_id),
100
+ taskId: String(row.task_id),
101
+ runId: String(row.run_id),
102
+ receiptId: String(row.receipt_id),
103
+ receiptSha256: String(row.receipt_sha256),
104
+ capabilityKind: String(row.capability_kind),
105
+ originalCapabilityId: row.original_capability_id == null ? null : String(row.original_capability_id),
106
+ residualInventorySha256: row.residual_inventory_sha256 == null ? null : String(row.residual_inventory_sha256),
107
+ actorUserId: String(row.actor_user_id),
108
+ accountId: String(row.account_id),
109
+ region: String(row.region),
110
+ availabilityZone: String(row.availability_zone),
111
+ readPrincipalArn: String(row.read_principal_arn),
112
+ brokerKeyFingerprint: String(row.broker_key_fingerprint),
113
+ capabilitySha256: String(row.capability_sha256),
114
+ preflightSha256: String(row.preflight_sha256),
115
+ logicalEnvelopeSha256: String(row.logical_envelope_sha256),
116
+ sourceCommit: String(row.source_commit),
117
+ roleMapSha256: String(row.role_map_sha256),
118
+ oidcAudienceSha256: String(row.oidc_audience_sha256),
119
+ issuedAt: String(row.issued_at),
120
+ expiresAt: String(row.expires_at),
121
+ mutationDeadline: String(row.mutation_deadline),
122
+ cleanupDeadline: String(row.cleanup_deadline),
123
+ status: String(row.status),
124
+ hardStoppedAt: row.hard_stopped_at == null ? null : String(row.hard_stopped_at),
125
+ createdAt: String(row.created_at),
126
+ updatedAt: String(row.updated_at),
127
+ };
128
+ }
129
+ function grantFromRow(row) {
130
+ return {
131
+ grantId: String(row.grant_id),
132
+ capabilityId: String(row.capability_id),
133
+ workspaceId: String(row.workspace_id),
134
+ taskId: String(row.task_id),
135
+ runId: String(row.run_id),
136
+ receiptId: String(row.receipt_id),
137
+ phase: String(row.phase),
138
+ roleArn: String(row.role_arn),
139
+ grantSha256: String(row.grant_sha256),
140
+ tokenId: String(row.token_id),
141
+ nonceId: String(row.nonce_id),
142
+ senderProofSha256: String(row.sender_proof_sha256),
143
+ brokerKeyFingerprint: String(row.broker_key_fingerprint),
144
+ sourceIdentity: String(row.source_identity),
145
+ sessionTagsSha256: String(row.session_tags_sha256),
146
+ policySha256: String(row.policy_sha256),
147
+ issuedAt: String(row.issued_at),
148
+ expiresAt: String(row.expires_at),
149
+ usedAt: row.used_at == null ? null : String(row.used_at),
150
+ status: String(row.status),
151
+ createdAt: String(row.created_at),
152
+ updatedAt: String(row.updated_at),
153
+ };
154
+ }
155
+ function nonceFromRow(row) {
156
+ return {
157
+ nonceId: String(row.nonce_id),
158
+ capabilityId: String(row.capability_id),
159
+ requestSha256: String(row.request_sha256),
160
+ phase: String(row.phase),
161
+ issuedAt: String(row.issued_at),
162
+ expiresAt: String(row.expires_at),
163
+ consumedAt: row.consumed_at == null ? null : String(row.consumed_at),
164
+ status: String(row.status),
165
+ createdAt: String(row.created_at),
166
+ updatedAt: String(row.updated_at),
167
+ };
168
+ }
169
+ export class ExecutorPhaseARunAuthorizationStore {
170
+ db;
171
+ tenantId;
172
+ constructor(db, tenantId) {
173
+ this.db = db;
174
+ this.tenantId = tenantId;
175
+ }
176
+ findCapability(capabilityId) {
177
+ const row = this.db.prepare(`
178
+ SELECT * FROM executor_phase_a_run_capabilities
179
+ WHERE tenant_id = ? AND capability_id = ?
180
+ LIMIT 1
181
+ `).get(this.tenantId, capabilityId);
182
+ return row ? capabilityFromRow(row) : null;
183
+ }
184
+ persistCapability(candidate) {
185
+ this.assertCapability(candidate);
186
+ try {
187
+ this.db.prepare(`
188
+ INSERT INTO executor_phase_a_run_capabilities (
189
+ capability_id, tenant_id, workspace_id, task_id, run_id, receipt_id, receipt_sha256,
190
+ capability_kind, original_capability_id, residual_inventory_sha256, actor_user_id,
191
+ account_id, region, availability_zone, read_principal_arn, broker_key_fingerprint,
192
+ capability_sha256, preflight_sha256, logical_envelope_sha256, source_commit,
193
+ role_map_sha256, oidc_audience_sha256, issued_at, expires_at, mutation_deadline,
194
+ cleanup_deadline, status, hard_stopped_at, created_at, updated_at
195
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
196
+ `).run(candidate.capabilityId, this.tenantId, candidate.workspaceId, candidate.taskId, candidate.runId, candidate.receiptId, candidate.receiptSha256, candidate.capabilityKind, candidate.originalCapabilityId, candidate.residualInventorySha256, candidate.actorUserId, candidate.accountId, candidate.region, candidate.availabilityZone, candidate.readPrincipalArn, candidate.brokerKeyFingerprint, candidate.capabilitySha256, candidate.preflightSha256, candidate.logicalEnvelopeSha256, candidate.sourceCommit, candidate.roleMapSha256, candidate.oidcAudienceSha256, candidate.issuedAt, candidate.expiresAt, candidate.mutationDeadline, candidate.cleanupDeadline, candidate.status, candidate.hardStoppedAt, candidate.createdAt, candidate.updatedAt);
197
+ }
198
+ catch (error) {
199
+ if (!isUniqueConstraintError(error))
200
+ throw error;
201
+ throw new ExecutorPhaseARunAuthorizationError('The receipt, broker key, or capability is already bound to a Phase A run.');
202
+ }
203
+ return this.findCapability(candidate.capabilityId);
204
+ }
205
+ hardStop(capabilityId, stoppedAt) {
206
+ timestamp(stoppedAt, 'hardStoppedAt');
207
+ const stop = this.db.transaction(() => {
208
+ const result = this.db.prepare(`
209
+ UPDATE executor_phase_a_run_capabilities
210
+ SET status = 'awaiting-cleanup-approval', hard_stopped_at = ?, updated_at = ?
211
+ WHERE tenant_id = ? AND capability_id = ? AND capability_kind = 'main' AND status = 'active'
212
+ `).run(stoppedAt, stoppedAt, this.tenantId, capabilityId);
213
+ if (Number(result.changes ?? result.rowCount ?? 0) !== 1) {
214
+ throw new ExecutorPhaseARunAuthorizationError('Only one active main capability can be hard-stopped.');
215
+ }
216
+ this.db.prepare(`
217
+ UPDATE executor_phase_a_sender_nonces
218
+ SET status = 'revoked', updated_at = ?
219
+ WHERE tenant_id = ? AND capability_id = ? AND status = 'issued'
220
+ `).run(stoppedAt, this.tenantId, capabilityId);
221
+ this.db.prepare(`
222
+ UPDATE executor_phase_a_workload_grants
223
+ SET status = 'revoked', updated_at = ?
224
+ WHERE tenant_id = ? AND capability_id = ? AND status = 'issued'
225
+ `).run(stoppedAt, this.tenantId, capabilityId);
226
+ return this.findCapability(capabilityId);
227
+ });
228
+ return stop();
229
+ }
230
+ issueNonce(candidate) {
231
+ const issue = this.db.transaction(() => {
232
+ const capability = this.findCapability(candidate.capabilityId);
233
+ const issuedAt = timestamp(candidate.issuedAt, 'issuedAt');
234
+ const expiresAt = timestamp(candidate.expiresAt, 'expiresAt');
235
+ if (!capability || capability.status !== 'active') {
236
+ throw new ExecutorPhaseARunAuthorizationError('The sender nonce is not valid for an active capability.');
237
+ }
238
+ const phaseDeadline = timestamp(candidate.phase === 'cleanup' ? capability.cleanupDeadline : capability.mutationDeadline, candidate.phase === 'cleanup' ? 'cleanupDeadline' : 'mutationDeadline');
239
+ if (candidate.status !== 'issued' || candidate.consumedAt !== null
240
+ || expiresAt <= issuedAt || expiresAt - issuedAt > 2 * 60 * 1000
241
+ || issuedAt >= phaseDeadline || expiresAt > phaseDeadline
242
+ || !/^[a-f0-9]{64}$/.test(candidate.requestSha256)
243
+ || (capability.capabilityKind === 'cleanup-only' && candidate.phase !== 'cleanup')) {
244
+ throw new ExecutorPhaseARunAuthorizationError('The sender nonce is not valid for an active capability.');
245
+ }
246
+ const guard = this.db.prepare(`
247
+ UPDATE executor_phase_a_run_capabilities
248
+ SET updated_at = updated_at
249
+ WHERE tenant_id = ? AND capability_id = ? AND status = 'active'
250
+ `).run(this.tenantId, candidate.capabilityId);
251
+ if (Number(guard.changes ?? guard.rowCount ?? 0) !== 1) {
252
+ throw new ExecutorPhaseARunAuthorizationError('The run capability was revoked before nonce issuance.');
253
+ }
254
+ try {
255
+ this.db.prepare(`
256
+ INSERT INTO executor_phase_a_sender_nonces (
257
+ nonce_id, tenant_id, capability_id, request_sha256, phase, issued_at, expires_at,
258
+ consumed_at, status, created_at, updated_at
259
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
260
+ `).run(candidate.nonceId, this.tenantId, candidate.capabilityId, candidate.requestSha256, candidate.phase, candidate.issuedAt, candidate.expiresAt, candidate.consumedAt, candidate.status, candidate.createdAt, candidate.updatedAt);
261
+ }
262
+ catch (error) {
263
+ if (!isUniqueConstraintError(error))
264
+ throw error;
265
+ throw new ExecutorPhaseARunAuthorizationError('The sender nonce is already registered.');
266
+ }
267
+ const row = this.db.prepare(`
268
+ SELECT * FROM executor_phase_a_sender_nonces WHERE tenant_id = ? AND nonce_id = ?
269
+ `).get(this.tenantId, candidate.nonceId);
270
+ return nonceFromRow(row);
271
+ });
272
+ return issue();
273
+ }
274
+ persistGrant(candidate, now) {
275
+ const persist = this.db.transaction(() => {
276
+ const capability = this.findCapability(candidate.capabilityId);
277
+ if (!capability || capability.status !== 'active') {
278
+ throw new ExecutorPhaseARunAuthorizationError('The run capability is unavailable or revoked.');
279
+ }
280
+ if (candidate.status !== 'issued' || candidate.usedAt !== null) {
281
+ throw new ExecutorPhaseARunAuthorizationError('A new workload grant must begin issued and unused.');
282
+ }
283
+ if (candidate.workspaceId !== capability.workspaceId || candidate.taskId !== capability.taskId
284
+ || candidate.runId !== capability.runId || candidate.receiptId !== capability.receiptId
285
+ || candidate.brokerKeyFingerprint !== capability.brokerKeyFingerprint) {
286
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant scope differs from its run capability.');
287
+ }
288
+ const nowMs = timestamp(now, 'now');
289
+ const issuedAt = timestamp(candidate.issuedAt, 'issuedAt');
290
+ const expiresAt = timestamp(candidate.expiresAt, 'expiresAt');
291
+ if (issuedAt !== nowMs || expiresAt <= issuedAt || expiresAt - issuedAt > 2 * 60 * 1000) {
292
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant lifetime is invalid.');
293
+ }
294
+ if (capability.capabilityKind === 'cleanup-only' && candidate.phase !== 'cleanup') {
295
+ throw new ExecutorPhaseARunAuthorizationError('A cleanup-only capability cannot issue a mutation grant.');
296
+ }
297
+ const deadline = candidate.phase === 'cleanup'
298
+ ? timestamp(capability.cleanupDeadline, 'cleanupDeadline')
299
+ : timestamp(capability.mutationDeadline, 'mutationDeadline');
300
+ if (nowMs >= deadline || expiresAt > deadline) {
301
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant exceeds the approved phase deadline.');
302
+ }
303
+ const guard = this.db.prepare(`
304
+ UPDATE executor_phase_a_run_capabilities
305
+ SET updated_at = updated_at
306
+ WHERE tenant_id = ? AND capability_id = ? AND status = 'active'
307
+ `).run(this.tenantId, candidate.capabilityId);
308
+ if (Number(guard.changes ?? guard.rowCount ?? 0) !== 1) {
309
+ throw new ExecutorPhaseARunAuthorizationError('The run capability was revoked before grant issuance.');
310
+ }
311
+ const nonce = this.db.prepare(`
312
+ SELECT * FROM executor_phase_a_sender_nonces
313
+ WHERE tenant_id = ? AND capability_id = ? AND nonce_id = ?
314
+ `).get(this.tenantId, candidate.capabilityId, candidate.nonceId);
315
+ if (!nonce || nonce.status !== 'issued' || nonce.phase !== candidate.phase
316
+ || timestamp(String(nonce.expires_at), 'nonceExpiresAt') <= nowMs) {
317
+ throw new ExecutorPhaseARunAuthorizationError('The sender nonce is missing, expired, consumed, or bound to another phase.');
318
+ }
319
+ const consumed = this.db.prepare(`
320
+ UPDATE executor_phase_a_sender_nonces
321
+ SET status = 'consumed', consumed_at = ?, updated_at = ?
322
+ WHERE tenant_id = ? AND capability_id = ? AND nonce_id = ? AND status = 'issued'
323
+ `).run(now, now, this.tenantId, candidate.capabilityId, candidate.nonceId);
324
+ if (Number(consumed.changes ?? consumed.rowCount ?? 0) !== 1) {
325
+ throw new ExecutorPhaseARunAuthorizationError('The sender nonce was already consumed.');
326
+ }
327
+ try {
328
+ this.db.prepare(`
329
+ INSERT INTO executor_phase_a_workload_grants (
330
+ grant_id, tenant_id, capability_id, workspace_id, task_id, run_id, receipt_id,
331
+ phase, role_arn, grant_sha256, token_id, nonce_id, sender_proof_sha256, broker_key_fingerprint,
332
+ source_identity, session_tags_sha256, policy_sha256, issued_at, expires_at,
333
+ used_at, status, created_at, updated_at
334
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
335
+ `).run(candidate.grantId, this.tenantId, candidate.capabilityId, candidate.workspaceId, candidate.taskId, candidate.runId, candidate.receiptId, candidate.phase, candidate.roleArn, candidate.grantSha256, candidate.tokenId, candidate.nonceId, candidate.senderProofSha256, candidate.brokerKeyFingerprint, candidate.sourceIdentity, candidate.sessionTagsSha256, candidate.policySha256, candidate.issuedAt, candidate.expiresAt, candidate.usedAt, candidate.status, candidate.createdAt, candidate.updatedAt);
336
+ }
337
+ catch (error) {
338
+ if (!isUniqueConstraintError(error))
339
+ throw error;
340
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant token or sender proof was already used.');
341
+ }
342
+ const row = this.db.prepare(`
343
+ SELECT * FROM executor_phase_a_workload_grants
344
+ WHERE tenant_id = ? AND grant_id = ?
345
+ `).get(this.tenantId, candidate.grantId);
346
+ return grantFromRow(row);
347
+ });
348
+ return persist();
349
+ }
350
+ redeemVerifiedGrant(bundle, requestId, requestSha256, canonicalResponseBytes, responseSha256, usedAt) {
351
+ if (!/^issuer-request-[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/.test(requestId)
352
+ || !/^[a-f0-9]{64}$/.test(requestSha256)
353
+ || createHash('sha256').update(canonicalResponseBytes).digest('hex') !== responseSha256) {
354
+ throw new ExecutorPhaseARunAuthorizationError('The issuer redemption record is invalid.');
355
+ }
356
+ timestamp(usedAt, 'usedAt');
357
+ const use = this.db.transaction(() => {
358
+ const readExisting = () => {
359
+ const existing = this.db.prepare(`
360
+ SELECT grant_id, grant_sha256, sender_proof_sha256, request_sha256,
361
+ canonical_response_bytes, response_sha256
362
+ FROM executor_phase_a_issuer_redemptions
363
+ WHERE tenant_id = ? AND request_id = ?
364
+ `).get(this.tenantId, requestId);
365
+ if (!existing)
366
+ return null;
367
+ if (String(existing.grant_id) !== bundle.grant.payload.grantId
368
+ || String(existing.grant_sha256) !== bundle.grantSha256
369
+ || String(existing.sender_proof_sha256) !== bundle.senderProofSha256
370
+ || String(existing.request_sha256) !== requestSha256) {
371
+ throw new ExecutorPhaseARunAuthorizationError('The issuer request ID was already used for different redemption bytes.');
372
+ }
373
+ return {
374
+ bytes: Buffer.from(existing.canonical_response_bytes),
375
+ digest: String(existing.response_sha256),
376
+ created: false,
377
+ status: 'used',
378
+ };
379
+ };
380
+ const existing = readExisting();
381
+ if (existing)
382
+ return existing;
383
+ const grantId = bundle.grant.payload.grantId;
384
+ const row = this.db.prepare(`
385
+ SELECT capability_id, phase, expires_at FROM executor_phase_a_workload_grants
386
+ WHERE tenant_id = ? AND grant_id = ? AND status = 'issued'
387
+ AND grant_sha256 = ? AND sender_proof_sha256 = ?
388
+ `).get(this.tenantId, grantId, bundle.grantSha256, bundle.senderProofSha256);
389
+ const capability = row?.capability_id ? this.findCapability(row.capability_id) : null;
390
+ const usedAtMs = timestamp(usedAt, 'usedAt');
391
+ const phaseDeadline = capability && row?.phase
392
+ ? timestamp(row.phase === 'cleanup' ? capability.cleanupDeadline : capability.mutationDeadline, 'phaseDeadline')
393
+ : Number.NaN;
394
+ if (!row?.capability_id || !row.phase || !row.expires_at || !capability || capability.status !== 'active'
395
+ || usedAtMs >= timestamp(row.expires_at, 'grantExpiresAt') || usedAtMs >= phaseDeadline) {
396
+ const retry = readExisting();
397
+ if (retry)
398
+ return retry;
399
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant is unavailable or revoked.');
400
+ }
401
+ const guard = this.db.prepare(`
402
+ UPDATE executor_phase_a_run_capabilities
403
+ SET updated_at = updated_at
404
+ WHERE tenant_id = ? AND capability_id = ? AND status = 'active'
405
+ `).run(this.tenantId, row.capability_id);
406
+ if (Number(guard.changes ?? guard.rowCount ?? 0) !== 1) {
407
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant capability was hard-stopped before redemption.');
408
+ }
409
+ const result = this.db.prepare(`
410
+ UPDATE executor_phase_a_workload_grants
411
+ SET status = 'used', used_at = ?, updated_at = ?
412
+ WHERE tenant_id = ? AND grant_id = ? AND status = 'issued'
413
+ `).run(usedAt, usedAt, this.tenantId, grantId);
414
+ if (Number(result.changes ?? result.rowCount ?? 0) !== 1) {
415
+ const retry = readExisting();
416
+ if (retry)
417
+ return retry;
418
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant was already consumed or revoked.');
419
+ }
420
+ const inserted = this.db.prepare(`
421
+ INSERT INTO executor_phase_a_issuer_redemptions (
422
+ request_id, tenant_id, grant_id, grant_sha256, sender_proof_sha256,
423
+ request_sha256, canonical_response_bytes, response_sha256, redeemed_at
424
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
425
+ ON CONFLICT DO NOTHING
426
+ `).run(requestId, this.tenantId, grantId, bundle.grantSha256, bundle.senderProofSha256, requestSha256, canonicalResponseBytes, responseSha256, usedAt);
427
+ if (Number(inserted.changes ?? inserted.rowCount ?? 0) !== 1) {
428
+ const retry = readExisting();
429
+ if (retry)
430
+ return retry;
431
+ throw new ExecutorPhaseARunAuthorizationError('The workload grant or issuer request was already redeemed.');
432
+ }
433
+ return { bytes: canonicalResponseBytes, digest: responseSha256, created: true, status: 'used' };
434
+ });
435
+ return use();
436
+ }
437
+ assertCapability(candidate) {
438
+ if (candidate.status !== 'active' || candidate.hardStoppedAt !== null) {
439
+ throw new ExecutorPhaseARunAuthorizationError('A new run capability must begin active and not hard-stopped.');
440
+ }
441
+ const issuedAt = timestamp(candidate.issuedAt, 'issuedAt');
442
+ const expiresAt = timestamp(candidate.expiresAt, 'expiresAt');
443
+ const mutationDeadline = timestamp(candidate.mutationDeadline, 'mutationDeadline');
444
+ const cleanupDeadline = timestamp(candidate.cleanupDeadline, 'cleanupDeadline');
445
+ const receipt = this.db.prepare(`
446
+ SELECT receipt_kind, original_capability_id, residual_inventory_sha256,
447
+ receipt_sha256, approved_at, expires_at
448
+ FROM executor_phase_a_approval_receipts
449
+ WHERE tenant_id = ? AND receipt_id = ?
450
+ LIMIT 1
451
+ `).get(this.tenantId, candidate.receiptId);
452
+ const receiptApprovedAt = receipt ? timestamp(String(receipt.approved_at), 'receipt.approvedAt') : NaN;
453
+ const receiptExpiresAt = receipt ? timestamp(String(receipt.expires_at), 'receipt.expiresAt') : NaN;
454
+ if (!receipt || String(receipt.receipt_sha256) !== candidate.receiptSha256
455
+ || String(receipt.receipt_kind) !== candidate.capabilityKind
456
+ || (receipt.original_capability_id == null ? null : String(receipt.original_capability_id)) !== candidate.originalCapabilityId
457
+ || (receipt.residual_inventory_sha256 == null ? null : String(receipt.residual_inventory_sha256)) !== candidate.residualInventorySha256
458
+ || issuedAt < receiptApprovedAt || issuedAt >= receiptExpiresAt || issuedAt >= cleanupDeadline) {
459
+ throw new ExecutorPhaseARunAuthorizationError('The run capability is not bound to a durable approval receipt.');
460
+ }
461
+ if (candidate.capabilityKind === 'main') {
462
+ if (candidate.originalCapabilityId !== null || candidate.residualInventorySha256 !== null
463
+ || mutationDeadline !== receiptApprovedAt + 8 * 60 * 60 * 1000
464
+ || cleanupDeadline !== receiptApprovedAt + EXECUTOR_PHASE_A_MAIN_CAPABILITY_TTL_MS
465
+ || expiresAt !== cleanupDeadline) {
466
+ throw new ExecutorPhaseARunAuthorizationError('The main capability lifetime or ancestry is invalid.');
467
+ }
468
+ return;
469
+ }
470
+ const original = candidate.originalCapabilityId
471
+ ? this.findCapability(candidate.originalCapabilityId)
472
+ : null;
473
+ if (!original || original.capabilityKind !== 'main' || original.status !== 'awaiting-cleanup-approval'
474
+ || !candidate.residualInventorySha256 || !/^[a-f0-9]{64}$/.test(candidate.residualInventorySha256)
475
+ || original.workspaceId !== candidate.workspaceId || original.taskId !== candidate.taskId
476
+ || original.runId !== candidate.runId
477
+ || original.accountId !== candidate.accountId || original.region !== candidate.region
478
+ || original.availabilityZone !== candidate.availabilityZone
479
+ || original.readPrincipalArn !== candidate.readPrincipalArn
480
+ || original.brokerKeyFingerprint !== candidate.brokerKeyFingerprint
481
+ || original.preflightSha256 !== candidate.preflightSha256
482
+ || original.logicalEnvelopeSha256 !== candidate.logicalEnvelopeSha256
483
+ || original.sourceCommit !== candidate.sourceCommit
484
+ || original.roleMapSha256 !== candidate.roleMapSha256
485
+ || original.oidcAudienceSha256 !== candidate.oidcAudienceSha256
486
+ || original.receiptId === candidate.receiptId
487
+ || mutationDeadline !== receiptApprovedAt || cleanupDeadline !== expiresAt
488
+ || cleanupDeadline !== receiptApprovedAt + EXECUTOR_PHASE_A_CLEANUP_CAPABILITY_TTL_MS) {
489
+ throw new ExecutorPhaseARunAuthorizationError('The cleanup capability requires a hard-stopped main run and a distinct bounded receipt.');
490
+ }
491
+ }
492
+ }
@@ -0,0 +1,26 @@
1
+ import type { DatabaseAdapter } from './databaseAdapter.js';
2
+ export interface GitHubReviewEvidenceInstallationBinding {
3
+ workspaceId: string;
4
+ installationId: string;
5
+ accountId: string;
6
+ accountLogin: string;
7
+ accountType: string;
8
+ repositorySelection: string;
9
+ boundByUserId: string;
10
+ createdAt: string;
11
+ updatedAt: string;
12
+ }
13
+ export declare class GitHubReviewEvidenceInstallationConflictError extends Error {
14
+ readonly code = "github_installation_already_bound";
15
+ readonly statusCode = 409;
16
+ constructor();
17
+ }
18
+ export declare class GitHubReviewEvidenceInstallationStore {
19
+ private readonly db;
20
+ private readonly tenantId;
21
+ private readonly now;
22
+ constructor(db: DatabaseAdapter, tenantId: string, now?: () => Date);
23
+ get(workspaceId: string): GitHubReviewEvidenceInstallationBinding | null;
24
+ put(input: Omit<GitHubReviewEvidenceInstallationBinding, 'createdAt' | 'updatedAt'>): GitHubReviewEvidenceInstallationBinding;
25
+ delete(workspaceId: string): boolean;
26
+ }
@@ -0,0 +1,89 @@
1
+ export class GitHubReviewEvidenceInstallationConflictError extends Error {
2
+ code = 'github_installation_already_bound';
3
+ statusCode = 409;
4
+ constructor() {
5
+ super('This GitHub App installation is already bound to another workspace.');
6
+ this.name = 'GitHubReviewEvidenceInstallationConflictError';
7
+ }
8
+ }
9
+ export class GitHubReviewEvidenceInstallationStore {
10
+ db;
11
+ tenantId;
12
+ now;
13
+ constructor(db, tenantId, now = () => new Date()) {
14
+ this.db = db;
15
+ this.tenantId = tenantId;
16
+ this.now = now;
17
+ }
18
+ get(workspaceId) {
19
+ const normalizedWorkspaceId = String(workspaceId || '').trim();
20
+ if (!normalizedWorkspaceId)
21
+ return null;
22
+ const row = this.db.prepare(`
23
+ SELECT *
24
+ FROM github_review_evidence_installation_bindings
25
+ WHERE tenant_id = ? AND workspace_id = ?
26
+ LIMIT 1
27
+ `).get(this.tenantId, normalizedWorkspaceId);
28
+ if (!row)
29
+ return null;
30
+ return {
31
+ workspaceId: String(row.workspace_id || ''),
32
+ installationId: String(row.installation_id || ''),
33
+ accountId: String(row.account_id || ''),
34
+ accountLogin: String(row.account_login || ''),
35
+ accountType: String(row.account_type || ''),
36
+ repositorySelection: String(row.repository_selection || ''),
37
+ boundByUserId: String(row.bound_by_user_id || ''),
38
+ createdAt: String(row.created_at || ''),
39
+ updatedAt: String(row.updated_at || ''),
40
+ };
41
+ }
42
+ put(input) {
43
+ const workspaceId = String(input.workspaceId || '').trim();
44
+ if (!workspaceId)
45
+ throw new Error('workspaceId is required.');
46
+ const installationId = String(input.installationId || '').trim();
47
+ const accountId = String(input.accountId || '').trim();
48
+ const accountLogin = String(input.accountLogin || '').trim();
49
+ const boundByUserId = String(input.boundByUserId || '').trim();
50
+ if (!installationId || !accountId || !accountLogin || !boundByUserId) {
51
+ throw new Error('Installation, account, and binding actor are required.');
52
+ }
53
+ const now = this.now().toISOString();
54
+ try {
55
+ this.db.prepare(`
56
+ INSERT INTO github_review_evidence_installation_bindings (
57
+ tenant_id, workspace_id, installation_id, account_id, account_login,
58
+ account_type, repository_selection, bound_by_user_id, created_at, updated_at
59
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
60
+ ON CONFLICT (tenant_id, workspace_id) DO UPDATE SET
61
+ installation_id = EXCLUDED.installation_id,
62
+ account_id = EXCLUDED.account_id,
63
+ account_login = EXCLUDED.account_login,
64
+ account_type = EXCLUDED.account_type,
65
+ repository_selection = EXCLUDED.repository_selection,
66
+ bound_by_user_id = EXCLUDED.bound_by_user_id,
67
+ updated_at = EXCLUDED.updated_at
68
+ `).run(this.tenantId, workspaceId, installationId, accountId, accountLogin, String(input.accountType || 'unknown').trim() || 'unknown', String(input.repositorySelection || 'selected').trim() || 'selected', boundByUserId, now, now);
69
+ }
70
+ catch (error) {
71
+ const message = String(error?.message || '').toLowerCase();
72
+ if (message.includes('unique') || message.includes('duplicate')) {
73
+ throw new GitHubReviewEvidenceInstallationConflictError();
74
+ }
75
+ throw error;
76
+ }
77
+ return this.get(workspaceId);
78
+ }
79
+ delete(workspaceId) {
80
+ const normalizedWorkspaceId = String(workspaceId || '').trim();
81
+ if (!normalizedWorkspaceId)
82
+ return false;
83
+ const result = this.db.prepare(`
84
+ DELETE FROM github_review_evidence_installation_bindings
85
+ WHERE tenant_id = ? AND workspace_id = ?
86
+ `).run(this.tenantId, normalizedWorkspaceId);
87
+ return Number(result?.changes || 0) > 0;
88
+ }
89
+ }