@xopcai/xopc 0.0.235 → 0.0.239

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 (307) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  3. package/dist/extensions/feishu/src/schema/config-schema.d.ts +8 -8
  4. package/dist/extensions/telegram/src/config-schema.d.ts +8 -8
  5. package/dist/extensions/telegram/xopc.extension.json +1 -1
  6. package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
  7. package/dist/gateway/static/root/assets/{activity-store-BzswYHcj.js → activity-store-DLfkwJzZ.js} +1 -1
  8. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-dvh9aEm6.js → agent-avatar-dicebear-C1rtpjd7.js} +1 -1
  9. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-oW6wFuP9.js +1 -0
  10. package/dist/gateway/static/root/assets/agents-V-nDPOk2.js +1 -0
  11. package/dist/gateway/static/root/assets/{api-7zOtMbaE.js → api-IUm57Zse.js} +1 -1
  12. package/dist/gateway/static/root/assets/app-management-settings-panel-CRDnRN4G.js +1 -0
  13. package/dist/gateway/static/root/assets/appearance-settings-BCYZIKqQ.js +1 -0
  14. package/dist/gateway/static/root/assets/apps-page-dcvQDCvy.js +1 -0
  15. package/dist/gateway/static/root/assets/{archive-plugin-DawToDU8.js → archive-plugin-Bha1jUhj.js} +1 -1
  16. package/dist/gateway/static/root/assets/{attachment-load-DmBAKvsi.js → attachment-load-Bgfh7Ag2.js} +1 -1
  17. package/dist/gateway/static/root/assets/{automations-page-BGkF6XNH.js → automations-page-BdH131M0.js} +1 -1
  18. package/dist/gateway/static/root/assets/automations-workspace-BtwzQZAR.js +6 -0
  19. package/dist/gateway/static/root/assets/{binary-plugins-B-6Ski7l.js → binary-plugins-BwXg9na-.js} +1 -1
  20. package/dist/gateway/static/root/assets/{block-editor-BgeKQN1F.js → block-editor-BngtUSNv.js} +56 -56
  21. package/dist/gateway/static/root/assets/browser-settings-page-kfNOKQ2x.js +8 -0
  22. package/dist/gateway/static/root/assets/{browser-workflow-inputs-4ooVX-Tx.js → browser-workflow-inputs-CHHw7Ula.js} +1 -1
  23. package/dist/gateway/static/root/assets/{browser-workflows-page-D92g81lS.js → browser-workflows-page-Ael9sxrp.js} +2 -2
  24. package/dist/gateway/static/root/assets/capabilities-settings-panel-DOymgkUM.js +7 -0
  25. package/dist/gateway/static/root/assets/channels-settings-YscUvFub.js +1 -0
  26. package/dist/gateway/static/root/assets/{channels-status-swr-BDJvMnA_.js → channels-status-swr-CwUSKmeY.js} +1 -1
  27. package/dist/gateway/static/root/assets/chat-terminal-dock-DI0lYVKk.js +36 -0
  28. package/dist/gateway/static/root/assets/connectors-page-BtzCRQGz.js +2 -0
  29. package/dist/gateway/static/root/assets/{cron-expression-BYmr5ZuN.js → cron-expression-CLuvPZ3b.js} +1 -1
  30. package/dist/gateway/static/root/assets/{date-picker-FKL_b_S0.js → date-picker-D4QS8Zzn.js} +1 -1
  31. package/dist/gateway/static/root/assets/dependency-picker-DZn-RhEm.js +1 -0
  32. package/dist/gateway/static/root/assets/{desktop-pet-DOXjRTqK.js → desktop-pet-C6KqTQas.js} +1 -1
  33. package/dist/gateway/static/root/assets/desktop-pet-settings-Bov3XuPO.js +1 -0
  34. package/dist/gateway/static/root/assets/{extension-debug-page-BeJ1-5ID.js → extension-debug-page-DpeeYAjX.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-page-CncDndLS.js → extension-page-Cescx_be.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-settings-page-BxxL0HqU.js → extension-settings-page-C_ubW61U.js} +1 -1
  37. package/dist/gateway/static/root/assets/{gateway-config-api-Dc6A6HyJ.js → gateway-config-api-BM79X1jC.js} +1 -1
  38. package/dist/gateway/static/root/assets/{gateway-config-swr-R702lNJR.js → gateway-config-swr-DfMY-MLf.js} +1 -1
  39. package/dist/gateway/static/root/assets/gateway-settings-GV5KAj-l.js +1 -0
  40. package/dist/gateway/static/root/assets/{gateway-startup-retry-2rVSUvyw.js → gateway-startup-retry-S6aB0hVI.js} +1 -1
  41. package/dist/gateway/static/root/assets/heartbeat-settings-CZ1KeXXU.js +1 -0
  42. package/dist/gateway/static/root/assets/home-page-YdVal_8I.js +1 -0
  43. package/dist/gateway/static/root/assets/{image-generation-api-B28USRCK.js → image-generation-api-DOX5uq-R.js} +1 -1
  44. package/dist/gateway/static/root/assets/index-7GLgmvAm.css +2 -0
  45. package/dist/gateway/static/root/assets/index-DKP23eMn.js +70 -0
  46. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-Cwinks_5.js → keyboard-shortcuts-settings-Tn7xSeVT.js} +1 -1
  47. package/dist/gateway/static/root/assets/local-app-workbench-page-DCt7cbvK.js +2 -0
  48. package/dist/gateway/static/root/assets/local-apps-page-Co5_qKEQ.js +1 -0
  49. package/dist/gateway/static/root/assets/{locale-store-8k4mvYGL.js → locale-store-XDFAPNNu.js} +1 -1
  50. package/dist/gateway/static/root/assets/logs-page-ChfSQQSV.js +2 -0
  51. package/dist/gateway/static/root/assets/management-settings-DE0o5c7Y.js +1 -0
  52. package/dist/gateway/static/root/assets/{markdown-split-B6wQhwLV.js → markdown-split-CADkGbQi.js} +1 -1
  53. package/dist/gateway/static/root/assets/markdown-view-Y68dCxuc.css +1 -0
  54. package/dist/gateway/static/root/assets/markdown-view-v-O3cOpk.js +201 -0
  55. package/dist/gateway/static/root/assets/{media-plugins-BSEPuO76.js → media-plugins-mHodPaFz.js} +1 -1
  56. package/dist/gateway/static/root/assets/messages-B1HDp_j8.js +3 -0
  57. package/dist/gateway/static/root/assets/mobile-pairing-wizard-43FyMswX.js +1 -0
  58. package/dist/gateway/static/root/assets/models-hub-cache-Bngs8o1m.js +1 -0
  59. package/dist/gateway/static/root/assets/{notes-api-p2Pncp2B.js → notes-api-BMhFpRmW.js} +1 -1
  60. package/dist/gateway/static/root/assets/{notes-page-CPgbeO1u.js → notes-page-BMUyJStB.js} +1 -1
  61. package/dist/gateway/static/root/assets/notes-workbench-DjHIQneE.js +4 -0
  62. package/dist/gateway/static/root/assets/{oauth-api-DpLONwfK.js → oauth-api-B_pcOUfT.js} +1 -1
  63. package/dist/gateway/static/root/assets/popover-select-DBrVS3tZ.js +1 -0
  64. package/dist/gateway/static/root/assets/{product-delivery-tRr-7IxY.js → product-delivery-dUJgmBQZ.js} +1 -1
  65. package/dist/gateway/static/root/assets/product-open-page-B8cjLdm4.js +1 -0
  66. package/dist/gateway/static/root/assets/project-detail-page-CXD2pVgQ.js +1 -0
  67. package/dist/gateway/static/root/assets/projects-page-cqKqkTwG.js +1 -0
  68. package/dist/gateway/static/root/assets/{registry-api-B7b0LJgI.js → registry-api-DeVvBsl4.js} +1 -1
  69. package/dist/gateway/static/root/assets/remote-access-hub-UEinEd7d.js +1 -0
  70. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-D3TCJGy3.js → runtime-tools-settings-panel-ClCEmwPY.js} +1 -1
  71. package/dist/gateway/static/root/assets/{schema-form-DUAlwNoO.js → schema-form-0vcUqeqa.js} +1 -1
  72. package/dist/gateway/static/root/assets/sessions-page-Cc6ve-qc.js +1 -0
  73. package/dist/gateway/static/root/assets/settings-advanced-gate-_J5FSEYX.js +1 -0
  74. package/dist/gateway/static/root/assets/{settings-form-section-D7nQ3Lfu.js → settings-form-section-BkdLf_sS.js} +1 -1
  75. package/dist/gateway/static/root/assets/settings-loading-skeleton-CAmWMaOT.js +1 -0
  76. package/dist/gateway/static/root/assets/{settings-page-CMAkMc3I.js → settings-page-QBTaBpBn.js} +1 -1
  77. package/dist/gateway/static/root/assets/setup-status-panel-bQcSMkVr.js +1 -0
  78. package/dist/gateway/static/root/assets/share-preview-page-D_OuXnah.js +2 -0
  79. package/dist/gateway/static/root/assets/shares-settings-DJfcpok3.js +1 -0
  80. package/dist/gateway/static/root/assets/skeleton-BwbyijEw.js +1 -0
  81. package/dist/gateway/static/root/assets/skill-reload-api-Bbqp5HaH.js +1 -0
  82. package/dist/gateway/static/root/assets/{skills-page-DJRr5HFw.js → skills-page-BNcnmaTg.js} +1 -1
  83. package/dist/gateway/static/root/assets/{skills-page.utils-DcrBe39q.js → skills-page.utils-BWWcFShl.js} +1 -1
  84. package/dist/gateway/static/root/assets/system-settings-panel-BsH7b3B4.js +1 -0
  85. package/dist/gateway/static/root/assets/task-detail-page-CcAhyw2Z.js +1 -0
  86. package/dist/gateway/static/root/assets/{theme-store-CpcBI73Q.js → theme-store-5-XHH7F0.js} +1 -1
  87. package/dist/gateway/static/root/assets/tunnel-api-D5-Hggt3.js +1 -0
  88. package/dist/gateway/static/root/assets/{use-autosave-DDEypreQ.js → use-autosave-Dp1ycDa8.js} +1 -1
  89. package/dist/gateway/static/root/assets/user-context-page-Dd_oMNie.js +1 -0
  90. package/dist/gateway/static/root/assets/{voice-api-key-field-BLa_vdXE.js → voice-api-key-field-DhrQXH3c.js} +1 -1
  91. package/dist/gateway/static/root/assets/{voice-config-api-ynE-vY6I.js → voice-config-api-Bk_bVeGX.js} +1 -1
  92. package/dist/gateway/static/root/assets/{work-discovery-overlay-DS3w1Fyq.js → work-discovery-overlay-B7zKAPrb.js} +1 -1
  93. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-jQl_wmYC.js → workflow-run-setup-panel-Cek9K48F.js} +2 -2
  94. package/dist/gateway/static/root/assets/workflows-page-T2q2Mx6H.js +5 -0
  95. package/dist/gateway/static/root/index.html +18 -17
  96. package/dist/package.js +1 -1
  97. package/dist/packages/gateway-contract/src/device-pairing.js +39 -0
  98. package/dist/packages/gateway-contract/src/model-selection.js +7 -0
  99. package/dist/packages/gateway-contract/src/new-session.js +9 -2
  100. package/dist/packages/gateway-contract/src/turn-outcome.js +27 -2
  101. package/dist/src/agent/agent-manager.js +4 -4
  102. package/dist/src/agent/background-review/run-background-review.js +1 -1
  103. package/dist/src/agent/embedded/model-runtime.js +1 -1
  104. package/dist/src/agent/embedded/run-for-session.js +1 -1
  105. package/dist/src/agent/embedded/run-turn.js +5 -0
  106. package/dist/src/agent/image/tool-model-config.js +1 -1
  107. package/dist/src/agent/ipc/inbox.js +1 -1
  108. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  109. package/dist/src/agent/models/manager.d.ts +3 -0
  110. package/dist/src/agent/models/manager.js +9 -0
  111. package/dist/src/agent/prompt/sections/tooling.js +1 -0
  112. package/dist/src/agent/service.js +2 -2
  113. package/dist/src/agent/session/session-config-service.d.ts +6 -2
  114. package/dist/src/agent/session/session-config-service.js +78 -17
  115. package/dist/src/agent/session/session-hydrator.d.ts +3 -4
  116. package/dist/src/agent/session/session-hydrator.js +19 -8
  117. package/dist/src/agent/session/session-inspector.d.ts +3 -1
  118. package/dist/src/agent/session/session-inspector.js +8 -4
  119. package/dist/src/agent/skills/hub-lock.js +1 -1
  120. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  121. package/dist/src/agent/tools/exec-command.js +1 -0
  122. package/dist/src/agent/tools/publish-artifacts.d.ts +1 -0
  123. package/dist/src/agent/tools/publish-artifacts.js +15 -4
  124. package/dist/src/agent/tools/xopc-use-tool.js +4 -4
  125. package/dist/src/agent/transcript/thinking-types.d.ts +1 -1
  126. package/dist/src/agent/transcript/thinking-types.js +2 -0
  127. package/dist/src/agent-config/schema.d.ts +16 -16
  128. package/dist/src/ai-assist/text-assist.js +1 -1
  129. package/dist/src/auth/credentials.js +2 -2
  130. package/dist/src/auth/profiles/store.js +1 -1
  131. package/dist/src/auth/sync-provider-auth.js +2 -2
  132. package/dist/src/automations/domain/validation.d.ts +62 -62
  133. package/dist/src/automations/draft/automation-draft-validator.d.ts +10 -10
  134. package/dist/src/browser/providers/browser-ext-install.js +1 -1
  135. package/dist/src/chat-commands/builtins/thinking.js +1 -0
  136. package/dist/src/cli/commands/channels.js +1 -1
  137. package/dist/src/cli/commands/connectors.js +1 -1
  138. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  139. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  140. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  141. package/dist/src/cli/commands/models.js +2 -2
  142. package/dist/src/cli/commands/onboard.js +1 -1
  143. package/dist/src/config/index.js +4 -4
  144. package/dist/src/config/loader.js +1 -1
  145. package/dist/src/config/models-json.d.ts +137 -11
  146. package/dist/src/config/models-json.js +29 -2
  147. package/dist/src/config/schema.d.ts +15 -15
  148. package/dist/src/execution-environments/git.d.ts +27 -0
  149. package/dist/src/execution-environments/git.js +125 -0
  150. package/dist/src/execution-environments/index.d.ts +7 -0
  151. package/dist/src/execution-environments/index.js +8 -0
  152. package/dist/src/execution-environments/local-worktree-manager.d.ts +37 -0
  153. package/dist/src/execution-environments/local-worktree-manager.js +322 -0
  154. package/dist/src/execution-environments/paths.d.ts +2 -0
  155. package/dist/src/execution-environments/paths.js +18 -0
  156. package/dist/src/execution-environments/session-environment-service.d.ts +22 -0
  157. package/dist/src/execution-environments/session-environment-service.js +73 -0
  158. package/dist/src/execution-environments/store.d.ts +13 -0
  159. package/dist/src/execution-environments/store.js +183 -0
  160. package/dist/src/execution-environments/subject.d.ts +2 -0
  161. package/dist/src/execution-environments/subject.js +12 -0
  162. package/dist/src/execution-environments/types.d.ts +74 -0
  163. package/dist/src/execution-environments/types.js +54 -0
  164. package/dist/src/extensions/lockfile.js +1 -1
  165. package/dist/src/extensions/sdk/index.js +1 -1
  166. package/dist/src/extensions/update.js +1 -1
  167. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  168. package/dist/src/gateway/agents-admin.js +1 -1
  169. package/dist/src/gateway/custom-image-providers.d.ts +1 -1
  170. package/dist/src/gateway/file-path-classifier.js +1 -1
  171. package/dist/src/gateway/heartbeat/service.js +1 -1
  172. package/dist/src/gateway/hono/lib/config-payload.d.ts +4 -4
  173. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  174. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  175. package/dist/src/gateway/hono/routes/chat-model-config.d.ts +34 -0
  176. package/dist/src/gateway/hono/routes/chat-model-config.js +42 -0
  177. package/dist/src/gateway/hono/routes/device-pairing-approval.d.ts +3 -0
  178. package/dist/src/gateway/hono/routes/device-pairing-approval.js +100 -0
  179. package/dist/src/gateway/hono/routes/devices.js +15 -8
  180. package/dist/src/gateway/hono/routes/execution-environments.d.ts +3 -0
  181. package/dist/src/gateway/hono/routes/execution-environments.js +136 -0
  182. package/dist/src/gateway/hono/routes/index.js +4 -0
  183. package/dist/src/gateway/hono/routes/mobile-privacy.d.ts +3 -0
  184. package/dist/src/gateway/hono/routes/mobile-privacy.js +13 -0
  185. package/dist/src/gateway/hono/routes/models.js +10 -1
  186. package/dist/src/gateway/hono/routes/projects.js +43 -4
  187. package/dist/src/gateway/hono/routes/session-input-handler.d.ts +15 -1
  188. package/dist/src/gateway/hono/routes/session-input-handler.js +122 -52
  189. package/dist/src/gateway/hono/routes/sessions.js +105 -22
  190. package/dist/src/gateway/hono/routes/tasks.js +4 -12
  191. package/dist/src/gateway/mobile-privacy.d.ts +7 -0
  192. package/dist/src/gateway/mobile-privacy.js +102 -0
  193. package/dist/src/gateway/security/gateway-scopes.js +1 -0
  194. package/dist/src/gateway/service/agent-runner.d.ts +1 -1
  195. package/dist/src/gateway/service/config-coordinator.js +2 -2
  196. package/dist/src/gateway/service/session-input-coordinator.d.ts +2 -1
  197. package/dist/src/gateway/service/session-input-coordinator.js +14 -5
  198. package/dist/src/gateway/service/sessions-api.d.ts +4 -12
  199. package/dist/src/gateway/service/sessions-api.js +13 -0
  200. package/dist/src/gateway/service.d.ts +1 -1
  201. package/dist/src/gateway/service.js +8 -8
  202. package/dist/src/gateway/session-context-summary.d.ts +5 -0
  203. package/dist/src/gateway/session-context-summary.js +151 -0
  204. package/dist/src/heartbeat/index.js +1 -1
  205. package/dist/src/i18n/response-language.d.ts +1 -1
  206. package/dist/src/infra/update-runner.js +1 -1
  207. package/dist/src/projects/index.js +3 -3
  208. package/dist/src/projects/project-kind.d.ts +7 -0
  209. package/dist/src/projects/project-kind.js +6 -1
  210. package/dist/src/projects/project-service.js +10 -2
  211. package/dist/src/projects/project-store.d.ts +1 -0
  212. package/dist/src/projects/project-store.js +10 -7
  213. package/dist/src/projects/types.d.ts +4 -0
  214. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  215. package/dist/src/providers/index.js +2 -2
  216. package/dist/src/providers/model-registry.js +3 -1
  217. package/dist/src/providers/model-thinking.d.ts +4 -0
  218. package/dist/src/providers/model-thinking.js +41 -0
  219. package/dist/src/providers/register-runtime-providers.js +1 -1
  220. package/dist/src/session/config-types.d.ts +1 -0
  221. package/dist/src/session/index.js +1 -1
  222. package/dist/src/session/model-config-lock.d.ts +2 -0
  223. package/dist/src/session/model-config-lock.js +14 -0
  224. package/dist/src/session/session-workspace.d.ts +2 -1
  225. package/dist/src/session/session-workspace.js +5 -1
  226. package/dist/src/session/store.js +1 -1
  227. package/dist/src/session/turn-outcome-projector.js +9 -9
  228. package/dist/src/share/hosted-session-share.js +1 -1
  229. package/dist/src/storage/sqlite/config-repository.js +6 -5
  230. package/dist/src/storage/sqlite/device-access-repository.d.ts +2 -0
  231. package/dist/src/storage/sqlite/device-access-repository.js +12 -2
  232. package/dist/src/storage/sqlite/device-pairing-approval.d.ts +19 -0
  233. package/dist/src/storage/sqlite/device-pairing-approval.js +154 -0
  234. package/dist/src/storage/sqlite/device-pairing-repository.d.ts +1 -1
  235. package/dist/src/storage/sqlite/device-pairing-repository.js +11 -4
  236. package/dist/src/storage/sqlite/index.js +2 -2
  237. package/dist/src/storage/sqlite/migrations/141_device_pairing_approval.sql +17 -0
  238. package/dist/src/storage/sqlite/migrations/142_session_input_instance.sql +1 -0
  239. package/dist/src/storage/sqlite/migrations/143_fixed_session_model.sql +1 -0
  240. package/dist/src/storage/sqlite/migrations/144_execution_environments.sql +59 -0
  241. package/dist/src/storage/sqlite/migrations/145_project_execution_mode.sql +5 -0
  242. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  243. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  244. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  245. package/dist/src/storage/sqlite/row-mappers.d.ts +1 -0
  246. package/dist/src/storage/sqlite/row-mappers.js +3 -2
  247. package/dist/src/storage/sqlite/schema.js +1 -1
  248. package/dist/src/storage/sqlite/session-input-repository.d.ts +5 -0
  249. package/dist/src/storage/sqlite/session-input-repository.js +15 -4
  250. package/dist/src/storage/sqlite/session-repository.js +1 -1
  251. package/dist/src/tasks/execution-context.d.ts +3 -1
  252. package/dist/src/tasks/execution-context.js +7 -2
  253. package/dist/src/tasks/home-query-service.js +2 -2
  254. package/dist/src/tui/backends/embedded-backend.js +2 -2
  255. package/dist/src/tui/components/thinking-selector.js +1 -0
  256. package/dist/src/tui/tui-settings.js +1 -1
  257. package/dist/src/tui/tui-startup-resources.js +1 -1
  258. package/dist/src/tui/tui.js +1 -1
  259. package/dist/src/user-context/config.d.ts +9 -9
  260. package/dist/src/work-discovery/service.d.ts +1 -1
  261. package/dist/src/workflows/service/workflow-run-service.js +2 -2
  262. package/package.json +3 -3
  263. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-B9tkmkUj.js +0 -1
  264. package/dist/gateway/static/root/assets/agents-DTXYo-7z.js +0 -1
  265. package/dist/gateway/static/root/assets/app-management-settings-panel-DXFTk7x6.js +0 -1
  266. package/dist/gateway/static/root/assets/appearance-settings-D-FD5SOq.js +0 -1
  267. package/dist/gateway/static/root/assets/apps-page-BT102W58.js +0 -1
  268. package/dist/gateway/static/root/assets/automations-workspace-BRb45-_R.js +0 -6
  269. package/dist/gateway/static/root/assets/browser-settings-page-BkRWxC7D.js +0 -8
  270. package/dist/gateway/static/root/assets/capabilities-settings-panel-DfT-vWTA.js +0 -7
  271. package/dist/gateway/static/root/assets/channels-settings-C9oGpLR0.js +0 -1
  272. package/dist/gateway/static/root/assets/chat-terminal-dock-C_9LUs7G.js +0 -36
  273. package/dist/gateway/static/root/assets/connectors-page-SJKV6SHT.js +0 -2
  274. package/dist/gateway/static/root/assets/dependency-picker-BP68vqBI.js +0 -1
  275. package/dist/gateway/static/root/assets/desktop-pet-settings-CuG2qYoY.js +0 -1
  276. package/dist/gateway/static/root/assets/gateway-settings-C2XcazGD.js +0 -1
  277. package/dist/gateway/static/root/assets/heartbeat-settings-BjUEqkkC.js +0 -1
  278. package/dist/gateway/static/root/assets/home-page-DTSjwfAQ.js +0 -1
  279. package/dist/gateway/static/root/assets/index-BTUuTnc9.css +0 -2
  280. package/dist/gateway/static/root/assets/index-DFfvY8IN.js +0 -70
  281. package/dist/gateway/static/root/assets/local-app-workbench-page-0wntj9mK.js +0 -2
  282. package/dist/gateway/static/root/assets/local-apps-page-WeKm5vZ0.js +0 -1
  283. package/dist/gateway/static/root/assets/logs-page-DFgJr7Zx.js +0 -2
  284. package/dist/gateway/static/root/assets/management-settings-8bEvKO0R.js +0 -1
  285. package/dist/gateway/static/root/assets/markdown-view-B1bGSQqt.css +0 -1
  286. package/dist/gateway/static/root/assets/markdown-view-D02mJdoU.js +0 -201
  287. package/dist/gateway/static/root/assets/messages-CoovNoMn.js +0 -3
  288. package/dist/gateway/static/root/assets/mobile-device-api-CvjVB_TB.js +0 -1
  289. package/dist/gateway/static/root/assets/models-hub-cache-CYr6LzvY.js +0 -1
  290. package/dist/gateway/static/root/assets/notes-workbench-DIXCtwhs.js +0 -4
  291. package/dist/gateway/static/root/assets/popover-select-3E24E65N.js +0 -1
  292. package/dist/gateway/static/root/assets/product-open-page-DNHWn_26.js +0 -1
  293. package/dist/gateway/static/root/assets/project-detail-page-6jgRJg4w.js +0 -1
  294. package/dist/gateway/static/root/assets/projects-page-Bd4nXs4y.js +0 -1
  295. package/dist/gateway/static/root/assets/remote-access-hub-C_5-u9U-.js +0 -1
  296. package/dist/gateway/static/root/assets/sessions-page-BqYAR86S.js +0 -1
  297. package/dist/gateway/static/root/assets/settings-advanced-gate-a146I0uZ.js +0 -1
  298. package/dist/gateway/static/root/assets/settings-loading-skeleton-CwGM9zKH.js +0 -1
  299. package/dist/gateway/static/root/assets/setup-status-panel-rhaERxAL.js +0 -1
  300. package/dist/gateway/static/root/assets/share-preview-page-BzkXvuH6.js +0 -2
  301. package/dist/gateway/static/root/assets/shares-settings-BvsM3Im5.js +0 -1
  302. package/dist/gateway/static/root/assets/skill-reload-api-u7E0gqFo.js +0 -1
  303. package/dist/gateway/static/root/assets/system-settings-panel-BUsykmjx.js +0 -1
  304. package/dist/gateway/static/root/assets/task-detail-page-C9QgWfYG.js +0 -1
  305. package/dist/gateway/static/root/assets/user-context-page-Ch0cfQfI.js +0 -1
  306. package/dist/gateway/static/root/assets/workflows-page-DyTwkdzs.js +0 -5
  307. /package/dist/gateway/static/root/assets/{dist-DqPZM2MH2.js → dist-DqPZM2MH.js} +0 -0
