@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
@@ -35,6 +35,10 @@ export function useUiNotice() {
35
35
  ttlMs,
36
36
  actionLabel: action?.label,
37
37
  onAction: action?.onAction,
38
+ actionPrimary: action?.primary,
39
+ secondaryActionLabel: action?.secondaryLabel,
40
+ onSecondaryAction: action?.onSecondaryAction,
41
+ dismissible: action?.dismissible,
38
42
  ownerKey: action?.ownerKey
39
43
  });
40
44
  // Actionable notices stay available until the action or explicit
@@ -78,11 +78,11 @@ export function registerAdminWorkspaceTools(registerTool, executeTool) {
78
78
  description: { type: 'string' },
79
79
  category: { type: 'string' },
80
80
  type: { type: 'string' },
81
- priority: { type: 'number', description: context.priorityDesc },
81
+ priority: { type: 'integer', description: context.priorityDesc, enum: context.priorityEnum },
82
82
  assignee: { type: 'string', description: `${context.assigneeHint} Call list_assignees to inspect the current eligible IDs.` },
83
83
  owner: { type: 'string', description: `${context.assigneeHint} Alias for assignee.` },
84
84
  status: { type: 'string', enum: ['task', 'on-hold', 'in-progress', 'review', 'done', 'cancelled'] },
85
- complexity: { type: 'number', description: context.complexityDesc },
85
+ complexity: { type: 'integer', minimum: 1, maximum: 5, description: context.complexityDesc },
86
86
  },
87
87
  required: ['id'],
88
88
  }),
@@ -101,7 +101,7 @@ export function registerAdminWorkspaceTools(registerTool, executeTool) {
101
101
  priorities: arrayProperty('Ordered priority definitions to save.', {
102
102
  type: 'object',
103
103
  properties: {
104
- value: { type: 'number' },
104
+ value: { type: 'integer', minimum: 1 },
105
105
  label: { type: 'string' },
106
106
  },
107
107
  }),
@@ -35,12 +35,23 @@ export interface CanonicalAssetHelpersDeps {
35
35
  assetId: string;
36
36
  };
37
37
  }
38
+ export declare class CanonicalDocumentHeadStaleError extends Error {
39
+ readonly details: Record<string, unknown>;
40
+ readonly code = "MCP_DOCUMENT_HEAD_STALE";
41
+ readonly statusCode = 409;
42
+ constructor(details: Record<string, unknown>);
43
+ }
38
44
  export declare function createCanonicalAssetHelpers(deps: CanonicalAssetHelpersDeps): {
39
45
  normalizeAttachmentStorageKey: (pathValue: unknown, fsPathValue: unknown) => string | null;
40
46
  buildSyntheticAttachmentId: (taskId: string, attachment: TaskAttachmentRecord) => string;
41
47
  getAttachmentAssetRecord: (attachment: TaskAttachmentRecord) => WorkspaceAssetEntry | null;
42
48
  buildAttachmentDownloadUrl: (attachment: McpTaskAttachmentDescriptor) => string;
43
49
  buildDocumentDownloadUrl: (asset: WorkspaceAssetEntry | WorkspaceDocumentEntry) => string;
50
+ assertCanonicalDocumentHeadCurrent: (asset: WorkspaceAssetEntry | WorkspaceDocumentEntry) => import("../sync/engine/workspaceSyncPublishedContentResolver.js").WorkspaceSyncPublishedLegacyContent | import("../sync/engine/workspaceSyncPublishedContentResolver.js").WorkspaceSyncPublishedVersionedContent | {
51
+ source: "legacy";
52
+ physicalKey: string;
53
+ storageProvider: import("../storage/objectStorage.js").ObjectStorageProvider;
54
+ };
44
55
  readCanonicalAttachmentBuffer: (taskId: string, attachment: McpTaskAttachmentDescriptor, targetLabel?: string) => Promise<Buffer>;
45
56
  readCanonicalDocumentBuffer: (asset: WorkspaceAssetEntry | WorkspaceDocumentEntry) => Promise<Buffer>;
46
57
  toTaskAttachmentRecord: (attachment: string | TaskAttachmentRecord) => TaskAttachmentRecord;
@@ -68,6 +79,7 @@ export declare function createCanonicalAssetHelpers(deps: CanonicalAssetHelpersD
68
79
  scanEngine?: string | null;
69
80
  scanDetails?: string | null;
70
81
  createLink?: boolean;
82
+ displayName?: string;
71
83
  }) => Promise<WorkspaceAssetEntry | null>;
