@taskforcehq/taskforce 0.3.304 → 0.3.306

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 (383) hide show
  1. package/README.md +140 -247
  2. package/dist/Taskforce.module.css +295 -89
  3. package/dist/TaskforceCore.js +378 -111
  4. package/dist/TaskforceCore.test.js +1221 -107
  5. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  8. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  10. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  11. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  12. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  13. package/dist/compat/workspaceSyncCompat.js +52 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  16. package/dist/components/context/ContextAttachmentManager.js +549 -0
  17. package/dist/components/features/AgentsModule.d.ts +10 -1
  18. package/dist/components/features/AgentsModule.js +260 -15
  19. package/dist/components/features/AgentsModule.test.js +255 -5
  20. package/dist/components/features/DocumentIndex.d.ts +1 -1
  21. package/dist/components/features/DocumentIndex.js +1 -1
  22. package/dist/components/features/DocumentViewer.d.ts +6 -2
  23. package/dist/components/features/DocumentViewer.js +90 -10
  24. package/dist/components/features/DocumentWorkspace.d.ts +5 -22
  25. package/dist/components/features/DocumentWorkspace.js +12 -155
  26. package/dist/components/features/DocumentWorkspace.test.js +226 -6
  27. package/dist/components/features/TaskSettings.js +29 -3
  28. package/dist/components/features/TaskSettings.test.js +42 -1
  29. package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
  30. package/dist/components/features/documentWorkspaceModel.js +57 -0
  31. package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
  32. package/dist/components/features/useDocumentWorkspaceController.js +113 -0
  33. package/dist/components/task/TaskCard.js +19 -28
  34. package/dist/components/task/TaskCard.test.js +38 -3
  35. package/dist/components/task/TaskContextUpload.js +4 -526
  36. package/dist/components/task/TaskForm.d.ts +8 -8
  37. package/dist/components/task/TaskForm.js +362 -230
  38. package/dist/components/task/TaskForm.test.js +558 -381
  39. package/dist/components/task/TaskKanban.d.ts +2 -1
  40. package/dist/components/task/TaskKanban.js +96 -14
  41. package/dist/components/task/TaskKanban.test.js +36 -0
  42. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  43. package/dist/components/ui/EditableAvatarButton.js +18 -0
  44. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  45. package/dist/components/views/PlanComparisonPage.js +70 -17
  46. package/dist/components/views/PlanComparisonPage.test.js +289 -41
  47. package/dist/components/views/PlansPage.js +239 -106
  48. package/dist/components/views/PlansPage.test.js +593 -42
  49. package/dist/components/views/StandaloneLayout.js +310 -554
  50. package/dist/components/views/panels/FilterToolbar.test.js +6 -4
  51. package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
  52. package/dist/components/views/panels/PlanningDrawer.js +18 -11
  53. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  54. package/dist/components/views/panels/PlanningDrawer.test.js +141 -0
  55. package/dist/components/views/planningScope.d.ts +20 -0
  56. package/dist/components/views/planningScope.js +25 -0
  57. package/dist/components/views/planningScope.test.d.ts +1 -0
  58. package/dist/components/views/planningScope.test.js +60 -0
  59. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +27 -14
  60. package/dist/components/views/standalone/modals/AccountHubModal.js +87 -15
  61. package/dist/components/views/standalone/modals/AccountHubModal.test.js +42 -2
  62. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  63. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  64. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  65. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  66. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  67. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  68. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  69. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  70. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  71. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  72. package/dist/config/envSchema.js +1 -1
  73. package/dist/core/AiProfileService.d.ts +45 -3
  74. package/dist/core/AiProfileService.js +774 -63
  75. package/dist/core/AiProfileService.test.js +22 -2
  76. package/dist/core/AiProfiles.test.js +761 -2
  77. package/dist/core/AttachmentLinkService.js +57 -15
  78. package/dist/core/AuthIdentityService.d.ts +107 -0
  79. package/dist/core/AuthIdentityService.js +284 -0
  80. package/dist/core/AuthTokenService.d.ts +4 -0
  81. package/dist/core/AuthTokenService.js +34 -6
  82. package/dist/core/AuthTokenService.test.d.ts +1 -0
  83. package/dist/core/AuthTokenService.test.js +78 -0
  84. package/dist/core/EntitlementsPolicy.test.js +77 -15
  85. package/dist/core/GlobalSettingsService.js +115 -6
  86. package/dist/core/PlanEntitlementService.d.ts +30 -3
  87. package/dist/core/PlanEntitlementService.js +454 -93
  88. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  89. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  90. package/dist/core/PlanVersionPolicy.test.js +54 -28
  91. package/dist/core/PlanningEntities.test.js +52 -0
  92. package/dist/core/SignupMonetizationSettings.test.js +241 -44
  93. package/dist/core/SyncReconciliationService.js +2 -65
  94. package/dist/core/SystemAdmin.test.js +244 -88
  95. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  96. package/dist/core/TaskTaxonomyValidation.test.js +53 -0
  97. package/dist/core/Taskforce.d.ts +228 -14
  98. package/dist/core/Taskforce.js +814 -201
  99. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  100. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  101. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  102. package/dist/core/WorkspaceLifecycleService.js +0 -5
  103. package/dist/core/WorkspacePermissions.test.js +25 -1
  104. package/dist/core/WorkspacePlanMode.test.js +128 -27
  105. package/dist/core/shared.d.ts +3 -1
  106. package/dist/core/shared.js +16 -1
  107. package/dist/core/types.d.ts +68 -2
  108. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
  109. package/dist/hooks/sync/auth.js +3 -1
  110. package/dist/hooks/sync/bootstrap.js +2 -0
  111. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  112. package/dist/hooks/sync/controlPlane.js +78 -0
  113. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  114. package/dist/hooks/sync/controlPlane.test.js +121 -0
  115. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  116. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  117. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  118. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  119. package/dist/hooks/sync/orchestratorShared.d.ts +10 -1
  120. package/dist/hooks/sync/orchestratorShared.js +68 -47
  121. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  122. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  123. package/dist/hooks/sync/pullLifecycle.js +24 -0
  124. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  125. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  126. package/dist/hooks/sync/recovery.d.ts +16 -2
  127. package/dist/hooks/sync/recovery.js +171 -53
  128. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  129. package/dist/hooks/sync/recovery.test.js +292 -0
  130. package/dist/hooks/sync/transfers.d.ts +16 -3
  131. package/dist/hooks/sync/transfers.js +186 -65
  132. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  133. package/dist/hooks/sync/transfers.test.js +396 -0
  134. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  135. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  136. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  137. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  138. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  139. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  140. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  141. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  142. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  143. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  144. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  145. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  146. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  147. package/dist/hooks/useSyncOrchestrator.d.ts +16 -6
  148. package/dist/hooks/useSyncOrchestrator.js +424 -175
  149. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +487 -10
  150. package/dist/hooks/useTaskData.js +8 -3
  151. package/dist/hooks/useTaskData.test.js +45 -0
  152. package/dist/hooks/useTaskMutations.d.ts +2 -1
  153. package/dist/hooks/useTaskMutations.js +12 -1
  154. package/dist/hooks/useTaskMutations.test.js +30 -1
  155. package/dist/hooks/useTaskforce.d.ts +65 -4
  156. package/dist/hooks/useTaskforce.js +564 -243
  157. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  158. package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
  159. package/dist/hooks/useTaskforce.sync-behavior.test.js +2454 -208
  160. package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
  161. package/dist/hooks/useWorkspaceSyncController.js +17 -2
  162. package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
  163. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  164. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
  165. package/dist/localization/locales/en-US.d.ts +0 -1
  166. package/dist/localization/locales/en-US.js +0 -1
  167. package/dist/localization/locales/es-419.js +0 -1
  168. package/dist/localization/locales/pt-BR.js +0 -1
  169. package/dist/mcp/adminWorkspaceRegistrar.d.ts +2 -0
  170. package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
  171. package/dist/mcp/collaborationRegistrar.d.ts +2 -0
  172. package/dist/mcp/collaborationRegistrar.js +71 -0
  173. package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
  174. package/dist/mcp/documentAssetRegistrar.js +346 -0
  175. package/dist/mcp/runtime.d.ts +2 -0
  176. package/dist/mcp/runtime.js +2433 -3534
  177. package/dist/mcp/runtime.test.js +440 -2
  178. package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
  179. package/dist/mcp/taskPlanningRegistrar.js +418 -0
  180. package/dist/mcp/toolCatalog.d.ts +35 -0
  181. package/dist/mcp/toolCatalog.js +3 -0
  182. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  183. package/dist/migrations/taskSchemaMigrations.js +171 -61
  184. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  185. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  186. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  187. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  188. package/dist/resources/templates/workflows/plan.yaml +1 -1
  189. package/dist/resources/templates/workflows/review.yaml +2 -2
  190. package/dist/server/annotatedAttachmentsRoutes.test.js +3 -3
  191. package/dist/server/auth/providers/apple.d.ts +33 -0
  192. package/dist/server/auth/providers/apple.js +82 -0
  193. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  194. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  195. package/dist/server/auth/providers/github.d.ts +26 -0
  196. package/dist/server/auth/providers/github.js +86 -0
  197. package/dist/server/auth/providers/google.d.ts +21 -0
  198. package/dist/server/auth/providers/google.js +56 -0
  199. package/dist/server/auth/providers/types.d.ts +21 -0
  200. package/dist/server/auth/providers/types.js +1 -0
  201. package/dist/server/auth.d.ts +2 -0
  202. package/dist/server/auth.js +6 -3
  203. package/dist/server/documentReviewRoutes.test.js +36 -3
  204. package/dist/server/index.cookieProxy.test.js +1 -0
  205. package/dist/server/index.d.ts +12 -0
  206. package/dist/server/index.js +120 -9
  207. package/dist/server/index.rateLimit.test.js +3 -0
  208. package/dist/server/index.test.js +106 -3
  209. package/dist/server/routes/admin.d.ts +4 -5
  210. package/dist/server/routes/admin.js +410 -80
  211. package/dist/server/routes/annotatedAttachments.d.ts +1 -1
  212. package/dist/server/routes/annotatedAttachments.js +1 -1
  213. package/dist/server/routes/auth.d.ts +16 -6
  214. package/dist/server/routes/auth.js +1015 -118
  215. package/dist/server/routes/authSupport.d.ts +30 -0
  216. package/dist/server/routes/authSupport.js +81 -0
  217. package/dist/server/routes/billing.d.ts +1 -1
  218. package/dist/server/routes/billing.js +276 -34
  219. package/dist/server/routes/billing.test.js +760 -52
  220. package/dist/server/routes/documentReviews.d.ts +1 -1
  221. package/dist/server/routes/documentReviews.js +1 -1
  222. package/dist/server/routes/documents.d.ts +5 -2
  223. package/dist/server/routes/documents.js +242 -74
  224. package/dist/server/routes/primitives.d.ts +11 -0
  225. package/dist/server/routes/primitives.js +73 -0
  226. package/dist/server/routes/resources.d.ts +1 -1
  227. package/dist/server/routes/resources.js +1 -1
  228. package/dist/server/routes/shared.d.ts +29 -3
  229. package/dist/server/routes/shared.js +69 -4
  230. package/dist/server/routes/sync.d.ts +1 -1
  231. package/dist/server/routes/sync.integration.test.js +437 -39
  232. package/dist/server/routes/sync.js +62 -606
  233. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  234. package/dist/server/routes/syncAuxRoutes.js +91 -0
  235. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  236. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  237. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  238. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  239. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  240. package/dist/server/routes/syncPushRoutes.js +212 -0
  241. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  242. package/dist/server/routes/syncRouteGuards.js +67 -0
  243. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  244. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  245. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  246. package/dist/server/routes/syncRouteTypes.js +1 -0
  247. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  248. package/dist/server/routes/syncSnapshotRoutes.js +180 -0
  249. package/dist/server/routes/tasks.d.ts +1 -1
  250. package/dist/server/routes/tasks.js +44 -2
  251. package/dist/server/routes/workspaces.d.ts +1 -1
  252. package/dist/server/routes/workspaces.js +37 -6
  253. package/dist/server/routes.d.ts +2 -9
  254. package/dist/server/routes.js +136 -165
  255. package/dist/server/routes.test.js +2457 -162
  256. package/dist/services/workflowExportSnapshots.test.js +2 -0
  257. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  258. package/dist/shared/aiProfileSeatScope.js +21 -0
  259. package/dist/shared/passwordPolicy.d.ts +13 -0
  260. package/dist/shared/passwordPolicy.js +84 -0
  261. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  262. package/dist/shared/passwordPolicy.test.js +34 -0
  263. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  264. package/dist/storage/workspaceAssetStore.js +132 -44
  265. package/dist/storage/workspaceAssetStore.test.js +93 -6
  266. package/dist/styles/fonts.css +70 -0
  267. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  268. package/dist/sync/collaborationSyncPayload.js +17 -11
  269. package/dist/sync/collaborationSyncPayload.test.js +13 -1
  270. package/dist/sync/contentSyncState.d.ts +4 -8
  271. package/dist/sync/contentSyncState.js +33 -77
  272. package/dist/sync/syncApplyHandlers.d.ts +7 -0
  273. package/dist/sync/syncApplyHandlers.js +28 -13
  274. package/dist/sync/syncApplyHandlers.test.js +72 -3
  275. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  276. package/dist/sync/syncFieldSemantics.js +55 -0
  277. package/dist/sync/syncResourceAdapters.d.ts +44 -0
  278. package/dist/sync/syncResourceAdapters.js +77 -0
  279. package/dist/sync/syncService.d.ts +6 -0
  280. package/dist/sync/syncService.js +60 -0
  281. package/dist/sync/syncService.test.js +71 -3
  282. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  283. package/dist/sync/taskSyncChangeKey.js +143 -0
  284. package/dist/sync/taskSyncPayload.js +3 -8
  285. package/dist/sync/workspacePullFeed.js +4 -3
  286. package/dist/sync/workspacePullFeed.test.js +43 -0
  287. package/dist/sync/workspaceRepair.js +5 -2
  288. package/dist/sync/workspaceSyncModel.d.ts +48 -0
  289. package/dist/sync/workspaceSyncModel.js +195 -31
  290. package/dist/sync/workspaceSyncModel.test.js +325 -12
  291. package/dist/sync/workspaceSyncState.d.ts +19 -0
  292. package/dist/sync/workspaceSyncState.js +3 -1
  293. package/dist/sync/workspaceSyncSurface.js +3 -8
  294. package/dist/types.d.ts +17 -0
  295. package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
  296. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BlS-cqnl.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
  297. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  298. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  299. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  300. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  301. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +252 -0
  302. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
  303. package/dist/ui/assets/{InitiativesModule-BjR6iBf9.js → InitiativesModule-9E6ParrY.js} +1 -1
  304. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  305. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  306. package/dist/ui/assets/PlansPage-CvfnMiWq.css +1 -0
  307. package/dist/ui/assets/PlansPage-DRXscYxH.js +1 -0
  308. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  309. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  310. package/dist/ui/assets/TaskSettings-DZX4jk7e.js +9 -0
  311. package/dist/ui/assets/{WorkflowsModule-DnFqdUME.js → WorkflowsModule-BA7jcEpH.js} +1 -1
  312. package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
  313. package/dist/ui/assets/index-C6k75jr8.js +6 -0
  314. package/dist/ui/assets/{vendor-icons-I7ZwG1z_.js → vendor-icons-DuEd_65c.js} +1 -1
  315. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  316. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  317. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  318. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  319. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  320. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  321. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  322. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  323. package/dist/ui/fonts/Noir_medium.otf +0 -0
  324. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  325. package/dist/ui/fonts/Noir_regular.otf +0 -0
  326. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  327. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  328. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  329. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  330. package/dist/ui/index.html +3 -3
  331. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  332. package/dist/utils/assignees.d.ts +2 -0
  333. package/dist/utils/assignees.js +2 -0
  334. package/dist/utils/avatarUpload.d.ts +27 -0
  335. package/dist/utils/avatarUpload.js +132 -0
  336. package/dist/utils/avatarUpload.test.d.ts +1 -0
  337. package/dist/utils/avatarUpload.test.js +40 -0
  338. package/dist/utils/bootstrapTrace.d.ts +7 -0
  339. package/dist/utils/bootstrapTrace.js +29 -0
  340. package/dist/utils/commercialLifecyclePresentation.d.ts +19 -0
  341. package/dist/utils/commercialLifecyclePresentation.js +199 -0
  342. package/dist/utils/contextAssetEvents.d.ts +2 -0
  343. package/dist/utils/syncEventDetails.d.ts +3 -0
  344. package/dist/utils/syncEventDetails.js +64 -0
  345. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  346. package/dist/utils/syncEventDetails.test.js +23 -0
  347. package/dist/utils/syncEventPresentation.d.ts +15 -0
  348. package/dist/utils/syncEventPresentation.js +129 -0
  349. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  350. package/dist/utils/syncEventPresentation.test.js +64 -0
  351. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  352. package/dist/utils/syncStatusPresentation.js +217 -0
  353. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  354. package/dist/utils/syncStatusPresentation.test.js +164 -0
  355. package/dist/utils/taskActivity.d.ts +2 -0
  356. package/dist/utils/taskActivity.js +228 -22
  357. package/dist/utils/taskActivity.test.js +119 -8
  358. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  359. package/dist/utils/workspaceSyncPresentation.js +68 -2
  360. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  361. package/package.json +10 -2
  362. package/scripts/check-cloud-mcp.mjs +83 -0
  363. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  364. package/scripts/playwright-auth.sh +5 -1
  365. package/scripts/run-billing-performance-smoke.sh +24 -0
  366. package/scripts/run-e2e-realtime.sh +17 -3
  367. package/scripts/run-smoke.sh +17 -5
  368. package/scripts/run-soak.sh +17 -5
  369. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  370. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  371. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  372. package/src/resources/templates/workflows/plan.yaml +1 -1
  373. package/src/resources/templates/workflows/review.yaml +2 -2
  374. package/dist/ui/assets/AgentsModule-BLWVbuKP.js +0 -1
  375. package/dist/ui/assets/DocumentWorkspace-BH_6DF6x.js +0 -250
  376. package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
  377. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  378. package/dist/ui/assets/PlansPage-CSDQ4sLa.js +0 -1
  379. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  380. package/dist/ui/assets/TaskSettings-CEDy34Jo.js +0 -9
  381. package/dist/ui/assets/index-DXUdtH1B.js +0 -6
  382. package/dist/ui/assets/index-Ii0B0rTO.css +0 -1
  383. package/scripts/migrate-planning-model.ts +0 -233