@@ -5,7 +5,7 @@ import { ensureSessionInTransaction } from "./session-repository.js";
5
5
  function readConfigRow(db, sessionKey) {
6
6
  return db.prepare(`SELECT session_key, thinking_level, reasoning_level, verbose_level, elevated_mode,
7
7
  model_override, provider_override, working_directory_override, response_language,
8
- user_context_mode, updated_at
8
+ user_context_mode, fixed_model, updated_at
9
9
  FROM session_config WHERE session_key = ?`).get(sessionKey);
10
10
  }
11
11
  function getSessionConfig(sessionKey) {
@@ -23,15 +23,15 @@ function listSessionWorkspaceOverrides() {
23
23
  function setSessionConfig(sessionKey, config, cwd) {
24
24
  return runSqliteWriteTransaction((db) => {
25
25
  ensureSessionInTransaction(db, sessionKey, cwd);
26
- const updatedAt = Date.now();
26
+ const updatedAt = Math.max(Date.now(), (readConfigRow(db, sessionKey)?.updated_at ?? 0) + 1);
27
27
  const next = {
28
28
  ...config,
29
29
  updatedAt
30
30
  };
31
31
  db.prepare(`INSERT INTO session_config (
32
32
  session_key, thinking_level, reasoning_level, verbose_level, elevated_mode,
33
- model_override, provider_override, working_directory_override, response_language, user_context_mode, updated_at
34
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
33
+ model_override, provider_override, working_directory_override, response_language, user_context_mode, fixed_model, updated_at
34
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
35
35
  ON CONFLICT(session_key) DO UPDATE SET
36
36
  thinking_level = excluded.thinking_level,
37
37
  reasoning_level = excluded.reasoning_level,
@@ -42,7 +42,8 @@ function setSessionConfig(sessionKey, config, cwd) {
42
42
  working_directory_override = excluded.working_directory_override,
43
43
  response_language = excluded.response_language,
44
44
  user_context_mode = excluded.user_context_mode,
45
- updated_at = excluded.updated_at`).run(sessionKey, next.thinkingLevel ?? null, next.reasoningLevel ?? null, next.verboseLevel ?? null, next.elevatedMode ?? null, next.modelOverride ?? null, next.providerOverride ?? null, next.workingDirectoryOverride ?? null, next.responseLanguage ?? null, next.userContextMode ?? null, updatedAt);
45
+ fixed_model = excluded.fixed_model,
46
+ updated_at = excluded.updated_at`).run(sessionKey, next.thinkingLevel ?? null, next.reasoningLevel ?? null, next.verboseLevel ?? null, next.elevatedMode ?? null, next.modelOverride ?? null, next.providerOverride ?? null, next.workingDirectoryOverride ?? null, next.responseLanguage ?? null, next.userContextMode ?? null, next.fixedModel ? 1 : 0, updatedAt);
46
47
  return next;
47
48
  });
48
49
  }
@@ -34,6 +34,8 @@ export declare function createDevice(input: {
34
34
  export declare function getDevice(deviceId: string): DeviceRecord | undefined;
35
35
  export declare function listDevices(): DeviceRecord[];
36
36
  export declare function issueDeviceTokenPair(deviceId: string, now?: number): DeviceTokenPair;
37
+ /** Registers a phone-generated bootstrap credential without persisting its secret. */
38
+ export declare function registerInitialDeviceRefreshToken(deviceId: string, token: string, now?: number): number;
37
39
  export declare function authenticateDeviceAccessToken(token: string, now?: number): DeviceAccessIdentity | undefined;
38
40
  export declare function buildRefreshProofMessage(input: {
39
41
  credentialId: string;
@@ -1,4 +1,5 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ import { initialDeviceRefreshTokenSchema } from "../../../packages/gateway-contract/src/device-pairing.js";
2
3
  import { parseGatewayScopes } from "../../gateway/security/gateway-scopes.js";
3
4
  import crypto from "node:crypto";
4
5
  //#region src/storage/sqlite/device-access-repository.ts
@@ -82,6 +83,15 @@ function issueDeviceTokenPair(deviceId, now = Date.now()) {
82
83
  refreshTokenExpiresAt
83
84
  };
84
85
  }
86
+ /** Registers a phone-generated bootstrap credential without persisting its secret. */
87
+ function registerInitialDeviceRefreshToken(deviceId, token, now = Date.now()) {
88
+ initialDeviceRefreshTokenSchema.parse(token);
89
+ const parsed = parseToken(token, REFRESH_TOKEN_PREFIX);
90
+ const expiresAt = now + REFRESH_TOKEN_TTL_MS;
91
+ getSqliteDatabase().prepare(`INSERT INTO device_refresh_credentials
92
+ (credential_id, device_id, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?)`).run(parsed.id, deviceId, tokenHash(token), expiresAt, now);
93
+ return expiresAt;
94
+ }
85
95
  function authenticateDeviceAccessToken(token, now = Date.now()) {
86
96
  const parsed = parseToken(token, ACCESS_TOKEN_PREFIX);
87
97
  if (!parsed) return void 0;
@@ -147,7 +157,7 @@ function rotateDeviceRefreshToken(input) {
147
157
  rotation_request_id, revoked_at
148
158
  FROM device_refresh_credentials WHERE credential_id = ?
149
159
  `).get(nextParsed.id);
150
- if (nextCredential?.token_hash === tokenHash(input.nextRefreshToken)) return {
160
+ if (nextCredential?.token_hash === tokenHash(input.nextRefreshToken) && nextCredential.revoked_at === null && nextCredential.replaced_by === null && nextCredential.expires_at > now) return {
151
161
  ...issueAccessToken(credential.device_id, now),
152
162
  refreshToken: input.nextRefreshToken,
153
163
  refreshTokenExpiresAt: nextCredential.expires_at
@@ -191,4 +201,4 @@ function revokeDevice(deviceId, now = Date.now()) {
191
201
  });
192
202
  }
193
203
  //#endregion
194
- export { authenticateDeviceAccessToken, buildRefreshProofMessage, createDevice, getDevice, issueDeviceTokenPair, listDevices, revokeDevice, rotateDeviceRefreshToken };
204
+ export { authenticateDeviceAccessToken, buildRefreshProofMessage, createDevice, getDevice, issueDeviceTokenPair, listDevices, registerInitialDeviceRefreshToken, revokeDevice, rotateDeviceRefreshToken };
@@ -0,0 +1,19 @@
1
+ import { type DevicePairingAction, type DevicePairingStatus } from '@xopcai/gateway-contract';
2
+ import type { DeviceRoute } from './device-pairing-repository.js';
3
+ export declare class DevicePairingError extends Error {
4
+ readonly code: string;
5
+ readonly status: 400 | 401 | 404 | 409;
6
+ constructor(code: string, status?: 400 | 401 | 404 | 409);
7
+ }
8
+ export declare function submitDevicePairingRequest(body: Record<string, unknown>, now?: number): DevicePairingStatus;
9
+ export declare function readDevicePairingSetup(setupId: string, now?: number): {
10
+ request: DevicePairingStatus | null;
11
+ serverTime: number;
12
+ };
13
+ export declare function decideDevicePairingRequest(id: string, decision: 'approve' | 'reject', revision: number, now?: number): DevicePairingStatus;
14
+ export declare function cancelDevicePairingSetup(id: string, now?: number): void;
15
+ export declare function operateDevicePairingRequest(action: Exclude<DevicePairingAction, 'request'>, body: Record<string, unknown>, now?: number): {
16
+ request: DevicePairingStatus;
17
+ routes: DeviceRoute[];
18
+ scopes?: readonly string[];
19
+ };
@@ -0,0 +1,154 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ import { buildDevicePairingProof, devicePairingCompleteSchema, devicePairingDeviceSchema } from "../../../packages/gateway-contract/src/device-pairing.js";
3
+ import { DEFAULT_MOBILE_SCOPES } from "../../gateway/security/gateway-scopes.js";
4
+ import { createDevice, getDevice, registerInitialDeviceRefreshToken, revokeDevice } from "./device-access-repository.js";
5
+ import { getOrCreateGatewayIdentity } from "./gateway-identity-repository.js";
6
+ import crypto from "node:crypto";
7
+ //#region src/storage/sqlite/device-pairing-approval.ts
8
+ const PROOF_WINDOW_MS = 5 * 6e4;
9
+ const APPROVAL_WINDOW_MS = 2 * 6e4;
10
+ const RECOVERY_WINDOW_MS = 1440 * 6e4;
11
+ var DevicePairingError = class extends Error {
12
+ constructor(code, status = 409) {
13
+ super(code);
14
+ this.code = code;
15
+ this.status = status;
16
+ }
17
+ };
18
+ const hash = (value) => crypto.createHash("sha256").update(value).digest("hex");
19
+ const fail = (code, status) => {
20
+ throw new DevicePairingError(code, status);
21
+ };
22
+ function requestRow(id, now) {
23
+ const db = getSqliteDatabase();
24
+ db.prepare(`UPDATE device_pairing_requests SET status = 'expired', revision = revision + 1
25
+ WHERE request_id = ? AND expires_at <= ? AND status IN ('pending', 'approved')`).run(id, now);
26
+ const row = db.prepare("SELECT * FROM device_pairing_requests WHERE request_id = ?").get(id);
27
+ if (!row) return fail("PAIRING_NOT_FOUND", 404);
28
+ return row;
29
+ }
30
+ function statusFromRow(row, now) {
31
+ const device = devicePairingDeviceSchema.parse(JSON.parse(row.device_json));
32
+ return {
33
+ requestId: row.request_id,
34
+ setupId: row.pairing_id,
35
+ status: row.status,
36
+ revision: row.revision,
37
+ displayName: device.displayName,
38
+ platform: device.platform,
39
+ confirmationCode: row.confirmation_code,
40
+ expiresAt: row.expires_at,
41
+ serverTime: now,
42
+ ...row.device_id ? { deviceId: row.device_id } : {}
43
+ };
44
+ }
45
+ function verifiedSetup(token, now) {
46
+ const id = /^xopc_pair_([0-9a-f-]{36})_/i.exec(token)?.[1];
47
+ if (!id) return fail("PAIRING_DENIED", 401);
48
+ const row = getSqliteDatabase().prepare("SELECT * FROM device_pairing_sessions WHERE pairing_id = ?").get(id);
49
+ if (!row || row.protocol_version !== 3 || row.attempts_remaining <= 0) return fail("PAIRING_DENIED", 401);
50
+ if (!crypto.timingSafeEqual(Buffer.from(row.secret_hash, "hex"), Buffer.from(hash(token), "hex"))) {
51
+ getSqliteDatabase().prepare("UPDATE device_pairing_sessions SET attempts_remaining = attempts_remaining - 1 WHERE pairing_id = ?").run(id);
52
+ return fail("PAIRING_DENIED", 401);
53
+ }
54
+ if (now > row.expires_at + RECOVERY_WINDOW_MS) return fail("PAIRING_EXPIRED");
55
+ return row;
56
+ }
57
+ function verifyProof(action, body, deviceJson, now) {
58
+ if (body.gatewayId !== getOrCreateGatewayIdentity().id) fail("PAIRING_IDENTITY_MISMATCH", 401);
59
+ if (typeof body.timestamp !== "number" || Math.abs(now - body.timestamp) > PROOF_WINDOW_MS) fail("PAIRING_PROOF_EXPIRED", 401);
60
+ const device = devicePairingDeviceSchema.parse(JSON.parse(deviceJson));
61
+ let valid = false;
62
+ try {
63
+ valid = crypto.verify("sha256", Buffer.from(buildDevicePairingProof(action, body)), {
64
+ key: crypto.createPublicKey({
65
+ key: device.publicKeyJwk,
66
+ format: "jwk"
67
+ }),
68
+ dsaEncoding: "ieee-p1363"
69
+ }, Buffer.from(String(body.signature), "base64url"));
70
+ } catch {}
71
+ if (!valid) fail("PAIRING_DENIED", 401);
72
+ }
73
+ function submitDevicePairingRequest(body, now = Date.now()) {
74
+ const setup = verifiedSetup(String(body.pairingToken), now);
75
+ const device = devicePairingDeviceSchema.parse(body.device);
76
+ const deviceJson = JSON.stringify(device);
77
+ verifyProof("request", body, deviceJson, now);
78
+ return runSqliteWriteTransaction((db) => {
79
+ const existing = db.prepare("SELECT request_id, device_json FROM device_pairing_requests WHERE pairing_id = ?").get(setup.pairing_id);
80
+ if (existing) {
81
+ if (existing.request_id !== body.requestId || existing.device_json !== deviceJson) return fail("PAIRING_BUSY");
82
+ return statusFromRow(requestRow(existing.request_id, now), now);
83
+ }
84
+ if (setup.consumed_at !== null) return fail("PAIRING_CANCELLED");
85
+ if (setup.expires_at <= now) return fail("PAIRING_EXPIRED");
86
+ const expiresAt = Math.min(setup.expires_at, now + APPROVAL_WINDOW_MS);
87
+ db.prepare(`INSERT INTO device_pairing_requests (request_id, pairing_id, device_json, status,
88
+ confirmation_code, expires_at, recovery_until, created_at) VALUES (?, ?, ?, 'pending', ?, ?, ?, ?)`).run(String(body.requestId), setup.pairing_id, deviceJson, crypto.randomInt(0, 1e6).toString().padStart(6, "0"), expiresAt, setup.expires_at + RECOVERY_WINDOW_MS, now);
89
+ return statusFromRow(requestRow(String(body.requestId), now), now);
90
+ });
91
+ }
92
+ function readDevicePairingSetup(setupId, now = Date.now()) {
93
+ if (!getSqliteDatabase().prepare("SELECT pairing_id FROM device_pairing_sessions WHERE pairing_id = ?").get(setupId)) return fail("PAIRING_NOT_FOUND", 404);
94
+ const row = getSqliteDatabase().prepare("SELECT request_id FROM device_pairing_requests WHERE pairing_id = ?").get(setupId);
95
+ return {
96
+ request: row ? statusFromRow(requestRow(row.request_id, now), now) : null,
97
+ serverTime: now
98
+ };
99
+ }
100
+ function decideDevicePairingRequest(id, decision, revision, now = Date.now()) {
101
+ return runSqliteWriteTransaction((db) => {
102
+ const row = requestRow(id, now);
103
+ if (row.revision !== revision || row.status !== "pending") return fail("PAIRING_CHANGED");
104
+ db.prepare(`UPDATE device_pairing_requests SET status = ?, revision = revision + 1 WHERE request_id = ?`).run(decision === "approve" ? "approved" : "rejected", id);
105
+ return statusFromRow(requestRow(id, now), now);
106
+ });
107
+ }
108
+ function cancelDevicePairingSetup(id, now = Date.now()) {
109
+ runSqliteWriteTransaction((db) => {
110
+ db.prepare("UPDATE device_pairing_sessions SET consumed_at = ? WHERE pairing_id = ? AND consumed_at IS NULL").run(now, id);
111
+ db.prepare(`UPDATE device_pairing_requests SET status = 'cancelled', revision = revision + 1
112
+ WHERE pairing_id = ? AND status IN ('pending', 'approved')`).run(id);
113
+ });
114
+ }
115
+ function operateDevicePairingRequest(action, body, now = Date.now()) {
116
+ const setup = verifiedSetup(String(body.pairingToken), now);
117
+ const row = requestRow(String(body.requestId), now);
118
+ if (row.pairing_id !== setup.pairing_id) return fail("PAIRING_DENIED", 401);
119
+ verifyProof(action, body, row.device_json, now);
120
+ if (action !== "cancel" && row.device_id && getDevice(row.device_id)?.revokedAt !== void 0) return fail("DEVICE_REVOKED", 401);
121
+ if (now >= row.recovery_until) return fail("PAIRING_EXPIRED");
122
+ if (action === "cancel") runSqliteWriteTransaction((db) => {
123
+ if (row.device_id) revokeDevice(row.device_id, now);
124
+ cancelDevicePairingSetup(row.pairing_id, now);
125
+ db.prepare("UPDATE device_pairing_requests SET status = 'cancelled' WHERE request_id = ?").run(row.request_id);
126
+ });
127
+ else if (action === "complete") {
128
+ const complete = devicePairingCompleteSchema.parse(body);
129
+ runSqliteWriteTransaction((db) => {
130
+ const current = requestRow(row.request_id, now);
131
+ if (current.status === "completed") {
132
+ if (current.completion_key !== complete.idempotencyKey || current.initial_token_hash !== hash(complete.initialRefreshToken)) fail("PAIRING_CHANGED");
133
+ return;
134
+ }
135
+ if (current.status !== "approved") fail("PAIRING_NOT_APPROVED");
136
+ const created = createDevice({
137
+ ...devicePairingDeviceSchema.parse(JSON.parse(current.device_json)),
138
+ scopes: DEFAULT_MOBILE_SCOPES,
139
+ now
140
+ });
141
+ registerInitialDeviceRefreshToken(created.id, complete.initialRefreshToken, now);
142
+ db.prepare(`UPDATE device_pairing_requests SET status = 'completed', revision = revision + 1,
143
+ completion_key = ?, initial_token_hash = ?, device_id = ? WHERE request_id = ?`).run(complete.idempotencyKey, hash(complete.initialRefreshToken), created.id, current.request_id);
144
+ db.prepare("UPDATE device_pairing_sessions SET consumed_at = ? WHERE pairing_id = ?").run(now, setup.pairing_id);
145
+ });
146
+ }
147
+ return {
148
+ request: statusFromRow(requestRow(row.request_id, now), now),
149
+ routes: JSON.parse(setup.routes_json),
150
+ ...action === "complete" ? { scopes: DEFAULT_MOBILE_SCOPES } : {}
151
+ };
152
+ }
153
+ //#endregion
154
+ export { DevicePairingError, cancelDevicePairingSetup, decideDevicePairingRequest, operateDevicePairingRequest, readDevicePairingSetup, submitDevicePairingRequest };
@@ -17,6 +17,6 @@ export type PairingConsumeResult = {
17
17
  ok: false;
18
18
  reason: 'invalid' | 'expired' | 'consumed';
19
19
  };
20
- export declare function createDevicePairingSetup(routes: readonly DeviceRoute[], now?: number): DevicePairingSetup;
20
+ export declare function createDevicePairingSetup(routes: readonly DeviceRoute[], now?: number, protocolVersion?: 2 | 3): DevicePairingSetup;
21
21
  export declare function consumeDevicePairingToken(token: string, now?: number): PairingConsumeResult;
22
22
  export declare function isDevicePairingSetupActive(pairingId: string, now?: number): boolean;
@@ -16,18 +16,21 @@ function tokenId(token) {
16
16
  if (separator <= 10 || separator === token.length - 1) return void 0;
17
17
  return token.slice(10, separator);
18
18
  }
19
- function createDevicePairingSetup(routes, now = Date.now()) {
19
+ function createDevicePairingSetup(routes, now = Date.now(), protocolVersion = 2) {
20
20
  if (routes.length === 0) throw new Error("No secure mobile route is available");
21
21
  const id = crypto.randomUUID();
22
22
  const token = `${PAIRING_TOKEN_PREFIX}${id}_${crypto.randomBytes(32).toString("base64url")}`;
23
23
  const expiresAt = now + PAIRING_TTL_MS;
24
24
  runSqliteWriteTransaction((db) => {
25
- db.prepare("DELETE FROM device_pairing_sessions WHERE expires_at <= ? OR consumed_at IS NOT NULL").run(now);
25
+ db.prepare(`DELETE FROM device_pairing_sessions WHERE
26
+ (protocol_version = 2 AND (expires_at <= ? OR consumed_at IS NOT NULL)) OR
27
+ (protocol_version = 3 AND expires_at < ?)`).run(now, now - 1440 * 6e4);
26
28
  db.prepare(`
27
29
  INSERT INTO device_pairing_sessions (
28
30
  pairing_id, secret_hash, routes_json, expires_at, attempts_remaining, created_at
29
- ) VALUES (?, ?, ?, ?, ?, ?)
30
- `).run(id, hashToken(token), JSON.stringify(routes), expiresAt, PAIRING_ATTEMPTS, now);
31
+ , protocol_version
32
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
33
+ `).run(id, hashToken(token), JSON.stringify(routes), expiresAt, PAIRING_ATTEMPTS, now, protocolVersion);
31
34
  });
32
35
  return {
33
36
  id,
@@ -48,6 +51,10 @@ function consumeDevicePairingToken(token, now = Date.now()) {
48
51
  ok: false,
49
52
  reason: "invalid"
50
53
  };
54
+ if (row.protocol_version !== 2) return {
55
+ ok: false,
56
+ reason: "invalid"
57
+ };
51
58
  if (row.consumed_at !== null) return {
52
59
  ok: false,
53
60
  reason: "consumed"
@@ -16,9 +16,10 @@ import { finishContextConsolidationRun, getContextConsolidationRun, listContextC
16
16
  import { summarizeUnderstandingFeedback, summarizeUserUnderstandingQuality } from "./user-context-quality-repository.js";
17
17
  import { closeUnderstandingValidity, consumeContextConsent, createCollaborationRule, createContextEvidence, createUnderstanding, decideContextConsent, deleteCollaborationRule, deleteUnderstanding, ensureContextConsent, getCollaborationRule, getTurnPersonalization, getUnderstanding, getUserProfile, hasContextConsent, isUnderstandingSuppressed, linkUnderstandingEvidence, listCollaborationRules, listUnderstandingEvidence, listUnderstandingStatusEvents, listUnderstandings, recordContextFeedback, recordContextRun, rejectUnderstanding, reviseCollaborationRule, reviseUnderstanding, searchActiveUnderstandings, setCollaborationRuleStatus, setUnderstandingStatus, updateUserProfile } from "./user-context-repository.js";
18
18
  import { getUserPeopleIndexState, getUserPerson, listUserPeople, mergeUserPeople, replaceUserPeopleIndex, summarizeUserPeople, updateUserPerson } from "./user-people-repository.js";
19
- import { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, insertSessionInput, listActiveSessionInputRuns, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "./session-input-repository.js";
20
19
  import { buildDefaultSessionMetadata } from "./session-metadata.js";
21
20
  import { buildGlobalSessionStats, classifyStoredRow, estimateTokensFromMessages, extractFtsContent, metadataToSessionInsert, sessionConfigRowToConfig, sessionRowToMetadata, transcriptEntryRowToStoredRow } from "./row-mappers.js";
21
+ import { deleteSessionRecord, ensureSessionRecord, findSessionKeyBySessionId, getCurrentSessionId, getGlobalSessionStats, getSessionMetadata, getSessionPersistedLevels, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats } from "./session-repository.js";
22
+ import { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, insertSessionInput, listActiveSessionInputRuns, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus } from "./session-input-repository.js";
22
23
  import { replaceLatestSessionTurnAndQueueInput, validateLatestSessionTurnTarget } from "./session-turn-replace-repository.js";
23
24
  import { acknowledgeHomeAttention, isHomeAttentionAcknowledged } from "./home-attention-repository.js";
24
25
  import { claimNextConnectorLearningJob, enqueueConnectorLearningJob, listConnectorLearningJobs, recoverStaleConnectorLearningJobs, setConnectorLearningPaused, updateConnectorLearningJob } from "./connector-learning-repository.js";
@@ -26,7 +27,6 @@ import { COMPOSER_INPUT_HISTORY_LIMIT, appendComposerInputHistory, clearComposer
26
27
  import { bindEndpointPrincipal, createEndpointPrincipal, getEndpointPrincipal, listEndpointPrincipals, revokeEndpointPrincipal, touchEndpointPrincipal } from "./endpoint-principal-repository.js";
27
28
  import { finishEndpointToolInvocationAudit, listEndpointToolInvocationAudits, startEndpointToolInvocationAudit } from "./endpoint-tool-invocation-repository.js";
28
29
  import { getInteractionState, setInteractionState, updateInteractionStateFromMessage } from "./interaction-state-repository.js";
29
- import { deleteSessionRecord, ensureSessionRecord, findSessionKeyBySessionId, getCurrentSessionId, getGlobalSessionStats, getSessionMetadata, getSessionPersistedLevels, incrementSessionStatsOnAppend, listSessionMetadata, listSessionsByAgent, patchSessionMetadata, resetSessionRecord, resolveSessionAgentId, updateSessionStats } from "./session-repository.js";
30
30
  import { getSessionTaskPlan, setSessionTaskPlan } from "./session-task-plan-repository.js";
31
31
  import { buildRelationshipPrompt, getRelationshipSettings, isProactiveSupportAllowed, updateRelationshipSettings } from "./relationship-settings-repository.js";
32
32
  import { appendCompactionBoundaryIfUnchanged, appendTranscriptEntry, listCompactionBoundaries, loadCompactionSourceSnapshot, loadLlmMessagesForSession, loadTranscriptHistoryRowsForSession, loadTranscriptRows, loadTranscriptRowsForSession, paginateTranscriptMessages, replaceTranscriptRows, restoreBeforeCompactionBoundary, searchSessionTranscript } from "./transcript-repository.js";
@@ -0,0 +1,17 @@
1
+ ALTER TABLE device_pairing_sessions ADD COLUMN protocol_version INTEGER NOT NULL DEFAULT 2;
2
+
3
+ CREATE TABLE device_pairing_requests (
4
+ request_id TEXT PRIMARY KEY,
5
+ pairing_id TEXT NOT NULL UNIQUE REFERENCES device_pairing_sessions(pairing_id) ON DELETE CASCADE,
6
+ device_json TEXT NOT NULL,
7
+ status TEXT NOT NULL CHECK (status IN ('pending', 'approved', 'completed', 'rejected', 'cancelled', 'expired')),
8
+ revision INTEGER NOT NULL DEFAULT 1,
9
+ confirmation_code TEXT NOT NULL,
10
+ expires_at INTEGER NOT NULL,
11
+ recovery_until INTEGER NOT NULL,
12
+ completion_key TEXT,
13
+ initial_token_hash TEXT,
14
+ device_id TEXT REFERENCES devices(device_id),
15
+ created_at INTEGER NOT NULL
16
+ );
17
+ CREATE INDEX idx_device_pairing_requests_expiry ON device_pairing_requests(recovery_until);
@@ -0,0 +1 @@
1
+ ALTER TABLE session_inputs ADD COLUMN expected_session_id TEXT;
@@ -0,0 +1 @@
1
+ ALTER TABLE session_config ADD COLUMN fixed_model INTEGER NOT NULL DEFAULT 0 CHECK (fixed_model IN (0, 1));
@@ -0,0 +1,59 @@
1
+ CREATE TABLE execution_environments (
2
+ environment_id TEXT PRIMARY KEY,
3
+ project_id TEXT REFERENCES projects(project_id) ON DELETE SET NULL,
4
+ kind TEXT NOT NULL CHECK (kind IN ('local_checkout', 'managed_worktree')),
5
+ status TEXT NOT NULL CHECK (status IN (
6
+ 'requested', 'provisioning', 'ready', 'degraded', 'deleting', 'deleted', 'error'
7
+ )),
8
+ root_path TEXT NOT NULL CHECK (length(root_path) > 0),
9
+ repository_root TEXT,
10
+ git_common_dir TEXT,
11
+ base_ref TEXT,
12
+ base_sha TEXT,
13
+ branch_ref TEXT,
14
+ version INTEGER NOT NULL DEFAULT 1 CHECK (version > 0),
15
+ last_error TEXT,
16
+ created_at INTEGER NOT NULL,
17
+ updated_at INTEGER NOT NULL,
18
+ last_used_at INTEGER,
19
+ deleted_at INTEGER
20
+ );
21
+
22
+ CREATE UNIQUE INDEX idx_execution_environments_active_root
23
+ ON execution_environments(root_path)
24
+ WHERE deleted_at IS NULL;
25
+
26
+ CREATE INDEX idx_execution_environments_project
27
+ ON execution_environments(project_id, updated_at DESC);
28
+
29
+ CREATE TABLE execution_environment_bindings (
30
+ binding_id TEXT PRIMARY KEY,
31
+ session_key TEXT NOT NULL,
32
+ environment_id TEXT NOT NULL REFERENCES execution_environments(environment_id) ON DELETE CASCADE,
33
+ created_at INTEGER NOT NULL,
34
+ released_at INTEGER
35
+ );
36
+
37
+ CREATE UNIQUE INDEX idx_execution_environment_bindings_active_session
38
+ ON execution_environment_bindings(session_key)
39
+ WHERE released_at IS NULL;
40
+
41
+ CREATE INDEX idx_execution_environment_bindings_environment
42
+ ON execution_environment_bindings(environment_id, created_at DESC);
43
+
44
+ CREATE TABLE execution_environment_events (
45
+ event_id TEXT PRIMARY KEY,
46
+ environment_id TEXT NOT NULL REFERENCES execution_environments(environment_id) ON DELETE CASCADE,
47
+ from_status TEXT CHECK (from_status IS NULL OR from_status IN (
48
+ 'requested', 'provisioning', 'ready', 'degraded', 'deleting', 'deleted', 'error'
49
+ )),
50
+ to_status TEXT NOT NULL CHECK (to_status IN (
51
+ 'requested', 'provisioning', 'ready', 'degraded', 'deleting', 'deleted', 'error'
52
+ )),
53
+ reason TEXT NOT NULL,
54
+ metadata_json TEXT NOT NULL DEFAULT '{}',
55
+ created_at INTEGER NOT NULL
56
+ );
57
+
58
+ CREATE INDEX idx_execution_environment_events_environment
59
+ ON execution_environment_events(environment_id, created_at DESC);
@@ -0,0 +1,5 @@
1
+ ALTER TABLE projects ADD COLUMN execution_mode TEXT NOT NULL DEFAULT 'local_checkout'
2
+ CHECK (execution_mode IN ('local_checkout', 'managed_worktree'));
3
+
4
+ CREATE INDEX idx_projects_execution_mode
5
+ ON projects(execution_mode, updated_at DESC);
@@ -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 = 11;
5
5
  /** Latest schema version this release supports (increment when adding migrations). */
6
- export declare const XOPC_DB_SCHEMA_VERSION = 140;
6
+ export declare const XOPC_DB_SCHEMA_VERSION = 145;
7
7
  export declare function resolveMigrationsDir(override?: string): string;
8
8
  /**
9
9
  * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
@@ -12,7 +12,7 @@ const log = createLogger("Sqlite:Migrations");
12
12
  /** Baseline schema version applied from schema.sql on first open. */
13
13
  const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
14
14
  /** Latest schema version this release supports (increment when adding migrations). */
15
- const XOPC_DB_SCHEMA_VERSION = 140;
15
+ const XOPC_DB_SCHEMA_VERSION = 145;
16
16
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
17
17
  function backupBeforeTaskCutover(db, databasePath) {
18
18
  db.exec("PRAGMA wal_checkpoint(FULL)");
@@ -57,7 +57,7 @@ function applySingleMigration(db, migration) {
57
57
  * Each step runs in its own transaction and updates schema_meta on success.
58
58
  */
59
59
  function applyPendingMigrations(db, options = {}) {
60
- const targetVersion = options.targetVersion ?? 140;
60
+ const targetVersion = options.targetVersion ?? 145;
61
61
  let currentVersion = readSchemaVersion(db);
62
62
  if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
63
63
  if (currentVersion >= targetVersion) return currentVersion;
@@ -94,7 +94,7 @@ function applyPendingMigrations(db, options = {}) {
94
94
  }
95
95
  /** Inspect schema version without mutating the database. */
96
96
  function inspectSchemaMigrationStatus(db, options = {}) {
97
- const appVersion = options.targetVersion ?? 140;
97
+ const appVersion = options.targetVersion ?? 145;
98
98
  const dbVersion = readSchemaVersion(db);
99
99
  if (dbVersion > appVersion) return {
100
100
  dbVersion,
@@ -19,7 +19,7 @@ const log = createLogger('Sqlite:Migrations');
19
19
  export const XOPC_DB_BASELINE_SCHEMA_VERSION = 11;
20
20
 
21
21
  /** Latest schema version this release supports (increment when adding migrations). */
22
- export const XOPC_DB_SCHEMA_VERSION = 140;
22
+ export const XOPC_DB_SCHEMA_VERSION = 145;
23
23
 
24
24
  const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
25
25
 
@@ -51,6 +51,7 @@ export type SessionConfigRow = {
51
51
  verbose_level: string | null;
52
52
  elevated_mode: string | null;
53
53
  model_override: string | null;
54
+ fixed_model?: number;
54
55
  provider_override: string | null;
55
56
  working_directory_override: string | null;
56
57
  response_language: string | null;
@@ -1,7 +1,7 @@
1
- import { isTranscriptContextEntry } from "../../session/session-context-for-llm.js";
2
1
  import "../../session/types.js";
3
- import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../../routing/agent-session-key.js";
4
2
  import { buildDefaultSessionMetadata } from "./session-metadata.js";
3
+ import { isTranscriptContextEntry } from "../../session/session-context-for-llm.js";
4
+ import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../../routing/agent-session-key.js";
5
5
  //#region src/storage/sqlite/row-mappers.ts
6
6
  init_agent_session_key();
7
7
  function parseJson(raw) {
@@ -107,6 +107,7 @@ function sessionConfigRowToConfig(row) {
107
107
  ...row.working_directory_override ? { workingDirectoryOverride: row.working_directory_override } : {},
108
108
  ...row.response_language ? { responseLanguage: row.response_language } : {},
109
109
  ...row.user_context_mode ? { userContextMode: row.user_context_mode } : {},
110
+ ...row.fixed_model === 1 ? { fixedModel: true } : {},
110
111
  updatedAt: row.updated_at
111
112
  };
112
113
  }
@@ -32,7 +32,7 @@ function ensureXopcDatabaseSchema(db, options = {}) {
32
32
  currentVersion = 11;
33
33
  }
34
34
  applyPendingMigrations(db, {
35
- targetVersion: 140,
35
+ targetVersion: 145,
36
36
  databasePath: options.databasePath
37
37
  });
38
38
  }
@@ -6,6 +6,7 @@ export type SessionInput = {
6
6
  id: string;
7
7
  sessionKey: string;
8
8
  clientMessageId: string;
9
+ expectedSessionId?: string;
9
10
  requestedDelivery: SessionInputDelivery;
10
11
  effectiveDelivery: SessionInputDelivery;
11
12
  status: SessionInputStatus;
@@ -38,10 +39,14 @@ export declare function listActiveSessionInputRuns(): Array<{
38
39
  }>;
39
40
  export declare function findSessionInput(sessionKey: string, clientMessageId: string): SessionInput | undefined;
40
41
  export declare function getSessionInputById(sessionKey: string, id: string): SessionInput | undefined;
42
+ export declare class SessionInstanceChangedError extends Error {
43
+ constructor();
44
+ }
41
45
  export declare function insertSessionInput(input: {
42
46
  id: string;
43
47
  sessionKey: string;
44
48
  clientMessageId: string;
49
+ expectedSessionId?: string;
45
50
  requestedDelivery: SessionInputDelivery;
46
51
  effectiveDelivery: SessionInputDelivery;
47
52
  status: 'queued' | 'injecting';
@@ -1,4 +1,5 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
+ import { readCurrentSessionId } from "./session-repository.js";
2
3
  import { turnOriginSchema } from "../../../packages/endpoint-tools-protocol/src/index.js";
3
4
  //#region src/storage/sqlite/session-input-repository.ts
4
5
  function mapInput(row) {
@@ -6,6 +7,7 @@ function mapInput(row) {
6
7
  id: row.id,
7
8
  sessionKey: row.session_key,
8
9
  clientMessageId: row.client_message_id,
10
+ expectedSessionId: row.expected_session_id ?? void 0,
9
11
  requestedDelivery: row.requested_delivery,
10
12
  effectiveDelivery: row.effective_delivery,
11
13
  status: row.status,
@@ -24,7 +26,7 @@ function mapInput(row) {
24
26
  updatedAtMs: row.updated_at_ms
25
27
  };
26
28
  }
27
- const SELECT_INPUTS = `SELECT id, session_key, client_message_id, requested_delivery,
29
+ const SELECT_INPUTS = `SELECT id, session_key, client_message_id, expected_session_id, requested_delivery,
28
30
  effective_delivery, status, content, attachments_json, context_refs_json, context_snapshots_json,
29
31
  thinking, origin_json, position,
30
32
  target_run_id, run_id, version, error, created_at_ms, updated_at_ms
@@ -72,18 +74,24 @@ function getSessionInputById(sessionKey, id) {
72
74
  const row = getSqliteDatabase().prepare(`${SELECT_INPUTS} WHERE session_key = ? AND id = ?`).get(sessionKey, id);
73
75
  return row ? mapInput(row) : void 0;
74
76
  }
77
+ var SessionInstanceChangedError = class extends Error {
78
+ constructor() {
79
+ super("Session instance changed");
80
+ }
81
+ };
75
82
  function insertSessionInput(input) {
76
83
  return runSqliteWriteTransaction((db) => {
77
84
  const existing = db.prepare(`${SELECT_INPUTS} WHERE session_key = ? AND client_message_id = ?`).get(input.sessionKey, input.clientMessageId);
78
85
  if (existing) return mapInput(existing);
86
+ if (input.expectedSessionId && readCurrentSessionId(db, input.sessionKey) !== input.expectedSessionId) throw new SessionInstanceChangedError();
79
87
  const now = Date.now();
80
88
  const max = db.prepare(`SELECT COALESCE(MAX(position), 0) AS value FROM session_inputs
81
89
  WHERE session_key = ? AND status IN ('queued','running','injecting','interrupted')`).get(input.sessionKey);
82
- db.prepare(`INSERT INTO session_inputs(id, session_key, client_message_id,
90
+ db.prepare(`INSERT INTO session_inputs(id, session_key, client_message_id, expected_session_id,
83
91
  requested_delivery, effective_delivery, status, content, attachments_json,
84
92
  context_refs_json, context_snapshots_json, thinking, origin_json, position,
85
93
  target_run_id, version, created_at_ms, updated_at_ms)
86
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)`).run(input.id, input.sessionKey, input.clientMessageId, input.requestedDelivery, input.effectiveDelivery, input.status, input.content, input.attachments ? JSON.stringify(input.attachments) : null, input.contextRefs ? JSON.stringify(input.contextRefs) : null, input.contextSnapshots ? JSON.stringify(input.contextSnapshots) : null, input.thinking ?? null, JSON.stringify(input.origin), max.value + 1, input.targetRunId ?? null, now, now);
94
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)`).run(input.id, input.sessionKey, input.clientMessageId, input.expectedSessionId ?? null, input.requestedDelivery, input.effectiveDelivery, input.status, input.content, input.attachments ? JSON.stringify(input.attachments) : null, input.contextRefs ? JSON.stringify(input.contextRefs) : null, input.contextSnapshots ? JSON.stringify(input.contextSnapshots) : null, input.thinking ?? null, JSON.stringify(input.origin), max.value + 1, input.targetRunId ?? null, now, now);
87
95
  bumpRevision(db, input.sessionKey);
88
96
  return mapInput(db.prepare(`${SELECT_INPUTS} WHERE id = ?`).get(input.id));
89
97
  });
@@ -92,6 +100,9 @@ function claimNextSessionInput(sessionKey, runId) {
92
100
  return runSqliteWriteTransaction((db) => {
93
101
  ensureRuntime(db, sessionKey);
94
102
  if (db.prepare(`SELECT active_run_id FROM session_input_runtime WHERE session_key = ?`).get(sessionKey).active_run_id) return void 0;
103
+ if (db.prepare(`UPDATE session_inputs SET status = 'interrupted', error = 'Session changed before delivery',
104
+ version = version + 1, updated_at_ms = ? WHERE session_key = ? AND status = 'queued'
105
+ AND expected_session_id IS NOT NULL AND expected_session_id IS NOT ?`).run(Date.now(), sessionKey, readCurrentSessionId(db, sessionKey)).changes) bumpRevision(db, sessionKey);
95
106
  const row = db.prepare(`${SELECT_INPUTS} WHERE session_key = ? AND effective_delivery = 'next'
96
107
  AND status = 'queued' ORDER BY position, created_at_ms, id LIMIT 1`).get(sessionKey);
97
108
  if (!row) return void 0;
@@ -166,4 +177,4 @@ function recoverSessionInputState() {
166
177
  });
167
178
  }
168
179
  //#endregion
169
- export { cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, insertSessionInput, listActiveSessionInputRuns, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus };
180
+ export { SessionInstanceChangedError, cancelQueuedSessionInput, claimNextSessionInput, findSessionInput, finishSessionInputRun, getSessionInputById, getSessionInputState, insertSessionInput, listActiveSessionInputRuns, mutateQueuedSessionInput, recoverSessionInputState, setSessionInputStatus };
@@ -1,8 +1,8 @@
1
1
  import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
2
2
  import { buildFts5SearchQuery } from "./fts.js";
3
+ import { validateSessionId } from "../../session/session-id.js";
3
4
  import { buildDefaultSessionMetadata } from "./session-metadata.js";
4
5
  import { buildGlobalSessionStats, metadataToSessionInsert, sessionRowToMetadata } from "./row-mappers.js";
5
- import { validateSessionId } from "../../session/session-id.js";
6
6
  import { randomUUID } from "node:crypto";
7
7
  //#region src/storage/sqlite/session-repository.ts
8
8
  const SESSION_COLUMNS = `
@@ -1,4 +1,5 @@
1
1
  import type { SessionMetadata } from '../session/types.js';
2
+ import type { ExecutionEnvironmentKind } from '../execution-environments/types.js';
2
3
  export type ExecutionOrigin = 'chat' | 'task' | 'workflow' | 'automation' | 'browser' | 'proactive';
3
4
  export type ExecutionTrigger = 'user' | 'schedule' | 'webhook' | 'proactive' | 'retry';
4
5
  export interface ExecutionContext {
@@ -6,7 +7,8 @@ export interface ExecutionContext {
6
7
  sessionKey: string;
7
8
  channel: string;
8
9
  agentId?: string;
9
- strategy?: string;
10
+ executionEnvironmentId?: string;
11
+ executionKind?: ExecutionEnvironmentKind;
10
12
  taskId?: string;
11
13
  projectId?: string;
12
14
  origin: ExecutionOrigin;