@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
@@ -11,10 +11,12 @@
11
11
  * POST /api/taskforce/agents/model-gateway/test
12
12
  * PATCH /api/taskforce/agents/:agentId/conversations/:conversationId
13
13
  */
14
+ import { createHash } from 'node:crypto';
14
15
  import { assignedAiProfileColor, normalizeAiProfileColor } from '../../shared/aiProfileColors.js';
15
16
  import { BedrockAnthropicMessagesModelGateway } from '../../services/bedrockAnthropicMessagesModelGateway.js';
16
17
  import { BedrockMantleModelGateway } from '../../services/bedrockMantleModelGateway.js';
17
18
  import { BedrockModelGateway } from '../../services/bedrockModelGateway.js';
19
+ import { CodexAppServerModelGateway } from '../../services/codexAppServerModelGateway.js';
18
20
  import { saveAiProfileAvatarAssets } from '../aiProfileAvatarAssets.js';
19
21
  import { ModelGatewayConfigurationError, normalizePersistedModelGatewayMessages } from '../../services/modelGateway.js';
20
22
  import { BedrockAvatarImageProvider, buildTaskforceAgentAvatarPrompt, } from '../../services/taskforceAgentAvatarImageProvider.js';
@@ -25,10 +27,11 @@ import { TaskforceAgentSkillStore } from '../../storage/taskforceAgentSkillStore
25
27
  import { WorkflowStore } from '../../storage/workflowStore.js';
26
28
  import { WorkspaceSyncDurabilityStore } from '../../sync/v3/syncDurabilityStore.js';
27
29
  import { projectLegacyTaskforceAgentResponse } from '../../compat/taskforceAgentDefinitionCompat.js';
28
- import { TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY, resolveAppGateAccess, } from '../../runtime/appGates.js';
30
+ import { TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY, } from '../../runtime/appGates.js';
31
+ import { resolveNodeAppGateAccess } from '../../runtime/nodeAppGates.js';
29
32
  import { DEFAULT_TASKFORCE_AGENT_MODEL_KEY, DEFAULT_TASKFORCE_AGENT_PROVIDER_KEY, getTaskforceAgentModel, isTaskforceAgentModelVisible, labelForTaskforceAgentModel, labelForTaskforceAgentProvider, normalizeTaskforceAgentModelKey, normalizeTaskforceAgentModelSelection, normalizeTaskforceAgentProviderKey, } from '../../shared/taskforceAgentModels.js';
30
33
  import { buildTaskforceAgentRunContext } from '../../shared/taskforceAgentRunContext.js';
31
- import { inspectAgentDefinition } from '../../shared/taskforceAgentDefinition.js';
34
+ import { inspectAgentDefinition, serializeCanonicalJson } from '../../shared/taskforceAgentDefinition.js';
32
35
  import { buildResolvedTaskforceAgentSystemPrompt, resolveTaskforceAgentRuntimeConfiguration, TaskforceAgentRuntimeResolutionError, } from '../../shared/taskforceAgentRuntimeResolution.js';
33
36
  import { serializeTaskforceAgentExecutionSnapshot } from '../../shared/taskforceAgentExecutionSnapshot.js';
34
37
  import { getTaskReferenceLabel } from '../../utils/taskReferences.js';
@@ -113,6 +116,11 @@ function normalizeMessages(value, fallbackPrompt) {
113
116
  return { error: 'Prompt must be 4,000 characters or less.' };
114
117
  return { messages: [{ role: 'user', content: prompt }] };
115
118
  }
