@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
|
@@ -57,7 +57,7 @@ import { resolveBuildInfo } from '../buildInfo.js';
|
|
|
57
57
|
import { resolveRealtimeSyncFlag } from '../../sync/realtimeFeature.js';
|
|
58
58
|
import { parseJsonBody } from './primitives.js';
|
|
59
59
|
import { resolveRequestAccess } from '../auth.js';
|
|
60
|
-
import { getRouteTimingNow, logSlowBootstrapRoute, requestBootstrapTraceId, requestHeader, requestRuntimeMode,
|
|
60
|
+
import { currentPerformanceTraceDiagnostics, getRouteTimingNow, logSlowBootstrapRoute, performanceTraceServerTimingMetrics, requestBootstrapTraceId, requestHeader, requestHumanActorRef, requestRuntimeMode, respondWithPerformanceTraceJson, resolveErrorStatusCode, runWithPerformanceTrace, serializeJsonWithTiming, setPerformanceTraceHeaders, setServerTimingHeader } from './shared.js';
|
|
61
61
|
import { listBuiltInCustomTaxonomyLibraryPacks } from '../../shared/customTaxonomyLibrary.js';
|
|
62
62
|
import { getBuiltInTaxonomyLibraryPack, listBuiltInTaxonomyLibraryPacks } from '../../shared/taxonomyLibrary.js';
|
|
63
63
|
import { shouldUseProvisionalTaskReferences } from '../../utils/taskReferences.js';
|
|
@@ -177,7 +177,7 @@ export function registerTaskRoutes(deps) {
|
|
|
177
177
|
surface: 'http',
|
|
178
178
|
tenantId: core.getTenantId(),
|
|
179
179
|
workspaceId,
|
|
180
|
-
actorRef:
|
|
180
|
+
actorRef: requestHumanActorRef(req),
|
|
181
181
|
cloudClientId: 'http-cloud',
|
|
182
182
|
...(operationId ? { createOperationId: () => operationId } : {}),
|
|
183
183
|
});
|
|
@@ -192,7 +192,7 @@ export function registerTaskRoutes(deps) {
|
|
|
192
192
|
surface: 'http',
|
|
193
193
|
tenantId: core.getTenantId(),
|
|
194
194
|
workspaceId,
|
|
195
|
-
actorRef:
|
|
195
|
+
actorRef: requestHumanActorRef(req),
|
|
196
196
|
cloudClientId: 'http-cloud',
|
|
197
197
|
...(operationId ? { createOperationId: () => operationId } : {}),
|
|
198
198
|
});
|
|
@@ -465,9 +465,70 @@ export function registerTaskRoutes(deps) {
|
|
|
465
465
|
if (!ensureAppAccess(req, res))
|
|
466
466
|
return;
|
|
467
467
|
const workspaceId = requestWorkspaceId(req);
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
468
|
+
respondWithPerformanceTraceJson({
|
|
469
|
+
req,
|
|
470
|
+
res,
|
|
471
|
+
route: '/api/taskforce/tasks',
|
|
472
|
+
workspaceId,
|
|
473
|
+
// Local V2 sync still builds an outbound snapshot from these collections.
|
|
474
|
+
// Keep its full graph until that writer is retired; cloud is read-authoritative.
|
|
475
|
+
load: () => (context.authConfig?.runtimeMode === 'cloud' ? 'cloud' : requestRuntimeMode(req)) === 'cloud'
|
|
476
|
+
? core.listActiveTaskSummaries(workspaceId)
|
|
477
|
+
: core.listTasks(workspaceId),
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
// GET /api/taskforce/tasks/search - Search lightweight task summaries across lifecycles
|
|
481
|
+
addRoute('GET', '/api/taskforce/tasks/search', async (req, res) => {
|
|
482
|
+
if (!ensureAppAccess(req, res))
|
|
483
|
+
return;
|
|
484
|
+
try {
|
|
485
|
+
const requestUrl = new URL(req.url || '', 'http://localhost');
|
|
486
|
+
const query = String(requestUrl.searchParams.get('query') || '').trim();
|
|
487
|
+
if (!query) {
|
|
488
|
+
throw new TaskforceRuleError('query is required.', 400, 'TASK_SEARCH_QUERY_REQUIRED');
|
|
489
|
+
}
|
|
490
|
+
if (query.length > 200) {
|
|
491
|
+
throw new TaskforceRuleError('query must be 200 characters or fewer.', 400, 'TASK_SEARCH_QUERY_TOO_LONG');
|
|
492
|
+
}
|
|
493
|
+
const scopeInput = String(requestUrl.searchParams.get('scope') || 'all').trim();
|
|
494
|
+
if (!['all', 'active', 'archive'].includes(scopeInput)) {
|
|
495
|
+
throw new TaskforceRuleError('scope must be all, active, or archive.', 400, 'TASK_SEARCH_SCOPE_INVALID');
|
|
496
|
+
}
|
|
497
|
+
const parseBoundedInteger = (name, fallback, max) => {
|
|
498
|
+
const raw = requestUrl.searchParams.get(name);
|
|
499
|
+
if (raw === null || raw === '')
|
|
500
|
+
return fallback;
|
|
501
|
+
const parsed = Number(raw);
|
|
502
|
+
if (!Number.isInteger(parsed) || parsed < (name === 'limit' ? 1 : 0) || parsed > max) {
|
|
503
|
+
throw new TaskforceRuleError(`${name} must be an integer between ${name === 'limit' ? 1 : 0} and ${max}.`, 400, `TASK_SEARCH_${name.toUpperCase()}_INVALID`);
|
|
504
|
+
}
|
|
505
|
+
return parsed;
|
|
506
|
+
};
|
|
507
|
+
const limit = parseBoundedInteger('limit', 50, 50);
|
|
508
|
+
const offset = parseBoundedInteger('offset', 0, 10_000);
|
|
509
|
+
const workspaceId = requestWorkspaceId(req);
|
|
510
|
+
const rows = core.searchTaskSummaries(query, scopeInput, workspaceId, { limit: limit + 1, offset });
|
|
511
|
+
const hasMore = rows.length > limit;
|
|
512
|
+
const matches = rows.slice(0, limit);
|
|
513
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
514
|
+
res.end(JSON.stringify({
|
|
515
|
+
matches,
|
|
516
|
+
pagination: {
|
|
517
|
+
limit,
|
|
518
|
+
offset,
|
|
519
|
+
returned: matches.length,
|
|
520
|
+
hasMore,
|
|
521
|
+
nextOffset: hasMore ? offset + matches.length : null,
|
|
522
|
+
},
|
|
523
|
+
}));
|
|
524
|
+
}
|
|
525
|
+
catch (error) {
|
|
526
|
+
const statusCode = resolveErrorStatusCode(error, 400);
|
|
527
|
+
const message = error instanceof Error ? error.message : 'Failed to search tasks.';
|
|
528
|
+
const code = error instanceof TaskforceRuleError ? error.code : error?.code;
|
|
529
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
530
|
+
res.end(JSON.stringify({ error: message, code }));
|
|
531
|
+
}
|
|
471
532
|
});
|
|
472
533
|
addRoute('GET', '/api/taskforce/task-relationships', async (req, res) => {
|
|
473
534
|
if (!ensureAppAccess(req, res))
|
|
@@ -480,9 +541,13 @@ export function registerTaskRoutes(deps) {
|
|
|
480
541
|
if (!ensureAppAccess(req, res))
|
|
481
542
|
return;
|
|
482
543
|
const workspaceId = requestWorkspaceId(req);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
544
|
+
respondWithPerformanceTraceJson({
|
|
545
|
+
req,
|
|
546
|
+
res,
|
|
547
|
+
route: '/api/taskforce/deleted',
|
|
548
|
+
workspaceId,
|
|
549
|
+
load: () => core.listDeletedTasks(workspaceId),
|
|
550
|
+
});
|
|
486
551
|
};
|
|
487
552
|
// GET /api/taskforce/deleted - List deleted tasks
|
|
488
553
|
addRoute('GET', '/api/taskforce/deleted', handleListDeletedTasks);
|
|
@@ -589,7 +654,7 @@ export function registerTaskRoutes(deps) {
|
|
|
589
654
|
const durableRouter = createTaskHttpRootRouter(req, workspaceId);
|
|
590
655
|
const task = durableRouter.enabled ? durableRouter.create(taskInput) : core.createTask(taskInput, {
|
|
591
656
|
workspaceId,
|
|
592
|
-
actorRef:
|
|
657
|
+
actorRef: requestHumanActorRef(req),
|
|
593
658
|
provisionalLocalReference: shouldUseProvisionalTaskReferences(requestRuntimeMode(req))
|
|
594
659
|
});
|
|
595
660
|
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
@@ -609,6 +674,20 @@ export function registerTaskRoutes(deps) {
|
|
|
609
674
|
}));
|
|
610
675
|
}
|
|
611
676
|
});
|
|
677
|
+
// GET /api/taskforce/task/:id - Read complete active or archived task detail
|
|
678
|
+
addRoute('GET', '/api/taskforce/task/:id', async (req, res, params) => {
|
|
679
|
+
if (!ensureAppAccess(req, res))
|
|
680
|
+
return;
|
|
681
|
+
const workspaceId = requestWorkspaceId(req);
|
|
682
|
+
const task = core.getTaskDetailSnapshot(params.id, workspaceId);
|
|
683
|
+
if (!task) {
|
|
684
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
685
|
+
res.end(JSON.stringify({ error: 'Task not found' }));
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
689
|
+
res.end(JSON.stringify(task));
|
|
690
|
+
});
|
|
612
691
|
// PATCH /api/taskforce/task/:id - Update a task
|
|
613
692
|
addRoute('PATCH', '/api/taskforce/task/:id', async (req, res, params) => {
|
|
614
693
|
if (!ensureAppAccess(req, res))
|
|
@@ -617,8 +696,15 @@ export function registerTaskRoutes(deps) {
|
|
|
617
696
|
try {
|
|
618
697
|
const workspaceId = requestWorkspaceId(req);
|
|
619
698
|
const saveSource = body?.saveSource === 'autosave' ? 'autosave' : 'manual';
|
|
699
|
+
const expectedDetailRevision = typeof body?.expectedDetailRevision === 'string'
|
|
700
|
+
? body.expectedDetailRevision.trim()
|
|
701
|
+
: null;
|
|
702
|
+
if (body && Object.prototype.hasOwnProperty.call(body, 'expectedDetailRevision')
|
|
703
|
+
&& !expectedDetailRevision) {
|
|
704
|
+
throw new TaskforceRuleError('expectedDetailRevision must be a non-empty string.', 400, 'TASK_DETAIL_REVISION_INVALID');
|
|
705
|
+
}
|
|
620
706
|
const updates = body && typeof body === 'object'
|
|
621
|
-
? Object.fromEntries(Object.entries(body).filter(([key]) => key !== 'saveSource'))
|
|
707
|
+
? Object.fromEntries(Object.entries(body).filter(([key]) => (key !== 'saveSource' && key !== 'expectedDetailRevision')))
|
|
622
708
|
: body;
|
|
623
709
|
const durableRouters = createTaskHttpDurableRouters({ core, context, req, workspaceId });
|
|
624
710
|
const durableRouter = durableRouters.root;
|
|
@@ -630,22 +716,34 @@ export function registerTaskRoutes(deps) {
|
|
|
630
716
|
if (hasAttachments && !Array.isArray(updates.attachments)) {
|
|
631
717
|
throw new TaskforceRuleError('attachments must be an array.', 400, 'TASK_ATTACHMENT_LINKS_INVALID');
|
|
632
718
|
}
|
|
719
|
+
const hasCardCover = Object.prototype.hasOwnProperty.call(updates || {}, 'cardCoverAssetId');
|
|
720
|
+
if (hasCardCover && updates.cardCoverAssetId !== null
|
|
721
|
+
&& (typeof updates.cardCoverAssetId !== 'string' || !updates.cardCoverAssetId.trim())) {
|
|
722
|
+
throw new TaskforceRuleError('cardCoverAssetId must be a non-empty string or null.', 400, 'TASK_CARD_COVER_INVALID');
|
|
723
|
+
}
|
|
633
724
|
const checklistDurable = hasChecklist && durableRouters.checklist.enabled;
|
|
634
|
-
const attachmentLinksDurable = hasAttachments && durableRouters.attachmentLinks.enabled;
|
|
725
|
+
const attachmentLinksDurable = (hasAttachments || hasCardCover) && durableRouters.attachmentLinks.enabled;
|
|
635
726
|
const rawChecklistItems = hasChecklist ? updates.checklistItems : [];
|
|
636
|
-
const rawAttachments = hasAttachments
|
|
727
|
+
const rawAttachments = hasAttachments
|
|
728
|
+
? updates.attachments
|
|
729
|
+
: (core.getTask(params.id, workspaceId)?.attachments || []);
|
|
637
730
|
const remainingUpdates = checklistDurable || attachmentLinksDurable
|
|
638
731
|
? Object.fromEntries(Object.entries(updates).filter(([key]) => (!(checklistDurable && key === 'checklistItems')
|
|
639
|
-
&& !(attachmentLinksDurable && key === 'attachments')
|
|
732
|
+
&& !(attachmentLinksDurable && key === 'attachments')
|
|
733
|
+
&& !(attachmentLinksDurable && key === 'cardCoverAssetId'))))
|
|
640
734
|
: updates;
|
|
641
735
|
let updated;
|
|
642
736
|
const durableTargetCount = Number(checklistDurable)
|
|
643
737
|
+ Number(attachmentLinksDurable)
|
|
644
738
|
+ Number(Object.keys(remainingUpdates).length > 0);
|
|
645
|
-
if (durableTargetCount > 1) {
|
|
739
|
+
if (durableTargetCount > 1 || Boolean(expectedDetailRevision && (checklistDurable || attachmentLinksDurable))) {
|
|
646
740
|
const aggregate = durableRouters.bulk.updateFields([
|
|
647
741
|
{ id: params.id, ...updates },
|
|
648
|
-
], {
|
|
742
|
+
], {
|
|
743
|
+
saveSource,
|
|
744
|
+
atomicItemFailures: true,
|
|
745
|
+
...(expectedDetailRevision ? { expectedDetailRevision } : {}),
|
|
746
|
+
});
|
|
649
747
|
const failure = aggregate.errors[0];
|
|
650
748
|
if (failure) {
|
|
651
749
|
throw new TaskforceRuleError(failure.message, failure.statusCode, failure.code || 'TASK_UPDATE_FAILED', failure.details);
|
|
@@ -655,11 +753,13 @@ export function registerTaskRoutes(deps) {
|
|
|
655
753
|
else {
|
|
656
754
|
updated = Object.keys(remainingUpdates || {}).length > 0
|
|
657
755
|
? (durableRouter.enabled
|
|
658
|
-
? durableRouter.update(params.id, remainingUpdates, saveSource)
|
|
659
|
-
:
|
|
660
|
-
actorRef:
|
|
661
|
-
|
|
662
|
-
|
|
756
|
+
? durableRouter.update(params.id, remainingUpdates, saveSource, undefined, expectedDetailRevision || undefined)
|
|
757
|
+
: expectedDetailRevision !== null
|
|
758
|
+
? core.updateTaskIfDetailRevisionMatches(params.id, expectedDetailRevision, remainingUpdates, workspaceId, { actorRef: requestHumanActorRef(req), saveSource })
|
|
759
|
+
: core.updateTask(params.id, remainingUpdates, workspaceId, {
|
|
760
|
+
actorRef: requestHumanActorRef(req),
|
|
761
|
+
saveSource,
|
|
762
|
+
}))
|
|
663
763
|
: core.getTask(params.id, workspaceId);
|
|
664
764
|
if (updated && checklistDurable) {
|
|
665
765
|
const checklistRouter = durableRouters.createChecklistRouter(durableRouters.deriveChildOperationId('task-patch-checklist', 0, params.id));
|
|
@@ -679,7 +779,15 @@ export function registerTaskRoutes(deps) {
|
|
|
679
779
|
core,
|
|
680
780
|
workspaceId,
|
|
681
781
|
});
|
|
682
|
-
updated = attachmentLinksRouter.replace({
|
|
782
|
+
updated = attachmentLinksRouter.replace({
|
|
783
|
+
taskId: params.id,
|
|
784
|
+
links,
|
|
785
|
+
...(hasCardCover ? {
|
|
786
|
+
cardCoverAssetId: updates.cardCoverAssetId === null
|
|
787
|
+
? null
|
|
788
|
+
: String(updates.cardCoverAssetId).trim(),
|
|
789
|
+
} : {}),
|
|
790
|
+
}).task;
|
|
683
791
|
}
|
|
684
792
|
}
|
|
685
793
|
if (!updated) {
|
|
@@ -687,8 +795,14 @@ export function registerTaskRoutes(deps) {
|
|
|
687
795
|
res.end(JSON.stringify({ error: 'Task not found' }));
|
|
688
796
|
return;
|
|
689
797
|
}
|
|
798
|
+
const authoritative = core.getTaskDetailSnapshot(params.id, workspaceId);
|
|
799
|
+
if (!authoritative) {
|
|
800
|
+
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
801
|
+
res.end(JSON.stringify({ error: 'Task not found' }));
|
|
802
|
+
return;
|
|
803
|
+
}
|
|
690
804
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
691
|
-
res.end(JSON.stringify(
|
|
805
|
+
res.end(JSON.stringify(authoritative));
|
|
692
806
|
}
|
|
693
807
|
catch (error) {
|
|
694
808
|
const statusCode = resolveErrorStatusCode(error, 400);
|
|
@@ -766,43 +880,53 @@ export function registerTaskRoutes(deps) {
|
|
|
766
880
|
addRoute('GET', '/api/taskforce/planning/bootstrap', async (req, res) => {
|
|
767
881
|
if (!ensureAppAccess(req, res))
|
|
768
882
|
return;
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
883
|
+
runWithPerformanceTrace(req, () => {
|
|
884
|
+
const startedAt = getRouteTimingNow();
|
|
885
|
+
const workspaceId = requestWorkspaceId(req);
|
|
886
|
+
const traceId = requestBootstrapTraceId(req);
|
|
887
|
+
const diagnostics = {};
|
|
888
|
+
const data = core.listPlanningBootstrap(workspaceId, diagnostics);
|
|
889
|
+
const serializeStartedAt = getRouteTimingNow();
|
|
890
|
+
const serialized = serializeJsonWithTiming(data, serializeStartedAt);
|
|
891
|
+
const totalDurationMs = Math.max(0, getRouteTimingNow() - startedAt);
|
|
892
|
+
const details = diagnostics;
|
|
893
|
+
const performanceDiagnostics = currentPerformanceTraceDiagnostics();
|
|
894
|
+
setServerTimingHeader(res, [
|
|
895
|
+
{ name: 'planning-bootstrap', durationMs: totalDurationMs },
|
|
896
|
+
{ name: 'planning-bootstrap-initiatives', durationMs: details.initiativeLoadMs ?? 0 },
|
|
897
|
+
{ name: 'planning-bootstrap-workstreams', durationMs: details.workstreamLoadMs ?? 0 },
|
|
898
|
+
{ name: 'planning-bootstrap-tasks', durationMs: details.taskSummaryQueryMs ?? 0 },
|
|
899
|
+
{ name: 'planning-bootstrap-build', durationMs: details.taskSummaryBuildMs ?? 0 },
|
|
900
|
+
{ name: 'planning-bootstrap-json', durationMs: serialized.durationMs },
|
|
901
|
+
...performanceTraceServerTimingMetrics(performanceDiagnostics),
|
|
902
|
+
]);
|
|
903
|
+
setPerformanceTraceHeaders(res, performanceDiagnostics, serialized.byteLength);
|
|
904
|
+
logSlowBootstrapRoute({
|
|
905
|
+
route: '/api/taskforce/planning/bootstrap',
|
|
906
|
+
workspaceId,
|
|
907
|
+
traceId,
|
|
908
|
+
durationMs: totalDurationMs,
|
|
909
|
+
details: {
|
|
910
|
+
initiativeCount: details.initiativeCount ?? 0,
|
|
911
|
+
workstreamCount: details.workstreamCount ?? 0,
|
|
912
|
+
workstreamLinkedTaskCount: details.workstreamLinkedTaskCount ?? 0,
|
|
913
|
+
workstreamTaskSummaryCount: details.workstreamTaskSummaryCount ?? 0,
|
|
914
|
+
responseBytes: serialized.byteLength,
|
|
915
|
+
initiativeLoadMs: details.initiativeLoadMs ?? 0,
|
|
916
|
+
workstreamLoadMs: details.workstreamLoadMs ?? 0,
|
|
917
|
+
taskSummaryQueryMs: details.taskSummaryQueryMs ?? 0,
|
|
918
|
+
taskSummaryBuildMs: details.taskSummaryBuildMs ?? 0,
|
|
919
|
+
jsonSerializeMs: serialized.durationMs,
|
|
920
|
+
...(performanceDiagnostics ? {
|
|
921
|
+
postgresQueryCount: performanceDiagnostics.postgresQueryCount,
|
|
922
|
+
postgresWorkerCallCount: performanceDiagnostics.postgresWorkerCallCount,
|
|
923
|
+
postgresWorkerWaitMs: Math.round(performanceDiagnostics.postgresWorkerWaitMs),
|
|
924
|
+
} : {}),
|
|
925
|
+
},
|
|
926
|
+
});
|
|
927
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
928
|
+
res.end(serialized.body);
|
|
803
929
|
});
|
|
804
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
805
|
-
res.end(serialized.body);
|
|
806
930
|
});
|
|
807
931
|
// POST /api/taskforce/initiative - Create initiative
|
|
808
932
|
addRoute('POST', '/api/taskforce/initiative', async (req, res) => {
|
|
@@ -812,7 +936,7 @@ export function registerTaskRoutes(deps) {
|
|
|
812
936
|
try {
|
|
813
937
|
const workspaceId = requestWorkspaceId(req);
|
|
814
938
|
const router = createInitiativeRouter(req, workspaceId);
|
|
815
|
-
const allowed = new Set(['id', 'title', 'description', 'ownerId', 'order', 'attachments', 'createdAt']);
|
|
939
|
+
const allowed = new Set(['id', 'title', 'description', 'ownerId', 'order', 'attachments', 'createdAt', 'icon', 'color']);
|
|
816
940
|
const unsupported = Object.keys(body || {}).filter((key) => !allowed.has(key));
|
|
817
941
|
if (router.enabled && unsupported.length > 0) {
|
|
818
942
|
const error = new Error(`Unsupported initiative fields: ${unsupported.sort().join(', ')}`);
|
|
@@ -826,16 +950,28 @@ export function registerTaskRoutes(deps) {
|
|
|
826
950
|
error.statusCode = 400;
|
|
827
951
|
throw error;
|
|
828
952
|
}
|
|
829
|
-
const initiative =
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
953
|
+
const initiative = core.getDatabaseAdapter().transaction(() => {
|
|
954
|
+
const created = router.enabled
|
|
955
|
+
? initiativeResult(router.create(String(body?.id || '').trim() || `initiative-${randomUUID()}`, {
|
|
956
|
+
title: body?.title,
|
|
957
|
+
description: body?.description ?? null,
|
|
958
|
+
ownerId: body?.ownerId ?? null,
|
|
959
|
+
order: body?.order ?? null,
|
|
960
|
+
attachments: serializeCanonicalPlanningAttachmentLinks(body?.attachments ?? []),
|
|
961
|
+
createdAt: String(body?.createdAt || '').trim() || new Date().toISOString(),
|
|
962
|
+
}))
|
|
963
|
+
: core.createInitiative(body || {}, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
964
|
+
if (!created)
|
|
965
|
+
throw new Error('Durable initiative capture did not return a provisional initiative.');
|
|
966
|
+
const hasIdentity = Object.prototype.hasOwnProperty.call(body || {}, 'icon')
|
|
967
|
+
|| Object.prototype.hasOwnProperty.call(body || {}, 'color');
|
|
968
|
+
return hasIdentity
|
|
969
|
+
? core.updatePlanningEntityIdentity('initiative', created.id, {
|
|
970
|
+
...(Object.prototype.hasOwnProperty.call(body || {}, 'icon') ? { icon: body.icon } : {}),
|
|
971
|
+
...(Object.prototype.hasOwnProperty.call(body || {}, 'color') ? { color: body.color } : {}),
|
|
972
|
+
}, workspaceId)
|
|
973
|
+
: created;
|
|
974
|
+
})();
|
|
839
975
|
if (!initiative)
|
|
840
976
|
throw new Error('Durable initiative capture did not return a provisional initiative.');
|
|
841
977
|
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
@@ -883,7 +1019,7 @@ export function registerTaskRoutes(deps) {
|
|
|
883
1019
|
};
|
|
884
1020
|
const updated = router.enabled
|
|
885
1021
|
? initiativeResult(router.updateMetadata(params.id, durablePatch))
|
|
886
|
-
: core.updateInitiative(params.id, body || {}, workspaceId, { actorRef:
|
|
1022
|
+
: core.updateInitiative(params.id, body || {}, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
887
1023
|
if (!updated)
|
|
888
1024
|
throw new Error('Durable initiative capture did not return a provisional initiative.');
|
|
889
1025
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -893,6 +1029,30 @@ export function registerTaskRoutes(deps) {
|
|
|
893
1029
|
writeInitiativeMutationError(res, error, 'Failed to update initiative');
|
|
894
1030
|
}
|
|
895
1031
|
});
|
|
1032
|
+
addRoute('PATCH', '/api/taskforce/initiative/:id/identity', async (req, res, params) => {
|
|
1033
|
+
if (!ensureAppAccess(req, res))
|
|
1034
|
+
return;
|
|
1035
|
+
const body = await parseJsonBody(req);
|
|
1036
|
+
try {
|
|
1037
|
+
const workspaceId = requestWorkspaceId(req);
|
|
1038
|
+
const source = body && typeof body === 'object' && !Array.isArray(body) ? body : {};
|
|
1039
|
+
const keys = Object.keys(source);
|
|
1040
|
+
if (keys.length === 0 || keys.some((key) => key !== 'icon' && key !== 'color')) {
|
|
1041
|
+
throw new TaskforceRuleError('Planning identity update must contain only icon or color.', 400, 'PLANNING_IDENTITY_INVALID');
|
|
1042
|
+
}
|
|
1043
|
+
const updated = core.updatePlanningEntityIdentity('initiative', params.id, source, workspaceId);
|
|
1044
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1045
|
+
res.end(JSON.stringify(updated));
|
|
1046
|
+
}
|
|
1047
|
+
catch (error) {
|
|
1048
|
+
const statusCode = resolveErrorStatusCode(error, 400);
|
|
1049
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
1050
|
+
res.end(JSON.stringify({
|
|
1051
|
+
error: error instanceof Error ? error.message : 'Failed to update initiative identity',
|
|
1052
|
+
code: error instanceof TaskforceRuleError ? error.code : undefined,
|
|
1053
|
+
}));
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
896
1056
|
addRoute('POST', '/api/taskforce/initiative/:id/archive', async (req, res, params) => {
|
|
897
1057
|
if (!ensureAppAccess(req, res))
|
|
898
1058
|
return;
|
|
@@ -901,7 +1061,7 @@ export function registerTaskRoutes(deps) {
|
|
|
901
1061
|
const router = createInitiativeRouter(req, workspaceId);
|
|
902
1062
|
const archived = router.enabled
|
|
903
1063
|
? initiativeResult(router.archive(params.id))
|
|
904
|
-
: core.archiveInitiative(params.id, workspaceId, { actorRef:
|
|
1064
|
+
: core.archiveInitiative(params.id, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
905
1065
|
if (!archived)
|
|
906
1066
|
throw new Error('Durable initiative capture did not return a provisional initiative.');
|
|
907
1067
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -919,7 +1079,7 @@ export function registerTaskRoutes(deps) {
|
|
|
919
1079
|
const router = createInitiativeRouter(req, workspaceId);
|
|
920
1080
|
const restored = router.enabled
|
|
921
1081
|
? initiativeResult(router.unarchive(params.id))
|
|
922
|
-
: core.unarchiveInitiative(params.id, workspaceId, { actorRef:
|
|
1082
|
+
: core.unarchiveInitiative(params.id, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
923
1083
|
if (!restored)
|
|
924
1084
|
throw new Error('Durable initiative capture did not return a provisional initiative.');
|
|
925
1085
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -946,7 +1106,7 @@ export function registerTaskRoutes(deps) {
|
|
|
946
1106
|
try {
|
|
947
1107
|
const workspaceId = requestWorkspaceId(req);
|
|
948
1108
|
const router = createWorkstreamRouter(req, workspaceId);
|
|
949
|
-
const allowed = new Set(['id', 'initiativeId', 'title', 'description', 'ownerId', 'order', 'attachments', 'createdAt']);
|
|
1109
|
+
const allowed = new Set(['id', 'initiativeId', 'title', 'description', 'ownerId', 'order', 'attachments', 'createdAt', 'icon', 'color']);
|
|
950
1110
|
const unsupported = Object.keys(body || {}).filter((key) => !allowed.has(key));
|
|
951
1111
|
if (router.enabled && unsupported.length > 0) {
|
|
952
1112
|
const error = new Error(`Unsupported workstream fields: ${unsupported.sort().join(', ')}`);
|
|
@@ -960,17 +1120,29 @@ export function registerTaskRoutes(deps) {
|
|
|
960
1120
|
error.statusCode = 400;
|
|
961
1121
|
throw error;
|
|
962
1122
|
}
|
|
963
|
-
const workstream =
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1123
|
+
const workstream = core.getDatabaseAdapter().transaction(() => {
|
|
1124
|
+
const created = router.enabled
|
|
1125
|
+
? workstreamResult(router.create(String(body?.id || '').trim(), {
|
|
1126
|
+
initiativeId: body?.initiativeId ?? null,
|
|
1127
|
+
title: body?.title,
|
|
1128
|
+
description: body?.description ?? null,
|
|
1129
|
+
ownerId: body?.ownerId ?? null,
|
|
1130
|
+
order: body?.order ?? null,
|
|
1131
|
+
attachments: serializeCanonicalPlanningAttachmentLinks(body?.attachments ?? []),
|
|
1132
|
+
createdAt: String(body?.createdAt || '').trim(),
|
|
1133
|
+
}))
|
|
1134
|
+
: core.createWorkstream(body || {}, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1135
|
+
if (!created)
|
|
1136
|
+
throw new Error('Durable workstream capture did not return a provisional workstream.');
|
|
1137
|
+
const hasIdentity = Object.prototype.hasOwnProperty.call(body || {}, 'icon')
|
|
1138
|
+
|| Object.prototype.hasOwnProperty.call(body || {}, 'color');
|
|
1139
|
+
return hasIdentity
|
|
1140
|
+
? core.updatePlanningEntityIdentity('workstream', created.id, {
|
|
1141
|
+
...(Object.prototype.hasOwnProperty.call(body || {}, 'icon') ? { icon: body.icon } : {}),
|
|
1142
|
+
...(Object.prototype.hasOwnProperty.call(body || {}, 'color') ? { color: body.color } : {}),
|
|
1143
|
+
}, workspaceId)
|
|
1144
|
+
: created;
|
|
1145
|
+
})();
|
|
974
1146
|
if (!workstream)
|
|
975
1147
|
throw new Error('Durable workstream capture did not return a provisional workstream.');
|
|
976
1148
|
res.writeHead(201, { 'Content-Type': 'application/json' });
|
|
@@ -1018,7 +1190,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1018
1190
|
};
|
|
1019
1191
|
const updated = router.enabled
|
|
1020
1192
|
? workstreamResult(router.updateMetadata(params.id, durablePatch))
|
|
1021
|
-
: core.updateWorkstream(params.id, body || {}, workspaceId, { actorRef:
|
|
1193
|
+
: core.updateWorkstream(params.id, body || {}, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1022
1194
|
if (!updated)
|
|
1023
1195
|
throw new Error('Durable workstream capture did not return a provisional workstream.');
|
|
1024
1196
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -1028,6 +1200,30 @@ export function registerTaskRoutes(deps) {
|
|
|
1028
1200
|
writeWorkstreamMutationError(res, error, 'Failed to update workstream');
|
|
1029
1201
|
}
|
|
1030
1202
|
});
|
|
1203
|
+
addRoute('PATCH', '/api/taskforce/workstream/:id/identity', async (req, res, params) => {
|
|
1204
|
+
if (!ensureAppAccess(req, res))
|
|
1205
|
+
return;
|
|
1206
|
+
const body = await parseJsonBody(req);
|
|
1207
|
+
try {
|
|
1208
|
+
const workspaceId = requestWorkspaceId(req);
|
|
1209
|
+
const source = body && typeof body === 'object' && !Array.isArray(body) ? body : {};
|
|
1210
|
+
const keys = Object.keys(source);
|
|
1211
|
+
if (keys.length === 0 || keys.some((key) => key !== 'icon' && key !== 'color')) {
|
|
1212
|
+
throw new TaskforceRuleError('Planning identity update must contain only icon or color.', 400, 'PLANNING_IDENTITY_INVALID');
|
|
1213
|
+
}
|
|
1214
|
+
const updated = core.updatePlanningEntityIdentity('workstream', params.id, source, workspaceId);
|
|
1215
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1216
|
+
res.end(JSON.stringify(updated));
|
|
1217
|
+
}
|
|
1218
|
+
catch (error) {
|
|
1219
|
+
const statusCode = resolveErrorStatusCode(error, 400);
|
|
1220
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
1221
|
+
res.end(JSON.stringify({
|
|
1222
|
+
error: error instanceof Error ? error.message : 'Failed to update workstream identity',
|
|
1223
|
+
code: error instanceof TaskforceRuleError ? error.code : undefined,
|
|
1224
|
+
}));
|
|
1225
|
+
}
|
|
1226
|
+
});
|
|
1031
1227
|
addRoute('POST', '/api/taskforce/workstream/:id/archive', async (req, res, params) => {
|
|
1032
1228
|
if (!ensureAppAccess(req, res))
|
|
1033
1229
|
return;
|
|
@@ -1036,7 +1232,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1036
1232
|
const router = createWorkstreamRouter(req, workspaceId);
|
|
1037
1233
|
const archived = router.enabled
|
|
1038
1234
|
? workstreamResult(router.archive(params.id))
|
|
1039
|
-
: core.archiveWorkstream(params.id, workspaceId, { actorRef:
|
|
1235
|
+
: core.archiveWorkstream(params.id, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1040
1236
|
if (!archived)
|
|
1041
1237
|
throw new Error('Durable workstream capture did not return a provisional workstream.');
|
|
1042
1238
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -1054,7 +1250,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1054
1250
|
const router = createWorkstreamRouter(req, workspaceId);
|
|
1055
1251
|
const restored = router.enabled
|
|
1056
1252
|
? workstreamResult(router.unarchive(params.id))
|
|
1057
|
-
: core.unarchiveWorkstream(params.id, workspaceId, { actorRef:
|
|
1253
|
+
: core.unarchiveWorkstream(params.id, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1058
1254
|
if (!restored)
|
|
1059
1255
|
throw new Error('Durable workstream capture did not return a provisional workstream.');
|
|
1060
1256
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
@@ -1180,9 +1376,15 @@ export function registerTaskRoutes(deps) {
|
|
|
1180
1376
|
if (!ensureAppAccess(req, res))
|
|
1181
1377
|
return;
|
|
1182
1378
|
const workspaceId = requestWorkspaceId(req);
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1379
|
+
respondWithPerformanceTraceJson({
|
|
1380
|
+
req,
|
|
1381
|
+
res,
|
|
1382
|
+
route: '/api/taskforce/archive',
|
|
1383
|
+
workspaceId,
|
|
1384
|
+
load: () => (context.authConfig?.runtimeMode === 'cloud' ? 'cloud' : requestRuntimeMode(req)) === 'cloud'
|
|
1385
|
+
? core.listArchiveSummaries(workspaceId)
|
|
1386
|
+
: core.listArchive(workspaceId),
|
|
1387
|
+
});
|
|
1186
1388
|
});
|
|
1187
1389
|
// POST /api/taskforce/task/:id/complete - Archive as complete
|
|
1188
1390
|
addRoute('POST', '/api/taskforce/task/:id/complete', async (req, res, params) => {
|
|
@@ -1193,7 +1395,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1193
1395
|
const durableRouter = createTaskHttpRootRouter(req, workspaceId);
|
|
1194
1396
|
const archived = durableRouter.enabled
|
|
1195
1397
|
? durableRouter.archive(params.id, false, null)
|
|
1196
|
-
: core.archiveTask(params.id, false, undefined, workspaceId, { actorRef:
|
|
1398
|
+
: core.archiveTask(params.id, false, undefined, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1197
1399
|
if (!archived) {
|
|
1198
1400
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
1199
1401
|
res.end(JSON.stringify({ error: 'Task not found' }));
|
|
@@ -1221,7 +1423,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1221
1423
|
const durableRouter = createTaskHttpRootRouter(req, workspaceId);
|
|
1222
1424
|
const archived = durableRouter.enabled
|
|
1223
1425
|
? durableRouter.archive(params.id, true, reason)
|
|
1224
|
-
: core.archiveTask(params.id, true, reason, workspaceId, { actorRef:
|
|
1426
|
+
: core.archiveTask(params.id, true, reason, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1225
1427
|
if (!archived) {
|
|
1226
1428
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
1227
1429
|
res.end(JSON.stringify({ error: 'Task not found' }));
|
|
@@ -1247,7 +1449,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1247
1449
|
const durableRouter = createTaskHttpRootRouter(req, workspaceId);
|
|
1248
1450
|
const deleted = durableRouter.enabled
|
|
1249
1451
|
? durableRouter.delete(params.id)
|
|
1250
|
-
: core.softDeleteTask(params.id, workspaceId, { actorRef:
|
|
1452
|
+
: core.softDeleteTask(params.id, workspaceId, { actorRef: requestHumanActorRef(req), source: 'ui' });
|
|
1251
1453
|
if (!deleted) {
|
|
1252
1454
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
1253
1455
|
res.end(JSON.stringify({ error: 'Task not found' }));
|
|
@@ -1272,7 +1474,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1272
1474
|
const durableRouter = createTaskHttpRootRouter(req, workspaceId);
|
|
1273
1475
|
const restored = durableRouter.enabled
|
|
1274
1476
|
? durableRouter.restore(params.id)
|
|
1275
|
-
: core.restoreDeletedTask(params.id, workspaceId, { actorRef:
|
|
1477
|
+
: core.restoreDeletedTask(params.id, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1276
1478
|
if (!restored) {
|
|
1277
1479
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
1278
1480
|
res.end(JSON.stringify({ error: 'Deleted task not found' }));
|
|
@@ -1362,7 +1564,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1362
1564
|
continue;
|
|
1363
1565
|
}
|
|
1364
1566
|
const task = core.restoreDeletedTask(deletedRecordId, workspaceId, {
|
|
1365
|
-
actorRef:
|
|
1567
|
+
actorRef: requestHumanActorRef(req),
|
|
1366
1568
|
restoreDestination,
|
|
1367
1569
|
});
|
|
1368
1570
|
if (!task) {
|
|
@@ -1533,7 +1735,7 @@ export function registerTaskRoutes(deps) {
|
|
|
1533
1735
|
const durableRouter = createTaskHttpRootRouter(req, workspaceId);
|
|
1534
1736
|
const restored = durableRouter.enabled
|
|
1535
1737
|
? durableRouter.unarchive(params.id)
|
|
1536
|
-
: core.unarchiveTask(params.id, workspaceId, { actorRef:
|
|
1738
|
+
: core.unarchiveTask(params.id, workspaceId, { actorRef: requestHumanActorRef(req) });
|
|
1537
1739
|
if (!restored) {
|
|
1538
1740
|
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
1539
1741
|
res.end(JSON.stringify({ error: 'Archived task not found' }));
|