@taskforcehq/taskforce 0.3.305 → 0.3.307

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 (440) hide show
  1. package/README.md +0 -2
  2. package/dist/Taskforce.module.css +603 -107
  3. package/dist/TaskforceCore.js +216 -43
  4. package/dist/TaskforceCore.test.js +611 -28
  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 +46 -2
  14. package/dist/compat/workspaceSyncCompat.test.js +38 -1
  15. package/dist/components/activity/EntityActivityTimeline.d.ts +34 -0
  16. package/dist/components/activity/EntityActivityTimeline.js +81 -0
  17. package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
  18. package/dist/components/context/ContextAttachmentManager.js +561 -0
  19. package/dist/components/features/AgentsModule.d.ts +14 -1
  20. package/dist/components/features/AgentsModule.js +366 -18
  21. package/dist/components/features/AgentsModule.test.js +507 -8
  22. package/dist/components/features/AnnotatedAttachmentWorkspace.d.ts +3 -1
  23. package/dist/components/features/AnnotatedAttachmentWorkspace.js +118 -4
  24. package/dist/components/features/AnnotatedAttachmentWorkspace.test.js +52 -0
  25. package/dist/components/features/DocumentIndex.d.ts +2 -2
  26. package/dist/components/features/DocumentIndex.js +3 -4
  27. package/dist/components/features/DocumentViewer.d.ts +7 -1
  28. package/dist/components/features/DocumentViewer.js +62 -4
  29. package/dist/components/features/DocumentWorkspace.d.ts +10 -2
  30. package/dist/components/features/DocumentWorkspace.js +15 -4
  31. package/dist/components/features/DocumentWorkspace.test.js +51 -1
  32. package/dist/components/features/TaskSettings.d.ts +2 -0
  33. package/dist/components/features/TaskSettings.js +83 -78
  34. package/dist/components/features/TaskSettings.test.js +171 -82
  35. package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
  36. package/dist/components/task/TaskActionHeader.js +11 -5
  37. package/dist/components/task/TaskActionHeader.test.js +10 -0
  38. package/dist/components/task/TaskCard.js +24 -29
  39. package/dist/components/task/TaskCard.test.js +38 -3
  40. package/dist/components/task/TaskContextUpload.js +4 -526
  41. package/dist/components/task/TaskContextUpload.test.js +3 -3
  42. package/dist/components/task/TaskForm.js +61 -116
  43. package/dist/components/task/TaskForm.test.js +110 -8
  44. package/dist/components/task/TaskKanban.d.ts +2 -1
  45. package/dist/components/task/TaskKanban.js +94 -21
  46. package/dist/components/task/TaskKanban.test.js +36 -0
  47. package/dist/components/task/TaskList.js +5 -1
  48. package/dist/components/task/TaskList.test.js +4 -0
  49. package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
  50. package/dist/components/ui/EditableAvatarButton.js +18 -0
  51. package/dist/components/ui/HierarchyActionBadge.d.ts +10 -0
  52. package/dist/components/ui/HierarchyActionBadge.js +5 -0
  53. package/dist/components/views/AppShellHeader.d.ts +3 -1
  54. package/dist/components/views/AppShellHeader.js +27 -11
  55. package/dist/components/views/AppShellHeader.test.js +18 -1
  56. package/dist/components/views/PlanComparisonPage.d.ts +9 -1
  57. package/dist/components/views/PlanComparisonPage.js +78 -14
  58. package/dist/components/views/PlanComparisonPage.test.js +257 -0
  59. package/dist/components/views/PlansPage.js +127 -36
  60. package/dist/components/views/PlansPage.test.js +294 -12
  61. package/dist/components/views/StandaloneLayout.js +529 -592
  62. package/dist/components/views/WidgetView.js +10 -8
  63. package/dist/components/views/panels/PlanningDrawer.d.ts +25 -5
  64. package/dist/components/views/panels/PlanningDrawer.js +270 -55
  65. package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
  66. package/dist/components/views/panels/PlanningDrawer.test.js +529 -0
  67. package/dist/components/views/planningScope.d.ts +20 -0
  68. package/dist/components/views/planningScope.js +25 -0
  69. package/dist/components/views/planningScope.test.d.ts +1 -0
  70. package/dist/components/views/planningScope.test.js +60 -0
  71. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
  72. package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
  73. package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
  74. package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
  75. package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
  76. package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
  77. package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
  78. package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
  79. package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
  80. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
  81. package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
  82. package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
  83. package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
  84. package/dist/config/envSchema.js +1 -0
  85. package/dist/core/AiProfileService.d.ts +46 -2
  86. package/dist/core/AiProfileService.js +1073 -82
  87. package/dist/core/AiProfileService.test.js +19 -1
  88. package/dist/core/AiProfiles.test.js +1249 -44
  89. package/dist/core/AttachmentLinkService.d.ts +3 -0
  90. package/dist/core/AttachmentLinkService.js +110 -23
  91. package/dist/core/AuthIdentityService.d.ts +107 -0
  92. package/dist/core/AuthIdentityService.js +284 -0
  93. package/dist/core/AuthTokenService.d.ts +4 -0
  94. package/dist/core/AuthTokenService.js +34 -6
  95. package/dist/core/AuthTokenService.test.js +3 -3
  96. package/dist/core/EntitlementsPolicy.test.js +2 -2
  97. package/dist/core/GlobalSettingsService.js +127 -6
  98. package/dist/core/McpTokenService.d.ts +12 -0
  99. package/dist/core/McpTokenService.js +44 -1
  100. package/dist/core/PlanEntitlementService.d.ts +23 -2
  101. package/dist/core/PlanEntitlementService.js +343 -57
  102. package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
  103. package/dist/core/PlanFeatureCatalog.test.js +84 -0
  104. package/dist/core/PlanVersionPolicy.test.js +35 -2
  105. package/dist/core/PlanningEntities.test.js +418 -4
  106. package/dist/core/SignupMonetizationSettings.test.js +199 -27
  107. package/dist/core/SyncReconciliationService.js +2 -65
  108. package/dist/core/SystemAdmin.test.js +42 -42
  109. package/dist/core/TaskActivityService.d.ts +28 -1
  110. package/dist/core/TaskActivityService.js +227 -46
  111. package/dist/core/TaskActivitySync.test.d.ts +1 -0
  112. package/dist/core/TaskActivitySync.test.js +90 -0
  113. package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
  114. package/dist/core/TaskAuditTimeline.test.js +96 -0
  115. package/dist/core/Taskforce.d.ts +415 -40
  116. package/dist/core/Taskforce.ids.test.js +58 -0
  117. package/dist/core/Taskforce.js +1543 -266
  118. package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
  119. package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
  120. package/dist/core/Taskforce.mcpAuth.test.js +109 -0
  121. package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
  122. package/dist/core/WorkspaceLifecycleService.js +0 -5
  123. package/dist/core/WorkspacePermissions.test.js +25 -1
  124. package/dist/core/WorkspacePlanMode.test.js +117 -16
  125. package/dist/core/shared.d.ts +1 -1
  126. package/dist/core/shared.js +5 -1
  127. package/dist/core/types.d.ts +75 -2
  128. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +28 -2
  129. package/dist/hooks/bootstrapTimeouts.d.ts +4 -0
  130. package/dist/hooks/bootstrapTimeouts.js +8 -0
  131. package/dist/hooks/bootstrapTimeouts.test.d.ts +1 -0
  132. package/dist/hooks/bootstrapTimeouts.test.js +12 -0
  133. package/dist/hooks/sync/bootstrap.js +2 -0
  134. package/dist/hooks/sync/controlPlane.d.ts +37 -0
  135. package/dist/hooks/sync/controlPlane.js +78 -0
  136. package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
  137. package/dist/hooks/sync/controlPlane.test.js +121 -0
  138. package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
  139. package/dist/hooks/sync/lifecyclePolicy.js +93 -0
  140. package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
  141. package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
  142. package/dist/hooks/sync/orchestratorShared.d.ts +13 -4
  143. package/dist/hooks/sync/orchestratorShared.js +129 -48
  144. package/dist/hooks/sync/orchestratorShared.test.js +50 -1
  145. package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
  146. package/dist/hooks/sync/pullLifecycle.js +24 -0
  147. package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
  148. package/dist/hooks/sync/pullLifecycle.test.js +80 -0
  149. package/dist/hooks/sync/recovery.d.ts +16 -2
  150. package/dist/hooks/sync/recovery.js +179 -53
  151. package/dist/hooks/sync/recovery.test.d.ts +1 -0
  152. package/dist/hooks/sync/recovery.test.js +292 -0
  153. package/dist/hooks/sync/transfers.d.ts +16 -3
  154. package/dist/hooks/sync/transfers.js +210 -66
  155. package/dist/hooks/sync/transfers.test.d.ts +1 -0
  156. package/dist/hooks/sync/transfers.test.js +928 -0
  157. package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
  158. package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
  159. package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
  160. package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
  161. package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
  162. package/dist/hooks/sync/useSyncStatusActions.js +88 -0
  163. package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
  164. package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
  165. package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
  166. package/dist/hooks/sync/useSyncStatusControls.js +60 -0
  167. package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
  168. package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
  169. package/dist/hooks/useFilterSort.js +13 -13
  170. package/dist/hooks/useFilterSort.test.js +87 -1
  171. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
  172. package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
  173. package/dist/hooks/useSyncOrchestrator.js +409 -183
  174. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
  175. package/dist/hooks/useTaskData.js +8 -3
  176. package/dist/hooks/useTaskData.test.js +45 -0
  177. package/dist/hooks/useTaskforce.d.ts +145 -52
  178. package/dist/hooks/useTaskforce.js +592 -253
  179. package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
  180. package/dist/hooks/useTaskforce.runtime-routing.test.js +246 -0
  181. package/dist/hooks/useTaskforce.sync-behavior.test.js +2468 -201
  182. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  183. package/dist/hooks/useWorkspaceSyncController.js +13 -2
  184. package/dist/hooks/useWorkspaceSyncController.test.js +48 -0
  185. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
  186. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +328 -40
  187. package/dist/localization/locales/en-US.d.ts +0 -1
  188. package/dist/localization/locales/en-US.js +0 -1
  189. package/dist/localization/locales/es-419.js +0 -1
  190. package/dist/localization/locales/pt-BR.js +0 -1
  191. package/dist/mcp/canonicalAssetHelpers.d.ts +16 -4
  192. package/dist/mcp/canonicalAssetHelpers.js +18 -10
  193. package/dist/mcp/canonicalAssetHelpers.test.d.ts +1 -0
  194. package/dist/mcp/canonicalAssetHelpers.test.js +67 -0
  195. package/dist/mcp/clientIntegrations.d.ts +1 -0
  196. package/dist/mcp/clientIntegrations.js +25 -0
  197. package/dist/mcp/clientIntegrations.test.js +14 -3
  198. package/dist/mcp/clientProfileDefaults.js +3 -3
  199. package/dist/mcp/collaborationRegistrar.js +7 -7
  200. package/dist/mcp/documentAssetRegistrar.js +116 -10
  201. package/dist/mcp/runtime.d.ts +3 -0
  202. package/dist/mcp/runtime.js +1099 -185
  203. package/dist/mcp/runtime.test.js +1491 -140
  204. package/dist/mcp/taskAttachmentTypes.d.ts +1 -1
  205. package/dist/mcp/taskPlanningRegistrar.js +48 -0
  206. package/dist/mcp/toolRegistry.d.ts +56 -0
  207. package/dist/mcp/toolRegistry.js +8 -0
  208. package/dist/mcp/toolRegistry.test.js +4 -0
  209. package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
  210. package/dist/migrations/taskSchemaMigrations.js +192 -61
  211. package/dist/migrations/taskSchemaMigrations.test.js +15 -0
  212. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  213. package/dist/resources/templates/workflows/collaborate.yaml +1 -1
  214. package/dist/resources/templates/workflows/evaluate.yaml +2 -2
  215. package/dist/resources/templates/workflows/plan.yaml +1 -1
  216. package/dist/resources/templates/workflows/review.yaml +2 -2
  217. package/dist/server/aiProfileAvatarAssets.d.ts +49 -0
  218. package/dist/server/aiProfileAvatarAssets.js +319 -0
  219. package/dist/server/aiProfileAvatarAssets.test.d.ts +1 -0
  220. package/dist/server/aiProfileAvatarAssets.test.js +213 -0
  221. package/dist/server/annotatedAttachmentsRoutes.test.js +69 -10
  222. package/dist/server/auth/providers/apple.d.ts +33 -0
  223. package/dist/server/auth/providers/apple.js +82 -0
  224. package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
  225. package/dist/server/auth/providers/appleClientSecret.js +65 -0
  226. package/dist/server/auth/providers/github.d.ts +26 -0
  227. package/dist/server/auth/providers/github.js +86 -0
  228. package/dist/server/auth/providers/google.d.ts +21 -0
  229. package/dist/server/auth/providers/google.js +56 -0
  230. package/dist/server/auth/providers/types.d.ts +21 -0
  231. package/dist/server/auth/providers/types.js +1 -0
  232. package/dist/server/auth.d.ts +2 -0
  233. package/dist/server/auth.js +6 -3
  234. package/dist/server/documentReviewRoutes.test.js +36 -3
  235. package/dist/server/index.cookieProxy.test.js +1 -0
  236. package/dist/server/index.d.ts +12 -0
  237. package/dist/server/index.js +124 -9
  238. package/dist/server/index.rateLimit.test.js +3 -0
  239. package/dist/server/index.test.js +111 -3
  240. package/dist/server/routes/admin.d.ts +3 -0
  241. package/dist/server/routes/admin.js +459 -28
  242. package/dist/server/routes/annotatedAttachments.js +51 -0
  243. package/dist/server/routes/auth.d.ts +26 -2
  244. package/dist/server/routes/auth.js +1170 -71
  245. package/dist/server/routes/authSupport.d.ts +5 -1
  246. package/dist/server/routes/authSupport.js +13 -2
  247. package/dist/server/routes/billing.js +372 -35
  248. package/dist/server/routes/billing.test.js +595 -12
  249. package/dist/server/routes/documents.d.ts +1 -0
  250. package/dist/server/routes/documents.js +182 -70
  251. package/dist/server/routes/shared.d.ts +28 -2
  252. package/dist/server/routes/shared.js +69 -14
  253. package/dist/server/routes/sync.integration.test.js +658 -39
  254. package/dist/server/routes/sync.js +74 -608
  255. package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
  256. package/dist/server/routes/syncAuxRoutes.js +91 -0
  257. package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
  258. package/dist/server/routes/syncAuxRoutes.test.js +158 -0
  259. package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
  260. package/dist/server/routes/syncPullApplyRoutes.js +204 -0
  261. package/dist/server/routes/syncPushRoutes.d.ts +24 -0
  262. package/dist/server/routes/syncPushRoutes.js +212 -0
  263. package/dist/server/routes/syncRouteGuards.d.ts +36 -0
  264. package/dist/server/routes/syncRouteGuards.js +67 -0
  265. package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
  266. package/dist/server/routes/syncRouteGuards.test.js +94 -0
  267. package/dist/server/routes/syncRouteTypes.d.ts +13 -0
  268. package/dist/server/routes/syncRouteTypes.js +1 -0
  269. package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
  270. package/dist/server/routes/syncSnapshotRoutes.js +182 -0
  271. package/dist/server/routes/tasks.js +55 -10
  272. package/dist/server/routes/workspaces.js +36 -5
  273. package/dist/server/routes.js +147 -11
  274. package/dist/server/routes.test.js +2704 -183
  275. package/dist/services/workflowExportSnapshots.test.js +2 -0
  276. package/dist/shared/aiProfileSeatScope.d.ts +5 -0
  277. package/dist/shared/aiProfileSeatScope.js +21 -0
  278. package/dist/shared/aiProfileSurfaceType.d.ts +1 -1
  279. package/dist/shared/aiProfileSurfaceType.js +10 -8
  280. package/dist/shared/passwordPolicy.d.ts +13 -0
  281. package/dist/shared/passwordPolicy.js +84 -0
  282. package/dist/shared/passwordPolicy.test.d.ts +1 -0
  283. package/dist/shared/passwordPolicy.test.js +34 -0
  284. package/dist/storage/objectStorage.d.ts +1 -0
  285. package/dist/storage/objectStorage.js +2 -1
  286. package/dist/storage/objectStorageClient.d.ts +1 -0
  287. package/dist/storage/objectStorageClient.js +41 -8
  288. package/dist/storage/objectStorageClient.test.js +26 -1
  289. package/dist/storage/objectStorageConfig.js +3 -1
  290. package/dist/storage/objectStorageConfig.test.js +13 -1
  291. package/dist/storage/workspaceAssetStore.d.ts +15 -3
  292. package/dist/storage/workspaceAssetStore.js +132 -44
  293. package/dist/storage/workspaceAssetStore.test.js +93 -6
  294. package/dist/styles/fonts.css +70 -0
  295. package/dist/sync/collaborationSyncPayload.d.ts +6 -1
  296. package/dist/sync/collaborationSyncPayload.js +19 -11
  297. package/dist/sync/collaborationSyncPayload.test.js +14 -1
  298. package/dist/sync/collaborationSyncState.d.ts +3 -3
  299. package/dist/sync/collaborationSyncState.js +19 -12
  300. package/dist/sync/contentSyncPayload.d.ts +5 -1
  301. package/dist/sync/contentSyncPayload.js +9 -0
  302. package/dist/sync/contentSyncPayload.test.js +39 -0
  303. package/dist/sync/contentSyncState.d.ts +9 -9
  304. package/dist/sync/contentSyncState.js +248 -107
  305. package/dist/sync/planningSyncPayload.js +5 -0
  306. package/dist/sync/planningSyncPayload.test.js +24 -0
  307. package/dist/sync/syncApplyHandlers.d.ts +11 -4
  308. package/dist/sync/syncApplyHandlers.js +115 -42
  309. package/dist/sync/syncApplyHandlers.test.js +251 -4
  310. package/dist/sync/syncFieldSemantics.d.ts +12 -0
  311. package/dist/sync/syncFieldSemantics.js +55 -0
  312. package/dist/sync/syncResourceAdapters.d.ts +46 -0
  313. package/dist/sync/syncResourceAdapters.js +79 -0
  314. package/dist/sync/syncService.d.ts +6 -0
  315. package/dist/sync/syncService.js +65 -1
  316. package/dist/sync/syncService.test.js +96 -3
  317. package/dist/sync/taskSyncChangeKey.d.ts +2 -0
  318. package/dist/sync/taskSyncChangeKey.js +143 -0
  319. package/dist/sync/taskSyncPayload.js +3 -8
  320. package/dist/sync/workspacePullFeed.d.ts +4 -0
  321. package/dist/sync/workspacePullFeed.js +132 -72
  322. package/dist/sync/workspacePullFeed.test.js +92 -0
  323. package/dist/sync/workspaceRepair.js +5 -2
  324. package/dist/sync/workspaceSyncModel.d.ts +73 -6
  325. package/dist/sync/workspaceSyncModel.js +342 -73
  326. package/dist/sync/workspaceSyncModel.test.js +559 -14
  327. package/dist/sync/workspaceSyncState.d.ts +17 -0
  328. package/dist/sync/workspaceSyncState.js +2 -1
  329. package/dist/sync/workspaceSyncSurface.js +3 -8
  330. package/dist/types.d.ts +50 -2
  331. package/dist/ui/assets/AgentsModule-2y82_3DO.js +1 -0
  332. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BTLZZCiQ.js +3 -0
  333. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BVKew-mH.css +1 -0
  334. package/dist/ui/assets/ContextAttachmentManager-D2epuNnG.js +3 -0
  335. package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
  336. package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
  337. package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
  338. package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
  339. package/dist/ui/assets/DocumentWorkspace-D4rJKXzd.css +1 -0
  340. package/dist/ui/assets/DocumentWorkspace-sVa-3Do6.js +252 -0
  341. package/dist/ui/assets/EntityActivityTimeline-DyqvvhuF.css +1 -0
  342. package/dist/ui/assets/EntityActivityTimeline-Zods27y_.js +1 -0
  343. package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-D4XseTwW.js} +1 -1
  344. package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
  345. package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
  346. package/dist/ui/assets/PlansPage-D5AcbO0L.js +1 -0
  347. package/dist/ui/assets/PlansPage-Dvqsz5zc.css +1 -0
  348. package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
  349. package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
  350. package/dist/ui/assets/TaskContextUpload-uC5qx4Bv.js +1 -0
  351. package/dist/ui/assets/TaskSettings-CqvPAsTv.js +9 -0
  352. package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-oOA9bcdK.js} +4 -4
  353. package/dist/ui/assets/documentReferences-DPZuTgHh.js +1 -0
  354. package/dist/ui/assets/index-607WPo_X.js +4 -0
  355. package/dist/ui/assets/index-CYyodXsg.css +1 -0
  356. package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-B32hGuF2.js} +1 -1
  357. package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
  358. package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
  359. package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
  360. package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
  361. package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
  362. package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
  363. package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
  364. package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
  365. package/dist/ui/fonts/Noir_medium.otf +0 -0
  366. package/dist/ui/fonts/Noir_medium.woff2 +0 -0
  367. package/dist/ui/fonts/Noir_regular.otf +0 -0
  368. package/dist/ui/fonts/Noir_regular.woff2 +0 -0
  369. package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
  370. package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
  371. package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
  372. package/dist/ui/index.html +3 -3
  373. package/dist/ui/product/agent manager.png +0 -0
  374. package/dist/ui/product/agent_manager_02.png +0 -0
  375. package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
  376. package/dist/utils/aiProfileEvents.d.ts +7 -0
  377. package/dist/utils/aiProfileEvents.js +6 -0
  378. package/dist/utils/assignees.d.ts +8 -0
  379. package/dist/utils/assignees.js +10 -1
  380. package/dist/utils/assignees.test.d.ts +1 -0
  381. package/dist/utils/assignees.test.js +25 -0
  382. package/dist/utils/avatarDisplay.d.ts +1 -0
  383. package/dist/utils/avatarDisplay.js +15 -0
  384. package/dist/utils/avatarUpload.d.ts +27 -0
  385. package/dist/utils/avatarUpload.js +132 -0
  386. package/dist/utils/avatarUpload.test.d.ts +1 -0
  387. package/dist/utils/avatarUpload.test.js +40 -0
  388. package/dist/utils/bootstrapTrace.d.ts +7 -0
  389. package/dist/utils/bootstrapTrace.js +29 -0
  390. package/dist/utils/commercialLifecyclePresentation.js +3 -0
  391. package/dist/utils/contextAssetEvents.d.ts +2 -0
  392. package/dist/utils/contextFiles.d.ts +3 -1
  393. package/dist/utils/contextFiles.js +2 -1
  394. package/dist/utils/syncEventDetails.d.ts +3 -0
  395. package/dist/utils/syncEventDetails.js +64 -0
  396. package/dist/utils/syncEventDetails.test.d.ts +1 -0
  397. package/dist/utils/syncEventDetails.test.js +23 -0
  398. package/dist/utils/syncEventPresentation.d.ts +15 -0
  399. package/dist/utils/syncEventPresentation.js +129 -0
  400. package/dist/utils/syncEventPresentation.test.d.ts +1 -0
  401. package/dist/utils/syncEventPresentation.test.js +64 -0
  402. package/dist/utils/syncStatusPresentation.d.ts +72 -0
  403. package/dist/utils/syncStatusPresentation.js +217 -0
  404. package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
  405. package/dist/utils/syncStatusPresentation.test.js +164 -0
  406. package/dist/utils/taskActivity.d.ts +9 -1
  407. package/dist/utils/taskActivity.js +290 -22
  408. package/dist/utils/taskActivity.test.js +141 -8
  409. package/dist/utils/taskSearch.d.ts +22 -0
  410. package/dist/utils/taskSearch.js +87 -0
  411. package/dist/utils/taskSearch.test.d.ts +1 -0
  412. package/dist/utils/taskSearch.test.js +69 -0
  413. package/dist/utils/taskUtils.js +10 -3
  414. package/dist/utils/taskUtils.test.d.ts +1 -0
  415. package/dist/utils/taskUtils.test.js +19 -0
  416. package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
  417. package/dist/utils/workspaceSyncPresentation.js +68 -2
  418. package/dist/utils/workspaceSyncPresentation.test.js +36 -1
  419. package/package.json +3 -2
  420. package/scripts/export-sqlite-to-postgres.mjs +7 -9
  421. package/scripts/run-e2e-realtime.sh +17 -3
  422. package/scripts/run-smoke.sh +17 -5
  423. package/scripts/run-soak.sh +17 -5
  424. package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
  425. package/src/resources/templates/workflows/collaborate.yaml +1 -1
  426. package/src/resources/templates/workflows/evaluate.yaml +2 -2
  427. package/src/resources/templates/workflows/plan.yaml +1 -1
  428. package/src/resources/templates/workflows/review.yaml +2 -2
  429. package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
  430. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BG6P_GVW.js +0 -3
  431. package/dist/ui/assets/AnnotatedAttachmentWorkspace-BaS2VwIr.css +0 -1
  432. package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
  433. package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
  434. package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
  435. package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
  436. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  437. package/dist/ui/assets/TaskSettings-ln0aF7xc.js +0 -9
  438. package/dist/ui/assets/index-C2-OXZV7.css +0 -1
  439. package/dist/ui/assets/index-DcSI5F86.js +0 -6
  440. package/scripts/migrate-planning-model.ts +0 -233
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,91 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { TaskforceCore } from './Taskforce';
6
+ const createdRoots = [];
7
+ const originalHome = process.env.HOME;
8
+ function createProjectRoot(prefix = 'taskforce-list-tasks-slim-') {
9
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), prefix));
10
+ process.env.HOME = root;
11
+ createdRoots.push(root);
12
+ return root;
13
+ }
14
+ afterEach(() => {
15
+ process.env.HOME = originalHome;
16
+ while (createdRoots.length > 0) {
17
+ const root = createdRoots.pop();
18
+ if (root && fs.existsSync(root)) {
19
+ fs.rmSync(root, { recursive: true, force: true });
20
+ }
21
+ }
22
+ });
23
+ describe('TaskforceCore.listTasksSlim', () => {
24
+ it('does not hydrate comments, task events, attachments, or checklist items', () => {
25
+ const projectRoot = createProjectRoot();
26
+ const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
27
+ const task = core.createTask({ title: 'Heavy task' }, { workspaceId: 'default' });
28
+ core.addComment(task.id, 'note from reviewer', 'user', 'default');
29
+ core.replaceChecklistItems(task.id, [{ title: 'step one', isCompleted: false }], 'default');
30
+ const slim = core.listTasksSlim('default');
31
+ const entry = slim.find((t) => t.id === task.id);
32
+ expect(entry).toBeDefined();
33
+ expect(entry).not.toHaveProperty('comments');
34
+ expect(entry).not.toHaveProperty('taskEvents');
35
+ expect(entry).not.toHaveProperty('activity');
36
+ expect(entry).not.toHaveProperty('attachments');
37
+ expect(entry).not.toHaveProperty('checklistItems');
38
+ expect(entry).not.toHaveProperty('description');
39
+ expect(entry).not.toHaveProperty('createdByActor');
40
+ expect(entry).not.toHaveProperty('assigneeActor');
41
+ expect(entry).toMatchObject({
42
+ id: task.id,
43
+ title: 'Heavy task',
44
+ });
45
+ });
46
+ it('pushes assignee, status, openOnly, type, and priority filters into the query', () => {
47
+ const projectRoot = createProjectRoot();
48
+ const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
49
+ const mine = core.createTask({ title: 'Mine open', status: 'in-progress', assignee: 'user-a', priority: 3, type: 'issue' }, { workspaceId: 'default' });
50
+ core.createTask({ title: 'Other assigned', status: 'task', assignee: 'user-b', priority: 3 }, { workspaceId: 'default' });
51
+ const mineDone = core.createTask({ title: 'Mine done', status: 'done', assignee: 'user-a', priority: 1 }, { workspaceId: 'default' });
52
+ core.createTask({ title: 'Mine unassigned' }, { workspaceId: 'default' });
53
+ const byAssignee = core.listTasksSlim('default', { assignee: 'user-a' }).map((t) => t.id);
54
+ expect(byAssignee).toEqual(expect.arrayContaining([mine.id, mineDone.id]));
55
+ expect(byAssignee).toHaveLength(2);
56
+ const openOnly = core.listTasksSlim('default', { assignee: 'user-a', openOnly: true }).map((t) => t.id);
57
+ expect(openOnly).toEqual([mine.id]);
58
+ const byStatus = core.listTasksSlim('default', { status: 'done' }).map((t) => t.id);
59
+ expect(byStatus).toEqual([mineDone.id]);
60
+ const byType = core.listTasksSlim('default', { type: 'issue' }).map((t) => t.id);
61
+ expect(byType).toEqual([mine.id]);
62
+ const byPriority = core.listTasksSlim('default', { priority: 3 }).map((t) => t.id).sort();
63
+ expect(byPriority).toHaveLength(2);
64
+ const byCategory = core.listTasksSlim('default', { category: 'default' }).map((t) => t.id);
65
+ expect(byCategory).toHaveLength(4);
66
+ });
67
+ it('matches unassigned filter against null, empty-string, and "unassigned" values', () => {
68
+ const projectRoot = createProjectRoot();
69
+ const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
70
+ const unassigned = core.createTask({ title: 'no one' }, { workspaceId: 'default' });
71
+ const assigned = core.createTask({ title: 'someone', assignee: 'user-x' }, { workspaceId: 'default' });
72
+ const db = core.getDatabaseAdapter();
73
+ // Inject a row with assignee stored as empty string to exercise the fallback branch.
74
+ db.prepare(`UPDATE tasks SET assignee = '' WHERE id = ?`).run(unassigned.id);
75
+ const results = core.listTasksSlim('default', { assignee: 'unassigned' }).map((t) => t.id);
76
+ expect(results).toContain(unassigned.id);
77
+ expect(results).not.toContain(assigned.id);
78
+ });
79
+ it('applies sort, order, and limit in SQL', () => {
80
+ const projectRoot = createProjectRoot();
81
+ const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
82
+ const low = core.createTask({ title: 'low', priority: 1 }, { workspaceId: 'default' });
83
+ const mid = core.createTask({ title: 'mid', priority: 2 }, { workspaceId: 'default' });
84
+ const high = core.createTask({ title: 'high', priority: 4 }, { workspaceId: 'default' });
85
+ const byPriorityDesc = core.listTasksSlim('default', { sort: 'priority', order: 'desc' }).map((t) => t.id);
86
+ expect(byPriorityDesc.slice(0, 3)).toEqual([high.id, mid.id, low.id]);
87
+ const limited = core.listTasksSlim('default', { sort: 'priority', order: 'desc', limit: 1 });
88
+ expect(limited).toHaveLength(1);
89
+ expect(limited[0]?.id).toBe(high.id);
90
+ });
91
+ });
@@ -289,6 +289,82 @@ describe('TaskforceCore MCP auth invalidation', () => {
289
289
  cleanup();
290
290
  }
291
291
  });
