@allbluecn/web-app 0.22.0 → 0.22.3

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 (93) hide show
  1. package/package.json +6 -8
  2. package/public/logo/allblue-logo-app-icon.svg +1 -1
  3. package/src/components/changelog/changelog-page.tsx +24 -5
  4. package/src/components/desktop/cloud-login.tsx +91 -0
  5. package/src/components/desktop/conflict-center.tsx +148 -0
  6. package/src/components/desktop/renamed-toast.tsx +23 -0
  7. package/src/components/desktop/shell-widgets.tsx +19 -0
  8. package/src/components/desktop/sync-indicator.tsx +60 -0
  9. package/src/components/desktop/sync-status-card.tsx +60 -0
  10. package/src/components/layout/sidebar-03/app-sidebar.tsx +38 -3
  11. package/src/components/shared-kit/avatars/__tests__/avatar-shape.test.ts +17 -1
  12. package/src/components/shared-kit/avatars/avatar-shape.ts +10 -0
  13. package/src/components/shared-kit/avatars/user-avatar.tsx +2 -2
  14. package/src/lib/auth/auth.config.ts +4 -1
  15. package/src/lib/changelog/sdk-versions.ts +33 -2
  16. package/src/lib/desktop-bridge-types.ts +30 -0
  17. package/src/lib/desktop-detect.ts +2 -0
  18. package/src/lib/vector-store/__tests__/factory.test.ts +0 -7
  19. package/src/lib/vector-store/index.ts +2 -4
  20. package/src/paraglide/messages/_index.d.ts +1 -1
  21. package/src/paraglide/messages/_index.js +32 -16
  22. package/src/paraglide/messages/common_sidebar_usermenu_loginsaas3.d.ts +1 -1
  23. package/src/paraglide/messages/common_sidebar_usermenu_loginsaas3.js +3 -3
  24. package/src/paraglide/messages/en.js +11 -6
  25. package/src/paraglide/messages/{tasks_ai_desktop_notice.d.ts → settings_tabs_sync.d.ts} +5 -5
  26. package/src/paraglide/messages/settings_tabs_sync.js +29 -0
  27. package/src/paraglide/messages/zh.js +11 -6
  28. package/src/providers/index.tsx +6 -0
  29. package/src/routeTree.gen.ts +107 -49
  30. package/src/routes/_nav/route.lazy.tsx +12 -0
  31. package/src/routes/_nav/settings/-settings-tabs.tsx +1 -1
  32. package/src/routes/_nav/settings/sync/route.lazy.tsx +40 -0
  33. package/src/routes/_nav/settings/sync/route.tsx +15 -0
  34. package/src/routes/_nav/tasks/index.lazy.tsx +1 -11
  35. package/src/routes/api/billing-webhook.ts +6 -2
  36. package/src/routes/api/sync/bootstrap.ts +38 -0
  37. package/src/routes/api/sync/pull.ts +96 -0
  38. package/src/routes/api/sync/push.ts +169 -0
  39. package/src/routes/api/sync/snapshot.ts +104 -0
  40. package/src/server/__tests__/fetch-guard.test.ts +2 -2
  41. package/src/server/__tests__/resource-registry.test.ts +4 -2
  42. package/src/server/__tests__/sandbox-entitlement.test.ts +5 -0
  43. package/src/server/__tests__/security-headers.test.ts +25 -0
  44. package/src/server/__tests__/task-assigned-query.test.ts +0 -11
  45. package/src/server/__tests__/task-serverfn-crud.test.ts +1 -22
  46. package/src/server/__tests__/task-serverfn-queries.test.ts +1 -9
  47. package/src/server/ai-gateway/__tests__/chat-stream-builder-memory.test.ts +0 -11
  48. package/src/server/ai-gateway/__tests__/embedding-request.test.ts +1 -1
  49. package/src/server/ai-gateway/__tests__/provider-adapter.test.ts +2 -2
  50. package/src/server/ai-gateway/__tests__/run-store-durable.test.ts +1 -1
  51. package/src/server/ai-gateway/durability/__tests__/pg-stream.test.ts +1 -1
  52. package/src/server/ai-gateway/durability/__tests__/reaper-real-db.test.ts +1 -1
  53. package/src/server/ai-gateway/memory/index.ts +2 -2
  54. package/src/server/ai-gateway/sandbox/__tests__/instance-store.test.ts +1 -1
  55. package/src/server/ai-task/assigned-query.ts +4 -15
  56. package/src/server/desktop-guest.ts +12 -0
  57. package/src/server/fetch-guard.ts +3 -3
  58. package/src/server/middlewares/desktop-token.ts +23 -0
  59. package/src/server/remote-auth.ts +6 -0
  60. package/src/server/serverFns/__tests__/billing.test.ts +58 -1
  61. package/src/server/serverFns/__tests__/update-seats.test.ts +8 -8
  62. package/src/server/serverFns/agents/agent-crud.ts +3 -1
  63. package/src/server/serverFns/auth/session.ts +9 -0
  64. package/src/server/serverFns/billing.ts +10 -4
  65. package/src/server/serverFns/bug/bug-crud.ts +7 -2
  66. package/src/server/serverFns/story/__tests__/labels.test.ts +37 -15
  67. package/src/server/serverFns/story/story-comments.ts +2 -1
  68. package/src/server/serverFns/story/story-crud/activities.ts +1 -1
  69. package/src/server/serverFns/story/story-crud/user-brief.ts +1 -1
  70. package/src/server/serverFns/story/story-crud.ts +2 -1
  71. package/src/server/serverFns/story/story-transfer.ts +2 -1
  72. package/src/server/serverFns/tasks/task-crud.ts +0 -13
  73. package/src/server/serverFns/tasks/task-queries.ts +1 -12
  74. package/src/server/serverFns/testcase/plans.ts +1 -1
  75. package/src/server/serverFns/testcase/run-cases.ts +1 -1
  76. package/src/server/serverFns/testcase/runs.ts +1 -1
  77. package/src/server/serverFns/testcase/testcase-activities.ts +1 -1
  78. package/src/server/serverFns/testcase/testcase-board.ts +1 -1
  79. package/src/server/serverFns/testcase/testcase-crud.ts +1 -1
  80. package/src/server/serverFns/workspace.ts +1 -1
  81. package/src/server/story/types.ts +7 -22
  82. package/src/server/story/user-brief.ts +48 -0
  83. package/src/server/sync/scopes.ts +29 -0
  84. package/src/start.ts +10 -2
  85. package/src/styles/globals.css +10 -0
  86. package/src/__tests__/desktop-connection-validate.test.ts +0 -66
  87. package/src/lib/vector-store/__tests__/sqlite-vec-store.test.ts +0 -143
  88. package/src/lib/vector-store/sqlite-vec-store.ts +0 -224
  89. package/src/paraglide/messages/tasks_ai_desktop_notice.js +0 -29
  90. package/src/routes/__desktop/onboarding/route.lazy.tsx +0 -175
  91. package/src/routes/__desktop/onboarding/route.tsx +0 -11
  92. package/src/routes/_nav/settings/connection/route.lazy.tsx +0 -64
  93. package/src/routes/_nav/settings/connection/route.tsx +0 -10
