@taskforcehq/taskforce 0.3.302 → 0.3.304

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.
Files changed (192) hide show
  1. package/dist/Taskforce.module.css +113 -5
  2. package/dist/TaskforceCore.js +560 -208
  3. package/dist/TaskforceCore.test.js +1833 -91
  4. package/dist/annotatedAttachments/service.d.ts +1 -1
  5. package/dist/annotatedAttachments/types.d.ts +1 -1
  6. package/dist/components/features/AgentsModule.js +1 -1
  7. package/dist/components/features/AgentsModule.test.js +1 -1
  8. package/dist/components/features/TaskSettings.js +58 -38
  9. package/dist/components/features/TaskSettings.test.js +139 -40
  10. package/dist/components/task/TaskActionHeader.d.ts +2 -1
  11. package/dist/components/task/TaskActionHeader.js +3 -3
  12. package/dist/components/task/TaskActionHeader.test.js +8 -0
  13. package/dist/components/task/TaskCard.js +16 -1
  14. package/dist/components/task/TaskCard.test.js +31 -0
  15. package/dist/components/task/TaskForm.d.ts +2 -1
  16. package/dist/components/task/TaskForm.js +22 -4
  17. package/dist/components/task/TaskForm.test.js +46 -0
  18. package/dist/components/task/TaskKanban.d.ts +1 -1
  19. package/dist/components/task/TaskKanban.js +31 -160
  20. package/dist/components/task/TaskKanban.test.js +17 -0
  21. package/dist/components/task/TaskStatusActions.d.ts +6 -1
  22. package/dist/components/task/TaskStatusActions.js +8 -3
  23. package/dist/components/task/TaskStatusActions.test.js +9 -0
  24. package/dist/components/task/taskKanbanDropRules.d.ts +58 -0
  25. package/dist/components/task/taskKanbanDropRules.js +187 -0
  26. package/dist/components/task/taskKanbanDropRules.test.d.ts +1 -0
  27. package/dist/components/task/taskKanbanDropRules.test.js +114 -0
  28. package/dist/components/ui/Modal.d.ts +1 -1
  29. package/dist/components/ui/Modal.js +1 -0
  30. package/dist/components/views/AppShellHeader.js +5 -1
  31. package/dist/components/views/AppShellHeader.test.js +4 -0
  32. package/dist/components/views/PlanComparisonPage.d.ts +3 -2
  33. package/dist/components/views/PlanComparisonPage.js +4 -2
  34. package/dist/components/views/PlanComparisonPage.test.js +4 -0
  35. package/dist/components/views/PlansPage.d.ts +7 -1
  36. package/dist/components/views/PlansPage.js +139 -53
  37. package/dist/components/views/PlansPage.test.d.ts +1 -0
  38. package/dist/components/views/PlansPage.test.js +157 -0
  39. package/dist/components/views/StandaloneLayout.d.ts +1 -0
  40. package/dist/components/views/StandaloneLayout.js +216 -186
  41. package/dist/components/views/WidgetView.js +11 -2
  42. package/dist/components/views/standalone/modals/AccountHubModal.d.ts +8 -3
  43. package/dist/components/views/standalone/modals/AccountHubModal.js +16 -2
  44. package/dist/components/views/standalone/modals/AccountHubModal.test.d.ts +1 -0
  45. package/dist/components/views/standalone/modals/AccountHubModal.test.js +26 -0
  46. package/dist/components/views/standalone/modals/SyncStatusModal.js +1 -1
  47. package/dist/core/DeletedTaskLifecycleService.d.ts +2 -1
  48. package/dist/core/EntitlementsPolicy.test.js +2 -2
  49. package/dist/core/GlobalSettingsService.js +78 -18
  50. package/dist/core/PlanEntitlementService.d.ts +31 -5
  51. package/dist/core/PlanEntitlementService.js +350 -222
  52. package/dist/core/SignupMonetizationSettings.test.js +208 -49
  53. package/dist/core/SystemAdmin.test.js +186 -96
  54. package/dist/core/TaskActivityService.d.ts +4 -1
  55. package/dist/core/TaskActivityService.js +45 -0
  56. package/dist/core/TaskAuditTimeline.test.js +52 -1
  57. package/dist/core/Taskforce.d.ts +65 -20
  58. package/dist/core/Taskforce.js +261 -51
  59. package/dist/core/Taskforce.mcpAuth.test.js +0 -2
  60. package/dist/core/UserProfileAvatarDrafts.test.js +12 -3
  61. package/dist/core/WorkspacePlanMode.test.js +65 -0
  62. package/dist/core/types.d.ts +11 -12
  63. package/dist/documentReviews/service.d.ts +1 -1
  64. package/dist/documentReviews/types.d.ts +1 -1
  65. package/dist/hooks/auth/useTaskforceAuthBootstrap.d.ts +48 -0
  66. package/dist/hooks/auth/useTaskforceAuthBootstrap.js +219 -0
  67. package/dist/hooks/sync/auth.d.ts +37 -0
  68. package/dist/hooks/sync/auth.js +61 -0
  69. package/dist/hooks/sync/bootstrap.d.ts +34 -0
  70. package/dist/hooks/sync/bootstrap.js +52 -0
  71. package/dist/hooks/sync/orchestratorShared.d.ts +36 -0
  72. package/dist/hooks/sync/orchestratorShared.js +209 -0
  73. package/dist/hooks/sync/orchestratorShared.test.d.ts +1 -0
  74. package/dist/hooks/sync/orchestratorShared.test.js +49 -0
  75. package/dist/hooks/sync/realtime.d.ts +25 -0
  76. package/dist/hooks/sync/realtime.js +60 -0
  77. package/dist/hooks/sync/recovery.d.ts +69 -0
  78. package/dist/hooks/sync/recovery.js +118 -0
  79. package/dist/hooks/sync/transfers.d.ts +122 -0
  80. package/dist/hooks/sync/transfers.js +431 -0
  81. package/dist/hooks/sync/useDataVersionRefresh.d.ts +16 -0
  82. package/dist/hooks/sync/useDataVersionRefresh.js +73 -0
  83. package/dist/hooks/ui/useResourceExport.d.ts +3 -1
  84. package/dist/hooks/ui/useResourceExport.js +5 -2
  85. package/dist/hooks/ui/useWorkflowTemplates.js +11 -6
  86. package/dist/hooks/useRealtimeSync.js +2 -1
  87. package/dist/hooks/useSyncOrchestrator.aiProfiles.test.js +8 -0
  88. package/dist/hooks/useSyncOrchestrator.context-assets.test.d.ts +1 -0
  89. package/dist/hooks/useSyncOrchestrator.context-assets.test.js +228 -0
  90. package/dist/hooks/useSyncOrchestrator.d.ts +5 -4
  91. package/dist/hooks/useSyncOrchestrator.js +315 -860
  92. package/dist/hooks/useSyncOrchestrator.retry-closure.test.js +665 -8
  93. package/dist/hooks/useTaskMutations.js +45 -6
  94. package/dist/hooks/useTaskMutations.test.js +147 -0
  95. package/dist/hooks/useTaskforce.d.ts +11 -2
  96. package/dist/hooks/useTaskforce.js +290 -812
  97. package/dist/hooks/useWorkspaceSyncController.d.ts +1 -0
  98. package/dist/hooks/useWorkspaceSyncController.js +22 -10
  99. package/dist/hooks/workspace/useTaskforceApiRouting.test.js +17 -0
  100. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.d.ts +166 -0
  101. package/dist/hooks/workspace/useTaskforceWorkspaceBootstrap.js +434 -0
  102. package/dist/hooks/workspace/workspaceLocalState.d.ts +19 -0
  103. package/dist/hooks/workspace/workspaceLocalState.js +100 -0
  104. package/dist/hooks/workspace/workspaceLocalState.test.d.ts +1 -0
  105. package/dist/hooks/workspace/workspaceLocalState.test.js +59 -0
  106. package/dist/localization/locales/en-US.js +2 -2
  107. package/dist/mcp/canonicalAssetHelpers.d.ts +70 -0
  108. package/dist/mcp/canonicalAssetHelpers.js +259 -0
  109. package/dist/mcp/clientIntegrations.d.ts +12 -1
  110. package/dist/mcp/clientIntegrations.js +161 -6
  111. package/dist/mcp/clientIntegrations.test.js +76 -4
  112. package/dist/mcp/documentHelpers.d.ts +100 -0
  113. package/dist/mcp/documentHelpers.js +161 -0
  114. package/dist/mcp/runtime.js +264 -505
  115. package/dist/mcp/runtime.test.js +353 -89
  116. package/dist/mcp/taskAttachmentHelpers.d.ts +41 -0
  117. package/dist/mcp/taskAttachmentHelpers.js +60 -0
  118. package/dist/mcp/taskAttachmentTypes.d.ts +37 -0
  119. package/dist/mcp/taskAttachmentTypes.js +1 -0
  120. package/dist/migrations/billingSchemaParity.test.js +3 -0
  121. package/dist/migrations/taskSchemaMigrations.js +15 -0
  122. package/dist/plugins/vite.js +1 -1
  123. package/dist/runtime/appGateDefinitions.d.ts +1 -1
  124. package/dist/runtime/appGateDefinitions.js +1 -1
  125. package/dist/server/index.cookieProxy.test.js +1 -0
  126. package/dist/server/index.d.ts +1 -0
  127. package/dist/server/index.js +48 -3
  128. package/dist/server/index.test.js +14 -2
  129. package/dist/server/mockStripe.d.ts +1 -0
  130. package/dist/server/mockStripe.js +2 -0
  131. package/dist/server/routes/admin.js +91 -40
  132. package/dist/server/routes/auth.d.ts +1 -0
  133. package/dist/server/routes/auth.js +231 -55
  134. package/dist/server/routes/billing.js +473 -39
  135. package/dist/server/routes/billing.test.js +972 -37
  136. package/dist/server/routes/shared.d.ts +30 -0
  137. package/dist/server/routes/shared.js +31 -3
  138. package/dist/server/routes/sync.integration.test.js +180 -0
  139. package/dist/server/routes/sync.js +125 -242
  140. package/dist/server/routes/tasks.js +49 -7
  141. package/dist/server/routes.js +11 -22
  142. package/dist/server/routes.test.js +530 -81
  143. package/dist/shared/taskActor.d.ts +10 -0
  144. package/dist/shared/taskActor.js +1 -0
  145. package/dist/sync/cloudSyncApi.d.ts +1 -0
  146. package/dist/sync/collaborationSyncPayload.js +4 -0
  147. package/dist/sync/collaborationSyncPayload.test.js +8 -0
  148. package/dist/sync/collaborationSyncState.d.ts +3 -1
  149. package/dist/sync/collaborationSyncState.js +19 -0
  150. package/dist/sync/contentSyncState.d.ts +10 -0
  151. package/dist/sync/contentSyncState.js +277 -14
  152. package/dist/sync/syncApplyHandlers.d.ts +87 -1
  153. package/dist/sync/syncApplyHandlers.js +370 -8
  154. package/dist/sync/syncApplyHandlers.test.d.ts +1 -0
  155. package/dist/sync/syncApplyHandlers.test.js +377 -0
  156. package/dist/sync/syncService.d.ts +9 -1
  157. package/dist/sync/syncService.js +57 -10
  158. package/dist/sync/syncService.test.js +48 -0
  159. package/dist/sync/workspacePullFeed.d.ts +11 -0
  160. package/dist/sync/workspacePullFeed.js +123 -68
  161. package/dist/sync/workspacePullFeed.test.js +180 -0
  162. package/dist/sync/workspaceSyncModel.d.ts +22 -1
  163. package/dist/sync/workspaceSyncModel.js +65 -0
  164. package/dist/sync/workspaceSyncModel.test.js +119 -0
  165. package/dist/types.d.ts +2 -10
  166. package/dist/ui/assets/AgentsModule-BLWVbuKP.js +1 -0
  167. package/dist/ui/assets/{AnnotatedAttachmentWorkspace-Dvi02Y7q.js → AnnotatedAttachmentWorkspace-BlS-cqnl.js} +1 -1
  168. package/dist/ui/assets/{DocumentWorkspace-iys3zfca.js → DocumentWorkspace-BH_6DF6x.js} +1 -1
  169. package/dist/ui/assets/{InitiativesModule-DJvLJI3A.js → InitiativesModule-BjR6iBf9.js} +1 -1
  170. package/dist/ui/assets/{PlansPage-BlVC_lRq.css → PlansPage-C2dd2n1X.css} +1 -1
  171. package/dist/ui/assets/PlansPage-CSDQ4sLa.js +1 -0
  172. package/dist/ui/assets/TaskSettings-CEDy34Jo.js +9 -0
  173. package/dist/ui/assets/{WorkflowsModule-BguHeQaV.js → WorkflowsModule-DnFqdUME.js} +1 -1
  174. package/dist/ui/assets/index-DXUdtH1B.js +6 -0
  175. package/dist/ui/assets/index-Ii0B0rTO.css +1 -0
  176. package/dist/ui/assets/{vendor-icons-C8EED3Oh.js → vendor-icons-I7ZwG1z_.js} +1 -1
  177. package/dist/ui/index.html +4 -4
  178. package/dist/utils/accountProfileSummaryCache.d.ts +31 -0
  179. package/dist/utils/accountProfileSummaryCache.js +97 -0
  180. package/dist/utils/accountProfileSummaryCache.test.d.ts +1 -0
  181. package/dist/utils/accountProfileSummaryCache.test.js +63 -0
  182. package/dist/utils/taskActivity.js +4 -0
  183. package/dist/utils/taskActivity.test.js +25 -1
  184. package/package.json +5 -3
  185. package/scripts/playwright-auth.sh +4 -0
  186. package/dist/ui/assets/AgentsModule-JG5jc3he.js +0 -1
  187. package/dist/ui/assets/PlansPage-BMPlpFpw.js +0 -1
  188. package/dist/ui/assets/TaskSettings-Bqd4cCzW.js +0 -8
  189. package/dist/ui/assets/index-MXeWoebC.css +0 -1
  190. package/dist/ui/assets/index-YJ4k5QNa.js +0 -6
  191. package/dist/utils/billingStatusCache.d.ts +0 -21
  192. package/dist/utils/billingStatusCache.js +0 -70