@@ -323,6 +323,7 @@ describe('Taskforce MCP tool descriptions', () => {
323
323
  const getTask = getTool(result, 'get_task');
324
324
  const getPaths = getTool(result, 'get_paths');
325
325
  const searchImages = getTool(result, 'search_images');
326
+ const getImage = getTool(result, 'get_image');
326
327
  const getDocument = getTool(result, 'get_document');
327
328
  const searchDocuments = getTool(result, 'search_documents');
328
329
  const listAnnotatedAttachmentSessions = getTool(result, 'get_annotated_attachment_sessions');
@@ -341,10 +342,13 @@ describe('Taskforce MCP tool descriptions', () => {
341
342
  expect(getTask.description).toContain('Do not use this for image references like I-123 or document references like D-123.');
342
343
  expect(getPaths.description).toContain('Get project and Taskforce storage paths.');
343
344
  expect(searchImages.description).toContain('I-123 reference');
345
+ expect(getImage.description).toContain('placement, or visual correction feedback');
344
346
  expect(getDocument.description).toContain('D-123');
345
347
  expect(searchDocuments.description).toContain('D-123 reference');
346
348
  expect(listAnnotatedAttachmentSessions.description).toContain('saved annotation sessions');
349
+ expect(listAnnotatedAttachmentSessions.description).toContain('inspect the saved session payload next');
347
350
  expect(readAnnotatedAttachmentPayload.description).toContain('derived crop hints');
351
+ expect(readAnnotatedAttachmentPayload.description).toContain('authoritative instruction source');
348
352
  expect(createAnnotatedAttachmentSession.description).toContain('before adding markers');
349
353
  expect(deleteAnnotatedAttachmentSession.description).toContain('rather than deleting markers one by one');
350
354
  expect(reviewImage.description).toContain('first-pass visual review');
@@ -400,6 +404,7 @@ describe('Taskforce MCP tool descriptions', () => {
400
404
  expect(getTask.description).toContain('Do not use this for image references like I-123 or document references like D-123.');
401
405
  expect(searchImages.description).toContain('get_image');
402
406
  expect(getImage.description).toContain('Use this first when the user references an image');
407
+ expect(getImage.description).toContain('read the saved annotation payload before making changes');
403
408
  expect(searchDocuments.description).toContain('get_document');
404
409
  expect(searchDocuments.description).toContain('read_document_content');
405
410
  expect(getDocument.description).toContain('Use this first when the user references a document');
@@ -733,6 +738,63 @@ describe('Taskforce MCP tool descriptions', () => {
733
738
  fs.rmSync(projectRoot, { recursive: true, force: true });
734
739
  }
735
740
  });
741
+ it('creates a separate cloud profile and persists metadata when a same-name local profile already exists', async () => {
742
+ const projectRoot = createProjectRoot();
743
+ try {
744
+ const initial = parseToolJson(await callTool(projectRoot, 'local', 'resolve_profile', {
745
+ name: 'Automation Codex',
746
+ icon: 'Bot',
747
+ color: '#64748b'
748
+ }));
749
+ expect(initial.profile.description).toBeNull();
750
+ expect(initial.profile.role).toBeNull();
751
+ const currentProfile = parseToolJson(await callTool(projectRoot, 'cloud', 'get_current_profile', {}, {
752
+ workspaceId: 'workspace-1',
753
+ resolveProfile: false,
754
+ authAiProfileName: 'Automation Codex',
755
+ authAiProfileDescription: 'OpenAI Codex coding agent connected through MCP.',
756
+ authAiProfileRole: 'Coding Agent',
757
+ authAiProfileProvider: 'OpenAI',
758
+ authAiProfileModel: 'Codex',
759
+ authAiProfileSurfaceType: 'coding_tool'
760
+ }));
761
+ expect(currentProfile.profile).toEqual(expect.objectContaining({
762
+ name: 'Automation Codex',
763
+ description: 'OpenAI Codex coding agent connected through MCP.',
764
+ role: 'Coding Agent',
765
+ provider: 'OpenAI',
766
+ model: 'Codex',
767
+ surfaceType: 'coding_tool',
768
+ seatScope: 'cloud_metered'
769
+ }));
770
+ expect(currentProfile.profile.id).not.toBe(initial.profile.id);
771
+ const reloadedCore = new TaskforceCore({
772
+ projectRoot,
773
+ storagePath: path.join(projectRoot, '.taskforce')
774
+ });
775
+ expect(reloadedCore.listAiProfiles('workspace-1')).toEqual(expect.arrayContaining([
776
+ expect.objectContaining({
777
+ id: initial.profile.id,
778
+ name: 'Automation Codex',
779
+ seatScope: 'local_unmetered'
780
+ }),
781
+ expect.objectContaining({
782
+ id: currentProfile.profile.id,
783
+ name: 'Automation Codex',
784
+ description: 'OpenAI Codex coding agent connected through MCP.',
785
+ role: 'Coding Agent',
786
+ provider: 'OpenAI',
787
+ model: 'Codex',
788
+ surfaceType: 'coding_tool',
789
+ seatScope: 'cloud_metered'
790
+ })
791
+ ]));
792
+ reloadedCore.close();
793
+ }
794
+ finally {
795
+ fs.rmSync(projectRoot, { recursive: true, force: true });
796
+ }
797
+ });
736
798
  it('allows mutating MCP tools in a fresh runtime when profileToken is passed', async () => {
737
799
  const projectRoot = createProjectRoot();
738
800
  try {
@@ -759,9 +821,12 @@ describe('Taskforce MCP tool descriptions', () => {
759
821
  it('allows mutating cloud MCP tools when the connection is configured with an AI profile token', async () => {
760
822
  const projectRoot = createProjectRoot();
761
823
  try {
762
- const resolved = parseToolJson(await callTool(projectRoot, 'local', 'resolve_profile', {
824
+ const resolved = parseToolJson(await callTool(projectRoot, 'cloud', 'resolve_profile', {
763
825
  name: 'Automation Codex'
764
- }, { resolveProfile: false }));
826
+ }, {
827
+ workspaceId: 'workspace-1',
828
+ resolveProfile: false
829
+ }));
765
830
  const created = parseToolJson(await callTool(projectRoot, 'cloud', 'create_task', {
766
831
  title: 'Configured token write'
767
832
  }, {
@@ -816,6 +881,154 @@ describe('Taskforce MCP tool descriptions', () => {
816
881
  fs.rmSync(projectRoot, { recursive: true, force: true });
817
882
  }
818
883
  });
884
+ it('blocks cloud auto-bind when the configured AI profile has been retired by name until resolve_profile explicitly reactivates it', async () => {
885
+ const projectRoot = createProjectRoot();
886
+ try {
887
+ const core = new TaskforceCore({
888
+ projectRoot,
889
+ storagePath: path.join(projectRoot, '.taskforce')
890
+ });
891
+ const resolved = core.resolveAiProfile({
892
+ workspaceId: 'workspace-1',
893
+ name: 'Automation Codex',
894
+ }, { trustedSeatScope: 'cloud_metered' });
895
+ core.archiveAiProfile({
896
+ workspaceId: 'workspace-1',
897
+ profileId: resolved.profile.id,
898
+ archivedBy: 'owner-1',
899
+ reason: 'manual_archive'
900
+ });
901
+ core.close();
902
+ const blocked = await callTool(projectRoot, 'cloud', 'create_task', {
903
+ title: 'Should stay retired'
904
+ }, {
905
+ workspaceId: 'workspace-1',
906
+ resolveProfile: false,
907
+ authAiProfileName: 'Automation Codex'
908
+ });
909
+ expect(blocked.isError).toBe(true);
910
+ const blockedPayload = parseToolJson(blocked);
911
+ expect(blockedPayload.code).toBe('AI_PROFILE_RETIRED');
912
+ expect(blockedPayload.error).toContain('has been retired from this workspace');
913
+ expect(blockedPayload.nextTool).toBe('resolve_profile');
914
+ const reactivated = parseToolJson(await callTool(projectRoot, 'cloud', 'resolve_profile', {
915
+ name: 'Automation Codex',
916
+ surfaceType: 'agent'
917
+ }, {
918
+ workspaceId: 'workspace-1',
919
+ resolveProfile: false,
920
+ authAiProfileName: 'Automation Codex'
921
+ }));
922
+ expect(reactivated.created).toBe(false);
923
+ expect(reactivated.profile.id).toBe(resolved.profile.id);
924
+ expect(reactivated.profile.archivedAt ?? null).toBeNull();
925
+ const created = parseToolJson(await callTool(projectRoot, 'cloud', 'create_task', {
926
+ title: 'Reactivated automation write'
927
+ }, {
928
+ workspaceId: 'workspace-1',
929
+ resolveProfile: false,
930
+ authAiProfileName: 'Automation Codex'
931
+ }));
932
+ expect(created.title).toBe('Reactivated automation write');
933
+ expect(created.createdBy).toBe(resolved.profile.id);
934
+ }
935
+ finally {
936
+ fs.rmSync(projectRoot, { recursive: true, force: true });
937
+ }
938
+ });
939
+ it('blocks cloud auto-bind when the configured AI profile token belongs to a retired profile', async () => {
940
+ const projectRoot = createProjectRoot();
941
+ try {
942
+ const core = new TaskforceCore({
943
+ projectRoot,
944
+ storagePath: path.join(projectRoot, '.taskforce')
945
+ });
946
+ const resolved = core.resolveAiProfile({
947
+ workspaceId: 'workspace-1',
948
+ name: 'Automation Codex',
949
+ }, { trustedSeatScope: 'cloud_metered' });
950
+ core.archiveAiProfile({
951
+ workspaceId: 'workspace-1',
952
+ profileId: resolved.profile.id,
953
+ archivedBy: 'owner-1',
954
+ reason: 'manual_archive'
955
+ });
956
+ core.close();
957
+ const blocked = await callTool(projectRoot, 'cloud', 'create_task', {
958
+ title: 'Token should stay retired'
959
+ }, {
960
+ workspaceId: 'workspace-1',
961
+ resolveProfile: false,
962
+ authAiProfileToken: resolved.profile.profileToken,
963
+ authAiProfileName: 'Automation Codex'
964
+ });
965
+ expect(blocked.isError).toBe(true);
966
+ const blockedPayload = parseToolJson(blocked);
967
+ expect(blockedPayload.code).toBe('AI_PROFILE_RETIRED');
968
+ expect(blockedPayload.details).toEqual(expect.objectContaining({
969
+ profileId: resolved.profile.id,
970
+ profileToken: resolved.profile.profileToken,
971
+ archivedReason: 'manual_archive'
972
+ }));
973
+ }
974
+ finally {
975
+ fs.rmSync(projectRoot, { recursive: true, force: true });
976
+ }
977
+ });
978
+ it('blocks cloud auto-bind when the workspace has no remaining ai profile seats', async () => {
979
+ const projectRoot = createProjectRoot();
980
+ try {
981
+ const core = new TaskforceCore({
982
+ projectRoot,
983
+ storagePath: path.join(projectRoot, '.taskforce')
984
+ });
985
+ core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
986
+ core.ensureBootstrapUserAccess({
987
+ userId: 'owner-u1',
988
+ workspaceId: 'workspace-1',
989
+ role: 'owner',
990
+ email: 'owner@example.com'
991
+ });
992
+ core.updatePlanVersionFeatures({
993
+ planVersionId: 'free-v1',
994
+ features: [
995
+ { featureKey: 'collaboration.ai_profiles', access: 'limited', config: { maxAiProfiles: 1 } }
996
+ ]
997
+ });
998
+ core.updateAccountEntitlement({
999
+ accountId: 'owner-u1',
1000
+ planVersionId: 'free-v1',
1001
+ entitlementState: 'active',
1002
+ actorUserId: 'system-admin',
1003
+ actorRole: 'system_admin'
1004
+ });
1005
+ core.resolveAiProfile({
1006
+ workspaceId: 'workspace-1',
1007
+ name: 'Existing Automation Bot',
1008
+ }, { trustedSeatScope: 'cloud_metered' });
1009
+ core.close();
1010
+ const result = await callTool(projectRoot, 'cloud', 'create_task', {
1011
+ title: 'Blocked automation write'
1012
+ }, {
1013
+ workspaceId: 'workspace-1',
1014
+ resolveProfile: false,
1015
+ authAiProfileName: 'Automation Codex'
1016
+ });
1017
+ expect(result.isError).toBe(true);
1018
+ const payload = parseToolJson(result);
1019
+ expect(payload.code).toBe('AI_PROFILE_LIMIT_REACHED');
1020
+ expect(payload.error).toContain('No AI seats are available for this workspace');
1021
+ expect(payload.details).toEqual({
1022
+ workspaceId: 'workspace-1',
1023
+ limit: 1,
1024
+ used: 1,
1025
+ remaining: 0
1026
+ });
1027
+ }
1028
+ finally {
1029
+ fs.rmSync(projectRoot, { recursive: true, force: true });
1030
+ }
1031
+ });
819
1032
  it('rejects invalid profileToken values on mutating MCP tools', async () => {
820
1033
  const projectRoot = createProjectRoot();
821
1034
  try {
@@ -876,6 +1089,185 @@ describe('Taskforce MCP tool descriptions', () => {
876
1089
  fs.rmSync(projectRoot, { recursive: true, force: true });
877
1090
  }
878
1091
  });
1092
+ it('surfaces ai profile seat limits when an invalid per-call token falls back to a configured AI name', async () => {
1093
+ const projectRoot = createProjectRoot();
1094
+ try {
1095
+ const core = new TaskforceCore({
1096
+ projectRoot,
1097
+ storagePath: path.join(projectRoot, '.taskforce')
1098
+ });
1099
+ core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
1100
+ core.ensureBootstrapUserAccess({
1101
+ userId: 'owner-u1',
1102
+ workspaceId: 'workspace-1',
1103
+ role: 'owner',
1104
+ email: 'owner@example.com'
1105
+ });
1106
+ core.updatePlanVersionFeatures({
1107
+ planVersionId: 'free-v1',
1108
+ features: [
1109
+ { featureKey: 'collaboration.ai_profiles', access: 'limited', config: { maxAiProfiles: 1 } }
1110
+ ]
1111
+ });
1112
+ core.updateAccountEntitlement({
1113
+ accountId: 'owner-u1',
1114
+ planVersionId: 'free-v1',
1115
+ entitlementState: 'active',
1116
+ actorUserId: 'system-admin',
1117
+ actorRole: 'system_admin'
1118
+ });
1119
+ core.resolveAiProfile({
1120
+ workspaceId: 'workspace-1',
1121
+ name: 'Existing Automation Bot',
1122
+ }, { trustedSeatScope: 'cloud_metered' });
1123
+ core.close();
1124
+ const result = await callTool(projectRoot, 'cloud', 'create_task', {
1125
+ title: 'Recovered per-call token write',
1126
+ profileToken: 'tfp_invalid_token',
1127
+ }, {
1128
+ workspaceId: 'workspace-1',
1129
+ resolveProfile: false,
1130
+ authAiProfileName: 'Automation Codex'
1131
+ });
1132
+ expect(result.isError).toBe(true);
1133
+ const payload = parseToolJson(result);
1134
+ expect(payload.code).toBe('AI_PROFILE_LIMIT_REACHED');
1135
+ expect(payload.error).toContain('No AI seats are available for this workspace');
1136
+ expect(payload.details).toEqual({
1137
+ workspaceId: 'workspace-1',
1138
+ limit: 1,
1139
+ used: 1,
1140
+ remaining: 0
1141
+ });
1142
+ }
1143
+ finally {
1144
+ fs.rmSync(projectRoot, { recursive: true, force: true });
1145
+ }
1146
+ });
1147
+ it('keeps local MCP profile resolution unmetered even when cloud seats are full', async () => {
1148
+ const projectRoot = createProjectRoot();
1149
+ try {
1150
+ const core = new TaskforceCore({
1151
+ projectRoot,
1152
+ storagePath: path.join(projectRoot, '.taskforce')
1153
+ });
1154
+ core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
1155
+ core.ensureBootstrapUserAccess({
1156
+ userId: 'owner-u1',
1157
+ workspaceId: 'workspace-1',
1158
+ role: 'owner',
1159
+ email: 'owner@example.com'
1160
+ });
1161
+ core.updatePlanVersionFeatures({
1162
+ planVersionId: 'free-v1',
1163
+ features: [
1164
+ { featureKey: 'collaboration.ai_profiles', access: 'limited', config: { maxAiProfiles: 1 } }
1165
+ ]
1166
+ });
1167
+ core.updateAccountEntitlement({
1168
+ accountId: 'owner-u1',
1169
+ planVersionId: 'free-v1',
1170
+ entitlementState: 'active',
1171
+ actorUserId: 'system-admin',
1172
+ actorRole: 'system_admin'
1173
+ });
1174
+ core.resolveAiProfile({
1175
+ workspaceId: 'workspace-1',
1176
+ name: 'Existing Automation Bot',
1177
+ }, { trustedSeatScope: 'cloud_metered' });
1178
+ core.close();
1179
+ const payload = parseToolJson(await callTool(projectRoot, 'local', 'resolve_profile', {
1180
+ name: 'Local Codex'
1181
+ }, {
1182
+ workspaceId: 'workspace-1',
1183
+ resolveProfile: false
1184
+ }));
1185
+ expect(payload.created).toBe(true);
1186
+ expect(payload.profile.name).toBe('Local Codex');
1187
+ expect(payload.profile.seatScope).toBe('local_unmetered');
1188
+ }
1189
+ finally {
1190
+ fs.rmSync(projectRoot, { recursive: true, force: true });
1191
+ }
1192
+ });
1193
+ it('derives profile seat scope from the MCP runtime instead of auth metadata', async () => {
1194
+ const projectRoot = createProjectRoot();
1195
+ try {
1196
+ const localRuntime = createTaskforceMcpServer({
1197
+ projectRoot,
1198
+ runtimeMode: 'local',
1199
+ workspaceId: 'workspace-1',
1200
+ logStartup: false,
1201
+ auth: {
1202
+ aiProfileSeatScope: 'cloud_metered',
1203
+ aiProfileName: 'Codex',
1204
+ aiProfileRole: 'Implementation',
1205
+ aiProfileProvider: 'OpenAI',
1206
+ aiProfileModel: 'gpt-5',
1207
+ aiProfileSurfaceType: 'coding_tool',
1208
+ }
1209
+ });
1210
+ const localPayload = parseToolJson(await callToolWithRuntime(localRuntime, 'resolve_profile', {
1211
+ name: 'Codex',
1212
+ surfaceType: 'coding_tool',
1213
+ }, {
1214
+ resolveProfile: false
1215
+ }));
1216
+ expect(localPayload.profile.seatScope).toBe('local_unmetered');
1217
+ const cloudRuntime = createTaskforceMcpServer({
1218
+ projectRoot,
1219
+ runtimeMode: 'cloud',
1220
+ workspaceId: 'workspace-1',
1221
+ logStartup: false,
1222
+ auth: {
1223
+ scopes: ['tasks:read', 'tasks:write', 'workspace:read'],
1224
+ userId: 'owner-1',
1225
+ actorType: 'oauth',
1226
+ aiProfileSeatScope: 'local_unmetered',
1227
+ aiProfileName: 'Cloud Codex',
1228
+ aiProfileSurfaceType: 'coding_tool',
1229
+ }
1230
+ });
1231
+ const cloudPayload = parseToolJson(await callToolWithRuntime(cloudRuntime, 'resolve_profile', {
1232
+ name: 'Cloud Codex',
1233
+ surfaceType: 'coding_tool',
1234
+ }, {
1235
+ resolveProfile: false
1236
+ }));
1237
+ expect(cloudPayload.profile.seatScope).toBe('cloud_metered');
1238
+ }
1239
+ finally {
1240
+ fs.rmSync(projectRoot, { recursive: true, force: true });
1241
+ }
1242
+ });
1243
+ it('creates a separate local MCP profile when a cloud profile with the same name already exists', async () => {
1244
+ const projectRoot = createProjectRoot();
1245
+ try {
1246
+ const core = new TaskforceCore({
1247
+ projectRoot,
1248
+ storagePath: path.join(projectRoot, '.taskforce')
1249
+ });
1250
+ const cloud = core.resolveAiProfile({
1251
+ workspaceId: 'workspace-1',
1252
+ name: 'Codex',
1253
+ surfaceType: 'coding_tool'
1254
+ }, { trustedSeatScope: 'cloud_metered' });
1255
+ core.close();
1256
+ const payload = parseToolJson(await callTool(projectRoot, 'local', 'resolve_profile', {
1257
+ name: 'Codex',
1258
+ surfaceType: 'coding_tool'
1259
+ }, {
1260
+ workspaceId: 'workspace-1',
1261
+ resolveProfile: false
1262
+ }));
1263
+ expect(payload.created).toBe(true);
1264
+ expect(payload.profile.id).not.toBe(cloud.profile.id);
1265
+ expect(payload.profile.seatScope).toBe('local_unmetered');
1266
+ }
1267
+ finally {
1268
+ fs.rmSync(projectRoot, { recursive: true, force: true });
1269
+ }
1270
+ });
879
1271
  it('claims unassigned tasks and marks them in progress through start_task', async () => {
880
1272
  const projectRoot = createProjectRoot();
881
1273
  try {
@@ -2486,6 +2878,52 @@ describe('Taskforce MCP tool descriptions', () => {
2486
2878
  fs.rmSync(projectRoot, { recursive: true, force: true });
2487
2879
  }
2488
2880
  });
2881
+ it('accepts documented schedule helper arguments', async () => {
2882
+ const projectRoot = createProjectRoot();
2883
+ try {
2884
+ const core = new TaskforceCore({
2885
+ projectRoot,
2886
+ storagePath: path.join(projectRoot, '.taskforce')
2887
+ });
2888
+ const first = core.createTask({ title: 'First documented schedule helper test' }, { workspaceId: 'workspace-1' });
2889
+ const second = core.createTask({ title: 'Second documented schedule helper test' }, { workspaceId: 'workspace-1' });
2890
+ core.close();
2891
+ const board = parseToolJson(await callTool(projectRoot, 'local', 'get_schedule_board', {}));
2892
+ expect(board.week).toMatch(/^\d{4}-W\d{2}$/);
2893
+ const scheduled = parseToolJson(await callTool(projectRoot, 'local', 'schedule_task', {
2894
+ taskId: first.referenceLabel,
2895
+ date: '2099-01-05',
2896
+ order: 3
2897
+ }));
2898
+ expect(scheduled.scheduling.persistedDate).toBe('2099-01-05');
2899
+ expect(scheduled.scheduling.persistedOrderInDay).toBe(3);
2900
+ await callTool(projectRoot, 'local', 'reorder_scheduled_tasks', {
2901
+ date: '2099-01-05',
2902
+ taskIds: [second.referenceLabel, first.referenceLabel]
2903
+ });
2904
+ await callTool(projectRoot, 'local', 'unschedule_task', {
2905
+ taskId: first.referenceLabel
2906
+ });
2907
+ const after = new TaskforceCore({
2908
+ projectRoot,
2909
+ storagePath: path.join(projectRoot, '.taskforce')
2910
+ });
2911
+ try {
2912
+ const firstTask = after.getTask(first.id, 'workspace-1');
2913
+ const secondTask = after.getTask(second.id, 'workspace-1');
2914
+ expect(firstTask?.scheduledDate).toBeNull();
2915
+ expect(firstTask?.orderInDay).toBeNull();
2916
+ expect(secondTask?.scheduledDate).toBe('2099-01-05');
2917
+ expect(secondTask?.orderInDay).toBe(0);
2918
+ }
2919
+ finally {
2920
+ after.close();
2921
+ }
2922
+ }
2923
+ finally {
2924
+ fs.rmSync(projectRoot, { recursive: true, force: true });
2925
+ }
2926
+ });
2489
2927
  it('maps legacy agent assignee writes to unassigned even when a profile is resolved', async () => {
2490
2928
  const projectRoot = createProjectRoot();
2491
2929
  try {
@@ -0,0 +1,2 @@
1
+ import type { DomainToolExecutor, RegisterMcpTool } from './toolCatalog.js';
2
+ export declare function registerTaskPlanningTools(registerTool: RegisterMcpTool, executeTool: DomainToolExecutor): void;