@@ -17,7 +17,6 @@ import { Route as PublicRouteRouteImport } from './routes/_public/route'
17
17
  import { Route as DocsRouteImport } from './routes/docs'
18
18
  import { Route as ShareRouteRouteImport } from './routes/share/route'
19
19
  import { Route as WorkspaceRouteImport } from './routes/workspace'
20
- import { Route as _desktopOnboardingRouteRouteImport } from './routes/__desktop/onboarding/route'
21
20
  import { Route as LoginEmailUnsubscribeRouteRouteImport } from './routes/_login/email-unsubscribe/route'
22
21
  import { Route as LoginForgotPasswordRouteRouteImport } from './routes/_login/forgot-password/route'
23
22
  import { Route as LoginLoginRouteRouteImport } from './routes/_login/login/route'
@@ -75,10 +74,10 @@ import { Route as NavSettingsAccountRouteRouteImport } from './routes/_nav/setti
75
74
  import { Route as NavSettingsAgentsRouteRouteImport } from './routes/_nav/settings/agents/route'
76
75
  import { Route as NavSettingsAiRouteRouteImport } from './routes/_nav/settings/ai/route'
77
76
  import { Route as NavSettingsBillingRouteRouteImport } from './routes/_nav/settings/billing/route'
78
- import { Route as NavSettingsConnectionRouteRouteImport } from './routes/_nav/settings/connection/route'
79
77
  import { Route as NavSettingsGeneralRouteRouteImport } from './routes/_nav/settings/general/route'
80
78
  import { Route as NavSettingsNotificationsRouteRouteImport } from './routes/_nav/settings/notifications/route'
81
79
  import { Route as NavSettingsPrivacyRouteRouteImport } from './routes/_nav/settings/privacy/route'
80
+ import { Route as NavSettingsSyncRouteRouteImport } from './routes/_nav/settings/sync/route'
82
81
  import { Route as NavSettingsTeamRouteRouteImport } from './routes/_nav/settings/team/route'
83
82
  import { Route as NavStoriesIndexRouteImport } from './routes/_nav/stories/index'
84
83
  import { Route as NavStoriesStoryIdRouteRouteImport } from './routes/_nav/stories/$storyId/route'
@@ -105,6 +104,10 @@ import { Route as ApiLicenseActivateRouteRouteImport } from './routes/api/licens
105
104
  import { Route as ApiLicenseHeartbeatRouteRouteImport } from './routes/api/license/heartbeat/route'
106
105
  import { Route as ApiMcpBugsRouteImport } from './routes/api/mcp/bugs'
107
106
  import { Route as ApiNotificationsStreamRouteImport } from './routes/api/notifications/stream'
107
+ import { Route as ApiSyncBootstrapRouteImport } from './routes/api/sync/bootstrap'
108
+ import { Route as ApiSyncPullRouteImport } from './routes/api/sync/pull'
109
+ import { Route as ApiSyncPushRouteImport } from './routes/api/sync/push'
110
+ import { Route as ApiSyncSnapshotRouteImport } from './routes/api/sync/snapshot'
108
111
  import { Route as ServerAnyhubProxySplatRouteImport } from './routes/server/anyhub-proxy/$'
109
112
  import { Route as ShareComplianceIdRouteRouteImport } from './routes/share/compliance/$id/route'
110
113
  import { Route as ShareDesignDesignIdRouteRouteImport } from './routes/share/design/$designId/route'
@@ -202,15 +205,6 @@ const WorkspaceRoute = WorkspaceRouteImport.update({
202
205
  path: '/workspace',
203
206
  getParentRoute: () => rootRouteImport,
204
207
  } as any)
205
- const _desktopOnboardingRouteRoute = _desktopOnboardingRouteRouteImport
206
- .update({
207
- id: '/__desktop/onboarding',
208
- path: '/onboarding',
209
- getParentRoute: () => rootRouteImport,
210
- } as any)
211
- .lazy(() =>
212
- import('./routes/__desktop/onboarding/route.lazy').then((d) => d.Route),
213
- )
214
208
  const LoginEmailUnsubscribeRouteRoute =