@@ -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;
@@ -343,14 +335,10 @@ export interface InitiativeTemplate {
343
335
  milestones: InitiativeTemplateMilestone[];
344
336
  }
345
337
  type WorkspaceSyncSettingsPayload = Record<string, Record<string, unknown>>;
346
- type SignupMonetizationStrategy = 'auto_assign_default' | 'plan_selection_required';
347
- interface SignupMonetizationSettings {
348
- strategy: SignupMonetizationStrategy;
349
- defaultSignupPlanVersionId: string | null;
350
- }
351
338
  type AccessRole = 'owner' | 'admin' | 'member' | 'read-only';
352
339
  export type SystemRole = 'system_admin' | 'user';
353
340
  type PermissionMode = 'read-only' | 'read-write';
341
+ type AuthTokenPurpose = 'email_verification' | 'password_reset' | 'invite_accept';
354
342
  export type McpAccessTokenScope = 'tasks:read' | 'tasks:write' | 'workspace:read';
355
343
  type McpAccessTokenStatus = 'active' | 'revoked' | 'expired';
356
344
  export type McpOAuthProvider = 'chatgpt' | 'claude';
@@ -453,6 +441,24 @@ interface SystemUserRecord {
453
441
  updatedAt?: string | null;
454
442
  emailVerifiedAt?: string | null;
455
443
  }
