@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
|
@@ -17,9 +17,11 @@ import { parseJsonBody } from './primitives.js';
|
|
|
17
17
|
import { resolveRequestAccess, createSessionTokenCookie, resolveSessionCookieAttributesForRequest, } from '../auth.js';
|
|
18
18
|
import { isWorkspaceSwitchingEnabledForRuntime } from '../../shared/runtimeContract.js';
|
|
19
19
|
import { getRouteTimingNow, logSlowBootstrapRoute, requestBootstrapTraceId, resolveErrorStatusCode, serializeJsonWithTiming, setServerTimingHeader } from './shared.js';
|
|
20
|
+
import { WorkspaceDeletionAdmission } from '../workspaceDeletionAdmission.js';
|
|
20
21
|
// === SECTION: Registration ===
|
|
21
22
|
export function registerWorkspaceRoutes(deps) {
|
|
22
23
|
const { addRoute, core, context, ensureAppAccess, auditAuthAction, getObjectStorageClient, ensureWithinDir, sanitizeStorageSegment, sanitizeTaskIdForPath, normalizeDocumentPathInput, } = deps;
|
|
24
|
+
const workspaceDeletionAdmission = new WorkspaceDeletionAdmission();
|
|
23
25
|
// === SECTION: Storage cleanup helper ===
|
|
24
26
|
const cleanupDeletedWorkspaceStorage = async (summary) => {
|
|
25
27
|
const warnings = [];
|
|
@@ -231,12 +233,49 @@ export function registerWorkspaceRoutes(deps) {
|
|
|
231
233
|
res.end(JSON.stringify({ success: false, error: 'workspaceId is required.', code: 'WORKSPACE_ID_REQUIRED' }));
|
|
232
234
|
return;
|
|
233
235
|
}
|
|
234
|
-
const
|
|
236
|
+
const writeAdmissionError = (decision) => {
|
|
237
|
+
res.setHeader('Retry-After', String(Math.max(1, Math.ceil(decision.retryAfterMs / 1_000))));
|
|
238
|
+
const inProgress = decision.code === 'WORKSPACE_DELETE_IN_PROGRESS';
|
|
239
|
+
res.writeHead(inProgress ? 409 : 429, { 'Content-Type': 'application/json' });
|
|
240
|
+
res.end(JSON.stringify({
|
|
241
|
+
success: false,
|
|
242
|
+
error: inProgress
|
|
243
|
+
? 'Workspace deletion is already running for this workspace.'
|
|
244
|
+
: 'Workspace deletion was attempted recently. Wait before retrying.',
|
|
245
|
+
code: decision.code,
|
|
246
|
+
retryAfterMs: decision.retryAfterMs,
|
|
247
|
+
}));
|
|
248
|
+
};
|
|
249
|
+
const existingAdmission = workspaceDeletionAdmission.checkExisting(targetWorkspaceId);
|
|
250
|
+
if (existingAdmission) {
|
|
251
|
+
writeAdmissionError(existingAdmission);
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
let resolvedAccess;
|
|
255
|
+
try {
|
|
256
|
+
resolvedAccess = core.resolveUserAccess(access.userId, targetWorkspaceId, 'member');
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
const statusCode = resolveErrorStatusCode(error, 400);
|
|
260
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
261
|
+
res.end(JSON.stringify({
|
|
262
|
+
success: false,
|
|
263
|
+
error: String(error?.message || 'Unable to resolve workspace access'),
|
|
264
|
+
code: error?.code,
|
|
265
|
+
}));
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
235
268
|
if (!resolvedAccess || resolvedAccess.role !== 'owner' || resolvedAccess.disabled) {
|
|
236
269
|
res.writeHead(403, { 'Content-Type': 'application/json' });
|
|
237
270
|
res.end(JSON.stringify({ success: false, error: 'Only workspace owners can delete this workspace.' }));
|
|
238
271
|
return;
|
|
239
272
|
}
|
|
273
|
+
const deletionAdmissionKey = targetWorkspaceId;
|
|
274
|
+
const admission = workspaceDeletionAdmission.acquire(deletionAdmissionKey);
|
|
275
|
+
if (!admission.allowed) {
|
|
276
|
+
writeAdmissionError(admission);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
240
279
|
try {
|
|
241
280
|
const deleted = core.deleteWorkspace({ workspaceId: targetWorkspaceId });
|
|
242
281
|
const cleanupWarnings = await cleanupDeletedWorkspaceStorage(deleted);
|
|
@@ -277,6 +316,9 @@ export function registerWorkspaceRoutes(deps) {
|
|
|
277
316
|
code: error?.code
|
|
278
317
|
}));
|
|
279
318
|
}
|
|
319
|
+
finally {
|
|
320
|
+
workspaceDeletionAdmission.settle(deletionAdmissionKey);
|
|
321
|
+
}
|
|
280
322
|
});
|
|
281
323
|
// === SECTION: Session workspace switch ===
|
|
282
324
|
// POST /api/taskforce/session/workspace - Switch active workspace in auth session
|
package/dist/server/routes.js
CHANGED
|
@@ -602,7 +602,7 @@ export function createRoutes(core, context = {}) {
|
|
|
602
602
|
taskId: input.taskId,
|
|
603
603
|
workspaceId: input.workspaceId,
|
|
604
604
|
action: 'task-attachments-changed',
|
|
605
|
-
actor: 'user',
|
|
605
|
+
actor: String(input.actorRef || '').trim() || 'user',
|
|
606
606
|
createdAt: input.createdAt || new Date().toISOString(),
|
|
607
607
|
details: {
|
|
608
608
|
changes: {
|
|
@@ -725,6 +725,7 @@ export function createRoutes(core, context = {}) {
|
|
|
725
725
|
asset,
|
|
726
726
|
beforeTask: taskBeforeLink,
|
|
727
727
|
createdAt: asset.updatedAt,
|
|
728
|
+
actorRef: params.actorRef,
|
|
728
729
|
});
|
|
729
730
|
}
|
|
730
731
|
}
|
|
@@ -788,7 +789,7 @@ export function createRoutes(core, context = {}) {
|
|
|
788
789
|
return false;
|
|
789
790
|
return /^workspaces\/[^/]+\/assets\/documents\/.+\.(md|markdown)$/.test(normalized);
|
|
790
791
|
};
|
|
791
|
-
const
|
|
792
|
+
const resolveCanonicalContentRead = async (params) => {
|
|
792
793
|
const resolvedObjectStorage = resolveEffectiveObjectStorageConfig();
|
|
793
794
|
const objectStorageClient = getObjectStorageClient();
|
|
794
795
|
const { basePath } = core.getPaths();
|
|
@@ -800,17 +801,19 @@ export function createRoutes(core, context = {}) {
|
|
|
800
801
|
: params.asset.storageProvider === 'local'
|
|
801
802
|
? 'local'
|
|
802
803
|
: null;
|
|
804
|
+
const contentKind = params.asset.kind === 'document' ? 'document' : 'asset';
|
|
805
|
+
const contentLabel = params.asset.kind === 'document' ? 'Document' : 'Asset';
|
|
803
806
|
const resolvedContent = publishedContentResolver && resolverOwnedProvider
|
|
804
807
|
? publishedContentResolver.resolve({
|
|
805
808
|
tenantId: core.getTenantId(),
|
|
806
809
|
workspaceId: params.asset.workspaceId,
|
|
807
|
-
kind:
|
|
810
|
+
kind: contentKind,
|
|
808
811
|
logicalPath: logicalStorageKey,
|
|
809
812
|
legacyProvider: resolverOwnedProvider
|
|
810
813
|
})
|
|
811
814
|
: {
|
|
812
815
|
source: 'legacy',
|
|
813
|
-
kind:
|
|
816
|
+
kind: contentKind,
|
|
814
817
|
logicalPath: logicalStorageKey,
|
|
815
818
|
physicalKey: logicalStorageKey,
|
|
816
819
|
storageProvider: params.asset.storageProvider
|
|
@@ -818,6 +821,31 @@ export function createRoutes(core, context = {}) {
|
|
|
818
821
|
if (resolvedContent.source === 'deleted') {
|
|
819
822
|
return { statusCode: 404 };
|
|
820
823
|
}
|
|
824
|
+
if (resolvedContent.source === 'versioned' && (resolvedContent.storageProvider !== params.asset.storageProvider
|
|
825
|
+
|| resolvedContent.contentSha256 !== params.asset.contentSha256
|
|
826
|
+
|| resolvedContent.sizeBytes !== params.asset.sizeBytes)) {
|
|
827
|
+
return {
|
|
828
|
+
statusCode: 409,
|
|
829
|
+
headers: { 'Content-Type': 'application/json' },
|
|
830
|
+
body: Buffer.from(JSON.stringify({
|
|
831
|
+
error: params.asset.kind === 'document'
|
|
832
|
+
? 'The published document head does not match the current canonical document metadata.'
|
|
833
|
+
: 'The published asset head does not match the current canonical asset metadata.',
|
|
834
|
+
code: params.asset.kind === 'document' ? 'MCP_DOCUMENT_HEAD_STALE' : 'WORKSPACE_ASSET_HEAD_STALE',
|
|
835
|
+
details: {
|
|
836
|
+
assetId: params.asset.assetId,
|
|
837
|
+
currentVersion: params.asset.version,
|
|
838
|
+
currentStorageProvider: params.asset.storageProvider,
|
|
839
|
+
currentContentSha256: params.asset.contentSha256,
|
|
840
|
+
currentSizeBytes: params.asset.sizeBytes,
|
|
841
|
+
headVersionId: resolvedContent.versionId,
|
|
842
|
+
headStorageProvider: resolvedContent.storageProvider,
|
|
843
|
+
headContentSha256: resolvedContent.contentSha256,
|
|
844
|
+
headSizeBytes: resolvedContent.sizeBytes,
|
|
845
|
+
},
|
|
846
|
+
})),
|
|
847
|
+
};
|
|
848
|
+
}
|
|
821
849
|
const physicalStorageKey = normalizeRelativeStorageKey(resolvedContent.physicalKey);
|
|
822
850
|
if (!physicalStorageKey)
|
|
823
851
|
return { statusCode: 404 };
|
|
@@ -852,7 +880,7 @@ export function createRoutes(core, context = {}) {
|
|
|
852
880
|
'Content-Disposition': contentDisposition
|
|
853
881
|
},
|
|
854
882
|
body: resolvedContent.source === 'versioned'
|
|
855
|
-
? verifyWorkspaceSyncPublishedContentBody(object.body, resolvedContent,
|
|
883
|
+
? verifyWorkspaceSyncPublishedContentBody(object.body, resolvedContent, `${contentLabel} ${params.asset.assetId}`)
|
|
856
884
|
: object.body
|
|
857
885
|
};
|
|
858
886
|
}
|
|
@@ -879,7 +907,7 @@ export function createRoutes(core, context = {}) {
|
|
|
879
907
|
'Content-Disposition': contentDisposition
|
|
880
908
|
},
|
|
881
909
|
body: resolvedContent.source === 'versioned'
|
|
882
|
-
? verifyWorkspaceSyncPublishedContentBody(body, resolvedContent,
|
|
910
|
+
? verifyWorkspaceSyncPublishedContentBody(body, resolvedContent, `${contentLabel} ${params.asset.assetId}`)
|
|
883
911
|
: body
|
|
884
912
|
};
|
|
885
913
|
}
|
|
@@ -1497,7 +1525,7 @@ export function createRoutes(core, context = {}) {
|
|
|
1497
1525
|
sanitizeDownloadFilename,
|
|
1498
1526
|
contentTypeForExt,
|
|
1499
1527
|
inferInlineDocumentFromPath,
|
|
1500
|
-
|
|
1528
|
+
resolveCanonicalContentRead,
|
|
1501
1529
|
inferWorkspaceIdFromStoragePath,
|
|
1502
1530
|
inferTaskIdFromStoragePath,
|
|
1503
1531
|
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const WORKSPACE_DELETE_RETRY_COOLDOWN_MS = 30000;
|
|
2
|
+
export type WorkspaceDeletionAdmissionDecision = {
|
|
3
|
+
allowed: true;
|
|
4
|
+
} | {
|
|
5
|
+
allowed: false;
|
|
6
|
+
code: 'WORKSPACE_DELETE_IN_PROGRESS' | 'WORKSPACE_DELETE_RETRY_COOLDOWN';
|
|
7
|
+
retryAfterMs: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Serializes destructive workspace cleanup inside one server process and
|
|
11
|
+
* throttles immediate retries after an attempt settles. The caller supplies
|
|
12
|
+
* time so the admission policy can be verified without timers.
|
|
13
|
+
*/
|
|
14
|
+
export declare class WorkspaceDeletionAdmission {
|
|
15
|
+
private readonly cooldownMs;
|
|
16
|
+
private readonly entries;
|
|
17
|
+
constructor(cooldownMs?: number);
|
|
18
|
+
checkExisting(key: string, now?: number): Exclude<WorkspaceDeletionAdmissionDecision, {
|
|
19
|
+
allowed: true;
|
|
20
|
+
}> | null;
|
|
21
|
+
acquire(key: string, now?: number): WorkspaceDeletionAdmissionDecision;
|
|
22
|
+
settle(key: string, now?: number): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export const WORKSPACE_DELETE_RETRY_COOLDOWN_MS = 30_000;
|
|
2
|
+
/**
|
|
3
|
+
* Serializes destructive workspace cleanup inside one server process and
|
|
4
|
+
* throttles immediate retries after an attempt settles. The caller supplies
|
|
5
|
+
* time so the admission policy can be verified without timers.
|
|
6
|
+
*/
|
|
7
|
+
export class WorkspaceDeletionAdmission {
|
|
8
|
+
cooldownMs;
|
|
9
|
+
entries = new Map();
|
|
10
|
+
constructor(cooldownMs = WORKSPACE_DELETE_RETRY_COOLDOWN_MS) {
|
|
11
|
+
this.cooldownMs = cooldownMs;
|
|
12
|
+
}
|
|
13
|
+
checkExisting(key, now = Date.now()) {
|
|
14
|
+
let existing = this.entries.get(key);
|
|
15
|
+
if (existing?.state === 'cooldown' && existing.retryAt <= now) {
|
|
16
|
+
this.entries.delete(key);
|
|
17
|
+
existing = undefined;
|
|
18
|
+
}
|
|
19
|
+
if (existing?.state === 'in-flight') {
|
|
20
|
+
return {
|
|
21
|
+
allowed: false,
|
|
22
|
+
code: 'WORKSPACE_DELETE_IN_PROGRESS',
|
|
23
|
+
retryAfterMs: Math.max(1_000, this.cooldownMs),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
if (existing?.state === 'cooldown') {
|
|
27
|
+
return {
|
|
28
|
+
allowed: false,
|
|
29
|
+
code: 'WORKSPACE_DELETE_RETRY_COOLDOWN',
|
|
30
|
+
retryAfterMs: Math.max(1_000, existing.retryAt - now),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
acquire(key, now = Date.now()) {
|
|
36
|
+
const existing = this.checkExisting(key, now);
|
|
37
|
+
if (existing)
|
|
38
|
+
return existing;
|
|
39
|
+
this.entries.set(key, { state: 'in-flight' });
|
|
40
|
+
return { allowed: true };
|
|
41
|
+
}
|
|
42
|
+
settle(key, now = Date.now()) {
|
|
43
|
+
if (this.entries.get(key)?.state !== 'in-flight')
|
|
44
|
+
return;
|
|
45
|
+
this.entries.set(key, {
|
|
46
|
+
state: 'cooldown',
|
|
47
|
+
retryAt: now + this.cooldownMs,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
+
import { applyLocalServiceCloudTarget, localServiceCloudTargetsEqual, parseLocalServiceCloudTarget, resolveLocalServiceCloudTarget, } from '../config/localServiceCloudTarget.js';
|
|
4
|
+
import { localServiceRuntimeContractsEqual, parseLocalServiceRuntimeContract, resolveLocalServiceRuntimeContract, } from '../config/localServiceRuntimeContract.js';
|
|
3
5
|
import { createStandaloneServer } from '../server/index.js';
|
|
4
6
|
import { inspectLocalServiceDescriptor, redactLocalServiceDescriptor, } from '../server/localServiceLease.js';
|
|
5
7
|
import { acquireLocalServiceOwnershipForRuntime, } from '../server/localServiceOwnershipBootstrap.js';
|
|
6
|
-
import { LOCAL_SERVICE_API_BASE_PATH, LOCAL_SERVICE_PROTOCOL_VERSION, resolveLocalServiceLeaseInput, spawnDetachedLocalService, waitForLocalServiceDescriptor, } from './localServiceClientLifecycle.js';
|
|
8
|
+
import { discoverOrStartLocalService, LOCAL_SERVICE_API_BASE_PATH, LOCAL_SERVICE_PROTOCOL_VERSION, resolveLocalServiceLeaseInput, spawnDetachedLocalService, waitForLocalServiceDescriptor, } from './localServiceClientLifecycle.js';
|
|
7
9
|
import { listSqliteWalHolders } from '../storage/sqliteWalHealth.js';
|
|
8
10
|
const STARTUP_TIMEOUT_MS = 15_000;
|
|
9
11
|
export { LOCAL_SERVICE_PROTOCOL_VERSION } from './localServiceClientLifecycle.js';
|
|
@@ -58,6 +60,20 @@ function reportIncompatibleDescriptor(inspection, error) {
|
|
|
58
60
|
error(`Taskforce service protocol ${inspection.descriptor.protocolVersion} is incompatible with client protocol ${LOCAL_SERVICE_PROTOCOL_VERSION}.`);
|
|
59
61
|
return true;
|
|
60
62
|
}
|
|
63
|
+
function reportCloudTargetMismatch(descriptorTarget, requestedTarget, error) {
|
|
64
|
+
if (localServiceCloudTargetsEqual(descriptorTarget, requestedTarget))
|
|
65
|
+
return false;
|
|
66
|
+
error('Taskforce service is running for a different or unverified cloud target. '
|
|
67
|
+
+ 'Stop it with `taskforce service stop --drain`, then retry.');
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
function reportRuntimeContractMismatch(descriptorContract, requestedContract, error) {
|
|
71
|
+
if (localServiceRuntimeContractsEqual(descriptorContract, requestedContract))
|
|
72
|
+
return false;
|
|
73
|
+
error('Taskforce service is running with a different or unverified local runtime contract. '
|
|
74
|
+
+ 'Stop it with `taskforce service stop --drain`, then retry.');
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
61
77
|
function defaultRegisterShutdownSignals(handler) {
|
|
62
78
|
process.once('SIGINT', handler);
|
|
63
79
|
process.once('SIGTERM', handler);
|
|
@@ -75,6 +91,9 @@ async function waitForDescriptor(input, expected, options) {
|
|
|
75
91
|
});
|
|
76
92
|
}
|
|
77
93
|
async function runForeground(command, options) {
|
|
94
|
+
const requestedCloudTarget = resolveLocalServiceCloudTarget(options.env);
|
|
95
|
+
applyLocalServiceCloudTarget(options.env, requestedCloudTarget);
|
|
96
|
+
const requestedRuntimeContract = resolveLocalServiceRuntimeContract(options.env);
|
|
78
97
|
const ownership = await options.acquireOwnership(command.projectRoot, options.env);
|
|
79
98
|
if (!ownership)
|
|
80
99
|
throw new Error('The shared local service requires local runtime mode.');
|
|
@@ -84,6 +103,10 @@ async function runForeground(command, options) {
|
|
|
84
103
|
if (inspection.status === 'live' && inspection.descriptor) {
|
|
85
104
|
if (reportIncompatibleDescriptor(inspection, options.error))
|
|
86
105
|
return 2;
|
|
106
|
+
if (reportCloudTargetMismatch(inspection.descriptor.cloudTarget, requestedCloudTarget, options.error))
|
|
107
|
+
return 2;
|
|
108
|
+
if (reportRuntimeContractMismatch(inspection.descriptor.runtimeContract, requestedRuntimeContract, options.error))
|
|
109
|
+
return 2;
|
|
87
110
|
options.log(`Taskforce service is already running at ${inspection.descriptor.endpoint}.`);
|
|
88
111
|
return 0;
|
|
89
112
|
}
|
|
@@ -116,6 +139,8 @@ async function runForeground(command, options) {
|
|
|
116
139
|
ownerPid: process.pid,
|
|
117
140
|
bootstrapCapability: ownership.lease.bootstrapCapability,
|
|
118
141
|
ownershipKey: ownership.lease.identity.ownershipKey,
|
|
142
|
+
cloudTarget: requestedCloudTarget,
|
|
143
|
+
runtimeContract: requestedRuntimeContract,
|
|
119
144
|
},
|
|
120
145
|
afterShutdown: async () => {
|
|
121
146
|
removeSignals();
|
|
@@ -138,6 +163,8 @@ async function runForeground(command, options) {
|
|
|
138
163
|
endpoint: `http://127.0.0.1:${address.port}`,
|
|
139
164
|
protocolVersion: LOCAL_SERVICE_PROTOCOL_VERSION,
|
|
140
165
|
appVersion: options.appVersion,
|
|
166
|
+
cloudTarget: requestedCloudTarget,
|
|
167
|
+
runtimeContract: requestedRuntimeContract,
|
|
141
168
|
});
|
|
142
169
|
removeSignals = options.registerShutdownSignals(shutdown);
|
|
143
170
|
server.once('error', (error) => {
|
|
@@ -164,34 +191,28 @@ async function runForeground(command, options) {
|
|
|
164
191
|
}
|
|
165
192
|
}
|
|
166
193
|
async function runStart(command, options) {
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
194
|
+
const requestedCloudTarget = resolveLocalServiceCloudTarget(options.env);
|
|
195
|
+
applyLocalServiceCloudTarget(options.env, requestedCloudTarget);
|
|
196
|
+
try {
|
|
197
|
+
const descriptor = await discoverOrStartLocalService({
|
|
198
|
+
projectRoot: command.projectRoot,
|
|
199
|
+
env: options.env,
|
|
200
|
+
executablePath: options.executablePath,
|
|
201
|
+
cliEntryPath: options.cliEntryPath,
|
|
202
|
+
execArgv: options.execArgv,
|
|
203
|
+
inspectDescriptor: options.inspectDescriptor,
|
|
204
|
+
spawnDetached: options.spawnDetached,
|
|
205
|
+
fetch: options.fetch,
|
|
206
|
+
sleep: options.sleep,
|
|
207
|
+
nowMs: options.nowMs,
|
|
208
|
+
});
|
|
209
|
+
options.log(`Taskforce service is ready at ${descriptor.endpoint}.`);
|
|
173
210
|
return 0;
|
|
174
211
|
}
|
|
175
|
-
|
|
176
|
-
options.error(
|
|
177
|
-
return 2;
|
|
178
|
-
}
|
|
179
|
-
options.spawnDetached(options.executablePath, [
|
|
180
|
-
...options.execArgv,
|
|
181
|
-
options.cliEntryPath,
|
|
182
|
-
'service',
|
|
183
|
-
command.projectRoot,
|
|
184
|
-
'--detached-child',
|
|
185
|
-
], options.env);
|
|
186
|
-
const inspection = await waitForDescriptor(leaseInput, 'live', options);
|
|
187
|
-
if (inspection.status !== 'live' || !inspection.descriptor) {
|
|
188
|
-
options.error('Taskforce service did not become ready before the startup deadline.');
|
|
212
|
+
catch (startError) {
|
|
213
|
+
options.error(String(startError?.message || startError));
|
|
189
214
|
return 2;
|
|
190
215
|
}
|
|
191
|
-
if (reportIncompatibleDescriptor(inspection, options.error))
|
|
192
|
-
return 2;
|
|
193
|
-
options.log(`Taskforce service started at ${inspection.descriptor.endpoint}.`);
|
|
194
|
-
return 0;
|
|
195
216
|
}
|
|
196
217
|
async function runStatus(command, options) {
|
|
197
218
|
const leaseInput = resolveLocalServiceLeaseInput(command.projectRoot, options.env);
|
|
@@ -222,9 +243,15 @@ async function runStatus(command, options) {
|
|
|
222
243
|
throw new Error(`HTTP ${response.status}`);
|
|
223
244
|
const payload = await response.json();
|
|
224
245
|
const coordinatorPayload = payload.coordinator;
|
|
246
|
+
const diagnosticCloudTarget = parseLocalServiceCloudTarget(payload.cloudTarget);
|
|
247
|
+
const diagnosticRuntimeContract = parseLocalServiceRuntimeContract(payload.runtimeContract);
|
|
225
248
|
if (payload.ownerPid !== inspection.descriptor.pid
|
|
226
249
|
|| payload.generation !== inspection.descriptor.generation
|
|
227
250
|
|| payload.protocolVersion !== inspection.descriptor.protocolVersion
|
|
251
|
+
|| (inspection.descriptor.cloudTarget
|
|
252
|
+
&& !localServiceCloudTargetsEqual(diagnosticCloudTarget, inspection.descriptor.cloudTarget))
|
|
253
|
+
|| (inspection.descriptor.runtimeContract
|
|
254
|
+
&& !localServiceRuntimeContractsEqual(diagnosticRuntimeContract, inspection.descriptor.runtimeContract))
|
|
228
255
|
|| !Array.isArray(payload.sessions)
|
|
229
256
|
|| !coordinatorPayload
|
|
230
257
|
|| typeof coordinatorPayload !== 'object'
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import * as fs from 'fs';
|
|
3
3
|
import * as path from 'path';
|
|
4
|
+
import { applyLocalServiceCloudTarget, localServiceCloudTargetsEqual, parseLocalServiceCloudTarget, resolveLocalServiceCloudTarget, } from '../config/localServiceCloudTarget.js';
|
|
5
|
+
import { localServiceRuntimeContractsEqual, parseLocalServiceRuntimeContract, resolveLocalServiceRuntimeContract, } from '../config/localServiceRuntimeContract.js';
|
|
4
6
|
import { inspectLocalServiceDescriptor, } from '../server/localServiceLease.js';
|
|
5
7
|
import { resolveLocalDatabaseIdentity } from '../server/localDatabaseIdentity.js';
|
|
6
8
|
export const LOCAL_SERVICE_PROTOCOL_VERSION = '1';
|
|
@@ -22,6 +24,11 @@ const LOCAL_MCP_CLIENT_ENV_KEYS = [
|
|
|
22
24
|
'TASKFORCE_AI_SURFACE_TYPE',
|
|
23
25
|
'TASKFORCE_AI_SEAT_SCOPE',
|
|
24
26
|
];
|
|
27
|
+
function isQaIdentityEnvironmentKey(key) {
|
|
28
|
+
return key.startsWith('TASKFORCE_E2E_')
|
|
29
|
+
|| key.startsWith('TASKFORCE_PLAYWRIGHT_')
|
|
30
|
+
|| key.startsWith('SYNC_SOAK_');
|
|
31
|
+
}
|
|
25
32
|
export function resolveLocalServiceLeaseInput(projectRoot, env) {
|
|
26
33
|
const provider = env.TASKFORCE_DB_PROVIDER === 'postgres' ? 'postgres' : 'sqlite';
|
|
27
34
|
return {
|
|
@@ -39,10 +46,15 @@ export function spawnDetachedLocalService(executablePath, args, env) {
|
|
|
39
46
|
});
|
|
40
47
|
child.unref();
|
|
41
48
|
}
|
|
42
|
-
function buildLocalServiceProcessEnv(env) {
|
|
49
|
+
function buildLocalServiceProcessEnv(env, cloudTarget) {
|
|
43
50
|
const serviceEnv = { ...env };
|
|
44
51
|
for (const key of LOCAL_MCP_CLIENT_ENV_KEYS)
|
|
45
52
|
delete serviceEnv[key];
|
|
53
|
+
for (const key of Object.keys(serviceEnv)) {
|
|
54
|
+
if (isQaIdentityEnvironmentKey(key))
|
|
55
|
+
delete serviceEnv[key];
|
|
56
|
+
}
|
|
57
|
+
applyLocalServiceCloudTarget(serviceEnv, cloudTarget);
|
|
46
58
|
return serviceEnv;
|
|
47
59
|
}
|
|
48
60
|
export async function waitForLocalServiceDescriptor(input, expected, options = {}) {
|
|
@@ -78,15 +90,72 @@ async function validateLocalServiceReadiness(descriptor, fetchFn) {
|
|
|
78
90
|
catch {
|
|
79
91
|
throw new Error('Taskforce shared local service readiness returned invalid JSON.');
|
|
80
92
|
}
|
|
93
|
+
const readinessHasCloudTarget = Object.prototype.hasOwnProperty.call(readiness, 'cloudTarget');
|
|
94
|
+
const readinessCloudTarget = readinessHasCloudTarget
|
|
95
|
+
? parseLocalServiceCloudTarget(readiness.cloudTarget)
|
|
96
|
+
: null;
|
|
97
|
+
const readinessHasRuntimeContract = Object.prototype.hasOwnProperty.call(readiness, 'runtimeContract');
|
|
98
|
+
const readinessRuntimeContract = readinessHasRuntimeContract
|
|
99
|
+
? parseLocalServiceRuntimeContract(readiness.runtimeContract)
|
|
100
|
+
: null;
|
|
101
|
+
const descriptorCloudTarget = descriptor.cloudTarget || null;
|
|
102
|
+
const descriptorRuntimeContract = descriptor.runtimeContract || null;
|
|
103
|
+
const cloudTargetsMatch = descriptorCloudTarget || readinessCloudTarget
|
|
104
|
+
? localServiceCloudTargetsEqual(descriptorCloudTarget, readinessCloudTarget)
|
|
105
|
+
: true;
|
|
106
|
+
const runtimeContractsMatch = descriptorRuntimeContract || readinessRuntimeContract
|
|
107
|
+
? localServiceRuntimeContractsEqual(descriptorRuntimeContract, readinessRuntimeContract)
|
|
108
|
+
: true;
|
|
81
109
|
if (readiness.ready !== true
|
|
82
110
|
|| readiness.protocolVersion !== LOCAL_SERVICE_PROTOCOL_VERSION
|
|
83
111
|
|| readiness.protocolVersion !== descriptor.protocolVersion
|
|
84
112
|
|| readiness.generation !== descriptor.generation
|
|
85
113
|
|| readiness.pid !== descriptor.pid
|
|
86
114
|
|| readiness.endpoint !== descriptor.endpoint
|
|
87
|
-
|| readiness.dataIdentity !== descriptor.ownershipKey
|
|
115
|
+
|| readiness.dataIdentity !== descriptor.ownershipKey
|
|
116
|
+
|| (readinessHasCloudTarget && !readinessCloudTarget)
|
|
117
|
+
|| !cloudTargetsMatch
|
|
118
|
+
|| (readinessHasRuntimeContract && !readinessRuntimeContract)
|
|
119
|
+
|| !runtimeContractsMatch) {
|
|
88
120
|
throw new Error('Taskforce shared local service readiness does not match its descriptor.');
|
|
89
121
|
}
|
|
122
|
+
return {
|
|
123
|
+
cloudTarget: descriptorCloudTarget,
|
|
124
|
+
runtimeContract: descriptorRuntimeContract,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function requestIdleLocalServiceShutdown(descriptor, fetchFn) {
|
|
128
|
+
let response;
|
|
129
|
+
try {
|
|
130
|
+
response = await fetchFn(`${descriptor.endpoint}${LOCAL_SERVICE_API_BASE_PATH}/shutdown`, {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: {
|
|
133
|
+
'content-type': 'application/json',
|
|
134
|
+
'x-taskforce-local-service-capability': descriptor.bootstrapCapability,
|
|
135
|
+
},
|
|
136
|
+
body: JSON.stringify({
|
|
137
|
+
intent: 'administrative-stop',
|
|
138
|
+
mode: 'refuse',
|
|
139
|
+
pid: descriptor.pid,
|
|
140
|
+
generation: descriptor.generation,
|
|
141
|
+
}),
|
|
142
|
+
redirect: 'error',
|
|
143
|
+
signal: AbortSignal.timeout(LOCAL_SERVICE_STARTUP_TIMEOUT_MS),
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
throw new Error('Taskforce service uses a different cloud target or runtime contract and could not be stopped safely. '
|
|
148
|
+
+ `No replacement was started. ${String(error?.message || error)}`);
|
|
149
|
+
}
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const detail = (await response.text()).slice(0, 500);
|
|
152
|
+
const activeClientHint = response.status === 409
|
|
153
|
+
? ' It may have active MCP clients; close them or run `taskforce service stop --drain`, then retry.'
|
|
154
|
+
: '';
|
|
155
|
+
throw new Error(`Taskforce service uses a different cloud target or runtime contract and refused safe idle replacement (${response.status}).`
|
|
156
|
+
+ activeClientHint
|
|
157
|
+
+ (detail ? ` ${detail}` : ''));
|
|
158
|
+
}
|
|
90
159
|
}
|
|
91
160
|
export async function discoverOrStartLocalService(input) {
|
|
92
161
|
const requestedRoot = path.resolve(input.projectRoot);
|
|
@@ -94,13 +163,27 @@ export async function discoverOrStartLocalService(input) {
|
|
|
94
163
|
const leaseInput = resolveLocalServiceLeaseInput(projectRoot, input.env);
|
|
95
164
|
const inspectDescriptor = input.inspectDescriptor || inspectLocalServiceDescriptor;
|
|
96
165
|
const fetchFn = input.fetch || fetch;
|
|
166
|
+
const requestedCloudTarget = resolveLocalServiceCloudTarget(input.env);
|
|
167
|
+
const requestedRuntimeContract = resolveLocalServiceRuntimeContract(input.env);
|
|
97
168
|
const current = await inspectDescriptor(leaseInput);
|
|
98
169
|
if (current.status === 'live' && current.descriptor) {
|
|
99
170
|
if (current.descriptor.protocolVersion !== LOCAL_SERVICE_PROTOCOL_VERSION) {
|
|
100
171
|
throw new Error(`Taskforce service protocol ${current.descriptor.protocolVersion} is incompatible with client protocol ${LOCAL_SERVICE_PROTOCOL_VERSION}.`);
|
|
101
172
|
}
|
|
102
|
-
await validateLocalServiceReadiness(current.descriptor, fetchFn);
|
|
103
|
-
|
|
173
|
+
const running = await validateLocalServiceReadiness(current.descriptor, fetchFn);
|
|
174
|
+
if (localServiceCloudTargetsEqual(running.cloudTarget, requestedCloudTarget)
|
|
175
|
+
&& localServiceRuntimeContractsEqual(running.runtimeContract, requestedRuntimeContract)) {
|
|
176
|
+
return current.descriptor;
|
|
177
|
+
}
|
|
178
|
+
await requestIdleLocalServiceShutdown(current.descriptor, fetchFn);
|
|
179
|
+
const stopped = await waitForLocalServiceDescriptor(leaseInput, 'stale', {
|
|
180
|
+
inspectDescriptor,
|
|
181
|
+
sleep: input.sleep,
|
|
182
|
+
nowMs: input.nowMs,
|
|
183
|
+
});
|
|
184
|
+
if (stopped.status !== 'stale') {
|
|
185
|
+
throw new Error('Taskforce service accepted configuration replacement but did not release its owner lease. No replacement was started.');
|
|
186
|
+
}
|
|
104
187
|
}
|
|
105
188
|
if (current.status === 'indeterminate') {
|
|
106
189
|
throw new Error('Taskforce service state is indeterminate; refusing to start a competing owner.');
|
|
@@ -111,7 +194,7 @@ export async function discoverOrStartLocalService(input) {
|
|
|
111
194
|
'service',
|
|
112
195
|
projectRoot,
|
|
113
196
|
'--detached-child',
|
|
114
|
-
], buildLocalServiceProcessEnv(input.env));
|
|
197
|
+
], buildLocalServiceProcessEnv(input.env, requestedCloudTarget));
|
|
115
198
|
const inspection = await waitForLocalServiceDescriptor(leaseInput, 'live', {
|
|
116
199
|
inspectDescriptor,
|
|
117
200
|
sleep: input.sleep,
|
|
@@ -123,6 +206,10 @@ export async function discoverOrStartLocalService(input) {
|
|
|
123
206
|
if (inspection.descriptor.protocolVersion !== LOCAL_SERVICE_PROTOCOL_VERSION) {
|
|
124
207
|
throw new Error(`Taskforce service protocol ${inspection.descriptor.protocolVersion} is incompatible with client protocol ${LOCAL_SERVICE_PROTOCOL_VERSION}.`);
|
|
125
208
|
}
|
|
126
|
-
await validateLocalServiceReadiness(inspection.descriptor, fetchFn);
|
|
209
|
+
const started = await validateLocalServiceReadiness(inspection.descriptor, fetchFn);
|
|
210
|
+
if (!localServiceCloudTargetsEqual(started.cloudTarget, requestedCloudTarget)
|
|
211
|
+
|| !localServiceRuntimeContractsEqual(started.runtimeContract, requestedRuntimeContract)) {
|
|
212
|
+
throw new Error('Taskforce service started with a different or unverified cloud target/runtime contract; refusing to attach.');
|
|
213
|
+
}
|
|
127
214
|
return inspection.descriptor;
|
|
128
215
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { ModelGateway, ModelGatewayGenerateInput, ModelGatewayGenerateResult } from './modelGateway.js';
|
|
2
|
+
export type CodexAppServerModelKeyIdMap = Partial<Record<string, string>>;
|
|
3
|
+
type CodexAppServerApprovalPolicy = 'never';
|
|
4
|
+
type CodexAppServerSandboxMode = 'read-only';
|
|
5
|
+
type CodexAppServerSandboxPolicy = {
|
|
6
|
+
type: 'readOnly';
|
|
7
|
+
networkAccess: false;
|
|
8
|
+
};
|
|
9
|
+
type CodexAppServerRuntimePolicy = {
|
|
10
|
+
cwd: string;
|
|
11
|
+
approvalPolicy: CodexAppServerApprovalPolicy;
|
|
12
|
+
sandbox: CodexAppServerSandboxMode;
|
|
13
|
+
sandboxPolicy: CodexAppServerSandboxPolicy;
|
|
14
|
+
};
|
|
15
|
+
export interface CodexAppServerClient {
|
|
16
|
+
initialize(): Promise<void>;
|
|
17
|
+
assertChatGptSubscriptionAuth(): Promise<void>;
|
|
18
|
+
startThread(input: {
|
|
19
|
+
model: string;
|
|
20
|
+
developerInstructions?: string;
|
|
21
|
+
} & CodexAppServerRuntimePolicy): Promise<{
|
|
22
|
+
threadId: string;
|
|
23
|
+
}>;
|
|
24
|
+
startTurnAndCollectText(input: {
|
|
25
|
+
threadId: string;
|
|
26
|
+
prompt: string;
|
|
27
|
+
model: string;
|
|
28
|
+
timeoutMs: number;
|
|
29
|
+
} & CodexAppServerRuntimePolicy): Promise<{
|
|
30
|
+
text: string;
|
|
31
|
+
stopReason?: string;
|
|
32
|
+
}>;
|
|
33
|
+
close(): void;
|
|
34
|
+
}
|
|
35
|
+
export interface CodexAppServerModelGatewayOptions {
|
|
36
|
+
client?: CodexAppServerClient;
|
|
37
|
+
clientFactory?: () => CodexAppServerClient;
|
|
38
|
+
command?: string;
|
|
39
|
+
args?: string[];
|
|
40
|
+
cwd?: string;
|
|
41
|
+
env?: NodeJS.ProcessEnv;
|
|
42
|
+
modelKeyIds?: CodexAppServerModelKeyIdMap;
|
|
43
|
+
timeoutMs?: number;
|
|
44
|
+
requestTimeoutMs?: number;
|
|
45
|
+
}
|
|
46
|
+
export declare const DEFAULT_CODEX_APP_SERVER_MODEL_KEY_IDS: CodexAppServerModelKeyIdMap;
|
|
47
|
+
export declare function buildCodexAppServerEnv(source?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
48
|
+
export declare function sanitizeCodexAppServerStderr(value: unknown): string;
|
|
49
|
+
export declare function collectCodexAppServerStderr(current: string, chunk: unknown): string;
|
|
50
|
+
export declare function assertCodexChatGptSubscriptionAccount(result: unknown): void;
|
|
51
|
+
export declare function isCodexSubscriptionDevRuntimeAllowed(source?: NodeJS.ProcessEnv): boolean;
|
|
52
|
+
export declare function extractCodexTurnCompletion(messages: unknown[]): {
|
|
53
|
+
text: string;
|
|
54
|
+
stopReason: string;
|
|
55
|
+
} | null;
|
|
56
|
+
export declare class CodexAppServerJsonRpcClient implements CodexAppServerClient {
|
|
57
|
+
private readonly process;
|
|
58
|
+
private readonly pending;
|
|
59
|
+
private readonly notifications;
|
|
60
|
+
private nextId;
|
|
61
|
+
private initialized;
|
|
62
|
+
private readonly lineReader;
|
|
63
|
+
private readonly requestTimeoutMs;
|
|
64
|
+
private readonly turnRejectors;
|
|
65
|
+
private terminalError;
|
|
66
|
+
private stderrTail;
|
|
67
|
+
constructor(options?: {
|
|
68
|
+
command?: string;
|
|
69
|
+
args?: string[];
|
|
70
|
+
cwd?: string;
|
|
71
|
+
env?: NodeJS.ProcessEnv;
|
|
72
|
+
requestTimeoutMs?: number;
|
|
73
|
+
});
|
|
74
|
+
initialize(): Promise<void>;
|
|
75
|
+
assertChatGptSubscriptionAuth(): Promise<void>;
|
|
76
|
+
startThread(input: {
|
|
77
|
+
model: string;
|
|
78
|
+
developerInstructions?: string;
|
|
79
|
+
} & CodexAppServerRuntimePolicy): Promise<{
|
|
80
|
+
threadId: string;
|
|
81
|
+
}>;
|
|
82
|
+
startTurnAndCollectText(input: {
|
|
83
|
+
threadId: string;
|
|
84
|
+
prompt: string;
|
|
85
|
+
system?: string;
|
|
86
|
+
model: string;
|
|
87
|
+
timeoutMs: number;
|
|
88
|
+
} & CodexAppServerRuntimePolicy): Promise<{
|
|
89
|
+
text: string;
|
|
90
|
+
stopReason?: string;
|
|
91
|
+
}>;
|
|
92
|
+
close(): void;
|
|
93
|
+
private request;
|
|
94
|
+
private sendNotification;
|
|
95
|
+
private handleLine;
|
|
96
|
+
private sendResponseError;
|
|
97
|
+
private waitForTurnCompletion;
|
|
98
|
+
private rejectAll;
|
|
99
|
+
private fail;
|
|
100
|
+
}
|
|
101
|
+
export declare class CodexAppServerModelGateway implements ModelGateway {
|
|
102
|
+
private readonly client?;
|
|
103
|
+
private readonly clientFactory;
|
|
104
|
+
private readonly modelKeyIds;
|
|
105
|
+
private readonly timeoutMs;
|
|
106
|
+
private readonly cwd;
|
|
107
|
+
constructor(options?: CodexAppServerModelGatewayOptions);
|
|
108
|
+
generate(input: ModelGatewayGenerateInput): Promise<ModelGatewayGenerateResult>;
|
|
109
|
+
private resolveModelId;
|
|
110
|
+
private formatMessages;
|
|
111
|
+
}
|
|
112
|
+
export {};
|