@xopcai/xopc 0.0.241 → 0.0.243

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 (257) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{activity-store-CLnbVm9G.js → activity-store-CAah-_8h.js} +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DuBewmbW.js → agent-avatar-dicebear-DDH4HgP7.js} +1 -1
  5. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BDCfJZhh.js +1 -0
  6. package/dist/gateway/static/root/assets/agents-B0ZWgf-U.js +1 -0
  7. package/dist/gateway/static/root/assets/{api-DjBZe303.js → api-B2tKxbcz.js} +1 -1
  8. package/dist/gateway/static/root/assets/app-management-settings-panel-Blfwszzn.js +1 -0
  9. package/dist/gateway/static/root/assets/{appearance-settings-B-iul0RG.js → appearance-settings-C3V7Na75.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-BiEks0-F.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-BOx0EJZs.js → archive-plugin-BmSx7wzY.js} +1 -1
  12. package/dist/gateway/static/root/assets/{attachment-load-Cfk1lwBo.js → attachment-load-BS-S4LJ9.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-page-BTSGvaeS.js → automations-page-C7Y3L30D.js} +1 -1
  14. package/dist/gateway/static/root/assets/automations-workspace-A3zPkPuo.js +6 -0
  15. package/dist/gateway/static/root/assets/{binary-plugins-ChZyZK45.js → binary-plugins-BM9B5kcm.js} +1 -1
  16. package/dist/gateway/static/root/assets/block-editor-BbnpkYP9.js +185 -0
  17. package/dist/gateway/static/root/assets/browser-settings-page-Dk4FQ7fY.js +8 -0
  18. package/dist/gateway/static/root/assets/{browser-workflow-inputs-jvfcgFG-.js → browser-workflow-inputs-CRnkgZHI.js} +1 -1
  19. package/dist/gateway/static/root/assets/{browser-workflows-page-DrHW7XNi.js → browser-workflows-page-B9qGL-it.js} +2 -2
  20. package/dist/gateway/static/root/assets/{button-CSEbl4zT.js → button-CtTvuElV.js} +1 -1
  21. package/dist/gateway/static/root/assets/capabilities-settings-panel--tR_El9e.js +7 -0
  22. package/dist/gateway/static/root/assets/channels-settings-D347vl_J.js +1 -0
  23. package/dist/gateway/static/root/assets/{channels-status-swr-CC9MFway.js → channels-status-swr-DuY4MGxe.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-DeeZrVbV.js → chat-terminal-dock-DABPvwBT.js} +2 -2
  25. package/dist/gateway/static/root/assets/connectors-page-B-tvJkRJ.js +2 -0
  26. package/dist/gateway/static/root/assets/{cron-expression-CiqQOeQ3.js → cron-expression-D3bsKbNd.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-CGAMGPfU.js → date-picker-BsGM6Yty.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-CxWeUTsc.js → dependency-picker-Dj3g6YXZ.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-C3QmYO75.js → desktop-pet-C1QT0Sur.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-CAADkWYy.js → desktop-pet-settings-r6kAOnfY.js} +1 -1
  31. package/dist/gateway/static/root/assets/dist-CpzYSoz7.js +1 -0
  32. package/dist/gateway/static/root/assets/{dist-DaxPZj9e.js → dist-DBS3OB8K.js} +1 -1
  33. package/dist/gateway/static/root/assets/dist-DLmwHyAh.js +1 -0
  34. package/dist/gateway/static/root/assets/es2015-BvLh9GaE.js +41 -0
  35. package/dist/gateway/static/root/assets/{extension-debug-page-FQXjDJ8P.js → extension-debug-page-DOkf7nh9.js} +1 -1
  36. package/dist/gateway/static/root/assets/{extension-page-BJE1D5Ji.js → extension-page-Cq2IA4Ho.js} +1 -1
  37. package/dist/gateway/static/root/assets/{extension-settings-page-5Ik2tNry.js → extension-settings-page-DQn4qjDZ.js} +1 -1
  38. package/dist/gateway/static/root/assets/{files-DQjhZjr2.js → files-D6vf3S30.js} +1 -1
  39. package/dist/gateway/static/root/assets/{gateway-config-api-cTj71t2a.js → gateway-config-api-DM3poL22.js} +1 -1
  40. package/dist/gateway/static/root/assets/{gateway-config-swr-Bxe_R-JH.js → gateway-config-swr-BC3pgb_P.js} +1 -1
  41. package/dist/gateway/static/root/assets/{gateway-settings-KXBUjNcx.js → gateway-settings-DPgH1hnh.js} +1 -1
  42. package/dist/gateway/static/root/assets/{gateway-startup-retry-DJG-I0wW.js → gateway-startup-retry-uMcSfLru.js} +1 -1
  43. package/dist/gateway/static/root/assets/{heartbeat-settings-C8cVzIcs.js → heartbeat-settings-Bk80-E3b.js} +1 -1
  44. package/dist/gateway/static/root/assets/home-page-DKo5JiMR.js +1 -0
  45. package/dist/gateway/static/root/assets/{image-generation-api-Dc_ojQuj.js → image-generation-api-D1qlQA-A.js} +1 -1
  46. package/dist/gateway/static/root/assets/index-B0WJL9N1.js +71 -0
  47. package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +2 -0
  48. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-pOKl7blR.js → keyboard-shortcuts-settings-BEwvd8ZU.js} +1 -1
  49. package/dist/gateway/static/root/assets/local-app-workbench-page--eJ5rmNj.js +2 -0
  50. package/dist/gateway/static/root/assets/{local-apps-page-Bi6wwKgm.js → local-apps-page-CgkY9E-r.js} +1 -1
  51. package/dist/gateway/static/root/assets/{locale-store-C5wr3_pc.js → locale-store-CMZljTJx.js} +1 -1
  52. package/dist/gateway/static/root/assets/logs-page-Z49Td0J9.js +2 -0
  53. package/dist/gateway/static/root/assets/{management-settings-DGlVizWi.js → management-settings-Dv8NSJKt.js} +1 -1
  54. package/dist/gateway/static/root/assets/{markdown-split-CXP5zBx_.js → markdown-split-Cm0RBB-t.js} +1 -1
  55. package/dist/gateway/static/root/assets/{markdown-view-D6LxlDxr.js → markdown-view-PPCLt7fu.js} +3 -3
  56. package/dist/gateway/static/root/assets/{media-plugins-BsENGLr2.js → media-plugins-Bcr5sU1f.js} +1 -1
  57. package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +3 -0
  58. package/dist/gateway/static/root/assets/mobile-pairing-wizard-kKDiXofY.js +1 -0
  59. package/dist/gateway/static/root/assets/{models-hub-cache-Y7GUjxHx.js → models-hub-cache-ZrbGRiGY.js} +1 -1
  60. package/dist/gateway/static/root/assets/{notes-page-D2EqpDyo.js → notes-page-CgsaRaGi.js} +1 -1
  61. package/dist/gateway/static/root/assets/notes-workbench-C1DEE09k.js +4 -0
  62. package/dist/gateway/static/root/assets/{oauth-api-C5NVcsKE.js → oauth-api-4VeMbkTJ.js} +1 -1
  63. package/dist/gateway/static/root/assets/popover-select-C-Hj-nXR.js +1 -0
  64. package/dist/gateway/static/root/assets/{product-delivery-dUJgmBQZ.js → product-delivery-CV4pDOtG.js} +1 -1
  65. package/dist/gateway/static/root/assets/product-open-page-BU0HiZtv.js +1 -0
  66. package/dist/gateway/static/root/assets/project-detail-page-isRapnp5.js +1 -0
  67. package/dist/gateway/static/root/assets/projects-page-zvsjg0mi.js +1 -0
  68. package/dist/gateway/static/root/assets/{registry-api-FXdFaoWM.js → registry-api-CWOtPFrE.js} +1 -1
  69. package/dist/gateway/static/root/assets/remote-access-hub-C9TGZ9Hc.js +1 -0
  70. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-2zm9edMA.js +5 -0
  71. package/dist/gateway/static/root/assets/{schema-form-BUzdHWx6.js → schema-form-54A5gzkN.js} +1 -1
  72. package/dist/gateway/static/root/assets/{schemas-zIBW3wiV.js → schemas-BHS7bo06.js} +1 -1
  73. package/dist/gateway/static/root/assets/sessions-page-BP8RyiUn.js +1 -0
  74. package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +1 -0
  75. package/dist/gateway/static/root/assets/{settings-page-C0OBLqpu.js → settings-page-DzDhoyxv.js} +1 -1
  76. package/dist/gateway/static/root/assets/{setup-status-panel-NpLQkFCh.js → setup-status-panel-uDicHU1w.js} +1 -1
  77. package/dist/gateway/static/root/assets/{share-preview-page-BtbPYaYC.js → share-preview-page-lOmLCWFS.js} +1 -1
  78. package/dist/gateway/static/root/assets/shares-settings-T4Yvouvv.js +1 -0
  79. package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +1 -0
  80. package/dist/gateway/static/root/assets/{skills-page-CYk8pN97.js → skills-page-CnyNH3To.js} +1 -1
  81. package/dist/gateway/static/root/assets/skills-page.utils-CgDtf2qs.js +1 -0
  82. package/dist/gateway/static/root/assets/{system-settings-panel-DmCRSvtd.js → system-settings-panel-C8yWfwtR.js} +1 -1
  83. package/dist/gateway/static/root/assets/task-detail-page-Tzfjlbf3.js +1 -0
  84. package/dist/gateway/static/root/assets/{theme-store-DUko1ZnE.js → theme-store-uxUwr10D.js} +1 -1
  85. package/dist/gateway/static/root/assets/tunnel-api-Bvg679no.js +1 -0
  86. package/dist/gateway/static/root/assets/{use-autosave-W_P8Kiv4.js → use-autosave-D88VGoyG.js} +1 -1
  87. package/dist/gateway/static/root/assets/user-context-page-RijPtyfO.js +1 -0
  88. package/dist/gateway/static/root/assets/{voice-api-key-field-BZD0j1jc.js → voice-api-key-field-CBHLsMcc.js} +1 -1
  89. package/dist/gateway/static/root/assets/voice-config-api-MqyI6cgq.js +1 -0
  90. package/dist/gateway/static/root/assets/work-discovery-overlay-GGe2TQ98.js +1 -0
  91. package/dist/gateway/static/root/assets/workflow-run-setup-panel-C0layUE9.js +3 -0
  92. package/dist/gateway/static/root/assets/workflows-page-DQXIzBAc.js +5 -0
  93. package/dist/gateway/static/root/index.html +21 -22
  94. package/dist/package.js +1 -1
  95. package/dist/packages/realtime-protocol/src/voice-audio.js +20 -0
  96. package/dist/packages/realtime-protocol/src/voice.js +208 -0
  97. package/dist/src/agent/agent-manager.js +1 -0
  98. package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
  99. package/dist/src/agent/embedded/run-for-session.js +2 -1
  100. package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
  101. package/dist/src/agent/inbound/turn-dispatcher.js +2 -1
  102. package/dist/src/agent/prompt/voice-presentation.d.ts +2 -0
  103. package/dist/src/agent/prompt/voice-presentation.js +12 -0
  104. package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -0
  105. package/dist/src/agent/service/direct-turn-helpers.js +1 -0
  106. package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
  107. package/dist/src/agent/service/process-direct-streaming.js +2 -1
  108. package/dist/src/agent/session/session-config-service.js +4 -2
  109. package/dist/src/agent/skills/installer.d.ts +1 -0
  110. package/dist/src/agent/skills/installer.js +9 -6
  111. package/dist/src/agent/tools/factory.d.ts +2 -0
  112. package/dist/src/agent/tools/factory.js +5 -1
  113. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  114. package/dist/src/config/models-json.d.ts +8 -8
  115. package/dist/src/config/schema.d.ts +60 -0
  116. package/dist/src/config/schema.js +36 -4
  117. package/dist/src/extensions/install.js +1 -1
  118. package/dist/src/files/file-service.d.ts +1 -0
  119. package/dist/src/files/file-service.js +4 -0
  120. package/dist/src/gateway/chat-stream/thinking-delta-coalescer.js +8 -3
  121. package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -11
  122. package/dist/src/gateway/hono/lib/config-payload.js +2 -2
  123. package/dist/src/gateway/hono/lib/safe-voice-config.d.ts +14 -0
  124. package/dist/src/gateway/hono/lib/safe-voice-config.js +29 -1
  125. package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
  126. package/dist/src/gateway/hono/routes/files.js +7 -0
  127. package/dist/src/gateway/hono/routes/lazy-fallback.js +18 -4
  128. package/dist/src/gateway/hono/routes/runtime-tools.js +7 -1
  129. package/dist/src/gateway/hono/routes/session-input-handler.js +14 -0
  130. package/dist/src/gateway/hono/routes/sessions.js +4 -1
  131. package/dist/src/gateway/hono/routes/voice.js +140 -3
  132. package/dist/src/gateway/server.js +1 -0
  133. package/dist/src/gateway/service/agent-runner.d.ts +1 -0
  134. package/dist/src/gateway/service/agent-runner.js +1 -6
  135. package/dist/src/gateway/service/run-gateway-agent.d.ts +1 -0
  136. package/dist/src/gateway/service/run-gateway-agent.js +19 -1
  137. package/dist/src/gateway/service.d.ts +2 -0
  138. package/dist/src/gateway/service.js +73 -0
  139. package/dist/src/media-understanding/types.d.ts +61 -0
  140. package/dist/src/runtime-tools/archive.js +17 -3
  141. package/dist/src/runtime-tools/command.d.ts +1 -0
  142. package/dist/src/runtime-tools/command.js +29 -8
  143. package/dist/src/runtime-tools/environment.d.ts +1 -0
  144. package/dist/src/runtime-tools/environment.js +11 -16
  145. package/dist/src/runtime-tools/install-lock.d.ts +1 -1
  146. package/dist/src/runtime-tools/install-lock.js +34 -21
  147. package/dist/src/runtime-tools/manager.d.ts +1 -1
  148. package/dist/src/runtime-tools/manager.js +99 -64
  149. package/dist/src/runtime-tools/manifest-store.d.ts +2 -0
  150. package/dist/src/runtime-tools/manifest-store.js +29 -8
  151. package/dist/src/runtime-tools/paths.d.ts +2 -1
  152. package/dist/src/runtime-tools/paths.js +19 -8
  153. package/dist/src/runtime-tools/probe.d.ts +2 -0
  154. package/dist/src/runtime-tools/probe.js +13 -1
  155. package/dist/src/runtime-tools/prune.js +21 -7
  156. package/dist/src/session/client-history.js +12 -0
  157. package/dist/src/session/manager.d.ts +1 -0
  158. package/dist/src/session/session-context-for-llm.js +8 -0
  159. package/dist/src/session/store.d.ts +1 -0
  160. package/dist/src/session/store.js +1 -0
  161. package/dist/src/session/stored-rows-to-file-entries.js +5 -1
  162. package/dist/src/session/voice-transcript.d.ts +9 -0
  163. package/dist/src/session/voice-transcript.js +45 -0
  164. package/dist/src/storage/sqlite/config-repository.js +9 -0
  165. package/dist/src/storage/sqlite/remote-context-repository.d.ts +3 -0
  166. package/dist/src/storage/sqlite/remote-context-repository.js +40 -0
  167. package/dist/src/storage/sqlite/session-repository.js +13 -0
  168. package/dist/src/storage/sqlite/user-context-repository.d.ts +3 -1
  169. package/dist/src/storage/sqlite/user-context-repository.js +50 -4
  170. package/dist/src/tui/tui.js +2 -1
  171. package/dist/src/user-context/automatic-context.d.ts +17 -0
  172. package/dist/src/user-context/automatic-context.js +85 -0
  173. package/dist/src/user-context/changes.d.ts +7 -0
  174. package/dist/src/user-context/changes.js +28 -0
  175. package/dist/src/user-context/planner.js +1 -24
  176. package/dist/src/user-context/retriever.js +10 -11
  177. package/dist/src/user-context/selection-policy.d.ts +20 -0
  178. package/dist/src/user-context/selection-policy.js +33 -0
  179. package/dist/src/user-context/sources/index.js +2 -2
  180. package/dist/src/user-context/sources/repository.d.ts +2 -1
  181. package/dist/src/user-context/sources/repository.js +26 -5
  182. package/dist/src/voice/dashscope/streaming-stt-session.d.ts +2 -0
  183. package/dist/src/voice/dashscope/streaming-stt-session.js +249 -0
  184. package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +12 -0
  185. package/dist/src/voice/dashscope/streaming-tts-stream.js +153 -0
  186. package/dist/src/voice/realtime/agentEngine.d.ts +10 -0
  187. package/dist/src/voice/realtime/agentEngine.js +403 -0
  188. package/dist/src/voice/realtime/audio-playback-window.d.ts +9 -0
  189. package/dist/src/voice/realtime/audio-playback-window.js +49 -0
  190. package/dist/src/voice/realtime/conversation-context.d.ts +11 -0
  191. package/dist/src/voice/realtime/conversation-context.js +76 -0
  192. package/dist/src/voice/realtime/engine.d.ts +13 -0
  193. package/dist/src/voice/realtime/engine.js +1 -0
  194. package/dist/src/voice/realtime/memory-context.d.ts +17 -0
  195. package/dist/src/voice/realtime/memory-context.js +100 -0
  196. package/dist/src/voice/realtime/omniEngine.d.ts +18 -0
  197. package/dist/src/voice/realtime/omniEngine.js +443 -0
  198. package/dist/src/voice/realtime/omniRoute.d.ts +10 -0
  199. package/dist/src/voice/realtime/omniRoute.js +31 -0
  200. package/dist/src/voice/realtime/runtime.d.ts +99 -0
  201. package/dist/src/voice/realtime/runtime.js +622 -0
  202. package/dist/src/voice/realtime/speakable-segmenter.d.ts +10 -0
  203. package/dist/src/voice/realtime/speakable-segmenter.js +87 -0
  204. package/dist/src/voice/stt/list-providers.js +2 -1
  205. package/dist/src/voice/stt/providers/alibaba-transcription.js +13 -1
  206. package/dist/src/voice/stt/providers/xopc-cloud-transcription.js +23 -0
  207. package/dist/src/voice/tts/factory.js +1 -0
  208. package/dist/src/voice/tts/openai-compatible-speech.js +3 -1
  209. package/dist/src/voice/tts/providers/alibaba-speech.d.ts +1 -5
  210. package/dist/src/voice/tts/providers/alibaba-speech.js +25 -8
  211. package/dist/src/voice/tts/providers/edge-speech.js +21 -22
  212. package/dist/src/voice/tts/providers/minimax-speech.js +6 -3
  213. package/dist/src/voice/tts/providers/xopc-cloud-speech.js +26 -1
  214. package/dist/src/voice/tts/speak-core.d.ts +6 -2
  215. package/dist/src/voice/tts/speak-core.js +46 -34
  216. package/dist/src/voice/tts/speech-provider-types.d.ts +1 -0
  217. package/package.json +6 -6
  218. package/dist/gateway/static/root/assets/Combination-14nmIgxH.js +0 -41
  219. package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DbdgX6AA.js +0 -1
  220. package/dist/gateway/static/root/assets/agents-BX3uRVm4.js +0 -1
  221. package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +0 -1
  222. package/dist/gateway/static/root/assets/app-management-settings-panel-D8evZyFQ.js +0 -1
  223. package/dist/gateway/static/root/assets/apps-page-CoZd_cZu.js +0 -1
  224. package/dist/gateway/static/root/assets/automations-workspace-C8RRKT-a.js +0 -6
  225. package/dist/gateway/static/root/assets/block-editor-DCH9b2Ht.js +0 -184
  226. package/dist/gateway/static/root/assets/browser-settings-page-D1GPwIfx.js +0 -8
  227. package/dist/gateway/static/root/assets/capabilities-settings-panel-CrXB1Q-l.js +0 -7
  228. package/dist/gateway/static/root/assets/channels-settings-DWMSYaNZ.js +0 -1
  229. package/dist/gateway/static/root/assets/connectors-page-DXTl1fNB.js +0 -2
  230. package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +0 -1
  231. package/dist/gateway/static/root/assets/dist-DqPZM2MH.js +0 -1
  232. package/dist/gateway/static/root/assets/home-page-NdWtBda5.js +0 -1
  233. package/dist/gateway/static/root/assets/index-7i2P3312.js +0 -70
  234. package/dist/gateway/static/root/assets/index-DTo3IcbW.css +0 -2
  235. package/dist/gateway/static/root/assets/local-app-workbench-page-C_j_od5f.js +0 -2
  236. package/dist/gateway/static/root/assets/logs-page-D6PDZEVP.js +0 -2
  237. package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +0 -3
  238. package/dist/gateway/static/root/assets/mobile-pairing-wizard-DcEz7qcX.js +0 -1
  239. package/dist/gateway/static/root/assets/notes-workbench-Bu0a83Oj.js +0 -4
  240. package/dist/gateway/static/root/assets/popover-select-DrILF6mR.js +0 -1
  241. package/dist/gateway/static/root/assets/product-open-page-DMhf1rdz.js +0 -1
  242. package/dist/gateway/static/root/assets/project-detail-page-DDHi0Y4Q.js +0 -1
  243. package/dist/gateway/static/root/assets/projects-page-CVMFKpmu.js +0 -1
  244. package/dist/gateway/static/root/assets/remote-access-hub-B74aErBY.js +0 -1
  245. package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Bv-akndY.js +0 -5
  246. package/dist/gateway/static/root/assets/sessions-page-D2wmGNZE.js +0 -1
  247. package/dist/gateway/static/root/assets/settings-advanced-gate-CYCCUMEt.js +0 -1
  248. package/dist/gateway/static/root/assets/shares-settings-rf8f1OGq.js +0 -1
  249. package/dist/gateway/static/root/assets/skill-reload-api-BkvclZ_o.js +0 -1
  250. package/dist/gateway/static/root/assets/skills-page.utils-DGjnz-NG.js +0 -1
  251. package/dist/gateway/static/root/assets/task-detail-page-6a2RdDl2.js +0 -1
  252. package/dist/gateway/static/root/assets/tunnel-api-Chfiba_x.js +0 -1
  253. package/dist/gateway/static/root/assets/user-context-page-SeOHP6XO.js +0 -1
  254. package/dist/gateway/static/root/assets/voice-config-api-BO6A8V3Z.js +0 -1
  255. package/dist/gateway/static/root/assets/work-discovery-overlay-BfwEoOGL.js +0 -1
  256. package/dist/gateway/static/root/assets/workflow-run-setup-panel-X7Z5_lRX.js +0 -3
  257. package/dist/gateway/static/root/assets/workflows-page-BklMzkg8.js +0 -5
