@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.
- package/README.md +241 -0
- package/dist/Taskforce.d.ts +3 -0
- package/dist/Taskforce.js +3 -0
- package/dist/Taskforce.module.css +7587 -0
- package/dist/TaskforceCore.CategoryFallback.test.d.ts +1 -0
- package/dist/TaskforceCore.CategoryFallback.test.js +98 -0
- package/dist/TaskforceCore.d.ts +12 -0
- package/dist/TaskforceCore.js +729 -0
- package/dist/TaskforceCore.test.d.ts +1 -0
- package/dist/TaskforceCore.test.js +2132 -0
- package/dist/TaskforceScreenshot.d.ts +11 -0
- package/dist/TaskforceScreenshot.js +113 -0
- package/dist/TaskforceWidget.d.ts +6 -0
- package/dist/TaskforceWidget.js +101 -0
- package/dist/TaskforceWidget.test.d.ts +1 -0
- package/dist/TaskforceWidget.test.js +92 -0
- package/dist/UnsavedChangesRelaxed.test.d.ts +1 -0
- package/dist/UnsavedChangesRelaxed.test.js +16 -0
- package/dist/__tests__/localizationCatalogs.test.d.ts +1 -0
- package/dist/__tests__/localizationCatalogs.test.js +37 -0
- package/dist/__tests__/planParser.test.d.ts +1 -0
- package/dist/__tests__/planParser.test.js +183 -0
- package/dist/__tests__/releaseVersion.test.d.ts +1 -0
- package/dist/__tests__/releaseVersion.test.js +32 -0
- package/dist/__tests__/structuredCommentValidation.test.d.ts +1 -0
- package/dist/__tests__/structuredCommentValidation.test.js +31 -0
- package/dist/__tests__/structuredDocValidation.test.d.ts +1 -0
- package/dist/__tests__/structuredDocValidation.test.js +30 -0
- package/dist/__tests__/templateEngine.test.d.ts +1 -0
- package/dist/__tests__/templateEngine.test.js +150 -0
- package/dist/__tests__/templates.test.d.ts +1 -0
- package/dist/__tests__/templates.test.js +45 -0
- package/dist/__tests__/workflowDocumentFixtures.test.d.ts +1 -0
- package/dist/__tests__/workflowDocumentFixtures.test.js +78 -0
- package/dist/__tests__/workflowExportMatrix.test.d.ts +1 -0
- package/dist/__tests__/workflowExportMatrix.test.js +113 -0
- package/dist/__tests__/workflowExportSnapshots.test.d.ts +1 -0
- package/dist/__tests__/workflowExportSnapshots.test.js +28 -0
- package/dist/__tests__/workflowGeneration.test.d.ts +1 -0
- package/dist/__tests__/workflowGeneration.test.js +12 -0
- package/dist/__tests__/workflowSimulation.test.d.ts +1 -0
- package/dist/__tests__/workflowSimulation.test.js +113 -0
- package/dist/__tests__/workflowV2Policy.test.d.ts +1 -0
- package/dist/__tests__/workflowV2Policy.test.js +80 -0
- package/dist/api.d.ts +30 -0
- package/dist/api.js +85 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +217 -0
- package/dist/compat/priorityCompat.d.ts +2 -0
- package/dist/compat/priorityCompat.js +24 -0
- package/dist/components/features/DocumentGenerateModal.d.ts +9 -0
- package/dist/components/features/DocumentGenerateModal.js +114 -0
- package/dist/components/features/DocumentIndex.d.ts +19 -0
- package/dist/components/features/DocumentIndex.js +51 -0
- package/dist/components/features/DocumentViewer.d.ts +9 -0
- package/dist/components/features/DocumentViewer.js +253 -0
- package/dist/components/features/DocumentWorkspace.d.ts +21 -0
- package/dist/components/features/DocumentWorkspace.js +88 -0
- package/dist/components/features/TaskSettings.d.ts +209 -0
- package/dist/components/features/TaskSettings.js +500 -0
- package/dist/components/features/TaskSettings.test.d.ts +1 -0
- package/dist/components/features/TaskSettings.test.js +308 -0
- package/dist/components/features/settings/CategoryManager.d.ts +19 -0
- package/dist/components/features/settings/CategoryManager.js +113 -0
- package/dist/components/features/settings/TaxonomyEditor.d.ts +8 -0
- package/dist/components/features/settings/TaxonomyEditor.js +98 -0
- package/dist/components/features/settings/TaxonomyManager 2.d.ts +52 -0
- package/dist/components/features/settings/TaxonomyManager 2.js +75 -0
- package/dist/components/features/settings/TaxonomyManager.d.ts +54 -0
- package/dist/components/features/settings/TaxonomyManager.js +77 -0
- package/dist/components/features/settings/TypeManager.d.ts +10 -0
- package/dist/components/features/settings/TypeManager.js +50 -0
- package/dist/components/features/settings/WorkflowEditorPrototype.d.ts +15 -0
- package/dist/components/features/settings/WorkflowEditorPrototype.js +245 -0
- package/dist/components/task/TaskActionHeader.d.ts +20 -0
- package/dist/components/task/TaskActionHeader.js +13 -0
- package/dist/components/task/TaskCard.d.ts +47 -0
- package/dist/components/task/TaskCard.js +326 -0
- package/dist/components/task/TaskCard.test.d.ts +1 -0
- package/dist/components/task/TaskCard.test.js +95 -0
- package/dist/components/task/TaskContextUpload.d.ts +12 -0
- package/dist/components/task/TaskContextUpload.js +393 -0
- package/dist/components/task/TaskContextUpload.test.d.ts +1 -0
- package/dist/components/task/TaskContextUpload.test.js +189 -0
- package/dist/components/task/TaskForm.d.ts +105 -0
- package/dist/components/task/TaskForm.js +241 -0
- package/dist/components/task/TaskForm.test.d.ts +1 -0
- package/dist/components/task/TaskForm.test.js +288 -0
- package/dist/components/task/TaskKanban 2.d.ts +76 -0
- package/dist/components/task/TaskKanban 2.js +1004 -0
- package/dist/components/task/TaskKanban.d.ts +76 -0
- package/dist/components/task/TaskKanban.empty-column-drop.test.d.ts +1 -0
- package/dist/components/task/TaskKanban.empty-column-drop.test.js +66 -0
- package/dist/components/task/TaskKanban.js +1026 -0
- package/dist/components/task/TaskKanban.test.d.ts +1 -0
- package/dist/components/task/TaskKanban.test.js +46 -0
- package/dist/components/task/TaskList.d.ts +74 -0
- package/dist/components/task/TaskList.js +38 -0
- package/dist/components/task/TaskList.test.d.ts +1 -0
- package/dist/components/task/TaskList.test.js +270 -0
- package/dist/components/task/TaskScreenshotSection.d.ts +15 -0
- package/dist/components/task/TaskScreenshotSection.js +22 -0
- package/dist/components/ui/LevelSelector.d.ts +13 -0
- package/dist/components/ui/LevelSelector.js +25 -0
- package/dist/components/ui/LevelSelector.test.d.ts +1 -0
- package/dist/components/ui/LevelSelector.test.js +55 -0
- package/dist/components/ui/Markdown.d.ts +6 -0
- package/dist/components/ui/Markdown.js +94 -0
- package/dist/components/ui/Markdown.test.d.ts +1 -0
- package/dist/components/ui/Markdown.test.js +38 -0
- package/dist/components/ui/Modal.d.ts +16 -0
- package/dist/components/ui/Modal.js +49 -0
- package/dist/components/ui/MultiSelectFilter.d.ts +10 -0
- package/dist/components/ui/MultiSelectFilter.js +71 -0
- package/dist/components/ui/MultiSelectFilter.test.d.ts +1 -0
- package/dist/components/ui/MultiSelectFilter.test.js +74 -0
- package/dist/components/ui/TaxonomyDropdown.d.ts +17 -0
- package/dist/components/ui/TaxonomyDropdown.js +145 -0
- package/dist/components/ui/TaxonomyDropdown.test.d.ts +1 -0
- package/dist/components/ui/TaxonomyDropdown.test.js +130 -0
- package/dist/components/views/StandaloneLayout 2.d.ts +8 -0
- package/dist/components/views/StandaloneLayout 2.js +1660 -0
- package/dist/components/views/StandaloneLayout.d.ts +8 -0
- package/dist/components/views/StandaloneLayout.js +2117 -0
- package/dist/components/views/WidgetView.d.ts +8 -0
- package/dist/components/views/WidgetView.js +221 -0
- package/dist/config/envSchema.d.ts +28 -0
- package/dist/config/envSchema.js +374 -0
- package/dist/config/envSchema.test.d.ts +1 -0
- package/dist/config/envSchema.test.js +97 -0
- package/dist/config/surfaceBase.d.ts +2 -0
- package/dist/config/surfaceBase.js +8 -0
- package/dist/core/BulkUpdateFieldsPreview.test.d.ts +1 -0
- package/dist/core/BulkUpdateFieldsPreview.test.js +62 -0
- package/dist/core/CompletedAt.test.d.ts +1 -0
- package/dist/core/CompletedAt.test.js +44 -0
- package/dist/core/CreatedBy.test.d.ts +1 -0
- package/dist/core/CreatedBy.test.js +60 -0
- package/dist/core/EntitlementsPolicy.test.d.ts +1 -0
- package/dist/core/EntitlementsPolicy.test.js +145 -0
- package/dist/core/InitiativeTemplates.test.d.ts +1 -0
- package/dist/core/InitiativeTemplates.test.js +50 -0
- package/dist/core/ParentLifecycle.test.d.ts +1 -0
- package/dist/core/ParentLifecycle.test.js +98 -0
- package/dist/core/ScheduleFields.test.d.ts +1 -0
- package/dist/core/ScheduleFields.test.js +197 -0
- package/dist/core/SetupState.test.d.ts +1 -0
- package/dist/core/SetupState.test.js +113 -0
- package/dist/core/SystemAdmin.test.d.ts +1 -0
- package/dist/core/SystemAdmin.test.js +295 -0
- package/dist/core/TaskTaxonomyValidation.test.d.ts +1 -0
- package/dist/core/TaskTaxonomyValidation.test.js +64 -0
- package/dist/core/Taskforce.d.ts +1063 -0
- package/dist/core/Taskforce.ids.test.d.ts +1 -0
- package/dist/core/Taskforce.ids.test.js +168 -0
- package/dist/core/Taskforce.js +5981 -0
- package/dist/core/Taskforce.realtimeMutation.test.d.ts +1 -0
- package/dist/core/Taskforce.realtimeMutation.test.js +76 -0
- package/dist/core/WorkspaceDelete.test.d.ts +1 -0
- package/dist/core/WorkspaceDelete.test.js +140 -0
- package/dist/core/WorkspacePermissions.test.d.ts +1 -0
- package/dist/core/WorkspacePermissions.test.js +151 -0
- package/dist/core/WorkspacePlanMode.test.d.ts +1 -0
- package/dist/core/WorkspacePlanMode.test.js +104 -0
- package/dist/hooks/authGuardPolicy.d.ts +26 -0
- package/dist/hooks/authGuardPolicy.js +32 -0
- package/dist/hooks/authGuardPolicy.test.d.ts +1 -0
- package/dist/hooks/authGuardPolicy.test.js +76 -0
- package/dist/hooks/useDraggable.d.ts +12 -0
- package/dist/hooks/useDraggable.js +65 -0
- package/dist/hooks/useRealtimeSync.d.ts +24 -0
- package/dist/hooks/useRealtimeSync.js +275 -0
- package/dist/hooks/useRealtimeSync.test.d.ts +1 -0
- package/dist/hooks/useRealtimeSync.test.js +284 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +164 -0
- package/dist/hooks/useSyncOrchestrator.js +1427 -0
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.d.ts +1 -0
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +367 -0
- package/dist/hooks/useTaskforce.d.ts +727 -0
- package/dist/hooks/useTaskforce.js +4396 -0
- package/dist/hooks/useTaskforce.priority-filters.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.priority-filters.test.js +33 -0
- package/dist/hooks/useWorkspaceSyncController.d.ts +80 -0
- package/dist/hooks/useWorkspaceSyncController.js +598 -0
- package/dist/hooks/useWorkspaceSyncController.test.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.test.js +236 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +11 -0
- package/dist/localization/index.d.ts +8 -0
- package/dist/localization/index.js +81 -0
- package/dist/localization/locales/en-US.d.ts +151 -0
- package/dist/localization/locales/en-US.js +150 -0
- package/dist/localization/locales/es-419.d.ts +2 -0
- package/dist/localization/locales/es-419.js +150 -0
- package/dist/localization/locales/pt-BR.d.ts +2 -0
- package/dist/localization/locales/pt-BR.js +150 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +33 -0
- package/dist/mcp/optionResolution.d.ts +14 -0
- package/dist/mcp/optionResolution.js +126 -0
- package/dist/mcp/optionResolution.test.d.ts +1 -0
- package/dist/mcp/optionResolution.test.js +39 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +1793 -0
- package/dist/mcp/structuredCommentValidation.d.ts +6 -0
- package/dist/mcp/structuredCommentValidation.js +56 -0
- package/dist/mcp/structuredDocValidation.d.ts +6 -0
- package/dist/mcp/structuredDocValidation.js +75 -0
- package/dist/migrations/billingSchemaParity.test.d.ts +1 -0
- package/dist/migrations/billingSchemaParity.test.js +46 -0
- package/dist/migrations/clientMigrations.d.ts +9 -0
- package/dist/migrations/clientMigrations.js +74 -0
- package/dist/migrations/flags.d.ts +6 -0
- package/dist/migrations/flags.js +8 -0
- package/dist/migrations/taskMigrations.d.ts +71 -0
- package/dist/migrations/taskMigrations.js +236 -0
- package/dist/migrations/taskMigrations.test.d.ts +1 -0
- package/dist/migrations/taskMigrations.test.js +34 -0
- package/dist/migrations/taskSchemaMigrations.d.ts +11 -0
- package/dist/migrations/taskSchemaMigrations.js +453 -0
- package/dist/plugins/index.d.ts +10 -0
- package/dist/plugins/index.js +10 -0
- package/dist/plugins/vite.d.ts +19 -0
- package/dist/plugins/vite.js +271 -0
- package/dist/public/android-chrome-192x192.png +0 -0
- package/dist/public/android-chrome-512x512.png +0 -0
- package/dist/public/apple-touch-icon.png +0 -0
- package/dist/public/favicon-16x16.png +0 -0
- package/dist/public/favicon-32x32.png +0 -0
- package/dist/public/favicon.ico +0 -0
- package/dist/public/favicon.png +0 -0
- package/dist/public/site.webmanifest +1 -0
- package/dist/public/taskforce.png +0 -0
- package/dist/resources/templates/WORKFLOW_V2_POLICY.md +55 -0
- package/dist/resources/templates/environments/aider.yaml +14 -0
- package/dist/resources/templates/environments/antigravity.yaml +10 -0
- package/dist/resources/templates/environments/claude.yaml +10 -0
- package/dist/resources/templates/environments/cline.yaml +10 -0
- package/dist/resources/templates/environments/codex.yaml +13 -0
- package/dist/resources/templates/environments/copilot.yaml +10 -0
- package/dist/resources/templates/environments/cursor.yaml +9 -0
- package/dist/resources/templates/environments/gemini.yaml +9 -0
- package/dist/resources/templates/environments/windsurf.yaml +10 -0
- package/dist/resources/templates/workflow-sources/README.md +9 -0
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +520 -0
- package/dist/resources/templates/workflow-sources/workflowEditorOverrides.json +1 -0
- package/dist/resources/templates/workflows/collaborate.yaml +104 -0
- package/dist/resources/templates/workflows/do.yaml +82 -0
- package/dist/resources/templates/workflows/evaluate.yaml +111 -0
- package/dist/resources/templates/workflows/execute.yaml +142 -0
- package/dist/resources/templates/workflows/plan.yaml +112 -0
- package/dist/resources/templates/workflows/review.yaml +109 -0
- package/dist/runtime/capabilities.d.ts +8 -0
- package/dist/runtime/capabilities.js +16 -0
- package/dist/security/virusScan.d.ts +16 -0
- package/dist/security/virusScan.js +83 -0
- package/dist/server/auth.d.ts +51 -0
- package/dist/server/auth.js +266 -0
- package/dist/server/auth.test.d.ts +1 -0
- package/dist/server/auth.test.js +111 -0
- package/dist/server/buildInfo.d.ts +7 -0
- package/dist/server/buildInfo.js +100 -0
- package/dist/server/buildInfo.test.d.ts +1 -0
- package/dist/server/buildInfo.test.js +29 -0
- package/dist/server/cors.d.ts +7 -0
- package/dist/server/cors.js +76 -0
- package/dist/server/cors.test.d.ts +1 -0
- package/dist/server/cors.test.js +71 -0
- package/dist/server/email.d.ts +28 -0
- package/dist/server/email.js +138 -0
- package/dist/server/email.test.d.ts +1 -0
- package/dist/server/email.test.js +113 -0
- package/dist/server/index.cookieProxy.test.d.ts +1 -0
- package/dist/server/index.cookieProxy.test.js +19 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.js +757 -0
- package/dist/server/index.rateLimit.test.d.ts +1 -0
- package/dist/server/index.rateLimit.test.js +13 -0
- package/dist/server/index.test.d.ts +1 -0
- package/dist/server/index.test.js +19 -0
- package/dist/server/rateLimit.d.ts +29 -0
- package/dist/server/rateLimit.js +99 -0
- package/dist/server/rateLimit.test.d.ts +1 -0
- package/dist/server/rateLimit.test.js +107 -0
- package/dist/server/realtimeSync.auth.test.d.ts +1 -0
- package/dist/server/realtimeSync.auth.test.js +62 -0
- package/dist/server/realtimeSync.replay.test.d.ts +1 -0
- package/dist/server/realtimeSync.replay.test.js +192 -0
- package/dist/server/realtimeSync.workspaceIsolation.test.d.ts +1 -0
- package/dist/server/realtimeSync.workspaceIsolation.test.js +101 -0
- package/dist/server/realtimeSyncWs.d.ts +30 -0
- package/dist/server/realtimeSyncWs.js +257 -0
- package/dist/server/routes.billing.d.ts +15 -0
- package/dist/server/routes.billing.js +991 -0
- package/dist/server/routes.billing.test.d.ts +1 -0
- package/dist/server/routes.billing.test.js +387 -0
- package/dist/server/routes.d.ts +72 -0
- package/dist/server/routes.js +4820 -0
- package/dist/server/routes.sync.d.ts +17 -0
- package/dist/server/routes.sync.integration.test.d.ts +1 -0
- package/dist/server/routes.sync.integration.test.js +470 -0
- package/dist/server/routes.sync.js +1141 -0
- package/dist/server/routes.test.d.ts +1 -0
- package/dist/server/routes.test.js +4945 -0
- package/dist/server/runtimeMode.d.ts +4 -0
- package/dist/server/runtimeMode.js +25 -0
- package/dist/server/runtimeMode.test.d.ts +1 -0
- package/dist/server/runtimeMode.test.js +26 -0
- package/dist/server/securityHeaders.d.ts +3 -0
- package/dist/server/securityHeaders.js +25 -0
- package/dist/server/securityHeaders.test.d.ts +1 -0
- package/dist/server/securityHeaders.test.js +32 -0
- package/dist/server/smtpTransport.d.ts +21 -0
- package/dist/server/smtpTransport.js +11 -0
- package/dist/server/start.d.ts +1 -0
- package/dist/server/start.js +17 -0
- package/dist/services/formatTransformers.d.ts +29 -0
- package/dist/services/formatTransformers.js +56 -0
- package/dist/services/templateEngine.d.ts +46 -0
- package/dist/services/templateEngine.js +148 -0
- package/dist/shared/runtimeContract.d.ts +12 -0
- package/dist/shared/runtimeContract.js +23 -0
- package/dist/shared/runtimeContract.test.d.ts +1 -0
- package/dist/shared/runtimeContract.test.js +23 -0
- package/dist/soak/preflight.cli.d.ts +1 -0
- package/dist/soak/preflight.cli.js +28 -0
- package/dist/soak/preflight.d.ts +26 -0
- package/dist/soak/preflight.js +113 -0
- package/dist/soak/preflight.test.d.ts +1 -0
- package/dist/soak/preflight.test.js +39 -0
- package/dist/soak/syncSoakHarness.d.ts +6 -0
- package/dist/soak/syncSoakHarness.js +10 -0
- package/dist/storage/createDatabaseAdapter.d.ts +2 -0
- package/dist/storage/createDatabaseAdapter.js +9 -0
- package/dist/storage/databaseAdapter.d.ts +22 -0
- package/dist/storage/databaseAdapter.js +1 -0
- package/dist/storage/documentIntegrity.d.ts +28 -0
- package/dist/storage/documentIntegrity.js +103 -0
- package/dist/storage/documentPurge.d.ts +14 -0
- package/dist/storage/documentPurge.js +46 -0
- package/dist/storage/documentRegistry.d.ts +39 -0
- package/dist/storage/documentRegistry.js +115 -0
- package/dist/storage/integritySchedule.d.ts +17 -0
- package/dist/storage/integritySchedule.js +62 -0
- package/dist/storage/objectStorage.d.ts +20 -0
- package/dist/storage/objectStorage.js +15 -0
- package/dist/storage/objectStorageClient.d.ts +18 -0
- package/dist/storage/objectStorageClient.js +301 -0
- package/dist/storage/objectStorageConfig.d.ts +2 -0
- package/dist/storage/objectStorageConfig.js +45 -0
- package/dist/storage/postgresAdapter.d.ts +20 -0
- package/dist/storage/postgresAdapter.js +204 -0
- package/dist/storage/postgresWorker.d.ts +1 -0
- package/dist/storage/postgresWorker.js +110 -0
- package/dist/storage/providerConfig.d.ts +6 -0
- package/dist/storage/providerConfig.js +11 -0
- package/dist/storage/sqliteAdapter.d.ts +14 -0
- package/dist/storage/sqliteAdapter.js +28 -0
- package/dist/storage/taskAssetStore.d.ts +56 -0
- package/dist/storage/taskAssetStore.js +297 -0
- package/dist/sync/cloudSyncApi.d.ts +47 -0
- package/dist/sync/cloudSyncApi.js +138 -0
- package/dist/sync/cloudSyncApi.test.d.ts +1 -0
- package/dist/sync/cloudSyncApi.test.js +54 -0
- package/dist/sync/encryptionService.d.ts +11 -0
- package/dist/sync/encryptionService.js +61 -0
- package/dist/sync/encryptionService.test.d.ts +1 -0
- package/dist/sync/encryptionService.test.js +52 -0
- package/dist/sync/realtimeFeature.d.ts +6 -0
- package/dist/sync/realtimeFeature.js +20 -0
- package/dist/sync/realtimeFeature.test.d.ts +1 -0
- package/dist/sync/realtimeFeature.test.js +30 -0
- package/dist/sync/realtimeReconcile.d.ts +30 -0
- package/dist/sync/realtimeReconcile.js +90 -0
- package/dist/sync/realtimeReconcile.test.d.ts +1 -0
- package/dist/sync/realtimeReconcile.test.js +43 -0
- package/dist/sync/syncService.d.ts +96 -0
- package/dist/sync/syncService.js +423 -0
- package/dist/sync/syncService.test.d.ts +1 -0
- package/dist/sync/syncService.test.js +484 -0
- package/dist/sync/workspaceSyncModel.d.ts +61 -0
- package/dist/sync/workspaceSyncModel.js +136 -0
- package/dist/sync/workspaceSyncModel.test.d.ts +1 -0
- package/dist/sync/workspaceSyncModel.test.js +73 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.js +15 -0
- package/dist/types.d.ts +157 -0
- package/dist/types.js +41 -0
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/index-0W5vyCpn.css +1 -0
- package/dist/ui/assets/index-MCZuNNfn.js +23 -0
- package/dist/ui/assets/logo_white_01-0Vx-iIIv.png +0 -0
- package/dist/ui/assets/taskforce-BxLPokNB.png +0 -0
- package/dist/ui/assets/vendor-dnd-BI1K77C1.js +5 -0
- package/dist/ui/assets/vendor-icons-ZFG3SGwo.js +1 -0
- package/dist/ui/assets/vendor-markdown-CKYkQHfj.js +29 -0
- package/dist/ui/assets/vendor-react-DdIDsh7f.js +9 -0
- package/dist/ui/assets/vendor-router-BtiNU7Dl.js +3 -0
- package/dist/ui/branding/logos/logo_black_01.png +0 -0
- package/dist/ui/branding/logos/logo_black_02.png +0 -0
- package/dist/ui/branding/logos/logo_white_01.png +0 -0
- package/dist/ui/branding/logos/logo_white_02.png +0 -0
- package/dist/ui/favicon/android-chrome-192x192.png +0 -0
- package/dist/ui/favicon/android-chrome-512x512.png +0 -0
- package/dist/ui/favicon/apple-touch-icon.png +0 -0
- package/dist/ui/favicon/favicon-16x16.png +0 -0
- package/dist/ui/favicon/favicon-32x32.png +0 -0
- package/dist/ui/favicon/favicon.ico +0 -0
- package/dist/ui/favicon/favicon.png +0 -0
- package/dist/ui/favicon/site.webmanifest +1 -0
- package/dist/ui/fonts/RussoOne-Regular.ttf +0 -0
- package/dist/ui/images/taskforce.png +0 -0
- package/dist/ui/index.html +19 -0
- package/dist/utils/checklistMarkdown.d.ts +9 -0
- package/dist/utils/checklistMarkdown.js +46 -0
- package/dist/utils/constants.d.ts +21 -0
- package/dist/utils/constants.icons.test.d.ts +1 -0
- package/dist/utils/constants.icons.test.js +40 -0
- package/dist/utils/constants.js +100 -0
- package/dist/utils/contextFiles.d.ts +8 -0
- package/dist/utils/contextFiles.js +54 -0
- package/dist/utils/formatting.d.ts +5 -0
- package/dist/utils/formatting.js +30 -0
- package/dist/utils/planParser.d.ts +22 -0
- package/dist/utils/planParser.js +151 -0
- package/dist/utils/taskDragZones.d.ts +8 -0
- package/dist/utils/taskDragZones.js +14 -0
- package/dist/utils/taskDragZones.test.d.ts +1 -0
- package/dist/utils/taskDragZones.test.js +14 -0
- package/dist/utils/taskHierarchy.d.ts +4 -0
- package/dist/utils/taskHierarchy.js +69 -0
- package/dist/utils/taskHierarchy.test.d.ts +1 -0
- package/dist/utils/taskHierarchy.test.js +38 -0
- package/dist/utils/taskParenting.d.ts +3 -0
- package/dist/utils/taskParenting.js +24 -0
- package/dist/utils/taskParenting.test.d.ts +1 -0
- package/dist/utils/taskParenting.test.js +21 -0
- package/dist/utils/taskRelations.d.ts +6 -0
- package/dist/utils/taskRelations.js +24 -0
- package/dist/utils/taskRelations.test.d.ts +1 -0
- package/dist/utils/taskRelations.test.js +34 -0
- package/dist/utils/taskUtils.d.ts +2 -0
- package/dist/utils/taskUtils.js +20 -0
- package/dist/utils/taskforceApiClient.d.ts +7 -0
- package/dist/utils/taskforceApiClient.js +42 -0
- package/dist/utils/workspaceIdentity.d.ts +8 -0
- package/dist/utils/workspaceIdentity.js +47 -0
- package/dist/utils/workspaceIdentity.test.d.ts +1 -0
- package/dist/utils/workspaceIdentity.test.js +32 -0
- package/dist/utils/workspaceLifecycle.d.ts +26 -0
- package/dist/utils/workspaceLifecycle.js +69 -0
- package/dist/utils/workspaceLifecycle.test.d.ts +1 -0
- package/dist/utils/workspaceLifecycle.test.js +64 -0
- package/package.json +133 -0
- package/scripts/check-compat-boundaries.js +48 -0
- package/scripts/check-env.ts +24 -0
- package/scripts/check-localization-strings.mjs +49 -0
- package/scripts/check-runtime-boundaries.mjs +44 -0
- package/scripts/debug-global.mjs +34 -0
- package/scripts/debug-server.mjs +36 -0
- package/scripts/export-sqlite-to-postgres.mjs +125 -0
- package/scripts/generate-env-example.ts +8 -0
- package/scripts/generate-workflow-templates.mjs +134 -0
- package/scripts/mcp-stdio-adapter.mjs +160 -0
- package/scripts/postinstall.js +60 -0
- package/scripts/release-version-lib.mjs +88 -0
- package/scripts/release-version.mjs +72 -0
- package/scripts/run-dev-proxy.sh +49 -0
- package/scripts/run-e2e-realtime.sh +16 -0
- package/scripts/run-smoke.sh +23 -0
- package/scripts/run-soak.sh +29 -0
- package/scripts/test-global.js +143 -0
- package/scripts/update-homebrew-formula.sh +38 -0
- package/src/resources/templates/WORKFLOW_V2_POLICY.md +55 -0
- package/src/resources/templates/environments/aider.yaml +14 -0
- package/src/resources/templates/environments/antigravity.yaml +10 -0
- package/src/resources/templates/environments/claude.yaml +10 -0
- package/src/resources/templates/environments/cline.yaml +10 -0
- package/src/resources/templates/environments/codex.yaml +13 -0
- package/src/resources/templates/environments/copilot.yaml +10 -0
- package/src/resources/templates/environments/cursor.yaml +9 -0
- package/src/resources/templates/environments/gemini.yaml +9 -0
- package/src/resources/templates/environments/windsurf.yaml +10 -0
- package/src/resources/templates/workflow-sources/README.md +9 -0
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +520 -0
- package/src/resources/templates/workflow-sources/workflowEditorOverrides.json +1 -0
- package/src/resources/templates/workflows/collaborate.yaml +104 -0
- package/src/resources/templates/workflows/do.yaml +82 -0
- package/src/resources/templates/workflows/evaluate.yaml +111 -0
- package/src/resources/templates/workflows/execute.yaml +142 -0
- package/src/resources/templates/workflows/plan.yaml +112 -0
- package/src/resources/templates/workflows/review.yaml +109 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function toPublicObjectStorageConfig(config) {
|
|
2
|
+
if (config.provider !== 'r2' || !config.r2) {
|
|
3
|
+
return { provider: config.provider };
|
|
4
|
+
}
|
|
5
|
+
return {
|
|
6
|
+
provider: 'r2',
|
|
7
|
+
r2: {
|
|
8
|
+
bucket: config.r2.bucket,
|
|
9
|
+
endpoint: config.r2.endpoint,
|
|
10
|
+
keyPrefix: config.r2.keyPrefix,
|
|
11
|
+
signedUploadTtlSeconds: config.r2.signedUploadTtlSeconds,
|
|
12
|
+
signedDownloadTtlSeconds: config.r2.signedDownloadTtlSeconds
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ResolvedObjectStorageConfig } from './objectStorage.js';
|
|
2
|
+
export interface StoredObject {
|
|
3
|
+
body: Buffer;
|
|
4
|
+
contentType: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class ObjectStorageClient {
|
|
7
|
+
private readonly config;
|
|
8
|
+
constructor(config: ResolvedObjectStorageConfig);
|
|
9
|
+
provider(): 'local' | 'r2';
|
|
10
|
+
keyForRelativePath(relativePath: string): string;
|
|
11
|
+
putObject(relativePath: string, body: Buffer, contentType: string): Promise<void>;
|
|
12
|
+
getObject(relativePath: string): Promise<StoredObject | null>;
|
|
13
|
+
objectExists(relativePath: string): Promise<boolean>;
|
|
14
|
+
deleteObject(relativePath: string): Promise<boolean>;
|
|
15
|
+
createSignedGetUrl(relativePath: string, expiresInSeconds: number): string;
|
|
16
|
+
createSignedPutUrl(relativePath: string, expiresInSeconds: number): string;
|
|
17
|
+
}
|
|
18
|
+
export declare function normalizeTaskDataRelativePath(rawPath: string): string | null;
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
import { createHash, createHmac } from 'crypto';
|
|
2
|
+
const AWS_ALGORITHM = 'AWS4-HMAC-SHA256';
|
|
3
|
+
const AWS_SERVICE = 's3';
|
|
4
|
+
const AWS_REGION = 'auto';
|
|
5
|
+
function sha256Hex(value) {
|
|
6
|
+
return createHash('sha256').update(value).digest('hex');
|
|
7
|
+
}
|
|
8
|
+
function hmac(key, value) {
|
|
9
|
+
return createHmac('sha256', key).update(value, 'utf8').digest();
|
|
10
|
+
}
|
|
11
|
+
function encodeRfc3986(value) {
|
|
12
|
+
return encodeURIComponent(value).replace(/[!*'()]/g, (ch) => `%${ch.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
13
|
+
}
|
|
14
|
+
function encodeUriPath(pathname) {
|
|
15
|
+
return pathname
|
|
16
|
+
.split('/')
|
|
17
|
+
.map((segment) => encodeRfc3986(segment))
|
|
18
|
+
.join('/');
|
|
19
|
+
}
|
|
20
|
+
function normalizeRelativePath(rawPath) {
|
|
21
|
+
const value = String(rawPath || '').trim().replace(/\\/g, '/');
|
|
22
|
+
if (!value || value.startsWith('/'))
|
|
23
|
+
return null;
|
|
24
|
+
const parts = value.split('/').filter(Boolean);
|
|
25
|
+
if (parts.length === 0)
|
|
26
|
+
return null;
|
|
27
|
+
if (parts.some((part) => part === '.' || part === '..'))
|
|
28
|
+
return null;
|
|
29
|
+
return parts.join('/');
|
|
30
|
+
}
|
|
31
|
+
function buildObjectKey(config, relativePath) {
|
|
32
|
+
const normalized = normalizeRelativePath(relativePath);
|
|
33
|
+
if (!normalized)
|
|
34
|
+
throw new Error('Invalid object path.');
|
|
35
|
+
if (config.provider !== 'r2' || !config.r2?.keyPrefix)
|
|
36
|
+
return normalized;
|
|
37
|
+
const prefix = config.r2.keyPrefix.replace(/^\/+|\/+$/g, '');
|
|
38
|
+
return prefix ? `${prefix}/${normalized}` : normalized;
|
|
39
|
+
}
|
|
40
|
+
function buildCanonicalQuery(searchParams) {
|
|
41
|
+
const entries = Array.from(searchParams.entries())
|
|
42
|
+
.map(([key, value]) => [encodeRfc3986(key), encodeRfc3986(value)])
|
|
43
|
+
.sort((a, b) => (a[0] === b[0] ? a[1].localeCompare(b[1]) : a[0].localeCompare(b[0])));
|
|
44
|
+
return entries.map(([key, value]) => `${key}=${value}`).join('&');
|
|
45
|
+
}
|
|
46
|
+
function buildSigningKey(secretAccessKey, dateStamp) {
|
|
47
|
+
const kDate = hmac(`AWS4${secretAccessKey}`, dateStamp);
|
|
48
|
+
const kRegion = hmac(kDate, AWS_REGION);
|
|
49
|
+
const kService = hmac(kRegion, AWS_SERVICE);
|
|
50
|
+
return hmac(kService, 'aws4_request');
|
|
51
|
+
}
|
|
52
|
+
function toDateStamp(amzDate) {
|
|
53
|
+
return amzDate.slice(0, 8);
|
|
54
|
+
}
|
|
55
|
+
function createAmzDate(now = new Date()) {
|
|
56
|
+
const iso = now.toISOString();
|
|
57
|
+
return iso.replace(/[:-]|\.\d{3}/g, '');
|
|
58
|
+
}
|
|
59
|
+
function signRequest(params) {
|
|
60
|
+
const amzDate = createAmzDate(params.now);
|
|
61
|
+
const dateStamp = toDateStamp(amzDate);
|
|
62
|
+
const host = params.url.host;
|
|
63
|
+
const canonicalUri = encodeUriPath(params.url.pathname);
|
|
64
|
+
const canonicalQuery = buildCanonicalQuery(params.url.searchParams);
|
|
65
|
+
const canonicalHeaders = `host:${host}\n` + `x-amz-content-sha256:${params.payloadHash}\n` + `x-amz-date:${amzDate}\n`;
|
|
66
|
+
const signedHeaders = 'host;x-amz-content-sha256;x-amz-date';
|
|
67
|
+
const canonicalRequest = [
|
|
68
|
+
params.method.toUpperCase(),
|
|
69
|
+
canonicalUri,
|
|
70
|
+
canonicalQuery,
|
|
71
|
+
canonicalHeaders,
|
|
72
|
+
signedHeaders,
|
|
73
|
+
params.payloadHash
|
|
74
|
+
].join('\n');
|
|
75
|
+
const credentialScope = `${dateStamp}/${AWS_REGION}/${AWS_SERVICE}/aws4_request`;
|
|
76
|
+
const stringToSign = [
|
|
77
|
+
AWS_ALGORITHM,
|
|
78
|
+
amzDate,
|
|
79
|
+
credentialScope,
|
|
80
|
+
sha256Hex(canonicalRequest)
|
|
81
|
+
].join('\n');
|
|
82
|
+
const signature = createHmac('sha256', buildSigningKey(params.secretAccessKey, dateStamp))
|
|
83
|
+
.update(stringToSign, 'utf8')
|
|
84
|
+
.digest('hex');
|
|
85
|
+
const authorization = `${AWS_ALGORITHM} Credential=${params.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
|
|
86
|
+
return { authorization, amzDate, canonicalQuery };
|
|
87
|
+
}
|
|
88
|
+
export class ObjectStorageClient {
|
|
89
|
+
config;
|
|
90
|
+
constructor(config) {
|
|
91
|
+
this.config = config;
|
|
92
|
+
}
|
|
93
|
+
provider() {
|
|
94
|
+
return this.config.provider;
|
|
95
|
+
}
|
|
96
|
+
keyForRelativePath(relativePath) {
|
|
97
|
+
return buildObjectKey(this.config, relativePath);
|
|
98
|
+
}
|
|
99
|
+
async putObject(relativePath, body, contentType) {
|
|
100
|
+
if (this.config.provider !== 'r2' || !this.config.r2) {
|
|
101
|
+
throw new Error('R2 object storage is not configured.');
|
|
102
|
+
}
|
|
103
|
+
const key = this.keyForRelativePath(relativePath);
|
|
104
|
+
const url = new URL(`/${this.config.r2.bucket}/${key}`, this.config.r2.endpoint);
|
|
105
|
+
const payloadHash = sha256Hex(body);
|
|
106
|
+
const signed = signRequest({
|
|
107
|
+
method: 'PUT',
|
|
108
|
+
url,
|
|
109
|
+
accessKeyId: this.config.r2.accessKeyId,
|
|
110
|
+
secretAccessKey: this.config.r2.secretAccessKey,
|
|
111
|
+
payloadHash
|
|
112
|
+
});
|
|
113
|
+
const response = await fetch(url, {
|
|
114
|
+
method: 'PUT',
|
|
115
|
+
headers: {
|
|
116
|
+
'authorization': signed.authorization,
|
|
117
|
+
'x-amz-date': signed.amzDate,
|
|
118
|
+
'x-amz-content-sha256': payloadHash,
|
|
119
|
+
'content-type': contentType
|
|
120
|
+
},
|
|
121
|
+
body: new Uint8Array(body)
|
|
122
|
+
});
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
const text = await response.text().catch(() => '');
|
|
125
|
+
throw new Error(`Failed to upload object (${response.status}): ${text || response.statusText}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async getObject(relativePath) {
|
|
129
|
+
if (this.config.provider !== 'r2' || !this.config.r2) {
|
|
130
|
+
throw new Error('R2 object storage is not configured.');
|
|
131
|
+
}
|
|
132
|
+
const key = this.keyForRelativePath(relativePath);
|
|
133
|
+
const url = new URL(`/${this.config.r2.bucket}/${key}`, this.config.r2.endpoint);
|
|
134
|
+
const payloadHash = sha256Hex('');
|
|
135
|
+
const signed = signRequest({
|
|
136
|
+
method: 'GET',
|
|
137
|
+
url,
|
|
138
|
+
accessKeyId: this.config.r2.accessKeyId,
|
|
139
|
+
secretAccessKey: this.config.r2.secretAccessKey,
|
|
140
|
+
payloadHash
|
|
141
|
+
});
|
|
142
|
+
const response = await fetch(url, {
|
|
143
|
+
method: 'GET',
|
|
144
|
+
headers: {
|
|
145
|
+
'authorization': signed.authorization,
|
|
146
|
+
'x-amz-date': signed.amzDate,
|
|
147
|
+
'x-amz-content-sha256': payloadHash
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
if (response.status === 404)
|
|
151
|
+
return null;
|
|
152
|
+
if (!response.ok) {
|
|
153
|
+
const text = await response.text().catch(() => '');
|
|
154
|
+
throw new Error(`Failed to read object (${response.status}): ${text || response.statusText}`);
|
|
155
|
+
}
|
|
156
|
+
const contentType = String(response.headers.get('content-type') || 'application/octet-stream');
|
|
157
|
+
const body = Buffer.from(await response.arrayBuffer());
|
|
158
|
+
return { body, contentType };
|
|
159
|
+
}
|
|
160
|
+
async objectExists(relativePath) {
|
|
161
|
+
if (this.config.provider !== 'r2' || !this.config.r2) {
|
|
162
|
+
throw new Error('R2 object storage is not configured.');
|
|
163
|
+
}
|
|
164
|
+
const key = this.keyForRelativePath(relativePath);
|
|
165
|
+
const url = new URL(`/${this.config.r2.bucket}/${key}`, this.config.r2.endpoint);
|
|
166
|
+
const payloadHash = sha256Hex('');
|
|
167
|
+
const signed = signRequest({
|
|
168
|
+
method: 'HEAD',
|
|
169
|
+
url,
|
|
170
|
+
accessKeyId: this.config.r2.accessKeyId,
|
|
171
|
+
secretAccessKey: this.config.r2.secretAccessKey,
|
|
172
|
+
payloadHash
|
|
173
|
+
});
|
|
174
|
+
const response = await fetch(url, {
|
|
175
|
+
method: 'HEAD',
|
|
176
|
+
headers: {
|
|
177
|
+
'authorization': signed.authorization,
|
|
178
|
+
'x-amz-date': signed.amzDate,
|
|
179
|
+
'x-amz-content-sha256': payloadHash
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
if (response.status === 404)
|
|
183
|
+
return false;
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
const text = await response.text().catch(() => '');
|
|
186
|
+
throw new Error(`Failed to check object (${response.status}): ${text || response.statusText}`);
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
async deleteObject(relativePath) {
|
|
191
|
+
if (this.config.provider !== 'r2' || !this.config.r2) {
|
|
192
|
+
throw new Error('R2 object storage is not configured.');
|
|
193
|
+
}
|
|
194
|
+
const key = this.keyForRelativePath(relativePath);
|
|
195
|
+
const url = new URL(`/${this.config.r2.bucket}/${key}`, this.config.r2.endpoint);
|
|
196
|
+
const payloadHash = sha256Hex('');
|
|
197
|
+
const signed = signRequest({
|
|
198
|
+
method: 'DELETE',
|
|
199
|
+
url,
|
|
200
|
+
accessKeyId: this.config.r2.accessKeyId,
|
|
201
|
+
secretAccessKey: this.config.r2.secretAccessKey,
|
|
202
|
+
payloadHash
|
|
203
|
+
});
|
|
204
|
+
const response = await fetch(url, {
|
|
205
|
+
method: 'DELETE',
|
|
206
|
+
headers: {
|
|
207
|
+
'authorization': signed.authorization,
|
|
208
|
+
'x-amz-date': signed.amzDate,
|
|
209
|
+
'x-amz-content-sha256': payloadHash
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
if (response.status === 404)
|
|
213
|
+
return false;
|
|
214
|
+
if (!response.ok) {
|
|
215
|
+
const text = await response.text().catch(() => '');
|
|
216
|
+
throw new Error(`Failed to delete object (${response.status}): ${text || response.statusText}`);
|
|
217
|
+
}
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
createSignedGetUrl(relativePath, expiresInSeconds) {
|
|
221
|
+
if (this.config.provider !== 'r2' || !this.config.r2) {
|
|
222
|
+
throw new Error('R2 object storage is not configured.');
|
|
223
|
+
}
|
|
224
|
+
const ttl = Number.isFinite(expiresInSeconds) ? Math.max(1, Math.min(3600, Math.floor(expiresInSeconds))) : 300;
|
|
225
|
+
const key = this.keyForRelativePath(relativePath);
|
|
226
|
+
const url = new URL(`/${this.config.r2.bucket}/${key}`, this.config.r2.endpoint);
|
|
227
|
+
const amzDate = createAmzDate();
|
|
228
|
+
const dateStamp = toDateStamp(amzDate);
|
|
229
|
+
const credentialScope = `${dateStamp}/${AWS_REGION}/${AWS_SERVICE}/aws4_request`;
|
|
230
|
+
url.searchParams.set('X-Amz-Algorithm', AWS_ALGORITHM);
|
|
231
|
+
url.searchParams.set('X-Amz-Credential', `${this.config.r2.accessKeyId}/${credentialScope}`);
|
|
232
|
+
url.searchParams.set('X-Amz-Date', amzDate);
|
|
233
|
+
url.searchParams.set('X-Amz-Expires', String(ttl));
|
|
234
|
+
url.searchParams.set('X-Amz-SignedHeaders', 'host');
|
|
235
|
+
const canonicalUri = encodeUriPath(url.pathname);
|
|
236
|
+
const canonicalQuery = buildCanonicalQuery(url.searchParams);
|
|
237
|
+
const canonicalRequest = [
|
|
238
|
+
'GET',
|
|
239
|
+
canonicalUri,
|
|
240
|
+
canonicalQuery,
|
|
241
|
+
`host:${url.host}\n`,
|
|
242
|
+
'host',
|
|
243
|
+
'UNSIGNED-PAYLOAD'
|
|
244
|
+
].join('\n');
|
|
245
|
+
const stringToSign = [
|
|
246
|
+
AWS_ALGORITHM,
|
|
247
|
+
amzDate,
|
|
248
|
+
credentialScope,
|
|
249
|
+
sha256Hex(canonicalRequest)
|
|
250
|
+
].join('\n');
|
|
251
|
+
const signingKey = buildSigningKey(this.config.r2.secretAccessKey, dateStamp);
|
|
252
|
+
const signature = createHmac('sha256', signingKey).update(stringToSign, 'utf8').digest('hex');
|
|
253
|
+
url.searchParams.set('X-Amz-Signature', signature);
|
|
254
|
+
return url.toString();
|
|
255
|
+
}
|
|
256
|
+
createSignedPutUrl(relativePath, expiresInSeconds) {
|
|
257
|
+
if (this.config.provider !== 'r2' || !this.config.r2) {
|
|
258
|
+
throw new Error('R2 object storage is not configured.');
|
|
259
|
+
}
|
|
260
|
+
const ttl = Number.isFinite(expiresInSeconds) ? Math.max(1, Math.min(3600, Math.floor(expiresInSeconds))) : 600;
|
|
261
|
+
const key = this.keyForRelativePath(relativePath);
|
|
262
|
+
const url = new URL(`/${this.config.r2.bucket}/${key}`, this.config.r2.endpoint);
|
|
263
|
+
const amzDate = createAmzDate();
|
|
264
|
+
const dateStamp = toDateStamp(amzDate);
|
|
265
|
+
const credentialScope = `${dateStamp}/${AWS_REGION}/${AWS_SERVICE}/aws4_request`;
|
|
266
|
+
url.searchParams.set('X-Amz-Algorithm', AWS_ALGORITHM);
|
|
267
|
+
url.searchParams.set('X-Amz-Credential', `${this.config.r2.accessKeyId}/${credentialScope}`);
|
|
268
|
+
url.searchParams.set('X-Amz-Date', amzDate);
|
|
269
|
+
url.searchParams.set('X-Amz-Expires', String(ttl));
|
|
270
|
+
url.searchParams.set('X-Amz-SignedHeaders', 'host');
|
|
271
|
+
const canonicalUri = encodeUriPath(url.pathname);
|
|
272
|
+
const canonicalQuery = buildCanonicalQuery(url.searchParams);
|
|
273
|
+
const canonicalRequest = [
|
|
274
|
+
'PUT',
|
|
275
|
+
canonicalUri,
|
|
276
|
+
canonicalQuery,
|
|
277
|
+
`host:${url.host}\n`,
|
|
278
|
+
'host',
|
|
279
|
+
'UNSIGNED-PAYLOAD'
|
|
280
|
+
].join('\n');
|
|
281
|
+
const stringToSign = [
|
|
282
|
+
AWS_ALGORITHM,
|
|
283
|
+
amzDate,
|
|
284
|
+
credentialScope,
|
|
285
|
+
sha256Hex(canonicalRequest)
|
|
286
|
+
].join('\n');
|
|
287
|
+
const signingKey = buildSigningKey(this.config.r2.secretAccessKey, dateStamp);
|
|
288
|
+
const signature = createHmac('sha256', signingKey).update(stringToSign, 'utf8').digest('hex');
|
|
289
|
+
url.searchParams.set('X-Amz-Signature', signature);
|
|
290
|
+
return url.toString();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function normalizeTaskDataRelativePath(rawPath) {
|
|
294
|
+
const normalized = normalizeRelativePath(rawPath);
|
|
295
|
+
if (!normalized)
|
|
296
|
+
return null;
|
|
297
|
+
const allowedRoots = ['task-data/', 'users/', 'workspaces/', 'system/', 'tmp/', 'quarantine/'];
|
|
298
|
+
if (!allowedRoots.some((root) => normalized.startsWith(root)))
|
|
299
|
+
return null;
|
|
300
|
+
return normalized;
|
|
301
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
function readProvider(env) {
|
|
2
|
+
const raw = String(env.TASKFORCE_OBJECT_STORAGE_PROVIDER || env.TASKFORCE_STORAGE_PROVIDER || '').trim().toLowerCase();
|
|
3
|
+
if (raw === 'r2')
|
|
4
|
+
return 'r2';
|
|
5
|
+
return 'local';
|
|
6
|
+
}
|
|
7
|
+
function readPositiveInteger(value, fallback) {
|
|
8
|
+
const parsed = Number.parseInt(String(value || '').trim(), 10);
|
|
9
|
+
if (!Number.isFinite(parsed) || parsed <= 0)
|
|
10
|
+
return fallback;
|
|
11
|
+
return parsed;
|
|
12
|
+
}
|
|
13
|
+
function readRequired(env, key) {
|
|
14
|
+
const value = String(env[key] || '').trim();
|
|
15
|
+
if (!value) {
|
|
16
|
+
throw new Error(`[Taskforce] ${key} is required when object storage provider is r2.`);
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
export function resolveObjectStorageConfigFromEnv(env = process.env) {
|
|
21
|
+
const provider = readProvider(env);
|
|
22
|
+
if (provider !== 'r2')
|
|
23
|
+
return { provider: 'local' };
|
|
24
|
+
const accountId = readRequired(env, 'R2_ACCOUNT_ID');
|
|
25
|
+
const bucket = readRequired(env, 'R2_BUCKET');
|
|
26
|
+
const accessKeyId = readRequired(env, 'R2_ACCESS_KEY_ID');
|
|
27
|
+
const secretAccessKey = readRequired(env, 'R2_SECRET_ACCESS_KEY');
|
|
28
|
+
const endpoint = String(env.R2_ENDPOINT || '').trim() || `https://${accountId}.r2.cloudflarestorage.com`;
|
|
29
|
+
const keyPrefix = String(env.R2_KEY_PREFIX || 'taskforce').trim() || 'taskforce';
|
|
30
|
+
const signedUploadTtlSeconds = readPositiveInteger(env.R2_SIGNED_UPLOAD_TTL_SECONDS, 600);
|
|
31
|
+
const signedDownloadTtlSeconds = readPositiveInteger(env.R2_SIGNED_DOWNLOAD_TTL_SECONDS, 300);
|
|
32
|
+
return {
|
|
33
|
+
provider: 'r2',
|
|
34
|
+
r2: {
|
|
35
|
+
accountId,
|
|
36
|
+
bucket,
|
|
37
|
+
endpoint,
|
|
38
|
+
accessKeyId,
|
|
39
|
+
secretAccessKey,
|
|
40
|
+
keyPrefix,
|
|
41
|
+
signedUploadTtlSeconds,
|
|
42
|
+
signedDownloadTtlSeconds
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DatabaseAdapter, DatabaseStatement } from './databaseAdapter.js';
|
|
2
|
+
export declare class PostgresAdapter implements DatabaseAdapter {
|
|
3
|
+
readonly provider: "postgres";
|
|
4
|
+
readonly open = true;
|
|
5
|
+
private readonly worker;
|
|
6
|
+
private readonly encoder;
|
|
7
|
+
private readonly decoder;
|
|
8
|
+
private txId;
|
|
9
|
+
constructor(connectionString?: string);
|
|
10
|
+
private callWorker;
|
|
11
|
+
private query;
|
|
12
|
+
private bindParams;
|
|
13
|
+
prepare(sql: string): DatabaseStatement;
|
|
14
|
+
exec(sql: string): void;
|
|
15
|
+
transaction<T extends (...args: any[]) => any>(fn: T): T;
|
|
16
|
+
pragma(name: string, options?: {
|
|
17
|
+
simple?: boolean;
|
|
18
|
+
}): unknown;
|
|
19
|
+
close(): void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { TextDecoder, TextEncoder } from 'util';
|
|
2
|
+
import { Worker } from 'worker_threads';
|
|
3
|
+
const RESPONSE_STATUS_INDEX = 0;
|
|
4
|
+
const RESPONSE_LENGTH_INDEX = 1;
|
|
5
|
+
const RESPONSE_READY = 1;
|
|
6
|
+
const RESPONSE_INITIAL = 0;
|
|
7
|
+
const RESPONSE_TIMEOUT_MS = 20_000;
|
|
8
|
+
const RESPONSE_BUFFER_BYTES = 2 * 1024 * 1024;
|
|
9
|
+
function isPlainObject(value) {
|
|
10
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
11
|
+
}
|
|
12
|
+
function replaceQMarkParams(sql, params) {
|
|
13
|
+
let index = 0;
|
|
14
|
+
const text = sql.replace(/\?/g, () => {
|
|
15
|
+
index += 1;
|
|
16
|
+
return `$${index}`;
|
|
17
|
+
});
|
|
18
|
+
return { text, values: params };
|
|
19
|
+
}
|
|
20
|
+
function replaceNamedParams(sql, params) {
|
|
21
|
+
const values = [];
|
|
22
|
+
const keyToIndex = new Map();
|
|
23
|
+
const text = sql.replace(/@([a-zA-Z_][a-zA-Z0-9_]*)/g, (_match, key) => {
|
|
24
|
+
if (!keyToIndex.has(key)) {
|
|
25
|
+
keyToIndex.set(key, values.length + 1);
|
|
26
|
+
values.push(params[key]);
|
|
27
|
+
}
|
|
28
|
+
return `$${keyToIndex.get(key)}`;
|
|
29
|
+
});
|
|
30
|
+
return { text, values };
|
|
31
|
+
}
|
|
32
|
+
function translateInsertOrReplace(sql) {
|
|
33
|
+
const match = sql.match(/INSERT\s+OR\s+REPLACE\s+INTO\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([\s\S]*?)\)\s*VALUES\s*\(([\s\S]*?)\)/i);
|
|
34
|
+
if (!match)
|
|
35
|
+
return sql;
|
|
36
|
+
const table = match[1];
|
|
37
|
+
const columns = match[2].split(',').map((c) => c.trim()).filter(Boolean);
|
|
38
|
+
if (columns.length === 0)
|
|
39
|
+
return sql.replace(/INSERT\s+OR\s+REPLACE/i, 'INSERT');
|
|
40
|
+
const updateColumns = columns.filter((c) => c !== 'id');
|
|
41
|
+
const updateClause = updateColumns.length === 0
|
|
42
|
+
? 'NOTHING'
|
|
43
|
+
: `UPDATE SET ${updateColumns.map((c) => `${c} = EXCLUDED.${c}`).join(', ')}`;
|
|
44
|
+
return sql.replace(/INSERT\s+OR\s+REPLACE\s+INTO[\s\S]*?\)\s*VALUES\s*\([\s\S]*?\)/i, `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${match[3]}) ON CONFLICT (id) DO ${updateClause}`);
|
|
45
|
+
}
|
|
46
|
+
function normalizeSchemaSql(sql) {
|
|
47
|
+
return sql
|
|
48
|
+
.replace(/\bBOOLEAN\b/gi, 'INTEGER')
|
|
49
|
+
.replace(/\bTRUE\b/gi, '1')
|
|
50
|
+
.replace(/\bFALSE\b/gi, '0');
|
|
51
|
+
}
|
|
52
|
+
function parsePragmaTableInfo(sql) {
|
|
53
|
+
const match = sql.trim().match(/^PRAGMA\s+table_info\((['"]?)([a-zA-Z_][a-zA-Z0-9_]*)\1\)\s*;?$/i);
|
|
54
|
+
return match?.[2] || null;
|
|
55
|
+
}
|
|
56
|
+
function toRowCount(result) {
|
|
57
|
+
return typeof result.rowCount === 'number' ? result.rowCount : 0;
|
|
58
|
+
}
|
|
59
|
+
export class PostgresAdapter {
|
|
60
|
+
provider = 'postgres';
|
|
61
|
+
open = true;
|
|
62
|
+
worker;
|
|
63
|
+
encoder = new TextEncoder();
|
|
64
|
+
decoder = new TextDecoder();
|
|
65
|
+
txId = null;
|
|
66
|
+
constructor(connectionString) {
|
|
67
|
+
if (!connectionString || !connectionString.trim()) {
|
|
68
|
+
throw new Error('[Taskforce] Postgres adapter requires a non-empty connection string.');
|
|
69
|
+
}
|
|
70
|
+
this.worker = new Worker(new URL('./postgresWorker.js', import.meta.url), {
|
|
71
|
+
workerData: {
|
|
72
|
+
connectionString
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
callWorker(payload) {
|
|
77
|
+
const statusBuffer = new SharedArrayBuffer(8);
|
|
78
|
+
const status = new Int32Array(statusBuffer);
|
|
79
|
+
status[RESPONSE_STATUS_INDEX] = RESPONSE_INITIAL;
|
|
80
|
+
status[RESPONSE_LENGTH_INDEX] = 0;
|
|
81
|
+
const responseBuffer = new SharedArrayBuffer(RESPONSE_BUFFER_BYTES);
|
|
82
|
+
const responseBytes = new Uint8Array(responseBuffer);
|
|
83
|
+
this.worker.postMessage({
|
|
84
|
+
payload,
|
|
85
|
+
statusBuffer,
|
|
86
|
+
responseBuffer
|
|
87
|
+
});
|
|
88
|
+
const waitResult = Atomics.wait(status, RESPONSE_STATUS_INDEX, RESPONSE_INITIAL, RESPONSE_TIMEOUT_MS);
|
|
89
|
+
if (waitResult === 'timed-out') {
|
|
90
|
+
throw new Error('[Taskforce] Postgres worker timed out.');
|
|
91
|
+
}
|
|
92
|
+
const responseLength = status[RESPONSE_LENGTH_INDEX];
|
|
93
|
+
if (!Number.isFinite(responseLength) || responseLength <= 0 || responseLength > RESPONSE_BUFFER_BYTES) {
|
|
94
|
+
throw new Error('[Taskforce] Invalid Postgres worker response.');
|
|
95
|
+
}
|
|
96
|
+
const body = this.decoder.decode(responseBytes.subarray(0, responseLength));
|
|
97
|
+
const parsed = JSON.parse(body);
|
|
98
|
+
if (!parsed.ok) {
|
|
99
|
+
throw new Error(parsed.error || 'Unknown Postgres worker error');
|
|
100
|
+
}
|
|
101
|
+
return parsed;
|
|
102
|
+
}
|
|
103
|
+
query(sql, values = []) {
|
|
104
|
+
const response = this.callWorker({
|
|
105
|
+
op: 'query',
|
|
106
|
+
sql,
|
|
107
|
+
values,
|
|
108
|
+
txId: this.txId || undefined
|
|
109
|
+
});
|
|
110
|
+
return response.result || { rows: [], rowCount: 0 };
|
|
111
|
+
}
|
|
112
|
+
bindParams(sql, params) {
|
|
113
|
+
const translated = translateInsertOrReplace(sql);
|
|
114
|
+
if (params.length === 1 && isPlainObject(params[0])) {
|
|
115
|
+
return replaceNamedParams(translated, params[0]);
|
|
116
|
+
}
|
|
117
|
+
return replaceQMarkParams(translated, params);
|
|
118
|
+
}
|
|
119
|
+
prepare(sql) {
|
|
120
|
+
const pragmaTable = parsePragmaTableInfo(sql);
|
|
121
|
+
if (pragmaTable) {
|
|
122
|
+
return {
|
|
123
|
+
run: () => ({ changes: 0 }),
|
|
124
|
+
get: () => {
|
|
125
|
+
const row = this.query(`SELECT column_name AS name
|
|
126
|
+
FROM information_schema.columns
|
|
127
|
+
WHERE table_schema = 'public' AND table_name = $1
|
|
128
|
+
ORDER BY ordinal_position
|
|
129
|
+
LIMIT 1`, [pragmaTable]).rows[0];
|
|
130
|
+
return row || undefined;
|
|
131
|
+
},
|
|
132
|
+
all: () => this.query(`SELECT column_name AS name
|
|
133
|
+
FROM information_schema.columns
|
|
134
|
+
WHERE table_schema = 'public' AND table_name = $1
|
|
135
|
+
ORDER BY ordinal_position`, [pragmaTable]).rows
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
run: (...params) => {
|
|
140
|
+
const { text, values } = this.bindParams(sql, params);
|
|
141
|
+
const result = this.query(text, values);
|
|
142
|
+
return { changes: toRowCount(result) };
|
|
143
|
+
},
|
|
144
|
+
get: (...params) => {
|
|
145
|
+
const { text, values } = this.bindParams(sql, params);
|
|
146
|
+
const result = this.query(text, values);
|
|
147
|
+
return result.rows[0] || undefined;
|
|
148
|
+
},
|
|
149
|
+
all: (...params) => {
|
|
150
|
+
const { text, values } = this.bindParams(sql, params);
|
|
151
|
+
return this.query(text, values).rows;
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
exec(sql) {
|
|
156
|
+
const normalized = normalizeSchemaSql(sql);
|
|
157
|
+
this.query(normalized, []);
|
|
158
|
+
}
|
|
159
|
+
transaction(fn) {
|
|
160
|
+
const wrapped = ((...args) => {
|
|
161
|
+
if (this.txId) {
|
|
162
|
+
return fn(...args);
|
|
163
|
+
}
|
|
164
|
+
const txId = `tx-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
165
|
+
this.callWorker({ op: 'begin', txId });
|
|
166
|
+
this.txId = txId;
|
|
167
|
+
try {
|
|
168
|
+
const value = fn(...args);
|
|
169
|
+
this.callWorker({ op: 'commit', txId });
|
|
170
|
+
return value;
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
try {
|
|
174
|
+
this.callWorker({ op: 'rollback', txId });
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// Best effort rollback.
|
|
178
|
+
}
|
|
179
|
+
throw error;
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
this.txId = null;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
return wrapped;
|
|
186
|
+
}
|
|
187
|
+
pragma(name, options) {
|
|
188
|
+
const normalized = String(name || '').trim().toLowerCase();
|
|
189
|
+
if (normalized === 'data_version') {
|
|
190
|
+
const row = this.query('SELECT EXTRACT(EPOCH FROM now())::bigint AS version').rows[0];
|
|
191
|
+
const version = Number(row?.version || 0);
|
|
192
|
+
return options?.simple ? version : [{ data_version: version }];
|
|
193
|
+
}
|
|
194
|
+
return options?.simple ? null : [];
|
|
195
|
+
}
|
|
196
|
+
close() {
|
|
197
|
+
try {
|
|
198
|
+
this.callWorker({ op: 'close' });
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
this.worker.terminate();
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|