@xopcai/xopc 0.0.308 → 0.0.309

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 (181) hide show
  1. package/dist/browser-ext/_locales/en/messages.json +8 -0
  2. package/dist/browser-ext/_locales/zh_CN/messages.json +8 -0
  3. package/dist/browser-ext/dist/assets/{sidepanel-BbSQr-6P.css → sidepanel-DD6GEMvc.css} +16 -0
  4. package/dist/browser-ext/dist/sidepanel.html +1 -1
  5. package/dist/browser-ext/dist/sidepanel.js +537 -96
  6. package/dist/browser-ext/manifest.json +1 -1
  7. package/dist/extensions/telegram/xopc.extension.json +1 -1
  8. package/dist/gateway/static/root/assets/{activity-store-wgSB2HYK.js → activity-store-XKNYlFUI.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dUotwUO6.js → agent-avatar-dicebear-1S2TFECE.js} +1 -1
  10. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-C6LflMXr.js → agent-defaults-settings-panel-f0-YFMUz.js} +1 -1
  11. package/dist/gateway/static/root/assets/{agents-VPDIGRSS.js → agents-CPqUMtCL.js} +1 -1
  12. package/dist/gateway/static/root/assets/{api-BKHmTb0w.js → api-BEUEE4f2.js} +1 -1
  13. package/dist/gateway/static/root/assets/api-CN4id43t.js +1 -0
  14. package/dist/gateway/static/root/assets/{app-management-settings-panel-zPz0rOND.js → app-management-settings-panel-CgVBSqzu.js} +1 -1
  15. package/dist/gateway/static/root/assets/{appearance-settings-DhvhR43G.js → appearance-settings-CoWdCokb.js} +1 -1
  16. package/dist/gateway/static/root/assets/{apps-page-Pmslbzzr.js → apps-page-CexHOcWg.js} +1 -1
  17. package/dist/gateway/static/root/assets/{archive-plugin-BQVZMreT.js → archive-plugin-C3ZA6LRS.js} +1 -1
  18. package/dist/gateway/static/root/assets/{attachment-load-CPE-TMPf.js → attachment-load-CdgS6_zy.js} +1 -1
  19. package/dist/gateway/static/root/assets/{automations-page-C4IAy_zF.js → automations-page-BtHL2hpg.js} +1 -1
  20. package/dist/gateway/static/root/assets/{automations-workspace-Fx5VUJRu.js → automations-workspace-onJPfmO6.js} +1 -1
  21. package/dist/gateway/static/root/assets/{binary-plugins-DgTl7diZ.js → binary-plugins-CiDhtq_H.js} +1 -1
  22. package/dist/gateway/static/root/assets/{block-editor-CcOVA-Gw.js → block-editor-Br00T83w.js} +1 -1
  23. package/dist/gateway/static/root/assets/{browser-automation-inputs-BzkJog8e.js → browser-automation-inputs-D2tILykA.js} +1 -1
  24. package/dist/gateway/static/root/assets/{browser-automations-page--zKAgj1k.js → browser-automations-page-BVuEmryB.js} +1 -1
  25. package/dist/gateway/static/root/assets/{browser-settings-page-DBms6d35.js → browser-settings-page-BgVTyPFY.js} +1 -1
  26. package/dist/gateway/static/root/assets/{capabilities-settings-panel-epdDWIZy.js → capabilities-settings-panel-Dra8wj1S.js} +1 -1
  27. package/dist/gateway/static/root/assets/{channels-settings-B0bsDtmP.js → channels-settings-CkxiMDJ4.js} +1 -1
  28. package/dist/gateway/static/root/assets/{channels-status-swr-B2JwuTjG.js → channels-status-swr-Dtder4G_.js} +1 -1
  29. package/dist/gateway/static/root/assets/{chat-terminal-dock-BfLd2rIJ.js → chat-terminal-dock-JsMtzDao.js} +1 -1
  30. package/dist/gateway/static/root/assets/{computer-settings-page-Ckgc0Py-.js → computer-settings-page-DHerePwo.js} +1 -1
  31. package/dist/gateway/static/root/assets/{connector-service-page-BlC1OXX4.js → connector-service-page-DZFNUTiN.js} +1 -1
  32. package/dist/gateway/static/root/assets/{connectors-page-By33-bF1.js → connectors-page-cl9ZrV4D.js} +1 -1
  33. package/dist/gateway/static/root/assets/{cron-expression-CqNE-nf6.js → cron-expression-DAhdv_Xv.js} +1 -1
  34. package/dist/gateway/static/root/assets/{date-picker-BS9ZjzYJ.js → date-picker-PacO1m3a.js} +1 -1
  35. package/dist/gateway/static/root/assets/{dependency-picker-CF_zYzxX.js → dependency-picker-B-BcuG1y.js} +1 -1
  36. package/dist/gateway/static/root/assets/{desktop-pet-CDwtLR7Z.js → desktop-pet-CdBBhhdY.js} +1 -1
  37. package/dist/gateway/static/root/assets/{desktop-pet-settings-C0djIc1J.js → desktop-pet-settings-Gy03NgMI.js} +1 -1
  38. package/dist/gateway/static/root/assets/{device-pairing-wizard-CDKj9LQj.js → device-pairing-wizard-aV25nKag.js} +1 -1
  39. package/dist/gateway/static/root/assets/{extension-debug-page-CX5OXxEU.js → extension-debug-page-BFp5eKtY.js} +1 -1
  40. package/dist/gateway/static/root/assets/{extension-page-BytR1PaY.js → extension-page-DL3vyyH6.js} +1 -1
  41. package/dist/gateway/static/root/assets/{extension-settings-page-CkaMJA5F.js → extension-settings-page-BXtvdAsY.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-config-swr-B6wHa6ZI.js → gateway-config-swr-xAOGtenO.js} +1 -1
  43. package/dist/gateway/static/root/assets/{gateway-realtime-B53R0CA4.js → gateway-realtime-BuaTsMSi.js} +1 -1
  44. package/dist/gateway/static/root/assets/gateway-realtime-store-BG95uGVW.js +1 -0
  45. package/dist/gateway/static/root/assets/{gateway-settings-_YU-1p0z.js → gateway-settings-Dcr2Ikeh.js} +1 -1
  46. package/dist/gateway/static/root/assets/{gateway-startup-retry-DRzGnEV-.js → gateway-startup-retry-BwDxKHd4.js} +1 -1
  47. package/dist/gateway/static/root/assets/{heartbeat-settings-CVIvvm4x.js → heartbeat-settings-DOy3alvT.js} +1 -1
  48. package/dist/gateway/static/root/assets/{home-page-COCHelcL.js → home-page-CDm3dGVy.js} +1 -1
  49. package/dist/gateway/static/root/assets/{image-generation-api-Ck_pyDom.js → image-generation-api-wGMeI_yW.js} +1 -1
  50. package/dist/gateway/static/root/assets/{imports-page-DrtbjL8O.js → imports-page-zexFT5Rq.js} +1 -1
  51. package/dist/gateway/static/root/assets/index-D-vczw_0.css +1 -0
  52. package/dist/gateway/static/root/assets/{index-CDfcPiPb.js → index-DJo4DimT.js} +47 -47
  53. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BlZh41Xq.js → keyboard-shortcuts-settings-CutG9zLh.js} +1 -1
  54. package/dist/gateway/static/root/assets/{local-app-workbench-page-D7_Raxjw.js → local-app-workbench-page-CwLvTwjn.js} +1 -1
  55. package/dist/gateway/static/root/assets/{local-apps-page-DbP7wWuh.js → local-apps-page-CJy6I7Dt.js} +1 -1
  56. package/dist/gateway/static/root/assets/{locale-store-msTfRK8P.js → locale-store-DPZ79W1-.js} +1 -1
  57. package/dist/gateway/static/root/assets/{logs-page-C0n66FiO.js → logs-page-egGcPHNi.js} +1 -1
  58. package/dist/gateway/static/root/assets/{management-settings-i6GhxpGV.js → management-settings-BQhIOELc.js} +1 -1
  59. package/dist/gateway/static/root/assets/{markdown-view-BInabSKf.js → markdown-view-p2P5hP1U.js} +1 -1
  60. package/dist/gateway/static/root/assets/{media-plugins-CnWChQ3Y.js → media-plugins-CsBylqlN.js} +1 -1
  61. package/dist/gateway/static/root/assets/messages-BiYTyLJr.js +3 -0
  62. package/dist/gateway/static/root/assets/{note-detail-panel-C59d8vDW.js → note-detail-panel-c2k5Uz6X.js} +3 -3
  63. package/dist/gateway/static/root/assets/{notes-page-C1GBPrVI.js → notes-page-BLQWJMhf.js} +1 -1
  64. package/dist/gateway/static/root/assets/{page-tabs-BWitjb3e.js → page-tabs-ChQ4jJFs.js} +1 -1
  65. package/dist/gateway/static/root/assets/{preview-open-alternatives-UaCWCxZv.js → preview-open-alternatives-9B5W7nVE.js} +1 -1
  66. package/dist/gateway/static/root/assets/{proactive-page-CtSFJxoM.js → proactive-page-iOjI0d_e.js} +1 -1
  67. package/dist/gateway/static/root/assets/{product-open-page-gmi5LLwM.js → product-open-page-BADxWEdP.js} +1 -1
  68. package/dist/gateway/static/root/assets/{project-detail-page-ILTmQ1YN.js → project-detail-page-BcxbQn2M.js} +1 -1
  69. package/dist/gateway/static/root/assets/{projects-page-snl4rOQZ.js → projects-page-BuSvld0O.js} +1 -1
  70. package/dist/gateway/static/root/assets/{registry-api-BSWtko7U.js → registry-api-B_e_nZSN.js} +1 -1
  71. package/dist/gateway/static/root/assets/{remote-access-hub-BbaAcEN3.js → remote-access-hub-CFS8LQKW.js} +1 -1
  72. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-CtOjKGWg.js → runtime-tools-settings-panel-D-pwiIyp.js} +1 -1
  73. package/dist/gateway/static/root/assets/{schema-form-DkyyDcl2.js → schema-form-IWmb05DX.js} +1 -1
  74. package/dist/gateway/static/root/assets/{sessions-page-DrWL71O8.js → sessions-page-DZjc__ok.js} +1 -1
  75. package/dist/gateway/static/root/assets/settings-advanced-gate-C1SM5B93.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-form-section-C0JDGN_V.js → settings-form-section-B0veRBZs.js} +1 -1
  77. package/dist/gateway/static/root/assets/{settings-page-DiIyMQ52.js → settings-page-CxRWyWYe.js} +1 -1
  78. package/dist/gateway/static/root/assets/{setup-status-panel-EPazhoZO.js → setup-status-panel-D9Rl7Tec.js} +1 -1
  79. package/dist/gateway/static/root/assets/{share-preview-page-Bt1K657Y.js → share-preview-page-CirpgkfD.js} +1 -1
  80. package/dist/gateway/static/root/assets/{shares-settings-g2MdRXSZ.js → shares-settings-CwCThBs0.js} +1 -1
  81. package/dist/gateway/static/root/assets/skill-reload-api-DG6VGbOX.js +1 -0
  82. package/dist/gateway/static/root/assets/{skills-page-Wd0uYSPG.js → skills-page-BdRJ2vnL.js} +1 -1
  83. package/dist/gateway/static/root/assets/{skills-page.utils-vq5Ujm03.js → skills-page.utils-B42mpWKV.js} +1 -1
  84. package/dist/gateway/static/root/assets/{system-settings-panel-Cz1P-HDH.js → system-settings-panel-DXIZpAvU.js} +1 -1
  85. package/dist/gateway/static/root/assets/{task-detail-page-BG3A5gPZ.js → task-detail-page-QXo9LJly.js} +1 -1
  86. package/dist/gateway/static/root/assets/{theme-store-1SZ-HFHX.js → theme-store-BFbj_2Tu.js} +1 -1
  87. package/dist/gateway/static/root/assets/{tunnel-api-DQGoFuZO.js → tunnel-api-Db2guRdW.js} +1 -1
  88. package/dist/gateway/static/root/assets/{use-autosave-DVDlBb95.js → use-autosave-DDY9qoXZ.js} +1 -1
  89. package/dist/gateway/static/root/assets/{user-model-page-qM5UiTGx.js → user-model-page-CzPmMkaO.js} +1 -1
  90. package/dist/gateway/static/root/assets/{voice-api-key-field-B2pZCcxY.js → voice-api-key-field-BZbKQ8HT.js} +1 -1
  91. package/dist/gateway/static/root/assets/{voice-config-api-DgJML_uM.js → voice-config-api-SKCeQLrH.js} +1 -1
  92. package/dist/gateway/static/root/assets/{work-discovery-overlay-Bptv7bEY.js → work-discovery-overlay-BRVTTXNG.js} +1 -1
  93. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BijCrNc4.js → workflow-run-setup-panel-D2kuwv5e.js} +1 -1
  94. package/dist/gateway/static/root/assets/{workflows-page-DRy1RAYH.js → workflows-page-CQXtiYtq.js} +1 -1
  95. package/dist/gateway/static/root/index.html +12 -12
  96. package/dist/package.js +1 -1
  97. package/dist/packages/gateway-contract/src/sessions.js +6 -1
  98. package/dist/src/agent/agent-manager.js +29 -4
  99. package/dist/src/agent/child-agent-factory.d.ts +1 -0
  100. package/dist/src/agent/child-agent-factory.js +18 -4
  101. package/dist/src/agent/coding/repository-instructions.d.ts +4 -0
  102. package/dist/src/agent/coding/repository-instructions.js +46 -2
  103. package/dist/src/agent/data-acquisition/git.d.ts +17 -0
  104. package/dist/src/agent/data-acquisition/git.js +100 -0
  105. package/dist/src/agent/data-acquisition/render.d.ts +7 -0
  106. package/dist/src/agent/data-acquisition/render.js +79 -0
  107. package/dist/src/agent/data-acquisition/scheduler.d.ts +12 -0
  108. package/dist/src/agent/data-acquisition/scheduler.js +53 -0
  109. package/dist/src/agent/data-acquisition/schema.d.ts +75 -0
  110. package/dist/src/agent/data-acquisition/schema.js +206 -0
  111. package/dist/src/agent/data-acquisition/service.d.ts +10 -0
  112. package/dist/src/agent/data-acquisition/service.js +292 -0
  113. package/dist/src/agent/data-acquisition/types.d.ts +37 -0
  114. package/dist/src/agent/data-acquisition/types.js +5 -0
  115. package/dist/src/agent/embedded/run-turn.js +16 -4
  116. package/dist/src/agent/embedded/session-runner.d.ts +1 -0
  117. package/dist/src/agent/embedded/session-runner.js +3 -0
  118. package/dist/src/agent/embedded/tool-result-truncation.js +11 -0
  119. package/dist/src/agent/embedded/xopc-tools-bridge.js +2 -1
  120. package/dist/src/agent/external-tools/composio-provider.js +12 -1
  121. package/dist/src/agent/external-tools/gateway-tools.js +2 -1
  122. package/dist/src/agent/external-tools/index.js +8 -1
  123. package/dist/src/agent/external-tools/read-policy.d.ts +6 -0
  124. package/dist/src/agent/external-tools/read-policy.js +21 -0
  125. package/dist/src/agent/external-tools/service.d.ts +1 -0
  126. package/dist/src/agent/external-tools/service.js +4 -1
  127. package/dist/src/agent/external-tools/types.d.ts +2 -0
  128. package/dist/src/agent/orchestration/agent-turn-policy.js +25 -10
  129. package/dist/src/agent/orchestration/delegation-scope.d.ts +9 -0
  130. package/dist/src/agent/orchestration/delegation-scope.js +11 -0
  131. package/dist/src/agent/prompt/sections/tooling.js +3 -1
  132. package/dist/src/agent/prompt/subagent-context.js +4 -2
  133. package/dist/src/agent/sandbox/fileAccess.d.ts +2 -0
  134. package/dist/src/agent/sandbox/fileAccess.js +31 -2
  135. package/dist/src/agent/tools/dataBatch.d.ts +4 -0
  136. package/dist/src/agent/tools/dataBatch.js +50 -0
  137. package/dist/src/agent/tools/delegate-tool.d.ts +6 -3
  138. package/dist/src/agent/tools/delegate-tool.js +65 -48
  139. package/dist/src/agent/tools/delegation-parent-policy.d.ts +7 -0
  140. package/dist/src/agent/tools/delegation-parent-policy.js +41 -0
  141. package/dist/src/agent/tools/delegation-policy.d.ts +16 -0
  142. package/dist/src/agent/tools/delegation-policy.js +93 -0
  143. package/dist/src/agent/tools/factory.d.ts +2 -0
  144. package/dist/src/agent/tools/factory.js +42 -3
  145. package/dist/src/agent/tools/fetch-text.d.ts +7 -0
  146. package/dist/src/agent/tools/fetch-text.js +86 -0
  147. package/dist/src/agent/tools/find.js +1 -1
  148. package/dist/src/agent/tools/grep.js +11 -23
  149. package/dist/src/agent/tools/index.d.ts +1 -0
  150. package/dist/src/agent/tools/index.js +2 -1
  151. package/dist/src/agent/tools/knowledge-memory-tool.js +10 -2
  152. package/dist/src/agent/tools/read.js +7 -5
  153. package/dist/src/agent/tools/repository-search.d.ts +12 -2
  154. package/dist/src/agent/tools/repository-search.js +127 -74
  155. package/dist/src/agent/tools/web.js +19 -28
  156. package/dist/src/agent/workflow/subagent-runner.js +25 -3
  157. package/dist/src/agent/workflow/workflow-child-tools.js +13 -8
  158. package/dist/src/agent-config/schema.d.ts +7 -0
  159. package/dist/src/agent-config/schema.js +2 -0
  160. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  161. package/dist/src/config/schema.d.ts +4 -0
  162. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  163. package/dist/src/gateway/heartbeat/service.js +2 -2
  164. package/dist/src/gateway/hono/lib/config-payload.d.ts +2 -0
  165. package/dist/src/gateway/hono/routes/sessions.js +141 -13
  166. package/dist/src/heartbeat/index.js +1 -1
  167. package/dist/src/storage/sqlite/index.d.ts +1 -0
  168. package/dist/src/storage/sqlite/index.js +2 -1
  169. package/dist/src/storage/sqlite/migrations/186_sidebar_layout.sql +16 -0
  170. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  171. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  172. package/dist/src/storage/sqlite/schema.js +1 -1
  173. package/dist/src/storage/sqlite/sidebar-layout-repository.d.ts +12 -0
  174. package/dist/src/storage/sqlite/sidebar-layout-repository.js +53 -0
  175. package/package.json +3 -3
  176. package/dist/gateway/static/root/assets/api-DFOlahZv.js +0 -1
  177. package/dist/gateway/static/root/assets/gateway-realtime-store-BLDgrJ30.js +0 -1
  178. package/dist/gateway/static/root/assets/index-CRu1p38D.css +0 -1
  179. package/dist/gateway/static/root/assets/messages-F74LVAiU.js +0 -3
  180. package/dist/gateway/static/root/assets/settings-advanced-gate-BG0kl4HT.js +0 -1
  181. package/dist/gateway/static/root/assets/skill-reload-api-B1DPzu98.js +0 -1
