@taskforcehq/taskforce 0.3.327 → 0.3.329

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 (360) hide show
  1. package/dist/Taskforce.module.css +257 -87
  2. package/dist/TaskforceCore.js +237 -230
  3. package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
  4. package/dist/cli.js +34 -0
  5. package/dist/cliCloudTargetGuard.d.ts +5 -0
  6. package/dist/cliCloudTargetGuard.js +11 -0
  7. package/dist/components/activity/EntityActivityTimeline.js +15 -5
  8. package/dist/components/context/AttachmentPreviewHost.js +1 -1
  9. package/dist/components/context/ContextAttachmentManager.d.ts +3 -0
  10. package/dist/components/context/ContextAttachmentManager.js +116 -20
  11. package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
  12. package/dist/components/features/TaskSettings.d.ts +12 -1
  13. package/dist/components/features/TaskSettings.js +147 -40
  14. package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
  15. package/dist/components/features/planning/PlanningEntitySummary.d.ts +3 -1
  16. package/dist/components/features/planning/PlanningEntitySummary.js +3 -2
  17. package/dist/components/features/planning/PlanningLinkPicker.d.ts +3 -1
  18. package/dist/components/features/planning/PlanningLinkPicker.js +5 -3
  19. package/dist/components/features/planning/PlanningModule.js +28 -14
  20. package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
  21. package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
  22. package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
  23. package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
  24. package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
  25. package/dist/components/features/planning/planningTaskArrangement.js +5 -5
  26. package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
  27. package/dist/components/features/taskforceAgentEditorModel.js +3 -1
  28. package/dist/components/task/TaskActionHeader.d.ts +2 -1
  29. package/dist/components/task/TaskActionHeader.js +2 -2
  30. package/dist/components/task/TaskCard.d.ts +5 -0
  31. package/dist/components/task/TaskCard.js +101 -13
  32. package/dist/components/task/TaskContextUpload.d.ts +3 -0
  33. package/dist/components/task/TaskContextUpload.js +2 -2
  34. package/dist/components/task/TaskForm.d.ts +4 -0
  35. package/dist/components/task/TaskForm.js +32 -7
  36. package/dist/components/task/TaskImageReviews.js +28 -19
  37. package/dist/components/task/TaskKanban.d.ts +6 -1
  38. package/dist/components/task/TaskKanban.js +152 -6
  39. package/dist/components/task/TaskList.d.ts +5 -0
  40. package/dist/components/task/TaskList.js +3 -3
  41. package/dist/components/task/TaskStatusActions.js +11 -2
  42. package/dist/components/task/TaskWorkstreamPicker.js +2 -1
  43. package/dist/components/ui/DocumentTypeIcon.d.ts +7 -0
  44. package/dist/components/ui/DocumentTypeIcon.js +8 -0
  45. package/dist/components/ui/PasswordInput.d.ts +6 -0
  46. package/dist/components/ui/PasswordInput.js +11 -0
  47. package/dist/components/ui/TaxonomyDropdown.d.ts +9 -1
  48. package/dist/components/ui/TaxonomyDropdown.js +30 -3
  49. package/dist/components/ui/TopNoticeLayer.js +1 -1
  50. package/dist/components/views/AppShellHeader.js +32 -11
  51. package/dist/components/views/PlanComparisonPage.js +12 -0
  52. package/dist/components/views/StandaloneLayout.js +68 -39
  53. package/dist/components/views/WidgetView.js +10 -7
  54. package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
  55. package/dist/components/views/panels/PlanningDrawer.js +51 -54
  56. package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
  57. package/dist/config/envSchema.js +13 -0
  58. package/dist/config/localServiceCloudTarget.d.ts +10 -0
  59. package/dist/config/localServiceCloudTarget.js +76 -0
  60. package/dist/config/localServiceRuntimeContract.d.ts +13 -0
  61. package/dist/config/localServiceRuntimeContract.js +135 -0
  62. package/dist/core/AiProfileService.d.ts +1 -0
  63. package/dist/core/AiProfileService.js +48 -9
  64. package/dist/core/AttachmentLinkService.js +7 -4
  65. package/dist/core/DeletedTaskLifecycleService.d.ts +5 -0
  66. package/dist/core/DeletedTaskLifecycleService.js +55 -3
  67. package/dist/core/McpTokenService.d.ts +4 -0
  68. package/dist/core/McpTokenService.js +52 -0
  69. package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +8 -2
  70. package/dist/core/TaskAttachmentLinksDurableMutationService.js +51 -18
  71. package/dist/core/Taskforce.d.ts +124 -2
  72. package/dist/core/Taskforce.js +1175 -87
  73. package/dist/core/types.d.ts +8 -1
  74. package/dist/documentReviews/DocumentReviewCommentStore.d.ts +11 -0
  75. package/dist/documentReviews/DocumentReviewCommentStore.js +35 -2
  76. package/dist/documentReviews/service.d.ts +4 -0
  77. package/dist/documentReviews/service.js +141 -46
  78. package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
  79. package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
  80. package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
  81. package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
  82. package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
  83. package/dist/hooks/tasks/taskHttpMutation.js +1 -0
  84. package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
  85. package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
  86. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
  87. package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
  88. package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
  89. package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
  90. package/dist/hooks/tasks/useTaskFormActions.d.ts +9 -0
  91. package/dist/hooks/tasks/useTaskFormActions.js +96 -17
  92. package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
  93. package/dist/hooks/ui/useSettingsModel.js +13 -2
  94. package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
  95. package/dist/hooks/ui/useSettingsPersistence.js +74 -47
  96. package/dist/hooks/useFilterSort.d.ts +7 -3
  97. package/dist/hooks/useFilterSort.js +15 -5
  98. package/dist/hooks/useTaskData.d.ts +10 -1
  99. package/dist/hooks/useTaskData.js +216 -7
  100. package/dist/hooks/useTaskMutations.d.ts +10 -2
  101. package/dist/hooks/useTaskMutations.js +223 -43
  102. package/dist/hooks/useTaskforce.d.ts +94 -57
  103. package/dist/hooks/useTaskforce.js +428 -16
  104. package/dist/hooks/useUiNotice.d.ts +4 -0
  105. package/dist/hooks/useUiNotice.js +4 -0
  106. package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
  107. package/dist/mcp/canonicalAssetHelpers.d.ts +13 -0
  108. package/dist/mcp/canonicalAssetHelpers.js +39 -5
  109. package/dist/mcp/collaborationRegistrar.js +15 -13
  110. package/dist/mcp/documentAssetRegistrar.js +60 -44
  111. package/dist/mcp/documentHelpers.d.ts +1 -0
  112. package/dist/mcp/documentHelpers.js +7 -3
  113. package/dist/mcp/localServiceProxy.js +4 -1
  114. package/dist/mcp/runtime.d.ts +16 -0
  115. package/dist/mcp/runtime.js +735 -210
  116. package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
  117. package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
  118. package/dist/mcp/taskPlanningRegistrar.js +78 -67
  119. package/dist/mcp/toolCallCompatibility.js +38 -1
  120. package/dist/mcp/toolCatalog.d.ts +1 -0
  121. package/dist/mcp/toolRegistry.js +2 -2
  122. package/dist/migrations/taskSchemaMigrations.js +47 -0
  123. package/dist/runtime/appGateDefinitions.d.ts +30 -6
  124. package/dist/runtime/appGateDefinitions.js +6 -6
  125. package/dist/runtime/appGates.d.ts +12 -13
  126. package/dist/runtime/appGates.js +29 -13
  127. package/dist/runtime/nodeAppGates.d.ts +8 -0
  128. package/dist/runtime/nodeAppGates.js +27 -0
  129. package/dist/server/appAccess.d.ts +12 -0
  130. package/dist/server/appAccess.js +21 -0
  131. package/dist/server/authorizedWorkspaceAccess.d.ts +12 -0
  132. package/dist/server/authorizedWorkspaceAccess.js +40 -0
  133. package/dist/server/cloudCollectionRead.d.ts +25 -0
  134. package/dist/server/cloudCollectionRead.js +120 -0
  135. package/dist/server/cloudCollectionReadPool.d.ts +52 -0
  136. package/dist/server/cloudCollectionReadPool.js +140 -0
  137. package/dist/server/cloudCollectionReadWorker.d.ts +1 -0
  138. package/dist/server/cloudCollectionReadWorker.js +36 -0
  139. package/dist/server/index.d.ts +6 -11
  140. package/dist/server/index.js +67 -42
  141. package/dist/server/localServiceLease.d.ts +6 -0
  142. package/dist/server/localServiceLease.js +17 -1
  143. package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
  144. package/dist/server/rateLimit.d.ts +1 -0
  145. package/dist/server/rateLimit.js +4 -0
  146. package/dist/server/realtimeSyncWs.js +36 -12
  147. package/dist/server/routes/admin.js +1 -0
  148. package/dist/server/routes/agentRoles.js +3 -2
  149. package/dist/server/routes/agentSkills.js +3 -2
  150. package/dist/server/routes/agents.js +118 -16
  151. package/dist/server/routes/annotatedAttachments.js +3 -2
  152. package/dist/server/routes/auth.js +3 -1
  153. package/dist/server/routes/documents.d.ts +5 -2
  154. package/dist/server/routes/documents.js +160 -13
  155. package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
  156. package/dist/server/routes/durableTaskHttpRouters.js +2 -2
  157. package/dist/server/routes/localService.js +4 -0
  158. package/dist/server/routes/primitives.d.ts +4 -0
  159. package/dist/server/routes/shared.d.ts +24 -0
  160. package/dist/server/routes/shared.js +114 -18
  161. package/dist/server/routes/sync.js +22 -0
  162. package/dist/server/routes/syncAuxRoutes.js +5 -2
  163. package/dist/server/routes/syncPullApplyRoutes.js +23 -4
  164. package/dist/server/routes/syncV3FeedRoutes.js +22 -18
  165. package/dist/server/routes/syncV3LocalCaptureRoutes.js +48 -4
  166. package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
  167. package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
  168. package/dist/server/routes/syncV3OperationRoutes.js +27 -2
  169. package/dist/server/routes/tasks.js +299 -97
  170. package/dist/server/routes/workspaces.js +43 -1
  171. package/dist/server/routes.js +35 -7
  172. package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
  173. package/dist/server/workspaceDeletionAdmission.js +50 -0
  174. package/dist/service/localServiceCli.js +52 -25
  175. package/dist/service/localServiceClientLifecycle.js +93 -6
  176. package/dist/services/codexAppServerModelGateway.d.ts +112 -0
  177. package/dist/services/codexAppServerModelGateway.js +438 -0
  178. package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
  179. package/dist/services/taskforceAgentMcpBridge.js +23 -3
  180. package/dist/shared/planningIdentity.d.ts +20 -0
  181. package/dist/shared/planningIdentity.js +79 -0
  182. package/dist/shared/taskforceAgentDefinition.js +7 -1
  183. package/dist/shared/taskforceAgentModels.d.ts +1 -0
  184. package/dist/shared/taskforceAgentModels.js +30 -1
  185. package/dist/storage/postgresAdapter.d.ts +20 -3
  186. package/dist/storage/postgresAdapter.js +110 -14
  187. package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
  188. package/dist/storage/postgresRequestDiagnostics.js +24 -0
  189. package/dist/storage/postgresWorker.js +13 -4
  190. package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
  191. package/dist/storage/postgresWorkerProtocol.js +30 -0
  192. package/dist/storage/workspaceAssetStore.d.ts +32 -0
  193. package/dist/storage/workspaceAssetStore.js +70 -0
  194. package/dist/sync/cloudSyncApi.d.ts +4 -1
  195. package/dist/sync/cloudSyncApi.js +7 -2
  196. package/dist/sync/contentSyncState.d.ts +1 -1
  197. package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +17 -0
  198. package/dist/sync/coordinator/localSyncExecutionPermitStore.js +77 -23
  199. package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
  200. package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
  201. package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
  202. package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
  203. package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
  204. package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +16 -0
  205. package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
  206. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
  207. package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +46 -4
  208. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
  209. package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +51 -11
  210. package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
  211. package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
  212. package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +2 -0
  213. package/dist/sync/syncApplyHandlers.d.ts +3 -1
  214. package/dist/sync/syncApplyHandlers.js +29 -0
  215. package/dist/sync/syncService.d.ts +2 -0
  216. package/dist/sync/syncService.js +13 -1
  217. package/dist/sync/taskSyncPayload.d.ts +1 -0
  218. package/dist/sync/taskSyncPayload.js +6 -0
  219. package/dist/sync/v3/combinedFeedCapability.js +4 -0
  220. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +3 -0
  221. package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +31 -3
  222. package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
  223. package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
  224. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
  225. package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +47 -12
  226. package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
  227. package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
  228. package/dist/sync/v3/localInitiativeOutboxService.js +4 -2
  229. package/dist/sync/v3/localOutboxDispatcher.js +5 -1
  230. package/dist/sync/v3/localTaskAttachmentLinksOutboxHandler.js +12 -2
  231. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +3 -0
  232. package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +62 -10
  233. package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
  234. package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
  235. package/dist/sync/v3/localTaskMetadataClient.js +1 -0
  236. package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
  237. package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
  238. package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
  239. package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
  240. package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
  241. package/dist/sync/v3/localTaskStatusClient.js +6 -1
  242. package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
  243. package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
  244. package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
  245. package/dist/sync/v3/syncDurabilityStore.d.ts +15 -0
  246. package/dist/sync/v3/syncDurabilityStore.js +201 -43
  247. package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +7 -4
  248. package/dist/sync/v3/taskAttachmentLinksMutationService.js +37 -12
  249. package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
  250. package/dist/sync/v3/taskChecklistMutationService.js +4 -0
  251. package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
  252. package/dist/sync/v3/taskCreateMutationService.js +7 -4
  253. package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
  254. package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
  255. package/dist/sync/v3/taskMetadataMutationService.js +4 -0
  256. package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
  257. package/dist/sync/v3/taskRestoreMutationService.js +7 -4
  258. package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
  259. package/dist/sync/v3/taskStatusMutationService.js +4 -0
  260. package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
  261. package/dist/sync/v3/workflowAssignmentSync.js +3 -0
  262. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
  263. package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +14 -12
  264. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
  265. package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
  266. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
  267. package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
  268. package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +10 -1
  269. package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +15 -4
  270. package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +66 -13
  271. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +11 -0
  272. package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +57 -22
  273. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +10 -4
  274. package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -51
  275. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
  276. package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +120 -28
  277. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
  278. package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
  279. package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
  280. package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
  281. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
  282. package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
  283. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
  284. package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
  285. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
  286. package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
  287. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
  288. package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
  289. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
  290. package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
  291. package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
  292. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
  293. package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
  294. package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
  295. package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -0
  296. package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
  297. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
  298. package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
  299. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
  300. package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
  301. package/dist/sync/v3/workspaceSyncV3TaskRootProjection.d.ts +1 -1
  302. package/dist/sync/v3/workspaceSyncV3TaskRootProjection.js +1 -1
  303. package/dist/sync/workspacePullFeed.d.ts +6 -1
  304. package/dist/sync/workspacePullFeed.js +174 -162
  305. package/dist/sync/workspaceRepair.d.ts +3 -0
  306. package/dist/sync/workspaceRepair.js +67 -6
  307. package/dist/sync/workspaceSyncModel.d.ts +11 -0
  308. package/dist/sync/workspaceSyncModel.js +27 -2
  309. package/dist/types.d.ts +55 -1
  310. package/dist/types.js +6 -0
  311. package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
  312. package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
  313. package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
  314. package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
  315. package/dist/ui/assets/AssetTraySortControl-C8Rztyal.js +1 -0
  316. package/dist/ui/assets/ContextAttachmentManager-Cj3c7X9y.js +3 -0
  317. package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-B5uvzems.js} +4 -4
  318. package/dist/ui/assets/EntityActivityTimeline-BVFvCB5R.js +1 -0
  319. package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
  320. package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
  321. package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
  322. package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
  323. package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
  324. package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
  325. package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
  326. package/dist/ui/assets/WorkflowManagerModule-DEr5di_r.js +1 -0
  327. package/dist/ui/assets/index-I5zhdtgt.js +7 -0
  328. package/dist/ui/assets/index-VRFsx3wz.css +1 -0
  329. package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-D9Lpw-j4.js} +1 -1
  330. package/dist/ui/index.html +3 -3
  331. package/dist/utils/constants.d.ts +2 -2
  332. package/dist/utils/constants.js +1 -1
  333. package/dist/utils/contextAttachmentUpload.d.ts +2 -0
  334. package/dist/utils/contextAttachmentUpload.js +7 -0
  335. package/dist/utils/contextFiles.d.ts +1 -1
  336. package/dist/utils/contextFiles.js +4 -4
  337. package/dist/utils/taskActivity.d.ts +3 -2
  338. package/dist/utils/taskActivity.js +19 -2
  339. package/dist/utils/taskEditorReconciliation.d.ts +40 -0
  340. package/dist/utils/taskEditorReconciliation.js +217 -0
  341. package/dist/utils/taskNormalization.d.ts +1 -0
  342. package/dist/utils/taskNormalization.js +39 -0
  343. package/dist/utils/taskSearch.js +2 -2
  344. package/dist/utils/uiNotice.d.ts +4 -0
  345. package/package.json +21 -4
  346. package/dist/ui/assets/AiProfilesModule-DPxQeF9N.js +0 -1
  347. package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
  348. package/dist/ui/assets/AnnotatedAttachmentWorkspace-DHNYaNg6.js +0 -3
  349. package/dist/ui/assets/AssetTraySortControl-DphbyHVc.js +0 -1
  350. package/dist/ui/assets/ContextAttachmentManager-CMxSzHqc.js +0 -3
  351. package/dist/ui/assets/EntityActivityTimeline-pJ2ZjZ-k.js +0 -1
  352. package/dist/ui/assets/PlanningModule-CeTqXMMz.css +0 -1
  353. package/dist/ui/assets/PlanningModule-t5GbvVR9.js +0 -1
  354. package/dist/ui/assets/PlansPage-BVH_NfgT.js +0 -1
  355. package/dist/ui/assets/TaskContextUpload-Ds4LnDzV.css +0 -1
  356. package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
  357. package/dist/ui/assets/TaskSettings-xVsxSa0g.js +0 -12
  358. package/dist/ui/assets/WorkflowManagerModule-BKqIGVnF.js +0 -1
  359. package/dist/ui/assets/index-BzJlVnNS.css +0 -1
  360. package/dist/ui/assets/index-Cx7vZJHL.js +0 -7
