@hienlh/ppm 0.18.9 → 0.18.11
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/.spike/cdp-client.ts +116 -0
- package/.spike/cleanup-ppm-workspace.mjs +44 -0
- package/.spike/group-protected-probe.ts +21 -0
- package/.spike/pip-eval.ts +17 -0
- package/.spike/pip-page-helpers.js +119 -0
- package/.spike/pip-results-editor-glue.json +105 -0
- package/.spike/pip-results-editor.json +158 -0
- package/.spike/pip-results-input-isolation.json +28 -0
- package/.spike/pip-results-key-probe.json +58 -0
- package/.spike/pip-results-listener-survival.json +98 -0
- package/.spike/pip-results-listeners.json +36 -0
- package/.spike/pip-results-pagehide.json +92 -0
- package/.spike/pip-results-resize.json +104 -0
- package/.spike/pip-results-terminal-debug.json +99 -0
- package/.spike/pip-results-terminal-v2.json +191 -0
- package/.spike/pip-results-terminal.json +220 -0
- package/.spike/pip-results-xterm-trace.json +73 -0
- package/.spike/pip-spike-common.ts +83 -0
- package/.spike/pip-spike-editor-glue.ts +82 -0
- package/.spike/pip-spike-editor.ts +129 -0
- package/.spike/pip-spike-input-isolation.ts +38 -0
- package/.spike/pip-spike-key-probe.ts +34 -0
- package/.spike/pip-spike-listener-survival.ts +54 -0
- package/.spike/pip-spike-listeners.ts +19 -0
- package/.spike/pip-spike-pagehide.ts +59 -0
- package/.spike/pip-spike-resize.ts +42 -0
- package/.spike/pip-spike-setup.ts +63 -0
- package/.spike/pip-spike-terminal-debug.ts +81 -0
- package/.spike/pip-spike-terminal-v2.ts +139 -0
- package/.spike/pip-spike-terminal.ts +169 -0
- package/.spike/pip-spike-xterm-trace.ts +36 -0
- package/.spike/probe-drag-memo-error.mjs +67 -0
- package/.spike/read-dev-db.ts +15 -0
- package/.spike/scratch-editor-target.ts +7 -0
- package/.spike/smoke-unified-chrome-pip.mjs +353 -0
- package/.spike/tunnel.err +63 -42
- package/.spike/vite-restart.err +663 -0
- package/.spike/w.err +569 -94
- package/CHANGELOG.md +25 -0
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/adaptive-context-menu-DGCKKeTy.js +1 -0
- package/dist/web/assets/ai-resource-editor-BOHHTTe7.js +1 -0
- package/dist/web/assets/ai-settings-section-BigC_nZR.js +1 -0
- package/dist/web/assets/{angular-html-Ctz0zN01.js → angular-html-BYPaydvh.js} +1 -1
- package/dist/web/assets/{angular-ts-QXHpgB1C.js → angular-ts-Bb4AMKlk.js} +1 -1
- package/dist/web/assets/api-client-DTZEgjBQ.js +1 -0
- package/dist/web/assets/{api-settings-kQHV6pYZ.js → api-settings-Bd3M4YpI.js} +1 -1
- package/dist/web/assets/api-settings-kd1j4iR8.js +1 -0
- package/dist/web/assets/{api-themes-CrK0tkW_.js → api-themes-Cpx419SL.js} +1 -1
- package/dist/web/assets/{apl-b9KVk-O4.js → apl-DB2VjFCS.js} +1 -1
- package/dist/web/assets/architecture-PBZL5I3N-8dCMT9r7.js +1 -0
- package/dist/web/assets/{astro-BlFEeGYr.js → astro-BeoJdVpk.js} +1 -1
- package/dist/web/assets/{audio-preview-CZLmhf__.js → audio-preview-BgFuTn-0.js} +1 -1
- package/dist/web/assets/{blade-CGkj2MUI.js → blade-Cf2q1sPf.js} +1 -1
- package/dist/web/assets/{bsl-CVsbb6ap.js → bsl-W1kOaNpu.js} +1 -1
- package/dist/web/assets/{button-BA_fJOtX.js → button-5zTrkEoN.js} +1 -1
- package/dist/web/assets/{cairo-BbIHl2iE.js → cairo-BoAZFcje.js} +1 -1
- package/dist/web/assets/chat-tab-E3bf_V8X.js +15 -0
- package/dist/web/assets/chevron-down-Dp0rpHb8.js +1 -0
- package/dist/web/assets/clipboard-7fw0Shic.js +1 -0
- package/dist/web/assets/{cobol-BWSGjmWb.js → cobol-B0Nm7RXj.js} +1 -1
- package/dist/web/assets/code-editor-BUlM2gXk.js +10 -0
- package/dist/web/assets/{coffee-CWGNOxds.js → coffee-BakMn3on.js} +1 -1
- package/dist/web/assets/{conflict-editor-CdH_h0vD.js → conflict-editor-BUs5k9q_.js} +4 -4
- package/dist/web/assets/context-menu-Bq92km4s.js +1 -0
- package/dist/web/assets/{cpp-DHGV24J2.js → cpp-BRAJQHK2.js} +1 -1
- package/dist/web/assets/{crystal-Vlwf2UMP.js → crystal-kqqO3zkK.js} +1 -1
- package/dist/web/assets/{csv-preview-CY_454vd.js → csv-preview-ByoDgLAZ.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-D9il5DZS.js → data-grid-overlay-editor-Brkf9z41.js} +1 -1
- package/dist/web/assets/database-viewer-Btc3h8Yu.js +1 -0
- package/dist/web/assets/dialog-DwtGlowE.js +1 -0
- package/dist/web/assets/diff-viewer-CZaDnR4w.js +4 -0
- package/dist/web/assets/docx-preview-DAD_vg59.js +12 -0
- package/dist/web/assets/{edge-Bhqk64zS.js → edge-Cq1ZKZuE.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-gq6ALf2B.js → edit-diff-preview-B_VE7ppQ.js} +1 -1
- package/dist/web/assets/{elixir-D466WCFm.js → elixir-BM_JoJRk.js} +1 -1
- package/dist/web/assets/{elm-Bfs2qNPR.js → elm-Dw7oO08Y.js} +1 -1
- package/dist/web/assets/{erb-WI7jUaB6.js → erb-CfKOGAfk.js} +1 -1
- package/dist/web/assets/{erlang-BCBe8nCc.js → erlang-DlDmGVeE.js} +1 -1
- package/dist/web/assets/{esm-CZs9WVDO.js → esm-DGAP0GFh.js} +1 -1
- package/dist/web/assets/explorer-body-9aBmyVpZ.js +2 -0
- package/dist/web/assets/explorer-window-content-DRtqoSPA.js +1 -0
- package/dist/web/assets/extension-store-Cpfh2vMm.js +1 -0
- package/dist/web/assets/{extension-webview-CuOQrHIS.js → extension-webview-B2OnjuCu.js} +2 -2
- package/dist/web/assets/external-link-B8BynhvY.js +1 -0
- package/dist/web/assets/file-store-aOERIEo-.js +1 -0
- package/dist/web/assets/folder-symlink-B8XrtvQK.js +1 -0
- package/dist/web/assets/format-bytes-WVcFxJuT.js +1 -0
- package/dist/web/assets/{fortran-fixed-form-CXLIv8Ox.js → fortran-fixed-form-XnAhQWxS.js} +1 -1
- package/dist/web/assets/{fsharp-CZsYmiw9.js → fsharp-CdNvy0PG.js} +1 -1
- package/dist/web/assets/{gdresource-BGRvoWfC.js → gdresource-DxuG5i8i.js} +1 -1
- package/dist/web/assets/{git-commit-DH6mY3Km.js → git-commit-3lMonsur.js} +1 -1
- package/dist/web/assets/git-log-panel-Co0PBPHC.js +1 -0
- package/dist/web/assets/{git-rebase-C5Gql6Ma.js → git-rebase-N8Z9kIMf.js} +1 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-2e_8dfbs.js +1 -0
- package/dist/web/assets/{glide-data-grid-Cehfgrzc.js → glide-data-grid-C4_zIneN.js} +8 -8
- package/dist/web/assets/{glimmer-js-1-6JMJlj.js → glimmer-js-Dp9OXiib.js} +1 -1
- package/dist/web/assets/{glimmer-ts-C_Njj0nK.js → glimmer-ts-CDVKBcDj.js} +1 -1
- package/dist/web/assets/{glsl-DbkxE1TN.js → glsl-DPJxI4us.js} +1 -1
- package/dist/web/assets/{graphql-BK75fiXl.js → graphql-BrFhaQQl.js} +1 -1
- package/dist/web/assets/group-chat-tab-rOd8J8GC.js +1 -0
- package/dist/web/assets/{hack-DG151vit.js → hack-BzXbDMlA.js} +1 -1
- package/dist/web/assets/{haml-DKeIPQWM.js → haml-CPpkX0s5.js} +1 -1
- package/dist/web/assets/{handlebars-398uCI13.js → handlebars-BqrApy52.js} +1 -1
- package/dist/web/assets/{html-NLWdst5q.js → html-DmjUl-OA.js} +1 -1
- package/dist/web/assets/{html-derivative-CJf_Le2z.js → html-derivative-Cnd6XFR5.js} +1 -1
- package/dist/web/assets/{http-G1K2FozA.js → http-DMLWYun2.js} +1 -1
- package/dist/web/assets/{hurl-WDC6sSBz.js → hurl-CKkCVxbj.js} +1 -1
- package/dist/web/assets/{hxml-Dc3jBXuf.js → hxml-CAx19TtQ.js} +1 -1
- package/dist/web/assets/image-preview-DHUoylQ1.js +1 -0
- package/dist/web/assets/index-BImUaigO.js +52 -0
- package/dist/web/assets/index-CSfi6DSU.css +2 -0
- package/dist/web/assets/info-3K5VOQVL-BZi1Gha1.js +1 -0
- package/dist/web/assets/input-DcEk7mA3.js +1 -0
- package/dist/web/assets/{jinja-CWsQj2y0.js → jinja-BmB9YN9l.js} +1 -1
- package/dist/web/assets/{jison-CciJg2NW.js → jison-BaVsKKpw.js} +1 -1
- package/dist/web/assets/{julia-IOQNJAB7.js → julia-BgVBLveX.js} +1 -1
- package/dist/web/assets/{just-BGdHchwS.js → just-C2ENIbl9.js} +1 -1
- package/dist/web/assets/keybindings-store-BGIyqXHI.js +1 -0
- package/dist/web/assets/keybindings-store-CzV2sPls.js +1 -0
- package/dist/web/assets/{latex-D6TOl-L2.js → latex-BiDIWxKL.js} +1 -1
- package/dist/web/assets/{liquid-CVSvu_Wn.js → liquid-NxpapreE.js} +1 -1
- package/dist/web/assets/loader-circle-gSPVxfvH.js +1 -0
- package/dist/web/assets/lock-Did-87UV.js +1 -0
- package/dist/web/assets/{lua-CcKiU6HW.js → lua-DVepQvwH.js} +1 -1
- package/dist/web/assets/markdown-renderer-CcbR33VG.js +1 -0
- package/dist/web/assets/{markdown-renderer-pVzBdkpl.js → markdown-renderer-DlcDhgrF.js} +3 -3
- package/dist/web/assets/{marko--UOicMGo.js → marko-CJ2606Xl.js} +1 -1
- package/dist/web/assets/{mdc-D690aU2C.js → mdc-D2bjqclE.js} +1 -1
- package/dist/web/assets/{media-url-CylYQld1.js → media-url-H17XJF-I.js} +1 -1
- package/dist/web/assets/mobile-bottom-sheet-g-r2hCFa.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-SIwQXlwA.js +1 -0
- package/dist/web/assets/monitor-Dv8vn_6O.js +1 -0
- package/dist/web/assets/{nextflow-DR8PhpF8.js → nextflow-BtJwUbfF.js} +1 -1
- package/dist/web/assets/{nginx-Qb9pUk1g.js → nginx-j4gyIhHE.js} +1 -1
- package/dist/web/assets/{nim-DLa8R3NS.js → nim-ClH_gjP5.js} +1 -1
- package/dist/web/assets/notification-store-DV5QtUTg.js +1 -0
- package/dist/web/assets/{number-overlay-editor-D9SkFg1Y.js → number-overlay-editor-C1EqJnWq.js} +1 -1
- package/dist/web/assets/overview-panel-vTeeJYVZ.js +1 -0
- package/dist/web/assets/packet-RMMSAZCW-o5htEcin.js +1 -0
- package/dist/web/assets/panel-store-BSnkjgHt.js +1 -0
- package/dist/web/assets/pdf-preview-CqFGRY0Z.js +1 -0
- package/dist/web/assets/pencil-BlIIg6RH.js +1 -0
- package/dist/web/assets/{perl-AMNGIneF.js → perl-C9H7X7CT.js} +1 -1
- package/dist/web/assets/{php-CDsOOxXn.js → php-Bx2U-cQ_.js} +1 -1
- package/dist/web/assets/pie-UPGHQEXC-BXAIFSAD.js +1 -0
- package/dist/web/assets/play-4MZi1Axp.js +1 -0
- package/dist/web/assets/portal-container-context-Cm5HipFr.js +1 -0
- package/dist/web/assets/{postgres-viewer-CR6VpTrX.js → postgres-viewer-DHwcQucn.js} +3 -3
- package/dist/web/assets/process-table-BGRJNlpn.js +1 -0
- package/dist/web/assets/{project-store-B8BkHXy5.js → project-store--nvQiy75.js} +1 -1
- package/dist/web/assets/{pug-C2kdkhQ6.js → pug-Cw74sKsE.js} +1 -1
- package/dist/web/assets/{qml-DRDkUp75.js → qml-BXD94Eqz.js} +1 -1
- package/dist/web/assets/radar-KQ55EAFF-Dbt2Aebl.js +1 -0
- package/dist/web/assets/{razor-wY_6wUeC.js → razor-DZ0-Ge0S.js} +1 -1
- package/dist/web/assets/refresh-cw-B06yaBrW.js +1 -0
- package/dist/web/assets/resolve-theme-CRt_7wpd.js +1 -0
- package/dist/web/assets/rotate-ccw-COXu_9oj.js +1 -0
- package/dist/web/assets/{rst-BRpofyNs.js → rst-Dtdh0QUj.js} +1 -1
- package/dist/web/assets/{ruby-ieATBhWm.js → ruby-BC51BW2Q.js} +1 -1
- package/dist/web/assets/{run-in-terminal-CyS5Itj-.js → run-in-terminal-Sd3KyjN4.js} +1 -1
- package/dist/web/assets/{sas-CoOOEbOO.js → sas-BN8i4qOU.js} +1 -1
- package/dist/web/assets/scroll-area-0gljZ6lF.js +1 -0
- package/dist/web/assets/{scss-_nWV0bsb.js → scss-H-QtA7Rz.js} +1 -1
- package/dist/web/assets/send-BlyNJAzy.js +1 -0
- package/dist/web/assets/{send-to-chat-BcO39BDR.js → send-to-chat-u6m8l-rH.js} +1 -1
- package/dist/web/assets/{settings-store-C20lqh0G.js → settings-store-CHY6Kzin.js} +2 -2
- package/dist/web/assets/settings-tab-Dic6TKkU.js +1 -0
- package/dist/web/assets/settings-tab-IY6K1MiZ.js +3 -0
- package/dist/web/assets/{shaderlab-XkqfIfO8.js → shaderlab-CalNsj_x.js} +1 -1
- package/dist/web/assets/shallow-DYo6goJ4.js +1 -0
- package/dist/web/assets/{shellsession-BKBIqTlM.js → shellsession-BFrcoR8x.js} +1 -1
- package/dist/web/assets/{soy-oVDnPzzh.js → soy-CNbku7vP.js} +1 -1
- package/dist/web/assets/{sparql-N2VclEsF.js → sparql-BN_orcVp.js} +1 -1
- package/dist/web/assets/{sql-query-editor-BPYsJDsn.js → sql-query-editor-C6pC3I8l.js} +1 -1
- package/dist/web/assets/sqlite-viewer-DTr5PzUb.js +1 -0
- package/dist/web/assets/{stata-BuuClVDg.js → stata-C6a5Ijzq.js} +1 -1
- package/dist/web/assets/{surrealql-DE5_63MS.js → surrealql-ClplI_HY.js} +1 -1
- package/dist/web/assets/{svelte--YWjlOrK.js → svelte-DNm-UNXB.js} +1 -1
- package/dist/web/assets/switch-DKvKya9y.js +1 -0
- package/dist/web/assets/system-monitor-body-iwGiCns9.js +2 -0
- package/dist/web/assets/system-monitor-tab-DdXQhEel.js +1 -0
- package/dist/web/assets/system-monitor-window-content-BUqRsPK2.js +1 -0
- package/dist/web/assets/tab-host-window-content-BnqGPu8a.js +1 -0
- package/dist/web/assets/{tab-store-DAsvpx4t.js → tab-store-CJuJRapl.js} +1 -1
- package/dist/web/assets/team-member-sheet-LkAFSCvb.js +2 -0
- package/dist/web/assets/team-member-window-content-T4Q5JI-G.js +1 -0
- package/dist/web/assets/{templ-MlpvJx4a.js → templ-CSdqVobu.js} +1 -1
- package/dist/web/assets/terminal-tab-Bb2rZegQ.js +3 -0
- package/dist/web/assets/{tex-0loAoXJG.js → tex-DzSJ4kcZ.js} +1 -1
- package/dist/web/assets/text-wrap-CBT4Gxtg.js +1 -0
- package/dist/web/assets/tool-cards-lhqhrDTT.js +8 -0
- package/dist/web/assets/trash-2-Bk4yYlck.js +1 -0
- package/dist/web/assets/treemap-KZPCXAKY-DUbnl9dz.js +1 -0
- package/dist/web/assets/triangle-alert-B8EYecpe.js +1 -0
- package/dist/web/assets/{ts-tags-pt-Ug0hK.js → ts-tags-C28w3bTg.js} +1 -1
- package/dist/web/assets/{twig-DOePpLOL.js → twig-i5jY3QXB.js} +1 -1
- package/dist/web/assets/upload-BNlX8D07.js +1 -0
- package/dist/web/assets/{use-blob-url-BKyVxOZw.js → use-blob-url-Dsq9OjTh.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-CGucu3fb.js → use-monaco-theme-BZvlsoBv.js} +1 -1
- package/dist/web/assets/use-open-team-member-DkiEjFYE.js +1 -0
- package/dist/web/assets/{use-websocket-C-Rxv8JN.js → use-websocket-B8R50f7f.js} +1 -1
- package/dist/web/assets/{vendor-mermaid-DrwG0NYt.js → vendor-mermaid-By4AVvJY.js} +1 -1
- package/dist/web/assets/video-preview-m0-3p7QZ.js +1 -0
- package/dist/web/assets/{vue-D6f-rprj.js → vue-Ceyet_lv.js} +1 -1
- package/dist/web/assets/{vue-html-DEYRkS1V.js → vue-html-GuU7g_hg.js} +1 -1
- package/dist/web/assets/{vue-vine-CxSG2ojf.js → vue-vine-CxXoaJr2.js} +1 -1
- package/dist/web/assets/window-store-CsEW6jiE.js +1 -0
- package/dist/web/assets/{xml-DhrxbATj.js → xml-CbqOVhkP.js} +1 -1
- package/dist/web/assets/{xsl-CU0ZndUO.js → xsl-KfAmCauy.js} +1 -1
- package/dist/web/index.html +56 -27
- package/dist/web/sw.js +1 -1
- package/docs/code-standards.md +8 -0
- package/docs/codebase-summary.md +19 -5
- package/docs/design-guidelines.md +13 -2
- package/docs/project-roadmap.md +9 -0
- package/docs/system-architecture.md +83 -6
- package/package.json +1 -1
- package/src/web/components/chat/file-picker.tsx +5 -2
- package/src/web/components/chat/mode-selector.tsx +5 -2
- package/src/web/components/chat/model-selector.tsx +5 -2
- package/src/web/components/chat/model-thinking-selector.tsx +5 -2
- package/src/web/components/chat/provider-selector.tsx +5 -2
- package/src/web/components/chat/slash-command-picker.tsx +5 -2
- package/src/web/components/editor/code-editor.tsx +13 -3
- package/src/web/components/editor/conflict-editor.tsx +9 -0
- package/src/web/components/editor/diff-viewer.tsx +9 -0
- package/src/web/components/floating-window/floating-window.tsx +23 -15
- package/src/web/components/floating-window/pip/pip-caption-button.tsx +108 -0
- package/src/web/components/floating-window/pip/pip-focus-target.ts +58 -0
- package/src/web/components/floating-window/pip/pip-geometry.ts +46 -0
- package/src/web/components/floating-window/pip/pip-host.ts +156 -0
- package/src/web/components/floating-window/pip/pip-key-forward.ts +59 -0
- package/src/web/components/floating-window/pip/pip-resize-signal.ts +33 -0
- package/src/web/components/floating-window/pip/pip-style-copy.ts +108 -0
- package/src/web/components/floating-window/pip/pip-support.ts +33 -0
- package/src/web/components/floating-window/tab-host-window-content.tsx +80 -0
- package/src/web/components/floating-window/use-window-body-element.ts +67 -0
- package/src/web/components/floating-window/use-window-drag.ts +5 -0
- package/src/web/components/floating-window/use-window-gesture-context.ts +14 -0
- package/src/web/components/floating-window/use-window-resize.ts +5 -0
- package/src/web/components/floating-window/window-content-registry.ts +4 -16
- package/src/web/components/floating-window/window-layer.tsx +1 -2
- package/src/web/components/floating-window/window-persistence.ts +9 -2
- package/src/web/components/floating-window/window-pip-placeholder.tsx +31 -0
- package/src/web/components/floating-window/window-pip-registry.ts +69 -0
- package/src/web/components/floating-window/window-skin-chrome.tsx +21 -0
- package/src/web/components/floating-window/window-store-types.ts +8 -2
- package/src/web/components/layout/reparenting-tab.tsx +136 -0
- package/src/web/components/layout/tab-bar.tsx +2 -0
- package/src/web/components/layout/tab-pool-collect.ts +38 -2
- package/src/web/components/layout/tab-pool-registry.ts +48 -0
- package/src/web/components/layout/tab-pool.tsx +54 -168
- package/src/web/components/layout/tab-pop-out-menu-item.tsx +42 -0
- package/src/web/components/layout/use-window-panel-reconcile.ts +48 -0
- package/src/web/components/os-explorer/skins/macos-window-chrome.tsx +16 -7
- package/src/web/components/os-explorer/skins/windows-window-chrome.tsx +14 -8
- package/src/web/components/system/build-kill-request.ts +28 -1
- package/src/web/components/system/chart-scale.ts +3 -3
- package/src/web/components/system/kill-confirm-dialog.tsx +44 -28
- package/src/web/components/system/metric-chart-canvas.tsx +1 -2
- package/src/web/components/system/process-columns-grid.ts +39 -29
- package/src/web/components/system/process-group-row.tsx +31 -8
- package/src/web/components/system/process-row.tsx +6 -7
- package/src/web/components/system/process-table-model.ts +4 -22
- package/src/web/components/system/process-table-toolbar.tsx +12 -43
- package/src/web/components/system/process-table.tsx +22 -63
- package/src/web/components/system/sortable-header.tsx +33 -8
- package/src/web/components/system/system-monitor-body.tsx +1 -1
- package/src/web/components/system/use-column-widths.ts +91 -0
- package/src/web/components/system/use-process-kill.ts +100 -0
- package/src/web/components/ui/context-menu.tsx +10 -3
- package/src/web/components/ui/dialog.tsx +10 -1
- package/src/web/components/ui/dropdown-menu.tsx +10 -3
- package/src/web/components/ui/mobile-bottom-sheet.tsx +7 -4
- package/src/web/components/ui/portal-container-context.tsx +40 -0
- package/src/web/components/ui/select.tsx +3 -1
- package/src/web/components/ui/tooltip.tsx +3 -1
- package/src/web/hooks/use-terminal.ts +24 -3
- package/src/web/stores/panel-store.ts +72 -7
- package/src/web/stores/panel-utils.ts +36 -0
- package/src/web/stores/window-panel-actions.ts +211 -0
- package/src/web/stores/window-panel-persistence.ts +115 -0
- package/src/web/stores/window-panel-reconcile.ts +97 -0
- package/src/web/styles/globals.css +5 -3
- package/src/web/theme/builtin/aurora.ts +8 -5
- package/dist/web/assets/ai-resource-editor-DFCuNe-P.js +0 -1
- package/dist/web/assets/api-client-CzABTreM.js +0 -1
- package/dist/web/assets/api-settings-nblja3Rk.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-C7ra20CE.js +0 -1
- package/dist/web/assets/chat-tab-flMPLoKb.js +0 -15
- package/dist/web/assets/code-editor-C2VQbXzw.js +0 -10
- package/dist/web/assets/context-menu-Cq0u3SK9.js +0 -1
- package/dist/web/assets/database-viewer-BCZOTrPT.js +0 -1
- package/dist/web/assets/diff-viewer-BwfMN-nW.js +0 -4
- package/dist/web/assets/docx-preview-D3Sdh_aT.js +0 -12
- package/dist/web/assets/explorer-body-BKOMM566.js +0 -2
- package/dist/web/assets/explorer-window-content-Bbzijk8t.js +0 -1
- package/dist/web/assets/format-bytes-Dk7B73B7.js +0 -1
- package/dist/web/assets/git-log-panel-DcV7PhqW.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-D4hYLNJU.js +0 -1
- package/dist/web/assets/group-chat-tab-BVPYxjz-.js +0 -1
- package/dist/web/assets/image-preview-D-Ok10eZ.js +0 -1
- package/dist/web/assets/index-CerSxGdf.js +0 -52
- package/dist/web/assets/index-DRA_OpWY.css +0 -2
- package/dist/web/assets/info-3K5VOQVL-lRlrTlkb.js +0 -1
- package/dist/web/assets/keybindings-store-aIY40k2o.js +0 -1
- package/dist/web/assets/markdown-renderer-I89kyQhe.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-BUOJgiaZ.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-5Uj9ZMM9.js +0 -1
- package/dist/web/assets/notification-store-DJ-OtAG3.js +0 -1
- package/dist/web/assets/overview-panel-Cgi3UPY1.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-BIhk1mvp.js +0 -1
- package/dist/web/assets/panel-store-DCD82zc1.js +0 -1
- package/dist/web/assets/pdf-preview-Di5xHFyT.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-SLS6i76l.js +0 -1
- package/dist/web/assets/process-table-DL6shbzt.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-JJ6O1Er_.js +0 -1
- package/dist/web/assets/resolve-theme-IdhSR-gx.js +0 -1
- package/dist/web/assets/settings-tab-jbiQwozX.js +0 -1
- package/dist/web/assets/sqlite-viewer-Bq9ZJA2y.js +0 -1
- package/dist/web/assets/system-monitor-body-CKEYWyN9.js +0 -2
- package/dist/web/assets/system-monitor-tab-WjhFFHyM.js +0 -1
- package/dist/web/assets/system-monitor-window-content-CMiISeoC.js +0 -1
- package/dist/web/assets/team-member-sheet-oY5EkH53.js +0 -2
- package/dist/web/assets/team-member-window-content-yCBeI_5X.js +0 -1
- package/dist/web/assets/terminal-tab-BxHtMR7h.js +0 -3
- package/dist/web/assets/tool-cards-BcGrk1zk.js +0 -8
- package/dist/web/assets/treemap-KZPCXAKY-Be3KNmns.js +0 -1
- package/dist/web/assets/use-open-team-member-DdrRXj-M.js +0 -1
- package/dist/web/assets/video-preview-DYAbbmd0.js +0 -1
- package/src/web/components/floating-window/default-window-chrome.tsx +0 -71
- package/src/web/components/os-explorer/skins/explorer-skin-chrome.tsx +0 -17
- package/src/web/components/system/sparkline-canvas.tsx +0 -63
- /package/dist/web/assets/{abap-MRbmsXOs.js → abap-C6nB04tn.js} +0 -0
- /package/dist/web/assets/{actionscript-3-BDDHKqa4.js → actionscript-3-Vx4rw2sC.js} +0 -0
- /package/dist/web/assets/{ada-DpuV9KwV.js → ada-Ccd8vM20.js} +0 -0
- /package/dist/web/assets/{andromeeda-D6qUCKJo.js → andromeeda-DnBX5xMg.js} +0 -0
- /package/dist/web/assets/{apache-CX1NU_Tl.js → apache-B-9_sx0g.js} +0 -0
- /package/dist/web/assets/{apex-B4-aoQ3K.js → apex-_wPVBYoL.js} +0 -0
- /package/dist/web/assets/{api-client-BSB14J4w.js → api-client-aQb5hHE5.js} +0 -0
- /package/dist/web/assets/{applescript-Dm9NI6KR.js → applescript-CcvD-qr0.js} +0 -0
- /package/dist/web/assets/{apply-theme-BH_d4amk.js → apply-theme-BeLRfsSu.js} +0 -0
- /package/dist/web/assets/{ara-BGN8GAYn.js → ara-C40Ztoms.js} +0 -0
- /package/dist/web/assets/{asciidoc-s_yVuR3t.js → asciidoc-CybYkJV4.js} +0 -0
- /package/dist/web/assets/{asm-BzQdSvTe.js → asm-9eOKwzR0.js} +0 -0
- /package/dist/web/assets/{aurora-x-BJTLETG_.js → aurora-x-B5ZH4t7t.js} +0 -0
- /package/dist/web/assets/{awk-BQEGWxvX.js → awk-Dqilob-2.js} +0 -0
- /package/dist/web/assets/{ayu-dark-CpTORmLc.js → ayu-dark-CPgRhf5r.js} +0 -0
- /package/dist/web/assets/{ayu-light-D8PVj-e6.js → ayu-light-Do06Q52f.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-DyElQHtm.js → ayu-mirage-_BhxcrxY.js} +0 -0
- /package/dist/web/assets/{ballerina-C82NkRtj.js → ballerina-DDwK54QW.js} +0 -0
- /package/dist/web/assets/{bat-0X7DtGI-.js → bat-BGyGlzGk.js} +0 -0
- /package/dist/web/assets/{beancount-Xgvy6YRl.js → beancount-CRWBdapI.js} +0 -0
- /package/dist/web/assets/{berry-CCT2pZcQ.js → berry-DbSFn2gO.js} +0 -0
- /package/dist/web/assets/{bibtex-CpXgZ9M_.js → bibtex-QpsV9gm9.js} +0 -0
- /package/dist/web/assets/{bicep-fkeSA62l.js → bicep-CxS8CUve.js} +0 -0
- /package/dist/web/assets/{bird2-Co7SeAI8.js → bird2-CuZhQzYR.js} +0 -0
- /package/dist/web/assets/{bot-CunPuEdW.js → bot-D6sx11y0.js} +0 -0
- /package/dist/web/assets/{c-BpmrTvJh.js → c-9bnDqE3g.js} +0 -0
- /package/dist/web/assets/{c3-BZ_Z0RrR.js → c3-JMZTrOhA.js} +0 -0
- /package/dist/web/assets/{cadence-B0GBC8OF.js → cadence-DsDNayJS.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-omBzUBBq.js → can-open-in-ppm-BJfpynya.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DIt_xR7m.js → catppuccin-frappe-DYIKXXBe.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-Dw40AcqA.js → catppuccin-latte-IYYOnUJ8.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-BJ7DfVEF.js → catppuccin-macchiato-BrJ_7mfS.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-NI2lfXzU.js → catppuccin-mocha-gzSu7v7-.js} +0 -0
- /package/dist/web/assets/{chevron-right-BLOtX8Vy.js → chevron-right-De-Wz5Lz.js} +0 -0
- /package/dist/web/assets/{circle-hjUGru6R.js → circle-BCy0AUCo.js} +0 -0
- /package/dist/web/assets/{clarity-F39L0xMJ.js → clarity-DLzsC0Hb.js} +0 -0
- /package/dist/web/assets/{clock-CvhF4DJP.js → clock-C1CQUQPZ.js} +0 -0
- /package/dist/web/assets/{clojure-DloMkd8K.js → clojure-DS1BvoTt.js} +0 -0
- /package/dist/web/assets/{cmake-CwerJun_.js → cmake-CDvsJwYp.js} +0 -0
- /package/dist/web/assets/{code-DDPoqVri.js → code-DJgYrFzm.js} +0 -0
- /package/dist/web/assets/{codeowners-CQyVz4Qf.js → codeowners-BjsYiflJ.js} +0 -0
- /package/dist/web/assets/{codeql-Bb229zuY.js → codeql-CG-7ARat.js} +0 -0
- /package/dist/web/assets/{common-lisp-KMlIwq5I.js → common-lisp-DSO1Lbh9.js} +0 -0
- /package/dist/web/assets/{copy-DKn11Pye.js → copy-BewHj66E.js} +0 -0
- /package/dist/web/assets/{coq-DHX_3IIo.js → coq-DYdh3oP_.js} +0 -0
- /package/dist/web/assets/{csharp-CEmCZv9Q.js → csharp-DxEBz5s0.js} +0 -0
- /package/dist/web/assets/{css-CqZqBD05.js → css-dal3Q-8C.js} +0 -0
- /package/dist/web/assets/{csv-l1g_V5MV.js → csv-CpqjMGiA.js} +0 -0
- /package/dist/web/assets/{csv-parser-CnS0wqr6.js → csv-parser-3umBA4NY.js} +0 -0
- /package/dist/web/assets/{cue-BrxRmilg.js → cue-DinoJ_5k.js} +0 -0
- /package/dist/web/assets/{cypher-rZkKwqZc.js → cypher-DzxqmkUW.js} +0 -0
- /package/dist/web/assets/{d-BALR-QuP.js → d-BxNwJuEC.js} +0 -0
- /package/dist/web/assets/{dark-plus-Cj7rVwh-.js → dark-plus-Clmv3V-0.js} +0 -0
- /package/dist/web/assets/{dart-CWQcdkXk.js → dart-BWVtXD35.js} +0 -0
- /package/dist/web/assets/{data-grid-types-CYvF-xK5.js → data-grid-types-B4n51Fck.js} +0 -0
- /package/dist/web/assets/{database-BH0urvbs.js → database-Y3ESDK4-.js} +0 -0
- /package/dist/web/assets/{dax-BNHD-QBA.js → dax-DsImuWgJ.js} +0 -0
- /package/dist/web/assets/{desktop-CN0IXPrP.js → desktop-B0jJuG2r.js} +0 -0
- /package/dist/web/assets/{diff-BtOXapES.js → diff-CWqAAxoE.js} +0 -0
- /package/dist/web/assets/{dist-DB1Oaqcc.js → dist-B-EXdSYE.js} +0 -0
- /package/dist/web/assets/{dist-Di6G_5jU.js → dist-C0eNNfbt.js} +0 -0
- /package/dist/web/assets/{docker-DNsAo_qO.js → docker-CYFCJdIL.js} +0 -0
- /package/dist/web/assets/{dotenv-D6Pl6aOU.js → dotenv-CKDUjURg.js} +0 -0
- /package/dist/web/assets/{download-zCATy4x4.js → download-DG3_9xXy.js} +0 -0
- /package/dist/web/assets/{dracula-C3m-w12D.js → dracula-CSoPspHE.js} +0 -0
- /package/dist/web/assets/{dracula-soft-BYqvXm6Z.js → dracula-soft-BuFjw5L1.js} +0 -0
- /package/dist/web/assets/{dream-maker-DZAPbPTi.js → dream-maker-B6PdDRZu.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-Ao5SW8ay.js → emacs-lisp-CMcXvD0G.js} +0 -0
- /package/dist/web/assets/{everforest-dark-uC8QYotQ.js → everforest-dark-cU8-wYzi.js} +0 -0
- /package/dist/web/assets/{everforest-light-CTgsVNMr.js → everforest-light-KhorllqK.js} +0 -0
- /package/dist/web/assets/{fennel-WuBw6IR1.js → fennel-BCELZK87.js} +0 -0
- /package/dist/web/assets/{file-exclamation-point-COAwgNGw.js → file-exclamation-point-CZ4DiR75.js} +0 -0
- /package/dist/web/assets/{fish-Byy9dusu.js → fish-BQc0y_jy.js} +0 -0
- /package/dist/web/assets/{fluent-CDxb_sgw.js → fluent-BTINnwF6.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-DKWSTamT.js → fortran-free-form-BQim9wDz.js} +0 -0
- /package/dist/web/assets/{gdscript-prYHMgtD.js → gdscript-03w5u8un.js} +0 -0
- /package/dist/web/assets/{gdshader-D-RM-SQk.js → gdshader-Dp2daNzU.js} +0 -0
- /package/dist/web/assets/{genie-CowkJhej.js → genie-CoNcjPiD.js} +0 -0
- /package/dist/web/assets/{gherkin-CLFpoVYJ.js → gherkin-NrPOSPQL.js} +0 -0
- /package/dist/web/assets/{github-dark-default-BK_1Qgb8.js → github-dark-default-DOKw-1cI.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-Cv9lj6f-.js → github-dark-dimmed-DJRNMkEA.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-CW5ZgIDh.js → github-dark-high-contrast-Bj7jJ_Gs.js} +0 -0
- /package/dist/web/assets/{github-dark-nW2F-RLd.js → github-dark-z4RE9ZqA.js} +0 -0
- /package/dist/web/assets/{github-light-D4PqBHGZ.js → github-light-B4k_yMFu.js} +0 -0
- /package/dist/web/assets/{github-light-default-B-cHtJJV.js → github-light-default-BHc-Uzhs.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-Dt0HJq50.js → github-light-high-contrast-CHisIywL.js} +0 -0
- /package/dist/web/assets/{gleam-DwSyXJWP.js → gleam-CfbypZ4q.js} +0 -0
- /package/dist/web/assets/{gn-Cv5WEzHc.js → gn-YoAjyhJa.js} +0 -0
- /package/dist/web/assets/{gnuplot-D7bRdY_M.js → gnuplot-xVkc1f1c.js} +0 -0
- /package/dist/web/assets/{go-DiRVJ22U.js → go-GPCwP3Gu.js} +0 -0
- /package/dist/web/assets/{groovy-BHAgLTeO.js → groovy-Crh4Yww9.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-C8QZ3gzY.js → gruvbox-dark-hard-BluUFuDS.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-Dp1eeid2.js → gruvbox-dark-medium-Cxk1FWQp.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-Cwq0dWVj.js → gruvbox-dark-soft-CHXMiFmj.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-CLQCq2-w.js → gruvbox-light-hard-B6eKPjAD.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-APHsh6Mo.js → gruvbox-light-medium-pDwMm1ut.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-CX-fYc64.js → gruvbox-light-soft-Cxu6kHqK.js} +0 -0
- /package/dist/web/assets/{haskell-C4Tw-TDa.js → haskell-C6JKHjbK.js} +0 -0
- /package/dist/web/assets/{haxe-B7fSduTQ.js → haxe-BuBNdF0a.js} +0 -0
- /package/dist/web/assets/{hcl-Bi3ho6yC.js → hcl-DZpDdGj2.js} +0 -0
- /package/dist/web/assets/{hjson-BXwae2M1.js → hjson-CBkhYRuo.js} +0 -0
- /package/dist/web/assets/{hlsl-CRuQLBSa.js → hlsl-C5nMxnp9.js} +0 -0
- /package/dist/web/assets/{horizon-DtdQ6qjv.js → horizon-VAFvA6R6.js} +0 -0
- /package/dist/web/assets/{horizon-bright-BXSF_uKq.js → horizon-bright-BC0xn7T3.js} +0 -0
- /package/dist/web/assets/{houston-C6ASpUjT.js → houston-BxrUivmz.js} +0 -0
- /package/dist/web/assets/{hy-BrWBHtHY.js → hy-DLtOXoaH.js} +0 -0
- /package/dist/web/assets/{image-gallery-CGvlv8zR.js → image-gallery-Gnf7TdCR.js} +0 -0
- /package/dist/web/assets/{imba-C_JJXckG.js → imba-BdpFXM2W.js} +0 -0
- /package/dist/web/assets/{ini-DEE_vSHQ.js → ini-BInJO_T0.js} +0 -0
- /package/dist/web/assets/{java-CnmpcjcT.js → java-Dxuddnkb.js} +0 -0
- /package/dist/web/assets/{javascript-C-M7sa2e.js → javascript-CVamJfLY.js} +0 -0
- /package/dist/web/assets/{json-BjZ3dAk6.js → json-BLZ0ozYk.js} +0 -0
- /package/dist/web/assets/{json5-BQ2vpqjp.js → json5-BnXzmMKs.js} +0 -0
- /package/dist/web/assets/{jsonc-C5MjoWGx.js → jsonc-CSgkSga7.js} +0 -0
- /package/dist/web/assets/{jsonl-JvhrmQJI.js → jsonl-CY5W2nF2.js} +0 -0
- /package/dist/web/assets/{jsonnet-C5pdZVuo.js → jsonnet-CEJYH3sF.js} +0 -0
- /package/dist/web/assets/{jssm-Db17uybX.js → jssm-CsJc7Uhk.js} +0 -0
- /package/dist/web/assets/{jsx-tJp2Cyqu.js → jsx-jCiRaHU7.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-BculT_Y1.js → kanagawa-dragon-DfoA_GxX.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-yQgHUGwU.js → kanagawa-lotus-BOLYJpWd.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-CyGoWN4d.js → kanagawa-wave-DfKlbT1G.js} +0 -0
- /package/dist/web/assets/{kdl-Bn8R1REF.js → kdl-CmssIFTi.js} +0 -0
- /package/dist/web/assets/{kotlin-DWughK73.js → kotlin-BRsNgp6x.js} +0 -0
- /package/dist/web/assets/{kusto--serPb0x.js → kusto-T8X9jUab.js} +0 -0
- /package/dist/web/assets/{laserwave-DfAPJ1tt.js → laserwave-DkJMVJ8Z.js} +0 -0
- /package/dist/web/assets/{lean-UAm1HOKl.js → lean-C65KGVPq.js} +0 -0
- /package/dist/web/assets/{less-Xj6Ka0fF.js → less-exIPdDlf.js} +0 -0
- /package/dist/web/assets/{lib-DgNcCtj3.js → lib-mC1NZfuw.js} +0 -0
- /package/dist/web/assets/{libesm-CPh1Av0r.js → libesm-DSutUtl1.js} +0 -0
- /package/dist/web/assets/{light-plus-BfS7gPcj.js → light-plus-DiHUXAZt.js} +0 -0
- /package/dist/web/assets/{llvm-DvWiVwvU.js → llvm-CJBnEzFM.js} +0 -0
- /package/dist/web/assets/{log-Bo5z9bNz.js → log-DxMyUMuP.js} +0 -0
- /package/dist/web/assets/{logo-CrIjcMZT.js → logo-CC9NKzca.js} +0 -0
- /package/dist/web/assets/{luau-C9TsYwNt.js → luau-Bw10I6zf.js} +0 -0
- /package/dist/web/assets/{make-GYq4qVbx.js → make-C_6M90m6.js} +0 -0
- /package/dist/web/assets/{markdown-p5mNledS.js → markdown-bR9_R-LF.js} +0 -0
- /package/dist/web/assets/{material-theme-CWYOVxsP.js → material-theme-BUx2Qujn.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-BDGty7YH.js → material-theme-darker-CRJrPgKm.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-JbgOgV3n.js → material-theme-lighter-CUAYppPa.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-EMOpLpa2.js → material-theme-ocean-DuINF1fg.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-CY5hgm7h.js → material-theme-palenight-W6_icGCj.js} +0 -0
- /package/dist/web/assets/{matlab-C-He_NTH.js → matlab-rfqn_b3z.js} +0 -0
- /package/dist/web/assets/{mdx-Cr2TR5fj.js → mdx-Bh1B_YOJ.js} +0 -0
- /package/dist/web/assets/{mermaid-BYc0-B0U.js → mermaid-Dxf6Ya2k.js} +0 -0
- /package/dist/web/assets/{min-dark-CMJwqJqB.js → min-dark-CivZ2L0h.js} +0 -0
- /package/dist/web/assets/{min-light-Cx6vFiEX.js → min-light-B1Ykqtma.js} +0 -0
- /package/dist/web/assets/{mipsasm-Bjer5HwK.js → mipsasm-DynHaM0d.js} +0 -0
- /package/dist/web/assets/{mojo-t90PR-Y2.js → mojo-Clw5PbGH.js} +0 -0
- /package/dist/web/assets/{monokai-dci_PdCm.js → monokai-DFIooFZT.js} +0 -0
- /package/dist/web/assets/{moonbit-AAzI-Hd-.js → moonbit-DnBSZWGM.js} +0 -0
- /package/dist/web/assets/{move-kwBhnhrG.js → move-CCcL2PfL.js} +0 -0
- /package/dist/web/assets/{narrat-CXww2YQL.js → narrat-BDarg5Lk.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CJXsuXGB.js → nextflow-groovy-DrZOeCNW.js} +0 -0
- /package/dist/web/assets/{night-owl-_GD204Wr.js → night-owl-BnZZCK7v.js} +0 -0
- /package/dist/web/assets/{night-owl-light-DNgkw3kl.js → night-owl-light-CEwBsVHS.js} +0 -0
- /package/dist/web/assets/{nix-BgiorKFd.js → nix-amCzOPMR.js} +0 -0
- /package/dist/web/assets/{nord-CaBmcxFC.js → nord-BIs2BC6q.js} +0 -0
- /package/dist/web/assets/{nushell-DUh4UGx1.js → nushell-Y02fo4yw.js} +0 -0
- /package/dist/web/assets/{objective-c-Cl9KU86S.js → objective-c-7xOZtWW1.js} +0 -0
- /package/dist/web/assets/{objective-cpp-DVkIA8A0.js → objective-cpp-eVtjUvVB.js} +0 -0
- /package/dist/web/assets/{ocaml-vvoHTak0.js → ocaml-Bi6ZwqG4.js} +0 -0
- /package/dist/web/assets/{odin-Cyjw8woZ.js → odin-8xf1Y0S9.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-B1cviILi.js → one-dark-pro-hVv-_y_b.js} +0 -0
- /package/dist/web/assets/{one-light-BPGUJeYI.js → one-light-CJJ3MtHt.js} +0 -0
- /package/dist/web/assets/{openscad-BLMdTUU8.js → openscad-B2HcywLk.js} +0 -0
- /package/dist/web/assets/{pascal-i5niy3e7.js → pascal-C7fllV_7.js} +0 -0
- /package/dist/web/assets/{pkl-CuOV7SsU.js → pkl-qvLC1IWP.js} +0 -0
- /package/dist/web/assets/{plastic-Bf_zE5KL.js → plastic-BT1wHZv2.js} +0 -0
- /package/dist/web/assets/{plsql-cfqEtMD3.js → plsql-1MsmdmJD.js} +0 -0
- /package/dist/web/assets/{plus-BM-Ty0fp.js → plus-BhMZqFsN.js} +0 -0
- /package/dist/web/assets/{po-CFJcWgjr.js → po-BigskytD.js} +0 -0
- /package/dist/web/assets/{poimandres-G5YoaIFf.js → poimandres-DuklniF7.js} +0 -0
- /package/dist/web/assets/{polar-rcjs3i9R.js → polar-e2pjN_sp.js} +0 -0
- /package/dist/web/assets/{postcss-CBKY1FTZ.js → postcss-DtAeYjWw.js} +0 -0
- /package/dist/web/assets/{powerquery-Db7SXLbO.js → powerquery-Cr2PtehI.js} +0 -0
- /package/dist/web/assets/{powershell-LFy3MUTP.js → powershell-BxFTGLJ4.js} +0 -0
- /package/dist/web/assets/{prisma-BE8GR1lH.js → prisma-COWJiwdZ.js} +0 -0
- /package/dist/web/assets/{prolog-DOn5lR1e.js → prolog-DFvGKRx6.js} +0 -0
- /package/dist/web/assets/{proto-wr-TpAK_.js → proto-CcK80lFt.js} +0 -0
- /package/dist/web/assets/{puppet-D2Dkv62u.js → puppet-BF60bZ4F.js} +0 -0
- /package/dist/web/assets/{purescript-DvgJgPdy.js → purescript-zL_69MzU.js} +0 -0
- /package/dist/web/assets/{python-C7TlkHhK.js → python-CIwKhfb_.js} +0 -0
- /package/dist/web/assets/{qmldir-CtZMwhcW.js → qmldir-CXNe04Lo.js} +0 -0
- /package/dist/web/assets/{qss-dNZ2btnl.js → qss-C8lAWe6G.js} +0 -0
- /package/dist/web/assets/{r-BlqnNkHS.js → r-CL5ZVL3_.js} +0 -0
- /package/dist/web/assets/{racket-CzRQrGc4.js → racket-BBfh0uh0.js} +0 -0
- /package/dist/web/assets/{raku-BwutWhBF.js → raku-o6E8R5Q3.js} +0 -0
- /package/dist/web/assets/{react-I_EwPIZi.js → react-CBTnT4sY.js} +0 -0
- /package/dist/web/assets/{red-BMXMywmL.js → red-GomRF2Xp.js} +0 -0
- /package/dist/web/assets/{reg-BqOKrIOw.js → reg-_ffDIvx9.js} +0 -0
- /package/dist/web/assets/{regexp-Bero1BN2.js → regexp-Bl5sF65W.js} +0 -0
- /package/dist/web/assets/{rel-BXKWIElA.js → rel-DgMdqDuj.js} +0 -0
- /package/dist/web/assets/{riscv-BbbBYJBo.js → riscv-8b3-Ye4X.js} +0 -0
- /package/dist/web/assets/{ron-BtVTWW4b.js → ron-DrmU1KHP.js} +0 -0
- /package/dist/web/assets/{rose-pine-hvkvQzvU.js → rose-pine-C_-E2tF1.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-D7lwhUei.js → rose-pine-dawn-DEfhNlFH.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CoHDmsIw.js → rose-pine-moon-BdvX3gdn.js} +0 -0
- /package/dist/web/assets/{rosmsg-CdaZFgI8.js → rosmsg-B6GhGpd5.js} +0 -0
- /package/dist/web/assets/{rust-Dy2qsphD.js → rust-DmC97M1-.js} +0 -0
- /package/dist/web/assets/{sass-Bz7NVxDb.js → sass-B0tJOHLM.js} +0 -0
- /package/dist/web/assets/{save-C4z1p51e.js → save-CtIGOjmx.js} +0 -0
- /package/dist/web/assets/{scala-sXSwsNyq.js → scala-n8zaFOXv.js} +0 -0
- /package/dist/web/assets/{scheme-DS7TUbN7.js → scheme-BKD9ztBU.js} +0 -0
- /package/dist/web/assets/{sdbl-iISFvIep.js → sdbl-D8gB5-rS.js} +0 -0
- /package/dist/web/assets/{shellscript-BkIl4ApC.js → shellscript-BfXlf_Ao.js} +0 -0
- /package/dist/web/assets/{shield-check-C5laObJv.js → shield-check-B0iGUiOK.js} +0 -0
- /package/dist/web/assets/{shield-off-DULFtyLS.js → shield-off-BNLWBhcq.js} +0 -0
- /package/dist/web/assets/{slack-dark-B1eg0_m2.js → slack-dark-CylEddse.js} +0 -0
- /package/dist/web/assets/{slack-ochin-mdkc1ldu.js → slack-ochin-w8wg8vuC.js} +0 -0
- /package/dist/web/assets/{smalltalk-CORtd03t.js → smalltalk-hiAXA64u.js} +0 -0
- /package/dist/web/assets/{snazzy-light-Bc6Q2G89.js → snazzy-light-BwlV3Xty.js} +0 -0
- /package/dist/web/assets/{solarized-dark-CF83zRXM.js → solarized-dark-vmNGdykz.js} +0 -0
- /package/dist/web/assets/{solarized-light-BoKQZaYU.js → solarized-light-DGv_0JXq.js} +0 -0
- /package/dist/web/assets/{solidity-DOgi1N4w.js → solidity-Y7QSH0B1.js} +0 -0
- /package/dist/web/assets/{sparkles-Dqsf3hq6.js → sparkles-Dh-_J2Rd.js} +0 -0
- /package/dist/web/assets/{splunk-BXfw5ZLy.js → splunk-BtgpLjHi.js} +0 -0
- /package/dist/web/assets/{sql-BcVs-eX4.js → sql-CRHYhOia.js} +0 -0
- /package/dist/web/assets/{ssh-config-CLCtNkkd.js → ssh-config-DOqSs3au.js} +0 -0
- /package/dist/web/assets/{stylus-DdP992aO.js → stylus-crCAEaBT.js} +0 -0
- /package/dist/web/assets/{swift-BnGb6Lgc.js → swift-eE3rT7TC.js} +0 -0
- /package/dist/web/assets/{synthwave-84-cg9264l9.js → synthwave-84-BWy14LBX.js} +0 -0
- /package/dist/web/assets/{system-verilog-GbHpszs3.js → system-verilog-DC0-DZM4.js} +0 -0
- /package/dist/web/assets/{systemd-Dz-bNsDQ.js → systemd-to5p6N8I.js} +0 -0
- /package/dist/web/assets/{table-CHmxuh6M.js → table-Bbc783ko.js} +0 -0
- /package/dist/web/assets/{talonscript-CFIidoBA.js → talonscript-DoTcU8wm.js} +0 -0
- /package/dist/web/assets/{tasl-Cu-TRTKx.js → tasl-cNZvUs95.js} +0 -0
- /package/dist/web/assets/{tcl-DwCHCB1K.js → tcl-mZE8sZH8.js} +0 -0
- /package/dist/web/assets/{terraform-BzZw4T1z.js → terraform-CqHPpIfu.js} +0 -0
- /package/dist/web/assets/{tokyo-night-RKsj2-tv.js → tokyo-night-Tp2rTIZd.js} +0 -0
- /package/dist/web/assets/{toml-CirbOgDP.js → toml-CU_vscgn.js} +0 -0
- /package/dist/web/assets/{tsv-CraRcWdU.js → tsv-ik7iFB9D.js} +0 -0
- /package/dist/web/assets/{tsx-CjFg0lgw.js → tsx-BMvvMKiv.js} +0 -0
- /package/dist/web/assets/{turtle-B-WBIOa6.js → turtle-DBqKCq9o.js} +0 -0
- /package/dist/web/assets/{typescript-MpLarYn1.js → typescript-DXJDmMZZ.js} +0 -0
- /package/dist/web/assets/{typespec-B7QlHMZ_.js → typespec-CBseCMtZ.js} +0 -0
- /package/dist/web/assets/{typst-CcHSKFZj.js → typst-4oY25U9y.js} +0 -0
- /package/dist/web/assets/{use-is-mobile-BXGVvczu.js → use-is-mobile-D1weanbj.js} +0 -0
- /package/dist/web/assets/{utils-DoY4yTP-.js → utils-BNRH507E.js} +0 -0
- /package/dist/web/assets/{v-xTGhWZuD.js → v-BXaZ_1oy.js} +0 -0
- /package/dist/web/assets/{vala-DwebjH3H.js → vala-BImWJE7z.js} +0 -0
- /package/dist/web/assets/{vb-BxJT2RAy.js → vb-CLfj2_sy.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-CU6zIYMB.js → vendor-xterm-_yyu5n32.js} +0 -0
- /package/dist/web/assets/{verilog-CvV6RHPD.js → verilog-BWa8Ed2b.js} +0 -0
- /package/dist/web/assets/{vesper-CY3qd7E_.js → vesper-BGj1cg6m.js} +0 -0
- /package/dist/web/assets/{vhdl-B9ZX-sUL.js → vhdl-mByK7mlx.js} +0 -0
- /package/dist/web/assets/{viml-Y42h_ExQ.js → viml-CugmlW5g.js} +0 -0
- /package/dist/web/assets/{vitesse-black-DkXP6Sv-.js → vitesse-black-vPdpy9TL.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-B9CkIB6r.js → vitesse-dark-BuQK3dUh.js} +0 -0
- /package/dist/web/assets/{vitesse-light-C7DHrJCK.js → vitesse-light-B3nz1XL9.js} +0 -0
- /package/dist/web/assets/{vyper-Cnd9s5j-.js → vyper-DH_GTIHG.js} +0 -0
- /package/dist/web/assets/{wasm-DQE71XTB.js → wasm-C-LF9GjX.js} +0 -0
- /package/dist/web/assets/{wasm-iWe7Fzjc.js → wasm-DfVbVJlW.js} +0 -0
- /package/dist/web/assets/{wenyan-Bc5Pnm9l.js → wenyan-CzQkHyHx.js} +0 -0
- /package/dist/web/assets/{wgsl-D-YUAWkP.js → wgsl-Du_M1DW9.js} +0 -0
- /package/dist/web/assets/{wikitext-DYQDUYf2.js → wikitext-BWN_w5S7.js} +0 -0
- /package/dist/web/assets/{wit-P6u7mfwy.js → wit-BR13v5HD.js} +0 -0
- /package/dist/web/assets/{wolfram-6SXLUqao.js → wolfram-BoXxp_Xl.js} +0 -0
- /package/dist/web/assets/{x-BcqfTY_7.js → x-nhriOX9o.js} +0 -0
- /package/dist/web/assets/{yaml-CQiMLVcZ.js → yaml-DpR_EF-d.js} +0 -0
- /package/dist/web/assets/{zenscript-DFMywo_P.js → zenscript-C-EdUtUd.js} +0 -0
- /package/dist/web/assets/{zig-CtAjaIiF.js → zig-BD4eA5nU.js} +0 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Debug: which keyboard events reach the xterm textarea (main doc) under CDP input; effect of focus emulation.
|
|
2
|
+
import { connectApp, saveResults, sleep } from "./pip-spike-common";
|
|
3
|
+
|
|
4
|
+
const TAB = "terminal:1@panel-8281c2e3";
|
|
5
|
+
const Q = `document.querySelector('[data-tab-pool-id="${TAB}"]')`;
|
|
6
|
+
const R: Record<string, unknown> = {};
|
|
7
|
+
const h = await connectApp();
|
|
8
|
+
const { ev, cdp, sid } = h;
|
|
9
|
+
|
|
10
|
+
await ev(`(() => { const S = window.__spike; if (S.pip && !S.pip.closed) { if (S.tw && S.tw.ownerDocument !== document) S.moveBack(S.tw); S.pip.close(); } S.pip = null; return 'reset'; })()`);
|
|
11
|
+
await h.openViaUrl("/project/ppm/terminal/1");
|
|
12
|
+
await h.waitFor(`${Q} && ${Q}.style.display !== 'none'`, 15000, "terminal visible");
|
|
13
|
+
await ev(`window.__spike.tw = ${Q}; (() => { const S = window.__spike; const ta = S.tw.querySelector('.xterm-helper-textarea'); S.keyLog = [];
|
|
14
|
+
if (!S.keyProbe) { for (const t of ['keydown','keypress','input','beforeinput','keyup']) ta.addEventListener(t, e => S.keyLog.push(t + ':' + (e.key ?? e.data ?? '') + ':' + e.isTrusted)); S.keyProbe = true; }
|
|
15
|
+
return 'probe'; })()`);
|
|
16
|
+
|
|
17
|
+
async function probe(label: string) {
|
|
18
|
+
await ev(`window.__spike.keyLog = []; window.__spike.dataLog = []; window.__spike.tw.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
19
|
+
await cdp.typeText(sid, "ab");
|
|
20
|
+
await sleep(300);
|
|
21
|
+
R[label] = await ev(`({ hasFocus: document.hasFocus(), vis: document.visibilityState, active: document.activeElement && document.activeElement.className, keyLog: window.__spike.keyLog, dataLog: window.__spike.dataLog })`);
|
|
22
|
+
}
|
|
23
|
+
await probe("noEmulation");
|
|
24
|
+
await cdp.send("Page.bringToFront", {}, sid);
|
|
25
|
+
await sleep(300);
|
|
26
|
+
await probe("afterBringToFront");
|
|
27
|
+
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, sid);
|
|
28
|
+
await sleep(300);
|
|
29
|
+
await probe("withFocusEmulation");
|
|
30
|
+
// Clean the typed junk from the shell line
|
|
31
|
+
await cdp.pressKey(sid, "Escape", "Escape", 27);
|
|
32
|
+
for (let i = 0; i < 8; i++) await cdp.pressKey(sid, "Backspace", "Backspace", 8);
|
|
33
|
+
await saveResults("pip-results-key-probe.json", R);
|
|
34
|
+
cdp.close();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Verify: do node-level event listeners survive adoption into a Document PiP window? Minimal, controlled.
|
|
2
|
+
import { connectApp, saveResults, sleep } from "./pip-spike-common";
|
|
3
|
+
|
|
4
|
+
const R: Record<string, unknown> = {};
|
|
5
|
+
const h = await connectApp();
|
|
6
|
+
const { ev, cdp, sid } = h;
|
|
7
|
+
|
|
8
|
+
async function listenersOf(expr: string) {
|
|
9
|
+
const r = await cdp.send("Runtime.evaluate", { expression: expr }, sid);
|
|
10
|
+
if (!r.result?.objectId) return "no object";
|
|
11
|
+
const l = await cdp.send("DOMDebugger.getEventListeners", { objectId: r.result.objectId }, sid);
|
|
12
|
+
return (l.listeners as any[]).map((x) => `${x.type}${x.useCapture ? "(c)" : ""}`).sort();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Fresh probe nodes in the main doc with listeners; a plain iframe-less popup for comparison is not possible w/o gesture, so PiP only.
|
|
16
|
+
await ev(`(() => { const S = window.__spike; S.probeDiv = document.createElement('div'); S.probeTa = document.createElement('textarea'); S.probeDiv.append(S.probeTa);
|
|
17
|
+
S.probeHits = { div: 0, ta: 0 }; S.probeDiv.addEventListener('click', () => S.probeHits.div++, true); S.probeTa.addEventListener('keydown', () => S.probeHits.ta++); S.probeTa.addEventListener('input', () => S.probeHits.ta++, true);
|
|
18
|
+
document.body.append(S.probeDiv); return 'ok'; })()`);
|
|
19
|
+
R.before = { div: await listenersOf("window.__spike.probeDiv"), ta: await listenersOf("window.__spike.probeTa") };
|
|
20
|
+
|
|
21
|
+
// Also take the fresh terminal wrapper (tw2) along, checking its listeners right after adoption while PiP is open
|
|
22
|
+
R.tw2Before = { ta: await listenersOf("window.__spike.tw2.querySelector('.xterm-helper-textarea')"), xterm: await listenersOf("window.__spike.tw2.querySelector('.xterm')") };
|
|
23
|
+
|
|
24
|
+
R.move = await h.runGesture("pip-listener-test", `async () => {
|
|
25
|
+
const S = window.__spike; if (S.pip && !S.pip.closed) S.pip.close();
|
|
26
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 800, height: 500 }); S.pip = pip; S.copyStyles(pip.document);
|
|
27
|
+
pip.document.body.append(S.probeDiv);
|
|
28
|
+
const moved = S.moveToPip(pip, S.tw2);
|
|
29
|
+
await new Promise(r => setTimeout(r, 300));
|
|
30
|
+
// Fire synthetic events on the adopted probe nodes: do the listeners run?
|
|
31
|
+
S.probeHits = { div: 0, ta: 0 }; S.probeDiv.dispatchEvent(new MouseEvent('click', { bubbles: true })); S.probeTa.dispatchEvent(new KeyboardEvent('keydown', { key: 'a', bubbles: true })); S.probeTa.dispatchEvent(new InputEvent('input', { data: 'a', inputType: 'insertText', bubbles: true }));
|
|
32
|
+
return { moved, probeDivDoc: S.probeDiv.ownerDocument === pip.document, hitsAfterAdoption: { ...S.probeHits } };
|
|
33
|
+
}`);
|
|
34
|
+
R.afterAdoption = { div: await listenersOf("window.__spike.probeDiv"), ta: await listenersOf("window.__spike.probeTa") };
|
|
35
|
+
R.tw2AfterAdoption = { ta: await listenersOf("window.__spike.tw2.querySelector('.xterm-helper-textarea')"), xterm: await listenersOf("window.__spike.tw2.querySelector('.xterm')") };
|
|
36
|
+
|
|
37
|
+
// Type into the adopted fresh terminal via its PiP target (trusted)
|
|
38
|
+
const pipSid = await h.attachPip();
|
|
39
|
+
if (pipSid) {
|
|
40
|
+
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, pipSid);
|
|
41
|
+
await cdp.eval(pipSid, `document.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
42
|
+
await ev(`window.__spike.dataLog2 = []; 'r'`);
|
|
43
|
+
await cdp.typeText(pipSid, "echo PIP-FRESH");
|
|
44
|
+
await cdp.pressKey(pipSid, "Enter", "Enter", 13, "\r");
|
|
45
|
+
await sleep(1200);
|
|
46
|
+
R.tw2TypingInPip = await ev(`({ dataLog: window.__spike.dataLog2.join(''), echoed: window.__spike.termText(window.__spike.t2, 60).includes('PIP-FRESH') })`);
|
|
47
|
+
}
|
|
48
|
+
// Move back while the PiP is still open, then check listeners again
|
|
49
|
+
R.back = await ev(`(() => { const S = window.__spike; const r = S.moveBack(S.tw2); document.body.append(S.probeDiv); S.probeHits = { div: 0, ta: 0 }; S.probeDiv.dispatchEvent(new MouseEvent('click', { bubbles: true })); S.probeTa.dispatchEvent(new KeyboardEvent('keydown', { key: 'a', bubbles: true })); return { ...r, hitsAfterReturn: { ...S.probeHits } }; })()`);
|
|
50
|
+
R.afterReturn = { div: await listenersOf("window.__spike.probeDiv"), ta: await listenersOf("window.__spike.probeTa") };
|
|
51
|
+
R.tw2AfterReturn = { ta: await listenersOf("window.__spike.tw2.querySelector('.xterm-helper-textarea')") };
|
|
52
|
+
await ev(`window.__spike.pip.close(); 'c'`);
|
|
53
|
+
await saveResults("pip-results-listener-survival.json", R);
|
|
54
|
+
cdp.close();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Debug: compare registered DOM listeners on the round-tripped vs fresh xterm textarea (DOMDebugger.getEventListeners).
|
|
2
|
+
import { connectApp, saveResults } from "./pip-spike-common";
|
|
3
|
+
|
|
4
|
+
const R: Record<string, unknown> = {};
|
|
5
|
+
const h = await connectApp();
|
|
6
|
+
const { cdp, sid } = h;
|
|
7
|
+
|
|
8
|
+
async function listeners(label: string, expr: string) {
|
|
9
|
+
const r = await cdp.send("Runtime.evaluate", { expression: expr }, sid);
|
|
10
|
+
if (!r.result?.objectId) { R[label] = "no object: " + JSON.stringify(r.result); return; }
|
|
11
|
+
const l = await cdp.send("DOMDebugger.getEventListeners", { objectId: r.result.objectId }, sid);
|
|
12
|
+
R[label] = (l.listeners as any[]).map((x) => `${x.type}${x.useCapture ? "(capture)" : ""}${x.passive ? "(passive)" : ""} @${x.lineNumber}:${x.columnNumber}`).sort();
|
|
13
|
+
}
|
|
14
|
+
await listeners("roundTrippedTextarea", `window.__spike.tw.querySelector('.xterm-helper-textarea')`);
|
|
15
|
+
await listeners("freshTextarea", `window.__spike.tw2.querySelector('.xterm-helper-textarea')`);
|
|
16
|
+
await listeners("roundTrippedXtermEl", `window.__spike.tw.querySelector('.xterm')`);
|
|
17
|
+
await listeners("freshXtermEl", `window.__spike.tw2.querySelector('.xterm')`);
|
|
18
|
+
await saveResults("pip-results-listeners.json", R);
|
|
19
|
+
cdp.close();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// Debug: does a synchronous moveBack inside the PiP 'pagehide' handler preserve listeners? Plus canvas inventory.
|
|
2
|
+
import { connectApp, saveResults, sleep } from "./pip-spike-common";
|
|
3
|
+
|
|
4
|
+
const R: Record<string, unknown> = {};
|
|
5
|
+
const h = await connectApp();
|
|
6
|
+
const { ev, cdp, sid } = h;
|
|
7
|
+
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, sid);
|
|
8
|
+
|
|
9
|
+
async function listenersOf(expr: string) {
|
|
10
|
+
const r = await cdp.send("Runtime.evaluate", { expression: expr }, sid);
|
|
11
|
+
if (!r.result?.objectId) return "no object";
|
|
12
|
+
const l = await cdp.send("DOMDebugger.getEventListeners", { objectId: r.result.objectId }, sid);
|
|
13
|
+
return (l.listeners as any[]).map((x) => `${x.type}${x.useCapture ? "(c)" : ""}`).sort();
|
|
14
|
+
}
|
|
15
|
+
R.t2TextareaListenersNow = await listenersOf("window.__spike.tw2.querySelector('.xterm-helper-textarea')");
|
|
16
|
+
R.t2Canvases = await ev(`[...window.__spike.tw2.querySelectorAll('canvas')].map(c => ({ cls: c.className, parent: c.parentElement.className, w: c.width, h: c.height, gl: !!c.getContext('webgl2') }))`);
|
|
17
|
+
|
|
18
|
+
// Fresh terminal 3 for a clean pagehide test
|
|
19
|
+
await h.openViaUrl("/project/ppm/terminal/3");
|
|
20
|
+
const Q3 = `document.querySelector('[data-tab-pool-id^="terminal:3"]')`;
|
|
21
|
+
await h.waitFor(`${Q3} && ${Q3}.style.display !== 'none' && ${Q3}.querySelector('.xterm-helper-textarea')`, 15000, "terminal 3");
|
|
22
|
+
await sleep(2500);
|
|
23
|
+
await ev(`window.__spike.tw3 = ${Q3}; window.__spike.t3 = window.__spike.findTerminal(window.__spike.tw3); 'ok'`);
|
|
24
|
+
R.t3Before = await listenersOf("window.__spike.tw3.querySelector('.xterm-helper-textarea')");
|
|
25
|
+
async function typeMarker(marker: string) {
|
|
26
|
+
await ev(`window.__spike.tw3.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
27
|
+
await cdp.typeText(sid, `echo ${marker}`);
|
|
28
|
+
await cdp.pressKey(sid, "Enter", "Enter", 13, "\r");
|
|
29
|
+
await sleep(1300);
|
|
30
|
+
return ev(`window.__spike.termText(window.__spike.t3, 60).includes(${JSON.stringify(marker)})`);
|
|
31
|
+
}
|
|
32
|
+
R.t3Baseline = await typeMarker("T3-BASE");
|
|
33
|
+
|
|
34
|
+
// A: pagehide handler moves back synchronously, then pip.close()
|
|
35
|
+
R.pagehideA = await h.runGesture("pip-pagehide-a", `async () => {
|
|
36
|
+
const S = window.__spike; const w = S.tw3; S.phLog = [];
|
|
37
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 800, height: 500 }); S.pip = pip; S.copyStyles(pip.document); S.moveToPip(pip, w);
|
|
38
|
+
pip.addEventListener('pagehide', (e) => { S.phLog.push('pagehide owner=' + (w.ownerDocument === pip.document ? 'pip' : 'other') + ' persisted=' + e.persisted); S.moveBack(w); S.phLog.push('moved back, owner main=' + (w.ownerDocument === document)); });
|
|
39
|
+
pip.addEventListener('unload', () => S.phLog.push('unload'));
|
|
40
|
+
await new Promise(r => setTimeout(r, 400));
|
|
41
|
+
const beforeClose = { owner: w.ownerDocument === pip.document ? 'pip' : 'main' };
|
|
42
|
+
pip.close();
|
|
43
|
+
await new Promise(r => setTimeout(r, 400));
|
|
44
|
+
return { beforeClose, phLog: S.phLog, ownerAfter: w.ownerDocument === document ? 'main' : 'other', closed: pip.closed };
|
|
45
|
+
}`);
|
|
46
|
+
R.t3AfterA = await listenersOf("window.__spike.tw3.querySelector('.xterm-helper-textarea')");
|
|
47
|
+
R.t3TypingAfterA = await typeMarker("T3-AFTER-A");
|
|
48
|
+
|
|
49
|
+
// B: explicit moveBack BEFORE close (the known-good path) as control
|
|
50
|
+
R.controlB = await h.runGesture("pip-pagehide-b", `async () => {
|
|
51
|
+
const S = window.__spike; const w = S.tw3;
|
|
52
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 800, height: 500 }); S.pip = pip; S.copyStyles(pip.document); S.moveToPip(pip, w);
|
|
53
|
+
await new Promise(r => setTimeout(r, 400)); S.moveBack(w); pip.close(); await new Promise(r => setTimeout(r, 400));
|
|
54
|
+
return { ownerAfter: w.ownerDocument === document ? 'main' : 'other' };
|
|
55
|
+
}`);
|
|
56
|
+
R.t3AfterB = await listenersOf("window.__spike.tw3.querySelector('.xterm-helper-textarea')");
|
|
57
|
+
R.t3TypingAfterB = await typeMarker("T3-AFTER-B");
|
|
58
|
+
await saveResults("pip-results-pagehide.json", R);
|
|
59
|
+
cdp.close();
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Debug: ResizeObserver (created in main window) vs PiP window resizes; does pip 'resize' + manual fit() work?
|
|
2
|
+
import { connectApp, saveResults, sleep } from "./pip-spike-common";
|
|
3
|
+
|
|
4
|
+
const R: Record<string, unknown> = {};
|
|
5
|
+
const h = await connectApp();
|
|
6
|
+
const { ev, cdp, sid } = h;
|
|
7
|
+
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, sid);
|
|
8
|
+
await h.openViaUrl("/project/ppm/terminal/3");
|
|
9
|
+
await sleep(500);
|
|
10
|
+
const W = `window.__spike.tw3`, T = `window.__spike.t3`;
|
|
11
|
+
|
|
12
|
+
R.move = await h.runGesture("pip-resize", `async () => {
|
|
13
|
+
const S = window.__spike; const w = ${W}; const t = ${T};
|
|
14
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 900, height: 600 }); S.pip = pip; S.copyStyles(pip.document); S.moveToPip(pip, w);
|
|
15
|
+
S.roLog = []; const ro = new ResizeObserver(es => S.roLog.push('main-RO ' + Math.round(es[0].contentRect.width) + 'x' + Math.round(es[0].contentRect.height))); ro.observe(w);
|
|
16
|
+
const pipRo = new pip.ResizeObserver(es => S.roLog.push('pip-RO ' + Math.round(es[0].contentRect.width) + 'x' + Math.round(es[0].contentRect.height))); pipRo.observe(w);
|
|
17
|
+
pip.addEventListener('resize', () => S.roLog.push('pip-resize-event ' + pip.innerWidth + 'x' + pip.innerHeight));
|
|
18
|
+
await new Promise(r => setTimeout(r, 500));
|
|
19
|
+
return { pipSize: [pip.innerWidth, pip.innerHeight], rowsCols: [t.rows, t.cols], roLog: S.roLog.slice() };
|
|
20
|
+
}`);
|
|
21
|
+
const pipSid = await h.attachPip();
|
|
22
|
+
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, pipSid!);
|
|
23
|
+
// resizeTo inside a trusted click in the PiP
|
|
24
|
+
const pt = await cdp.eval<any>(pipSid!, `(() => { const b = document.createElement('button'); b.id = 'rz'; b.textContent = 'rz'; b.style.cssText = 'position:fixed;right:4px;bottom:4px;z-index:99999'; b.onclick = () => window.resizeTo(700, 450); document.body.append(b); const r = b.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; })()`);
|
|
25
|
+
await ev(`window.__spike.roLog = []; 'r'`);
|
|
26
|
+
await cdp.click(pipSid!, pt.x, pt.y);
|
|
27
|
+
const samples: unknown[] = [];
|
|
28
|
+
for (const ms of [300, 1000, 3000]) {
|
|
29
|
+
await sleep(ms);
|
|
30
|
+
samples.push(await ev(`({ afterMs: ${ms}, pip: [window.__spike.pip.innerWidth, window.__spike.pip.innerHeight], wrapper: [${W}.offsetWidth, ${W}.offsetHeight], rowsCols: [${T}.rows, ${T}.cols], roLog: window.__spike.roLog.slice() })`));
|
|
31
|
+
}
|
|
32
|
+
R.afterResizeTo = samples;
|
|
33
|
+
// Nudge: force a main-document rendering update; does the main RO now deliver?
|
|
34
|
+
R.afterMainNudge = await ev(`(async () => { document.body.style.outline = '1px solid transparent'; document.body.offsetWidth; await new Promise(r => setTimeout(r, 600)); document.body.style.outline = ''; return { rowsCols: [${T}.rows, ${T}.cols], roLog: window.__spike.roLog.slice() }; })()`);
|
|
35
|
+
// Glue candidate: manual fit via the FitAddon reached through the fiber (fitRef) — or xterm's proposeDimensions
|
|
36
|
+
R.manualFit = await ev(`(() => { const S = window.__spike; const t = ${T}; const w = ${W}; let fit = null; let f = S.fiberOf(w.querySelector('.xterm').parentElement);
|
|
37
|
+
for (let d = 0; f && d < 40 && !fit; d++, f = f.return) { let hk = f.memoizedState; for (let i = 0; hk && i < 200; i++, hk = hk.next) { const c = hk.memoizedState && hk.memoizedState.current; if (c && typeof c.fit === 'function' && typeof c.proposeDimensions === 'function') { fit = c; break; } } }
|
|
38
|
+
if (!fit) return 'no fitAddon'; const before = [t.rows, t.cols]; const proposed = fit.proposeDimensions(); fit.fit(); return { before, proposed, after: [t.rows, t.cols] }; })()`);
|
|
39
|
+
await h.pipShot(pipSid, "spike-01e-terminal-in-pip-after-manual-fit.png");
|
|
40
|
+
await ev(`(() => { const S = window.__spike; S.moveBack(${W}); S.pip.close(); return 'done'; })()`);
|
|
41
|
+
await saveResults("pip-results-resize.json", R);
|
|
42
|
+
cdp.close();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Stage 1: authenticate the spike Chrome, open terminal + editor tabs, verify instances reachable.
|
|
2
|
+
import { Database } from "bun:sqlite";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CdpClient, sleep } from "./cdp-client";
|
|
6
|
+
|
|
7
|
+
const PORT = 9333;
|
|
8
|
+
const APP = "http://localhost:5173";
|
|
9
|
+
const helpers = await Bun.file(join(import.meta.dir, "pip-page-helpers.js")).text();
|
|
10
|
+
|
|
11
|
+
const db = new Database(join(homedir(), ".ppm", "ppm.dev.db"), { readonly: true });
|
|
12
|
+
const token = JSON.parse((db.query("SELECT value FROM config WHERE key='auth'").get() as any).value).token as string;
|
|
13
|
+
|
|
14
|
+
const cdp = await CdpClient.connect(PORT);
|
|
15
|
+
const page = (await cdp.targets()).find((t) => t.type === "page" && t.url.startsWith(APP));
|
|
16
|
+
if (!page) throw new Error("no app page target: " + JSON.stringify(await cdp.targets()));
|
|
17
|
+
const sid = await cdp.attach(page.targetId);
|
|
18
|
+
await cdp.send("Page.enable", {}, sid);
|
|
19
|
+
await cdp.send("Runtime.enable", {}, sid);
|
|
20
|
+
|
|
21
|
+
async function waitFor(expr: string, timeoutMs = 20000, label = expr) {
|
|
22
|
+
const t0 = Date.now();
|
|
23
|
+
while (Date.now() - t0 < timeoutMs) {
|
|
24
|
+
if (await cdp.eval<boolean>(sid, `!!(${expr})`)) return;
|
|
25
|
+
await sleep(250);
|
|
26
|
+
}
|
|
27
|
+
throw new Error(`timeout waiting: ${label}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Auth
|
|
31
|
+
const hasToken = await cdp.eval<boolean>(sid, `localStorage.getItem('ppm-auth-token') === ${JSON.stringify(token)}`);
|
|
32
|
+
if (!hasToken) {
|
|
33
|
+
await cdp.eval(sid, `localStorage.setItem('ppm-auth-token', ${JSON.stringify(token)}); 'set'`);
|
|
34
|
+
await cdp.send("Page.navigate", { url: `${APP}/project/ppm` }, sid);
|
|
35
|
+
await sleep(1500);
|
|
36
|
+
}
|
|
37
|
+
await waitFor(`document.querySelector('[data-panel-drop-zone]')`, 30000, "app shell");
|
|
38
|
+
console.log("app shell ready, url:", await cdp.eval(sid, "location.href"));
|
|
39
|
+
|
|
40
|
+
// Open terminal via URL routing (pushState + popstate → autoOpenFromUrl)
|
|
41
|
+
async function openViaUrl(path: string) {
|
|
42
|
+
await cdp.eval(sid, `history.pushState(null, '', ${JSON.stringify(path)}); dispatchEvent(new PopStateEvent('popstate')); 'ok'`);
|
|
43
|
+
}
|
|
44
|
+
await openViaUrl("/project/ppm/terminal/1");
|
|
45
|
+
await waitFor(`document.querySelector('[data-tab-pool-id^="terminal"] .xterm-helper-textarea')`, 20000, "xterm");
|
|
46
|
+
await openViaUrl("/project/ppm/editor/.spike/scratch-editor-target.ts");
|
|
47
|
+
await waitFor(`document.querySelector('[data-tab-pool-id^="editor"] .monaco-editor .view-lines')`, 30000, "monaco");
|
|
48
|
+
|
|
49
|
+
await cdp.eval(sid, helpers);
|
|
50
|
+
const info = await cdp.eval(sid, `(() => {
|
|
51
|
+
const S = window.__spike;
|
|
52
|
+
const tw = document.querySelector('[data-tab-pool-id^="terminal"]');
|
|
53
|
+
const ew = document.querySelector('[data-tab-pool-id^="editor"]');
|
|
54
|
+
const term = S.findTerminal(tw); const ed = S.findEditor(ew);
|
|
55
|
+
return {
|
|
56
|
+
wrappers: [...document.querySelectorAll('[data-tab-pool-id]')].map(w => ({ id: w.dataset.tabPoolId, display: w.style.display, parent: w.parentElement?.className })),
|
|
57
|
+
termFound: !!term, termSize: term && { rows: term.rows, cols: term.cols }, termTail: term && S.termText(term, 5),
|
|
58
|
+
editorFound: !!ed, editorLine1: ed && ed.getModel().getLineContent(1), layout: ed && ed.getLayoutInfo().width,
|
|
59
|
+
htmlClass: document.documentElement.className, sheets: document.styleSheets.length, monacoGlobal: !!window.monaco,
|
|
60
|
+
};
|
|
61
|
+
})()`);
|
|
62
|
+
console.log(JSON.stringify(info, null, 2));
|
|
63
|
+
cdp.close();
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// Debug stage: why does typing stop echoing after the PiP move, and does the DOM renderer survive?
|
|
2
|
+
import { connectApp, saveResults, sleep } from "./pip-spike-common";
|
|
3
|
+
|
|
4
|
+
const TAB = "terminal:1@panel-8281c2e3";
|
|
5
|
+
const Q = `document.querySelector('[data-tab-pool-id="${TAB}"]')`;
|
|
6
|
+
const W = `window.__spike.tw`;
|
|
7
|
+
const T = `window.__spike.findTerminal(${W})`;
|
|
8
|
+
const R: Record<string, unknown> = {};
|
|
9
|
+
const h = await connectApp();
|
|
10
|
+
const { ev, cdp, sid } = h;
|
|
11
|
+
|
|
12
|
+
R.reset = await ev(`(() => { const S = window.__spike; const r = { hadPip: !!(S.pip && !S.pip.closed), twInPip: !!(S.tw && S.tw.ownerDocument !== document) };
|
|
13
|
+
if (r.twInPip) S.moveBack(S.tw); if (r.hadPip) S.pip.close(); S.pip = null; S.results = {}; return r; })()`);
|
|
14
|
+
await sleep(500);
|
|
15
|
+
await h.openViaUrl("/project/ppm/terminal/1");
|
|
16
|
+
await h.waitFor(`${Q} && ${Q}.style.display !== 'none' && ${Q}.querySelector('.xterm-helper-textarea')`, 15000, "terminal visible");
|
|
17
|
+
await ev(`window.__spike.tw = ${Q}; 'held'`);
|
|
18
|
+
|
|
19
|
+
// Instrument: xterm onData, WebSocket ref (fiber hook whose .current is a WebSocket), ws messages
|
|
20
|
+
R.instrument = await ev(`(() => {
|
|
21
|
+
const S = window.__spike; const w = ${W}; const t = ${T};
|
|
22
|
+
S.dataLog = []; S.wsMsgs = 0; S.writes = 0;
|
|
23
|
+
if (!S.instrumented) {
|
|
24
|
+
t.onData(d => S.dataLog.push(d));
|
|
25
|
+
const origWrite = t.write.bind(t); t.write = (d, cb) => { S.writes++; return origWrite(d, cb); };
|
|
26
|
+
const container = w.querySelector('.xterm').parentElement; let f = S.fiberOf(container); let ws = null;
|
|
27
|
+
for (let depth = 0; f && depth < 40 && !ws; depth++, f = f.return) {
|
|
28
|
+
let hook = f.memoizedState;
|
|
29
|
+
for (let i = 0; hook && i < 200; i++, hook = hook.next) { const c = hook.memoizedState && hook.memoizedState.current; if (c instanceof WebSocket) { ws = c; S.wsHook = hook.memoizedState; break; } }
|
|
30
|
+
}
|
|
31
|
+
if (ws) ws.addEventListener('message', () => S.wsMsgs++);
|
|
32
|
+
S.instrumented = true;
|
|
33
|
+
}
|
|
34
|
+
const ws = S.wsHook && S.wsHook.current;
|
|
35
|
+
return { wsFound: !!ws, wsState: ws && ws.readyState, wsUrl: ws && ws.url, rows: t.rows, cols: t.cols, textareaDoc: w.querySelector('.xterm-helper-textarea').ownerDocument === document };
|
|
36
|
+
})()`);
|
|
37
|
+
|
|
38
|
+
async function typeAndCheck(label: string, marker: string, targetSid: string, focusExpr: string) {
|
|
39
|
+
await cdp.eval(targetSid, focusExpr);
|
|
40
|
+
await ev(`window.__spike.dataLog = []; window.__spike.wsMsgs = 0; window.__spike.writes = 0; 'r'`);
|
|
41
|
+
await cdp.typeText(targetSid, `echo ${marker}`);
|
|
42
|
+
await cdp.pressKey(targetSid, "Enter", "Enter", 13, "\r");
|
|
43
|
+
await sleep(1500);
|
|
44
|
+
R[label] = await ev(`(() => { const S = window.__spike; const t = ${T}; const ws = S.wsHook && S.wsHook.current;
|
|
45
|
+
return { dataSent: S.dataLog.join(''), wsMsgs: S.wsMsgs, writes: S.writes, wsState: ws && ws.readyState, echoed: S.termText(t, 80).includes(${JSON.stringify(marker)}), tail: S.termText(t, 4) }; })()`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
await typeAndCheck("mainBeforePip", "DBG-MAIN-1", sid, `window.__spike.tw.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
49
|
+
|
|
50
|
+
R.move = await h.runGesture("pip-terminal-dbg", `async () => {
|
|
51
|
+
const S = window.__spike; const w = ${W};
|
|
52
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 900, height: 600 });
|
|
53
|
+
S.pip = pip; S.copyStyles(pip.document); const moved = S.moveToPip(pip, w);
|
|
54
|
+
await new Promise(r => setTimeout(r, 400));
|
|
55
|
+
const gl = [...w.querySelectorAll('canvas')].map(c => { const ctx = c.getContext('webgl2') || c.getContext('webgl'); return ctx ? { lost: ctx.isContextLost(), dbw: ctx.drawingBufferWidth, dbh: ctx.drawingBufferHeight } : { ctx2d: !!c.getContext('2d') }; });
|
|
56
|
+
return { moved, gl, pipSize: [pip.innerWidth, pip.innerHeight], screenBg: pip.getComputedStyle(w.querySelector('.xterm-viewport')).backgroundColor };
|
|
57
|
+
}`);
|
|
58
|
+
const pipSid = await h.attachPip();
|
|
59
|
+
R.pipAttached = !!pipSid;
|
|
60
|
+
if (pipSid) {
|
|
61
|
+
R.pipFocus = await cdp.eval(pipSid, `(() => { const ta = document.querySelector('.xterm-helper-textarea'); ta.focus(); return { active: document.activeElement === ta, hasFocus: document.hasFocus(), vis: document.visibilityState }; })()`);
|
|
62
|
+
await typeAndCheck("pipTrusted", "DBG-PIP-1", pipSid, `document.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
63
|
+
R.shotWebgl = await h.pipShot(pipSid, "spike-01c-terminal-pip-webgl-debug.png");
|
|
64
|
+
// Force GL context loss → app's onContextLoss disposes the WebGL addon → DOM renderer
|
|
65
|
+
R.forceLoss = await ev(`(async () => { const w = ${W}; const t = ${T}; const c = w.querySelector('canvas'); const gl = c && (c.getContext('webgl2') || c.getContext('webgl'));
|
|
66
|
+
if (!gl) return 'no gl canvas'; const ext = gl.getExtension('WEBGL_lose_context'); if (!ext) return 'no lose_context ext'; ext.loseContext();
|
|
67
|
+
await new Promise(r => setTimeout(r, 800)); t.refresh(0, t.rows - 1); await new Promise(r => setTimeout(r, 300));
|
|
68
|
+
return { canvasesLeft: w.querySelectorAll('canvas').length, rowsDom: w.querySelectorAll('.xterm-rows > div').length, rowsText: [...w.querySelectorAll('.xterm-rows > div')].slice(0, 3).map(r => r.textContent.trim()).filter(Boolean) }; })()`);
|
|
69
|
+
await sleep(500);
|
|
70
|
+
R.shotDom = await h.pipShot(pipSid, "spike-01d-terminal-pip-dom-renderer.png");
|
|
71
|
+
await typeAndCheck("pipTrustedAfterDomRenderer", "DBG-PIP-2", pipSid, `document.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
72
|
+
// Resize check with DOM renderer
|
|
73
|
+
R.resizeDom = await ev(`(async () => { const w = ${W}; const t = ${T}; const b = [t.rows, t.cols]; w.style.height = '50%'; await new Promise(r => setTimeout(r, 700)); const a = [t.rows, t.cols]; w.style.height = '100%'; await new Promise(r => setTimeout(r, 700)); return { before: b, after: a, restored: [t.rows, t.cols] }; })()`);
|
|
74
|
+
}
|
|
75
|
+
R.back = await ev(`(async () => { const S = window.__spike; const w = ${W}; const t = ${T}; const r = S.moveBack(w); await new Promise(res => setTimeout(res, 800)); return { ...r, rows: t.rows, cols: t.cols }; })()`);
|
|
76
|
+
await ev(`window.__spike.pip.close(); 'c'`);
|
|
77
|
+
await sleep(400);
|
|
78
|
+
await typeAndCheck("mainAfterReturn", "DBG-MAIN-2", sid, `window.__spike.tw.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
79
|
+
await cdp.screenshot(sid, "C:/Users/PC/ppm/plans/reports/screenshots/spike-03b-terminal-after-return-dom-renderer.png");
|
|
80
|
+
await saveResults("pip-results-terminal-debug.json", R);
|
|
81
|
+
cdp.close();
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Stage 2 (clean re-run on a healthy terminal): full PASS/FAIL matrix for xterm in a Document PiP window.
|
|
2
|
+
import { connectApp, saveResults, sleep } from "./pip-spike-common";
|
|
3
|
+
|
|
4
|
+
const TAB = "terminal:2@panel-8281c2e3";
|
|
5
|
+
const Q = `document.querySelector('[data-tab-pool-id="${TAB}"]')`;
|
|
6
|
+
const W = `window.__spike.tw2`;
|
|
7
|
+
const T = `window.__spike.t2`;
|
|
8
|
+
const R: Record<string, unknown> = {};
|
|
9
|
+
const h = await connectApp();
|
|
10
|
+
const { ev, cdp, sid } = h;
|
|
11
|
+
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, sid);
|
|
12
|
+
|
|
13
|
+
await ev(`(() => { const S = window.__spike; if (S.pip && !S.pip.closed) { if (S.tw2 && S.tw2.ownerDocument !== document) S.moveBack(S.tw2); S.pip.close(); } S.pip = null; S.results = {}; return 'reset'; })()`);
|
|
14
|
+
await h.openViaUrl("/project/ppm/terminal/2");
|
|
15
|
+
await h.waitFor(`${Q} && ${Q}.style.display !== 'none' && ${Q}.querySelector('.xterm-helper-textarea')`, 15000, "terminal 2 visible");
|
|
16
|
+
await ev(`(() => { const S = window.__spike; S.tw2 = ${Q}; S.t2 = S.findTerminal(S.tw2); if (!S.t2Hooked) { S.dataLog2 = []; S.t2.onData(d => S.dataLog2.push(d)); S.t2Hooked = true; } return 'held'; })()`);
|
|
17
|
+
|
|
18
|
+
async function typeMarker(targetSid: string, marker: string, focusExpr: string) {
|
|
19
|
+
await cdp.eval(targetSid, focusExpr);
|
|
20
|
+
await ev(`window.__spike.dataLog2 = []; 'r'`);
|
|
21
|
+
await cdp.typeText(targetSid, `echo ${marker}`);
|
|
22
|
+
await cdp.pressKey(targetSid, "Enter", "Enter", 13, "\r");
|
|
23
|
+
await sleep(1300);
|
|
24
|
+
return ev(`({ sent: window.__spike.dataLog2.join('').includes(${JSON.stringify(marker)}), echoed: window.__spike.termText(${T}, 60).includes(${JSON.stringify(marker)}) })`);
|
|
25
|
+
}
|
|
26
|
+
R.baselineTyping = await typeMarker(sid, "T2-BASE", `${W}.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
27
|
+
R.baselineSize = await ev(`({ rows: ${T}.rows, cols: ${T}.cols, canvases: ${W}.querySelectorAll('canvas').length })`);
|
|
28
|
+
|
|
29
|
+
R.move = await h.runGesture("pip-terminal-v2", `async () => {
|
|
30
|
+
const S = window.__spike; const w = ${W}; const t = ${T};
|
|
31
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 900, height: 600 }); S.pip = pip;
|
|
32
|
+
const styles = S.copyStyles(pip.document); const moved = S.moveToPip(pip, w); S.installClickProbes(pip, w);
|
|
33
|
+
S.glEvents = []; for (const c of w.querySelectorAll('canvas')) { c.addEventListener('webglcontextlost', () => S.glEvents.push('lost')); c.addEventListener('webglcontextrestored', () => S.glEvents.push('restored')); }
|
|
34
|
+
await new Promise(r => setTimeout(r, 600));
|
|
35
|
+
const gl = [...w.querySelectorAll('canvas')].map(c => { const g = c.getContext('webgl2'); return g ? { webgl2: true, lost: g.isContextLost() } : { webgl2: false }; });
|
|
36
|
+
return { styles, moved, pipSize: [pip.innerWidth, pip.innerHeight], rowsCols: [t.rows, t.cols], canvasesNow: w.querySelectorAll('canvas').length, gl, glEvents: S.glEvents, domRows: w.querySelectorAll('.xterm-rows > div').length,
|
|
37
|
+
theme: { pipHtmlClass: pip.document.documentElement.className, statusBg: pip.getComputedStyle(w.querySelector('.bg-surface')).backgroundColor, mainSurfaceBg: getComputedStyle(document.querySelector('.bg-surface') || document.body).backgroundColor } };
|
|
38
|
+
}`);
|
|
39
|
+
const pipSid = await h.attachPip();
|
|
40
|
+
R.pipAttached = !!pipSid;
|
|
41
|
+
if (!pipSid) throw new Error("no pip target");
|
|
42
|
+
await cdp.send("Emulation.setFocusEmulationEnabled", { enabled: true }, pipSid);
|
|
43
|
+
await sleep(700);
|
|
44
|
+
R.afterFocusEmu = await ev(`({ canvases: ${W}.querySelectorAll('canvas').length, domRows: ${W}.querySelectorAll('.xterm-rows > div').length, glEvents: window.__spike.glEvents, rowsCols: [${T}.rows, ${T}.cols], vis: window.__spike.pip.document.visibilityState })`);
|
|
45
|
+
R.shotInPip = await h.pipShot(pipSid, "spike-01-terminal-in-pip.png");
|
|
46
|
+
|
|
47
|
+
// (b) keyboard — trusted keys via the PiP target
|
|
48
|
+
R.typingInPip = await typeMarker(pipSid, "T2-IN-PIP", `document.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
49
|
+
R.shotTyped = await h.pipShot(pipSid, "spike-01b-terminal-in-pip-typed.png");
|
|
50
|
+
|
|
51
|
+
// (c) drag selection — trusted mouse via PiP target, over the row that has the echoed text
|
|
52
|
+
R.dragSelect = await (async () => {
|
|
53
|
+
const geo = await cdp.eval<any>(pipSid, `(() => { const s = document.querySelector('.xterm-screen').getBoundingClientRect(); return { x: s.x, y: s.y, w: s.width, h: s.height }; })()`);
|
|
54
|
+
const row = await ev<number>(`(() => { const t = ${T}; const b = t.buffer.active; for (let i = b.length - 1; i >= 0; i--) { if ((b.getLine(i)?.translateToString(true) ?? '').includes('T2-IN-PIP')) return i - b.viewportY; } return -1; })()`);
|
|
55
|
+
const cell = await ev<any>(`(() => { const d = ${T}._core._renderService.dimensions.css.cell; return { w: d.width, h: d.height }; })()`);
|
|
56
|
+
if (row < 0) return { error: "row not found" };
|
|
57
|
+
const y = geo.y + row * cell.h + cell.h / 2;
|
|
58
|
+
const x0 = geo.x + 2;
|
|
59
|
+
await cdp.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: x0, y }, pipSid);
|
|
60
|
+
await cdp.send("Input.dispatchMouseEvent", { type: "mousePressed", x: x0, y, button: "left", clickCount: 1 }, pipSid);
|
|
61
|
+
for (let i = 1; i <= 8; i++) await cdp.send("Input.dispatchMouseEvent", { type: "mouseMoved", x: x0 + i * cell.w * 2, y, button: "left", buttons: 1 }, pipSid);
|
|
62
|
+
await cdp.send("Input.dispatchMouseEvent", { type: "mouseReleased", x: x0 + 16 * cell.w, y, button: "left", clickCount: 1 }, pipSid);
|
|
63
|
+
await sleep(300);
|
|
64
|
+
const sel = await ev<string>(`${T}.getSelection()`);
|
|
65
|
+
await h.pipShot(pipSid, "spike-01c-terminal-in-pip-selection.png");
|
|
66
|
+
await ev(`${T}.clearSelection(); 'c'`);
|
|
67
|
+
return { row, cell, selection: sel, pass: sel.length > 0 };
|
|
68
|
+
})();
|
|
69
|
+
|
|
70
|
+
// (d) resize: style change on wrapper (ResizeObserver path) and window.resizeTo inside a trusted click in the PiP doc
|
|
71
|
+
R.resizeViaStyle = await ev(`(async () => { const w = ${W}; const t = ${T}; const before = [t.rows, t.cols]; w.style.height = '50%'; w.style.width = '70%';
|
|
72
|
+
await new Promise(r => setTimeout(r, 800)); const after = [t.rows, t.cols]; w.style.height = '100%'; w.style.width = '100%'; await new Promise(r => setTimeout(r, 800));
|
|
73
|
+
return { before, after, restored: [t.rows, t.cols], refit: before[0] !== after[0] || before[1] !== after[1] }; })()`);
|
|
74
|
+
R.resizeViaWindow = await (async () => {
|
|
75
|
+
const pt = await cdp.eval<any>(pipSid, `(() => { const b = document.createElement('button'); b.id = 'rz'; b.textContent = 'rz'; b.style.cssText = 'position:fixed;right:4px;bottom:4px;z-index:99999'; b.onclick = () => { try { window.resizeTo(700, 450); window.__rz = 'ok'; } catch (e) { window.__rz = String(e); } }; document.body.append(b); const r = b.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; })()`);
|
|
76
|
+
const before = await ev<any>(`[${T}.rows, ${T}.cols, window.__spike.pip.innerWidth, window.__spike.pip.innerHeight]`);
|
|
77
|
+
await cdp.click(pipSid, pt.x, pt.y);
|
|
78
|
+
await sleep(1200);
|
|
79
|
+
const after = await ev<any>(`[${T}.rows, ${T}.cols, window.__spike.pip.innerWidth, window.__spike.pip.innerHeight]`);
|
|
80
|
+
const err = await cdp.eval(pipSid, `window.__rz`);
|
|
81
|
+
await cdp.eval(pipSid, `document.getElementById('rz').remove(); 'x'`);
|
|
82
|
+
return { before, after, resizeToResult: err, refit: before[0] !== after[0] || before[1] !== after[1] };
|
|
83
|
+
})();
|
|
84
|
+
R.shotResized = await h.pipShot(pipSid, "spike-01d-terminal-in-pip-resized.png");
|
|
85
|
+
|
|
86
|
+
// (f) React onClick inside the moved wrapper: trusted click on "Chat" (would toast "Sent to chat" in main doc)
|
|
87
|
+
R.reactClickInPip = await (async () => {
|
|
88
|
+
const pt = await cdp.eval<any>(pipSid, `(() => { const r = document.querySelector('button[title="Send to Chat"]').getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; })()`);
|
|
89
|
+
await ev(`window.__spike.probe = { mainDocClick: 0, pipDocClick: 0, wrapperClick: 0, reactRootClick: 0 }; 'r'`);
|
|
90
|
+
await cdp.click(pipSid, pt.x, pt.y);
|
|
91
|
+
await sleep(700);
|
|
92
|
+
return ev(`({ probe: { ...window.__spike.probe }, toast: window.__spike.toastText(), reactHandlerFired: window.__spike.toastText().includes('Sent to chat') })`);
|
|
93
|
+
})();
|
|
94
|
+
|
|
95
|
+
// Pull-back probe: re-render ReparentingTab by switching active tab away and back via URL
|
|
96
|
+
R.pullback = await (async () => {
|
|
97
|
+
const inPip0 = await ev<boolean>(`${W}.ownerDocument !== document`);
|
|
98
|
+
await h.openViaUrl("/project/ppm/editor/.spike/scratch-editor-target.ts");
|
|
99
|
+
const afterAway = await ev<any>(`({ inPip: ${W}.ownerDocument !== document, display: ${W}.style.display, parentIsSlot: ${W}.parentElement && ${W}.parentElement.className.includes('absolute inset-0') })`);
|
|
100
|
+
await h.openViaUrl("/project/ppm/terminal/2");
|
|
101
|
+
const afterBack = await ev<any>(`({ inPip: ${W}.ownerDocument !== document, display: ${W}.style.display })`);
|
|
102
|
+
return { inPipBefore: inPip0, afterSwitchAway: afterAway, afterSwitchBack: afterBack, note: "ReparentingTab layout effect re-appends wrapper into the panel slot on every re-render" };
|
|
103
|
+
})();
|
|
104
|
+
// Whatever state we are in now, ensure wrapper is in main, then test pagehide→moveBack survival with a second PiP
|
|
105
|
+
R.ensureBack = await ev(`(() => { const S = window.__spike; const w = ${W}; const was = w.ownerDocument !== document; if (was) S.moveBack(w); return { wasInPip: was, inMain: w.ownerDocument === document }; })()`);
|
|
106
|
+
await ev(`window.__spike.pip.close(); 'c'`);
|
|
107
|
+
await sleep(600);
|
|
108
|
+
R.afterReturnTyping = await typeMarker(sid, "T2-AFTER-RETURN", `${W}.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
109
|
+
R.afterReturnState = await ev(`(async () => { const S = window.__spike; const w = ${W}; const t = ${T}; const txt = S.termText(t, 200);
|
|
110
|
+
const btn = w.querySelector('button[title="Send to Chat"]'); btn.click(); await new Promise(r => setTimeout(r, 600));
|
|
111
|
+
return { rows: t.rows, cols: t.cols, canvases: w.querySelectorAll('canvas').length, scrollback: { base: txt.includes('T2-BASE'), inPip: txt.includes('T2-IN-PIP'), after: txt.includes('T2-AFTER-RETURN') }, reactClickToast: S.toastText().includes('Sent to chat') }; })()`);
|
|
112
|
+
await cdp.screenshot(sid, "C:/Users/PC/ppm/plans/reports/screenshots/spike-03-terminal-after-return.png");
|
|
113
|
+
|
|
114
|
+
// pagehide → move back synchronously: do listeners survive the PiP window closing?
|
|
115
|
+
R.pagehideGuard = await h.runGesture("pip-terminal-pagehide", `async () => {
|
|
116
|
+
const S = window.__spike; const w = ${W};
|
|
117
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 800, height: 500 }); S.pip = pip; S.copyStyles(pip.document); S.moveToPip(pip, w);
|
|
118
|
+
pip.addEventListener('pagehide', () => { S.moveBack(w); S.note('pagehide: moved back'); });
|
|
119
|
+
await new Promise(r => setTimeout(r, 500));
|
|
120
|
+
pip.close();
|
|
121
|
+
await new Promise(r => setTimeout(r, 500));
|
|
122
|
+
return { inMain: w.ownerDocument === document, closed: pip.closed };
|
|
123
|
+
}`);
|
|
124
|
+
R.afterPagehideTyping = await typeMarker(sid, "T2-AFTER-PAGEHIDE", `${W}.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
125
|
+
// Control (destructive, last): close a PiP with the wrapper still inside, then let React pull it back — listeners stripped?
|
|
126
|
+
R.closeWithWrapperInside = await h.runGesture("pip-terminal-destroy", `async () => {
|
|
127
|
+
const S = window.__spike; const w = ${W};
|
|
128
|
+
const pip = await documentPictureInPicture.requestWindow({ width: 800, height: 500 }); S.pip = pip; S.copyStyles(pip.document); S.moveToPip(pip, w);
|
|
129
|
+
await new Promise(r => setTimeout(r, 500)); pip.close(); await new Promise(r => setTimeout(r, 500));
|
|
130
|
+
const r = { ownerAfterClose: w.ownerDocument === document ? 'main' : 'dead-pip-doc', connected: w.isConnected };
|
|
131
|
+
S.moveBack(w); // simulate React's layout effect re-adopting from the destroyed document
|
|
132
|
+
return { ...r, inMainNow: w.ownerDocument === document };
|
|
133
|
+
}`);
|
|
134
|
+
await sleep(500);
|
|
135
|
+
R.afterDestroyTyping = await typeMarker(sid, "T2-AFTER-DESTROY", `${W}.querySelector('.xterm-helper-textarea').focus(); 'f'`);
|
|
136
|
+
R.afterDestroyInputApi = await ev(`(async () => { const S = window.__spike; S.dataLog2 = []; S.t2.input('echo T2-INPUT-API\\r', true); await new Promise(r => setTimeout(r, 1200)); return { sent: S.dataLog2.join('').includes('T2-INPUT-API'), echoed: S.termText(S.t2, 60).includes('T2-INPUT-API') }; })()`);
|
|
137
|
+
R.log = await ev(`window.__spike.log.slice(-10)`);
|
|
138
|
+
await saveResults("pip-results-terminal-v2.json", R);
|
|
139
|
+
cdp.close();
|