@taskforcehq/taskforce 0.3.305 → 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 (337) hide show
  1. package/dist/Taskforce.module.css +295 -89
  2. package/dist/TaskforceCore.js +215 -43
  3. package/dist/TaskforceCore.test.js +433 -28
  4. package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
  5. package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  6. package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
  7. package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
  8. package/dist/assets/fonts/Noir_medium.woff2 +0 -0
  9. package/dist/assets/fonts/Noir_regular.woff2 +0 -0
  10. package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
  11. package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
  12. package/dist/compat/workspaceSyncCompat.js +46 -2
  13. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  14. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  15. package/dist/components/context/ContextAttachmentManager.js +549 -0
  16. package/dist/components/features/AgentsModule.d.ts +10 -1
  17. package/dist/components/features/AgentsModule.js +260 -15
  18. package/dist/components/features/AgentsModule.test.js +255 -5
  19. package/dist/components/features/DocumentViewer.d.ts +5 -1
  20. package/dist/components/features/DocumentViewer.js +60 -3
  21. package/dist/components/features/DocumentWorkspace.js +1 -1
  22. package/dist/components/features/DocumentWorkspace.test.js +33 -0
  23. package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
  24. package/dist/components/task/TaskCard.js +19 -28
  25. package/dist/components/task/TaskCard.test.js +38 -3
  26. package/dist/components/task/TaskContextUpload.js +4 -526
  27. package/dist/components/task/TaskForm.js +85 -90
  28. package/dist/components/task/TaskForm.test.js +110 -8
  29. package/dist/components/task/TaskKanban.d.ts +2 -1
  30. package/dist/components/task/TaskKanban.js +94 -13
  31. package/dist/components/task/TaskKanban.test.js +36 -0
  32. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  33. package/dist/components/ui/EditableAvatarButton.js +18 -0
  34. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  35. package/dist/components/views/PlanComparisonPage.js +70 -14
  36. package/dist/components/views/PlanComparisonPage.test.js +238 -0
  37. package/dist/components/views/PlansPage.js +127 -36
  38. package/dist/components/views/PlansPage.test.js +294 -12
  39. package/dist/components/views/StandaloneLayout.js +283 -533
  40. package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
  41. package/dist/components/views/panels/PlanningDrawer.js +18 -11
  42. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  43. package/dist/components/views/panels/PlanningDrawer.test.js +141 -0
  44. package/dist/components/views/planningScope.d.ts +20 -0
  45. package/dist/components/views/planningScope.js +25 -0
  46. package/dist/components/views/planningScope.test.d.ts +1 -0
  47. package/dist/components/views/planningScope.test.js +60 -0
  48. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
  49. package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
  50. package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
  51. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  52. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  53. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  54. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  55. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  56. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  57. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  58. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  59. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  60. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  61. package/dist/core/AiProfileService.d.ts +39 -2
  62. package/dist/core/AiProfileService.js +639 -73
  63. package/dist/core/AiProfileService.test.js +19 -1
  64. package/dist/core/AiProfiles.test.js +566 -7
  65. package/dist/core/AttachmentLinkService.js +57 -15
  66. package/dist/core/AuthIdentityService.d.ts +107 -0
  67. package/dist/core/AuthIdentityService.js +284 -0
  68. package/dist/core/AuthTokenService.d.ts +4 -0
  69. package/dist/core/AuthTokenService.js +34 -6
  70. package/dist/core/AuthTokenService.test.js +3 -3
  71. package/dist/core/EntitlementsPolicy.test.js +2 -2
  72. package/dist/core/GlobalSettingsService.js +115 -6
  73. package/dist/core/PlanEntitlementService.d.ts +23 -2
  74. package/dist/core/PlanEntitlementService.js +343 -57
  75. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  76. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  77. package/dist/core/PlanVersionPolicy.test.js +35 -2
  78. package/dist/core/PlanningEntities.test.js +52 -0
  79. package/dist/core/SignupMonetizationSettings.test.js +199 -27
  80. package/dist/core/SyncReconciliationService.js +2 -65
  81. package/dist/core/SystemAdmin.test.js +42 -42
  82. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  83. package/dist/core/Taskforce.d.ts +225 -14
  84. package/dist/core/Taskforce.js +765 -192
  85. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  86. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  87. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  88. package/dist/core/WorkspaceLifecycleService.js +0 -5
  89. package/dist/core/WorkspacePermissions.test.js +25 -1
  90. package/dist/core/WorkspacePlanMode.test.js +117 -16
  91. package/dist/core/shared.d.ts +1 -1
  92. package/dist/core/shared.js +5 -1
  93. package/dist/core/types.d.ts +68 -2
  94. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
  95. package/dist/hooks/sync/bootstrap.js +2 -0
  96. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  97. package/dist/hooks/sync/controlPlane.js +78 -0
  98. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  99. package/dist/hooks/sync/controlPlane.test.js +121 -0
  100. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  101. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  102. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  103. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  104. package/dist/hooks/sync/orchestratorShared.d.ts +10 -1
  105. package/dist/hooks/sync/orchestratorShared.js +68 -47
  106. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  107. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  108. package/dist/hooks/sync/pullLifecycle.js +24 -0
  109. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  110. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  111. package/dist/hooks/sync/recovery.d.ts +16 -2
  112. package/dist/hooks/sync/recovery.js +171 -53
  113. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  114. package/dist/hooks/sync/recovery.test.js +292 -0
  115. package/dist/hooks/sync/transfers.d.ts +15 -3
  116. package/dist/hooks/sync/transfers.js +179 -62
  117. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  118. package/dist/hooks/sync/transfers.test.js +396 -0
  119. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  120. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  121. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  122. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  123. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  124. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  125. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  126. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  127. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  128. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  129. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  130. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  131. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  132. package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
  133. package/dist/hooks/useSyncOrchestrator.js +359 -178
  134. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
  135. package/dist/hooks/useTaskData.js +8 -3
  136. package/dist/hooks/useTaskData.test.js +45 -0
  137. package/dist/hooks/useTaskforce.d.ts +60 -2
  138. package/dist/hooks/useTaskforce.js +549 -240
  139. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  140. package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
  141. package/dist/hooks/useTaskforce.sync-behavior.test.js +2380 -212
  142. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  143. package/dist/hooks/useWorkspaceSyncController.js +6 -1
  144. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  145. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
  146. package/dist/localization/locales/en-US.d.ts +0 -1
  147. package/dist/localization/locales/en-US.js +0 -1
  148. package/dist/localization/locales/es-419.js +0 -1
  149. package/dist/localization/locales/pt-BR.js +0 -1
  150. package/dist/mcp/documentAssetRegistrar.js +3 -3
  151. package/dist/mcp/runtime.d.ts +2 -0
  152. package/dist/mcp/runtime.js +131 -64
  153. package/dist/mcp/runtime.test.js +291 -12
  154. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  155. package/dist/migrations/taskSchemaMigrations.js +171 -61
  156. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  157. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  158. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  159. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  160. package/dist/resources/templates/workflows/plan.yaml +1 -1
  161. package/dist/resources/templates/workflows/review.yaml +2 -2
  162. package/dist/server/annotatedAttachmentsRoutes.test.js +3 -3
  163. package/dist/server/auth/providers/apple.d.ts +33 -0
  164. package/dist/server/auth/providers/apple.js +82 -0
  165. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  166. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  167. package/dist/server/auth/providers/github.d.ts +26 -0
  168. package/dist/server/auth/providers/github.js +86 -0
  169. package/dist/server/auth/providers/google.d.ts +21 -0
  170. package/dist/server/auth/providers/google.js +56 -0
  171. package/dist/server/auth/providers/types.d.ts +21 -0
  172. package/dist/server/auth/providers/types.js +1 -0
  173. package/dist/server/auth.d.ts +2 -0
  174. package/dist/server/auth.js +6 -3
  175. package/dist/server/documentReviewRoutes.test.js +36 -3
  176. package/dist/server/index.cookieProxy.test.js +1 -0
  177. package/dist/server/index.d.ts +12 -0
  178. package/dist/server/index.js +120 -9
  179. package/dist/server/index.rateLimit.test.js +3 -0
  180. package/dist/server/index.test.js +106 -3
  181. package/dist/server/routes/admin.d.ts +3 -0
  182. package/dist/server/routes/admin.js +272 -19
  183. package/dist/server/routes/auth.d.ts +15 -2
  184. package/dist/server/routes/auth.js +994 -57
  185. package/dist/server/routes/authSupport.d.ts +1 -1
  186. package/dist/server/routes/authSupport.js +1 -1
  187. package/dist/server/routes/billing.js +361 -35
  188. package/dist/server/routes/billing.test.js +592 -12
  189. package/dist/server/routes/documents.d.ts +1 -0
  190. package/dist/server/routes/documents.js +172 -70
  191. package/dist/server/routes/shared.d.ts +28 -2
  192. package/dist/server/routes/shared.js +69 -4
  193. package/dist/server/routes/sync.integration.test.js +437 -39
  194. package/dist/server/routes/sync.js +61 -605
  195. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  196. package/dist/server/routes/syncAuxRoutes.js +91 -0
  197. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  198. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  199. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  200. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  201. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  202. package/dist/server/routes/syncPushRoutes.js +212 -0
  203. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  204. package/dist/server/routes/syncRouteGuards.js +67 -0
  205. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  206. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  207. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  208. package/dist/server/routes/syncRouteTypes.js +1 -0
  209. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  210. package/dist/server/routes/syncSnapshotRoutes.js +180 -0
  211. package/dist/server/routes/tasks.js +43 -1
  212. package/dist/server/routes/workspaces.js +36 -5
  213. package/dist/server/routes.js +60 -3
  214. package/dist/server/routes.test.js +1824 -171
  215. package/dist/services/workflowExportSnapshots.test.js +2 -0
  216. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  217. package/dist/shared/aiProfileSeatScope.js +21 -0
  218. package/dist/shared/passwordPolicy.d.ts +13 -0
  219. package/dist/shared/passwordPolicy.js +84 -0
  220. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  221. package/dist/shared/passwordPolicy.test.js +34 -0
  222. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  223. package/dist/storage/workspaceAssetStore.js +132 -44
  224. package/dist/storage/workspaceAssetStore.test.js +93 -6
  225. package/dist/styles/fonts.css +70 -0
  226. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  227. package/dist/sync/collaborationSyncPayload.js +17 -11
  228. package/dist/sync/collaborationSyncPayload.test.js +13 -1
  229. package/dist/sync/contentSyncState.d.ts +4 -8
  230. package/dist/sync/contentSyncState.js +17 -70
  231. package/dist/sync/syncApplyHandlers.d.ts +7 -0
  232. package/dist/sync/syncApplyHandlers.js +28 -13
  233. package/dist/sync/syncApplyHandlers.test.js +70 -3
  234. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  235. package/dist/sync/syncFieldSemantics.js +55 -0
  236. package/dist/sync/syncResourceAdapters.d.ts +44 -0
  237. package/dist/sync/syncResourceAdapters.js +77 -0
  238. package/dist/sync/syncService.d.ts +5 -0
  239. package/dist/sync/syncService.js +52 -0
  240. package/dist/sync/syncService.test.js +57 -3
  241. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  242. package/dist/sync/taskSyncChangeKey.js +143 -0
  243. package/dist/sync/taskSyncPayload.js +3 -8
  244. package/dist/sync/workspacePullFeed.js +4 -3
  245. package/dist/sync/workspacePullFeed.test.js +43 -0
  246. package/dist/sync/workspaceRepair.js +5 -2
  247. package/dist/sync/workspaceSyncModel.d.ts +45 -0
  248. package/dist/sync/workspaceSyncModel.js +183 -28
  249. package/dist/sync/workspaceSyncModel.test.js +291 -12
  250. package/dist/sync/workspaceSyncState.d.ts +17 -0
  251. package/dist/sync/workspaceSyncState.js +2 -1
  252. package/dist/sync/workspaceSyncSurface.js +3 -8
  253. package/dist/types.d.ts +17 -0
  254. package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
  255. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BG6P_GVW.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
  256. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  257. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  258. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  259. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  260. package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +252 -0
  261. package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
  262. package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-9E6ParrY.js} +1 -1
  263. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  264. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  265. package/dist/ui/assets/PlansPage-CvfnMiWq.css +1 -0
  266. package/dist/ui/assets/PlansPage-DRXscYxH.js +1 -0
  267. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  268. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  269. package/dist/ui/assets/{TaskSettings-ln0aF7xc.js → TaskSettings-DZX4jk7e.js} +1 -1
  270. package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-BA7jcEpH.js} +1 -1
  271. package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
  272. package/dist/ui/assets/index-C6k75jr8.js +6 -0
  273. package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-DuEd_65c.js} +1 -1
  274. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  275. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  276. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  277. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  278. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  279. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  280. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  281. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  282. package/dist/ui/fonts/Noir_medium.otf +0 -0
  283. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  284. package/dist/ui/fonts/Noir_regular.otf +0 -0
  285. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  286. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  287. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  288. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  289. package/dist/ui/index.html +3 -3
  290. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  291. package/dist/utils/assignees.d.ts +2 -0
  292. package/dist/utils/assignees.js +2 -0
  293. package/dist/utils/avatarUpload.d.ts +27 -0
  294. package/dist/utils/avatarUpload.js +132 -0
  295. package/dist/utils/avatarUpload.test.d.ts +1 -0
  296. package/dist/utils/avatarUpload.test.js +40 -0
  297. package/dist/utils/bootstrapTrace.d.ts +7 -0
  298. package/dist/utils/bootstrapTrace.js +29 -0
  299. package/dist/utils/commercialLifecyclePresentation.js +3 -0
  300. package/dist/utils/contextAssetEvents.d.ts +2 -0
  301. package/dist/utils/syncEventDetails.d.ts +3 -0
  302. package/dist/utils/syncEventDetails.js +64 -0
  303. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  304. package/dist/utils/syncEventDetails.test.js +23 -0
  305. package/dist/utils/syncEventPresentation.d.ts +15 -0
  306. package/dist/utils/syncEventPresentation.js +129 -0
  307. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  308. package/dist/utils/syncEventPresentation.test.js +64 -0
  309. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  310. package/dist/utils/syncStatusPresentation.js +217 -0
  311. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  312. package/dist/utils/syncStatusPresentation.test.js +164 -0
  313. package/dist/utils/taskActivity.d.ts +2 -0
  314. package/dist/utils/taskActivity.js +228 -22
  315. package/dist/utils/taskActivity.test.js +119 -8
  316. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  317. package/dist/utils/workspaceSyncPresentation.js +68 -2
  318. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  319. package/package.json +3 -2
  320. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  321. package/scripts/run-e2e-realtime.sh +17 -3
  322. package/scripts/run-smoke.sh +17 -5
  323. package/scripts/run-soak.sh +17 -5
  324. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  325. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  326. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  327. package/src/resources/templates/workflows/plan.yaml +1 -1
  328. package/src/resources/templates/workflows/review.yaml +2 -2
  329. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
  330. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
  331. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
  332. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  333. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
  334. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  335. package/dist/ui/assets/index-C2-OXZV7.css +0 -1
  336. package/dist/ui/assets/index-DcSI5F86.js +0 -6
  337. package/scripts/migrate-planning-model.ts +0 -233