@@ -17,9 +17,11 @@ import { parseJsonBody } from './primitives.js';
17
17
  import { resolveRequestAccess, createSessionTokenCookie, resolveSessionCookieAttributesForRequest, } from '../auth.js';
18
18
  import { isWorkspaceSwitchingEnabledForRuntime } from '../../shared/runtimeContract.js';
19
19
  import { getRouteTimingNow, logSlowBootstrapRoute, requestBootstrapTraceId, resolveErrorStatusCode, serializeJsonWithTiming, setServerTimingHeader } from './shared.js';
20
+ import { WorkspaceDeletionAdmission } from '../workspaceDeletionAdmission.js';
20
21
  // === SECTION: Registration ===
21
22
  export function registerWorkspaceRoutes(deps) {
22
23
  const { addRoute, core, context, ensureAppAccess, auditAuthAction, getObjectStorageClient, ensureWithinDir, sanitizeStorageSegment, sanitizeTaskIdForPath, normalizeDocumentPathInput, } = deps;
24
+ const workspaceDeletionAdmission = new WorkspaceDeletionAdmission();
23
25
  // === SECTION: Storage cleanup helper ===
24
26
  const cleanupDeletedWorkspaceStorage = async (summary) => {
25
27
  const warnings = [];
@@ -231,12 +233,49 @@ export function registerWorkspaceRoutes(deps) {
231
233
  res.end(JSON.stringify({ success: false, error: 'workspaceId is required.', code: 'WORKSPACE_ID_REQUIRED' }));
232
234
  return;
233
235
  }
234
- const resolvedAccess = core.resolveUserAccess(access.userId, targetWorkspaceId, 'member');
236
+ const writeAdmissionError = (decision) => {
237
+ res.setHeader('Retry-After', String(Math.max(1, Math.ceil(decision.retryAfterMs / 1_000))));
238
+ const inProgress = decision.code === 'WORKSPACE_DELETE_IN_PROGRESS';
239
+ res.writeHead(inProgress ? 409 : 429, { 'Content-Type': 'application/json' });
240
+ res.end(JSON.stringify({
241
+ success: false,
242
+ error: inProgress
243
+ ? 'Workspace deletion is already running for this workspace.'
244
+ : 'Workspace deletion was attempted recently. Wait before retrying.',
245
+ code: decision.code,
246
+ retryAfterMs: decision.retryAfterMs,
247
+ }));
248
+ };
249
+ const existingAdmission = workspaceDeletionAdmission.checkExisting(targetWorkspaceId);
250
+ if (existingAdmission) {
251
+ writeAdmissionError(existingAdmission);
252
+ return;
253
+ }
254
+ let resolvedAccess;
255
+ try {
256
+ resolvedAccess = core.resolveUserAccess(access.userId, targetWorkspaceId, 'member');
257
+ }
258
+ catch (error) {
259
+ const statusCode = resolveErrorStatusCode(error, 400);
260
+ res.writeHead(statusCode, { 'Content-Type': 'application/json' });
261
+ res.end(JSON.stringify({
262
+ success: false,
263
+ error: String(error?.message || 'Unable to resolve workspace access'),
264
+ code: error?.code,
265
+ }));
266
+ return;
267
+ }
235
268
  if (!resolvedAccess || resolvedAccess.role !== 'owner' || resolvedAccess.disabled) {
236
269
  res.writeHead(403, { 'Content-Type': 'application/json' });
237
270
  res.end(JSON.stringify({ success: false, error: 'Only workspace owners can delete this workspace.' }));
238
271
  return;
239
272
  }
273
+ const deletionAdmissionKey = targetWorkspaceId;
274
+ const admission = workspaceDeletionAdmission.acquire(deletionAdmissionKey);
275
+ if (!admission.allowed) {
276
+ writeAdmissionError(admission);
277
+ return;
278
+ }
240
279
  try {
241
280
  const deleted = core.deleteWorkspace({ workspaceId: targetWorkspaceId });
242
281
  const cleanupWarnings = await cleanupDeletedWorkspaceStorage(deleted);
@@ -277,6 +316,9 @@ export function registerWorkspaceRoutes(deps) {
277
316
  code: error?.code
278
317
  }));
279
318
  }
