@taskforcehq/taskforce 0.3.327 → 0.3.329
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/dist/Taskforce.module.css +257 -87
- package/dist/TaskforceCore.js +237 -230
- package/dist/annotatedAttachments/AnnotatedAttachmentSessionStore.js +1 -1
- package/dist/cli.js +34 -0
- package/dist/cliCloudTargetGuard.d.ts +5 -0
- package/dist/cliCloudTargetGuard.js +11 -0
- package/dist/components/activity/EntityActivityTimeline.js +15 -5
- package/dist/components/context/AttachmentPreviewHost.js +1 -1
- package/dist/components/context/ContextAttachmentManager.d.ts +3 -0
- package/dist/components/context/ContextAttachmentManager.js +116 -20
- package/dist/components/features/AnnotatedAttachmentWorkspace.js +24 -8
- package/dist/components/features/TaskSettings.d.ts +12 -1
- package/dist/components/features/TaskSettings.js +147 -40
- package/dist/components/features/agentCapabilities/AgentCapabilitiesPrototype.d.ts +1 -1
- package/dist/components/features/planning/PlanningEntitySummary.d.ts +3 -1
- package/dist/components/features/planning/PlanningEntitySummary.js +3 -2
- package/dist/components/features/planning/PlanningLinkPicker.d.ts +3 -1
- package/dist/components/features/planning/PlanningLinkPicker.js +5 -3
- package/dist/components/features/planning/PlanningModule.js +28 -14
- package/dist/components/features/planning/PlanningTaskOrderList.d.ts +1 -1
- package/dist/components/features/planning/PlanningTaskOrderList.js +17 -6
- package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
- package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
- package/dist/components/features/planning/planningTaskArrangement.d.ts +1 -0
- package/dist/components/features/planning/planningTaskArrangement.js +5 -5
- package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
- package/dist/components/features/taskforceAgentEditorModel.js +3 -1
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +2 -2
- package/dist/components/task/TaskCard.d.ts +5 -0
- package/dist/components/task/TaskCard.js +101 -13
- package/dist/components/task/TaskContextUpload.d.ts +3 -0
- package/dist/components/task/TaskContextUpload.js +2 -2
- package/dist/components/task/TaskForm.d.ts +4 -0
- package/dist/components/task/TaskForm.js +32 -7
- package/dist/components/task/TaskImageReviews.js +28 -19
- package/dist/components/task/TaskKanban.d.ts +6 -1
- package/dist/components/task/TaskKanban.js +152 -6
- package/dist/components/task/TaskList.d.ts +5 -0
- package/dist/components/task/TaskList.js +3 -3
- package/dist/components/task/TaskStatusActions.js +11 -2
- package/dist/components/task/TaskWorkstreamPicker.js +2 -1
- package/dist/components/ui/DocumentTypeIcon.d.ts +7 -0
- package/dist/components/ui/DocumentTypeIcon.js +8 -0
- package/dist/components/ui/PasswordInput.d.ts +6 -0
- package/dist/components/ui/PasswordInput.js +11 -0
- package/dist/components/ui/TaxonomyDropdown.d.ts +9 -1
- package/dist/components/ui/TaxonomyDropdown.js +30 -3
- package/dist/components/ui/TopNoticeLayer.js +1 -1
- package/dist/components/views/AppShellHeader.js +32 -11
- package/dist/components/views/PlanComparisonPage.js +12 -0
- package/dist/components/views/StandaloneLayout.js +68 -39
- package/dist/components/views/WidgetView.js +10 -7
- package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
- package/dist/components/views/panels/PlanningDrawer.js +51 -54
- package/dist/components/views/standalone/modals/AccountSettingsModal.js +26 -17
- package/dist/config/envSchema.js +13 -0
- package/dist/config/localServiceCloudTarget.d.ts +10 -0
- package/dist/config/localServiceCloudTarget.js +76 -0
- package/dist/config/localServiceRuntimeContract.d.ts +13 -0
- package/dist/config/localServiceRuntimeContract.js +135 -0
- package/dist/core/AiProfileService.d.ts +1 -0
- package/dist/core/AiProfileService.js +48 -9
- package/dist/core/AttachmentLinkService.js +7 -4
- package/dist/core/DeletedTaskLifecycleService.d.ts +5 -0
- package/dist/core/DeletedTaskLifecycleService.js +55 -3
- package/dist/core/McpTokenService.d.ts +4 -0
- package/dist/core/McpTokenService.js +52 -0
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +8 -2
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +51 -18
- package/dist/core/Taskforce.d.ts +124 -2
- package/dist/core/Taskforce.js +1175 -87
- package/dist/core/types.d.ts +8 -1
- package/dist/documentReviews/DocumentReviewCommentStore.d.ts +11 -0
- package/dist/documentReviews/DocumentReviewCommentStore.js +35 -2
- package/dist/documentReviews/service.d.ts +4 -0
- package/dist/documentReviews/service.js +141 -46
- package/dist/hooks/sync/useDurableLocalOutboxDrain.d.ts +1 -1
- package/dist/hooks/sync/useDurableTaskCreateMutation.js +1 -1
- package/dist/hooks/sync/useDurableTaskMetadataMutation.d.ts +1 -0
- package/dist/hooks/sync/useDurableTaskMetadataMutation.js +1 -0
- package/dist/hooks/sync/useDurableTaskStatusMutation.d.ts +1 -0
- package/dist/hooks/tasks/taskHttpMutation.js +1 -0
- package/dist/hooks/tasks/useCloudTaskSearch.d.ts +12 -0
- package/dist/hooks/tasks/useCloudTaskSearch.js +71 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.d.ts +16 -0
- package/dist/hooks/tasks/useTaskDescriptionImageDraftRecovery.js +197 -0
- package/dist/hooks/tasks/useTaskEditorNavigation.d.ts +16 -3
- package/dist/hooks/tasks/useTaskEditorNavigation.js +72 -13
- package/dist/hooks/tasks/useTaskFormActions.d.ts +9 -0
- package/dist/hooks/tasks/useTaskFormActions.js +96 -17
- package/dist/hooks/ui/useSettingsModel.d.ts +24 -2
- package/dist/hooks/ui/useSettingsModel.js +13 -2
- package/dist/hooks/ui/useSettingsPersistence.d.ts +12 -1
- package/dist/hooks/ui/useSettingsPersistence.js +74 -47
- package/dist/hooks/useFilterSort.d.ts +7 -3
- package/dist/hooks/useFilterSort.js +15 -5
- package/dist/hooks/useTaskData.d.ts +10 -1
- package/dist/hooks/useTaskData.js +216 -7
- package/dist/hooks/useTaskMutations.d.ts +10 -2
- package/dist/hooks/useTaskMutations.js +223 -43
- package/dist/hooks/useTaskforce.d.ts +94 -57
- package/dist/hooks/useTaskforce.js +428 -16
- package/dist/hooks/useUiNotice.d.ts +4 -0
- package/dist/hooks/useUiNotice.js +4 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +3 -3
- package/dist/mcp/canonicalAssetHelpers.d.ts +13 -0
- package/dist/mcp/canonicalAssetHelpers.js +39 -5
- package/dist/mcp/collaborationRegistrar.js +15 -13
- package/dist/mcp/documentAssetRegistrar.js +60 -44
- package/dist/mcp/documentHelpers.d.ts +1 -0
- package/dist/mcp/documentHelpers.js +7 -3
- package/dist/mcp/localServiceProxy.js +4 -1
- package/dist/mcp/runtime.d.ts +16 -0
- package/dist/mcp/runtime.js +735 -210
- package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
- package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
- package/dist/mcp/taskPlanningRegistrar.js +78 -67
- package/dist/mcp/toolCallCompatibility.js +38 -1
- package/dist/mcp/toolCatalog.d.ts +1 -0
- package/dist/mcp/toolRegistry.js +2 -2
- package/dist/migrations/taskSchemaMigrations.js +47 -0
- package/dist/runtime/appGateDefinitions.d.ts +30 -6
- package/dist/runtime/appGateDefinitions.js +6 -6
- package/dist/runtime/appGates.d.ts +12 -13
- package/dist/runtime/appGates.js +29 -13
- package/dist/runtime/nodeAppGates.d.ts +8 -0
- package/dist/runtime/nodeAppGates.js +27 -0
- package/dist/server/appAccess.d.ts +12 -0
- package/dist/server/appAccess.js +21 -0
- package/dist/server/authorizedWorkspaceAccess.d.ts +12 -0
- package/dist/server/authorizedWorkspaceAccess.js +40 -0
- package/dist/server/cloudCollectionRead.d.ts +25 -0
- package/dist/server/cloudCollectionRead.js +120 -0
- package/dist/server/cloudCollectionReadPool.d.ts +52 -0
- package/dist/server/cloudCollectionReadPool.js +140 -0
- package/dist/server/cloudCollectionReadWorker.d.ts +1 -0
- package/dist/server/cloudCollectionReadWorker.js +36 -0
- package/dist/server/index.d.ts +6 -11
- package/dist/server/index.js +67 -42
- package/dist/server/localServiceLease.d.ts +6 -0
- package/dist/server/localServiceLease.js +17 -1
- package/dist/server/localWorkspaceSyncServerRuntime.js +10 -3
- package/dist/server/rateLimit.d.ts +1 -0
- package/dist/server/rateLimit.js +4 -0
- package/dist/server/realtimeSyncWs.js +36 -12
- package/dist/server/routes/admin.js +1 -0
- package/dist/server/routes/agentRoles.js +3 -2
- package/dist/server/routes/agentSkills.js +3 -2
- package/dist/server/routes/agents.js +118 -16
- package/dist/server/routes/annotatedAttachments.js +3 -2
- package/dist/server/routes/auth.js +3 -1
- package/dist/server/routes/documents.d.ts +5 -2
- package/dist/server/routes/documents.js +160 -13
- package/dist/server/routes/durableTaskHttpRouters.d.ts +11 -2
- package/dist/server/routes/durableTaskHttpRouters.js +2 -2
- package/dist/server/routes/localService.js +4 -0
- package/dist/server/routes/primitives.d.ts +4 -0
- package/dist/server/routes/shared.d.ts +24 -0
- package/dist/server/routes/shared.js +114 -18
- package/dist/server/routes/sync.js +22 -0
- package/dist/server/routes/syncAuxRoutes.js +5 -2
- package/dist/server/routes/syncPullApplyRoutes.js +23 -4
- package/dist/server/routes/syncV3FeedRoutes.js +22 -18
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +48 -4
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.d.ts +1 -0
- package/dist/server/routes/syncV3LocalFeedApplyRoutes.js +26 -0
- package/dist/server/routes/syncV3OperationRoutes.js +27 -2
- package/dist/server/routes/tasks.js +299 -97
- package/dist/server/routes/workspaces.js +43 -1
- package/dist/server/routes.js +35 -7
- package/dist/server/workspaceDeletionAdmission.d.ts +23 -0
- package/dist/server/workspaceDeletionAdmission.js +50 -0
- package/dist/service/localServiceCli.js +52 -25
- package/dist/service/localServiceClientLifecycle.js +93 -6
- package/dist/services/codexAppServerModelGateway.d.ts +112 -0
- package/dist/services/codexAppServerModelGateway.js +438 -0
- package/dist/services/taskforceAgentMcpBridge.d.ts +7 -1
- package/dist/services/taskforceAgentMcpBridge.js +23 -3
- package/dist/shared/planningIdentity.d.ts +20 -0
- package/dist/shared/planningIdentity.js +79 -0
- package/dist/shared/taskforceAgentDefinition.js +7 -1
- package/dist/shared/taskforceAgentModels.d.ts +1 -0
- package/dist/shared/taskforceAgentModels.js +30 -1
- package/dist/storage/postgresAdapter.d.ts +20 -3
- package/dist/storage/postgresAdapter.js +110 -14
- package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
- package/dist/storage/postgresRequestDiagnostics.js +24 -0
- package/dist/storage/postgresWorker.js +13 -4
- package/dist/storage/postgresWorkerProtocol.d.ts +29 -0
- package/dist/storage/postgresWorkerProtocol.js +30 -0
- package/dist/storage/workspaceAssetStore.d.ts +32 -0
- package/dist/storage/workspaceAssetStore.js +70 -0
- package/dist/sync/cloudSyncApi.d.ts +4 -1
- package/dist/sync/cloudSyncApi.js +7 -2
- package/dist/sync/contentSyncState.d.ts +1 -1
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +17 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +77 -23
- package/dist/sync/coordinator/localWorkspaceSyncRunner.js +6 -2
- package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
- package/dist/sync/engine/workspaceSyncEngineBrowserGatewayRemoteServices.js +20 -2
- package/dist/sync/engine/workspaceSyncEngineLocalServices.d.ts +4 -0
- package/dist/sync/engine/workspaceSyncEngineLocalServices.js +11 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +16 -0
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.js +2 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +46 -4
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.d.ts +3 -1
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +51 -11
- package/dist/sync/engine/workspaceSyncEngineTransfers.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineTransfers.js +8 -3
- package/dist/sync/engine/workspaceSyncV2ChangeDispatcher.js +2 -0
- package/dist/sync/syncApplyHandlers.d.ts +3 -1
- package/dist/sync/syncApplyHandlers.js +29 -0
- package/dist/sync/syncService.d.ts +2 -0
- package/dist/sync/syncService.js +13 -1
- package/dist/sync/taskSyncPayload.d.ts +1 -0
- package/dist/sync/taskSyncPayload.js +6 -0
- package/dist/sync/v3/combinedFeedCapability.js +4 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +3 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +31 -3
- package/dist/sync/v3/durableTaskChecklistMutationRouter.d.ts +2 -0
- package/dist/sync/v3/durableTaskChecklistMutationRouter.js +4 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +47 -12
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.d.ts +5 -3
- package/dist/sync/v3/durableTaskHttpRootMutationRouter.js +27 -2
- package/dist/sync/v3/localInitiativeOutboxService.js +4 -2
- package/dist/sync/v3/localOutboxDispatcher.js +5 -1
- package/dist/sync/v3/localTaskAttachmentLinksOutboxHandler.js +12 -2
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.d.ts +3 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +62 -10
- package/dist/sync/v3/localTaskCreateOutboxService.js +15 -6
- package/dist/sync/v3/localTaskMetadataClient.d.ts +1 -0
- package/dist/sync/v3/localTaskMetadataClient.js +1 -0
- package/dist/sync/v3/localTaskMetadataOutboxHandler.js +5 -1
- package/dist/sync/v3/localTaskMetadataOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskMetadataOutboxService.js +7 -0
- package/dist/sync/v3/localTaskRestoreOutboxService.js +14 -6
- package/dist/sync/v3/localTaskStatusClient.d.ts +1 -0
- package/dist/sync/v3/localTaskStatusClient.js +6 -1
- package/dist/sync/v3/localTaskStatusOutboxService.d.ts +2 -0
- package/dist/sync/v3/localTaskStatusOutboxService.js +54 -13
- package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
- package/dist/sync/v3/syncDurabilityStore.d.ts +15 -0
- package/dist/sync/v3/syncDurabilityStore.js +201 -43
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +7 -4
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +37 -12
- package/dist/sync/v3/taskChecklistMutationService.d.ts +4 -2
- package/dist/sync/v3/taskChecklistMutationService.js +4 -0
- package/dist/sync/v3/taskCreateMutationService.d.ts +2 -2
- package/dist/sync/v3/taskCreateMutationService.js +7 -4
- package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
- package/dist/sync/v3/taskMetadataMutationService.d.ts +3 -0
- package/dist/sync/v3/taskMetadataMutationService.js +4 -0
- package/dist/sync/v3/taskRestoreMutationService.d.ts +2 -2
- package/dist/sync/v3/taskRestoreMutationService.js +7 -4
- package/dist/sync/v3/taskStatusMutationService.d.ts +2 -0
- package/dist/sync/v3/taskStatusMutationService.js +4 -0
- package/dist/sync/v3/workflowAssignmentSync.d.ts +1 -0
- package/dist/sync/v3/workflowAssignmentSync.js +3 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +14 -12
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3AttachmentApplyObligationStore.js +27 -10
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3AttachmentAssetHydration.js +52 -10
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +10 -1
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +15 -4
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +66 -13
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +11 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +57 -22
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +10 -4
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +124 -51
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.d.ts +10 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +120 -28
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.d.ts +3 -1
- package/dist/sync/v3/workspaceSyncV3CombinedWireContract.js +18 -0
- package/dist/sync/v3/workspaceSyncV3CoverageRegistry.js +6 -0
- package/dist/sync/v3/workspaceSyncV3FeedProfile.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3LegacyBoundaryAttestation.js +23 -10
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskApply.js +64 -13
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.d.ts +9 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskCodecs.js +26 -0
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.d.ts +15 -5
- package/dist/sync/v3/workspaceSyncV3NestedTaskProjection.js +50 -14
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.d.ts +2 -1
- package/dist/sync/v3/workspaceSyncV3NestedTaskRepairSnapshot.js +11 -3
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +3 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3OperatorDiagnostics.js +19 -7
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -0
- package/dist/sync/v3/workspaceSyncV3TaskCommentAudit.js +9 -2
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.d.ts +7 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverCoverage.js +37 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.d.ts +6 -0
- package/dist/sync/v3/workspaceSyncV3TaskCoverWireContract.js +9 -0
- package/dist/sync/v3/workspaceSyncV3TaskRootProjection.d.ts +1 -1
- package/dist/sync/v3/workspaceSyncV3TaskRootProjection.js +1 -1
- package/dist/sync/workspacePullFeed.d.ts +6 -1
- package/dist/sync/workspacePullFeed.js +174 -162
- package/dist/sync/workspaceRepair.d.ts +3 -0
- package/dist/sync/workspaceRepair.js +67 -6
- package/dist/sync/workspaceSyncModel.d.ts +11 -0
- package/dist/sync/workspaceSyncModel.js +27 -2
- package/dist/types.d.ts +55 -1
- package/dist/types.js +6 -0
- package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-BZM4aQnM.js} +1 -1
- package/dist/ui/assets/AiProfilesModule-BbAEWtHH.js +1 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-B68Wg-RV.js +3 -0
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-TzYu7pkG.css +1 -0
- package/dist/ui/assets/AssetTraySortControl-C8Rztyal.js +1 -0
- package/dist/ui/assets/ContextAttachmentManager-Cj3c7X9y.js +3 -0
- package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-B5uvzems.js} +4 -4
- package/dist/ui/assets/EntityActivityTimeline-BVFvCB5R.js +1 -0
- package/dist/ui/assets/PlanningModule-B5DWQOGz.js +1 -0
- package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
- package/dist/ui/assets/PlansPage-AY4cGWco.js +1 -0
- package/dist/ui/assets/TaskContextUpload-DZxTVesW.js +1 -0
- package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
- package/dist/ui/assets/TaskSettings-BeWAuyZj.js +12 -0
- package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BifCYtjR.js} +6 -6
- package/dist/ui/assets/WorkflowManagerModule-DEr5di_r.js +1 -0
- package/dist/ui/assets/index-I5zhdtgt.js +7 -0
- package/dist/ui/assets/index-VRFsx3wz.css +1 -0
- package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-D9Lpw-j4.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.js +1 -1
- package/dist/utils/contextAttachmentUpload.d.ts +2 -0
- package/dist/utils/contextAttachmentUpload.js +7 -0
- package/dist/utils/contextFiles.d.ts +1 -1
- package/dist/utils/contextFiles.js +4 -4
- package/dist/utils/taskActivity.d.ts +3 -2
- package/dist/utils/taskActivity.js +19 -2
- package/dist/utils/taskEditorReconciliation.d.ts +40 -0
- package/dist/utils/taskEditorReconciliation.js +217 -0
- package/dist/utils/taskNormalization.d.ts +1 -0
- package/dist/utils/taskNormalization.js +39 -0
- package/dist/utils/taskSearch.js +2 -2
- package/dist/utils/uiNotice.d.ts +4 -0
- package/package.json +21 -4
- package/dist/ui/assets/AiProfilesModule-DPxQeF9N.js +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-CBRZ8rca.css +0 -1
- package/dist/ui/assets/AnnotatedAttachmentWorkspace-DHNYaNg6.js +0 -3
- package/dist/ui/assets/AssetTraySortControl-DphbyHVc.js +0 -1
- package/dist/ui/assets/ContextAttachmentManager-CMxSzHqc.js +0 -3
- package/dist/ui/assets/EntityActivityTimeline-pJ2ZjZ-k.js +0 -1
- package/dist/ui/assets/PlanningModule-CeTqXMMz.css +0 -1
- package/dist/ui/assets/PlanningModule-t5GbvVR9.js +0 -1
- package/dist/ui/assets/PlansPage-BVH_NfgT.js +0 -1
- package/dist/ui/assets/TaskContextUpload-Ds4LnDzV.css +0 -1
- package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
- package/dist/ui/assets/TaskSettings-xVsxSa0g.js +0 -12
- package/dist/ui/assets/WorkflowManagerModule-BKqIGVnF.js +0 -1
- package/dist/ui/assets/index-BzJlVnNS.css +0 -1
- package/dist/ui/assets/index-Cx7vZJHL.js +0 -7
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { Worker } from 'node:worker_threads';
|
|
2
|
+
const DEFAULT_POOL_SIZE = 2;
|
|
3
|
+
const MAX_POOL_SIZE = 8;
|
|
4
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
5
|
+
function positiveInteger(value, fallback) {
|
|
6
|
+
if (!Number.isFinite(value) || Number(value) <= 0)
|
|
7
|
+
return fallback;
|
|
8
|
+
return Math.max(1, Math.floor(Number(value)));
|
|
9
|
+
}
|
|
10
|
+
export class CloudCollectionReadPool {
|
|
11
|
+
slots = [];
|
|
12
|
+
queue = [];
|
|
13
|
+
requestTimeoutMs;
|
|
14
|
+
desiredSize;
|
|
15
|
+
workerData;
|
|
16
|
+
workerFactory;
|
|
17
|
+
nextRequestId = 1;
|
|
18
|
+
closing = false;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.requestTimeoutMs = positiveInteger(options.requestTimeoutMs, DEFAULT_REQUEST_TIMEOUT_MS);
|
|
21
|
+
this.workerData = {
|
|
22
|
+
projectRoot: options.projectRoot,
|
|
23
|
+
tenantId: options.tenantId,
|
|
24
|
+
connectionString: options.connectionString,
|
|
25
|
+
};
|
|
26
|
+
this.workerFactory = options.workerFactory || (() => new Worker(new URL('./cloudCollectionReadWorker.js', import.meta.url), { workerData: this.workerData }));
|
|
27
|
+
this.desiredSize = Math.min(MAX_POOL_SIZE, positiveInteger(options.size, DEFAULT_POOL_SIZE));
|
|
28
|
+
}
|
|
29
|
+
execute(request) {
|
|
30
|
+
if (this.closing) {
|
|
31
|
+
return Promise.reject(new Error('[Taskforce] Cloud collection read pool is closed.'));
|
|
32
|
+
}
|
|
33
|
+
this.ensureSlots();
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
this.queue.push({ request, resolve, reject });
|
|
36
|
+
this.pump();
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async close() {
|
|
40
|
+
if (this.closing)
|
|
41
|
+
return;
|
|
42
|
+
this.closing = true;
|
|
43
|
+
const closedError = new Error('[Taskforce] Cloud collection read pool closed before the request completed.');
|
|
44
|
+
for (const pending of this.queue.splice(0))
|
|
45
|
+
pending.reject(closedError);
|
|
46
|
+
await Promise.all(this.slots.splice(0).map(async (slot) => {
|
|
47
|
+
if (slot.active) {
|
|
48
|
+
clearTimeout(slot.active.timeout);
|
|
49
|
+
slot.active.reject(closedError);
|
|
50
|
+
slot.active = null;
|
|
51
|
+
}
|
|
52
|
+
slot.worker.postMessage({ type: 'close' });
|
|
53
|
+
await slot.worker.terminate();
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
spawnSlot() {
|
|
57
|
+
if (this.closing)
|
|
58
|
+
return;
|
|
59
|
+
const worker = this.workerFactory();
|
|
60
|
+
const slot = { worker, ready: false, active: null };
|
|
61
|
+
this.slots.push(slot);
|
|
62
|
+
worker.on('message', (message) => this.handleMessage(slot, message));
|
|
63
|
+
worker.on('error', (error) => this.handleWorkerFailure(slot, error instanceof Error ? error : new Error(String(error))));
|
|
64
|
+
worker.on('exit', (code) => {
|
|
65
|
+
if (!this.closing && this.slots.includes(slot)) {
|
|
66
|
+
this.handleWorkerFailure(slot, new Error(`[Taskforce] Cloud collection read worker exited with code ${code}.`));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
handleMessage(slot, message) {
|
|
71
|
+
if (message.type === 'ready') {
|
|
72
|
+
slot.ready = true;
|
|
73
|
+
this.ensureSlots();
|
|
74
|
+
this.pump();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const active = slot.active;
|
|
78
|
+
if (!active || active.requestId !== message.requestId)
|
|
79
|
+
return;
|
|
80
|
+
clearTimeout(active.timeout);
|
|
81
|
+
slot.active = null;
|
|
82
|
+
if (message.type === 'result')
|
|
83
|
+
active.resolve(message.response);
|
|
84
|
+
else
|
|
85
|
+
active.reject(new Error(message.error || '[Taskforce] Cloud collection read worker failed.'));
|
|
86
|
+
this.pump();
|
|
87
|
+
}
|
|
88
|
+
handleWorkerFailure(slot, error) {
|
|
89
|
+
const slotIndex = this.slots.indexOf(slot);
|
|
90
|
+
if (slotIndex < 0)
|
|
91
|
+
return;
|
|
92
|
+
this.slots.splice(slotIndex, 1);
|
|
93
|
+
if (slot.active) {
|
|
94
|
+
clearTimeout(slot.active.timeout);
|
|
95
|
+
slot.active.reject(error);
|
|
96
|
+
slot.active = null;
|
|
97
|
+
}
|
|
98
|
+
void slot.worker.terminate();
|
|
99
|
+
if (!this.closing && this.slots.length === 0) {
|
|
100
|
+
for (const pending of this.queue.splice(0))
|
|
101
|
+
pending.reject(error);
|
|
102
|
+
}
|
|
103
|
+
this.pump();
|
|
104
|
+
}
|
|
105
|
+
ensureSlots() {
|
|
106
|
+
if (this.closing)
|
|
107
|
+
return;
|
|
108
|
+
if (this.slots.some((slot) => !slot.ready))
|
|
109
|
+
return;
|
|
110
|
+
if (this.slots.length < this.desiredSize)
|
|
111
|
+
this.spawnSlot();
|
|
112
|
+
}
|
|
113
|
+
pump() {
|
|
114
|
+
if (this.closing || this.queue.length === 0)
|
|
115
|
+
return;
|
|
116
|
+
for (const slot of this.slots) {
|
|
117
|
+
if (!slot.ready || slot.active || this.queue.length === 0)
|
|
118
|
+
continue;
|
|
119
|
+
const pending = this.queue.shift();
|
|
120
|
+
const requestId = this.nextRequestId++;
|
|
121
|
+
const timeout = setTimeout(() => {
|
|
122
|
+
this.handleWorkerFailure(slot, new Error(`[Taskforce] Cloud collection read worker timed out after ${this.requestTimeoutMs}ms.`));
|
|
123
|
+
}, this.requestTimeoutMs);
|
|
124
|
+
timeout.unref?.();
|
|
125
|
+
slot.active = { ...pending, requestId, timeout };
|
|
126
|
+
slot.worker.postMessage({ type: 'execute', requestId, request: pending.request });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
export function resolveCloudCollectionReadPoolSize(env = process.env) {
|
|
131
|
+
if (String(env.TASKFORCE_CLOUD_READ_WORKERS || '').trim() === '0')
|
|
132
|
+
return 0;
|
|
133
|
+
return Math.min(MAX_POOL_SIZE, positiveInteger(Number(env.TASKFORCE_CLOUD_READ_WORKERS), DEFAULT_POOL_SIZE));
|
|
134
|
+
}
|
|
135
|
+
export function shouldUseCloudCollectionReadPool(input) {
|
|
136
|
+
return input.runtimeMode === 'cloud'
|
|
137
|
+
&& input.databaseProvider === 'postgres'
|
|
138
|
+
&& Boolean(String(input.connectionString || '').trim())
|
|
139
|
+
&& input.workerCount > 0;
|
|
140
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { parentPort, workerData } from 'node:worker_threads';
|
|
2
|
+
import { TaskforceCore } from '../core/Taskforce.js';
|
|
3
|
+
import { executeCloudCollectionRead, } from './cloudCollectionRead.js';
|
|
4
|
+
if (!parentPort) {
|
|
5
|
+
throw new Error('[Taskforce] Cloud collection read worker requires a parent port.');
|
|
6
|
+
}
|
|
7
|
+
const config = workerData;
|
|
8
|
+
const core = new TaskforceCore({
|
|
9
|
+
projectRoot: config.projectRoot,
|
|
10
|
+
tenantId: config.tenantId,
|
|
11
|
+
runtimeMode: 'cloud',
|
|
12
|
+
initializationMode: 'cloud-read-worker',
|
|
13
|
+
database: {
|
|
14
|
+
provider: 'postgres',
|
|
15
|
+
connectionString: config.connectionString,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
parentPort.on('message', (message) => {
|
|
19
|
+
if (message.type === 'close') {
|
|
20
|
+
core.close();
|
|
21
|
+
parentPort?.close();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const response = executeCloudCollectionRead(core, message.request);
|
|
26
|
+
parentPort?.postMessage({ type: 'result', requestId: message.requestId, response });
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
parentPort?.postMessage({
|
|
30
|
+
type: 'error',
|
|
31
|
+
requestId: message.requestId,
|
|
32
|
+
error: error instanceof Error ? error.message : String(error),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
parentPort.postMessage({ type: 'ready' });
|
package/dist/server/index.d.ts
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as http from 'http';
|
|
8
8
|
import { WebSocketServer } from 'ws';
|
|
9
|
-
|
|
10
|
-
import type {
|
|
9
|
+
export { resolveAuthorizedWorkspaceAccess, resolveDisabledAccessError, isWorkspaceAccessRecoveryRoute, } from './authorizedWorkspaceAccess.js';
|
|
10
|
+
import type { LocalServiceCloudTarget } from '../config/localServiceCloudTarget.js';
|
|
11
|
+
import type { LocalServiceRuntimeContract } from '../config/localServiceRuntimeContract.js';
|
|
11
12
|
import type { LocalSyncCoordinatorHost } from '../sync/coordinator/localSyncCoordinatorHost.js';
|
|
12
13
|
import type { LocalSyncProcessLock } from '../sync/coordinator/localSyncProcessLock.js';
|
|
13
14
|
import type { LocalDataOwnerPermit } from './localDataOwnerPermit.js';
|
|
@@ -25,6 +26,8 @@ export interface StandaloneServerOptions {
|
|
|
25
26
|
ownerPid: number;
|
|
26
27
|
bootstrapCapability: string;
|
|
27
28
|
ownershipKey: string;
|
|
29
|
+
cloudTarget: LocalServiceCloudTarget;
|
|
30
|
+
runtimeContract: LocalServiceRuntimeContract;
|
|
28
31
|
};
|
|
29
32
|
}
|
|
30
33
|
export interface TaskforceStandaloneServer extends http.Server {
|
|
@@ -45,17 +48,10 @@ export declare const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = "x-taskforce-origin-p
|
|
|
45
48
|
export declare const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = "x-taskforce-origin-base-url";
|
|
46
49
|
export declare const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = "x-taskforce-origin-runtime";
|
|
47
50
|
export declare const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = "x-taskforce-cloud-environment";
|
|
48
|
-
|
|
49
|
-
disabled?: boolean;
|
|
50
|
-
accountDisabled?: boolean;
|
|
51
|
-
workspaceDisabled?: boolean;
|
|
52
|
-
}
|
|
53
|
-
export declare function isWorkspaceAccessRecoveryRoute(pathname: string): boolean;
|
|
54
|
-
export declare function resolveDisabledAccessError(access: Pick<AuthorizedRequestAccess, 'disabled' | 'accountDisabled' | 'workspaceDisabled'>, pathname: string): string | null;
|
|
51
|
+
export declare function sanitizeQaRunIdHeader(raw: unknown): string;
|
|
55
52
|
export declare function shouldProxyCloudPath(pathname: string): boolean;
|
|
56
53
|
export declare function shouldProxyCloudRequest(url: Pick<URL, 'pathname' | 'searchParams'>, env?: NodeJS.ProcessEnv): boolean;
|
|
57
54
|
export declare function resolveCloudProxyUpstreamBaseUrl(req: http.IncomingMessage, fallbackBaseUrl: string): string;
|
|
58
|
-
export declare function resolveAuthorizedWorkspaceAccess(core: Pick<TaskforceCore, 'resolveUserAccess' | 'getSystemRole'>, access: AuthorizedRequestAccess, requestedWorkspaceId: string): AuthorizedRequestAccess;
|
|
59
55
|
export declare function shouldApplyReadOnlyMutationGuard(methodRaw: string | undefined, pathname: string): boolean;
|
|
60
56
|
export declare function resolveEffectiveRequestUserId(accessUserId: string, explicitUserId: string): string;
|
|
61
57
|
export declare function resolveMaxPayloadBytesForPath(pathname: string, defaultMaxBytes: number): number;
|
|
@@ -72,4 +68,3 @@ export declare function ensurePublicPricingAuthExclusion(excludedPaths: string[]
|
|
|
72
68
|
export declare function ensurePublicSiteConfigAuthExclusion(excludedPaths: string[]): string[];
|
|
73
69
|
export declare function isBillingWebhookPath(pathname: string): boolean;
|
|
74
70
|
export declare function createStandaloneServer(options: StandaloneServerOptions): TaskforceStandaloneServer;
|
|
75
|
-
export {};
|
package/dist/server/index.js
CHANGED
|
@@ -14,9 +14,12 @@ import chokidar from 'chokidar';
|
|
|
14
14
|
import { TaskforceCore } from '../core/Taskforce.js';
|
|
15
15
|
import { createRoutes, matchRoute } from './routes.js';
|
|
16
16
|
import { formatApiErrorResponse } from './routes/primitives.js';
|
|
17
|
+
import { logSlowBootstrapRoute } from './routes/shared.js';
|
|
17
18
|
import { applyCorsHeaders, getAllowedOriginsFromEnv } from './cors.js';
|
|
18
|
-
import { applyPrefixedRateLimitHeaders, applyRateLimitHeaders, InMemoryRateLimiter, resolveRateLimitKey } from './rateLimit.js';
|
|
19
|
+
import { applyPrefixedRateLimitHeaders, applyRateLimitHeaders, InMemoryRateLimiter, isWorkspaceSyncFeedRead, resolveRateLimitKey, } from './rateLimit.js';
|
|
19
20
|
import { isRequestAuthorized, resolveAuthConfigFromEnv, resolveRequestAccess } from './auth.js';
|
|
21
|
+
import { resolveAuthorizedWorkspaceAccess, resolveDisabledAccessError, } from './authorizedWorkspaceAccess.js';
|
|
22
|
+
export { resolveAuthorizedWorkspaceAccess, resolveDisabledAccessError, isWorkspaceAccessRecoveryRoute, } from './authorizedWorkspaceAccess.js';
|
|
20
23
|
import { assertCloudDatabaseProvider, resolveRuntimeModeFromEnv } from './runtimeMode.js';
|
|
21
24
|
import { applySecurityHeaders } from './securityHeaders.js';
|
|
22
25
|
import { resolveDatabaseConfigFromEnv } from '../storage/providerConfig.js';
|
|
@@ -37,6 +40,8 @@ import { createWorkspaceSyncServerComposition, shutdownWorkspaceSyncServerCompos
|
|
|
37
40
|
import { LocalServiceSessionManager } from './localServiceSessions.js';
|
|
38
41
|
import { LocalSyncIdentityStore } from '../sync/v3/localSyncIdentityStore.js';
|
|
39
42
|
import { shouldBroadcastLocalFileInvalidation } from './localRealtimeFileInvalidation.js';
|
|
43
|
+
import { resolveCloudCollectionReadOperation, } from './cloudCollectionRead.js';
|
|
44
|
+
import { CloudCollectionReadPool, resolveCloudCollectionReadPoolSize, shouldUseCloudCollectionReadPool, } from './cloudCollectionReadPool.js';
|
|
40
45
|
const __filename = fileURLToPath(import.meta.url);
|
|
41
46
|
const __dirname = path.dirname(__filename);
|
|
42
47
|
const MIME_TYPES = {
|
|
@@ -173,20 +178,11 @@ export const TASKFORCE_PROXY_ORIGIN_PROTO_HEADER = 'x-taskforce-origin-proto';
|
|
|
173
178
|
export const TASKFORCE_PROXY_ORIGIN_BASE_URL_HEADER = 'x-taskforce-origin-base-url';
|
|
174
179
|
export const TASKFORCE_PROXY_ORIGIN_RUNTIME_HEADER = 'x-taskforce-origin-runtime';
|
|
175
180
|
export const TASKFORCE_PROXY_CLOUD_ENVIRONMENT_HEADER = 'x-taskforce-cloud-environment';
|
|
176
|
-
export function
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (pathname.startsWith('/api/taskforce/auth/'))
|
|
182
|
-
return null;
|
|
183
|
-
if (access.accountDisabled ?? access.disabled) {
|
|
184
|
-
return 'Forbidden: user account is disabled.';
|
|
185
|
-
}
|
|
186
|
-
if (access.workspaceDisabled && !isWorkspaceAccessRecoveryRoute(pathname)) {
|
|
187
|
-
return 'Forbidden: workspace access is not active for this user.';
|
|
188
|
-
}
|
|
189
|
-
return null;
|
|
181
|
+
export function sanitizeQaRunIdHeader(raw) {
|
|
182
|
+
const normalized = String(Array.isArray(raw) ? raw[0] : raw || '')
|
|
183
|
+
.trim()
|
|
184
|
+
.replace(/[^A-Za-z0-9._-]+/g, '-');
|
|
185
|
+
return normalized.slice(0, 128) || '-';
|
|
190
186
|
}
|
|
191
187
|
function shouldLogRefreshDiagnostic(pathname) {
|
|
192
188
|
return REFRESH_DIAGNOSTIC_PATH_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(prefix));
|
|
@@ -301,31 +297,6 @@ export function resolveCloudProxyUpstreamBaseUrl(req, fallbackBaseUrl) {
|
|
|
301
297
|
return fallbackBaseUrl;
|
|
302
298
|
return TASKFORCE_CLOUD_ENVIRONMENTS[requestedEnvironment].appBaseUrl;
|
|
303
299
|
}
|
|
304
|
-
export function resolveAuthorizedWorkspaceAccess(core, access, requestedWorkspaceId) {
|
|
305
|
-
if (!access.authenticated || !access.userId || access.userId === 'anonymous')
|
|
306
|
-
return access;
|
|
307
|
-
const trimmedRequestedWorkspaceId = String(requestedWorkspaceId || '').trim();
|
|
308
|
-
const candidateWorkspaceIds = [
|
|
309
|
-
trimmedRequestedWorkspaceId,
|
|
310
|
-
String(access.workspaceId || '').trim()
|
|
311
|
-
].filter((workspaceId, index, values) => Boolean(workspaceId) && values.indexOf(workspaceId) === index);
|
|
312
|
-
for (const workspaceId of candidateWorkspaceIds) {
|
|
313
|
-
const resolved = core.resolveUserAccess(access.userId, workspaceId, access.role);
|
|
314
|
-
if (!resolved)
|
|
315
|
-
continue;
|
|
316
|
-
return {
|
|
317
|
-
...access,
|
|
318
|
-
role: resolved.role,
|
|
319
|
-
workspaceId: resolved.workspaceId,
|
|
320
|
-
userId: resolved.userId,
|
|
321
|
-
systemRole: core.getSystemRole(resolved.userId),
|
|
322
|
-
disabled: resolved.disabled,
|
|
323
|
-
accountDisabled: resolved.accountDisabled ?? resolved.disabled,
|
|
324
|
-
workspaceDisabled: resolved.workspaceDisabled ?? false
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
return access;
|
|
328
|
-
}
|
|
329
300
|
export function shouldApplyReadOnlyMutationGuard(methodRaw, pathname) {
|
|
330
301
|
const method = String(methodRaw || 'GET').toUpperCase();
|
|
331
302
|
if (method !== 'POST' && method !== 'PATCH' && method !== 'DELETE')
|
|
@@ -673,16 +644,33 @@ export function createStandaloneServer(options) {
|
|
|
673
644
|
},
|
|
674
645
|
} : undefined,
|
|
675
646
|
});
|
|
647
|
+
const cloudCollectionReadWorkerCount = resolveCloudCollectionReadPoolSize(process.env);
|
|
648
|
+
const cloudCollectionReadPool = shouldUseCloudCollectionReadPool({
|
|
649
|
+
runtimeMode,
|
|
650
|
+
databaseProvider: db.provider,
|
|
651
|
+
connectionString: db.connectionString,
|
|
652
|
+
workerCount: cloudCollectionReadWorkerCount,
|
|
653
|
+
})
|
|
654
|
+
? new CloudCollectionReadPool({
|
|
655
|
+
projectRoot: options.projectRoot,
|
|
656
|
+
tenantId: core.getTenantId(),
|
|
657
|
+
connectionString: db.connectionString,
|
|
658
|
+
size: cloudCollectionReadWorkerCount,
|
|
659
|
+
})
|
|
660
|
+
: null;
|
|
676
661
|
const allowedOrigins = getAllowedOriginsFromEnv(process.env.TASKFORCE_ALLOWED_ORIGINS, runtimeMode);
|
|
677
662
|
const rateLimitEnabled = typeof process.env.TASKFORCE_API_RATE_LIMIT_ENABLED === 'string'
|
|
678
663
|
? process.env.TASKFORCE_API_RATE_LIMIT_ENABLED !== 'false'
|
|
679
664
|
: (runtimeMode === 'cloud');
|
|
680
665
|
const rateLimitLimit = Number.parseInt(process.env.TASKFORCE_API_RATE_LIMIT_MAX_REQUESTS || '', 10) || 120;
|
|
681
666
|
const rateLimitWindowMs = Number.parseInt(process.env.TASKFORCE_API_RATE_LIMIT_WINDOW_MS || '', 10) || 60_000;
|
|
667
|
+
const syncFeedRateLimit = Number.parseInt(process.env.TASKFORCE_SYNC_FEED_RATE_LIMIT_MAX_REQUESTS || '', 10) || 600;
|
|
668
|
+
const syncFeedRateLimitWindowMs = Number.parseInt(process.env.TASKFORCE_SYNC_FEED_RATE_LIMIT_WINDOW_MS || '', 10) || 60_000;
|
|
682
669
|
const webhookRateLimitMaxRequests = Number.parseInt(process.env.TASKFORCE_STRIPE_WEBHOOK_RATE_LIMIT_MAX_REQUESTS || '', 10) || 600;
|
|
683
670
|
const webhookRateLimitWindowMs = Number.parseInt(process.env.TASKFORCE_STRIPE_WEBHOOK_RATE_LIMIT_WINDOW_MS || '', 10) || 60_000;
|
|
684
671
|
const maxPayloadBytes = Number.parseInt(process.env.TASKFORCE_MAX_PAYLOAD_BYTES || '', 10) || 1_048_576;
|
|
685
672
|
const rateLimiter = new InMemoryRateLimiter(rateLimitLimit, rateLimitWindowMs);
|
|
673
|
+
const syncFeedRateLimiter = new InMemoryRateLimiter(syncFeedRateLimit, syncFeedRateLimitWindowMs);
|
|
686
674
|
const webhookRateLimiter = new InMemoryRateLimiter(webhookRateLimitMaxRequests, webhookRateLimitWindowMs);
|
|
687
675
|
const resolveAuthRateLimitSettings = () => {
|
|
688
676
|
const auth = core.getGlobalSettings().auth || {};
|
|
@@ -786,7 +774,8 @@ export function createStandaloneServer(options) {
|
|
|
786
774
|
const requestId = String(req.headers['x-request-id'] || req.headers['x-railway-request-id'] || '').trim() || '-';
|
|
787
775
|
const workspaceId = String(req.headers['x-taskforce-workspace-id'] || '').trim() || '-';
|
|
788
776
|
const userId = String(req.headers['x-taskforce-user-id'] || '').trim() || '-';
|
|
789
|
-
|
|
777
|
+
const qaRunId = sanitizeQaRunIdHeader(req.headers['x-taskforce-qa-run-id']);
|
|
778
|
+
console.info(`[Taskforce RefreshDiag] method=${method} path=${pathname} status=${statusCode} durationMs=${durationMs} requestId=${requestId} workspaceId=${workspaceId} userId=${userId} qaRunId=${qaRunId}`);
|
|
790
779
|
};
|
|
791
780
|
// Resolve static files directory at runtime
|
|
792
781
|
// Standalone UI source now lives in apps/app and builds to dist/ui.
|
|
@@ -1013,7 +1002,9 @@ export function createStandaloneServer(options) {
|
|
|
1013
1002
|
});
|
|
1014
1003
|
const rateLimitResult = isBillingWebhook
|
|
1015
1004
|
? webhookRateLimiter.check(key)
|
|
1016
|
-
:
|
|
1005
|
+
: isWorkspaceSyncFeedRead(req.method, url.pathname)
|
|
1006
|
+
? syncFeedRateLimiter.check(key)
|
|
1007
|
+
: rateLimiter.check(key);
|
|
1017
1008
|
if (isBillingWebhook) {
|
|
1018
1009
|
applyPrefixedRateLimitHeaders(res, rateLimitResult, 'X-Webhook-RateLimit');
|
|
1019
1010
|
}
|
|
@@ -1066,6 +1057,39 @@ export function createStandaloneServer(options) {
|
|
|
1066
1057
|
res.end(JSON.stringify({ error: auth.reason || 'Unauthorized' }));
|
|
1067
1058
|
return;
|
|
1068
1059
|
}
|
|
1060
|
+
const cloudCollectionReadOperation = cloudCollectionReadPool
|
|
1061
|
+
? resolveCloudCollectionReadOperation(req.method, url.pathname)
|
|
1062
|
+
: null;
|
|
1063
|
+
if (cloudCollectionReadPool && cloudCollectionReadOperation) {
|
|
1064
|
+
try {
|
|
1065
|
+
const requestedWorkspaceId = Array.isArray(req.headers['x-taskforce-workspace-id'])
|
|
1066
|
+
? String(req.headers['x-taskforce-workspace-id'][0] || '')
|
|
1067
|
+
: String(req.headers['x-taskforce-workspace-id'] || '');
|
|
1068
|
+
const response = await cloudCollectionReadPool.execute({
|
|
1069
|
+
operation: cloudCollectionReadOperation,
|
|
1070
|
+
pathname: url.pathname,
|
|
1071
|
+
requestedWorkspaceId,
|
|
1072
|
+
access: accessForRateLimit,
|
|
1073
|
+
performanceTrace: String(req.headers['x-taskforce-performance-trace'] || '').trim() === '1',
|
|
1074
|
+
});
|
|
1075
|
+
if (response.performance) {
|
|
1076
|
+
logSlowBootstrapRoute({
|
|
1077
|
+
route: url.pathname,
|
|
1078
|
+
workspaceId: response.workspaceId,
|
|
1079
|
+
traceId: String(req.headers['x-taskforce-bootstrap-trace-id'] || '').trim(),
|
|
1080
|
+
durationMs: response.performance.durationMs,
|
|
1081
|
+
details: response.performance.details,
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
response.headers['X-Taskforce-Cloud-Read-Execution'] = 'worker';
|
|
1085
|
+
res.writeHead(response.statusCode, response.headers);
|
|
1086
|
+
res.end(response.body);
|
|
1087
|
+
return;
|
|
1088
|
+
}
|
|
1089
|
+
catch (error) {
|
|
1090
|
+
console.error(`[Taskforce] Cloud collection read worker failed; using synchronous fallback path=${url.pathname}:`, error instanceof Error ? error.message : String(error));
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1069
1093
|
const pathname = url.pathname;
|
|
1070
1094
|
const isMutation = shouldApplyReadOnlyMutationGuard(req.method, pathname);
|
|
1071
1095
|
let access = accessForRateLimit;
|
|
@@ -1203,6 +1227,7 @@ export function createStandaloneServer(options) {
|
|
|
1203
1227
|
if (serverResult.status === 'rejected') {
|
|
1204
1228
|
throw serverResult.reason;
|
|
1205
1229
|
}
|
|
1230
|
+
await cloudCollectionReadPool?.close();
|
|
1206
1231
|
},
|
|
1207
1232
|
closeCore: () => core.close(),
|
|
1208
1233
|
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { type LocalServiceCloudTarget } from '../config/localServiceCloudTarget.js';
|
|
2
|
+
import { type LocalServiceRuntimeContract } from '../config/localServiceRuntimeContract.js';
|
|
1
3
|
import { type WindowsAclCommandRunner } from './localServiceWindowsAcl.js';
|
|
2
4
|
export interface LocalServiceDescriptor {
|
|
3
5
|
schemaVersion: 1;
|
|
@@ -9,6 +11,8 @@ export interface LocalServiceDescriptor {
|
|
|
9
11
|
generation: string;
|
|
10
12
|
bootstrapCapability: string;
|
|
11
13
|
publishedAt: string;
|
|
14
|
+
cloudTarget?: LocalServiceCloudTarget | null;
|
|
15
|
+
runtimeContract?: LocalServiceRuntimeContract | null;
|
|
12
16
|
}
|
|
13
17
|
export interface LocalServiceLeaseIdentityInput {
|
|
14
18
|
projectRoot: string;
|
|
@@ -27,6 +31,8 @@ export interface LocalServiceDescriptorPublication {
|
|
|
27
31
|
endpoint: string;
|
|
28
32
|
protocolVersion: string;
|
|
29
33
|
appVersion: string;
|
|
34
|
+
cloudTarget: LocalServiceCloudTarget;
|
|
35
|
+
runtimeContract: LocalServiceRuntimeContract;
|
|
30
36
|
}
|
|
31
37
|
export interface LocalServiceLease {
|
|
32
38
|
readonly identity: LocalServiceLeaseIdentity;
|
|
@@ -3,6 +3,8 @@ import * as fs from 'fs';
|
|
|
3
3
|
import * as net from 'net';
|
|
4
4
|
import * as os from 'os';
|
|
5
5
|
import * as path from 'path';
|
|
6
|
+
import { parseLocalServiceCloudTarget, } from '../config/localServiceCloudTarget.js';
|
|
7
|
+
import { parseLocalServiceRuntimeContract, } from '../config/localServiceRuntimeContract.js';
|
|
6
8
|
import { resolveLocalSyncProcessLockIdentity } from './localDatabaseIdentity.js';
|
|
7
9
|
import { ensureWindowsUserOnlyDirectoryAcl, } from './localServiceWindowsAcl.js';
|
|
8
10
|
const DESCRIPTOR_SCHEMA_VERSION = 1;
|
|
@@ -161,8 +163,20 @@ function parseDescriptor(value, ownershipKey) {
|
|
|
161
163
|
|| typeof value.publishedAt !== 'string') {
|
|
162
164
|
throw new Error('Local service descriptor is invalid.');
|
|
163
165
|
}
|
|
166
|
+
const cloudTarget = value.cloudTarget == null
|
|
167
|
+
? null
|
|
168
|
+
: parseLocalServiceCloudTarget(value.cloudTarget);
|
|
169
|
+
if (value.cloudTarget != null && !cloudTarget) {
|
|
170
|
+
throw new Error('Local service descriptor cloud target is invalid.');
|
|
171
|
+
}
|
|
172
|
+
const runtimeContract = value.runtimeContract == null
|
|
173
|
+
? null
|
|
174
|
+
: parseLocalServiceRuntimeContract(value.runtimeContract);
|
|
175
|
+
if (value.runtimeContract != null && !runtimeContract) {
|
|
176
|
+
throw new Error('Local service descriptor runtime contract is invalid.');
|
|
177
|
+
}
|
|
164
178
|
assertLoopbackEndpoint(value.endpoint);
|
|
165
|
-
return value;
|
|
179
|
+
return { ...value, cloudTarget, runtimeContract };
|
|
166
180
|
}
|
|
167
181
|
function readOptionalDescriptor(identity) {
|
|
168
182
|
try {
|
|
@@ -363,6 +377,8 @@ export async function acquireLocalServiceLease(input, dependencies = {}) {
|
|
|
363
377
|
generation,
|
|
364
378
|
bootstrapCapability,
|
|
365
379
|
publishedAt: (dependencies.now?.() || new Date()).toISOString(),
|
|
380
|
+
cloudTarget: publication.cloudTarget,
|
|
381
|
+
runtimeContract: publication.runtimeContract,
|
|
366
382
|
};
|
|
367
383
|
publishJsonFileAtomically(identity.descriptorPath, descriptor, platform);
|
|
368
384
|
return descriptor;
|
|
@@ -15,6 +15,7 @@ import { createWorkspaceSyncEngineServerRunnerOperations } from '../sync/engine/
|
|
|
15
15
|
import { workspaceSyncTransferEvidenceEvent } from '../sync/engine/workspaceSyncTransferEvidence.js';
|
|
16
16
|
import { createWorkspaceSyncEngineServerPushCandidateProvider, createWorkspaceSyncEngineServerSnapshotReader, } from '../sync/engine/workspaceSyncEngineServerSnapshotReader.js';
|
|
17
17
|
import { readWorkspaceSyncLocalOwnershipSnapshot } from '../sync/v3/workspaceSyncLocalOwnershipSnapshot.js';
|
|
18
|
+
import { resolveRequestedCombinedFeedCoverage } from '../sync/v3/combinedFeedCapability.js';
|
|
18
19
|
import { resolveWorkspaceSyncV3CombinedWireContract, } from '../sync/v3/workspaceSyncV3CombinedWireContract.js';
|
|
19
20
|
import { LocalWorkspaceSyncServerOutboxDispatcher, } from '../sync/v3/localWorkspaceSyncServerOutboxDispatcher.js';
|
|
20
21
|
import { readWorkspaceSyncV3LocalOutboxStatus, } from '../sync/v3/workspaceSyncV3LocalOutboxStatus.js';
|
|
@@ -950,15 +951,21 @@ export class LocalWorkspaceSyncServerRuntime {
|
|
|
950
951
|
if (combined.owner === 'v3' && !combinedContract) {
|
|
951
952
|
throw Object.assign(new Error('The persisted combined-feed ownership contract is invalid.'), { code: 'SYNC_RUNNER_V3_OWNERSHIP_INVALID' });
|
|
952
953
|
}
|
|
954
|
+
const desiredCombinedCoverage = combined.owner === 'v3'
|
|
955
|
+
? resolveRequestedCombinedFeedCoverage(this.options.env || process.env)
|
|
956
|
+
: null;
|
|
957
|
+
const desiredCombinedContract = desiredCombinedCoverage
|
|
958
|
+
? resolveWorkspaceSyncV3CombinedWireContract(desiredCombinedCoverage)
|
|
959
|
+
: null;
|
|
953
960
|
return {
|
|
954
961
|
initiativeFeedActivationEnabled: ownership.initiativeProjection.owner === 'v3',
|
|
955
962
|
initiativeProjection: ownership.initiativeProjection,
|
|
956
963
|
combinedFeedActivationEnabled: combined.owner === 'v3',
|
|
957
964
|
combinedProjection: combined,
|
|
958
|
-
...(combinedContract
|
|
965
|
+
...(combinedContract && desiredCombinedContract
|
|
959
966
|
? {
|
|
960
|
-
combinedFeedCoverage:
|
|
961
|
-
combinedFeedExcludedProjections:
|
|
967
|
+
combinedFeedCoverage: desiredCombinedContract.coverage,
|
|
968
|
+
combinedFeedExcludedProjections: desiredCombinedContract.excludedProjections,
|
|
962
969
|
}
|
|
963
970
|
: {}),
|
|
964
971
|
};
|
|
@@ -26,5 +26,6 @@ export declare function resolveRateLimitKey(params: {
|
|
|
26
26
|
sessionId?: string | null;
|
|
27
27
|
userId?: string | null;
|
|
28
28
|
}): string;
|
|
29
|
+
export declare function isWorkspaceSyncFeedRead(method: string | undefined, pathname: string): boolean;
|
|
29
30
|
export declare function applyRateLimitHeaders(res: ServerResponse, result: RateLimitResult): void;
|
|
30
31
|
export declare function applyPrefixedRateLimitHeaders(res: ServerResponse, result: RateLimitResult, prefix: string): void;
|
package/dist/server/rateLimit.js
CHANGED
|
@@ -97,6 +97,10 @@ export function resolveRateLimitKey(params) {
|
|
|
97
97
|
}
|
|
98
98
|
return `ip:${ip}:${method}:${route}`;
|
|
99
99
|
}
|
|
100
|
+
export function isWorkspaceSyncFeedRead(method, pathname) {
|
|
101
|
+
return String(method || 'GET').trim().toUpperCase() === 'GET'
|
|
102
|
+
&& pathname === '/api/taskforce/sync/v3/workspace/feed';
|
|
103
|
+
}
|
|
100
104
|
export function applyRateLimitHeaders(res, result) {
|
|
101
105
|
res.setHeader('X-RateLimit-Limit', String(result.limit));
|
|
102
106
|
res.setHeader('X-RateLimit-Remaining', String(result.remaining));
|
|
@@ -68,23 +68,34 @@ export function createRealtimeSyncWsManager(core, authConfig, logger = console,
|
|
|
68
68
|
}
|
|
69
69
|
connections.delete(ws);
|
|
70
70
|
};
|
|
71
|
-
const
|
|
71
|
+
const resolveSubscriptionAccess = (state, workspaceId) => {
|
|
72
72
|
if (!workspaceId)
|
|
73
|
-
return
|
|
73
|
+
return 'forbidden';
|
|
74
74
|
if (!authConfig.enabled || !authConfig.requiredForApi)
|
|
75
|
-
return
|
|
75
|
+
return 'allowed';
|
|
76
76
|
if (!state.authenticated || !state.userId || state.userId === 'anonymous')
|
|
77
|
-
return
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
return 'forbidden';
|
|
78
|
+
try {
|
|
79
|
+
const resolved = core.resolveUserAccess(state.userId, workspaceId, state.role);
|
|
80
|
+
return resolved?.workspaceId === workspaceId ? 'allowed' : 'forbidden';
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
logger.warn(`[Taskforce] WebSocket access check unavailable workspace=${workspaceId}: ${String(error instanceof Error ? error.message : error)}`);
|
|
84
|
+
return 'unavailable';
|
|
85
|
+
}
|
|
80
86
|
};
|
|
81
87
|
const closeUnauthorized = (ws, reason) => {
|
|
82
88
|
logger.warn(`[Taskforce] WebSocket rejected: ${reason}`);
|
|
83
89
|
ws.close(1008, reason);
|
|
84
90
|
};
|
|
85
91
|
const subscribeWorkspace = (ws, state, workspaceId) => {
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
const accessDecision = resolveSubscriptionAccess(state, workspaceId);
|
|
93
|
+
if (accessDecision !== 'allowed') {
|
|
94
|
+
send(ws, {
|
|
95
|
+
type: 'taskforce:subscription-error',
|
|
96
|
+
workspaceId,
|
|
97
|
+
reason: accessDecision === 'unavailable' ? 'temporarily-unavailable' : 'forbidden'
|
|
98
|
+
});
|
|
88
99
|
return;
|
|
89
100
|
}
|
|
90
101
|
state.workspaceIds.add(workspaceId);
|
|
@@ -132,8 +143,13 @@ export function createRealtimeSyncWsManager(core, authConfig, logger = console,
|
|
|
132
143
|
send(ws, { type: 'taskforce:replay-error', reason: 'workspace-required' });
|
|
133
144
|
return;
|
|
134
145
|
}
|
|
135
|
-
|
|
136
|
-
|
|
146
|
+
const accessDecision = resolveSubscriptionAccess(state, workspaceId);
|
|
147
|
+
if (accessDecision !== 'allowed') {
|
|
148
|
+
send(ws, {
|
|
149
|
+
type: 'taskforce:replay-error',
|
|
150
|
+
workspaceId,
|
|
151
|
+
reason: accessDecision === 'unavailable' ? 'temporarily-unavailable' : 'forbidden'
|
|
152
|
+
});
|
|
137
153
|
return;
|
|
138
154
|
}
|
|
139
155
|
state.workspaceIds.add(workspaceId);
|
|
@@ -191,8 +207,16 @@ export function createRealtimeSyncWsManager(core, authConfig, logger = console,
|
|
|
191
207
|
connections.set(ws, state);
|
|
192
208
|
logger.log(`[Taskforce] WebSocket client connected user=${state.userId}`);
|
|
193
209
|
const initialWorkspaceId = parseWorkspaceId(access.workspaceId);
|
|
194
|
-
if (initialWorkspaceId
|
|
195
|
-
state
|
|
210
|
+
if (initialWorkspaceId) {
|
|
211
|
+
const accessDecision = resolveSubscriptionAccess(state, initialWorkspaceId);
|
|
212
|
+
if (accessDecision === 'unavailable') {
|
|
213
|
+
ws.close(1013, 'access-unavailable');
|
|
214
|
+
removeConnection(ws);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (accessDecision === 'allowed') {
|
|
218
|
+
state.workspaceIds.add(initialWorkspaceId);
|
|
219
|
+
}
|
|
196
220
|
}
|
|
197
221
|
ws.on('message', (rawData) => {
|
|
198
222
|
const payload = parseJson(rawData);
|
|
@@ -1953,6 +1953,7 @@ export function registerAdminRoutes(deps) {
|
|
|
1953
1953
|
workspaceAssetStore,
|
|
1954
1954
|
publishedContentResolver,
|
|
1955
1955
|
repairMissingAssetLinks: true,
|
|
1956
|
+
repairMissingContentFiles: body?.repairMissingContentFiles === true,
|
|
1956
1957
|
aiProfiles: typeof core.listAiProfiles === 'function'
|
|
1957
1958
|
? core.listAiProfiles(workspaceId, { includeArchived: true }) || []
|
|
1958
1959
|
: [],
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY,
|
|
1
|
+
import { TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY, } from '../../runtime/appGates.js';
|
|
2
|
+
import { resolveNodeAppGateAccess } from '../../runtime/nodeAppGates.js';
|
|
2
3
|
import { AgentRoleDefinitionValidationError } from '../../shared/agentRoleDefinition.js';
|
|
3
4
|
import { AgentRoleConflictError, AgentRoleNotFoundError, AgentRoleRetiredError, AgentRoleStore, } from '../../storage/agentRoleStore.js';
|
|
4
5
|
import { parseJsonBody } from './primitives.js';
|
|
@@ -128,7 +129,7 @@ export function registerAgentRolesRoutes(deps) {
|
|
|
128
129
|
const guard = (req, res) => {
|
|
129
130
|
if (!ensureAppAccess(req, res))
|
|
130
131
|
return false;
|
|
131
|
-
const gate =
|
|
132
|
+
const gate = resolveNodeAppGateAccess(TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY);
|
|
132
133
|
if (gate.allowed)
|
|
133
134
|
return true;
|
|
134
135
|
writeJson(res, 403, {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY,
|
|
1
|
+
import { TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY, } from '../../runtime/appGates.js';
|
|
2
|
+
import { resolveNodeAppGateAccess } from '../../runtime/nodeAppGates.js';
|
|
2
3
|
import { compileTaskforceAgentSkillPrompt } from '../../shared/taskforceAgentSkill.js';
|
|
3
4
|
import { TaskforceAgentStore } from '../../storage/taskforceAgentStore.js';
|
|
4
5
|
import { TaskforceAgentSkillConflictError, TaskforceAgentSkillStore, } from '../../storage/taskforceAgentSkillStore.js';
|
|
@@ -73,7 +74,7 @@ export function registerAgentSkillsRoutes(deps) {
|
|
|
73
74
|
const ensureFeatureAccess = (req, res) => {
|
|
74
75
|
if (!ensureAppAccess(req, res))
|
|
75
76
|
return false;
|
|
76
|
-
const gate =
|
|
77
|
+
const gate = resolveNodeAppGateAccess(TASKFORCE_AGENTS_WORKSPACE_FEATURE_KEY);
|
|
77
78
|
if (gate.allowed)
|
|
78
79
|
return true;
|
|
79
80
|
writeJson(res, 403, {
|