119
+ function buildManagedAgentExecutionRequestId(input) {
120
+ return createHash('sha256')
121
+ .update(serializeCanonicalJson(input))
122
+ .digest('hex');
123
+ }
116
124
  function toGatewayMessages(messages) {
117
125
  return messages.map((message) => ({
118
126
  role: message.role,
@@ -122,7 +130,13 @@ function toGatewayMessages(messages) {
122
130
  function requestsWorkflowStepCompletion(messages) {
123
131
  const latestUserMessage = [...messages].reverse().find((message) => message.role === 'user');
124
132
  const content = String(latestUserMessage?.content || '').trim().toLowerCase();
125
- return /^(?:please\s+|(?:can|could|would)\s+you\s+)?(?:perform\s+and\s+complete|complete|finish)\s+(?:your|the|this)\s+(?:current\s+)?workflow\s+step[.!?]*$/.test(content);
133
+ return /^(?:(?:hey|hi|hello)\b[^,!?]{0,80},?\s+)?(?:please\s+|(?:can|could|would)\s+you\s+)?(?:perform\s+and\s+complete|complete|finish)\s+(?:your|the|this)\s+(?:current\s+)?workflow\s+step(?:\s+(?:on|for)\s+(?:task\s+)?(?:t-\d+|[a-z0-9][a-z0-9-]{0,119}))?[.!?]*$/.test(content);
134
+ }
135
+ function extractLatestExplicitTaskReference(messages) {
136
+ const latestUserMessage = [...messages].reverse().find((message) => message.role === 'user');
137
+ const matches = String(latestUserMessage?.content || '').match(/\bT-\d+\b/gi) || [];
138
+ const references = [...new Set(matches.map((match) => match.toUpperCase()))];
139
+ return references.length === 1 ? references[0] : null;
126
140
  }
127
141
  function normalizeTaskId(value) {
128
142
  const taskId = String(value || '').trim();
@@ -144,6 +158,18 @@ function resolveTaskContextTask(core, workspaceId, taskId) {
144
158
  return core.getTask(taskId, workspaceId)
145
159
  || (typeof core.resolveTaskIdentifier === 'function' ? core.resolveTaskIdentifier(taskId, workspaceId) : null);
146
160
  }
161
+ function workflowToolCallsTargetSameTask(core, workspaceId, left, right) {
162
+ const resolveCanonicalId = (value) => {
163
+ const taskId = normalizeTaskId(value);
164
+ if (!taskId)
165
+ return null;
166
+ const task = resolveTaskContextTask(core, workspaceId, taskId);
167
+ return normalizeTaskId(task?.id)?.toLowerCase() || taskId.toLowerCase();
168
+ };
169
+ const leftTaskId = resolveCanonicalId(left);
170
+ const rightTaskId = resolveCanonicalId(right);
171
+ return Boolean(leftTaskId && rightTaskId && leftTaskId === rightTaskId);
172
+ }
147
173
  function resolveTaskScopeContext(core, workspaceId, input) {
148
174
  const taskId = String(input.taskId || '').trim();
149
175
  if (!taskId)
@@ -244,6 +270,12 @@ function createDefaultModelGateway(selection) {
244
270
  }
245
271
  const source = selection?.modelSource || model?.source || 'bedrock';
246
272
  const runtime = selection?.runtime || model?.runtime || 'bedrock-runtime';
273
+ if (source === 'subscription_dev' && runtime === 'subscription-dev') {
274
+ if (selection?.connectionScope !== 'local_dev') {
275
+ throw new ModelGatewayConfigurationError('Subscription-dev models require local_dev connection scope.', 'MODEL_SOURCE_UNAVAILABLE');
276
+ }
277
+ return new CodexAppServerModelGateway();
278
+ }
247
279
  if (source !== 'bedrock') {
248
280
  throw new ModelGatewayConfigurationError('Selected model source is not configured yet.', 'MODEL_SOURCE_NOT_IMPLEMENTED');
249
281
  }
@@ -693,7 +725,7 @@ export function registerAgentsRoutes(deps) {
693
725
  const ensureTaskforceAgentsAccess = (req, res) => {
694
726
  if (!ensureAppAccess(req, res))
695
727
  return false;
696
- const gate = resolveAppGateAccess(TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY);
728
+ const gate = resolveNodeAppGateAccess(TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY);
697
729
  if (gate.allowed)
698
730
  return true;
699
731
  writeJson(res, 403, {
@@ -1149,9 +1181,30 @@ export function registerAgentsRoutes(deps) {
1149
1181
  }
1150
1182
  }
1151
1183
  const savedConversationTaskId = savedConversation?.taskId ? normalizeTaskId(savedConversation.taskId) : null;
1152
- const taskId = hasTaskId ? bodyTaskId : savedConversationTaskId;
1153
- const taskReference = taskId ? normalizeTaskContextValue(body?.taskReference) : '';
1154
- const taskTitle = taskId ? normalizeTaskContextValue(body?.taskTitle) : '';
1184
+ const explicitTaskReference = extractLatestExplicitTaskReference(normalizedMessages.messages);
1185
+ const explicitTask = explicitTaskReference
1186
+ ? resolveTaskContextTask(core, workspaceId, explicitTaskReference)
1187
+ : null;
1188
+ if (explicitTaskReference
1189
+ && !explicitTask
1190
+ && requestsWorkflowStepCompletion(normalizedMessages.messages)) {
1191
+ writeJson(res, 404, {
1192
+ success: false,
1193
+ error: `Task ${explicitTaskReference} was not found.`,
1194
+ code: 'TASK_NOT_FOUND',
1195
+ });
1196
+ return;
1197
+ }
1198
+ const taskId = normalizeTaskId(explicitTask?.id)
1199
+ || (explicitTaskReference ? null : hasTaskId ? bodyTaskId : savedConversationTaskId);
1200
+ const taskReference = taskId
1201
+ ? normalizeTaskContextValue(getTaskReferenceLabel(explicitTask)
1202
+ || (explicitTask ? explicitTaskReference : null)
1203
+ || body?.taskReference)
1204
+ : '';
1205
+ const taskTitle = taskId
1206
+ ? normalizeTaskContextValue(explicitTask?.title || body?.taskTitle)
1207
+ : '';
1155
1208
  if (resolvedRuntimeConfiguration) {
1156
1209
  const definition = resolvedRuntimeConfiguration.definition;
1157
1210
  const draftDiffers = ((body?.providerKey !== undefined
@@ -1272,6 +1325,13 @@ export function registerAgentsRoutes(deps) {
1272
1325
  allowedMutationTaskId: taskId ?? null,
1273
1326
  readOnly: !savedAgent,
1274
1327
  toolPolicy: resolvedRuntimeConfiguration?.definition.toolPolicy,
1328
+ executionRequestId: buildManagedAgentExecutionRequestId({
1329
+ workspaceId,
1330
+ agentId: savedAgent?.id || agentId || null,
1331
+ conversationId,
1332
+ taskId: taskId ?? null,
1333
+ messages: normalizedMessages.messages,
1334
+ }),
1275
1335
  system: scopedAgentSystem,
1276
1336
  });
1277
1337
  const executionSnapshot = savedAgent && resolvedRuntimeConfiguration
@@ -1304,21 +1364,40 @@ export function registerAgentsRoutes(deps) {
1304
1364
  && mcpBridge?.availableToolNames.includes('complete_workflow_step')
1305
1365
  && requestsWorkflowStepCompletion(gatewayInput.messages));
1306
1366
  let workflowCompletionCorrectionSent = false;
1367
+ let reservedWorkflowCompletionUsed = false;
1307
1368
  while (mcpBridge) {
1308
1369
  if (requestedToolCall) {
1309
- if (mcpToolResults.length >= MAX_MCP_TOOL_ITERATIONS)
1370
+ const activeToolCall = requestedToolCall;
1371
+ const workflowStepAlreadyCompleted = mcpToolResults.some((toolResult) => (toolResult.name === 'complete_workflow_step' && toolResult.ok));
1372
+ const workflowStepLoaded = activeToolCall.name === 'complete_workflow_step'
1373
+ && mcpToolResults.some((toolResult) => (toolResult.name === 'get_task_workflow'
1374
+ && toolResult.ok
1375
+ && workflowToolCallsTargetSameTask(core, workspaceId, toolResult.arguments?.taskId, activeToolCall.arguments?.taskId)));
1376
+ const canUseReservedWorkflowCompletion = Boolean(workflowCompletionRequested
1377
+ && !workflowStepAlreadyCompleted
1378
+ && !reservedWorkflowCompletionUsed
1379
+ && activeToolCall.name === 'complete_workflow_step'
1380
+ && workflowStepLoaded
1381
+ && unresolvedFailedMutations.size === 0);
1382
+ if (mcpToolResults.length >= MAX_MCP_TOOL_ITERATIONS
1383
+ && !canUseReservedWorkflowCompletion)
1310
1384
  break;
1311
- const blocksWorkflowCompletion = requestedToolCall.name === 'complete_workflow_step'
1312
- && unresolvedFailedMutations.size > 0;
1385
+ if (mcpToolResults.length >= MAX_MCP_TOOL_ITERATIONS) {
1386
+ reservedWorkflowCompletionUsed = true;
1387
+ }
1388
+ const blocksWorkflowCompletion = activeToolCall.name === 'complete_workflow_step'
1389
+ && (!workflowStepLoaded || unresolvedFailedMutations.size > 0);
1313
1390
  const unresolvedMutationNames = [...new Set(unresolvedFailedMutations.values())];
1314
1391
  const toolResult = blocksWorkflowCompletion
1315
1392
  ? {
1316
- name: requestedToolCall.name,
1317
- arguments: requestedToolCall.arguments,
1393
+ name: activeToolCall.name,
1394
+ arguments: activeToolCall.arguments,
1318
1395
  ok: false,
1319
- text: `Taskforce refused workflow completion because these earlier changes failed: ${unresolvedMutationNames.join(', ')}. Retry the failed changes successfully before completing the step.`,
1396
+ text: !workflowStepLoaded
1397
+ ? 'Taskforce refused workflow completion because the current workflow step was not loaded successfully. Call get_task_workflow first, perform its instructions, then retry completion.'
1398
+ : `Taskforce refused workflow completion because these earlier changes failed: ${unresolvedMutationNames.join(', ')}. Retry the failed changes successfully before completing the step.`,
1320
1399
  }
1321
- : await mcpBridge.executeToolCall(requestedToolCall);
1400
+ : await mcpBridge.executeToolCall(activeToolCall);
1322
1401
  mcpToolResults.push(toolResult);
1323
1402
  if (isTaskforceAgentMutationToolName(toolResult.name)
1324
1403
  && toolResult.name !== 'complete_workflow_step') {
@@ -1349,6 +1428,17 @@ export function registerAgentsRoutes(deps) {
1349
1428
  throw error;
1350
1429
  }
1351
1430
  requestedToolCall = mcpBridge.parseToolCall(result.text);
1431
+ if (toolResult.name === 'complete_workflow_step'
1432
+ && toolResult.ok
1433
+ && requestedToolCall
1434
+ && mcpToolResults.length >= MAX_MCP_TOOL_ITERATIONS) {
1435
+ result = {
1436
+ ...result,
1437
+ text: 'Workflow step completed successfully.',
1438
+ };
1439
+ requestedToolCall = null;
1440
+ break;
1441
+ }
1352
1442
  continue;
1353
1443
  }
1354
1444
  const workflowStepCompleted = mcpToolResults.some((toolResult) => (toolResult.name === 'complete_workflow_step' && toolResult.ok));
@@ -1358,7 +1448,7 @@ export function registerAgentsRoutes(deps) {
1358
1448
  role: 'user',
1359
1449
  content: unresolvedFailedMutations.size > 0
1360
1450
  ? `The workflow step is not complete because these Taskforce changes failed: ${[...new Set(unresolvedFailedMutations.values())].join(', ')}. Retry those exact changes successfully before calling complete_workflow_step. If they cannot succeed, respond exactly WORKFLOW_STEP_INCOMPLETE: followed by the reason.`
1361
- : 'The workflow step is not authoritatively complete. If all required work succeeded, call complete_workflow_step now. Otherwise respond exactly WORKFLOW_STEP_INCOMPLETE: followed by the reason. Do not claim completion without a successful tool result.',
1451
+ : 'The workflow step is not authoritatively complete. Call get_task_workflow first if it has not succeeded in this response, perform the returned step instructions, then call complete_workflow_step. Otherwise respond exactly WORKFLOW_STEP_INCOMPLETE: followed by the reason. Do not claim completion without successful tool results.',
1362
1452
  });
1363
1453
  result = await gateway.generate({
1364
1454
  ...gatewayInput,
@@ -1370,7 +1460,19 @@ export function registerAgentsRoutes(deps) {
1370
1460
  break;
1371
1461
  }
1372
1462
  if (requestedToolCall) {
1373
- throw new Error('Taskforce tool call limit reached before the agent returned a final response.');
1463
+ mcpToolResults.push({
1464
+ name: requestedToolCall.name,
1465
+ arguments: requestedToolCall.arguments,
1466
+ ok: false,
1467
+ text: 'Taskforce did not execute this call because the per-message tool limit was reached.',
1468
+ });
1469
+ result = {
1470
+ ...result,
1471
+ text: workflowCompletionRequested
1472
+ ? 'WORKFLOW_STEP_INCOMPLETE: Taskforce reached the per-message tool limit before finishing the workflow step. Review Tool Activity and retry.'
1473
+ : 'Taskforce reached the per-message tool limit. Review Tool Activity and retry.',
1474
+ };
1475
+ requestedToolCall = null;
1374
1476
  }
1375
1477
  if (workflowCompletionRequested && !mcpToolResults.some((toolResult) => (toolResult.name === 'complete_workflow_step' && toolResult.ok))) {
1376
1478
  const incompletePrefix = 'WORKFLOW_STEP_INCOMPLETE:';
@@ -11,7 +11,8 @@
11
11
  * DELETE /api/taskforce/annotated-attachments/sessions/:id
12
12
  * GET /api/taskforce/annotated-attachments/sessions/:id/payload
13
13
  */
14
- import { ANNOTATED_ATTACHMENTS_WORKSPACE_FEATURE_KEY, resolveAppGateAccess, } from '../../runtime/appGates.js';
14
+ import { ANNOTATED_ATTACHMENTS_WORKSPACE_FEATURE_KEY, } from '../../runtime/appGates.js';
15
+ import { resolveNodeAppGateAccess } from '../../runtime/nodeAppGates.js';
15
16
  import { parseJsonBody } from './primitives.js';
16
17
  import { resolveErrorStatusCode } from './shared.js';
17
18
  import { getImageReferenceLabel, parseImageReference } from '../../utils/imageReferences.js';
@@ -37,7 +38,7 @@ export function registerAnnotatedAttachmentRoutes(deps) {
37
38
  const ensureAnnotatedAttachmentAccess = (req, res, workspaceId) => {
38
39
  if (!ensureAppAccess(req, res))
39
40
  return false;
40
- const gate = resolveAppGateAccess(ANNOTATED_ATTACHMENTS_WORKSPACE_FEATURE_KEY);
41
+ const gate = resolveNodeAppGateAccess(ANNOTATED_ATTACHMENTS_WORKSPACE_FEATURE_KEY);
41
42
  if (gate.allowed)
42
43
  return true;
43
44
  writeJson(res, 403, {
@@ -60,6 +60,7 @@ import { buildGithubAuthUrl, exchangeGithubCode } from '../auth/providers/github
60
60
  import { hasValidSession, createClearSessionCookie, createSessionTokenCookie, resolveRequestAccess, resolveSessionCookieAttributesForRequest, } from '../auth.js';
61
61
  import { sendEmail } from '../email.js';
62
62
  import { resolveDeploymentConfig } from '../../config/deployment.js';
63
+ import { resolveNodeAppGateAccessMap } from '../../runtime/nodeAppGates.js';
63
64
  import { resolveTaskMetadataActivationCapability } from '../../sync/v3/taskMetadataActivation.js';
64
65
  import { resolveTaskCreateActivationCapability } from '../../sync/v3/taskCreateActivation.js';
65
66
  import { resolveTaskStatusActivationCapability } from '../../sync/v3/taskStatusActivation.js';
@@ -401,7 +402,7 @@ export function registerAuthRoutes(deps) {
401
402
  : 'Reset your Taskforce password';
402
403
  const text = kind === 'verify-email'
403
404
  ? `Welcome to Taskforce.\n\nYou're almost in. Enter this verification token on the verification screen to activate your account:\n\n${token}\n\nPrefer the faster route? Open the link below to verify your email automatically:\n${link}\n\nIf you didn't create a Taskforce account, you can safely ignore this email.`
404
- : `Reset your Taskforce password using this link:\n${link}\n\nIf you did not request this reset, you can ignore this message.`;
405
+ : `Enter this password reset token on the reset screen:\n\n${token}\n\nOr reset your Taskforce password using this link:\n${link}\n\nIf you did not request this reset, you can ignore this message.`;
405
406
  const result = await sendEmail({
406
407
  to: email,
407
408
  subject,
@@ -470,6 +471,7 @@ export function registerAuthRoutes(deps) {
470
471
  authSource: runtimeContract.authSource,
471
472
  workspaceMode: runtimeContract.workspaceMode,
472
473
  workspaceSwitchingEnabled: runtimeContract.workspaceSwitchingEnabled,
474
+ appGates: resolveNodeAppGateAccessMap(process.env),
473
475
  syncV3
474
476
  }
475
477
  }));
@@ -8,6 +8,8 @@
8
8
  * POST /api/taskforce/context-upload/init
9
9
  * POST /api/taskforce/context-upload/finalize
10
10
  * POST /api/taskforce/context-upload
11
+ * POST /api/taskforce/context-upload/draft/promote
12
+ * POST /api/taskforce/context-upload/draft/discard
11
13
  * GET /api/taskforce/context/:filename
12
14
  * GET /api/taskforce/documents/:assetId/content
13
15
  * GET /api/taskforce/context-link
@@ -39,7 +41,7 @@ type AssetMetadata = DocumentRegistryEntry & {
39
41
  originalFilename?: string | null;
40
42
  };
41
43
  interface CanonicalReadResult {
42
- statusCode: 200 | 302 | 404;
44
+ statusCode: 200 | 302 | 404 | 409;
43
45
  headers?: Record<string, string>;
44
46
  body?: Buffer;
45
47
  }
@@ -81,6 +83,7 @@ export interface DocumentRouteDependencies {
81
83
  workspaceId?: string;
82
84
  taskId?: string | null;
83
85
  originalName?: string | null;
86
+ actorRef?: string | null;
84
87
  }) => Promise<{
85
88
  scan?: {
86
89
  verdict?: string;
@@ -110,7 +113,7 @@ export interface DocumentRouteDependencies {
110
113
  sanitizeDownloadFilename: (nameRaw: string, fallback?: string) => string;
111
114
  contentTypeForExt: (ext: string) => string;
112
115
  inferInlineDocumentFromPath: (pathValue: string | null | undefined) => boolean;
113
- resolveCanonicalDocumentRead: (params: {
116
+ resolveCanonicalContentRead: (params: {
114
117
  asset: WorkspaceAssetEntry;
115
118
  forceDownload: boolean;
116
119
  requestedFilename?: string | null;
@@ -8,6 +8,8 @@
8
8
  * POST /api/taskforce/context-upload/init
9
9
  * POST /api/taskforce/context-upload/finalize
10
10
  * POST /api/taskforce/context-upload
11
+ * POST /api/taskforce/context-upload/draft/promote
12
+ * POST /api/taskforce/context-upload/draft/discard
11
13
  * GET /api/taskforce/context/:filename
12
14
  * GET /api/taskforce/documents/:assetId/content
13
15
  * GET /api/taskforce/context-link
@@ -33,7 +35,7 @@ import { parsePlan } from '../../utils/planParser.js';
33
35
  import { getCanonicalDocumentName, getReadableDocumentName, isGeneratedDocumentName } from '../../utils/documentNames.js';
34
36
  import { createWorkspaceAssetAccessGuard } from './assetAccess.js';
35
37
  import { parseJsonBody } from './primitives.js';
36
- import { requestHeader, requestRuntimeMode, resolveErrorStatusCode } from './shared.js';
38
+ import { requestHeader, requestHumanActorRef, requestRuntimeMode, requestUserId, resolveErrorStatusCode, } from './shared.js';
37
39
  import { resolveDeploymentConfig } from '../../config/deployment.js';
38
40
  import { isAiProfileAvatarStorageKey } from '../../utils/aiProfileAvatarPaths.js';
39
41
  import { createTaskHttpDurableRouters } from './durableTaskHttpRouters.js';
@@ -110,7 +112,7 @@ async function proxyCloudUserProfileAvatar(req, res, relativePath, contentTypeFo
110
112
  }
111
113
  }
112
114
  export function registerDocumentRoutes(deps) {
113
- const { addRoute, core, context, requestWorkspaceId, ensureAdminRole, resolveEffectiveObjectStorageConfig, getObjectStorageClient, resolveStorageWorkspaceId, ensureContextUploadAllowed, parseStorageFolderSegments, buildCanonicalWorkspaceAssetRelativePath, inferAssetKindFromPath, appendStorageTelemetry, scanAndRecordDocument, buildTaskAttachmentPayload, workspaceAssetStore, taskAssetStore, normalizeDocumentPathInput, getAssetMetadata, getCanonicalAssetMetadata, documentRetentionDays, appendDocumentPurgeHistory, markAssetDeleted, isAssetDeleted, clearAssetDeleted, ensureWithinDir, sanitizeDownloadFilename, contentTypeForExt, inferInlineDocumentFromPath, resolveCanonicalDocumentRead, inferWorkspaceIdFromStoragePath, inferTaskIdFromStoragePath, } = deps;
115
+ const { addRoute, core, context, requestWorkspaceId, ensureAdminRole, resolveEffectiveObjectStorageConfig, getObjectStorageClient, resolveStorageWorkspaceId, ensureContextUploadAllowed, parseStorageFolderSegments, buildCanonicalWorkspaceAssetRelativePath, inferAssetKindFromPath, appendStorageTelemetry, scanAndRecordDocument, buildTaskAttachmentPayload, workspaceAssetStore, taskAssetStore, normalizeDocumentPathInput, getAssetMetadata, getCanonicalAssetMetadata, documentRetentionDays, appendDocumentPurgeHistory, markAssetDeleted, isAssetDeleted, clearAssetDeleted, ensureWithinDir, sanitizeDownloadFilename, contentTypeForExt, inferInlineDocumentFromPath, resolveCanonicalContentRead, inferWorkspaceIdFromStoragePath, inferTaskIdFromStoragePath, } = deps;
114
116
  const isTaskAttachmentDurable = (req, workspaceId) => (createTaskHttpDurableRouters({ core, context, req, workspaceId }).attachmentLinks.enabled);
115
117
  const durableUploadIdentity = (req, workspaceId, taskId) => {
116
118
  const normalizedTaskId = String(taskId || '').trim();
@@ -172,6 +174,69 @@ export function registerDocumentRoutes(deps) {
172
174
  return String(url.searchParams.get('workspaceId') || '').trim() || requestWorkspaceId(req);
173
175
  };
174
176
  const { ensureWorkspaceAssetAccess, isCloudAssetRequest } = createWorkspaceAssetAccessGuard({ core, context });
177
+ const readTaskDescriptionDraftUpload = (body) => {
178
+ const draftId = String(body?.draftUploadId || '').trim();
179
+ const purpose = String(body?.uploadPurpose || '').trim();
180
+ if (!draftId && !purpose)
181
+ return null;
182
+ if (purpose !== 'task-description-draft' || !/^[a-zA-Z0-9-]{16,160}$/.test(draftId)) {
183
+ throw Object.assign(new Error('Invalid task Description draft upload identity.'), { statusCode: 400 });
184
+ }
185
+ return { draftId, purpose };
186
+ };
187
+ const recordTaskDescriptionDraftUpload = (input) => {
188
+ const draft = readTaskDescriptionDraftUpload(input.body);
189
+ if (!draft || !workspaceAssetStore)
190
+ return;
191
+ workspaceAssetStore.recordUploadDraft({
192
+ workspaceId: input.workspaceId,
193
+ draftId: draft.draftId,
194
+ assetId: input.assetId,
195
+ storageKey: input.storageKey,
196
+ purpose: draft.purpose,
197
+ createdByUserId: String(requestUserId(input.req) || '').trim() || 'anonymous',
198
+ });
199
+ };
200
+ const retireOrDeleteTaskDescriptionDraftUploads = async (input) => {
201
+ if (!workspaceAssetStore)
202
+ return { total: 0, promoted: 0, discarded: 0 };
203
+ const records = workspaceAssetStore.listUploadDrafts(input);
204
+ const now = new Date();
205
+ const deletedAt = now.toISOString();
206
+ const purgeAfter = new Date(now.getTime() + documentRetentionDays * 86_400_000).toISOString();
207
+ let promoted = 0;
208
+ let discarded = 0;
209
+ for (const record of records) {
210
+ const links = workspaceAssetStore.listLinksForAsset(record.assetId, record.workspaceId);
211
+ if (links.length > 0) {
212
+ workspaceAssetStore.retireUploadDraft({
213
+ workspaceId: record.workspaceId,
214
+ draftId: record.draftId,
215
+ assetId: record.assetId,
216
+ retiredAt: deletedAt,
217
+ });
218
+ promoted += 1;
219
+ continue;
220
+ }
221
+ const asset = workspaceAssetStore.get(record.assetId, record.workspaceId);
222
+ if (asset && !asset.deletedAt) {
223
+ workspaceAssetStore.assertAssetDeletionAllowed(record.assetId, record.workspaceId);
224
+ workspaceAssetStore.markDeleted(record.assetId, record.workspaceId, deletedAt, purgeAfter);
225
+ core.notifyDocumentMetadataMutation(record.workspaceId, [record.storageKey], 'delete');
226
+ }
227
+ else if (!asset) {
228
+ await getObjectStorageClient()?.deleteObject(record.storageKey);
229
+ }
230
+ workspaceAssetStore.retireUploadDraft({
231
+ workspaceId: record.workspaceId,
232
+ draftId: record.draftId,
233
+ assetId: record.assetId,
234
+ retiredAt: deletedAt,
235
+ });
236
+ discarded += 1;
237
+ }
238
+ return { total: records.length, promoted, discarded };
239
+ };
175
240
  const removeDocumentAttachmentFromTaskAttachments = (attachmentsRaw, asset) => {
176
241
  const canonicalDocumentPath = `/api/taskforce/documents/${encodeURIComponent(asset.assetId)}/content`;
177
242
  const legacyContextPath = `/api/taskforce/context/${encodeURIComponent(asset.storageKey)}`;
@@ -260,6 +325,13 @@ export function registerDocumentRoutes(deps) {
260
325
  const relativeToStorage = canonicalAsset.relativePath;
261
326
  const relativePath = path.relative(projectRoot, path.join(basePath, relativeToStorage));
262
327
  if (objectStorageClient && resolvedObjectStorage.provider === 'r2' && resolvedObjectStorage.r2) {
328
+ recordTaskDescriptionDraftUpload({
329
+ req,
330
+ body,
331
+ workspaceId,
332
+ assetId: canonicalAsset.assetId,
333
+ storageKey: relativeToStorage,
334
+ });
263
335
  const uploadUrl = objectStorageClient.createSignedPutUrl(relativeToStorage, resolvedObjectStorage.r2.signedUploadTtlSeconds, String(mimeType || 'application/octet-stream'));
264
336
  appendStorageTelemetry('upload.initiated', {
265
337
  path: relativeToStorage,
@@ -345,8 +417,19 @@ export function registerDocumentRoutes(deps) {
345
417
  provider: 'r2',
346
418
  workspaceId: inferWorkspaceIdFromStoragePath(relativeToStorage),
347
419
  taskId: durableTaskAttachment ? null : taskId,
348
- originalName: typeof body?.originalName === 'string' ? body.originalName.trim() : null
420
+ originalName: typeof body?.originalName === 'string' ? body.originalName.trim() : null,
421
+ actorRef: requestHumanActorRef(req),
349
422
  });
423
+ const finalizedAsset = workspaceAssetStore?.getByStorageKey(relativeToStorage, workspaceId);
424
+ if (finalizedAsset) {
425
+ recordTaskDescriptionDraftUpload({
426
+ req,
427
+ body,
428
+ workspaceId,
429
+ assetId: finalizedAsset.assetId,
430
+ storageKey: relativeToStorage,
431
+ });
432
+ }
350
433
  if (durableTaskAttachment && taskId) {
351
434
  attachUploadedAssetThroughDurableBoundary({
352
435
  req,
@@ -456,7 +539,8 @@ export function registerDocumentRoutes(deps) {
456
539
  provider: 'r2',
457
540
  workspaceId,
458
541
  taskId: durableTaskAttachment ? null : normalizedTaskId,
459
- originalName: safeOriginal || actualFilename
542
+ originalName: safeOriginal || actualFilename,
543
+ actorRef: requestHumanActorRef(req),
460
544
  });
461
545
  appendStorageTelemetry('upload.completed', {
462
546
  path: relativeToStorage,
@@ -476,7 +560,8 @@ export function registerDocumentRoutes(deps) {
476
560
  provider: 'local',
477
561
  workspaceId,
478
562
  taskId: durableTaskAttachment ? null : normalizedTaskId,
479
- originalName: safeOriginal || actualFilename
563
+ originalName: safeOriginal || actualFilename,
564
+ actorRef: requestHumanActorRef(req),
480
565
  });
481
566
  appendStorageTelemetry('upload.completed', {
482
567
  path: relativeToStorage,
@@ -494,6 +579,16 @@ export function registerDocumentRoutes(deps) {
494
579
  caption: safeOriginal || actualFilename,
495
580
  });
496
581
  }
582
+ const uploadedAsset = workspaceAssetStore?.getByStorageKey(relativeToStorage, workspaceId);
583
+ if (uploadedAsset) {
584
+ recordTaskDescriptionDraftUpload({
585
+ req,
586
+ body,
587
+ workspaceId,
588
+ assetId: uploadedAsset.assetId,
589
+ storageKey: relativeToStorage,
590
+ });
591
+ }
497
592
  res.writeHead(200, { 'Content-Type': 'application/json' });
498
593
  const attachment = buildTaskAttachmentPayload(relativeToStorage, {
499
594
  caption: safeOriginal || actualFilename,
@@ -508,6 +603,40 @@ export function registerDocumentRoutes(deps) {
508
603
  })
509
604
  }));
510
605
  });
606
+ addRoute('POST', '/api/taskforce/context-upload/draft/promote', async (req, res) => {
607
+ const body = await parseJsonBody(req);
608
+ const workspaceId = resolveStorageWorkspaceId(req, body);
609
+ const draft = readTaskDescriptionDraftUpload(body);
610
+ if (!workspaceId || !draft) {
611
+ res.writeHead(400, { 'Content-Type': 'application/json' });
612
+ res.end(JSON.stringify({ error: 'workspaceId and draft upload identity are required.' }));
613
+ return;
614
+ }
615
+ const summary = await retireOrDeleteTaskDescriptionDraftUploads({
616
+ workspaceId,
617
+ draftId: draft.draftId,
618
+ createdByUserId: String(requestUserId(req) || '').trim() || 'anonymous',
619
+ });
620
+ res.writeHead(200, { 'Content-Type': 'application/json' });
621
+ res.end(JSON.stringify({ success: true, ...summary }));
622
+ });
623
+ addRoute('POST', '/api/taskforce/context-upload/draft/discard', async (req, res) => {
624
+ const body = await parseJsonBody(req);
625
+ const workspaceId = resolveStorageWorkspaceId(req, body);
626
+ const draft = readTaskDescriptionDraftUpload(body);
627
+ if (!workspaceId || !draft) {
628
+ res.writeHead(400, { 'Content-Type': 'application/json' });
629
+ res.end(JSON.stringify({ error: 'workspaceId and draft upload identity are required.' }));
630
+ return;
631
+ }
632
+ const summary = await retireOrDeleteTaskDescriptionDraftUploads({
633
+ workspaceId,
634
+ draftId: draft.draftId,
635
+ createdByUserId: String(requestUserId(req) || '').trim() || 'anonymous',
636
+ });
637
+ res.writeHead(200, { 'Content-Type': 'application/json' });
638
+ res.end(JSON.stringify({ success: true, ...summary }));
639
+ });
511
640
  addRoute('GET', '/api/taskforce/context/:filename', async (req, res, params) => {
512
641
  const resolvedObjectStorage = resolveEffectiveObjectStorageConfig();
513
642
  const objectStorageClient = getObjectStorageClient();
@@ -556,8 +685,8 @@ export function registerDocumentRoutes(deps) {
556
685
  ? `attachment; filename="${resolvedDownloadName.replace(/"/g, '')}"`
557
686
  : 'inline';
558
687
  const shouldProxyInlineDocument = !forceDownload && (canonicalAsset?.kind === 'document' || inferInlineDocumentFromPath(normalizedRelative));
559
- if (canonicalAsset?.kind === 'document' && !canonicalAsset.deletedAt) {
560
- const response = await resolveCanonicalDocumentRead({
688
+ if (canonicalAsset && !canonicalAsset.deletedAt && (canonicalAsset.kind === 'document' || !filePath)) {
689
+ const response = await resolveCanonicalContentRead({
561
690
  asset: canonicalAsset,
562
691
  forceDownload,
563
692
  requestedFilename
@@ -567,6 +696,11 @@ export function registerDocumentRoutes(deps) {
567
696
  res.end('Context file not found');
568
697
  return;
569
698
  }
699
+ if (response.statusCode === 409) {
700
+ res.writeHead(409, response.headers || { 'Content-Type': 'application/json' });
701
+ res.end(response.body);
702
+ return;
703
+ }
570
704
  if (forceDownload && response.statusCode === 302 && response.headers?.Location) {
571
705
  res.writeHead(302, { Location: response.headers.Location });
572
706
  res.end();
@@ -659,7 +793,7 @@ export function registerDocumentRoutes(deps) {
659
793
  res.end('Document scan pending');
660
794
  return;
661
795
  }
662
- const response = await resolveCanonicalDocumentRead({
796
+ const response = await resolveCanonicalContentRead({
663
797
  asset,
664
798
  forceDownload,
665
799
  requestedFilename
@@ -669,6 +803,11 @@ export function registerDocumentRoutes(deps) {
669
803
  res.end(JSON.stringify({ error: 'Document content not found' }));
670
804
  return;
671
805
  }
806
+ if (response.statusCode === 409) {
807
+ res.writeHead(409, response.headers || { 'Content-Type': 'application/json' });
808
+ res.end(response.body);
809
+ return;
810
+ }
672
811
  if (forceDownload && response.statusCode === 302 && response.headers?.Location) {
673
812
  res.writeHead(302, { Location: response.headers.Location });
674
813
  res.end();
@@ -791,6 +930,12 @@ export function registerDocumentRoutes(deps) {
791
930
  res.end(JSON.stringify({ error: 'Forbidden: admin role required.' }));
792
931
  return;
793
932
  }
933
+ const workspaceId = requestWorkspaceId(req);
934
+ const draftExpiry = new Date(Date.now() - 30 * 86_400_000).toISOString();
935
+ const draftSummary = await retireOrDeleteTaskDescriptionDraftUploads({
936
+ workspaceId,
937
+ createdBefore: draftExpiry,
938
+ });
794
939
  const { basePath } = core.getPaths();
795
940
  const summary = await purgeExpiredDocuments({
796
941
  basePath,
@@ -804,7 +949,7 @@ export function registerDocumentRoutes(deps) {
804
949
  provider: resolveEffectiveObjectStorageConfig().provider
805
950
  });
806
951
  res.writeHead(200, { 'Content-Type': 'application/json' });
807
- res.end(JSON.stringify({ success: true, ...summary }));
952
+ res.end(JSON.stringify({ success: true, ...summary, draftUploads: draftSummary }));
808
953
  });
809
954
  addRoute('GET', '/api/taskforce/documents', async (req, res) => {
810
955
  const workspaceId = requestWorkspaceIdWithQuery(req);
@@ -1059,7 +1204,7 @@ export function registerDocumentRoutes(deps) {
1059
1204
  core.updateTask(targetId, {
1060
1205
  attachments: [...(Array.isArray(task.attachments) ? task.attachments : []), payload],
1061
1206
  }, workspaceId, {
1062
- actorRef: 'user',
1207
+ actorRef: requestHumanActorRef(req),
1063
1208
  saveSource: 'manual',
1064
1209
  });
1065
1210
  }
@@ -1124,7 +1269,7 @@ export function registerDocumentRoutes(deps) {
1124
1269
  else {
1125
1270
  const updatedAttachments = removeDocumentAttachmentFromTaskAttachments(task.attachments, asset);
1126
1271
  core.updateTask(taskId, { attachments: updatedAttachments }, workspaceId, {
1127
- actorRef: 'user',
1272
+ actorRef: requestHumanActorRef(req),
1128
1273
  saveSource: 'manual'
1129
1274
  });
1130
1275
  }
@@ -1280,7 +1425,8 @@ export function registerDocumentRoutes(deps) {
1280
1425
  contentType: 'text/markdown; charset=utf-8',
1281
1426
  provider: 'r2',
1282
1427
  workspaceId: assetWorkspaceId,
1283
- originalName: metadata.logicalName || metadata.originalFilename || path.basename(normalizedStoragePath)
1428
+ originalName: metadata.logicalName || metadata.originalFilename || path.basename(normalizedStoragePath),
1429
+ actorRef: requestHumanActorRef(req),
1284
1430
  });
1285
1431
  clearAssetDeleted(normalizedStoragePath);
1286
1432
  const version = workspaceAssetStore
@@ -1336,7 +1482,8 @@ export function registerDocumentRoutes(deps) {
1336
1482
  contentType: 'text/markdown; charset=utf-8',
1337
1483
  provider: 'local',
1338
1484
  workspaceId: assetWorkspaceId,
1339
- originalName: path.basename(normalizedStoragePath)
1485
+ originalName: path.basename(normalizedStoragePath),
1486
+ actorRef: requestHumanActorRef(req),
1340
1487
  });
1341
1488
  clearAssetDeleted(normalizedStoragePath);
1342
1489
  version = workspaceAssetStore