215
209
  LoginEmailUnsubscribeRouteRouteImport.update({
216
210
  id: '/email-unsubscribe',
@@ -566,14 +560,6 @@ const NavSettingsBillingRouteRoute = NavSettingsBillingRouteRouteImport.update({
566
560
  } as any).lazy(() =>
567
561
  import('./routes/_nav/settings/billing/route.lazy').then((d) => d.Route),
568
562
  )
569
- const NavSettingsConnectionRouteRoute =
570
- NavSettingsConnectionRouteRouteImport.update({
571
- id: '/connection',
572
- path: '/connection',
573
- getParentRoute: () => NavSettingsRouteRoute,
574
- } as any).lazy(() =>
575
- import('./routes/_nav/settings/connection/route.lazy').then((d) => d.Route),
576
- )
577
563
  const NavSettingsGeneralRouteRoute = NavSettingsGeneralRouteRouteImport.update({
578
564
  id: '/general',
579
565
  path: '/general',
@@ -598,6 +584,13 @@ const NavSettingsPrivacyRouteRoute = NavSettingsPrivacyRouteRouteImport.update({
598
584
  } as any).lazy(() =>
599
585
  import('./routes/_nav/settings/privacy/route.lazy').then((d) => d.Route),
600
586
  )
587
+ const NavSettingsSyncRouteRoute = NavSettingsSyncRouteRouteImport.update({
588
+ id: '/sync',
589
+ path: '/sync',
590
+ getParentRoute: () => NavSettingsRouteRoute,
591
+ } as any).lazy(() =>
592
+ import('./routes/_nav/settings/sync/route.lazy').then((d) => d.Route),
593
+ )
601
594
  const NavSettingsTeamRouteRoute = NavSettingsTeamRouteRouteImport.update({
602
595
  id: '/team',
603
596
  path: '/team',
@@ -752,6 +745,26 @@ const ApiNotificationsStreamRoute = ApiNotificationsStreamRouteImport.update({
752
745
  path: '/api/notifications/stream',
753
746
  getParentRoute: () => rootRouteImport,
754
747
  } as any)
748
+ const ApiSyncBootstrapRoute = ApiSyncBootstrapRouteImport.update({
749
+ id: '/api/sync/bootstrap',
750
+ path: '/api/sync/bootstrap',
751
+ getParentRoute: () => rootRouteImport,
752
+ } as any)
753
+ const ApiSyncPullRoute = ApiSyncPullRouteImport.update({
754
+ id: '/api/sync/pull',
755
+ path: '/api/sync/pull',
756
+ getParentRoute: () => rootRouteImport,
757
+ } as any)
758
+ const ApiSyncPushRoute = ApiSyncPushRouteImport.update({
759
+ id: '/api/sync/push',
760
+ path: '/api/sync/push',
761
+ getParentRoute: () => rootRouteImport,
762
+ } as any)
763
+ const ApiSyncSnapshotRoute = ApiSyncSnapshotRouteImport.update({
764
+ id: '/api/sync/snapshot',
765
+ path: '/api/sync/snapshot',
766
+ getParentRoute: () => rootRouteImport,
767
+ } as any)
755
768
  const ServerAnyhubProxySplatRoute = ServerAnyhubProxySplatRouteImport.update({
756
769
  id: '/server/anyhub-proxy/$',
757
770
  path: '/server/anyhub-proxy/$',
@@ -1092,7 +1105,6 @@ export interface FileRoutesByFullPath {
1092
1105
  '/share': typeof ShareRouteRouteWithChildren
1093
1106
  '/docs': typeof DocsRoute
1094
1107
  '/workspace': typeof WorkspaceRoute
1095
- '/onboarding': typeof _desktopOnboardingRouteRoute
1096
1108
  '/email-unsubscribe': typeof LoginEmailUnsubscribeRouteRoute
1097
1109
  '/forgot-password': typeof LoginForgotPasswordRouteRoute
1098
1110
  '/login': typeof LoginLoginRouteRoute
@@ -1144,10 +1156,10 @@ export interface FileRoutesByFullPath {
1144
1156
  '/settings/agents': typeof NavSettingsAgentsRouteRoute
1145
1157
  '/settings/ai': typeof NavSettingsAiRouteRouteWithChildren
1146
1158
  '/settings/billing': typeof NavSettingsBillingRouteRoute
1147
- '/settings/connection': typeof NavSettingsConnectionRouteRoute
1148
1159
  '/settings/general': typeof NavSettingsGeneralRouteRoute
1149
1160
  '/settings/notifications': typeof NavSettingsNotificationsRouteRoute
1150
1161
  '/settings/privacy': typeof NavSettingsPrivacyRouteRoute
1162
+ '/settings/sync': typeof NavSettingsSyncRouteRoute
1151
1163
  '/settings/team': typeof NavSettingsTeamRouteRoute
1152
1164
  '/stories/$storyId': typeof NavStoriesStoryIdRouteRoute
1153
1165
  '/tasks/$taskId': typeof NavTasksTaskIdRouteRoute
@@ -1175,6 +1187,10 @@ export interface FileRoutesByFullPath {
1175
1187
  '/api/knowledge/sync-github': typeof ApiKnowledgeSyncGithubRoute
1176
1188
  '/api/mcp/bugs': typeof ApiMcpBugsRoute
1177
1189
  '/api/notifications/stream': typeof ApiNotificationsStreamRoute
1190
+ '/api/sync/bootstrap': typeof ApiSyncBootstrapRoute
1191
+ '/api/sync/pull': typeof ApiSyncPullRoute
1192
+ '/api/sync/push': typeof ApiSyncPushRoute
1193
+ '/api/sync/snapshot': typeof ApiSyncSnapshotRoute
1178
1194
  '/server/anyhub-proxy/$': typeof ServerAnyhubProxySplatRoute
1179
1195
  '/share/prd/$designId': typeof SharePrdDesignIdRoute
1180
1196
  '/bugs/': typeof NavBugsIndexRoute
@@ -1226,7 +1242,6 @@ export interface FileRoutesByTo {
1226
1242
  '/share': typeof ShareRouteRouteWithChildren
1227
1243
  '/docs': typeof DocsRoute
1228
1244
  '/workspace': typeof WorkspaceRoute
1229
- '/onboarding': typeof _desktopOnboardingRouteRoute
1230
1245
  '/email-unsubscribe': typeof LoginEmailUnsubscribeRouteRoute
1231
1246
  '/forgot-password': typeof LoginForgotPasswordRouteRoute
1232
1247
  '/login': typeof LoginLoginRouteRoute
@@ -1263,10 +1278,10 @@ export interface FileRoutesByTo {
1263
1278
  '/settings/account': typeof NavSettingsAccountRouteRoute
1264
1279
  '/settings/agents': typeof NavSettingsAgentsRouteRoute
1265
1280
  '/settings/billing': typeof NavSettingsBillingRouteRoute
1266
- '/settings/connection': typeof NavSettingsConnectionRouteRoute
1267
1281
  '/settings/general': typeof NavSettingsGeneralRouteRoute
1268
1282
  '/settings/notifications': typeof NavSettingsNotificationsRouteRoute
1269
1283
  '/settings/privacy': typeof NavSettingsPrivacyRouteRoute
1284
+ '/settings/sync': typeof NavSettingsSyncRouteRoute
1270
1285
  '/settings/team': typeof NavSettingsTeamRouteRoute
1271
1286
  '/stories/$storyId': typeof NavStoriesStoryIdRouteRoute
1272
1287
  '/tasks/$taskId': typeof NavTasksTaskIdRouteRoute
@@ -1294,6 +1309,10 @@ export interface FileRoutesByTo {
1294
1309
  '/api/knowledge/sync-github': typeof ApiKnowledgeSyncGithubRoute
1295
1310
  '/api/mcp/bugs': typeof ApiMcpBugsRoute
1296
1311
  '/api/notifications/stream': typeof ApiNotificationsStreamRoute
1312
+ '/api/sync/bootstrap': typeof ApiSyncBootstrapRoute
1313
+ '/api/sync/pull': typeof ApiSyncPullRoute
1314
+ '/api/sync/push': typeof ApiSyncPushRoute
1315
+ '/api/sync/snapshot': typeof ApiSyncSnapshotRoute
1297
1316
  '/server/anyhub-proxy/$': typeof ServerAnyhubProxySplatRoute
1298
1317
  '/share/prd/$designId': typeof SharePrdDesignIdRoute
1299
1318
  '/bugs': typeof NavBugsIndexRoute
@@ -1349,7 +1368,6 @@ export interface FileRoutesById {
1349
1368
  '/docs': typeof DocsRoute
1350
1369
  '/workspace': typeof WorkspaceRoute
1351
1370
  '/_public/': typeof PublicIndexRouteRoute
1352
- '/__desktop/onboarding': typeof _desktopOnboardingRouteRoute
1353
1371
  '/_login/email-unsubscribe': typeof LoginEmailUnsubscribeRouteRoute
1354
1372
  '/_login/forgot-password': typeof LoginForgotPasswordRouteRoute
1355
1373
  '/_login/login': typeof LoginLoginRouteRoute
@@ -1401,10 +1419,10 @@ export interface FileRoutesById {
1401
1419
  '/_nav/settings/agents': typeof NavSettingsAgentsRouteRoute
1402
1420
  '/_nav/settings/ai': typeof NavSettingsAiRouteRouteWithChildren
1403
1421
  '/_nav/settings/billing': typeof NavSettingsBillingRouteRoute
1404
- '/_nav/settings/connection': typeof NavSettingsConnectionRouteRoute
1405
1422
  '/_nav/settings/general': typeof NavSettingsGeneralRouteRoute
1406
1423
  '/_nav/settings/notifications': typeof NavSettingsNotificationsRouteRoute
1407
1424
  '/_nav/settings/privacy': typeof NavSettingsPrivacyRouteRoute
1425
+ '/_nav/settings/sync': typeof NavSettingsSyncRouteRoute
1408
1426
  '/_nav/settings/team': typeof NavSettingsTeamRouteRoute
1409
1427
  '/_nav/stories/$storyId': typeof NavStoriesStoryIdRouteRoute
1410
1428
  '/_nav/tasks/$taskId': typeof NavTasksTaskIdRouteRoute
@@ -1432,6 +1450,10 @@ export interface FileRoutesById {
1432
1450
  '/api/knowledge/sync-github': typeof ApiKnowledgeSyncGithubRoute
1433
1451
  '/api/mcp/bugs': typeof ApiMcpBugsRoute
1434
1452
  '/api/notifications/stream': typeof ApiNotificationsStreamRoute
1453
+ '/api/sync/bootstrap': typeof ApiSyncBootstrapRoute
1454
+ '/api/sync/pull': typeof ApiSyncPullRoute
1455
+ '/api/sync/push': typeof ApiSyncPushRoute
1456
+ '/api/sync/snapshot': typeof ApiSyncSnapshotRoute
1435
1457
  '/server/anyhub-proxy/$': typeof ServerAnyhubProxySplatRoute
1436
1458
  '/share/prd/$designId': typeof SharePrdDesignIdRoute
1437
1459
  '/_nav/bugs/': typeof NavBugsIndexRoute
@@ -1485,7 +1507,6 @@ export interface FileRouteTypes {
1485
1507
  | '/share'
1486
1508
  | '/docs'
1487
1509
  | '/workspace'
1488
- | '/onboarding'
1489
1510
  | '/email-unsubscribe'
1490
1511
  | '/forgot-password'
1491
1512
  | '/login'
@@ -1537,10 +1558,10 @@ export interface FileRouteTypes {
1537
1558
  | '/settings/agents'
1538
1559
  | '/settings/ai'
1539
1560
  | '/settings/billing'
1540
- | '/settings/connection'
1541
1561
  | '/settings/general'
1542
1562
  | '/settings/notifications'
1543
1563
  | '/settings/privacy'
1564
+ | '/settings/sync'
1544
1565
  | '/settings/team'
1545
1566
  | '/stories/$storyId'
1546
1567
  | '/tasks/$taskId'
@@ -1568,6 +1589,10 @@ export interface FileRouteTypes {
1568
1589
  | '/api/knowledge/sync-github'
1569
1590
  | '/api/mcp/bugs'
1570
1591
  | '/api/notifications/stream'
1592
+ | '/api/sync/bootstrap'
1593
+ | '/api/sync/pull'
1594
+ | '/api/sync/push'
1595
+ | '/api/sync/snapshot'
1571
1596
  | '/server/anyhub-proxy/$'
1572
1597
  | '/share/prd/$designId'
1573
1598
  | '/bugs/'
@@ -1619,7 +1644,6 @@ export interface FileRouteTypes {
1619
1644
  | '/share'
1620
1645
  | '/docs'
1621
1646
  | '/workspace'
1622
- | '/onboarding'
1623
1647
  | '/email-unsubscribe'
1624
1648
  | '/forgot-password'
1625
1649
  | '/login'
@@ -1656,10 +1680,10 @@ export interface FileRouteTypes {
1656
1680
  | '/settings/account'
1657
1681
  | '/settings/agents'
1658
1682
  | '/settings/billing'
1659
- | '/settings/connection'
1660
1683
  | '/settings/general'
1661
1684
  | '/settings/notifications'
1662
1685
  | '/settings/privacy'
1686
+ | '/settings/sync'
1663
1687
  | '/settings/team'
1664
1688
  | '/stories/$storyId'
1665
1689
  | '/tasks/$taskId'
@@ -1687,6 +1711,10 @@ export interface FileRouteTypes {
1687
1711
  | '/api/knowledge/sync-github'
1688
1712
  | '/api/mcp/bugs'
1689
1713
  | '/api/notifications/stream'
1714
+ | '/api/sync/bootstrap'
1715
+ | '/api/sync/pull'
1716
+ | '/api/sync/push'
1717
+ | '/api/sync/snapshot'
1690
1718
  | '/server/anyhub-proxy/$'
1691
1719
  | '/share/prd/$designId'
1692
1720
  | '/bugs'
@@ -1741,7 +1769,6 @@ export interface FileRouteTypes {
1741
1769
  | '/docs'
1742
1770
  | '/workspace'
1743
1771
  | '/_public/'
1744
- | '/__desktop/onboarding'
1745
1772
  | '/_login/email-unsubscribe'
1746
1773
  | '/_login/forgot-password'
1747
1774
  | '/_login/login'
@@ -1793,10 +1820,10 @@ export interface FileRouteTypes {
1793
1820
  | '/_nav/settings/agents'
1794
1821
  | '/_nav/settings/ai'
1795
1822
  | '/_nav/settings/billing'
1796
- | '/_nav/settings/connection'
1797
1823
  | '/_nav/settings/general'
1798
1824
  | '/_nav/settings/notifications'
1799
1825
  | '/_nav/settings/privacy'
1826
+ | '/_nav/settings/sync'
1800
1827
  | '/_nav/settings/team'
1801
1828
  | '/_nav/stories/$storyId'
1802
1829
  | '/_nav/tasks/$taskId'
@@ -1824,6 +1851,10 @@ export interface FileRouteTypes {
1824
1851
  | '/api/knowledge/sync-github'
1825
1852
  | '/api/mcp/bugs'
1826
1853
  | '/api/notifications/stream'
1854
+ | '/api/sync/bootstrap'
1855
+ | '/api/sync/pull'
1856
+ | '/api/sync/push'
1857
+ | '/api/sync/snapshot'
1827
1858
  | '/server/anyhub-proxy/$'
1828
1859
  | '/share/prd/$designId'
1829
1860
  | '/_nav/bugs/'
@@ -1878,7 +1909,6 @@ export interface RootRouteChildren {
1878
1909
  ShareRouteRoute: typeof ShareRouteRouteWithChildren
1879
1910
  DocsRoute: typeof DocsRoute
1880
1911
  WorkspaceRoute: typeof WorkspaceRoute
1881
- _desktopOnboardingRouteRoute: typeof _desktopOnboardingRouteRoute
1882
1912
  CollectTokenRouteRoute: typeof CollectTokenRouteRoute
1883
1913
  InviteTokenRouteRoute: typeof InviteTokenRouteRoute
1884
1914
  ApiBillingWebhookRoute: typeof ApiBillingWebhookRoute
@@ -1906,6 +1936,10 @@ export interface RootRouteChildren {
1906
1936
  ApiKnowledgeSyncGithubRoute: typeof ApiKnowledgeSyncGithubRoute
1907
1937
  ApiMcpBugsRoute: typeof ApiMcpBugsRoute
1908
1938
  ApiNotificationsStreamRoute: typeof ApiNotificationsStreamRoute
1939
+ ApiSyncBootstrapRoute: typeof ApiSyncBootstrapRoute
1940
+ ApiSyncPullRoute: typeof ApiSyncPullRoute
1941
+ ApiSyncPushRoute: typeof ApiSyncPushRoute
1942
+ ApiSyncSnapshotRoute: typeof ApiSyncSnapshotRoute
1909
1943
  ServerAnyhubProxySplatRoute: typeof ServerAnyhubProxySplatRoute
1910
1944
  ApiAttachmentsIdContentRoute: typeof ApiAttachmentsIdContentRoute
1911
1945
  ApiTestRunsRunIdEventsRoute: typeof ApiTestRunsRunIdEventsRoute
@@ -1957,13 +1991,6 @@ declare module '@tanstack/react-router' {
1957
1991
  preLoaderRoute: typeof WorkspaceRouteImport
1958
1992
  parentRoute: typeof rootRouteImport
1959
1993
  }
1960
- '/__desktop/onboarding': {
1961
- id: '/__desktop/onboarding'
1962
- path: '/onboarding'
1963
- fullPath: '/onboarding'
1964
- preLoaderRoute: typeof _desktopOnboardingRouteRouteImport
1965
- parentRoute: typeof rootRouteImport
1966
- }
1967
1994
  '/_login/email-unsubscribe': {
1968
1995
  id: '/_login/email-unsubscribe'
1969
1996
  path: '/email-unsubscribe'
@@ -2363,13 +2390,6 @@ declare module '@tanstack/react-router' {
2363
2390
  preLoaderRoute: typeof NavSettingsBillingRouteRouteImport
2364
2391
  parentRoute: typeof NavSettingsRouteRoute
2365
2392
  }
2366
- '/_nav/settings/connection': {
2367
- id: '/_nav/settings/connection'
2368
- path: '/connection'
2369
- fullPath: '/settings/connection'
2370
- preLoaderRoute: typeof NavSettingsConnectionRouteRouteImport
2371
- parentRoute: typeof NavSettingsRouteRoute
2372
- }
2373
2393
  '/_nav/settings/general': {
2374
2394
  id: '/_nav/settings/general'
2375
2395
  path: '/general'
@@ -2391,6 +2411,13 @@ declare module '@tanstack/react-router' {
2391
2411
  preLoaderRoute: typeof NavSettingsPrivacyRouteRouteImport
2392
2412
  parentRoute: typeof NavSettingsRouteRoute
2393
2413
  }
2414
+ '/_nav/settings/sync': {
2415
+ id: '/_nav/settings/sync'
2416
+ path: '/sync'
2417
+ fullPath: '/settings/sync'
2418
+ preLoaderRoute: typeof NavSettingsSyncRouteRouteImport
2419
+ parentRoute: typeof NavSettingsRouteRoute
2420
+ }
2394
2421
  '/_nav/settings/team': {
2395
2422
  id: '/_nav/settings/team'
2396
2423
  path: '/team'
@@ -2573,6 +2600,34 @@ declare module '@tanstack/react-router' {
2573
2600
  preLoaderRoute: typeof ApiNotificationsStreamRouteImport
2574
2601
  parentRoute: typeof rootRouteImport
2575
2602
  }
2603
+ '/api/sync/bootstrap': {
2604
+ id: '/api/sync/bootstrap'
2605
+ path: '/api/sync/bootstrap'
2606
+ fullPath: '/api/sync/bootstrap'
2607
+ preLoaderRoute: typeof ApiSyncBootstrapRouteImport
2608
+ parentRoute: typeof rootRouteImport
2609
+ }
2610
+ '/api/sync/pull': {
2611
+ id: '/api/sync/pull'
2612
+ path: '/api/sync/pull'
2613
+ fullPath: '/api/sync/pull'
2614
+ preLoaderRoute: typeof ApiSyncPullRouteImport
2615
+ parentRoute: typeof rootRouteImport
2616
+ }
2617
+ '/api/sync/push': {
2618
+ id: '/api/sync/push'
2619
+ path: '/api/sync/push'
2620
+ fullPath: '/api/sync/push'
2621
+ preLoaderRoute: typeof ApiSyncPushRouteImport
2622
+ parentRoute: typeof rootRouteImport
2623
+ }
2624
+ '/api/sync/snapshot': {
2625
+ id: '/api/sync/snapshot'
2626
+ path: '/api/sync/snapshot'
2627
+ fullPath: '/api/sync/snapshot'
2628
+ preLoaderRoute: typeof ApiSyncSnapshotRouteImport
2629
+ parentRoute: typeof rootRouteImport
2630
+ }
2576
2631
  '/server/anyhub-proxy/$': {
2577
2632
  id: '/server/anyhub-proxy/$'
2578
2633
  path: '/server/anyhub-proxy/$'
@@ -3138,10 +3193,10 @@ interface NavSettingsRouteRouteChildren {
3138
3193
  NavSettingsAgentsRouteRoute: typeof NavSettingsAgentsRouteRoute
3139
3194
  NavSettingsAiRouteRoute: typeof NavSettingsAiRouteRouteWithChildren
3140
3195
  NavSettingsBillingRouteRoute: typeof NavSettingsBillingRouteRoute
3141
- NavSettingsConnectionRouteRoute: typeof NavSettingsConnectionRouteRoute
3142
3196
  NavSettingsGeneralRouteRoute: typeof NavSettingsGeneralRouteRoute
3143
3197
  NavSettingsNotificationsRouteRoute: typeof NavSettingsNotificationsRouteRoute
3144
3198
  NavSettingsPrivacyRouteRoute: typeof NavSettingsPrivacyRouteRoute
3199
+ NavSettingsSyncRouteRoute: typeof NavSettingsSyncRouteRoute
3145
3200
  NavSettingsTeamRouteRoute: typeof NavSettingsTeamRouteRoute
3146
3201
  }
3147
3202
 
@@ -3150,10 +3205,10 @@ const NavSettingsRouteRouteChildren: NavSettingsRouteRouteChildren = {
3150
3205
  NavSettingsAgentsRouteRoute: NavSettingsAgentsRouteRoute,
3151
3206
  NavSettingsAiRouteRoute: NavSettingsAiRouteRouteWithChildren,
3152
3207
  NavSettingsBillingRouteRoute: NavSettingsBillingRouteRoute,
3153
- NavSettingsConnectionRouteRoute: NavSettingsConnectionRouteRoute,
3154
3208
  NavSettingsGeneralRouteRoute: NavSettingsGeneralRouteRoute,
3155
3209
  NavSettingsNotificationsRouteRoute: NavSettingsNotificationsRouteRoute,
3156
3210
  NavSettingsPrivacyRouteRoute: NavSettingsPrivacyRouteRoute,
3211
+ NavSettingsSyncRouteRoute: NavSettingsSyncRouteRoute,
3157
3212
  NavSettingsTeamRouteRoute: NavSettingsTeamRouteRoute,
3158
3213
  }
3159
3214
 
@@ -3342,7 +3397,6 @@ const rootRouteChildren: RootRouteChildren = {
3342
3397
  ShareRouteRoute: ShareRouteRouteWithChildren,
3343
3398
  DocsRoute: DocsRoute,
3344
3399
  WorkspaceRoute: WorkspaceRoute,
3345
- _desktopOnboardingRouteRoute: _desktopOnboardingRouteRoute,
3346
3400
  CollectTokenRouteRoute: CollectTokenRouteRoute,
3347
3401
  InviteTokenRouteRoute: InviteTokenRouteRoute,
3348
3402
  ApiBillingWebhookRoute: ApiBillingWebhookRoute,
@@ -3370,6 +3424,10 @@ const rootRouteChildren: RootRouteChildren = {
3370
3424
  ApiKnowledgeSyncGithubRoute: ApiKnowledgeSyncGithubRoute,
3371
3425
  ApiMcpBugsRoute: ApiMcpBugsRoute,
3372
3426
  ApiNotificationsStreamRoute: ApiNotificationsStreamRoute,
3427
+ ApiSyncBootstrapRoute: ApiSyncBootstrapRoute,
3428
+ ApiSyncPullRoute: ApiSyncPullRoute,
3429
+ ApiSyncPushRoute: ApiSyncPushRoute,
3430
+ ApiSyncSnapshotRoute: ApiSyncSnapshotRoute,
3373
3431
  ServerAnyhubProxySplatRoute: ServerAnyhubProxySplatRoute,
3374
3432
  ApiAttachmentsIdContentRoute: ApiAttachmentsIdContentRoute,
3375
3433
  ApiTestRunsRunIdEventsRoute: ApiTestRunsRunIdEventsRoute,
@@ -25,6 +25,17 @@ import { CommandPalette } from '@/components/command/command-palette'
25
25
  import type { Session } from '@/lib/auth/auth-client'
26
26
  import { usePresenceReport } from '@/lib/collab/use-presence-report'
27
27
  import { NavigationIndicator } from './-components/navigation-indicator'
28
+ import { isDesktopEdition } from '@/lib/edition-desktop'
29
+
30
+ // 桌面壳顶缘拖动条:内容区顶部没有可吸附的顶栏组件,窗口上缘条补齐
31
+ // 「整个顶部区域可拖动」(侧栏 header 已整块 drag,见 app-sidebar.tsx)。
32
+ // h-11 覆盖侧栏第一行 + 内容区上缘(用户红框区域)。z-0 是层叠关键:
33
+ // Sidebar 容器 fixed z-10(stacking context),条必须低于它让按钮可点、
34
+ // 高于内容区(非定位)拿拖动命中。浏览器/云端部署 no-op。
35
+ function DesktopDragStrip() {
36
+ if (!isDesktopEdition()) return null
37
+ return <div aria-hidden className="app-region-drag fixed inset-x-0 top-0 z-0 h-11" />
38
+ }
28
39
 
29
40
  export const Route = createLazyFileRoute('/_nav')({
30
41
  component: AppLayout,
@@ -40,6 +51,7 @@ function AppLayout() {
40
51
  return (
41
52
  <>
42
53
  <NavigationIndicator />
54
+ <DesktopDragStrip />
43
55
  <TimezoneBootstrap timezone={session?.user?.timezone} />
44
56
  <LayoutResponsiveProvider>
45
57
  <SubscriptionProvider>
@@ -65,7 +65,7 @@ const groups: SettingsGroup[] = [
65
65
  const desktopGroups: SettingsGroup[] = [
66
66
  {
67
67
  title: m.settings_tabs_desktop,
68
- tabs: [{ label: m.settings_tabs_connectionMode, path: '/settings/connection', icon: Plug }],
68
+ tabs: [{ label: m.settings_tabs_sync, path: '/settings/sync', icon: Plug }],
69
69
  },
70
70
  ]
71
71
 
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+
5
+ import { createLazyFileRoute } from '@tanstack/react-router'
6
+ import { DesktopCloudLogin } from '@/components/desktop/cloud-login'
7
+ import { DesktopConflictCenter } from '@/components/desktop/conflict-center'
8
+ import { DesktopSyncStatusCard } from '@/components/desktop/sync-status-card'
9
+
10
+ export const Route = createLazyFileRoute('/_nav/settings/sync')({
11
+ component: SyncSettingsPage,
12
+ })
13
+
14
+ function SyncSettingsPage() {
15
+ return (
16
+ <div className="flex max-w-3xl flex-col gap-6 p-6">
17
+ <div>
18
+ <h2 className="text-lg font-semibold">同步</h2>
19
+ <p className="text-sm text-muted-foreground">
20
+ 本地优先存储,登录云端账号后可多端同步。断网时照常编辑,恢复后自动推送。
21
+ </p>
22
+ </div>
23
+
24
+ <section className="space-y-3 rounded-lg border p-4">
25
+ <h3 className="text-sm font-medium">云端账号</h3>
26
+ <DesktopCloudLogin />
27
+ </section>
28
+
29
+ <section className="space-y-3 rounded-lg border p-4">
30
+ <h3 className="text-sm font-medium">同步状态</h3>
31
+ <DesktopSyncStatusCard />
32
+ </section>
33
+
34
+ <section className="space-y-3 rounded-lg border p-4">
35
+ <h3 className="text-sm font-medium">冲突处理</h3>
36
+ <DesktopConflictCenter />
37
+ </section>
38
+ </div>
39
+ )
40
+ }
@@ -0,0 +1,15 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+
5
+ // 桌面同步设置页(迁移设计 §3.5/§3.7):云端账号登录桥 + 冲突中心。
6
+ // 仅桌面端可访问(beforeLoad 守卫复用 VITE_DEPLOY_TARGET,与 connection 页同口径)。
7
+ import { createFileRoute, redirect } from '@tanstack/react-router'
8
+
9
+ export const Route = createFileRoute('/_nav/settings/sync')({
10
+ beforeLoad: () => {
11
+ if (import.meta.env.VITE_DEPLOY_TARGET !== 'desktop') {
12
+ throw redirect({ to: '/settings' })
13
+ }
14
+ },
15
+ })
@@ -20,10 +20,9 @@
20
20
  // 标题/指令 includes 匹配)、右簇「新建任务」;@container 行由 flex-col 直排
21
21
  // 拿满宽(页面容器 h-full p-4 应用式,无需 min-w-0 包装)。数据来自 index.tsx
22
22
  // beforeLoad context(Route.useRouteContext);AI 任务创建触发 CreateAiTaskDialog;
23
- // 桌面端降级(ai.degraded)时禁用新建并提示。Skeleton pending 由 index.tsx 承担。
23
+ // 历史 sqlite 降级(ai.degraded)已随 Tauri 清退移除(迁移 P1)。Skeleton pending 由 index.tsx 承担。
24
24
  import { useState } from "react";
25
25
  import { createLazyFileRoute } from "@tanstack/react-router";
26
- import { Alert, AlertDescription } from "@/components/ui/alert";
27
26
  import { Button } from "@/components/ui/button";
28
27
  import { Input } from "@/components/ui/input";
29
28
  import {
@@ -47,7 +46,6 @@ function TasksIndexPage() {
47
46
  const { assigned, ai } = Route.useRouteContext();
48
47
  const [createOpen, setCreateOpen] = useState(false);
49
48
  const [search, setSearch] = useState("");
50
- const desktopDegraded = ai.degraded === true;
51
49
  const filtered = useTaskFilter(search, assigned, ai.items);
52
50
 
53
51
  return (
@@ -75,7 +73,6 @@ function TasksIndexPage() {
75
73
  <Button
76
74
  size="sm"
77
75
  onClick={() => setCreateOpen(true)}
78
- disabled={desktopDegraded}
79
76
  >
80
77
  <CREATE_ICON data-icon="inline-start" />
81
78
  {m.tasks_create_new()}
@@ -87,16 +84,9 @@ function TasksIndexPage() {
87
84
  <AssignedList result={filtered.assigned} searching={filtered.searching} />
88
85
  </TabsContent>
89
86
  <TabsContent value="ai" className="flex flex-col gap-3">
90
- {desktopDegraded ? (
91
- <Alert>
92
- <AlertDescription>{m.tasks_ai_desktop_notice()}</AlertDescription>
93
- </Alert>
94
- ) : null}
95
87
  <AiTaskList
96
88
  items={filtered.ai}
97
89
  onRequestCreate={() => setCreateOpen(true)}
98
- createDisabled={desktopDegraded}
99
- runDisabled={desktopDegraded}
100
90
  searching={filtered.searching}
101
91
  />
102
92
  </TabsContent>
@@ -38,8 +38,12 @@ export const Route = createFileRoute('/api/billing-webhook')({
38
38
  return new Response('Billing module unavailable', { status: 501 })
39
39
  }
40
40
  try {
41
- await billing.handleWebhookEvent(rawBody, signature)
42
- await sendBillingEmailForEvent(rawBody, signature, billing)
41
+ const result = await billing.handleWebhookEvent(rawBody, signature)
42
+ // 审计 M13:幂等命中的重投事件跳过幂等门外的邮件链路,防重复收据;
43
+ // 旧版 Pro 包无 alreadyProcessed 字段,按未命中处理(行为不变)
44
+ if (!result.alreadyProcessed) {
45
+ await sendBillingEmailForEvent(rawBody, signature, billing)
46
+ }
43
47
  return new Response(JSON.stringify({ received: true }), {
44
48
  status: 200,
45
49
  headers: { 'Content-Type': 'application/json' },
@@ -0,0 +1,38 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+
5
+ // bootstrap 端点(迁移设计 §3.4):返回当前水位 + 各表行数。首登快照拉取
6
+ // 按 (table, pk) 分页全量行(后续端点),完成后续走 last_seq = watermark 增量
7
+ // ——不依赖 change_log 从头回放(30 天滚动清理)。
8
+ import { createFileRoute } from "@tanstack/react-router"
9
+ import { getRequest } from "@tanstack/react-start/server"
10
+ import { getPrisma } from "@allbluecn/database/get-prisma"
11
+ import { requireAuth } from "@/server/auth-helpers"
12
+ import { resolveSyncScopes } from "@/server/sync/scopes"
13
+ import { SYNC_TABLES } from "@allbluecn/sync-core/registrations"
14
+
15
+ export const Route = createFileRoute("/api/sync/bootstrap")({
16
+ server: {
17
+ handlers: {
18
+ GET: async () => {
19
+ const session = await requireAuth(getRequest())
20
+ const prisma = await getPrisma()
21
+
22
+ const [{ seq }] = await prisma.$queryRawUnsafe<Array<{ seq: bigint }>>(
23
+ `SELECT COALESCE(MAX(seq), 0) AS seq FROM sync_change_log`,
24
+ )
25
+ const counts = await Promise.all(
26
+ SYNC_TABLES.map(async (reg) => {
27
+ const [r] = await prisma.$queryRawUnsafe<Array<{ c: bigint }>>(
28
+ `SELECT COUNT(*)::bigint AS c FROM ${reg.table}`,
29
+ )
30
+ return { name: reg.table, count: Number(r.c) }
31
+ }),
32
+ )
33
+ void resolveSyncScopes // scopes 解析在快照分页端点逐页执行(此处仅鉴权)
34
+ return Response.json({ watermarkSeq: Number(seq), tables: counts })
35
+ },
36
+ },
37
+ },
38
+ })