@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
@@ -1,5 +1,6 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { buildWorkspaceSyncPayloadModel, buildWorkspaceSyncSignatureModel } from './workspaceSyncModel';
3
+ import { aiProfileSyncResourceAdapter, taskSyncResourceAdapter } from './syncResourceAdapters';
3
4
  describe('workspaceSyncModel', () => {
4
5
  describe('buildWorkspaceSyncPayloadModel', () => {
5
6
  it('emits document-delete when a previously pushed document path is now missing', () => {
@@ -20,6 +21,28 @@ describe('workspaceSyncModel', () => {
20
21
  expect.objectContaining({ op: 'document-delete', path: 'docs/remove.md' })
21
22
  ]));
22
23
  });
24
+ it('does not emit document-delete when a canonical path is still known but missing from the readable snapshot', () => {
25
+ const payload = buildWorkspaceSyncPayloadModel({
26
+ tasks: [],
27
+ archivedTasks: [],
28
+ lastPushedTaskIds: new Set(),
29
+ pendingDeletedTaskIds: new Set(),
30
+ documents: [
31
+ { path: 'docs/keep.md', updatedAt: '2026-02-01T00:00:00.000Z', content: 'keep' }
32
+ ],
33
+ currentDocumentPaths: new Set(['docs/keep.md', 'docs/missing-content.md']),
34
+ lastPushedDocumentPaths: new Set(['docs/keep.md', 'docs/missing-content.md', 'docs/remove.md'])
35
+ });
36
+ expect(Array.from(payload.currentDocumentPaths).sort()).toEqual(['docs/keep.md', 'docs/missing-content.md']);
37
+ expect(Array.from(payload.deleteDocumentPaths).sort()).toEqual(['docs/remove.md']);
38
+ expect(payload.changes).toEqual(expect.arrayContaining([
39
+ expect.objectContaining({ op: 'document-upsert', path: 'docs/keep.md' }),
40
+ expect.objectContaining({ op: 'document-delete', path: 'docs/remove.md' })
41
+ ]));
42
+ expect(payload.changes).not.toEqual(expect.arrayContaining([
43
+ expect.objectContaining({ op: 'document-delete', path: 'docs/missing-content.md' })
44
+ ]));
45
+ });
23
46
  it('emits task-event-upsert changes for new activity events and tracks event watermarks', () => {
24
47
  const payload = buildWorkspaceSyncPayloadModel({
25
48
  tasks: [],
@@ -124,6 +147,32 @@ describe('workspaceSyncModel', () => {
124
147
  ['docs/new.md', '2026-02-03T00:00:00.000Z']
125
148
  ]);
126
149
  });
150
+ it('reports send-all diagnostics when a domain has no baseline', () => {
151
+ const payload = buildWorkspaceSyncPayloadModel({
152
+ tasks: [],
153
+ archivedTasks: [],
154
+ lastPushedTaskIds: new Set(),
155
+ pendingDeletedTaskIds: new Set(),
156
+ documents: [
157
+ { path: 'docs/a.md', updatedAt: '2026-02-01T00:00:00.000Z', content: 'a' },
158
+ { path: 'docs/b.md', updatedAt: '2026-02-02T00:00:00.000Z', content: 'b' }
159
+ ],
160
+ baselineResetReason: 'repair-reset'
161
+ });
162
+ expect(payload.deltaDiagnostics).toEqual(expect.objectContaining({
163
+ totalChanges: 2,
164
+ domains: expect.objectContaining({
165
+ documents: expect.objectContaining({
166
+ mode: 'send-all',
167
+ reason: 'repair-reset',
168
+ currentCount: 2,
169
+ baselineCount: 0,
170
+ changeCount: 2
171
+ })
172
+ })
173
+ }));
174
+ expect(payload.deltaDiagnostics?.byOp['document-upsert']).toBe(2);
175
+ });
127
176
  it('preserves canonical document metadata on document-upsert changes', () => {
128
177
  const payload = buildWorkspaceSyncPayloadModel({
129
178
  tasks: [],
@@ -196,6 +245,47 @@ describe('workspaceSyncModel', () => {
196
245
  })
197
246
  ]));
198
247
  });
248
+ it('does not emit asset-delete when a canonical asset path is still known but missing from the readable snapshot', () => {
249
+ const payload = buildWorkspaceSyncPayloadModel({
250
+ tasks: [],
251
+ archivedTasks: [],
252
+ lastPushedTaskIds: new Set(),
253
+ pendingDeletedTaskIds: new Set(),
254
+ assets: [
255
+ {
256
+ path: 'workspaces/default/assets/images/asset-image-1-diagram.png',
257
+ updatedAt: '2026-03-17T12:00:00.000Z',
258
+ contentBase64: 'aW1hZ2UtYnl0ZXM=',
259
+ assetId: 'asset-image-1',
260
+ kind: 'image',
261
+ mimeType: 'image/png',
262
+ taskId: 'task-1',
263
+ originalFilename: 'diagram.png',
264
+ linkRole: 'image'
265
+ }
266
+ ],
267
+ currentAssetPaths: new Set([
268
+ 'workspaces/default/assets/images/asset-image-1-diagram.png',
269
+ 'workspaces/default/assets/files/asset-file-missing.pdf'
270
+ ]),
271
+ lastPushedAssetPaths: new Set([
272
+ 'workspaces/default/assets/images/asset-image-1-diagram.png',
273
+ 'workspaces/default/assets/files/asset-file-missing.pdf',
274
+ 'workspaces/default/assets/files/asset-file-old-document.pdf'
275
+ ])
276
+ });
277
+ expect(Array.from(payload.currentAssetPaths).sort()).toEqual([
278
+ 'workspaces/default/assets/files/asset-file-missing.pdf',
279
+ 'workspaces/default/assets/images/asset-image-1-diagram.png'
280
+ ]);
281
+ expect(Array.from(payload.deleteAssetPaths)).toEqual(['workspaces/default/assets/files/asset-file-old-document.pdf']);
282
+ expect(payload.changes).not.toEqual(expect.arrayContaining([
283
+ expect.objectContaining({
284
+ op: 'asset-delete',
285
+ path: 'workspaces/default/assets/files/asset-file-missing.pdf'
286
+ })
287
+ ]));
288
+ });
199
289
  it('emits timestamped task deletes for previously pushed tasks that are now missing', () => {
200
290
  const payload = buildWorkspaceSyncPayloadModel({
201
291
  tasks: [],
@@ -277,6 +367,7 @@ describe('workspaceSyncModel', () => {
277
367
  provider: 'OpenAI',
278
368
  model: 'gpt-5.4',
279
369
  surfaceType: 'coding_tool',
370
+ rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
280
371
  createdAt: '2026-03-22T10:00:00.000Z',
281
372
  updatedAt: '2026-03-22T10:05:00.000Z',
282
373
  lastActiveAt: '2026-03-22T10:05:00.000Z'
@@ -293,14 +384,49 @@ describe('workspaceSyncModel', () => {
293
384
  role: 'Implementer',
294
385
  provider: 'OpenAI',
295
386
  model: 'gpt-5.4',
296
- surfaceType: 'coding_tool'
387
+ surfaceType: 'coding_tool',
388
+ rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z'
297
389
  })
298
390
  })
299
391
  ]));
300
392
  expect(Array.from(payload.currentAiProfileIds)).toEqual(['ai-profile-1']);
301
393
  expect(payload.currentAiProfileWatermarks.get('ai-profile-1')).toBe('2026-03-22T10:05:00.000Z');
302
394
  });
303
- it('filters unchanged ai profiles when ai watermark state already matches', () => {
395
+ it('filters unchanged ai profiles when ai change-key state already matches', () => {
396
+ const profile = {
397
+ id: 'ai-profile-1',
398
+ workspaceId: 'ws-1',
399
+ profileToken: 'tfp_test',
400
+ name: 'Codex',
401
+ username: 'codex',
402
+ icon: 'Bot',
403
+ color: '#0ea5e9',
404
+ description: 'Terminal-first coding agent',
405
+ role: 'Implementer',
406
+ provider: 'OpenAI',
407
+ model: 'gpt-5.4',
408
+ surfaceType: 'coding_tool',
409
+ rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
410
+ createdAt: '2026-03-22T10:00:00.000Z',
411
+ updatedAt: '2026-03-22T10:05:00.000Z',
412
+ lastActiveAt: '2026-03-22T10:05:00.000Z'
413
+ };
414
+ const payload = buildWorkspaceSyncPayloadModel({
415
+ tasks: [],
416
+ archivedTasks: [],
417
+ lastPushedTaskIds: new Set(),
418
+ pendingDeletedTaskIds: new Set(),
419
+ aiProfiles: [profile],
420
+ lastPushedAiProfileIds: new Set(['ai-profile-1']),
421
+ lastPushedAiProfileWatermarks: new Map([['ai-profile-1', '2026-03-22T10:05:00.000Z']]),
422
+ lastPushedAiProfileChangeKeys: new Map([
423
+ ['ai-profile-1', aiProfileSyncResourceAdapter.getChangeKey(profile)]
424
+ ])
425
+ });
426
+ expect(payload.changes.some((change) => change.op === 'ai-profile-upsert')).toBe(false);
427
+ expect(Array.from(payload.currentAiProfileIds)).toEqual(['ai-profile-1']);
428
+ });
429
+ it('resends ai profiles when a legacy watermark did not include avatar fields', () => {
304
430
  const payload = buildWorkspaceSyncPayloadModel({
305
431
  tasks: [],
306
432
  archivedTasks: [],
@@ -315,11 +441,14 @@ describe('workspaceSyncModel', () => {
315
441
  username: 'codex',
316
442
  icon: 'Bot',
317
443
  color: '#0ea5e9',
444
+ avatarUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Favatar.webp',
445
+ avatarSourceUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Fsource.webp',
318
446
  description: 'Terminal-first coding agent',
319
447
  role: 'Implementer',
320
448
  provider: 'OpenAI',
321
449
  model: 'gpt-5.4',
322
450
  surfaceType: 'coding_tool',
451
+ rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
323
452
  createdAt: '2026-03-22T10:00:00.000Z',
324
453
  updatedAt: '2026-03-22T10:05:00.000Z',
325
454
  lastActiveAt: '2026-03-22T10:05:00.000Z'
@@ -328,8 +457,82 @@ describe('workspaceSyncModel', () => {
328
457
  lastPushedAiProfileIds: new Set(['ai-profile-1']),
329
458
  lastPushedAiProfileWatermarks: new Map([['ai-profile-1', '2026-03-22T10:05:00.000Z']])
330
459
  });
331
- expect(payload.changes.some((change) => change.op === 'ai-profile-upsert')).toBe(false);
332
- expect(Array.from(payload.currentAiProfileIds)).toEqual(['ai-profile-1']);
460
+ expect(payload.changes).toEqual(expect.arrayContaining([
461
+ expect.objectContaining({
462
+ op: 'ai-profile-upsert',
463
+ profile: expect.objectContaining({
464
+ id: 'ai-profile-1',
465
+ avatarUrl: expect.stringContaining('/api/taskforce/context/'),
466
+ avatarSourceUrl: expect.stringContaining('/api/taskforce/context/')
467
+ })
468
+ })
469
+ ]));
470
+ expect(payload.currentAiProfileWatermarks.get('ai-profile-1')).toBe('2026-03-22T10:05:00.000Z');
471
+ expect(payload.currentAiProfileChangeKeys?.get('ai-profile-1')).toBe(aiProfileSyncResourceAdapter.getChangeKey({
472
+ id: 'ai-profile-1',
473
+ workspaceId: 'ws-1',
474
+ profileToken: 'tfp_test',
475
+ name: 'Codex',
476
+ username: 'codex',
477
+ icon: 'Bot',
478
+ color: '#0ea5e9',
479
+ avatarUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Favatar.webp',
480
+ avatarSourceUrl: '/api/taskforce/context/workspaces%2Fws-1%2Fassets%2Fimages%2Fai-profiles%2Fai-profile-1%2Favatar%2Fsource.webp',
481
+ description: 'Terminal-first coding agent',
482
+ role: 'Implementer',
483
+ provider: 'OpenAI',
484
+ model: 'gpt-5.4',
485
+ surfaceType: 'coding_tool',
486
+ rosterStateUpdatedAt: '2026-03-22T10:00:00.000Z',
487
+ createdAt: '2026-03-22T10:00:00.000Z',
488
+ updatedAt: '2026-03-22T10:05:00.000Z',
489
+ lastActiveAt: '2026-03-22T10:05:00.000Z'
490
+ }));
491
+ });
492
+ it('resends ai profiles when lifecycle state advances beyond metadata updatedAt', () => {
493
+ const payload = buildWorkspaceSyncPayloadModel({
494
+ tasks: [],
495
+ archivedTasks: [],
496
+ lastPushedTaskIds: new Set(),
497
+ pendingDeletedTaskIds: new Set(),
498
+ aiProfiles: [
499
+ {
500
+ id: 'ai-profile-1',
501
+ workspaceId: 'ws-1',
502
+ profileToken: 'tfp_test',
503
+ name: 'Codex',
504
+ username: 'codex',
505
+ icon: 'Bot',
506
+ color: '#0ea5e9',
507
+ description: 'Terminal-first coding agent',
508
+ role: 'Implementer',
509
+ provider: 'OpenAI',
510
+ model: 'gpt-5.4',
511
+ surfaceType: 'coding_tool',
512
+ archivedAt: '2026-03-22T10:10:00.000Z',
513
+ archivedBy: 'owner-1',
514
+ archivedReason: 'manual_archive',
515
+ rosterStateUpdatedAt: '2026-03-22T10:10:00.000Z',
516
+ createdAt: '2026-03-22T10:00:00.000Z',
517
+ updatedAt: '2026-03-22T10:05:00.000Z',
518
+ lastActiveAt: '2026-03-22T10:05:00.000Z'
519
+ }
520
+ ],
521
+ lastPushedAiProfileIds: new Set(['ai-profile-1']),
522
+ lastPushedAiProfileWatermarks: new Map([['ai-profile-1', '2026-03-22T10:05:00.000Z']])
523
+ });
524
+ expect(payload.changes).toEqual(expect.arrayContaining([
525
+ expect.objectContaining({
526
+ op: 'ai-profile-upsert',
527
+ profile: expect.objectContaining({
528
+ id: 'ai-profile-1',
529
+ archivedAt: '2026-03-22T10:10:00.000Z',
530
+ rosterStateUpdatedAt: '2026-03-22T10:10:00.000Z',
531
+ updatedAt: '2026-03-22T10:05:00.000Z'
532
+ })
533
+ })
534
+ ]));
535
+ expect(payload.currentAiProfileWatermarks.get('ai-profile-1')).toBe('2026-03-22T10:10:00.000Z');
333
536
  });
334
537
  it('emits initiative and workstream upserts and tracks their watermarks', () => {
335
538
  const payload = buildWorkspaceSyncPayloadModel({
@@ -836,15 +1039,16 @@ describe('workspaceSyncModel', () => {
836
1039
  });
837
1040
  });
838
1041
  describe('dirty task watermarks', () => {
839
- it('emits an upsert when a status-only server-confirmed update changes updatedAt', () => {
1042
+ it('resends once when a legacy watermark-only task baseline exists', () => {
1043
+ const task = {
1044
+ id: 'task-1',
1045
+ title: 'Task 1',
1046
+ status: 'in-progress',
1047
+ createdAt: '2026-03-16T10:00:00.000Z',
1048
+ updatedAt: '2026-03-16T10:05:00.000Z'
1049
+ };
840
1050
  const payload = buildWorkspaceSyncPayloadModel({
841
- tasks: [{
842
- id: 'task-1',
843
- title: 'Task 1',
844
- status: 'in-progress',
845
- createdAt: '2026-03-16T10:00:00.000Z',
846
- updatedAt: '2026-03-16T10:05:00.000Z'
847
- }],
1051
+ tasks: [task],
848
1052
  archivedTasks: [],
849
1053
  lastPushedTaskIds: new Set(['task-1']),
850
1054
  pendingDeletedTaskIds: new Set(),
@@ -863,6 +1067,81 @@ describe('workspaceSyncModel', () => {
863
1067
  })
864
1068
  ]));
865
1069
  expect(payload.pushedWatermarks.get('task-1')).toBe('2026-03-16T10:05:00.000Z');
1070
+ expect(payload.pushedTaskChangeKeys.get('task-1')).toBe(taskSyncResourceAdapter.getChangeKey({ ...task, isArchived: false }));
1071
+ });
1072
+ it('does not resend a task when only updatedAt changes but the replicated change key matches', () => {
1073
+ const task = {
1074
+ id: 'task-1',
1075
+ title: 'Task 1',
1076
+ status: 'in-progress',
1077
+ createdAt: '2026-03-16T10:00:00.000Z',
1078
+ updatedAt: '2026-03-16T10:05:00.000Z'
1079
+ };
1080
+ const payload = buildWorkspaceSyncPayloadModel({
1081
+ tasks: [task],
1082
+ archivedTasks: [],
1083
+ lastPushedTaskIds: new Set(['task-1']),
1084
+ pendingDeletedTaskIds: new Set(),
1085
+ lastPushedWatermarks: new Map([
1086
+ ['task-1', '2026-03-16T10:00:00.000Z']
1087
+ ]),
1088
+ lastPushedTaskChangeKeys: new Map([
1089
+ ['task-1', taskSyncResourceAdapter.getChangeKey({ ...task, isArchived: false })]
1090
+ ])
1091
+ });
1092
+ expect(payload.changes.some((change) => change.op === 'upsert' && change.task.id === 'task-1')).toBe(false);
1093
+ expect(payload.currentTaskWatermarks.get('task-1')).toBe('2026-03-16T10:05:00.000Z');
1094
+ });
1095
+ it('treats comment and attachment changes as replicated task-state changes', () => {
1096
+ const task = {
1097
+ id: 'task-1',
1098
+ title: 'Task 1',
1099
+ status: 'task',
1100
+ createdAt: '2026-03-16T10:00:00.000Z',
1101
+ updatedAt: '2026-03-16T10:05:00.000Z',
1102
+ comments: [{
1103
+ id: 'comment-1',
1104
+ author: 'ai-profile-1',
1105
+ text: 'Shipped',
1106
+ timestamp: '2026-03-16T10:05:00.000Z'
1107
+ }],
1108
+ attachments: [{
1109
+ path: 'workspaces/ws-1/assets/files/asset-1.txt',
1110
+ caption: 'Spec',
1111
+ timestamp: '2026-03-16T10:05:00.000Z'
1112
+ }]
1113
+ };
1114
+ const previousTask = {
1115
+ ...task,
1116
+ comments: [],
1117
+ attachments: []
1118
+ };
1119
+ const payload = buildWorkspaceSyncPayloadModel({
1120
+ tasks: [task],
1121
+ archivedTasks: [],
1122
+ lastPushedTaskIds: new Set(['task-1']),
1123
+ pendingDeletedTaskIds: new Set(),
1124
+ lastPushedWatermarks: new Map([
1125
+ ['task-1', '2026-03-16T10:05:00.000Z']
1126
+ ]),
1127
+ lastPushedTaskChangeKeys: new Map([
1128
+ ['task-1', taskSyncResourceAdapter.getChangeKey({ ...previousTask, isArchived: false })]
1129
+ ])
1130
+ });
1131
+ expect(payload.changes).toEqual(expect.arrayContaining([
1132
+ expect.objectContaining({
1133
+ op: 'upsert',
1134
+ task: expect.objectContaining({
1135
+ id: 'task-1',
1136
+ comments: expect.arrayContaining([
1137
+ expect.objectContaining({ id: 'comment-1' })
1138
+ ]),
1139
+ attachments: expect.arrayContaining([
1140
+ expect.objectContaining({ path: 'workspaces/ws-1/assets/files/asset-1.txt' })
1141
+ ])
1142
+ })
1143
+ })
1144
+ ]));
866
1145
  });
867
1146
  it('keeps provisional local-reference tasks dirty until a canonical reference is assigned', () => {
868
1147
  const payload = buildWorkspaceSyncPayloadModel({
@@ -1,5 +1,21 @@
1
1
  export type WorkspaceSyncPhase = 'idle' | 'provision-local' | 'attach-cloud' | 'active' | 'error';
2
2
  export type WorkspaceSyncSetupIntent = 'attach-cloud-import' | null;
3
+ export interface WorkspaceSyncPushBaselineSnapshot {
4
+ taskIds?: string[];
5
+ taskWatermarks: Array<[string, string]>;
6
+ taskChangeKeys?: Array<[string, string]>;
7
+ initiativeWatermarks: Array<[string, string]>;
8
+ workstreamWatermarks: Array<[string, string]>;
9
+ aiProfileWatermarks: Array<[string, string]>;
10
+ aiProfileChangeKeys?: Array<[string, string]>;
11
+ documentWatermarks: Array<[string, string]>;
12
+ assetWatermarks: Array<[string, string]>;
13
+ documentReviewSessionWatermarks: Array<[string, string]>;
14
+ documentReviewCommentWatermarks: Array<[string, string]>;
15
+ annotatedAttachmentSessionWatermarks: Array<[string, string]>;
16
+ taskEventWatermarks: Array<[string, string]>;
17
+ taxonomyStateFingerprint: string;
18
+ }
3
19
  export interface WorkspaceSyncStateV2 {
4
20
  version: 2;
5
21
  enabled: boolean;
@@ -10,5 +26,6 @@ export interface WorkspaceSyncStateV2 {
10
26
  lastPushAt: string | null;
11
27
  lastSyncedAt: string | null;
12
28
  lastErrorMessage: string | null;
29
+ pushBaseline?: WorkspaceSyncPushBaselineSnapshot | null;
13
30
  }
14
31
  export declare function createDefaultWorkspaceSyncState(): WorkspaceSyncStateV2;
@@ -8,6 +8,7 @@ export function createDefaultWorkspaceSyncState() {
8
8
  lastPullAt: null,
9
9
  lastPushAt: null,
10
10
  lastSyncedAt: null,
11
- lastErrorMessage: null
11
+ lastErrorMessage: null,
12
+ pushBaseline: null
12
13
  };
13
14
  }
@@ -1,3 +1,4 @@
1
+ import { taskSyncResourceAdapter } from './syncResourceAdapters.js';
1
2
  export function compareWorkspaceMutationOrdering(incomingWatermark, existingWatermark, incomingTieBreak, existingTieBreak) {
2
3
  const incomingMs = Date.parse(String(incomingWatermark || '').trim());
3
4
  const existingMs = Date.parse(String(existingWatermark || '').trim());
@@ -18,16 +19,10 @@ export function compareWorkspaceMutationOrdering(incomingWatermark, existingWate
18
19
  return String(incomingTieBreak || '').localeCompare(String(existingTieBreak || ''));
19
20
  }
20
21
  export function getTaskMutationWatermark(task) {
21
- return String(task?.updatedAt || task?.createdAt || '').trim();
22
+ return taskSyncResourceAdapter.getWatermark(task || {});
22
23
  }
23
24
  export function getTaskMutationTieBreak(task, archived) {
24
- const source = task || {};
25
- return JSON.stringify({
26
- id: String(source.id || ''),
27
- title: String(source.title || ''),
28
- status: String(source.status || ''),
29
- archived: archived ? 1 : 0
30
- });
25
+ return taskSyncResourceAdapter.getChangeKey({ ...(task || {}), isArchived: archived });
31
26
  }
32
27
  export function getDocumentMutationWatermark(document) {
33
28
  return String(document?.updatedAt || '').trim();
package/dist/types.d.ts CHANGED
@@ -143,6 +143,23 @@ export interface WorkstreamItem {
143
143
  order?: number | null;
144
144
  isArchived?: boolean;
145
145
  }
146
+ export interface PlanningBootstrapTaskPreview {
147
+ id: string;
148
+ referenceNumber?: number | null;
149
+ title: string;
150
+ status?: string | null;
151
+ }
152
+ export interface PlanningBootstrapWorkstreamTaskSummary {
153
+ workstreamId: string;
154
+ taskCount: number;
155
+ completedTaskCount: number;
156
+ tasks: PlanningBootstrapTaskPreview[];
157
+ }
158
+ export interface PlanningBootstrapPayload {
159
+ initiatives: InitiativeItem[];
160
+ workstreams: WorkstreamItem[];
161
+ workstreamTaskSummaries: PlanningBootstrapWorkstreamTaskSummary[];
162
+ }
146
163
  export interface ChecklistItem {
147
164
  id: string;
148
165
  taskId: string;
@@ -0,0 +1 @@
1
+ import{r as c,j as e}from"./vendor-react-CKJs5o3c.js";import{u as se,p as oe,v as ne,w as ce,x as _,y as de,z as pe,t as r,E as fe,B as me,C as K}from"./index-C6k75jr8.js";import{h as ue,B as V,k as U,b as he,$ as ve,a3 as ge}from"./vendor-icons-DuEd_65c.js";import"./vendor-markdown-BUxTU7dS.js";import"./vendor-dnd-DRzYolkg.js";import"./vendor-router-BbWMxlnO.js";function J(d){return!d||typeof d!="object"?null:{used:Math.max(0,Number(d.used||0)),limit:d.limit===null||d.limit===void 0?null:Math.max(0,Number(d.limit||0)),remaining:d.remaining===null||d.remaining===void 0?null:Math.max(0,Number(d.remaining||0))}}function W(d,P){const x=P?.variant==="inline"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconInline}`:P?.variant==="detail"?`${r.aiProfileSeatScopeIcon} ${r.aiProfileSeatScopeIconDetail}`:r.aiProfileSeatScopeIcon;return d==="cloud_metered"?e.jsx("span",{className:`${x} ${r.aiProfileSeatScopeIconCloud}`,title:"Cloud MCP","aria-label":"Cloud MCP",children:e.jsx(ve,{size:20})}):d==="local_unmetered"?e.jsx("span",{className:`${x} ${r.aiProfileSeatScopeIconLocal}`,title:"Local MCP","aria-label":"Local MCP",children:e.jsx(ge,{size:20})}):null}function Ie({workspaceId:d,cloudAuthConfigured:P=!1,authSessionResolved:x=!1,isAuthenticated:Y=!1,cloudAiProfileSeatUsage:q=null}){const[S,L]=c.useState([]),[Q,X]=c.useState(null),[M,$]=c.useState(!1),[f,j]=c.useState(null),[I,v]=c.useState(null),[N,A]=c.useState(null),[g,b]=c.useState(null),[E,T]=c.useState(null),[B,D]=c.useState(!1),[Z,m]=c.useState(null),w=c.useCallback(async()=>{if(d){$(!0);try{const a=`/api/taskforce/workspace/assignee-options?workspaceId=${encodeURIComponent(d)}`,i=await fetch(a,{credentials:"include"}),t=i.ok?await i.json().catch(()=>({})):{},s=J(t?.aiProfileSeatUsage),n=Array.isArray(t?.assignees)?t.assignees.filter(l=>l.kind==="agent").map(l=>({id:String(l.value||""),name:String(l.label||l.value||"Unknown Agent"),username:String(l.username||l.value||""),icon:String(l.icon||"Bot"),color:String(l.color||"#6B7280"),avatarUrl:typeof l.avatarUrl=="string"?l.avatarUrl:null,avatarSourceUrl:typeof l.avatarSourceUrl=="string"?l.avatarSourceUrl:null,kind:String(l.kind||"agent"),description:typeof l.description=="string"?l.description:null,role:typeof l.role=="string"?l.role:null,provider:typeof l.provider=="string"?l.provider:null,model:typeof l.model=="string"?l.model:null,surfaceType:oe(l.surfaceType),seatScope:se(l.seatScope),archivedAt:typeof l.archivedAt=="string"?l.archivedAt:null,createdAt:String(l.createdAt||""),updatedAt:String(l.updatedAt||l.createdAt||""),lastActiveAt:typeof l.lastActiveAt=="string"?l.lastActiveAt:null})):[];L(n),X(s),A(l=>l&&!n.some(h=>h.id===l.profileId)?null:l)}finally{$(!1)}}},[d]);c.useEffect(()=>{w()},[w]);const k=c.useMemo(()=>{const a=new Map;for(const i of S){const t=ne(i.surfaceType);a.has(t)||a.set(t,new Map);const s=a.get(t),n=i.name.toLowerCase();s.has(n)||s.set(n,[]),s.get(n).push(i)}return ce.map(i=>({section:i,label:_(i),groups:Array.from(a.get(i)?.entries()||[]).map(([t,s])=>({groupId:`${i}:${t}`,section:i,sectionLabel:_(i),profiles:s,primaryProfile:s[0]}))})).filter(i=>i.groups.length>0)},[S]),u=c.useMemo(()=>k.flatMap(a=>a.groups),[k]),o=c.useMemo(()=>u.find(a=>a.groupId===g)||u[0]||null,[u,g]),p=c.useMemo(()=>S.find(a=>a.id===E)||null,[S,E]);c.useEffect(()=>{if(!u.length){g!==null&&b(null);return}(!g||!u.some(a=>a.groupId===g))&&b(u[0].groupId)},[u,g]);const ee=async(a,i)=>{v(null),A(null);try{const t=await fetch("/api/taskforce/workspace/ai-profiles/merge",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({keepId:a,mergeId:i})}),s=await t.json().catch(()=>({}));if(!t.ok){v({type:"error",message:String(s?.error||"Failed to merge AI profiles.")});return}j(null),v({type:"success",message:"AI profiles merged."}),await w()}catch{v({type:"error",message:"Failed to merge AI profiles."})}},G=async a=>{if(window.confirm(`Remove ${a.name} from the active roster? This frees an AI profile seat and preserves task and comment history.`)){A(null),v(null);try{const t=await fetch("/api/taskforce/workspace/ai-profiles/archive",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a.id,reason:"manual_archive"})}),s=await t.json().catch(()=>({}));if(!t.ok){A({profileId:a.id,message:String(s?.error||"Failed to remove AI profile from roster.")});return}(f?.keepId===a.id||f?.mergeId===a.id)&&j(null),v({type:"success",message:"AI profile removed from active roster."}),await w()}catch{A({profileId:a.id,message:"Failed to remove AI profile from roster."})}}},ae=a=>new Promise((i,t)=>{const s=new FileReader;s.onload=()=>i(String(s.result||"")),s.onerror=()=>t(new Error("Failed to read image file.")),s.readAsDataURL(a)}),re=a=>{const i=String(a?.id||"").trim();i&&L(t=>t.map(s=>s.id===i?{...s,avatarUrl:typeof a.avatarUrl=="string"?a.avatarUrl:null,avatarSourceUrl:typeof a.avatarSourceUrl=="string"?a.avatarSourceUrl:null,updatedAt:typeof a.updatedAt=="string"?a.updatedAt:s.updatedAt}:s))},F=async(a,i,t)=>{const s=await fetch("/api/taskforce/workspace/ai-profiles/avatar",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({profileId:a,avatarUrl:i,...t!==void 0?{avatarSourceUrl:t}:{}})}),n=await s.json().catch(()=>({}));if(!s.ok||!n?.profile)throw new Error(String(n?.error||"Failed to update AI profile avatar."));re(n.profile)},z=async(a,i,t)=>{const s=await ae(a),n=await fetch("/api/taskforce/context-upload",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({workspaceId:d,file:s,originalName:`${t}-${a.name}`,folderPath:`ai-profiles/${i.id}/avatar`})}),l=await n.json().catch(()=>({})),h=typeof l?.path=="string"?l.path:"";if(!n.ok||!h)throw new Error(String(l?.error||"Failed to upload AI profile photo."));return h},ie=async(a,i)=>{if(!p)return!1;if(!a.type.startsWith("image/"))return m("AI profile photo must be an image file."),!1;D(!0),m(null);try{const t=await K(a,{maxBytes:5242880});if(t.exceededLimit)throw new Error(a.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile photo must be 5 MB or smaller.");const s=t.file,n=await z(s,p,"cropped");let l;if(i){const h=await K(i,{maxBytes:5242880});if(h.exceededLimit)throw new Error(i.type==="image/gif"?"Animated GIF AI profile photos must be 5 MB or smaller.":"AI profile source photo must be 5 MB or smaller.");l=i.type==="image/gif"?n:await z(h.file,p,"source")}return await F(p.id,n,l),!0}catch(t){return m(String(t?.message||"Failed to update AI profile photo.")),!1}finally{D(!1)}},te=async()=>{if(p){D(!0),m(null);try{await F(p.id,null,null)}catch(a){m(String(a?.message||"Failed to remove AI profile photo."))}finally{D(!1)}}},y=a=>{const i=String(a||"").trim();if(!i)return"Unknown";const t=Date.parse(i);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:"medium",timeStyle:"short"}):i},H=c.useMemo(()=>{if(!o)return{attributes:[],dates:[]};const a=o.primaryProfile,i=t=>t||"Not set";return{attributes:[{label:"Category",value:a.surfaceType?de(a.surfaceType):""},{label:"Connection",value:a.seatScope?pe(a.seatScope):""},{label:"Provider",value:a.provider||""},{label:"Model",value:a.model||""}].map(t=>({...t,value:i(t.value)})),dates:[{label:"Recruited",value:y(a.createdAt)},{label:"Last updated",value:y(a.updatedAt)},{label:"Last active",value:y(a.lastActiveAt)},{label:"Status",value:a.archivedAt?"Retired":"Active"}].map(t=>({...t,value:i(t.value)}))}},[o]),le=!!o&&o.profiles.length>1,O=P&&x&&!Y,C=P?J(q):Q,R=O?"Log into account for Cloud agents":C?`${C.used}/${C.limit===null?"Unlimited":C.limit}`:null;return e.jsxs("section",{className:r.agentsModuleRoot,children:[e.jsx("div",{className:r.agentsModuleContent,children:e.jsx("div",{className:`${r.settingGroup} ${r.agentsModuleGroup}`,children:e.jsxs("div",{children:[e.jsx("h4",{className:r.settingSubTitle,children:"Registered AI Profiles"}),e.jsx("p",{className:`${r.settingsHint} ${r.marginBottom12}`,children:"AI agents register profiles when connecting via MCP. Merge duplicates created when a token was lost, or remove inactive profiles from the active roster to free seats while preserving history."}),R&&e.jsx("div",{className:r.aiProfileSeatSummary,children:O?R:`Registered Cloud Agents: ${R}`}),M&&e.jsxs("div",{className:r.settingsHint,children:[e.jsx(ue,{size:13,className:r.spinner})," Loading profiles…"]}),!M&&S.length===0&&e.jsx("div",{className:r.settingsHint,children:"No AI profiles registered yet."}),!M&&k.length>0&&e.jsxs("div",{className:r.aiProfilesExplorer,children:[e.jsx("div",{className:`${r.aiProfilesListPane} tf-scrollbar tf-scrollbar--track-transparent`,children:e.jsx("div",{className:r.aiProfilesList,children:k.map(a=>e.jsxs("div",{className:r.aiProfilesSection,children:[e.jsx("div",{className:r.aiProfilesSectionHeader,children:a.label}),a.groups.map(i=>{const t=o?.groupId===i.groupId,s=i.primaryProfile;return e.jsxs("div",{role:"button",tabIndex:0,className:`${r.aiProfileGroup} ${i.profiles.length>1?r.aiProfileGroupDuplicate:""} ${t?r.aiProfileGroupSelected:""}`,onClick:()=>b(i.groupId),onKeyDown:n=>{n.key!=="Enter"&&n.key!==" "||(n.preventDefault(),b(i.groupId))},"aria-pressed":t,children:[W(s.seatScope),e.jsxs("div",{className:r.aiProfileGroupHeader,children:[e.jsx("span",{className:r.aiProfileGroupAvatar,style:{color:s.color},children:s.avatarUrl?e.jsx("img",{src:s.avatarUrl,alt:""}):e.jsx(V,{size:22})}),e.jsxs("span",{className:r.aiProfileGroupIdentity,children:[e.jsx("span",{className:r.aiProfileName,children:s.name}),e.jsxs("span",{className:r.aiProfileHandle,children:["@",s.username]}),e.jsx("span",{className:r.aiProfileRole,children:s.role||"Role not set"}),i.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDuplicateBadge,children:[e.jsx(U,{size:11})," ",i.profiles.length," duplicates"]})]})]})]},i.groupId)})]},a.section))})}),o&&e.jsx("div",{className:r.aiProfileDetailPane,children:e.jsxs("div",{className:r.aiProfileDetailCard,children:[W(o.primaryProfile.seatScope,{variant:"detail"}),e.jsxs("div",{className:r.aiProfileDetailHero,children:[e.jsx(fe,{label:"Edit AI profile photo",imageUrl:o.primaryProfile.avatarUrl,fallback:e.jsx(V,{size:38}),accentColor:o.primaryProfile.color,size:176,width:153,height:207,radius:6,editBadgeSize:28,editIconSize:14,className:r.aiProfileDetailAvatar,onClick:()=>{m(null),T(o.primaryProfile.id)}}),e.jsxs("div",{className:r.aiProfileDetailHeading,children:[e.jsx("div",{className:r.aiProfileDetailTitleRow,children:e.jsx("h5",{className:r.aiProfileDetailTitle,children:o.primaryProfile.name})}),e.jsxs("div",{className:r.aiProfileDetailMetaRow,children:[e.jsxs("span",{className:r.aiProfileDetailHandle,children:["@",o.primaryProfile.username]}),o.profiles.length>1&&e.jsxs("span",{className:r.aiProfileDetailLinkedCount,children:[o.profiles.length," linked"]})]}),e.jsxs("div",{className:r.aiProfileDetailRole,children:["Role: ",o.primaryProfile.role||"Not set"]}),o.primaryProfile.description&&e.jsx("div",{className:r.aiProfileDetailDescription,children:o.primaryProfile.description})]})]}),e.jsxs("div",{className:r.aiProfileDetailDataList,children:[e.jsx("div",{className:r.aiProfileDetailDataGroup,children:H.attributes.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))}),e.jsx("div",{className:`${r.aiProfileDetailDataGroup} ${r.aiProfileDetailDateGroup}`,children:H.dates.map(a=>e.jsxs("div",{className:r.aiProfileDetailDataRow,children:[e.jsx("span",{className:r.aiProfileDetailDataLabel,children:a.label}),a.label==="Status"?e.jsx("span",{className:r.aiProfileDetailDataValue,children:e.jsxs("select",{className:r.aiProfileStatusSelect,"aria-label":"Agent roster status",value:o.primaryProfile.archivedAt?"retired":"active",onChange:i=>{i.target.value==="retire"&&G(o.primaryProfile)},children:[e.jsx("option",{value:"active",children:"Active"}),o.primaryProfile.archivedAt?e.jsx("option",{value:"retired",children:"Retired"}):e.jsx("option",{value:"retire",children:"Retire from roster"})]})}):e.jsx("span",{className:r.aiProfileDetailDataValue,children:a.value})]},a.label))})]}),le?e.jsxs("div",{className:r.aiProfileInstanceSection,children:[e.jsxs("div",{className:r.aiProfileInstanceSectionHeader,children:[e.jsx("span",{children:"Profile instances"}),e.jsx("span",{className:r.settingsHint,children:"Choose a keeper here if duplicates need to be merged."})]}),e.jsx("div",{className:r.aiProfileInstanceList,children:o.profiles.map(a=>e.jsxs("div",{className:r.aiProfileInstanceCard,children:[e.jsxs("div",{className:r.aiProfileInstanceTopRow,children:[e.jsxs("div",{children:[e.jsxs("div",{className:r.aiProfileInstanceName,children:["@",a.username]}),e.jsx("div",{className:r.aiProfileIdChip,children:a.id})]}),f?.keepId===a.id&&e.jsx("span",{className:r.aiProfileKeepBadge,children:"Keeping"})]}),e.jsxs("div",{className:r.aiProfileInstanceMeta,children:[e.jsxs("span",{children:["Created ",y(a.createdAt)]}),e.jsxs("span",{children:["Updated ",y(a.updatedAt)]})]}),f?.keepId!==a.id&&e.jsx("button",{className:r.secondaryHeaderBtn,title:"Keep this profile, merge others into it",onClick:()=>{const i=o.profiles.find(t=>t.id!==a.id)?.id;i&&j({keepId:a.id,mergeId:i})},children:"Keep this"}),N?.profileId===a.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(U,{size:12}),e.jsx("span",{children:N.message})]}),e.jsx("button",{className:r.aiProfileDangerTextButton,title:"Remove this profile from the active roster",onClick:()=>{G(a)},children:"Remove from roster"})]},a.id))}),f&&o.profiles.some(a=>a.id===f.keepId)&&e.jsxs("div",{className:r.aiProfileMergeActions,children:[e.jsx("button",{className:r.dangerBtn,onClick:()=>{ee(f.keepId,f.mergeId)},children:"Merge duplicates"}),e.jsx("button",{className:r.secondaryHeaderBtn,onClick:()=>j(null),children:"Cancel"})]})]}):e.jsxs("div",{className:r.aiProfileIdFooter,children:[e.jsx("div",{className:r.aiProfileIdFooterValue,children:o.primaryProfile.id}),N?.profileId===o.primaryProfile.id&&e.jsxs("div",{className:r.aiProfileInlineError,role:"alert",children:[e.jsx(U,{size:12}),e.jsx("span",{children:N.message})]})]})]})})]}),I&&e.jsxs("div",{className:`${I.type==="success"?r.successMessage:r.errorMessage} ${r.marginTop12}`,children:[I.type==="success"?e.jsx(he,{size:14}):e.jsx(U,{size:14}),I.message]})]})})}),e.jsx(me,{isOpen:!!p,theme:"dark",title:"Edit AI Profile Photo",currentImageUrl:p?.avatarUrl||"",editorImageUrl:p?.avatarSourceUrl||"",fallbackInitial:(p?.name||"AI").charAt(0).toUpperCase(),accept:"image/png,image/jpeg,image/webp,image/gif",busy:B,hasPendingImage:!1,canRemove:!!p?.avatarUrl,error:Z,notice:null,onClose:()=>{B||(T(null),m(null))},onApplyImage:ie,onRemoveImage:te})]})}export{Ie as AgentsModule};