@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
|
@@ -5,11 +5,13 @@
|
|
|
5
5
|
* session JSONL (no isSidechain lines, no parent_tool_use_id). Instead each
|
|
6
6
|
* agent gets its own transcript at:
|
|
7
7
|
* ~/.claude/projects/<slug>/<sessionId>/subagents/agent-<id>.jsonl
|
|
8
|
-
* with a sibling agent-<id>.meta.json carrying the spawning Agent tool_use id
|
|
8
|
+
* with a sibling agent-<id>.meta.json carrying the spawning Agent tool_use id
|
|
9
|
+
* (session-spawned agents) or the spawning agent's id (nested agents).
|
|
9
10
|
*
|
|
10
11
|
* Without merging these, a reloaded session shows bare Agent cards and the
|
|
11
|
-
* live-streamed children are lost. This module
|
|
12
|
-
*
|
|
12
|
+
* live-streamed children are lost. This module groups the transcripts under
|
|
13
|
+
* their session-level card, parses each one, and attaches the events — every
|
|
14
|
+
* nesting level flattened into one time-ordered list — as the card's children.
|
|
13
15
|
*/
|
|
14
16
|
|
|
15
17
|
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
@@ -17,18 +19,20 @@ import { homedir } from "node:os";
|
|
|
17
19
|
import { join } from "node:path";
|
|
18
20
|
import type { ChatEvent } from "../types/chat.ts";
|
|
19
21
|
import { parseSessionMessage } from "./jsonl-transcript-parser.ts";
|
|
22
|
+
import { groupSubagentsByCard } from "./team-member-activity/subagent-transcript-index.ts";
|
|
20
23
|
|
|
21
24
|
/**
|
|
22
25
|
* Locate the per-session directory (…/projects/<slug>/<sessionId>) that holds
|
|
23
|
-
* subagents/. The SDK encodes the cwd by replacing separators
|
|
24
|
-
* with "-"
|
|
25
|
-
*
|
|
26
|
+
* subagents/. The SDK encodes the cwd by replacing separators, drive colon
|
|
27
|
+
* and dots with "-" (`…\ppm\.claude\worktrees\x` → `…-ppm--claude-worktrees-x`);
|
|
28
|
+
* when that drifts (drive-letter case), fall back to scanning project dirs for
|
|
29
|
+
* the session's main JSONL.
|
|
26
30
|
*/
|
|
27
31
|
export function resolveSessionDir(sessionId: string, projectPath: string | null | undefined): string | null {
|
|
28
32
|
const home = homedir();
|
|
29
33
|
const projectsRoot = join(home, ".claude", "projects");
|
|
30
34
|
if (projectPath) {
|
|
31
|
-
const encoded = projectPath.replace(/[
|
|
35
|
+
const encoded = projectPath.replace(/[/\\:.]/g, "-");
|
|
32
36
|
const dir = join(projectsRoot, encoded);
|
|
33
37
|
if (existsSync(join(dir, `${sessionId}.jsonl`))) return join(dir, sessionId);
|
|
34
38
|
}
|
|
@@ -53,92 +57,105 @@ interface MessageLike {
|
|
|
53
57
|
const MAX_CHILDREN_PER_AGENT = 2000;
|
|
54
58
|
const MAX_CHILD_OUTPUT_CHARS = 50_000;
|
|
55
59
|
|
|
56
|
-
/**
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
try {
|
|
61
|
-
entries = readdirSync(subagentsDir);
|
|
62
|
-
} catch {
|
|
63
|
-
return map;
|
|
64
|
-
}
|
|
65
|
-
for (const name of entries) {
|
|
66
|
-
if (!name.endsWith(".meta.json")) continue;
|
|
67
|
-
try {
|
|
68
|
-
const meta = JSON.parse(readFileSync(join(subagentsDir, name), "utf8"));
|
|
69
|
-
const toolUseId = meta?.toolUseId as string | undefined;
|
|
70
|
-
if (!toolUseId) continue;
|
|
71
|
-
const transcript = join(subagentsDir, name.replace(/\.meta\.json$/, ".jsonl"));
|
|
72
|
-
if (existsSync(transcript)) map.set(toolUseId, transcript);
|
|
73
|
-
} catch {
|
|
74
|
-
/* unreadable meta — skip this agent */
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return map;
|
|
60
|
+
/** One child event plus the transcript record time it came from (epoch ms). */
|
|
61
|
+
export interface TimedChatEvent {
|
|
62
|
+
ts: number;
|
|
63
|
+
ev: ChatEvent;
|
|
78
64
|
}
|
|
79
65
|
|
|
80
|
-
/**
|
|
81
|
-
|
|
82
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Incremental parser for one agent transcript. Feed it JSONL lines in file
|
|
68
|
+
* order (whole file at once, or a live tail's new lines) and it returns the
|
|
69
|
+
* child events those lines carry, keeping the skip/limit state across calls.
|
|
70
|
+
*/
|
|
71
|
+
export function createAgentTranscriptLineParser() {
|
|
72
|
+
let isFirstUser = true;
|
|
73
|
+
let emitted = 0;
|
|
74
|
+
let lastTs = 0;
|
|
75
|
+
return {
|
|
76
|
+
feed(line: string): TimedChatEvent[] {
|
|
77
|
+
const out: TimedChatEvent[] = [];
|
|
78
|
+
const trimmed = line.trim();
|
|
79
|
+
if (!trimmed || emitted >= MAX_CHILDREN_PER_AGENT) return out;
|
|
80
|
+
let entry: any;
|
|
81
|
+
try {
|
|
82
|
+
entry = JSON.parse(trimmed);
|
|
83
|
+
} catch {
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
if (entry.type !== "user" && entry.type !== "assistant") return out;
|
|
87
|
+
if (!entry.message) return out;
|
|
88
|
+
// The first user record is the agent's spawn prompt — the live stream
|
|
89
|
+
// never showed it as a child, so skip it to match the streaming view.
|
|
90
|
+
if (entry.type === "user" && isFirstUser) {
|
|
91
|
+
isFirstUser = false;
|
|
92
|
+
const content = entry.message?.content;
|
|
93
|
+
const hasToolResult = Array.isArray(content) && content.some((b: any) => b?.type === "tool_result");
|
|
94
|
+
if (!hasToolResult) return out;
|
|
95
|
+
}
|
|
96
|
+
// Records without a timestamp inherit the previous one so file order holds.
|
|
97
|
+
const parsedTs = typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
|
|
98
|
+
if (!Number.isNaN(parsedTs)) lastTs = parsedTs;
|
|
99
|
+
const parsed = parseSessionMessage(entry);
|
|
100
|
+
for (const ev of parsed.events ?? []) {
|
|
101
|
+
if (emitted >= MAX_CHILDREN_PER_AGENT) break;
|
|
102
|
+
// Keep single events from ballooning the history payload (agent files
|
|
103
|
+
// can carry multi-MB tool outputs the live stream also showed in full,
|
|
104
|
+
// but 24 agents × full outputs breaks mobile reloads).
|
|
105
|
+
if (ev.type === "tool_result" && typeof ev.output === "string" && ev.output.length > MAX_CHILD_OUTPUT_CHARS) {
|
|
106
|
+
ev.output = ev.output.slice(0, MAX_CHILD_OUTPUT_CHARS) + "\n… [truncated]";
|
|
107
|
+
}
|
|
108
|
+
out.push({ ts: lastTs, ev });
|
|
109
|
+
emitted++;
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Parse one whole agent transcript into timed child events (file order). */
|
|
117
|
+
export function parseAgentTranscriptTimed(filePath: string): TimedChatEvent[] {
|
|
83
118
|
let text: string;
|
|
84
119
|
try {
|
|
85
120
|
text = readFileSync(filePath, "utf8");
|
|
86
121
|
} catch {
|
|
87
|
-
return
|
|
88
|
-
}
|
|
89
|
-
let isFirstUser = true;
|
|
90
|
-
for (const line of text.split("\n")) {
|
|
91
|
-
const trimmed = line.trim();
|
|
92
|
-
if (!trimmed) continue;
|
|
93
|
-
let entry: any;
|
|
94
|
-
try {
|
|
95
|
-
entry = JSON.parse(trimmed);
|
|
96
|
-
} catch {
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
if (entry.type !== "user" && entry.type !== "assistant") continue;
|
|
100
|
-
if (!entry.message) continue;
|
|
101
|
-
if (children.length >= MAX_CHILDREN_PER_AGENT) break;
|
|
102
|
-
// The first user record is the agent's spawn prompt — the live stream
|
|
103
|
-
// never showed it as a child, so skip it to match the streaming view.
|
|
104
|
-
if (entry.type === "user" && isFirstUser) {
|
|
105
|
-
isFirstUser = false;
|
|
106
|
-
const content = entry.message?.content;
|
|
107
|
-
const hasToolResult = Array.isArray(content) && content.some((b: any) => b?.type === "tool_result");
|
|
108
|
-
if (!hasToolResult) continue;
|
|
109
|
-
}
|
|
110
|
-
const parsed = parseSessionMessage(entry);
|
|
111
|
-
for (const ev of parsed.events ?? []) {
|
|
112
|
-
// Keep single events from ballooning the history payload (agent files
|
|
113
|
-
// can carry multi-MB tool outputs the live stream also showed in full,
|
|
114
|
-
// but 24 agents × full outputs breaks mobile reloads).
|
|
115
|
-
if (ev.type === "tool_result" && typeof ev.output === "string" && ev.output.length > MAX_CHILD_OUTPUT_CHARS) {
|
|
116
|
-
ev.output = ev.output.slice(0, MAX_CHILD_OUTPUT_CHARS) + "\n… [truncated]";
|
|
117
|
-
}
|
|
118
|
-
children.push(ev);
|
|
119
|
-
}
|
|
122
|
+
return [];
|
|
120
123
|
}
|
|
121
|
-
|
|
124
|
+
const parser = createAgentTranscriptLineParser();
|
|
125
|
+
const out: TimedChatEvent[] = [];
|
|
126
|
+
for (const line of text.split("\n")) out.push(...parser.feed(line));
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/** Parse one agent transcript into a flat children event list (stream order). */
|
|
131
|
+
export function parseAgentTranscript(filePath: string): ChatEvent[] {
|
|
132
|
+
return parseAgentTranscriptTimed(filePath).map((t) => t.ev);
|
|
122
133
|
}
|
|
123
134
|
|
|
124
135
|
/**
|
|
125
136
|
* Attach subagent transcript events as children of their Agent/Task cards.
|
|
126
137
|
* `sessionDir` is the per-session directory next to the main JSONL
|
|
127
|
-
* (…/projects/<slug>/<sessionId>).
|
|
128
|
-
*
|
|
129
|
-
*
|
|
138
|
+
* (…/projects/<slug>/<sessionId>). A card's group — the agent it spawned plus
|
|
139
|
+
* any agents that one spawned in turn — is merged into one list ordered by
|
|
140
|
+
* record time, so a nested worker's steps read where they happened rather
|
|
141
|
+
* than after the parent agent's conclusion. Existing children are replaced —
|
|
142
|
+
* the disk transcripts are the complete record, while live-collected children
|
|
143
|
+
* may be a partial overlap. Mutates messages in-place.
|
|
130
144
|
*/
|
|
131
145
|
export function mergeSubagentChildren(sessionDir: string, messages: MessageLike[]): void {
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
146
|
+
const groups = groupSubagentsByCard(join(sessionDir, "subagents"));
|
|
147
|
+
if (groups.size === 0) return;
|
|
134
148
|
|
|
135
149
|
for (const msg of messages) {
|
|
136
150
|
for (const ev of msg.events ?? []) {
|
|
137
151
|
if (ev.type !== "tool_use" || (ev.tool !== "Agent" && ev.tool !== "Task") || !ev.toolUseId) continue;
|
|
138
|
-
const
|
|
139
|
-
if (!
|
|
140
|
-
const
|
|
141
|
-
|
|
152
|
+
const group = groups.get(ev.toolUseId);
|
|
153
|
+
if (!group) continue;
|
|
154
|
+
const timed: TimedChatEvent[] = [];
|
|
155
|
+
for (const agent of group) timed.push(...parseAgentTranscriptTimed(agent.transcriptPath));
|
|
156
|
+
// Stable sort: same-timestamp events keep transcript order.
|
|
157
|
+
timed.sort((a, b) => a.ts - b.ts);
|
|
158
|
+
if (timed.length > 0) ev.children = timed.map((t) => t.ev);
|
|
142
159
|
}
|
|
143
160
|
}
|
|
144
161
|
}
|
|
@@ -13,13 +13,36 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
|
-
* Anthropic's
|
|
17
|
-
*
|
|
16
|
+
* Anthropic's prompt-cache lifetime, per auth mode. From the SDK's own typings: "1 hour on a
|
|
17
|
+
* Claude subscription within its usage limits, 5 minutes on an API key, Bedrock, Vertex or
|
|
18
|
+
* Foundry."
|
|
18
19
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* Both are named here because the retention window is *derived* from whichever applies — the
|
|
21
|
+
* delay was previously equal to the TTL by coincidence, which read as arbitrary.
|
|
22
|
+
*
|
|
23
|
+
* Which one a session gets is not a constant: PPM supports settings `api_key` and a custom
|
|
24
|
+
* `base_url` as first-class options, and "within its usage limits" excludes exactly the
|
|
25
|
+
* accounts the rotation exists for. Holding a subprocess for an hour on an API-key install
|
|
26
|
+
* guards a cache that died at minute five, at ~350MB a session. The provider decides; these
|
|
27
|
+
* are the two values it picks between.
|
|
28
|
+
*/
|
|
29
|
+
export const SUBSCRIPTION_PROMPT_CACHE_TTL_MS = 60 * 60_000;
|
|
30
|
+
export const API_KEY_PROMPT_CACHE_TTL_MS = 5 * 60_000;
|
|
31
|
+
|
|
32
|
+
/** The longer of the two — what a timer that must outlast any cache window has to clear. */
|
|
33
|
+
export const PROMPT_CACHE_TTL_MS = SUBSCRIPTION_PROMPT_CACHE_TTL_MS;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* What a provider that does not state a window gets.
|
|
37
|
+
*
|
|
38
|
+
* The short one, deliberately. `promptCacheTtlMs` is optional on the provider interface, so
|
|
39
|
+
* "no opinion" and "an hour" would otherwise be the same answer — and the providers without
|
|
40
|
+
* an opinion are exactly the ones with no Anthropic prompt cache to protect. Codex reaches
|
|
41
|
+
* this path today: it implements `hasStreamingSession` but not `promptCacheTtlMs`, so an
|
|
42
|
+
* hour here would hold ~350MB per abandoned session guarding a cache it never had. A
|
|
43
|
+
* provider that benefits from the long window says so.
|
|
21
44
|
*/
|
|
22
|
-
|
|
45
|
+
const UNDECLARED_PROMPT_CACHE_TTL_MS = API_KEY_PROMPT_CACHE_TTL_MS;
|
|
23
46
|
|
|
24
47
|
/**
|
|
25
48
|
* Milliseconds until a session's prompt cache lapses.
|
|
@@ -31,7 +54,7 @@ export const PROMPT_CACHE_TTL_MS = 5 * 60_000;
|
|
|
31
54
|
export function cacheReleaseDelayMs(
|
|
32
55
|
lastTurnEndedAt: number | undefined,
|
|
33
56
|
now: number,
|
|
34
|
-
ttlMs: number =
|
|
57
|
+
ttlMs: number = UNDECLARED_PROMPT_CACHE_TTL_MS,
|
|
35
58
|
): number {
|
|
36
59
|
// No completed turn means nothing has been cached, so there is nothing to protect.
|
|
37
60
|
if (lastTurnEndedAt == null) return 0;
|
|
@@ -52,6 +52,9 @@ const TUNNEL_URL_REGEX = /https:\/\/(?!api\.)[a-z0-9-]+\.trycloudflare\.com/;
|
|
|
52
52
|
const NAMED_TUNNEL_READY_REGEX = /Registered tunnel connection/;
|
|
53
53
|
const UPGRADE_CHECK_INTERVAL_MS = 900_000; // 15min
|
|
54
54
|
const UPGRADE_SKIP_INITIAL_MS = 300_000; // 5min delay before first check
|
|
55
|
+
const DB_BACKUP_INTERVAL_MS = 3_600_000; // 1h — the recovery-point target
|
|
56
|
+
const DB_BACKUP_START_DELAY_MS = 30_000; // let the server settle before the first snapshot
|
|
57
|
+
const DB_BACKUP_STALE_WARN_MS = 21_600_000; // 6h — snapshots stopped happening
|
|
55
58
|
const SELF_REPLACE_TIMEOUT_MS = 30_000; // 30s to wait for new supervisor
|
|
56
59
|
const EDGE_PROBE_INTERVAL_MS = 10_000; // the public port is dark while the edge is down — check often
|
|
57
60
|
const SERVER_PORT_MIRROR_TIMEOUT_MS = 30_000; // how long to wait for the server to publish its port
|
|
@@ -127,6 +130,7 @@ let healthTimer: ReturnType<typeof setInterval> | null = null;
|
|
|
127
130
|
let tunnelProbeTimer: ReturnType<typeof setInterval> | null = null;
|
|
128
131
|
let heartbeatTimer: ReturnType<typeof setInterval> | null = null;
|
|
129
132
|
let upgradeCheckTimer: ReturnType<typeof setInterval> | null = null;
|
|
133
|
+
let dbBackupTimer: ReturnType<typeof setInterval> | null = null;
|
|
130
134
|
let upgradeDelayTimer: ReturnType<typeof setTimeout> | null = null;
|
|
131
135
|
let cloudMonitorTimer: ReturnType<typeof setInterval> | null = null;
|
|
132
136
|
let descendantSnapshotTimer: ReturnType<typeof setInterval> | null = null; // win32 only
|
|
@@ -936,6 +940,41 @@ export async function spawnTunnel(port: number, generation: number = ++tunnelGen
|
|
|
936
940
|
return retryTunnelAfterFailure(generation);
|
|
937
941
|
}
|
|
938
942
|
|
|
943
|
+
// ─── Config-database snapshots ─────────────────────────────────────────
|
|
944
|
+
let dbBackupDelayTimer: ReturnType<typeof setTimeout> | null = null;
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* Take one verified snapshot of the config database, then report whether
|
|
948
|
+
* snapshots are keeping up.
|
|
949
|
+
*
|
|
950
|
+
* Failures are logged and swallowed: a backup problem must never take the
|
|
951
|
+
* server down. The staleness warning exists because a silently-failing backup
|
|
952
|
+
* is worse than no backup — it is the state where recovery is believed to be
|
|
953
|
+
* available and is not.
|
|
954
|
+
*/
|
|
955
|
+
async function runDbBackupTick(reason: "hourly" | "start"): Promise<void> {
|
|
956
|
+
if (shuttingDown) return;
|
|
957
|
+
try {
|
|
958
|
+
const { backupDb } = await import("./db-backup/db-backup.service.ts");
|
|
959
|
+
const result = await backupDb(reason);
|
|
960
|
+
const mb = (result.bytes / 1_048_576).toFixed(1);
|
|
961
|
+
const prunedNote = result.pruned.length ? `, pruned ${result.pruned.length}` : "";
|
|
962
|
+
log("INFO", `DB snapshot (${reason}): ${result.path} ${mb}MB in ${result.ms}ms${prunedNote}`);
|
|
963
|
+
} catch (e: any) {
|
|
964
|
+
log("ERROR", `DB snapshot (${reason}) failed: ${e?.message ?? e}`);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
try {
|
|
968
|
+
const { newestBackupAgeMs } = await import("./db-backup/db-backup.service.ts");
|
|
969
|
+
const age = await newestBackupAgeMs();
|
|
970
|
+
if (age === null) {
|
|
971
|
+
log("WARN", "DB snapshot: no backups exist yet — the database is currently unrecoverable");
|
|
972
|
+
} else if (age > DB_BACKUP_STALE_WARN_MS) {
|
|
973
|
+
log("WARN", `DB snapshot: newest backup is ${Math.round(age / 3_600_000)}h old — recovery point is degraded`);
|
|
974
|
+
}
|
|
975
|
+
} catch { /* staleness reporting is advisory only */ }
|
|
976
|
+
}
|
|
977
|
+
|
|
939
978
|
// ─── Health checks ─────────────────────────────────────────────────────
|
|
940
979
|
function startServerHealthCheck() {
|
|
941
980
|
healthTimer = setInterval(async () => {
|
|
@@ -1314,6 +1353,8 @@ async function selfReplace(): Promise<{ success: boolean; error?: string }> {
|
|
|
1314
1353
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
1315
1354
|
if (upgradeCheckTimer) clearInterval(upgradeCheckTimer);
|
|
1316
1355
|
if (upgradeDelayTimer) clearTimeout(upgradeDelayTimer);
|
|
1356
|
+
if (dbBackupTimer) clearInterval(dbBackupTimer);
|
|
1357
|
+
if (dbBackupDelayTimer) clearTimeout(dbBackupDelayTimer);
|
|
1317
1358
|
if (cloudMonitorTimer) clearInterval(cloudMonitorTimer);
|
|
1318
1359
|
// Disconnect Cloud WS so new supervisor can reconnect cleanly
|
|
1319
1360
|
try { const { disconnect } = await import("./cloud-ws.service.ts"); disconnect(); } catch {}
|
|
@@ -1398,6 +1439,8 @@ async function selfReplace(): Promise<{ success: boolean; error?: string }> {
|
|
|
1398
1439
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
1399
1440
|
if (upgradeCheckTimer) clearInterval(upgradeCheckTimer);
|
|
1400
1441
|
if (upgradeDelayTimer) clearTimeout(upgradeDelayTimer);
|
|
1442
|
+
if (dbBackupTimer) clearInterval(dbBackupTimer);
|
|
1443
|
+
if (dbBackupDelayTimer) clearTimeout(dbBackupDelayTimer);
|
|
1401
1444
|
process.exit(0);
|
|
1402
1445
|
}
|
|
1403
1446
|
} catch {}
|
|
@@ -1680,6 +1723,8 @@ export function shutdown() {
|
|
|
1680
1723
|
if (heartbeatTimer) clearInterval(heartbeatTimer);
|
|
1681
1724
|
if (upgradeCheckTimer) clearInterval(upgradeCheckTimer);
|
|
1682
1725
|
if (upgradeDelayTimer) clearTimeout(upgradeDelayTimer);
|
|
1726
|
+
if (dbBackupTimer) clearInterval(dbBackupTimer);
|
|
1727
|
+
if (dbBackupDelayTimer) clearTimeout(dbBackupDelayTimer);
|
|
1683
1728
|
if (cloudMonitorTimer) clearInterval(cloudMonitorTimer);
|
|
1684
1729
|
if (descendantSnapshotTimer) clearInterval(descendantSnapshotTimer);
|
|
1685
1730
|
|
|
@@ -1962,6 +2007,19 @@ export async function runSupervisor(opts: {
|
|
|
1962
2007
|
}
|
|
1963
2008
|
}, RESUME_TICK_MS);
|
|
1964
2009
|
|
|
2010
|
+
// Snapshot the config database on a schedule. The supervisor is the only
|
|
2011
|
+
// always-on process, so this is the one place a periodic snapshot survives
|
|
2012
|
+
// both server restarts and crash-backoff windows.
|
|
2013
|
+
//
|
|
2014
|
+
// The start-up snapshot is not redundant with the hourly one: a machine that
|
|
2015
|
+
// is only powered on for short sessions, or a supervisor that sat paused
|
|
2016
|
+
// after exhausting its restart budget, would otherwise take no snapshot at
|
|
2017
|
+
// all for as long as that lasted.
|
|
2018
|
+
dbBackupDelayTimer = setTimeout(() => {
|
|
2019
|
+
void runDbBackupTick("start");
|
|
2020
|
+
dbBackupTimer = setInterval(() => void runDbBackupTick("hourly"), DB_BACKUP_INTERVAL_MS);
|
|
2021
|
+
}, DB_BACKUP_START_DELAY_MS);
|
|
2022
|
+
|
|
1965
2023
|
// Start upgrade check timer (5min initial delay, then every 15min)
|
|
1966
2024
|
upgradeDelayTimer = setTimeout(() => {
|
|
1967
2025
|
checkAvailableVersion();
|
|
@@ -26,6 +26,15 @@ export interface SubagentTranscriptEntry {
|
|
|
26
26
|
model?: string;
|
|
27
27
|
/** tool_use id of the spawning Agent call — links back to the chat card. */
|
|
28
28
|
toolUseId?: string;
|
|
29
|
+
/** Raw id from the `agent-<id>` file stem — the form `parentAgentId` uses. */
|
|
30
|
+
agentId: string;
|
|
31
|
+
/**
|
|
32
|
+
* agentId of the agent that spawned this one. Set on nested agents (a
|
|
33
|
+
* subagent that itself called Agent/Skill); those metas carry no toolUseId
|
|
34
|
+
* because the spawning tool_use lives in the parent agent's transcript, not
|
|
35
|
+
* the session's.
|
|
36
|
+
*/
|
|
37
|
+
parentAgentId?: string;
|
|
29
38
|
/** Absolute path of the agent's JSONL transcript. */
|
|
30
39
|
transcriptPath: string;
|
|
31
40
|
/** Transcript size in bytes — the cheap "how much work" signal. */
|
|
@@ -69,6 +78,8 @@ export function listSubagentTranscripts(subagentsDir: string): SubagentTranscrip
|
|
|
69
78
|
description: typeof meta.description === "string" ? meta.description : undefined,
|
|
70
79
|
model: typeof meta.model === "string" ? meta.model : undefined,
|
|
71
80
|
toolUseId: typeof meta.toolUseId === "string" ? meta.toolUseId : undefined,
|
|
81
|
+
agentId: file.replace(/^agent-/, "").replace(/\.meta\.json$/, ""),
|
|
82
|
+
parentAgentId: typeof meta.parentAgentId === "string" ? meta.parentAgentId : undefined,
|
|
72
83
|
transcriptPath,
|
|
73
84
|
sizeBytes,
|
|
74
85
|
modifiedAt,
|
|
@@ -77,6 +88,51 @@ export function listSubagentTranscripts(subagentsDir: string): SubagentTranscrip
|
|
|
77
88
|
return out;
|
|
78
89
|
}
|
|
79
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Group every transcript under the session-level Agent card it belongs to.
|
|
93
|
+
*
|
|
94
|
+
* The CLI only stamps `toolUseId` on agents the session itself spawned. A
|
|
95
|
+
* nested agent (spawned by another agent, e.g. a reviewer running a skill that
|
|
96
|
+
* forks its own worker) has only `parentAgentId`, and the SDK streams none of
|
|
97
|
+
* its activity — so the card's transcript group is the only place its work can
|
|
98
|
+
* surface. Walk each chain up to the root and key by that root's toolUseId.
|
|
99
|
+
* Entries are ordered root first, then descendants by depth.
|
|
100
|
+
*/
|
|
101
|
+
export function groupSubagentsByCard(subagentsDir: string): Map<string, SubagentTranscriptEntry[]> {
|
|
102
|
+
const entries = listSubagentTranscripts(subagentsDir);
|
|
103
|
+
const byId = new Map(entries.map((e) => [e.agentId, e]));
|
|
104
|
+
const rootOf = (entry: SubagentTranscriptEntry): { root: SubagentTranscriptEntry; depth: number } | null => {
|
|
105
|
+
let cur = entry;
|
|
106
|
+
let depth = 0;
|
|
107
|
+
const seen = new Set<string>();
|
|
108
|
+
while (cur.parentAgentId) {
|
|
109
|
+
if (seen.has(cur.agentId)) return null; // cyclic metas — corrupt, skip
|
|
110
|
+
seen.add(cur.agentId);
|
|
111
|
+
const parent = byId.get(cur.parentAgentId);
|
|
112
|
+
if (!parent) return null; // parent meta missing — cannot attach anywhere
|
|
113
|
+
cur = parent;
|
|
114
|
+
depth++;
|
|
115
|
+
}
|
|
116
|
+
return cur.toolUseId ? { root: cur, depth } : null;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const groups = new Map<string, Array<{ entry: SubagentTranscriptEntry; depth: number }>>();
|
|
120
|
+
for (const entry of entries) {
|
|
121
|
+
const resolved = rootOf(entry);
|
|
122
|
+
if (!resolved) continue;
|
|
123
|
+
const key = resolved.root.toolUseId!;
|
|
124
|
+
const list = groups.get(key) ?? [];
|
|
125
|
+
list.push({ entry, depth: resolved.depth });
|
|
126
|
+
groups.set(key, list);
|
|
127
|
+
}
|
|
128
|
+
const out = new Map<string, SubagentTranscriptEntry[]>();
|
|
129
|
+
for (const [key, list] of groups) {
|
|
130
|
+
list.sort((a, b) => a.depth - b.depth);
|
|
131
|
+
out.set(key, list.map((l) => l.entry));
|
|
132
|
+
}
|
|
133
|
+
return out;
|
|
134
|
+
}
|
|
135
|
+
|
|
80
136
|
/**
|
|
81
137
|
* Newest transcript per teammate name.
|
|
82
138
|
*
|
package/src/types/chat.ts
CHANGED
|
@@ -49,6 +49,8 @@ export interface AIProvider {
|
|
|
49
49
|
getUsage?(): Promise<UsageInfo>;
|
|
50
50
|
/** True when a live streaming subprocess exists for this session */
|
|
51
51
|
hasStreamingSession?(sessionId: string): boolean;
|
|
52
|
+
/** Prompt-cache lifetime for this session, in ms — how long holding its subprocess pays. */
|
|
53
|
+
promptCacheTtlMs?(sessionId: string): number;
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
export interface ModelOption {
|
package/src/web/app.tsx
CHANGED
|
@@ -48,6 +48,9 @@ const MobileExplorerSheet = lazy(() =>
|
|
|
48
48
|
const TeamMemberSheet = lazy(() =>
|
|
49
49
|
import("@/components/chat/team-member-sheet").then((m) => ({ default: m.TeamMemberSheet })),
|
|
50
50
|
);
|
|
51
|
+
const RemoteDesktopMobileSheet = lazy(() =>
|
|
52
|
+
import("@/components/remote-desktop/remote-desktop-mobile-sheet").then((m) => ({ default: m.RemoteDesktopMobileSheet })),
|
|
53
|
+
);
|
|
51
54
|
|
|
52
55
|
type AuthState = "checking" | "authenticated" | "unauthenticated";
|
|
53
56
|
|
|
@@ -357,6 +360,11 @@ export function App() {
|
|
|
357
360
|
<TeamMemberSheet />
|
|
358
361
|
</Suspense>
|
|
359
362
|
|
|
363
|
+
{/* Mobile full-screen remote-desktop viewer — same reason as TeamMemberSheet above */}
|
|
364
|
+
<Suspense fallback={null}>
|
|
365
|
+
<RemoteDesktopMobileSheet />
|
|
366
|
+
</Suspense>
|
|
367
|
+
|
|
360
368
|
{/* Global bug report popup */}
|
|
361
369
|
<BugReportPopup />
|
|
362
370
|
|
|
@@ -70,9 +70,14 @@ export function AddAccountDialog({ open, onOpenChange, onSuccess }: AddAccountDi
|
|
|
70
70
|
try {
|
|
71
71
|
let code = oauthCode.trim();
|
|
72
72
|
if (code.includes("#")) code = code.split("#")[0] ?? code;
|
|
73
|
-
await exchangeOAuthCode(code, oauthState);
|
|
73
|
+
const acc = await exchangeOAuthCode(code, oauthState);
|
|
74
74
|
handleClose();
|
|
75
|
-
|
|
75
|
+
// Signing in again on an account this machine parked carries the token in but
|
|
76
|
+
// deliberately leaves it out of the rotation. A flat success over a toggle that is
|
|
77
|
+
// still off reads as a bug, and this is the only place the user finds out otherwise.
|
|
78
|
+
onSuccess(acc?.status === "disabled"
|
|
79
|
+
? "Signed in. This account is still disabled — enable it to use it."
|
|
80
|
+
: "Account connected via OAuth!");
|
|
76
81
|
} catch (e) {
|
|
77
82
|
setAddError((e as Error).message);
|
|
78
83
|
}
|
|
@@ -84,9 +89,11 @@ export function AddAccountDialog({ open, onOpenChange, onSuccess }: AddAccountDi
|
|
|
84
89
|
setAdding(true);
|
|
85
90
|
setAddError(null);
|
|
86
91
|
try {
|
|
87
|
-
await addAccount({ apiKey: newToken.trim(), label: newLabel.trim() || undefined });
|
|
92
|
+
const acc = await addAccount({ apiKey: newToken.trim(), label: newLabel.trim() || undefined });
|
|
88
93
|
handleClose();
|
|
89
|
-
onSuccess(
|
|
94
|
+
onSuccess(acc?.status === "disabled"
|
|
95
|
+
? "Token updated. This account is still disabled — enable it to use it."
|
|
96
|
+
: "Account added!");
|
|
90
97
|
} catch (e) {
|
|
91
98
|
setAddError((e as Error).message);
|
|
92
99
|
}
|
|
@@ -90,7 +90,11 @@ function useQuestionKeyboard(config: {
|
|
|
90
90
|
useEffect(() => {
|
|
91
91
|
if (!config.enabled) return;
|
|
92
92
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
93
|
-
|
|
93
|
+
// Resolve focus from the input's OWN document: this card can be rendered inside a
|
|
94
|
+
// picture-in-picture window, and the module-global `document` is always the main one —
|
|
95
|
+
// there the input is never active, so every printable key would be treated as a shortcut.
|
|
96
|
+
const input = config.customInputRef.current;
|
|
97
|
+
const isTyping = !!input && input.ownerDocument.activeElement === input;
|
|
94
98
|
|
|
95
99
|
// Number keys 1-9
|
|
96
100
|
if (!isTyping && e.key >= "1" && e.key <= "9") {
|
|
@@ -132,7 +136,10 @@ function useQuestionKeyboard(config: {
|
|
|
132
136
|
if (el) {
|
|
133
137
|
el.addEventListener("keydown", handleKeyDown);
|
|
134
138
|
el.setAttribute("tabindex", "0");
|
|
135
|
-
|
|
139
|
+
// Same reason: asking the main document whether focus is already inside the card answers
|
|
140
|
+
// "no" for a card living in another document, and this effect re-runs on every render —
|
|
141
|
+
// which would yank focus out of the custom input after each keystroke.
|
|
142
|
+
if (!el.contains(el.ownerDocument.activeElement)) el.focus();
|
|
136
143
|
}
|
|
137
144
|
return () => { el?.removeEventListener("keydown", handleKeyDown); };
|
|
138
145
|
}, [config, focusedOption]);
|
|
@@ -154,11 +154,12 @@ function formatLastUpdated(ts: number | null | undefined): string | null {
|
|
|
154
154
|
return `${days}d ago`;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
function AccountUsageCard({ entry, isActive, accountInfo, onToggle, onDelete, onExport, onViewProfile, flash, fullscreen }: {
|
|
157
|
+
function AccountUsageCard({ entry, isActive, accountInfo, onToggle, toggling, onDelete, onExport, onViewProfile, flash, fullscreen }: {
|
|
158
158
|
entry: AccountUsageEntry;
|
|
159
159
|
isActive: boolean;
|
|
160
160
|
accountInfo?: AccountInfo;
|
|
161
161
|
onToggle?: (id: string, status: string) => void;
|
|
162
|
+
toggling?: boolean;
|
|
162
163
|
onDelete?: (id: string, display: string) => void;
|
|
163
164
|
onExport?: (id: string) => void;
|
|
164
165
|
onViewProfile?: (profile: OAuthProfileData, accountId: string) => void;
|
|
@@ -207,7 +208,7 @@ function AccountUsageCard({ entry, isActive, accountInfo, onToggle, onDelete, on
|
|
|
207
208
|
<Switch
|
|
208
209
|
checked={status !== "disabled"}
|
|
209
210
|
onCheckedChange={() => onToggle(entry.accountId, status)}
|
|
210
|
-
disabled={status === "cooldown"}
|
|
211
|
+
disabled={toggling || status === "cooldown"}
|
|
211
212
|
className="scale-[0.6] cursor-pointer"
|
|
212
213
|
/>
|
|
213
214
|
)}
|
|
@@ -269,6 +270,7 @@ export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, l
|
|
|
269
270
|
const [exportPreselect, setExportPreselect] = useState<string | null>(null);
|
|
270
271
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
271
272
|
const [message, setMessage] = useState<string | null>(null);
|
|
273
|
+
const [togglingId, setTogglingId] = useState<string | null>(null);
|
|
272
274
|
const msgTimer = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
273
275
|
const prevUsagesRef = useRef<AccountUsageEntry[]>([]);
|
|
274
276
|
|
|
@@ -345,7 +347,18 @@ export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, l
|
|
|
345
347
|
const fsRows = Math.ceil(fsCount / fsCols);
|
|
346
348
|
|
|
347
349
|
async function handleToggle(id: string, status: string) {
|
|
348
|
-
|
|
350
|
+
// Enabling a parked account proves its token server-side first, which is a network
|
|
351
|
+
// round trip that can come back 400 — and patchAccount throws on that. Without the
|
|
352
|
+
// catch the message the server takes care to write reaches nobody: unhandled
|
|
353
|
+
// rejection, no toast, no reload, and the Switch silently snaps back. The pending
|
|
354
|
+
// flag is because that round trip can take most of a minute in the worst case.
|
|
355
|
+
setTogglingId(id);
|
|
356
|
+
try {
|
|
357
|
+
await patchAccount(id, { status: status === "disabled" ? "active" : "disabled" });
|
|
358
|
+
} catch (e) {
|
|
359
|
+
showMessage((e as Error).message);
|
|
360
|
+
}
|
|
361
|
+
setTogglingId(null);
|
|
349
362
|
loadAll();
|
|
350
363
|
onReload?.();
|
|
351
364
|
}
|
|
@@ -440,6 +453,7 @@ export function UsageDetailPanel({ usage, visible, onClose, onReload, loading, l
|
|
|
440
453
|
isActive={entry.accountId === (activeAccountId ?? usage.activeAccountId)}
|
|
441
454
|
accountInfo={accountMap.get(entry.accountId)}
|
|
442
455
|
onToggle={handleToggle}
|
|
456
|
+
toggling={togglingId === entry.accountId}
|
|
443
457
|
onDelete={(id, display) => setDeleteTarget({ id, display })}
|
|
444
458
|
onExport={(id) => { setExportPreselect(id); setShowExportDialog(true); }}
|
|
445
459
|
onViewProfile={(profile, accountId) => setProfileView({ profile, accountId })}
|
|
@@ -19,6 +19,7 @@ import { PortalContainerProvider } from "@/components/ui/portal-container-contex
|
|
|
19
19
|
import { TITLEBAR_HEIGHT } from "./window-chrome-contract";
|
|
20
20
|
import { useWindowBodyElement } from "./use-window-body-element";
|
|
21
21
|
import { WindowPipPlaceholder } from "./window-pip-placeholder";
|
|
22
|
+
import { isPipOnlyWindow } from "./window-pip-registry";
|
|
22
23
|
import { WindowSkinChrome } from "./window-skin-chrome";
|
|
23
24
|
import { windowZIndex, type Bounds, type Rect } from "./window-geometry";
|
|
24
25
|
import { useWindowStore, type WindowRuntimeState } from "./window-store";
|
|
@@ -120,6 +121,8 @@ export function FloatingWindow({
|
|
|
120
121
|
movable: !maximized,
|
|
121
122
|
});
|
|
122
123
|
|
|
124
|
+
const hiddenHost = Boolean(pip) && isPipOnlyWindow(win.id);
|
|
125
|
+
|
|
123
126
|
return (
|
|
124
127
|
<div
|
|
125
128
|
ref={rootRef}
|
|
@@ -135,6 +138,10 @@ export function FloatingWindow({
|
|
|
135
138
|
focused ? "shadow-2xl shadow-black/40" : "shadow-lg shadow-black/20",
|
|
136
139
|
// Transitions are for maximize/restore only; during a gesture they would lag the pointer.
|
|
137
140
|
gesturing ? "transition-none" : "transition-[transform,width,height] duration-150 motion-reduce:transition-none",
|
|
141
|
+
// A window opened only to carry a tab into PiP is never shown: the user asked for a
|
|
142
|
+
// PiP, not a window. `hidden` and not an unmount — the body must stay connected, or
|
|
143
|
+
// the PiP host has nowhere to put the tab back.
|
|
144
|
+
hiddenHost && "hidden",
|
|
138
145
|
)}
|
|
139
146
|
>
|
|
140
147
|
<WindowSkinChrome
|
|
@@ -158,7 +165,7 @@ export function FloatingWindow({
|
|
|
158
165
|
onClose={close}
|
|
159
166
|
/>
|
|
160
167
|
|
|
161
|
-
{pip && <WindowPipPlaceholder pip={pip} minimized={minimized} />}
|
|
168
|
+
{pip && !hiddenHost && <WindowPipPlaceholder pip={pip} minimized={minimized} />}
|
|
162
169
|
|
|
163
170
|
{!maximized && !minimized && (
|
|
164
171
|
<WindowResizeHandles bind={(handle) => bindResize(handle) as Record<string, unknown>} />
|