319
+ finally {
320
+ workspaceDeletionAdmission.settle(deletionAdmissionKey);
321
+ }
280
322
  });
281
323
  // === SECTION: Session workspace switch ===
282
324
  // POST /api/taskforce/session/workspace - Switch active workspace in auth session
@@ -602,7 +602,7 @@ export function createRoutes(core, context = {}) {
602
602
  taskId: input.taskId,
603
603
  workspaceId: input.workspaceId,
604
604
  action: 'task-attachments-changed',
605
- actor: 'user',
605
+ actor: String(input.actorRef || '').trim() || 'user',
606
606
  createdAt: input.createdAt || new Date().toISOString(),
607
607
  details: {
608
608
  changes: {
@@ -725,6 +725,7 @@ export function createRoutes(core, context = {}) {
725
725
  asset,
726
726
  beforeTask: taskBeforeLink,
727
727
  createdAt: asset.updatedAt,
728
+ actorRef: params.actorRef,
728
729
  });
729
730
  }
730
731
  }
@@ -788,7 +789,7 @@ export function createRoutes(core, context = {}) {
788
789
  return false;
789
790
  return /^workspaces\/[^/]+\/assets\/documents\/.+\.(md|markdown)$/.test(normalized);
790
791
  };
791
- const resolveCanonicalDocumentRead = async (params) => {
792
+ const resolveCanonicalContentRead = async (params) => {
792
793
  const resolvedObjectStorage = resolveEffectiveObjectStorageConfig();
793
794
  const objectStorageClient = getObjectStorageClient();
794
795
  const { basePath } = core.getPaths();
@@ -800,17 +801,19 @@ export function createRoutes(core, context = {}) {
800
801
  : params.asset.storageProvider === 'local'
801
802
  ? 'local'
802
803
  : null;
804
+ const contentKind = params.asset.kind === 'document' ? 'document' : 'asset';
805
+ const contentLabel = params.asset.kind === 'document' ? 'Document' : 'Asset';
803
806
  const resolvedContent = publishedContentResolver && resolverOwnedProvider
804
807
  ? publishedContentResolver.resolve({
805
808
  tenantId: core.getTenantId(),
806
809
  workspaceId: params.asset.workspaceId,
807
- kind: 'document',
810
+ kind: contentKind,
808
811
  logicalPath: logicalStorageKey,
809
812
  legacyProvider: resolverOwnedProvider
810
813
  })
811
814
  : {
812
815
  source: 'legacy',
813
- kind: 'document',
816
+ kind: contentKind,
814
817
  logicalPath: logicalStorageKey,
815
818
  physicalKey: logicalStorageKey,
816
819
  storageProvider: params.asset.storageProvider
@@ -818,6 +821,31 @@ export function createRoutes(core, context = {}) {
818
821
  if (resolvedContent.source === 'deleted') {
819
822
  return { statusCode: 404 };
820
823
  }
824
+ if (resolvedContent.source === 'versioned' && (resolvedContent.storageProvider !== params.asset.storageProvider
825
+ || resolvedContent.contentSha256 !== params.asset.contentSha256
826
+ || resolvedContent.sizeBytes !== params.asset.sizeBytes)) {
827
+ return {
828
+ statusCode: 409,
829
+ headers: { 'Content-Type': 'application/json' },
830
+ body: Buffer.from(JSON.stringify({
831
+ error: params.asset.kind === 'document'
832
+ ? 'The published document head does not match the current canonical document metadata.'
833
+ : 'The published asset head does not match the current canonical asset metadata.',
834
+ code: params.asset.kind === 'document' ? 'MCP_DOCUMENT_HEAD_STALE' : 'WORKSPACE_ASSET_HEAD_STALE',
835
+ details: {
836
+ assetId: params.asset.assetId,
837
+ currentVersion: params.asset.version,
838
+ currentStorageProvider: params.asset.storageProvider,
839
+ currentContentSha256: params.asset.contentSha256,
840
+ currentSizeBytes: params.asset.sizeBytes,
841
+ headVersionId: resolvedContent.versionId,
842
+ headStorageProvider: resolvedContent.storageProvider,
843
+ headContentSha256: resolvedContent.contentSha256,
844
+ headSizeBytes: resolvedContent.sizeBytes,
845
+ },
846
+ })),
847
+ };
848
+ }
821
849
  const physicalStorageKey = normalizeRelativeStorageKey(resolvedContent.physicalKey);
822
850
  if (!physicalStorageKey)
823
851
  return { statusCode: 404 };
@@ -852,7 +880,7 @@ export function createRoutes(core, context = {}) {
852
880
  'Content-Disposition': contentDisposition
853
881
  },
854
882
  body: resolvedContent.source === 'versioned'
855
- ? verifyWorkspaceSyncPublishedContentBody(object.body, resolvedContent, `Document ${params.asset.assetId}`)
883
+ ? verifyWorkspaceSyncPublishedContentBody(object.body, resolvedContent, `${contentLabel} ${params.asset.assetId}`)
856
884
  : object.body
857
885
  };
858
886
  }
@@ -879,7 +907,7 @@ export function createRoutes(core, context = {}) {
879
907
  'Content-Disposition': contentDisposition
880
908
  },
881
909
  body: resolvedContent.source === 'versioned'
882
- ? verifyWorkspaceSyncPublishedContentBody(body, resolvedContent, `Document ${params.asset.assetId}`)
910
+ ? verifyWorkspaceSyncPublishedContentBody(body, resolvedContent, `${contentLabel} ${params.asset.assetId}`)
883
911
  : body
884
912
  };
885
913
  }
@@ -1497,7 +1525,7 @@ export function createRoutes(core, context = {}) {
1497
1525
  sanitizeDownloadFilename,
1498
1526
  contentTypeForExt,
1499
1527
  inferInlineDocumentFromPath,
1500
- resolveCanonicalDocumentRead,
1528
+ resolveCanonicalContentRead,
1501
1529
  inferWorkspaceIdFromStoragePath,
1502
1530
  inferTaskIdFromStoragePath,
1503
1531
  });