@@ -2,6 +2,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
3
  import { McpAccessTokenScope, TaskforceCore } from '../core/Taskforce.js';
4
4
  import { type AiProfileBootstrapConfig } from './aiProfileBootstrap.js';
5
+ import { type AiProfileSeatScope } from '../shared/aiProfileSeatScope.js';
5
6
  export interface TaskforceMcpServerOptions {
6
7
  projectRoot?: string;
7
8
  tenantId?: string;
@@ -23,6 +24,7 @@ export interface TaskforceMcpServerOptions {
23
24
  aiProfileProvider?: AiProfileBootstrapConfig['aiProfileProvider'];
24
25
  aiProfileModel?: AiProfileBootstrapConfig['aiProfileModel'];
25
26
  aiProfileSurfaceType?: AiProfileBootstrapConfig['aiProfileSurfaceType'];
27
+ aiProfileSeatScope?: AiProfileSeatScope | null;
26
28
  actorType?: 'local' | 'user' | 'token' | 'oauth';
27
29
  requestId?: string | null;
28
30
  ip?: string | null;
@@ -23,6 +23,7 @@ import { getImageReferenceLabel, parseImageReference } from '../utils/imageRefer
23
23
  import { inferCanonicalAssetKind, isValidCanonicalDocumentAsset } from '../utils/canonicalAssetKind.js';
24
24
  import { getTaskReferenceLabel, shouldUseProvisionalTaskReferences } from '../utils/taskReferences.js';
25
25
  import { parseAiProfileSurfaceType } from '../shared/aiProfileSurfaceType.js';
26
+ import { parseAiProfileSeatScope } from '../shared/aiProfileSeatScope.js';
26
27
  import { formatWorkstreamReference, resolveInitiativeReference, parseWorkstreamReference, } from '../utils/planningReferences.js';
27
28
  import { MCP_TOOL_PERMISSIONS, MCP_WRITE_TOOL_NAMES } from './toolRegistry.js';
28
29
  import { registerAdminWorkspaceTools } from './adminWorkspaceRegistrar.js';
@@ -102,6 +103,13 @@ function resolveRecoverableToolError(error) {
102
103
  message,
103
104
  code,
104
105
  ...(details !== undefined ? { details } : {}),
106
+ ...(code === 'AI_PROFILE_RETIRED'
107
+ ? {
108
+ nextTool: 'resolve_profile',
109
+ suggestedArgs: {},
110
+ retryHint: 'Call resolve_profile to intentionally reactivate the retired AI identity, then retry the original mutating tool call.'
111
+ }
112
+ : {}),
105
113
  ...(code === 'TAXONOMY_NEEDS_CONFIRMATION' ? { needs_confirmation: true } : {})
106
114
  };
107
115
  }
@@ -227,6 +235,7 @@ export function createTaskforceMcpServer(options = {}) {
227
235
  const allowedScopes = Array.isArray(options.auth?.scopes)
228
236
  ? Array.from(new Set(options.auth.scopes))
229
237
  : null;
238
+ const configuredAiProfileSeatScope = runtimeMode === 'cloud' ? 'cloud_metered' : 'local_unmetered';
230
239
  if (logStartup) {
231
240
  console.error(`[Taskforce MCP] Starting for project: ${PROJECT_NAME} at ${PROJECT_ROOT}`);
232
241
  }
@@ -333,7 +342,7 @@ export function createTaskforceMcpServer(options = {}) {
333
342
  },
334
343
  tools: {},
335
344
  },
336
- instructions: `You are an AI collaborator connected to Taskforce, a shared task management system for AI-developer pairs.\n\nIMPORTANT: Before mutating Taskforce data, ensure Taskforce knows which AI profile you are acting as. The preferred path is ambient session binding: if your MCP connection is configured with x-taskforce-ai-name and optionally x-taskforce-ai-profile-token headers, Taskforce can auto-bind that AI identity for get_current_profile and later writes. If no AI identity is currently bound, call resolve_profile with your name. Reuse the returned profileToken across sessions, especially for stateless clients.\n\nStateless client pattern: call resolve_profile, save the returned profileToken, and include profileToken on later mutating tool calls only when your MCP client does not preserve session identity between calls.\n\nTo inspect your current attribution state before writes, call get_current_profile. It reports whether identity is bound, how it was resolved, and the suggested args to use with list_tasks.\n\nWhen setting resolve_profile.surfaceType, classify yourself by the kind of identity you are registering: use agent for a persistent named AI collaborator in Taskforce, coding_tool for the coding surface or terminal tool itself, chat_app for a conversational app identity, ide for an IDE-native copilot identity, and other only when none of those fit. If you are unsure and you are registering a named collaborator such as a teammate-style AI persona, choose agent.\n\nTo get tasks assigned to yourself, call get_current_profile, then use the returned suggestedArgs with list_tasks. When you begin active work on a tracked task, prefer start_task. It sets the task to in-progress and claims it for your AI profile when the task is currently unassigned. When work on a tracked task is complete, prefer finish_task for the final handoff: use outcome='review' when the next step is human validation or approval, and use outcome='done' only when no explicit human action is requested. Do not leave a task in-progress after reporting completed implementation unless the user explicitly wants more work to continue in the same task.\n\nTaxonomy rule: always call get_config before setting category, type, priority, approach, status, or complexity. Do not rely on remembered enum values.\n\nUse identifier prefixes to choose the correct retrieval path: T-123 goes to task tools such as get_task, IN-123 goes to initiative tools such as get_initiative, WS-123 goes to workstream tools such as get_workstream, I-123 goes to image tools such as get_image, and D-123 goes to document tools such as get_document. Do not send I-123 or D-123 identifiers to get_task.\n\nFor annotated images, use search_images first when you know only a keyword, filename, or rough title. Once you have the exact identifier, call get_image, then use get_annotated_attachment_sessions to list saved sessions, then use read_annotated_attachment_payload for the structured annotation payload.\n\nFor documents, use search_documents first when you know only a keyword, filename, or rough title. Once you have the exact identifier, call get_document, then read_document_content to inspect the document body. For a lower-friction review flow, prefer review_document; otherwise use get_document_review_sessions or create_document_review_session, then add_document_review_comment to record review feedback.`,
345
+ instructions: `You are an AI collaborator connected to Taskforce, a shared task management system for AI-developer pairs.\n\nIMPORTANT: Before mutating Taskforce data, ensure Taskforce knows which AI profile you are acting as. The preferred path is ambient session binding: if your MCP connection is configured with x-taskforce-ai-name and optionally x-taskforce-ai-profile-token headers, Taskforce can auto-bind that AI identity for get_current_profile and later writes. If no AI identity is currently bound, call resolve_profile with your name. Reuse the returned profileToken across sessions, especially for stateless clients.\n\nStateless client pattern: call resolve_profile, save the returned profileToken, and include profileToken on later mutating tool calls only when your MCP client does not preserve session identity between calls.\n\nTo inspect your current attribution state before writes, call get_current_profile. It reports whether identity is bound, how it was resolved, and the suggested args to use with list_tasks.\n\nWhen setting resolve_profile.surfaceType, classify yourself by the kind of identity you are registering: use agent for a persistent named AI collaborator in Taskforce, coding_tool for the coding surface or terminal tool itself, chat_app for a conversational app identity, ide for an IDE-native copilot identity, and other only when none of those fit. If you are unsure and you are registering a named collaborator such as a teammate-style AI persona, choose agent.\n\nTo get tasks assigned to yourself, call get_current_profile, then use the returned suggestedArgs with list_tasks. When you begin active work on a tracked task, prefer start_task. It sets the task to in-progress and claims it for your AI profile when the task is currently unassigned. When work on a tracked task is complete, prefer finish_task for the final handoff: use outcome='review' when the next step is human validation or approval, and use outcome='done' only when no explicit human action is requested. Do not leave a task in-progress after reporting completed implementation unless the user explicitly wants more work to continue in the same task.\n\nTaxonomy rule: always call get_config before setting category, type, priority, approach, status, or complexity. Do not rely on remembered enum values.\n\nUse identifier prefixes to choose the correct retrieval path: T-123 goes to task tools such as get_task, IN-123 goes to initiative tools such as get_initiative, WS-123 goes to workstream tools such as get_workstream, I-123 goes to image tools such as get_image, and D-123 goes to document tools such as get_document. Do not send I-123 or D-123 identifiers to get_task.\n\nFor annotated images, use search_images first when you know only a keyword, filename, or rough title. Once you have the exact identifier, call get_image, then use get_annotated_attachment_sessions to list saved sessions, then use read_annotated_attachment_payload for the structured annotation payload. If an image reference is being used for UI, placement, or visual correction feedback, treat the saved annotation payload as the source of truth and do not infer intent from the screenshot alone.\n\nFor documents, use search_documents first when you know only a keyword, filename, or rough title. Once you have the exact identifier, call get_document, then read_document_content to inspect the document body. For a lower-friction review flow, prefer review_document; otherwise use get_document_review_sessions or create_document_review_session, then add_document_review_comment to record review feedback.`,
337
346
  });