@@ -2,7 +2,9 @@ import { deleteBrowserTabBinding } from "../../../storage/sqlite/browser-tab-bin
2
2
  import { conversationIdSchema } from "../../../../packages/gateway-contract/src/conversation-identity.js";
3
3
  import { SessionDiscoveryQuerySchema } from "../../../../packages/gateway-contract/src/session-identity.js";
4
4
  import { init_src } from "../../../../packages/gateway-contract/src/index.js";
5
+ import "../../../session/types.js";
5
6
  import { deleteSessionRecord, init_session_repository } from "../../../storage/sqlite/session-repository.js";
7
+ import { SidebarLayoutConflictError, getSidebarLayout, replaceSidebarLayout, sortBySidebarLayout } from "../../../storage/sqlite/sidebar-layout-repository.js";
6
8
  import { ConversationAlreadyExistsError, createConversation, init_conversation_repository } from "../../../storage/sqlite/conversation-repository.js";
7
9
  import { resolveProjectAgentId } from "../../../projects/project-agent.js";
8
10
  import "../../../projects/index.js";
@@ -48,6 +50,21 @@ function parseOffset(value) {
48
50
  const parsed = value ? Number.parseInt(value, 10) : 0;
49
51
  return Number.isFinite(parsed) ? Math.max(0, parsed) : 0;
50
52
  }