@@ -9,9 +9,9 @@ import { canFallbackRuntimeDownload, downloadVerifiedArchive } from "./downloade
9
9
  import { canFallbackPythonInstall, resolveRuntimeDownloadSource, runtimeGatewayPythonMirror } from "./download-source.js";
10
10
  import { withInstallLock } from "./install-lock.js";
11
11
  import { runtimeDownloadPath, runtimeLockPath, runtimeStagingDir, runtimeToolsRoot, runtimeVersionDir } from "./paths.js";
12
- import { readRuntimeManifest, writeRuntimeManifest } from "./manifest-store.js";
12
+ import { readRuntimeManifests, writeRuntimeManifest } from "./manifest-store.js";
13
13
  import { bundledPythonArchiveName, resolveOfflineBundleArtifact } from "./offline-bundle.js";
14
- import { parseRuntimeVersion, probeSystemRuntime, versionSatisfies } from "./probe.js";
14
+ import { normalizeRuntimeVersionRequest, parseRuntimeVersion, probeSystemRuntime, resolveInstallVersion, versionSatisfies } from "./probe.js";
15
15
  import { dirname, join } from "node:path";
16
16
  import { randomUUID } from "node:crypto";
17
17
  import { access, mkdir, realpath, rename, rm } from "node:fs/promises";