338
347
  const TOOL_PERMISSIONS = MCP_TOOL_PERMISSIONS;
339
348
  const RESOURCE_PERMISSIONS = {
@@ -562,6 +571,7 @@ export function createTaskforceMcpServer(options = {}) {
562
571
  provider: typeof actor.meta?.provider === 'string' ? actor.meta.provider : null,
563
572
  model: typeof actor.meta?.model === 'string' ? actor.meta.model : null,
564
573
  surfaceType: typeof actor.meta?.surfaceType === 'string' ? actor.meta.surfaceType : null,
574
+ seatScope: parseAiProfileSeatScope(actor.meta?.seatScope),
565
575
  } : {}),
566
576
  ...(activeAiProfileId && actor.id === activeAiProfileId ? { isCurrentProfile: true } : {})
567
577
  }))
@@ -581,6 +591,7 @@ export function createTaskforceMcpServer(options = {}) {
581
591
  provider: profile.provider ?? null,
582
592
  model: profile.model ?? null,
583
593
  surfaceType: profile.surfaceType ?? null,
594
+ seatScope: profile.seatScope ?? null,
584
595
  lastActiveAt: profile.lastActiveAt ?? null,
585
596
  };
586
597
  }
@@ -692,7 +703,7 @@ export function createTaskforceMcpServer(options = {}) {
692
703
  }
