@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,113 @@
1
+ function asNonEmpty(value) {
2
+ return String(value || '').trim();
3
+ }
4
+ function parsePositiveInt(value, fallback) {
5
+ const parsed = Number.parseInt(String(value || '').trim(), 10);
6
+ if (!Number.isFinite(parsed) || parsed <= 0)
7
+ return fallback;
8
+ return parsed;
9
+ }
10
+ function parseBoolean(value, fallback = false) {
11
+ const normalized = String(value || '').trim().toLowerCase();
12
+ if (!normalized)
13
+ return fallback;
14
+ if (['1', 'true', 'yes', 'on'].includes(normalized))
15
+ return true;
16
+ if (['0', 'false', 'no', 'off'].includes(normalized))
17
+ return false;
18
+ return fallback;
19
+ }
20
+ function parseProfile(value) {
21
+ const normalized = String(value || '').trim().toLowerCase();
22
+ if (normalized === 'stress')
23
+ return 'stress';
24
+ if (normalized === 'overnight')
25
+ return 'overnight';
26
+ return 'smoke';
27
+ }
28
+ function isHttpUrl(value) {
29
+ try {
30
+ const url = new URL(value);
31
+ return url.protocol === 'http:' || url.protocol === 'https:';
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ function containsProdHint(value) {
38
+ return /\bprod(uction)?\b/i.test(value);
39
+ }
40
+ export function loadSyncEndurancePreflightConfig(env = process.env) {
41
+ const sharedWorkspaceId = asNonEmpty(env.SYNC_SOAK_WORKSPACE_ID);
42
+ const sharedEmail = asNonEmpty(env.SYNC_SOAK_EMAIL);
43
+ const sharedPassword = asNonEmpty(env.SYNC_SOAK_PASSWORD);
44
+ const workspaceId = sharedWorkspaceId;
45
+ const localWorkspaceId = workspaceId;
46
+ const cloudWorkspaceId = workspaceId;
47
+ const localEmail = sharedEmail;
48
+ const localPassword = sharedPassword;
49
+ const cloudEmail = sharedEmail;
50
+ const cloudPassword = sharedPassword;
51
+ return {
52
+ localBaseUrl: asNonEmpty(env.SYNC_SOAK_LOCAL_BASE_URL),
53
+ cloudBaseUrl: asNonEmpty(env.SYNC_SOAK_CLOUD_BASE_URL),
54
+ workspaceId,
55
+ localWorkspaceId,
56
+ cloudWorkspaceId,
57
+ localEmail,
58
+ localPassword,
59
+ cloudEmail,
60
+ cloudPassword,
61
+ durationMin: parsePositiveInt(env.SYNC_SOAK_DURATION_MIN, 60),
62
+ seed: asNonEmpty(env.SYNC_SOAK_SEED) || String(Date.now()),
63
+ profile: parseProfile(env.SYNC_SOAK_PROFILE),
64
+ artifactDir: asNonEmpty(env.SYNC_SOAK_ARTIFACT_DIR) || '.taskforce/soak-artifacts',
65
+ enableSyncDebug: parseBoolean(env.SYNC_SOAK_ENABLE_SYNC_DEBUG, false)
66
+ };
67
+ }
68
+ export function validateSyncEndurancePreflight(config) {
69
+ const errors = [];
70
+ const warnings = [];
71
+ if (!config.localBaseUrl)
72
+ errors.push('Missing SYNC_SOAK_LOCAL_BASE_URL.');
73
+ if (!config.cloudBaseUrl)
74
+ errors.push('Missing SYNC_SOAK_CLOUD_BASE_URL.');
75
+ if (config.localBaseUrl && !isHttpUrl(config.localBaseUrl)) {
76
+ errors.push('SYNC_SOAK_LOCAL_BASE_URL must be an absolute http(s) URL.');
77
+ }
78
+ if (config.cloudBaseUrl && !isHttpUrl(config.cloudBaseUrl)) {
79
+ errors.push('SYNC_SOAK_CLOUD_BASE_URL must be an absolute http(s) URL.');
80
+ }
81
+ if (!config.workspaceId)
82
+ errors.push('Missing SYNC_SOAK_WORKSPACE_ID.');
83
+ if (!config.localEmail)
84
+ errors.push('Missing SYNC_SOAK_EMAIL.');
85
+ if (!config.localPassword)
86
+ errors.push('Missing SYNC_SOAK_PASSWORD.');
87
+ if (!config.cloudEmail)
88
+ errors.push('Missing SYNC_SOAK_EMAIL.');
89
+ if (!config.cloudPassword)
90
+ errors.push('Missing SYNC_SOAK_PASSWORD.');
91
+ if (!config.artifactDir)
92
+ errors.push('Missing SYNC_SOAK_ARTIFACT_DIR.');
93
+ if (config.durationMin < 5)
94
+ errors.push('SYNC_SOAK_DURATION_MIN must be >= 5.');
95
+ if (containsProdHint(config.localBaseUrl) || containsProdHint(config.cloudBaseUrl)) {
96
+ warnings.push('One or more base URLs look production-like; prefer dedicated test environments.');
97
+ }
98
+ return {
99
+ ok: errors.length === 0,
100
+ config,
101
+ errors,
102
+ warnings
103
+ };
104
+ }
105
+ export function assertSyncEndurancePreflight(env = process.env) {
106
+ const config = loadSyncEndurancePreflightConfig(env);
107
+ const result = validateSyncEndurancePreflight(config);
108
+ if (!result.ok) {
109
+ const details = result.errors.map((entry) => `- ${entry}`).join('\n');
110
+ throw new Error(`Sync soak preflight failed:\n${details}`);
111
+ }
112
+ return result.config;
113
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,39 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { assertSyncEndurancePreflight, loadSyncEndurancePreflightConfig, validateSyncEndurancePreflight } from './preflight';
3
+ const validEnv = {
4
+ SYNC_SOAK_LOCAL_BASE_URL: 'http://localhost:5174',
5
+ SYNC_SOAK_CLOUD_BASE_URL: 'https://cloud.example.com',
6
+ SYNC_SOAK_WORKSPACE_ID: 'workspace-sync-test',
7
+ SYNC_SOAK_EMAIL: 'shared-sync-test@example.com',
8
+ SYNC_SOAK_PASSWORD: 'shared-password',
9
+ SYNC_SOAK_DURATION_MIN: '90',
10
+ SYNC_SOAK_PROFILE: 'stress',
11
+ SYNC_SOAK_SEED: 'seed-123'
12
+ };
13
+ describe('soak/preflight', () => {
14
+ it('loads typed preflight config from env', () => {
15
+ const config = loadSyncEndurancePreflightConfig(validEnv);
16
+ expect(config.localBaseUrl).toBe('http://localhost:5174');
17
+ expect(config.profile).toBe('stress');
18
+ expect(config.durationMin).toBe(90);
19
+ expect(config.seed).toBe('seed-123');
20
+ expect(config.workspaceId).toBe('workspace-sync-test');
21
+ expect(config.localWorkspaceId).toBe('workspace-sync-test');
22
+ expect(config.cloudWorkspaceId).toBe('workspace-sync-test');
23
+ });
24
+ it('fails validation when required fields are missing', () => {
25
+ const config = loadSyncEndurancePreflightConfig({});
26
+ const result = validateSyncEndurancePreflight(config);
27
+ expect(result.ok).toBe(false);
28
+ expect(result.errors.length).toBeGreaterThan(0);
29
+ });
30
+ it('throws with a readable error when preflight fails', () => {
31
+ expect(() => assertSyncEndurancePreflight({})).toThrowError(/preflight failed/i);
32
+ });
33
+ it('passes for valid environment', () => {
34
+ expect(() => assertSyncEndurancePreflight(validEnv)).not.toThrow();
35
+ const config = loadSyncEndurancePreflightConfig(validEnv);
36
+ expect(config.localEmail).toBe('shared-sync-test@example.com');
37
+ expect(config.cloudEmail).toBe('shared-sync-test@example.com');
38
+ });
39
+ });
@@ -0,0 +1,6 @@
1
+ import { type SyncEndurancePreflightConfig } from './preflight';
2
+ export interface SyncEnduranceHarness {
3
+ config: SyncEndurancePreflightConfig;
4
+ run: () => Promise<void>;
5
+ }
6
+ export declare function createSyncEnduranceHarnessFromEnv(env?: NodeJS.ProcessEnv): SyncEnduranceHarness;
@@ -0,0 +1,10 @@
1
+ import { assertSyncEndurancePreflight } from './preflight';
2
+ export function createSyncEnduranceHarnessFromEnv(env = process.env) {
3
+ const config = assertSyncEndurancePreflight(env);
4
+ return {
5
+ config,
6
+ run: async () => {
7
+ throw new Error('Sync soak harness is not implemented yet.');
8
+ }
9
+ };
10
+ }
@@ -0,0 +1,2 @@
1
+ import type { DatabaseAdapter, DatabaseAdapterOptions } from './databaseAdapter.js';
2
+ export declare function createDatabaseAdapter(options: DatabaseAdapterOptions): DatabaseAdapter;
@@ -0,0 +1,9 @@
1
+ import { PostgresAdapter } from './postgresAdapter.js';
2
+ import { SqliteAdapter } from './sqliteAdapter.js';
3
+ export function createDatabaseAdapter(options) {
4
+ const provider = options.provider || 'sqlite';
5
+ if (provider === 'postgres') {
6
+ return new PostgresAdapter(options.postgresConnectionString);
7
+ }
8
+ return new SqliteAdapter(options.sqliteDbPath);
9
+ }
@@ -0,0 +1,22 @@
1
+ export type DatabaseProvider = 'sqlite' | 'postgres';
2
+ export interface DatabaseStatement {
3
+ run(...params: any[]): any;
4
+ get(...params: any[]): any;
5
+ all(...params: any[]): any[];
6
+ }
7
+ export interface DatabaseAdapter {
8
+ readonly provider: DatabaseProvider;
9
+ readonly open: boolean;
10
+ prepare(sql: string): DatabaseStatement;
11
+ exec(sql: string): void;
12
+ transaction<T extends (...args: any[]) => any>(fn: T): T;
13
+ pragma(name: string, options?: {
14
+ simple?: boolean;
15
+ }): unknown;
16
+ close(): void;
17
+ }
18
+ export interface DatabaseAdapterOptions {
19
+ provider?: DatabaseProvider;
20
+ sqliteDbPath: string;
21
+ postgresConnectionString?: string;
22
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { ResolvedObjectStorageConfig } from './objectStorage.js';
2
+ import type { TaskAssetStore } from './taskAssetStore.js';
3
+ export type IntegrityIssueCode = 'missing_expected_local' | 'missing_expected_r2' | 'hash_mismatch_local' | 'hash_mismatch_r2' | 'missing_local_mirror' | 'missing_r2_mirror' | 'r2_check_failed';
4
+ export interface DocumentIntegrityIssue {
5
+ path: string;
6
+ code: IntegrityIssueCode;
7
+ message: string;
8
+ expectedProvider: 'local' | 'r2';
9
+ }
10
+ export interface DocumentIntegrityScanSummary {
11
+ totalChecked: number;
12
+ totalIssues: number;
13
+ byCode: Record<string, number>;
14
+ skippedDeleted: number;
15
+ }
16
+ export interface DocumentIntegrityScanResult {
17
+ summary: DocumentIntegrityScanSummary;
18
+ issues: DocumentIntegrityIssue[];
19
+ }
20
+ export declare function scanDocumentIntegrity(params: {
21
+ basePath: string;
22
+ objectStorage: ResolvedObjectStorageConfig;
23
+ verifyHash?: boolean;
24
+ includeDeleted?: boolean;
25
+ requireMirror?: boolean;
26
+ limit?: number;
27
+ assetStore?: TaskAssetStore;
28
+ }): Promise<DocumentIntegrityScanResult>;
@@ -0,0 +1,103 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { DocumentRegistry, createDocumentHash } from './documentRegistry.js';
4
+ import { ObjectStorageClient } from './objectStorageClient.js';
5
+ function isPathInsideRoot(candidatePath, rootDir) {
6
+ const resolved = path.resolve(candidatePath);
7
+ const root = path.resolve(rootDir);
8
+ const relative = path.relative(root, resolved);
9
+ return !relative.startsWith('..') && !path.isAbsolute(relative);
10
+ }
11
+ function inc(byCode, code) {
12
+ byCode[code] = (byCode[code] || 0) + 1;
13
+ }
14
+ export async function scanDocumentIntegrity(params) {
15
+ const verifyHash = params.verifyHash === true;
16
+ const includeDeleted = params.includeDeleted === true;
17
+ const requireMirror = params.requireMirror === true;
18
+ const maxItems = Number.isFinite(params.limit) ? Math.max(1, Math.floor(Number(params.limit))) : 500;
19
+ const registry = new DocumentRegistry(params.basePath);
20
+ const entriesRaw = params.assetStore
21
+ ? params.assetStore.listAll(maxItems)
22
+ : registry
23
+ .listAll()
24
+ .sort((a, b) => a.path.localeCompare(b.path))
25
+ .slice(0, maxItems);
26
+ const issues = [];
27
+ const byCode = {};
28
+ let skippedDeleted = 0;
29
+ const r2Client = params.objectStorage.provider === 'r2'
30
+ ? new ObjectStorageClient(params.objectStorage)
31
+ : null;
32
+ const addIssue = (entry, code, message) => {
33
+ issues.push({
34
+ path: entry.path,
35
+ code,
36
+ message,
37
+ expectedProvider: entry.provider
38
+ });
39
+ inc(byCode, code);
40
+ };
41
+ for (const entry of entriesRaw) {
42
+ if (entry.deletedAt && !includeDeleted) {
43
+ skippedDeleted += 1;
44
+ continue;
45
+ }
46
+ const localPath = path.resolve(params.basePath, entry.path);
47
+ const localInRoot = isPathInsideRoot(localPath, params.basePath);
48
+ const localExists = localInRoot && fs.existsSync(localPath);
49
+ let r2Exists = false;
50
+ let r2CheckFailed = false;
51
+ if (r2Client) {
52
+ try {
53
+ r2Exists = await r2Client.objectExists(entry.path);
54
+ }
55
+ catch (error) {
56
+ r2CheckFailed = true;
57
+ addIssue(entry, 'r2_check_failed', `Failed to verify R2 object existence: ${String(error?.message || error)}`);
58
+ }
59
+ }
60
+ if (entry.provider === 'local' && !localExists) {
61
+ addIssue(entry, 'missing_expected_local', 'Registry expects a local file that does not exist on disk.');
62
+ }
63
+ if (entry.provider === 'r2' && !r2Exists && !r2CheckFailed) {
64
+ addIssue(entry, 'missing_expected_r2', 'Registry expects an R2 object that does not exist.');
65
+ }
66
+ if (requireMirror) {
67
+ if (!localExists) {
68
+ addIssue(entry, 'missing_local_mirror', 'Local mirror copy is missing.');
69
+ }
70
+ if (r2Client && !r2Exists && !r2CheckFailed) {
71
+ addIssue(entry, 'missing_r2_mirror', 'R2 mirror copy is missing.');
72
+ }
73
+ }
74
+ if (verifyHash && entry.provider === 'local' && localExists) {
75
+ const localBuffer = fs.readFileSync(localPath);
76
+ const localHash = createDocumentHash(localBuffer);
77
+ if (localHash !== entry.sha256) {
78
+ addIssue(entry, 'hash_mismatch_local', 'Registry hash does not match local file bytes.');
79
+ }
80
+ }
81
+ if (verifyHash && entry.provider === 'r2' && r2Client && r2Exists && !r2CheckFailed) {
82
+ const object = await r2Client.getObject(entry.path);
83
+ if (!object) {
84
+ addIssue(entry, 'missing_expected_r2', 'Registry expects an R2 object that does not exist.');
85
+ }
86
+ else {
87
+ const objectHash = createDocumentHash(object.body);
88
+ if (objectHash !== entry.sha256) {
89
+ addIssue(entry, 'hash_mismatch_r2', 'Registry hash does not match R2 object bytes.');
90
+ }
91
+ }
92
+ }
93
+ }
94
+ return {
95
+ summary: {
96
+ totalChecked: entriesRaw.length - skippedDeleted,
97
+ totalIssues: issues.length,
98
+ byCode,
99
+ skippedDeleted
100
+ },
101
+ issues
102
+ };
103
+ }
@@ -0,0 +1,14 @@
1
+ import type { ResolvedObjectStorageConfig } from './objectStorage.js';
2
+ import type { TaskAssetStore } from './taskAssetStore.js';
3
+ export interface DocumentPurgeSummary {
4
+ total: number;
5
+ purged: number;
6
+ failed: number;
7
+ }
8
+ export declare function purgeExpiredDocuments(params: {
9
+ basePath: string;
10
+ taskDataDir: string;
11
+ objectStorage: ResolvedObjectStorageConfig;
12
+ now?: Date;
13
+ assetStore?: TaskAssetStore;
14
+ }): Promise<DocumentPurgeSummary>;
@@ -0,0 +1,46 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { DocumentRegistry } from './documentRegistry.js';
4
+ import { ObjectStorageClient } from './objectStorageClient.js';
5
+ export async function purgeExpiredDocuments(params) {
6
+ const registry = new DocumentRegistry(params.basePath);
7
+ const candidates = params.assetStore
8
+ ? params.assetStore.listPurgeCandidates(params.now || new Date())
9
+ : registry.listPurgeCandidates(params.now || new Date());
10
+ const summary = {
11
+ total: candidates.length,
12
+ purged: 0,
13
+ failed: 0
14
+ };
15
+ const objectStorageClient = params.objectStorage.provider === 'r2'
16
+ ? new ObjectStorageClient(params.objectStorage)
17
+ : null;
18
+ for (const entry of candidates) {
19
+ try {
20
+ if (objectStorageClient) {
21
+ await objectStorageClient.deleteObject(entry.path);
22
+ }
23
+ else {
24
+ const filePath = path.resolve(params.basePath, entry.path);
25
+ const storageRoot = path.resolve(params.basePath);
26
+ const relative = path.relative(storageRoot, filePath);
27
+ const insideStorageRoot = !relative.startsWith('..') && !path.isAbsolute(relative);
28
+ if (insideStorageRoot && fs.existsSync(filePath)) {
29
+ fs.unlinkSync(filePath);
30
+ }
31
+ }
32
+ if (params.assetStore) {
33
+ const workspaceId = entry?.workspaceId ? String(entry.workspaceId) : undefined;
34
+ params.assetStore.remove(entry.path, workspaceId);
35
+ }
36
+ else {
37
+ registry.remove(entry.path);
38
+ }
39
+ summary.purged += 1;
40
+ }
41
+ catch {
42
+ summary.failed += 1;
43
+ }
44
+ }
45
+ return summary;
46
+ }
@@ -0,0 +1,39 @@
1
+ import type { ObjectStorageProvider } from './objectStorage.js';
2
+ import type { VirusScanResult } from '../security/virusScan.js';
3
+ export interface DocumentRegistryEntry {
4
+ path: string;
5
+ provider: ObjectStorageProvider;
6
+ version: number;
7
+ contentType: string;
8
+ sizeBytes: number;
9
+ sha256: string;
10
+ uploadedAt: string;
11
+ scan: VirusScanResult & {
12
+ scannedAt: string;
13
+ };
14
+ deletedAt?: string | null;
15
+ purgeAfter?: string | null;
16
+ }
17
+ export declare function createDocumentHash(buffer: Buffer): string;
18
+ export declare class DocumentRegistry {
19
+ private readonly registryFilePath;
20
+ constructor(basePath: string);
21
+ private readRegistry;
22
+ private writeRegistry;
23
+ get(pathValue: string): DocumentRegistryEntry | null;
24
+ recordUpload(input: {
25
+ path: string;
26
+ provider: ObjectStorageProvider;
27
+ contentType: string;
28
+ sizeBytes: number;
29
+ sha256: string;
30
+ uploadedAt?: string;
31
+ scan: VirusScanResult;
32
+ }): DocumentRegistryEntry;
33
+ isDeleted(pathValue: string): boolean;
34
+ markDeleted(pathValue: string, retentionDays: number): DocumentRegistryEntry | null;
35
+ clearDeleted(pathValue: string): DocumentRegistryEntry | null;
36
+ remove(pathValue: string): boolean;
37
+ listPurgeCandidates(now?: Date): DocumentRegistryEntry[];
38
+ listAll(): DocumentRegistryEntry[];
39
+ }
@@ -0,0 +1,115 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { createHash } from 'crypto';
4
+ function normalizeRegistryPath(rawPath) {
5
+ return String(rawPath || '').trim().replace(/\\/g, '/');
6
+ }
7
+ export function createDocumentHash(buffer) {
8
+ return createHash('sha256').update(buffer).digest('hex');
9
+ }
10
+ export class DocumentRegistry {
11
+ registryFilePath;
12
+ constructor(basePath) {
13
+ this.registryFilePath = path.join(basePath, 'document-registry.json');
14
+ }
15
+ readRegistry() {
16
+ if (!fs.existsSync(this.registryFilePath))
17
+ return { documents: {} };
18
+ try {
19
+ const parsed = JSON.parse(fs.readFileSync(this.registryFilePath, 'utf8'));
20
+ if (!parsed || typeof parsed !== 'object' || typeof parsed.documents !== 'object') {
21
+ return { documents: {} };
22
+ }
23
+ return parsed;
24
+ }
25
+ catch {
26
+ return { documents: {} };
27
+ }
28
+ }
29
+ writeRegistry(registry) {
30
+ fs.mkdirSync(path.dirname(this.registryFilePath), { recursive: true });
31
+ fs.writeFileSync(this.registryFilePath, `${JSON.stringify(registry, null, 2)}\n`, 'utf8');
32
+ }
33
+ get(pathValue) {
34
+ const key = normalizeRegistryPath(pathValue);
35
+ const registry = this.readRegistry();
36
+ return registry.documents[key] || null;
37
+ }
38
+ recordUpload(input) {
39
+ const key = normalizeRegistryPath(input.path);
40
+ const registry = this.readRegistry();
41
+ const existing = registry.documents[key];
42
+ const entry = {
43
+ path: key,
44
+ provider: input.provider,
45
+ version: existing ? existing.version + 1 : 1,
46
+ contentType: input.contentType,
47
+ sizeBytes: input.sizeBytes,
48
+ sha256: input.sha256,
49
+ uploadedAt: input.uploadedAt || new Date().toISOString(),
50
+ scan: {
51
+ ...input.scan,
52
+ scannedAt: new Date().toISOString()
53
+ },
54
+ deletedAt: null,
55
+ purgeAfter: null
56
+ };
57
+ registry.documents[key] = entry;
58
+ this.writeRegistry(registry);
59
+ return entry;
60
+ }
61
+ isDeleted(pathValue) {
62
+ const entry = this.get(pathValue);
63
+ return Boolean(entry?.deletedAt);
64
+ }
65
+ markDeleted(pathValue, retentionDays) {
66
+ const key = normalizeRegistryPath(pathValue);
67
+ const registry = this.readRegistry();
68
+ const entry = registry.documents[key];
69
+ if (!entry)
70
+ return null;
71
+ const now = new Date();
72
+ const safeDays = Number.isFinite(retentionDays) ? Math.max(1, Math.floor(retentionDays)) : 7;
73
+ const purgeAt = new Date(now.getTime() + safeDays * 24 * 60 * 60 * 1000);
74
+ entry.deletedAt = now.toISOString();
75
+ entry.purgeAfter = purgeAt.toISOString();
76
+ registry.documents[key] = entry;
77
+ this.writeRegistry(registry);
78
+ return entry;
79
+ }
80
+ clearDeleted(pathValue) {
81
+ const key = normalizeRegistryPath(pathValue);
82
+ const registry = this.readRegistry();
83
+ const entry = registry.documents[key];
84
+ if (!entry)
85
+ return null;
86
+ entry.deletedAt = null;
87
+ entry.purgeAfter = null;
88
+ registry.documents[key] = entry;
89
+ this.writeRegistry(registry);
90
+ return entry;
91
+ }
92
+ remove(pathValue) {
93
+ const key = normalizeRegistryPath(pathValue);
94
+ const registry = this.readRegistry();
95
+ if (!registry.documents[key])
96
+ return false;
97
+ delete registry.documents[key];
98
+ this.writeRegistry(registry);
99
+ return true;
100
+ }
101
+ listPurgeCandidates(now = new Date()) {
102
+ const registry = this.readRegistry();
103
+ const nowMs = now.getTime();
104
+ return Object.values(registry.documents).filter((entry) => {
105
+ if (!entry.deletedAt || !entry.purgeAfter)
106
+ return false;
107
+ const purgeMs = Date.parse(entry.purgeAfter);
108
+ return Number.isFinite(purgeMs) && purgeMs <= nowMs;
109
+ });
110
+ }
111
+ listAll() {
112
+ const registry = this.readRegistry();
113
+ return Object.values(registry.documents);
114
+ }
115
+ }
@@ -0,0 +1,17 @@
1
+ export type IntegrityScheduleFrequency = 'daily' | 'weekly';
2
+ export interface StorageIntegrityScheduleSettings {
3
+ enabled: boolean;
4
+ frequency: IntegrityScheduleFrequency;
5
+ dayOfWeek: number;
6
+ hourUTC: number;
7
+ minuteUTC: number;
8
+ verifyHash: boolean;
9
+ includeDeleted: boolean;
10
+ requireMirror: boolean;
11
+ limit: number;
12
+ lastRunAt?: string | null;
13
+ }
14
+ export declare const DEFAULT_STORAGE_INTEGRITY_SCHEDULE: StorageIntegrityScheduleSettings;
15
+ export declare function normalizeStorageIntegrityScheduleSettings(raw: any): StorageIntegrityScheduleSettings;
16
+ export declare function resolveStorageIntegrityScheduleSettings(globalSettings: any): StorageIntegrityScheduleSettings;
17
+ export declare function shouldRunStorageIntegritySchedule(settings: StorageIntegrityScheduleSettings, now: Date): boolean;
@@ -0,0 +1,62 @@
1
+ export const DEFAULT_STORAGE_INTEGRITY_SCHEDULE = {
2
+ enabled: false,
3
+ frequency: 'daily',
4
+ dayOfWeek: 0,
5
+ hourUTC: 3,
6
+ minuteUTC: 0,
7
+ verifyHash: false,
8
+ includeDeleted: false,
9
+ requireMirror: false,
10
+ limit: 500,
11
+ lastRunAt: null
12
+ };
13
+ export function normalizeStorageIntegrityScheduleSettings(raw) {
14
+ const frequency = raw?.frequency === 'weekly' ? 'weekly' : 'daily';
15
+ const dayOfWeekRaw = Number(raw?.dayOfWeek);
16
+ const hourRaw = Number(raw?.hourUTC);
17
+ const minuteRaw = Number(raw?.minuteUTC);
18
+ const limitRaw = Number(raw?.limit);
19
+ const lastRunAtRaw = typeof raw?.lastRunAt === 'string' ? raw.lastRunAt : null;
20
+ return {
21
+ enabled: raw?.enabled === true,
22
+ frequency,
23
+ dayOfWeek: Number.isFinite(dayOfWeekRaw) ? Math.max(0, Math.min(6, Math.floor(dayOfWeekRaw))) : 0,
24
+ hourUTC: Number.isFinite(hourRaw) ? Math.max(0, Math.min(23, Math.floor(hourRaw))) : 3,
25
+ minuteUTC: Number.isFinite(minuteRaw) ? Math.max(0, Math.min(59, Math.floor(minuteRaw))) : 0,
26
+ verifyHash: raw?.verifyHash === true,
27
+ includeDeleted: raw?.includeDeleted === true,
28
+ requireMirror: raw?.requireMirror === true,
29
+ limit: Number.isFinite(limitRaw) ? Math.max(1, Math.floor(limitRaw)) : 500,
30
+ lastRunAt: lastRunAtRaw
31
+ };
32
+ }
33
+ export function resolveStorageIntegrityScheduleSettings(globalSettings) {
34
+ const raw = globalSettings?.storageIntegritySchedule || {};
35
+ return normalizeStorageIntegrityScheduleSettings({
36
+ ...DEFAULT_STORAGE_INTEGRITY_SCHEDULE,
37
+ ...raw
38
+ });
39
+ }
40
+ export function shouldRunStorageIntegritySchedule(settings, now) {
41
+ if (!settings.enabled)
42
+ return false;
43
+ if (now.getUTCHours() !== settings.hourUTC || now.getUTCMinutes() !== settings.minuteUTC)
44
+ return false;
45
+ if (settings.frequency === 'weekly' && now.getUTCDay() !== settings.dayOfWeek)
46
+ return false;
47
+ const lastRunAt = settings.lastRunAt ? Date.parse(settings.lastRunAt) : NaN;
48
+ if (!Number.isFinite(lastRunAt))
49
+ return true;
50
+ const last = new Date(lastRunAt);
51
+ const sameDay = last.getUTCFullYear() === now.getUTCFullYear()
52
+ && last.getUTCMonth() === now.getUTCMonth()
53
+ && last.getUTCDate() === now.getUTCDate();
54
+ if (sameDay)
55
+ return false;
56
+ if (settings.frequency === 'weekly') {
57
+ const daysSince = Math.floor((Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()) - Date.UTC(last.getUTCFullYear(), last.getUTCMonth(), last.getUTCDate())) / (24 * 60 * 60 * 1000));
58
+ if (daysSince < 7)
59
+ return false;
60
+ }
61
+ return true;
62
+ }
@@ -0,0 +1,20 @@
1
+ export type ObjectStorageProvider = 'local' | 'r2';
2
+ export interface R2ObjectStorageConfig {
3
+ accountId: string;
4
+ bucket: string;
5
+ endpoint: string;
6
+ accessKeyId: string;
7
+ secretAccessKey: string;
8
+ keyPrefix: string;
9
+ signedUploadTtlSeconds: number;
10
+ signedDownloadTtlSeconds: number;
11
+ }
12
+ export interface ResolvedObjectStorageConfig {
13
+ provider: ObjectStorageProvider;
14
+ r2?: R2ObjectStorageConfig;
15
+ }
16
+ export interface PublicObjectStorageConfig {
17
+ provider: ObjectStorageProvider;
18
+ r2?: Omit<R2ObjectStorageConfig, 'accessKeyId' | 'secretAccessKey' | 'accountId'>;
19
+ }
20
+ export declare function toPublicObjectStorageConfig(config: ResolvedObjectStorageConfig): PublicObjectStorageConfig;