444
+ export interface PurgedSystemUserSummary {
445
+ targetUserId: string;
446
+ email: string;
447
+ unassignedTaskCount: number;
448
+ clearedInitiativeOwnerCount: number;
449
+ clearedWorkstreamOwnerCount: number;
450
+ deletedWorkspaceMembershipCount: number;
451
+ deletedAuthTokenCount: number;
452
+ deletedAvatarDraftCount: number;
453
+ deletedMcpAccessTokenCount: number;
454
+ deletedMcpOauthAuthCodeCount: number;
455
+ deletedMcpOauthConnectorGrantCount: number;
456
+ deletedUiStateCount: number;
457
+ deletedUserPreferenceCount: number;
458
+ deletedEntitlementCount: number;
459
+ deletedUserBillingCount: number;
460
+ deletedUserCount: number;
461
+ }
456
462
  export type SetupState = 'present' | 'missing' | 'unreadable';
457
463
  export type RuntimeMode = 'local' | 'cloud';
458
464
  export type WorkspaceMode = 'core' | 'operations';
@@ -529,7 +535,7 @@ interface McpAuditLogRecord {
529
535
  reasonCode: string | null;
530
536
  details: Record<string, unknown>;
531
537
  }
532
- export type EntitlementState = 'active' | 'trialing' | 'grace' | 'suspended' | 'canceled';
538
+ export type EntitlementState = 'pending_plan_selection' | 'checkout_pending' | 'active' | 'trialing' | 'grace' | 'suspended' | 'canceled';
533
539
  export type PlanFeatureAccess = 'enabled' | 'disabled' | 'limited';
534
540
  export interface PlanFeatureSnapshot {
535
541
  featureKey: string;
@@ -591,6 +597,11 @@ interface PasswordAuthResult {
591
597
  };
592
598
  code?: 'INVALID_CREDENTIALS' | 'EMAIL_NOT_VERIFIED';
593
599
  }
600
+ interface AuthTokenInspection {
601
+ state: 'valid' | 'expired' | 'used' | 'missing' | 'revoked';
602
+ userId?: string;
603
+ workspaceId?: string;
604
+ }
594
605
  export interface McpAccessTokenRecord {
595
606
  id: string;
596
607
  workspaceId: string;
@@ -736,6 +747,9 @@ export interface TaskforceSyncCapable {
736
747
  workspaceId?: string | null;
737
748
  includeDeleted?: boolean;
738
749
  }): AnnotatedAttachmentSessionRecord[];