@@ -0,0 +1,23 @@
1
+ export declare const WORKSPACE_DELETE_RETRY_COOLDOWN_MS = 30000;
2
+ export type WorkspaceDeletionAdmissionDecision = {
3
+ allowed: true;
4
+ } | {
5
+ allowed: false;
6
+ code: 'WORKSPACE_DELETE_IN_PROGRESS' | 'WORKSPACE_DELETE_RETRY_COOLDOWN';
7
+ retryAfterMs: number;
8
+ };
9
+ /**
10
+ * Serializes destructive workspace cleanup inside one server process and
11
+ * throttles immediate retries after an attempt settles. The caller supplies
12
+ * time so the admission policy can be verified without timers.
13
+ */
14
+ export declare class WorkspaceDeletionAdmission {
15
+ private readonly cooldownMs;
16
+ private readonly entries;
17
+ constructor(cooldownMs?: number);
18
+ checkExisting(key: string, now?: number): Exclude<WorkspaceDeletionAdmissionDecision, {
19
+ allowed: true;
20
+ }> | null;
21
+ acquire(key: string, now?: number): WorkspaceDeletionAdmissionDecision;
22
+ settle(key: string, now?: number): void;
23
+ }
@@ -0,0 +1,50 @@
1
+ export const WORKSPACE_DELETE_RETRY_COOLDOWN_MS = 30_000;
2
+ /**
3
+ * Serializes destructive workspace cleanup inside one server process and
4
+ * throttles immediate retries after an attempt settles. The caller supplies
5
+ * time so the admission policy can be verified without timers.
6
+ */
7
+ export class WorkspaceDeletionAdmission {
8
+ cooldownMs;
9
+ entries = new Map();
10
+ constructor(cooldownMs = WORKSPACE_DELETE_RETRY_COOLDOWN_MS) {
11
+ this.cooldownMs = cooldownMs;
12
+ }
13
+ checkExisting(key, now = Date.now()) {
14
+ let existing = this.entries.get(key);
15
+ if (existing?.state === 'cooldown' && existing.retryAt <= now) {
16
+ this.entries.delete(key);
17
+ existing = undefined;
18
+ }
19
+ if (existing?.state === 'in-flight') {
20
+ return {
21
+ allowed: false,
22
+ code: 'WORKSPACE_DELETE_IN_PROGRESS',
23
+ retryAfterMs: Math.max(1_000, this.cooldownMs),
24
+ };
25
+ }
26
+ if (existing?.state === 'cooldown') {
27
+ return {
28
+ allowed: false,
29
+ code: 'WORKSPACE_DELETE_RETRY_COOLDOWN',
30
+ retryAfterMs: Math.max(1_000, existing.retryAt - now),
31
+ };
32
+ }
33
+ return null;
34
+ }
35
+ acquire(key, now = Date.now()) {
36
+ const existing = this.checkExisting(key, now);
37
+ if (existing)
38
+ return existing;
39
+ this.entries.set(key, { state: 'in-flight' });
40
+ return { allowed: true };
41
+ }
42
+ settle(key, now = Date.now()) {
43
+ if (this.entries.get(key)?.state !== 'in-flight')
44
+ return;
45
+ this.entries.set(key, {
46
+ state: 'cooldown',
47
+ retryAt: now + this.cooldownMs,
48
+ });
49
+ }
50
+ }
@@ -1,9 +1,11 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
+ import { applyLocalServiceCloudTarget, localServiceCloudTargetsEqual, parseLocalServiceCloudTarget, resolveLocalServiceCloudTarget, } from '../config/localServiceCloudTarget.js';
4
+ import { localServiceRuntimeContractsEqual, parseLocalServiceRuntimeContract, resolveLocalServiceRuntimeContract, } from '../config/localServiceRuntimeContract.js';
3
5
  import { createStandaloneServer } from '../server/index.js';