292
+ it('does not delete active MCP access tokens', () => {
293
+ const { core, cleanup } = makeCore();
294
+ try {
295
+ setupWorkspace(core, 'owner-1', 'workspace-1');
296
+ const issued = core.createMcpAccessToken({
297
+ userId: 'owner-1',
298
+ workspaceId: 'workspace-1',
299
+ name: 'Active Token',
300
+ scopes: ['tasks:read']
301
+ });
302
+ expect(() => core.deleteMcpAccessToken({
303
+ actorUserId: 'owner-1',
304
+ workspaceId: 'workspace-1',
305
+ tokenId: issued.record.id
306
+ })).toThrow('Active MCP tokens must be revoked before deletion');
307
+ expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items).toHaveLength(1);
308
+ }
309
+ finally {
310
+ cleanup();
311
+ }
312
+ });
313
+ it('deletes revoked MCP access token records', () => {
314
+ const { core, cleanup } = makeCore();
315
+ try {
316
+ setupWorkspace(core, 'owner-1', 'workspace-1');
317
+ const issued = core.createMcpAccessToken({
318
+ userId: 'owner-1',
319
+ workspaceId: 'workspace-1',
320
+ name: 'Revoked Token',
321
+ scopes: ['tasks:read']
322
+ });
323
+ core.revokeMcpAccessToken({
324
+ actorUserId: 'owner-1',
325
+ workspaceId: 'workspace-1',
326
+ tokenId: issued.record.id
327
+ });
328
+ expect(core.deleteMcpAccessToken({
329
+ actorUserId: 'owner-1',
330
+ workspaceId: 'workspace-1',
331
+ tokenId: issued.record.id
332
+ })).toBe(true);
333
+ expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items).toHaveLength(0);
334
+ expect(core.authenticateMcpAccessToken(issued.token)).toBeNull();
335
+ }
336
+ finally {
337
+ cleanup();
338
+ }
339
+ });
340
+ it('deletes expired MCP access token records', () => {
341
+ const { core, cleanup } = makeCore();
342
+ try {
343
+ setupWorkspace(core, 'owner-1', 'workspace-1');
344
+ const issued = core.createMcpAccessToken({
345
+ userId: 'owner-1',
346
+ workspaceId: 'workspace-1',
347
+ name: 'Expired Token',
348
+ scopes: ['tasks:read'],
349
+ expiresAt: new Date(Date.now() + 60_000).toISOString()
350
+ });
351
+ core.db.prepare(`
352
+ UPDATE mcp_access_tokens
353
+ SET expires_at = ?
354
+ WHERE tenant_id = ? AND id = ?
355
+ `).run(new Date(Date.now() - 60_000).toISOString(), 'default', issued.record.id);
356
+ expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items[0]?.status).toBe('expired');
357
+ expect(core.deleteMcpAccessToken({
358
+ actorUserId: 'owner-1',
359
+ workspaceId: 'workspace-1',
360
+ tokenId: issued.record.id
361
+ })).toBe(true);
362
+ expect(core.listMcpAccessTokens({ userId: 'owner-1', workspaceId: 'workspace-1' }).items).toHaveLength(0);
363
+ }
364
+ finally {
365
+ cleanup();
366
+ }
367
+ });
292
368
  it('denies OAuth authentication after the authorized member is disabled', () => {
293
369
  const { core, cleanup } = makeCore();
294
370
  try {
@@ -308,6 +384,39 @@ describe('TaskforceCore MCP auth invalidation', () => {
308
384
  cleanup();
309
385
  }
310
386
  });
387
+ it('returns persisted AI profile binding on OAuth connector authentication', () => {
388
+ const { core, cleanup } = makeCore();
389
+ try {
390
+ setupWorkspace(core, 'owner-1', 'workspace-1');
391
+ const accessToken = createOauthGrantToken(core, 'owner-1', 'workspace-1');
392
+ const auth = core.authenticateMcpOAuthAccessToken(accessToken);
393
+ expect(auth?.aiProfileToken).toBeFalsy();
394
+ const resolved = core.resolveAiProfile({
395
+ workspaceId: 'workspace-1',
396
+ name: 'Codex Connector',
397
+ icon: 'Code',
398
+ color: '#0ea5e9',
399
+ }, {
400
+ trustedSeatScope: 'cloud_metered',
401
+ });
402
+ expect(core.bindMcpOAuthConnectorGrantAiProfile({
403
+ grantId: auth.grantId,
404
+ workspaceId: 'workspace-1',
405
+ profileId: resolved.profile.id,
406
+ profileToken: resolved.profile.profileToken,
407
+ profileName: resolved.profile.name,
408
+ })).toBe(true);
409
+ expect(core.authenticateMcpOAuthAccessToken(accessToken)).toEqual(expect.objectContaining({
410
+ grantId: auth.grantId,
411
+ aiProfileId: resolved.profile.id,
412
+ aiProfileToken: resolved.profile.profileToken,
413
+ aiProfileName: 'Codex Connector',
414
+ }));
415
+ }
416
+ finally {
417
+ cleanup();
418
+ }
419
+ });
311
420
  it('denies OAuth authentication after account access is suspended', () => {
312
421
  const { core, cleanup } = makeCore();
313
422
  try {
@@ -24,7 +24,7 @@ function seedPlans(core) {
24
24
  billing: {
25
25
  onboardingPolicy: {
26
26
  mode: 'auto_grant_free',
27
- planVersionId: 'starter-v1'
27
+ planId: 'starter'
28
28
  }
29
29
  }
30
30
  });
@@ -44,7 +44,7 @@ describe('TaskforceCore user profile avatar drafts', () => {
44
44
  try {
45
45
  const created = core.registerPasswordUser({
46
46
  email: 'avatar-user@example.com',
47
- password: 'password123'
47
+ password: 'ValidPassphrase123!'
48
48
  });
49
49
  const updated = core.updateUserProfile(created.userId, {
50
50
  displayName: 'Avatar User',
@@ -62,13 +62,40 @@ describe('TaskforceCore user profile avatar drafts', () => {
62
62
  fs.rmSync(projectRoot, { recursive: true, force: true });
63
63
  }
64
64
  });
65
+ it('exposes cloud-owned user avatarUrl on live workspace member records', () => {
66
+ const projectRoot = makeProjectRoot();
67
+ const core = openCore(projectRoot);
68
+ try {
69
+ core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
70
+ const created = core.registerPasswordUser({
71
+ email: 'member-avatar@example.com',
72
+ password: 'ValidPassphrase123!',
73
+ workspaceId: 'workspace-1'
74
+ });
75
+ const avatarUrl = `/api/taskforce/context/${encodeURIComponent(`users/${created.userId}/profile/avatar/headshot.webp`)}`;
76
+ core.updateUserProfile(created.userId, {
77
+ displayName: 'Member Avatar',
78
+ avatarUrl
79
+ });
80
+ const members = core.listWorkspaceUsers('workspace-1');
81
+ expect(members.find((member) => member.userId === created.userId)).toEqual(expect.objectContaining({
82
+ userId: created.userId,
83
+ displayName: 'Member Avatar',
84
+ avatarUrl
85
+ }));
86
+ }
87
+ finally {
88
+ core.close();
89
+ fs.rmSync(projectRoot, { recursive: true, force: true });
90
+ }
91
+ });
65
92
  it('tracks, finalizes, discards, and cleans up stale avatar upload drafts', () => {
66
93
  const projectRoot = makeProjectRoot();
67
94
  const core = openCore(projectRoot);
68
95
  try {
69
96
  const created = core.registerPasswordUser({
70
97
  email: 'draft-user@example.com',
71
- password: 'password123'
98
+ password: 'ValidPassphrase123!'
72
99
  });
73
100
  const draft = core.createUserAvatarUploadDraft({
74
101
  userId: created.userId,
@@ -55,11 +55,6 @@ export function deleteWorkspaceService(deps, input) {
55
55
  const result = deps.db.prepare(sql).run(...params);
56
56
  counts[tableName] = Number(result?.changes || 0);
57
57
  };
58
- deps.db.prepare(`
59
- UPDATE tasks
60
- SET parent_task_id = NULL
61
- WHERE tenant_id = ? AND workspace_id = ? AND parent_task_id IS NOT NULL
62
- `).run(deps.tenantId, normalizedWorkspaceId);
63
58
  runDelete('comments', 'DELETE FROM comments WHERE tenant_id = ? AND workspace_id = ?', deps.tenantId, normalizedWorkspaceId);
64
59
  runDelete('task_events', 'DELETE FROM task_events WHERE tenant_id = ? AND workspace_id = ?', deps.tenantId, normalizedWorkspaceId);
65
60
  runDelete('deleted_tasks', 'DELETE FROM deleted_tasks WHERE tenant_id = ? AND workspace_id = ?', deps.tenantId, normalizedWorkspaceId);
@@ -124,10 +124,11 @@ describe('TaskforceCore workspace permission invariants', () => {
124
124
  cleanup();
125
125
  }
126
126
  });
127
- it('marks deactivated users as disabled in access resolution immediately', () => {
127
+ it('marks deactivated workspace memberships as disabled without disabling the global account', () => {
128
128
  const { core, cleanup } = makeCore();
129
129
  try {
130
130
  core.createWorkspace({ workspaceId: 'workspace-1', name: 'Workspace 1' });
131
+ core.createWorkspace({ workspaceId: 'workspace-home', name: 'Workspace Home' });
131
132
  core.ensureBootstrapUserAccess({
132
133
  userId: 'owner-1',
133
134
  workspaceId: 'workspace-1',
@@ -140,9 +141,32 @@ describe('TaskforceCore workspace permission invariants', () => {
140
141
  role: 'member',
141
142
  email: 'member@example.com'
142
143
  });
144
+ core.ensureBootstrapUserAccess({
145
+ userId: 'member-1',
146
+ workspaceId: 'workspace-home',
147
+ role: 'owner',
148
+ email: 'member@example.com'
149
+ });
143
150
  expect(core.setWorkspaceUserDisabled('member-1', 'workspace-1', true)).toBe(true);
144
151
  const access = core.resolveUserAccess('member-1', 'workspace-1', 'member');
145
152
  expect(access?.disabled).toBe(true);
153
+ expect(access?.accountDisabled).toBe(false);
154
+ expect(access?.workspaceDisabled).toBe(true);
155
+ expect(core.resolveUserAccess('member-1', 'workspace-home', 'owner')).toEqual(expect.objectContaining({
156
+ role: 'owner',
157
+ disabled: false,
158
+ accountDisabled: false,
159
+ workspaceDisabled: false
160
+ }));
161
+ expect(core.listUserWorkspaces('member-1').map((workspace) => workspace.id)).toEqual(['workspace-home']);
162
+ expect(core.listWorkspaceUsers('workspace-1').find((user) => user.userId === 'member-1')).toEqual(expect.objectContaining({
163
+ status: 'disabled',
164
+ disabled: true
165
+ }));
166
+ const row = core.db.prepare(`
167
+ SELECT is_disabled FROM users WHERE tenant_id = ? AND id = ? LIMIT 1
168
+ `).get('default', 'member-1');
169
+ expect(Boolean(row?.is_disabled)).toBe(false);
146
170
  }
147
171
  finally {
148
172
  cleanup();
@@ -31,7 +31,7 @@ function openCore(projectRoot) {
31
31
  core.updatePlanVersionFeatures({
32
32
  planVersionId: 'free-v1',
33
33
  features: [
34
- { featureKey: 'workspace.switching', access: 'enabled' }
34
+ { featureKey: 'workspace.workspaces', access: 'enabled' }
35
35
  ]
36
36
  });
37
37
  core.upsertPlanCatalog({ planId: 'team-5', displayName: 'Team 5' });
@@ -71,17 +71,17 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
71
71
  VALUES (?, ?, ?, ?, ?, ?)
72
72
  `).run('workspace-u1-second', 'default', 'workspace-u1-second', 'Second U1 Workspace', now, now);
73
73
  db.prepare(`
74
- INSERT INTO users (id, tenant_id, email, display_name, auth_provider, external_auth_id, is_disabled, created_at, updated_at)
75
- VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?)
76
- `).run('u1', 'default', 'u1@example.com', 'U1', 'token', 'u1', now, now);
74
+ INSERT INTO users (id, tenant_id, email, display_name, is_disabled, created_at, updated_at)
75
+ VALUES (?, ?, ?, ?, 0, ?, ?)
76
+ `).run('u1', 'default', 'u1@example.com', 'U1', now, now);
77
77
  db.prepare(`
78
- INSERT INTO users (id, tenant_id, email, display_name, auth_provider, external_auth_id, is_disabled, created_at, updated_at)
79
- VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?)
80
- `).run('u2', 'default', 'u2@example.com', 'U2', 'token', 'u2', now, now);
78
+ INSERT INTO users (id, tenant_id, email, display_name, is_disabled, created_at, updated_at)
79
+ VALUES (?, ?, ?, ?, 0, ?, ?)
80
+ `).run('u2', 'default', 'u2@example.com', 'U2', now, now);
81
81
  db.prepare(`
82
- INSERT INTO users (id, tenant_id, email, display_name, auth_provider, external_auth_id, is_disabled, created_at, updated_at)
83
- VALUES (?, ?, ?, ?, ?, ?, 0, ?, ?)
84
- `).run('u3', 'default', 'u3@example.com', 'U3', 'token', 'u3', now, now);
82
+ INSERT INTO users (id, tenant_id, email, display_name, is_disabled, created_at, updated_at)
83
+ VALUES (?, ?, ?, ?, 0, ?, ?)
84
+ `).run('u3', 'default', 'u3@example.com', 'U3', now, now);
85
85
  db.prepare(`
86
86
  INSERT INTO workspace_memberships (id, tenant_id, workspace_id, user_id, role, status, created_at, updated_at)
87
87
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
@@ -153,7 +153,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
153
153
  });
154
154
  core.ensurePasswordUser({
155
155
  email: 'existing@example.com',
156
- password: 'Password123!',
156
+ password: 'HarborLanternOrbit!2026',
157
157
  workspaceId: 'workspace-invite',
158
158
  role: 'member'
159
159
  });
@@ -190,7 +190,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
190
190
  core.setUserAccountPlanMode('owner-user', 'team');
191
191
  const existing = core.ensurePasswordUser({
192
192
  email: 'existing@example.com',
193
- password: 'Password123!',
193
+ password: 'HarborLanternOrbit!2026',
194
194
  workspaceId: 'workspace-invite',
195
195
  role: 'member'
196
196
  });
@@ -202,7 +202,8 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
202
202
  WHERE tenant_id = ? AND user_id = ? AND workspace_id = ?
203
203
  `).run('default', existing.userId, 'workspace-invite');
204
204
  const before = db.prepare(`
205
- SELECT password_hash FROM users WHERE tenant_id = ? AND id = ? LIMIT 1
205
+ SELECT password_hash FROM user_auth_identities
206
+ WHERE tenant_id = ? AND user_id = ? AND provider = 'password' LIMIT 1
206
207
  `).get('default', existing.userId);
207
208
  const invite = core.requestInviteAcceptance({ userId: existing.userId, workspaceId: 'workspace-invite' });
208
209
  const accepted = core.joinInviteWithAuthenticatedUser({
@@ -210,7 +211,8 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
210
211
  userId: existing.userId
211
212
  });
212
213
  const after = db.prepare(`
213
- SELECT password_hash FROM users WHERE tenant_id = ? AND id = ? LIMIT 1
214
+ SELECT password_hash FROM user_auth_identities
215
+ WHERE tenant_id = ? AND user_id = ? AND provider = 'password' LIMIT 1
214
216
  `).get('default', existing.userId);
215
217
  const membership = db.prepare(`
216
218
  SELECT status FROM workspace_memberships WHERE tenant_id = ? AND user_id = ? AND workspace_id = ? LIMIT 1
@@ -233,7 +235,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
233
235
  billing: {
234
236
  onboardingPolicy: {
235
237
  mode: 'auto_grant_free',
236
- planVersionId: 'free-v1'
238
+ planId: 'free'
237
239
  }
238
240
  }
239
241
  });
@@ -261,7 +263,7 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
261
263
  const invite = core.requestInviteAcceptance({ userId: 'invited-user', workspaceId: 'workspace-invite' });
262
264
  const accepted = core.acceptInviteWithToken({
263
265
  token: String(invite.token),
264
- password: 'Password123!'
266
+ password: 'LanternHarborOrbit!2026'
265
267
  });
266
268
  expect(accepted.workspaceId).toBe('workspace-invite');
267
269
  expect(core.hasAccountEntitlement('invited-user')).toBe(true);
@@ -279,4 +281,103 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
279
281
  fs.rmSync(projectRoot, { recursive: true, force: true });
280
282
  }
281
283
  });
284
+ it('grants the free personal entitlement to newly accepted invited accounts even without explicit self-serve onboarding policy', () => {
285
+ const projectRoot = makeProjectRoot();
286
+ const core = openCore(projectRoot);
287
+ try {
288
+ core.createWorkspace({ workspaceId: 'workspace-invite', name: 'Invite Workspace' });
289
+ core.ensureBootstrapUserAccess({
290
+ userId: 'owner-user',
291
+ workspaceId: 'workspace-invite',
292
+ role: 'owner',
293
+ email: 'owner@example.com'
294
+ });
295
+ core.setUserAccountPlanMode('owner-user', 'team');
296
+ core.ensureBootstrapUserAccess({
297
+ userId: 'invited-user',
298
+ workspaceId: 'workspace-invite',
299
+ role: 'member',
300
+ email: 'invited-no-policy@example.com'
301
+ });
302
+ core.setWorkspaceUserDisabled('invited-user', 'workspace-invite', true);
303
+ const db = core.db;
304
+ db.prepare(`
305
+ UPDATE workspace_memberships
306
+ SET status = 'invited'
307
+ WHERE tenant_id = ? AND user_id = ? AND workspace_id = ?
308
+ `).run('default', 'invited-user', 'workspace-invite');
309
+ const invite = core.requestInviteAcceptance({ userId: 'invited-user', workspaceId: 'workspace-invite' });
310
+ const accepted = core.acceptInviteWithToken({
311
+ token: String(invite.token),
312
+ password: 'LanternHarborOrbit!2026'
313
+ });
314
+ expect(accepted.workspaceId).toBe('workspace-invite');
315
+ expect(core.hasAccountEntitlement('invited-user')).toBe(true);
316
+ expect(core.getAccountEntitlement('invited-user')).toEqual(expect.objectContaining({
317
+ planVersionId: 'free-v1',
318
+ state: 'active'
319
+ }));
320
+ expect(core.getAccountAccessStatus('invited-user')).toEqual(expect.objectContaining({
321
+ gate: 'ok',
322
+ canAccessApp: true
323
+ }));
324
+ }
325
+ finally {
326
+ core.close();
327
+ fs.rmSync(projectRoot, { recursive: true, force: true });
328
+ }
329
+ });
330
+ it('reactivates blocked placeholder entitlements when a new invited user accepts a reused seat', () => {
331
+ const projectRoot = makeProjectRoot();
332
+ const core = openCore(projectRoot);
333
+ try {
334
+ core.createWorkspace({ workspaceId: 'workspace-invite', name: 'Invite Workspace' });
335
+ core.ensureBootstrapUserAccess({
336
+ userId: 'owner-user',
337
+ workspaceId: 'workspace-invite',
338
+ role: 'owner',
339
+ email: 'owner@example.com'
340
+ });
341
+ core.setUserAccountPlanMode('owner-user', 'team');
342
+ core.ensureBootstrapUserAccess({
343
+ userId: 'invited-user',
344
+ workspaceId: 'workspace-invite',
345
+ role: 'member',
346
+ email: 'invited@example.com'
347
+ });
348
+ core.setWorkspaceUserDisabled('invited-user', 'workspace-invite', true);
349
+ const db = core.db;
350
+ db.prepare(`
351
+ UPDATE workspace_memberships
352
+ SET status = 'invited'
353
+ WHERE tenant_id = ? AND user_id = ? AND workspace_id = ?
354
+ `).run('default', 'invited-user', 'workspace-invite');
355
+ core.updateAccountEntitlement({
356
+ accountId: 'invited-user',
357
+ planVersionId: 'free-v1',
358
+ entitlementState: 'canceled',
359
+ actorUserId: 'system-admin',
360
+ actorRole: 'system_admin',
361
+ reason: 'invite-reaccept-regression'
362
+ });
363
+ const invite = core.requestInviteAcceptance({ userId: 'invited-user', workspaceId: 'workspace-invite' });
364
+ const accepted = core.acceptInviteWithToken({
365
+ token: String(invite.token),
366
+ password: 'LanternHarborOrbit!2026'
367
+ });
368
+ expect(accepted.workspaceId).toBe('workspace-invite');
369
+ expect(core.getAccountEntitlement('invited-user')).toEqual(expect.objectContaining({
370
+ planVersionId: 'free-v1',
371
+ state: 'active'
372
+ }));
373
+ expect(core.getAccountAccessStatus('invited-user')).toEqual(expect.objectContaining({
374
+ gate: 'ok',
375
+ canAccessApp: true
376
+ }));
377
+ }
378
+ finally {
379
+ core.close();
380
+ fs.rmSync(projectRoot, { recursive: true, force: true });
381
+ }
382
+ });
282
383
  });
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import type { McpAccessTokenScope, PlanFeatureCatalogItem } from './types.js';
18
18
  export declare const DOCUMENT_CLOUD_STORAGE_FEATURE_KEY = "context.uploads";
19
- export declare const WORKSPACES_FEATURE_KEY = "workspace.switching";
19
+ export declare const WORKSPACES_FEATURE_KEY = "workspace.workspaces";
20
20
  export declare const AI_PROFILES_FEATURE_KEY = "collaboration.ai_profiles";
21
21
  export declare const DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY = "storageLimitMb";
22
22
  export declare const WORKSPACES_LIMIT_CONFIG_KEY = "maxWorkspaces";
@@ -17,7 +17,7 @@
17
17
  import { createHash, pbkdf2Sync, randomBytes, timingSafeEqual } from 'crypto';
18
18
  // === SECTION: Constants ===
19
19
  export const DOCUMENT_CLOUD_STORAGE_FEATURE_KEY = 'context.uploads';
20
- export const WORKSPACES_FEATURE_KEY = 'workspace.switching';
20
+ export const WORKSPACES_FEATURE_KEY = 'workspace.workspaces';
21
21
  export const AI_PROFILES_FEATURE_KEY = 'collaboration.ai_profiles';
22
22
  export const DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY = 'storageLimitMb';
23
23
  export const WORKSPACES_LIMIT_CONFIG_KEY = 'maxWorkspaces';
@@ -32,6 +32,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
32
32
  featureKey: 'collaboration.team_management',
33
33
  label: 'Team Management',
34
34
  description: 'Allow managing members, invites, roles, and collaboration settings.',
35
+ publicDisplayOrder: 40,
35
36
  allowedAccessModes: ['enabled', 'disabled'],
36
37
  configTemplate: {}
37
38
  },
@@ -39,6 +40,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
39
40
  featureKey: DOCUMENT_CLOUD_STORAGE_FEATURE_KEY,
40
41
  label: 'Document Cloud Storage',
41
42
  description: 'Allow cloud document storage with an optional storage allowance in MB.',
43
+ publicDisplayOrder: 30,
42
44
  allowedAccessModes: ['enabled', 'disabled'],
43
45
  configTemplate: {
44
46
  [DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY]: 1024
@@ -48,6 +50,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
48
50
  featureKey: WORKSPACES_FEATURE_KEY,
49
51
  label: 'Workspaces',
50
52
  description: 'Allow multiple workspaces with a configurable workspace limit.',
53
+ publicDisplayOrder: 10,
51
54
  allowedAccessModes: ['enabled', 'disabled'],
52
55
  configTemplate: {
53
56
  [WORKSPACES_LIMIT_CONFIG_KEY]: 1
@@ -57,6 +60,7 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
57
60
  featureKey: AI_PROFILES_FEATURE_KEY,
58
61
  label: 'AI Profiles',
59
62
  description: 'Allow registered AI collaborator profiles with an optional per-workspace limit.',
63
+ publicDisplayOrder: 20,
60
64
  allowedAccessModes: ['enabled', 'limited', 'disabled'],
61
65
  configTemplate: {
62
66
  [AI_PROFILES_LIMIT_CONFIG_KEY]: 1