@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
@@ -0,0 +1,37 @@
1
+ import { ExecutionEnvironmentStore } from './store.js';
2
+ import { type ExecutionEnvironment } from './types.js';
3
+ export interface ProvisionManagedWorktreeInput {
4
+ projectId: string;
5
+ repositoryPath: string;
6
+ baseRef?: string;
7
+ environmentId?: string;
8
+ }
9
+ export interface LocalWorktreeInspection {
10
+ healthy: boolean;
11
+ registered: boolean;
12
+ rootExists: boolean;
13
+ dirty: boolean;
14
+ headSha?: string;
15
+ branchRef?: string;
16
+ locked: boolean;
17
+ problems: string[];
18
+ }
19
+ export interface LocalWorktreeManagerOptions {
20
+ store?: ExecutionEnvironmentStore;
21
+ stateDir?: string;
22
+ }
23
+ export declare class LocalWorktreeManager {
24
+ private readonly store;
25
+ private readonly stateDir?;
26
+ constructor(options?: LocalWorktreeManagerOptions);
27
+ registerLocalCheckout(input: {
28
+ projectId?: string;
29
+ workspacePath: string;
30
+ environmentId?: string;
31
+ }): Promise<ExecutionEnvironment>;
32
+ provisionManagedWorktree(input: ProvisionManagedWorktreeInput): Promise<ExecutionEnvironment>;
33
+ inspect(environmentId: string): Promise<LocalWorktreeInspection>;
34
+ reconcile(environmentId: string): Promise<ExecutionEnvironment>;
35
+ remove(environmentId: string): Promise<ExecutionEnvironment>;
36
+ private cleanupFailedProvision;
37
+ }
@@ -0,0 +1,322 @@
1
+ import { createLogger } from "../utils/logger/index.js";
2
+ import { init_logger } from "../utils/logger.js";
3
+ import { ExecutionEnvironmentConflictError } from "./types.js";
4
+ import { ExecutionEnvironmentStore } from "./store.js";
5
+ import { findGitWorktree, inspectGitRepository, resolveGitCommit, runGit } from "./git.js";
6
+ import { resolveExecutionWorktreesRoot, resolveManagedWorktreePath } from "./paths.js";
7
+ import { dirname, relative, resolve } from "node:path";
8
+ import { existsSync } from "node:fs";
9
+ import { randomUUID } from "node:crypto";
10
+ import { mkdir, rm, stat } from "node:fs/promises";
11
+ import lockfile from "proper-lockfile";
12
+ //#region src/execution-environments/local-worktree-manager.ts
13
+ init_logger();
14
+ const log = createLogger("ExecutionEnvironment:LocalWorktree");
15
+ async function withRepositoryLock(gitCommonDir, fn) {
16
+ const lockPath = resolve(gitCommonDir, "xopc-worktree.lock");
17
+ const release = await lockfile.lock(gitCommonDir, {
18
+ realpath: false,
19
+ lockfilePath: lockPath,
20
+ retries: {
21
+ retries: 20,
22
+ factor: 1.2,
23
+ minTimeout: 25,
24
+ maxTimeout: 250
25
+ }
26
+ });
27
+ try {
28
+ return await fn();
29
+ } finally {
30
+ await release();
31
+ }
32
+ }
33
+ function errorMessage(error) {
34
+ return (error instanceof Error ? error.message : String(error)).slice(0, 2e3);
35
+ }
36
+ async function isDirectory(path) {
37
+ try {
38
+ return (await stat(path)).isDirectory();
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+ function assertManagedPath(rootPath, stateDir) {
44
+ const managedRoot = resolveExecutionWorktreesRoot(stateDir);
45
+ const candidate = resolve(rootPath);
46
+ const child = relative(managedRoot, candidate);
47
+ if (!child || child.startsWith("..") || resolve(managedRoot, child) !== candidate) throw new Error(`Refusing to manage worktree outside ${managedRoot}`);
48
+ }
49
+ var LocalWorktreeManager = class {
50
+ store;
51
+ stateDir;
52
+ constructor(options = {}) {
53
+ this.store = options.store ?? new ExecutionEnvironmentStore();
54
+ this.stateDir = options.stateDir;
55
+ }
56
+ async registerLocalCheckout(input) {
57
+ if (!await isDirectory(input.workspacePath)) throw new Error(`Local checkout does not exist: ${input.workspacePath}`);
58
+ const repository = await inspectGitRepository(input.workspacePath).catch(() => void 0);
59
+ const environment = this.store.create({
60
+ ...input.environmentId ? { id: input.environmentId } : {},
61
+ ...input.projectId ? { projectId: input.projectId } : {},
62
+ kind: "local_checkout",
63
+ rootPath: input.workspacePath,
64
+ ...repository ? {
65
+ repositoryRoot: repository.repositoryRoot,
66
+ gitCommonDir: repository.gitCommonDir,
67
+ baseRef: repository.branchRef ?? "HEAD",
68
+ baseSha: repository.headSha,
69
+ branchRef: repository.branchRef
70
+ } : {}
71
+ });
72
+ const provisioning = this.store.transition({
73
+ environmentId: environment.id,
74
+ expectedVersion: environment.version,
75
+ toStatus: "provisioning",
76
+ reason: "local checkout validation started"
77
+ });
78
+ return this.store.transition({
79
+ environmentId: environment.id,
80
+ expectedVersion: provisioning.version,
81
+ toStatus: "ready",
82
+ reason: "local checkout validated"
83
+ });
84
+ }
85
+ async provisionManagedWorktree(input) {
86
+ const repository = await inspectGitRepository(input.repositoryPath);
87
+ if (repository.dirty) throw new ExecutionEnvironmentConflictError(`Repository has uncommitted changes: ${repository.repositoryRoot}`);
88
+ const baseRef = input.baseRef?.trim() || "HEAD";
89
+ const baseSha = await resolveGitCommit(repository.repositoryRoot, baseRef);
90
+ const environmentId = input.environmentId?.trim() || randomUUID();
91
+ const rootPath = resolveManagedWorktreePath(input.projectId, environmentId, this.stateDir);
92
+ assertManagedPath(rootPath, this.stateDir);
93
+ if (existsSync(rootPath)) throw new ExecutionEnvironmentConflictError(`Worktree path already exists: ${rootPath}`);
94
+ const environment = this.store.create({
95
+ id: environmentId,
96
+ projectId: input.projectId,
97
+ kind: "managed_worktree",
98
+ rootPath,
99
+ repositoryRoot: repository.repositoryRoot,
100
+ gitCommonDir: repository.gitCommonDir,
101
+ baseRef,
102
+ baseSha
103
+ });
104
+ const provisioning = this.store.transition({
105
+ environmentId: environment.id,
106
+ expectedVersion: environment.version,
107
+ toStatus: "provisioning",
108
+ reason: "managed worktree provisioning started"
109
+ });
110
+ try {
111
+ await withRepositoryLock(repository.gitCommonDir, async () => {
112
+ await mkdir(dirname(rootPath), {
113
+ recursive: true,
114
+ mode: 448
115
+ });
116
+ await runGit(repository.repositoryRoot, [
117
+ "worktree",
118
+ "add",
119
+ "--detach",
120
+ "--lock",
121
+ rootPath,
122
+ baseSha
123
+ ]);
124
+ if (!await findGitWorktree(repository.repositoryRoot, rootPath)) throw new Error(`Git did not register worktree ${rootPath}`);
125
+ });
126
+ const ready = this.store.transition({
127
+ environmentId: environment.id,
128
+ expectedVersion: provisioning.version,
129
+ toStatus: "ready",
130
+ reason: "managed worktree provisioned",
131
+ metadata: { baseSha }
132
+ });
133
+ log.info({
134
+ environmentId: ready.id,
135
+ projectId: ready.projectId,
136
+ path: ready.rootPath
137
+ }, "Managed worktree ready");
138
+ return ready;
139
+ } catch (error) {
140
+ await this.cleanupFailedProvision(repository.repositoryRoot, repository.gitCommonDir, rootPath);
141
+ const failed = this.store.transition({
142
+ environmentId: environment.id,
143
+ expectedVersion: provisioning.version,
144
+ toStatus: "error",
145
+ reason: "managed worktree provisioning failed",
146
+ error: errorMessage(error)
147
+ });
148
+ log.error({
149
+ err: error,
150
+ environmentId: failed.id,
151
+ path: rootPath
152
+ }, `Managed worktree provisioning failed: ${failed.lastError}`);
153
+ throw error;
154
+ }
155
+ }
156
+ async inspect(environmentId) {
157
+ const environment = this.store.getRequired(environmentId);
158
+ if (environment.kind !== "managed_worktree" || !environment.repositoryRoot) throw new Error(`Execution environment ${environmentId} is not a managed worktree`);
159
+ const rootExists = await isDirectory(environment.rootPath);
160
+ const registered = await findGitWorktree(environment.repositoryRoot, environment.rootPath).catch(() => void 0);
161
+ const problems = [];
162
+ if (!rootExists) problems.push("worktree root is missing");
163
+ if (!registered) problems.push("worktree is not registered in Git");
164
+ let dirty = false;
165
+ if (rootExists && registered) dirty = Boolean(await runGit(environment.rootPath, [
166
+ "status",
167
+ "--porcelain=v1",
168
+ "-z",
169
+ "--untracked-files=all"
170
+ ]));
171
+ return {
172
+ healthy: problems.length === 0,
173
+ registered: Boolean(registered),
174
+ rootExists,
175
+ dirty,
176
+ ...registered?.headSha ? { headSha: registered.headSha } : {},
177
+ ...registered?.branchRef ? { branchRef: registered.branchRef } : {},
178
+ locked: registered?.locked ?? false,
179
+ problems
180
+ };
181
+ }
182
+ async reconcile(environmentId) {
183
+ const environment = this.store.getRequired(environmentId);
184
+ const inspection = await this.inspect(environmentId);
185
+ if (inspection.healthy) {
186
+ if (environment.status !== "degraded" && environment.status !== "provisioning") return environment;
187
+ const provisioning = environment.status === "provisioning" ? environment : this.store.transition({
188
+ environmentId,
189
+ expectedVersion: environment.version,
190
+ toStatus: "provisioning",
191
+ reason: "managed worktree reconciliation started"
192
+ });
193
+ return this.store.transition({
194
+ environmentId,
195
+ expectedVersion: provisioning.version,
196
+ toStatus: "ready",
197
+ reason: "managed worktree reconciliation succeeded"
198
+ });
199
+ }
200
+ if (environment.status === "degraded" || environment.status === "error") return environment;
201
+ if (environment.status !== "ready" && environment.status !== "provisioning") throw new ExecutionEnvironmentConflictError(`Cannot reconcile managed worktree ${environmentId} while ${environment.status}`);
202
+ return this.store.transition({
203
+ environmentId,
204
+ expectedVersion: environment.version,
205
+ toStatus: "degraded",
206
+ reason: "managed worktree reconciliation detected drift",
207
+ error: inspection.problems.join("; ")
208
+ });
209
+ }
210
+ async remove(environmentId) {
211
+ const environment = this.store.getRequired(environmentId);
212
+ if (environment.status === "deleted") return environment;
213
+ if (environment.kind === "local_checkout") {
214
+ if (this.store.listBindings(environmentId).length > 0) throw new ExecutionEnvironmentConflictError(`Local checkout ${environmentId} still has active bindings`);
215
+ const deleting = environment.status === "deleting" ? environment : this.store.transition({
216
+ environmentId,
217
+ expectedVersion: environment.version,
218
+ toStatus: "deleting",
219
+ reason: "local checkout retirement started"
220
+ });
221
+ const deleted = this.store.transition({
222
+ environmentId,
223
+ expectedVersion: deleting.version,
224
+ toStatus: "deleted",
225
+ reason: "local checkout retired"
226
+ });
227
+ log.info({
228
+ environmentId,
229
+ path: environment.rootPath
230
+ }, "Local checkout retired");
231
+ return deleted;
232
+ }
233
+ if (environment.kind !== "managed_worktree" || !environment.repositoryRoot || !environment.gitCommonDir) throw new Error(`Execution environment ${environmentId} is not a managed worktree`);
234
+ assertManagedPath(environment.rootPath, this.stateDir);
235
+ if (this.store.listBindings(environmentId).length > 0) throw new ExecutionEnvironmentConflictError(`Managed worktree ${environmentId} still has active bindings`);
236
+ const deleting = environment.status === "deleting" ? environment : this.store.transition({
237
+ environmentId,
238
+ expectedVersion: environment.version,
239
+ toStatus: "deleting",
240
+ reason: "managed worktree deletion started"
241
+ });
242
+ try {
243
+ await withRepositoryLock(environment.gitCommonDir, async () => {
244
+ const registered = await findGitWorktree(environment.repositoryRoot, environment.rootPath);
245
+ if (!registered && existsSync(environment.rootPath)) throw new ExecutionEnvironmentConflictError("Refusing to delete a directory no longer registered as this worktree");
246
+ if (registered) {
247
+ if (registered.headSha && registered.headSha !== environment.baseSha) {
248
+ if (!(await runGit(environment.repositoryRoot, [
249
+ "for-each-ref",
250
+ `--contains=${registered.headSha}`,
251
+ "--format=%(refname)",
252
+ "refs/heads",
253
+ "refs/remotes"
254
+ ])).trim()) throw new ExecutionEnvironmentConflictError("Save detached commits on a branch before deleting this worktree");
255
+ }
256
+ if (registered.locked) await runGit(environment.repositoryRoot, [
257
+ "worktree",
258
+ "unlock",
259
+ environment.rootPath
260
+ ]);
261
+ try {
262
+ await runGit(environment.repositoryRoot, [
263
+ "worktree",
264
+ "remove",
265
+ environment.rootPath
266
+ ]);
267
+ } catch (error) {
268
+ if (registered.locked) await runGit(environment.repositoryRoot, [
269
+ "worktree",
270
+ "lock",
271
+ environment.rootPath
272
+ ]).catch(() => "");
273
+ throw error;
274
+ }
275
+ }
276
+ });
277
+ const deleted = this.store.transition({
278
+ environmentId,
279
+ expectedVersion: deleting.version,
280
+ toStatus: "deleted",
281
+ reason: "managed worktree deleted"
282
+ });
283
+ log.info({
284
+ environmentId,
285
+ path: environment.rootPath
286
+ }, "Managed worktree deleted");
287
+ return deleted;
288
+ } catch (error) {
289
+ this.store.transition({
290
+ environmentId,
291
+ expectedVersion: deleting.version,
292
+ toStatus: "error",
293
+ reason: "managed worktree deletion failed",
294
+ error: errorMessage(error)
295
+ });
296
+ throw error;
297
+ }
298
+ }
299
+ async cleanupFailedProvision(repositoryRoot, gitCommonDir, rootPath) {
300
+ await withRepositoryLock(gitCommonDir, async () => {
301
+ if (await findGitWorktree(repositoryRoot, rootPath).catch(() => void 0)) {
302
+ await runGit(repositoryRoot, [
303
+ "worktree",
304
+ "unlock",
305
+ rootPath
306
+ ]).catch(() => "");
307
+ await runGit(repositoryRoot, [
308
+ "worktree",
309
+ "remove",
310
+ "--force",
311
+ rootPath
312
+ ]).catch(() => "");
313
+ }
314
+ if (existsSync(rootPath)) await rm(rootPath, {
315
+ recursive: true,
316
+ force: true
317
+ });
318
+ }).catch(() => void 0);
319
+ }
320
+ };
321
+ //#endregion
322
+ export { LocalWorktreeManager };
@@ -0,0 +1,2 @@
1
+ export declare function resolveExecutionWorktreesRoot(stateDir?: string): string;
2
+ export declare function resolveManagedWorktreePath(projectId: string, environmentId: string, stateDir?: string): string;
@@ -0,0 +1,18 @@
1
+ import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
2
+ import { join, resolve } from "node:path";
3
+ //#region src/execution-environments/paths.ts
4
+ init_paths_state();
5
+ const SAFE_PATH_SEGMENT = /^[a-zA-Z0-9._-]+$/;
6
+ function safePathSegment(value, label) {
7
+ const normalized = value.trim();
8
+ if (!normalized || !SAFE_PATH_SEGMENT.test(normalized) || normalized === "." || normalized === "..") throw new Error(`${label} contains unsupported path characters`);
9
+ return normalized;
10
+ }
11
+ function resolveExecutionWorktreesRoot(stateDir = resolveStateDir()) {
12
+ return resolve(stateDir, "worktrees");
13
+ }
14
+ function resolveManagedWorktreePath(projectId, environmentId, stateDir = resolveStateDir()) {
15
+ return join(resolveExecutionWorktreesRoot(stateDir), safePathSegment(projectId, "projectId"), safePathSegment(environmentId, "environmentId"));
16
+ }
17
+ //#endregion
18
+ export { resolveExecutionWorktreesRoot, resolveManagedWorktreePath };
@@ -0,0 +1,22 @@
1
+ import type { Project, ProjectExecutionMode } from '../projects/types.js';
2
+ import { LocalWorktreeManager } from './local-worktree-manager.js';
3
+ import { ExecutionEnvironmentStore } from './store.js';
4
+ import { type ExecutionEnvironment } from './types.js';
5
+ export interface SessionEnvironmentServiceOptions {
6
+ store?: ExecutionEnvironmentStore;
7
+ worktrees?: LocalWorktreeManager;
8
+ }
9
+ export declare class SessionEnvironmentService {
10
+ private readonly store;
11
+ private readonly worktrees;
12
+ constructor(options?: SessionEnvironmentServiceOptions);
13
+ get(sessionKey: string): ExecutionEnvironment | undefined;
14
+ attach(input: {
15
+ sessionKey: string;
16
+ project: Project;
17
+ mode?: ProjectExecutionMode;
18
+ baseRef?: string;
19
+ }): Promise<ExecutionEnvironment>;
20
+ release(sessionKey: string, removeManaged?: boolean): Promise<ExecutionEnvironment | undefined>;
21
+ private resolveLocalCheckout;
22
+ }
@@ -0,0 +1,73 @@
1
+ import { ExecutionEnvironmentConflictError } from "./types.js";
2
+ import { ExecutionEnvironmentStore } from "./store.js";
3
+ import { LocalWorktreeManager } from "./local-worktree-manager.js";
4
+ import { resolve } from "node:path";
5
+ //#region src/execution-environments/session-environment-service.ts
6
+ var SessionEnvironmentService = class {
7
+ store;
8
+ worktrees;
9
+ constructor(options = {}) {
10
+ this.store = options.store ?? new ExecutionEnvironmentStore();
11
+ this.worktrees = options.worktrees ?? new LocalWorktreeManager({ store: this.store });
12
+ }
13
+ get(sessionKey) {
14
+ const binding = this.store.resolveBinding(sessionKey);
15
+ return binding ? this.store.get(binding.environmentId) : void 0;
16
+ }
17
+ async attach(input) {
18
+ const existing = this.get(input.sessionKey);
19
+ if (existing) {
20
+ if (existing.projectId !== input.project.id) throw new ExecutionEnvironmentConflictError(`Session ${input.sessionKey} is already bound to a different project's execution environment`);
21
+ if (input.mode && existing.kind !== input.mode) throw new ExecutionEnvironmentConflictError(`Session ${input.sessionKey} is already using ${existing.kind}; release it before switching to ${input.mode}`);
22
+ return existing;
23
+ }
24
+ const workspaceRoot = input.project.workspaceRoot?.trim();
25
+ if (!workspaceRoot) throw new ExecutionEnvironmentConflictError(`Project ${input.project.id} needs a fixed workspace before an execution environment can be created`);
26
+ const environment = (input.mode ?? input.project.executionMode) === "managed_worktree" ? await this.worktrees.provisionManagedWorktree({
27
+ projectId: input.project.id,
28
+ repositoryPath: workspaceRoot,
29
+ baseRef: input.baseRef
30
+ }) : await this.resolveLocalCheckout(input.project.id, workspaceRoot);
31
+ try {
32
+ this.store.bind({
33
+ sessionKey: input.sessionKey,
34
+ environmentId: environment.id
35
+ });
36
+ return environment;
37
+ } catch (error) {
38
+ if (environment.kind === "managed_worktree") await this.worktrees.remove(environment.id).catch(() => void 0);
39
+ throw error;
40
+ }
41
+ }
42
+ async release(sessionKey, removeManaged = true) {
43
+ const binding = this.store.resolveBinding(sessionKey);
44
+ if (!binding) return void 0;
45
+ const environment = this.store.get(binding.environmentId);
46
+ this.store.releaseBinding(sessionKey, binding.environmentId);
47
+ if (removeManaged && environment?.kind === "managed_worktree") await this.worktrees.remove(environment.id);
48
+ return environment;
49
+ }
50
+ async resolveLocalCheckout(projectId, workspaceRoot) {
51
+ const rootPath = resolve(workspaceRoot);
52
+ const existing = this.store.list({
53
+ projectId,
54
+ limit: 500
55
+ }).find((environment) => environment.kind === "local_checkout" && environment.rootPath === rootPath && environment.status === "ready");
56
+ if (existing) return existing;
57
+ try {
58
+ return await this.worktrees.registerLocalCheckout({
59
+ projectId,
60
+ workspacePath: rootPath
61
+ });
62
+ } catch (error) {
63
+ const raced = this.store.list({
64
+ projectId,
65
+ limit: 500
66
+ }).find((environment) => environment.kind === "local_checkout" && environment.rootPath === rootPath && environment.status === "ready");
67
+ if (raced) return raced;
68
+ throw error;
69
+ }
70
+ }
71
+ };
72
+ //#endregion
73
+ export { SessionEnvironmentService };
@@ -0,0 +1,13 @@
1
+ import { type BindExecutionEnvironmentInput, type CreateExecutionEnvironmentInput, type ExecutionEnvironment, type ExecutionEnvironmentBinding, type ExecutionEnvironmentEvent, type ExecutionEnvironmentListQuery, type TransitionExecutionEnvironmentInput } from './types.js';
2
+ export declare class ExecutionEnvironmentStore {
3
+ create(input: CreateExecutionEnvironmentInput): ExecutionEnvironment;
4
+ get(environmentId: string): ExecutionEnvironment | undefined;
5
+ getRequired(environmentId: string): ExecutionEnvironment;
6
+ list(query?: ExecutionEnvironmentListQuery): ExecutionEnvironment[];
7
+ transition(input: TransitionExecutionEnvironmentInput): ExecutionEnvironment;
8
+ bind(input: BindExecutionEnvironmentInput): ExecutionEnvironmentBinding;
9
+ resolveBinding(sessionKey: string): ExecutionEnvironmentBinding | undefined;
10
+ listBindings(environmentId: string, includeReleased?: boolean): ExecutionEnvironmentBinding[];
11
+ releaseBinding(sessionKey: string, expectedEnvironmentId?: string): ExecutionEnvironmentBinding | undefined;
12
+ listEvents(environmentId: string): ExecutionEnvironmentEvent[];
13
+ }
@@ -0,0 +1,183 @@
1
+ import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
2
+ import { ExecutionEnvironmentConflictError, ExecutionEnvironmentNotFoundError, canTransitionExecutionEnvironment } from "./types.js";
3
+ import { resolve } from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ //#region src/execution-environments/store.ts
6
+ function optionalText(value) {
7
+ return value?.trim() || void 0;
8
+ }
9
+ function requiredText(value, label) {
10
+ const normalized = value.trim();
11
+ if (!normalized) throw new Error(`${label} is required`);
12
+ return normalized;
13
+ }
14
+ function environmentFromRow(row) {
15
+ return {
16
+ id: row.environment_id,
17
+ ...row.project_id ? { projectId: row.project_id } : {},
18
+ kind: row.kind,
19
+ status: row.status,
20
+ rootPath: row.root_path,
21
+ ...row.repository_root ? { repositoryRoot: row.repository_root } : {},
22
+ ...row.git_common_dir ? { gitCommonDir: row.git_common_dir } : {},
23
+ ...row.base_ref ? { baseRef: row.base_ref } : {},
24
+ ...row.base_sha ? { baseSha: row.base_sha } : {},
25
+ ...row.branch_ref ? { branchRef: row.branch_ref } : {},
26
+ version: row.version,
27
+ ...row.last_error ? { lastError: row.last_error } : {},
28
+ createdAt: row.created_at,
29
+ updatedAt: row.updated_at,
30
+ ...row.last_used_at == null ? {} : { lastUsedAt: row.last_used_at },
31
+ ...row.deleted_at == null ? {} : { deletedAt: row.deleted_at }
32
+ };
33
+ }
34
+ function bindingFromRow(row) {
35
+ return {
36
+ id: row.binding_id,
37
+ sessionKey: row.session_key,
38
+ environmentId: row.environment_id,
39
+ createdAt: row.created_at,
40
+ ...row.released_at == null ? {} : { releasedAt: row.released_at }
41
+ };
42
+ }
43
+ function eventFromRow(row) {
44
+ return {
45
+ id: row.event_id,
46
+ environmentId: row.environment_id,
47
+ ...row.from_status ? { fromStatus: row.from_status } : {},
48
+ toStatus: row.to_status,
49
+ reason: row.reason,
50
+ metadata: JSON.parse(row.metadata_json),
51
+ createdAt: row.created_at
52
+ };
53
+ }
54
+ function getEnvironmentRow(environmentId) {
55
+ return getSqliteDatabase().prepare(`SELECT * FROM execution_environments WHERE environment_id = ?`).get(environmentId);
56
+ }
57
+ var ExecutionEnvironmentStore = class {
58
+ create(input) {
59
+ const id = input.id?.trim() || randomUUID();
60
+ const rootPath = resolve(requiredText(input.rootPath, "rootPath"));
61
+ const projectId = optionalText(input.projectId);
62
+ const repositoryRoot = optionalText(input.repositoryRoot);
63
+ const gitCommonDir = optionalText(input.gitCommonDir);
64
+ if (input.kind === "managed_worktree" && (!repositoryRoot || !gitCommonDir)) throw new Error("managed_worktree requires repositoryRoot and gitCommonDir");
65
+ const now = Date.now();
66
+ runSqliteWriteTransaction((db) => {
67
+ db.prepare(`INSERT INTO execution_environments (
68
+ environment_id, project_id, kind, status, root_path,
69
+ repository_root, git_common_dir, base_ref, base_sha, branch_ref,
70
+ version, created_at, updated_at
71
+ ) VALUES (?, ?, ?, 'requested', ?, ?, ?, ?, ?, ?, 1, ?, ?)`).run(id, projectId ?? null, input.kind, rootPath, repositoryRoot ? resolve(repositoryRoot) : null, gitCommonDir ? resolve(gitCommonDir) : null, optionalText(input.baseRef) ?? null, optionalText(input.baseSha) ?? null, optionalText(input.branchRef) ?? null, now, now);
72
+ db.prepare(`INSERT INTO execution_environment_events (
73
+ event_id, environment_id, from_status, to_status, reason, metadata_json, created_at
74
+ ) VALUES (?, ?, NULL, 'requested', 'created', '{}', ?)`).run(randomUUID(), id, now);
75
+ });
76
+ return this.getRequired(id);
77
+ }
78
+ get(environmentId) {
79
+ const row = getEnvironmentRow(environmentId);
80
+ return row ? environmentFromRow(row) : void 0;
81
+ }
82
+ getRequired(environmentId) {
83
+ const environment = this.get(environmentId);
84
+ if (!environment) throw new ExecutionEnvironmentNotFoundError(environmentId);
85
+ return environment;
86
+ }
87
+ list(query = {}) {
88
+ const clauses = [];
89
+ const params = [];
90
+ if (query.projectId) {
91
+ clauses.push("project_id = ?");
92
+ params.push(query.projectId);
93
+ }
94
+ if (query.status) {
95
+ clauses.push("status = ?");
96
+ params.push(query.status);
97
+ }
98
+ if (!query.includeDeleted) clauses.push("deleted_at IS NULL");
99
+ const limit = Math.min(500, Math.max(1, Math.floor(query.limit ?? 100)));
100
+ params.push(limit);
101
+ const where = clauses.length > 0 ? `WHERE ${clauses.join(" AND ")}` : "";
102
+ return getSqliteDatabase().prepare(`SELECT * FROM execution_environments ${where} ORDER BY updated_at DESC LIMIT ?`).all(...params).map(environmentFromRow);
103
+ }
104
+ transition(input) {
105
+ const reason = requiredText(input.reason, "reason");
106
+ const now = Date.now();
107
+ runSqliteWriteTransaction((db) => {
108
+ const row = getEnvironmentRow(input.environmentId);
109
+ if (!row) throw new ExecutionEnvironmentNotFoundError(input.environmentId);
110
+ if (row.version !== input.expectedVersion) throw new ExecutionEnvironmentConflictError(`Execution environment ${input.environmentId} changed from version ${input.expectedVersion} to ${row.version}`);
111
+ if (!canTransitionExecutionEnvironment(row.status, input.toStatus)) throw new ExecutionEnvironmentConflictError(`Cannot transition execution environment ${input.environmentId} from ${row.status} to ${input.toStatus}`);
112
+ const error = optionalText(input.error);
113
+ const lastError = input.toStatus === "error" || input.toStatus === "degraded" ? error ?? row.last_error : null;
114
+ if (db.prepare(`UPDATE execution_environments
115
+ SET status = ?, version = version + 1, updated_at = ?, last_error = ?,
116
+ deleted_at = CASE WHEN ? = 'deleted' THEN ? ELSE deleted_at END
117
+ WHERE environment_id = ? AND version = ?`).run(input.toStatus, now, lastError, input.toStatus, now, input.environmentId, input.expectedVersion).changes !== 1) throw new ExecutionEnvironmentConflictError(`Execution environment ${input.environmentId} changed concurrently`);
118
+ db.prepare(`INSERT INTO execution_environment_events (
119
+ event_id, environment_id, from_status, to_status, reason, metadata_json, created_at
120
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)`).run(randomUUID(), input.environmentId, row.status, input.toStatus, reason, JSON.stringify(input.metadata ?? {}), now);
121
+ });
122
+ return this.getRequired(input.environmentId);
123
+ }
124
+ bind(input) {
125
+ const sessionKey = requiredText(input.sessionKey, "sessionKey");
126
+ return runSqliteWriteTransaction((db) => {
127
+ const environment = getEnvironmentRow(input.environmentId);
128
+ if (!environment) throw new ExecutionEnvironmentNotFoundError(input.environmentId);
129
+ if (environment.status !== "ready") throw new ExecutionEnvironmentConflictError(`Execution environment ${input.environmentId} is not bindable while ${environment.status}`);
130
+ const active = db.prepare(`SELECT * FROM execution_environment_bindings
131
+ WHERE session_key = ? AND released_at IS NULL`).get(sessionKey);
132
+ if (active) {
133
+ if (active.environment_id === input.environmentId) return bindingFromRow(active);
134
+ throw new ExecutionEnvironmentConflictError(`Session ${sessionKey} is already bound to ${active.environment_id}`);
135
+ }
136
+ if (environment.kind === "managed_worktree") {
137
+ const owner = db.prepare(`SELECT * FROM execution_environment_bindings
138
+ WHERE environment_id = ? AND released_at IS NULL LIMIT 1`).get(input.environmentId);
139
+ if (owner) throw new ExecutionEnvironmentConflictError(`Managed worktree ${input.environmentId} is already bound to session ${owner.session_key}`);
140
+ }
141
+ const binding = {
142
+ id: randomUUID(),
143
+ sessionKey,
144
+ environmentId: input.environmentId,
145
+ createdAt: Date.now()
146
+ };
147
+ db.prepare(`INSERT INTO execution_environment_bindings (
148
+ binding_id, session_key, environment_id, created_at
149
+ ) VALUES (?, ?, ?, ?)`).run(binding.id, binding.sessionKey, binding.environmentId, binding.createdAt);
150
+ db.prepare(`UPDATE execution_environments SET last_used_at = ?, updated_at = ? WHERE environment_id = ?`).run(binding.createdAt, binding.createdAt, binding.environmentId);
151
+ return binding;
152
+ });
153
+ }
154
+ resolveBinding(sessionKey) {
155
+ const row = getSqliteDatabase().prepare(`SELECT * FROM execution_environment_bindings
156
+ WHERE session_key = ? AND released_at IS NULL`).get(sessionKey);
157
+ return row ? bindingFromRow(row) : void 0;
158
+ }
159
+ listBindings(environmentId, includeReleased = false) {
160
+ return getSqliteDatabase().prepare(`SELECT * FROM execution_environment_bindings
161
+ WHERE environment_id = ? ${includeReleased ? "" : "AND released_at IS NULL"}
162
+ ORDER BY created_at, rowid`).all(environmentId).map(bindingFromRow);
163
+ }
164
+ releaseBinding(sessionKey, expectedEnvironmentId) {
165
+ return runSqliteWriteTransaction((db) => {
166
+ const active = db.prepare(`SELECT * FROM execution_environment_bindings
167
+ WHERE session_key = ? AND released_at IS NULL`).get(sessionKey);
168
+ if (!active) return void 0;
169
+ if (expectedEnvironmentId && active.environment_id !== expectedEnvironmentId) throw new ExecutionEnvironmentConflictError(`Session ${sessionKey} is bound to ${active.environment_id}, not ${expectedEnvironmentId}`);
170
+ const releasedAt = Date.now();
171
+ db.prepare(`UPDATE execution_environment_bindings SET released_at = ? WHERE binding_id = ? AND released_at IS NULL`).run(releasedAt, active.binding_id);
172
+ return bindingFromRow({
173
+ ...active,
174
+ released_at: releasedAt
175
+ });
176
+ });
177
+ }
178
+ listEvents(environmentId) {
179
+ return getSqliteDatabase().prepare(`SELECT * FROM execution_environment_events WHERE environment_id = ? ORDER BY created_at, rowid`).all(environmentId).map(eventFromRow);
180
+ }
181
+ };
182
+ //#endregion
183
+ export { ExecutionEnvironmentStore };
@@ -0,0 +1,2 @@
1
+ import type { ExecutionEnvironment } from './types.js';
2
+ export declare function getExecutionEnvironmentForSession(sessionKey: string): ExecutionEnvironment | undefined;