4
6
  import { inspectLocalServiceDescriptor, redactLocalServiceDescriptor, } from '../server/localServiceLease.js';
5
7
  import { acquireLocalServiceOwnershipForRuntime, } from '../server/localServiceOwnershipBootstrap.js';
6
- import { LOCAL_SERVICE_API_BASE_PATH, LOCAL_SERVICE_PROTOCOL_VERSION, resolveLocalServiceLeaseInput, spawnDetachedLocalService, waitForLocalServiceDescriptor, } from './localServiceClientLifecycle.js';
8
+ import { discoverOrStartLocalService, LOCAL_SERVICE_API_BASE_PATH, LOCAL_SERVICE_PROTOCOL_VERSION, resolveLocalServiceLeaseInput, spawnDetachedLocalService, waitForLocalServiceDescriptor, } from './localServiceClientLifecycle.js';
7
9
  import { listSqliteWalHolders } from '../storage/sqliteWalHealth.js';
8
10
  const STARTUP_TIMEOUT_MS = 15_000;
9
11
  export { LOCAL_SERVICE_PROTOCOL_VERSION } from './localServiceClientLifecycle.js';
@@ -58,6 +60,20 @@ function reportIncompatibleDescriptor(inspection, error) {
58
60
  error(`Taskforce service protocol ${inspection.descriptor.protocolVersion} is incompatible with client protocol ${LOCAL_SERVICE_PROTOCOL_VERSION}.`);
59
61
  return true;
60
62
  }
63
+ function reportCloudTargetMismatch(descriptorTarget, requestedTarget, error) {
64
+ if (localServiceCloudTargetsEqual(descriptorTarget, requestedTarget))
65
+ return false;
66
+ error('Taskforce service is running for a different or unverified cloud target. '
67
+ + 'Stop it with `taskforce service stop --drain`, then retry.');
68
+ return true;
69
+ }
70
+ function reportRuntimeContractMismatch(descriptorContract, requestedContract, error) {
71
+ if (localServiceRuntimeContractsEqual(descriptorContract, requestedContract))
72
+ return false;
73
+ error('Taskforce service is running with a different or unverified local runtime contract. '
74
+ + 'Stop it with `taskforce service stop --drain`, then retry.');
75
+ return true;
76
+ }
61
77
  function defaultRegisterShutdownSignals(handler) {
62
78
  process.once('SIGINT', handler);
63
79
  process.once('SIGTERM', handler);
@@ -75,6 +91,9 @@ async function waitForDescriptor(input, expected, options) {
75
91
  });
