@taskforcehq/taskforce 0.3.305 → 0.3.306
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 +295 -89
- package/dist/TaskforceCore.js +215 -43
- package/dist/TaskforceCore.test.js +433 -28
- package/dist/assets/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/assets/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/assets/fonts/Noir_medium.woff2 +0 -0
- package/dist/assets/fonts/Noir_regular.woff2 +0 -0
- package/dist/assets/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/assets/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/compat/workspaceSyncCompat.js +46 -2
- package/dist/compat/workspaceSyncCompat.test.js +38 -1
- package/dist/components/context/ContextAttachmentManager.d.ts +14 -0
- package/dist/components/context/ContextAttachmentManager.js +549 -0
- package/dist/components/features/AgentsModule.d.ts +10 -1
- package/dist/components/features/AgentsModule.js +260 -15
- package/dist/components/features/AgentsModule.test.js +255 -5
- package/dist/components/features/DocumentViewer.d.ts +5 -1
- package/dist/components/features/DocumentViewer.js +60 -3
- package/dist/components/features/DocumentWorkspace.js +1 -1
- package/dist/components/features/DocumentWorkspace.test.js +33 -0
- package/dist/components/features/documentWorkspaceModel.d.ts +1 -1
- package/dist/components/task/TaskCard.js +19 -28
- package/dist/components/task/TaskCard.test.js +38 -3
- package/dist/components/task/TaskContextUpload.js +4 -526
- package/dist/components/task/TaskForm.js +85 -90
- package/dist/components/task/TaskForm.test.js +110 -8
- package/dist/components/task/TaskKanban.d.ts +2 -1
- package/dist/components/task/TaskKanban.js +94 -13
- package/dist/components/task/TaskKanban.test.js +36 -0
- package/dist/components/ui/EditableAvatarButton.d.ts +18 -0
- package/dist/components/ui/EditableAvatarButton.js +18 -0
- package/dist/components/views/PlanComparisonPage.d.ts +9 -1
- package/dist/components/views/PlanComparisonPage.js +70 -14
- package/dist/components/views/PlanComparisonPage.test.js +238 -0
- package/dist/components/views/PlansPage.js +127 -36
- package/dist/components/views/PlansPage.test.js +294 -12
- package/dist/components/views/StandaloneLayout.js +283 -533
- package/dist/components/views/panels/PlanningDrawer.d.ts +8 -1
- package/dist/components/views/panels/PlanningDrawer.js +18 -11
- package/dist/components/views/panels/PlanningDrawer.test.d.ts +1 -0
- package/dist/components/views/panels/PlanningDrawer.test.js +141 -0
- package/dist/components/views/planningScope.d.ts +20 -0
- package/dist/components/views/planningScope.js +25 -0
- package/dist/components/views/planningScope.test.d.ts +1 -0
- package/dist/components/views/planningScope.test.js +60 -0
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +26 -1
- package/dist/components/views/standalone/modals/AccountHubModal.js +76 -2
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +20 -3
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.d.ts +20 -0
- package/dist/components/views/standalone/modals/AvatarImageManagerModal.js +127 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +2 -9
- package/dist/components/views/standalone/modals/EditProfileModal.js +3 -2
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.d.ts +1 -0
- package/dist/components/views/standalone/modals/SyncEnableWarningModal.test.js +24 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +2 -1
- package/dist/components/views/standalone/modals/SyncStatusModal.js +2 -2
- package/dist/core/AiProfileService.d.ts +39 -2
- package/dist/core/AiProfileService.js +639 -73
- package/dist/core/AiProfileService.test.js +19 -1
- package/dist/core/AiProfiles.test.js +566 -7
- package/dist/core/AttachmentLinkService.js +57 -15
- package/dist/core/AuthIdentityService.d.ts +107 -0
- package/dist/core/AuthIdentityService.js +284 -0
- package/dist/core/AuthTokenService.d.ts +4 -0
- package/dist/core/AuthTokenService.js +34 -6
- package/dist/core/AuthTokenService.test.js +3 -3
- package/dist/core/EntitlementsPolicy.test.js +2 -2
- package/dist/core/GlobalSettingsService.js +115 -6
- package/dist/core/PlanEntitlementService.d.ts +23 -2
- package/dist/core/PlanEntitlementService.js +343 -57
- package/dist/core/PlanFeatureCatalog.test.d.ts +1 -0
- package/dist/core/PlanFeatureCatalog.test.js +84 -0
- package/dist/core/PlanVersionPolicy.test.js +35 -2
- package/dist/core/PlanningEntities.test.js +52 -0
- package/dist/core/SignupMonetizationSettings.test.js +199 -27
- package/dist/core/SyncReconciliationService.js +2 -65
- package/dist/core/SystemAdmin.test.js +42 -42
- package/dist/core/TaskAttachmentsCanonical.test.js +51 -1
- package/dist/core/Taskforce.d.ts +225 -14
- package/dist/core/Taskforce.js +765 -192
- package/dist/core/Taskforce.listTasksSlim.test.d.ts +1 -0
- package/dist/core/Taskforce.listTasksSlim.test.js +91 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +30 -3
- package/dist/core/WorkspaceLifecycleService.js +0 -5
- package/dist/core/WorkspacePermissions.test.js +25 -1
- package/dist/core/WorkspacePlanMode.test.js +117 -16
- package/dist/core/shared.d.ts +1 -1
- package/dist/core/shared.js +5 -1
- package/dist/core/types.d.ts +68 -2
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +26 -1
- package/dist/hooks/sync/bootstrap.js +2 -0
- package/dist/hooks/sync/controlPlane.d.ts +37 -0
- package/dist/hooks/sync/controlPlane.js +78 -0
- package/dist/hooks/sync/controlPlane.test.d.ts +1 -0
- package/dist/hooks/sync/controlPlane.test.js +121 -0
- package/dist/hooks/sync/lifecyclePolicy.d.ts +45 -0
- package/dist/hooks/sync/lifecyclePolicy.js +93 -0
- package/dist/hooks/sync/lifecyclePolicy.test.d.ts +1 -0
- package/dist/hooks/sync/lifecyclePolicy.test.js +124 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +10 -1
- package/dist/hooks/sync/orchestratorShared.js +68 -47
- package/dist/hooks/sync/orchestratorShared.test.js +50 -1
- package/dist/hooks/sync/pullLifecycle.d.ts +31 -0
- package/dist/hooks/sync/pullLifecycle.js +24 -0
- package/dist/hooks/sync/pullLifecycle.test.d.ts +1 -0
- package/dist/hooks/sync/pullLifecycle.test.js +80 -0
- package/dist/hooks/sync/recovery.d.ts +16 -2
- package/dist/hooks/sync/recovery.js +171 -53
- package/dist/hooks/sync/recovery.test.d.ts +1 -0
- package/dist/hooks/sync/recovery.test.js +292 -0
- package/dist/hooks/sync/transfers.d.ts +15 -3
- package/dist/hooks/sync/transfers.js +179 -62
- package/dist/hooks/sync/transfers.test.d.ts +1 -0
- package/dist/hooks/sync/transfers.test.js +396 -0
- package/dist/hooks/sync/useRecentSyncEvents.d.ts +21 -0
- package/dist/hooks/sync/useRecentSyncEvents.js +92 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.d.ts +1 -0
- package/dist/hooks/sync/useRecentSyncEvents.test.js +124 -0
- package/dist/hooks/sync/useSyncStatusActions.d.ts +30 -0
- package/dist/hooks/sync/useSyncStatusActions.js +88 -0
- package/dist/hooks/sync/useSyncStatusActions.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusActions.test.js +133 -0
- package/dist/hooks/sync/useSyncStatusControls.d.ts +25 -0
- package/dist/hooks/sync/useSyncStatusControls.js +60 -0
- package/dist/hooks/sync/useSyncStatusControls.test.d.ts +1 -0
- package/dist/hooks/sync/useSyncStatusControls.test.js +88 -0
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +12 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +9 -2
- package/dist/hooks/useSyncOrchestrator.js +359 -178
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +407 -0
- package/dist/hooks/useTaskData.js +8 -3
- package/dist/hooks/useTaskData.test.js +45 -0
- package/dist/hooks/useTaskforce.d.ts +60 -2
- package/dist/hooks/useTaskforce.js +549 -240
- package/dist/hooks/useTaskforce.runtime-routing.test.d.ts +1 -0
- package/dist/hooks/useTaskforce.runtime-routing.test.js +152 -0
- package/dist/hooks/useTaskforce.sync-behavior.test.js +2380 -212
- package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
- package/dist/hooks/useWorkspaceSyncController.js +6 -1
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +16 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +316 -35
- package/dist/localization/locales/en-US.d.ts +0 -1
- package/dist/localization/locales/en-US.js +0 -1
- package/dist/localization/locales/es-419.js +0 -1
- package/dist/localization/locales/pt-BR.js +0 -1
- package/dist/mcp/documentAssetRegistrar.js +3 -3
- package/dist/mcp/runtime.d.ts +2 -0
- package/dist/mcp/runtime.js +131 -64
- package/dist/mcp/runtime.test.js +291 -12
- package/dist/migrations/taskSchemaMigrations.d.ts +1 -1
- package/dist/migrations/taskSchemaMigrations.js +171 -61
- package/dist/migrations/taskSchemaMigrations.test.js +15 -0
- package/dist/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/dist/resources/templates/workflows/collaborate.yaml +1 -1
- package/dist/resources/templates/workflows/evaluate.yaml +2 -2
- package/dist/resources/templates/workflows/plan.yaml +1 -1
- package/dist/resources/templates/workflows/review.yaml +2 -2
- package/dist/server/annotatedAttachmentsRoutes.test.js +3 -3
- package/dist/server/auth/providers/apple.d.ts +33 -0
- package/dist/server/auth/providers/apple.js +82 -0
- package/dist/server/auth/providers/appleClientSecret.d.ts +37 -0
- package/dist/server/auth/providers/appleClientSecret.js +65 -0
- package/dist/server/auth/providers/github.d.ts +26 -0
- package/dist/server/auth/providers/github.js +86 -0
- package/dist/server/auth/providers/google.d.ts +21 -0
- package/dist/server/auth/providers/google.js +56 -0
- package/dist/server/auth/providers/types.d.ts +21 -0
- package/dist/server/auth/providers/types.js +1 -0
- package/dist/server/auth.d.ts +2 -0
- package/dist/server/auth.js +6 -3
- package/dist/server/documentReviewRoutes.test.js +36 -3
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +120 -9
- package/dist/server/index.rateLimit.test.js +3 -0
- package/dist/server/index.test.js +106 -3
- package/dist/server/routes/admin.d.ts +3 -0
- package/dist/server/routes/admin.js +272 -19
- package/dist/server/routes/auth.d.ts +15 -2
- package/dist/server/routes/auth.js +994 -57
- package/dist/server/routes/authSupport.d.ts +1 -1
- package/dist/server/routes/authSupport.js +1 -1
- package/dist/server/routes/billing.js +361 -35
- package/dist/server/routes/billing.test.js +592 -12
- package/dist/server/routes/documents.d.ts +1 -0
- package/dist/server/routes/documents.js +172 -70
- package/dist/server/routes/shared.d.ts +28 -2
- package/dist/server/routes/shared.js +69 -4
- package/dist/server/routes/sync.integration.test.js +437 -39
- package/dist/server/routes/sync.js +61 -605
- package/dist/server/routes/syncAuxRoutes.d.ts +15 -0
- package/dist/server/routes/syncAuxRoutes.js +91 -0
- package/dist/server/routes/syncAuxRoutes.test.d.ts +1 -0
- package/dist/server/routes/syncAuxRoutes.test.js +158 -0
- package/dist/server/routes/syncPullApplyRoutes.d.ts +36 -0
- package/dist/server/routes/syncPullApplyRoutes.js +204 -0
- package/dist/server/routes/syncPushRoutes.d.ts +24 -0
- package/dist/server/routes/syncPushRoutes.js +212 -0
- package/dist/server/routes/syncRouteGuards.d.ts +36 -0
- package/dist/server/routes/syncRouteGuards.js +67 -0
- package/dist/server/routes/syncRouteGuards.test.d.ts +1 -0
- package/dist/server/routes/syncRouteGuards.test.js +94 -0
- package/dist/server/routes/syncRouteTypes.d.ts +13 -0
- package/dist/server/routes/syncRouteTypes.js +1 -0
- package/dist/server/routes/syncSnapshotRoutes.d.ts +66 -0
- package/dist/server/routes/syncSnapshotRoutes.js +180 -0
- package/dist/server/routes/tasks.js +43 -1
- package/dist/server/routes/workspaces.js +36 -5
- package/dist/server/routes.js +60 -3
- package/dist/server/routes.test.js +1824 -171
- package/dist/services/workflowExportSnapshots.test.js +2 -0
- package/dist/shared/aiProfileSeatScope.d.ts +5 -0
- package/dist/shared/aiProfileSeatScope.js +21 -0
- package/dist/shared/passwordPolicy.d.ts +13 -0
- package/dist/shared/passwordPolicy.js +84 -0
- package/dist/shared/passwordPolicy.test.d.ts +1 -0
- package/dist/shared/passwordPolicy.test.js +34 -0
- package/dist/storage/workspaceAssetStore.d.ts +15 -3
- package/dist/storage/workspaceAssetStore.js +132 -44
- package/dist/storage/workspaceAssetStore.test.js +93 -6
- package/dist/styles/fonts.css +70 -0
- package/dist/sync/collaborationSyncPayload.d.ts +6 -1
- package/dist/sync/collaborationSyncPayload.js +17 -11
- package/dist/sync/collaborationSyncPayload.test.js +13 -1
- package/dist/sync/contentSyncState.d.ts +4 -8
- package/dist/sync/contentSyncState.js +17 -70
- package/dist/sync/syncApplyHandlers.d.ts +7 -0
- package/dist/sync/syncApplyHandlers.js +28 -13
- package/dist/sync/syncApplyHandlers.test.js +70 -3
- package/dist/sync/syncFieldSemantics.d.ts +12 -0
- package/dist/sync/syncFieldSemantics.js +55 -0
- package/dist/sync/syncResourceAdapters.d.ts +44 -0
- package/dist/sync/syncResourceAdapters.js +77 -0
- package/dist/sync/syncService.d.ts +5 -0
- package/dist/sync/syncService.js +52 -0
- package/dist/sync/syncService.test.js +57 -3
- package/dist/sync/taskSyncChangeKey.d.ts +2 -0
- package/dist/sync/taskSyncChangeKey.js +143 -0
- package/dist/sync/taskSyncPayload.js +3 -8
- package/dist/sync/workspacePullFeed.js +4 -3
- package/dist/sync/workspacePullFeed.test.js +43 -0
- package/dist/sync/workspaceRepair.js +5 -2
- package/dist/sync/workspaceSyncModel.d.ts +45 -0
- package/dist/sync/workspaceSyncModel.js +183 -28
- package/dist/sync/workspaceSyncModel.test.js +291 -12
- package/dist/sync/workspaceSyncState.d.ts +17 -0
- package/dist/sync/workspaceSyncState.js +2 -1
- package/dist/sync/workspaceSyncSurface.js +3 -8
- package/dist/types.d.ts +17 -0
- package/dist/ui/assets/AgentsModule-DrLawwNl.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-BG6P_GVW.js → AnnotatedAttachmentWorkspace-Z9_whf7F.js} +1 -1
- package/dist/ui/assets/CourierPrime-Bold-BuLj_dpw.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-BoldItalic-BrK2pUkZ.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Italic-DFUZK5Ey.woff2 +0 -0
- package/dist/ui/assets/CourierPrime-Regular-BsKphzVf.woff2 +0 -0
- package/dist/ui/assets/DocumentWorkspace-B03MaSkw.js +252 -0
- package/dist/ui/assets/DocumentWorkspace-Dhdso07p.css +1 -0
- package/dist/ui/assets/{InitiativesModule-Dhm7M8e7.js → InitiativesModule-9E6ParrY.js} +1 -1
- package/dist/ui/assets/Noir_medium-bxQwKGzB.woff2 +0 -0
- package/dist/ui/assets/Noir_regular-ojf2kxlG.woff2 +0 -0
- package/dist/ui/assets/PlansPage-CvfnMiWq.css +1 -0
- package/dist/ui/assets/PlansPage-DRXscYxH.js +1 -0
- package/dist/ui/assets/RussoOne-Regular-Cu_qq_qC.woff2 +0 -0
- package/dist/ui/assets/SpecialElite-Regular-Di6gSvAS.woff2 +0 -0
- package/dist/ui/assets/{TaskSettings-ln0aF7xc.js → TaskSettings-DZX4jk7e.js} +1 -1
- package/dist/ui/assets/{WorkflowsModule-BcS4afRn.js → WorkflowsModule-BA7jcEpH.js} +1 -1
- package/dist/ui/assets/index-9eT8e0Lu.css +1 -0
- package/dist/ui/assets/index-C6k75jr8.js +6 -0
- package/dist/ui/assets/{vendor-icons-BSUaRwF8.js → vendor-icons-DuEd_65c.js} +1 -1
- package/dist/ui/fonts/CourierPrime-Bold.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Bold.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-BoldItalic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Italic.woff2 +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.ttf +0 -0
- package/dist/ui/fonts/CourierPrime-Regular.woff2 +0 -0
- package/dist/ui/fonts/Noir_medium.otf +0 -0
- package/dist/ui/fonts/Noir_medium.woff2 +0 -0
- package/dist/ui/fonts/Noir_regular.otf +0 -0
- package/dist/ui/fonts/Noir_regular.woff2 +0 -0
- package/dist/ui/fonts/RussoOne-Regular.woff2 +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.ttf +0 -0
- package/dist/ui/fonts/SpecialElite-Regular.woff2 +0 -0
- package/dist/ui/index.html +3 -3
- package/dist/utils/accountProfileSummaryCache.d.ts +5 -0
- package/dist/utils/assignees.d.ts +2 -0
- package/dist/utils/assignees.js +2 -0
- package/dist/utils/avatarUpload.d.ts +27 -0
- package/dist/utils/avatarUpload.js +132 -0
- package/dist/utils/avatarUpload.test.d.ts +1 -0
- package/dist/utils/avatarUpload.test.js +40 -0
- package/dist/utils/bootstrapTrace.d.ts +7 -0
- package/dist/utils/bootstrapTrace.js +29 -0
- package/dist/utils/commercialLifecyclePresentation.js +3 -0
- package/dist/utils/contextAssetEvents.d.ts +2 -0
- package/dist/utils/syncEventDetails.d.ts +3 -0
- package/dist/utils/syncEventDetails.js +64 -0
- package/dist/utils/syncEventDetails.test.d.ts +1 -0
- package/dist/utils/syncEventDetails.test.js +23 -0
- package/dist/utils/syncEventPresentation.d.ts +15 -0
- package/dist/utils/syncEventPresentation.js +129 -0
- package/dist/utils/syncEventPresentation.test.d.ts +1 -0
- package/dist/utils/syncEventPresentation.test.js +64 -0
- package/dist/utils/syncStatusPresentation.d.ts +72 -0
- package/dist/utils/syncStatusPresentation.js +217 -0
- package/dist/utils/syncStatusPresentation.test.d.ts +1 -0
- package/dist/utils/syncStatusPresentation.test.js +164 -0
- package/dist/utils/taskActivity.d.ts +2 -0
- package/dist/utils/taskActivity.js +228 -22
- package/dist/utils/taskActivity.test.js +119 -8
- package/dist/utils/workspaceSyncPresentation.d.ts +4 -0
- package/dist/utils/workspaceSyncPresentation.js +68 -2
- package/dist/utils/workspaceSyncPresentation.test.js +36 -1
- package/package.json +3 -2
- package/scripts/export-sqlite-to-postgres.mjs +7 -9
- package/scripts/run-e2e-realtime.sh +17 -3
- package/scripts/run-smoke.sh +17 -5
- package/scripts/run-soak.sh +17 -5
- package/src/resources/templates/workflow-sources/workflowDocs.mjs +6 -6
- package/src/resources/templates/workflows/collaborate.yaml +1 -1
- package/src/resources/templates/workflows/evaluate.yaml +2 -2
- package/src/resources/templates/workflows/plan.yaml +1 -1
- package/src/resources/templates/workflows/review.yaml +2 -2
- package/dist/ui/assets/AgentsModule-N2MnQBZk.js +0 -1
- package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +0 -1
- package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +0 -252
- package/dist/ui/assets/PlansPage-C2dd2n1X.css +0 -1
- package/dist/ui/assets/PlansPage-Cq0zXj3I.js +0 -1
- package/dist/ui/assets/RussoOne-Regular-C3BxZIj7.ttf +0 -0
- package/dist/ui/assets/index-C2-OXZV7.css +0 -1
- package/dist/ui/assets/index-DcSI5F86.js +0 -6
- package/scripts/migrate-planning-model.ts +0 -233
|
@@ -2,29 +2,60 @@ import { useCallback, useEffect } from 'react';
|
|
|
2
2
|
import { createDefaultAssigneeOptions, createWorkspaceAssigneeOptions, mergeAssigneeOptions } from '../../utils/assignees';
|
|
3
3
|
import { hasWorkspaceTaxonomyStatePayload, normalizeWorkspaceTaxonomyStatePayload } from '../../shared/taxonomyState.js';
|
|
4
4
|
import { logBootstrapDebug, readPersistedWorkspaceId } from './workspaceLocalState';
|
|
5
|
+
function getBootstrapTimestamp() {
|
|
6
|
+
return typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
7
|
+
}
|
|
5
8
|
export function useTaskforceWorkspaceBootstrap(args) {
|
|
6
|
-
const { shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, getWorkspaceRequestState, isWorkspaceRequestStale, isWorkspaceEpochStale, isAbortError, isBootstrapTimeoutError, fetchWithTimeout, handleUnauthorized, applyBootstrapConfig, loadPersistedUiState, fetchBuildInfo, markBootstrapPhase, markBootstrapStalled, fetchWorkflows, fetchInitiativeTemplates, loadAvailableEnvironments, setReferenceDataLoaded, setCustomCategories, setCustomTypes, setPriorities, setTaxonomies, setTaxonomyDisplayLabels, setConfigLoaded, hasLoadedUiStateRef, currentWorkspaceIdRef, referenceDataRequestRef, referenceDataAbortRef, bootstrapConfigAbortRef, workspaceListAbortRef, assigneeOptionsAbortRef, workspaceListHydratedRef, setAvailableWorkspaces, runtimeMode, applyResolvedWorkspaceId, workspaceSwitchingEnabled, authSessionResolved, isAuthenticated, authUserId, setHydratedWorkspaceRole, setAssigneeOptions, setAssigneeOptionsLoaded, commitCurrentWorkspaceId, currentWorkspaceId, workspaceSelectionScope, abortWorkspaceScopedRequests, setWorkspaceBootstrapPending, checkAuthSession, lastConfigRefreshKeyRef, lastAssigneeOptionsLoadKeyRef, lastWorkspaceSyncStateLoadKeyRef, lastTaskSurfaceLoadKeyRef, lastSettingsSurfaceLoadKeyRef, isOpen, activeTab, showArchive, taskScope, settingsSection, fetchTasks, fetchArchive, fetchPlanningEntities, refreshTaskCollections, loadWorkspaceSyncState, archiveBootstrapTimerRef, hasBootstrappedDataRef } = args;
|
|
9
|
+
const { shouldDeferProtectedApiCalls, shouldBlockProtectedApiCalls, getWorkspaceRequestState, isWorkspaceRequestStale, isWorkspaceEpochStale, isAbortError, isBootstrapTimeoutError, fetchWithTimeout, handleUnauthorized, applyBootstrapConfig, loadPersistedUiState, fetchBuildInfo, markBootstrapPhase, markBootstrapStalled, fetchWorkflows, fetchInitiativeTemplates, loadAvailableEnvironments, setReferenceDataLoaded, setCustomCategories, setCustomTypes, setPriorities, setTaxonomies, setTaxonomyDisplayLabels, setConfigLoaded, hasLoadedUiStateRef, currentWorkspaceIdRef, referenceDataRequestRef, referenceDataAbortRef, bootstrapConfigAbortRef, workspaceListAbortRef, assigneeOptionsAbortRef, workspaceListHydratedRef, setAvailableWorkspaces, runtimeMode, applyResolvedWorkspaceId, workspaceSwitchingEnabled, authSessionResolved, isAuthenticated, authUserId, authUserAvatarUrl, setHydratedWorkspaceRole, setAssigneeOptions, setAssigneeOptionsLoaded, commitCurrentWorkspaceId, currentWorkspaceId, workspaceSelectionScope, abortWorkspaceScopedRequests, setWorkspaceBootstrapPending, checkAuthSession, lastConfigRefreshKeyRef, lastAssigneeOptionsLoadKeyRef, lastWorkspaceSyncStateLoadKeyRef, lastTaskSurfaceLoadKeyRef, lastSettingsSurfaceLoadKeyRef, isOpen, activeTab, showArchive, taskScope, settingsSection, workspaceBootstrapPending, fetchTasks, fetchArchive, fetchPlanningEntities, refreshTaskCollections, loadWorkspaceSyncState, archiveBootstrapTimerRef, hasBootstrappedDataRef } = args;
|
|
7
10
|
const fetchReferenceData = useCallback(async (options) => {
|
|
8
11
|
const ignoreAuthGuard = options?.ignoreAuthGuard === true;
|
|
9
12
|
const force = options?.force === true;
|
|
10
|
-
if (!ignoreAuthGuard && (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls))
|
|
13
|
+
if (!ignoreAuthGuard && (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls)) {
|
|
14
|
+
logBootstrapDebug('bootstrap_reference_data_skipped', {
|
|
15
|
+
reason: shouldBlockProtectedApiCalls ? 'auth_blocked' : 'auth_deferred',
|
|
16
|
+
runtimeMode,
|
|
17
|
+
workspaceId: String(getWorkspaceRequestState().workspaceId || '').trim() || 'default',
|
|
18
|
+
force
|
|
19
|
+
});
|
|
11
20
|
return;
|
|
21
|
+
}
|
|
12
22
|
const requestState = getWorkspaceRequestState();
|
|
23
|
+
const normalizedWorkspaceId = String(requestState.workspaceId || '').trim() || 'default';
|
|
24
|
+
const cloudWorkspaceResolved = runtimeMode !== 'cloud'
|
|
25
|
+
|| !authSessionResolved
|
|
26
|
+
|| !isAuthenticated
|
|
27
|
+
|| (normalizedWorkspaceId !== '' && normalizedWorkspaceId !== 'default');
|
|
28
|
+
if (!cloudWorkspaceResolved) {
|
|
29
|
+
logBootstrapDebug('bootstrap_reference_data_skipped', {
|
|
30
|
+
reason: 'workspace_unresolved',
|
|
31
|
+
runtimeMode,
|
|
32
|
+
workspaceId: normalizedWorkspaceId,
|
|
33
|
+
force
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
13
37
|
if (!force && referenceDataRequestRef.current?.workspaceId === requestState.workspaceId) {
|
|
38
|
+
logBootstrapDebug('bootstrap_reference_data_reused', {
|
|
39
|
+
workspaceId: normalizedWorkspaceId,
|
|
40
|
+
force
|
|
41
|
+
});
|
|
14
42
|
await referenceDataRequestRef.current.promise;
|
|
15
43
|
return;
|
|
16
44
|
}
|
|
17
45
|
setReferenceDataLoaded(false);
|
|
46
|
+
const startedAt = getBootstrapTimestamp();
|
|
18
47
|
const abortController = new AbortController();
|
|
19
48
|
referenceDataAbortRef.current = abortController;
|
|
20
49
|
const request = (async () => {
|
|
21
50
|
await Promise.allSettled([
|
|
22
51
|
(async () => {
|
|
52
|
+
let source = 'empty-taxonomy-state';
|
|
23
53
|
const taxonomyRes = await fetch('/api/taskforce/taxonomy-state', { signal: abortController.signal });
|
|
24
54
|
if (!taxonomyRes.ok)
|
|
25
55
|
return;
|
|
26
56
|
const taxonomyData = await taxonomyRes.json().catch(() => ({}));
|
|
27
57
|
if (!hasWorkspaceTaxonomyStatePayload(taxonomyData)) {
|
|
58
|
+
source = 'fallback-endpoints';
|
|
28
59
|
const [catRes, typeRes, priorityRes, taxRes] = await Promise.all([
|
|
29
60
|
fetch('/api/taskforce/categories', { signal: abortController.signal }),
|
|
30
61
|
fetch('/api/taskforce/types', { signal: abortController.signal }),
|
|
@@ -42,9 +73,17 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
42
73
|
taxonomyData.priorities = priorityData.priorities;
|
|
43
74
|
taxonomyData.taxonomies = taxData.taxonomies;
|
|
44
75
|
}
|
|
76
|
+
else {
|
|
77
|
+
source = 'taxonomy-state';
|
|
78
|
+
}
|
|
45
79
|
const normalized = normalizeWorkspaceTaxonomyStatePayload(taxonomyData);
|
|
46
|
-
if (isWorkspaceRequestStale(requestState))
|
|
80
|
+
if (isWorkspaceRequestStale(requestState)) {
|
|
81
|
+
logBootstrapDebug('bootstrap_reference_data_stale_drop', {
|
|
82
|
+
workspaceId: normalizedWorkspaceId,
|
|
83
|
+
source
|
|
84
|
+
});
|
|
47
85
|
return;
|
|
86
|
+
}
|
|
48
87
|
if (normalized.categories.length > 0)
|
|
49
88
|
setCustomCategories(normalized.categories);
|
|
50
89
|
if (normalized.types.length > 0)
|
|
@@ -53,6 +92,14 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
53
92
|
setPriorities(normalized.priorities);
|
|
54
93
|
setTaxonomies(normalized.taxonomies);
|
|
55
94
|
setTaxonomyDisplayLabels(normalized.displayLabels || {});
|
|
95
|
+
logBootstrapDebug('bootstrap_reference_data_source', {
|
|
96
|
+
workspaceId: normalizedWorkspaceId,
|
|
97
|
+
source,
|
|
98
|
+
categories: normalized.categories.length,
|
|
99
|
+
types: normalized.types.length,
|
|
100
|
+
priorities: normalized.priorities.length,
|
|
101
|
+
taxonomies: normalized.taxonomies.length
|
|
102
|
+
});
|
|
56
103
|
})(),
|
|
57
104
|
fetchWorkflows(),
|
|
58
105
|
fetchInitiativeTemplates(),
|
|
@@ -61,6 +108,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
61
108
|
if (isWorkspaceRequestStale(requestState))
|
|
62
109
|
return;
|
|
63
110
|
setReferenceDataLoaded(true);
|
|
111
|
+
logBootstrapDebug('bootstrap_reference_data_loaded', {
|
|
112
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
113
|
+
workspaceId: normalizedWorkspaceId,
|
|
114
|
+
force
|
|
115
|
+
});
|
|
64
116
|
})();
|
|
65
117
|
referenceDataRequestRef.current = { workspaceId: requestState.workspaceId, promise: request };
|
|
66
118
|
try {
|
|
@@ -72,13 +124,14 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
72
124
|
if (referenceDataAbortRef.current === abortController)
|
|
73
125
|
referenceDataAbortRef.current = null;
|
|
74
126
|
}
|
|
75
|
-
}, [fetchInitiativeTemplates, fetchWorkflows, getWorkspaceRequestState, isWorkspaceRequestStale, loadAvailableEnvironments, referenceDataAbortRef, referenceDataRequestRef, setCustomCategories, setCustomTypes, setPriorities, setReferenceDataLoaded, setTaxonomies, setTaxonomyDisplayLabels, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
|
|
127
|
+
}, [authSessionResolved, fetchInitiativeTemplates, fetchWorkflows, getWorkspaceRequestState, isAuthenticated, isWorkspaceRequestStale, loadAvailableEnvironments, referenceDataAbortRef, referenceDataRequestRef, runtimeMode, setCustomCategories, setCustomTypes, setPriorities, setReferenceDataLoaded, setTaxonomies, setTaxonomyDisplayLabels, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
|
|
76
128
|
const fetchBootstrapConfig = useCallback(async (options) => {
|
|
77
129
|
const ignoreAuthGuard = options?.ignoreAuthGuard === true;
|
|
78
130
|
if (!ignoreAuthGuard && (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls))
|
|
79
131
|
return;
|
|
80
132
|
markBootstrapPhase('config');
|
|
81
133
|
const requestState = getWorkspaceRequestState();
|
|
134
|
+
const startedAt = getBootstrapTimestamp();
|
|
82
135
|
const abortController = new AbortController();
|
|
83
136
|
bootstrapConfigAbortRef.current = abortController;
|
|
84
137
|
try {
|
|
@@ -114,6 +167,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
114
167
|
}
|
|
115
168
|
setConfigLoaded(true);
|
|
116
169
|
markBootstrapPhase('ready');
|
|
170
|
+
logBootstrapDebug('bootstrap_config_loaded', {
|
|
171
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
172
|
+
status: res.status,
|
|
173
|
+
workspaceId: configResolvedWorkspaceId || requestState.workspaceId
|
|
174
|
+
});
|
|
117
175
|
void fetchBuildInfo();
|
|
118
176
|
}
|
|
119
177
|
catch (error) {
|
|
@@ -125,6 +183,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
125
183
|
}
|
|
126
184
|
markBootstrapStalled(isBootstrapTimeoutError(error) ? 'Startup checks timed out.' : 'Unable to finish startup checks.');
|
|
127
185
|
setConfigLoaded(true);
|
|
186
|
+
logBootstrapDebug('bootstrap_config_failed', {
|
|
187
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
188
|
+
workspaceId: requestState.workspaceId,
|
|
189
|
+
error: error instanceof Error ? error.message : String(error)
|
|
190
|
+
});
|
|
128
191
|
}
|
|
129
192
|
finally {
|
|
130
193
|
if (bootstrapConfigAbortRef.current === abortController)
|
|
@@ -135,6 +198,16 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
135
198
|
await fetchBootstrapConfig(options);
|
|
136
199
|
await fetchReferenceData(options);
|
|
137
200
|
}, [fetchBootstrapConfig, fetchReferenceData]);
|
|
201
|
+
const scheduleDeferredArchiveBootstrap = useCallback(() => {
|
|
202
|
+
if (typeof window === 'undefined')
|
|
203
|
+
return;
|
|
204
|
+
if (archiveBootstrapTimerRef.current !== null)
|
|
205
|
+
window.clearTimeout(archiveBootstrapTimerRef.current);
|
|
206
|
+
archiveBootstrapTimerRef.current = window.setTimeout(() => {
|
|
207
|
+
archiveBootstrapTimerRef.current = null;
|
|
208
|
+
void fetchArchive(true).then(() => logBootstrapDebug('bootstrap_archive_loaded_deferred', {}));
|
|
209
|
+
}, 1500);
|
|
210
|
+
}, [archiveBootstrapTimerRef, fetchArchive]);
|
|
138
211
|
const fetchWorkspaces = useCallback(async () => {
|
|
139
212
|
if (!workspaceSwitchingEnabled) {
|
|
140
213
|
setAvailableWorkspaces([]);
|
|
@@ -142,6 +215,7 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
142
215
|
return { success: true, workspaces: [] };
|
|
143
216
|
}
|
|
144
217
|
const requestState = getWorkspaceRequestState();
|
|
218
|
+
const startedAt = getBootstrapTimestamp();
|
|
145
219
|
const abortController = new AbortController();
|
|
146
220
|
workspaceListAbortRef.current = abortController;
|
|
147
221
|
try {
|
|
@@ -177,6 +251,12 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
177
251
|
if (runtimeMode !== 'local' && typeof data?.currentWorkspaceId === 'string' && data.currentWorkspaceId.trim().length > 0) {
|
|
178
252
|
applyResolvedWorkspaceId(data.currentWorkspaceId.trim(), { preserveNonDefaultDefault: true });
|
|
179
253
|
}
|
|
254
|
+
logBootstrapDebug('bootstrap_workspaces_loaded', {
|
|
255
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
256
|
+
workspaceId: requestState.workspaceId,
|
|
257
|
+
count: workspaces.length,
|
|
258
|
+
status: res.status
|
|
259
|
+
});
|
|
180
260
|
return { success: true, workspaces };
|
|
181
261
|
}
|
|
182
262
|
catch (error) {
|
|
@@ -184,6 +264,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
184
264
|
markBootstrapStalled('Startup checks timed out.');
|
|
185
265
|
setAvailableWorkspaces([]);
|
|
186
266
|
workspaceListHydratedRef.current = false;
|
|
267
|
+
logBootstrapDebug('bootstrap_workspaces_failed', {
|
|
268
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
269
|
+
workspaceId: requestState.workspaceId,
|
|
270
|
+
error: error instanceof Error ? error.message : String(error)
|
|
271
|
+
});
|
|
187
272
|
return { success: false, error: isAbortError(error) ? 'Workspace list request aborted.' : 'Failed to load workspaces.' };
|
|
188
273
|
}
|
|
189
274
|
finally {
|
|
@@ -193,6 +278,7 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
193
278
|
}, [applyResolvedWorkspaceId, fetchWithTimeout, getWorkspaceRequestState, isAbortError, isBootstrapTimeoutError, isWorkspaceEpochStale, markBootstrapStalled, runtimeMode, setAvailableWorkspaces, workspaceListAbortRef, workspaceListHydratedRef, workspaceSwitchingEnabled]);
|
|
194
279
|
const fetchAssigneeOptions = useCallback(async () => {
|
|
195
280
|
const requestState = getWorkspaceRequestState();
|
|
281
|
+
const startedAt = getBootstrapTimestamp();
|
|
196
282
|
const abortController = new AbortController();
|
|
197
283
|
assigneeOptionsAbortRef.current = abortController;
|
|
198
284
|
setAssigneeOptionsLoaded(false);
|
|
@@ -218,6 +304,19 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
218
304
|
setAssigneeOptionsLoaded(true);
|
|
219
305
|
return { success: false, error: data?.error || `Failed to load assignee options (${assigneeResult.status})` };
|
|
220
306
|
}
|
|
307
|
+
const normalizedAuthUserId = String(authUserId || '').trim();
|
|
308
|
+
const currentUserAvatarUrl = String(authUserAvatarUrl || '').trim();
|
|
309
|
+
const resolveMemberAvatarUrl = (candidate, fallbackValue) => {
|
|
310
|
+
const candidateAvatarUrl = typeof candidate?.avatarUrl === 'string' && candidate.avatarUrl.trim().length > 0
|
|
311
|
+
? candidate.avatarUrl.trim()
|
|
312
|
+
: '';
|
|
313
|
+
if (candidateAvatarUrl)
|
|
314
|
+
return candidateAvatarUrl;
|
|
315
|
+
const candidateUserId = String(candidate?.userId || fallbackValue || '').trim();
|
|
316
|
+
return normalizedAuthUserId && candidateUserId === normalizedAuthUserId && currentUserAvatarUrl
|
|
317
|
+
? currentUserAvatarUrl
|
|
318
|
+
: null;
|
|
319
|
+
};
|
|
221
320
|
const assignees = Array.isArray(data?.assignees) ? data.assignees : [];
|
|
222
321
|
const directOptions = assignees.map((entry) => {
|
|
223
322
|
const value = String(entry?.value || '').trim();
|
|
@@ -225,21 +324,35 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
225
324
|
if (!value)
|
|
226
325
|
return null;
|
|
227
326
|
if (kindRaw === 'agent' || kindRaw === 'ai')
|
|
228
|
-
return {
|
|
327
|
+
return {
|
|
328
|
+
value,
|
|
329
|
+
label: String(entry?.label || value).trim() || value,
|
|
330
|
+
icon: String(entry?.icon || 'Bot'),
|
|
331
|
+
color: String(entry?.color || '#8b5cf6'),
|
|
332
|
+
kind: 'agent',
|
|
333
|
+
avatarUrl: typeof entry?.avatarUrl === 'string' && entry.avatarUrl.trim().length > 0 ? entry.avatarUrl.trim() : null
|
|
334
|
+
};
|
|
229
335
|
if (kindRaw === 'member' || kindRaw === 'human')
|
|
230
|
-
return {
|
|
336
|
+
return {
|
|
337
|
+
value,
|
|
338
|
+
label: String(entry?.label || value).trim() || value,
|
|
339
|
+
icon: String(entry?.icon || 'User'),
|
|
340
|
+
color: String(entry?.color || '#22c55e'),
|
|
341
|
+
kind: 'member',
|
|
342
|
+
avatarUrl: resolveMemberAvatarUrl(entry, value)
|
|
343
|
+
};
|
|
231
344
|
return null;
|
|
232
345
|
}).filter(Boolean);
|
|
233
346
|
const fallbackCandidates = assignees.map((candidate) => ({
|
|
234
347
|
userId: String(candidate?.userId || '').trim(),
|
|
235
348
|
email: String(candidate?.email || '').trim().toLowerCase(),
|
|
236
|
-
displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null
|
|
349
|
+
displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null,
|
|
350
|
+
avatarUrl: resolveMemberAvatarUrl(candidate)
|
|
237
351
|
})).filter((candidate) => candidate.userId);
|
|
238
352
|
let memberCandidates = fallbackCandidates;
|
|
239
353
|
if (workspaceMembersResult?.ok) {
|
|
240
354
|
const workspaceMembersData = await workspaceMembersResult.json().catch(() => ({}));
|
|
241
355
|
const users = Array.isArray(workspaceMembersData?.users) ? workspaceMembersData.users : [];
|
|
242
|
-
const normalizedAuthUserId = String(authUserId || '').trim();
|
|
243
356
|
const currentMember = users.find((candidate) => String(candidate?.userId || '').trim() === normalizedAuthUserId);
|
|
244
357
|
const currentMemberRole = String(currentMember?.role || '').trim().toLowerCase();
|
|
245
358
|
if (currentMemberRole === 'owner' || currentMemberRole === 'admin' || currentMemberRole === 'member' || currentMemberRole === 'read-only') {
|
|
@@ -251,7 +364,8 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
251
364
|
const workspaceMemberCandidates = users.map((candidate) => ({
|
|
252
365
|
userId: String(candidate?.userId || '').trim(),
|
|
253
366
|
email: String(candidate?.email || '').trim().toLowerCase(),
|
|
254
|
-
displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null
|
|
367
|
+
displayName: typeof candidate?.displayName === 'string' ? candidate.displayName : null,
|
|
368
|
+
avatarUrl: resolveMemberAvatarUrl(candidate)
|
|
255
369
|
})).filter((candidate) => candidate.userId);
|
|
256
370
|
memberCandidates = Array.from(new Map([...fallbackCandidates, ...workspaceMemberCandidates].map((candidate) => [candidate.userId, candidate])).values());
|
|
257
371
|
}
|
|
@@ -263,6 +377,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
263
377
|
return { success: false, error: 'Workspace changed while loading assignee options.' };
|
|
264
378
|
setAssigneeOptions(merged);
|
|
265
379
|
setAssigneeOptionsLoaded(true);
|
|
380
|
+
logBootstrapDebug('bootstrap_assignee_options_loaded', {
|
|
381
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
382
|
+
workspaceId: requestState.workspaceId,
|
|
383
|
+
count: merged.length
|
|
384
|
+
});
|
|
266
385
|
return { success: true };
|
|
267
386
|
}
|
|
268
387
|
catch (error) {
|
|
@@ -270,20 +389,32 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
270
389
|
setAssigneeOptions(createDefaultAssigneeOptions());
|
|
271
390
|
setAssigneeOptionsLoaded(true);
|
|
272
391
|
}
|
|
392
|
+
logBootstrapDebug('bootstrap_assignee_options_failed', {
|
|
393
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
394
|
+
workspaceId: requestState.workspaceId,
|
|
395
|
+
error: error instanceof Error ? error.message : String(error)
|
|
396
|
+
});
|
|
273
397
|
return { success: false, error: isAbortError(error) ? 'Assignee options request aborted.' : 'Failed to load assignee options.' };
|
|
274
398
|
}
|
|
275
399
|
finally {
|
|
276
400
|
if (assigneeOptionsAbortRef.current === abortController)
|
|
277
401
|
assigneeOptionsAbortRef.current = null;
|
|
278
402
|
}
|
|
279
|
-
}, [assigneeOptionsAbortRef, authSessionResolved, authUserId, fetchWithTimeout, getWorkspaceRequestState, isAbortError, isAuthenticated, isWorkspaceRequestStale, setAssigneeOptions, setAssigneeOptionsLoaded, setHydratedWorkspaceRole, workspaceSwitchingEnabled]);
|
|
403
|
+
}, [assigneeOptionsAbortRef, authSessionResolved, authUserAvatarUrl, authUserId, fetchWithTimeout, getWorkspaceRequestState, isAbortError, isAuthenticated, isWorkspaceRequestStale, setAssigneeOptions, setAssigneeOptionsLoaded, setHydratedWorkspaceRole, workspaceSwitchingEnabled]);
|
|
280
404
|
const switchWorkspace = useCallback(async (workspaceId, options) => {
|
|
281
405
|
if (!workspaceSwitchingEnabled)
|
|
282
406
|
return { success: false, error: 'Workspace switching is unavailable in local mode.', code: 'WORKSPACE_SWITCHING_DISABLED' };
|
|
283
407
|
const normalizedWorkspaceId = String(workspaceId || '').trim();
|
|
284
408
|
if (!normalizedWorkspaceId)
|
|
285
409
|
return { success: false, error: 'workspaceId is required.' };
|
|
410
|
+
const previousWorkspaceId = String(currentWorkspaceIdRef.current || '').trim() || 'default';
|
|
411
|
+
const startedAt = getBootstrapTimestamp();
|
|
286
412
|
try {
|
|
413
|
+
logBootstrapDebug('bootstrap_workspace_switch_started', {
|
|
414
|
+
fromWorkspaceId: previousWorkspaceId,
|
|
415
|
+
toWorkspaceId: normalizedWorkspaceId,
|
|
416
|
+
hydrate: options?.hydrate !== false
|
|
417
|
+
});
|
|
287
418
|
const res = await fetch('/api/taskforce/session/workspace', {
|
|
288
419
|
method: 'POST',
|
|
289
420
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -309,17 +440,36 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
309
440
|
lastTaskSurfaceLoadKeyRef.current = `${normalizedWorkspaceId}:${activeTab}:${showArchive ? 'archive' : 'active'}:${taskScope}`;
|
|
310
441
|
if (isOpen && activeTab === 'settings')
|
|
311
442
|
lastSettingsSurfaceLoadKeyRef.current = `${normalizedWorkspaceId}:${activeTab}:${settingsSection}`;
|
|
312
|
-
await Promise.all([
|
|
443
|
+
await Promise.all([
|
|
444
|
+
fetchConfig(),
|
|
445
|
+
fetchWorkspaces(),
|
|
446
|
+
refreshTaskCollections({ isSilent: false }),
|
|
447
|
+
loadWorkspaceSyncState()
|
|
448
|
+
]);
|
|
449
|
+
void fetchPlanningEntities({ ignoreAuthGuard: true });
|
|
313
450
|
}
|
|
451
|
+
logBootstrapDebug('bootstrap_workspace_switch_completed', {
|
|
452
|
+
fromWorkspaceId: previousWorkspaceId,
|
|
453
|
+
toWorkspaceId: normalizedWorkspaceId,
|
|
454
|
+
hydrate: options?.hydrate !== false,
|
|
455
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt))
|
|
456
|
+
});
|
|
314
457
|
return { success: true };
|
|
315
458
|
}
|
|
316
|
-
catch {
|
|
459
|
+
catch (error) {
|
|
460
|
+
logBootstrapDebug('bootstrap_workspace_switch_failed', {
|
|
461
|
+
fromWorkspaceId: previousWorkspaceId,
|
|
462
|
+
toWorkspaceId: normalizedWorkspaceId,
|
|
463
|
+
hydrate: options?.hydrate !== false,
|
|
464
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
465
|
+
error: error instanceof Error ? error.message : String(error)
|
|
466
|
+
});
|
|
317
467
|
return { success: false, error: 'Failed to switch workspace.' };
|
|
318
468
|
}
|
|
319
469
|
finally {
|
|
320
470
|
setWorkspaceBootstrapPending(false);
|
|
321
471
|
}
|
|
322
|
-
}, [abortWorkspaceScopedRequests, activeTab, checkAuthSession, commitCurrentWorkspaceId,
|
|
472
|
+
}, [abortWorkspaceScopedRequests, activeTab, checkAuthSession, commitCurrentWorkspaceId, currentWorkspaceIdRef, fetchConfig, fetchPlanningEntities, fetchWorkspaces, isOpen, lastAssigneeOptionsLoadKeyRef, lastConfigRefreshKeyRef, lastSettingsSurfaceLoadKeyRef, lastTaskSurfaceLoadKeyRef, lastWorkspaceSyncStateLoadKeyRef, loadWorkspaceSyncState, markBootstrapPhase, refreshTaskCollections, runtimeMode, settingsSection, setWorkspaceBootstrapPending, showArchive, taskScope, workspaceSelectionScope, workspaceSwitchingEnabled]);
|
|
323
473
|
const resolveWorkspaceAfterAuth = useCallback(async (options) => {
|
|
324
474
|
markBootstrapPhase('workspace');
|
|
325
475
|
setWorkspaceBootstrapPending(true);
|
|
@@ -366,59 +516,188 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
366
516
|
}, [commitCurrentWorkspaceId, currentWorkspaceId, currentWorkspaceIdRef, fetchWorkspaces, markBootstrapPhase, markBootstrapStalled, setWorkspaceBootstrapPending, switchWorkspace, workspaceSelectionScope, workspaceSwitchingEnabled]);
|
|
367
517
|
const retryBootstrapChecks = useCallback(async () => {
|
|
368
518
|
markBootstrapPhase('auth');
|
|
519
|
+
const startedAt = getBootstrapTimestamp();
|
|
520
|
+
logBootstrapDebug('bootstrap_retry_started', {
|
|
521
|
+
workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default'
|
|
522
|
+
});
|
|
369
523
|
const authenticated = await checkAuthSession({ force: true });
|
|
524
|
+
let workspaceSetupRequired = false;
|
|
370
525
|
if (workspaceSwitchingEnabled && authenticated) {
|
|
371
526
|
const workspaceResolution = await resolveWorkspaceAfterAuth();
|
|
372
527
|
if (!workspaceResolution.success || workspaceResolution.workspaceSetupRequired) {
|
|
373
528
|
await fetchConfig({ ignoreAuthGuard: true });
|
|
529
|
+
logBootstrapDebug('bootstrap_retry_completed', {
|
|
530
|
+
workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default',
|
|
531
|
+
authenticated,
|
|
532
|
+
workspaceSetupRequired: workspaceResolution.workspaceSetupRequired === true,
|
|
533
|
+
success: workspaceResolution.success,
|
|
534
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt))
|
|
535
|
+
});
|
|
374
536
|
return;
|
|
375
537
|
}
|
|
376
538
|
}
|
|
377
|
-
|
|
378
|
-
|
|
539
|
+
setWorkspaceBootstrapPending(true);
|
|
540
|
+
try {
|
|
541
|
+
await fetchConfig({ ignoreAuthGuard: true });
|
|
542
|
+
if (authenticated && !workspaceSetupRequired) {
|
|
543
|
+
await Promise.all([
|
|
544
|
+
fetchTasks(true, { ignoreAuthGuard: true }),
|
|
545
|
+
fetchReferenceData({ ignoreAuthGuard: true, force: true })
|
|
546
|
+
]);
|
|
547
|
+
void fetchPlanningEntities({ ignoreAuthGuard: true });
|
|
548
|
+
}
|
|
549
|
+
logBootstrapDebug('bootstrap_retry_completed', {
|
|
550
|
+
workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default',
|
|
551
|
+
authenticated,
|
|
552
|
+
workspaceSetupRequired,
|
|
553
|
+
success: true,
|
|
554
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt))
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
finally {
|
|
558
|
+
setWorkspaceBootstrapPending(false);
|
|
559
|
+
}
|
|
560
|
+
}, [checkAuthSession, currentWorkspaceIdRef, fetchConfig, fetchPlanningEntities, fetchReferenceData, fetchTasks, markBootstrapPhase, resolveWorkspaceAfterAuth, setWorkspaceBootstrapPending, workspaceSwitchingEnabled]);
|
|
561
|
+
const runCloudBootstrap = useCallback(async (options) => {
|
|
562
|
+
const reason = options?.reason || 'initial-load';
|
|
563
|
+
const ignoreAuthGuard = options?.ignoreAuthGuard === true;
|
|
564
|
+
const tasksSilent = options?.tasksSilent !== false;
|
|
565
|
+
const includeDeferredArchive = options?.includeDeferredArchive !== false;
|
|
566
|
+
const startedAt = getBootstrapTimestamp();
|
|
567
|
+
markBootstrapPhase('auth');
|
|
568
|
+
const authenticated = await checkAuthSession({ force: true });
|
|
569
|
+
if (!authenticated) {
|
|
570
|
+
await fetchConfig({ ignoreAuthGuard: true });
|
|
571
|
+
logBootstrapDebug('cloud_bootstrap_completed', {
|
|
572
|
+
reason,
|
|
573
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
574
|
+
authenticated: false,
|
|
575
|
+
workspaceSetupRequired: false,
|
|
576
|
+
success: false
|
|
577
|
+
});
|
|
578
|
+
return { success: false, authenticated: false, workspaceSetupRequired: false, error: 'Sign in required.', code: 'AUTH_REQUIRED' };
|
|
579
|
+
}
|
|
580
|
+
if (workspaceSwitchingEnabled) {
|
|
581
|
+
const workspaceResolution = await resolveWorkspaceAfterAuth();
|
|
582
|
+
if (!workspaceResolution.success) {
|
|
583
|
+
await fetchConfig({ ignoreAuthGuard: true });
|
|
584
|
+
logBootstrapDebug('cloud_bootstrap_completed', {
|
|
585
|
+
reason,
|
|
586
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
587
|
+
authenticated: true,
|
|
588
|
+
workspaceSetupRequired: false,
|
|
589
|
+
success: false,
|
|
590
|
+
error: workspaceResolution.error || 'Workspace resolution failed.'
|
|
591
|
+
});
|
|
592
|
+
return {
|
|
593
|
+
success: false,
|
|
594
|
+
authenticated: true,
|
|
595
|
+
workspaceSetupRequired: false,
|
|
596
|
+
error: workspaceResolution.error || 'Unable to resolve workspace access.',
|
|
597
|
+
code: workspaceResolution.code
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
if (workspaceResolution.workspaceSetupRequired) {
|
|
601
|
+
await fetchConfig({ ignoreAuthGuard: true });
|
|
602
|
+
logBootstrapDebug('cloud_bootstrap_completed', {
|
|
603
|
+
reason,
|
|
604
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
605
|
+
authenticated: true,
|
|
606
|
+
workspaceSetupRequired: true,
|
|
607
|
+
success: true
|
|
608
|
+
});
|
|
609
|
+
return { success: true, authenticated: true, workspaceSetupRequired: true };
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
setWorkspaceBootstrapPending(true);
|
|
613
|
+
try {
|
|
614
|
+
await fetchBootstrapConfig({ ignoreAuthGuard });
|
|
615
|
+
await Promise.all([
|
|
616
|
+
fetchTasks(tasksSilent, { ignoreAuthGuard }),
|
|
617
|
+
fetchReferenceData({ ignoreAuthGuard })
|
|
618
|
+
]);
|
|
619
|
+
void fetchPlanningEntities({ ignoreAuthGuard });
|
|
620
|
+
if (includeDeferredArchive) {
|
|
621
|
+
scheduleDeferredArchiveBootstrap();
|
|
622
|
+
}
|
|
623
|
+
logBootstrapDebug('cloud_bootstrap_completed', {
|
|
624
|
+
reason,
|
|
625
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
626
|
+
authenticated: true,
|
|
627
|
+
workspaceSetupRequired: false,
|
|
628
|
+
success: true,
|
|
629
|
+
workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default'
|
|
630
|
+
});
|
|
631
|
+
return { success: true, authenticated: true, workspaceSetupRequired: false };
|
|
632
|
+
}
|
|
633
|
+
finally {
|
|
634
|
+
setWorkspaceBootstrapPending(false);
|
|
635
|
+
}
|
|
636
|
+
}, [
|
|
637
|
+
checkAuthSession,
|
|
638
|
+
currentWorkspaceIdRef,
|
|
639
|
+
fetchBootstrapConfig,
|
|
640
|
+
fetchPlanningEntities,
|
|
641
|
+
fetchReferenceData,
|
|
642
|
+
fetchTasks,
|
|
643
|
+
markBootstrapPhase,
|
|
644
|
+
resolveWorkspaceAfterAuth,
|
|
645
|
+
scheduleDeferredArchiveBootstrap,
|
|
646
|
+
setWorkspaceBootstrapPending,
|
|
647
|
+
workspaceSwitchingEnabled
|
|
648
|
+
]);
|
|
379
649
|
useEffect(() => {
|
|
380
650
|
if (!shouldDeferProtectedApiCalls && !shouldBlockProtectedApiCalls && !hasBootstrappedDataRef.current) {
|
|
381
651
|
hasBootstrappedDataRef.current = true;
|
|
382
652
|
void (async () => {
|
|
653
|
+
const startedAt = getBootstrapTimestamp();
|
|
383
654
|
if (runtimeMode === 'cloud' && authSessionResolved && isAuthenticated) {
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
655
|
+
const result = await runCloudBootstrap({
|
|
656
|
+
reason: 'initial-load',
|
|
657
|
+
tasksSilent: false,
|
|
658
|
+
includeDeferredArchive: true
|
|
659
|
+
});
|
|
660
|
+
if (!result.success || result.workspaceSetupRequired) {
|
|
388
661
|
return;
|
|
389
662
|
}
|
|
390
663
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
664
|
+
else {
|
|
665
|
+
await Promise.all([
|
|
666
|
+
fetchBootstrapConfig(),
|
|
667
|
+
fetchTasks(false),
|
|
668
|
+
fetchReferenceData()
|
|
669
|
+
]);
|
|
670
|
+
void fetchPlanningEntities();
|
|
671
|
+
}
|
|
672
|
+
if (runtimeMode !== 'cloud') {
|
|
673
|
+
scheduleDeferredArchiveBootstrap();
|
|
400
674
|
}
|
|
675
|
+
logBootstrapDebug('bootstrap_initial_load_completed', {
|
|
676
|
+
durationMs: Math.max(0, Math.round(getBootstrapTimestamp() - startedAt)),
|
|
677
|
+
runtimeMode,
|
|
678
|
+
workspaceId: String(currentWorkspaceIdRef.current || 'default').trim() || 'default'
|
|
679
|
+
});
|
|
401
680
|
})();
|
|
402
681
|
}
|
|
403
|
-
}, [
|
|
682
|
+
}, [authSessionResolved, currentWorkspaceIdRef, fetchBootstrapConfig, fetchPlanningEntities, fetchReferenceData, fetchTasks, hasBootstrappedDataRef, isAuthenticated, runCloudBootstrap, runtimeMode, scheduleDeferredArchiveBootstrap, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
|
|
404
683
|
useEffect(() => {
|
|
405
|
-
if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls || workspaceSelectionScope === 'bootstrap' || !hasBootstrappedDataRef.current)
|
|
684
|
+
if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls || workspaceBootstrapPending || workspaceSelectionScope === 'bootstrap' || !hasBootstrappedDataRef.current)
|
|
406
685
|
return;
|
|
407
686
|
const loadKey = `${runtimeMode}:${currentWorkspaceId}:${workspaceSelectionScope}`;
|
|
408
687
|
if (lastConfigRefreshKeyRef.current === loadKey)
|
|
409
688
|
return;
|
|
410
689
|
lastConfigRefreshKeyRef.current = loadKey;
|
|
411
690
|
void fetchConfig();
|
|
412
|
-
}, [currentWorkspaceId, fetchConfig, hasBootstrappedDataRef, lastConfigRefreshKeyRef, runtimeMode, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls, workspaceSelectionScope]);
|
|
691
|
+
}, [currentWorkspaceId, fetchConfig, hasBootstrappedDataRef, lastConfigRefreshKeyRef, runtimeMode, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls, workspaceBootstrapPending, workspaceSelectionScope]);
|
|
413
692
|
useEffect(() => {
|
|
414
|
-
if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls)
|
|
693
|
+
if (shouldDeferProtectedApiCalls || shouldBlockProtectedApiCalls || workspaceBootstrapPending)
|
|
415
694
|
return;
|
|
416
695
|
const loadKey = currentWorkspaceId;
|
|
417
696
|
if (lastWorkspaceSyncStateLoadKeyRef.current === loadKey)
|
|
418
697
|
return;
|
|
419
698
|
lastWorkspaceSyncStateLoadKeyRef.current = loadKey;
|
|
420
699
|
void loadWorkspaceSyncState();
|
|
421
|
-
}, [currentWorkspaceId, lastWorkspaceSyncStateLoadKeyRef, loadWorkspaceSyncState, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls]);
|
|
700
|
+
}, [currentWorkspaceId, lastWorkspaceSyncStateLoadKeyRef, loadWorkspaceSyncState, shouldBlockProtectedApiCalls, shouldDeferProtectedApiCalls, workspaceBootstrapPending]);
|
|
422
701
|
useEffect(() => {
|
|
423
702
|
if (runtimeMode !== 'cloud' || !authSessionResolved || !isAuthenticated) {
|
|
424
703
|
if (runtimeMode !== 'cloud')
|
|
@@ -426,9 +705,11 @@ export function useTaskforceWorkspaceBootstrap(args) {
|
|
|
426
705
|
workspaceListHydratedRef.current = false;
|
|
427
706
|
return;
|
|
428
707
|
}
|
|
708
|
+
if (workspaceBootstrapPending)
|
|
709
|
+
return;
|
|
429
710
|
if (!hasBootstrappedDataRef.current || workspaceListHydratedRef.current)
|
|
430
711
|
return;
|
|
431
712
|
void fetchWorkspaces();
|
|
432
|
-
}, [authSessionResolved, fetchWorkspaces, hasBootstrappedDataRef, isAuthenticated, runtimeMode, setAvailableWorkspaces, workspaceListHydratedRef]);
|
|
433
|
-
return { fetchReferenceData, fetchBootstrapConfig, fetchConfig, fetchWorkspaces, fetchAssigneeOptions, switchWorkspace, resolveWorkspaceAfterAuth, retryBootstrapChecks };
|
|
713
|
+
}, [authSessionResolved, fetchWorkspaces, hasBootstrappedDataRef, isAuthenticated, runtimeMode, setAvailableWorkspaces, workspaceBootstrapPending, workspaceListHydratedRef]);
|
|
714
|
+
return { fetchReferenceData, fetchBootstrapConfig, fetchConfig, fetchWorkspaces, fetchAssigneeOptions, switchWorkspace, resolveWorkspaceAfterAuth, retryBootstrapChecks, runCloudBootstrap };
|
|
434
715
|
}
|
|
@@ -12,7 +12,6 @@ export const enUS = {
|
|
|
12
12
|
updatedLabel: 'Updated:',
|
|
13
13
|
completedLabel: 'Completed:',
|
|
14
14
|
emptyValue: '—',
|
|
15
|
-
parentCannotSchedule: 'Parent tasks cannot be scheduled. Schedule leaf tasks instead.',
|
|
16
15
|
dueBeforeScheduled: 'Due date is before scheduled date.',
|
|
17
16
|
overdue: 'This task is overdue.'
|
|
18
17
|
},
|
|
@@ -12,7 +12,6 @@ export const es419 = {
|
|
|
12
12
|
updatedLabel: 'Actualizado:',
|
|
13
13
|
completedLabel: 'Completado:',
|
|
14
14
|
emptyValue: '—',
|
|
15
|
-
parentCannotSchedule: 'Las tareas padre no se pueden programar. Programa tareas hoja en su lugar.',
|
|
16
15
|
dueBeforeScheduled: 'La fecha de vencimiento es anterior a la fecha programada.',
|
|
17
16
|
overdue: 'Esta tarea esta vencida.'
|
|
18
17
|
},
|
|
@@ -12,7 +12,6 @@ export const ptBR = {
|
|
|
12
12
|
updatedLabel: 'Atualizado:',
|
|
13
13
|
completedLabel: 'Concluido:',
|
|
14
14
|
emptyValue: '—',
|
|
15
|
-
parentCannotSchedule: 'Tarefas pai nao podem ser agendadas. Agende as tarefas folha.',
|
|
16
15
|
dueBeforeScheduled: 'A data de vencimento e anterior a data agendada.',
|
|
17
16
|
overdue: 'Esta tarefa esta atrasada.'
|
|
18
17
|
},
|
|
@@ -61,7 +61,7 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
|
|
|
61
61
|
},
|
|
62
62
|
}));
|
|
63
63
|
register('get_image', (context) => ({
|
|
64
|
-
description: context.describeTool('Get a single image by asset id or image reference such as I-123. Use this first when the user references an image, then use get_annotated_attachment_sessions and read_annotated_attachment_payload for annotation details.'),
|
|
64
|
+
description: context.describeTool('Get a single image by asset id or image reference such as I-123. Use this first when the user references an image, then use get_annotated_attachment_sessions and read_annotated_attachment_payload for annotation details. When the image is being used for UI, placement, or visual correction feedback, read the saved annotation payload before making changes.'),
|
|
65
65
|
inputSchema: {
|
|
66
66
|
properties: {
|
|
67
67
|
id: stringProperty('Image asset id or image reference such as I-123.'),
|
|
@@ -99,7 +99,7 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
|
|
|
99
99
|
},
|
|
100
100
|
}));
|
|
101
101
|
register('get_annotated_attachment_sessions', (context) => ({
|
|
102
|
-
description: context.describeTool('List saved annotation sessions for one image. Use this after get_image when you need the saved annotation sessions before opening one payload.'),
|
|
102
|
+
description: context.describeTool('List saved annotation sessions for one image. Use this after get_image when you need the saved annotation sessions before opening one payload. If the user is pointing at a visual target in I-123, do not stop at the screenshot alone; inspect the saved session payload next.'),
|
|
103
103
|
inputSchema: {
|
|
104
104
|
properties: {
|
|
105
105
|
imageId: stringProperty('Image asset id or image reference such as I-123.'),
|
|
@@ -108,7 +108,7 @@ export function registerDocumentAssetTools(registerTool, executeTool) {
|
|
|
108
108
|
},
|
|
109
109
|
}));
|
|
110
110
|
register('read_annotated_attachment_payload', (context) => ({
|
|
111
|
-
description: context.describeTool('Read the structured payload for one annotated attachment session, including markers, geometry, and derived crop hints.'),
|
|
111
|
+
description: context.describeTool('Read the structured payload for one annotated attachment session, including markers, geometry, and derived crop hints. Use this as the authoritative instruction source when I-123 is being used for UI placement or visual change requests.'),
|
|
112
112
|
inputSchema: {
|
|
113
113
|
properties: {
|
|
114
114
|
sessionId: stringProperty('Annotated attachment session id.'),
|