@hienlh/ppm 0.18.13 → 0.18.15
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/.rdtest2-cf.out +0 -0
- package/CHANGELOG.md +23 -0
- package/CLAUDE.md +3 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +18 -0
- package/assets/skills/ppm/references/http-api.md +8 -1
- package/dist/web/assets/{adaptive-context-menu-CbgPYQmj.js → adaptive-context-menu-ChBZWLLq.js} +1 -1
- package/dist/web/assets/{ai-resource-editor-unM2HNmg.js → ai-resource-editor-C8aAY8Po.js} +1 -1
- package/dist/web/assets/{ai-settings-section-CdktdrwF.js → ai-settings-section-ERu1WiZc.js} +1 -1
- package/dist/web/assets/{angular-html-DcpbdcNG.js → angular-html-CXgHIQ2U.js} +1 -1
- package/dist/web/assets/{angular-ts-Bv_WIk34.js → angular-ts-C8renMV9.js} +1 -1
- package/dist/web/assets/api-client-WpZ2FDHg.js +1 -0
- package/dist/web/assets/api-settings-BgSEE6et.js +1 -0
- package/dist/web/assets/{api-settings-BdCtex9i.js → api-settings-R59c66DE.js} +1 -1
- package/dist/web/assets/{api-themes-pRRoLvgD.js → api-themes-DKxrwJda.js} +1 -1
- package/dist/web/assets/{apl-D5_lLszu.js → apl-DkGH8laI.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-CCalSKAt.js +1 -0
- package/dist/web/assets/{astro-CBHwddYL.js → astro-tHUd8Zlg.js} +1 -1
- package/dist/web/assets/{audio-preview-BD1iDovf.js → audio-preview-B_C6Dpvz.js} +1 -1
- package/dist/web/assets/{blade-DGe1d2Pq.js → blade-BbKpjIYK.js} +1 -1
- package/dist/web/assets/{bsl-2lyAzRJA.js → bsl-DA0UYto0.js} +1 -1
- package/dist/web/assets/{button-2WCAS8dI.js → button-DBSpDPS0.js} +1 -1
- package/dist/web/assets/{cairo-DjzZeJrq.js → cairo-79ayucbB.js} +1 -1
- package/dist/web/assets/chat-tab-BraiJsYG.js +15 -0
- package/dist/web/assets/{cobol-cC3XIuAJ.js → cobol-DSS2EOYo.js} +1 -1
- package/dist/web/assets/code-editor-lhmLNhXu.js +10 -0
- package/dist/web/assets/{coffee-4eGboVoU.js → coffee-DvSxq2iD.js} +1 -1
- package/dist/web/assets/{conflict-editor-DdJag4QK.js → conflict-editor-C4VCv51R.js} +1 -1
- package/dist/web/assets/{context-menu-BO1c9jKy.js → context-menu-BpwUny-o.js} +1 -1
- package/dist/web/assets/{cpp-DF9_G-OU.js → cpp-BhWZ-FSn.js} +1 -1
- package/dist/web/assets/{crystal-OavZlzcm.js → crystal-yP2OeF-f.js} +1 -1
- package/dist/web/assets/{csv-preview-DnXwouF3.js → csv-preview-D46W_icb.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-B9Gpjm3l.js → data-grid-overlay-editor-DeGkPYtA.js} +1 -1
- package/dist/web/assets/{database-viewer-Dk8oGyZx.js → database-viewer-DFI4YtrH.js} +1 -1
- package/dist/web/assets/{dialog-B-l2ZxVm.js → dialog-RIpeb87v.js} +1 -1
- package/dist/web/assets/diff-viewer-eaNOLcBL.js +4 -0
- package/dist/web/assets/{docx-preview-DAdHPlhZ.js → docx-preview-Cbj-pOK3.js} +1 -1
- package/dist/web/assets/{edge-TzYh8OlN.js → edge-D3K9cd-p.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-DlwP3UIU.js → edit-diff-preview-DDqy3KLA.js} +1 -1
- package/dist/web/assets/{elixir-Cy3RhKKH.js → elixir-D4PBmsLp.js} +1 -1
- package/dist/web/assets/{elm-BTBZdweK.js → elm-DSpXjuaH.js} +1 -1
- package/dist/web/assets/{erb-dv1mI0y4.js → erb-CaYZMTJW.js} +1 -1
- package/dist/web/assets/{erlang-DjeiDrkl.js → erlang-DX5BFqJj.js} +1 -1
- package/dist/web/assets/{esm-FRwvcesu.js → esm-Cv7HsFnk.js} +1 -1
- package/dist/web/assets/explorer-body-BxbSttfl.js +2 -0
- package/dist/web/assets/explorer-window-content-DUqQCC7A.js +1 -0
- package/dist/web/assets/{extension-store-DUaZINyC.js → extension-store-B1EClUAr.js} +1 -1
- package/dist/web/assets/{extension-webview-W0qRfaAU.js → extension-webview-BaGvDk8v.js} +1 -1
- package/dist/web/assets/{file-store-yReVbR8q.js → file-store-m9crh6uq.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-BCH9DAIJ.js → fortran-fixed-form-B0bAufUe.js} +1 -1
- package/dist/web/assets/{fsharp-C93NYKYD.js → fsharp-C2AL2b1M.js} +1 -1
- package/dist/web/assets/{gdresource-BcIEE2eX.js → gdresource-DRQsDMNI.js} +1 -1
- package/dist/web/assets/{git-commit-BVjlXEy8.js → git-commit-GtBdnrzk.js} +1 -1
- package/dist/web/assets/{git-log-panel-2_4HuP47.js → git-log-panel-hwV1flSO.js} +1 -1
- package/dist/web/assets/{git-rebase-Bj_21B1V.js → git-rebase-h_0CGA6F.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-DAUrJCqi.js +1 -0
- package/dist/web/assets/glide-data-grid-YsN-xm6x.js +138 -0
- package/dist/web/assets/{glimmer-js-C20yj4Zv.js → glimmer-js-Bxwu93bS.js} +1 -1
- package/dist/web/assets/{glimmer-ts-ipbYC7kh.js → glimmer-ts-CIUYdR4E.js} +1 -1
- package/dist/web/assets/{glsl-Dovazu3t.js → glsl-CfxLI5jn.js} +1 -1
- package/dist/web/assets/{graphql-DpMlM7hC.js → graphql-CstqDPde.js} +1 -1
- package/dist/web/assets/group-chat-tab-B7mJO1gG.js +1 -0
- package/dist/web/assets/{hack-gc7LCBuV.js → hack-Bjqnssb5.js} +1 -1
- package/dist/web/assets/{haml-vtlFm9gm.js → haml-lVc-DfbM.js} +1 -1
- package/dist/web/assets/hand-x0ejq3fS.js +1 -0
- package/dist/web/assets/{handlebars-DGKhpCji.js → handlebars-Yy6fPQI_.js} +1 -1
- package/dist/web/assets/{html-derivative-C3oTSSCN.js → html-derivative-CchzCY1z.js} +1 -1
- package/dist/web/assets/{html-DvfhQbXb.js → html-lqtcy6-2.js} +1 -1
- package/dist/web/assets/{http-SG6zLTo7.js → http-ChclRrko.js} +1 -1
- package/dist/web/assets/{hurl-BWXsYlqW.js → hurl-CoOK7sXa.js} +1 -1
- package/dist/web/assets/{hxml-DUdMzaoh.js → hxml-fZSZ7Iyt.js} +1 -1
- package/dist/web/assets/{image-preview-DxgFOV1T.js → image-preview-ClAcqDlL.js} +1 -1
- package/dist/web/assets/index-CtJbMNNI.css +2 -0
- package/dist/web/assets/index-H_gScEOk.js +52 -0
- package/dist/web/assets/info-3K5VOQVL-Cx1ZfJbp.js +1 -0
- package/dist/web/assets/{input-DuAF-Stj.js → input-DXPgUtxi.js} +1 -1
- package/dist/web/assets/{jinja-955w9RKM.js → jinja-Y0w_KBdE.js} +1 -1
- package/dist/web/assets/{jison-WWfqPo50.js → jison-BILj3F2e.js} +1 -1
- package/dist/web/assets/{julia-BFrfnaNl.js → julia-DRfOPDts.js} +1 -1
- package/dist/web/assets/{just-BrZdyR_I.js → just-n3U_oODO.js} +1 -1
- package/dist/web/assets/keybindings-store-BqctreaI.js +1 -0
- package/dist/web/assets/{keybindings-store-0Wqfa7Qp.js → keybindings-store-D-CHdq-G.js} +1 -1
- package/dist/web/assets/keyboard-DBBaoQSu.js +1 -0
- package/dist/web/assets/{latex-CwtPPASD.js → latex-D6gztEOL.js} +1 -1
- package/dist/web/assets/{liquid-CYZuvDDd.js → liquid-DPqCEVb9.js} +1 -1
- package/dist/web/assets/{lua-BV095ZyY.js → lua-I40KPUm-.js} +1 -1
- package/dist/web/assets/markdown-renderer-BwOkiZC1.js +1 -0
- package/dist/web/assets/{markdown-renderer-CnRcKK3d.js → markdown-renderer-oJ9jPdQ2.js} +3 -3
- package/dist/web/assets/{marko-CNeljZ1C.js → marko-DMjsThSW.js} +1 -1
- package/dist/web/assets/{mdc-JfGapShy.js → mdc-CN2alsbo.js} +1 -1
- package/dist/web/assets/{media-url-Bm4PsduE.js → media-url-COUvasjn.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-Cj1YBq-c.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-D1nM0Ik1.js +1 -0
- package/dist/web/assets/{nextflow-DD5C8nqX.js → nextflow-CGa4JeZ6.js} +1 -1
- package/dist/web/assets/{nginx-Ca7B__x_.js → nginx-CmqrIj84.js} +1 -1
- package/dist/web/assets/{nim-B8FogsDw.js → nim-CqhmTeMa.js} +1 -1
- package/dist/web/assets/notification-store-n-XEQ5pH.js +1 -0
- package/dist/web/assets/{number-overlay-editor-DG9xJwEG.js → number-overlay-editor-BEzJ1YeD.js} +1 -1
- package/dist/web/assets/{overview-panel-s53bnl0q.js → overview-panel-Bf9Gn8qV.js} +1 -1
- package/dist/web/assets/packet-RMMSAZCW-Bqwiy7dz.js +1 -0
- package/dist/web/assets/{panel-store-B4rijFKN.js → panel-store-UWCH6B-_.js} +1 -1
- package/dist/web/assets/{pdf-preview-DYt3aBzM.js → pdf-preview-BMHM5cR2.js} +1 -1
- package/dist/web/assets/{perl-BR78hS8R.js → perl-BOwpb6Tb.js} +1 -1
- package/dist/web/assets/{php-DXBOMC9z.js → php-wT9fVxxu.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BXSJ2God.js +1 -0
- package/dist/web/assets/{postgres-viewer-BvoWSuoZ.js → postgres-viewer-D8rfEY5b.js} +3 -3
- package/dist/web/assets/process-table-CsQ-hDJr.js +1 -0
- package/dist/web/assets/{project-store-BuY7rxn_.js → project-store-CKAOr23O.js} +1 -1
- package/dist/web/assets/{pug-CvTwVVKV.js → pug-DdlNnj-p.js} +1 -1
- package/dist/web/assets/{qml-CPSoZ1-B.js → qml-C5zBdydf.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-D6XrM7HH.js +1 -0
- package/dist/web/assets/{razor-BUA1YKtF.js → razor-DqcJX4iq.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-CTiipn4k.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-Cf5B0dKo.js +1 -0
- package/dist/web/assets/remote-desktop-stats-overlay-vhJBIW7s.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-wCJUfI6G.js +1 -0
- package/dist/web/assets/{rst-BJsq7ISz.js → rst-DiMiMYUO.js} +1 -1
- package/dist/web/assets/{ruby-DSDMeYf5.js → ruby-DK62iflA.js} +1 -1
- package/dist/web/assets/{run-in-terminal-C9xpskFn.js → run-in-terminal-DJSL6nwZ.js} +1 -1
- package/dist/web/assets/{sas-B1nJOjbN.js → sas-6QPGJRa5.js} +1 -1
- package/dist/web/assets/{scroll-area-DBcG1fQo.js → scroll-area-DXGXeiRz.js} +1 -1
- package/dist/web/assets/{scss-BZFyRiQn.js → scss-DmUqh48_.js} +1 -1
- package/dist/web/assets/{send-to-chat-BIg70MUZ.js → send-to-chat-BOony0sO.js} +1 -1
- package/dist/web/assets/settings-store-BpcY5aYE.js +2 -0
- package/dist/web/assets/settings-tab-BVqRO01j.js +1 -0
- package/dist/web/assets/settings-tab-FH581A_i.js +3 -0
- package/dist/web/assets/{shaderlab-laINRXBo.js → shaderlab-DopFR1mi.js} +1 -1
- package/dist/web/assets/{shellsession-BpOOvWVR.js → shellsession-Bp_TGuXb.js} +1 -1
- package/dist/web/assets/{soy-BW4d91Sa.js → soy-DEB9KEFb.js} +1 -1
- package/dist/web/assets/{sparql-BsvvyoHn.js → sparql-C8lEwO1p.js} +1 -1
- package/dist/web/assets/{sql-query-editor-qQce5QJ6.js → sql-query-editor-MMfk0Kbz.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-yhc0YNvu.js → sqlite-viewer-vglzrgnZ.js} +1 -1
- package/dist/web/assets/{stata-K-dZInUt.js → stata-DVep4apN.js} +1 -1
- package/dist/web/assets/{surrealql-CpNp2sgf.js → surrealql-fSlJApOA.js} +1 -1
- package/dist/web/assets/{svelte-BG6iBA8R.js → svelte-DezWBEDi.js} +1 -1
- package/dist/web/assets/{switch-_NcrktLe.js → switch-DqL_ZjB_.js} +1 -1
- package/dist/web/assets/system-monitor-body-BYUfyF8f.js +2 -0
- package/dist/web/assets/system-monitor-tab-CKGXB8lH.js +1 -0
- package/dist/web/assets/{system-monitor-window-content-CaOhD0AU.js → system-monitor-window-content-CiJ2yIsr.js} +1 -1
- package/dist/web/assets/tab-host-window-content-DYlXR0cg.js +1 -0
- package/dist/web/assets/{tab-store-tFnyPmm4.js → tab-store-D2thn4Vv.js} +1 -1
- package/dist/web/assets/team-member-sheet-Bnygu7Xw.js +2 -0
- package/dist/web/assets/{team-member-window-content-B1jkKkDi.js → team-member-window-content-qrgFTC96.js} +1 -1
- package/dist/web/assets/{templ-gxNKXmt3.js → templ-D0zB42a9.js} +1 -1
- package/dist/web/assets/{terminal-tab-UvwM0sty.js → terminal-tab-D_-R5rGm.js} +3 -3
- package/dist/web/assets/{tex-C0ON27g5.js → tex-BJiPijcH.js} +1 -1
- package/dist/web/assets/{tool-cards-jB7GT-wj.js → tool-cards-BW7Xc20J.js} +4 -4
- package/dist/web/assets/treemap-KZPCXAKY-BobWhcHN.js +1 -0
- package/dist/web/assets/{ts-tags-BX_CTVgQ.js → ts-tags-Dcr4u6y5.js} +1 -1
- package/dist/web/assets/{twig-CwL7XnU0.js → twig-B-SQU0bg.js} +1 -1
- package/dist/web/assets/{use-blob-url-DcRcjNTE.js → use-blob-url-BtPlqwLr.js} +1 -1
- package/dist/web/assets/use-monaco-theme-DQY1ZSaf.js +1 -0
- package/dist/web/assets/{use-open-team-member-1hRsHLKg.js → use-open-team-member-C5LQ_TCM.js} +1 -1
- package/dist/web/assets/use-visual-viewport-pVxLfE5B.js +1 -0
- package/dist/web/assets/{use-websocket-rxJLbFqy.js → use-websocket-l39Odhlp.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-CHTa6D69.js → vendor-mermaid-CtDsSxbM.js} +1 -1
- package/dist/web/assets/{video-preview-DMhnf2Gi.js → video-preview-C5AhkIDl.js} +1 -1
- package/dist/web/assets/{vue-Bykm6wSS.js → vue-Cw10Sfbh.js} +1 -1
- package/dist/web/assets/{vue-html-CETdK_iV.js → vue-html-Cc5C_Z_w.js} +1 -1
- package/dist/web/assets/{vue-vine-DiJb6fO5.js → vue-vine-BuNMlnvu.js} +1 -1
- package/dist/web/assets/window-pip-registry-C7oz3Dfy.js +1 -0
- package/dist/web/assets/window-store-B5ZswdYg.js +1 -0
- package/dist/web/assets/{xml-BNw8J5YW.js → xml-DqT1wkky.js} +1 -1
- package/dist/web/assets/{xsl-CsG9L31b.js → xsl-DLkge3A2.js} +1 -1
- package/dist/web/index.html +45 -42
- package/dist/web/sw.js +1 -1
- package/docs/architecture/ai-chat-and-providers.md +3 -0
- package/docs/architecture/workspace-and-ui.md +8 -0
- package/docs/design-guidelines.md +3 -2
- package/package.json +1 -1
- package/src/cli/commands/backup-cmd.ts +119 -0
- package/src/index.ts +3 -0
- package/src/providers/claude-agent-sdk.ts +29 -1
- package/src/server/index.ts +42 -15
- package/src/server/routes/accounts.ts +30 -2
- package/src/server/routes/chat.ts +8 -1
- package/src/server/routes/named-tunnel.ts +5 -2
- package/src/server/routes/remote-desktop.ts +64 -0
- package/src/server/routes/settings.ts +1 -0
- package/src/server/ws/chat.ts +126 -7
- package/src/server/ws/remote-desktop.ts +86 -0
- package/src/services/account.service.ts +106 -23
- package/src/services/db-backup/db-backup-paths.ts +66 -0
- package/src/services/db-backup/db-backup-restore.ts +105 -0
- package/src/services/db-backup/db-backup-retention.ts +96 -0
- package/src/services/db-backup/db-backup-sync.ts +113 -0
- package/src/services/db-backup/db-backup.service.ts +61 -0
- package/src/services/db.service.ts +29 -1
- package/src/services/fs-credential-path-guard.ts +19 -1
- package/src/services/named-tunnel/cloudflared-login.service.ts +2 -2
- package/src/services/nested-subagent-spy.ts +206 -0
- package/src/services/remote-desktop/access-unit-assembler.ts +90 -0
- package/src/services/remote-desktop/avc1-codec-string.ts +18 -0
- package/src/services/remote-desktop/nal-splitter.ts +100 -0
- package/src/services/remote-desktop/remote-desktop-capture.ts +120 -0
- package/src/services/remote-desktop/remote-desktop-encoder-args.ts +42 -0
- package/src/services/remote-desktop/remote-desktop-flag.ts +10 -0
- package/src/services/remote-desktop/remote-desktop-input.ts +217 -0
- package/src/services/remote-desktop/remote-desktop-nonce.ts +38 -0
- package/src/services/remote-desktop/remote-desktop-session.ts +189 -0
- package/src/services/remote-desktop/remote-desktop-vk-map.ts +41 -0
- package/src/services/subagent-transcript-merger.ts +92 -75
- package/src/services/subprocess-retention.ts +29 -6
- package/src/services/supervisor.ts +58 -0
- package/src/services/team-member-activity/subagent-transcript-index.ts +56 -0
- package/src/types/chat.ts +2 -0
- package/src/web/app.tsx +8 -0
- package/src/web/components/chat/account-dialogs.tsx +11 -4
- package/src/web/components/chat/question-card.tsx +9 -2
- package/src/web/components/chat/usage-badge.tsx +17 -3
- package/src/web/components/floating-window/floating-window.tsx +8 -1
- package/src/web/components/floating-window/open-tab-in-pip.ts +78 -0
- package/src/web/components/floating-window/window-content-registry.ts +2 -0
- package/src/web/components/floating-window/window-pip-registry.ts +46 -0
- package/src/web/components/floating-window/window-store-types.ts +1 -1
- package/src/web/components/layout/mobile-drawer.tsx +38 -27
- package/src/web/components/layout/nav-section-rail.tsx +10 -2
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +25 -2
- package/src/web/components/remote-desktop/open-remote-desktop.ts +26 -0
- package/src/web/components/remote-desktop/remote-desktop-coords.ts +98 -0
- package/src/web/components/remote-desktop/remote-desktop-frame-timestamp.ts +21 -0
- package/src/web/components/remote-desktop/remote-desktop-gesture-classifiers.ts +56 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-key-bar.tsx +131 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-sheet.tsx +43 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-toolbar.tsx +79 -0
- package/src/web/components/remote-desktop/remote-desktop-mobile-view.tsx +190 -0
- package/src/web/components/remote-desktop/remote-desktop-stats-overlay.tsx +54 -0
- package/src/web/components/remote-desktop/remote-desktop-stats.ts +37 -0
- package/src/web/components/remote-desktop/remote-desktop-touch-gesture-tracker.ts +195 -0
- package/src/web/components/remote-desktop/remote-desktop-window-content.tsx +72 -0
- package/src/web/components/remote-desktop/remote-desktop-ws-url.ts +22 -0
- package/src/web/components/remote-desktop/use-h264-canvas-decoder.ts +175 -0
- package/src/web/components/remote-desktop/use-remote-desktop-available.ts +29 -0
- package/src/web/components/remote-desktop/use-remote-desktop-connection.ts +147 -0
- package/src/web/components/remote-desktop/use-remote-desktop-mobile-open-state.ts +18 -0
- package/src/web/components/remote-desktop/use-remote-desktop-touch.ts +224 -0
- package/src/web/components/remote-desktop/use-remote-desktop-virtual-keyboard.ts +50 -0
- package/src/web/components/remote-desktop/use-remote-input-capture.ts +92 -0
- package/src/web/components/tunnels/named-tunnel/named-tunnel-copy.ts +59 -59
- package/src/web/components/tunnels/named-tunnel/named-tunnel-section.tsx +2 -2
- package/src/web/hooks/use-notification-badge.ts +19 -11
- package/src/web/lib/feature-badges.ts +2 -0
- package/src/web/stores/settings-store.ts +13 -0
- package/src/web/stores/streaming-store.ts +21 -2
- package/dist/web/assets/api-client-BogqsFna.js +0 -1
- package/dist/web/assets/api-settings-DfXViPKz.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-BzFm9ELu.js +0 -1
- package/dist/web/assets/chat-tab-DzK8LGti.js +0 -15
- package/dist/web/assets/code-editor-CuMfPN9X.js +0 -10
- package/dist/web/assets/diff-viewer-eaUBjLCH.js +0 -4
- package/dist/web/assets/explorer-body-DkCkSVrN.js +0 -2
- package/dist/web/assets/explorer-window-content-MsnTVngu.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-B72vcb2r.js +0 -1
- package/dist/web/assets/glide-data-grid-B0IY6n_Q.js +0 -138
- package/dist/web/assets/group-chat-tab-DRLDHOp6.js +0 -1
- package/dist/web/assets/index-CBn4SOoT.js +0 -52
- package/dist/web/assets/index-DWpNR3nB.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-3irPxRK_.js +0 -1
- package/dist/web/assets/keybindings-store-d54pv2NK.js +0 -1
- package/dist/web/assets/markdown-renderer-BTS8ifdu.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-M5iZDX7y.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-BqK2-WuN.js +0 -1
- package/dist/web/assets/notification-store-Yvy1I8gd.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-Z5jWjFCV.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-Bq7UMi8P.js +0 -1
- package/dist/web/assets/process-table-BYwKigiD.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-BLo4BOTD.js +0 -1
- package/dist/web/assets/settings-store-GV5pkkke.js +0 -2
- package/dist/web/assets/settings-tab-BePvIcjd.js +0 -3
- package/dist/web/assets/settings-tab-Br-lJSPa.js +0 -1
- package/dist/web/assets/system-monitor-body-D8Z5QXBB.js +0 -2
- package/dist/web/assets/system-monitor-tab-BclYXFTe.js +0 -1
- package/dist/web/assets/tab-host-window-content-f_Rc5rJK.js +0 -1
- package/dist/web/assets/team-member-sheet-QDHoYCs0.js +0 -2
- package/dist/web/assets/treemap-KZPCXAKY-dyrE6SW2.js +0 -1
- package/dist/web/assets/use-monaco-theme--9tOOkDA.js +0 -1
- package/dist/web/assets/window-store-CQ1lghvv.js +0 -1
- /package/dist/web/assets/{abap-DGlrX_8G.js → abap-CKgBNk5K.js} +0 -0
- /package/dist/web/assets/{actionscript-3-CUqRtUJE.js → actionscript-3-oARhAY6c.js} +0 -0
- /package/dist/web/assets/{ada-CY3Spa33.js → ada-2vi8ASy3.js} +0 -0
- /package/dist/web/assets/{andromeeda-Lxs2TJn7.js → andromeeda-B3vMjPKd.js} +0 -0
- /package/dist/web/assets/{apache-DfxgGdgM.js → apache-DnIEr338.js} +0 -0
- /package/dist/web/assets/{apex-QVDF1dnI.js → apex-B7Qs5AY5.js} +0 -0
- /package/dist/web/assets/{api-client-oY1tC3tM.js → api-client-BkGKTjsq.js} +0 -0
- /package/dist/web/assets/{applescript-pwJ8QXh-.js → applescript-EbQNUCWb.js} +0 -0
- /package/dist/web/assets/{apply-theme-B_bMVL6a.js → apply-theme-Dd_cqGa-.js} +0 -0
- /package/dist/web/assets/{ara-mPjeX5YX.js → ara-CtHdhFRw.js} +0 -0
- /package/dist/web/assets/{asciidoc-Bf7LsDkI.js → asciidoc-BH6qin_O.js} +0 -0
- /package/dist/web/assets/{asm-rRKC1OUx.js → asm-D1XU1ACk.js} +0 -0
- /package/dist/web/assets/{aurora-x-DwQr0DkG.js → aurora-x-BkhcxkuS.js} +0 -0
- /package/dist/web/assets/{awk-Bpt768fN.js → awk-DijzB6o7.js} +0 -0
- /package/dist/web/assets/{ayu-dark-D9lwQHMs.js → ayu-dark-tysG77WC.js} +0 -0
- /package/dist/web/assets/{ayu-light-B4-ptrU5.js → ayu-light-Dg0WMETC.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-DAyRzH5Q.js → ayu-mirage--RsJCjC4.js} +0 -0
- /package/dist/web/assets/{ballerina-Cgdpj1HC.js → ballerina-DT_5-l82.js} +0 -0
- /package/dist/web/assets/{bat-4FrN36S2.js → bat-BRpDlkv0.js} +0 -0
- /package/dist/web/assets/{beancount-DkcxQER3.js → beancount--8Df-WGG.js} +0 -0
- /package/dist/web/assets/{berry-Dnuut-Ml.js → berry-Bc9fo35J.js} +0 -0
- /package/dist/web/assets/{bibtex-CCDwmbuA.js → bibtex-CwyBpp9X.js} +0 -0
- /package/dist/web/assets/{bicep-BC0ryoGM.js → bicep-DiyH2Bs7.js} +0 -0
- /package/dist/web/assets/{bird2-C50V_A-0.js → bird2-CHgK4a2A.js} +0 -0
- /package/dist/web/assets/{c-Ddorhq0U.js → c-BM1qL6-f.js} +0 -0
- /package/dist/web/assets/{c3-DdIf5r9E.js → c3-D2oOjrP7.js} +0 -0
- /package/dist/web/assets/{cadence-s9pd1Wng.js → cadence-nS45wqF6.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-C6hZV1OP.js → can-open-in-ppm-DwP9KU8o.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-CzJNTyu-.js → catppuccin-frappe-BpnJHiCj.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-BNpt-m7s.js → catppuccin-latte-Bb95Wj3h.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-FYGkfsJ5.js → catppuccin-macchiato-Btx8c17W.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-it2g5D1q.js → catppuccin-mocha-B4DZOUGI.js} +0 -0
- /package/dist/web/assets/{clarity-BVFBTjMe.js → clarity-1ps69jU6.js} +0 -0
- /package/dist/web/assets/{clipboard-BWznymz7.js → clipboard-CrHX8AYw.js} +0 -0
- /package/dist/web/assets/{clojure-BSYvXMI8.js → clojure-BklC0hKV.js} +0 -0
- /package/dist/web/assets/{cmake-DGEqH-Np.js → cmake-B573LYAQ.js} +0 -0
- /package/dist/web/assets/{codeowners-D8FCOxWg.js → codeowners-BoYeX89M.js} +0 -0
- /package/dist/web/assets/{codeql-COV0eluG.js → codeql-7Dhf5Udk.js} +0 -0
- /package/dist/web/assets/{common-lisp-xHnZUlgt.js → common-lisp-m1nxlthv.js} +0 -0
- /package/dist/web/assets/{coq-Cs_2i3Xg.js → coq-DNhGmd4a.js} +0 -0
- /package/dist/web/assets/{csharp-B1ONB4PT.js → csharp-P-nAurtS.js} +0 -0
- /package/dist/web/assets/{css-BgGQbvrZ.js → css-LYbSeh3-.js} +0 -0
- /package/dist/web/assets/{csv-CNHmQBzs.js → csv-DHZZZm7X.js} +0 -0
- /package/dist/web/assets/{csv-parser-DWR24J17.js → csv-parser-CY9Ggtg5.js} +0 -0
- /package/dist/web/assets/{cue-ZXAKzwIy.js → cue-D8yLUOle.js} +0 -0
- /package/dist/web/assets/{cypher-4PL5bmT5.js → cypher-9cbW8RYA.js} +0 -0
- /package/dist/web/assets/{d-CEsV3RT2.js → d-ZihzhxqI.js} +0 -0
- /package/dist/web/assets/{dark-plus-NtFnYSDz.js → dark-plus-C8xIA1u3.js} +0 -0
- /package/dist/web/assets/{dart-CKHn4mDf.js → dart-CBm6jKc7.js} +0 -0
- /package/dist/web/assets/{data-grid-types-CxU8oo-j.js → data-grid-types-DkEQ-Na9.js} +0 -0
- /package/dist/web/assets/{dax-Cmkj1I_M.js → dax-B3cx6YeV.js} +0 -0
- /package/dist/web/assets/{desktop-DJLalvPQ.js → desktop-C03SpXth.js} +0 -0
- /package/dist/web/assets/{diff-BnS2wpj6.js → diff-D8LnnvFY.js} +0 -0
- /package/dist/web/assets/{dist-uYjs3Wv6.js → dist-C4XoS_zo.js} +0 -0
- /package/dist/web/assets/{dist-CuIdRyUB.js → dist-Do3fljss.js} +0 -0
- /package/dist/web/assets/{docker-CovNy7ml.js → docker-DwFiOQWW.js} +0 -0
- /package/dist/web/assets/{dotenv-Gh4w3I6B.js → dotenv-CVJ_vFSQ.js} +0 -0
- /package/dist/web/assets/{dracula-NF0tAHXl.js → dracula-DMw8UACY.js} +0 -0
- /package/dist/web/assets/{dracula-soft-Cj_qBurK.js → dracula-soft-BnB3nDrA.js} +0 -0
- /package/dist/web/assets/{dream-maker-CRuZPcl7.js → dream-maker-2riXUQXo.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-BACmC9qj.js → emacs-lisp-BQdYaiB5.js} +0 -0
- /package/dist/web/assets/{everforest-dark-Dd9av4QG.js → everforest-dark-C2FPIWdj.js} +0 -0
- /package/dist/web/assets/{everforest-light-C-jsss-B.js → everforest-light-DMOWf9sD.js} +0 -0
- /package/dist/web/assets/{fennel-BJA9XnL8.js → fennel-JtSHp0vW.js} +0 -0
- /package/dist/web/assets/{fish-CKlhNSc2.js → fish-CflDcRfe.js} +0 -0
- /package/dist/web/assets/{fluent-wfglRk5D.js → fluent-D4eu6Vac.js} +0 -0
- /package/dist/web/assets/{format-bytes-utwHMTry.js → format-bytes-DR3228bu.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-BlXCdid3.js → fortran-free-form-hO4RuC9Z.js} +0 -0
- /package/dist/web/assets/{gdscript-BwAVG6Et.js → gdscript-D7n3a8VM.js} +0 -0
- /package/dist/web/assets/{gdshader-DPc_T7ib.js → gdshader-BhUmrlzG.js} +0 -0
- /package/dist/web/assets/{genie-B-zZSLCX.js → genie-VbyftqBp.js} +0 -0
- /package/dist/web/assets/{gherkin-CJ0ajpGs.js → gherkin-BZzhvUUb.js} +0 -0
- /package/dist/web/assets/{github-dark-Dz8ZkzSP.js → github-dark-C4q41woW.js} +0 -0
- /package/dist/web/assets/{github-dark-default-CNUYo_kp.js → github-dark-default-CMNi7dQX.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-241z_Ycx.js → github-dark-dimmed-BRf_-LlY.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-7r6yZZYH.js → github-dark-high-contrast-xanKBsRI.js} +0 -0
- /package/dist/web/assets/{github-light-C8gmZn-D.js → github-light-BEQeNQCs.js} +0 -0
- /package/dist/web/assets/{github-light-default-GAEgq1eA.js → github-light-default-ceQrtdXg.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-3z91352E.js → github-light-high-contrast-doKbXzgW.js} +0 -0
- /package/dist/web/assets/{gleam-C7vxW5zd.js → gleam-Chzqf4fT.js} +0 -0
- /package/dist/web/assets/{gn-CyJIXwHP.js → gn-CCN_-6fp.js} +0 -0
- /package/dist/web/assets/{gnuplot-CqLbGgPd.js → gnuplot-CIplgwwP.js} +0 -0
- /package/dist/web/assets/{go-DdDcK9aX.js → go-Cjj-9dRs.js} +0 -0
- /package/dist/web/assets/{groovy-UYHggEqH.js → groovy-PqD4K7X1.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-B4ierkJn.js → gruvbox-dark-hard-BAbpUSF-.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-DYwkDSZ6.js → gruvbox-dark-medium-BWcWXDBB.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-CVL4P-Lz.js → gruvbox-dark-soft-Dkx1okkk.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-BJ0LewUZ.js → gruvbox-light-hard-WVsDK0MM.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-CaqqjeGJ.js → gruvbox-light-medium-tiR9t7gr.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-ByKMoVNr.js → gruvbox-light-soft-HzHohaX6.js} +0 -0
- /package/dist/web/assets/{haskell-BilYRVPp.js → haskell-B1eIZfr6.js} +0 -0
- /package/dist/web/assets/{haxe-Brs9Bj1s.js → haxe-BcDdi5xr.js} +0 -0
- /package/dist/web/assets/{hcl-ClrZpol-.js → hcl-Dq-HKVni.js} +0 -0
- /package/dist/web/assets/{hjson-9PvHnYMX.js → hjson-Dr9D9WVU.js} +0 -0
- /package/dist/web/assets/{hlsl-BbBk4vqV.js → hlsl-Bo8t2FuZ.js} +0 -0
- /package/dist/web/assets/{horizon-E5Py0cny.js → horizon-DWG5IXc-.js} +0 -0
- /package/dist/web/assets/{horizon-bright-DVCsNGEk.js → horizon-bright-DFr9wTTx.js} +0 -0
- /package/dist/web/assets/{houston-JdFEax9Y.js → houston-NAVNhkup.js} +0 -0
- /package/dist/web/assets/{hy-W_W3tLKT.js → hy-DnyvUk3B.js} +0 -0
- /package/dist/web/assets/{image-gallery-5IURd6db.js → image-gallery-DoFdNF9i.js} +0 -0
- /package/dist/web/assets/{imba-CfAqJz7T.js → imba-CPbR5W_A.js} +0 -0
- /package/dist/web/assets/{ini-C_3gvKWs.js → ini-lc8_Lt0y.js} +0 -0
- /package/dist/web/assets/{java-CKqtXZ-j.js → java-B0KCo2vK.js} +0 -0
- /package/dist/web/assets/{javascript-C7gSEfae.js → javascript-YqEbNRpd.js} +0 -0
- /package/dist/web/assets/{json-BoN6e11T.js → json-Co0WtOlh.js} +0 -0
- /package/dist/web/assets/{json5-CgE7C8HW.js → json5-2Jhb0QUN.js} +0 -0
- /package/dist/web/assets/{jsonc-DjyoattY.js → jsonc-e72F11nU.js} +0 -0
- /package/dist/web/assets/{jsonl-lI82wGSw.js → jsonl-Bff8IPye.js} +0 -0
- /package/dist/web/assets/{jsonnet-CszEI8va.js → jsonnet-DRCkb-_H.js} +0 -0
- /package/dist/web/assets/{jssm-CZXDlszb.js → jssm-C6UiwVEm.js} +0 -0
- /package/dist/web/assets/{jsx-BeRz0eEz.js → jsx-u1aZlnfA.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-BOmnUiyd.js → kanagawa-dragon-De-RQFV3.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-ffU_P5w-.js → kanagawa-lotus-K8elE4QU.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-DKTJZrMu.js → kanagawa-wave-BrStl_zx.js} +0 -0
- /package/dist/web/assets/{kdl-BWECJveH.js → kdl-CLCfMeZy.js} +0 -0
- /package/dist/web/assets/{kotlin-DpVwBCSt.js → kotlin-DEEC3pNh.js} +0 -0
- /package/dist/web/assets/{kusto-BgVqjUZA.js → kusto-DTqRhCup.js} +0 -0
- /package/dist/web/assets/{laserwave-CEVCi8em.js → laserwave-DsgpUSbA.js} +0 -0
- /package/dist/web/assets/{lean-CGyfRhLJ.js → lean-Dl9MI0Y3.js} +0 -0
- /package/dist/web/assets/{less-B0_H10Ku.js → less-Bg21rao6.js} +0 -0
- /package/dist/web/assets/{lib-hrC3bruJ.js → lib-CXUwxw1M.js} +0 -0
- /package/dist/web/assets/{libesm-DVpFmwJu.js → libesm-CVkncAQz.js} +0 -0
- /package/dist/web/assets/{light-plus-DqzMqPID.js → light-plus-DGNbbK1V.js} +0 -0
- /package/dist/web/assets/{llvm-9ucnfNiF.js → llvm-91_ZX3p-.js} +0 -0
- /package/dist/web/assets/{loader-circle-Dpqcv0eS.js → loader-circle-DouKgIXy.js} +0 -0
- /package/dist/web/assets/{lock-DldbT31x.js → lock-CNxUGpTk.js} +0 -0
- /package/dist/web/assets/{log-m6A2dOSj.js → log-DSXzbq8u.js} +0 -0
- /package/dist/web/assets/{logo-ByPcsC9P.js → logo-BQRNd4tc.js} +0 -0
- /package/dist/web/assets/{luau-DFCo8nBn.js → luau-BE-TMpiZ.js} +0 -0
- /package/dist/web/assets/{make-C90w3MeA.js → make-ePYGKTpc.js} +0 -0
- /package/dist/web/assets/{markdown-DT0uywZG.js → markdown-Cst3wgMW.js} +0 -0
- /package/dist/web/assets/{material-theme-BVUO93tJ.js → material-theme-9XyvnNLb.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-xXgGDwnF.js → material-theme-darker-H1VN4MTS.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-BjStPzWB.js → material-theme-lighter-DAreBbuF.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-wFmSiKjy.js → material-theme-ocean-BpTR-3II.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-e-0CtRoe.js → material-theme-palenight-DUNzX711.js} +0 -0
- /package/dist/web/assets/{matlab-BNaNQAUH.js → matlab-BpYNufBU.js} +0 -0
- /package/dist/web/assets/{mdx-DfpVWAqO.js → mdx-BYjfe1DK.js} +0 -0
- /package/dist/web/assets/{mermaid-Bpq7wFCP.js → mermaid-DPCcIW9B.js} +0 -0
- /package/dist/web/assets/{min-dark-CL2Y0WH6.js → min-dark-DnGOAGCo.js} +0 -0
- /package/dist/web/assets/{min-light-DOgr_IdP.js → min-light-CwV-o31y.js} +0 -0
- /package/dist/web/assets/{mipsasm-C9ie2zlB.js → mipsasm-DdeCPC97.js} +0 -0
- /package/dist/web/assets/{mojo-Md2A2sJy.js → mojo-BmxxZ3iM.js} +0 -0
- /package/dist/web/assets/{monitor-4vWfqzuN.js → monitor-C835ucWH.js} +0 -0
- /package/dist/web/assets/{monokai-nbXIEySB.js → monokai-Cx6cQ-MA.js} +0 -0
- /package/dist/web/assets/{moonbit-CJ-T-s4A.js → moonbit-D2-Gj5vj.js} +0 -0
- /package/dist/web/assets/{move-DwEehLIK.js → move-DSWGoQa8.js} +0 -0
- /package/dist/web/assets/{narrat-CuF4sIKr.js → narrat-D9TnZSSu.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-1dYhfPfq.js → nextflow-groovy-BbL-8PwD.js} +0 -0
- /package/dist/web/assets/{night-owl-gZS5mfzY.js → night-owl-CZitKm5d.js} +0 -0
- /package/dist/web/assets/{night-owl-light-DDAster5.js → night-owl-light-DJVX1Pno.js} +0 -0
- /package/dist/web/assets/{nix-BlbEYs2c.js → nix-R6hr3oln.js} +0 -0
- /package/dist/web/assets/{nord-BRiPb8Vy.js → nord-ChGHya3l.js} +0 -0
- /package/dist/web/assets/{nushell-DgWicB1i.js → nushell-QQWB-GWx.js} +0 -0
- /package/dist/web/assets/{objective-c-D8mPZ42Y.js → objective-c-C0pZ6y73.js} +0 -0
- /package/dist/web/assets/{objective-cpp-B0pNXzuj.js → objective-cpp-BdzVM31a.js} +0 -0
- /package/dist/web/assets/{ocaml-lQd7aK5d.js → ocaml-D4KktNlS.js} +0 -0
- /package/dist/web/assets/{odin-CxtIOBjm.js → odin-Y-fypmGT.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-T_UFnWfe.js → one-dark-pro-BwecIxQL.js} +0 -0
- /package/dist/web/assets/{one-light-LBVqwyV-.js → one-light-Cz7UVzLU.js} +0 -0
- /package/dist/web/assets/{openscad-C5dnS6J7.js → openscad-DtRe3qYD.js} +0 -0
- /package/dist/web/assets/{pascal-CmWCWQML.js → pascal-Ck6I1fGG.js} +0 -0
- /package/dist/web/assets/{pkl-BWWOtDQk.js → pkl-DdFK94VW.js} +0 -0
- /package/dist/web/assets/{plastic-ekhupckF.js → plastic-BQSAzZwR.js} +0 -0
- /package/dist/web/assets/{play-CpCAoQRZ.js → play-CJlWpVMw.js} +0 -0
- /package/dist/web/assets/{plsql-BPsDHXx4.js → plsql-DjXg_CP0.js} +0 -0
- /package/dist/web/assets/{po-BX2FiuW2.js → po-Bw2SuM4r.js} +0 -0
- /package/dist/web/assets/{poimandres-DzXOdZcN.js → poimandres-YMK6c5VN.js} +0 -0
- /package/dist/web/assets/{polar-DDRXgJzG.js → polar-BMu17-O0.js} +0 -0
- /package/dist/web/assets/{portal-container-context-a399Hd9F.js → portal-container-context-DSGdlXrJ.js} +0 -0
- /package/dist/web/assets/{postcss-BHW6XBhx.js → postcss-DWib10RZ.js} +0 -0
- /package/dist/web/assets/{powerquery-B89c2NBb.js → powerquery-Dht4CK0b.js} +0 -0
- /package/dist/web/assets/{powershell-Dvxrd3Tu.js → powershell-DvrCg8ji.js} +0 -0
- /package/dist/web/assets/{prisma-lMK8EFLU.js → prisma-DbodYvCM.js} +0 -0
- /package/dist/web/assets/{prolog-D0YrtMG4.js → prolog-DZ-m6ysB.js} +0 -0
- /package/dist/web/assets/{proto-J0mM25aw.js → proto-HHpG3tGO.js} +0 -0
- /package/dist/web/assets/{puppet-CUT0xkhh.js → puppet-BljHe_75.js} +0 -0
- /package/dist/web/assets/{purescript-CoJWSGRp.js → purescript-DzCiFR0B.js} +0 -0
- /package/dist/web/assets/{python-BBrmuz6P.js → python-B5BQ27cC.js} +0 -0
- /package/dist/web/assets/{qmldir-CUtzs4Q7.js → qmldir-CYlcXrnn.js} +0 -0
- /package/dist/web/assets/{qss-Dm1RZ8aL.js → qss-Ce7T_TEg.js} +0 -0
- /package/dist/web/assets/{r-BGP7qZTe.js → r-Bku-2Jp_.js} +0 -0
- /package/dist/web/assets/{racket-K_6U1lqJ.js → racket-DtfSL3WR.js} +0 -0
- /package/dist/web/assets/{raku-bNSiZeW_.js → raku-CnDLsBJr.js} +0 -0
- /package/dist/web/assets/{react-X4jUntEf.js → react-Dfio3PfK.js} +0 -0
- /package/dist/web/assets/{red-uVeIEF0f.js → red-vbqcE9b-.js} +0 -0
- /package/dist/web/assets/{refresh-cw-B9iv7csb.js → refresh-cw-84mz8aOE.js} +0 -0
- /package/dist/web/assets/{reg-DSm9GWjh.js → reg-DIDLT8-A.js} +0 -0
- /package/dist/web/assets/{regexp-CljRm_j_.js → regexp-CB4h-VPu.js} +0 -0
- /package/dist/web/assets/{rel-d3JcopZg.js → rel-CiQEnWXa.js} +0 -0
- /package/dist/web/assets/{resolve-theme-DLKmm-lE.js → resolve-theme-DPTQHAy1.js} +0 -0
- /package/dist/web/assets/{riscv-CJmaELjT.js → riscv-R78iq5Rf.js} +0 -0
- /package/dist/web/assets/{ron-D0g9B1rW.js → ron-DhYENxc4.js} +0 -0
- /package/dist/web/assets/{rose-pine-DOrD2BSH.js → rose-pine-5wBeyjfJ.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-CzZQ-LCF.js → rose-pine-dawn-FpKtPCuH.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CdmsYp7C.js → rose-pine-moon-BwcIYc7C.js} +0 -0
- /package/dist/web/assets/{rosmsg-CmDth6pO.js → rosmsg-DWIGAYMl.js} +0 -0
- /package/dist/web/assets/{rotate-ccw-DnuPzJRE.js → rotate-ccw-CNTk2J7l.js} +0 -0
- /package/dist/web/assets/{rust-DGdP6jiR.js → rust-DU_ofKgt.js} +0 -0
- /package/dist/web/assets/{sass-Dkgt2FKZ.js → sass-U9SUuYEy.js} +0 -0
- /package/dist/web/assets/{save-DxonD4y1.js → save-CtW9ojKk.js} +0 -0
- /package/dist/web/assets/{scala-BQLTON6C.js → scala-op4gjA6j.js} +0 -0
- /package/dist/web/assets/{scheme-DKlxUGCi.js → scheme-tEjkR8rL.js} +0 -0
- /package/dist/web/assets/{sdbl-C3iZJQeZ.js → sdbl-C6SSRmZg.js} +0 -0
- /package/dist/web/assets/{send-B-t5Mz26.js → send-C_sLFt56.js} +0 -0
- /package/dist/web/assets/{shallow-jwPzEunk.js → shallow-C1YoJQA-.js} +0 -0
- /package/dist/web/assets/{shellscript-BRu-ZQAx.js → shellscript-Bf2KiwQj.js} +0 -0
- /package/dist/web/assets/{shield-check-CdTiK1j2.js → shield-check-Du6HKYn9.js} +0 -0
- /package/dist/web/assets/{shield-off-DuetkXKM.js → shield-off-CWKb1MQL.js} +0 -0
- /package/dist/web/assets/{slack-dark-qkm_u2zz.js → slack-dark-oGgCey8r.js} +0 -0
- /package/dist/web/assets/{slack-ochin-BP8_8e4m.js → slack-ochin-CemlB8cE.js} +0 -0
- /package/dist/web/assets/{smalltalk-Bnz4gt07.js → smalltalk-CTE-6jrZ.js} +0 -0
- /package/dist/web/assets/{snazzy-light-fbPZg5io.js → snazzy-light-DoEIGnmz.js} +0 -0
- /package/dist/web/assets/{solarized-dark-CM0vTRoi.js → solarized-dark-CStiJyBg.js} +0 -0
- /package/dist/web/assets/{solarized-light-C4_W9mvs.js → solarized-light-CfuNycS9.js} +0 -0
- /package/dist/web/assets/{solidity-Bz6v1PoD.js → solidity-DL6sO5rd.js} +0 -0
- /package/dist/web/assets/{splunk-DyNxu-0i.js → splunk-yK4ZUFBB.js} +0 -0
- /package/dist/web/assets/{sql-DXRL1gw1.js → sql-Lw03eoN8.js} +0 -0
- /package/dist/web/assets/{ssh-config-2z1QHuOG.js → ssh-config-DeRp25TR.js} +0 -0
- /package/dist/web/assets/{stylus-D4I-VaeY.js → stylus-D8OMsPh-.js} +0 -0
- /package/dist/web/assets/{swift-C_2G-tIc.js → swift-nsl9stPV.js} +0 -0
- /package/dist/web/assets/{synthwave-84-osBjChRP.js → synthwave-84-exAgsgpf.js} +0 -0
- /package/dist/web/assets/{system-verilog-zQP2qPNU.js → system-verilog-DBWf00T6.js} +0 -0
- /package/dist/web/assets/{systemd-UGfjRSBM.js → systemd-nhu27Dw5.js} +0 -0
- /package/dist/web/assets/{table-FLU8ei8b.js → table-GAR4upb6.js} +0 -0
- /package/dist/web/assets/{talonscript-C1XrFPwo.js → talonscript-CNOEcGDc.js} +0 -0
- /package/dist/web/assets/{tasl-B5raVn43.js → tasl-CjYZenSH.js} +0 -0
- /package/dist/web/assets/{tcl-3-vbeMIc.js → tcl-BVA09RDz.js} +0 -0
- /package/dist/web/assets/{terraform-a8VXZDm9.js → terraform-C5EloH1q.js} +0 -0
- /package/dist/web/assets/{text-wrap-B05VGRa-.js → text-wrap-D71Jqz5U.js} +0 -0
- /package/dist/web/assets/{tokyo-night-4SRhf-Hz.js → tokyo-night-D764DdhO.js} +0 -0
- /package/dist/web/assets/{toml-B4N0i8wT.js → toml-CCDYblSB.js} +0 -0
- /package/dist/web/assets/{trash-2-CTXlTflF.js → trash-2-C08fhIg1.js} +0 -0
- /package/dist/web/assets/{triangle-alert-BRq0VAfd.js → triangle-alert-85BQgs3T.js} +0 -0
- /package/dist/web/assets/{tsv-DA5k9Lvw.js → tsv-BZ4sA05e.js} +0 -0
- /package/dist/web/assets/{tsx-D9SZ8owC.js → tsx-DPLBzAt5.js} +0 -0
- /package/dist/web/assets/{turtle-BTHTvyY_.js → turtle-CwGHCq40.js} +0 -0
- /package/dist/web/assets/{typescript-DYzV9p5L.js → typescript-CUH0vBAl.js} +0 -0
- /package/dist/web/assets/{typespec-BC15eh7F.js → typespec-Bq31Vq4u.js} +0 -0
- /package/dist/web/assets/{typst-BJUqzA6D.js → typst-MD9BR9W5.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-DFWViA4S.js → use-is-mobile-DUuki97q.js} +0 -0
- /package/dist/web/assets/{utils-C9OjCrou.js → utils-u2fbYPrY.js} +0 -0
- /package/dist/web/assets/{v-50Lps6oA.js → v-DZV7IxIT.js} +0 -0
- /package/dist/web/assets/{vala-8wiUvvrD.js → vala-urd1zi9S.js} +0 -0
- /package/dist/web/assets/{vb-BlgPLt6B.js → vb-DIZU3zbJ.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-BZOrwF_F.js → vendor-xterm-DCj0zgSC.js} +0 -0
- /package/dist/web/assets/{verilog-CD9pVW5p.js → verilog-Ndz_ciTA.js} +0 -0
- /package/dist/web/assets/{vesper-BrivW4PT.js → vesper-C86M7LJp.js} +0 -0
- /package/dist/web/assets/{vhdl-Bunxfa7N.js → vhdl-_klwDUjd.js} +0 -0
- /package/dist/web/assets/{viml-DndUb2qM.js → viml-DzRXWoQh.js} +0 -0
- /package/dist/web/assets/{vitesse-black-BurZSkxW.js → vitesse-black-TWZ20_3U.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-8UShspzC.js → vitesse-dark-Dl7R6fy9.js} +0 -0
- /package/dist/web/assets/{vitesse-light-DghCAZ90.js → vitesse-light-Cs0Dt2_n.js} +0 -0
- /package/dist/web/assets/{vyper-b-Clr-8u.js → vyper-qnCVj8ia.js} +0 -0
- /package/dist/web/assets/{wasm-CpcKStkw.js → wasm-Ckx9jBPe.js} +0 -0
- /package/dist/web/assets/{wasm-C5v2T06Y.js → wasm-Dy-SJ3W9.js} +0 -0
- /package/dist/web/assets/{wenyan-Dz2srLZR.js → wenyan-DTEy2Lx-.js} +0 -0
- /package/dist/web/assets/{wgsl-CeD1-dRb.js → wgsl-DC7n63Sy.js} +0 -0
- /package/dist/web/assets/{wikitext-CyeS-9FH.js → wikitext-1zFoZiW6.js} +0 -0
- /package/dist/web/assets/{wit-Kr-q-qBQ.js → wit-DtTfCRph.js} +0 -0
- /package/dist/web/assets/{wolfram-BKm8bmln.js → wolfram-B2Bgu1KL.js} +0 -0
- /package/dist/web/assets/{x-YDu4m2Iq.js → x-CeN0Qybc.js} +0 -0
- /package/dist/web/assets/{yaml-2XSxomjM.js → yaml-B-Jxk0IQ.js} +0 -0
- /package/dist/web/assets/{zenscript-CKIS34vf.js → zenscript-BWRfvNER.js} +0 -0
- /package/dist/web/assets/{zig-DdHGNllX.js → zig-CkwuvETm.js} +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `ppm backup` / `ppm restore` — manual control over config-database
|
|
5
|
+
* snapshots. Snapshots also happen automatically (hourly, at start-up, and
|
|
6
|
+
* before any schema migration); these commands exist for the two moments
|
|
7
|
+
* automation cannot cover: taking one deliberately before a risky change, and
|
|
8
|
+
* getting back on your feet after something ate the database.
|
|
9
|
+
*
|
|
10
|
+
* Kept out of `db-cmd.ts` on purpose — that command group manages *external*
|
|
11
|
+
* database connections, so `ppm db backup` would read as backing one of those
|
|
12
|
+
* up rather than PPM's own store.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const C = {
|
|
16
|
+
reset: "\x1b[0m",
|
|
17
|
+
bold: "\x1b[1m",
|
|
18
|
+
green: "\x1b[32m",
|
|
19
|
+
red: "\x1b[31m",
|
|
20
|
+
yellow: "\x1b[33m",
|
|
21
|
+
cyan: "\x1b[36m",
|
|
22
|
+
dim: "\x1b[2m",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function mb(bytes: number): string {
|
|
26
|
+
return `${(bytes / 1_048_576).toFixed(1)} MB`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function ago(date: Date, now = new Date()): string {
|
|
30
|
+
const mins = Math.round((now.getTime() - date.getTime()) / 60_000);
|
|
31
|
+
if (mins < 60) return `${mins}m ago`;
|
|
32
|
+
const hours = Math.round(mins / 60);
|
|
33
|
+
if (hours < 48) return `${hours}h ago`;
|
|
34
|
+
return `${Math.round(hours / 24)}d ago`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function registerBackupCommands(program: Command): void {
|
|
38
|
+
program
|
|
39
|
+
.command("backup")
|
|
40
|
+
.description("Snapshot the PPM config database now")
|
|
41
|
+
.option("--json", "Output as JSON")
|
|
42
|
+
.action(async (options: { json?: boolean }) => {
|
|
43
|
+
try {
|
|
44
|
+
const { backupDb } = await import("../../services/db-backup/db-backup.service.ts");
|
|
45
|
+
const result = await backupDb("manual");
|
|
46
|
+
if (options.json) {
|
|
47
|
+
console.log(JSON.stringify(result, null, 2));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
console.log(`${C.green}Snapshot written${C.reset} ${result.path}`);
|
|
51
|
+
console.log(` ${mb(result.bytes)} in ${result.ms}ms, integrity verified`);
|
|
52
|
+
if (result.pruned.length) {
|
|
53
|
+
console.log(` ${C.dim}pruned ${result.pruned.length} older snapshot(s) per retention policy${C.reset}`);
|
|
54
|
+
}
|
|
55
|
+
} catch (e: any) {
|
|
56
|
+
console.error(`${C.red}Backup failed:${C.reset} ${e?.message ?? e}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
program
|
|
62
|
+
.command("restore")
|
|
63
|
+
.description("Restore the PPM config database from a snapshot")
|
|
64
|
+
.argument("[backup]", "Snapshot filename or path (default: the newest one)")
|
|
65
|
+
.option("--list", "List available snapshots and exit")
|
|
66
|
+
.option("--force", "Restore even while PPM is running (stop it first when you can)")
|
|
67
|
+
.option("--json", "Output as JSON")
|
|
68
|
+
.action(async (backupArg: string | undefined, options: { list?: boolean; force?: boolean; json?: boolean }) => {
|
|
69
|
+
try {
|
|
70
|
+
const { listBackups, activeDbStem } = await import("../../services/db-backup/db-backup.service.ts");
|
|
71
|
+
const { getBackupsDir } = await import("../../services/db-backup/db-backup-paths.ts");
|
|
72
|
+
const { restoreDb, resolveBackupArg } = await import("../../services/db-backup/db-backup-restore.ts");
|
|
73
|
+
const { getDbPath } = await import("../../services/db.service.ts");
|
|
74
|
+
|
|
75
|
+
const stem = await activeDbStem();
|
|
76
|
+
const entries = listBackups(stem);
|
|
77
|
+
|
|
78
|
+
if (options.list) {
|
|
79
|
+
if (options.json) {
|
|
80
|
+
console.log(JSON.stringify(entries, null, 2));
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (entries.length === 0) {
|
|
84
|
+
console.log(`${C.yellow}No snapshots in ${getBackupsDir()}${C.reset}`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
console.log(`${C.bold}Snapshots in ${getBackupsDir()}${C.reset}`);
|
|
88
|
+
for (const e of entries) {
|
|
89
|
+
console.log(` ${C.cyan}${e.name}${C.reset} ${mb(e.bytes)} ${C.dim}${e.reason}, ${ago(e.date)}${C.reset}`);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const target = backupArg
|
|
95
|
+
? resolveBackupArg(backupArg, getBackupsDir())
|
|
96
|
+
: entries[0]?.path;
|
|
97
|
+
if (!target) {
|
|
98
|
+
console.error(`${C.red}No snapshot to restore${C.reset} — nothing in ${getBackupsDir()}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const result = restoreDb(target, { dbPath: getDbPath(), force: options.force });
|
|
104
|
+
if (options.json) {
|
|
105
|
+
console.log(JSON.stringify(result, null, 2));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log(`${C.green}Restored${C.reset} ${result.dbPath} (${mb(result.bytes)})`);
|
|
109
|
+
console.log(` from ${result.restoredFrom}`);
|
|
110
|
+
if (result.archivedTo) {
|
|
111
|
+
console.log(` ${C.dim}previous database kept at ${result.archivedTo}${C.reset}`);
|
|
112
|
+
}
|
|
113
|
+
console.log(` ${C.dim}start PPM with: ppm start${C.reset}`);
|
|
114
|
+
} catch (e: any) {
|
|
115
|
+
console.error(`${C.red}Restore failed:${C.reset} ${e?.message ?? e}`);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -154,6 +154,9 @@ export async function buildProgram(): Promise<Command> {
|
|
|
154
154
|
const { registerDbCommands } = await import("./cli/commands/db-cmd.ts");
|
|
155
155
|
registerDbCommands(program);
|
|
156
156
|
|
|
157
|
+
const { registerBackupCommands } = await import("./cli/commands/backup-cmd.ts");
|
|
158
|
+
registerBackupCommands(program);
|
|
159
|
+
|
|
157
160
|
const { registerBotCommands } = await import("./cli/commands/bot-cmd.ts");
|
|
158
161
|
registerBotCommands(program);
|
|
159
162
|
|
|
@@ -20,7 +20,8 @@ import { configService } from "../services/config.service.ts";
|
|
|
20
20
|
import { mcpConfigService } from "../services/mcp-config.service.ts";
|
|
21
21
|
import { listInheritedClaudeMcpServers } from "../services/claude-code-mcp.service.ts";
|
|
22
22
|
import { updateFromSdkEvent } from "../services/claude-usage.service.ts";
|
|
23
|
-
import { getSessionProjectPath, setSessionMetadata, getSessionTitles, insertTurnUsage } from "../services/db.service.ts";
|
|
23
|
+
import { getSessionProjectPath, setSessionMetadata, getSessionTitles, insertTurnUsage, getSessionAccount } from "../services/db.service.ts";
|
|
24
|
+
import { SUBSCRIPTION_PROMPT_CACHE_TTL_MS, API_KEY_PROMPT_CACHE_TTL_MS } from "../services/subprocess-retention.ts";
|
|
24
25
|
import { buildTurnUsage, formatTurnUsageLog } from "../shared/turn-usage.ts";
|
|
25
26
|
import { accountSelector } from "../services/account-selector.service.ts";
|
|
26
27
|
import { accountService, type AccountWithTokens } from "../services/account.service.ts";
|
|
@@ -761,6 +762,33 @@ export class ClaudeAgentSdkProvider implements AIProvider {
|
|
|
761
762
|
return this.streamingSessions.has(sessionId);
|
|
762
763
|
}
|
|
763
764
|
|
|
765
|
+
/**
|
|
766
|
+
* How long this session's prompt cache is worth holding a subprocess for.
|
|
767
|
+
*
|
|
768
|
+
* The hour only applies to a Claude subscription; an API key — settings `api_key`, a shell
|
|
769
|
+
* key, or anything behind a custom `base_url` — gets five minutes. Mirrors
|
|
770
|
+
* `buildQueryEnv`'s precedence, since that is what actually decides how the subprocess
|
|
771
|
+
* authenticates: settings api_key first, then the session's account, then the shell.
|
|
772
|
+
*/
|
|
773
|
+
promptCacheTtlMs(sessionId: string): number {
|
|
774
|
+
const cfg = this.getProviderConfig();
|
|
775
|
+
// A custom endpoint is not Anthropic's subscription API whatever the credential is.
|
|
776
|
+
const shellBaseUrl = process.env.ANTHROPIC_BASE_URL ?? "";
|
|
777
|
+
if (cfg.base_url || (shellBaseUrl && !shellBaseUrl.includes("/proxy"))) {
|
|
778
|
+
return API_KEY_PROMPT_CACHE_TTL_MS;
|
|
779
|
+
}
|
|
780
|
+
if (cfg.api_key?.trim()) return API_KEY_PROMPT_CACHE_TTL_MS;
|
|
781
|
+
|
|
782
|
+
const accountId = getSessionAccount(sessionId);
|
|
783
|
+
const token = accountId ? accountService.getWithTokens(accountId)?.accessToken : undefined;
|
|
784
|
+
if (token) return token.startsWith("sk-ant-oat") ? SUBSCRIPTION_PROMPT_CACHE_TTL_MS : API_KEY_PROMPT_CACHE_TTL_MS;
|
|
785
|
+
|
|
786
|
+
// No account recorded yet: the shell's own credentials decide, and an OAuth token there
|
|
787
|
+
// is still a subscription. Nothing at all means the CLI's own auth, which we cannot
|
|
788
|
+
// classify — take the short window rather than hold memory on a guess.
|
|
789
|
+
return process.env.CLAUDE_CODE_OAUTH_TOKEN ? SUBSCRIPTION_PROMPT_CACHE_TTL_MS : API_KEY_PROMPT_CACHE_TTL_MS;
|
|
790
|
+
}
|
|
791
|
+
|
|
764
792
|
async *sendMessage(
|
|
765
793
|
_sessionId: string,
|
|
766
794
|
message: string,
|
package/src/server/index.ts
CHANGED
|
@@ -30,6 +30,8 @@ import { chatWebSocket } from "./ws/chat.ts";
|
|
|
30
30
|
import { extensionWebSocket } from "./ws/extensions.ts";
|
|
31
31
|
import { globalWebSocket } from "./ws/global.ts";
|
|
32
32
|
import { groupChatWebSocket } from "./ws/group-chat.ts";
|
|
33
|
+
import { remoteDesktopWebSocket } from "./ws/remote-desktop.ts";
|
|
34
|
+
import { isRemoteDesktopEnabled } from "../services/remote-desktop/remote-desktop-flag.ts";
|
|
33
35
|
import { ok, err } from "../types/api.ts";
|
|
34
36
|
|
|
35
37
|
/** Tee console.log/error to ~/.ppm/ppm.log while preserving terminal output */
|
|
@@ -175,6 +177,10 @@ app.route("/api/system", resourceRoutes);
|
|
|
175
177
|
import { hostInfoRoutes } from "./routes/host-info.ts";
|
|
176
178
|
app.route("/api/system", hostInfoRoutes);
|
|
177
179
|
|
|
180
|
+
// Remote desktop (video capture + input) — feature-flagged off by default, see remote-desktop-flag.ts
|
|
181
|
+
import { remoteDesktopRoutes } from "./routes/remote-desktop.ts";
|
|
182
|
+
app.route("/api/remote-desktop", remoteDesktopRoutes);
|
|
183
|
+
|
|
178
184
|
// Finishes an OAuth loopback login started from another device
|
|
179
185
|
import { loopbackRoutes } from "./routes/oauth-loopback.ts";
|
|
180
186
|
app.route("/api/loopback", loopbackRoutes);
|
|
@@ -860,6 +866,20 @@ if (process.argv.includes("__serve__")) {
|
|
|
860
866
|
return new Response("WebSocket upgrade failed", { status: 400 });
|
|
861
867
|
}
|
|
862
868
|
|
|
869
|
+
if (url.pathname === "/ws/remote-desktop") {
|
|
870
|
+
// Explicit branch so this socket can never fall through to the terminal (shell)
|
|
871
|
+
// handler's default case. Feature flag + `auth.enabled` are re-checked here
|
|
872
|
+
// independently of `isWsUpgradeAuthorized` above, which returns true unconditionally
|
|
873
|
+
// when PPM auth is disabled — a live keyboard/mouse channel must not inherit that.
|
|
874
|
+
if (!isRemoteDesktopEnabled()) return new Response("Not Found", { status: 404 });
|
|
875
|
+
if (!configService.get("auth").enabled) {
|
|
876
|
+
return new Response("Forbidden: remote desktop requires PPM authentication to be enabled", { status: 403 });
|
|
877
|
+
}
|
|
878
|
+
const upgraded = server.upgrade(req, { data: { type: "remote-desktop" } });
|
|
879
|
+
if (upgraded) return undefined;
|
|
880
|
+
return new Response("WebSocket upgrade failed", { status: 400 });
|
|
881
|
+
}
|
|
882
|
+
|
|
863
883
|
if (url.pathname.startsWith("/ws/project/")) {
|
|
864
884
|
const parts = url.pathname.split("/");
|
|
865
885
|
const projectName = decodeURIComponent(parts[3] ?? "");
|
|
@@ -901,25 +921,32 @@ if (process.argv.includes("__serve__")) {
|
|
|
901
921
|
sendPong: true,
|
|
902
922
|
perMessageDeflate: false,
|
|
903
923
|
open(ws: any) {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
else if (
|
|
907
|
-
else if (
|
|
908
|
-
else
|
|
924
|
+
const t = ws.data?.type;
|
|
925
|
+
if (t === "chat") chatWebSocket.open(ws);
|
|
926
|
+
else if (t === "group") groupChatWebSocket.open(ws);
|
|
927
|
+
else if (t === "extensions") extensionWebSocket.open(ws);
|
|
928
|
+
else if (t === "global") globalWebSocket.open(ws);
|
|
929
|
+
else if (t === "remote-desktop") remoteDesktopWebSocket.open(ws);
|
|
930
|
+
else if (t === "terminal") terminalWebSocket.open(ws);
|
|
931
|
+
else ws.close(1008, "unknown socket type");
|
|
909
932
|
},
|
|
910
933
|
message(ws: any, msg: any) {
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
else if (
|
|
914
|
-
else if (
|
|
915
|
-
else
|
|
934
|
+
const t = ws.data?.type;
|
|
935
|
+
if (t === "chat") chatWebSocket.message(ws, msg);
|
|
936
|
+
else if (t === "group") groupChatWebSocket.message(ws, msg);
|
|
937
|
+
else if (t === "extensions") extensionWebSocket.message(ws, msg);
|
|
938
|
+
else if (t === "global") globalWebSocket.message(ws, msg);
|
|
939
|
+
else if (t === "remote-desktop") remoteDesktopWebSocket.message(ws, msg);
|
|
940
|
+
else if (t === "terminal") terminalWebSocket.message(ws, msg);
|
|
916
941
|
},
|
|
917
942
|
close(ws: any) {
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
else if (
|
|
921
|
-
else if (
|
|
922
|
-
else
|
|
943
|
+
const t = ws.data?.type;
|
|
944
|
+
if (t === "chat") chatWebSocket.close(ws);
|
|
945
|
+
else if (t === "group") groupChatWebSocket.close(ws);
|
|
946
|
+
else if (t === "extensions") extensionWebSocket.close(ws);
|
|
947
|
+
else if (t === "global") globalWebSocket.close(ws);
|
|
948
|
+
else if (t === "remote-desktop") remoteDesktopWebSocket.close(ws);
|
|
949
|
+
else if (t === "terminal") terminalWebSocket.close(ws);
|
|
923
950
|
},
|
|
924
951
|
} as Parameters<typeof Bun.serve>[0] extends { websocket?: infer W } ? W : never,
|
|
925
952
|
});
|
|
@@ -376,8 +376,36 @@ accountsRoutes.patch("/:id", async (c) => {
|
|
|
376
376
|
const body = await c.req.json<{ status?: string }>();
|
|
377
377
|
try {
|
|
378
378
|
if (body.status === "disabled") accountService.setDisabled(id);
|
|
379
|
-
else if (body.status === "active")
|
|
380
|
-
|
|
379
|
+
else if (body.status === "active") {
|
|
380
|
+
const wasParked = accountService.list().find((a) => a.id === id)?.status === "disabled";
|
|
381
|
+
// Enabling is where this machine claims the token, so prove it *before* the account
|
|
382
|
+
// becomes selectable rather than after. postRefreshGrant is three 15s attempts with
|
|
383
|
+
// 2s and 6s backoff between them — 53s worst case — so enabling first would leave the
|
|
384
|
+
// account active with an unproven token for most of a minute, long enough for
|
|
385
|
+
// accountSelector.next() or the proxy to pick it, and the re-park would land only
|
|
386
|
+
// after that turn had already failed. Refreshing while still
|
|
387
|
+
// parked needs no rollback at all: on failure setEnabled() simply never runs.
|
|
388
|
+
//
|
|
389
|
+
// Only for an account that has a refresh token: a temporary one has nothing to prove,
|
|
390
|
+
// and setEnabled()'s own guard says something more useful than a refresh error would.
|
|
391
|
+
if (wasParked && accountService.hasRefreshToken(id)) {
|
|
392
|
+
const proof = await accountService.ensureFreshTokenChecked(id);
|
|
393
|
+
if (!proof.account) {
|
|
394
|
+
// Worth splitting: invalid_grant means the token is gone and only a fresh sign-in
|
|
395
|
+
// brings it back, while a network drop or a 429 is worth trying again in a minute.
|
|
396
|
+
// Telling someone to re-authenticate because their wifi blinked is a bad trade.
|
|
397
|
+
return c.json(
|
|
398
|
+
err(
|
|
399
|
+
proof.rejected
|
|
400
|
+
? "This account's login was rejected — it stays disabled. Sign in again to give it a live token, then enable it."
|
|
401
|
+
: "Could not reach Anthropic to check this account — it stays disabled. Try again in a moment.",
|
|
402
|
+
),
|
|
403
|
+
400,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
accountService.setEnabled(id);
|
|
408
|
+
} else return c.json(err("status must be active or disabled"), 400);
|
|
381
409
|
} catch (e) {
|
|
382
410
|
return c.json(err((e as Error).message), 400);
|
|
383
411
|
}
|
|
@@ -802,7 +802,7 @@ chatRoutes.post("/sessions/:id/images/strip", async (c) => {
|
|
|
802
802
|
const mode: StripMode = (body as { mode?: unknown }).mode === "all" ? "all" : "oversized";
|
|
803
803
|
const includeAttachments = (body as { includeAttachments?: unknown }).includeAttachments === true;
|
|
804
804
|
|
|
805
|
-
const { listRunningSessions } = await import("../ws/chat.ts");
|
|
805
|
+
const { listRunningSessions, dropSubprocessForTranscriptRewrite } = await import("../ws/chat.ts");
|
|
806
806
|
if (listRunningSessions().some((s) => s.sessionId === sessionId)) {
|
|
807
807
|
return c.json(err("Session is running — wait for the turn to finish"), 409);
|
|
808
808
|
}
|
|
@@ -810,6 +810,13 @@ chatRoutes.post("/sessions/:id/images/strip", async (c) => {
|
|
|
810
810
|
const found = locateTranscript(sessionId);
|
|
811
811
|
if ("error" in found) return c.json(err(found.error), found.status);
|
|
812
812
|
|
|
813
|
+
// A subprocess that is merely idle is not "running", but it still holds the conversation
|
|
814
|
+
// in memory — including the image being stripped. Leaving it alive means the next turn
|
|
815
|
+
// re-sends the oversized attachment from memory and fails exactly as before, which is the
|
|
816
|
+
// failure this endpoint exists to clear. Drop it so the turn is rebuilt from the file we
|
|
817
|
+
// are about to rewrite.
|
|
818
|
+
dropSubprocessForTranscriptRewrite(sessionId);
|
|
819
|
+
|
|
813
820
|
const result = await stripTranscriptImagesFile(found.path, mode, { includeAttachments });
|
|
814
821
|
return c.json(ok({
|
|
815
822
|
removed: result.removed,
|
|
@@ -28,9 +28,12 @@ function assertMutationAllowed(c: Context): Response | null {
|
|
|
28
28
|
}
|
|
29
29
|
const origin = c.req.header("origin");
|
|
30
30
|
if (origin) {
|
|
31
|
+
// Compare hostname only, not host:port: a 2-process dev setup (Vite proxy rewrites
|
|
32
|
+
// Host without X-Forwarded-Host) always differs by port, so a full-host compare rejects
|
|
33
|
+
// every dev request. Origin is browser-set, so a real cross-site attacker still can't forge it.
|
|
31
34
|
let originHost: string | null = null;
|
|
32
|
-
try { originHost = new URL(origin).
|
|
33
|
-
const requestHost = new URL(c.req.url).
|
|
35
|
+
try { originHost = new URL(origin).hostname; } catch { originHost = null; }
|
|
36
|
+
const requestHost = new URL(c.req.url).hostname;
|
|
34
37
|
if (!originHost || originHost !== requestHost) {
|
|
35
38
|
return c.json(err("cross-origin request rejected"), 403);
|
|
36
39
|
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /api/remote-desktop/capabilities` (read-only, always answerable) and
|
|
3
|
+
* `POST /api/remote-desktop/session` (mints the single-use WS nonce). Guard style mirrors
|
|
4
|
+
* `named-tunnel.ts`: `authMiddleware` already passes every request through when PPM auth is
|
|
5
|
+
* disabled, so a feature that hands out host control must enforce `auth.enabled` itself, plus
|
|
6
|
+
* a same-origin check so a foreign page can't drive it via ambient browser credentials.
|
|
7
|
+
*/
|
|
8
|
+
import { Hono, type Context } from "hono";
|
|
9
|
+
import { ok, err } from "../../types/api.ts";
|
|
10
|
+
import { configService } from "../../services/config.service.ts";
|
|
11
|
+
import { getFfmpegCapabilities } from "../../services/media-transcode/ffmpeg-capabilities.ts";
|
|
12
|
+
import { isRemoteDesktopEnabled } from "../../services/remote-desktop/remote-desktop-flag.ts";
|
|
13
|
+
import { mintRemoteDesktopNonce } from "../../services/remote-desktop/remote-desktop-nonce.ts";
|
|
14
|
+
import { isInputAvailable } from "../../services/remote-desktop/remote-desktop-input.ts";
|
|
15
|
+
|
|
16
|
+
export const remoteDesktopRoutes = new Hono();
|
|
17
|
+
|
|
18
|
+
function assertSessionAllowed(c: Context): Response | null {
|
|
19
|
+
if (!isRemoteDesktopEnabled()) {
|
|
20
|
+
return c.json(err("remote desktop is disabled (set REMOTE_DESKTOP_ENABLED=1)"), 404);
|
|
21
|
+
}
|
|
22
|
+
if (!configService.get("auth").enabled) {
|
|
23
|
+
return c.json(err("remote desktop requires PPM authentication to be enabled"), 403);
|
|
24
|
+
}
|
|
25
|
+
const origin = c.req.header("origin");
|
|
26
|
+
if (origin) {
|
|
27
|
+
// Compare *hostname* only, not host:port. `named-tunnel.ts`'s copy of this check compares
|
|
28
|
+
// the full `host` (hostname:port), which only ever matches when the browser's page and the
|
|
29
|
+
// API it's calling share one origin verbatim — true for the compiled/production build (one
|
|
30
|
+
// server, one port) but NOT for the standard two-process dev topology (`bun dev:web` on
|
|
31
|
+
// 5173 proxying to `bun dev:server` on 8081, or this feature's own alt-port test setup):
|
|
32
|
+
// Vite's dev proxy rewrites the `Host` header to the proxy target's port without adding
|
|
33
|
+
// `X-Forwarded-Host`, so the backend always sees a different port than the browser's real
|
|
34
|
+
// `Origin` — the full-host check would reject every dev-mode session request. A real
|
|
35
|
+
// cross-origin attacker (e.g. evil.com) cannot spoof `Origin` to say `localhost` in the
|
|
36
|
+
// first place — the browser sets it from the page's actual origin — so relaxing port
|
|
37
|
+
// equality does not weaken the protection this check exists for.
|
|
38
|
+
let originHost: string | null = null;
|
|
39
|
+
try { originHost = new URL(origin).hostname; } catch { originHost = null; }
|
|
40
|
+
let requestHost: string | null = null;
|
|
41
|
+
try { requestHost = new URL(c.req.url).hostname; } catch { requestHost = null; }
|
|
42
|
+
if (!originHost || !requestHost || originHost !== requestHost) {
|
|
43
|
+
return c.json(err("cross-origin request rejected"), 403);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
remoteDesktopRoutes.get("/capabilities", async (c) => {
|
|
50
|
+
if (!isRemoteDesktopEnabled()) return c.json(err("remote desktop is disabled"), 404);
|
|
51
|
+
const caps = await getFfmpegCapabilities();
|
|
52
|
+
return c.json(ok({
|
|
53
|
+
ffmpegAvailable: !!caps.ffmpeg,
|
|
54
|
+
videoAvailable: process.platform === "win32" && !!caps.ffmpeg,
|
|
55
|
+
inputAvailable: isInputAvailable(),
|
|
56
|
+
authRequired: configService.get("auth").enabled,
|
|
57
|
+
}));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
remoteDesktopRoutes.post("/session", (c) => {
|
|
61
|
+
const rejected = assertSessionAllowed(c);
|
|
62
|
+
if (rejected) return rejected;
|
|
63
|
+
return c.json(ok({ nonce: mintRemoteDesktopNonce(), wsPath: "/ws/remote-desktop" }));
|
|
64
|
+
});
|
|
@@ -114,6 +114,7 @@ const UI_PREF_VALIDATORS: Record<string, (v: unknown) => boolean> = {
|
|
|
114
114
|
wordWrap: (v) => typeof v === "boolean",
|
|
115
115
|
tabWrap: (v) => typeof v === "boolean",
|
|
116
116
|
sidebarCollapsed: (v) => typeof v === "boolean",
|
|
117
|
+
remoteDesktopStatsVisible: (v) => typeof v === "boolean",
|
|
117
118
|
sidebarWidth: (v) => typeof v === "number" && v >= 200 && v <= 600,
|
|
118
119
|
gitStatusViewMode: (v) => v === "flat" || v === "tree",
|
|
119
120
|
editorTabStyle: (v) => v === "default" || v === "boxed" || v === "pill",
|