@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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-CLnbVm9G.js → activity-store-CAah-_8h.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DuBewmbW.js → agent-avatar-dicebear-DDH4HgP7.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BDCfJZhh.js +1 -0
- package/dist/gateway/static/root/assets/agents-B0ZWgf-U.js +1 -0
- package/dist/gateway/static/root/assets/{api-DjBZe303.js → api-B2tKxbcz.js} +1 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-Blfwszzn.js +1 -0
- package/dist/gateway/static/root/assets/{appearance-settings-B-iul0RG.js → appearance-settings-C3V7Na75.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BiEks0-F.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-BOx0EJZs.js → archive-plugin-BmSx7wzY.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Cfk1lwBo.js → attachment-load-BS-S4LJ9.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BTSGvaeS.js → automations-page-C7Y3L30D.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-A3zPkPuo.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-ChZyZK45.js → binary-plugins-BM9B5kcm.js} +1 -1
- package/dist/gateway/static/root/assets/block-editor-BbnpkYP9.js +185 -0
- package/dist/gateway/static/root/assets/browser-settings-page-Dk4FQ7fY.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-jvfcgFG-.js → browser-workflow-inputs-CRnkgZHI.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DrHW7XNi.js → browser-workflows-page-B9qGL-it.js} +2 -2
- package/dist/gateway/static/root/assets/{button-CSEbl4zT.js → button-CtTvuElV.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-settings-panel--tR_El9e.js +7 -0
- package/dist/gateway/static/root/assets/channels-settings-D347vl_J.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-CC9MFway.js → channels-status-swr-DuY4MGxe.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-DeeZrVbV.js → chat-terminal-dock-DABPvwBT.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-B-tvJkRJ.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-CiqQOeQ3.js → cron-expression-D3bsKbNd.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-CGAMGPfU.js → date-picker-BsGM6Yty.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-CxWeUTsc.js → dependency-picker-Dj3g6YXZ.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-C3QmYO75.js → desktop-pet-C1QT0Sur.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-CAADkWYy.js → desktop-pet-settings-r6kAOnfY.js} +1 -1
- package/dist/gateway/static/root/assets/dist-CpzYSoz7.js +1 -0
- package/dist/gateway/static/root/assets/{dist-DaxPZj9e.js → dist-DBS3OB8K.js} +1 -1
- package/dist/gateway/static/root/assets/dist-DLmwHyAh.js +1 -0
- package/dist/gateway/static/root/assets/es2015-BvLh9GaE.js +41 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-FQXjDJ8P.js → extension-debug-page-DOkf7nh9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BJE1D5Ji.js → extension-page-Cq2IA4Ho.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-5Ik2tNry.js → extension-settings-page-DQn4qjDZ.js} +1 -1
- package/dist/gateway/static/root/assets/{files-DQjhZjr2.js → files-D6vf3S30.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-cTj71t2a.js → gateway-config-api-DM3poL22.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-Bxe_R-JH.js → gateway-config-swr-BC3pgb_P.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-KXBUjNcx.js → gateway-settings-DPgH1hnh.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-DJG-I0wW.js → gateway-startup-retry-uMcSfLru.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-C8cVzIcs.js → heartbeat-settings-Bk80-E3b.js} +1 -1
- package/dist/gateway/static/root/assets/home-page-DKo5JiMR.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-Dc_ojQuj.js → image-generation-api-D1qlQA-A.js} +1 -1
- package/dist/gateway/static/root/assets/index-B0WJL9N1.js +71 -0
- package/dist/gateway/static/root/assets/index-Dbh5SXyV.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-pOKl7blR.js → keyboard-shortcuts-settings-BEwvd8ZU.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page--eJ5rmNj.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-Bi6wwKgm.js → local-apps-page-CgkY9E-r.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-C5wr3_pc.js → locale-store-CMZljTJx.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-Z49Td0J9.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-DGlVizWi.js → management-settings-Dv8NSJKt.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-CXP5zBx_.js → markdown-split-Cm0RBB-t.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-view-D6LxlDxr.js → markdown-view-PPCLt7fu.js} +3 -3
- package/dist/gateway/static/root/assets/{media-plugins-BsENGLr2.js → media-plugins-Bcr5sU1f.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CTSgFlE4.js +3 -0
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-kKDiXofY.js +1 -0
- package/dist/gateway/static/root/assets/{models-hub-cache-Y7GUjxHx.js → models-hub-cache-ZrbGRiGY.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-D2EqpDyo.js → notes-page-CgsaRaGi.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-C1DEE09k.js +4 -0
- package/dist/gateway/static/root/assets/{oauth-api-C5NVcsKE.js → oauth-api-4VeMbkTJ.js} +1 -1
- package/dist/gateway/static/root/assets/popover-select-C-Hj-nXR.js +1 -0
- package/dist/gateway/static/root/assets/{product-delivery-dUJgmBQZ.js → product-delivery-CV4pDOtG.js} +1 -1
- package/dist/gateway/static/root/assets/product-open-page-BU0HiZtv.js +1 -0
- package/dist/gateway/static/root/assets/project-detail-page-isRapnp5.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-zvsjg0mi.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-FXdFaoWM.js → registry-api-CWOtPFrE.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-C9TGZ9Hc.js +1 -0
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-2zm9edMA.js +5 -0
- package/dist/gateway/static/root/assets/{schema-form-BUzdHWx6.js → schema-form-54A5gzkN.js} +1 -1
- package/dist/gateway/static/root/assets/{schemas-zIBW3wiV.js → schemas-BHS7bo06.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-BP8RyiUn.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4EMxWAZ.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-C0OBLqpu.js → settings-page-DzDhoyxv.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-NpLQkFCh.js → setup-status-panel-uDicHU1w.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BtbPYaYC.js → share-preview-page-lOmLCWFS.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-T4Yvouvv.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DVb7nrXz.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-CYk8pN97.js → skills-page-CnyNH3To.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page.utils-CgDtf2qs.js +1 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DmCRSvtd.js → system-settings-panel-C8yWfwtR.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-Tzfjlbf3.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-DUko1ZnE.js → theme-store-uxUwr10D.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-Bvg679no.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-W_P8Kiv4.js → use-autosave-D88VGoyG.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-RijPtyfO.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-BZD0j1jc.js → voice-api-key-field-CBHLsMcc.js} +1 -1
- package/dist/gateway/static/root/assets/voice-config-api-MqyI6cgq.js +1 -0
- package/dist/gateway/static/root/assets/work-discovery-overlay-GGe2TQ98.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-C0layUE9.js +3 -0
- package/dist/gateway/static/root/assets/workflows-page-DQXIzBAc.js +5 -0
- package/dist/gateway/static/root/index.html +21 -22
- package/dist/package.js +1 -1
- package/dist/packages/realtime-protocol/src/voice-audio.js +20 -0
- package/dist/packages/realtime-protocol/src/voice.js +208 -0
- package/dist/src/agent/agent-manager.js +1 -0
- package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
- package/dist/src/agent/embedded/run-for-session.js +2 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +2 -1
- package/dist/src/agent/prompt/voice-presentation.d.ts +2 -0
- package/dist/src/agent/prompt/voice-presentation.js +12 -0
- package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -0
- package/dist/src/agent/service/direct-turn-helpers.js +1 -0
- package/dist/src/agent/service/process-direct-streaming.d.ts +1 -0
- package/dist/src/agent/service/process-direct-streaming.js +2 -1
- package/dist/src/agent/session/session-config-service.js +4 -2
- package/dist/src/agent/skills/installer.d.ts +1 -0
- package/dist/src/agent/skills/installer.js +9 -6
- package/dist/src/agent/tools/factory.d.ts +2 -0
- package/dist/src/agent/tools/factory.js +5 -1
- package/dist/src/automations/draft/automation-draft-service.js +1 -1
- package/dist/src/config/models-json.d.ts +8 -8
- package/dist/src/config/schema.d.ts +60 -0
- package/dist/src/config/schema.js +36 -4
- package/dist/src/extensions/install.js +1 -1
- package/dist/src/files/file-service.d.ts +1 -0
- package/dist/src/files/file-service.js +4 -0
- package/dist/src/gateway/chat-stream/thinking-delta-coalescer.js +8 -3
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -11
- package/dist/src/gateway/hono/lib/config-payload.js +2 -2
- package/dist/src/gateway/hono/lib/safe-voice-config.d.ts +14 -0
- package/dist/src/gateway/hono/lib/safe-voice-config.js +29 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +2 -2
- package/dist/src/gateway/hono/routes/files.js +7 -0
- package/dist/src/gateway/hono/routes/lazy-fallback.js +18 -4
- package/dist/src/gateway/hono/routes/runtime-tools.js +7 -1
- package/dist/src/gateway/hono/routes/session-input-handler.js +14 -0
- package/dist/src/gateway/hono/routes/sessions.js +4 -1
- package/dist/src/gateway/hono/routes/voice.js +140 -3
- package/dist/src/gateway/server.js +1 -0
- package/dist/src/gateway/service/agent-runner.d.ts +1 -0
- package/dist/src/gateway/service/agent-runner.js +1 -6
- package/dist/src/gateway/service/run-gateway-agent.d.ts +1 -0
- package/dist/src/gateway/service/run-gateway-agent.js +19 -1
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +73 -0
- package/dist/src/media-understanding/types.d.ts +61 -0
- package/dist/src/runtime-tools/archive.js +17 -3
- package/dist/src/runtime-tools/command.d.ts +1 -0
- package/dist/src/runtime-tools/command.js +29 -8
- package/dist/src/runtime-tools/environment.d.ts +1 -0
- package/dist/src/runtime-tools/environment.js +11 -16
- package/dist/src/runtime-tools/install-lock.d.ts +1 -1
- package/dist/src/runtime-tools/install-lock.js +34 -21
- package/dist/src/runtime-tools/manager.d.ts +1 -1
- package/dist/src/runtime-tools/manager.js +99 -64
- package/dist/src/runtime-tools/manifest-store.d.ts +2 -0
- package/dist/src/runtime-tools/manifest-store.js +29 -8
- package/dist/src/runtime-tools/paths.d.ts +2 -1
- package/dist/src/runtime-tools/paths.js +19 -8
- package/dist/src/runtime-tools/probe.d.ts +2 -0
- package/dist/src/runtime-tools/probe.js +13 -1
- package/dist/src/runtime-tools/prune.js +21 -7
- package/dist/src/session/client-history.js +12 -0
- package/dist/src/session/manager.d.ts +1 -0
- package/dist/src/session/session-context-for-llm.js +8 -0
- package/dist/src/session/store.d.ts +1 -0
- package/dist/src/session/store.js +1 -0
- package/dist/src/session/stored-rows-to-file-entries.js +5 -1
- package/dist/src/session/voice-transcript.d.ts +9 -0
- package/dist/src/session/voice-transcript.js +45 -0
- package/dist/src/storage/sqlite/config-repository.js +9 -0
- package/dist/src/storage/sqlite/remote-context-repository.d.ts +3 -0
- package/dist/src/storage/sqlite/remote-context-repository.js +40 -0
- package/dist/src/storage/sqlite/session-repository.js +13 -0
- package/dist/src/storage/sqlite/user-context-repository.d.ts +3 -1
- package/dist/src/storage/sqlite/user-context-repository.js +50 -4
- package/dist/src/tui/tui.js +2 -1
- package/dist/src/user-context/automatic-context.d.ts +17 -0
- package/dist/src/user-context/automatic-context.js +85 -0
- package/dist/src/user-context/changes.d.ts +7 -0
- package/dist/src/user-context/changes.js +28 -0
- package/dist/src/user-context/planner.js +1 -24
- package/dist/src/user-context/retriever.js +10 -11
- package/dist/src/user-context/selection-policy.d.ts +20 -0
- package/dist/src/user-context/selection-policy.js +33 -0
- package/dist/src/user-context/sources/index.js +2 -2
- package/dist/src/user-context/sources/repository.d.ts +2 -1
- package/dist/src/user-context/sources/repository.js +26 -5
- package/dist/src/voice/dashscope/streaming-stt-session.d.ts +2 -0
- package/dist/src/voice/dashscope/streaming-stt-session.js +249 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.d.ts +12 -0
- package/dist/src/voice/dashscope/streaming-tts-stream.js +153 -0
- package/dist/src/voice/realtime/agentEngine.d.ts +10 -0
- package/dist/src/voice/realtime/agentEngine.js +403 -0
- package/dist/src/voice/realtime/audio-playback-window.d.ts +9 -0
- package/dist/src/voice/realtime/audio-playback-window.js +49 -0
- package/dist/src/voice/realtime/conversation-context.d.ts +11 -0
- package/dist/src/voice/realtime/conversation-context.js +76 -0
- package/dist/src/voice/realtime/engine.d.ts +13 -0
- package/dist/src/voice/realtime/engine.js +1 -0
- package/dist/src/voice/realtime/memory-context.d.ts +17 -0
- package/dist/src/voice/realtime/memory-context.js +100 -0
- package/dist/src/voice/realtime/omniEngine.d.ts +18 -0
- package/dist/src/voice/realtime/omniEngine.js +443 -0
- package/dist/src/voice/realtime/omniRoute.d.ts +10 -0
- package/dist/src/voice/realtime/omniRoute.js +31 -0
- package/dist/src/voice/realtime/runtime.d.ts +99 -0
- package/dist/src/voice/realtime/runtime.js +622 -0
- package/dist/src/voice/realtime/speakable-segmenter.d.ts +10 -0
- package/dist/src/voice/realtime/speakable-segmenter.js +87 -0
- package/dist/src/voice/stt/list-providers.js +2 -1
- package/dist/src/voice/stt/providers/alibaba-transcription.js +13 -1
- package/dist/src/voice/stt/providers/xopc-cloud-transcription.js +23 -0
- package/dist/src/voice/tts/factory.js +1 -0
- package/dist/src/voice/tts/openai-compatible-speech.js +3 -1
- package/dist/src/voice/tts/providers/alibaba-speech.d.ts +1 -5
- package/dist/src/voice/tts/providers/alibaba-speech.js +25 -8
- package/dist/src/voice/tts/providers/edge-speech.js +21 -22
- package/dist/src/voice/tts/providers/minimax-speech.js +6 -3
- package/dist/src/voice/tts/providers/xopc-cloud-speech.js +26 -1
- package/dist/src/voice/tts/speak-core.d.ts +6 -2
- package/dist/src/voice/tts/speak-core.js +46 -34
- package/dist/src/voice/tts/speech-provider-types.d.ts +1 -0
- package/package.json +6 -6
- package/dist/gateway/static/root/assets/Combination-14nmIgxH.js +0 -41
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-DbdgX6AA.js +0 -1
- package/dist/gateway/static/root/assets/agents-BX3uRVm4.js +0 -1
- package/dist/gateway/static/root/assets/app-chrome-BeB4KgOf.js +0 -1
- package/dist/gateway/static/root/assets/app-management-settings-panel-D8evZyFQ.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-CoZd_cZu.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-C8RRKT-a.js +0 -6
- package/dist/gateway/static/root/assets/block-editor-DCH9b2Ht.js +0 -184
- package/dist/gateway/static/root/assets/browser-settings-page-D1GPwIfx.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-CrXB1Q-l.js +0 -7
- package/dist/gateway/static/root/assets/channels-settings-DWMSYaNZ.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DXTl1fNB.js +0 -2
- package/dist/gateway/static/root/assets/dist-BPoKqzeH.js +0 -1
- package/dist/gateway/static/root/assets/dist-DqPZM2MH.js +0 -1
- package/dist/gateway/static/root/assets/home-page-NdWtBda5.js +0 -1
- package/dist/gateway/static/root/assets/index-7i2P3312.js +0 -70
- package/dist/gateway/static/root/assets/index-DTo3IcbW.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-C_j_od5f.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-D6PDZEVP.js +0 -2
- package/dist/gateway/static/root/assets/messages-_tYhRAHD.js +0 -3
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-DcEz7qcX.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-Bu0a83Oj.js +0 -4
- package/dist/gateway/static/root/assets/popover-select-DrILF6mR.js +0 -1
- package/dist/gateway/static/root/assets/product-open-page-DMhf1rdz.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-DDHi0Y4Q.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CVMFKpmu.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-B74aErBY.js +0 -1
- package/dist/gateway/static/root/assets/runtime-tools-settings-panel-Bv-akndY.js +0 -5
- package/dist/gateway/static/root/assets/sessions-page-D2wmGNZE.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CYCCUMEt.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-rf8f1OGq.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BkvclZ_o.js +0 -1
- package/dist/gateway/static/root/assets/skills-page.utils-DGjnz-NG.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-6a2RdDl2.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-Chfiba_x.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-SeOHP6XO.js +0 -1
- package/dist/gateway/static/root/assets/voice-config-api-BO6A8V3Z.js +0 -1
- package/dist/gateway/static/root/assets/work-discovery-overlay-BfwEoOGL.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-X7Z5_lRX.js +0 -3
- 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 {
|
|
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
|
|
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
|
|
150
|
-
|
|
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 (
|
|
155
|
-
await
|
|
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))
|
|
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)
|
|
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
|
-
|
|
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
|
-
|
|
182
|
-
|
|
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
|
-
|
|
195
|
-
|
|
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) =>
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
2
|
-
import { dirname } from "node:path";
|
|
3
|
-
import {
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
10
|
-
return join(runtimeToolsRoot(stateDir), "manifests",
|
|
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}
|
|
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,
|
|
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 {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
|
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;
|
|
@@ -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
|
-
|
|
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 };
|