@@ -47,6 +47,16 @@ function uvExecutables(installDir) {
47
47
  uvx: join(installDir, executableName("uvx"))
48
48
  };
49
49
  }
50
+ function isPathWithin(root, target) {
51
+ return target === root || target.startsWith(`${root}${process.platform === "win32" ? "\\" : "/"}`);
52
+ }
53
+ async function validateManagedExecutables(installDir, executables) {
54
+ for (const executable of Object.values(executables)) {
55
+ if (!executable) continue;
56
+ if (!isPathWithin(installDir, await realpath(executable))) return false;
57
+ }
58
+ return true;
59
+ }
50
60
  function managedNodeProbeEnvironment(executables) {
51
61
  const env = { ...process.env };
52
62
  applyPathPrepend(env, [dirname(executables.node ?? executables.primary)]);
@@ -102,7 +112,9 @@ var ManagedRuntimeManager = class extends EventEmitter {
102
112
  }
103
113
  async resolve(request) {
104
114
  const config = runtimeConfig(this.options, request.runtime);
105
- const requestedVersion = request.version ?? this.defaultVersion(request.runtime);
115
+ const rawVersion = request.version ?? this.defaultVersion(request.runtime);
116
+ const requestedVersion = normalizeRuntimeVersionRequest(rawVersion);
117
+ if (!requestedVersion) throw new RuntimeError(`Invalid ${request.runtime} runtime version: ${rawVersion}`, "RUNTIME_VERSION_MISMATCH", request.runtime, "validate_version", false);
106
118
  if (!this.options.config.enabled || !config.enabled) throw new RuntimeError(`${request.runtime} runtime is disabled`, "RUNTIME_DISABLED", request.runtime, "resolve", false);
107
119
  const key = `${request.runtime}:${requestedVersion}:${request.allowProvision === true}`;
108
120
  const existing = this.inFlight.get(key);
@@ -146,22 +158,21 @@ var ManagedRuntimeManager = class extends EventEmitter {
146
158
  throw new RuntimeError(`${runtime} ${requestedVersion} is not available`, "RUNTIME_NOT_FOUND", runtime, "resolve", true, [`Run xopc runtime install ${runtime}`]);
147
159
  }
148
160
  async probeManaged(runtime, requestedVersion) {
149
- const manifest = await readRuntimeManifest(this.options.stateDir, runtime);
150
- if (!manifest || !versionSatisfies(manifest.version, requestedVersion)) return null;
151
- try {
161
+ const manifests = (await readRuntimeManifests(this.options.stateDir, runtime)).filter((manifest) => versionSatisfies(manifest.version, requestedVersion));
162
+ for (const manifest of manifests) try {
152
163
  const toolsRoot = await realpath(runtimeToolsRoot(this.options.stateDir));
153
164
  const installDir = await realpath(manifest.installDir);
154
- if (installDir !== toolsRoot && !installDir.startsWith(`${toolsRoot}${process.platform === "win32" ? "\\" : "/"}`)) return null;
155
- await access(manifest.executables.primary);
165
+ if (!isPathWithin(toolsRoot, installDir)) continue;
166
+ if (!await validateManagedExecutables(installDir, manifest.executables)) continue;
156
167
  const result = await runRuntimeCommand({
157
168
  command: manifest.executables.primary,
158
169
  args: ["--version"]
159
170
  });
160
171
  const version = parseRuntimeVersion(`${result.stdout}\n${result.stderr}`);
161
- if (!result.ok || !version || !versionSatisfies(version, requestedVersion)) return null;
172
+ if (!result.ok || !version || !versionSatisfies(version, requestedVersion)) continue;
162
173
  if (runtime === "node") {
163
174
  const packageManagers = await probeNodePackageManagers(manifest.executables);
164
- if (!packageManagers?.npm.ok || !packageManagers.npx.ok) return null;
175
+ if (!packageManagers?.npm.ok || !packageManagers.npx.ok) continue;
165
176
  }
166
177
  return {
167
178
  runtime,
@@ -171,17 +182,18 @@ var ManagedRuntimeManager = class extends EventEmitter {
171
182
  executables: manifest.executables,
172
183
  installDir: manifest.installDir
173
184
  };
174
- } catch {
175
- return null;
176
- }
185
+ } catch {}
186
+ return null;
177
187
  }
178
188
  async install(runtime, version = this.defaultVersion(runtime), signal) {
179
189
  const config = runtimeConfig(this.options, runtime);
180
190
  if (!this.options.config.enabled || !config.enabled) throw new RuntimeError(`${runtime} runtime is disabled`, "RUNTIME_DISABLED", runtime, "install", false);
181
- if (runtime === "python") return await this.installPython(version, signal);
182
- return await this.installDistribution(runtime, version, signal);
191
+ const installVersion = resolveInstallVersion(version, DEFAULT_RUNTIME_VERSIONS[runtime]);
192
+ if (!installVersion) throw new RuntimeError(`Managed ${runtime} installation requires an exact version or a range containing catalog version ${DEFAULT_RUNTIME_VERSIONS[runtime]}`, "RUNTIME_VERSION_MISMATCH", runtime, "validate_version", false);
193
+ if (runtime === "python") return await this.installPython(installVersion, signal);
194
+ return await this.installDistribution(runtime, installVersion, signal);
183
195
  }
184
- async installDistribution(runtime, version, signal) {
196
+ async installDistribution(runtime, version, signal, alreadyLocked = false) {
185
197
  const platform = detectRuntimePlatform();
186
198
  if (!platform) throw new RuntimeError(`Managed ${runtime} is not supported on ${process.platform}-${process.arch}`, "RUNTIME_UNSUPPORTED", runtime, "resolve_asset", false);
187
199
  const operationId = randomUUID();
@@ -191,11 +203,8 @@ var ManagedRuntimeManager = class extends EventEmitter {
191
203
  platform
192
204
  });
193
205
  const installDir = runtimeVersionDir(this.options.stateDir, runtime, version);
194
- return await withInstallLock(runtimeLockPath(this.options.stateDir, runtime, version), {
195
- operationId,
196
- runtime,
197
- version
198
- }, async () => {
206
+ const lockPath = runtimeLockPath(this.options.stateDir, runtime, version);
207
+ const performInstall = async () => {
199
208
  const ready = await this.probeManaged(runtime, version);
200
209
  if (ready) return ready;
201
210
  this.progress({
@@ -225,22 +234,28 @@ var ManagedRuntimeManager = class extends EventEmitter {
225
234
  let archivePath;
226
235
  if (offline) archivePath = offline.archivePath;
227
236
  else {
237
+ let lastDownloadProgressAt = 0;
228
238
  const download = async () => await downloadVerifiedArchive({
229
239
  runtime,
230
240
  url: selectedDownload.url,
231
- targetPath: runtimeDownloadPath(this.options.stateDir, asset.archiveFile),
241
+ targetPath: runtimeDownloadPath(this.options.stateDir, `${version}-${asset.archiveFile}`),
232
242
  expectedSha256,
233
243
  timeoutMs: this.options.config.download.timeoutMs,
234
244
  proxy: this.options.config.download.proxy,
235
245
  signal,
236
- onProgress: (downloadedBytes, totalBytes) => this.progress({
237
- operationId,
238
- runtime,
239
- phase: "download",
240
- message: `Downloading ${runtime} ${version}`,
241
- downloadedBytes,
242
- totalBytes
243
- })
246
+ onProgress: (downloadedBytes, totalBytes) => {
247
+ const now = Date.now();
248
+ if (downloadedBytes !== totalBytes && now - lastDownloadProgressAt < 100) return;
249
+ lastDownloadProgressAt = now;
250
+ this.progress({
251
+ operationId,
252
+ runtime,
253
+ phase: "download",
254
+ message: `Downloading ${runtime} ${version}`,
255
+ downloadedBytes,
256
+ totalBytes
257
+ });
258
+ }
244
259
  });
245
260
  try {
246
261
  archivePath = await download();
@@ -345,16 +360,25 @@ var ManagedRuntimeManager = class extends EventEmitter {
345
360
  executables,
346
361
  installDir
347
362
  };
348
- });
363
+ };
364
+ return alreadyLocked ? await performInstall() : await withInstallLock(lockPath, {
365
+ operationId,
366
+ runtime,
367
+ version
368
+ }, performInstall, signal);
349
369
  }
350
- async installPython(version, signal) {
370
+ async installPython(version, signal, alreadyLocked = false) {
351
371
  const operationId = randomUUID();
352
372
  const installDir = runtimeVersionDir(this.options.stateDir, "python", version);
353
- return await withInstallLock(runtimeLockPath(this.options.stateDir, "python", version), {
354
- operationId,
355
- runtime: "python",
356
- version
357
- }, async () => {
373
+ const lockPath = runtimeLockPath(this.options.stateDir, "python", version);
374
+ const ready = await this.probeManaged("python", version);
375
+ if (ready) return ready;
376
+ const uv = this.options.config.download.bundleDir ? null : await this.resolve({
377
+ runtime: "uv",
378
+ allowProvision: true,
379
+ signal
380
+ });
381
+ const performInstall = async () => {
358
382
  const ready = await this.probeManaged("python", version);
359
383
  if (ready) return ready;
360
384
  if (this.options.config.download.bundleDir) return await this.installBundledPython({
@@ -363,11 +387,7 @@ var ManagedRuntimeManager = class extends EventEmitter {
363
387
  installDir,
364
388
  bundleDir: this.options.config.download.bundleDir
365
389
  });
366
- const uv = await this.resolve({
367
- runtime: "uv",
368
- allowProvision: true,
369
- signal
370
- });
390
+ if (!uv) throw new Error("uv runtime was not resolved");
371
391
  await mkdir(dirname(installDir), { recursive: true });
372
392
  const uvEnv = this.uvEnvironment(installDir);
373
393
  this.progress({
@@ -457,7 +477,12 @@ var ManagedRuntimeManager = class extends EventEmitter {
457
477
  executables,
458
478
  installDir
459
479
  };
460
- });
480
+ };
481
+ return alreadyLocked ? await performInstall() : await withInstallLock(lockPath, {
482
+ operationId,
483
+ runtime: "python",
484
+ version
485
+ }, performInstall, signal);
461
486
  }
462
487
  async installBundledPython(params) {
463
488
  const platform = detectRuntimePlatform();
@@ -596,7 +621,7 @@ var ManagedRuntimeManager = class extends EventEmitter {
596
621
  repairable: false
597
622
  };
598
623
  } catch {}
599
- if (await readRuntimeManifest(this.options.stateDir, runtime)) return {
624
+ if ((await readRuntimeManifests(this.options.stateDir, runtime)).filter((manifest) => versionSatisfies(manifest.version, requestedVersion)).length > 0) return {
600
625
  runtime,
601
626
  state: "corrupted",
602
627
  requestedVersion,
@@ -618,32 +643,42 @@ var ManagedRuntimeManager = class extends EventEmitter {
618
643
  "python"
619
644
  ].map((runtime) => this.status(runtime)));
620
645
  }
621
- async repair(runtime) {
622
- const version = this.defaultVersion(runtime);
646
+ async repair(runtime, requestedVersion = this.defaultVersion(runtime)) {
647
+ const config = runtimeConfig(this.options, runtime);
648
+ if (!this.options.config.enabled || !config.enabled) throw new RuntimeError(`${runtime} runtime is disabled`, "RUNTIME_DISABLED", runtime, "repair", false);
649
+ const version = resolveInstallVersion(requestedVersion, DEFAULT_RUNTIME_VERSIONS[runtime]);
650
+ if (!version) throw new RuntimeError(`Managed ${runtime} repair requires an exact version or a range containing catalog version ${DEFAULT_RUNTIME_VERSIONS[runtime]}`, "RUNTIME_VERSION_MISMATCH", runtime, "validate_version", false);
623
651
  const installDir = runtimeVersionDir(this.options.stateDir, runtime, version);
624
652
  const backupDir = `${installDir}.repair-backup-${randomUUID()}`;
625
- let hasBackup = false;
626
- try {
627
- await rename(installDir, backupDir);
628
- hasBackup = true;
629
- } catch {}
630
- try {
631
- const resolved = await this.install(runtime, version);
632
- if (hasBackup) await rm(backupDir, {
633
- recursive: true,
634
- force: true
635
- });
636
- return resolved;
637
- } catch (error) {
638
- if (hasBackup) {
639
- await rm(installDir, {
653
+ return await withInstallLock(runtimeLockPath(this.options.stateDir, runtime, version), {
654
+ operationId: randomUUID(),
655
+ runtime,
656
+ version,
657
+ action: "repair"
658
+ }, async () => {
659
+ let hasBackup = false;
660
+ try {
661
+ await rename(installDir, backupDir);
662
+ hasBackup = true;
663
+ } catch {}
664
+ try {
665
+ const resolved = runtime === "python" ? await this.installPython(version, void 0, true) : await this.installDistribution(runtime, version, void 0, true);
666
+ if (hasBackup) await rm(backupDir, {
640
667
  recursive: true,
641
668
  force: true
642
669
  });
643
- await rename(backupDir, installDir);
670
+ return resolved;
671
+ } catch (error) {
672
+ if (hasBackup) {
673
+ await rm(installDir, {
674
+ recursive: true,
675
+ force: true
676
+ });
677
+ await rename(backupDir, installDir);
678
+ }
679
+ throw error;
644
680
  }
645
- throw error;
646
- }
681
+ });
647
682
  }
648
683
  progress(event) {
649
684
  this.emit("progress", event);
@@ -1,3 +1,5 @@
1
1
  import type { InstalledRuntimeManifest, RuntimeKind } from './types.js';
2
2
  export declare function readRuntimeManifest(stateDir: string, runtime: RuntimeKind): Promise<InstalledRuntimeManifest | null>;
3
+ export declare function readRuntimeManifests(stateDir: string, runtime: RuntimeKind): Promise<InstalledRuntimeManifest[]>;
3
4
  export declare function writeRuntimeManifest(stateDir: string, manifest: InstalledRuntimeManifest): Promise<void>;
5
+ export declare function removeRuntimeManifest(stateDir: string, runtime: RuntimeKind, version: string): Promise<void>;
@@ -1,26 +1,47 @@
1
- import { runtimeManifestPath } from "./paths.js";
2
- import { dirname } from "node:path";
3
- import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
1
+ import { runtimeVersionManifestDir, runtimeVersionManifestPath } from "./paths.js";
2
+ import { dirname, join } from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { mkdir, readFile, readdir, rename, rm, writeFile } from "node:fs/promises";
4
5
  //#region src/runtime-tools/manifest-store.ts
5
6
  function isManifest(value, runtime) {
6
7
  if (!value || typeof value !== "object") return false;
7
8
  const item = value;
8
- return item.schemaVersion === 1 && item.runtime === runtime && typeof item.version === "string" && typeof item.installDir === "string" && !!item.executables && typeof item.executables.primary === "string";
9
+ return item.schemaVersion === 1 && item.runtime === runtime && typeof item.version === "string" && typeof item.verifiedAt === "string" && typeof item.installDir === "string" && !!item.executables && typeof item.executables.primary === "string";
9
10
  }
10
11
  async function readRuntimeManifest(stateDir, runtime) {
12
+ return (await readRuntimeManifests(stateDir, runtime))[0] ?? null;
13
+ }
14
+ async function readManifestFile(path, runtime) {
11
15
  try {
12
- const parsed = JSON.parse(await readFile(runtimeManifestPath(stateDir, runtime), "utf8"));
16
+ const parsed = JSON.parse(await readFile(path, "utf8"));
13
17
  return isManifest(parsed, runtime) ? parsed : null;
14
18
  } catch {
15
19
  return null;
16
20
  }
17
21
  }
22
+ async function readRuntimeManifests(stateDir, runtime) {
23
+ const manifests = [];
24
+ const versionRoot = runtimeVersionManifestDir(stateDir, runtime);
25
+ try {
26
+ const names = (await readdir(versionRoot)).filter((name) => name.endsWith(".json")).sort();
27
+ for (const name of names) {
28
+ const manifest = await readManifestFile(join(versionRoot, name), runtime);
29
+ if (manifest) manifests.push(manifest);
30
+ }
31
+ } catch {
32
+ return [];
33
+ }
34
+ return manifests.sort((a, b) => b.verifiedAt.localeCompare(a.verifiedAt));
35
+ }
18
36
  async function writeRuntimeManifest(stateDir, manifest) {
19
- const target = runtimeManifestPath(stateDir, manifest.runtime);
37
+ const target = runtimeVersionManifestPath(stateDir, manifest.runtime, manifest.version);
20
38
  await mkdir(dirname(target), { recursive: true });
21
- const temporary = `${target}.${process.pid}.tmp`;
39
+ const temporary = `${target}.${process.pid}.${randomUUID()}.tmp`;
22
40
  await writeFile(temporary, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 384 });
23
41
  await rename(temporary, target);
24
42
  }
43
+ async function removeRuntimeManifest(stateDir, runtime, version) {
44
+ await rm(runtimeVersionManifestPath(stateDir, runtime, version), { force: true });
45
+ }
25
46
  //#endregion
26
- export { readRuntimeManifest, writeRuntimeManifest };
47
+ export { readRuntimeManifest, readRuntimeManifests, removeRuntimeManifest, writeRuntimeManifest };
@@ -1,7 +1,8 @@
1
1
  import type { RuntimeKind } from './types.js';
2
2
  export declare function runtimeToolsRoot(stateDir: string): string;
3
3
  export declare function runtimeVersionDir(stateDir: string, runtime: RuntimeKind, version: string): string;
4
- export declare function runtimeManifestPath(stateDir: string, runtime: RuntimeKind): string;
4
+ export declare function runtimeVersionManifestDir(stateDir: string, runtime: RuntimeKind): string;
5
+ export declare function runtimeVersionManifestPath(stateDir: string, runtime: RuntimeKind, version: string): string;
5
6
  export declare function runtimeLockPath(stateDir: string, runtime: RuntimeKind, version: string): string;
6
7
  export declare function runtimeDownloadPath(stateDir: string, archiveFile: string): string;
7
8
  export declare function runtimeStagingDir(stateDir: string, runtime: RuntimeKind, version: string, operationId: string): string;
@@ -1,22 +1,33 @@
1
- import { join } from "node:path";
1
+ import { join, relative, resolve } from "node:path";
2
2
  //#region src/runtime-tools/paths.ts
3
3
  function runtimeToolsRoot(stateDir) {
4
4
  return join(stateDir, "tools");
5
5
  }
6
6
  function runtimeVersionDir(stateDir, runtime, version) {
7
- return join(runtimeToolsRoot(stateDir), runtime, "versions", version);
7
+ return containedPath(join(runtimeToolsRoot(stateDir), runtime, "versions"), version, "runtime version");
8
8
  }
9
- function runtimeManifestPath(stateDir, runtime) {
10
- return join(runtimeToolsRoot(stateDir), "manifests", `${runtime}.json`);
9
+ function runtimeVersionManifestDir(stateDir, runtime) {
10
+ return join(runtimeToolsRoot(stateDir), "manifests", runtime);
11
+ }
12
+ function runtimeVersionManifestPath(stateDir, runtime, version) {
13
+ return containedPath(runtimeVersionManifestDir(stateDir, runtime), `${version}.json`, "runtime version");
11
14
  }
12
15
  function runtimeLockPath(stateDir, runtime, version) {
13
- return join(runtimeToolsRoot(stateDir), "locks", `${runtime}-${version}.lock`);
16
+ return join(runtimeToolsRoot(stateDir), "locks", `${runtime}.lock`);
14
17
  }
15
18
  function runtimeDownloadPath(stateDir, archiveFile) {
16
- return join(runtimeToolsRoot(stateDir), "downloads", `${archiveFile}.partial`);
19
+ return containedPath(join(runtimeToolsRoot(stateDir), "downloads"), `${archiveFile}.partial`, "archive file");
17
20
  }
18
21
  function runtimeStagingDir(stateDir, runtime, version, operationId) {
19
- return join(runtimeToolsRoot(stateDir), "staging", `${runtime}-${version}-${operationId}`);
22
+ return containedPath(join(runtimeToolsRoot(stateDir), "staging"), `${runtime}-${version}-${operationId}`, "runtime staging directory");
23
+ }
24
+ function containedPath(root, child, label) {
25
+ if (child.includes("/") || child.includes("\\") || child.includes("\0")) throw new Error(`Invalid ${label}: ${child}`);
26
+ const absoluteRoot = resolve(root);
27
+ const target = resolve(absoluteRoot, child);
28
+ const rel = relative(absoluteRoot, target);
29
+ if (!rel || rel.startsWith("..") || rel.includes(`..${process.platform === "win32" ? "\\" : "/"}`)) throw new Error(`Invalid ${label}: ${child}`);
30
+ return target;
20
31
  }
21
32
  //#endregion
22
- export { runtimeDownloadPath, runtimeLockPath, runtimeManifestPath, runtimeStagingDir, runtimeToolsRoot, runtimeVersionDir };
33
+ export { runtimeDownloadPath, runtimeLockPath, runtimeStagingDir, runtimeToolsRoot, runtimeVersionDir, runtimeVersionManifestDir, runtimeVersionManifestPath };
@@ -1,6 +1,8 @@
1
1
  import type { RuntimeExecutables, RuntimeKind } from './types.js';
2
2
  export declare function parseRuntimeVersion(output: string): string | null;
3
3
  export declare function versionSatisfies(actual: string, requested: string): boolean;
4
+ export declare function normalizeRuntimeVersionRequest(requested: string): string | null;
5
+ export declare function resolveInstallVersion(requested: string, catalogDefault: string): string | null;
4
6
  export declare function probeSystemRuntime(runtime: RuntimeKind, requestedVersion: string): Promise<{
5
7
  version: string;
6
8
  executables: RuntimeExecutables;
@@ -14,6 +14,18 @@ function versionSatisfies(actual, requested) {
14
14
  }
15
15
  return semver.satisfies(normalized, requested) || normalized === requested;
16
16
  }
17
+ function normalizeRuntimeVersionRequest(requested) {
18
+ const value = requested.trim();
19
+ if (!value || value.length > 128 || value.includes("/") || value.includes("\\") || value.includes("\0") || semver.validRange(value) === null) return null;
20
+ return value;
21
+ }
22
+ function resolveInstallVersion(requested, catalogDefault) {
23
+ const normalized = normalizeRuntimeVersionRequest(requested);
24
+ if (!normalized) return null;
25
+ const exact = semver.valid(normalized);
26
+ if (exact) return exact;
27
+ return versionSatisfies(catalogDefault, normalized) ? catalogDefault : null;
28
+ }
17
29
  function commandNames(runtime) {
18
30
  if (runtime === "node") return process.platform === "win32" ? ["node.exe", "node"] : ["node"];
19
31
  if (runtime === "uv") return process.platform === "win32" ? ["uv.exe", "uv"] : ["uv"];
@@ -68,4 +80,4 @@ async function probeSystemRuntime(runtime, requestedVersion) {
68
80
  return null;
69
81
  }
70
82
  //#endregion
71
- export { parseRuntimeVersion, probeSystemRuntime, versionSatisfies };
83
+ export { normalizeRuntimeVersionRequest, parseRuntimeVersion, probeSystemRuntime, resolveInstallVersion, versionSatisfies };
@@ -1,6 +1,9 @@
1
- import { runtimeToolsRoot } from "./paths.js";
2
- import { readRuntimeManifest } from "./manifest-store.js";
3
- import { join, resolve } from "node:path";
1
+ import { DEFAULT_RUNTIME_VERSIONS } from "./catalog.js";
2
+ import { withInstallLock } from "./install-lock.js";
3
+ import { runtimeLockPath, runtimeToolsRoot } from "./paths.js";
4
+ import { readRuntimeManifests, removeRuntimeManifest } from "./manifest-store.js";
5
+ import { versionSatisfies } from "./probe.js";
6
+ import { basename, join, resolve } from "node:path";
4
7
  import { lstat, readdir, rm, stat } from "node:fs/promises";
5
8
  //#region src/runtime-tools/prune.ts
6
9
  const RUNTIMES = [
@@ -9,6 +12,11 @@ const RUNTIMES = [
9
12
  "python"
10
13
  ];
11
14
  const STALE_TEMP_MS = 1440 * 60 * 1e3;
15
+ function configuredVersion(config, runtime) {
16
+ if (runtime === "node") return config.node.version ?? DEFAULT_RUNTIME_VERSIONS.node;
17
+ if (runtime === "python") return config.python.version ?? DEFAULT_RUNTIME_VERSIONS.python;
18
+ return config.uv.version ?? DEFAULT_RUNTIME_VERSIONS.uv;
19
+ }
12
20
  async function pathSize(path) {
13
21
  const details = await lstat(path);
14
22
  if (details.isSymbolicLink()) return details.size;
@@ -36,9 +44,14 @@ async function pruneRuntimeTools(params) {
36
44
  const removed = [];
37
45
  let reclaimedBytes = 0;
38
46
  const root = runtimeToolsRoot(params.stateDir);
39
- for (const runtime of RUNTIMES) {
47
+ for (const runtime of RUNTIMES) await withInstallLock(runtimeLockPath(params.stateDir, runtime, "prune"), {
48
+ pid: process.pid,
49
+ runtime,
50
+ action: "prune"
51
+ }, async () => {
40
52
  const entries = (await listEntries(join(root, runtime, "versions"))).sort((a, b) => b.mtimeMs - a.mtimeMs);
41
- const manifest = await readRuntimeManifest(params.stateDir, runtime);
53
+ const manifests = await readRuntimeManifests(params.stateDir, runtime);
54
+ const manifest = manifests.find((item) => versionSatisfies(item.version, configuredVersion(params.config, runtime))) ?? manifests[0];
42
55
  const entryPaths = new Set(entries.map((entry) => resolve(entry.path)));
43
56
  const activePath = manifest && entryPaths.has(resolve(manifest.installDir)) ? resolve(manifest.installDir) : null;
44
57
  const keep = /* @__PURE__ */ new Set();
@@ -53,10 +66,11 @@ async function pruneRuntimeTools(params) {
53
66
  recursive: true,
54
67
  force: true
55
68
  });
69
+ await removeRuntimeManifest(params.stateDir, runtime, basename(entry.path));
56
70
  removed.push(entry.path);
57
71
  reclaimedBytes += entry.size;
58
72
  }
59
- }
73
+ });
60
74
  const now = params.now ?? Date.now();
61
75
  for (const entry of await listEntries(join(root, "staging"))) {
62
76
  if (now - entry.mtimeMs < STALE_TEMP_MS) continue;
@@ -69,7 +83,7 @@ async function pruneRuntimeTools(params) {
69
83
  }
70
84
  const maxCacheBytes = params.config.retention.maxCacheBytes;
71
85
  if (maxCacheBytes !== void 0) {
72
- const cacheEntries = (await listEntries(join(root, "downloads"))).sort((a, b) => b.mtimeMs - a.mtimeMs);
86
+ const cacheEntries = (await listEntries(join(root, "downloads"))).filter((entry) => !entry.path.endsWith(".partial")).sort((a, b) => b.mtimeMs - a.mtimeMs);
73
87
  let retained = 0;
74
88
  for (const entry of cacheEntries) {
75
89
  if (retained + entry.size <= maxCacheBytes) {
@@ -267,6 +267,18 @@ function customRowToClientHistory(row) {
267
267
  if (r.role !== "custom" && r.type !== "custom_message") return null;
268
268
  const customType = optionalString(r.customType)?.trim();
269
269
  if (!customType) return null;
270
+ if (customType === "voice_omni_transcript") {
271
+ const details = r.details;
272
+ if (details?.role !== "user" && details?.role !== "assistant") return null;
273
+ const content = typeof r.content === "string" ? r.content : "";
274
+ return {
275
+ role: details.role,
276
+ kind: "message",
277
+ content,
278
+ rawContent: content,
279
+ timestamp: parseTimestampValue(typeof r.timestamp === "string" || typeof r.timestamp === "number" ? r.timestamp : void 0)
280
+ };
281
+ }
270
282
  const content = Array.isArray(r.content) || typeof r.content === "string" ? flattenMessageContent(r.content) : "";
271
283
  const timestamp = parseTimestampValue(typeof r.timestamp === "string" || typeof r.timestamp === "number" ? r.timestamp : void 0);
272
284
  return {
@@ -149,6 +149,7 @@ export declare class SessionIndex extends EventEmitter {
149
149
  data?: unknown;
150
150
  }): Promise<void>;
151
151
  appendTranscriptCustomMessageEntry(key: string, entry: {
152
+ expectedSessionId?: string;
152
153
  customType: string;
153
154
  content?: string | unknown[];
154
155
  display?: boolean;
@@ -1,3 +1,4 @@
1
+ import { voiceTranscriptMessage } from "./voice-transcript.js";
1
2
  import { isCompactionAudit, isCompactionHandover } from "./compaction-types.js";
2
3
  //#region src/session/session-context-for-llm.ts
3
4
  function isTranscriptContextEntry(x) {
@@ -245,6 +246,12 @@ function buildSessionContextForLlm(rows) {
245
246
  continue;
246
247
  }
247
248
  if (isTranscriptCustomMessageEntry(r)) {
249
+ if (r.customType === "voice_call") continue;
250
+ if (r.customType === "voice_omni_transcript") {
251
+ const message = voiceTranscriptMessage(r);
252
+ if (message) out.push(message);
253
+ continue;
254
+ }
248
255
  out.push(customMessageRowToLlmMessage(r));
249
256
  continue;
250
257
  }
@@ -257,6 +264,7 @@ function buildSessionDisplayMessages(rows) {
257
264
  const out = [];
258
265
  for (const r of rows) {
259
266
  if (isTranscriptCustomMessageEntry(r)) {
267
+ if (r.customType === "voice_call") continue;
260
268
  if (r.display === false) continue;
261
269
  out.push(customMessageRowToLlmMessage(r));
262
270
  continue;
@@ -124,6 +124,7 @@ export declare class SessionStore {
124
124
  data?: unknown;
125
125
  }): Promise<void>;
126
126
  appendTranscriptCustomMessageEntry(key: string, entry: {
127
+ expectedSessionId?: string;
127
128
  customType: string;
128
129
  content?: string | unknown[];
129
130
  display?: boolean;
@@ -386,6 +386,7 @@ var SessionStore = class {
386
386
  async appendTranscriptCustomMessageEntry(key, entry) {
387
387
  return this.runStoreMutation(async () => {
388
388
  requireXopcDatabase();
389
+ if (entry.expectedSessionId && getSessionMetadata(key)?.sessionId !== entry.expectedSessionId) throw new Error("Voice conversation session changed");
389
390
  ensureSessionRecord(key, this.resolveWorkspaceCwd(key));
390
391
  appendTranscriptEntry(key, {
391
392
  role: "custom",
@@ -1,3 +1,4 @@
1
+ import { voiceTranscriptMessage } from "./voice-transcript.js";
1
2
  import { isTranscriptContextEntry, isTranscriptCustomMessageEntry, isTranscriptCustomStateEntry } from "./session-context-for-llm.js";
2
3
  import { randomUUID } from "node:crypto";
3
4
  import { CURRENT_SESSION_VERSION } from "@earendil-works/pi-coding-agent";
@@ -100,7 +101,10 @@ function storedRowsToFileEntries(params) {
100
101
  continue;
101
102
  }
102
103
  if (isTranscriptCustomMessageEntry(row)) {
103
- const entry = customMessageRowToEntry(row, parentId, byId);
104
+ if (row.customType === "voice_call") continue;
105
+ const voiceMessage = row.customType === "voice_omni_transcript" ? voiceTranscriptMessage(row) : null;
106
+ if (row.customType === "voice_omni_transcript" && !voiceMessage) continue;
107
+ const entry = voiceMessage ? agentMessageToEntry(voiceMessage, parentId, byId) : customMessageRowToEntry(row, parentId, byId);
104
108
  byId.add(entry.id);
105
109
  entries.push(entry);
106
110
  parentId = entry.id;
@@ -0,0 +1,9 @@
1
+ import type { AgentMessage } from '@earendil-works/pi-agent-core';
2
+ export declare const VOICE_CALL_TYPE = "voice_call";
3
+ export declare const VOICE_TRANSCRIPT_TYPE = "voice_omni_transcript";
4
+ /** One projection for both direct LLM loads and the embedded SessionManager. */
5
+ export declare function voiceTranscriptMessage(row: {
6
+ content?: unknown;
7
+ details?: unknown;
8
+ timestamp?: string | number;
9
+ }): AgentMessage | null;
@@ -0,0 +1,45 @@
1
+ //#region src/session/voice-transcript.ts
2
+ const VOICE_CALL_TYPE = "voice_call";
3
+ const VOICE_TRANSCRIPT_TYPE = "voice_omni_transcript";
4
+ /** One projection for both direct LLM loads and the embedded SessionManager. */
5
+ function voiceTranscriptMessage(row) {
6
+ const details = row.details && typeof row.details === "object" ? row.details : {};
7
+ if (details.role !== "user" && details.role !== "assistant" || typeof row.content !== "string" || !row.content.trim()) return null;
8
+ const text = details.role === "assistant" && details.interrupted === true ? "[Voice reply was interrupted. Its generated text is omitted because the heard portion is unknown.]" : row.content;
9
+ const parsed = typeof row.timestamp === "number" ? row.timestamp : Date.parse(row.timestamp ?? "");
10
+ const timestamp = Number.isFinite(parsed) ? parsed : 0;
11
+ const content = [{
12
+ type: "text",
13
+ text
14
+ }];
15
+ if (details.role === "user") return {
16
+ role: "user",
17
+ content,
18
+ timestamp
19
+ };
20
+ return {
21
+ role: "assistant",
22
+ content,
23
+ timestamp,
24
+ api: "openai-completions",
25
+ provider: "xopc-voice",
26
+ model: "voice-transcript",
27
+ stopReason: "stop",
28
+ usage: {
29
+ input: 0,
30
+ output: 0,
31
+ cacheRead: 0,
32
+ cacheWrite: 0,
33
+ totalTokens: 0,
34
+ cost: {
35
+ input: 0,
36
+ output: 0,
37
+ cacheRead: 0,
38
+ cacheWrite: 0,
39
+ total: 0
40
+ }
41
+ }
42
+ };
43
+ }
44
+ //#endregion
45
+ export { VOICE_CALL_TYPE, VOICE_TRANSCRIPT_TYPE, voiceTranscriptMessage };