53
+ function listAllSidebarProjects(service, options = {}) {
54
+ const items = [];
55
+ let offset = 0;
56
+ while (true) {
57
+ const page = service.projects.listWithSidebarSessions({
58
+ status: "active",
59
+ limit: 50,
60
+ offset,
61
+ ...options
62
+ });
63
+ items.push(...page.items);
64
+ if (!page.hasMore || page.items.length === 0) return items;
65
+ offset += page.items.length;
66
+ }
67
+ }
51
68
  function isHistoryCursor(value) {
52
69
  if (!/^(0|[1-9]\d*)$/.test(value)) return false;
53
70
  return Number.isSafeInteger(Number(value));
@@ -101,18 +118,25 @@ function registerSessionsRoutes(authenticated, deps) {
101
118
  const staleDays = parsePositiveInt(c.req.query("staleDays"), DEFAULT_SIDEBAR_STALE_DAYS, 3650);
102
119
  const updatedAfter = Date.now() - staleDays * 24 * 60 * 60 * 1e3;
103
120
  const includeConversationId = c.req.query("includeConversationId")?.trim() || void 0;
104
- const projects = service.projects.listWithSidebarSessions({
105
- status: "active",
106
- limit: projectLimit,
107
- offset: projectOffset,
121
+ const allProjectItems = listAllSidebarProjects(service, {
108
122
  updatedAfter,
109
123
  includePinned: true,
110
124
  includeConversationId
111
125
  });
126
+ const projectLayout = getSidebarLayout("projects");
127
+ const orderedProjects = sortBySidebarLayout(allProjectItems, projectLayout, (project) => project.id);
128
+ const projects = {
129
+ items: orderedProjects.slice(projectOffset, projectOffset + projectLimit),
130
+ total: orderedProjects.length,
131
+ limit: projectLimit,
132
+ offset: projectOffset,
133
+ hasMore: projectOffset + projectLimit < orderedProjects.length
134
+ };
112
135
  const projectItems = await Promise.all(projects.items.map(async (project) => {
113
- const sessions = await service.sessions.listSessions({
136
+ const sessionLayout = getSidebarLayout(`project:${project.id}`);
137
+ const allSessions = await service.sessions.listSessions({
114
138
  projectId: project.id,
115
- limit: sessionPreviewLimit,
139
+ limit: 5e3,
116
140
  offset: 0,
117
141
  updatedAfter,
118
142
  includePinned: true,
@@ -122,21 +146,47 @@ function registerSessionsRoutes(authenticated, deps) {
122
146
  });
123
147
  return {
124
148
  project,
125
- sessions: sessions.items,
126
- sessionTotal: sessions.total,
127
- sessionHasMore: sessions.hasMore
149
+ sessions: sortBySidebarLayout(allSessions.items, sessionLayout, (session) => session.key).slice(0, sessionPreviewLimit),
150
+ sessionTotal: allSessions.total,
151
+ sessionHasMore: sessionPreviewLimit < allSessions.total
128
152
  };
129
153
  }));
130
- const inbox = await service.sessions.listSessions({
154
+ const inboxLayout = getSidebarLayout("inbox");
155
+ const allInbox = await service.sessions.listSessions({
131
156
  unassigned: true,
132
- limit: inboxLimit,
133
- offset: inboxOffset,
157
+ limit: 5e3,
158
+ offset: 0,
134
159
  updatedAfter,
135
160
  includePinned: true,
136
161
  includeConversationId,
137
162
  sortBy: "updatedAt",
138
163
  sortOrder: "desc"
139
164
  });
165
+ const orderedInbox = sortBySidebarLayout(allInbox.items, inboxLayout, (session) => session.key);
166
+ const inbox = {
167
+ ...allInbox,
168
+ items: orderedInbox.slice(inboxOffset, inboxOffset + inboxLimit),
169
+ limit: inboxLimit,
170
+ offset: inboxOffset,
171
+ hasMore: inboxOffset + inboxLimit < allInbox.total
172
+ };
173
+ const pinnedLayout = getSidebarLayout("pinned");
174
+ const pinned = sortBySidebarLayout((await service.sessions.listSessions({
175
+ status: "pinned",
176
+ limit: 5e3,
177
+ offset: 0,
178
+ sortBy: "updatedAt",
179
+ sortOrder: "desc"
180
+ })).items, pinnedLayout, (session) => session.key);
181
+ const layouts = Object.fromEntries([
182
+ projectLayout,
183
+ inboxLayout,
184
+ pinnedLayout,
185
+ ...projects.items.map((project) => getSidebarLayout(`project:${project.id}`))
186
+ ].map((layout) => [layout.containerId, {
187
+ itemIds: layout.itemIds,
188
+ revision: layout.revision
189
+ }]));
140
190
  return c.json({
141
191
  ok: true,
142
192
  projects: {
@@ -146,9 +196,87 @@ function registerSessionsRoutes(authenticated, deps) {
146
196
  offset: projects.offset,
147
197
  hasMore: projects.hasMore
148
198
  },
149
- inbox
199
+ inbox,
200
+ pinned,
201
+ layouts
150
202
  });
151
203
  });
204
+ authenticated.put("/api/sidebar/layouts/:containerId", async (c) => {
205
+ const blocked = ensureGatewayReadyForSessions(c, service, "sessions.list");
206
+ if (blocked) return blocked;
207
+ const containerId = decodeURIComponent(c.req.param("containerId"));
208
+ if (containerId !== "projects" && containerId !== "pinned" && containerId !== "inbox" && !containerId.startsWith("project:")) return c.json({
209
+ ok: false,
210
+ error: "Invalid sidebar container"
211
+ }, 400);
212
+ const body = await c.req.json().catch(() => ({}));
213
+ if (!Array.isArray(body.itemIds) || body.itemIds.length > 5e3 || body.itemIds.some((id) => typeof id !== "string" || !id.trim())) return c.json({
214
+ ok: false,
215
+ error: "itemIds must be an array of non-empty strings"
216
+ }, 400);
217
+ if (!Number.isInteger(body.expectedRevision) || body.expectedRevision < 0) return c.json({
218
+ ok: false,
219
+ error: "expectedRevision must be a non-negative integer"
220
+ }, 400);
221
+ const itemIds = [...new Set(body.itemIds)];
222
+ if (itemIds.length !== body.itemIds.length) return c.json({
223
+ ok: false,
224
+ error: "itemIds must be unique"
225
+ }, 400);
226
+ let completeItemIds = itemIds;
227
+ if (containerId === "projects") {
228
+ if (itemIds.some((id) => !service.projects.get(id))) return c.json({
229
+ ok: false,
230
+ error: "Project not found"
231
+ }, 404);
232
+ const allIds = listAllSidebarProjects(service).map((project) => project.id);
233
+ completeItemIds = [...itemIds, ...allIds.filter((id) => !itemIds.includes(id))];
234
+ } else {
235
+ const projectId = containerId.startsWith("project:") ? containerId.slice(8) : void 0;
236
+ if (projectId && !service.projects.get(projectId)) return c.json({
237
+ ok: false,
238
+ error: "Project not found"
239
+ }, 404);
240
+ if ((await Promise.all(itemIds.map((id) => service.sessions.getSession(id)))).some((session) => {
241
+ if (!session || session.status === "archived") return true;
242
+ if (containerId === "pinned") return session.status !== "pinned";
243
+ if (session.status === "pinned") return true;
244
+ if (containerId === "inbox") return Boolean(session.projectId);
245
+ return session.projectId !== projectId;
246
+ })) return c.json({
247
+ ok: false,
248
+ error: "Sidebar item does not belong to the container"
249
+ }, 409);
250
+ const eligibleIds = (await service.sessions.listSessions({
251
+ ...containerId === "pinned" ? { status: "pinned" } : containerId === "inbox" ? {
252
+ unassigned: true,
253
+ excludeArchived: true
254
+ } : {
255
+ projectId,
256
+ excludeArchived: true
257
+ },
258
+ limit: 5e3,
259
+ offset: 0,
260
+ sortBy: "updatedAt",
261
+ sortOrder: "desc"
262
+ })).items.filter((session) => containerId === "pinned" || session.status !== "pinned").map((session) => session.key);
263
+ completeItemIds = [...itemIds, ...eligibleIds.filter((id) => !itemIds.includes(id))];
264
+ }
265
+ try {
266
+ const layout = replaceSidebarLayout(containerId, completeItemIds, body.expectedRevision);
267
+ return c.json({
268
+ ok: true,
269
+ layout
270
+ });
271
+ } catch (error) {
272
+ if (error instanceof SidebarLayoutConflictError) return c.json({
273
+ ok: false,
274
+ error: error.message,
275
+ layout: error.current
276
+ }, 409);
277
+ throw error;
278
+ }
279
+ });
152
280
  authenticated.post("/api/sessions", async (c) => {
153
281
  const body = await c.req.json().catch(() => ({}));
154
282
  if (body.conversationId !== void 0 && !conversationIdSchema.safeParse(body.conversationId).success) return c.json({
@@ -1,6 +1,6 @@
1
1
  import { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, shouldSilence, stripHeartbeatToken } from "./tokens.js";
2
+ import { appendCronEventLines } from "./event-prompt.js";
2
3
  import { isWithinActiveHours } from "./active-hours.js";
3
4
  import { isHeartbeatContentEmpty } from "./content-check.js";
4
- import { appendCronEventLines } from "./event-prompt.js";
5
5
  import { createHeartbeatWake } from "./wake.js";
6
6
  export { DEFAULT_ACK_MAX_CHARS, HEARTBEAT_OK, NO_REPLY, appendCronEventLines, createHeartbeatWake, isHeartbeatContentEmpty, isWithinActiveHours, shouldSilence, stripHeartbeatToken };
@@ -29,6 +29,7 @@ export { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAll
29
29
  export { buildDefaultSessionMetadata, type SessionMetadataSeed, } from './session-metadata.js';
30
30
  export { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow, type SessionConfigRow, type SessionRow, type TranscriptEntryRow, } from './row-mappers.js';
31
31
  export { deleteSessionRecord, ensureSessionRecord, getCurrentTranscriptId, getGlobalSessionStats, findConversationIdByTranscriptId, getSessionPersistedLevels, getSessionMetadata, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats, } from './session-repository.js';
32
+ export { getSidebarLayout, replaceSidebarLayout, sortBySidebarLayout, SidebarLayoutConflictError, type SidebarLayout, } from './sidebar-layout-repository.js';
32
33
  export { appendCompactionBoundaryIfUnchanged, appendMediaToAssistantTranscriptEntry, appendTranscriptEntry, findLatestAssistantTranscriptEntryId, listCompactionBoundaries, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, loadCompactionSourceSnapshot, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript, type CompactionSourceSnapshot, type SessionTranscriptRecallMatch, type TranscriptSourceEntry, } from './transcript-repository.js';
33
34
  export { deleteNoteRecord, getNoteRecord, listNoteRecords, upsertNoteRecord, } from './notes-repository.js';
34
35
  export { deleteNoteAgentContextRecord, getNoteAgentContextRecord, upsertNoteAgentContextRecord, type NoteAgentContextRecord, } from './note-agent-context-repository.js';
@@ -33,6 +33,7 @@ import { appendConnectorExecutionAudit, claimConnectorWebhookDelivery, completeC
33
33
  import { deleteSessionRecord, ensureSessionRecord, findConversationIdByTranscriptId, getCurrentTranscriptId, getGlobalSessionStats, getSessionMetadata, getSessionPersistedLevels, incrementSessionStatsOnAppend, init_session_repository, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats } from "./session-repository.js";
34
34
  import { getSessionTaskPlan, setSessionTaskPlan } from "./session-task-plan-repository.js";
35
35
  import { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings } from "./relationship-settings-repository.js";
36
+ import { SidebarLayoutConflictError, getSidebarLayout, replaceSidebarLayout, sortBySidebarLayout } from "./sidebar-layout-repository.js";
36
37
  import { appendCompactionBoundaryIfUnchanged, appendMediaToAssistantTranscriptEntry, appendTranscriptEntry, findLatestAssistantTranscriptEntryId, listCompactionBoundaries, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript } from "./transcript-repository.js";
37
38
  import { deleteNoteRecord, getNoteRecord, listNoteRecords, upsertNoteRecord } from "./notes-repository.js";
38
39
  import { deleteNoteAgentContextRecord, getNoteAgentContextRecord, upsertNoteAgentContextRecord } from "./note-agent-context-repository.js";
@@ -56,4 +57,4 @@ init_session_repository();
56
57
  init_connector_repository();
57
58
  init_connector_account_repository();
58
59
  //#endregion
59
- export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, DatabaseSchemaTooOldError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMediaToAssistantTranscriptEntry, appendTranscriptEntry, applyPendingMigrations, authenticateDeviceAccessToken, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRefreshProofMessage, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, clearGatewayIdentityForTest, closeTemporalAssertions, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeClarificationApproval, consumeClarificationResume, consumeConnectorApproval, countKnowledgeSourceItems, createClarificationWait, createCollaborationRule, createConnectorApproval, createContextEvidence, createDevice, createDevicePairingSetup, createEndpointPrincipal, createObjectLinkRecord, createTemporalAssertion, decideConnectorApproval, deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, deleteConnectorConnection, deleteConnectorInstallation, deleteEndpointSessionBinding, deleteEndpointSessionBindingsByPrincipal, deleteKnowledgeSourceItems, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, enqueueConnectorLearningJob, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findConversationIdByTranscriptId, findLatestAssistantTranscriptEntryId, findSessionInput, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActiveClarification, getActivityEventRecord, getBrowserTabBinding, getBrowserTabBindingById, getCachedConnectorCatalogEntry, getClarification, getClarificationResumeInput, getClarificationSnapshot, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextExtractionRun, getCurrentTranscriptId, getDevice, getEndpointPrincipal, getEndpointSessionBinding, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getNoteAgentContextRecord, getNoteRecord, getOrCreateGatewayIdentity, getRelationshipSettings, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSqliteDatabase, getUserPeopleIndexState, getUserPerson, getUserTrustPolicy, getXopcDatabase, hasIndependentExtractionOutput, hasSessionConfig, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isClarificationSuspended, isDevicePairingSetupActive, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isXopcDatabaseOpen, issueDeviceTokenPair, linkContextObjects, listActiveSessionInputRuns, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextExtractionOutputs, listContextExtractionRuns, listContextObjectRelations, listDevices, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTemporalAssertions, listUserPeople, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, mergeUserPeople, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceTranscriptRows, replaceUserPeopleIndex, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveClarification, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, revokeDevice, revokeEndpointPrincipal, rotateDeviceRefreshToken, runSqliteWriteTransaction, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setBrowserTabBinding, setCollaborationRuleStatus, setConnectorLearningPaused, setEndpointSessionBinding, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUserTrustPolicy, signGatewayPayload, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeUserPeople, supersedeActiveClarification, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserPerson, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
60
+ export { COMPOSER_INPUT_HISTORY_LIMIT, DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, DatabaseSchemaTooOldError, SCHEMA_META_SCHEMA_VERSION_KEY, SidebarLayoutConflictError, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, acknowledgeHomeAttention, appendCompactionBoundaryIfUnchanged, appendComposerInputHistory, appendConnectorExecutionAudit, appendMediaToAssistantTranscriptEntry, appendTranscriptEntry, applyPendingMigrations, authenticateDeviceAccessToken, bindEndpointPrincipal, buildDefaultSessionMetadata, buildGlobalSessionStats, buildRefreshProofMessage, buildRelationshipPrompt, cancelQueuedSessionInput, claimConnectorWebhookDelivery, claimContextExtractionRun, claimKnowledgeSourceItems, claimNextConnectorLearningJob, claimNextSessionInput, classifyStoredRow, clearComposerInputHistory, clearGatewayIdentityForTest, closeTemporalAssertions, closeXopcDatabase, completeConnectorWebhookDelivery, completeKnowledgeSourceItemSynthesis, consumeClarificationApproval, consumeClarificationResume, consumeConnectorApproval, countKnowledgeSourceItems, createClarificationWait, createCollaborationRule, createConnectorApproval, createContextEvidence, createDevice, createDevicePairingSetup, createEndpointPrincipal, createObjectLinkRecord, createTemporalAssertion, decideConnectorApproval, deleteBrowserTabBinding, deleteBrowserTabBindingsByEndpoint, deleteBrowserTabBindingsByPrincipal, deleteConnectorConnection, deleteConnectorInstallation, deleteEndpointSessionBinding, deleteEndpointSessionBindingsByPrincipal, deleteKnowledgeSourceItems, deleteNoteAgentContextRecord, deleteNoteRecord, deleteObjectLinkRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, enqueueConnectorLearningJob, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, findConversationIdByTranscriptId, findLatestAssistantTranscriptEntryId, findSessionInput, finishContextExtractionRun, finishEndpointToolInvocationAudit, finishKnowledgeSyncRun, finishSessionInputRun, getActiveClarification, getActivityEventRecord, getBrowserTabBinding, getBrowserTabBindingById, getCachedConnectorCatalogEntry, getClarification, getClarificationResumeInput, getClarificationSnapshot, getCollaborationRule, getConnectorAccount, getConnectorApproval, getConnectorConnection, getConnectorInstallation, getConnectorSyncPolicy, getConnectorSyncPolicyForConnection, getContextExtractionRun, getCurrentTranscriptId, getDevice, getEndpointPrincipal, getEndpointSessionBinding, getGlobalSessionStats, getInteractionState, getKnowledgeConsumerWatermark, getKnowledgeSourceCursor, getKnowledgeSourceItem, getNoteAgentContextRecord, getNoteRecord, getOrCreateGatewayIdentity, getRelationshipSettings, getSessionConfig, getSessionInputById, getSessionInputState, getSessionMetadata, getSessionPersistedLevels, getSessionTaskPlan, getSidebarLayout, getSqliteDatabase, getUserPeopleIndexState, getUserPerson, getUserTrustPolicy, getXopcDatabase, hasIndependentExtractionOutput, hasSessionConfig, incrementSessionStatsOnAppend, insertSessionInput, inspectSchemaMigrationStatus, isClarificationSuspended, isDevicePairingSetupActive, isHomeAttentionAcknowledged, isProactiveSupportAllowed, isXopcDatabaseOpen, issueDeviceTokenPair, linkContextObjects, listActiveSessionInputRuns, listActivityRecords, listCachedConnectorCatalogEntries, listCollaborationRules, listCompactionBoundaries, listComposerInputHistory, listConnectorAccounts, listConnectorActionMetadata, listConnectorApprovals, listConnectorConnections, listConnectorExecutionAudit, listConnectorInstallations, listConnectorLearningJobs, listConnectorSyncPolicies, listContextExtractionOutputs, listContextExtractionRuns, listContextObjectRelations, listDevices, listEndpointPrincipals, listEndpointToolInvocationAudits, listKnowledgeSourceChanges, listKnowledgeSourceItems, listKnowledgeSyncRuns, listNoteRecords, listObjectActivityRecords, listObjectLinkRecords, listProjectActivityRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, listTemporalAssertions, listUserPeople, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, mergeUserPeople, metadataToSessionInsert, mutateQueuedSessionInput, openXopcDatabase, paginateTranscriptMessages, patchSessionMetadata, pruneBoundedKnowledgeSourceItems, readSchemaVersion, readSchemaVersionForTest, reconcileConnectorAccount, recordActivityEvent, recoverSessionInputState, recoverStaleConnectorLearningJobs, refreshConnectorAccountCurrent, releaseConnectorWebhookDelivery, replaceConnectorCatalogEntries, replaceLatestSessionTurnAndQueueInput, replaceSidebarLayout, replaceTranscriptRows, replaceUserPeopleIndex, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveClarification, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreBeforeCompactionBoundary, revokeDevice, revokeEndpointPrincipal, rotateDeviceRefreshToken, runSqliteWriteTransaction, searchSessionTranscript, sessionConfigRowToConfig, sessionRowToMetadata, setBrowserTabBinding, setCollaborationRuleStatus, setConnectorLearningPaused, setEndpointSessionBinding, setInteractionState, setKnowledgeConsumerWatermark, setKnowledgeSourceCursor, setKnowledgeSourceItemSynthesisStatus, setSessionConfig, setSessionInputStatus, setSessionTaskPlan, setUserTrustPolicy, signGatewayPayload, sortBySidebarLayout, startEndpointToolInvocationAudit, startKnowledgeSyncRun, summarizeUserPeople, supersedeActiveClarification, touchEndpointPrincipal, transcriptEntryRowToStoredRow, updateConnectorLearningJob, updateInteractionStateFromMessage, updateRelationshipSettings, updateSessionConfig, updateSessionStats, updateUserPerson, upsertConnectorActionMetadata, upsertConnectorCatalogEntry, upsertConnectorConnection, upsertConnectorInstallation, upsertConnectorSyncPolicy, upsertKnowledgeSourceItems, upsertNoteAgentContextRecord, upsertNoteRecord, validateLatestSessionTurnTarget };
@@ -0,0 +1,16 @@
1
+ CREATE TABLE sidebar_layouts (
2
+ container_id TEXT PRIMARY KEY,
3
+ revision INTEGER NOT NULL DEFAULT 0,
4
+ updated_at INTEGER NOT NULL
5
+ );
6
+
7
+ CREATE TABLE sidebar_positions (
8
+ container_id TEXT NOT NULL REFERENCES sidebar_layouts(container_id) ON DELETE CASCADE,
9
+ item_id TEXT NOT NULL,
10
+ position INTEGER NOT NULL,
11
+ PRIMARY KEY (container_id, item_id),
12
+ UNIQUE (container_id, position)
13
+ );
14
+
15
+ CREATE INDEX idx_sidebar_positions_order
16
+ ON sidebar_positions(container_id, position);
@@ -3,7 +3,7 @@ import type { ApplyMigrationsOptions } from './types.js';
3
3
  /** Baseline schema version applied from schema.sql on first open. */
4
4
  export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 165;
5
5
  /** Latest schema version this release supports (increment when adding migrations). */
6
- export declare const XOPC_DB_SCHEMA_VERSION = 185;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 186;
7
7
  export declare function resolveMigrationsDir(override?: string): string;
8
8
  /**
9
9
  * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
@@ -63,7 +63,7 @@ function applySingleMigration(db, migration) {
63
63
  * Each step runs in its own transaction and updates schema_meta on success.
64
64
  */
65
65
  function applyPendingMigrations(db, options = {}) {
66
- const targetVersion = options.targetVersion ?? 185;
66
+ const targetVersion = options.targetVersion ?? 186;
67
67
  let currentVersion = readSchemaVersion(db);
68
68
  if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
69
69
  if (!options.migrationsDir && currentVersion < 165) throw new DatabaseSchemaTooOldError(currentVersion, 165);
@@ -118,7 +118,7 @@ function applyPendingMigrations(db, options = {}) {
118
118
  }
119
119
  /** Inspect schema version without mutating the database. */
120
120
  function inspectSchemaMigrationStatus(db, options = {}) {
121
- const appVersion = options.targetVersion ?? 185;
121
+ const appVersion = options.targetVersion ?? 186;
122
122
  const dbVersion = readSchemaVersion(db);
123
123
  if (dbVersion > appVersion) return {
124
124
  dbVersion,
@@ -157,7 +157,7 @@ var init_runner = __esmMin((() => {
157
157
  init_errors();
158
158
  log = createLogger("Sqlite:Migrations");
159
159
  XOPC_DB_BASELINE_SCHEMA_VERSION = 165;
160
- XOPC_DB_SCHEMA_VERSION = 185;
160
+ XOPC_DB_SCHEMA_VERSION = 186;
161
161
  MODULE_DIR = dirname(fileURLToPath(import.meta.url));
162
162
  }));
163
163
  //#endregion
@@ -33,7 +33,7 @@ function ensureXopcDatabaseSchema(db, options = {}) {
33
33
  currentVersion = 165;
34
34
  }
35
35
  applyPendingMigrations(db, {
36
- targetVersion: 185,
36
+ targetVersion: 186,
37
37
  databasePath: fresh ? void 0 : options.databasePath
38
38
  });
39
39
  }
@@ -0,0 +1,12 @@
1
+ export type SidebarLayout = {
2
+ containerId: string;
3
+ itemIds: string[];
4
+ revision: number;
5
+ };
6
+ export declare class SidebarLayoutConflictError extends Error {
7
+ readonly current: SidebarLayout;
8
+ constructor(current: SidebarLayout);
9
+ }
10
+ export declare function getSidebarLayout(containerId: string): SidebarLayout;
11
+ export declare function replaceSidebarLayout(containerId: string, itemIds: string[], expectedRevision: number): SidebarLayout;
12
+ export declare function sortBySidebarLayout<T>(items: T[], layout: SidebarLayout, idOf: (item: T) => string): T[];
@@ -0,0 +1,53 @@
1
+ import { getSqliteDatabase, init_transaction, runSqliteWriteTransaction } from "./transaction.js";
2
+ //#region src/storage/sqlite/sidebar-layout-repository.ts
3
+ init_transaction();
4
+ var SidebarLayoutConflictError = class extends Error {
5
+ constructor(current) {
6
+ super("Sidebar layout changed in another window");
7
+ this.current = current;
8
+ this.name = "SidebarLayoutConflictError";
9
+ }
10
+ };
11
+ function getSidebarLayout(containerId) {
12
+ const db = getSqliteDatabase();
13
+ const row = db.prepare("SELECT revision FROM sidebar_layouts WHERE container_id = ?").get(containerId);
14
+ return {
15
+ containerId,
16
+ itemIds: db.prepare("SELECT item_id FROM sidebar_positions WHERE container_id = ? ORDER BY position ASC").all(containerId).map((position) => position.item_id),
17
+ revision: row?.revision ?? 0
18
+ };
19
+ }
20
+ function replaceSidebarLayout(containerId, itemIds, expectedRevision) {
21
+ return runSqliteWriteTransaction((db) => {
22
+ const current = getSidebarLayout(containerId);
23
+ if (current.revision !== expectedRevision) throw new SidebarLayoutConflictError(current);
24
+ const uniqueItemIds = [...new Set(itemIds)];
25
+ const nextRevision = current.revision + 1;
26
+ db.prepare(`INSERT INTO sidebar_layouts (container_id, revision, updated_at) VALUES (?, ?, ?)
27
+ ON CONFLICT(container_id) DO UPDATE SET revision = excluded.revision, updated_at = excluded.updated_at`).run(containerId, nextRevision, Date.now());
28
+ db.prepare("DELETE FROM sidebar_positions WHERE container_id = ?").run(containerId);
29
+ const insert = db.prepare("INSERT INTO sidebar_positions (container_id, item_id, position) VALUES (?, ?, ?)");
30
+ uniqueItemIds.forEach((itemId, position) => insert.run(containerId, itemId, position));
31
+ return {
32
+ containerId,
33
+ itemIds: uniqueItemIds,
34
+ revision: nextRevision
35
+ };
36
+ });
37
+ }
38
+ function sortBySidebarLayout(items, layout, idOf) {
39
+ if (layout.itemIds.length === 0) return items;
40
+ const ranks = new Map(layout.itemIds.map((id, index) => [id, index]));
41
+ return items.map((item, index) => ({
42
+ item,
43
+ index,
44
+ rank: ranks.get(idOf(item))
45
+ })).sort((a, b) => {
46
+ if (a.rank !== void 0 && b.rank !== void 0) return a.rank - b.rank;
47
+ if (a.rank !== void 0) return 1;
48
+ if (b.rank !== void 0) return -1;
49
+ return a.index - b.index;
50
+ }).map(({ item }) => item);
51
+ }
52
+ //#endregion
53
+ export { SidebarLayoutConflictError, getSidebarLayout, replaceSidebarLayout, sortBySidebarLayout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xopcai/xopc",
3
- "version": "0.0.308",
3
+ "version": "0.0.309",
4
4
  "description": "Local-first personal AI assistant with reviewable user understanding, durable tasks, workflows, automations, and local or cloud models.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -171,8 +171,8 @@
171
171
  "@xopcai/endpoint-tools-client": "0.0.0",
172
172
  "@xopcai/endpoint-tools-protocol": "0.0.0",
173
173
  "@xopcai/gateway-contract": "0.0.0",
174
- "@xopcai/realtime-protocol": "0.0.0",
175
- "@xopcai/realtime-client": "0.0.0"
174
+ "@xopcai/realtime-client": "0.0.0",
175
+ "@xopcai/realtime-protocol": "0.0.0"
176
176
  },
177
177
  "scripts": {
178
178
  "assets:brand": "node scripts/generate-brand-assets.mjs",
@@ -1 +0,0 @@
1
- import{a as e,r as t}from"./locale-store-msTfRK8P.js";var n=n=>e(t(n)),r=(n,r,i)=>e(t(n),{method:r,headers:{"content-type":`application/json`},body:JSON.stringify(i)});export{r as n,n as t};
@@ -1 +0,0 @@
1
- import{p as e}from"./locale-store-msTfRK8P.js";var t=e(()=>({connectionState:`idle`,error:null}));function n(e){t.setState(e)}export{t as n,n as t};