693
704
  function buildConfiguredAiProfileResolveInput(includeToken = true) {
694
705
  const configuredSurfaceType = parseAiProfileSurfaceType(configuredAiProfileSurfaceType);
695
- return buildResolveAiProfileInputFromBootstrap(ACTIVE_WORKSPACE_ID, {
706
+ const baseInput = buildResolveAiProfileInputFromBootstrap(ACTIVE_WORKSPACE_ID, {
696
707
  aiProfileToken: configuredAiProfileToken,
697
708
  aiProfileName: configuredAiProfileName,
698
709
  aiProfileIcon: configuredAiProfileIcon,
@@ -703,6 +714,51 @@ export function createTaskforceMcpServer(options = {}) {
703
714
  aiProfileModel: configuredAiProfileModel,
704
715
  aiProfileSurfaceType: configuredSurfaceType,
705
716
  }, includeToken);
717
+ if (!baseInput)
718
+ return null;
719
+ return baseInput;
720
+ }
721
+ function normalizeConfiguredAiProfileUsername(value, fallbackName) {
722
+ const source = String(value || fallbackName || '').trim().toLowerCase();
723
+ const normalized = source
724
+ .replace(/[^a-z0-9]+/g, '-')
725
+ .replace(/-+/g, '-')
726
+ .replace(/^-+|-+$/g, '')
727
+ .slice(0, 48);
728
+ return normalized || 'ai';
729
+ }
730
+ function findArchivedConfiguredAiProfileCandidate() {
731
+ if (configuredAiProfileToken) {
732
+ const profile = core.getAiProfileByToken({
733
+ workspaceId: ACTIVE_WORKSPACE_ID,
734
+ profileToken: configuredAiProfileToken,
735
+ includeArchived: true,
736
+ seatScope: configuredAiProfileSeatScope,
737
+ });
738
+ if (profile?.archivedAt)
739
+ return profile;
740
+ }
741
+ const configuredName = String(configuredAiProfileName || '').trim();
742
+ if (!configuredName)
743
+ return null;
744
+ const normalizedUsername = normalizeConfiguredAiProfileUsername(undefined, configuredName).toLowerCase();
745
+ return core.listAiProfiles(ACTIVE_WORKSPACE_ID, { includeArchived: true }).find((profile) => {
746
+ if (!profile.archivedAt)
747
+ return false;
748
+ if ((profile.seatScope ?? null) !== configuredAiProfileSeatScope)
749
+ return false;
750
+ const profileName = String(profile.name || '').trim().toLowerCase();
751
+ const profileUsername = String(profile.username || '').trim().toLowerCase();
752
+ return profileName === configuredName.toLowerCase() || profileUsername === normalizedUsername;
753
+ }) || null;
754
+ }
755
+ function throwArchivedConfiguredAiProfileError(profile) {
756
+ throw new TaskforceRuleError(`AI profile "${profile.name}" has been retired from this workspace. Call resolve_profile to reactivate it before retrying.`, 409, 'AI_PROFILE_RETIRED', {
757
+ workspaceId: ACTIVE_WORKSPACE_ID,
758
+ profileId: profile.id,
759
+ profileToken: profile.profileToken || null,
760
+ archivedReason: profile.archivedReason || null,
761
+ });
706
762
  }
707
763
  function ensureResolvedProfileFromConnection(defaults) {
708
764
  if (activeAiProfileId)
@@ -710,10 +766,16 @@ export function createTaskforceMcpServer(options = {}) {
710
766
  const allowCreateFromName = defaults?.allowCreateFromName === true;
711
767
  const configuredResolveInput = buildConfiguredAiProfileResolveInput(true);
712
768
  const configuredResolveFallbackInput = buildConfiguredAiProfileResolveInput(false);
769
+ const archivedConfiguredProfile = findArchivedConfiguredAiProfileCandidate();
770
+ if (archivedConfiguredProfile) {
771
+ throwArchivedConfiguredAiProfileError(archivedConfiguredProfile);
772
+ }
713
773
  if (configuredAiProfileToken) {
714
774
  if (configuredResolveInput) {
715
775
  try {
716
- const resolved = core.resolveAiProfile(configuredResolveInput);
776
+ const resolved = core.resolveAiProfile(configuredResolveInput, {
777
+ trustedSeatScope: configuredAiProfileSeatScope,
778
+ });
717
779
  activeAiProfileId = resolved.profile.id;
718
780
  activeAiBindingSource = 'connection_bootstrap';
719
781
  return;
@@ -725,6 +787,7 @@ export function createTaskforceMcpServer(options = {}) {
725
787
  const profile = core.getAiProfileByToken({
726
788
  workspaceId: ACTIVE_WORKSPACE_ID,
727
789
  profileToken: configuredAiProfileToken,
790
+ seatScope: configuredAiProfileSeatScope,
728
791
  });
729
792
  if (profile) {
730
793
  activeAiProfileId = profile.id;
@@ -736,7 +799,9 @@ export function createTaskforceMcpServer(options = {}) {
736
799
  }
737
800
  }
738
801
  if (allowCreateFromName && configuredResolveFallbackInput) {
739
- const resolved = core.resolveAiProfile(configuredResolveFallbackInput);
802
+ const resolved = core.resolveAiProfile(configuredResolveFallbackInput, {
803
+ trustedSeatScope: configuredAiProfileSeatScope,
804
+ });
740
805
  activeAiProfileId = resolved.profile.id;
741
806
  activeAiBindingSource = 'connection_bootstrap';
742
807
  }
@@ -756,6 +821,7 @@ export function createTaskforceMcpServer(options = {}) {
756
821
  const profile = core.getAiProfileByToken({
757
822
  workspaceId: ACTIVE_WORKSPACE_ID,
758
823
  profileToken,
824
+ seatScope: configuredAiProfileSeatScope,
759
825
  });
760
826
  if (profile) {
761
827
  activeAiProfileId = profile.id;
@@ -764,7 +830,9 @@ export function createTaskforceMcpServer(options = {}) {
764
830
  }
765
831
  const configuredResolveInput = buildConfiguredAiProfileResolveInput(false);
766
832
  if (configuredResolveInput) {
767
- const resolved = core.resolveAiProfile(configuredResolveInput);
833
+ const resolved = core.resolveAiProfile(configuredResolveInput, {
834
+ trustedSeatScope: configuredAiProfileSeatScope,
835
+ });
768
836
  activeAiProfileId = resolved.profile.id;
769
837
  activeAiBindingSource = 'connection_bootstrap';
770
838
  return;
@@ -1224,6 +1292,21 @@ export function createTaskforceMcpServer(options = {}) {
1224
1292
  const d = String(date.getDate()).padStart(2, '0');
1225
1293
  return `${y}-${m}-${d}`;
1226
1294
  }
1295
+ function dateOnlyToIsoWeekKey(dateOnly) {
1296
+ const parsed = parseDateOnlyLocal(dateOnly);
1297
+ if (!parsed)
1298
+ return null;
1299
+ const weekDate = new Date(Date.UTC(parsed.getFullYear(), parsed.getMonth(), parsed.getDate()));
1300
+ const day = weekDate.getUTCDay() || 7;
1301
+ weekDate.setUTCDate(weekDate.getUTCDate() + 4 - day);
1302
+ const year = weekDate.getUTCFullYear();
1303
+ const yearStart = new Date(Date.UTC(year, 0, 1));
1304
+ const week = Math.ceil((((weekDate.getTime() - yearStart.getTime()) / 86400000) + 1) / 7);
1305
+ return `${year}-W${String(week).padStart(2, '0')}`;
1306
+ }
1307
+ function currentIsoWeekKeyLocal() {
1308
+ return dateOnlyToIsoWeekKey(formatDateOnlyLocal(new Date())) || '';
1309
+ }
1227
1310
  function addDaysDateOnly(dateOnly, days) {
1228
1311
  const parsed = parseDateOnlyLocal(dateOnly);
1229
1312
  if (!parsed)
@@ -1817,53 +1900,20 @@ export function createTaskforceMcpServer(options = {}) {
1817
1900
  case "list_tasks": {
1818
1901
  const startedAtMs = Date.now();
1819
1902
  const { format = "markdown", category, status, openOnly = false, assignee, priority, type, sort = "created", order = "desc", limit } = args;
1820
- let data = core.listTasks(ACTIVE_WORKSPACE_ID);
1821
- let tasks = data.tasks;
1822
- const openStatuses = new Set(["task", "on-hold", "in-progress", "review"]);
1823
- // Filtering
1824
- if (category)
1825
- tasks = tasks.filter(t => t.category === category);
1826
- if (status)
1827
- tasks = tasks.filter(t => t.status === status);
1828
- if (openOnly)
1829
- tasks = tasks.filter(t => openStatuses.has(t.status));
1830
- if (assignee)
1831
- tasks = tasks.filter(t => (t.assignee || 'unassigned') === assignee);
1832
- if (priority !== undefined)
1833
- tasks = tasks.filter(t => t.priority === Number(priority));
1834
- if (type)
1835
- tasks = tasks.filter(t => t.type === type);
1836
- // Sorting
1837
- tasks.sort((a, b) => {
1838
- let aVal, bVal;
1839
- if (sort === "priority") {
1840
- aVal = a.priority;
1841
- bVal = b.priority;
1842
- }
1843
- else if (sort === "updated") {
1844
- aVal = a.updatedAt || a.createdAt;
1845
- bVal = b.updatedAt || b.createdAt;
1846
- }
1847
- else {
1848
- aVal = a.createdAt;
1849
- bVal = b.createdAt;
1850
- }
1851
- const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
1852
- return order === "asc" ? cmp : -cmp;
1903
+ const slimTasks = core.listTasksSlim(ACTIVE_WORKSPACE_ID, {
1904
+ category,
1905
+ status,
1906
+ openOnly: Boolean(openOnly),
1907
+ assignee,
1908
+ priority: priority !== undefined ? Number(priority) : undefined,
1909
+ type,
1910
+ sort,
1911
+ order,
1912
+ limit: typeof limit === 'number' ? limit : (limit ? Number(limit) : undefined),
1853
1913
  });
1854
- // Limiting
1855
- if (limit && limit > 0) {
1856
- tasks = tasks.slice(0, limit);
1857
- }
1858
- // Strip verbose detail fields — descriptions, comments, events, and derived
1859
- // activity are omitted from list responses to keep context window usage
1860
- // manageable. Use get_task to retrieve full details for a specific task.
1861
- const slimTasks = tasks.map(({ description, comments, taskEvents, activity, createdByActor, assigneeActor, attachments, checklistItems, ...rest }) => rest);
1862
1914
  logMcpReadObservation('list_tasks', startedAtMs, {
1863
1915
  format,
1864
- totalTasks: data.tasks.length,
1865
1916
  returnedTasks: slimTasks.length,
1866
- filtered: slimTasks.length !== data.tasks.length,
1867
1917
  openOnly,
1868
1918
  hasAssigneeFilter: Boolean(assignee),
1869
1919
  hasStatusFilter: Boolean(status),
@@ -1895,6 +1945,8 @@ export function createTaskforceMcpServer(options = {}) {
1895
1945
  model,
1896
1946
  surfaceType: typeof surfaceType === 'string' || surfaceType === null ? surfaceType : undefined,
1897
1947
  profileToken: typeof profileToken === 'string' ? profileToken : null
1948
+ }, {
1949
+ trustedSeatScope: configuredAiProfileSeatScope,
1898
1950
  });
1899
1951
  activeAiProfileId = resolved.profile.id;
1900
1952
  activeAiBindingSource = 'session';
@@ -1921,6 +1973,7 @@ export function createTaskforceMcpServer(options = {}) {
1921
1973
  provider: resolved.profile.provider ?? null,
1922
1974
  model: resolved.profile.model ?? null,
1923
1975
  surfaceType: resolved.profile.surfaceType ?? null,
1976
+ seatScope: resolved.profile.seatScope ?? null,
1924
1977
  lastActiveAt: resolved.profile.lastActiveAt
1925
1978
  },
1926
1979
  ...(resolved.duplicateWarning && { duplicateWarning: resolved.duplicateWarning })
@@ -1951,6 +2004,7 @@ export function createTaskforceMcpServer(options = {}) {
1951
2004
  profile = core.getAiProfileByToken({
1952
2005
  workspaceId: ACTIVE_WORKSPACE_ID,
1953
2006
  profileToken: profileToken.trim(),
2007
+ seatScope: configuredAiProfileSeatScope,
1954
2008
  });
1955
2009
  if (!profile) {
1956
2010
  throw new Error('Invalid AI profile token. Call resolve_profile again and retry.');
@@ -2430,19 +2484,21 @@ export function createTaskforceMcpServer(options = {}) {
2430
2484
  }
2431
2485
  const linkedTasks = (workspaceAssetStore?.listLinksForAsset(image.assetId, ACTIVE_WORKSPACE_ID) || [])
2432
2486
  .filter((entry) => !entry.deletedAt)
2487
+ .filter((entry) => entry.targetType === 'task' && !!entry.taskId)
2433
2488
  .reduce((entries, link) => {
2434
- if (entries.some((entry) => entry.taskId === link.taskId))
2489
+ const taskId = link.taskId;
2490
+ if (entries.some((entry) => entry.taskId === taskId))
2435
2491
  return entries;
2436
- const task = core.resolveTaskIdentifier(link.taskId, ACTIVE_WORKSPACE_ID);
2492
+ const task = core.resolveTaskIdentifier(taskId, ACTIVE_WORKSPACE_ID);
2437
2493
  const taskReferenceLabel = task?.referenceLabel || (task ? getTaskReferenceLabel(task) : null);
2438
- const sessions = (linkedTaskSessions.get(link.taskId) || []).map((session) => ({
2494
+ const sessions = (linkedTaskSessions.get(taskId) || []).map((session) => ({
2439
2495
  id: session.id,
2440
2496
  title: session.title,
2441
2497
  updatedAt: session.updatedAt,
2442
2498
  annotationCount: Array.isArray(session.annotations) ? session.annotations.length : 0,
2443
2499
  }));
2444
2500
  entries.push({
2445
- taskId: link.taskId,
2501
+ taskId,
2446
2502
  referenceLabel: taskReferenceLabel,
2447
2503
  role: link.role,
2448
2504
  caption: link.displayName || null,
@@ -2492,11 +2548,13 @@ export function createTaskforceMcpServer(options = {}) {
2492
2548
  const asset = resolveDocumentAssetByIdentifierOrThrow(documentId);
2493
2549
  const linkedTasks = (workspaceAssetStore?.listLinksForAsset(asset.assetId, ACTIVE_WORKSPACE_ID) || [])
2494
2550
  .filter((entry) => !entry.deletedAt)
2551
+ .filter((entry) => entry.targetType === 'task' && !!entry.taskId)
2495
2552
  .map((link) => {
2496
- const task = core.resolveTaskIdentifier(link.taskId, ACTIVE_WORKSPACE_ID);
2553
+ const taskId = link.taskId;
2554
+ const task = core.resolveTaskIdentifier(taskId, ACTIVE_WORKSPACE_ID);
2497
2555
  const taskReferenceLabel = task?.referenceLabel || (task ? getTaskReferenceLabel(task) : null);
2498
2556
  return {
2499
- taskId: link.taskId,
2557
+ taskId,
2500
2558
  referenceLabel: taskReferenceLabel,
2501
2559
  role: link.role,
2502
2560
  caption: link.displayName || null,
@@ -3188,16 +3246,19 @@ export function createTaskforceMcpServer(options = {}) {
3188
3246
  }
3189
3247
  case "get_schedule_board": {
3190
3248
  const { week, showWeekends = false } = args;
3191
- if (!week || typeof week !== 'string') {
3192
- throw new Error('week is required');
3193
- }
3194
- const board = core.getScheduleBoard(week, Boolean(showWeekends), ACTIVE_WORKSPACE_ID);
3249
+ const weekKey = typeof week === 'string' && week.trim()
3250
+ ? week.trim()
3251
+ : currentIsoWeekKeyLocal();
3252
+ const board = core.getScheduleBoard(weekKey, Boolean(showWeekends), ACTIVE_WORKSPACE_ID);
3195
3253
  return {
3196
3254
  content: [{ type: "text", text: JSON.stringify(board, null, 2) }],
3197
3255
  };
3198
3256
  }
3199
3257
  case "schedule_task": {
3200
- const { id: inputId, scheduledDate, orderInDay } = args;
3258
+ const { id: legacyInputId, taskId, scheduledDate: legacyScheduledDate, date, orderInDay: legacyOrderInDay, order } = args;
3259
+ const inputId = taskId ?? legacyInputId;
3260
+ const scheduledDate = date ?? legacyScheduledDate;
3261
+ const orderInDay = order ?? legacyOrderInDay;
3201
3262
  const { id } = resolveTaskByIdentifierOrThrow(inputId);
3202
3263
  if (!scheduledDate || typeof scheduledDate !== 'string')
3203
3264
  throw new Error('scheduledDate is required');
@@ -3230,7 +3291,8 @@ export function createTaskforceMcpServer(options = {}) {
3230
3291
  };
3231
3292
  }
3232
3293
  case "unschedule_task": {
3233
- const { id: inputId } = args;
3294
+ const { id: legacyInputId, taskId } = args;
3295
+ const inputId = taskId ?? legacyInputId;
3234
3296
  const { id } = resolveTaskByIdentifierOrThrow(inputId);
3235
3297
  const result = core.updateTaskSchedule(id, { scheduledDate: null, orderInDay: null }, ACTIVE_WORKSPACE_ID);
3236
3298
  if (!result) {
@@ -3261,13 +3323,18 @@ export function createTaskforceMcpServer(options = {}) {
3261
3323
  };
3262
3324
  }
3263
3325
  case "reorder_scheduled_tasks": {
3264
- const { moves } = args;
3265
- if (!Array.isArray(moves)) {
3326
+ const { moves, date, taskIds } = args;
3327
+ const inputMoves = Array.isArray(moves)
3328
+ ? moves
3329
+ : Array.isArray(taskIds) && typeof date === 'string'
3330
+ ? taskIds.map((taskId, index) => ({ id: taskId, scheduledDate: date, orderInDay: index }))
3331
+ : null;
3332
+ if (!Array.isArray(inputMoves)) {
3266
3333
  throw new Error('moves must be an array');
3267
3334
  }
3268
- const resolvedMoves = moves.map((move) => ({
3335
+ const resolvedMoves = inputMoves.map((move) => ({
3269
3336
  ...move,
3270
- id: resolveTaskByIdentifierOrThrow(move?.id).id
3337
+ id: resolveTaskByIdentifierOrThrow(move?.taskId ?? move?.id).id
3271
3338
  }));
3272
3339
  const result = core.reorderScheduledTasks(resolvedMoves, ACTIVE_WORKSPACE_ID);
3273
3340
  recordMcpWriteAudit('reorder_scheduled_tasks', {