750
+ listTaskEventsForSync(input: {
751
+ workspaceId?: string | null;
752
+ }): TaskEvent[];
739
753
  upsertAiProfileForSync(profile: AiProfileRecord): AiProfileRecord;
740
754
  replaceWorkspaceUsersForSync(input: {
741
755
  workspaceId: string;
@@ -746,6 +760,7 @@ export interface TaskforceSyncCapable {
746
760
  upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
747
761
  upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
748
762
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
763
+ upsertTaskEventForSync(event: TaskEvent): TaskEvent;
749
764
  deleteDocumentReviewSessionForSync(input: {
750
765
  workspaceId?: string | null;
751
766
  sessionId: string;
@@ -828,6 +843,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
828
843
  private areTaskEventValuesEqual;
829
844
  private normalizeTaskEventValue;
830
845
  private buildTaskUpdateChanges;
846
+ private filterAutosaveTaskEventChanges;
831
847
  private normalizeTaxonomyToken;
832
848
  private normalizeStatusValue;
833
849
  private sanitizeAssignee;
@@ -867,11 +883,25 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
867
883
  getWorkspaceAssetStore(): WorkspaceAssetStore;
868
884
  private normalizeEntitlementState;
869
885
  private upsertCanonicalEntitlementRecord;
886
+ transitionCanonicalCommercialState(input: {
887
+ accountId: string;
888
+ planVersionId?: string | null;
889
+ state: EntitlementState;
890
+ effectiveAt?: string | null;
891
+ effectiveUntil?: string | null;
892
+ billingMirrorPlanId?: string | null;
893
+ source: 'registration' | 'invite-accept' | 'checkout-start' | 'checkout-confirm' | 'stripe-webhook' | 'backfill' | 'legacy-plan-mode' | 'admin' | 'system';
894
+ updatedBy: string;
895
+ createdAt?: string | null;
896
+ updatedAt?: string | null;
897
+ }): import("./types.js").AccountEntitlementSnapshot;
870
898
  private resolveWorkspaceLimitForUser;
871
- private resolveRegistrationPlanAssignment;
899
+ private resolveRegistrationOnboardingOutcome;
900
+ private ensureDefaultOnboardingEntitlement;
872
901
  createUserBillingRecord(userId: string, options?: {
873
902
  entitlementState?: string;
874
903
  planId?: string | null;
904
+ effectiveUntil?: string | null;
875
905
  }): void;
876
906
  getUserEntitlement(userId: string): {
877
907
  entitlementState: string;
@@ -958,8 +988,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
958
988
  hasProjectThemeOverride(workspaceId?: string, userId?: string): boolean;
959
989
  getEffectiveTheme(workspaceId?: string, userId?: string): TaskforceTheme;
960
990
  hasProjectJsonBackupOverride(workspaceId?: string, userId?: string): boolean;
961
- getSignupMonetizationSettings(): import("./types.js").SignupMonetizationSettings;
962
- validateSignupMonetizationSettings(input?: Partial<SignupMonetizationSettings>): import("./types.js").SignupMonetizationValidationResult;
991
+ getOnboardingPolicy(): import("./types.js").OnboardingPolicy;
992
+ validateOnboardingPolicy(input?: {
993
+ mode?: 'require_plan_selection' | 'auto_grant_free' | 'auto_start_trial';
994
+ planVersionId?: string | null;
995
+ }): import("./types.js").OnboardingPolicyValidationResult;
963
996
  updateGlobalSettings(settings: GlobalTaskforceSettings): void;
964
997
  private sanitizeUserGlobalSyncSettings;
965
998
  getUserGlobalSyncSettings(userId: string): {
@@ -1137,6 +1170,11 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1137
1170
  setSystemRole(userId: string, role: SystemRole): boolean;
1138
1171
  setUserDisabledGlobal(userId: string, disabled: boolean): boolean;
1139
1172
  setUserBetaAccessGlobal(userId: string, enabled: boolean): boolean;
1173
+ purgeSystemUser(input: {
1174
+ targetUserId: string;
1175
+ actorUserId: string;
1176
+ emailConfirmation: string;
1177
+ }): PurgedSystemUserSummary;
1140
1178
  private clearActiveAssignmentsForUnavailableActor;
1141
1179
  listWorkspaceUsers(workspaceId: string): WorkspaceUserRecord[];
1142
1180
  replaceWorkspaceUsersForSync(input: {
@@ -1229,6 +1267,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1229
1267
  upsertDocumentReviewSessionForSync(session: DocumentReviewSessionRecord): DocumentReviewSessionRecord;
1230
1268
  upsertDocumentReviewCommentForSync(comment: DocumentReviewCommentSyncRecord): DocumentReviewCommentSyncRecord;
1231
1269
  upsertAnnotatedAttachmentSessionForSync(session: AnnotatedAttachmentSessionRecord): AnnotatedAttachmentSessionRecord;
1270
+ upsertTaskEventForSync(event: TaskEvent): TaskEvent;
1232
1271
  deleteDocumentReviewSessionForSync(input: {
1233
1272
  workspaceId?: string | null;
1234
1273
  sessionId: string;
@@ -1471,10 +1510,12 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1471
1510
  workspaceId: string | null;
1472
1511
  role: AccessRole;
1473
1512
  planSelectionRequired: boolean;
1513
+ checkoutPending: boolean;
1514
+ commercialState: EntitlementState;
1474
1515
  };
1475
1516
  private createOneTimeAuthToken;
1476
1517
  private consumeOneTimeAuthToken;
1477
- private inspectOneTimeAuthToken;
1518
+ inspectOneTimeAuthToken(token: string, purpose: AuthTokenPurpose): AuthTokenInspection;
1478
1519
  revokeMcpCredentialsForUserWorkspace(userId: string, workspaceId: string, revokedByUserId?: string | null): void;
1479
1520
  private revokeMcpCredentialsForWorkspace;
1480
1521
  listMcpAccessTokens(input: {
@@ -1627,6 +1668,9 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1627
1668
  updateWorkspaceUserRole(userId: string, workspaceId: string, role: AccessRole): boolean;
1628
1669
  getTask(id: string, workspaceId?: string): TaskItem | null;
1629
1670
  listTaskEvents(taskId: string, workspaceId?: string): TaskEvent[];
1671
+ listTaskEventsForSync(input: {
1672
+ workspaceId?: string | null;
1673
+ }): TaskEvent[];
1630
1674
  getScheduleBoard(weekKey: string, showWeekends?: boolean, workspaceId?: string): ScheduleBoardResult;
1631
1675
  updateTaskSchedule(id: string, input: {
1632
1676
  scheduledDate: string | null;
@@ -1658,6 +1702,7 @@ export declare class TaskforceCore implements TaskforceSyncCapable {
1658
1702
  syncUpdatedAt?: string;
1659
1703
  actorRef?: string;
1660
1704
  skipTaskEvents?: boolean;
1705
+ saveSource?: 'manual' | 'autosave';
1661
1706
  }): TaskItem | null;
1662
1707
  addComment(id: string, text: string, author: string, workspaceId?: string, options?: {
1663
1708
  persistBackup?: boolean;
@@ -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';
@@ -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()
@@ -1175,7 +1178,6 @@ export class TaskforceCore {
1175
1178
  writeGlobalConfig: (config) => this.writeGlobalConfig(config),
1176
1179
  });
1177
1180
  this.planEntitlementService.repairPlanCatalogDefaultsIfNeeded();
1178
- this.planEntitlementService.repairSignupMonetizationSettingsIfNeeded();
1179
1181
  this.planEntitlementService.normalizeLegacyPlanDataIfNeeded();
1180
1182
  this.planEntitlementService.backfillAccountEntitlements();
1181
1183
  this.repairDetachedAnnotatedAttachmentSessions();
@@ -1209,11 +1211,37 @@ export class TaskforceCore {
1209
1211
  upsertCanonicalEntitlementRecord(input) {
1210
1212
  return this.planEntitlementService.upsertCanonicalEntitlementRecord(input);
1211
1213
  }
1214
+ transitionCanonicalCommercialState(input) {
1215
+ return this.planEntitlementService.transitionCanonicalCommercialState(input);
1216
+ }
1212
1217
  resolveWorkspaceLimitForUser(userId) {
1213
1218
  return this.planEntitlementService.resolveWorkspaceLimitForUser(userId);
1214
1219
  }
1215
- resolveRegistrationPlanAssignment(selectedPlanVersionIdRaw) {
1216
- return this.planEntitlementService.resolveRegistrationPlanAssignment(selectedPlanVersionIdRaw);
1220
+ resolveRegistrationOnboardingOutcome(selectedPlanVersionIdRaw) {
1221
+ return this.planEntitlementService.resolveRegistrationOnboardingOutcome(selectedPlanVersionIdRaw);
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);
1217
1245
  }
1218
1246
  createUserBillingRecord(userId, options) {
1219
1247
  return this.planEntitlementService.createUserBillingRecord(userId, options);
@@ -2598,11 +2626,11 @@ export class TaskforceCore {
2598
2626
  const config = this.readConfig(workspaceId, userId) || {};
2599
2627
  return typeof config.jsonBackupEnabled === 'boolean';
2600
2628
  }
2601
- getSignupMonetizationSettings() {
2602
- return this.planEntitlementService.getSignupMonetizationSettings();
2629
+ getOnboardingPolicy() {
2630
+ return this.planEntitlementService.getOnboardingPolicy();
2603
2631
  }
2604
- validateSignupMonetizationSettings(input) {
2605
- return this.planEntitlementService.validateSignupMonetizationSettings(input);
2632
+ validateOnboardingPolicy(input) {
2633
+ return this.planEntitlementService.validateOnboardingPolicy(input);
2606
2634
  }
2607
2635
  updateGlobalSettings(settings) {
2608
2636
  updateGlobalSettingsService(this.getGlobalSettingsServiceDeps(), settings);
@@ -4375,6 +4403,193 @@ export class TaskforceCore {
4375
4403
  `).run(enabled ? 1 : 0, new Date().toISOString(), this.tenantId, normalizedUserId);
4376
4404
  return Number(result?.changes || 0) > 0;
4377
4405
  }
4406
+ purgeSystemUser(input) {
4407
+ const targetUserId = String(input.targetUserId || '').trim();
4408
+ const actorUserId = String(input.actorUserId || '').trim();
4409
+ const emailConfirmation = String(input.emailConfirmation || '').trim().toLowerCase();
4410
+ if (!targetUserId) {
4411
+ throw new TaskforceRuleError('targetUserId is required', 400, 'TARGET_USER_ID_REQUIRED');
4412
+ }
4413
+ if (!actorUserId || actorUserId === 'anonymous') {
4414
+ throw new TaskforceRuleError('actorUserId is required', 400, 'ACTOR_USER_ID_REQUIRED');
4415
+ }
4416
+ if (!emailConfirmation) {
4417
+ throw new TaskforceRuleError('Email confirmation is required', 400, 'EMAIL_CONFIRMATION_REQUIRED');
4418
+ }
4419
+ if (targetUserId === actorUserId) {
4420
+ throw new TaskforceRuleError('Cannot purge the current system admin session user', 400, 'CURRENT_SYSTEM_USER_PURGE_FORBIDDEN');
4421
+ }
4422
+ return this.db.transaction(() => {
4423
+ const user = this.db.prepare(`
4424
+ SELECT
4425
+ id,
4426
+ email,
4427
+ COALESCE(system_role, 'user') AS system_role,
4428
+ COALESCE(is_disabled, 0) AS is_disabled
4429
+ FROM users
4430
+ WHERE tenant_id = ? AND id = ?
4431
+ LIMIT 1
4432
+ `).get(this.tenantId, targetUserId);
4433
+ if (!user?.id || !user.email) {
4434
+ throw new TaskforceRuleError('User not found', 404, 'USER_NOT_FOUND');
4435
+ }
4436
+ const normalizedEmail = String(user.email).trim().toLowerCase();
4437
+ if (normalizedEmail !== emailConfirmation) {
4438
+ throw new TaskforceRuleError('Email confirmation did not match the target user', 400, 'EMAIL_CONFIRMATION_MISMATCH');
4439
+ }
4440
+ const currentRole = this.normalizeSystemRole(user.system_role, 'user');
4441
+ const isDisabled = Boolean(user.is_disabled);
4442
+ if (currentRole === 'system_admin' && !isDisabled && this.countSystemAdmins() <= 1) {
4443
+ throw new TaskforceRuleError('Cannot purge the last enabled system admin', 400, 'LAST_SYSTEM_ADMIN_REQUIRED');
4444
+ }
4445
+ const elevatedWorkspaceMemberships = this.db.prepare(`
4446
+ SELECT
4447
+ m.workspace_id AS workspace_id,
4448
+ COALESCE(m.role, 'member') AS role,
4449
+ w.name AS workspace_name
4450
+ FROM workspace_memberships m
4451
+ LEFT JOIN workspaces w
4452
+ ON w.tenant_id = m.tenant_id
4453
+ AND w.id = m.workspace_id
4454
+ WHERE m.tenant_id = ?
4455
+ AND m.user_id = ?
4456
+ AND COALESCE(m.status, 'active') = 'active'
4457
+ AND COALESCE(m.role, 'member') IN ('owner', 'admin')
4458
+ ORDER BY COALESCE(w.updated_at, w.created_at) DESC, w.name ASC
4459
+ LIMIT 10
4460
+ `).all(this.tenantId, targetUserId);
4461
+ if (elevatedWorkspaceMemberships.length > 0) {
4462
+ throw new TaskforceRuleError('Cannot purge a user with active owner/admin workspace memberships', 409, 'SYSTEM_USER_PURGE_BLOCKED_ACTIVE_WORKSPACE_ROLE', {
4463
+ memberships: elevatedWorkspaceMemberships.map((membership) => ({
4464
+ workspaceId: membership.workspace_id ? String(membership.workspace_id) : null,
4465
+ workspaceName: membership.workspace_name ? String(membership.workspace_name) : null,
4466
+ role: membership.role ? String(membership.role) : null
4467
+ }))
4468
+ });
4469
+ }
4470
+ const billingRow = this.db.prepare(`
4471
+ SELECT
4472
+ stripe_customer_id,
4473
+ stripe_subscription_id,
4474
+ stripe_price_id,
4475
+ stripe_status,
4476
+ billing_interval
4477
+ FROM user_billing
4478
+ WHERE tenant_id = ? AND user_id = ?
4479
+ LIMIT 1
4480
+ `).get(this.tenantId, targetUserId);
4481
+ const hasCommercialBillingState = [
4482
+ billingRow?.stripe_customer_id,
4483
+ billingRow?.stripe_subscription_id,
4484
+ billingRow?.stripe_price_id,
4485
+ billingRow?.stripe_status,
4486
+ billingRow?.billing_interval
4487
+ ].some((value) => String(value || '').trim().length > 0);
4488
+ if (hasCommercialBillingState) {
4489
+ throw new TaskforceRuleError('Cannot purge a user with active commercial billing state', 409, 'SYSTEM_USER_PURGE_BLOCKED_BILLING_STATE');
4490
+ }
4491
+ const now = new Date().toISOString();
4492
+ const runCount = (sql, ...params) => Number(this.db.prepare(sql).run(...params)?.changes || 0);
4493
+ const unassignedTaskCount = runCount(`
4494
+ UPDATE tasks
4495
+ SET assignee = 'unassigned',
4496
+ updated_at = ?
4497
+ WHERE tenant_id = ?
4498
+ AND assignee = ?
4499
+ AND is_archived = 0
4500
+ `, now, this.tenantId, targetUserId);
4501
+ const clearedInitiativeOwnerCount = runCount(`
4502
+ UPDATE initiatives
4503
+ SET owner_id = NULL,
4504
+ updated_at = ?
4505
+ WHERE tenant_id = ?
4506
+ AND owner_id = ?
4507
+ `, now, this.tenantId, targetUserId);
4508
+ const clearedWorkstreamOwnerCount = runCount(`
4509
+ UPDATE workstreams
4510
+ SET owner_id = NULL,
4511
+ updated_at = ?
4512
+ WHERE tenant_id = ?
4513
+ AND owner_id = ?
4514
+ `, now, this.tenantId, targetUserId);
4515
+ const deletedEntitlementCount = runCount(`
4516
+ DELETE FROM account_entitlements
4517
+ WHERE tenant_id = ?
4518
+ AND account_id = ?
4519
+ `, this.tenantId, targetUserId);
4520
+ const deletedWorkspaceMembershipCount = runCount(`
4521
+ DELETE FROM workspace_memberships
4522
+ WHERE tenant_id = ?
4523
+ AND user_id = ?
4524
+ `, this.tenantId, targetUserId);
4525
+ const deletedAuthTokenCount = runCount(`
4526
+ DELETE FROM auth_tokens
4527
+ WHERE tenant_id = ?
4528
+ AND user_id = ?
4529
+ `, this.tenantId, targetUserId);
4530
+ const deletedAvatarDraftCount = runCount(`
4531
+ DELETE FROM user_avatar_upload_drafts
4532
+ WHERE tenant_id = ?
4533
+ AND user_id = ?
4534
+ `, this.tenantId, targetUserId);
4535
+ const deletedMcpAccessTokenCount = runCount(`
4536
+ DELETE FROM mcp_access_tokens
4537
+ WHERE tenant_id = ?
4538
+ AND user_id = ?
4539
+ `, this.tenantId, targetUserId);
4540
+ const deletedMcpOauthAuthCodeCount = runCount(`
4541
+ DELETE FROM mcp_oauth_auth_codes
4542
+ WHERE tenant_id = ?
4543
+ AND user_id = ?
4544
+ `, this.tenantId, targetUserId);
4545
+ const deletedMcpOauthConnectorGrantCount = runCount(`
4546
+ DELETE FROM mcp_oauth_connector_grants
4547
+ WHERE tenant_id = ?
4548
+ AND user_id = ?
4549
+ `, this.tenantId, targetUserId);
4550
+ const deletedUiStateCount = runCount(`
4551
+ DELETE FROM ui_state
4552
+ WHERE tenant_id = ?
4553
+ AND user_id = ?
4554
+ `, this.tenantId, targetUserId);
4555
+ const deletedUserPreferenceCount = runCount(`
4556
+ DELETE FROM user_preferences
4557
+ WHERE tenant_id = ?
4558
+ AND user_id = ?
4559
+ `, this.tenantId, targetUserId);
4560
+ const deletedUserBillingCount = runCount(`
4561
+ DELETE FROM user_billing
4562
+ WHERE tenant_id = ?
4563
+ AND user_id = ?
4564
+ `, this.tenantId, targetUserId);
4565
+ const deletedUserCount = runCount(`
4566
+ DELETE FROM users
4567
+ WHERE tenant_id = ?
4568
+ AND id = ?
4569
+ `, this.tenantId, targetUserId);
4570
+ if (deletedUserCount !== 1) {
4571
+ throw new TaskforceRuleError('User not found', 404, 'USER_NOT_FOUND');
4572
+ }
4573
+ return {
4574
+ targetUserId,
4575
+ email: String(user.email),
4576
+ unassignedTaskCount,
4577
+ clearedInitiativeOwnerCount,
4578
+ clearedWorkstreamOwnerCount,
4579
+ deletedWorkspaceMembershipCount,
4580
+ deletedAuthTokenCount,
4581
+ deletedAvatarDraftCount,
4582
+ deletedMcpAccessTokenCount,
4583
+ deletedMcpOauthAuthCodeCount,
4584
+ deletedMcpOauthConnectorGrantCount,
4585
+ deletedUiStateCount,
4586
+ deletedUserPreferenceCount,
4587
+ deletedEntitlementCount,
4588
+ deletedUserBillingCount,
4589
+ deletedUserCount
4590
+ };
4591
+ })();
4592
+ }
4378
4593
  clearActiveAssignmentsForUnavailableActor(actorId, workspaceId, updatedAt) {
4379
4594
  const normalizedActorId = String(actorId || '').trim();
4380
4595
  const normalizedWorkspaceId = String(workspaceId || 'default').trim() || 'default';
@@ -4652,6 +4867,9 @@ export class TaskforceCore {
4652
4867
  deletedAt: session.deletedAt,
4653
4868
  });
4654
4869
  }
4870
+ upsertTaskEventForSync(event) {
4871
+ return upsertTaskEventForSyncService(this.getTaskActivityServiceDeps(), event);
4872
+ }
4655
4873
  deleteDocumentReviewSessionForSync(input) {
4656
4874
  const deps = this.getDocumentReviewServiceDeps();
4657
4875
  return deps.sessionStore.softDelete(input.sessionId, deps.normalizeWorkspaceId(input.workspaceId), input.deletedAt || undefined);
@@ -5329,7 +5547,20 @@ export class TaskforceCore {
5329
5547
  const assignFirstSystemAdmin = !this.hasAnySystemAdmin();
5330
5548
  const betaAccess = input.betaAccess !== false;
5331
5549
  const requestedWorkspaceId = String(input.workspaceId || '').trim();
5332
- const registrationPlanAssignment = this.resolveRegistrationPlanAssignment(input.planVersionId);
5550
+ const onboardingOutcome = this.resolveRegistrationOnboardingOutcome(input.planVersionId);
5551
+ const applyRegistrationCommercialState = (accountId, now) => {
5552
+ this.transitionCanonicalCommercialState({
5553
+ accountId,
5554
+ planVersionId: onboardingOutcome.planVersionId,
5555
+ state: onboardingOutcome.commercialState,
5556
+ effectiveAt: now,
5557
+ billingMirrorPlanId: onboardingOutcome.planId,
5558
+ source: 'registration',
5559
+ updatedBy: 'registration',
5560
+ createdAt: now,
5561
+ updatedAt: now
5562
+ });
5563
+ };
5333
5564
  if (!requestedWorkspaceId || requestedWorkspaceId.toLowerCase() === 'default') {
5334
5565
  const now = new Date().toISOString();
5335
5566
  const userId = this.generateEntityId('user');
@@ -5338,32 +5569,14 @@ export class TaskforceCore {
5338
5569
  INSERT INTO users (id, tenant_id, email, display_name, auth_provider, external_auth_id, password_hash, system_role, beta_access, is_disabled, created_at, updated_at)
5339
5570
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
5340
5571
  `).run(userId, this.tenantId, email, displayName, 'password', email, hashPassword(password), assignFirstSystemAdmin ? 'system_admin' : 'user', betaAccess ? 1 : 0, now, now);
5341
- if (registrationPlanAssignment.requiresPlanSelection) {
5342
- this.createUserBillingRecord(userId, {
5343
- entitlementState: 'pending_plan_selection',
5344
- planId: null
5345
- });
5346
- }
5347
- if (!registrationPlanAssignment.requiresPlanSelection && registrationPlanAssignment.planVersionId && registrationPlanAssignment.planId) {
5348
- this.createUserBillingRecord(userId, {
5349
- entitlementState: 'active',
5350
- planId: registrationPlanAssignment.planId
5351
- });
5352
- this.upsertCanonicalEntitlementRecord({
5353
- accountId: userId,
5354
- planVersionId: registrationPlanAssignment.planVersionId,
5355
- state: 'active',
5356
- effectiveAt: now,
5357
- updatedBy: 'registration',
5358
- createdAt: now,
5359
- updatedAt: now
5360
- });
5361
- }
5572
+ applyRegistrationCommercialState(userId, now);
5362
5573
  return {
5363
5574
  userId,
5364
5575
  workspaceId: null,
5365
5576
  role: 'member',
5366
- planSelectionRequired: registrationPlanAssignment.requiresPlanSelection
5577
+ planSelectionRequired: onboardingOutcome.requiresPlanSelection,
5578
+ checkoutPending: onboardingOutcome.checkoutPending,
5579
+ commercialState: onboardingOutcome.commercialState
5367
5580
  };
5368
5581
  }
5369
5582
  const workspaceId = requestedWorkspaceId;
@@ -5381,27 +5594,12 @@ export class TaskforceCore {
5381
5594
  WHERE tenant_id = ? AND id = ?
5382
5595
  `).run(new Date().toISOString(), this.tenantId, created.userId);
5383
5596
  }
5384
- if (registrationPlanAssignment.requiresPlanSelection) {
5385
- this.createUserBillingRecord(created.userId, {
5386
- entitlementState: 'pending_plan_selection',
5387
- planId: null
5388
- });
5389
- }
5390
- if (!registrationPlanAssignment.requiresPlanSelection && registrationPlanAssignment.planVersionId && registrationPlanAssignment.planId) {
5391
- this.createUserBillingRecord(created.userId, {
5392
- entitlementState: 'active',
5393
- planId: registrationPlanAssignment.planId
5394
- });
5395
- this.upsertCanonicalEntitlementRecord({
5396
- accountId: created.userId,
5397
- planVersionId: registrationPlanAssignment.planVersionId,
5398
- state: 'active',
5399
- updatedBy: 'registration'
5400
- });
5401
- }
5597
+ applyRegistrationCommercialState(created.userId);
5402
5598
  return {
5403
5599
  ...created,
5404
- planSelectionRequired: registrationPlanAssignment.requiresPlanSelection
5600
+ planSelectionRequired: onboardingOutcome.requiresPlanSelection,
5601
+ checkoutPending: onboardingOutcome.checkoutPending,
5602
+ commercialState: onboardingOutcome.commercialState
5405
5603
  };
5406
5604
  }
5407
5605
  createOneTimeAuthToken(userId, purpose, ttlSeconds, workspaceId) {
@@ -5626,6 +5824,11 @@ export class TaskforceCore {
5626
5824
  updated_at = ?
5627
5825
  WHERE tenant_id = ? AND id = ?
5628
5826
  `).run(hashPassword(password), 'password', user.email, now, now, this.tenantId, consumed.userId);
5827
+ this.ensureDefaultOnboardingEntitlement(consumed.userId, {
5828
+ source: 'invite-accept',
5829
+ updatedBy: 'invite-accept',
5830
+ now
5831
+ });
5629
5832
  return this.completeInviteWorkspaceActivation({
5630
5833
  userId: consumed.userId,
5631
5834
  workspaceId: inviteWorkspaceId
@@ -5784,6 +5987,10 @@ export class TaskforceCore {
5784
5987
  const normalizedWorkspaceId = this.normalizeWorkspaceId(workspaceId);
5785
5988
  return this.listTaskEventsInternal(taskId, normalizedWorkspaceId);
5786
5989
  }
5990
+ listTaskEventsForSync(input) {
5991
+ const normalizedWorkspaceId = this.normalizeWorkspaceId(input.workspaceId || undefined);
5992
+ return listWorkspaceTaskEventsService(this.getTaskActivityServiceDeps(), normalizedWorkspaceId);
5993
+ }
5787
5994
  getScheduleBoard(weekKey, showWeekends = false, workspaceId) {
5788
5995
  const parsedWeek = this.parseIsoWeekKeyToDates(weekKey);
5789
5996
  if (!parsedWeek) {
@@ -6341,7 +6548,10 @@ export class TaskforceCore {
6341
6548
  if (!nextTask)
6342
6549
  return null;
6343
6550
  if (options?.skipTaskEvents !== true) {
6344
- const changes = this.buildTaskUpdateChanges(existing, nextTask, patch);
6551
+ const rawChanges = this.buildTaskUpdateChanges(existing, nextTask, patch);
6552
+ const changes = options?.saveSource === 'autosave'
6553
+ ? this.filterAutosaveTaskEventChanges(rawChanges)
6554
+ : rawChanges;
6345
6555
  if (Object.keys(changes).length > 0) {
6346
6556
  let action = 'task-updated';
6347
6557
  if (changes.status) {
@@ -27,7 +27,6 @@ function setupWorkspace(core, userId = 'owner-1', workspaceId = 'workspace-1') {
27
27
  hasEntitlement: true,
28
28
  canAccessApp: true,
29
29
  canAccessPlans: true,
30
- signupMonetizationStrategy: 'none',
31
30
  planSelectionRequired: false,
32
31
  message: null,
33
32
  entitlement: null
@@ -328,7 +327,6 @@ describe('TaskforceCore MCP auth invalidation', () => {
328
327
  hasEntitlement: false,
329
328
  canAccessApp: false,
330
329
  canAccessPlans: true,
331
- signupMonetizationStrategy: 'none',
332
330
  planSelectionRequired: false,
333
331
  message: 'Suspended for test',
334
332
  entitlement: null
@@ -13,10 +13,19 @@ function seedPlans(core) {
13
13
  versionNumber: 1,
14
14
  seatLimit: 1
15
15
  });
16
+ const db = core.db;
17
+ const now = new Date().toISOString();
18
+ db.prepare(`
19
+ INSERT OR IGNORE INTO billing_price_mappings (
20
+ tenant_id, plan_version_id, billing_interval, stripe_price_id, pricing_type, active, unit_amount, currency, created_at, updated_at
21
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
22
+ `).run(core.getTenantId(), 'starter-v1', 'month', 'free:starter-v1:month', 'free', 1, 0, null, now, now);
16
23
  core.updateGlobalSettings({
17
- auth: {
18
- signupMonetizationStrategy: 'auto_assign_default',
19
- defaultSignupPlanVersionId: 'starter-v1'
24
+ billing: {
25
+ onboardingPolicy: {
26
+ mode: 'auto_grant_free',
27
+ planVersionId: 'starter-v1'
28
+ }
20
29
  }
21
30
  });
22
31
  }