@hienlh/ppm 0.19.0 → 0.19.2
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/CHANGELOG.md +13 -1
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/cli-reference.md +4 -4
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/dist/web/assets/{adaptive-context-menu-JfuUSqbe.js → adaptive-context-menu-BbuRVTLn.js} +1 -1
- package/dist/web/assets/{ai-resource-editor-MfdJKVM5.js → ai-resource-editor-BCCOUzox.js} +1 -1
- package/dist/web/assets/{ai-settings-section-CJE7jFsj.js → ai-settings-section-BEM1z7kp.js} +1 -1
- package/dist/web/assets/{angular-html-VzxSzTCy.js → angular-html-BlcrLjUx.js} +1 -1
- package/dist/web/assets/{angular-ts-CmJ4bmzM.js → angular-ts-BUjtceAJ.js} +1 -1
- package/dist/web/assets/{api-client-qRWu6_s5.js → api-client-BzWM7XPR.js} +1 -1
- package/dist/web/assets/api-client-D1CePgQ4.js +1 -0
- package/dist/web/assets/api-settings-CNtKkHqW.js +1 -0
- package/dist/web/assets/{api-settings-CPg4yGvS.js → api-settings-Cubuqjsu.js} +1 -1
- package/dist/web/assets/{api-themes-DsAp8m7m.js → api-themes-YsZgf6Xj.js} +1 -1
- package/dist/web/assets/{apl-do17bnVx.js → apl-B3g0v1pk.js} +1 -1
- package/dist/web/assets/{astro-ClY0e0OA.js → astro-FRnyn7cH.js} +1 -1
- package/dist/web/assets/{audio-preview-Fw935Mok.js → audio-preview-DWTRm4HC.js} +1 -1
- package/dist/web/assets/{blade-BXSdXDGq.js → blade-NLdOqUKw.js} +1 -1
- package/dist/web/assets/{bot-CWZAuloY.js → bot-D6sx11y0.js} +1 -1
- package/dist/web/assets/{bsl-MxsMKDUZ.js → bsl-CenHZfaU.js} +1 -1
- package/dist/web/assets/{button-CrwgGd1y.js → button-Cq8yixjf.js} +1 -1
- package/dist/web/assets/{cairo-4CIrzX_p.js → cairo-B_WR0aiQ.js} +1 -1
- package/dist/web/assets/chat-tab-CmXGsJGc.js +15 -0
- package/dist/web/assets/{chevron-down-D7CbB5f6.js → chevron-down-Dp0rpHb8.js} +1 -1
- package/dist/web/assets/chevron-right-De-Wz5Lz.js +1 -0
- package/dist/web/assets/circle-BCy0AUCo.js +1 -0
- package/dist/web/assets/{circle-question-mark-BBzFZrNh.js → circle-question-mark-CzR7YRc-.js} +1 -1
- package/dist/web/assets/clock-C1CQUQPZ.js +1 -0
- package/dist/web/assets/{cobol-phPOE89d.js → cobol-DOynhWYj.js} +1 -1
- package/dist/web/assets/code-DJgYrFzm.js +1 -0
- package/dist/web/assets/code-editor-DtHXzNZ1.js +7 -0
- package/dist/web/assets/{coffee-Cjuukfz3.js → coffee-Bn6dbw4P.js} +1 -1
- package/dist/web/assets/{conflict-editor-Ni0PPsKu.js → conflict-editor-Cgb-z12D.js} +1 -1
- package/dist/web/assets/{context-menu-BEAa1qhd.js → context-menu-DfWZAxQy.js} +1 -1
- package/dist/web/assets/{copy-CbPdNp7E.js → copy-BewHj66E.js} +1 -1
- package/dist/web/assets/{cpp-CT7tGBC3.js → cpp-CoZR9t8r.js} +1 -1
- package/dist/web/assets/{createLucideIcon-ConhwJnb.js → createLucideIcon-D8pyde1A.js} +1 -1
- package/dist/web/assets/{crystal-D8U1Qnqh.js → crystal-BSheONSg.js} +1 -1
- package/dist/web/assets/{csv-preview-Coc2oed1.js → csv-preview-BZMHfFH3.js} +1 -1
- package/dist/web/assets/{data-grid-overlay-editor-B8WQkZDB.js → data-grid-overlay-editor-gwPoVSCU.js} +1 -1
- package/dist/web/assets/{data-grid-types-KpjaKAci.js → data-grid-types-Dq_H1IPa.js} +1 -1
- package/dist/web/assets/{database-BqyeGogo.js → database-Y3ESDK4-.js} +1 -1
- package/dist/web/assets/database-viewer-GVaQVMdb.js +1 -0
- package/dist/web/assets/{dialog-DrL3WEXd.js → dialog-BSfuiTkJ.js} +1 -1
- package/dist/web/assets/{diff-viewer-CT0lmDc9.js → diff-viewer-BG5_fH1E.js} +1 -1
- package/dist/web/assets/{dist-C2_dKAa_.js → dist-aDSxTR_v.js} +1 -1
- package/dist/web/assets/{docx-preview-76KDw1eE.js → docx-preview-DqVDOMmv.js} +1 -1
- package/dist/web/assets/{download-DAF7SXcf.js → download-DG3_9xXy.js} +1 -1
- package/dist/web/assets/{edge-Db4ze6bw.js → edge-DTtoslQu.js} +1 -1
- package/dist/web/assets/{edit-diff-preview-DyC_-4My.js → edit-diff-preview-CXSbSUBX.js} +1 -1
- package/dist/web/assets/{elixir-RZPZ0472.js → elixir-CIBCZ3Zi.js} +1 -1
- package/dist/web/assets/{elm-DNZcQt_7.js → elm-BLmb7K1H.js} +1 -1
- package/dist/web/assets/{erb-DRONsZXs.js → erb-BBY8ApRd.js} +1 -1
- package/dist/web/assets/{erlang-DeG0-QwJ.js → erlang-D5Zb5_P0.js} +1 -1
- package/dist/web/assets/{esm-CZy-sSoK.js → esm-6F8v1jLL.js} +1 -1
- package/dist/web/assets/explorer-body-BPFnjxYj.js +2 -0
- package/dist/web/assets/explorer-window-content-Da1T9uM4.js +1 -0
- package/dist/web/assets/{extension-store-ClQpnxQr.js → extension-store-Bhu--fPX.js} +1 -1
- package/dist/web/assets/{extension-webview-BW5GuBnH.js → extension-webview-BSh6KGd7.js} +1 -1
- package/dist/web/assets/{external-link-ojDHcQxQ.js → external-link-B6Hl0U4X.js} +1 -1
- package/dist/web/assets/{eye-off-Rq1n2-oe.js → eye-off-CUdzgmX8.js} +1 -1
- package/dist/web/assets/{file-exclamation-point-Bpg-zDPP.js → file-exclamation-point-JzhTU2TX.js} +1 -1
- package/dist/web/assets/{file-store-28e44KP3.js → file-store-6HW2Lfl4.js} +1 -1
- package/dist/web/assets/{folder-symlink-LD-mr54V.js → folder-symlink-Dx1hOk8X.js} +1 -1
- package/dist/web/assets/{fortran-fixed-form-CK5VRJNd.js → fortran-fixed-form-CBdwkEUJ.js} +1 -1
- package/dist/web/assets/{fsharp-TVVgzHWp.js → fsharp-AT4XdVYH.js} +1 -1
- package/dist/web/assets/{gdresource-DiUcyewI.js → gdresource-D852fWBR.js} +1 -1
- package/dist/web/assets/{git-commit-CfOruFrg.js → git-commit-DWfWAyxy.js} +1 -1
- package/dist/web/assets/{git-log-panel-D1-YXZ0O.js → git-log-panel-DNC9fV0M.js} +1 -1
- package/dist/web/assets/{git-rebase-Bxyr24oc.js → git-rebase-C6opk8gr.js} +1 -1
- package/dist/web/assets/glide-data-grid-CICFjJon.js +141 -0
- package/dist/web/assets/{glimmer-js-CT5aJxz_.js → glimmer-js-DLi5mWYO.js} +1 -1
- package/dist/web/assets/{glimmer-ts-CRjP9Yey.js → glimmer-ts-D-scFX30.js} +1 -1
- package/dist/web/assets/{glsl-BX2--oI_.js → glsl-dbQzF4iA.js} +1 -1
- package/dist/web/assets/{graphql-BIQsvBxQ.js → graphql-D1m5Wen2.js} +1 -1
- package/dist/web/assets/group-chat-tab-DbUkcOaJ.js +1 -0
- package/dist/web/assets/{hack-CTWk0k1m.js → hack-CqYmpO7u.js} +1 -1
- package/dist/web/assets/{haml-DGh27hXc.js → haml-BXzKWEag.js} +1 -1
- package/dist/web/assets/{hand-DKSxDa5c.js → hand-x0ejq3fS.js} +1 -1
- package/dist/web/assets/{handlebars-BJL1jNrG.js → handlebars-DXnrtHtq.js} +1 -1
- package/dist/web/assets/{html-DALyDNqU.js → html-DhgQJ-xL.js} +1 -1
- package/dist/web/assets/{html-derivative-B4XcU57e.js → html-derivative-xZRft-YE.js} +1 -1
- package/dist/web/assets/{http-DfMo7nNu.js → http-B53mSj14.js} +1 -1
- package/dist/web/assets/{hurl-CGc_n2Qf.js → hurl-CsomVy04.js} +1 -1
- package/dist/web/assets/{hxml-40zZ1t4x.js → hxml-LffjWwKA.js} +1 -1
- package/dist/web/assets/{image-preview-Cp3XB8UO.js → image-preview-CNA6XMNS.js} +1 -1
- package/dist/web/assets/index-DTqbMiVc.js +52 -0
- package/dist/web/assets/{input-DTmI80l2.js → input-D0ol5jW0.js} +1 -1
- package/dist/web/assets/{jinja-D5zuIn9u.js → jinja-CCHURl7V.js} +1 -1
- package/dist/web/assets/{jison-Dxut9QwA.js → jison-7qBd8dnR.js} +1 -1
- package/dist/web/assets/{julia-Cu85tTPo.js → julia-BY9pnTcy.js} +1 -1
- package/dist/web/assets/{just-CctM4uLa.js → just-D7wRSNRr.js} +1 -1
- package/dist/web/assets/{keybindings-store-Bi0q9x4Q.js → keybindings-store-BGkB72gM.js} +1 -1
- package/dist/web/assets/keybindings-store-Bq6VWl5X.js +1 -0
- package/dist/web/assets/{keyboard-AdwmYDSu.js → keyboard-DBBaoQSu.js} +1 -1
- package/dist/web/assets/{latex-kpwS_CC7.js → latex-RgsCae55.js} +1 -1
- package/dist/web/assets/{lib-Ca7ai8xa.js → lib-v9x_qXgI.js} +1 -1
- package/dist/web/assets/{liquid-B8Rr0xue.js → liquid-CnDFzvOZ.js} +1 -1
- package/dist/web/assets/loader-circle-DouKgIXy.js +1 -0
- package/dist/web/assets/{lock-BEtt_eTO.js → lock-CNxUGpTk.js} +1 -1
- package/dist/web/assets/{lua-C_3gixwM.js → lua-0lj5W8sm.js} +1 -1
- package/dist/web/assets/markdown-renderer-DEAVpo0C.js +1 -0
- package/dist/web/assets/markdown-renderer-dbLIvU2M.js +3 -0
- package/dist/web/assets/{marko-B28rvNL-.js → marko-CQgqAhbV.js} +1 -1
- package/dist/web/assets/{mdc-DQ6-STFO.js → mdc-BkIcTiIy.js} +1 -1
- package/dist/web/assets/{media-url-BjvbfTTl.js → media-url-DDciwvLU.js} +1 -1
- package/dist/web/assets/{mobile-bottom-sheet-DXn5g2LB.js → mobile-bottom-sheet-pjcHKorA.js} +1 -1
- package/dist/web/assets/mobile-explorer-sheet-CD_kl-jA.js +1 -0
- package/dist/web/assets/{monitor-CXI_XpWJ.js → monitor-CxPV_fQI.js} +1 -1
- package/dist/web/assets/{monitor-smartphone-C1wUPOSg.js → monitor-smartphone-DLZ6Q05s.js} +1 -1
- package/dist/web/assets/{nextflow-B1xq2O8L.js → nextflow-DvIW68DS.js} +1 -1
- package/dist/web/assets/{nginx-xsLxRGxO.js → nginx-O-hft0gG.js} +1 -1
- package/dist/web/assets/{nim-wqcek3WO.js → nim-BxrR4HwQ.js} +1 -1
- package/dist/web/assets/notification-store-Dgbsw9p9.js +1 -0
- package/dist/web/assets/{number-overlay-editor-1c4sgZJt.js → number-overlay-editor-BoLRYuZT.js} +1 -1
- package/dist/web/assets/{overview-panel-Cr2xsHc6.js → overview-panel-l3g1gT5e.js} +1 -1
- package/dist/web/assets/{panel-store-Dv28vz3L.js → panel-store-UOV8wrfR.js} +1 -1
- package/dist/web/assets/{pdf-preview-DKeIIJTv.js → pdf-preview-B2CJ_EKv.js} +1 -1
- package/dist/web/assets/{pencil-CHKLOgLs.js → pencil-BlIIg6RH.js} +1 -1
- package/dist/web/assets/{perl-BH54gN9q.js → perl-Da-uNqmL.js} +1 -1
- package/dist/web/assets/{php-Br5ZrEZm.js → php-JMu45mEx.js} +1 -1
- package/dist/web/assets/play-DpEEBJTT.js +1 -0
- package/dist/web/assets/{plus-BxqD2FIZ.js → plus-BR0qewJI.js} +1 -1
- package/dist/web/assets/portal-container-context-D-495m5C.js +1 -0
- package/dist/web/assets/{postgres-viewer-BJPr_FYL.js → postgres-viewer-DstZwUai.js} +3 -3
- package/dist/web/assets/{process-table-BqTcAJ-h.js → process-table-kmQ2-8qJ.js} +1 -1
- package/dist/web/assets/{project-store-KHjFTCxf.js → project-store-DTUCS65m.js} +1 -1
- package/dist/web/assets/{pug-8VCubZ3H.js → pug-CLzyQhia.js} +1 -1
- package/dist/web/assets/{qml-D8AF1RZ6.js → qml-BHXfGB1l.js} +1 -1
- package/dist/web/assets/{razor-6v042IJW.js → razor-BqetJLN3.js} +1 -1
- package/dist/web/assets/{react-DHs6efqI.js → react-B549sK_T.js} +1 -1
- package/dist/web/assets/{refresh-cw-BALzw7L3.js → refresh-cw-BQU5g2CY.js} +1 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-KKTRNjOL.js +2 -0
- package/dist/web/assets/{remote-desktop-mobile-view-DaoB49k4.js → remote-desktop-mobile-view-C1ST4-Fm.js} +1 -1
- package/dist/web/assets/{remote-desktop-readiness-gate--LJgsuoj.js → remote-desktop-readiness-gate-BH3BE5wA.js} +1 -1
- package/dist/web/assets/{remote-desktop-window-content-Cihx4PNZ.js → remote-desktop-window-content-BaZJQt_N.js} +1 -1
- package/dist/web/assets/{rotate-ccw-CuvNBM80.js → rotate-ccw-CpjRo90J.js} +1 -1
- package/dist/web/assets/{rst-mTGFo4AQ.js → rst-iQdJZ0BP.js} +1 -1
- package/dist/web/assets/{ruby-BBaOP636.js → ruby-CNwzZGdH.js} +1 -1
- package/dist/web/assets/{run-in-terminal-Zl5iIx-B.js → run-in-terminal-CBXmVGWa.js} +1 -1
- package/dist/web/assets/{sas-D5QEkIH2.js → sas-BpBIT2eR.js} +1 -1
- package/dist/web/assets/{save-Dxq-Zepc.js → save-DYLiVzU8.js} +1 -1
- package/dist/web/assets/{scroll-area-B5yhPpZo.js → scroll-area-lc0ZHORr.js} +1 -1
- package/dist/web/assets/{scss-C5Mu6y2u.js → scss-D1MotuEp.js} +1 -1
- package/dist/web/assets/{send-Cits8q0l.js → send-C_sLFt56.js} +1 -1
- package/dist/web/assets/{send-to-chat-Cv7ikFUC.js → send-to-chat-DJAdlvJ8.js} +1 -1
- package/dist/web/assets/{settings-store-Dp4i8zeA.js → settings-store-zbPkG7o-.js} +2 -2
- package/dist/web/assets/settings-tab-Cn-AqUP_.js +1 -0
- package/dist/web/assets/{settings-tab-BtMvvKAF.js → settings-tab-xyRpt2gq.js} +1 -1
- package/dist/web/assets/{shaderlab-mLnpMpN3.js → shaderlab-BNqmcPQi.js} +1 -1
- package/dist/web/assets/{shallow-BBJ_qoEF.js → shallow-CmPMAPte.js} +1 -1
- package/dist/web/assets/{shellsession-qdcDfUuk.js → shellsession-BBLOVOO-.js} +1 -1
- package/dist/web/assets/{shield-check-CH7F1P7m.js → shield-check-CUI36aSc.js} +1 -1
- package/dist/web/assets/{shield-off-C9HiF0-6.js → shield-off-GdkkVhb3.js} +1 -1
- package/dist/web/assets/{soy-CGGf1G43.js → soy-BpTGo9uy.js} +1 -1
- package/dist/web/assets/{sparkles-BnuLH6Ck.js → sparkles-Dh-_J2Rd.js} +1 -1
- package/dist/web/assets/{sparql-tQHB50VD.js → sparql-D7A3yKob.js} +1 -1
- package/dist/web/assets/{sql-query-editor-DZqnYIB7.js → sql-query-editor-B86NiZHI.js} +1 -1
- package/dist/web/assets/{sqlite-viewer-DXutos0e.js → sqlite-viewer-DB775F6C.js} +1 -1
- package/dist/web/assets/{stata-DVQNLMcR.js → stata-B7N56ptS.js} +1 -1
- package/dist/web/assets/{surrealql-lu576tBi.js → surrealql-CTmnD-lv.js} +1 -1
- package/dist/web/assets/{svelte-CSCrOBjT.js → svelte-BppwY9TR.js} +1 -1
- package/dist/web/assets/{switch-BPol3BFC.js → switch-BmjKoIpR.js} +1 -1
- package/dist/web/assets/{system-monitor-body-Ct8_GX_f.js → system-monitor-body-BDxHQvy9.js} +2 -2
- package/dist/web/assets/system-monitor-tab-BoTHLx6B.js +1 -0
- package/dist/web/assets/system-monitor-window-content-B9Y98UW6.js +1 -0
- package/dist/web/assets/{tab-host-window-content-C5kYP0-z.js → tab-host-window-content-C1j8zr68.js} +1 -1
- package/dist/web/assets/{tab-store-DS3YlUwR.js → tab-store-DzYSsw5a.js} +1 -1
- package/dist/web/assets/{table-BXDyImqk.js → table-D5Q4ap4W.js} +1 -1
- package/dist/web/assets/team-member-sheet-Cxz6h5Ne.js +2 -0
- package/dist/web/assets/{team-member-window-content-BJ_XFw8-.js → team-member-window-content-CUSuRHCB.js} +1 -1
- package/dist/web/assets/{templ-CPt8AS4Q.js → templ-CvTMKKra.js} +1 -1
- package/dist/web/assets/{terminal-tab-8bKQ3CWR.js → terminal-tab-B9I_HlES.js} +3 -3
- package/dist/web/assets/{tex-BrTByT7i.js → tex--c4POEUE.js} +1 -1
- package/dist/web/assets/{text-wrap-CzMjB6GD.js → text-wrap-DBvQD3kc.js} +1 -1
- package/dist/web/assets/{tool-cards-pIu_cmEL.js → tool-cards-D3KSzd2K.js} +4 -4
- package/dist/web/assets/{trash-2-BjShZ7if.js → trash-2-By4VMbC4.js} +1 -1
- package/dist/web/assets/{triangle-alert-qQ6Plydp.js → triangle-alert-CUTURFbG.js} +1 -1
- package/dist/web/assets/{ts-tags-DSqEZ7A8.js → ts-tags--kx7D-Hw.js} +1 -1
- package/dist/web/assets/{twig-DW9qc1bf.js → twig-UG9uMHGd.js} +1 -1
- package/dist/web/assets/{upload-7Zs6oaK5.js → upload-BNlX8D07.js} +1 -1
- package/dist/web/assets/{use-blob-url-DKbV7PM_.js → use-blob-url-Bdxopwwc.js} +1 -1
- package/dist/web/assets/{use-coarse-long-press-DGyC48NF.js → use-coarse-long-press-BmI_GVW5.js} +1 -1
- package/dist/web/assets/{use-is-mobile-ClE-UcPF.js → use-is-mobile-B9UZNwSm.js} +1 -1
- package/dist/web/assets/{use-monaco-theme-DaxAk3gB.js → use-monaco-theme-CVCye2kq.js} +1 -1
- package/dist/web/assets/use-open-team-member-D9EOB8-i.js +1 -0
- package/dist/web/assets/{use-remote-desktop-display-choice-BUA_1eaH.js → use-remote-desktop-display-choice-neUqyE3p.js} +1 -1
- package/dist/web/assets/{use-visual-viewport-CCX21c9w.js → use-visual-viewport-Sfb6CZ80.js} +1 -1
- package/dist/web/assets/{use-websocket-CWpG7PWN.js → use-websocket-xOOwBdwP.js} +1 -1
- package/dist/web/assets/vendor-markdown-Ls5AcU91.js +291 -0
- package/dist/web/assets/{vendor-ui-CXJtBULr.js → vendor-ui-CaeeFO0B.js} +1 -1
- package/dist/web/assets/video-preview-DvpgBDhM.js +1 -0
- package/dist/web/assets/{vue-html-CG5BKtq1.js → vue-html-8KEW6-I9.js} +1 -1
- package/dist/web/assets/{vue-CJNDL1g-.js → vue-jjTomlbt.js} +1 -1
- package/dist/web/assets/{vue-vine-Dd5HZ7T5.js → vue-vine-C5tohCkU.js} +1 -1
- package/dist/web/assets/{window-pip-registry-9H6Y-HqR.js → window-pip-registry-FdZdGF7h.js} +1 -1
- package/dist/web/assets/{window-store-CNzkeUyO.js → window-store-D0x_fxr0.js} +1 -1
- package/dist/web/assets/x-DiOUR_mp.js +1 -0
- package/dist/web/assets/{xml-DTOm5niz.js → xml-ByFFosqL.js} +1 -1
- package/dist/web/assets/{xsl-BD_kBC04.js → xsl-CZUwiLkj.js} +1 -1
- package/dist/web/index.html +59 -59
- package/dist/web/monacoeditorwork/css.worker.bundle.js +122 -122
- package/dist/web/monacoeditorwork/editor.worker.bundle.js +78 -78
- package/dist/web/monacoeditorwork/html.worker.bundle.js +110 -110
- package/dist/web/monacoeditorwork/json.worker.bundle.js +108 -108
- package/dist/web/monacoeditorwork/ts.worker.bundle.js +81 -81
- package/dist/web/sw.js +1 -1
- package/package.json +1 -1
- package/scripts/check-ppm-dir-usage.sh +0 -0
- package/scripts/install.sh +0 -0
- package/scripts/release.sh +0 -0
- package/src/providers/claude-agent-sdk.ts +51 -43
- package/src/providers/codex-app-server/codex-provider.ts +7 -1
- package/src/server/routes/chat.ts +28 -3
- package/src/server/ws/chat.ts +9 -4
- package/src/server/ws/terminal.ts +9 -3
- package/src/services/media-transcode/ffmpeg-capabilities.ts +48 -7
- package/src/services/named-tunnel/named-tunnel-retry.ts +26 -0
- package/src/services/named-tunnel/network-ready.ts +63 -0
- package/src/services/supervisor.ts +98 -0
- package/src/services/transcript-images.ts +14 -7
- package/src/services/upgrade.service.ts +7 -2
- package/src/shared/image-limits.ts +37 -0
- package/src/types/api.ts +3 -1
- package/src/types/chat.ts +6 -0
- package/src/types/extension-messages.ts +2 -0
- package/src/web/components/chat/attachment-chips.tsx +10 -0
- package/src/web/components/chat/chat-tab.tsx +37 -13
- package/src/web/components/chat/message-input.tsx +102 -11
- package/src/web/components/chat/session-debug-dialog.tsx +2 -1
- package/src/web/components/chat/user-message-parse.ts +33 -11
- package/src/web/components/database/database-viewer.tsx +34 -11
- package/src/web/components/database/extract-query-table.ts +24 -0
- package/src/web/components/database/glide-data-grid.tsx +11 -4
- package/src/web/components/database/glide-grid-types.ts +4 -0
- package/src/web/components/database/split-sql-statements.ts +116 -0
- package/src/web/components/database/sql-completion-provider.ts +1 -26
- package/src/web/components/database/sql-query-editor.tsx +2 -1
- package/src/web/components/database/use-database.ts +16 -1
- package/src/web/components/database/use-glide-cell-content.ts +11 -6
- package/src/web/components/editor/code-editor.tsx +30 -56
- package/src/web/hooks/use-chat.ts +6 -3
- package/src/web/lib/attachment-marker-split.ts +44 -0
- package/src/web/lib/image-animation.ts +51 -0
- package/src/web/lib/image-resize-limits.ts +47 -0
- package/src/web/lib/image-resize.ts +133 -0
- package/dist/web/assets/api-client-DLWwuUkJ.js +0 -1
- package/dist/web/assets/api-settings-BFuaZrNC.js +0 -1
- package/dist/web/assets/chat-tab-bSOVoC5N.js +0 -15
- package/dist/web/assets/chevron-right-D7Pn5agw.js +0 -1
- package/dist/web/assets/circle-4g2coECH.js +0 -1
- package/dist/web/assets/clock-DbiNiwCG.js +0 -1
- package/dist/web/assets/code-DdKXqtf_.js +0 -1
- package/dist/web/assets/code-editor-COTa37oe.js +0 -10
- package/dist/web/assets/database-viewer-Dta7lSSk.js +0 -1
- package/dist/web/assets/explorer-body-BGjR2Gbt.js +0 -2
- package/dist/web/assets/explorer-window-content-DAhHh5EQ.js +0 -1
- package/dist/web/assets/glide-data-grid-BSsqxe2v.js +0 -138
- package/dist/web/assets/group-chat-tab-CMtzoaFc.js +0 -1
- package/dist/web/assets/index-BkHlMfPD.js +0 -52
- package/dist/web/assets/keybindings-store-_KfovSz7.js +0 -1
- package/dist/web/assets/loader-circle-DD65e9-7.js +0 -1
- package/dist/web/assets/markdown-renderer-DroTmKbJ.js +0 -1
- package/dist/web/assets/markdown-renderer-ntDi3Tx-.js +0 -3
- package/dist/web/assets/mobile-explorer-sheet-BP6iU4ma.js +0 -1
- package/dist/web/assets/notification-store-II5Kw9rD.js +0 -1
- package/dist/web/assets/play-CPbVzGgq.js +0 -1
- package/dist/web/assets/portal-container-context-BmG4--I-.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-CYZUjYTO.js +0 -2
- package/dist/web/assets/settings-tab-UPPycGRF.js +0 -1
- package/dist/web/assets/system-monitor-tab-DC_EerdI.js +0 -1
- package/dist/web/assets/system-monitor-window-content-D25DMNpw.js +0 -1
- package/dist/web/assets/team-member-sheet-DvmioeQL.js +0 -2
- package/dist/web/assets/use-open-team-member-CopUuDHG.js +0 -1
- package/dist/web/assets/vendor-markdown-CKTlmXbz.js +0 -291
- package/dist/web/assets/video-preview-C2_fdunE.js +0 -1
- package/dist/web/assets/x-Dzu9ecti.js +0 -1
- /package/dist/web/assets/{abap-Cjj2olMr.js → abap-C5DFF0s3.js} +0 -0
- /package/dist/web/assets/{actionscript-3-DCkW7kWC.js → actionscript-3-B0qyRNbc.js} +0 -0
- /package/dist/web/assets/{ada-AEWvZXuX.js → ada-bAJzplug.js} +0 -0
- /package/dist/web/assets/{andromeeda-D7cSpME6.js → andromeeda-DUCpISy6.js} +0 -0
- /package/dist/web/assets/{apache-DjvX0RSe.js → apache-BhAr84Z_.js} +0 -0
- /package/dist/web/assets/{apex-70xIZ0pH.js → apex-CRv8YnNq.js} +0 -0
- /package/dist/web/assets/{applescript-C3qKqxmA.js → applescript-CD-Cw8bt.js} +0 -0
- /package/dist/web/assets/{ara-iGt2zixk.js → ara-BUzeQYoG.js} +0 -0
- /package/dist/web/assets/{asciidoc-Bs2t-06W.js → asciidoc-CT2hTg-v.js} +0 -0
- /package/dist/web/assets/{asm-B-T0eqhE.js → asm-CAu35JeY.js} +0 -0
- /package/dist/web/assets/{aurora-x-D3h_9M3E.js → aurora-x-BeFJoIA1.js} +0 -0
- /package/dist/web/assets/{awk-CZwfwpPi.js → awk-Vau-DrGN.js} +0 -0
- /package/dist/web/assets/{ayu-dark-DulkglEA.js → ayu-dark-CLe-OTsQ.js} +0 -0
- /package/dist/web/assets/{ayu-light-DyNQiRpn.js → ayu-light-CJbQfu4M.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-CcEt4xkI.js → ayu-mirage-GWaKwdrx.js} +0 -0
- /package/dist/web/assets/{ballerina-OhQPjyHS.js → ballerina-DWu0USI5.js} +0 -0
- /package/dist/web/assets/{bat-DqKcJTUn.js → bat-_07Huw7E.js} +0 -0
- /package/dist/web/assets/{beancount-BdXlMi8T.js → beancount-EcvogrcF.js} +0 -0
- /package/dist/web/assets/{berry-DvgY6BkY.js → berry-BBB87SY7.js} +0 -0
- /package/dist/web/assets/{bibtex-BSRJq0yM.js → bibtex-DbueS87A.js} +0 -0
- /package/dist/web/assets/{bicep-DpAdumKt.js → bicep-tcmXnUo4.js} +0 -0
- /package/dist/web/assets/{bird2-rlbtp8di.js → bird2-B2qwilIR.js} +0 -0
- /package/dist/web/assets/{c-AjOLBXIs.js → c-Z58oivSt.js} +0 -0
- /package/dist/web/assets/{c3-DqIXz4Ia.js → c3-U40cGT9p.js} +0 -0
- /package/dist/web/assets/{cadence-DAJtUpOE.js → cadence-BFcD-LyM.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DUPoeZfb.js → catppuccin-frappe-RkC9AX6J.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-CK3U68Ql.js → catppuccin-latte-Bsi4l-nO.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-BzteLnIX.js → catppuccin-macchiato-B8JIdTW-.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-ozLd0aBR.js → catppuccin-mocha-oH8wwrDj.js} +0 -0
- /package/dist/web/assets/{clarity-6KqEoBfz.js → clarity-C3WNeRCR.js} +0 -0
- /package/dist/web/assets/{clojure-B_uBL5C7.js → clojure-CFoAz7u9.js} +0 -0
- /package/dist/web/assets/{cmake-B3nxBNmj.js → cmake-Bcsqp9yR.js} +0 -0
- /package/dist/web/assets/{codeowners-DkS-51at.js → codeowners-DC2Z7heP.js} +0 -0
- /package/dist/web/assets/{codeql-rpr1z_mR.js → codeql-BfG68Al5.js} +0 -0
- /package/dist/web/assets/{common-lisp-BfNbv_W6.js → common-lisp-Z5P-lKQe.js} +0 -0
- /package/dist/web/assets/{coq-EAW-1nw0.js → coq-BJslqrnv.js} +0 -0
- /package/dist/web/assets/{csharp-BE3Gn5bq.js → csharp-DhhZTOTs.js} +0 -0
- /package/dist/web/assets/{css-Cr27CfPY.js → css-DiFIpMfE.js} +0 -0
- /package/dist/web/assets/{csv-B5VtaPtH.js → csv-DViLbHxI.js} +0 -0
- /package/dist/web/assets/{cue-jm6lYNrx.js → cue-CoG3mg2I.js} +0 -0
- /package/dist/web/assets/{cypher-DXkvK-pn.js → cypher-jTxC8NAB.js} +0 -0
- /package/dist/web/assets/{d-CgG1_yzd.js → d-6hKIUAbU.js} +0 -0
- /package/dist/web/assets/{dark-plus-CALzcIVB.js → dark-plus-D_-np2Sr.js} +0 -0
- /package/dist/web/assets/{dart-BEVoLlWg.js → dart-CVpxLpVn.js} +0 -0
- /package/dist/web/assets/{dax-H0BW3Q_P.js → dax-BPqJ8qIY.js} +0 -0
- /package/dist/web/assets/{desktop-BtYq1l_0.js → desktop-u_y5_Hr5.js} +0 -0
- /package/dist/web/assets/{diff-CnBYdfTg.js → diff-Duj1XMrd.js} +0 -0
- /package/dist/web/assets/{dist-CJJKpgR7.js → dist-CEZ4plgH.js} +0 -0
- /package/dist/web/assets/{docker-COBitpld.js → docker-8UGSCc7N.js} +0 -0
- /package/dist/web/assets/{dotenv-CG0x1m7c.js → dotenv-DVnj8kyR.js} +0 -0
- /package/dist/web/assets/{dracula-CLCi47X-.js → dracula-D0cEmSg7.js} +0 -0
- /package/dist/web/assets/{dracula-soft-BMv5cCAV.js → dracula-soft-DfGS5Yfr.js} +0 -0
- /package/dist/web/assets/{dream-maker-1Bd4OSww.js → dream-maker-qG8kMGTF.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-B-2zKLn-.js → emacs-lisp-iVqyMLyT.js} +0 -0
- /package/dist/web/assets/{everforest-dark-BGVynCbV.js → everforest-dark-Cruygd5U.js} +0 -0
- /package/dist/web/assets/{everforest-light--rn3R7Cm.js → everforest-light-BiJa8RHL.js} +0 -0
- /package/dist/web/assets/{fennel-SWg9Us_u.js → fennel-H6XSEIoz.js} +0 -0
- /package/dist/web/assets/{fish-B04oqgKk.js → fish-ho_7CxX6.js} +0 -0
- /package/dist/web/assets/{fluent-BefzAGMN.js → fluent-1l5ssJTF.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-alw7jMxb.js → fortran-free-form-Bo1x233A.js} +0 -0
- /package/dist/web/assets/{gdscript-BAyhvjCx.js → gdscript-DffFMp_k.js} +0 -0
- /package/dist/web/assets/{gdshader-Crl09X-B.js → gdshader-CvnpAiAF.js} +0 -0
- /package/dist/web/assets/{genie-BSIGRHu7.js → genie-2eOvAEzW.js} +0 -0
- /package/dist/web/assets/{gherkin-DJhSnSWH.js → gherkin-DL-5OUlV.js} +0 -0
- /package/dist/web/assets/{github-dark-r8C6qwug.js → github-dark-DrTZprgG.js} +0 -0
- /package/dist/web/assets/{github-dark-default-FVtXjcm8.js → github-dark-default-_mDH8IMP.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-CzrUPgSb.js → github-dark-dimmed-C48hJuLn.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-1s9rF5EB.js → github-dark-high-contrast-BQ-zGGNe.js} +0 -0
- /package/dist/web/assets/{github-light-BvIWCkl7.js → github-light-BYc90Yx8.js} +0 -0
- /package/dist/web/assets/{github-light-default-CVdhzrxV.js → github-light-default-Daecj4J5.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-CBAf6hjF.js → github-light-high-contrast-DoafCbsU.js} +0 -0
- /package/dist/web/assets/{gleam-DvL1q7aa.js → gleam-hUWWjmnp.js} +0 -0
- /package/dist/web/assets/{gn-BG5NvwAf.js → gn-7PJ3R70o.js} +0 -0
- /package/dist/web/assets/{gnuplot-BARnM-zG.js → gnuplot-V-Pxck7b.js} +0 -0
- /package/dist/web/assets/{go-DXvjjq4q.js → go-ARF6DprD.js} +0 -0
- /package/dist/web/assets/{groovy-CRylSKhr.js → groovy-CKGBIPOz.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-BVPjnqm7.js → gruvbox-dark-hard-Cm9wqdI3.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-U_PDgq0a.js → gruvbox-dark-medium-Cmsd6dG8.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-CkzNtpbr.js → gruvbox-dark-soft-BBGlGGCz.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-DfMmR2G8.js → gruvbox-light-hard-BCR7KmqG.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-BGCak-dd.js → gruvbox-light-medium-CP32bga8.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-DnpM3fkN.js → gruvbox-light-soft-qjxk8ps6.js} +0 -0
- /package/dist/web/assets/{haskell-DXgGIDD_.js → haskell-C5DzwGRa.js} +0 -0
- /package/dist/web/assets/{haxe-B7qlTpRz.js → haxe-C8f_jCVv.js} +0 -0
- /package/dist/web/assets/{hcl-ADWfVe_Q.js → hcl-DetJkf6E.js} +0 -0
- /package/dist/web/assets/{hjson-BaM9gLbq.js → hjson-DeZhwIdo.js} +0 -0
- /package/dist/web/assets/{hlsl-iqaRA4MG.js → hlsl-SMIDLRyX.js} +0 -0
- /package/dist/web/assets/{horizon-BPpTnhB9.js → horizon-BMAVDxMx.js} +0 -0
- /package/dist/web/assets/{horizon-bright-yBLg3QbE.js → horizon-bright-3BaV_VGD.js} +0 -0
- /package/dist/web/assets/{houston-eFOp0ySL.js → houston-BWBbEPvb.js} +0 -0
- /package/dist/web/assets/{hy-BALeMn3i.js → hy-DcsmE-Nm.js} +0 -0
- /package/dist/web/assets/{imba-CdGUm_GD.js → imba-CnkgnYMf.js} +0 -0
- /package/dist/web/assets/{ini-DG7imsqe.js → ini-BnvTdau7.js} +0 -0
- /package/dist/web/assets/{java-D5GTT474.js → java-BLFACXat.js} +0 -0
- /package/dist/web/assets/{javascript-V7WwJvRm.js → javascript-BKcFWENk.js} +0 -0
- /package/dist/web/assets/{json-B9FhwAgR.js → json-3AJtJADf.js} +0 -0
- /package/dist/web/assets/{json5--Abk7MUy.js → json5-DLyDVlwe.js} +0 -0
- /package/dist/web/assets/{jsonc-C8jb-Z6x.js → jsonc-B5DgF1jW.js} +0 -0
- /package/dist/web/assets/{jsonl-CaJNxfkm.js → jsonl-CV_O71a2.js} +0 -0
- /package/dist/web/assets/{jsonnet-CPrKMSCU.js → jsonnet-DZfPLgYz.js} +0 -0
- /package/dist/web/assets/{jssm-DEu-9_uo.js → jssm-Cr1zYOsY.js} +0 -0
- /package/dist/web/assets/{jsx-MfAsCWDW.js → jsx-VN-JS2_q.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-DnbcAduF.js → kanagawa-dragon-D9CcT3xg.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-yxsY3ew8.js → kanagawa-lotus-DLXsB8fr.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-C2RyvZaM.js → kanagawa-wave-weDs3Wjz.js} +0 -0
- /package/dist/web/assets/{kdl-CvssmvcU.js → kdl-0XF56jnT.js} +0 -0
- /package/dist/web/assets/{kotlin-jufO49mU.js → kotlin-BPkH9vzk.js} +0 -0
- /package/dist/web/assets/{kusto-BAFnylR7.js → kusto-DMVpADb9.js} +0 -0
- /package/dist/web/assets/{laserwave-BgxFC4Ge.js → laserwave-Cl6T2cGP.js} +0 -0
- /package/dist/web/assets/{lean-Bgt24V1D.js → lean-BvwzQGl1.js} +0 -0
- /package/dist/web/assets/{less-Bk_UaqsM.js → less-DI_03xkC.js} +0 -0
- /package/dist/web/assets/{light-plus-nMxFfInN.js → light-plus-hIiIsQN_.js} +0 -0
- /package/dist/web/assets/{llvm-3_PASDOO.js → llvm-B5hjjSWc.js} +0 -0
- /package/dist/web/assets/{log-CKm0CxB1.js → log-D28raQiE.js} +0 -0
- /package/dist/web/assets/{logo-DFP1_5U6.js → logo-6Cdd4ASb.js} +0 -0
- /package/dist/web/assets/{luau-BcZnoyh3.js → luau-CK9nKpOX.js} +0 -0
- /package/dist/web/assets/{make-CpNSwgwT.js → make-CVnxKCB6.js} +0 -0
- /package/dist/web/assets/{markdown-DhU3Djpv.js → markdown-B9mMQzD5.js} +0 -0
- /package/dist/web/assets/{material-theme-DD5L3OqF.js → material-theme-BZSs2o0j.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-CG2_tD3R.js → material-theme-darker-BeAQBzQ_.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-CzNkUc9Y.js → material-theme-lighter-BAe0IXcs.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-BtLiAaF_.js → material-theme-ocean-CiPIf0Np.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-Brvjz035.js → material-theme-palenight-DJBb4_XN.js} +0 -0
- /package/dist/web/assets/{matlab-CCY0KtMD.js → matlab-CY0dbp_s.js} +0 -0
- /package/dist/web/assets/{mdx-CH6YY0aS.js → mdx-DU9zbF7h.js} +0 -0
- /package/dist/web/assets/{mermaid-Bqh3gFI0.js → mermaid-UmmjGwdh.js} +0 -0
- /package/dist/web/assets/{min-dark-BUwfTzI6.js → min-dark-C59GkzOm.js} +0 -0
- /package/dist/web/assets/{min-light-oLanXCOk.js → min-light-B9QglrdQ.js} +0 -0
- /package/dist/web/assets/{mipsasm-CTh3hPWK.js → mipsasm-Dc6Jsr_D.js} +0 -0
- /package/dist/web/assets/{mojo-DXdszZKa.js → mojo-D5ij-nGW.js} +0 -0
- /package/dist/web/assets/{monokai-TNE_tRxc.js → monokai-QAtE_yCP.js} +0 -0
- /package/dist/web/assets/{moonbit-jrk-Gx1X.js → moonbit-BMtIdiTL.js} +0 -0
- /package/dist/web/assets/{move-DItn61bH.js → move-BB_jMHYZ.js} +0 -0
- /package/dist/web/assets/{narrat-3kB4dkh0.js → narrat-BvvoKGVn.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-CSKtwETr.js → nextflow-groovy-CqxtAsnF.js} +0 -0
- /package/dist/web/assets/{night-owl-Dm91nSIq.js → night-owl-CLoE9kjt.js} +0 -0
- /package/dist/web/assets/{night-owl-light-riwrcPRg.js → night-owl-light-BwIFT5Xd.js} +0 -0
- /package/dist/web/assets/{nix-sLgl9zGF.js → nix-BKlnVT9r.js} +0 -0
- /package/dist/web/assets/{nord-TWkJPI6M.js → nord-B7R1KRAK.js} +0 -0
- /package/dist/web/assets/{nushell-CDZi4-Gf.js → nushell-CzUme-NJ.js} +0 -0
- /package/dist/web/assets/{objective-c-DW9PboNp.js → objective-c-D-UKKiOc.js} +0 -0
- /package/dist/web/assets/{objective-cpp-2XCCX6q1.js → objective-cpp-BucWn4Fx.js} +0 -0
- /package/dist/web/assets/{ocaml-CxPdnjrh.js → ocaml-EJCNXMGo.js} +0 -0
- /package/dist/web/assets/{odin-BJjlKpkM.js → odin-CEjnRU_3.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-K1KOmBZ7.js → one-dark-pro-Bv469NX5.js} +0 -0
- /package/dist/web/assets/{one-light-DQB-vUyZ.js → one-light-BlzO5RWI.js} +0 -0
- /package/dist/web/assets/{openscad-DCoLwn4j.js → openscad-Czl6alLw.js} +0 -0
- /package/dist/web/assets/{pascal-z2ktbbWp.js → pascal-BI9fLvG4.js} +0 -0
- /package/dist/web/assets/{pkl-Dyq4-v6z.js → pkl-ChQLsyjU.js} +0 -0
- /package/dist/web/assets/{plastic-C4Rq5PnD.js → plastic-DGL3mtdL.js} +0 -0
- /package/dist/web/assets/{plsql-BCIjO63y.js → plsql-BJDjqcWp.js} +0 -0
- /package/dist/web/assets/{po-_kXpd_0n.js → po-DK5O3OpF.js} +0 -0
- /package/dist/web/assets/{poimandres-C9XggjB3.js → poimandres-CnuqZT4T.js} +0 -0
- /package/dist/web/assets/{polar-DV_1L04z.js → polar-DCsUxSsQ.js} +0 -0
- /package/dist/web/assets/{postcss-BuqS91mQ.js → postcss-8UjdFmis.js} +0 -0
- /package/dist/web/assets/{powerquery-DK13B2Dc.js → powerquery-CAp0CGQj.js} +0 -0
- /package/dist/web/assets/{powershell-tkuhhtuP.js → powershell-CbBsKZJP.js} +0 -0
- /package/dist/web/assets/{prisma-WNXfBtpr.js → prisma-BnNpXCJN.js} +0 -0
- /package/dist/web/assets/{prolog-BzEdNKfO.js → prolog-CC-l9E8Y.js} +0 -0
- /package/dist/web/assets/{proto-B5meVsrA.js → proto-CV_1k2rL.js} +0 -0
- /package/dist/web/assets/{puppet-C7h_p4r2.js → puppet-2D8HU2bv.js} +0 -0
- /package/dist/web/assets/{purescript-qH1KxAs6.js → purescript-BEJAORgU.js} +0 -0
- /package/dist/web/assets/{python-DeTIYd5V.js → python-BBdbb7nn.js} +0 -0
- /package/dist/web/assets/{qmldir-4Rm5AvD3.js → qmldir-D5ZYI4Ie.js} +0 -0
- /package/dist/web/assets/{qss-YRbeNtr0.js → qss-BOJVGyXE.js} +0 -0
- /package/dist/web/assets/{r-DHwHK0Jh.js → r-B5dlEtkj.js} +0 -0
- /package/dist/web/assets/{racket-gKn4SFLQ.js → racket-BUAEygJ6.js} +0 -0
- /package/dist/web/assets/{raku-DWTmAj3A.js → raku-BG0Ss0ID.js} +0 -0
- /package/dist/web/assets/{red-BFuHRZFS.js → red-C5yyQbtG.js} +0 -0
- /package/dist/web/assets/{reg-DYoOF5tH.js → reg-DHoBWtLf.js} +0 -0
- /package/dist/web/assets/{regexp-6rXQHD2-.js → regexp-DDtJrlKv.js} +0 -0
- /package/dist/web/assets/{rel-Z_tTruCU.js → rel-CR6WJDRD.js} +0 -0
- /package/dist/web/assets/{riscv-DfTfKuvU.js → riscv-2V9tC-nx.js} +0 -0
- /package/dist/web/assets/{ron-CsUtW8gQ.js → ron-QLTmqGUw.js} +0 -0
- /package/dist/web/assets/{rose-pine-Dng_vCo6.js → rose-pine-be0__X3A.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-Ds88Nezf.js → rose-pine-dawn-n_WQJwsW.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-DWpzrqNz.js → rose-pine-moon-t2aLtzgB.js} +0 -0
- /package/dist/web/assets/{rosmsg-h2sO84oD.js → rosmsg-Ce1JD8vt.js} +0 -0
- /package/dist/web/assets/{rust-Dx86yfCi.js → rust-5fHH-ZoW.js} +0 -0
- /package/dist/web/assets/{sass-BwwVhdT9.js → sass-DPmGFiOJ.js} +0 -0
- /package/dist/web/assets/{scala-WJqNEN-w.js → scala-BRMVFbZF.js} +0 -0
- /package/dist/web/assets/{scheme-uwj-t1Rp.js → scheme-BMSJWevF.js} +0 -0
- /package/dist/web/assets/{sdbl-BYy5hgEz.js → sdbl-DTZ-pEHI.js} +0 -0
- /package/dist/web/assets/{shellscript-DWTW_w2K.js → shellscript-6-9yg5Cz.js} +0 -0
- /package/dist/web/assets/{slack-dark-BvhGq5vQ.js → slack-dark-DKJgiR7e.js} +0 -0
- /package/dist/web/assets/{slack-ochin-C9g0ZRFr.js → slack-ochin-WjehVgyK.js} +0 -0
- /package/dist/web/assets/{smalltalk-ZEiZ6i7U.js → smalltalk-BChf4SN1.js} +0 -0
- /package/dist/web/assets/{snazzy-light-29OA24q5.js → snazzy-light-C1WAwOx6.js} +0 -0
- /package/dist/web/assets/{solarized-dark-Bnq9IOn_.js → solarized-dark-BxREZrGx.js} +0 -0
- /package/dist/web/assets/{solarized-light-CYdI7T5g.js → solarized-light-DG29B1pR.js} +0 -0
- /package/dist/web/assets/{solidity-DcuIDB-_.js → solidity-bDbtGwdR.js} +0 -0
- /package/dist/web/assets/{splunk-D5ONE91g.js → splunk-Ceqx5njI.js} +0 -0
- /package/dist/web/assets/{sql-DIwJJDU-.js → sql-OwMEKbz8.js} +0 -0
- /package/dist/web/assets/{ssh-config-D8717tLI.js → ssh-config-WAR3lu2k.js} +0 -0
- /package/dist/web/assets/{stylus-Cm1lO4Y6.js → stylus-Cjmoz3d8.js} +0 -0
- /package/dist/web/assets/{swift-X8oWpSeU.js → swift-S_ZSBG1q.js} +0 -0
- /package/dist/web/assets/{synthwave-84-DF-t1UKY.js → synthwave-84-DiUeWMSh.js} +0 -0
- /package/dist/web/assets/{system-verilog-JYyHFpPf.js → system-verilog-RRjqPjUV.js} +0 -0
- /package/dist/web/assets/{systemd-Da-5Ma_c.js → systemd-BD3SkXoU.js} +0 -0
- /package/dist/web/assets/{talonscript-CXraVPho.js → talonscript-DWefISOm.js} +0 -0
- /package/dist/web/assets/{tasl-BCmWezH9.js → tasl-DCjSS-09.js} +0 -0
- /package/dist/web/assets/{tcl-BTufzfbf.js → tcl-DTYqT_66.js} +0 -0
- /package/dist/web/assets/{terraform-CtUA9c8W.js → terraform-CkbP5QnR.js} +0 -0
- /package/dist/web/assets/{tokyo-night-BCThYXmz.js → tokyo-night-qVSqO9xy.js} +0 -0
- /package/dist/web/assets/{toml-D5YlDr6Y.js → toml-D9F5Osqs.js} +0 -0
- /package/dist/web/assets/{tsv-CBB-P_Sl.js → tsv-C5tpHoxm.js} +0 -0
- /package/dist/web/assets/{tsx-D5B4juDp.js → tsx-CMWkGtGm.js} +0 -0
- /package/dist/web/assets/{turtle-D8PCeJ-v.js → turtle-Cn4z3xOi.js} +0 -0
- /package/dist/web/assets/{typescript-CMPnTawp.js → typescript-DSyAEWsn.js} +0 -0
- /package/dist/web/assets/{typespec-CHxldxIW.js → typespec-B93Qap7y.js} +0 -0
- /package/dist/web/assets/{typst-Q8CqX5OR.js → typst-DtlOmFlX.js} +0 -0
- /package/dist/web/assets/{v-Bf2hKAMu.js → v-Dfzf-szS.js} +0 -0
- /package/dist/web/assets/{vala-Cbete-UE.js → vala-CyiQZQ9f.js} +0 -0
- /package/dist/web/assets/{vb-CA-xWAcX.js → vb-C7DGSldd.js} +0 -0
- /package/dist/web/assets/{verilog-B3wb8CfT.js → verilog-kF-hClY2.js} +0 -0
- /package/dist/web/assets/{vesper-D6r3VJq_.js → vesper-BmKcADuz.js} +0 -0
- /package/dist/web/assets/{vhdl-C42S_797.js → vhdl-CDnb16KJ.js} +0 -0
- /package/dist/web/assets/{viml-BePrIAs8.js → viml-B8cs6Ady.js} +0 -0
- /package/dist/web/assets/{vitesse-black-DRqn61Ck.js → vitesse-black-BR6o9Gto.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-39_8UE-w.js → vitesse-dark-Dye14-KB.js} +0 -0
- /package/dist/web/assets/{vitesse-light-B1jwrxDm.js → vitesse-light-BLpswIxf.js} +0 -0
- /package/dist/web/assets/{vyper-tDJv3imF.js → vyper-DU51Z97W.js} +0 -0
- /package/dist/web/assets/{wasm-DR7eskZH.js → wasm-CVqlJAR2.js} +0 -0
- /package/dist/web/assets/{wenyan-CezVfqN3.js → wenyan-DhCa3hCn.js} +0 -0
- /package/dist/web/assets/{wgsl-CwOcIiIG.js → wgsl-Bj1Ec4vv.js} +0 -0
- /package/dist/web/assets/{wikitext-C5coomYc.js → wikitext-C90DHNa0.js} +0 -0
- /package/dist/web/assets/{wit-C9yyX6-U.js → wit-DUgbOD7Z.js} +0 -0
- /package/dist/web/assets/{wolfram-BWi0rMAa.js → wolfram-BgwUqD1I.js} +0 -0
- /package/dist/web/assets/{yaml-CGXhKUtT.js → yaml-DEQulj-8.js} +0 -0
- /package/dist/web/assets/{zenscript-Do7WLoJh.js → zenscript-C7Jp7TgT.js} +0 -0
- /package/dist/web/assets/{zig-Cr80Qrru.js → zig-9x4qXYLg.js} +0 -0
|
@@ -49,7 +49,12 @@ export function useGlideCellContent(
|
|
|
49
49
|
pkCol: string | null,
|
|
50
50
|
addPendingEdit: (pkVal: unknown, col: string, newVal: unknown) => void,
|
|
51
51
|
pendingRef: React.RefObject<Map<string, PendingEdit>>,
|
|
52
|
+
readOnly = false,
|
|
52
53
|
): UseGlideCellContentResult {
|
|
54
|
+
// Read through a ref: getCellContent is stable (canvas render loop) and must
|
|
55
|
+
// still see the current mode without being re-created.
|
|
56
|
+
const readOnlyRef = useRef(readOnly);
|
|
57
|
+
readOnlyRef.current = readOnly;
|
|
53
58
|
const rowsRef = useRef(rows);
|
|
54
59
|
rowsRef.current = rows;
|
|
55
60
|
const colOrderRef = useRef(columnOrder);
|
|
@@ -106,7 +111,7 @@ export function useGlideCellContent(
|
|
|
106
111
|
}
|
|
107
112
|
return {
|
|
108
113
|
kind: GridCellKind.Text, data: "", displayData: placeholder,
|
|
109
|
-
allowOverlay: !isPk, readonly: isPk,
|
|
114
|
+
allowOverlay: !isPk, readonly: isPk || readOnlyRef.current,
|
|
110
115
|
themeOverride: hasPending ? PENDING_THEME : (isNewRow || placeholder !== "NULL" ? { textDark: "#9ca3af" } : { textDark: "#6b7280" }),
|
|
111
116
|
};
|
|
112
117
|
}
|
|
@@ -115,27 +120,27 @@ export function useGlideCellContent(
|
|
|
115
120
|
if (kind === GridCellKind.Number && typeof val === "number") {
|
|
116
121
|
return {
|
|
117
122
|
kind: GridCellKind.Number, data: val, displayData: String(val),
|
|
118
|
-
allowOverlay: !isPk, readonly: isPk,
|
|
123
|
+
allowOverlay: !isPk, readonly: isPk || readOnlyRef.current,
|
|
119
124
|
themeOverride: hasPending ? PENDING_THEME : undefined,
|
|
120
125
|
};
|
|
121
126
|
}
|
|
122
127
|
|
|
123
128
|
// Boolean cells
|
|
124
129
|
if (kind === GridCellKind.Boolean && typeof val === "boolean") {
|
|
125
|
-
return { kind: GridCellKind.Boolean, data: val, readonly: isPk, allowOverlay: false };
|
|
130
|
+
return { kind: GridCellKind.Boolean, data: val, readonly: isPk || readOnlyRef.current, allowOverlay: false };
|
|
126
131
|
}
|
|
127
132
|
|
|
128
133
|
// Text cell
|
|
129
134
|
const strVal = formatCellValue(val);
|
|
130
135
|
return {
|
|
131
136
|
kind: GridCellKind.Text, data: strVal, displayData: truncateDisplay(strVal),
|
|
132
|
-
allowOverlay: !isPk, readonly: isPk,
|
|
137
|
+
allowOverlay: !isPk, readonly: isPk || readOnlyRef.current,
|
|
133
138
|
themeOverride: hasPending ? PENDING_THEME : undefined,
|
|
134
139
|
};
|
|
135
140
|
}, []); // stable — reads from refs
|
|
136
141
|
|
|
137
142
|
const onCellEdited = useCallback(([colIdx, rowIdx]: Item, newValue: EditableGridCell) => {
|
|
138
|
-
if (!pkCol) return;
|
|
143
|
+
if (!pkCol || readOnly) return;
|
|
139
144
|
const colName = colOrderRef.current[colIdx];
|
|
140
145
|
const row = rowsRef.current[rowIdx];
|
|
141
146
|
if (!colName || !row) return;
|
|
@@ -153,7 +158,7 @@ export function useGlideCellContent(
|
|
|
153
158
|
}
|
|
154
159
|
|
|
155
160
|
addPendingEdit(pkVal, colName, parsed);
|
|
156
|
-
}, [pkCol, addPendingEdit]);
|
|
161
|
+
}, [pkCol, readOnly, addPendingEdit]);
|
|
157
162
|
|
|
158
163
|
return { getCellContent, onCellEdited };
|
|
159
164
|
}
|
|
@@ -14,7 +14,8 @@ import { EditorToolbar } from "./editor-toolbar";
|
|
|
14
14
|
import { EditorLanguagePicker } from "./editor-language-picker";
|
|
15
15
|
import { SaveAsDialog } from "./save-as-dialog";
|
|
16
16
|
import { EditorMobileToolbar } from "./editor-mobile-toolbar";
|
|
17
|
-
import { createSqlCompletionProvider, clearCompletionCache,
|
|
17
|
+
import { createSqlCompletionProvider, clearCompletionCache, type SchemaInfo } from "../database/sql-completion-provider";
|
|
18
|
+
import { getStatementAtCursor, splitSqlStatements } from "../database/split-sql-statements";
|
|
18
19
|
import { useConnections, type Connection } from "../database/use-connections";
|
|
19
20
|
import { GlideDataGrid } from "../database/glide-data-grid";
|
|
20
21
|
import type { GridColumnSchema } from "../database/glide-grid-types";
|
|
@@ -509,76 +510,49 @@ export const CodeEditor = memo(function CodeEditor({ metadata, tabId }: CodeEdit
|
|
|
509
510
|
if (model !== thisModel) return { lenses: [], dispose: () => {} };
|
|
510
511
|
|
|
511
512
|
const lenses: MonacoType.languages.CodeLens[] = [];
|
|
512
|
-
const text = model.getValue();
|
|
513
|
-
const lines = text.split("\n");
|
|
514
|
-
let stmtStartLine = -1;
|
|
515
|
-
let stmtLines: string[] = [];
|
|
516
|
-
let dollarBlock = false; // Track DO $$ ... $$ blocks
|
|
517
|
-
|
|
518
|
-
// Transaction block tracking: group BEGIN...COMMIT into single Run Transaction
|
|
519
|
-
const txPattern = /^(BEGIN|COMMIT|ROLLBACK|END)(;|\s|$)/i;
|
|
520
|
-
let txBlockStartLine = -1;
|
|
521
|
-
let txBlockStmts: string[] = [];
|
|
522
513
|
|
|
523
514
|
const addLens = (line: number, stmt: string, title = "\u25B7 Run") => {
|
|
524
515
|
const trimmed = stmt.trim();
|
|
525
|
-
if (!trimmed
|
|
516
|
+
if (!trimmed) return;
|
|
526
517
|
lenses.push({
|
|
527
518
|
range: { startLineNumber: line, startColumn: 1, endLineNumber: line, endColumn: 1 },
|
|
528
519
|
command: { id: cmdId, title, arguments: [trimmed] },
|
|
529
520
|
});
|
|
530
521
|
};
|
|
531
522
|
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
stmtStartLine = i + 1;
|
|
537
|
-
stmtLines = [];
|
|
538
|
-
}
|
|
539
|
-
stmtLines.push(lines[i]!);
|
|
540
|
-
|
|
541
|
-
// Detect $$ dollar-quoted block start/end
|
|
542
|
-
const dollarMatches = (trimmed.match(/\$\$/g) || []).length;
|
|
543
|
-
if (dollarMatches % 2 === 1) dollarBlock = !dollarBlock;
|
|
544
|
-
|
|
545
|
-
// Only split on ; when NOT inside a $$ block
|
|
546
|
-
if (!dollarBlock && trimmed.endsWith(";")) {
|
|
547
|
-
const stmt = stmtLines.join("\n").trim();
|
|
548
|
-
const isTxStart = /^BEGIN(;|\s|$)/i.test(stmt);
|
|
549
|
-
const isTxEnd = /^(COMMIT|ROLLBACK|END)(;|\s|$)/i.test(stmt);
|
|
550
|
-
|
|
551
|
-
if (txBlockStartLine === -1 && isTxStart) {
|
|
552
|
-
// Start collecting transaction block
|
|
553
|
-
txBlockStartLine = stmtStartLine;
|
|
554
|
-
txBlockStmts = [stmt];
|
|
555
|
-
} else if (txBlockStartLine > -1) {
|
|
556
|
-
txBlockStmts.push(stmt);
|
|
557
|
-
// Individual Run for non-tx-control statements inside block
|
|
558
|
-
if (!isTxEnd && !txPattern.test(stmt)) {
|
|
559
|
-
addLens(stmtStartLine, stmt);
|
|
560
|
-
}
|
|
561
|
-
if (isTxEnd) {
|
|
562
|
-
// Complete block — add Run Transaction at BEGIN line
|
|
563
|
-
addLens(txBlockStartLine, txBlockStmts.join("\n"), "\u25B7 Run Transaction");
|
|
564
|
-
txBlockStartLine = -1;
|
|
565
|
-
txBlockStmts = [];
|
|
566
|
-
}
|
|
567
|
-
} else {
|
|
568
|
-
addLens(stmtStartLine, stmt);
|
|
569
|
-
}
|
|
523
|
+
// Transaction block tracking: group BEGIN...COMMIT into single Run Transaction
|
|
524
|
+
const txPattern = /^(BEGIN|COMMIT|ROLLBACK|END)(;|\s|$)/i;
|
|
525
|
+
let txBlockStartLine = -1;
|
|
526
|
+
let txBlockStmts: string[] = [];
|
|
570
527
|
|
|
571
|
-
|
|
572
|
-
|
|
528
|
+
for (const { sql, startLine } of splitSqlStatements(model.getValue())) {
|
|
529
|
+
const isTxStart = /^BEGIN(;|\s|$)/i.test(sql);
|
|
530
|
+
const isTxEnd = /^(COMMIT|ROLLBACK|END)(;|\s|$)/i.test(sql);
|
|
531
|
+
|
|
532
|
+
if (txBlockStartLine === -1 && isTxStart) {
|
|
533
|
+
// Start collecting transaction block
|
|
534
|
+
txBlockStartLine = startLine;
|
|
535
|
+
txBlockStmts = [sql];
|
|
536
|
+
} else if (txBlockStartLine > -1) {
|
|
537
|
+
txBlockStmts.push(sql);
|
|
538
|
+
// Individual Run for non-tx-control statements inside block
|
|
539
|
+
if (!isTxEnd && !txPattern.test(sql)) {
|
|
540
|
+
addLens(startLine, sql);
|
|
541
|
+
}
|
|
542
|
+
if (isTxEnd) {
|
|
543
|
+
// Complete block — add Run Transaction at BEGIN line
|
|
544
|
+
addLens(txBlockStartLine, txBlockStmts.join("\n"), "\u25B7 Run Transaction");
|
|
545
|
+
txBlockStartLine = -1;
|
|
546
|
+
txBlockStmts = [];
|
|
547
|
+
}
|
|
548
|
+
} else {
|
|
549
|
+
addLens(startLine, sql);
|
|
573
550
|
}
|
|
574
551
|
}
|
|
575
552
|
// Unclosed transaction block — still offer Run Transaction
|
|
576
553
|
if (txBlockStartLine > -1 && txBlockStmts.length > 1) {
|
|
577
554
|
addLens(txBlockStartLine, txBlockStmts.join("\n"), "\u25B7 Run Transaction");
|
|
578
555
|
}
|
|
579
|
-
if (stmtStartLine > 0 && stmtLines.join("").trim()) {
|
|
580
|
-
addLens(stmtStartLine, stmtLines.join("\n"));
|
|
581
|
-
}
|
|
582
556
|
return { lenses, dispose: () => {} };
|
|
583
557
|
},
|
|
584
558
|
});
|
|
@@ -878,7 +852,7 @@ function SqlResultPanel({ result, error, loading, connName, onClose, onOpenInTab
|
|
|
878
852
|
<GlideDataGrid
|
|
879
853
|
columns={tableData.columns} rows={tableData.rows} total={tableData.total} limit={tableData.limit}
|
|
880
854
|
schema={querySchema} loading={false}
|
|
881
|
-
page={1} onPageChange={NOOP} onCellUpdate={NOOP}
|
|
855
|
+
page={1} onPageChange={NOOP} onCellUpdate={NOOP} readOnly
|
|
882
856
|
orderBy={null} orderDir="ASC" onToggleSort={NOOP}
|
|
883
857
|
connectionName={connName}
|
|
884
858
|
/>
|
|
@@ -90,7 +90,7 @@ interface UseChatReturn {
|
|
|
90
90
|
backgroundShells: BackgroundShell[];
|
|
91
91
|
killBackgroundShell: (shellId: string) => void;
|
|
92
92
|
findBackgroundShellByOutput: (name: string) => BackgroundShell | undefined;
|
|
93
|
-
sendMessage: (content: string, opts?: { permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }
|
|
93
|
+
sendMessage: (content: string, opts?: { permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }>; imagePaths?: string[] }) => void;
|
|
94
94
|
respondToApproval: (requestId: string, approved: boolean, data?: unknown) => void;
|
|
95
95
|
cancelStreaming: () => void;
|
|
96
96
|
reconnect: () => void;
|
|
@@ -1035,8 +1035,10 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
1035
1035
|
}, [sessionId, providerId, projectName, updateTeamActivity, loadTeamDetail]);
|
|
1036
1036
|
|
|
1037
1037
|
const sendMessage = useCallback(
|
|
1038
|
-
(content: string, opts?: { permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }
|
|
1039
|
-
|
|
1038
|
+
(content: string, opts?: { permissionMode?: string; priority?: 'now' | 'next' | 'later'; images?: Array<{ data: string; mediaType: string }>; imagePaths?: string[] }) => {
|
|
1039
|
+
// An attachment-only message is legitimate now that images travel with it: the
|
|
1040
|
+
// caller may have nothing to say beyond the picture.
|
|
1041
|
+
if (!content.trim() && !opts?.images?.length) return;
|
|
1040
1042
|
|
|
1041
1043
|
const isFollowUp = phaseRef.current !== "idle";
|
|
1042
1044
|
|
|
@@ -1089,6 +1091,7 @@ export function useChat(sessionId: string | null, providerId = "claude", project
|
|
|
1089
1091
|
permissionMode: opts?.permissionMode,
|
|
1090
1092
|
priority: opts?.priority,
|
|
1091
1093
|
images: opts?.images,
|
|
1094
|
+
imagePaths: opts?.imagePaths,
|
|
1092
1095
|
...(modelRef.current && { model: modelRef.current }),
|
|
1093
1096
|
...(effortRef.current && { effort: effortRef.current }),
|
|
1094
1097
|
...(thinkingRef.current !== null && { thinking: thinkingRef.current }),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which attachments are announced as already-included, and which as files to open.
|
|
3
|
+
*
|
|
4
|
+
* Split out from the composer so it can be asserted on. The decision looks obvious and is
|
|
5
|
+
* not: it has to follow the payloads that actually go out, not merely which attachments have
|
|
6
|
+
* one. The per-message caps can leave an image behind, and announcing that its contents are
|
|
7
|
+
* included would hand the model neither the picture nor a reason to open the file.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** The parts of an attachment this split needs. */
|
|
11
|
+
export interface MarkerCandidate {
|
|
12
|
+
serverPath?: string;
|
|
13
|
+
imageData?: { data: string; mediaType: string };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface MarkerSplit {
|
|
17
|
+
/** Uploaded paths whose payloads are travelling in this message. */
|
|
18
|
+
inlineImagePaths: string[];
|
|
19
|
+
/** Uploaded paths the model has to open for itself. */
|
|
20
|
+
pathOnlyPaths: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Sort `attachments` by whether their payload is in `inlineImages`.
|
|
25
|
+
*
|
|
26
|
+
* An attachment with no uploaded path is in neither list: there is nothing to name. Identity
|
|
27
|
+
* is what pairs a payload to its attachment — `inlineImages` holds the very objects the
|
|
28
|
+
* attachments carry, so a second image with byte-identical data is not mistaken for the one
|
|
29
|
+
* that was picked.
|
|
30
|
+
*/
|
|
31
|
+
export function splitAttachmentMarkers(
|
|
32
|
+
attachments: MarkerCandidate[],
|
|
33
|
+
inlineImages: Array<{ data: string; mediaType: string }>,
|
|
34
|
+
): MarkerSplit {
|
|
35
|
+
const sent = new Set(inlineImages);
|
|
36
|
+
const inlineImagePaths: string[] = [];
|
|
37
|
+
const pathOnlyPaths: string[] = [];
|
|
38
|
+
for (const a of attachments) {
|
|
39
|
+
if (!a.serverPath) continue;
|
|
40
|
+
if (a.imageData && sent.has(a.imageData)) inlineImagePaths.push(a.serverPath);
|
|
41
|
+
else pathOnlyPaths.push(a.serverPath);
|
|
42
|
+
}
|
|
43
|
+
return { inlineImagePaths, pathOnlyPaths };
|
|
44
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether an image file carries more than one frame.
|
|
3
|
+
*
|
|
4
|
+
* Re-encoding through a canvas keeps a single frame, so an animated image that goes through
|
|
5
|
+
* the downscaler comes out silently flattened — and for the animations people paste into a
|
|
6
|
+
* chat, a screen recording of a bug or a flow, the motion *is* the content. Better to leave
|
|
7
|
+
* such a file at its original size than to shrink away the thing being shown.
|
|
8
|
+
*
|
|
9
|
+
* Detection reads container markers rather than decoding: an animated WebP declares an `ANIM`
|
|
10
|
+
* chunk and an animated PNG an `acTL` chunk, both within the first few hundred bytes. GIF is
|
|
11
|
+
* treated as animated without inspection — the marker for a still GIF is the *absence* of
|
|
12
|
+
* extra frame separators, which cannot be established from a prefix, and a still GIF is rare
|
|
13
|
+
* enough that assuming motion costs almost nothing.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Bytes read from the front of a file to look for animation markers. */
|
|
17
|
+
const HEADER_BYTES = 4096;
|
|
18
|
+
|
|
19
|
+
function findAscii(bytes: Uint8Array, needle: string): boolean {
|
|
20
|
+
const target = new TextEncoder().encode(needle);
|
|
21
|
+
outer: for (let i = 0; i + target.length <= bytes.length; i++) {
|
|
22
|
+
for (let j = 0; j < target.length; j++) {
|
|
23
|
+
if (bytes[i + j] !== target[j]) continue outer;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function hasAnimationMarker(type: string, header: Uint8Array): boolean {
|
|
31
|
+
if (type === "image/gif") return true;
|
|
32
|
+
if (type === "image/webp") return findAscii(header, "ANIM");
|
|
33
|
+
if (type === "image/png" || type === "image/apng") return findAscii(header, "acTL");
|
|
34
|
+
// AVIF sequences and anything unrecognised: not decodable here anyway, so the caller
|
|
35
|
+
// falls back to sending the file by path.
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Read enough of `file` to answer, treating an unreadable file as animated (do not touch it). */
|
|
40
|
+
export async function isAnimatedImage(file: File): Promise<boolean> {
|
|
41
|
+
if (file.type === "image/gif") return true;
|
|
42
|
+
if (file.type !== "image/webp" && file.type !== "image/png" && file.type !== "image/apng") {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const head = new Uint8Array(await file.slice(0, HEADER_BYTES).arrayBuffer());
|
|
47
|
+
return hasAnimationMarker(file.type, head);
|
|
48
|
+
} catch {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ceilings on what may be sent as inline image payloads in one message.
|
|
3
|
+
*
|
|
4
|
+
* The chat socket refuses a message outright when it carries more than five images or one
|
|
5
|
+
* above seven million base64 characters, and the WebSocket frame itself has a size past which
|
|
6
|
+
* Bun closes the connection — which loses the message with nothing shown to the user. Both are
|
|
7
|
+
* worth staying under by a margin rather than discovering at the boundary.
|
|
8
|
+
*
|
|
9
|
+
* Exceeding these is not an error: the attachment travels by path instead, which is how every
|
|
10
|
+
* attachment worked before inlining existed.
|
|
11
|
+
*/
|
|
12
|
+
export const INLINE_IMAGE_LIMITS = {
|
|
13
|
+
/** Server refuses a message carrying more than five. */
|
|
14
|
+
maxImages: 4,
|
|
15
|
+
/** Server refuses a single payload above 7,000,000 base64 characters. */
|
|
16
|
+
maxBase64PerImage: 5_000_000,
|
|
17
|
+
/** Frame budget across all payloads in one message, well under the 16 MiB default. */
|
|
18
|
+
maxBase64Total: 10_000_000,
|
|
19
|
+
} as const;
|
|
20
|
+
|
|
21
|
+
/** The subset of an attachment this module needs to decide whether it can ride inline. */
|
|
22
|
+
export interface InlineCandidate {
|
|
23
|
+
imageData?: { data: string; mediaType: string };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The image payloads that may ride on one message, in order, up to those ceilings.
|
|
28
|
+
*
|
|
29
|
+
* An attachment past a ceiling is left out rather than refused: its path is still in the
|
|
30
|
+
* message, so the model can open it the old way. A candidate that does not fit is skipped
|
|
31
|
+
* instead of ending the scan, so one large image does not exclude the small ones after it.
|
|
32
|
+
*/
|
|
33
|
+
export function selectInlineImages(
|
|
34
|
+
attachments: InlineCandidate[],
|
|
35
|
+
): Array<{ data: string; mediaType: string }> {
|
|
36
|
+
const picked: Array<{ data: string; mediaType: string }> = [];
|
|
37
|
+
let total = 0;
|
|
38
|
+
for (const a of attachments) {
|
|
39
|
+
if (!a.imageData) continue;
|
|
40
|
+
if (picked.length >= INLINE_IMAGE_LIMITS.maxImages) break;
|
|
41
|
+
if (a.imageData.data.length > INLINE_IMAGE_LIMITS.maxBase64PerImage) continue;
|
|
42
|
+
if (total + a.imageData.data.length > INLINE_IMAGE_LIMITS.maxBase64Total) continue;
|
|
43
|
+
total += a.imageData.data.length;
|
|
44
|
+
picked.push(a.imageData);
|
|
45
|
+
}
|
|
46
|
+
return picked;
|
|
47
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { MAX_IMAGE_DIMENSION, fitWithin } from "../../shared/image-limits";
|
|
2
|
+
import { isAnimatedImage } from "./image-animation";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Downscaling of attachments before they are sent.
|
|
6
|
+
*
|
|
7
|
+
* An image is billed by area, so a screenshot straight off a high-resolution display costs
|
|
8
|
+
* several thousand tokens on every turn for the rest of the session's life — and past the
|
|
9
|
+
* API's ceiling it is refused outright, which fails not just that turn but every later one,
|
|
10
|
+
* since the transcript is replayed in full each time.
|
|
11
|
+
*
|
|
12
|
+
* Done in the browser because that is where the image already exists as pixels: the decoder
|
|
13
|
+
* scales it on the way in, and the smaller file is what gets uploaded, previewed, embedded and
|
|
14
|
+
* stored, so nothing downstream ever sees the oversized original.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Longest side an attachment is reduced to. Below the API ceiling, still legible for text. */
|
|
18
|
+
export const ATTACHMENT_MAX_DIMENSION = 1600;
|
|
19
|
+
|
|
20
|
+
/** Media types the chat socket accepts as an inline payload. */
|
|
21
|
+
const INLINE_MEDIA_TYPES = new Set(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
22
|
+
|
|
23
|
+
export type ResizeKind =
|
|
24
|
+
/** Re-encoded smaller. Safe to send inline: dimensions and type are both known good. */
|
|
25
|
+
| "scaled"
|
|
26
|
+
/** Already small enough and of a type the socket takes. Safe to send inline unchanged. */
|
|
27
|
+
| "inlineable"
|
|
28
|
+
/** Could not be measured or re-encoded. Must go by path — see the note on `downscaleImage`. */
|
|
29
|
+
| "asis";
|
|
30
|
+
|
|
31
|
+
export interface ResizeOutcome {
|
|
32
|
+
kind: ResizeKind;
|
|
33
|
+
file: File;
|
|
34
|
+
/** Original dimensions, when they could be read. */
|
|
35
|
+
from?: { width: number; height: number };
|
|
36
|
+
/** Dimensions after scaling, when a scale happened. */
|
|
37
|
+
to?: { width: number; height: number };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Canvas encodes to a handful of types; anything else round-trips as PNG. */
|
|
41
|
+
export function encodeType(type: string): string {
|
|
42
|
+
return type === "image/jpeg" || type === "image/webp" ? type : "image/png";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Return a copy of `file` scaled to fit `max`, and say whether the result may be sent inline.
|
|
47
|
+
*
|
|
48
|
+
* Never throws: a browser without `createImageBitmap`, an image it cannot decode (HEIC on
|
|
49
|
+
* Android, AVIF, a corrupt EXIF header), or a canvas that will not encode all resolve to
|
|
50
|
+
* `kind: "asis"` with the original file.
|
|
51
|
+
*
|
|
52
|
+
* That distinction is the point. Sending an unmeasured original inline is worse than not
|
|
53
|
+
* inlining at all: an oversized payload is refused by the API, and the refusal is not confined
|
|
54
|
+
* to the turn — the transcript replays it, so every later turn fails too, and the retry path
|
|
55
|
+
* pushes the same bytes again. A caller that cannot scale an image must fall back to passing
|
|
56
|
+
* its path, which is what the product did before inlining existed and still works.
|
|
57
|
+
*/
|
|
58
|
+
export async function downscaleImage(
|
|
59
|
+
file: File,
|
|
60
|
+
max: number = ATTACHMENT_MAX_DIMENSION,
|
|
61
|
+
): Promise<ResizeOutcome> {
|
|
62
|
+
const asis: ResizeOutcome = { kind: "asis", file };
|
|
63
|
+
if (!file.type.startsWith("image/") || file.type === "image/svg+xml") return asis;
|
|
64
|
+
if (typeof createImageBitmap !== "function" || typeof document === "undefined") return asis;
|
|
65
|
+
|
|
66
|
+
let probe: ImageBitmap;
|
|
67
|
+
try {
|
|
68
|
+
probe = await createImageBitmap(file);
|
|
69
|
+
} catch {
|
|
70
|
+
return asis;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const from = { width: probe.width, height: probe.height };
|
|
74
|
+
// `fitWithin` treats its bound as an exclusive ceiling, which is right for the API's limit
|
|
75
|
+
// but would re-encode an image measuring exactly the attachment target for one pixel.
|
|
76
|
+
const to = fitWithin(from.width, from.height, max + 1);
|
|
77
|
+
|
|
78
|
+
// A canvas keeps one frame, so scaling an animation throws the animation away. Send it at
|
|
79
|
+
// its own size when the API will still take it, and by path when it will not — losing the
|
|
80
|
+
// motion is not a trade worth making silently for a picture someone chose to send moving.
|
|
81
|
+
if (to && (await isAnimatedImage(file))) {
|
|
82
|
+
probe.close?.();
|
|
83
|
+
return Math.max(from.width, from.height) < MAX_IMAGE_DIMENSION && INLINE_MEDIA_TYPES.has(file.type)
|
|
84
|
+
? { kind: "inlineable", file, from }
|
|
85
|
+
: { kind: "asis", file, from };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!to) {
|
|
89
|
+
probe.close?.();
|
|
90
|
+
// Already small enough — inline it only if the socket takes this type as-is.
|
|
91
|
+
return INLINE_MEDIA_TYPES.has(file.type)
|
|
92
|
+
? { kind: "inlineable", file, from }
|
|
93
|
+
: { kind: "asis", file, from };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
let bitmap = probe;
|
|
97
|
+
try {
|
|
98
|
+
// Let the decoder do the scaling where it can: a full-size bitmap of a phone photo is
|
|
99
|
+
// tens of megabytes of RGBA held on the main thread purely to be thrown away.
|
|
100
|
+
try {
|
|
101
|
+
bitmap = await createImageBitmap(file, {
|
|
102
|
+
resizeWidth: to.width,
|
|
103
|
+
resizeHeight: to.height,
|
|
104
|
+
resizeQuality: "high",
|
|
105
|
+
});
|
|
106
|
+
probe.close?.();
|
|
107
|
+
} catch {
|
|
108
|
+
bitmap = probe;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const canvas = document.createElement("canvas");
|
|
112
|
+
canvas.width = to.width;
|
|
113
|
+
canvas.height = to.height;
|
|
114
|
+
const ctx = canvas.getContext("2d");
|
|
115
|
+
if (!ctx) return { kind: "asis", file, from };
|
|
116
|
+
ctx.imageSmoothingEnabled = true;
|
|
117
|
+
ctx.imageSmoothingQuality = "high";
|
|
118
|
+
ctx.drawImage(bitmap, 0, 0, to.width, to.height);
|
|
119
|
+
|
|
120
|
+
const type = encodeType(file.type);
|
|
121
|
+
const blob = await new Promise<Blob | null>((res) => canvas.toBlob(res, type, 0.92));
|
|
122
|
+
// Some encoders answer with an empty blob rather than null on failure.
|
|
123
|
+
if (!blob || blob.size === 0) return { kind: "asis", file, from };
|
|
124
|
+
|
|
125
|
+
const name = type === file.type ? file.name : file.name.replace(/\.[^.]+$/, "") + ".png";
|
|
126
|
+
return { kind: "scaled", file: new File([blob], name, { type }), from, to };
|
|
127
|
+
} catch {
|
|
128
|
+
return { kind: "asis", file, from };
|
|
129
|
+
} finally {
|
|
130
|
+
bitmap.close?.();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-CKTlmXbz.js";import"./vendor-ui-CXJtBULr.js";import{i as e,n as t}from"./api-client-qRWu6_s5.js";export{t as api,e as projectUrl};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./vendor-markdown-CKTlmXbz.js";import"./vendor-ui-CXJtBULr.js";import"./api-client-qRWu6_s5.js";import{v as e}from"./api-settings-CPg4yGvS.js";export{e as updateDeviceName};
|