@taskforcehq/taskforce 0.3.168

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 (492) hide show
  1. package/README.md +241 -0
  2. package/dist/Taskforce.d.ts +3 -0
  3. package/dist/Taskforce.js +3 -0
  4. package/dist/Taskforce.module.css +7587 -0
  5. package/dist/TaskforceCore.CategoryFallback.test.d.ts +1 -0
  6. package/dist/TaskforceCore.CategoryFallback.test.js +98 -0
  7. package/dist/TaskforceCore.d.ts +12 -0
  8. package/dist/TaskforceCore.js +729 -0
  9. package/dist/TaskforceCore.test.d.ts +1 -0
  10. package/dist/TaskforceCore.test.js +2132 -0
  11. package/dist/TaskforceScreenshot.d.ts +11 -0
  12. package/dist/TaskforceScreenshot.js +113 -0
  13. package/dist/TaskforceWidget.d.ts +6 -0
  14. package/dist/TaskforceWidget.js +101 -0
  15. package/dist/TaskforceWidget.test.d.ts +1 -0
  16. package/dist/TaskforceWidget.test.js +92 -0
  17. package/dist/UnsavedChangesRelaxed.test.d.ts +1 -0
  18. package/dist/UnsavedChangesRelaxed.test.js +16 -0
  19. package/dist/__tests__/localizationCatalogs.test.d.ts +1 -0
  20. package/dist/__tests__/localizationCatalogs.test.js +37 -0
  21. package/dist/__tests__/planParser.test.d.ts +1 -0
  22. package/dist/__tests__/planParser.test.js +183 -0
  23. package/dist/__tests__/releaseVersion.test.d.ts +1 -0
  24. package/dist/__tests__/releaseVersion.test.js +32 -0
  25. package/dist/__tests__/structuredCommentValidation.test.d.ts +1 -0
  26. package/dist/__tests__/structuredCommentValidation.test.js +31 -0
  27. package/dist/__tests__/structuredDocValidation.test.d.ts +1 -0
  28. package/dist/__tests__/structuredDocValidation.test.js +30 -0
  29. package/dist/__tests__/templateEngine.test.d.ts +1 -0
  30. package/dist/__tests__/templateEngine.test.js +150 -0
  31. package/dist/__tests__/templates.test.d.ts +1 -0
  32. package/dist/__tests__/templates.test.js +45 -0
  33. package/dist/__tests__/workflowDocumentFixtures.test.d.ts +1 -0
  34. package/dist/__tests__/workflowDocumentFixtures.test.js +78 -0
  35. package/dist/__tests__/workflowExportMatrix.test.d.ts +1 -0
  36. package/dist/__tests__/workflowExportMatrix.test.js +113 -0
  37. package/dist/__tests__/workflowExportSnapshots.test.d.ts +1 -0
  38. package/dist/__tests__/workflowExportSnapshots.test.js +28 -0
  39. package/dist/__tests__/workflowGeneration.test.d.ts +1 -0
  40. package/dist/__tests__/workflowGeneration.test.js +12 -0
  41. package/dist/__tests__/workflowSimulation.test.d.ts +1 -0
  42. package/dist/__tests__/workflowSimulation.test.js +113 -0
  43. package/dist/__tests__/workflowV2Policy.test.d.ts +1 -0
  44. package/dist/__tests__/workflowV2Policy.test.js +80 -0
  45. package/dist/api.d.ts +30 -0
  46. package/dist/api.js +85 -0
  47. package/dist/cli.d.ts +2 -0
  48. package/dist/cli.js +217 -0
  49. package/dist/compat/priorityCompat.d.ts +2 -0
  50. package/dist/compat/priorityCompat.js +24 -0
  51. package/dist/components/features/DocumentGenerateModal.d.ts +9 -0
  52. package/dist/components/features/DocumentGenerateModal.js +114 -0
  53. package/dist/components/features/DocumentIndex.d.ts +19 -0
  54. package/dist/components/features/DocumentIndex.js +51 -0
  55. package/dist/components/features/DocumentViewer.d.ts +9 -0
  56. package/dist/components/features/DocumentViewer.js +253 -0
  57. package/dist/components/features/DocumentWorkspace.d.ts +21 -0
  58. package/dist/components/features/DocumentWorkspace.js +88 -0
  59. package/dist/components/features/TaskSettings.d.ts +209 -0
  60. package/dist/components/features/TaskSettings.js +500 -0
  61. package/dist/components/features/TaskSettings.test.d.ts +1 -0
  62. package/dist/components/features/TaskSettings.test.js +308 -0
  63. package/dist/components/features/settings/CategoryManager.d.ts +19 -0
  64. package/dist/components/features/settings/CategoryManager.js +113 -0
  65. package/dist/components/features/settings/TaxonomyEditor.d.ts +8 -0
  66. package/dist/components/features/settings/TaxonomyEditor.js +98 -0
  67. package/dist/components/features/settings/TaxonomyManager 2.d.ts +52 -0
  68. package/dist/components/features/settings/TaxonomyManager 2.js +75 -0
  69. package/dist/components/features/settings/TaxonomyManager.d.ts +54 -0
  70. package/dist/components/features/settings/TaxonomyManager.js +77 -0
  71. package/dist/components/features/settings/TypeManager.d.ts +10 -0
  72. package/dist/components/features/settings/TypeManager.js +50 -0
  73. package/dist/components/features/settings/WorkflowEditorPrototype.d.ts +15 -0
  74. package/dist/components/features/settings/WorkflowEditorPrototype.js +245 -0
  75. package/dist/components/task/TaskActionHeader.d.ts +20 -0
  76. package/dist/components/task/TaskActionHeader.js +13 -0
  77. package/dist/components/task/TaskCard.d.ts +47 -0
  78. package/dist/components/task/TaskCard.js +326 -0
  79. package/dist/components/task/TaskCard.test.d.ts +1 -0
  80. package/dist/components/task/TaskCard.test.js +95 -0
  81. package/dist/components/task/TaskContextUpload.d.ts +12 -0
  82. package/dist/components/task/TaskContextUpload.js +393 -0
  83. package/dist/components/task/TaskContextUpload.test.d.ts +1 -0
  84. package/dist/components/task/TaskContextUpload.test.js +189 -0
  85. package/dist/components/task/TaskForm.d.ts +105 -0
  86. package/dist/components/task/TaskForm.js +241 -0
  87. package/dist/components/task/TaskForm.test.d.ts +1 -0
  88. package/dist/components/task/TaskForm.test.js +288 -0
  89. package/dist/components/task/TaskKanban 2.d.ts +76 -0
  90. package/dist/components/task/TaskKanban 2.js +1004 -0
  91. package/dist/components/task/TaskKanban.d.ts +76 -0
  92. package/dist/components/task/TaskKanban.empty-column-drop.test.d.ts +1 -0
  93. package/dist/components/task/TaskKanban.empty-column-drop.test.js +66 -0
  94. package/dist/components/task/TaskKanban.js +1026 -0
  95. package/dist/components/task/TaskKanban.test.d.ts +1 -0
  96. package/dist/components/task/TaskKanban.test.js +46 -0
  97. package/dist/components/task/TaskList.d.ts +74 -0
  98. package/dist/components/task/TaskList.js +38 -0
  99. package/dist/components/task/TaskList.test.d.ts +1 -0
  100. package/dist/components/task/TaskList.test.js +270 -0
  101. package/dist/components/task/TaskScreenshotSection.d.ts +15 -0
  102. package/dist/components/task/TaskScreenshotSection.js +22 -0
  103. package/dist/components/ui/LevelSelector.d.ts +13 -0
  104. package/dist/components/ui/LevelSelector.js +25 -0
  105. package/dist/components/ui/LevelSelector.test.d.ts +1 -0
  106. package/dist/components/ui/LevelSelector.test.js +55 -0
  107. package/dist/components/ui/Markdown.d.ts +6 -0
  108. package/dist/components/ui/Markdown.js +94 -0
  109. package/dist/components/ui/Markdown.test.d.ts +1 -0
  110. package/dist/components/ui/Markdown.test.js +38 -0
  111. package/dist/components/ui/Modal.d.ts +16 -0
  112. package/dist/components/ui/Modal.js +49 -0
  113. package/dist/components/ui/MultiSelectFilter.d.ts +10 -0
  114. package/dist/components/ui/MultiSelectFilter.js +71 -0
  115. package/dist/components/ui/MultiSelectFilter.test.d.ts +1 -0
  116. package/dist/components/ui/MultiSelectFilter.test.js +74 -0
  117. package/dist/components/ui/TaxonomyDropdown.d.ts +17 -0
  118. package/dist/components/ui/TaxonomyDropdown.js +145 -0
  119. package/dist/components/ui/TaxonomyDropdown.test.d.ts +1 -0
  120. package/dist/components/ui/TaxonomyDropdown.test.js +130 -0
  121. package/dist/components/views/StandaloneLayout 2.d.ts +8 -0
  122. package/dist/components/views/StandaloneLayout 2.js +1660 -0
  123. package/dist/components/views/StandaloneLayout.d.ts +8 -0
  124. package/dist/components/views/StandaloneLayout.js +2117 -0
  125. package/dist/components/views/WidgetView.d.ts +8 -0
  126. package/dist/components/views/WidgetView.js +221 -0
  127. package/dist/config/envSchema.d.ts +28 -0
  128. package/dist/config/envSchema.js +374 -0
  129. package/dist/config/envSchema.test.d.ts +1 -0
  130. package/dist/config/envSchema.test.js +97 -0
  131. package/dist/config/surfaceBase.d.ts +2 -0
  132. package/dist/config/surfaceBase.js +8 -0
  133. package/dist/core/BulkUpdateFieldsPreview.test.d.ts +1 -0
  134. package/dist/core/BulkUpdateFieldsPreview.test.js +62 -0
  135. package/dist/core/CompletedAt.test.d.ts +1 -0
  136. package/dist/core/CompletedAt.test.js +44 -0
  137. package/dist/core/CreatedBy.test.d.ts +1 -0
  138. package/dist/core/CreatedBy.test.js +60 -0
  139. package/dist/core/EntitlementsPolicy.test.d.ts +1 -0
  140. package/dist/core/EntitlementsPolicy.test.js +145 -0
  141. package/dist/core/InitiativeTemplates.test.d.ts +1 -0
  142. package/dist/core/InitiativeTemplates.test.js +50 -0
  143. package/dist/core/ParentLifecycle.test.d.ts +1 -0
  144. package/dist/core/ParentLifecycle.test.js +98 -0
  145. package/dist/core/ScheduleFields.test.d.ts +1 -0
  146. package/dist/core/ScheduleFields.test.js +197 -0
  147. package/dist/core/SetupState.test.d.ts +1 -0
  148. package/dist/core/SetupState.test.js +113 -0
  149. package/dist/core/SystemAdmin.test.d.ts +1 -0
  150. package/dist/core/SystemAdmin.test.js +295 -0
  151. package/dist/core/TaskTaxonomyValidation.test.d.ts +1 -0
  152. package/dist/core/TaskTaxonomyValidation.test.js +64 -0
  153. package/dist/core/Taskforce.d.ts +1063 -0
  154. package/dist/core/Taskforce.ids.test.d.ts +1 -0
  155. package/dist/core/Taskforce.ids.test.js +168 -0
  156. package/dist/core/Taskforce.js +5981 -0
  157. package/dist/core/Taskforce.realtimeMutation.test.d.ts +1 -0
  158. package/dist/core/Taskforce.realtimeMutation.test.js +76 -0
  159. package/dist/core/WorkspaceDelete.test.d.ts +1 -0
  160. package/dist/core/WorkspaceDelete.test.js +140 -0
  161. package/dist/core/WorkspacePermissions.test.d.ts +1 -0
  162. package/dist/core/WorkspacePermissions.test.js +151 -0
  163. package/dist/core/WorkspacePlanMode.test.d.ts +1 -0
  164. package/dist/core/WorkspacePlanMode.test.js +104 -0
  165. package/dist/hooks/authGuardPolicy.d.ts +26 -0
  166. package/dist/hooks/authGuardPolicy.js +32 -0
  167. package/dist/hooks/authGuardPolicy.test.d.ts +1 -0
  168. package/dist/hooks/authGuardPolicy.test.js +76 -0
  169. package/dist/hooks/useDraggable.d.ts +12 -0
  170. package/dist/hooks/useDraggable.js +65 -0
  171. package/dist/hooks/useRealtimeSync.d.ts +24 -0
  172. package/dist/hooks/useRealtimeSync.js +275 -0
  173. package/dist/hooks/useRealtimeSync.test.d.ts +1 -0
  174. package/dist/hooks/useRealtimeSync.test.js +284 -0
  175. package/dist/hooks/useSyncOrchestrator.d.ts +164 -0
  176. package/dist/hooks/useSyncOrchestrator.js +1427 -0
  177. package/dist/hooks/useSyncOrchestrator.retry-closure.test.d.ts +1 -0
  178. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +367 -0
  179. package/dist/hooks/useTaskforce.d.ts +727 -0
  180. package/dist/hooks/useTaskforce.js +4396 -0
  181. package/dist/hooks/useTaskforce.priority-filters.test.d.ts +1 -0
  182. package/dist/hooks/useTaskforce.priority-filters.test.js +33 -0
  183. package/dist/hooks/useWorkspaceSyncController.d.ts +80 -0
  184. package/dist/hooks/useWorkspaceSyncController.js +598 -0
  185. package/dist/hooks/useWorkspaceSyncController.test.d.ts +1 -0
  186. package/dist/hooks/useWorkspaceSyncController.test.js +236 -0
  187. package/dist/index.d.ts +12 -0
  188. package/dist/index.js +11 -0
  189. package/dist/localization/index.d.ts +8 -0
  190. package/dist/localization/index.js +81 -0
  191. package/dist/localization/locales/en-US.d.ts +151 -0
  192. package/dist/localization/locales/en-US.js +150 -0
  193. package/dist/localization/locales/es-419.d.ts +2 -0
  194. package/dist/localization/locales/es-419.js +150 -0
  195. package/dist/localization/locales/pt-BR.d.ts +2 -0
  196. package/dist/localization/locales/pt-BR.js +150 -0
  197. package/dist/main.d.ts +1 -0
  198. package/dist/main.js +33 -0
  199. package/dist/mcp/optionResolution.d.ts +14 -0
  200. package/dist/mcp/optionResolution.js +126 -0
  201. package/dist/mcp/optionResolution.test.d.ts +1 -0
  202. package/dist/mcp/optionResolution.test.js +39 -0
  203. package/dist/mcp/server.d.ts +1 -0
  204. package/dist/mcp/server.js +1793 -0
  205. package/dist/mcp/structuredCommentValidation.d.ts +6 -0
  206. package/dist/mcp/structuredCommentValidation.js +56 -0
  207. package/dist/mcp/structuredDocValidation.d.ts +6 -0
  208. package/dist/mcp/structuredDocValidation.js +75 -0
  209. package/dist/migrations/billingSchemaParity.test.d.ts +1 -0
  210. package/dist/migrations/billingSchemaParity.test.js +46 -0
  211. package/dist/migrations/clientMigrations.d.ts +9 -0
  212. package/dist/migrations/clientMigrations.js +74 -0
  213. package/dist/migrations/flags.d.ts +6 -0
  214. package/dist/migrations/flags.js +8 -0
  215. package/dist/migrations/taskMigrations.d.ts +71 -0
  216. package/dist/migrations/taskMigrations.js +236 -0
  217. package/dist/migrations/taskMigrations.test.d.ts +1 -0
  218. package/dist/migrations/taskMigrations.test.js +34 -0
  219. package/dist/migrations/taskSchemaMigrations.d.ts +11 -0
  220. package/dist/migrations/taskSchemaMigrations.js +453 -0
  221. package/dist/plugins/index.d.ts +10 -0
  222. package/dist/plugins/index.js +10 -0
  223. package/dist/plugins/vite.d.ts +19 -0
  224. package/dist/plugins/vite.js +271 -0
  225. package/dist/public/android-chrome-192x192.png +0 -0
  226. package/dist/public/android-chrome-512x512.png +0 -0
  227. package/dist/public/apple-touch-icon.png +0 -0
  228. package/dist/public/favicon-16x16.png +0 -0
  229. package/dist/public/favicon-32x32.png +0 -0
  230. package/dist/public/favicon.ico +0 -0
  231. package/dist/public/favicon.png +0 -0
  232. package/dist/public/site.webmanifest +1 -0
  233. package/dist/public/taskforce.png +0 -0
  234. package/dist/resources/templates/WORKFLOW_V2_POLICY.md +55 -0
  235. package/dist/resources/templates/environments/aider.yaml +14 -0
  236. package/dist/resources/templates/environments/antigravity.yaml +10 -0
  237. package/dist/resources/templates/environments/claude.yaml +10 -0
  238. package/dist/resources/templates/environments/cline.yaml +10 -0
  239. package/dist/resources/templates/environments/codex.yaml +13 -0
  240. package/dist/resources/templates/environments/copilot.yaml +10 -0
  241. package/dist/resources/templates/environments/cursor.yaml +9 -0
  242. package/dist/resources/templates/environments/gemini.yaml +9 -0
  243. package/dist/resources/templates/environments/windsurf.yaml +10 -0
  244. package/dist/resources/templates/workflow-sources/README.md +9 -0
  245. package/dist/resources/templates/workflow-sources/workflowDocs.mjs +520 -0
  246. package/dist/resources/templates/workflow-sources/workflowEditorOverrides.json +1 -0
  247. package/dist/resources/templates/workflows/collaborate.yaml +104 -0
  248. package/dist/resources/templates/workflows/do.yaml +82 -0
  249. package/dist/resources/templates/workflows/evaluate.yaml +111 -0
  250. package/dist/resources/templates/workflows/execute.yaml +142 -0
  251. package/dist/resources/templates/workflows/plan.yaml +112 -0
  252. package/dist/resources/templates/workflows/review.yaml +109 -0
  253. package/dist/runtime/capabilities.d.ts +8 -0
  254. package/dist/runtime/capabilities.js +16 -0
  255. package/dist/security/virusScan.d.ts +16 -0
  256. package/dist/security/virusScan.js +83 -0
  257. package/dist/server/auth.d.ts +51 -0
  258. package/dist/server/auth.js +266 -0
  259. package/dist/server/auth.test.d.ts +1 -0
  260. package/dist/server/auth.test.js +111 -0
  261. package/dist/server/buildInfo.d.ts +7 -0
  262. package/dist/server/buildInfo.js +100 -0
  263. package/dist/server/buildInfo.test.d.ts +1 -0
  264. package/dist/server/buildInfo.test.js +29 -0
  265. package/dist/server/cors.d.ts +7 -0
  266. package/dist/server/cors.js +76 -0
  267. package/dist/server/cors.test.d.ts +1 -0
  268. package/dist/server/cors.test.js +71 -0
  269. package/dist/server/email.d.ts +28 -0
  270. package/dist/server/email.js +138 -0
  271. package/dist/server/email.test.d.ts +1 -0
  272. package/dist/server/email.test.js +113 -0
  273. package/dist/server/index.cookieProxy.test.d.ts +1 -0
  274. package/dist/server/index.cookieProxy.test.js +19 -0
  275. package/dist/server/index.d.ts +17 -0
  276. package/dist/server/index.js +757 -0
  277. package/dist/server/index.rateLimit.test.d.ts +1 -0
  278. package/dist/server/index.rateLimit.test.js +13 -0
  279. package/dist/server/index.test.d.ts +1 -0
  280. package/dist/server/index.test.js +19 -0
  281. package/dist/server/rateLimit.d.ts +29 -0
  282. package/dist/server/rateLimit.js +99 -0
  283. package/dist/server/rateLimit.test.d.ts +1 -0
  284. package/dist/server/rateLimit.test.js +107 -0
  285. package/dist/server/realtimeSync.auth.test.d.ts +1 -0
  286. package/dist/server/realtimeSync.auth.test.js +62 -0
  287. package/dist/server/realtimeSync.replay.test.d.ts +1 -0
  288. package/dist/server/realtimeSync.replay.test.js +192 -0
  289. package/dist/server/realtimeSync.workspaceIsolation.test.d.ts +1 -0
  290. package/dist/server/realtimeSync.workspaceIsolation.test.js +101 -0
  291. package/dist/server/realtimeSyncWs.d.ts +30 -0
  292. package/dist/server/realtimeSyncWs.js +257 -0
  293. package/dist/server/routes.billing.d.ts +15 -0
  294. package/dist/server/routes.billing.js +991 -0
  295. package/dist/server/routes.billing.test.d.ts +1 -0
  296. package/dist/server/routes.billing.test.js +387 -0
  297. package/dist/server/routes.d.ts +72 -0
  298. package/dist/server/routes.js +4820 -0
  299. package/dist/server/routes.sync.d.ts +17 -0
  300. package/dist/server/routes.sync.integration.test.d.ts +1 -0
  301. package/dist/server/routes.sync.integration.test.js +470 -0
  302. package/dist/server/routes.sync.js +1141 -0
  303. package/dist/server/routes.test.d.ts +1 -0
  304. package/dist/server/routes.test.js +4945 -0
  305. package/dist/server/runtimeMode.d.ts +4 -0
  306. package/dist/server/runtimeMode.js +25 -0
  307. package/dist/server/runtimeMode.test.d.ts +1 -0
  308. package/dist/server/runtimeMode.test.js +26 -0
  309. package/dist/server/securityHeaders.d.ts +3 -0
  310. package/dist/server/securityHeaders.js +25 -0
  311. package/dist/server/securityHeaders.test.d.ts +1 -0
  312. package/dist/server/securityHeaders.test.js +32 -0
  313. package/dist/server/smtpTransport.d.ts +21 -0
  314. package/dist/server/smtpTransport.js +11 -0
  315. package/dist/server/start.d.ts +1 -0
  316. package/dist/server/start.js +17 -0
  317. package/dist/services/formatTransformers.d.ts +29 -0
  318. package/dist/services/formatTransformers.js +56 -0
  319. package/dist/services/templateEngine.d.ts +46 -0
  320. package/dist/services/templateEngine.js +148 -0
  321. package/dist/shared/runtimeContract.d.ts +12 -0
  322. package/dist/shared/runtimeContract.js +23 -0
  323. package/dist/shared/runtimeContract.test.d.ts +1 -0
  324. package/dist/shared/runtimeContract.test.js +23 -0
  325. package/dist/soak/preflight.cli.d.ts +1 -0
  326. package/dist/soak/preflight.cli.js +28 -0
  327. package/dist/soak/preflight.d.ts +26 -0
  328. package/dist/soak/preflight.js +113 -0
  329. package/dist/soak/preflight.test.d.ts +1 -0
  330. package/dist/soak/preflight.test.js +39 -0
  331. package/dist/soak/syncSoakHarness.d.ts +6 -0
  332. package/dist/soak/syncSoakHarness.js +10 -0
  333. package/dist/storage/createDatabaseAdapter.d.ts +2 -0
  334. package/dist/storage/createDatabaseAdapter.js +9 -0
  335. package/dist/storage/databaseAdapter.d.ts +22 -0
  336. package/dist/storage/databaseAdapter.js +1 -0
  337. package/dist/storage/documentIntegrity.d.ts +28 -0
  338. package/dist/storage/documentIntegrity.js +103 -0
  339. package/dist/storage/documentPurge.d.ts +14 -0
  340. package/dist/storage/documentPurge.js +46 -0
  341. package/dist/storage/documentRegistry.d.ts +39 -0
  342. package/dist/storage/documentRegistry.js +115 -0
  343. package/dist/storage/integritySchedule.d.ts +17 -0
  344. package/dist/storage/integritySchedule.js +62 -0
  345. package/dist/storage/objectStorage.d.ts +20 -0
  346. package/dist/storage/objectStorage.js +15 -0
  347. package/dist/storage/objectStorageClient.d.ts +18 -0
  348. package/dist/storage/objectStorageClient.js +301 -0
  349. package/dist/storage/objectStorageConfig.d.ts +2 -0
  350. package/dist/storage/objectStorageConfig.js +45 -0
  351. package/dist/storage/postgresAdapter.d.ts +20 -0
  352. package/dist/storage/postgresAdapter.js +204 -0
  353. package/dist/storage/postgresWorker.d.ts +1 -0
  354. package/dist/storage/postgresWorker.js +110 -0
  355. package/dist/storage/providerConfig.d.ts +6 -0
  356. package/dist/storage/providerConfig.js +11 -0
  357. package/dist/storage/sqliteAdapter.d.ts +14 -0
  358. package/dist/storage/sqliteAdapter.js +28 -0
  359. package/dist/storage/taskAssetStore.d.ts +56 -0
  360. package/dist/storage/taskAssetStore.js +297 -0
  361. package/dist/sync/cloudSyncApi.d.ts +47 -0
  362. package/dist/sync/cloudSyncApi.js +138 -0
  363. package/dist/sync/cloudSyncApi.test.d.ts +1 -0
  364. package/dist/sync/cloudSyncApi.test.js +54 -0
  365. package/dist/sync/encryptionService.d.ts +11 -0
  366. package/dist/sync/encryptionService.js +61 -0
  367. package/dist/sync/encryptionService.test.d.ts +1 -0
  368. package/dist/sync/encryptionService.test.js +52 -0
  369. package/dist/sync/realtimeFeature.d.ts +6 -0
  370. package/dist/sync/realtimeFeature.js +20 -0
  371. package/dist/sync/realtimeFeature.test.d.ts +1 -0
  372. package/dist/sync/realtimeFeature.test.js +30 -0
  373. package/dist/sync/realtimeReconcile.d.ts +30 -0
  374. package/dist/sync/realtimeReconcile.js +90 -0
  375. package/dist/sync/realtimeReconcile.test.d.ts +1 -0
  376. package/dist/sync/realtimeReconcile.test.js +43 -0
  377. package/dist/sync/syncService.d.ts +96 -0
  378. package/dist/sync/syncService.js +423 -0
  379. package/dist/sync/syncService.test.d.ts +1 -0
  380. package/dist/sync/syncService.test.js +484 -0
  381. package/dist/sync/workspaceSyncModel.d.ts +61 -0
  382. package/dist/sync/workspaceSyncModel.js +136 -0
  383. package/dist/sync/workspaceSyncModel.test.d.ts +1 -0
  384. package/dist/sync/workspaceSyncModel.test.js +73 -0
  385. package/dist/test/setup.d.ts +1 -0
  386. package/dist/test/setup.js +15 -0
  387. package/dist/types.d.ts +157 -0
  388. package/dist/types.js +41 -0
  389. package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
  390. package/dist/ui/assets/index-0W5vyCpn.css +1 -0
  391. package/dist/ui/assets/index-MCZuNNfn.js +23 -0
  392. package/dist/ui/assets/logo_white_01-0Vx-iIIv.png +0 -0
  393. package/dist/ui/assets/taskforce-BxLPokNB.png +0 -0
  394. package/dist/ui/assets/vendor-dnd-BI1K77C1.js +5 -0
  395. package/dist/ui/assets/vendor-icons-ZFG3SGwo.js +1 -0
  396. package/dist/ui/assets/vendor-markdown-CKYkQHfj.js +29 -0
  397. package/dist/ui/assets/vendor-react-DdIDsh7f.js +9 -0
  398. package/dist/ui/assets/vendor-router-BtiNU7Dl.js +3 -0
  399. package/dist/ui/branding/logos/logo_black_01.png +0 -0
  400. package/dist/ui/branding/logos/logo_black_02.png +0 -0
  401. package/dist/ui/branding/logos/logo_white_01.png +0 -0
  402. package/dist/ui/branding/logos/logo_white_02.png +0 -0
  403. package/dist/ui/favicon/android-chrome-192x192.png +0 -0
  404. package/dist/ui/favicon/android-chrome-512x512.png +0 -0
  405. package/dist/ui/favicon/apple-touch-icon.png +0 -0
  406. package/dist/ui/favicon/favicon-16x16.png +0 -0
  407. package/dist/ui/favicon/favicon-32x32.png +0 -0
  408. package/dist/ui/favicon/favicon.ico +0 -0
  409. package/dist/ui/favicon/favicon.png +0 -0
  410. package/dist/ui/favicon/site.webmanifest +1 -0
  411. package/dist/ui/fonts/RussoOne-Regular.ttf +0 -0
  412. package/dist/ui/images/taskforce.png +0 -0
  413. package/dist/ui/index.html +19 -0
  414. package/dist/utils/checklistMarkdown.d.ts +9 -0
  415. package/dist/utils/checklistMarkdown.js +46 -0
  416. package/dist/utils/constants.d.ts +21 -0
  417. package/dist/utils/constants.icons.test.d.ts +1 -0
  418. package/dist/utils/constants.icons.test.js +40 -0
  419. package/dist/utils/constants.js +100 -0
  420. package/dist/utils/contextFiles.d.ts +8 -0
  421. package/dist/utils/contextFiles.js +54 -0
  422. package/dist/utils/formatting.d.ts +5 -0
  423. package/dist/utils/formatting.js +30 -0
  424. package/dist/utils/planParser.d.ts +22 -0
  425. package/dist/utils/planParser.js +151 -0
  426. package/dist/utils/taskDragZones.d.ts +8 -0
  427. package/dist/utils/taskDragZones.js +14 -0
  428. package/dist/utils/taskDragZones.test.d.ts +1 -0
  429. package/dist/utils/taskDragZones.test.js +14 -0
  430. package/dist/utils/taskHierarchy.d.ts +4 -0
  431. package/dist/utils/taskHierarchy.js +69 -0
  432. package/dist/utils/taskHierarchy.test.d.ts +1 -0
  433. package/dist/utils/taskHierarchy.test.js +38 -0
  434. package/dist/utils/taskParenting.d.ts +3 -0
  435. package/dist/utils/taskParenting.js +24 -0
  436. package/dist/utils/taskParenting.test.d.ts +1 -0
  437. package/dist/utils/taskParenting.test.js +21 -0
  438. package/dist/utils/taskRelations.d.ts +6 -0
  439. package/dist/utils/taskRelations.js +24 -0
  440. package/dist/utils/taskRelations.test.d.ts +1 -0
  441. package/dist/utils/taskRelations.test.js +34 -0
  442. package/dist/utils/taskUtils.d.ts +2 -0
  443. package/dist/utils/taskUtils.js +20 -0
  444. package/dist/utils/taskforceApiClient.d.ts +7 -0
  445. package/dist/utils/taskforceApiClient.js +42 -0
  446. package/dist/utils/workspaceIdentity.d.ts +8 -0
  447. package/dist/utils/workspaceIdentity.js +47 -0
  448. package/dist/utils/workspaceIdentity.test.d.ts +1 -0
  449. package/dist/utils/workspaceIdentity.test.js +32 -0
  450. package/dist/utils/workspaceLifecycle.d.ts +26 -0
  451. package/dist/utils/workspaceLifecycle.js +69 -0
  452. package/dist/utils/workspaceLifecycle.test.d.ts +1 -0
  453. package/dist/utils/workspaceLifecycle.test.js +64 -0
  454. package/package.json +133 -0
  455. package/scripts/check-compat-boundaries.js +48 -0
  456. package/scripts/check-env.ts +24 -0
  457. package/scripts/check-localization-strings.mjs +49 -0
  458. package/scripts/check-runtime-boundaries.mjs +44 -0
  459. package/scripts/debug-global.mjs +34 -0
  460. package/scripts/debug-server.mjs +36 -0
  461. package/scripts/export-sqlite-to-postgres.mjs +125 -0
  462. package/scripts/generate-env-example.ts +8 -0
  463. package/scripts/generate-workflow-templates.mjs +134 -0
  464. package/scripts/mcp-stdio-adapter.mjs +160 -0
  465. package/scripts/postinstall.js +60 -0
  466. package/scripts/release-version-lib.mjs +88 -0
  467. package/scripts/release-version.mjs +72 -0
  468. package/scripts/run-dev-proxy.sh +49 -0
  469. package/scripts/run-e2e-realtime.sh +16 -0
  470. package/scripts/run-smoke.sh +23 -0
  471. package/scripts/run-soak.sh +29 -0
  472. package/scripts/test-global.js +143 -0
  473. package/scripts/update-homebrew-formula.sh +38 -0
  474. package/src/resources/templates/WORKFLOW_V2_POLICY.md +55 -0
  475. package/src/resources/templates/environments/aider.yaml +14 -0
  476. package/src/resources/templates/environments/antigravity.yaml +10 -0
  477. package/src/resources/templates/environments/claude.yaml +10 -0
  478. package/src/resources/templates/environments/cline.yaml +10 -0
  479. package/src/resources/templates/environments/codex.yaml +13 -0
  480. package/src/resources/templates/environments/copilot.yaml +10 -0
  481. package/src/resources/templates/environments/cursor.yaml +9 -0
  482. package/src/resources/templates/environments/gemini.yaml +9 -0
  483. package/src/resources/templates/environments/windsurf.yaml +10 -0
  484. package/src/resources/templates/workflow-sources/README.md +9 -0
  485. package/src/resources/templates/workflow-sources/workflowDocs.mjs +520 -0
  486. package/src/resources/templates/workflow-sources/workflowEditorOverrides.json +1 -0
  487. package/src/resources/templates/workflows/collaborate.yaml +104 -0
  488. package/src/resources/templates/workflows/do.yaml +82 -0
  489. package/src/resources/templates/workflows/evaluate.yaml +111 -0
  490. package/src/resources/templates/workflows/execute.yaml +142 -0
  491. package/src/resources/templates/workflows/plan.yaml +112 -0
  492. package/src/resources/templates/workflows/review.yaml +109 -0
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ interface ScreenshotCallbackData {
3
+ path: string;
4
+ fsPath?: string;
5
+ }
6
+ interface TaskforceScreenshotProps {
7
+ onCapture: (data: string | ScreenshotCallbackData) => void;
8
+ onCancel: () => void;
9
+ }
10
+ export declare const TaskforceScreenshot: React.FC<TaskforceScreenshotProps>;
11
+ export {};
@@ -0,0 +1,113 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { createPortal } from 'react-dom';
4
+ import html2canvas from 'html2canvas';
5
+ import { Camera, X, Check, Loader2 } from 'lucide-react';
6
+ import styles from './Taskforce.module.css';
7
+ export const TaskforceScreenshot = ({ onCapture, onCancel }) => {
8
+ const [preview, setPreview] = useState(null);
9
+ const [isCapturing, setIsCapturing] = useState(false);
10
+ const [isSaving, setIsSaving] = useState(false);
11
+ const [isSelectingRegion, setIsSelectingRegion] = useState(false);
12
+ const [selectionStart, setSelectionStart] = useState(null);
13
+ const [selectionCurrent, setSelectionCurrent] = useState(null);
14
+ const handleCapture = async (crop) => {
15
+ setIsCapturing(true);
16
+ try {
17
+ const options = {
18
+ useCORS: true,
19
+ scale: window.devicePixelRatio,
20
+ ignoreElements: (element) => {
21
+ return (element.id === 'taskforce-root' ||
22
+ element.classList.contains(styles.regionOverlay) ||
23
+ element.classList.contains(styles.overlay));
24
+ }
25
+ };
26
+ if (crop) {
27
+ options.x = crop.x;
28
+ options.y = crop.y;
29
+ options.width = crop.width;
30
+ options.height = crop.height;
31
+ // Important: windowWidth/windowHeight should match viewport if cropping to ensure correct rendering
32
+ options.windowWidth = document.documentElement.scrollWidth;
33
+ options.windowHeight = document.documentElement.scrollHeight;
34
+ }
35
+ const canvas = await html2canvas(document.body, options);
36
+ const imgData = canvas.toDataURL('image/png');
37
+ setPreview(imgData);
38
+ }
39
+ catch (error) {
40
+ console.error('Screenshot capture failed:', error);
41
+ }
42
+ finally {
43
+ setIsCapturing(false);
44
+ setIsSelectingRegion(false);
45
+ setSelectionStart(null);
46
+ setSelectionCurrent(null);
47
+ }
48
+ };
49
+ const handleMouseDown = (e) => {
50
+ setSelectionStart({ x: e.clientX, y: e.clientY });
51
+ setSelectionCurrent({ x: e.clientX, y: e.clientY });
52
+ };
53
+ const handleMouseMove = (e) => {
54
+ if (selectionStart) {
55
+ setSelectionCurrent({ x: e.clientX, y: e.clientY });
56
+ }
57
+ };
58
+ const handleMouseUp = () => {
59
+ if (selectionStart && selectionCurrent) {
60
+ const x = Math.min(selectionStart.x, selectionCurrent.x);
61
+ const y = Math.min(selectionStart.y, selectionCurrent.y);
62
+ const width = Math.abs(selectionCurrent.x - selectionStart.x);
63
+ const height = Math.abs(selectionCurrent.y - selectionStart.y);
64
+ // Add scroll offset to capturing coordinates
65
+ const scrollX = window.scrollX;
66
+ const scrollY = window.scrollY;
67
+ if (width > 10 && height > 10) {
68
+ handleCapture({ x: x + scrollX, y: y + scrollY, width, height });
69
+ }
70
+ else {
71
+ // Too small, cancel selection
72
+ setIsSelectingRegion(false);
73
+ setSelectionStart(null);
74
+ setSelectionCurrent(null);
75
+ }
76
+ }
77
+ };
78
+ const handleCancel = () => {
79
+ setPreview(null);
80
+ setIsSelectingRegion(false);
81
+ setSelectionStart(null);
82
+ setSelectionCurrent(null);
83
+ onCancel();
84
+ };
85
+ const handleConfirm = async () => {
86
+ if (!preview)
87
+ return;
88
+ setIsSaving(true);
89
+ try {
90
+ const res = await fetch('/api/taskforce/screenshot', {
91
+ method: 'POST',
92
+ headers: { 'Content-Type': 'application/json' },
93
+ body: JSON.stringify({ image: preview })
94
+ });
95
+ const data = await res.json();
96
+ if (data.success) {
97
+ onCapture({ path: data.path, fsPath: data.fsPath });
98
+ }
99
+ }
100
+ catch (error) {
101
+ console.error('Failed to save screenshot:', error);
102
+ }
103
+ finally {
104
+ setIsSaving(false);
105
+ }
106
+ };
107
+ return (_jsxs(_Fragment, { children: [isSelectingRegion && createPortal(_jsx("div", { className: styles.regionOverlay, onMouseDown: handleMouseDown, onMouseMove: handleMouseMove, onMouseUp: handleMouseUp, children: selectionStart && selectionCurrent && (_jsx("div", { className: styles.selectionBox, style: {
108
+ left: Math.min(selectionStart.x, selectionCurrent.x),
109
+ top: Math.min(selectionStart.y, selectionCurrent.y),
110
+ width: Math.abs(selectionCurrent.x - selectionStart.x),
111
+ height: Math.abs(selectionCurrent.y - selectionStart.y),
112
+ } })) }), document.body), _jsx("div", { className: styles.screenshotContainer, children: !preview ? (_jsxs("div", { className: styles.capturePrompt, children: [_jsxs("p", { children: [isCapturing && _jsx(Loader2, { className: styles.spin, size: 14, style: { display: 'inline', marginRight: '8px', verticalAlign: 'text-bottom' } }), isCapturing ? 'Capturing...' : 'Ready to capture the current screen context?'] }), _jsxs("div", { className: styles.actions, children: [_jsxs("button", { type: "button", className: styles.secondaryButton, onClick: handleCancel, disabled: isCapturing, children: [_jsx(X, { size: 16 }), " Cancel"] }), _jsxs("button", { type: "button", className: styles.secondaryButton, onClick: () => setIsSelectingRegion(true), disabled: isCapturing, children: [_jsx(Camera, { size: 16 }), " Select Area"] }), _jsxs("button", { type: "button", className: styles.secondaryButton, onClick: () => handleCapture(), disabled: isCapturing, children: [_jsx(Camera, { size: 16 }), "Capture Full"] })] })] })) : (_jsxs("div", { className: styles.previewContainer, children: [_jsxs("div", { className: styles.previewHeader, children: [_jsx("span", { children: "Screenshot Preview" }), _jsx("button", { type: "button", className: styles.iconButton, onClick: handleCancel, children: _jsx(X, { size: 16 }) })] }), _jsx("img", { src: preview, alt: "Captured", className: styles.screenshotPreview }), _jsxs("div", { className: styles.actions, children: [_jsx("button", { type: "button", className: styles.secondaryButton, onClick: handleCancel, disabled: isSaving, children: "Discard" }), _jsxs("button", { type: "button", className: styles.primaryButton, onClick: handleConfirm, disabled: isSaving, children: [isSaving ? _jsx(Loader2, { className: styles.spin, size: 16 }) : _jsx(Check, { size: 16 }), isSaving ? 'Saving...' : 'Use Screenshot'] })] })] })) })] }));
113
+ };
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { TaskforceConfig } from './types';
3
+ export interface TaskforceWidgetProps {
4
+ config?: Partial<TaskforceConfig>;
5
+ }
6
+ export declare const TaskforceWidget: React.FC<TaskforceWidgetProps>;
@@ -0,0 +1,101 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, useEffect, useCallback, useRef } from 'react';
3
+ import { ClipboardList } from 'lucide-react';
4
+ import { TaskforceCore } from './TaskforceCore';
5
+ import styles from './Taskforce.module.css';
6
+ import { DEFAULT_CONFIG } from './types';
7
+ export const TaskforceWidget = ({ config = {} }) => {
8
+ const mergedConfig = { ...DEFAULT_CONFIG, ...config };
9
+ const { shortcut: configShortcut } = mergedConfig;
10
+ const [isOpen, setIsOpen] = useState(false);
11
+ const [taskCount, setTaskCount] = useState(0);
12
+ // Draggable logic for the widget modal
13
+ const modalRef = useRef(null);
14
+ const [position, setPosition] = useState({ x: 0, y: 0 });
15
+ const [isDragging, setIsDragging] = useState(false);
16
+ const [dragStart, setDragStart] = useState({ x: 0, y: 0 });
17
+ const [initialTop, setInitialTop] = useState(0);
18
+ const handleMouseDown = (e) => {
19
+ // Prevent drag if clicking buttons or inputs within the header
20
+ if (e.target.closest('button'))
21
+ return;
22
+ if (modalRef.current) {
23
+ const rect = modalRef.current.getBoundingClientRect();
24
+ setInitialTop(rect.top - position.y);
25
+ }
26
+ setIsDragging(true);
27
+ setDragStart({
28
+ x: e.clientX - position.x,
29
+ y: e.clientY - position.y
30
+ });
31
+ };
32
+ const handleMouseMove = useCallback((e) => {
33
+ if (isDragging) {
34
+ let newX = e.clientX - dragStart.x;
35
+ let newY = e.clientY - dragStart.y;
36
+ if (newY < -initialTop) {
37
+ newY = -initialTop;
38
+ }
39
+ setPosition({ x: newX, y: newY });
40
+ }
41
+ }, [isDragging, dragStart, initialTop]);
42
+ const handleMouseUp = useCallback(() => {
43
+ setIsDragging(false);
44
+ }, []);
45
+ useEffect(() => {
46
+ if (isDragging) {
47
+ window.addEventListener('mousemove', handleMouseMove);
48
+ window.addEventListener('mouseup', handleMouseUp);
49
+ }
50
+ else {
51
+ window.removeEventListener('mousemove', handleMouseMove);
52
+ window.removeEventListener('mouseup', handleMouseUp);
53
+ }
54
+ return () => {
55
+ window.removeEventListener('mousemove', handleMouseMove);
56
+ window.removeEventListener('mouseup', handleMouseUp);
57
+ };
58
+ }, [isDragging, handleMouseMove, handleMouseUp]);
59
+ // Keyboard shortcut handler
60
+ const handleKeyDown = useCallback((e) => {
61
+ const keys = (configShortcut || 'Alt+T').toLowerCase().split('+').map(k => k.trim());
62
+ const key = keys[keys.length - 1];
63
+ const modifiers = keys.slice(0, keys.length - 1);
64
+ const hasAlt = modifiers.includes('alt') || modifiers.includes('option');
65
+ const hasCtrl = modifiers.includes('ctrl') || modifiers.includes('control');
66
+ const hasShift = modifiers.includes('shift');
67
+ const hasMeta = modifiers.includes('meta') || modifiers.includes('cmd') || modifiers.includes('command');
68
+ if ((e.key.toLowerCase() === key || e.code.toLowerCase() === `key${key}`) &&
69
+ (hasAlt === e.altKey) &&
70
+ (hasCtrl === e.ctrlKey) &&
71
+ (hasShift === e.shiftKey) &&
72
+ (hasMeta === e.metaKey)) {
73
+ e.preventDefault();
74
+ setIsOpen(prev => !prev);
75
+ }
76
+ }, [configShortcut]);
77
+ useEffect(() => {
78
+ window.addEventListener('keydown', handleKeyDown);
79
+ return () => window.removeEventListener('keydown', handleKeyDown);
80
+ }, [handleKeyDown]);
81
+ // Body scroll lock
82
+ useEffect(() => {
83
+ if (isOpen) {
84
+ const originalStyle = window.getComputedStyle(document.body).overflow;
85
+ document.body.style.overflow = 'hidden';
86
+ return () => {
87
+ document.body.style.overflow = originalStyle;
88
+ };
89
+ }
90
+ return undefined;
91
+ }, [isOpen]);
92
+ // Only render in development
93
+ if (!import.meta.env.DEV) {
94
+ return null;
95
+ }
96
+ return (_jsxs(_Fragment, { children: [_jsxs("button", { className: styles.floatingButton, onClick: () => setIsOpen(!isOpen), title: `Taskforce (${configShortcut})`, children: [_jsx(ClipboardList, { size: 22 }), taskCount > 0 && (_jsx("span", { className: styles.badge, children: taskCount }))] }), _jsx("div", { id: "taskforce-root", className: `${styles.overlay} ${styles.widgetOverlay}`, style: {
97
+ display: isOpen ? 'flex' : 'none',
98
+ }, children: _jsx("div", { ref: modalRef, className: `${styles.modal} ${styles.widgetModal}`, style: {
99
+ transform: `translate(${position.x}px, ${position.y}px)`,
100
+ }, children: _jsx(TaskforceCore, { config: config, mode: "standalone", onHeaderMouseDown: handleMouseDown, isDragging: isDragging, onTaskCountChange: setTaskCount, onClose: () => setIsOpen(false) }) }) })] }));
101
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,92 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { render, screen, fireEvent, waitFor } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import { describe, it, expect, vi } from 'vitest';
5
+ import React from 'react';
6
+ import { TaskforceWidget } from './TaskforceWidget';
7
+ // Mock TaskforceCore to avoid testing integration twice
8
+ vi.mock('./TaskforceCore', () => ({
9
+ TaskforceCore: ({ onTaskCountChange, onHeaderMouseDown, onClose }) => {
10
+ // Report a count of 3 on mount
11
+ React.useEffect(() => {
12
+ if (onTaskCountChange)
13
+ onTaskCountChange(3);
14
+ }, [onTaskCountChange]);
15
+ return (_jsxs("div", { "data-testid": "core-component", children: [_jsx("div", { "data-testid": "header", onMouseDown: onHeaderMouseDown, children: "Header" }), _jsx("button", { onClick: onClose, children: "Close" })] }));
16
+ }
17
+ }));
18
+ describe('TaskforceWidget Component', () => {
19
+ const user = userEvent.setup();
20
+ it('6.1 & 6.2 Renders floating button with badge count', async () => {
21
+ render(_jsx(TaskforceWidget, {}));
22
+ const button = screen.getByTitle(/Taskforce/i);
23
+ expect(button).toBeInTheDocument();
24
+ // Mock core reports 3 tasks
25
+ await waitFor(() => {
26
+ expect(screen.getByText('3')).toBeInTheDocument(); // Badge
27
+ });
28
+ });
29
+ it('6.3 & 6.4 Toggles modal on click', async () => {
30
+ render(_jsx(TaskforceWidget, {}));
31
+ const button = screen.getByTitle(/Taskforce/i);
32
+ // Initially hidden (display: none)
33
+ const root = document.getElementById('taskforce-root');
34
+ expect(root).toHaveStyle({ display: 'none' });
35
+ // Open
36
+ await user.click(button);
37
+ expect(root).toHaveStyle({ display: 'flex' });
38
+ // Close via internal button (passed to onClose)
39
+ const closeBtn = screen.getByText('Close');
40
+ await user.click(closeBtn);
41
+ expect(root).toHaveStyle({ display: 'none' });
42
+ });
43
+ it('6.6 Toggles modal on Alt+T keyboard shortcut', async () => {
44
+ render(_jsx(TaskforceWidget, {}));
45
+ const root = document.getElementById('taskforce-root');
46
+ // Alt+T
47
+ fireEvent.keyDown(window, { key: 't', altKey: true });
48
+ expect(root).toHaveStyle({ display: 'flex' });
49
+ // Alt+T again
50
+ fireEvent.keyDown(window, { key: 't', altKey: true });
51
+ expect(root).toHaveStyle({ display: 'none' });
52
+ });
53
+ it('6.9 State persistence: Core remains mounted when closed', async () => {
54
+ render(_jsx(TaskforceWidget, {}));
55
+ // It's always mounted
56
+ expect(screen.getByTestId('core-component')).toBeInTheDocument();
57
+ // Toggle open
58
+ fireEvent.keyDown(window, { key: 't', altKey: true });
59
+ // Use waitFor because of potential state updates
60
+ await waitFor(() => {
61
+ expect(screen.getByTestId('core-component')).toBeInTheDocument();
62
+ });
63
+ // Toggle closed
64
+ fireEvent.keyDown(window, { key: 't', altKey: true });
65
+ const root = document.getElementById('taskforce-root');
66
+ expect(root).toHaveStyle({ display: 'none' });
67
+ // Component is still in DOM (preserves state)
68
+ expect(screen.getByTestId('core-component')).toBeInTheDocument();
69
+ });
70
+ it('Locks body scroll when open and unlocks when closed', async () => {
71
+ render(_jsx(TaskforceWidget, {}));
72
+ const button = screen.getByTitle(/Taskforce/i);
73
+ // Initial state
74
+ expect(document.body.style.overflow).toBe('');
75
+ // Open
76
+ await user.click(button);
77
+ expect(document.body.style.overflow).toBe('hidden');
78
+ // Close
79
+ const closeBtn = screen.getByText('Close');
80
+ await user.click(closeBtn);
81
+ expect(document.body.style.overflow).toBe('');
82
+ });
83
+ it('Draggable: handles mouse down on header', () => {
84
+ render(_jsx(TaskforceWidget, {}));
85
+ const header = screen.getByTestId('header');
86
+ fireEvent.mouseDown(header, { clientX: 100, clientY: 100 });
87
+ fireEvent.mouseMove(window, { clientX: 150, clientY: 150 });
88
+ fireEvent.mouseUp(window);
89
+ const modal = screen.getByTestId('core-component').parentElement;
90
+ expect(modal).toBeInTheDocument();
91
+ });
92
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { describe, it, expect } from 'vitest';
4
+ describe('Unsaved Changes Dialog Contract', () => {
5
+ const standaloneLayoutPath = path.resolve(__dirname, 'components/views/StandaloneLayout.tsx');
6
+ const source = fs.readFileSync(standaloneLayoutPath, 'utf-8');
7
+ it('includes the unsaved changes modal title and message', () => {
8
+ expect(source).toContain('Unsaved Changes');
9
+ expect(source).toContain('You have unsaved changes. Would you like to save them?');
10
+ });
11
+ it('includes explicit action labels for close, discard, and save', () => {
12
+ expect(source).toContain('Close dialog and continue editing');
13
+ expect(source).toContain('Discard unsaved changes and leave');
14
+ expect(source).toContain('Save changes and leave');
15
+ });
16
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,37 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { enUS } from '../localization/locales/en-US';
3
+ import { es419 } from '../localization/locales/es-419';
4
+ import { ptBR } from '../localization/locales/pt-BR';
5
+ function collectLeafKeys(input, prefix = '') {
6
+ if (!input || typeof input !== 'object')
7
+ return [];
8
+ return Object.entries(input).flatMap(([key, value]) => {
9
+ const nextPrefix = prefix ? `${prefix}.${key}` : key;
10
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
11
+ return collectLeafKeys(value, nextPrefix);
12
+ }
13
+ return [nextPrefix];
14
+ });
15
+ }
16
+ describe('Localization catalogs', () => {
17
+ it('keeps identical key coverage across locales', () => {
18
+ const enKeys = collectLeafKeys(enUS).sort();
19
+ const esKeys = collectLeafKeys(es419).sort();
20
+ const ptKeys = collectLeafKeys(ptBR).sort();
21
+ expect(esKeys).toEqual(enKeys);
22
+ expect(ptKeys).toEqual(enKeys);
23
+ });
24
+ it('avoids blank translations in non-default locales', () => {
25
+ const values = [es419, ptBR];
26
+ for (const catalog of values) {
27
+ for (const key of collectLeafKeys(catalog)) {
28
+ const segments = key.split('.');
29
+ let cursor = catalog;
30
+ for (const segment of segments)
31
+ cursor = cursor?.[segment];
32
+ expect(typeof cursor).toBe('string');
33
+ expect(String(cursor).trim().length).toBeGreaterThan(0);
34
+ }
35
+ }
36
+ });
37
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,183 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { parsePlan, flattenSelected } from '../utils/planParser';
3
+ // ─── parsePlan ───────────────────────────────────────────────────────────────
4
+ describe('parsePlan', () => {
5
+ it('returns empty array for empty content', () => {
6
+ expect(parsePlan('')).toEqual([]);
7
+ expect(parsePlan(' \n\n ')).toEqual([]);
8
+ });
9
+ it('parses H2 headings as top-level root tasks', () => {
10
+ const result = parsePlan('## Phase 1\n## Phase 2');
11
+ expect(result).toHaveLength(2);
12
+ expect(result[0].title).toBe('Phase 1');
13
+ expect(result[1].title).toBe('Phase 2');
14
+ expect(result[0].depth).toBe(0);
15
+ });
16
+ it('parses H3 headings as children of the preceding H2', () => {
17
+ const md = `## Phase 1\n### Setup\n### Config`;
18
+ const result = parsePlan(md);
19
+ expect(result).toHaveLength(1);
20
+ expect(result[0].children).toHaveLength(2);
21
+ expect(result[0].children[0].title).toBe('Setup');
22
+ expect(result[0].children[0].depth).toBe(1);
23
+ });
24
+ it('parses dash list items as children of current heading', () => {
25
+ const md = `## Phase 1\n- Task A\n- Task B`;
26
+ const result = parsePlan(md);
27
+ expect(result[0].children).toHaveLength(2);
28
+ expect(result[0].children[0].title).toBe('Task A');
29
+ });
30
+ it('parses asterisk list items', () => {
31
+ const md = `## Phase 1\n* Task A\n* Task B`;
32
+ const result = parsePlan(md);
33
+ expect(result[0].children).toHaveLength(2);
34
+ });
35
+ it('parses numbered list items', () => {
36
+ const md = `## Phase 1\n1. Task A\n2. Task B`;
37
+ const result = parsePlan(md);
38
+ expect(result[0].children).toHaveLength(2);
39
+ expect(result[0].children[0].title).toBe('Task A');
40
+ });
41
+ it('nests list items under H3 when H3 is present', () => {
42
+ const md = `## Phase 1\n### API\n- Route A\n- Route B\n### UI\n- Component X`;
43
+ const result = parsePlan(md);
44
+ const phase = result[0];
45
+ expect(phase.children).toHaveLength(2); // API, UI
46
+ expect(phase.children[0].children).toHaveLength(2); // Route A, Route B
47
+ expect(phase.children[1].children).toHaveLength(1); // Component X
48
+ });
49
+ it('all nodes start selected by default', () => {
50
+ const md = `## Phase 1\n### Step\n- Item`;
51
+ const result = parsePlan(md);
52
+ expect(result[0].selected).toBe(true);
53
+ expect(result[0].children[0].selected).toBe(true);
54
+ expect(result[0].children[0].children[0].selected).toBe(true);
55
+ });
56
+ it('generates stable idempotency keys', () => {
57
+ const md = `## Phase 1\n- Task A`;
58
+ const r1 = parsePlan(md);
59
+ const r2 = parsePlan(md);
60
+ expect(r1[0].idempotencyKey).toBe(r2[0].idempotencyKey);
61
+ expect(r1[0].children[0].idempotencyKey).toBe(r2[0].children[0].idempotencyKey);
62
+ });
63
+ it('sibling tasks have different idempotency keys', () => {
64
+ const md = `## Phase 1\n- Task A\n- Task B`;
65
+ const result = parsePlan(md);
66
+ const keys = result[0].children.map((c) => c.idempotencyKey);
67
+ expect(new Set(keys).size).toBe(keys.length);
68
+ });
69
+ });
70
+ // ─── Type inference ──────────────────────────────────────────────────────────
71
+ describe('parsePlan — type inference', () => {
72
+ function typeOf(title) {
73
+ return parsePlan(`## ${title}`)[0].type;
74
+ }
75
+ it('infers "bug" for fix/bug keywords', () => {
76
+ expect(typeOf('Fix login bug')).toBe('bug');
77
+ expect(typeOf('Bug: broken redirect')).toBe('bug');
78
+ expect(typeOf('Hotfix for session issue')).toBe('bug');
79
+ });
80
+ it('infers "refactor" for refactor/cleanup keywords', () => {
81
+ expect(typeOf('Refactor auth module')).toBe('refactor');
82
+ expect(typeOf('Clean up legacy routes')).toBe('refactor');
83
+ });
84
+ it('infers "documentation" for docs keywords', () => {
85
+ expect(typeOf('Update README')).toBe('documentation');
86
+ expect(typeOf('Write docs for API')).toBe('documentation');
87
+ });
88
+ it('infers "chore" for setup/config/deploy keywords', () => {
89
+ expect(typeOf('Setup CI pipeline')).toBe('chore');
90
+ expect(typeOf('Config environment')).toBe('chore');
91
+ expect(typeOf('Deploy infrastructure')).toBe('chore');
92
+ });
93
+ it('defaults to "feature" for unrecognised titles', () => {
94
+ expect(typeOf('Add user dashboard')).toBe('feature');
95
+ expect(typeOf('Phase 1 — Core Module')).toBe('feature');
96
+ });
97
+ });
98
+ // ─── Priority inference ──────────────────────────────────────────────────────
99
+ describe('parsePlan — priority inference', () => {
100
+ function priorityOf(title) {
101
+ return parsePlan(`## ${title}`)[0].priority;
102
+ }
103
+ it('infers priority 4 (Critical) for "critical" / "blocker" / "p0"', () => {
104
+ expect(priorityOf('Critical: auth bypass')).toBe(4);
105
+ expect(priorityOf('Blocker — build fails')).toBe(4);
106
+ expect(priorityOf('P0 fix needed')).toBe(4);
107
+ });
108
+ it('infers priority 3 (High) for "high" / "important"', () => {
109
+ expect(priorityOf('High priority task')).toBe(3);
110
+ expect(priorityOf('Important migration')).toBe(3);
111
+ });
112
+ it('infers priority 1 (Low) for "low" / "minor" / "nice-to-have"', () => {
113
+ expect(priorityOf('Low priority cleanup')).toBe(1);
114
+ expect(priorityOf('Minor styling tweak')).toBe(1);
115
+ expect(priorityOf('Nice to have feature')).toBe(1);
116
+ });
117
+ it('defaults to priority 2 (Medium) for unrecognised titles', () => {
118
+ expect(priorityOf('Add user dashboard')).toBe(2);
119
+ });
120
+ });
121
+ // ─── flattenSelected ─────────────────────────────────────────────────────────
122
+ describe('flattenSelected', () => {
123
+ it('returns all nodes when all selected', () => {
124
+ const md = `## Phase\n### Step\n- Item`;
125
+ const tasks = parsePlan(md);
126
+ const flat = flattenSelected(tasks);
127
+ expect(flat.length).toBe(3);
128
+ });
129
+ it('excludes deselected nodes and their children', () => {
130
+ const md = `## Phase\n### Step\n- Item`;
131
+ const tasks = parsePlan(md);
132
+ // Deselect the H3 — should exclude it and its children
133
+ tasks[0].children[0].selected = false;
134
+ const flat = flattenSelected(tasks);
135
+ // Should only have the H2 root
136
+ expect(flat.length).toBe(1);
137
+ expect(flat[0].title).toBe('Phase');
138
+ });
139
+ it('returns empty array when root is deselected', () => {
140
+ const md = `## Phase\n- Item`;
141
+ const tasks = parsePlan(md);
142
+ tasks[0].selected = false;
143
+ const flat = flattenSelected(tasks);
144
+ expect(flat).toHaveLength(0);
145
+ });
146
+ it('preserves order (root before children)', () => {
147
+ const md = `## Phase 1\n- Task A\n- Task B\n## Phase 2\n- Task C`;
148
+ const tasks = parsePlan(md);
149
+ const flat = flattenSelected(tasks);
150
+ expect(flat[0].title).toBe('Phase 1');
151
+ expect(flat[1].title).toBe('Task A');
152
+ expect(flat[2].title).toBe('Task B');
153
+ expect(flat[3].title).toBe('Phase 2');
154
+ expect(flat[4].title).toBe('Task C');
155
+ });
156
+ });
157
+ // ─── Edge cases ──────────────────────────────────────────────────────────────
158
+ describe('parsePlan — edge cases', () => {
159
+ it('handles H3 without preceding H2 as root node', () => {
160
+ const result = parsePlan('### Orphan step');
161
+ expect(result).toHaveLength(1);
162
+ expect(result[0].title).toBe('Orphan step');
163
+ });
164
+ it('handles documents with no headings (only paragraphs)', () => {
165
+ const result = parsePlan('This is just a paragraph.\nAnd another one.');
166
+ // No actionable tasks parseable
167
+ expect(result).toHaveLength(0);
168
+ });
169
+ it('trims trailing/leading whitespace from titles', () => {
170
+ const result = parsePlan('## Phase 1 ');
171
+ expect(result[0].title).toBe('Phase 1');
172
+ });
173
+ it('handles mixed list markers in the same section', () => {
174
+ const md = `## Phase\n- Task A\n* Task B\n1. Task C`;
175
+ const result = parsePlan(md);
176
+ expect(result[0].children).toHaveLength(3);
177
+ });
178
+ it('ignores horizontal rules and other non-task lines', () => {
179
+ const md = `## Phase 1\n---\n- Task A`;
180
+ const result = parsePlan(md);
181
+ expect(result[0].children).toHaveLength(1);
182
+ });
183
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ // @ts-expect-error - JS module without generated .d.ts (validated by tests).
3
+ import { computeNextPatch, computeNextVersion } from '../../scripts/release-version-lib.mjs';
4
+ describe('release version automation', () => {
5
+ it('increments patch from latest matching tag', () => {
6
+ const next = computeNextVersion({
7
+ major: 1,
8
+ minor: 4,
9
+ releaseTags: ['v1.4.7', 'v1.4.8', 'v1.3.9'],
10
+ currentPackageVersion: '1.4.8'
11
+ });
12
+ expect(next).toBe('1.4.9');
13
+ });
14
+ it('uses package patch + 1 when no tags exist for configured line', () => {
15
+ const nextPatch = computeNextPatch({
16
+ major: 0,
17
+ minor: 3,
18
+ releaseTags: [],
19
+ currentPackageVersion: '0.3.13-beta.2'
20
+ });
21
+ expect(nextPatch).toBe(14);
22
+ });
23
+ it('starts new major/minor line at patch 0 when no tags exist', () => {
24
+ const next = computeNextVersion({
25
+ major: 2,
26
+ minor: 0,
27
+ releaseTags: ['v1.9.9'],
28
+ currentPackageVersion: '1.9.9'
29
+ });
30
+ expect(next).toBe('2.0.0');
31
+ });
32
+ });
@@ -0,0 +1,31 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { validateStructuredCommentForAdd } from '../mcp/structuredCommentValidation';
3
+ describe('structured comment add validation', () => {
4
+ it('passes ordinary comments', () => {
5
+ const result = validateStructuredCommentForAdd('LGTM. Proceeding with implementation.');
6
+ expect(result).toEqual({ ok: true });
7
+ });
8
+ it('passes complete evaluation summary comments', () => {
9
+ const comment = [
10
+ '## Evaluation Summary',
11
+ '### Recommendation (Proceed | Pivot | Kill)',
12
+ 'Proceed',
13
+ '### Value Score (1-5)',
14
+ '4',
15
+ '### Risk Score (1-5)',
16
+ '2',
17
+ '### Next Step',
18
+ 'Start implementation.'
19
+ ].join('\n');
20
+ expect(validateStructuredCommentForAdd(comment)).toEqual({ ok: true });
21
+ });
22
+ it('fails incomplete review summary comments', () => {
23
+ const comment = ['## Review Summary', '### Findings', '- Missing tests'].join('\n');
24
+ const result = validateStructuredCommentForAdd(comment);
25
+ expect(result.ok).toBe(false);
26
+ if (!result.ok) {
27
+ expect(result.message).toContain('### Verdict (PASS | WARN | FAIL)');
28
+ expect(result.message).toContain('### Next Status');
29
+ }
30
+ });
31
+ });
@@ -0,0 +1 @@
1
+ export {};