@taskforcehq/taskforce 0.3.301 → 0.3.302
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 +26 -2
- package/dist/TaskforceCore.filter-persistence.test.js +1 -1
- package/dist/TaskforceCore.js +13 -24
- package/dist/TaskforceCore.test.js +167 -152
- package/dist/components/features/TaskSettings.js +14 -82
- package/dist/components/features/TaskSettings.test.js +33 -70
- package/dist/components/features/settings/TaxonomyLibraryManager.js +8 -2
- package/dist/components/features/settings/TaxonomyLibraryManager.test.js +1 -1
- package/dist/components/task/TaskActionHeader.js +6 -3
- package/dist/components/task/TaskCard.js +6 -3
- package/dist/components/task/TaskForm.js +2 -2
- package/dist/components/task/TaskForm.test.js +41 -2
- package/dist/components/ui/ReferenceBadgeButton.js +1 -1
- package/dist/components/views/PlansPage.js +9 -8
- package/dist/components/views/StandaloneLayout.js +466 -204
- package/dist/components/views/panels/PlanningDrawer.js +18 -1
- package/dist/components/views/standalone/modals/AccountHubModal.d.ts +43 -0
- package/dist/components/views/standalone/modals/AccountHubModal.js +22 -0
- package/dist/components/views/standalone/modals/CreateWorkspaceConfirmModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/CreateWorkspaceConfirmModal.js +8 -0
- package/dist/components/views/standalone/modals/EditProfileModal.d.ts +26 -0
- package/dist/components/views/standalone/modals/EditProfileModal.js +10 -0
- package/dist/components/views/standalone/modals/HelpModal.d.ts +9 -0
- package/dist/components/views/standalone/modals/HelpModal.js +8 -0
- package/dist/components/views/standalone/modals/ScheduleWarningModal.d.ts +13 -0
- package/dist/components/views/standalone/modals/ScheduleWarningModal.js +6 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.d.ts +61 -0
- package/dist/components/views/standalone/modals/SyncStatusModal.js +38 -0
- package/dist/components/views/standalone/modals/TeamManagementModal.d.ts +64 -0
- package/dist/components/views/standalone/modals/TeamManagementModal.js +10 -0
- package/dist/components/views/standalone/modals/types.d.ts +2 -0
- package/dist/components/views/standalone/modals/types.js +1 -0
- package/dist/components/views/teamManagementAccess.d.ts +1 -1
- package/dist/components/views/teamManagementAccess.js +2 -2
- package/dist/components/views/teamManagementAccess.test.js +3 -3
- package/dist/config/deployment.js +2 -2
- package/dist/config/deployment.test.js +5 -3
- package/dist/core/AiProfileService.js +7 -2
- package/dist/core/AiProfiles.test.js +19 -0
- package/dist/core/SyncReconciliationService.d.ts +2 -0
- package/dist/core/SyncReconciliationService.js +3 -0
- package/dist/core/TaskAuditTimeline.test.js +40 -0
- package/dist/core/Taskforce.d.ts +49 -0
- package/dist/core/Taskforce.ids.test.js +133 -0
- package/dist/core/Taskforce.js +241 -78
- package/dist/core/UserProfileAvatarDrafts.test.d.ts +1 -0
- package/dist/core/UserProfileAvatarDrafts.test.js +102 -0
- package/dist/core/taskReferencePolicy.d.ts +28 -0
- package/dist/core/taskReferencePolicy.js +189 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/hooks/tasks/useTaskFormActions.js +3 -0
- package/dist/hooks/useTaskData.js +3 -2
- package/dist/hooks/useTaskData.test.js +66 -0
- package/dist/hooks/useTaskforce.d.ts +5 -0
- package/dist/hooks/useTaskforce.js +63 -15
- package/dist/hooks/useTaskforce.sync-behavior.test.js +185 -6
- package/dist/mcp/aiProfileBootstrap.d.ts +29 -0
- package/dist/mcp/aiProfileBootstrap.js +80 -0
- package/dist/mcp/aiProfileBootstrap.test.d.ts +1 -0
- package/dist/mcp/aiProfileBootstrap.test.js +68 -0
- package/dist/mcp/clientIntegrations.d.ts +2 -8
- package/dist/mcp/clientIntegrations.js +21 -40
- package/dist/mcp/clientIntegrations.test.js +28 -2
- package/dist/mcp/clientProfileDefaults.d.ts +12 -0
- package/dist/mcp/clientProfileDefaults.js +37 -0
- package/dist/mcp/runtime.d.ts +10 -7
- package/dist/mcp/runtime.js +41 -19
- package/dist/mcp/runtime.test.js +49 -2
- package/dist/migrations/taskSchemaMigrations.js +53 -1
- package/dist/qaOpen.test.d.ts +1 -0
- package/dist/qaOpen.test.js +56 -0
- package/dist/server/index.cookieProxy.test.js +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +15 -1
- package/dist/server/index.test.js +14 -1
- package/dist/server/routes/admin.js +25 -22
- package/dist/server/routes/auth.d.ts +5 -0
- package/dist/server/routes/auth.js +350 -16
- package/dist/server/routes/billing.js +11 -1
- package/dist/server/routes/billing.test.js +32 -2
- package/dist/server/routes/documents.js +6 -1
- package/dist/server/routes/shared.d.ts +1 -1
- package/dist/server/routes/shared.js +11 -3
- package/dist/server/routes/sync.integration.test.js +130 -0
- package/dist/server/routes/sync.js +226 -1924
- package/dist/server/routes/tasks.js +18 -4
- package/dist/server/routes.js +26 -19
- package/dist/server/routes.test.js +352 -6
- package/dist/shared/runtimeContract.d.ts +1 -1
- package/dist/sync/collaborationSyncPayload.d.ts +17 -0
- package/dist/sync/collaborationSyncPayload.js +131 -0
- package/dist/sync/collaborationSyncPayload.test.d.ts +1 -0
- package/dist/sync/collaborationSyncPayload.test.js +104 -0
- package/dist/sync/collaborationSyncState.d.ts +15 -0
- package/dist/sync/collaborationSyncState.js +60 -0
- package/dist/sync/contentSyncPayload.d.ts +45 -0
- package/dist/sync/contentSyncPayload.js +104 -0
- package/dist/sync/contentSyncPayload.test.d.ts +1 -0
- package/dist/sync/contentSyncPayload.test.js +104 -0
- package/dist/sync/contentSyncState.d.ts +88 -0
- package/dist/sync/contentSyncState.js +743 -0
- package/dist/sync/planningSyncPayload.d.ts +9 -0
- package/dist/sync/planningSyncPayload.js +82 -0
- package/dist/sync/planningSyncPayload.test.d.ts +1 -0
- package/dist/sync/planningSyncPayload.test.js +68 -0
- package/dist/sync/syncApplyHandlers.d.ts +83 -0
- package/dist/sync/syncApplyHandlers.js +445 -0
- package/dist/sync/taskSyncPayload.d.ts +33 -0
- package/dist/sync/taskSyncPayload.js +126 -0
- package/dist/sync/taskSyncPayload.test.d.ts +1 -0
- package/dist/sync/taskSyncPayload.test.js +54 -0
- package/dist/sync/workspacePullFeed.d.ts +28 -0
- package/dist/sync/workspacePullFeed.js +301 -0
- package/dist/sync/workspacePullFeed.test.d.ts +1 -0
- package/dist/sync/workspacePullFeed.test.js +166 -0
- package/dist/sync/workspaceSyncModel.d.ts +4 -1
- package/dist/sync/workspaceSyncModel.js +9 -2
- package/dist/sync/workspaceSyncModel.test.js +29 -0
- package/dist/test/setup.js +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/ui/assets/{AgentsModule-Bdq3T1Ts.js → AgentsModule-JG5jc3he.js} +1 -1
- package/dist/ui/assets/{AnnotatedAttachmentWorkspace-jKUVo-PJ.js → AnnotatedAttachmentWorkspace-Dvi02Y7q.js} +1 -1
- package/dist/ui/assets/{DocumentWorkspace-DuQa-uIC.js → DocumentWorkspace-iys3zfca.js} +2 -2
- package/dist/ui/assets/{InitiativesModule-C8Pi2VTk.js → InitiativesModule-DJvLJI3A.js} +1 -1
- package/dist/ui/assets/PlansPage-BMPlpFpw.js +1 -0
- package/dist/ui/assets/TaskSettings-Bqd4cCzW.js +8 -0
- package/dist/ui/assets/{TaskSettings-BwB9NtmJ.css → TaskSettings-CnIBL_Eb.css} +1 -1
- package/dist/ui/assets/{WorkflowsModule-b6TLuHwJ.js → WorkflowsModule-BguHeQaV.js} +1 -1
- package/dist/ui/assets/index-MXeWoebC.css +1 -0
- package/dist/ui/assets/index-YJ4k5QNa.js +6 -0
- package/dist/ui/assets/{vendor-icons-QZyhEwgT.js → vendor-icons-C8EED3Oh.js} +1 -1
- package/dist/ui/index.html +3 -3
- package/dist/utils/billingStatusCache.d.ts +21 -0
- package/dist/utils/billingStatusCache.js +70 -0
- package/dist/utils/taskActivity.js +17 -4
- package/dist/utils/taskActivity.test.js +27 -0
- package/dist/utils/taskNormalization.js +10 -2
- package/dist/utils/taskReferences.d.ts +11 -1
- package/dist/utils/taskReferences.js +33 -1
- package/package.json +2 -1
- package/scripts/qa-open-lib.mjs +175 -0
- package/scripts/qa-open-lib.mjs.d.ts +49 -0
- package/scripts/qa-open.mjs +352 -0
- package/dist/ui/assets/PlansPage-B6BDECSi.js +0 -1
- package/dist/ui/assets/TaskSettings-DUJgRTPU.js +0 -8
- package/dist/ui/assets/index-BiiF1cLQ.css +0 -1
- package/dist/ui/assets/index-xBWLPOEb.js +0 -6
|
@@ -140,6 +140,49 @@ describe('Server Routes Workspace Sync Integration', () => {
|
|
|
140
140
|
expect(task?.status).toBe('in-progress');
|
|
141
141
|
expect(defaultWorkspaceTasks.find((item) => item.id === 'task-cloud-1')).toBeUndefined();
|
|
142
142
|
});
|
|
143
|
+
it('lets the cloud task keep a colliding reference number during apply-local and records a diagnostic', async () => {
|
|
144
|
+
const projectRoot = createIsolatedProjectRoot('taskforce-sync-task-ref-collision-');
|
|
145
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
146
|
+
core.createWorkspace({ workspaceId, name: 'Local Active Workspace' });
|
|
147
|
+
const localTask = core.createTask({ title: 'Local incumbent' }, { workspaceId });
|
|
148
|
+
expect(localTask.referenceLabel).toBe('T-1');
|
|
149
|
+
const routes = createRoutes(core, { authConfig: { runtimeMode: 'local', enabled: false } });
|
|
150
|
+
const match = matchRoute('POST', '/api/taskforce/sync/workspace/apply-local', routes);
|
|
151
|
+
expect(match).toBeTruthy();
|
|
152
|
+
const req = createMockReq('POST', '/api/taskforce/sync/workspace/apply-local', {
|
|
153
|
+
changes: [
|
|
154
|
+
{
|
|
155
|
+
op: 'upsert',
|
|
156
|
+
archived: false,
|
|
157
|
+
task: {
|
|
158
|
+
id: 'task-cloud-ref-1',
|
|
159
|
+
title: 'Cloud winner',
|
|
160
|
+
status: 'task',
|
|
161
|
+
referenceNumber: 1,
|
|
162
|
+
updatedAt: '2026-04-10T16:00:00.000Z'
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
}, { 'x-taskforce-workspace-id': workspaceId });
|
|
167
|
+
const res = createMockRes();
|
|
168
|
+
await match?.handler(req, res, {});
|
|
169
|
+
expect(res.writeHead).toHaveBeenCalledWith(200, expect.any(Object));
|
|
170
|
+
const reloadedCore = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
171
|
+
expect(reloadedCore.getTask('task-cloud-ref-1', workspaceId)?.referenceLabel).toBe('T-1');
|
|
172
|
+
expect(reloadedCore.getTask(localTask.id, workspaceId)?.referenceLabel).toBe('T-2');
|
|
173
|
+
expect(reloadedCore.listSyncEvents(workspaceId, 10)).toEqual(expect.arrayContaining([
|
|
174
|
+
expect.objectContaining({
|
|
175
|
+
eventType: 'apply',
|
|
176
|
+
status: 'error',
|
|
177
|
+
errorMessage: 'Detected task reference number mismatch during normal sync.',
|
|
178
|
+
details: expect.objectContaining({
|
|
179
|
+
referenceLabel: 'T-1',
|
|
180
|
+
existingTaskId: localTask.id,
|
|
181
|
+
taskId: 'task-cloud-ref-1'
|
|
182
|
+
})
|
|
183
|
+
})
|
|
184
|
+
]));
|
|
185
|
+
});
|
|
143
186
|
it('persists synced comments via apply-local route', async () => {
|
|
144
187
|
const projectRoot = createIsolatedProjectRoot('taskforce-sync-apply-comments-');
|
|
145
188
|
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
@@ -1487,6 +1530,93 @@ describe('Server Routes Workspace Sync Integration', () => {
|
|
|
1487
1530
|
})
|
|
1488
1531
|
]);
|
|
1489
1532
|
});
|
|
1533
|
+
it('omits local provisional reference fields from authenticated pull payloads', async () => {
|
|
1534
|
+
const projectRoot = createIsolatedProjectRoot('taskforce-sync-pull-task-ref-payload-');
|
|
1535
|
+
const seedCore = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
1536
|
+
seedAuthenticatedWorkspace(seedCore);
|
|
1537
|
+
const created = seedCore.createTask({
|
|
1538
|
+
title: 'Offline draft',
|
|
1539
|
+
status: 'task'
|
|
1540
|
+
}, {
|
|
1541
|
+
workspaceId,
|
|
1542
|
+
provisionalLocalReference: true
|
|
1543
|
+
});
|
|
1544
|
+
expect(created.localReferenceNumber).toBe(1);
|
|
1545
|
+
expect(created.referenceLabel).toBe('LT-1');
|
|
1546
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
1547
|
+
const routes = createRoutes(core, { authConfig });
|
|
1548
|
+
const pullMatch = matchRoute('GET', '/api/taskforce/sync/workspace/pull', routes);
|
|
1549
|
+
expect(pullMatch).toBeTruthy();
|
|
1550
|
+
const cookie = createAuthCookie(workspaceId);
|
|
1551
|
+
const pullReq = createMockReq('GET', '/api/taskforce/sync/workspace/pull?workspaceId=workspace-local-active&limit=200', undefined, { cookie });
|
|
1552
|
+
const pullRes = createMockRes();
|
|
1553
|
+
await pullMatch?.handler(pullReq, pullRes, {});
|
|
1554
|
+
expect(pullRes.writeHead).toHaveBeenCalledWith(200, expect.any(Object));
|
|
1555
|
+
const pullBody = readJsonBody(pullRes);
|
|
1556
|
+
const upsert = (Array.isArray(pullBody?.changes) ? pullBody.changes : [])
|
|
1557
|
+
.find((change) => change?.op === 'upsert' && change?.task?.id === created.id);
|
|
1558
|
+
expect(upsert?.task).toEqual(expect.objectContaining({
|
|
1559
|
+
id: created.id,
|
|
1560
|
+
title: 'Offline draft',
|
|
1561
|
+
referenceNumber: null
|
|
1562
|
+
}));
|
|
1563
|
+
expect(upsert?.task).not.toHaveProperty('localReferenceNumber');
|
|
1564
|
+
expect(upsert?.task).not.toHaveProperty('referenceLabel');
|
|
1565
|
+
});
|
|
1566
|
+
it('returns a pushed provisional task on pull even when the caller cursor is newer than the stale local watermark', async () => {
|
|
1567
|
+
const projectRoot = createIsolatedProjectRoot('taskforce-sync-push-pull-provisional-task-');
|
|
1568
|
+
const seedCore = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
1569
|
+
seedAuthenticatedWorkspace(seedCore);
|
|
1570
|
+
const core = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|
|
1571
|
+
const routes = createRoutes(core, { authConfig });
|
|
1572
|
+
const pushMatch = matchRoute('POST', '/api/taskforce/sync/workspace/push', routes);
|
|
1573
|
+
const pullMatch = matchRoute('GET', '/api/taskforce/sync/workspace/pull', routes);
|
|
1574
|
+
expect(pushMatch).toBeTruthy();
|
|
1575
|
+
expect(pullMatch).toBeTruthy();
|
|
1576
|
+
const cookie = createAuthCookie(workspaceId);
|
|
1577
|
+
const taskId = 'task-provisional-roundtrip-1';
|
|
1578
|
+
const staleUpdatedAt = '2026-04-11T21:29:04.121Z';
|
|
1579
|
+
const pushReq = createMockReq('POST', '/api/taskforce/sync/workspace/push', {
|
|
1580
|
+
workspaceId,
|
|
1581
|
+
idempotencyKey: 'task-provisional-roundtrip-1',
|
|
1582
|
+
changes: [
|
|
1583
|
+
{
|
|
1584
|
+
op: 'upsert',
|
|
1585
|
+
archived: false,
|
|
1586
|
+
task: {
|
|
1587
|
+
id: taskId,
|
|
1588
|
+
title: 'Offline provisional task',
|
|
1589
|
+
status: 'task',
|
|
1590
|
+
createdAt: '2026-04-11T21:28:52.410Z',
|
|
1591
|
+
updatedAt: staleUpdatedAt,
|
|
1592
|
+
referenceNumber: null
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
]
|
|
1596
|
+
}, { cookie });
|
|
1597
|
+
const pushRes = createMockRes();
|
|
1598
|
+
await pushMatch?.handler(pushReq, pushRes, {});
|
|
1599
|
+
expect(pushRes.writeHead).toHaveBeenCalledWith(200, expect.any(Object));
|
|
1600
|
+
const persisted = core.getTask(taskId, workspaceId);
|
|
1601
|
+
expect(persisted?.referenceNumber).toBe(1);
|
|
1602
|
+
expect(Date.parse(String(persisted?.updatedAt || ''))).toBeGreaterThan(Date.parse(staleUpdatedAt));
|
|
1603
|
+
const cursor = Buffer.from(JSON.stringify({
|
|
1604
|
+
u: '2026-04-11T21:29:05.000Z',
|
|
1605
|
+
id: 'seed'
|
|
1606
|
+
})).toString('base64url');
|
|
1607
|
+
const pullReq = createMockReq('GET', `/api/taskforce/sync/workspace/pull?workspaceId=${workspaceId}&limit=200&cursor=${cursor}`, undefined, { cookie });
|
|
1608
|
+
const pullRes = createMockRes();
|
|
1609
|
+
await pullMatch?.handler(pullReq, pullRes, {});
|
|
1610
|
+
expect(pullRes.writeHead).toHaveBeenCalledWith(200, expect.any(Object));
|
|
1611
|
+
const pullBody = readJsonBody(pullRes);
|
|
1612
|
+
const upsert = (Array.isArray(pullBody?.changes) ? pullBody.changes : [])
|
|
1613
|
+
.find((change) => change?.op === 'upsert' && change?.task?.id === taskId);
|
|
1614
|
+
expect(upsert?.task).toEqual(expect.objectContaining({
|
|
1615
|
+
id: taskId,
|
|
1616
|
+
title: 'Offline provisional task',
|
|
1617
|
+
referenceNumber: 1
|
|
1618
|
+
}));
|
|
1619
|
+
});
|
|
1490
1620
|
it('keeps document deleted when push batch includes upsert and delete for same path', async () => {
|
|
1491
1621
|
const projectRoot = createIsolatedProjectRoot('taskforce-sync-push-doc-delete-wins-');
|
|
1492
1622
|
const seedCore = new TaskforceCore({ projectRoot, storagePath: '.taskforce' });
|