76
92
  }
77
93
  async function runForeground(command, options) {
94
+ const requestedCloudTarget = resolveLocalServiceCloudTarget(options.env);
95
+ applyLocalServiceCloudTarget(options.env, requestedCloudTarget);
96
+ const requestedRuntimeContract = resolveLocalServiceRuntimeContract(options.env);
78
97
  const ownership = await options.acquireOwnership(command.projectRoot, options.env);
79
98
  if (!ownership)
80
99
  throw new Error('The shared local service requires local runtime mode.');
@@ -84,6 +103,10 @@ async function runForeground(command, options) {
84
103
  if (inspection.status === 'live' && inspection.descriptor) {
85
104
  if (reportIncompatibleDescriptor(inspection, options.error))
86
105
  return 2;
106
+ if (reportCloudTargetMismatch(inspection.descriptor.cloudTarget, requestedCloudTarget, options.error))
107
+ return 2;
108
+ if (reportRuntimeContractMismatch(inspection.descriptor.runtimeContract, requestedRuntimeContract, options.error))
109
+ return 2;
87
110
  options.log(`Taskforce service is already running at ${inspection.descriptor.endpoint}.`);
88
111
  return 0;
89
112
  }
@@ -116,6 +139,8 @@ async function runForeground(command, options) {
116
139
  ownerPid: process.pid,
117
140
  bootstrapCapability: ownership.lease.bootstrapCapability,
118
141
  ownershipKey: ownership.lease.identity.ownershipKey,
142
+ cloudTarget: requestedCloudTarget,
143
+ runtimeContract: requestedRuntimeContract,
119
144
  },
120
145
  afterShutdown: async () => {
121
146
  removeSignals();
@@ -138,6 +163,8 @@ async function runForeground(command, options) {
138
163
  endpoint: `http://127.0.0.1:${address.port}`,
139
164
  protocolVersion: LOCAL_SERVICE_PROTOCOL_VERSION,
140
165
  appVersion: options.appVersion,
166
+ cloudTarget: requestedCloudTarget,
167
+ runtimeContract: requestedRuntimeContract,
141
168
  });
142
169
  removeSignals = options.registerShutdownSignals(shutdown);
143
170
  server.once('error', (error) => {
@@ -164,34 +191,28 @@ async function runForeground(command, options) {
164
191
  }
165
192
  }
166
193
  async function runStart(command, options) {
167
- const leaseInput = resolveLocalServiceLeaseInput(command.projectRoot, options.env);
168
- const current = await options.inspectDescriptor(leaseInput);
169
- if (current.status === 'live' && current.descriptor) {
170
- if (reportIncompatibleDescriptor(current, options.error))
171
- return 2;
172
- options.log(`Taskforce service is already running at ${current.descriptor.endpoint}.`);
194
+ const requestedCloudTarget = resolveLocalServiceCloudTarget(options.env);
195
+ applyLocalServiceCloudTarget(options.env, requestedCloudTarget);
196
+ try {
197
+ const descriptor = await discoverOrStartLocalService({
198
+ projectRoot: command.projectRoot,
199
+ env: options.env,
200
+ executablePath: options.executablePath,
201
+ cliEntryPath: options.cliEntryPath,
202
+ execArgv: options.execArgv,
203
+ inspectDescriptor: options.inspectDescriptor,
204
+ spawnDetached: options.spawnDetached,
205
+ fetch: options.fetch,
206
+ sleep: options.sleep,
207
+ nowMs: options.nowMs,
208
+ });
209
+ options.log(`Taskforce service is ready at ${descriptor.endpoint}.`);
173
210
  return 0;
174
211
  }
175
- if (current.status === 'indeterminate') {
176
- options.error('Taskforce service state is indeterminate; refusing to start a competing owner.');
177
- return 2;
178
- }
179
- options.spawnDetached(options.executablePath, [
180
- ...options.execArgv,
181
- options.cliEntryPath,
182
- 'service',
183
- command.projectRoot,
184
- '--detached-child',
185
- ], options.env);
186
- const inspection = await waitForDescriptor(leaseInput, 'live', options);
187
- if (inspection.status !== 'live' || !inspection.descriptor) {
188
- options.error('Taskforce service did not become ready before the startup deadline.');
212
+ catch (startError) {
213
+ options.error(String(startError?.message || startError));
189
214
  return 2;
190
215
  }
191
- if (reportIncompatibleDescriptor(inspection, options.error))
192
- return 2;
193
- options.log(`Taskforce service started at ${inspection.descriptor.endpoint}.`);
194
- return 0;
195
216
  }
196
217
  async function runStatus(command, options) {
197
218
  const leaseInput = resolveLocalServiceLeaseInput(command.projectRoot, options.env);
@@ -222,9 +243,15 @@ async function runStatus(command, options) {
222
243
  throw new Error(`HTTP ${response.status}`);
223
244
  const payload = await response.json();
224
245
  const coordinatorPayload = payload.coordinator;
246
+ const diagnosticCloudTarget = parseLocalServiceCloudTarget(payload.cloudTarget);
247
+ const diagnosticRuntimeContract = parseLocalServiceRuntimeContract(payload.runtimeContract);
225
248
  if (payload.ownerPid !== inspection.descriptor.pid
226
249
  || payload.generation !== inspection.descriptor.generation
227
250
  || payload.protocolVersion !== inspection.descriptor.protocolVersion
251
+ || (inspection.descriptor.cloudTarget
252
+ && !localServiceCloudTargetsEqual(diagnosticCloudTarget, inspection.descriptor.cloudTarget))
253
+ || (inspection.descriptor.runtimeContract
254
+ && !localServiceRuntimeContractsEqual(diagnosticRuntimeContract, inspection.descriptor.runtimeContract))
228
255
  || !Array.isArray(payload.sessions)
229
256
  || !coordinatorPayload
230
257
  || typeof coordinatorPayload !== 'object'
@@ -1,6 +1,8 @@
1
1
  import { spawn } from 'child_process';
2
2
  import * as fs from 'fs';
3
3
  import * as path from 'path';
4
+ import { applyLocalServiceCloudTarget, localServiceCloudTargetsEqual, parseLocalServiceCloudTarget, resolveLocalServiceCloudTarget, } from '../config/localServiceCloudTarget.js';
5
+ import { localServiceRuntimeContractsEqual, parseLocalServiceRuntimeContract, resolveLocalServiceRuntimeContract, } from '../config/localServiceRuntimeContract.js';
4
6
  import { inspectLocalServiceDescriptor, } from '../server/localServiceLease.js';
5
7
  import { resolveLocalDatabaseIdentity } from '../server/localDatabaseIdentity.js';
6
8
  export const LOCAL_SERVICE_PROTOCOL_VERSION = '1';
@@ -22,6 +24,11 @@ const LOCAL_MCP_CLIENT_ENV_KEYS = [
22
24
  'TASKFORCE_AI_SURFACE_TYPE',
23
25
  'TASKFORCE_AI_SEAT_SCOPE',
24
26
  ];
27
+ function isQaIdentityEnvironmentKey(key) {
28
+ return key.startsWith('TASKFORCE_E2E_')
29
+ || key.startsWith('TASKFORCE_PLAYWRIGHT_')
30
+ || key.startsWith('SYNC_SOAK_');
31
+ }
25
32
  export function resolveLocalServiceLeaseInput(projectRoot, env) {
26
33
  const provider = env.TASKFORCE_DB_PROVIDER === 'postgres' ? 'postgres' : 'sqlite';
27
34
  return {
@@ -39,10 +46,15 @@ export function spawnDetachedLocalService(executablePath, args, env) {
39
46
  });
40
47
  child.unref();
41
48
  }
42
- function buildLocalServiceProcessEnv(env) {
49
+ function buildLocalServiceProcessEnv(env, cloudTarget) {
43
50
  const serviceEnv = { ...env };
44
51
  for (const key of LOCAL_MCP_CLIENT_ENV_KEYS)
45
52
  delete serviceEnv[key];
53
+ for (const key of Object.keys(serviceEnv)) {
54
+ if (isQaIdentityEnvironmentKey(key))
55
+ delete serviceEnv[key];
56
+ }
57
+ applyLocalServiceCloudTarget(serviceEnv, cloudTarget);
46
58
  return serviceEnv;
47
59
  }
48
60
  export async function waitForLocalServiceDescriptor(input, expected, options = {}) {
@@ -78,15 +90,72 @@ async function validateLocalServiceReadiness(descriptor, fetchFn) {
78
90
  catch {
79
91
  throw new Error('Taskforce shared local service readiness returned invalid JSON.');
80
92
  }
93
+ const readinessHasCloudTarget = Object.prototype.hasOwnProperty.call(readiness, 'cloudTarget');
94
+ const readinessCloudTarget = readinessHasCloudTarget
95
+ ? parseLocalServiceCloudTarget(readiness.cloudTarget)
96
+ : null;
97
+ const readinessHasRuntimeContract = Object.prototype.hasOwnProperty.call(readiness, 'runtimeContract');
98
+ const readinessRuntimeContract = readinessHasRuntimeContract
99
+ ? parseLocalServiceRuntimeContract(readiness.runtimeContract)
100
+ : null;
101
+ const descriptorCloudTarget = descriptor.cloudTarget || null;
102
+ const descriptorRuntimeContract = descriptor.runtimeContract || null;
103
+ const cloudTargetsMatch = descriptorCloudTarget || readinessCloudTarget
104
+ ? localServiceCloudTargetsEqual(descriptorCloudTarget, readinessCloudTarget)
105
+ : true;
106
+ const runtimeContractsMatch = descriptorRuntimeContract || readinessRuntimeContract
107
+ ? localServiceRuntimeContractsEqual(descriptorRuntimeContract, readinessRuntimeContract)
108
+ : true;
81
109
  if (readiness.ready !== true
82
110
  || readiness.protocolVersion !== LOCAL_SERVICE_PROTOCOL_VERSION
83
111
  || readiness.protocolVersion !== descriptor.protocolVersion
84
112
  || readiness.generation !== descriptor.generation
85
113
  || readiness.pid !== descriptor.pid
86
114
  || readiness.endpoint !== descriptor.endpoint
87
- || readiness.dataIdentity !== descriptor.ownershipKey) {
115
+ || readiness.dataIdentity !== descriptor.ownershipKey
116
+ || (readinessHasCloudTarget && !readinessCloudTarget)
117
+ || !cloudTargetsMatch
118
+ || (readinessHasRuntimeContract && !readinessRuntimeContract)
119
+ || !runtimeContractsMatch) {
88
120
  throw new Error('Taskforce shared local service readiness does not match its descriptor.');
89
121
  }
122
+ return {
123
+ cloudTarget: descriptorCloudTarget,
124
+ runtimeContract: descriptorRuntimeContract,
125
+ };
126
+ }
127
+ async function requestIdleLocalServiceShutdown(descriptor, fetchFn) {
128
+ let response;
129
+ try {
130
+ response = await fetchFn(`${descriptor.endpoint}${LOCAL_SERVICE_API_BASE_PATH}/shutdown`, {
131
+ method: 'POST',
132
+ headers: {
133
+ 'content-type': 'application/json',
134
+ 'x-taskforce-local-service-capability': descriptor.bootstrapCapability,
135
+ },
136
+ body: JSON.stringify({
137
+ intent: 'administrative-stop',
138
+ mode: 'refuse',
139
+ pid: descriptor.pid,
140
+ generation: descriptor.generation,
141
+ }),
142
+ redirect: 'error',
143
+ signal: AbortSignal.timeout(LOCAL_SERVICE_STARTUP_TIMEOUT_MS),
144
+ });
145
+ }
146
+ catch (error) {
147
+ throw new Error('Taskforce service uses a different cloud target or runtime contract and could not be stopped safely. '
148
+ + `No replacement was started. ${String(error?.message || error)}`);
149
+ }
150
+ if (!response.ok) {
151
+ const detail = (await response.text()).slice(0, 500);
152
+ const activeClientHint = response.status === 409
153
+ ? ' It may have active MCP clients; close them or run `taskforce service stop --drain`, then retry.'
154
+ : '';
155
+ throw new Error(`Taskforce service uses a different cloud target or runtime contract and refused safe idle replacement (${response.status}).`
156
+ + activeClientHint
157
+ + (detail ? ` ${detail}` : ''));
158
+ }
90
159
  }
91
160
  export async function discoverOrStartLocalService(input) {
92
161
  const requestedRoot = path.resolve(input.projectRoot);
@@ -94,13 +163,27 @@ export async function discoverOrStartLocalService(input) {
94
163
  const leaseInput = resolveLocalServiceLeaseInput(projectRoot, input.env);
95
164
  const inspectDescriptor = input.inspectDescriptor || inspectLocalServiceDescriptor;
96
165
  const fetchFn = input.fetch || fetch;
166
+ const requestedCloudTarget = resolveLocalServiceCloudTarget(input.env);
167
+ const requestedRuntimeContract = resolveLocalServiceRuntimeContract(input.env);
97
168
  const current = await inspectDescriptor(leaseInput);
98
169
  if (current.status === 'live' && current.descriptor) {
99
170
  if (current.descriptor.protocolVersion !== LOCAL_SERVICE_PROTOCOL_VERSION) {
100
171
  throw new Error(`Taskforce service protocol ${current.descriptor.protocolVersion} is incompatible with client protocol ${LOCAL_SERVICE_PROTOCOL_VERSION}.`);
101
172
  }
102
- await validateLocalServiceReadiness(current.descriptor, fetchFn);
103
- return current.descriptor;
173
+ const running = await validateLocalServiceReadiness(current.descriptor, fetchFn);
174
+ if (localServiceCloudTargetsEqual(running.cloudTarget, requestedCloudTarget)
175
+ && localServiceRuntimeContractsEqual(running.runtimeContract, requestedRuntimeContract)) {
176
+ return current.descriptor;
177
+ }
178
+ await requestIdleLocalServiceShutdown(current.descriptor, fetchFn);
179
+ const stopped = await waitForLocalServiceDescriptor(leaseInput, 'stale', {
180
+ inspectDescriptor,
181
+ sleep: input.sleep,
182
+ nowMs: input.nowMs,
183
+ });
184
+ if (stopped.status !== 'stale') {
185
+ throw new Error('Taskforce service accepted configuration replacement but did not release its owner lease. No replacement was started.');
186
+ }
104
187
  }
105
188
  if (current.status === 'indeterminate') {
106
189
  throw new Error('Taskforce service state is indeterminate; refusing to start a competing owner.');
@@ -111,7 +194,7 @@ export async function discoverOrStartLocalService(input) {
111
194
  'service',
112
195
  projectRoot,
113
196
  '--detached-child',
114
- ], buildLocalServiceProcessEnv(input.env));
197
+ ], buildLocalServiceProcessEnv(input.env, requestedCloudTarget));
115
198
  const inspection = await waitForLocalServiceDescriptor(leaseInput, 'live', {
116
199
  inspectDescriptor,
117
200
  sleep: input.sleep,
@@ -123,6 +206,10 @@ export async function discoverOrStartLocalService(input) {
123
206
  if (inspection.descriptor.protocolVersion !== LOCAL_SERVICE_PROTOCOL_VERSION) {
124
207
  throw new Error(`Taskforce service protocol ${inspection.descriptor.protocolVersion} is incompatible with client protocol ${LOCAL_SERVICE_PROTOCOL_VERSION}.`);
125
208
  }
126
- await validateLocalServiceReadiness(inspection.descriptor, fetchFn);
209
+ const started = await validateLocalServiceReadiness(inspection.descriptor, fetchFn);
210
+ if (!localServiceCloudTargetsEqual(started.cloudTarget, requestedCloudTarget)
211
+ || !localServiceRuntimeContractsEqual(started.runtimeContract, requestedRuntimeContract)) {
212
+ throw new Error('Taskforce service started with a different or unverified cloud target/runtime contract; refusing to attach.');
213
+ }
127
214
  return inspection.descriptor;
128
215
  }
@@ -0,0 +1,112 @@
1
+ import type { ModelGateway, ModelGatewayGenerateInput, ModelGatewayGenerateResult } from './modelGateway.js';
2
+ export type CodexAppServerModelKeyIdMap = Partial<Record<string, string>>;
3
+ type CodexAppServerApprovalPolicy = 'never';
4
+ type CodexAppServerSandboxMode = 'read-only';
5
+ type CodexAppServerSandboxPolicy = {
6
+ type: 'readOnly';
7
+ networkAccess: false;
8
+ };
9
+ type CodexAppServerRuntimePolicy = {
10
+ cwd: string;
11
+ approvalPolicy: CodexAppServerApprovalPolicy;
12
+ sandbox: CodexAppServerSandboxMode;
13
+ sandboxPolicy: CodexAppServerSandboxPolicy;
14
+ };
15
+ export interface CodexAppServerClient {
16
+ initialize(): Promise<void>;
17
+ assertChatGptSubscriptionAuth(): Promise<void>;
18
+ startThread(input: {
19
+ model: string;
20
+ developerInstructions?: string;
21
+ } & CodexAppServerRuntimePolicy): Promise<{
22
+ threadId: string;
23
+ }>;
24
+ startTurnAndCollectText(input: {
25
+ threadId: string;
26
+ prompt: string;
27
+ model: string;
28
+ timeoutMs: number;
29
+ } & CodexAppServerRuntimePolicy): Promise<{
30
+ text: string;
31
+ stopReason?: string;
32
+ }>;
33
+ close(): void;
34
+ }
35
+ export interface CodexAppServerModelGatewayOptions {
36
+ client?: CodexAppServerClient;
37
+ clientFactory?: () => CodexAppServerClient;
38
+ command?: string;
39
+ args?: string[];
40
+ cwd?: string;
41
+ env?: NodeJS.ProcessEnv;
42
+ modelKeyIds?: CodexAppServerModelKeyIdMap;
43
+ timeoutMs?: number;
44
+ requestTimeoutMs?: number;
45
+ }
46
+ export declare const DEFAULT_CODEX_APP_SERVER_MODEL_KEY_IDS: CodexAppServerModelKeyIdMap;
47
+ export declare function buildCodexAppServerEnv(source?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
48
+ export declare function sanitizeCodexAppServerStderr(value: unknown): string;
49
+ export declare function collectCodexAppServerStderr(current: string, chunk: unknown): string;
50
+ export declare function assertCodexChatGptSubscriptionAccount(result: unknown): void;
51
+ export declare function isCodexSubscriptionDevRuntimeAllowed(source?: NodeJS.ProcessEnv): boolean;
52
+ export declare function extractCodexTurnCompletion(messages: unknown[]): {
53
+ text: string;
54
+ stopReason: string;
55
+ } | null;
56
+ export declare class CodexAppServerJsonRpcClient implements CodexAppServerClient {
57
+ private readonly process;
58
+ private readonly pending;
59
+ private readonly notifications;
60
+ private nextId;
61
+ private initialized;
62
+ private readonly lineReader;
63
+ private readonly requestTimeoutMs;
64
+ private readonly turnRejectors;
65
+ private terminalError;
66
+ private stderrTail;
67
+ constructor(options?: {
68
+ command?: string;
69
+ args?: string[];
70
+ cwd?: string;
71
+ env?: NodeJS.ProcessEnv;
72
+ requestTimeoutMs?: number;
73
+ });
74
+ initialize(): Promise<void>;
75
+ assertChatGptSubscriptionAuth(): Promise<void>;
76
+ startThread(input: {
77
+ model: string;
78
+ developerInstructions?: string;
79
+ } & CodexAppServerRuntimePolicy): Promise<{
80
+ threadId: string;
81
+ }>;
82
+ startTurnAndCollectText(input: {
83
+ threadId: string;
84
+ prompt: string;
85
+ system?: string;
86
+ model: string;
87
+ timeoutMs: number;
88
+ } & CodexAppServerRuntimePolicy): Promise<{
89
+ text: string;
90
+ stopReason?: string;
91
+ }>;
92
+ close(): void;
93
+ private request;
94
+ private sendNotification;
95
+ private handleLine;
96
+ private sendResponseError;
97
+ private waitForTurnCompletion;
98
+ private rejectAll;
99
+ private fail;
100
+ }
101
+ export declare class CodexAppServerModelGateway implements ModelGateway {
102
+ private readonly client?;
103
+ private readonly clientFactory;
104
+ private readonly modelKeyIds;
105
+ private readonly timeoutMs;
106
+ private readonly cwd;
107
+ constructor(options?: CodexAppServerModelGatewayOptions);
108
+ generate(input: ModelGatewayGenerateInput): Promise<ModelGatewayGenerateResult>;
109
+ private resolveModelId;
110
+ private formatMessages;
111
+ }
112
+ export {};