@taskforcehq/taskforce 0.3.303 → 0.3.305
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/README.md +140 -247
- package/dist/Taskforce.module.css +102 -5
- package/dist/TaskforceCore.js +635 -238
- package/dist/TaskforceCore.test.js +2243 -495
- package/dist/annotatedAttachments/service.d.ts +1 -1
- package/dist/annotatedAttachments/types.d.ts +1 -1
- package/dist/compat/workspaceSyncCompat.js +6 -0
- package/dist/components/features/AgentsModule.js +1 -1
- package/dist/components/features/AgentsModule.test.js +1 -1
- package/dist/components/features/DocumentIndex.d.ts +1 -1
- package/dist/components/features/DocumentIndex.js +1 -1
- package/dist/components/features/DocumentViewer.d.ts +1 -1
- package/dist/components/features/DocumentViewer.js +32 -9
- package/dist/components/features/DocumentWorkspace.d.ts +5 -22
- package/dist/components/features/DocumentWorkspace.js +12 -155
- package/dist/components/features/DocumentWorkspace.test.js +193 -6
- package/dist/components/features/TaskSettings.js +87 -41
- package/dist/components/features/TaskSettings.test.js +180 -40
- package/dist/components/features/documentWorkspaceModel.d.ts +24 -0
- package/dist/components/features/documentWorkspaceModel.js +57 -0
- package/dist/components/features/useDocumentWorkspaceController.d.ts +34 -0
- package/dist/components/features/useDocumentWorkspaceController.js +113 -0
- package/dist/components/task/TaskActionHeader.d.ts +2 -1
- package/dist/components/task/TaskActionHeader.js +3 -3
- package/dist/components/task/TaskActionHeader.test.js +8 -0
- package/dist/components/task/TaskCard.js +16 -1
- package/dist/components/task/TaskCard.test.js +31 -0
- package/dist/components/task/TaskForm.d.ts +9 -8
- package/dist/components/task/TaskForm.js +374 -219
- package/dist/components/task/TaskForm.test.js +482 -361
- package/dist/components/task/TaskKanban.d.ts +1 -1
- package/dist/components/task/TaskKanban.js +33 -161
- package/dist/components/task/TaskStatusActions.d.ts +6 -1
- package/dist/components/task/TaskStatusActions.js +8 -3
- package/dist/components/task/TaskStatusActions.test.js +9 -0
- package/dist/components/task/taskKanbanDropRules.d.ts +58 -0
- package/dist/components/task/taskKanbanDropRules.js +187 -0
- package/dist/components/task/taskKanbanDropRules.test.d.ts +1 -0
- package/dist/components/task/taskKanbanDropRules.test.js +114 -0
- package/dist/components/ui/Modal.d.ts +1 -1
- package/dist/components/ui/Modal.js +1 -0
- package/dist/components/views/AppShellHeader.js +5 -1
- package/dist/components/views/AppShellHeader.test.js +4 -0
- package/dist/components/views/PlanComparisonPage.d.ts +3 -2
- package/dist/components/views/PlanComparisonPage.js +9 -10
- package/dist/components/views/PlanComparisonPage.test.js +55 -41
- package/dist/components/views/PlansPage.d.ts +5 -1
- package/dist/components/views/PlansPage.js +150 -81
- package/dist/components/views/PlansPage.test.js +367 -41
- package/dist/components/views/StandaloneLayout.js +135 -54
- package/dist/components/views/WidgetView.js +11 -2
- package/dist/components/views/panels/FilterToolbar.test.js +6 -4
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +2 -14
- package/dist/components/views/standalone/modals/AccountHubModal.js +12 -14
- package/dist/components/views/standalone/modals/AccountHubModal.test.js +24 -1
- package/dist/components/views/standalone/modals/SyncStatusModal.js +1 -1
- package/dist/config/envSchema.js +1 -1
- package/dist/core/AiProfileService.d.ts +6 -1
- package/dist/core/AiProfileService.js +161 -16
- package/dist/core/AiProfileService.test.js +3 -1
- package/dist/core/AiProfiles.test.js +200 -0
- package/dist/core/AuthTokenService.test.d.ts +1 -0
- package/dist/core/AuthTokenService.test.js +78 -0
- package/dist/core/DeletedTaskLifecycleService.d.ts +2 -1
- package/dist/core/EntitlementsPolicy.test.js +75 -13
- package/dist/core/PlanEntitlementService.d.ts +9 -1
- package/dist/core/PlanEntitlementService.js +144 -19
- package/dist/core/PlanVersionPolicy.test.js +19 -26
- package/dist/core/SignupMonetizationSettings.test.js +75 -15
- package/dist/core/SystemAdmin.test.js +212 -56
- package/dist/core/TaskActivityService.d.ts +4 -1
- package/dist/core/TaskActivityService.js +45 -0
- package/dist/core/TaskAuditTimeline.test.js +52 -1
- package/dist/core/TaskTaxonomyValidation.test.js +53 -0
- package/dist/core/Taskforce.d.ts +18 -11
- package/dist/core/Taskforce.js +93 -12
- package/dist/core/WorkspacePlanMode.test.js +73 -8
- package/dist/core/shared.d.ts +2 -0
- package/dist/core/shared.js +11 -0
- package/dist/documentReviews/service.d.ts +1 -1
- package/dist/documentReviews/types.d.ts +1 -1
- package/dist/hooks/auth/useTaskforceAuthBootstrap.d.ts +48 -0
- package/dist/hooks/auth/useTaskforceAuthBootstrap.js +219 -0
- package/dist/hooks/sync/auth.d.ts +37 -0
- package/dist/hooks/sync/auth.js +63 -0
- package/dist/hooks/sync/bootstrap.d.ts +34 -0
- package/dist/hooks/sync/bootstrap.js +52 -0
- package/dist/hooks/sync/orchestratorShared.d.ts +36 -0
- package/dist/hooks/sync/orchestratorShared.js +209 -0
- package/dist/hooks/sync/orchestratorShared.test.d.ts +1 -0
- package/dist/hooks/sync/orchestratorShared.test.js +49 -0
- package/dist/hooks/sync/realtime.d.ts +25 -0
- package/dist/hooks/sync/realtime.js +60 -0
- package/dist/hooks/sync/recovery.d.ts +69 -0
- package/dist/hooks/sync/recovery.js +118 -0
- package/dist/hooks/sync/transfers.d.ts +123 -0
- package/dist/hooks/sync/transfers.js +435 -0
- package/dist/hooks/sync/useDataVersionRefresh.d.ts +16 -0
- package/dist/hooks/sync/useDataVersionRefresh.js +73 -0
- package/dist/hooks/ui/useResourceExport.d.ts +3 -1
- package/dist/hooks/ui/useResourceExport.js +5 -2
- package/dist/hooks/ui/useWorkflowTemplates.js +11 -6
- package/dist/hooks/useRealtimeSync.js +2 -1
- package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +8 -0
- package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +1 -0
- package/dist/hooks/useSyncOrchestrator.context-assets.test.js +228 -0
- package/dist/hooks/useSyncOrchestrator.d.ts +12 -8
- package/dist/hooks/useSyncOrchestrator.js +388 -879
- package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +641 -6
- package/dist/hooks/useTaskMutations.d.ts +2 -1
- package/dist/hooks/useTaskMutations.js +57 -7
- package/dist/hooks/useTaskMutations.test.js +176 -0
- package/dist/hooks/useTaskforce.d.ts +13 -4
- package/dist/hooks/useTaskforce.js +302 -817
- package/dist/hooks/useTaskforce.sync-behavior.test.js +78 -0
- package/dist/hooks/useWorkspaceSyncController.d.ts +4 -1
- package/dist/hooks/useWorkspaceSyncController.js +33 -11
- package/dist/hooks/useWorkspaceSyncController.test.js +1 -0
- package/dist/hooks/workspace/useTaskforceApiRouting.test.js +17 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +166 -0
- package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +434 -0
- package/dist/hooks/workspace/workspaceLocalState.d.ts +19 -0
- package/dist/hooks/workspace/workspaceLocalState.js +100 -0
- package/dist/hooks/workspace/workspaceLocalState.test.d.ts +1 -0
- package/dist/hooks/workspace/workspaceLocalState.test.js +59 -0
- package/dist/localization/locales/en-US.js +2 -2
- package/dist/mcp/adminWorkspaceRegistrar.d.ts +2 -0
- package/dist/mcp/adminWorkspaceRegistrar.js +154 -0
- package/dist/mcp/canonicalAssetHelpers.d.ts +70 -0
- package/dist/mcp/canonicalAssetHelpers.js +259 -0
- package/dist/mcp/clientIntegrations.d.ts +12 -1
- package/dist/mcp/clientIntegrations.js +161 -6
- package/dist/mcp/clientIntegrations.test.js +76 -4
- package/dist/mcp/collaborationRegistrar.d.ts +2 -0
- package/dist/mcp/collaborationRegistrar.js +71 -0
- package/dist/mcp/documentAssetRegistrar.d.ts +2 -0
- package/dist/mcp/documentAssetRegistrar.js +346 -0
- package/dist/mcp/documentHelpers.d.ts +100 -0
- package/dist/mcp/documentHelpers.js +161 -0
- package/dist/mcp/runtime.js +2455 -3925
- package/dist/mcp/runtime.test.js +240 -8
- package/dist/mcp/taskAttachmentHelpers.d.ts +41 -0
- package/dist/mcp/taskAttachmentHelpers.js +60 -0
- package/dist/mcp/taskAttachmentTypes.d.ts +37 -0
- package/dist/mcp/taskAttachmentTypes.js +1 -0
- package/dist/mcp/taskPlanningRegistrar.d.ts +2 -0
- package/dist/mcp/taskPlanningRegistrar.js +418 -0
- package/dist/mcp/toolCatalog.d.ts +35 -0
- package/dist/mcp/toolCatalog.js +3 -0
- package/dist/plugins/vite.js +1 -1
- package/dist/runtime/appGateDefinitions.d.ts +1 -1
- package/dist/runtime/appGateDefinitions.js +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +46 -3
- package/dist/server/index.test.js +12 -1
- package/dist/server/routes/admin.d.ts +1 -5
- package/dist/server/routes/admin.js +151 -80
- package/dist/server/routes/annotatedAttachments.d.ts +1 -1
- package/dist/server/routes/annotatedAttachments.js +1 -1
- package/dist/server/routes/auth.d.ts +1 -4
- package/dist/server/routes/auth.js +59 -64
- package/dist/server/routes/authSupport.d.ts +30 -0
- package/dist/server/routes/authSupport.js +81 -0
- package/dist/server/routes/billing.d.ts +1 -1
- package/dist/server/routes/billing.js +122 -255
- package/dist/server/routes/billing.test.js +257 -86
- package/dist/server/routes/documentReviews.d.ts +1 -1
- package/dist/server/routes/documentReviews.js +1 -1
- package/dist/server/routes/documents.d.ts +4 -2
- package/dist/server/routes/documents.js +73 -7
- package/dist/server/routes/primitives.d.ts +11 -0
- package/dist/server/routes/primitives.js +73 -0
- package/dist/server/routes/resources.d.ts +1 -1
- package/dist/server/routes/resources.js +1 -1
- package/dist/server/routes/shared.d.ts +31 -1
- package/dist/server/routes/shared.js +26 -0
- package/dist/server/routes/sync.d.ts +1 -1
- package/dist/server/routes/sync.integration.test.js +20 -0
- package/dist/server/routes/sync.js +111 -238
- package/dist/server/routes/tasks.d.ts +1 -1
- package/dist/server/routes/tasks.js +50 -8
- package/dist/server/routes/workspaces.d.ts +1 -1
- package/dist/server/routes/workspaces.js +1 -1
- package/dist/server/routes.d.ts +2 -9
- package/dist/server/routes.js +84 -181
- package/dist/server/routes.test.js +912 -32
- package/dist/shared/taskActor.d.ts +10 -0
- package/dist/shared/taskActor.js +1 -0
- package/dist/sync/collaborationSyncPayload.js +4 -0
- package/dist/sync/collaborationSyncPayload.test.js +8 -0
- package/dist/sync/collaborationSyncState.d.ts +3 -1
- package/dist/sync/collaborationSyncState.js +19 -0
- package/dist/sync/contentSyncState.js +28 -17
- package/dist/sync/syncApplyHandlers.d.ts +87 -1
- package/dist/sync/syncApplyHandlers.js +370 -8
- package/dist/sync/syncApplyHandlers.test.d.ts +1 -0
- package/dist/sync/syncApplyHandlers.test.js +379 -0
- package/dist/sync/syncService.d.ts +9 -1
- package/dist/sync/syncService.js +44 -2
- package/dist/sync/syncService.test.js +62 -0
- package/dist/sync/workspacePullFeed.d.ts +1 -0
- package/dist/sync/workspacePullFeed.js +66 -59
- package/dist/sync/workspacePullFeed.test.js +72 -4
- package/dist/sync/workspaceSyncModel.d.ts +25 -1
- package/dist/sync/workspaceSyncModel.js +77 -3
- package/dist/sync/workspaceSyncModel.test.js +153 -0
- package/dist/sync/workspaceSyncState.d.ts +2 -0
- package/dist/sync/workspaceSyncState.js +1 -0
- package/dist/types.d.ts +2 -10
- package/dist/ui/assets/AgentsModule-N2MnQBZk.js +1 -0
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-C_TmXZwA.js → AnnotatedAttachmentWorkspace-BG6P_GVW.js} +1 -1
- package/dist/ui/assets/DocumentWorkspace-B3nV_Gc5.css +1 -0
- package/dist/ui/assets/DocumentWorkspace-DRbDMwh8.js +252 -0
- package/dist/ui/assets/{InitiativesModule-4-Rh2K2n.js → InitiativesModule-Dhm7M8e7.js} +1 -1
- package/dist/ui/assets/{PlansPage-BlVC_lRq.css → PlansPage-C2dd2n1X.css} +1 -1
- package/dist/ui/assets/PlansPage-Cq0zXj3I.js +1 -0
- package/dist/ui/assets/TaskSettings-ln0aF7xc.js +9 -0
- package/dist/ui/assets/{WorkflowsModule-CGk9s3NJ.js → WorkflowsModule-BcS4afRn.js} +1 -1
- package/dist/ui/assets/index-C2-OXZV7.css +1 -0
- package/dist/ui/assets/index-DcSI5F86.js +6 -0
- package/dist/ui/assets/{vendor-icons-pWocEipT.js → vendor-icons-BSUaRwF8.js} +1 -1
- package/dist/ui/index.html +4 -4
- package/dist/utils/commercialLifecyclePresentation.d.ts +19 -0
- package/dist/utils/commercialLifecyclePresentation.js +196 -0
- package/dist/utils/taskActivity.js +4 -0
- package/dist/utils/taskActivity.test.js +25 -1
- package/package.json +10 -1
- package/scripts/check-cloud-mcp.mjs +83 -0
- package/scripts/playwright-auth.sh +9 -1
- package/scripts/run-billing-performance-smoke.sh +24 -0
- package/dist/ui/assets/AgentsModule-CpsTmrIW.js +0 -1
- package/dist/ui/assets/DocumentWorkspace-C3GyzrWm.js +0 -250
- package/dist/ui/assets/DocumentWorkspace-C_8T8oz-.css +0 -1
- package/dist/ui/assets/PlansPage-BP7AYOqr.js +0 -1
- package/dist/ui/assets/TaskSettings-BOC5F6Ag.js +0 -8
- package/dist/ui/assets/index-CLIMgR6g.js +0 -6
- package/dist/ui/assets/index-DneETxcu.css +0 -1
|
@@ -348,6 +348,59 @@ describe('TaskforceCore taxonomy validation', () => {
|
|
|
348
348
|
core.close();
|
|
349
349
|
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
350
350
|
});
|
|
351
|
+
it('migrates legacy config-backed taxonomy data once and no longer depends on config for runtime state', () => {
|
|
352
|
+
const projectRoot = makeTempProjectRoot();
|
|
353
|
+
fs.mkdirSync(path.join(projectRoot, '.taskforce'), { recursive: true });
|
|
354
|
+
const configPath = path.join(projectRoot, '.taskforce', 'config.json');
|
|
355
|
+
fs.writeFileSync(configPath, JSON.stringify({
|
|
356
|
+
categories: [{ value: 'legacy', label: 'Legacy' }],
|
|
357
|
+
types: [{ value: 'legacy-type', label: 'Legacy Type' }],
|
|
358
|
+
priorities: [{ value: 9, label: 'Legacy Priority', color: 'red-500', icon: 'AlertTriangle' }],
|
|
359
|
+
taxonomies: [{ id: 'legacy-taxonomy', label: 'Legacy Taxonomy', widgetType: 'select', isSystem: false, multiSelect: false, options: [] }]
|
|
360
|
+
}, null, 2));
|
|
361
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
362
|
+
const migratedState = core.getTaxonomyState('default');
|
|
363
|
+
expect((migratedState.categories || []).map((category) => (typeof category === 'string' ? category : category.value))).toEqual(['default', 'legacy']);
|
|
364
|
+
expect((migratedState.types || []).map((type) => type.value)).toEqual(['legacy-type']);
|
|
365
|
+
expect((migratedState.priorities || []).map((priority) => priority.value)).toEqual([9]);
|
|
366
|
+
expect((migratedState.taxonomies || []).map((taxonomy) => taxonomy.id)).toEqual(['legacy-taxonomy']);
|
|
367
|
+
core.close();
|
|
368
|
+
fs.writeFileSync(configPath, JSON.stringify({ checklistDropdownEnabled: true }, null, 2));
|
|
369
|
+
const reopened = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
370
|
+
const persistedState = reopened.getTaxonomyState('default');
|
|
371
|
+
expect((persistedState.categories || []).map((category) => (typeof category === 'string' ? category : category.value))).toEqual(['default', 'legacy']);
|
|
372
|
+
expect((persistedState.types || []).map((type) => type.value)).toEqual(['legacy-type']);
|
|
373
|
+
expect((persistedState.priorities || []).map((priority) => priority.value)).toEqual([9]);
|
|
374
|
+
expect((persistedState.taxonomies || []).map((taxonomy) => taxonomy.id)).toEqual(['legacy-taxonomy']);
|
|
375
|
+
reopened.close();
|
|
376
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
377
|
+
});
|
|
378
|
+
it('does not seed new workspaces from legacy config-backed taxonomy definitions', () => {
|
|
379
|
+
const projectRoot = makeTempProjectRoot();
|
|
380
|
+
fs.mkdirSync(path.join(projectRoot, '.taskforce'), { recursive: true });
|
|
381
|
+
const configPath = path.join(projectRoot, '.taskforce', 'config.json');
|
|
382
|
+
fs.writeFileSync(configPath, JSON.stringify({
|
|
383
|
+
categories: [{ value: 'legacy', label: 'Legacy' }],
|
|
384
|
+
types: [{ value: 'legacy-type', label: 'Legacy Type' }],
|
|
385
|
+
priorities: [{ value: 9, label: 'Legacy Priority' }],
|
|
386
|
+
taxonomies: [{ id: 'legacy-taxonomy', label: 'Legacy Taxonomy' }]
|
|
387
|
+
}, null, 2));
|
|
388
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
389
|
+
core.createWorkspace({ workspaceId: 'workspace-new', name: 'New Workspace' });
|
|
390
|
+
const state = core.getTaxonomyState('workspace-new');
|
|
391
|
+
expect((state.categories || []).map((category) => (typeof category === 'string' ? category : category.value))).toEqual(['default']);
|
|
392
|
+
expect((state.types || []).map((type) => type.value)).toEqual([
|
|
393
|
+
'task',
|
|
394
|
+
'deliverable',
|
|
395
|
+
'issue',
|
|
396
|
+
'idea',
|
|
397
|
+
'review'
|
|
398
|
+
]);
|
|
399
|
+
expect((state.priorities || []).map((priority) => priority.value)).toEqual([1, 2, 3]);
|
|
400
|
+
expect(state.taxonomies || []).toEqual([]);
|
|
401
|
+
core.close();
|
|
402
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
403
|
+
});
|
|
351
404
|
it('preserves existing first-class taxonomy sections when taxonomy state updates are partial', () => {
|
|
352
405
|
const projectRoot = makeTempProjectRoot();
|
|
353
406
|
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
package/dist/core/Taskforce.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { WorkspaceAssetStore } from '../storage/workspaceAssetStore.js';
|
|
|
3
3
|
import { type SyncEventInput } from './SyncReconciliationService.js';
|
|
4
4
|
import { type FirstClassTaxonomyDisplayLabels, type WorkspaceTaxonomyState } from '../shared/taxonomyState.js';
|
|
5
5
|
import { type AiProfileSurfaceType } from '../shared/aiProfileSurfaceType.js';
|
|
6
|
+
import type { TaskActor } from '../shared/taskActor.js';
|
|
7
|
+
export type { TaskActor } from '../shared/taskActor.js';
|
|
6
8
|
export type { WorkspaceDeletedAssetRecord, WorkspaceDeleteSummary } from './types.js';
|
|
7
9
|
import type { GlobalTaskforceSettings, UserGlobalSyncSettings, WorkspaceDeleteSummary } from './types.js';
|
|
8
10
|
import type { AnnotatedAttachmentAnnotation, AnnotatedAttachmentPayload, AnnotatedAttachmentSession, AnnotatedAttachmentSessionRecord } from '../annotatedAttachments/types.js';
|
|
@@ -73,16 +75,6 @@ export interface DeletedTaskRecord {
|
|
|
73
75
|
}
|
|
74
76
|
export type TaskStatus = 'task' | 'on-hold' | 'in-progress' | 'review' | 'done' | 'cancelled';
|
|
75
77
|
export type TaskAssignee = string;
|
|
76
|
-
export interface TaskActor {
|
|
77
|
-
id: string;
|
|
78
|
-
kind: 'human' | 'ai';
|
|
79
|
-
label: string;
|
|
80
|
-
username: string;
|
|
81
|
-
icon: string;
|
|
82
|
-
color: string;
|
|
83
|
-
isNamed: boolean;
|
|
84
|
-
meta?: Record<string, unknown>;
|
|
85
|
-
}
|
|
86
78
|
export interface TaskItem {
|
|
87
79
|
id: string;
|
|
88
80
|
referenceNumber?: number | null;
|
|
@@ -755,6 +747,9 @@ export interface TaskforceSyncCapable {
|
|
|
755
747
|
workspaceId?: string | null;
|
|
756
748
|
includeDeleted?: boolean;
|
|
757
749
|
}): AnnotatedAttachmentSessionRecord[];
|
|
750
|
+
listTaskEventsForSync(input: {
|
|
751
|
+
workspaceId?: string | null;
|
|
752
|
+
}): TaskEvent[];
|
|
758
753
|
upsertAiProfileForSync(profile: AiProfileRecord): AiProfileRecord;
|
|
759
754
|
replaceWorkspaceUsersForSync(input: {
|
|
760
755
|
workspaceId: string;
|
|
@@ -765,6 +760,7 @@ export interface TaskforceSyncCapable {
|
|
|
765
760
|
upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
|
|
766
761
|
upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
|
|
767
762
|
upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
|
|
763
|
+
upsertTaskEventForSync(event: TaskEvent): TaskEvent;
|
|
768
764
|
deleteDocumentReviewSessionForSync(input: {
|
|
769
765
|
workspaceId?: string | null;
|
|
770
766
|
sessionId: string;
|
|
@@ -847,6 +843,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
847
843
|
private areTaskEventValuesEqual;
|
|
848
844
|
private normalizeTaskEventValue;
|
|
849
845
|
private buildTaskUpdateChanges;
|
|
846
|
+
private filterAutosaveTaskEventChanges;
|
|
850
847
|
private normalizeTaxonomyToken;
|
|
851
848
|
private normalizeStatusValue;
|
|
852
849
|
private sanitizeAssignee;
|
|
@@ -893,16 +890,18 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
893
890
|
effectiveAt?: string | null;
|
|
894
891
|
effectiveUntil?: string | null;
|
|
895
892
|
billingMirrorPlanId?: string | null;
|
|
896
|
-
source: 'registration' | 'checkout-start' | 'checkout-confirm' | 'stripe-webhook' | 'backfill' | 'legacy-plan-mode' | 'admin' | 'system';
|
|
893
|
+
source: 'registration' | 'invite-accept' | 'checkout-start' | 'checkout-confirm' | 'stripe-webhook' | 'backfill' | 'legacy-plan-mode' | 'admin' | 'system';
|
|
897
894
|
updatedBy: string;
|
|
898
895
|
createdAt?: string | null;
|
|
899
896
|
updatedAt?: string | null;
|
|
900
897
|
}): import("./types.js").AccountEntitlementSnapshot;
|
|
901
898
|
private resolveWorkspaceLimitForUser;
|
|
902
899
|
private resolveRegistrationOnboardingOutcome;
|
|
900
|
+
private ensureDefaultOnboardingEntitlement;
|
|
903
901
|
createUserBillingRecord(userId: string, options?: {
|
|
904
902
|
entitlementState?: string;
|
|
905
903
|
planId?: string | null;
|
|
904
|
+
effectiveUntil?: string | null;
|
|
906
905
|
}): void;
|
|
907
906
|
getUserEntitlement(userId: string): {
|
|
908
907
|
entitlementState: string;
|
|
@@ -912,6 +911,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
912
911
|
getAccountAccessStatus(accountId: string): import("./types.js").AccountAccessStatus;
|
|
913
912
|
getEffectivePlanVersion(accountId: string): import("./types.js").PlanVersionSnapshot;
|
|
914
913
|
getAccountEntitlement(accountId: string): import("./types.js").AccountEntitlementSnapshot;
|
|
914
|
+
countAiProfileUsage(workspaceId: string): import("./types.js").SeatUsageSnapshot;
|
|
915
915
|
countWorkspaceSeatUsage(workspaceId: string, options?: {
|
|
916
916
|
includeInvited?: boolean;
|
|
917
917
|
}): import("./types.js").SeatUsageSnapshot;
|
|
@@ -969,6 +969,8 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
969
969
|
private resolveDefaultTypeValue;
|
|
970
970
|
private getLegacyTaxonomiesConfig;
|
|
971
971
|
private getLegacyPrioritiesConfig;
|
|
972
|
+
private readLegacyWorkspaceTaxonomyStateFromConfig;
|
|
973
|
+
private migrateLegacyWorkspaceTaxonomyStateIfNeeded;
|
|
972
974
|
private buildEmergencyWorkspaceTaxonomyState;
|
|
973
975
|
private getConfiguredDefaultStarterTaxonomyPackId;
|
|
974
976
|
private getResolvedStarterWorkspaceTaxonomyState;
|
|
@@ -1268,6 +1270,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1268
1270
|
upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
|
|
1269
1271
|
upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
|
|
1270
1272
|
upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
|
|
1273
|
+
upsertTaskEventForSync(event: TaskEvent): TaskEvent;
|
|
1271
1274
|
deleteDocumentReviewSessionForSync(input: {
|
|
1272
1275
|
workspaceId?: string | null;
|
|
1273
1276
|
sessionId: string;
|
|
@@ -1668,6 +1671,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1668
1671
|
updateWorkspaceUserRole(userId: string, workspaceId: string, role: AccessRole): boolean;
|
|
1669
1672
|
getTask(id: string, workspaceId?: string): TaskItem | null;
|
|
1670
1673
|
listTaskEvents(taskId: string, workspaceId?: string): TaskEvent[];
|
|
1674
|
+
listTaskEventsForSync(input: {
|
|
1675
|
+
workspaceId?: string | null;
|
|
1676
|
+
}): TaskEvent[];
|
|
1671
1677
|
getScheduleBoard(weekKey: string, showWeekends?: boolean, workspaceId?: string): ScheduleBoardResult;
|
|
1672
1678
|
updateTaskSchedule(id: string, input: {
|
|
1673
1679
|
scheduledDate: string | null;
|
|
@@ -1699,6 +1705,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
|
|
|
1699
1705
|
syncUpdatedAt?: string;
|
|
1700
1706
|
actorRef?: string;
|
|
1701
1707
|
skipTaskEvents?: boolean;
|
|
1708
|
+
saveSource?: 'manual' | 'autosave';
|
|
1702
1709
|
}): TaskItem | null;
|
|
1703
1710
|
addComment(id: string, text: string, author: string, workspaceId?: string, options?: {
|
|
1704
1711
|
persistBackup?: boolean;
|
package/dist/core/Taskforce.js
CHANGED
|
@@ -9,7 +9,7 @@ import { WorkspaceAssetStore } from '../storage/workspaceAssetStore.js';
|
|
|
9
9
|
import { AuthTokenService } from './AuthTokenService.js';
|
|
10
10
|
import { getAiProfileByTokenService, listAiProfilesService, mergeAiProfilesService, resolveAiProfileService, upsertAiProfileForSyncService, } from './AiProfileService.js';
|
|
11
11
|
import { syncCanonicalTaskAttachmentLinksService, } from './AttachmentLinkService.js';
|
|
12
|
-
import { addTaskEventService, buildTaskActivityService, listTaskEventsInternalService, replaceTaskCommentsService, replaceTaskEventsService, } from './TaskActivityService.js';
|
|
12
|
+
import { addTaskEventService, buildTaskActivityService, listTaskEventsInternalService, listWorkspaceTaskEventsService, replaceTaskCommentsService, replaceTaskEventsService, upsertTaskEventForSyncService, } from './TaskActivityService.js';
|
|
13
13
|
import { addDeletedTaskRecordService, getDeletedTaskService, listDeletedTasksService, mapDeletedTaskRowService, normalizeTaskSnapshotForRestoreService, pruneDeletedTasksService, purgeExpiredDeletedTasksService, } from './DeletedTaskLifecycleService.js';
|
|
14
14
|
import { applyWorkspaceSyncSnapshotService, deleteDocumentWatermarkService, getDocumentWatermarkService, listTasksForSyncService, listWorkspaceSyncDeletesSinceService, readPushIdempotencyService, recordSyncEventService, upsertDocumentWatermarkService, writePushIdempotencyService, } from './SyncReconciliationService.js';
|
|
15
15
|
import { getGlobalSettingsService, hasPersistedGlobalSettingsService, readGlobalConfigService, updateGlobalSettingsService, writeGlobalConfigService, } from './GlobalSettingsService.js';
|
|
@@ -79,7 +79,7 @@ const DEFAULT_PLAN_FEATURE_CATALOG = [
|
|
|
79
79
|
featureKey: DOCUMENT_CLOUD_STORAGE_FEATURE_KEY,
|
|
80
80
|
label: 'Document Cloud Storage',
|
|
81
81
|
description: 'Allow cloud document storage with an optional storage allowance in MB.',
|
|
82
|
-
allowedAccessModes: ['enabled', 'disabled'],
|
|
82
|
+
allowedAccessModes: ['enabled', 'limited', 'disabled'],
|
|
83
83
|
configTemplate: {
|
|
84
84
|
[DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY]: 1024
|
|
85
85
|
}
|
|
@@ -666,6 +666,9 @@ export class TaskforceCore {
|
|
|
666
666
|
}
|
|
667
667
|
return changes;
|
|
668
668
|
}
|
|
669
|
+
filterAutosaveTaskEventChanges(changes) {
|
|
670
|
+
return Object.fromEntries(Object.entries(changes).filter(([field]) => field !== 'title' && field !== 'description'));
|
|
671
|
+
}
|
|
669
672
|
normalizeTaxonomyToken(value) {
|
|
670
673
|
return String(value || '')
|
|
671
674
|
.trim()
|
|
@@ -1217,6 +1220,29 @@ export class TaskforceCore {
|
|
|
1217
1220
|
resolveRegistrationOnboardingOutcome(selectedPlanVersionIdRaw) {
|
|
1218
1221
|
return this.planEntitlementService.resolveRegistrationOnboardingOutcome(selectedPlanVersionIdRaw);
|
|
1219
1222
|
}
|
|
1223
|
+
ensureDefaultOnboardingEntitlement(accountIdRaw, options) {
|
|
1224
|
+
const accountId = String(accountIdRaw || '').trim();
|
|
1225
|
+
if (!accountId) {
|
|
1226
|
+
throw new TaskforceRuleError('accountId is required', 400, 'ACCOUNT_ID_REQUIRED');
|
|
1227
|
+
}
|
|
1228
|
+
if (this.hasAccountEntitlement(accountId)) {
|
|
1229
|
+
return this.getAccountEntitlement(accountId);
|
|
1230
|
+
}
|
|
1231
|
+
const now = options?.now || new Date().toISOString();
|
|
1232
|
+
const onboardingOutcome = this.resolveRegistrationOnboardingOutcome();
|
|
1233
|
+
this.transitionCanonicalCommercialState({
|
|
1234
|
+
accountId,
|
|
1235
|
+
planVersionId: onboardingOutcome.planVersionId,
|
|
1236
|
+
state: onboardingOutcome.commercialState,
|
|
1237
|
+
effectiveAt: now,
|
|
1238
|
+
billingMirrorPlanId: onboardingOutcome.planId,
|
|
1239
|
+
source: options?.source || 'registration',
|
|
1240
|
+
updatedBy: options?.updatedBy || 'registration',
|
|
1241
|
+
createdAt: now,
|
|
1242
|
+
updatedAt: now
|
|
1243
|
+
});
|
|
1244
|
+
return this.getAccountEntitlement(accountId);
|
|
1245
|
+
}
|
|
1220
1246
|
createUserBillingRecord(userId, options) {
|
|
1221
1247
|
return this.planEntitlementService.createUserBillingRecord(userId, options);
|
|
1222
1248
|
}
|
|
@@ -1235,6 +1261,9 @@ export class TaskforceCore {
|
|
|
1235
1261
|
getAccountEntitlement(accountId) {
|
|
1236
1262
|
return this.planEntitlementService.getAccountEntitlement(accountId);
|
|
1237
1263
|
}
|
|
1264
|
+
countAiProfileUsage(workspaceId) {
|
|
1265
|
+
return this.planEntitlementService.countAiProfileUsage(workspaceId);
|
|
1266
|
+
}
|
|
1238
1267
|
countWorkspaceSeatUsage(workspaceId, options = {}) {
|
|
1239
1268
|
return this.planEntitlementService.countWorkspaceSeatUsage(workspaceId, options);
|
|
1240
1269
|
}
|
|
@@ -2388,6 +2417,42 @@ export class TaskforceCore {
|
|
|
2388
2417
|
}
|
|
2389
2418
|
return [];
|
|
2390
2419
|
}
|
|
2420
|
+
readLegacyWorkspaceTaxonomyStateFromConfig() {
|
|
2421
|
+
const legacyCategories = this.getLegacyCategoriesConfig();
|
|
2422
|
+
const legacyTypes = this.getLegacyTypesConfig();
|
|
2423
|
+
const legacyPriorities = this.getLegacyPrioritiesConfig();
|
|
2424
|
+
const legacyTaxonomies = this.getLegacyTaxonomiesConfig();
|
|
2425
|
+
if (legacyCategories.length === 0
|
|
2426
|
+
&& legacyTypes.length === 0
|
|
2427
|
+
&& legacyPriorities.length === 0
|
|
2428
|
+
&& legacyTaxonomies.length === 0) {
|
|
2429
|
+
return null;
|
|
2430
|
+
}
|
|
2431
|
+
return normalizeWorkspaceTaxonomyStatePayload({
|
|
2432
|
+
categories: legacyCategories,
|
|
2433
|
+
types: legacyTypes,
|
|
2434
|
+
priorities: legacyPriorities,
|
|
2435
|
+
taxonomies: legacyTaxonomies
|
|
2436
|
+
});
|
|
2437
|
+
}
|
|
2438
|
+
migrateLegacyWorkspaceTaxonomyStateIfNeeded(workspaceId) {
|
|
2439
|
+
const normalizedWorkspaceId = this.normalizeWorkspaceId(workspaceId);
|
|
2440
|
+
if (normalizedWorkspaceId !== 'default') {
|
|
2441
|
+
return null;
|
|
2442
|
+
}
|
|
2443
|
+
const stored = this.readStoredWorkspaceTaxonomyState(normalizedWorkspaceId);
|
|
2444
|
+
if (Object.keys(stored.state).length > 0) {
|
|
2445
|
+
return stored;
|
|
2446
|
+
}
|
|
2447
|
+
const legacyState = this.readLegacyWorkspaceTaxonomyStateFromConfig();
|
|
2448
|
+
if (!legacyState)
|
|
2449
|
+
return null;
|
|
2450
|
+
const persisted = this.writeWorkspaceTaxonomyState(legacyState, normalizedWorkspaceId);
|
|
2451
|
+
return {
|
|
2452
|
+
state: persisted.state,
|
|
2453
|
+
updatedAt: persisted.updatedAt
|
|
2454
|
+
};
|
|
2455
|
+
}
|
|
2391
2456
|
buildEmergencyWorkspaceTaxonomyState() {
|
|
2392
2457
|
const emergencyPack = getEmergencyStarterTaxonomyLibraryPack();
|
|
2393
2458
|
return {
|
|
@@ -2428,17 +2493,13 @@ export class TaskforceCore {
|
|
|
2428
2493
|
}
|
|
2429
2494
|
getEffectiveWorkspaceTaxonomyState(workspaceId) {
|
|
2430
2495
|
const { state } = this.readStoredWorkspaceTaxonomyState(workspaceId);
|
|
2431
|
-
const legacyCategories = this.getLegacyCategoriesConfig();
|
|
2432
|
-
const legacyTypes = this.getLegacyTypesConfig();
|
|
2433
|
-
const legacyPriorities = this.getLegacyPrioritiesConfig();
|
|
2434
|
-
const legacyTaxonomies = this.getLegacyTaxonomiesConfig();
|
|
2435
2496
|
const starterState = this.getResolvedStarterWorkspaceTaxonomyState();
|
|
2436
2497
|
const emergencyState = this.buildEmergencyWorkspaceTaxonomyState();
|
|
2437
2498
|
return normalizeWorkspaceTaxonomyStatePayload({
|
|
2438
|
-
categories: state.categories ||
|
|
2439
|
-
types: state.types ||
|
|
2440
|
-
priorities: state.priorities ||
|
|
2441
|
-
taxonomies: state.taxonomies ||
|
|
2499
|
+
categories: state.categories || starterState.categories || emergencyState.categories,
|
|
2500
|
+
types: state.types || starterState.types || emergencyState.types,
|
|
2501
|
+
priorities: state.priorities || starterState.priorities || emergencyState.priorities,
|
|
2502
|
+
taxonomies: state.taxonomies || starterState.taxonomies || emergencyState.taxonomies
|
|
2442
2503
|
});
|
|
2443
2504
|
}
|
|
2444
2505
|
ensureWorkspaceTaxonomyStateSeeded(workspaceId) {
|
|
@@ -2447,6 +2508,10 @@ export class TaskforceCore {
|
|
|
2447
2508
|
if (Object.keys(stored.state).length > 0) {
|
|
2448
2509
|
return stored;
|
|
2449
2510
|
}
|
|
2511
|
+
const migratedLegacy = this.migrateLegacyWorkspaceTaxonomyStateIfNeeded(normalizedWorkspaceId);
|
|
2512
|
+
if (migratedLegacy) {
|
|
2513
|
+
return migratedLegacy;
|
|
2514
|
+
}
|
|
2450
2515
|
const seededState = this.getEffectiveWorkspaceTaxonomyState(normalizedWorkspaceId);
|
|
2451
2516
|
const persisted = this.writeWorkspaceTaxonomyState(seededState, normalizedWorkspaceId);
|
|
2452
2517
|
return {
|
|
@@ -4841,6 +4906,9 @@ export class TaskforceCore {
|
|
|
4841
4906
|
deletedAt: session.deletedAt,
|
|
4842
4907
|
});
|
|
4843
4908
|
}
|
|
4909
|
+
upsertTaskEventForSync(event) {
|
|
4910
|
+
return upsertTaskEventForSyncService(this.getTaskActivityServiceDeps(), event);
|
|
4911
|
+
}
|
|
4844
4912
|
deleteDocumentReviewSessionForSync(input) {
|
|
4845
4913
|
const deps = this.getDocumentReviewServiceDeps();
|
|
4846
4914
|
return deps.sessionStore.softDelete(input.sessionId, deps.normalizeWorkspaceId(input.workspaceId), input.deletedAt || undefined);
|
|
@@ -4883,7 +4951,8 @@ export class TaskforceCore {
|
|
|
4883
4951
|
aiProfileRowToRecord: (row) => this.aiProfileRowToRecord(row),
|
|
4884
4952
|
generateEntityId: (prefix) => this.generateEntityId(prefix),
|
|
4885
4953
|
issueProfileToken: () => `tfp_${randomBytes(24).toString('hex')}`,
|
|
4886
|
-
|
|
4954
|
+
countAiProfileUsage: (workspaceId) => this.countAiProfileUsage(workspaceId),
|
|
4955
|
+
createRuleError: (message, statusCode = 400, code = 'TASK_RULE_VIOLATION', details) => new TaskforceRuleError(message, statusCode, code, details),
|
|
4887
4956
|
};
|
|
4888
4957
|
}
|
|
4889
4958
|
resolveWorkspaceActor(workspaceId, actorRef) {
|
|
@@ -5795,6 +5864,11 @@ export class TaskforceCore {
|
|
|
5795
5864
|
updated_at = ?
|
|
5796
5865
|
WHERE tenant_id = ? AND id = ?
|
|
5797
5866
|
`).run(hashPassword(password), 'password', user.email, now, now, this.tenantId, consumed.userId);
|
|
5867
|
+
this.ensureDefaultOnboardingEntitlement(consumed.userId, {
|
|
5868
|
+
source: 'invite-accept',
|
|
5869
|
+
updatedBy: 'invite-accept',
|
|
5870
|
+
now
|
|
5871
|
+
});
|
|
5798
5872
|
return this.completeInviteWorkspaceActivation({
|
|
5799
5873
|
userId: consumed.userId,
|
|
5800
5874
|
workspaceId: inviteWorkspaceId
|
|
@@ -5953,6 +6027,10 @@ export class TaskforceCore {
|
|
|
5953
6027
|
const normalizedWorkspaceId = this.normalizeWorkspaceId(workspaceId);
|
|
5954
6028
|
return this.listTaskEventsInternal(taskId, normalizedWorkspaceId);
|
|
5955
6029
|
}
|
|
6030
|
+
listTaskEventsForSync(input) {
|
|
6031
|
+
const normalizedWorkspaceId = this.normalizeWorkspaceId(input.workspaceId || undefined);
|
|
6032
|
+
return listWorkspaceTaskEventsService(this.getTaskActivityServiceDeps(), normalizedWorkspaceId);
|
|
6033
|
+
}
|
|
5956
6034
|
getScheduleBoard(weekKey, showWeekends = false, workspaceId) {
|
|
5957
6035
|
const parsedWeek = this.parseIsoWeekKeyToDates(weekKey);
|
|
5958
6036
|
if (!parsedWeek) {
|
|
@@ -6510,7 +6588,10 @@ export class TaskforceCore {
|
|
|
6510
6588
|
if (!nextTask)
|
|
6511
6589
|
return null;
|
|
6512
6590
|
if (options?.skipTaskEvents !== true) {
|
|
6513
|
-
const
|
|
6591
|
+
const rawChanges = this.buildTaskUpdateChanges(existing, nextTask, patch);
|
|
6592
|
+
const changes = options?.saveSource === 'autosave'
|
|
6593
|
+
? this.filterAutosaveTaskEventChanges(rawChanges)
|
|
6594
|
+
: rawChanges;
|
|
6514
6595
|
if (Object.keys(changes).length > 0) {
|
|
6515
6596
|
let action = 'task-updated';
|
|
6516
6597
|
if (changes.status) {
|
|
@@ -20,19 +20,30 @@ function openCore(projectRoot) {
|
|
|
20
20
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
21
21
|
`).run('default', planVersionId, 'month', `free:${planVersionId}:month`, 'free', 1, 0, null, now, now);
|
|
22
22
|
};
|
|
23
|
-
core.upsertPlanCatalog({ planId: '
|
|
24
|
-
addFreeMapping('
|
|
25
|
-
core.upsertPlanCatalog({ planId: '
|
|
26
|
-
core.upsertPlanCatalog({ planId: 'collab', displayName: 'Collab' });
|
|
27
|
-
addFreeMapping('collab-v1');
|
|
28
|
-
core.upsertPlanCatalog({ planId: 'collab', displayName: 'Collab', status: 'active' });
|
|
23
|
+
core.upsertPlanCatalog({ planId: 'free', displayName: 'Free' });
|
|
24
|
+
addFreeMapping('free-v1');
|
|
25
|
+
core.upsertPlanCatalog({ planId: 'free', displayName: 'Free', status: 'active' });
|
|
29
26
|
core.updatePlanVersion({
|
|
30
|
-
planId: '
|
|
27
|
+
planId: 'free',
|
|
28
|
+
versionNumber: 1,
|
|
29
|
+
seatLimit: 1
|
|
30
|
+
});
|
|
31
|
+
core.updatePlanVersionFeatures({
|
|
32
|
+
planVersionId: 'free-v1',
|
|
33
|
+
features: [
|
|
34
|
+
{ featureKey: 'workspace.switching', access: 'enabled' }
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
core.upsertPlanCatalog({ planId: 'team-5', displayName: 'Team 5' });
|
|
38
|
+
addFreeMapping('team-5-v1');
|
|
39
|
+
core.upsertPlanCatalog({ planId: 'team-5', displayName: 'Team 5', status: 'active' });
|
|
40
|
+
core.updatePlanVersion({
|
|
41
|
+
planId: 'team-5',
|
|
31
42
|
versionNumber: 1,
|
|
32
43
|
seatLimit: 5
|
|
33
44
|
});
|
|
34
45
|
core.updatePlanVersionFeatures({
|
|
35
|
-
planVersionId: '
|
|
46
|
+
planVersionId: 'team-5-v1',
|
|
36
47
|
features: [
|
|
37
48
|
{ featureKey: 'collaboration.invites', access: 'enabled' },
|
|
38
49
|
{ featureKey: 'collaboration.team_management', access: 'enabled' }
|
|
@@ -214,4 +225,58 @@ describe('TaskforceCore account-level plan mode and invite revoke', () => {
|
|
|
214
225
|
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
215
226
|
}
|
|
216
227
|
});
|
|
228
|
+
it('grants the default onboarding entitlement to newly accepted invited accounts', () => {
|
|
229
|
+
const projectRoot = makeProjectRoot();
|
|
230
|
+
const core = openCore(projectRoot);
|
|
231
|
+
try {
|
|
232
|
+
core.updateGlobalSettings({
|
|
233
|
+
billing: {
|
|
234
|
+
onboardingPolicy: {
|
|
235
|
+
mode: 'auto_grant_free',
|
|
236
|
+
planVersionId: 'free-v1'
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
core.createWorkspace({ workspaceId: 'workspace-invite', name: 'Invite Workspace' });
|
|
241
|
+
core.ensureBootstrapUserAccess({
|
|
242
|
+
userId: 'owner-user',
|
|
243
|
+
workspaceId: 'workspace-invite',
|
|
244
|
+
role: 'owner',
|
|
245
|
+
email: 'owner@example.com'
|
|
246
|
+
});
|
|
247
|
+
core.setUserAccountPlanMode('owner-user', 'team');
|
|
248
|
+
core.ensureBootstrapUserAccess({
|
|
249
|
+
userId: 'invited-user',
|
|
250
|
+
workspaceId: 'workspace-invite',
|
|
251
|
+
role: 'member',
|
|
252
|
+
email: 'invited@example.com'
|
|
253
|
+
});
|
|
254
|
+
core.setWorkspaceUserDisabled('invited-user', 'workspace-invite', true);
|
|
255
|
+
const db = core.db;
|
|
256
|
+
db.prepare(`
|
|
257
|
+
UPDATE workspace_memberships
|
|
258
|
+
SET status = 'invited'
|
|
259
|
+
WHERE tenant_id = ? AND user_id = ? AND workspace_id = ?
|
|
260
|
+
`).run('default', 'invited-user', 'workspace-invite');
|
|
261
|
+
const invite = core.requestInviteAcceptance({ userId: 'invited-user', workspaceId: 'workspace-invite' });
|
|
262
|
+
const accepted = core.acceptInviteWithToken({
|
|
263
|
+
token: String(invite.token),
|
|
264
|
+
password: 'Password123!'
|
|
265
|
+
});
|
|
266
|
+
expect(accepted.workspaceId).toBe('workspace-invite');
|
|
267
|
+
expect(core.hasAccountEntitlement('invited-user')).toBe(true);
|
|
268
|
+
expect(core.getAccountEntitlement('invited-user')).toEqual(expect.objectContaining({
|
|
269
|
+
planVersionId: 'free-v1',
|
|
270
|
+
state: 'active'
|
|
271
|
+
}));
|
|
272
|
+
expect(core.getAccountAccessStatus('invited-user')).toEqual(expect.objectContaining({
|
|
273
|
+
gate: 'ok',
|
|
274
|
+
canAccessApp: true
|
|
275
|
+
}));
|
|
276
|
+
}
|
|
277
|
+
finally {
|
|
278
|
+
core.close();
|
|
279
|
+
fs.rmSync(projectRoot, { recursive: true, force: true });
|
|
280
|
+
}
|
|
281
|
+
});
|
|
217
282
|
});
|
package/dist/core/shared.d.ts
CHANGED
|
@@ -17,8 +17,10 @@
|
|
|
17
17
|
import type { McpAccessTokenScope, PlanFeatureCatalogItem } from './types.js';
|
|
18
18
|
export declare const DOCUMENT_CLOUD_STORAGE_FEATURE_KEY = "context.uploads";
|
|
19
19
|
export declare const WORKSPACES_FEATURE_KEY = "workspace.switching";
|
|
20
|
+
export declare const AI_PROFILES_FEATURE_KEY = "collaboration.ai_profiles";
|
|
20
21
|
export declare const DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY = "storageLimitMb";
|
|
21
22
|
export declare const WORKSPACES_LIMIT_CONFIG_KEY = "maxWorkspaces";
|
|
23
|
+
export declare const AI_PROFILES_LIMIT_CONFIG_KEY = "maxAiProfiles";
|
|
22
24
|
export declare const MCP_ACCESS_TOKEN_MAX_ACTIVE_PER_USER_WORKSPACE = 10;
|
|
23
25
|
export declare const MCP_ACCESS_TOKEN_DEFAULT_PAGE_SIZE = 20;
|
|
24
26
|
export declare const MCP_ACCESS_TOKEN_MAX_PAGE_SIZE = 100;
|
package/dist/core/shared.js
CHANGED
|
@@ -18,8 +18,10 @@ import { createHash, pbkdf2Sync, randomBytes, timingSafeEqual } from 'crypto';
|
|
|
18
18
|
// === SECTION: Constants ===
|
|
19
19
|
export const DOCUMENT_CLOUD_STORAGE_FEATURE_KEY = 'context.uploads';
|
|
20
20
|
export const WORKSPACES_FEATURE_KEY = 'workspace.switching';
|
|
21
|
+
export const AI_PROFILES_FEATURE_KEY = 'collaboration.ai_profiles';
|
|
21
22
|
export const DOCUMENT_CLOUD_STORAGE_LIMIT_CONFIG_KEY = 'storageLimitMb';
|
|
22
23
|
export const WORKSPACES_LIMIT_CONFIG_KEY = 'maxWorkspaces';
|
|
24
|
+
export const AI_PROFILES_LIMIT_CONFIG_KEY = 'maxAiProfiles';
|
|
23
25
|
export const MCP_ACCESS_TOKEN_MAX_ACTIVE_PER_USER_WORKSPACE = 10;
|
|
24
26
|
export const MCP_ACCESS_TOKEN_DEFAULT_PAGE_SIZE = 20;
|
|
25
27
|
export const MCP_ACCESS_TOKEN_MAX_PAGE_SIZE = 100;
|
|
@@ -50,6 +52,15 @@ export const DEFAULT_PLAN_FEATURE_CATALOG = [
|
|
|
50
52
|
configTemplate: {
|
|
51
53
|
[WORKSPACES_LIMIT_CONFIG_KEY]: 1
|
|
52
54
|
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
featureKey: AI_PROFILES_FEATURE_KEY,
|
|
58
|
+
label: 'AI Profiles',
|
|
59
|
+
description: 'Allow registered AI collaborator profiles with an optional per-workspace limit.',
|
|
60
|
+
allowedAccessModes: ['enabled', 'limited', 'disabled'],
|
|
61
|
+
configTemplate: {
|
|
62
|
+
[AI_PROFILES_LIMIT_CONFIG_KEY]: 1
|
|
63
|
+
}
|
|
53
64
|
}
|
|
54
65
|
];
|
|
55
66
|
export const PLAN_FEATURE_DEPENDENCIES = Object.freeze(DEFAULT_PLAN_FEATURE_CATALOG.reduce((acc, feature) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TaskActor } from '../
|
|
1
|
+
import type { TaskActor } from '../shared/taskActor.js';
|
|
2
2
|
import type { WorkspaceAssetStore } from '../storage/workspaceAssetStore.js';
|
|
3
3
|
import { DocumentReviewCommentStore } from './DocumentReviewCommentStore.js';
|
|
4
4
|
import { DocumentReviewSessionStore } from './DocumentReviewSessionStore.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TaskActor } from '../
|
|
1
|
+
import type { TaskActor } from '../shared/taskActor.js';
|
|
2
2
|
export type DocumentReviewSessionStatus = 'open' | 'resolved';
|
|
3
3
|
export type DocumentReviewAnchorKind = 'document' | 'quote' | 'line-range';
|
|
4
4
|
export interface DocumentReviewDocumentAnchor {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type MutableRefObject } from 'react';
|
|
2
|
+
import { createDefaultAssigneeOptions } from '../../utils/assignees';
|
|
3
|
+
export type BootstrapPhase = 'idle' | 'auth' | 'workspace' | 'config' | 'ready' | 'stalled';
|
|
4
|
+
interface UseTaskforceAuthBootstrapArgs {
|
|
5
|
+
runtimeConfigReady: boolean;
|
|
6
|
+
shouldProbeCloudAuth: boolean;
|
|
7
|
+
authSessionResolved: boolean;
|
|
8
|
+
resolveCloudAuthUrl: (path: string) => string;
|
|
9
|
+
authOnlyCloudMode: boolean;
|
|
10
|
+
authRequiredError: string;
|
|
11
|
+
runtimeMode: 'local' | 'cloud';
|
|
12
|
+
workspaceSelectionScope: string;
|
|
13
|
+
markBootstrapPhase: (phase: Exclude<BootstrapPhase, 'stalled'>) => void;
|
|
14
|
+
markBootstrapStalled: (message: string) => void;
|
|
15
|
+
setRuntimeMode: (mode: 'local' | 'cloud') => void;
|
|
16
|
+
setAuthRequiredForApi: (value: boolean) => void;
|
|
17
|
+
setIsAuthenticated: (value: boolean) => void;
|
|
18
|
+
setAuthUserId: (value: string) => void;
|
|
19
|
+
setAuthWorkspaceId: (value: string) => void;
|
|
20
|
+
setAuthUserEmail: (value: string) => void;
|
|
21
|
+
setAuthUserDisplayName: (value: string) => void;
|
|
22
|
+
setAuthUserAvatarUrl: (value: string) => void;
|
|
23
|
+
setUserGlobalSyncStatus: (value: 'idle' | 'disconnected') => void;
|
|
24
|
+
setUserGlobalSyncError: (value: string | null) => void;
|
|
25
|
+
setHasBetaAccess: (value: boolean) => void;
|
|
26
|
+
setAvailableWorkspaces: (value: any[]) => void;
|
|
27
|
+
setHydratedWorkspaceRole: (value: any) => void;
|
|
28
|
+
setAssigneeOptions: (value: ReturnType<typeof createDefaultAssigneeOptions>) => void;
|
|
29
|
+
setAuthBlocked: (value: boolean) => void;
|
|
30
|
+
setAuthSessionResolved: (value: boolean) => void;
|
|
31
|
+
setError: (value: string | ((prev: string) => string)) => void;
|
|
32
|
+
applyResolvedWorkspaceId: (workspaceId: string, options?: {
|
|
33
|
+
preserveNonDefaultDefault?: boolean;
|
|
34
|
+
}) => void;
|
|
35
|
+
readPersistedWorkspaceId: (scope: string) => string;
|
|
36
|
+
authSessionRequestRef: MutableRefObject<Promise<boolean> | null>;
|
|
37
|
+
authSessionEpochRef: MutableRefObject<number>;
|
|
38
|
+
authSessionLastCheckedAtRef: MutableRefObject<number>;
|
|
39
|
+
authSessionLastResultRef: MutableRefObject<boolean>;
|
|
40
|
+
isLoopbackHost: boolean;
|
|
41
|
+
setAuthStateReadyRefs: (authenticated: boolean, authSessionResolved: boolean, authRequiredForApi: boolean) => void;
|
|
42
|
+
}
|
|
43
|
+
export declare function useTaskforceAuthBootstrap({ runtimeConfigReady, shouldProbeCloudAuth, authSessionResolved, resolveCloudAuthUrl, authOnlyCloudMode, authRequiredError, runtimeMode, workspaceSelectionScope, markBootstrapPhase, markBootstrapStalled, setRuntimeMode, setAuthRequiredForApi, setIsAuthenticated, setAuthUserId, setAuthWorkspaceId, setAuthUserEmail, setAuthUserDisplayName, setAuthUserAvatarUrl, setUserGlobalSyncStatus, setUserGlobalSyncError, setHasBetaAccess, setAvailableWorkspaces, setHydratedWorkspaceRole, setAssigneeOptions, setAuthBlocked, setAuthSessionResolved, setError, applyResolvedWorkspaceId, readPersistedWorkspaceId, authSessionRequestRef, authSessionEpochRef, authSessionLastCheckedAtRef, authSessionLastResultRef, isLoopbackHost, setAuthStateReadyRefs }: UseTaskforceAuthBootstrapArgs): {
|
|
44
|
+
checkAuthSession: (options?: {
|
|
45
|
+
force?: boolean;
|
|
46
|
+
}) => Promise<boolean>;
|
|
47
|
+
};
|
|
48
|
+
export {};
|