@taskforcehq/taskforce 0.3.327 → 0.3.328
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 +24 -53
- 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/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 +26 -9
- package/dist/components/features/planning/PlanningVisualIdentity.d.ts +14 -0
- package/dist/components/features/planning/PlanningVisualIdentity.js +106 -0
- package/dist/components/features/planning/planningWorkspaceModel.d.ts +11 -0
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +2 -2
- package/dist/components/task/TaskCard.js +37 -4
- 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 +16 -16
- 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/TaxonomyDropdown.d.ts +9 -1
- package/dist/components/ui/TaxonomyDropdown.js +30 -3
- package/dist/components/views/StandaloneLayout.js +62 -9
- package/dist/components/views/WidgetView.js +8 -5
- package/dist/components/views/panels/PlanningDrawer.d.ts +7 -1
- package/dist/components/views/panels/PlanningDrawer.js +48 -44
- package/dist/config/envSchema.js +1 -0
- package/dist/config/localServiceCloudTarget.d.ts +10 -0
- package/dist/config/localServiceCloudTarget.js +76 -0
- package/dist/core/AiProfileService.d.ts +1 -0
- package/dist/core/AiProfileService.js +2 -1
- package/dist/core/AttachmentLinkService.js +7 -4
- package/dist/core/DeletedTaskLifecycleService.d.ts +4 -0
- package/dist/core/DeletedTaskLifecycleService.js +21 -0
- package/dist/core/McpTokenService.d.ts +4 -0
- package/dist/core/McpTokenService.js +52 -0
- package/dist/core/TaskAttachmentLinksDurableMutationService.d.ts +5 -0
- package/dist/core/TaskAttachmentLinksDurableMutationService.js +20 -11
- package/dist/core/Taskforce.d.ts +63 -1
- package/dist/core/Taskforce.js +558 -73
- package/dist/core/types.d.ts +2 -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/tasks/useTaskFormActions.d.ts +3 -0
- package/dist/hooks/tasks/useTaskFormActions.js +33 -7
- package/dist/hooks/useTaskforce.d.ts +59 -50
- package/dist/hooks/useTaskforce.js +103 -1
- 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 +16 -9
- package/dist/mcp/localServiceProxy.js +4 -1
- package/dist/mcp/runtime.d.ts +16 -0
- package/dist/mcp/runtime.js +566 -171
- package/dist/mcp/taskAttachmentCommandAdapter.d.ts +2 -0
- package/dist/mcp/taskAttachmentCommandAdapter.js +14 -8
- package/dist/mcp/taskPlanningRegistrar.js +42 -34
- package/dist/mcp/toolRegistry.js +2 -2
- package/dist/migrations/taskSchemaMigrations.js +35 -0
- package/dist/runtime/appGateDefinitions.d.ts +2 -2
- package/dist/runtime/appGateDefinitions.js +2 -2
- 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 +3 -11
- package/dist/server/index.js +53 -40
- package/dist/server/localServiceLease.d.ts +3 -0
- package/dist/server/localServiceLease.js +9 -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 +2 -0
- package/dist/server/routes/durableTaskHttpRouters.js +2 -2
- package/dist/server/routes/localService.js +2 -0
- package/dist/server/routes/primitives.d.ts +2 -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/syncV3FeedRoutes.js +4 -2
- package/dist/server/routes/syncV3LocalCaptureRoutes.js +20 -2
- package/dist/server/routes/syncV3OperationRoutes.js +17 -2
- package/dist/server/routes/tasks.js +199 -89
- package/dist/server/routes.js +35 -7
- package/dist/service/localServiceCli.js +36 -25
- package/dist/service/localServiceClientLifecycle.js +67 -6
- package/dist/shared/planningIdentity.d.ts +20 -0
- package/dist/shared/planningIdentity.js +79 -0
- package/dist/storage/postgresAdapter.js +4 -0
- package/dist/storage/postgresRequestDiagnostics.d.ts +8 -0
- package/dist/storage/postgresRequestDiagnostics.js +24 -0
- package/dist/storage/workspaceAssetStore.d.ts +32 -0
- package/dist/storage/workspaceAssetStore.js +70 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.d.ts +16 -0
- package/dist/sync/coordinator/localSyncExecutionPermitStore.js +70 -22
- package/dist/sync/coordinator/workspaceSyncTransportGateway.js +4 -2
- package/dist/sync/engine/workspaceSyncEngineRemoteServices.d.ts +5 -0
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.d.ts +1 -1
- package/dist/sync/engine/workspaceSyncEngineServerRemoteServices.js +15 -0
- package/dist/sync/engine/workspaceSyncEngineServerRunnerOperations.js +26 -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.js +9 -0
- package/dist/sync/taskSyncPayload.d.ts +1 -0
- package/dist/sync/taskSyncPayload.js +6 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.d.ts +1 -0
- package/dist/sync/v3/durableTaskAttachmentLinksMutationRouter.js +21 -3
- package/dist/sync/v3/durableTaskHttpBulkMutationRouter.js +17 -4
- 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 +1 -0
- package/dist/sync/v3/localTaskAttachmentLinksOutboxService.js +15 -3
- package/dist/sync/v3/localWorkstreamOutboxService.js +4 -2
- package/dist/sync/v3/syncDurabilityStore.d.ts +8 -0
- package/dist/sync/v3/syncDurabilityStore.js +171 -33
- package/dist/sync/v3/taskAttachmentLinksMutationService.d.ts +1 -0
- package/dist/sync/v3/taskAttachmentLinksMutationService.js +18 -2
- package/dist/sync/v3/taskMetadataCoexistence.js +4 -0
- package/dist/sync/v3/workspaceSyncV2ProjectionExclusions.js +1 -9
- package/dist/sync/v3/workspaceSyncV3CloudOperationHandler.js +1 -0
- package/dist/sync/v3/workspaceSyncV3CombinedFeedOrchestrator.js +7 -1
- package/dist/sync/v3/workspaceSyncV3CombinedLocalApply.js +15 -3
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.d.ts +4 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairBaseline.js +29 -6
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3CombinedRepairMaterialization.js +29 -7
- package/dist/sync/v3/workspaceSyncV3CombinedRepairSnapshot.js +62 -7
- package/dist/sync/v3/workspaceSyncV3OperationProtocol.d.ts +1 -0
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.d.ts +2 -0
- package/dist/sync/v3/workspaceSyncV3RepairSqlBatching.js +10 -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 +172 -161
- package/dist/sync/workspaceSyncModel.d.ts +11 -0
- package/dist/sync/workspaceSyncModel.js +27 -2
- package/dist/types.d.ts +8 -0
- package/dist/ui/assets/{AiIdentityRosterCard-DB1BLO_j.js → AiIdentityRosterCard-MZs7lVED.js} +1 -1
- package/dist/ui/assets/{AiProfilesModule-DPxQeF9N.js → AiProfilesModule-C3i0LOxe.js} +1 -1
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-DHNYaNg6.js → AnnotatedAttachmentWorkspace-DVZk5Tln.js} +1 -1
- package/dist/ui/assets/AssetTraySortControl-Kf1pelSy.js +1 -0
- package/dist/ui/assets/ContextAttachmentManager-B8boOs6Q.js +3 -0
- package/dist/ui/assets/{DocumentWorkspace-BC7sy5TG.js → DocumentWorkspace-DXH4XUsB.js} +4 -4
- package/dist/ui/assets/EntityActivityTimeline-BtSTq0ON.js +1 -0
- package/dist/ui/assets/PlanningModule-BPVyEa-f.js +1 -0
- package/dist/ui/assets/PlanningModule-CoIR9hbV.css +1 -0
- package/dist/ui/assets/{PlansPage-BVH_NfgT.js → PlansPage-ChqgxALc.js} +1 -1
- package/dist/ui/assets/TaskContextUpload-CB3ol0sN.js +1 -0
- package/dist/ui/assets/TaskContextUpload-qmBeUw3u.css +1 -0
- package/dist/ui/assets/{TaskSettings-xVsxSa0g.js → TaskSettings-g4ECKNOz.js} +1 -1
- package/dist/ui/assets/{TaskforceAgentsModule-CkAxW19K.js → TaskforceAgentsModule-BazdUwxZ.js} +1 -1
- package/dist/ui/assets/WorkflowManagerModule-DWFspC-o.js +1 -0
- package/dist/ui/assets/index-BUplSsv_.js +7 -0
- package/dist/ui/assets/index-gz2EXuoK.css +1 -0
- package/dist/ui/assets/{vendor-icons-B8ZNsH1g.js → vendor-icons-BkFLXavV.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/package.json +6 -1
- 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/TaskContextUpload-Ds4LnDzV.css +0 -1
- package/dist/ui/assets/TaskContextUpload-bl4fOOUz.js +0 -1
- 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
|
@@ -31,9 +31,10 @@
|
|
|
31
31
|
* === SECTION: Settings Model === Line ~4625 — settingsModel object
|
|
32
32
|
* === SECTION: Return Value === Line ~4817 — final return object (public API shape)
|
|
33
33
|
*/
|
|
34
|
-
import { type SetStateAction } from 'react';
|
|
34
|
+
import { type Dispatch, type SetStateAction } from 'react';
|
|
35
35
|
import type { TaskforceConfig, TaskforceTheme, Comment, AttachmentItem, CategoryConfig, TaskItem, TaxonomyDefinition, TaskAssignee, TaskStatus, DeletedTaskRecord, InitiativeItem, WorkstreamItem, ChecklistItem, PlanningBootstrapPayload, PlanningBootstrapWorkstreamTaskSummary, PlanningLoadState } from '../types';
|
|
36
36
|
import { type FirstClassTaxonomyDisplayLabels } from '../shared/taxonomyState.js';
|
|
37
|
+
import type { PlanningIdentityColor, PlanningIdentityIcon } from '../shared/planningIdentity.js';
|
|
37
38
|
import type { UiNotice } from '../utils/uiNotice';
|
|
38
39
|
import type { TaskAssigneeOption } from '../utils/assignees';
|
|
39
40
|
import { type WorkspaceModuleId } from './workspace/workspaceLocalState';
|
|
@@ -137,31 +138,31 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
137
138
|
showTaskCardStatusLabel: boolean;
|
|
138
139
|
};
|
|
139
140
|
isOpen: boolean;
|
|
140
|
-
setIsOpen:
|
|
141
|
+
setIsOpen: Dispatch<SetStateAction<boolean>>;
|
|
141
142
|
activeTab: "tasks" | "settings" | "add";
|
|
142
143
|
setActiveTab: (tab: "add" | "tasks" | "settings") => void;
|
|
143
144
|
currentTheme: "light" | "dawn" | "dark" | "midnight";
|
|
144
|
-
setCurrentTheme:
|
|
145
|
+
setCurrentTheme: Dispatch<SetStateAction<"light" | "dawn" | "dark" | "midnight">>;
|
|
145
146
|
configLoaded: boolean;
|
|
146
147
|
storagePath: string;
|
|
147
148
|
saveSettings: () => Promise<boolean>;
|
|
148
149
|
pathSaved: boolean;
|
|
149
150
|
keyShortcut: string;
|
|
150
|
-
setKeyShortcut:
|
|
151
|
+
setKeyShortcut: Dispatch<SetStateAction<string>>;
|
|
151
152
|
globalWeekStartsOn: WeekStartsOn;
|
|
152
153
|
locale: "en-US" | "es-419" | "pt-BR";
|
|
153
154
|
supportedLocales: ("en-US" | "es-419" | "pt-BR")[];
|
|
154
155
|
saveLocale: (nextLocale: string) => Promise<boolean>;
|
|
155
156
|
jsonBackupEnabled: boolean;
|
|
156
|
-
setJsonBackupEnabled:
|
|
157
|
+
setJsonBackupEnabled: Dispatch<SetStateAction<boolean>>;
|
|
157
158
|
manualComplexityEnabled: boolean;
|
|
158
159
|
checklistDropdownEnabled: boolean;
|
|
159
160
|
showTaskCardStatusLabel: boolean;
|
|
160
|
-
setManualComplexityEnabled:
|
|
161
|
+
setManualComplexityEnabled: Dispatch<SetStateAction<boolean>>;
|
|
161
162
|
mcpHostRoot: string;
|
|
162
|
-
setMcpHostRoot:
|
|
163
|
+
setMcpHostRoot: Dispatch<SetStateAction<string>>;
|
|
163
164
|
settingsSection: "mcp" | "categories" | "types" | "general" | "agents" | "taxonomy" | "documents" | "appearance-application" | "appearance-task-cards" | "appearance-task-forms" | "integrations" | null;
|
|
164
|
-
setSettingsSection:
|
|
165
|
+
setSettingsSection: Dispatch<SetStateAction<"mcp" | "categories" | "types" | "general" | "agents" | "taxonomy" | "documents" | "appearance-application" | "appearance-task-cards" | "appearance-task-forms" | "integrations" | null>>;
|
|
165
166
|
runtimeMode: "local" | "cloud";
|
|
166
167
|
workspaceMode: "single-local" | "multi-cloud";
|
|
167
168
|
workspaceSwitchingEnabled: boolean;
|
|
@@ -432,7 +433,7 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
432
433
|
}>;
|
|
433
434
|
logout: () => Promise<void>;
|
|
434
435
|
showFolderBrowser: boolean;
|
|
435
|
-
setShowFolderBrowser:
|
|
436
|
+
setShowFolderBrowser: Dispatch<SetStateAction<boolean>>;
|
|
436
437
|
folders: string[];
|
|
437
438
|
files: string[];
|
|
438
439
|
currentBrowsePath: string;
|
|
@@ -441,16 +442,16 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
441
442
|
type: "category";
|
|
442
443
|
value: string;
|
|
443
444
|
} | null;
|
|
444
|
-
setBrowserTarget:
|
|
445
|
+
setBrowserTarget: Dispatch<SetStateAction<"storage" | {
|
|
445
446
|
type: "category";
|
|
446
447
|
value: string;
|
|
447
448
|
} | null>>;
|
|
448
449
|
groupBy: "category" | "type" | "priority" | "status" | "complexity" | "assignee" | "schedule";
|
|
449
|
-
setGroupBy:
|
|
450
|
+
setGroupBy: Dispatch<SetStateAction<"category" | "type" | "priority" | "status" | "complexity" | "assignee" | "schedule">>;
|
|
450
451
|
activeWorkspaceModule: WorkspaceModuleId;
|
|
451
|
-
setActiveWorkspaceModule:
|
|
452
|
+
setActiveWorkspaceModule: Dispatch<SetStateAction<WorkspaceModuleId>>;
|
|
452
453
|
emptyColumnMode: "show" | "collapse" | "hide";
|
|
453
|
-
setEmptyColumnMode:
|
|
454
|
+
setEmptyColumnMode: Dispatch<SetStateAction<"show" | "collapse" | "hide">>;
|
|
454
455
|
zenMode: boolean;
|
|
455
456
|
setZenMode: () => Promise<void>;
|
|
456
457
|
handleSelectPath: (path: string) => void;
|
|
@@ -484,38 +485,38 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
484
485
|
taxonomyDisplayLabels: FirstClassTaxonomyDisplayLabels;
|
|
485
486
|
taxonomies: TaxonomyDefinition[];
|
|
486
487
|
searchQuery: string;
|
|
487
|
-
setSearchQuery:
|
|
488
|
+
setSearchQuery: Dispatch<SetStateAction<string>>;
|
|
488
489
|
filterCategories: string[];
|
|
489
|
-
setFilterCategories:
|
|
490
|
+
setFilterCategories: Dispatch<SetStateAction<string[]>>;
|
|
490
491
|
filterTypes: string[];
|
|
491
|
-
setFilterTypes:
|
|
492
|
+
setFilterTypes: Dispatch<SetStateAction<string[]>>;
|
|
492
493
|
filterPriorities: (string | number)[];
|
|
493
|
-
setFilterPriorities:
|
|
494
|
+
setFilterPriorities: Dispatch<SetStateAction<(string | number)[]>>;
|
|
494
495
|
filterStatus: (string | number)[];
|
|
495
|
-
setFilterStatus:
|
|
496
|
+
setFilterStatus: Dispatch<SetStateAction<(string | number)[]>>;
|
|
496
497
|
filterAssignees: string[];
|
|
497
498
|
setFilterAssignees: (nextValues: TaskAssignee[] | ((prev: TaskAssignee[]) => TaskAssignee[])) => void;
|
|
498
499
|
filterTaxonomies: Record<string, (string | number)[]>;
|
|
499
|
-
setFilterTaxonomies:
|
|
500
|
+
setFilterTaxonomies: Dispatch<SetStateAction<Record<string, (string | number)[]>>>;
|
|
500
501
|
hasInitedFilters: boolean;
|
|
501
502
|
sortBy: import("../utils/taxonomySorting").TaskSortKey;
|
|
502
|
-
setSortBy:
|
|
503
|
+
setSortBy: Dispatch<SetStateAction<import("../utils/taxonomySorting").TaskSortKey>>;
|
|
503
504
|
sortOrder: "asc" | "desc";
|
|
504
|
-
setSortOrder:
|
|
505
|
+
setSortOrder: Dispatch<SetStateAction<"asc" | "desc">>;
|
|
505
506
|
toggleSortOrder: () => void;
|
|
506
507
|
showArchive: boolean;
|
|
507
|
-
setShowArchive:
|
|
508
|
+
setShowArchive: Dispatch<SetStateAction<boolean>>;
|
|
508
509
|
taskScope: TaskScope;
|
|
509
|
-
setTaskScope:
|
|
510
|
+
setTaskScope: Dispatch<SetStateAction<TaskScope>>;
|
|
510
511
|
compressedCards: boolean;
|
|
511
|
-
setCompressedCards:
|
|
512
|
+
setCompressedCards: Dispatch<SetStateAction<boolean>>;
|
|
512
513
|
clearFilters: () => void;
|
|
513
514
|
filteredTasks: TaskItem[];
|
|
514
515
|
searchAgnosticTasks: TaskItem[];
|
|
515
516
|
filteredArchive: TaskItem[];
|
|
516
517
|
groupedTasks: Record<string, TaskItem[]>;
|
|
517
518
|
collapsedCategories: Record<string, boolean>;
|
|
518
|
-
setCollapsedCategories:
|
|
519
|
+
setCollapsedCategories: Dispatch<SetStateAction<Record<string, boolean>>>;
|
|
519
520
|
fetchTasks: (isSilent?: boolean, options?: {
|
|
520
521
|
ignoreAuthGuard?: boolean;
|
|
521
522
|
highlightChangedTaskIds?: readonly string[];
|
|
@@ -539,6 +540,10 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
539
540
|
}>;
|
|
540
541
|
createInitiative: (payload: Partial<InitiativeItem>) => Promise<InitiativeItem>;
|
|
541
542
|
updateInitiative: (id: string, payload: Partial<InitiativeItem>) => Promise<InitiativeItem>;
|
|
543
|
+
updatePlanningIdentity: (entityType: "initiative" | "workstream", id: string, patch: {
|
|
544
|
+
icon?: PlanningIdentityIcon | null;
|
|
545
|
+
color?: PlanningIdentityColor | null;
|
|
546
|
+
}) => Promise<InitiativeItem | WorkstreamItem>;
|
|
542
547
|
archiveInitiative: (id: string) => Promise<InitiativeItem>;
|
|
543
548
|
unarchiveInitiative: (id: string) => Promise<InitiativeItem>;
|
|
544
549
|
createWorkstream: (payload: Partial<WorkstreamItem>) => Promise<WorkstreamItem>;
|
|
@@ -574,55 +579,59 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
574
579
|
error: string;
|
|
575
580
|
clearTaskError: () => void;
|
|
576
581
|
title: string;
|
|
577
|
-
setTitle:
|
|
582
|
+
setTitle: Dispatch<SetStateAction<string>>;
|
|
578
583
|
setTitleDraft: (value: string) => void;
|
|
579
584
|
description: string;
|
|
580
|
-
setDescription:
|
|
585
|
+
setDescription: Dispatch<SetStateAction<string>>;
|
|
581
586
|
setDescriptionDraft: (value: string) => void;
|
|
582
587
|
checklistItems: ChecklistItem[];
|
|
583
|
-
setChecklistItems:
|
|
588
|
+
setChecklistItems: Dispatch<SetStateAction<ChecklistItem[]>>;
|
|
584
589
|
category: string;
|
|
585
|
-
setCategory:
|
|
590
|
+
setCategory: Dispatch<SetStateAction<string>>;
|
|
586
591
|
type: string;
|
|
587
|
-
setType:
|
|
592
|
+
setType: Dispatch<SetStateAction<string>>;
|
|
588
593
|
priority: string | number;
|
|
589
|
-
setPriority:
|
|
594
|
+
setPriority: Dispatch<SetStateAction<string | number>>;
|
|
590
595
|
complexity: string | number;
|
|
591
|
-
setComplexity:
|
|
596
|
+
setComplexity: Dispatch<SetStateAction<string | number>>;
|
|
592
597
|
status: TaskStatus;
|
|
593
|
-
setStatus:
|
|
598
|
+
setStatus: Dispatch<SetStateAction<TaskStatus>>;
|
|
594
599
|
assignee: string;
|
|
595
|
-
setAssignee:
|
|
600
|
+
setAssignee: Dispatch<SetStateAction<string>>;
|
|
596
601
|
scheduledDate: string;
|
|
597
|
-
setScheduledDate:
|
|
602
|
+
setScheduledDate: Dispatch<SetStateAction<string>>;
|
|
598
603
|
dueDate: string;
|
|
599
|
-
setDueDate:
|
|
604
|
+
setDueDate: Dispatch<SetStateAction<string>>;
|
|
600
605
|
workstreamInput: string;
|
|
601
|
-
setWorkstreamInput:
|
|
606
|
+
setWorkstreamInput: Dispatch<SetStateAction<string>>;
|
|
602
607
|
formTaxonomies: Record<string, string | number | string[] | number[]>;
|
|
603
|
-
setFormTaxonomies:
|
|
608
|
+
setFormTaxonomies: Dispatch<SetStateAction<Record<string, string | number | string[] | number[]>>>;
|
|
604
609
|
comments: Comment[];
|
|
605
610
|
newCommentText: string;
|
|
606
|
-
setNewCommentText:
|
|
611
|
+
setNewCommentText: Dispatch<SetStateAction<string>>;
|
|
607
612
|
attachments: (string | AttachmentItem)[];
|
|
608
|
-
setAttachments:
|
|
613
|
+
setAttachments: Dispatch<SetStateAction<(string | AttachmentItem)[]>>;
|
|
609
614
|
attachmentsDirty: boolean;
|
|
610
|
-
setAttachmentsDirty:
|
|
615
|
+
setAttachmentsDirty: Dispatch<SetStateAction<boolean>>;
|
|
616
|
+
descriptionImageUploadPending: boolean;
|
|
617
|
+
descriptionImageDraftId: string;
|
|
618
|
+
registerDescriptionImageUpload: (upload: Promise<void>) => void;
|
|
611
619
|
descriptionFocused: boolean;
|
|
612
|
-
setDescriptionFocused:
|
|
620
|
+
setDescriptionFocused: Dispatch<SetStateAction<boolean>>;
|
|
613
621
|
showMarkdownHelp: boolean;
|
|
614
|
-
setShowMarkdownHelp:
|
|
622
|
+
setShowMarkdownHelp: Dispatch<SetStateAction<boolean>>;
|
|
615
623
|
isCapturingScreenshot: boolean;
|
|
616
|
-
setIsCapturingScreenshot:
|
|
624
|
+
setIsCapturingScreenshot: Dispatch<SetStateAction<boolean>>;
|
|
617
625
|
handleSubmit: (event: React.FormEvent) => Promise<void>;
|
|
618
626
|
resetForm: () => void;
|
|
627
|
+
discardDescriptionImageDraft: () => Promise<void>;
|
|
619
628
|
handleAddComment: (text: string) => Promise<void>;
|
|
620
629
|
handleSetWorkstreamForCurrentTask: (workstreamIdOverride?: string | null) => Promise<void>;
|
|
621
630
|
handleOpenTaskById: (taskId: string) => void;
|
|
622
631
|
returnToPreviousTask: () => boolean;
|
|
623
632
|
autoSaveState: import("./tasks/useTaskFormActions").TaskAutoSaveState;
|
|
624
633
|
unsavedModalOpen: boolean;
|
|
625
|
-
setUnsavedModalOpen:
|
|
634
|
+
setUnsavedModalOpen: Dispatch<SetStateAction<boolean>>;
|
|
626
635
|
pendingNavigation: (() => void) | null;
|
|
627
636
|
handleNavigation: (action: () => void) => Promise<void>;
|
|
628
637
|
handleClose: () => void;
|
|
@@ -648,13 +657,13 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
648
657
|
confirmScheduleWarning: () => Promise<void>;
|
|
649
658
|
cancelScheduleWarning: () => void;
|
|
650
659
|
tasksScrollRef: import("react").RefObject<HTMLDivElement | null>;
|
|
651
|
-
setTasksScrollPos:
|
|
660
|
+
setTasksScrollPos: Dispatch<SetStateAction<number>>;
|
|
652
661
|
taskforceAgentId: string;
|
|
653
|
-
setTaskforceAgentId:
|
|
662
|
+
setTaskforceAgentId: Dispatch<SetStateAction<string>>;
|
|
654
663
|
taskforceAgentConversationId: string;
|
|
655
|
-
setTaskforceAgentConversationId:
|
|
664
|
+
setTaskforceAgentConversationId: Dispatch<SetStateAction<string>>;
|
|
656
665
|
taskforceAgentConversationByAgentId: Record<string, string>;
|
|
657
|
-
setTaskforceAgentConversationByAgentId:
|
|
666
|
+
setTaskforceAgentConversationByAgentId: Dispatch<SetStateAction<Record<string, string>>>;
|
|
658
667
|
uiStateReady: boolean;
|
|
659
668
|
handleUpdateCategory: (updatedCat: CategoryConfig, oldLabel?: string) => Promise<void>;
|
|
660
669
|
handleRemoveCategory: (catValue: string) => Promise<void>;
|
|
@@ -685,7 +694,7 @@ export declare function useTaskforce({ config, initialTaskId, initialActivityEnt
|
|
|
685
694
|
validatePaths: (paths: string[]) => Promise<void>;
|
|
686
695
|
getCategoryPaths: (cat: CategoryConfig) => string[];
|
|
687
696
|
customCategories: CategoryConfig[];
|
|
688
|
-
setCustomCategories:
|
|
697
|
+
setCustomCategories: Dispatch<SetStateAction<CategoryConfig[]>>;
|
|
689
698
|
projectRoot: string;
|
|
690
699
|
projectName: string;
|
|
691
700
|
mcpScriptPath: string;
|
|
@@ -1494,7 +1494,46 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
1494
1494
|
const [activeWorkspaceModule, setActiveWorkspaceModuleState] = useState('tasks');
|
|
1495
1495
|
const [descriptionFocused, setDescriptionFocused] = useState(false);
|
|
1496
1496
|
const [isCapturingScreenshot, setIsCapturingScreenshot] = useState(false);
|
|
1497
|
-
const
|
|
1497
|
+
const attachmentsDraftRef = useRef([]);
|
|
1498
|
+
const [attachments, setAttachmentsState] = useState([]);
|
|
1499
|
+
const setAttachments = useCallback((next) => {
|
|
1500
|
+
const nextAttachments = typeof next === 'function'
|
|
1501
|
+
? next(attachmentsDraftRef.current)
|
|
1502
|
+
: next;
|
|
1503
|
+
attachmentsDraftRef.current = nextAttachments;
|
|
1504
|
+
setAttachmentsState(nextAttachments);
|
|
1505
|
+
}, []);
|
|
1506
|
+
const getAttachmentsDraft = useCallback(() => [...attachmentsDraftRef.current], []);
|
|
1507
|
+
const pendingDescriptionImageUploadRef = useRef(null);
|
|
1508
|
+
const [descriptionImageUploadPending, setDescriptionImageUploadPending] = useState(false);
|
|
1509
|
+
const createDescriptionImageDraftId = useCallback(() => (`task-description-${globalThis.crypto?.randomUUID?.() || `${Date.now()}-${Math.random().toString(16).slice(2)}`}`), []);
|
|
1510
|
+
const descriptionImageDraftIdRef = useRef(createDescriptionImageDraftId());
|
|
1511
|
+
const [descriptionImageDraftId, setDescriptionImageDraftId] = useState(descriptionImageDraftIdRef.current);
|
|
1512
|
+
const rotateDescriptionImageDraftId = useCallback(() => {
|
|
1513
|
+
const nextDraftId = createDescriptionImageDraftId();
|
|
1514
|
+
descriptionImageDraftIdRef.current = nextDraftId;
|
|
1515
|
+
setDescriptionImageDraftId(nextDraftId);
|
|
1516
|
+
}, [createDescriptionImageDraftId]);
|
|
1517
|
+
const registerDescriptionImageUpload = useCallback((upload) => {
|
|
1518
|
+
pendingDescriptionImageUploadRef.current = upload;
|
|
1519
|
+
setDescriptionImageUploadPending(true);
|
|
1520
|
+
void upload.then(() => {
|
|
1521
|
+
if (pendingDescriptionImageUploadRef.current !== upload)
|
|
1522
|
+
return;
|
|
1523
|
+
pendingDescriptionImageUploadRef.current = null;
|
|
1524
|
+
setDescriptionImageUploadPending(false);
|
|
1525
|
+
}, () => {
|
|
1526
|
+
if (pendingDescriptionImageUploadRef.current !== upload)
|
|
1527
|
+
return;
|
|
1528
|
+
pendingDescriptionImageUploadRef.current = null;
|
|
1529
|
+
setDescriptionImageUploadPending(false);
|
|
1530
|
+
});
|
|
1531
|
+
}, []);
|
|
1532
|
+
const awaitPendingDescriptionImageUpload = useCallback(async () => {
|
|
1533
|
+
const upload = pendingDescriptionImageUploadRef.current;
|
|
1534
|
+
if (upload)
|
|
1535
|
+
await upload;
|
|
1536
|
+
}, []);
|
|
1498
1537
|
const [attachmentsDirty, setAttachmentsDirty] = useState(false);
|
|
1499
1538
|
const dataVersionRef = useRef(null);
|
|
1500
1539
|
const ambiguousRealtimeConfirmationTimerRef = useRef(null);
|
|
@@ -2804,6 +2843,24 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
2804
2843
|
setInitiatives((current) => upsertEntityById(current, data));
|
|
2805
2844
|
return data;
|
|
2806
2845
|
}, [fetchPlanningEntities, runInitiativeMutation]);
|
|
2846
|
+
const updatePlanningIdentity = useCallback(async (entityType, id, patch) => {
|
|
2847
|
+
const res = await runInitiativeMutation(`/api/taskforce/${entityType}/${encodeURIComponent(id)}/identity`, {
|
|
2848
|
+
method: 'PATCH',
|
|
2849
|
+
headers: { 'Content-Type': 'application/json' },
|
|
2850
|
+
body: JSON.stringify(patch),
|
|
2851
|
+
});
|
|
2852
|
+
const data = await res.json().catch(() => ({}));
|
|
2853
|
+
if (!res.ok)
|
|
2854
|
+
throw new Error(data?.error || `Failed to update ${entityType} identity (${res.status})`);
|
|
2855
|
+
if (entityType === 'initiative') {
|
|
2856
|
+
setInitiatives((current) => upsertEntityById(current, data));
|
|
2857
|
+
}
|
|
2858
|
+
else {
|
|
2859
|
+
setWorkstreams((current) => upsertEntityById(current, data));
|
|
2860
|
+
}
|
|
2861
|
+
void fetchPlanningEntities();
|
|
2862
|
+
return data;
|
|
2863
|
+
}, [fetchPlanningEntities, runInitiativeMutation]);
|
|
2807
2864
|
const refreshPlanningEntitiesInBackground = useCallback(() => {
|
|
2808
2865
|
void fetchPlanningEntities();
|
|
2809
2866
|
}, [fetchPlanningEntities]);
|
|
@@ -3784,6 +3841,22 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3784
3841
|
durableTaskHttpRootActivationEnabled: runtimeConfigOverride.syncV3TaskCloudHttpRootActivation,
|
|
3785
3842
|
workspaceId: currentWorkspaceId,
|
|
3786
3843
|
});
|
|
3844
|
+
const promoteDescriptionImageDraft = useCallback(async () => {
|
|
3845
|
+
const draftId = descriptionImageDraftIdRef.current;
|
|
3846
|
+
const response = await fetch('/api/taskforce/context-upload/draft/promote', {
|
|
3847
|
+
method: 'POST',
|
|
3848
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3849
|
+
body: JSON.stringify({
|
|
3850
|
+
workspaceId: currentWorkspaceId,
|
|
3851
|
+
draftUploadId: draftId,
|
|
3852
|
+
uploadPurpose: 'task-description-draft',
|
|
3853
|
+
}),
|
|
3854
|
+
});
|
|
3855
|
+
if (!response.ok) {
|
|
3856
|
+
throw new Error('Task was created, but its draft upload records could not be finalized.');
|
|
3857
|
+
}
|
|
3858
|
+
rotateDescriptionImageDraftId();
|
|
3859
|
+
}, [currentWorkspaceId, rotateDescriptionImageDraftId]);
|
|
3787
3860
|
const { autoSaveState, flushAutoSave, scheduleWarningPrompt, handleSubmit, confirmScheduleWarning, cancelScheduleWarning, handleAddComment } = useTaskFormActions({
|
|
3788
3861
|
activeCategories,
|
|
3789
3862
|
activeTab,
|
|
@@ -3804,9 +3877,12 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3804
3877
|
editingTaskId,
|
|
3805
3878
|
fetchTasks,
|
|
3806
3879
|
formTaxonomies,
|
|
3880
|
+
getAttachmentsDraft,
|
|
3807
3881
|
getDescriptionDraft,
|
|
3808
3882
|
getPreferredCategoryValue,
|
|
3809
3883
|
getTitleDraft,
|
|
3884
|
+
awaitPendingDescriptionImageUpload,
|
|
3885
|
+
onTaskCreateAccepted: promoteDescriptionImageDraft,
|
|
3810
3886
|
mergeTaskFromServer,
|
|
3811
3887
|
onTaskCreated: handleEdit,
|
|
3812
3888
|
workstreamInput,
|
|
@@ -3831,6 +3907,27 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
3831
3907
|
textDraftOccupied,
|
|
3832
3908
|
type
|
|
3833
3909
|
});
|
|
3910
|
+
const discardDescriptionImageDraft = useCallback(async () => {
|
|
3911
|
+
const draftId = descriptionImageDraftIdRef.current;
|
|
3912
|
+
rotateDescriptionImageDraftId();
|
|
3913
|
+
try {
|
|
3914
|
+
await awaitPendingDescriptionImageUpload();
|
|
3915
|
+
const response = await fetch('/api/taskforce/context-upload/draft/discard', {
|
|
3916
|
+
method: 'POST',
|
|
3917
|
+
headers: { 'Content-Type': 'application/json' },
|
|
3918
|
+
body: JSON.stringify({
|
|
3919
|
+
workspaceId: currentWorkspaceId,
|
|
3920
|
+
draftUploadId: draftId,
|
|
3921
|
+
uploadPurpose: 'task-description-draft',
|
|
3922
|
+
}),
|
|
3923
|
+
});
|
|
3924
|
+
if (!response.ok)
|
|
3925
|
+
throw new Error('Draft upload cleanup was rejected.');
|
|
3926
|
+
}
|
|
3927
|
+
catch (error) {
|
|
3928
|
+
console.warn('[Taskforce] Failed to clean discarded Description image uploads.', error);
|
|
3929
|
+
}
|
|
3930
|
+
}, [awaitPendingDescriptionImageUpload, currentWorkspaceId, rotateDescriptionImageDraftId]);
|
|
3834
3931
|
useEffect(() => {
|
|
3835
3932
|
flushAutoSaveRef.current = flushAutoSave;
|
|
3836
3933
|
}, [flushAutoSave]);
|
|
@@ -4181,6 +4278,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
4181
4278
|
fetchAssigneeOptions,
|
|
4182
4279
|
createInitiative,
|
|
4183
4280
|
updateInitiative,
|
|
4281
|
+
updatePlanningIdentity,
|
|
4184
4282
|
archiveInitiative,
|
|
4185
4283
|
unarchiveInitiative,
|
|
4186
4284
|
createWorkstream,
|
|
@@ -4244,6 +4342,9 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
4244
4342
|
setAttachments,
|
|
4245
4343
|
attachmentsDirty,
|
|
4246
4344
|
setAttachmentsDirty,
|
|
4345
|
+
descriptionImageUploadPending,
|
|
4346
|
+
descriptionImageDraftId,
|
|
4347
|
+
registerDescriptionImageUpload,
|
|
4247
4348
|
descriptionFocused,
|
|
4248
4349
|
setDescriptionFocused,
|
|
4249
4350
|
showMarkdownHelp,
|
|
@@ -4253,6 +4354,7 @@ export function useTaskforce({ config = {}, initialTaskId, initialActivityEntryI
|
|
|
4253
4354
|
// Form Actions
|
|
4254
4355
|
handleSubmit,
|
|
4255
4356
|
resetForm,
|
|
4357
|
+
discardDescriptionImageDraft,
|
|
4256
4358
|
handleAddComment,
|
|
4257
4359
|
handleSetWorkstreamForCurrentTask,
|
|
4258
4360
|
handleOpenTaskById,
|
|
@@ -35,12 +35,23 @@ export interface CanonicalAssetHelpersDeps {
|
|
|
35
35
|
assetId: string;
|
|
36
36
|
};
|
|
37
37
|
}
|
|
38
|
+
export declare class CanonicalDocumentHeadStaleError extends Error {
|
|
39
|
+
readonly details: Record<string, unknown>;
|
|
40
|
+
readonly code = "MCP_DOCUMENT_HEAD_STALE";
|
|
41
|
+
readonly statusCode = 409;
|
|
42
|
+
constructor(details: Record<string, unknown>);
|
|
43
|
+
}
|
|
38
44
|
export declare function createCanonicalAssetHelpers(deps: CanonicalAssetHelpersDeps): {
|
|
39
45
|
normalizeAttachmentStorageKey: (pathValue: unknown, fsPathValue: unknown) => string | null;
|
|
40
46
|
buildSyntheticAttachmentId: (taskId: string, attachment: TaskAttachmentRecord) => string;
|
|
41
47
|
getAttachmentAssetRecord: (attachment: TaskAttachmentRecord) => WorkspaceAssetEntry | null;
|
|
42
48
|
buildAttachmentDownloadUrl: (attachment: McpTaskAttachmentDescriptor) => string;
|
|
43
49
|
buildDocumentDownloadUrl: (asset: WorkspaceAssetEntry | WorkspaceDocumentEntry) => string;
|
|
50
|
+
assertCanonicalDocumentHeadCurrent: (asset: WorkspaceAssetEntry | WorkspaceDocumentEntry) => import("../sync/engine/workspaceSyncPublishedContentResolver.js").WorkspaceSyncPublishedLegacyContent | import("../sync/engine/workspaceSyncPublishedContentResolver.js").WorkspaceSyncPublishedVersionedContent | {
|
|
51
|
+
source: "legacy";
|
|
52
|
+
physicalKey: string;
|
|
53
|
+
storageProvider: import("../storage/objectStorage.js").ObjectStorageProvider;
|
|
54
|
+
};
|
|
44
55
|
readCanonicalAttachmentBuffer: (taskId: string, attachment: McpTaskAttachmentDescriptor, targetLabel?: string) => Promise<Buffer>;
|
|
45
56
|
readCanonicalDocumentBuffer: (asset: WorkspaceAssetEntry | WorkspaceDocumentEntry) => Promise<Buffer>;
|
|
46
57
|
toTaskAttachmentRecord: (attachment: string | TaskAttachmentRecord) => TaskAttachmentRecord;
|
|
@@ -68,6 +79,7 @@ export declare function createCanonicalAssetHelpers(deps: CanonicalAssetHelpersD
|
|
|
68
79
|
scanEngine?: string | null;
|
|
69
80
|
scanDetails?: string | null;
|
|
70
81
|
createLink?: boolean;
|
|
82
|
+
displayName?: string;
|
|
71
83
|
}) => Promise<WorkspaceAssetEntry | null>;
|
|
72
84
|
ensureCanonicalTaskAttachment: (relativePathRaw: string, taskIdRaw: string, captionRaw: string | undefined, timestampRaw: string | undefined, role: WorkspaceAssetLinkRole, options?: Parameters<(relativePathRaw: string, targetTypeRaw: WorkspaceAssetLinkTargetType, targetIdRaw: string, captionRaw: string | undefined, timestampRaw: string | undefined, role: WorkspaceAssetLinkRole, options?: {
|
|
73
85
|
originalFilename?: string;
|
|
@@ -80,6 +92,7 @@ export declare function createCanonicalAssetHelpers(deps: CanonicalAssetHelpersD
|
|
|
80
92
|
scanEngine?: string | null;
|
|
81
93
|
scanDetails?: string | null;
|
|
82
94
|
createLink?: boolean;
|
|
95
|
+
displayName?: string;
|
|
83
96
|
}) => Promise<WorkspaceAssetEntry | null>>[6]) => Promise<WorkspaceAssetEntry | null>;
|
|
84
97
|
buildCanonicalWorkspaceAssetRelativePath: (params: {
|
|
85
98
|
workspaceIdRaw: unknown;
|
|
@@ -3,6 +3,16 @@ import * as path from 'path';
|
|
|
3
3
|
import { createHash, randomUUID } from 'node:crypto';
|
|
4
4
|
import { verifyWorkspaceSyncPublishedContentBody, } from '../sync/engine/workspaceSyncPublishedContentResolver.js';
|
|
5
5
|
import { normalizeRelativeStorageKey, resolveExistingStorageKeyFilePathInsideRoot, resolveStorageKeyWritePathInsideRoot } from '../utils/pathSafety.js';
|
|
6
|
+
export class CanonicalDocumentHeadStaleError extends Error {
|
|
7
|
+
details;
|
|
8
|
+
code = 'MCP_DOCUMENT_HEAD_STALE';
|
|
9
|
+
statusCode = 409;
|
|
10
|
+
constructor(details) {
|
|
11
|
+
super('The published document head does not match the current canonical document metadata.');
|
|
12
|
+
this.details = details;
|
|
13
|
+
this.name = 'CanonicalDocumentHeadStaleError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
6
16
|
export function createCanonicalAssetHelpers(deps) {
|
|
7
17
|
const normalizeAttachmentStorageKey = (pathValue, fsPathValue) => {
|
|
8
18
|
const fsPathRaw = String(fsPathValue || '').trim().replace(/\\/g, '/');
|
|
@@ -50,6 +60,30 @@ export function createCanonicalAssetHelpers(deps) {
|
|
|
50
60
|
legacyProvider: asset.storageProvider,
|
|
51
61
|
});
|
|
52
62
|
};
|
|
63
|
+
const assertCanonicalDocumentHeadCurrent = (asset) => {
|
|
64
|
+
const resolved = resolveCanonicalContentRead(asset, 'document');
|
|
65
|
+
if (resolved.source === 'deleted') {
|
|
66
|
+
throw new Error(`Document ${asset.assetId} not found in workspace ${deps.activeWorkspaceId}.`);
|
|
67
|
+
}
|
|
68
|
+
if (resolved.source === 'versioned' && (resolved.storageProvider !== asset.storageProvider
|
|
69
|
+
|| resolved.contentSha256 !== asset.contentSha256
|
|
70
|
+
|| resolved.sizeBytes !== asset.sizeBytes)) {
|
|
71
|
+
throw new CanonicalDocumentHeadStaleError({
|
|
72
|
+
assetId: asset.assetId,
|
|
73
|
+
currentVersion: asset.version,
|
|
74
|
+
currentStorageProvider: asset.storageProvider,
|
|
75
|
+
currentContentSha256: asset.contentSha256,
|
|
76
|
+
currentSizeBytes: asset.sizeBytes,
|
|
77
|
+
headVersionId: resolved.versionId,
|
|
78
|
+
headStorageProvider: resolved.storageProvider,
|
|
79
|
+
headContentSha256: resolved.contentSha256,
|
|
80
|
+
headSizeBytes: resolved.sizeBytes,
|
|
81
|
+
nextTool: 'update_document',
|
|
82
|
+
guidance: 'Retry update_document with the complete current body and expectedVersion to republish the canonical immutable head. Do not use the returned download until the repair succeeds.',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return resolved;
|
|
86
|
+
};
|
|
53
87
|
const buildSyntheticAttachmentId = (taskId, attachment) => {
|
|
54
88
|
const stableSource = [
|
|
55
89
|
taskId,
|
|
@@ -157,10 +191,7 @@ export function createCanonicalAssetHelpers(deps) {
|
|
|
157
191
|
if (asset.scanStatus === 'pending') {
|
|
158
192
|
throw new Error('Document scan pending');
|
|
159
193
|
}
|
|
160
|
-
const resolved =
|
|
161
|
-
if (resolved.source === 'deleted') {
|
|
162
|
-
throw new Error(`Document ${asset.assetId} not found in workspace ${deps.activeWorkspaceId}.`);
|
|
163
|
-
}
|
|
194
|
+
const resolved = assertCanonicalDocumentHeadCurrent(asset);
|
|
164
195
|
if (resolved.storageProvider === 'r2') {
|
|
165
196
|
if (!normalizeRelativeStorageKey(resolved.physicalKey)) {
|
|
166
197
|
throw new Error(`Document ${asset.assetId} not found in workspace ${deps.activeWorkspaceId}.`);
|
|
@@ -324,7 +355,9 @@ export function createCanonicalAssetHelpers(deps) {
|
|
|
324
355
|
targetType,
|
|
325
356
|
targetId,
|
|
326
357
|
role,
|
|
327
|
-
displayName:
|
|
358
|
+
displayName: options?.displayName !== undefined
|
|
359
|
+
? options.displayName
|
|
360
|
+
: kind === 'document' ? null : (captionRaw || null),
|
|
328
361
|
updatedAt: timestamp,
|
|
329
362
|
deletedAt: null
|
|
330
363
|
});
|
|
@@ -338,6 +371,7 @@ export function createCanonicalAssetHelpers(deps) {
|
|
|
338
371
|
getAttachmentAssetRecord,
|
|
339
372
|
buildAttachmentDownloadUrl,
|
|
340
373
|
buildDocumentDownloadUrl,
|
|
374
|
+
assertCanonicalDocumentHeadCurrent,
|
|
341
375
|
readCanonicalAttachmentBuffer,
|
|
342
376
|
readCanonicalDocumentBuffer,
|
|
343
377
|
toTaskAttachmentRecord,
|
|
@@ -23,7 +23,7 @@ export function registerCollaborationTools(registerTool, executeTool) {
|
|
|
23
23
|
});
|
|
24
24
|
};
|
|
25
25
|
register('list_assignees', (context) => ({
|
|
26
|
-
description: context.describeTool('List eligible assignees for the active workspace.
|
|
26
|
+
description: context.describeTool('List eligible assignees for the active workspace. Includes members and AI profiles. Use query for a bounded ID, label, or username match.'),
|
|
27
27
|
inputSchema: {
|
|
28
28
|
properties: {
|
|
29
29
|
query: stringProperty('Optional case-insensitive substring matched against assignee ID, label, and username. When non-empty, returns at most 25 matches unless limit is set.'),
|
|
@@ -32,7 +32,7 @@ export function registerCollaborationTools(registerTool, executeTool) {
|
|
|
32
32
|
},
|
|
33
33
|
}));
|
|
34
34
|
register('get_current_profile', (context) => ({
|
|
35
|
-
description: context.describeTool('Inspect current AI identity for this call
|
|
35
|
+
description: context.describeTool('Inspect current AI identity for this call and write readiness. Stateless/scheduled agents may pass profileToken. Use before writes or to decide whether resolve_profile is needed.'),
|
|
36
36
|
inputSchema: {
|
|
37
37
|
properties: {
|
|
38
38
|
profileToken: stringProperty('Optional AI profile token to inspect when no profile is currently bound in session state. Pass only a token previously issued to this AI identity.'),
|
|
@@ -40,24 +40,25 @@ export function registerCollaborationTools(registerTool, executeTool) {
|
|
|
40
40
|
},
|
|
41
41
|
}));
|
|
42
42
|
register('resolve_profile', (context) => ({
|
|
43
|
-
description: context.describeTool('Resolve or create this AI collaborator profile
|
|
43
|
+
description: context.describeTool('Resolve or create this AI collaborator profile using a stable product name. Stateless agents use name + surfaceType and may reuse profileToken. If OAuth recovery returns candidates, retry with profileId. Store profileToken privately only; pass it on writes. Never write profileToken to repos, tasks, logs, or docs.'),
|
|
44
44
|
inputSchema: {
|
|
45
45
|
properties: {
|
|
46
|
-
name: stringProperty('Stable
|
|
47
|
-
icon: stringProperty('Optional icon
|
|
48
|
-
color: stringProperty('Optional
|
|
49
|
-
description: stringProperty('Optional
|
|
50
|
-
role: stringProperty('Optional role label
|
|
51
|
-
provider: stringProperty('Optional provider
|
|
52
|
-
model: stringProperty('Optional model
|
|
46
|
+
name: stringProperty('Stable collaborator or product name; exclude model names and versions.'),
|
|
47
|
+
icon: stringProperty('Optional profile icon or emoji; omit to leave unchanged.'),
|
|
48
|
+
color: stringProperty('Optional Taskforce palette token or hex color; omit to use the assigned default or retain the current value.'),
|
|
49
|
+
description: stringProperty('Optional profile description; omit to leave unchanged.'),
|
|
50
|
+
role: stringProperty('Optional role label; omit to leave unchanged.'),
|
|
51
|
+
provider: stringProperty('Optional provider metadata; omit to leave unchanged.'),
|
|
52
|
+
model: stringProperty('Optional model metadata; omit to leave unchanged.'),
|
|
53
53
|
surfaceType: {
|
|
54
54
|
anyOf: [
|
|
55
55
|
{ type: 'string', enum: [...AI_PROFILE_SURFACE_TYPES] },
|
|
56
56
|
{ type: 'null' },
|
|
57
57
|
],
|
|
58
|
-
description: 'Optional
|
|
58
|
+
description: 'Optional surface: agent (persistent collaborator), cli (terminal coding agent), coding_tool (other coding surface), chat_app (chat app), or ide (IDE copilot). Use agent when unsure. Omit to retain; null or empty clears.',
|
|
59
59
|
},
|
|
60
|
-
|
|
60
|
+
profileId: stringProperty('Compatible profile ID from a prior selection-required response.'),
|
|
61
|
+
profileToken: stringProperty('Private token previously issued for this AI identity; reuses and optionally updates that profile.'),
|
|
61
62
|
},
|
|
62
63
|
required: ['name'],
|
|
63
64
|
},
|
|
@@ -73,11 +74,12 @@ export function registerCollaborationTools(registerTool, executeTool) {
|
|
|
73
74
|
},
|
|
74
75
|
}));
|
|
75
76
|
register('add_comment', (context) => ({
|
|
76
|
-
description: context.describeTool('Add a comment to a task.
|
|
77
|
+
description: context.describeTool('Add a comment to a task. Pass idempotencyKey when retrying after an ambiguous timeout; reuse it only with the exact same target and text.'),
|
|
77
78
|
inputSchema: {
|
|
78
79
|
properties: {
|
|
79
80
|
id: stringProperty('Task ID or task reference such as T-123.'),
|
|
80
81
|
text: stringProperty('Comment text.'),
|
|
82
|
+
idempotencyKey: { type: 'string', minLength: 1, maxLength: 128, description: 'Optional opaque retry key scoped to the active workspace, actor, and tool.' },
|
|
81
83
|
},
|
|
82
84
|
required: ['id', 'text'],
|
|
83
85
|
},
|