72
84
  ensureCanonicalTaskAttachment: (relativePathRaw: string, taskIdRaw: string, captionRaw: string | undefined, timestampRaw: string | undefined, role: WorkspaceAssetLinkRole, options?: Parameters<(relativePathRaw: string, targetTypeRaw: WorkspaceAssetLinkTargetType, targetIdRaw: string, captionRaw: string | undefined, timestampRaw: string | undefined, role: WorkspaceAssetLinkRole, options?: {
73
85
  originalFilename?: string;
@@ -80,6 +92,7 @@ export declare function createCanonicalAssetHelpers(deps: CanonicalAssetHelpersD
80
92
  scanEngine?: string | null;
81
93
  scanDetails?: string | null;
82
94
  createLink?: boolean;
95
+ displayName?: string;
83
96
  }) => Promise<WorkspaceAssetEntry | null>>[6]) => Promise<WorkspaceAssetEntry | null>;
84
97
  buildCanonicalWorkspaceAssetRelativePath: (params: {
85
98
  workspaceIdRaw: unknown;
@@ -3,6 +3,16 @@ import * as path from 'path';
3
3
  import { createHash, randomUUID } from 'node:crypto';
4
4
  import { verifyWorkspaceSyncPublishedContentBody, } from '../sync/engine/workspaceSyncPublishedContentResolver.js';
5
5
  import { normalizeRelativeStorageKey, resolveExistingStorageKeyFilePathInsideRoot, resolveStorageKeyWritePathInsideRoot } from '../utils/pathSafety.js';
6
+ export class CanonicalDocumentHeadStaleError extends Error {
7
+ details;
8
+ code = 'MCP_DOCUMENT_HEAD_STALE';
9
+ statusCode = 409;
10
+ constructor(details) {
11
+ super('The published document head does not match the current canonical document metadata.');
12
+ this.details = details;
13
+ this.name = 'CanonicalDocumentHeadStaleError';
14
+ }
15
+ }
6
16
  export function createCanonicalAssetHelpers(deps) {
7
17
  const normalizeAttachmentStorageKey = (pathValue, fsPathValue) => {
8
18
  const fsPathRaw = String(fsPathValue || '').trim().replace(/\\/g, '/');
@@ -50,6 +60,30 @@ export function createCanonicalAssetHelpers(deps) {
50
60
  legacyProvider: asset.storageProvider,
51
61
  });
52
62
  };
63
+ const assertCanonicalDocumentHeadCurrent = (asset) => {
64
+ const resolved = resolveCanonicalContentRead(asset, 'document');
65
+ if (resolved.source === 'deleted') {
66
+ throw new Error(`Document ${asset.assetId} not found in workspace ${deps.activeWorkspaceId}.`);
67
+ }
68
+ if (resolved.source === 'versioned' && (resolved.storageProvider !== asset.storageProvider
69
+ || resolved.contentSha256 !== asset.contentSha256
70
+ || resolved.sizeBytes !== asset.sizeBytes)) {
71
+ throw new CanonicalDocumentHeadStaleError({
72
+ assetId: asset.assetId,
73
+ currentVersion: asset.version,
74
+ currentStorageProvider: asset.storageProvider,
75
+ currentContentSha256: asset.contentSha256,
76
+ currentSizeBytes: asset.sizeBytes,
77
+ headVersionId: resolved.versionId,
78
+ headStorageProvider: resolved.storageProvider,
79
+ headContentSha256: resolved.contentSha256,
80
+ headSizeBytes: resolved.sizeBytes,
81
+ nextTool: 'update_document',
82
+ guidance: 'Retry update_document with the complete current body and expectedVersion to republish the canonical immutable head. Do not use the returned download until the repair succeeds.',
83
+ });
84
+ }
85
+ return resolved;
86
+ };
53
87
  const buildSyntheticAttachmentId = (taskId, attachment) => {
54
88
  const stableSource = [
55
89
  taskId,
@@ -157,10 +191,7 @@ export function createCanonicalAssetHelpers(deps) {
157
191
  if (asset.scanStatus === 'pending') {
158
192
  throw new Error('Document scan pending');
159
193
  }
160
- const resolved = resolveCanonicalContentRead(asset, 'document');
161
- if (resolved.source === 'deleted') {
162
- throw new Error(`Document ${asset.assetId} not found in workspace ${deps.activeWorkspaceId}.`);
163
- }
194
+ const resolved = assertCanonicalDocumentHeadCurrent(asset);
164
195
  if (resolved.storageProvider === 'r2') {
165
196
  if (!normalizeRelativeStorageKey(resolved.physicalKey)) {
166
197
  throw new Error(`Document ${asset.assetId} not found in workspace ${deps.activeWorkspaceId}.`);
@@ -324,7 +355,9 @@ export function createCanonicalAssetHelpers(deps) {
324
355
  targetType,
325
356
  targetId,
326
357
  role,
327
- displayName: kind === 'document' ? null : (captionRaw || null),
358
+ displayName: options?.displayName !== undefined
359
+ ? options.displayName
360
+ : kind === 'document' ? null : (captionRaw || null),
328
361
  updatedAt: timestamp,
329
362
  deletedAt: null
330
363
  });
@@ -338,6 +371,7 @@ export function createCanonicalAssetHelpers(deps) {
338
371
  getAttachmentAssetRecord,
339
372
  buildAttachmentDownloadUrl,
340
373
  buildDocumentDownloadUrl,
374
+ assertCanonicalDocumentHeadCurrent,
341
375
  readCanonicalAttachmentBuffer,
342
376
  readCanonicalDocumentBuffer,
343
377
  toTaskAttachmentRecord,
@@ -23,7 +23,7 @@ export function registerCollaborationTools(registerTool, executeTool) {
23
23
  });
24
24
  };
25
25
  register('list_assignees', (context) => ({
26
- description: context.describeTool('List eligible assignees for the active workspace. Returns human workspace members and AI profiles that can own tasks. Use query to match a known ID, label, or username without loading the full catalog. Calls without query or limit preserve full-catalog discovery.'),
26
+ description: context.describeTool('List eligible assignees for the active workspace. Includes members and AI profiles. Use query for a bounded ID, label, or username match.'),
27
27
  inputSchema: {
28
28
  properties: {
29
29
  query: stringProperty('Optional case-insensitive substring matched against assignee ID, label, and username. When non-empty, returns at most 25 matches unless limit is set.'),
@@ -32,7 +32,7 @@ export function registerCollaborationTools(registerTool, executeTool) {
32
32
  },
33
33
  }));
34
34
  register('get_current_profile', (context) => ({
35
- description: context.describeTool('Inspect current AI identity for this call (ambient session, connection bootstrap, or explicit profileToken). Returns identityBound (true if this invocation has a resolved identity), bindingSource, profile, taskFilter, suggestedArgs, and guidance. Stateless/scheduled agents: call with profileToken if no ambient bind; use the returned suggestedArgs (with assignee) for list_tasks and pass profileToken on writes. Call before mutating or to decide on resolve_profile.'),
35
+ description: context.describeTool('Inspect current AI identity for this call and write readiness. Stateless/scheduled agents may pass profileToken. Use before writes or to decide whether resolve_profile is needed.'),
36
36
  inputSchema: {
37
37
  properties: {
38
38
  profileToken: stringProperty('Optional AI profile token to inspect when no profile is currently bound in session state. Pass only a token previously issued to this AI identity.'),
@@ -40,24 +40,25 @@ export function registerCollaborationTools(registerTool, executeTool) {
40
40
  },
41
41
  }));
42
42
  register('resolve_profile', (context) => ({
43
- description: context.describeTool('Resolve or create this AI collaborator profile. Use a stable collaborator/product name that does not change with the active model. For stateless agents (no ambient binding): call with name + surfaceType (and profileToken to re-use); the response includes created, profileToken, profile, *plus* identityBound, bindingSource, taskFilter, suggestedArgs, nextTool, guidance. Store profileToken privately only. Use suggestedArgs for list_tasks; pass profileToken on mutating calls. Never write profileToken to repos, tasks, logs, or docs.'),
43
+ description: context.describeTool('Resolve or create this AI collaborator profile using a stable product name. Stateless agents use name + surfaceType and may reuse profileToken. If OAuth recovery returns candidates, retry with profileId. Store profileToken privately only; pass it on writes. Never write profileToken to repos, tasks, logs, or docs.'),
44
44
  inputSchema: {
45
45
  properties: {
46
- name: stringProperty('Stable display name for the AI collaborator or product identity. Do not include the active model name or version.'),
47
- icon: stringProperty('Optional icon name or emoji saved with the AI profile. Omit to leave unchanged when profileToken is provided.'),
48
- color: stringProperty('Optional signature color as a Taskforce palette token or hex color. Omit on first registration to receive a stable application-assigned product or palette default. Omit to leave unchanged when profileToken is provided; workspace user overrides remain authoritative.'),
49
- description: stringProperty('Optional short description stored on the AI profile. Omit to leave unchanged when profileToken is provided.'),
50
- role: stringProperty('Optional role label stored on the AI profile. Omit to leave unchanged when profileToken is provided.'),
51
- provider: stringProperty('Optional provider name stored as secondary diagnostic metadata on the AI profile. Omit to leave unchanged when profileToken is provided.'),
52
- model: stringProperty('Optional model name stored as secondary diagnostic metadata on the AI profile. Omit to leave unchanged when profileToken is provided.'),
46
+ name: stringProperty('Stable collaborator or product name; exclude model names and versions.'),
47
+ icon: stringProperty('Optional profile icon or emoji; omit to leave unchanged.'),
48
+ color: stringProperty('Optional Taskforce palette token or hex color; omit to use the assigned default or retain the current value.'),
49
+ description: stringProperty('Optional profile description; omit to leave unchanged.'),
50
+ role: stringProperty('Optional role label; omit to leave unchanged.'),
51
+ provider: stringProperty('Optional provider metadata; omit to leave unchanged.'),
52
+ model: stringProperty('Optional model metadata; omit to leave unchanged.'),
53
53
  surfaceType: {
54
54
  anyOf: [
55
55
  { type: 'string', enum: [...AI_PROFILE_SURFACE_TYPES] },
56
56
  { type: 'null' },
57
57
  ],
58
- description: 'Optional self-declared AI surface type. Use agent for a persistent named AI collaborator in Taskforce, cli for terminal-native coding agents, coding_tool for coding surfaces that are not specifically CLI or IDE-native, chat_app for a conversational app identity, and ide for an IDE-native copilot identity. If you are unsure or none of those fit, choose agent. Omit to leave unchanged; pass null or an empty string to clear.',
58
+ description: 'Optional surface: agent (persistent collaborator), cli (terminal coding agent), coding_tool (other coding surface), chat_app (chat app), or ide (IDE copilot). Use agent when unsure. Omit to retain; null or empty clears.',
59
59
  },
60
- profileToken: stringProperty('Previously issued Taskforce profile token for this AI identity. Keep it in private agent/client state; when provided, Taskforce resolves the existing profile instead of creating a new one, and applies any supplied presentation field updates to that profile.'),
60
+ profileId: stringProperty('Compatible profile ID from a prior selection-required response.'),
61
+ profileToken: stringProperty('Private token previously issued for this AI identity; reuses and optionally updates that profile.'),
61
62
  },
62
63
  required: ['name'],
63
64
  },
@@ -73,11 +74,12 @@ export function registerCollaborationTools(registerTool, executeTool) {
73
74
  },
74
75
  }));
75
76
  register('add_comment', (context) => ({
76
- description: context.describeTool('Add a comment to a task. Use this for agent progress notes, handoff summaries, decision logs, and audit trails. Comments are visible in the task timeline.'),
77
+ description: context.describeTool('Add a comment to a task. Pass idempotencyKey when retrying after an ambiguous timeout; reuse it only with the exact same target and text.'),
77
78
  inputSchema: {
78
79
  properties: {
79
80
  id: stringProperty('Task ID or task reference such as T-123.'),
80
81
  text: stringProperty('Comment text.'),
82
+ idempotencyKey: { type: 'string', minLength: 1, maxLength: 128, description: 'Optional opaque retry key scoped to the active workspace, actor, and tool.' },
81
83
  },
82
84
  required: ['id', 'text'],
83
85
  },
@@ -2,8 +2,16 @@ import { bindDomainTool } from './toolCatalog.js';
2
2
  function stringProperty(description, enumValues) {
3
3
  return enumValues ? { type: 'string', description, enum: enumValues } : { type: 'string', description };
4
4
  }
5
- function numberProperty(description) {
6
- return { type: 'number', description };
5
+ function boundedNumberProperty(description, minimum, maximum) {
6
+ return { type: 'number', description, minimum, maximum };
7
+ }
8
+ function integerProperty(description, minimum, maximum) {
9
+ return {
10
+ type: 'integer',
11
+ description,
12
+ ...(minimum === undefined ? {} : { minimum }),
13
+ ...(maximum === undefined ? {} : { maximum }),
14
+ };
7
15
  }
8
16
  function booleanProperty(description) {
9
17
  return { type: 'boolean', description };
@@ -17,12 +25,12 @@ function annotatedAttachmentMarkerProperty() {
17
25
  properties: {
18
26
  type: { type: 'string' },
19
27
  kind: { type: 'string' },
20
- x: { type: 'number' },
21
- y: { type: 'number' },
22
- width: { type: 'number' },
23
- height: { type: 'number' },
24
- x2: { type: 'number' },
25
- y2: { type: 'number' },
28
+ x: { type: 'number', minimum: 0, maximum: 1 },
29
+ y: { type: 'number', minimum: 0, maximum: 1 },
30
+ width: { type: 'number', minimum: 0, maximum: 1 },
31
+ height: { type: 'number', minimum: 0, maximum: 1 },
32
+ x2: { type: 'number', minimum: 0, maximum: 1 },
33
+ y2: { type: 'number', minimum: 0, maximum: 1 },
26
34
  text: { type: 'string' },
27
35
  instruction: { type: 'string' },
28
36
  instructionType: { type: 'string' },
@@ -85,6 +93,7 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
85
93
  properties: descriptor.inputSchema.properties,
86
94
  ...(descriptor.inputSchema.required ? { required: descriptor.inputSchema.required } : {}),
87
95
  },
96
+ ...(descriptor.annotations ? { annotations: descriptor.annotations } : {}),
88
97
  };
89
98
  },
90
99
  handler: bindDomainTool(executeTool, name),
@@ -95,11 +104,11 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
95
104
  inputSchema: {
96
105
  properties: {
97
106
  taskId: stringProperty('Task ID or task reference such as T-123.'),
98
- id: stringProperty('Alias for taskId. Task ID or task reference such as T-123.'),
99
107
  attachmentId: stringProperty('Optional attachment descriptor id to include content for one attachment.'),
100
108
  format: stringProperty('Optional read format when attachmentId is provided. Use metadata for descriptors or download for a download URL.', ['text', 'metadata', 'download']),
101
- maxChars: numberProperty('Optional max inline character count for readable text attachments. Longer content is truncated with size metadata and a download hint.'),
109
+ maxChars: integerProperty('Optional max inline character count for readable text attachments. Longer content is truncated with size metadata and a download hint.', 1),
102
110
  },
111
+ required: ['taskId'],
103
112
  },
104
113
  }));
105
114
  register('get_workstream_attachments', (context) => ({
@@ -109,13 +118,14 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
109
118
  id: stringProperty('Workstream ID or workstream reference such as WS-123.'),
110
119
  attachmentId: stringProperty('Optional attachment descriptor id to include content for one attachment.'),
111
120
  format: stringProperty('Optional read format when attachmentId is provided. Use metadata for descriptors or download for a download URL.', ['text', 'metadata', 'download']),
112
- maxChars: numberProperty('Optional max inline character count for readable text attachments. Longer content is truncated with size metadata and a download hint.'),
121
+ maxChars: integerProperty('Optional max inline character count for readable text attachments. Longer content is truncated with size metadata and a download hint.', 1),
113
122
  },
114
123
  required: ['id'],
115
124
  },
116
125
  }));
117
126
  register('link_document', (context) => ({
118
127
  description: context.describeTool('Link an existing canonical document to a task, initiative, or workstream without copying it. The operation is idempotent. Use search_documents first when you do not know the exact D-123 reference or asset id.'),
128
+ annotations: { idempotentHint: true },
119
129
  inputSchema: {
120
130
  properties: {
121
131
  documentId: stringProperty('Canonical document reference such as D-123, document id, or asset id.'),
@@ -139,6 +149,7 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
139
149
  }));
140
150
  register('rehome_document', (context) => ({
141
151
  description: context.describeTool('Atomically move an existing canonical document reference between a task, initiative, or workstream without copying or deleting the document. Use this instead of separate link_document and unlink_document calls when correcting planning scope.'),
152
+ annotations: { idempotentHint: true },
142
153
  inputSchema: {
143
154
  properties: {
144
155
  documentId: stringProperty('Canonical document reference such as D-123, document id, or asset id.'),
@@ -159,18 +170,18 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
159
170
  }));
160
171
  register('save_workstream_attachment', (context) => ({
161
172
  description: context.describeTool(context.runtimeMode === 'cloud'
162
- ? 'Save generated content and attach it to a workstream. Provide inline content. Set overwrite=true to replace an existing canonical attachment with the same filename.'
163
- : 'Save a file and attach it to a workstream. Provide inline content or an approved local sourcePath. Set overwrite=true to replace an existing canonical attachment with the same filename.'),
173
+ ? 'Save inline content as a workstream-owned attachment. Use overwrite=true to replace the same filename.'
174
+ : 'Save inline content or an approved local file as a workstream-owned attachment. Use overwrite=true to replace the same filename.'),
164
175
  inputSchema: {
165
176
  properties: {
166
177
  id: stringProperty('Workstream ID or workstream reference such as WS-123.'),
167
178
  filename: stringProperty('Destination filename for the attachment.'),
168
- content: stringProperty('Inline file content; use this for AI-authored markdown/text attachments.'),
179
+ content: stringProperty('Inline text content.'),
169
180
  ...(context.runtimeMode === 'local' ? {
170
181
  sourcePath: stringProperty("Existing local file. Allowed roots: project, registered Git worktrees, Taskforce-managed sources, approved agent workspaces, or the bound profile's ~/.taskforce/qa/<username>/artifacts."),
171
182
  } : {}),
172
183
  caption: stringProperty('Optional attachment caption.'),
173
- overwrite: booleanProperty('When true, overwrite an existing canonical workstream attachment with the same filename instead of creating a new one.'),
184
+ overwrite: booleanProperty('Replace the existing attachment with the same filename.'),
174
185
  },
175
186
  required: ['id', 'filename'],
176
187
  },
@@ -192,25 +203,25 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
192
203
  id: stringProperty('Initiative ID or initiative reference such as IN-123.'),
193
204
  attachmentId: stringProperty('Optional attachment descriptor id to include content for one attachment.'),
194
205
  format: stringProperty('Optional read format when attachmentId is provided. Use metadata for descriptors or download for a download URL.', ['text', 'metadata', 'download']),
195
- maxChars: numberProperty('Optional max inline character count for readable text attachments. Longer content is truncated with size metadata and a download hint.'),
206
+ maxChars: integerProperty('Optional max inline character count for readable text attachments. Longer content is truncated with size metadata and a download hint.', 1),
196
207
  },
197
208
  required: ['id'],
198
209
  },
199
210
  }));
200
211
  register('save_initiative_attachment', (context) => ({
201
212
  description: context.describeTool(context.runtimeMode === 'cloud'
202
- ? 'Save generated content and attach it to an initiative. Provide inline content. Set overwrite=true to replace an existing canonical attachment with the same filename.'
203
- : 'Save a file and attach it to an initiative. Provide inline content or an approved local sourcePath. Set overwrite=true to replace an existing canonical attachment with the same filename.'),
213
+ ? 'Save inline content as an initiative-owned attachment. Use overwrite=true to replace the same filename.'
214
+ : 'Save inline content or an approved local file as an initiative-owned attachment. Use overwrite=true to replace the same filename.'),
204
215
  inputSchema: {
205
216
  properties: {
206
217
  id: stringProperty('Initiative ID or initiative reference such as IN-123.'),
207
218
  filename: stringProperty('Destination filename for the attachment.'),
208
- content: stringProperty('Inline file content; use this for AI-authored markdown/text attachments.'),
219
+ content: stringProperty('Inline text content.'),
209
220
  ...(context.runtimeMode === 'local' ? {
210
221
  sourcePath: stringProperty("Existing local file. Allowed roots: project, registered Git worktrees, Taskforce-managed sources, approved agent workspaces, or the bound profile's ~/.taskforce/qa/<username>/artifacts."),
211
222
  } : {}),
212
223
  caption: stringProperty('Optional attachment caption.'),
213
- overwrite: booleanProperty('When true, overwrite an existing canonical initiative attachment with the same filename instead of creating a new one.'),
224
+ overwrite: booleanProperty('Replace the existing attachment with the same filename.'),
214
225
  },
215
226
  required: ['id', 'filename'],
216
227
  },
@@ -226,11 +237,12 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
226
237
  },
227
238
  }));
228
239
  register('search_images', (context) => ({
229
- description: context.describeTool('Search image assets by keyword, title, filename, caption, or I-123 reference. Use this before get_image when you only know a rough identifier.'),
240
+ description: context.describeTool('Search image assets by keyword, title, filename, caption, or I-123 reference. Use offset/limit to continue broad searches, then call get_image for the selected result.'),
230
241
  inputSchema: {
231
242
  properties: {
232
243
  query: stringProperty('Search term for image lookup, including I-123 references.'),
233
- limit: numberProperty('Max images to return.'),
244
+ limit: integerProperty('Page size (default 10; max 50).', 1, 50),
245
+ offset: integerProperty('Non-negative result offset (default 0).', 0),
234
246
  },
235
247
  required: ['query'],
236
248
  },
@@ -239,17 +251,18 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
239
251
  description: context.describeTool('Get a single image by asset id or image reference such as I-123. Use this first when the user references an image, then use get_image_annotations for saved annotation sessions and payloads. When the image is being used for UI, placement, or visual correction feedback, read the saved annotation payload before making changes.'),
240
252
  inputSchema: {
241
253
  properties: {
242
- id: stringProperty('Image asset id or image reference such as I-123.'),
243
- imageId: stringProperty('Alias for id. Image asset id or image reference such as I-123.'),
254
+ imageId: stringProperty('Image asset id or image reference such as I-123.'),
244
255
  },
256
+ required: ['imageId'],
245
257
  },
246
258
  }));
247
259
  register('search_documents', (context) => ({
248
- description: context.describeTool('Search document assets by keyword, title, filename, caption, or D-123 reference. Use this before get_document when you only know a rough identifier. Search results guide the next step into get_document.'),
260
+ description: context.describeTool('Search document assets by keyword, title, filename, caption, or D-123 reference. Use offset/limit to continue broad searches, then call get_document for the selected result.'),
249
261
  inputSchema: {
250
262
  properties: {
251
263
  query: stringProperty('Search term for document lookup, including D-123 references.'),
252
- limit: numberProperty('Max documents to return.'),
264
+ limit: integerProperty('Page size (default 10; max 50).', 1, 50),
265
+ offset: integerProperty('Non-negative result offset (default 0).', 0),
253
266
  },
254
267
  required: ['query'],
255
268
  },
@@ -261,8 +274,9 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
261
274
  documentId: stringProperty('Document asset id or document reference such as D-123.'),
262
275
  includeContent: booleanProperty('When true, include bounded inline text content or a download reference for binary documents.'),
263
276
  format: stringProperty('Optional read mode when including content.', ['metadata', 'text', 'content', 'full', 'download']),
264
- maxChars: numberProperty('Optional max inline character count for readable documents. Longer content is truncated with size metadata and a download hint.'),
277
+ maxChars: integerProperty('Optional max inline character count for readable documents. Longer content is truncated with size metadata and a download hint.', 1),
265
278
  },
279
+ required: ['documentId'],
266
280
  },
267
281
  }));
268
282
  register('update_document', (context) => ({
@@ -285,7 +299,6 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
285
299
  inputSchema: {
286
300
  properties: {
287
301
  imageId: stringProperty('Image asset id or image reference such as I-123.'),
288
- imageAssetId: stringProperty('Alias for imageId. Image asset id or image reference such as I-123.'),
289
302
  taskId: stringProperty('Optional task ID or task reference such as T-123 to narrow sessions linked to one task.'),
290
303
  sessionId: stringProperty('Optional annotated attachment session id to include the structured payload for one session.'),
291
304
  },
@@ -344,16 +357,16 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
344
357
  sessionId: stringProperty('Annotated attachment session id.'),
345
358
  type: stringProperty('Marker type.'),
346
359
  kind: stringProperty('Alias for type. Marker kind: pin, box, arrow, or text-note.'),
347
- x: numberProperty('Normalized x coordinate in the 0..1 range.'),
348
- y: numberProperty('Normalized y coordinate in the 0..1 range.'),
349
- width: numberProperty('Optional normalized width in the 0..1 range.'),
350
- height: numberProperty('Optional normalized height in the 0..1 range.'),
360
+ x: boundedNumberProperty('Normalized x coordinate in the 0..1 range.', 0, 1),
361
+ y: boundedNumberProperty('Normalized y coordinate in the 0..1 range.', 0, 1),
362
+ width: boundedNumberProperty('Optional normalized width in the 0..1 range.', 0, 1),
363
+ height: boundedNumberProperty('Optional normalized height in the 0..1 range.', 0, 1),
351
364
  text: stringProperty('Optional marker text or note.'),
352
365
  instruction: stringProperty('Alias for text. Marker instruction or note.'),
353
366
  instructionType: stringProperty('Optional marker instruction category.'),
354
367
  color: stringProperty('Optional marker color.'),
355
- x2: numberProperty('Arrow endpoint normalized x coordinate.'),
356
- y2: numberProperty('Arrow endpoint normalized y coordinate.'),
368
+ x2: boundedNumberProperty('Arrow endpoint normalized x coordinate.', 0, 1),
369
+ y2: boundedNumberProperty('Arrow endpoint normalized y coordinate.', 0, 1),
357
370
  },
358
371
  required: ['sessionId'],
359
372
  },
@@ -374,12 +387,12 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
374
387
  properties: {
375
388
  sessionId: stringProperty('Annotated attachment session id.'),
376
389
  markerId: stringProperty('Marker id within the session.'),
377
- x: numberProperty('Updated normalized x coordinate.'),
378
- y: numberProperty('Updated normalized y coordinate.'),
379
- width: numberProperty('Updated normalized width.'),
380
- height: numberProperty('Updated normalized height.'),
381
- x2: numberProperty('Updated arrow endpoint normalized x coordinate.'),
382
- y2: numberProperty('Updated arrow endpoint normalized y coordinate.'),
390
+ x: boundedNumberProperty('Updated normalized x coordinate.', 0, 1),
391
+ y: boundedNumberProperty('Updated normalized y coordinate.', 0, 1),
392
+ width: boundedNumberProperty('Updated normalized width.', 0, 1),
393
+ height: boundedNumberProperty('Updated normalized height.', 0, 1),
394
+ x2: boundedNumberProperty('Updated arrow endpoint normalized x coordinate.', 0, 1),
395
+ y2: boundedNumberProperty('Updated arrow endpoint normalized y coordinate.', 0, 1),
383
396
  instruction: stringProperty('Updated marker instruction.'),
384
397
  instructionType: stringProperty('Updated marker instruction category.'),
385
398
  color: stringProperty('Updated marker color.'),
@@ -393,7 +406,7 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
393
406
  properties: {
394
407
  sessionId: stringProperty('Annotated attachment session id.'),
395
408
  markerId: stringProperty('Marker id within the session.'),
396
- toIndex: numberProperty('Target zero-based review order.'),
409
+ toIndex: integerProperty('Target zero-based review order.', 0),
397
410
  },
398
411
  required: ['sessionId', 'markerId', 'toIndex'],
399
412
  },
@@ -466,13 +479,14 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
466
479
  },
467
480
  }));
468
481
  register('add_document_review_comment', (context) => ({
469
- description: context.describeTool('Add one follow-up comment to an existing review session. Prefer review_document for multi-comment first-pass reviews.'),
482
+ description: context.describeTool('Add one follow-up comment to an existing review session. Prefer review_document for a complete review. Pass idempotencyKey only for exact retries after an ambiguous timeout.'),
470
483
  inputSchema: {
471
484
  properties: {
472
485
  sessionId: stringProperty('Document review session id.'),
473
486
  body: stringProperty('Comment text.'),
474
487
  anchor: documentReviewAnchorProperty(),
475
488
  parentCommentId: stringProperty('Optional root comment id. When supplied, adds a reply to that one-level thread; replies cannot target other replies.'),
489
+ idempotencyKey: { type: 'string', minLength: 1, maxLength: 128, description: 'Optional opaque retry key scoped to the active workspace, actor, and tool.' },
476
490
  },
477
491
  required: ['sessionId', 'body'],
478
492
  },
@@ -536,10 +550,11 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
536
550
  uploadedPath: stringProperty('Finalize a previously staged remote upload by passing the uploaded Taskforce storage path returned by save_task_attachment init mode.'),
537
551
  uploadDraftId: stringProperty('Finalize a previously staged remote upload by passing the uploadDraftId returned by save_task_attachment init mode.'),
538
552
  mimeType: stringProperty('Mime type for staged remote uploads such as image/png or image/jpeg. Provide this with sizeBytes to start a staged upload.'),
539
- sizeBytes: numberProperty('File size in bytes for staged remote uploads. Provide this with mimeType to start a staged upload.'),
553
+ sizeBytes: integerProperty('File size in bytes for staged remote uploads. Provide this with mimeType to start a staged upload.', 0),
540
554
  }),
541
- expectedSizeBytes: numberProperty('Optional exact byte count for integrity verification. The save is rejected before attachment when the persisted bytes would differ.'),
555
+ expectedSizeBytes: integerProperty('Optional exact byte count for integrity verification. The save is rejected before attachment when the persisted bytes would differ.', 0),
542
556
  expectedSha256: stringProperty('Optional lowercase or uppercase SHA-256 hex digest for integrity verification. The save is rejected before attachment when the persisted bytes would differ.'),
557
+ displayName: stringProperty('Optional attachment display name. Defaults to filename and is independent from caption.'),
543
558
  caption: stringProperty('Optional attachment caption.'),
544
559
  overwrite: booleanProperty('When true, overwrite an existing canonical task attachment with the same filename instead of creating a new one.'),
545
560
  },
@@ -548,6 +563,7 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
548
563
  }));
549
564
  register('set_task_plan', (context) => ({
550
565
  description: context.describeTool('Create or replace the canonical Markdown implementation plan for a task. Identical retries are no-ops. Optionally replace the task description with a concise summary after the plan is verified; a description failure preserves the valid plan and returns partial-success recovery guidance.'),
566
+ annotations: { idempotentHint: true },
551
567
  inputSchema: {
552
568
  properties: {
553
569
  taskId: stringProperty('Task ID or task reference such as T-123.'),
@@ -43,6 +43,7 @@ export declare function createDocumentHelpers(deps: DocumentHelpersDeps): {
43
43
  } | null;
44
44
  searchDocumentAssets: (queryRaw: unknown, options?: {
45
45
  limit?: unknown;
46
+ offset?: unknown;
46
47
  }) => Array<{
47
48
  asset: WorkspaceDocumentEntry;
48
49
  matchedOn: string[];
@@ -51,8 +51,10 @@ export function createDocumentHelpers(deps) {
51
51
  }
52
52
  const requestedLimit = Number(options?.limit);
53
53
  const limit = Number.isFinite(requestedLimit)
54
- ? Math.max(1, Math.min(50, Math.trunc(requestedLimit)))
54
+ ? Math.max(1, Math.min(51, Math.trunc(requestedLimit)))
55
55
  : 10;
56
+ const requestedOffset = Number(options?.offset);
57
+ const offset = Number.isFinite(requestedOffset) ? Math.max(0, Math.trunc(requestedOffset)) : 0;
56
58
  const normalize = (value) => typeof value === 'string' ? value.trim().toLowerCase() : '';
57
59
  const tokenize = (value) => normalize(value).split(/[^a-z0-9]+/i).filter(Boolean);
58
60
  const allDocuments = deps.workspaceAssetStore.listDocumentsByWorkspace(deps.activeWorkspaceId);
@@ -103,8 +105,10 @@ export function createDocumentHelpers(deps) {
103
105
  return [{ asset, matchedOn: Array.from(matchedOn), score }];
104
106
  });
105
107
  return scoredMatches
106
- .sort((a, b) => b.score - a.score || String(b.asset.updatedAt || '').localeCompare(String(a.asset.updatedAt || '')))
107
- .slice(0, limit);
108
+ .sort((a, b) => b.score - a.score
109
+ || String(b.asset.updatedAt || '').localeCompare(String(a.asset.updatedAt || ''))
110
+ || a.asset.assetId.localeCompare(b.asset.assetId))
111
+ .slice(offset, offset + limit);
108
112
  };
109
113
  const resolveDocumentAssetByIdentifierOrThrow = (documentIdentifier, options) => {
110
114
  const normalizedValue = typeof documentIdentifier === 'string' ? documentIdentifier.trim() : '';
@@ -3,6 +3,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
3
3
  import { JSONRPCMessageSchema, } from '@modelcontextprotocol/sdk/types.js';
4
4
  import { normalizeMcpConnectionId, parseMcpClientId } from './clientRegistry.js';
5
5
  import { normalizeMcpToolProfile } from './toolProfiles.js';
6
+ import { localServiceCloudTargetsEqual, parseLocalServiceCloudTarget, } from '../config/localServiceCloudTarget.js';
6
7
  import { discoverOrStartLocalService, LOCAL_SERVICE_API_BASE_PATH, LOCAL_SERVICE_PROTOCOL_VERSION, } from '../service/localServiceClientLifecycle.js';
7
8
  const REQUEST_TIMEOUT_MS = 120_000;
8
9
  const MAX_IN_FLIGHT = 32;
@@ -24,6 +25,7 @@ async function readJson(response, label) {
24
25
  }
25
26
  }
26
27
  function validateReadiness(readiness, descriptor) {
28
+ const readinessCloudTarget = parseLocalServiceCloudTarget(readiness.cloudTarget);
27
29
  if (!readiness.ready)
28
30
  throw new Error('Taskforce shared local service is not accepting new work.');
29
31
  if (readiness.protocolVersion !== LOCAL_SERVICE_PROTOCOL_VERSION
@@ -31,7 +33,8 @@ function validateReadiness(readiness, descriptor) {
31
33
  || readiness.generation !== descriptor.generation
32
34
  || readiness.pid !== descriptor.pid
33
35
  || readiness.endpoint !== descriptor.endpoint
34
- || readiness.dataIdentity !== descriptor.ownershipKey) {
36
+ || readiness.dataIdentity !== descriptor.ownershipKey
37
+ || !localServiceCloudTargetsEqual(readinessCloudTarget, descriptor.cloudTarget)) {
35
38
  throw new Error('Taskforce shared local service readiness does not match its descriptor.');
36
39
  }
37
40
  }
@@ -16,6 +16,18 @@ import { createDurableTaskCommentMutationRouter } from '../sync/v3/durableTaskCo
16
16
  import { createDurableTaskChecklistMutationRouter } from '../sync/v3/durableTaskChecklistMutationRouter.js';
17
17
  import { createDurableTaskAttachmentLinksMutationRouter } from '../sync/v3/durableTaskAttachmentLinksMutationRouter.js';
18
18
  import type { LocalDataOwnerPermit } from '../server/localDataOwnerPermit.js';
19
+ export type McpToolCallTiming = {
20
+ requestId: string | null;
21
+ toolName: string;
22
+ isWrite: boolean;
23
+ outcome: 'success' | 'failure';
24
+ totalMs: number;
25
+ preparationMs: number;
26
+ validationMs: number;
27
+ handlerMs: number;
28
+ responseBytes: number;
29
+ subphases: Record<string, number>;
30
+ };
19
31
  export interface TaskforceMcpServerOptions {
20
32
  projectRoot?: string;
21
33
  tenantId?: string;
@@ -34,6 +46,7 @@ export interface TaskforceMcpServerOptions {
34
46
  mutationKind: string;
35
47
  payloadFingerprint: string;
36
48
  }) => void;
49
+ onToolCallTiming?: (timing: McpToolCallTiming) => void;
37
50
  operationIdentityScope?: {
38
51
  generation: string;
39
52
  sessionId: string;
@@ -45,10 +58,12 @@ export interface TaskforceMcpServerOptions {
45
58
  durableTaxonomyMutationRouter?: ReturnType<typeof createDurableTaxonomyMutationRouter>;
46
59
  durableInitiativeMutationRouterFactory?: (actorRef: string, options?: {
47
60
  operationId?: string;
61
+ commentId?: string;
48
62
  deferPostCommitNotification?: (notify: () => void) => void;
49
63
  }) => ReturnType<typeof createDurableInitiativeMutationRouter>;
50
64
  durableWorkstreamMutationRouterFactory?: (actorRef: string, options?: {
51
65
  operationId?: string;
66
+ commentId?: string;
52
67
  deferPostCommitNotification?: (notify: () => void) => void;
53
68
  }) => ReturnType<typeof createDurableWorkstreamMutationRouter>;
54
69
  durableTaskRelationshipMutationRouter?: ReturnType<typeof createDurableTaskRelationshipMutationRouter>;
@@ -62,6 +77,7 @@ export interface TaskforceMcpServerOptions {
62
77
  userId?: string | null;
63
78
  tokenId?: string | null;
64
79
  aiProfileId?: string | null;
80
+ aiProfileIdentityAsserted?: boolean;
65
81
  aiProfileToken?: AiProfileBootstrapConfig['aiProfileToken'];
66
82
  aiProfileName?: AiProfileBootstrapConfig['aiProfileName'];
67
83
  aiProfileIcon?: AiProfileBootstrapConfig['aiProfileIcon'];