@hienlh/ppm 0.22.11 → 0.23.1
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 +24 -1
- package/CLAUDE.md +14 -0
- package/THIRD-PARTY-NOTICES.md +1 -1
- package/assets/skills/ppm/SKILL.md +1 -1
- package/assets/skills/ppm/references/http-api.md +1 -1
- package/bun.lock +17 -0
- package/dist/web/assets/__vite-browser-external-CHpXvvmW.js +1 -0
- package/dist/web/assets/accounts-settings-section-BR7t8CEk.js +1 -0
- package/dist/web/assets/ai-resource-editor-BFVg2d2a.js +1 -0
- package/dist/web/assets/ai-settings-section-BJw7E_lM.js +1 -0
- package/dist/web/assets/ai-settings-section-CO-i3ghA.js +1 -0
- package/dist/web/assets/angular-html-D-rbk4zq.js +1 -0
- package/dist/web/assets/angular-ts-B_ldKah2.js +1 -0
- package/dist/web/assets/api-client-BgedDTvo.js +1 -0
- package/dist/web/assets/api-client-c8YOpTlT.js +1 -0
- package/dist/web/assets/api-settings-0s1Rfgcu.js +1 -0
- package/dist/web/assets/api-settings-Bnp28Ysw.js +1 -0
- package/dist/web/assets/api-themes-Pp-AZvwV.js +1 -0
- package/dist/web/assets/apl-19Dr02g6.js +1 -0
- package/dist/web/assets/appearance-settings-section-Ck_FPs9g.js +1 -0
- package/dist/web/assets/architecture-PBZL5I3N-B_n8ddB4.js +1 -0
- package/dist/web/assets/astro-1q5o0N64.js +1 -0
- package/dist/web/assets/audio-preview-DXtE1Lpz.js +1 -0
- package/dist/web/assets/blade-BNgXZCCk.js +1 -0
- package/dist/web/assets/branch-review-tab-CNVxMRuo.js +1 -0
- package/dist/web/assets/bsl-C5u8-gEq.js +1 -0
- package/dist/web/assets/button-CBehaXpV.js +1 -0
- package/dist/web/assets/c-Dko4ZphN.js +1 -0
- package/dist/web/assets/cairo-CrhmfCJH.js +1 -0
- package/dist/web/assets/chat-tab-DqLqcBci.js +1 -0
- package/dist/web/assets/chat-tab-MdU9Jr3F.js +15 -0
- package/dist/web/assets/cobol-BgRxrYyZ.js +1 -0
- package/dist/web/assets/code-editor-wEeCvvMR.js +7 -0
- package/dist/web/assets/codex-daily-guard-B21M4m-P.js +1 -0
- package/dist/web/assets/coffee-9hmEOIYs.js +1 -0
- package/dist/web/assets/conflict-editor-Cu-z_LdX.js +19 -0
- package/dist/web/assets/context-menu-CjYTq8DI.js +1 -0
- package/dist/web/assets/cpp-BntsLe3X.js +1 -0
- package/dist/web/assets/createLucideIcon-DBXq3G0e.js +1 -0
- package/dist/web/assets/crystal-CoXN2Gj8.js +1 -0
- package/dist/web/assets/css-DKuKlxIj.js +1 -0
- package/dist/web/assets/csv-preview-DHbBIqUu.js +2 -0
- package/dist/web/assets/data-grid-overlay-editor-2ERlh7_N.js +1 -0
- package/dist/web/assets/data-grid-types-DatI2Wee.js +1 -0
- package/dist/web/assets/database-viewer-_McYjRzc.js +1 -0
- package/dist/web/assets/design-export-client-SWCbGwwU.js +1 -0
- package/dist/web/assets/design-responsive-dialog-CcJETHO2.js +1 -0
- package/dist/web/assets/design-tab-C0TUD5g-.js +33 -0
- package/dist/web/assets/designs-sidebar-panel-XCAwSNtg.js +1 -0
- package/dist/web/assets/dialog-tzBRkGeW.js +1 -0
- package/dist/web/assets/diff-viewer-C4z-_68x.js +4 -0
- package/dist/web/assets/dist-CgtN5c7X.js +1 -0
- package/dist/web/assets/dist-wmDsBD_Z.js +1 -0
- package/dist/web/assets/docx-preview-C-UKGMXR.js +12 -0
- package/dist/web/assets/edge-gf7weBFr.js +1 -0
- package/dist/web/assets/edit-diff-preview-8nIct7kS.js +7 -0
- package/dist/web/assets/editor-language-service-D8hW_eew.js +1 -0
- package/dist/web/assets/elixir-DOEwBYus.js +1 -0
- package/dist/web/assets/elm-7yx1A5qt.js +1 -0
- package/dist/web/assets/erb-Bm_J_rBw.js +1 -0
- package/dist/web/assets/erlang-DgkAVj5y.js +1 -0
- package/dist/web/assets/esm-wquH4IhX.js +2 -0
- package/dist/web/assets/explorer-body-CdxolRQG.js +2 -0
- package/dist/web/assets/explorer-window-content-D1fkI_cL.js +1 -0
- package/dist/web/assets/extension-manager-section-CAaSoAuG.js +1 -0
- package/dist/web/assets/extension-webview-DmBZun_i.js +12 -0
- package/dist/web/assets/file-icons-BlOxPo3P.js +1 -0
- package/dist/web/assets/file-store-CTlJqj2m.js +1 -0
- package/dist/web/assets/files-settings-section-BFIzSuBh.js +1 -0
- package/dist/web/assets/format-date-BMtvCeb9.js +1 -0
- package/dist/web/assets/format-file-meta-DLaHgkdx.js +1 -0
- package/dist/web/assets/fortran-fixed-form-s8lQifxM.js +1 -0
- package/dist/web/assets/fs-api-RVc5RtTA.js +1 -0
- package/dist/web/assets/fsharp-D6bmDjka.js +1 -0
- package/dist/web/assets/gdresource-wPII3GWW.js +1 -0
- package/dist/web/assets/general-settings-section-BLLUvdhX.js +1 -0
- package/dist/web/assets/git-commit-DqLhxK6K.js +1 -0
- package/dist/web/assets/git-log-panel-Lq2Vkm8w.js +1 -0
- package/dist/web/assets/git-rebase-Cy0Mp9W1.js +1 -0
- package/dist/web/assets/git-repo-store-DFTJ5ngK.js +1 -0
- package/dist/web/assets/gitGraph-HDMCJU4V-w1WApLyy.js +1 -0
- package/dist/web/assets/glide-data-grid-CHdKFqis.js +141 -0
- package/dist/web/assets/glimmer-js-CmHFqq4N.js +1 -0
- package/dist/web/assets/glimmer-ts-vLmZC1JJ.js +1 -0
- package/dist/web/assets/glsl-DArPh0ws.js +1 -0
- package/dist/web/assets/graphql-B-_Ilekp.js +1 -0
- package/dist/web/assets/group-chat-tab-D2bluLme.js +1 -0
- package/dist/web/assets/hack-4KVRpwwM.js +1 -0
- package/dist/web/assets/haml-DoK94C5G.js +1 -0
- package/dist/web/assets/handlebars-D0_6yNlK.js +1 -0
- package/dist/web/assets/html-BOqZwhzR.js +1 -0
- package/dist/web/assets/html-derivative-If_2xbJ8.js +1 -0
- package/dist/web/assets/http-B6pQhqN4.js +1 -0
- package/dist/web/assets/hurl-BjW79rql.js +1 -0
- package/dist/web/assets/hxml-B1Yl76u6.js +1 -0
- package/dist/web/assets/icons-CO_II6D-.js +1 -0
- package/dist/web/assets/image-preview-78Fguk1f.js +1 -0
- package/dist/web/assets/index-CzYrKDUF.css +1 -0
- package/dist/web/assets/index-DSbUqWiH.js +52 -0
- package/dist/web/assets/info-3K5VOQVL-Bv1wKdPY.js +1 -0
- package/dist/web/assets/input-CP31LZnN.js +1 -0
- package/dist/web/assets/java-DPqGHyuh.js +1 -0
- package/dist/web/assets/javascript-D8x_R8ev.js +1 -0
- package/dist/web/assets/jinja-DOkXV84k.js +1 -0
- package/dist/web/assets/jira-watcher-section-BOe_ztas.js +1 -0
- package/dist/web/assets/jison-CGzlyBWT.js +1 -0
- package/dist/web/assets/json-kcFjaEWA.js +1 -0
- package/dist/web/assets/jsx-BzlJCumN.js +1 -0
- package/dist/web/assets/julia-CZrbm1Fa.js +1 -0
- package/dist/web/assets/just-bRG6zWI_.js +1 -0
- package/dist/web/assets/keybindings-store-DFPJBiXT.js +1 -0
- package/dist/web/assets/keyboard-shortcuts-section-CJubMhMq.js +1 -0
- package/dist/web/assets/latex-CZHLEkde.js +1 -0
- package/dist/web/assets/lib-KePrAxj7.js +4 -0
- package/dist/web/assets/liquid-Dcfq3Ccc.js +1 -0
- package/dist/web/assets/lua-Ggfu9EYp.js +1 -0
- package/dist/web/assets/markdown-renderer-6oU-L6RN.js +5 -0
- package/dist/web/assets/markdown-renderer-DxSQ4aqW.js +1 -0
- package/dist/web/assets/marko-BUwN_Iax.js +1 -0
- package/dist/web/assets/mdc-CIifdeNY.js +1 -0
- package/dist/web/assets/media-url-GqzhazJS.js +1 -0
- package/dist/web/assets/mobile-bottom-sheet-Cf4kV1hS.js +1 -0
- package/dist/web/assets/mobile-explorer-sheet-D0968cuP.js +1 -0
- package/dist/web/assets/monaco-dotenv-language-COsgiuQg.js +1 -0
- package/dist/web/assets/new-chat-provider-CJx_waY3.js +1 -0
- package/dist/web/assets/new-design-dialog-CbrMbKum.js +1 -0
- package/dist/web/assets/nextflow-DufnRZW1.js +1 -0
- package/dist/web/assets/nginx-DtUJGfad.js +1 -0
- package/dist/web/assets/nim-BeBPwibr.js +1 -0
- package/dist/web/assets/notification-store-BO3RInEL.js +1 -0
- package/dist/web/assets/notifications-settings-section-Bfxqz65i.js +1 -0
- package/dist/web/assets/number-overlay-editor-xzM7GhYV.js +9 -0
- package/dist/web/assets/onboarding-entry-CcvySZ_l.js +1 -0
- package/dist/web/assets/onboarding-quick-orientation-CT4PylG0.js +1 -0
- package/dist/web/assets/overview-panel-DshAIz6C.js +1 -0
- package/dist/web/assets/packet-RMMSAZCW-Scl5HE6U.js +1 -0
- package/dist/web/assets/panel-store-BUQ-CPsd.js +1 -0
- package/dist/web/assets/pdf-preview-BWim6mu1.js +1 -0
- package/dist/web/assets/perl-hV0EoLCp.js +1 -0
- package/dist/web/assets/php-N1YBqBhK.js +1 -0
- package/dist/web/assets/pie-UPGHQEXC-sY83O9qJ.js +1 -0
- package/dist/web/assets/portal-container-context-NFSuymMu.js +1 -0
- package/dist/web/assets/postgres-viewer-HwlL1UTJ.js +3 -0
- package/dist/web/assets/ppmbot-settings-section-CHr2FIDj.js +1 -0
- package/dist/web/assets/pptx-export-D6DOknBD.js +111 -0
- package/dist/web/assets/problems-panel-41z59l78.js +1 -0
- package/dist/web/assets/process-table-CVMEMJqQ.js +1 -0
- package/dist/web/assets/project-framework-store-XxFXcUpb.js +1 -0
- package/dist/web/assets/project-store-C5gJXkvb.js +1 -0
- package/dist/web/assets/proxy-settings-section-B4dkvCCx.js +1 -0
- package/dist/web/assets/pug-IMA1knL7.js +1 -0
- package/dist/web/assets/qml-DuwVuXga.js +1 -0
- package/dist/web/assets/query-audit-section-Cn11xqgz.js +1 -0
- package/dist/web/assets/r-DsXT2lmn.js +1 -0
- package/dist/web/assets/radar-KQ55EAFF-CNhm_kzj.js +1 -0
- package/dist/web/assets/razor-Be4LE-G0.js +1 -0
- package/dist/web/assets/react-CzUPVyyG.js +1 -0
- package/dist/web/assets/regexp-ztLDvplH.js +1 -0
- package/dist/web/assets/remote-desktop-clipboard-notice-Co4vEiiB.js +1 -0
- package/dist/web/assets/remote-desktop-mobile-sheet-Cv4yo7K4.js +2 -0
- package/dist/web/assets/remote-desktop-mobile-view-CcuulHIu.js +1 -0
- package/dist/web/assets/remote-desktop-readiness-gate-ouPRvBlu.js +1 -0
- package/dist/web/assets/remote-desktop-window-content-DmH3jBuG.js +1 -0
- package/dist/web/assets/rolldown-runtime-C5c2KzVm.js +1 -0
- package/dist/web/assets/rst-BdtOZUlL.js +1 -0
- package/dist/web/assets/ruby-DTna6e9n.js +1 -0
- package/dist/web/assets/run-in-terminal-SU9cwoZ4.js +1 -0
- package/dist/web/assets/sas-X50YKLBX.js +1 -0
- package/dist/web/assets/schedules-settings-section-Dy6hARk0.js +1 -0
- package/dist/web/assets/scroll-area-xAtds1T-.js +1 -0
- package/dist/web/assets/scss-cQk9zuqD.js +1 -0
- package/dist/web/assets/send-to-chat-TSKk3fI9.js +1 -0
- package/dist/web/assets/separator-D8SNZI6E.js +1 -0
- package/dist/web/assets/settings-body-CZSwxG0i.js +2 -0
- package/dist/web/assets/settings-store-DXmQug0m.js +2 -0
- package/dist/web/assets/settings-tab-B_WPC-y7.js +1 -0
- package/dist/web/assets/settings-window-content-CSWdwQn1.js +1 -0
- package/dist/web/assets/shaderlab-CSeOcwk6.js +1 -0
- package/dist/web/assets/shellscript-Dtzjnpp9.js +1 -0
- package/dist/web/assets/shellsession-AqADqsjv.js +1 -0
- package/dist/web/assets/soy-DeMex-y3.js +1 -0
- package/dist/web/assets/sparql-CDZTYDwx.js +1 -0
- package/dist/web/assets/sql-BS_vTOM8.js +1 -0
- package/dist/web/assets/sql-query-editor-6Ee_Zn5j.js +1 -0
- package/dist/web/assets/sqlite-viewer-Cj0S_m9V.js +1 -0
- package/dist/web/assets/stata-PkjbLwNy.js +1 -0
- package/dist/web/assets/surrealql-BJ6bKPXV.js +1 -0
- package/dist/web/assets/svelte-D4u1sGpe.js +1 -0
- package/dist/web/assets/system-monitor-body-PQqXdK4a.js +2 -0
- package/dist/web/assets/system-monitor-tab-BEjvgQuQ.js +1 -0
- package/dist/web/assets/system-monitor-window-content-DZwvvN-M.js +1 -0
- package/dist/web/assets/tab-host-window-content-CnV4Z4Yt.js +1 -0
- package/dist/web/assets/tab-store-DqeaGhhE.js +1 -0
- package/dist/web/assets/team-member-sheet-8EVCTM-X.js +2 -0
- package/dist/web/assets/team-member-window-content-Bc0ydBAn.js +1 -0
- package/dist/web/assets/templ-vtFoIgGG.js +1 -0
- package/dist/web/assets/terminal-tab-0b63-txz.js +3 -0
- package/dist/web/assets/tex-o6JLe3Qo.js +1 -0
- package/dist/web/assets/tool-cards-C09WknHl.js +9 -0
- package/dist/web/assets/treemap-KZPCXAKY-CfpX4ULx.js +1 -0
- package/dist/web/assets/ts-tags-DkmPnhIx.js +1 -0
- package/dist/web/assets/tsx-BUq9xm2T.js +1 -0
- package/dist/web/assets/twig-I9ja_Rk_.js +1 -0
- package/dist/web/assets/typescript-CP3RLBKz.js +1 -0
- package/dist/web/assets/use-blob-url-mZfScQdx.js +1 -0
- package/dist/web/assets/use-inline-blame-BuAc9IXE.js +16 -0
- package/dist/web/assets/use-is-mobile-CkO33jqU.js +1 -0
- package/dist/web/assets/use-lsp-DAtq1G0M.js +6 -0
- package/dist/web/assets/use-monaco-theme-Ch_znquJ.js +1 -0
- package/dist/web/assets/use-open-team-member-DHzZiJZw.js +1 -0
- package/dist/web/assets/use-visual-viewport-C307OVeV.js +1 -0
- package/dist/web/assets/use-websocket-DGEOad8p.js +1 -0
- package/dist/web/assets/vendor-markdown-QKPNiWEd.js +291 -0
- package/dist/web/assets/vendor-mermaid-eg2XWIjK.js +2921 -0
- package/dist/web/assets/vendor-ui-BHh12_0v.js +45 -0
- package/dist/web/assets/video-preview-DH3RtwVT.js +1 -0
- package/dist/web/assets/vue-DJf-APPD.js +1 -0
- package/dist/web/assets/vue-html-DUJ89Ycn.js +1 -0
- package/dist/web/assets/vue-vine-CWUFwuRE.js +1 -0
- package/dist/web/assets/window-pip-registry-DH07f_8k.js +1 -0
- package/dist/web/assets/window-store-B4cbZ5rr.js +1 -0
- package/dist/web/assets/ws-auth-B_y5rMfZ.js +1 -0
- package/dist/web/assets/xml-DshhaDKq.js +1 -0
- package/dist/web/assets/xsl-BlRNlmF7.js +1 -0
- package/dist/web/assets/yaml-seUOGdyI.js +1 -0
- package/dist/web/index.html +37 -36
- package/dist/web/sw.js +1 -1
- package/docs/architecture/workspace-and-ui.md +47 -0
- package/docs/project-roadmap.md +16 -0
- package/docs/system-architecture.md +11 -1
- package/package.json +4 -1
- package/scripts/gen-product-icons.ts +10 -0
- package/src/providers/claude-agent-sdk-query-options.ts +68 -1
- package/src/providers/claude-agent-sdk.ts +44 -15
- package/src/providers/codex-app-server/codex-event-mapper.ts +18 -1
- package/src/providers/codex-app-server/codex-jsonrpc-client.ts +4 -3
- package/src/providers/codex-app-server/codex-permission-map.ts +11 -1
- package/src/providers/codex-app-server/codex-protocol.ts +5 -0
- package/src/providers/codex-app-server/codex-provider.ts +32 -15
- package/src/providers/codex-app-server/codex-thread-params.ts +96 -0
- package/src/server/helpers/preview-asset-guard.ts +36 -0
- package/src/server/index.ts +15 -0
- package/src/server/routes/chat.ts +41 -4
- package/src/server/routes/design-check.ts +48 -0
- package/src/server/routes/design-comments.ts +63 -0
- package/src/server/routes/design-export.ts +84 -0
- package/src/server/routes/design-preview.ts +159 -0
- package/src/server/routes/design-route-helpers.ts +25 -0
- package/src/server/routes/design-style.ts +28 -0
- package/src/server/routes/design-tweaks.ts +38 -0
- package/src/server/routes/design-undo.ts +27 -0
- package/src/server/routes/designs.ts +101 -0
- package/src/server/routes/html-preview.ts +4 -24
- package/src/server/routes/project-scoped.ts +2 -0
- package/src/server/ws/chat.ts +8 -1
- package/src/server/ws/global.ts +22 -1
- package/src/services/chat.service.ts +64 -1
- package/src/services/db.service.ts +73 -4
- package/src/services/design/bridge/bridge-anchor-resolve.ts +96 -0
- package/src/services/design/bridge/bridge-core.ts +205 -0
- package/src/services/design/bridge/bridge-element-info.ts +180 -0
- package/src/services/design/bridge/bridge-extract-blocks.ts +115 -0
- package/src/services/design/bridge/bridge-extract-images.ts +96 -0
- package/src/services/design/bridge/bridge-extract-slides.ts +169 -0
- package/src/services/design/bridge/bridge-extract-text.ts +187 -0
- package/src/services/design/bridge/bridge-layout-boxes.ts +137 -0
- package/src/services/design/bridge/bridge-layout-check.ts +99 -0
- package/src/services/design/bridge/bridge-layout-grid.ts +165 -0
- package/src/services/design/bridge/bridge-layout-screenshot.ts +106 -0
- package/src/services/design/bridge/bridge-nav-guard.ts +61 -0
- package/src/services/design/bridge/bridge-picker-overlay.ts +54 -0
- package/src/services/design/bridge/bridge-picker.ts +174 -0
- package/src/services/design/bridge/bridge-pins.ts +157 -0
- package/src/services/design/bridge/bridge-script.ts +104 -0
- package/src/services/design/bridge/bridge-transform-math.ts +104 -0
- package/src/services/design/bridge/bridge-transform-overlay.ts +94 -0
- package/src/services/design/bridge/bridge-transform-style.ts +78 -0
- package/src/services/design/bridge/bridge-transform.ts +201 -0
- package/src/services/design/bridge/bridge-tweaks.ts +118 -0
- package/src/services/design/check/design-canvas-check-broker.ts +77 -0
- package/src/services/design/comments/design-comment-element-context.ts +81 -0
- package/src/services/design/comments/design-comments-store.ts +81 -0
- package/src/services/design/design-comments.service.ts +140 -0
- package/src/services/design/design-edit-undo-journal.ts +125 -0
- package/src/services/design/design-error.ts +19 -0
- package/src/services/design/design-events.ts +46 -0
- package/src/services/design/design-fs.ts +67 -0
- package/src/services/design/design-instructions.ts +97 -0
- package/src/services/design/design-lock.ts +74 -0
- package/src/services/design/design-manifest.ts +92 -0
- package/src/services/design/design-paths.ts +97 -0
- package/src/services/design/design-restore-journal.ts +143 -0
- package/src/services/design/design-restore.service.ts +77 -0
- package/src/services/design/design-safe-walk.ts +114 -0
- package/src/services/design/design-slug.ts +35 -0
- package/src/services/design/design-snapshot-history.ts +159 -0
- package/src/services/design/design-snapshots.service.ts +161 -0
- package/src/services/design/design-starter-template.ts +100 -0
- package/src/services/design/design-store.service.ts +156 -0
- package/src/services/design/design-style-patch.service.ts +83 -0
- package/src/services/design/design-tool-policy.ts +111 -0
- package/src/services/design/design-turn-snapshot.ts +80 -0
- package/src/services/design/design-tweaks-commit.service.ts +138 -0
- package/src/services/design/design-write-rate-limit.ts +51 -0
- package/src/services/design/export/css-url-inline.ts +130 -0
- package/src/services/design/export/design-export-asset-reader.ts +57 -0
- package/src/services/design/export/design-export-entry.ts +33 -0
- package/src/services/design/export/design-standalone-html.ts +167 -0
- package/src/services/design/export/design-zip-export.ts +106 -0
- package/src/services/design/mcp/design-mcp-access.ts +16 -0
- package/src/services/design/mcp/design-mcp-endpoint.ts +118 -0
- package/src/services/design/mcp/design-mcp-tokens.ts +82 -0
- package/src/services/design/mcp/design-mcp-tool.ts +41 -0
- package/src/services/design/preview/design-csp.ts +31 -0
- package/src/services/design/preview/design-preview-html.ts +98 -0
- package/src/services/design/preview/design-preview-scope.ts +66 -0
- package/src/services/design/preview/design-preview-tokens.ts +137 -0
- package/src/services/design/preview/expired-page.ts +30 -0
- package/src/services/design/preview/html-instrument.ts +119 -0
- package/src/services/design/preview/print-view.ts +62 -0
- package/src/services/design/source/css-root-selector.ts +20 -0
- package/src/services/design/source/css-root-vars-patch.ts +202 -0
- package/src/services/design/source/design-source-file.ts +62 -0
- package/src/services/design/source/design-style-sources.ts +101 -0
- package/src/services/design/source/element-source-range.ts +65 -0
- package/src/services/design/source/html-style-blocks.ts +87 -0
- package/src/services/design/source/inline-style-declarations.ts +131 -0
- package/src/services/design/source/inline-style-patch.ts +79 -0
- package/src/services/design/source/tweak-patch-plan.ts +143 -0
- package/src/services/file-watcher/ignore-rules.ts +9 -1
- package/src/services/server-listen-address.ts +25 -0
- package/src/shared/design-bridge-messages-check.ts +44 -0
- package/src/shared/design-bridge-messages-picker.ts +142 -0
- package/src/shared/design-bridge-messages-slides.ts +37 -0
- package/src/shared/design-bridge-messages-transform.ts +121 -0
- package/src/shared/design-bridge-messages-tweaks.ts +65 -0
- package/src/shared/design-bridge-protocol.ts +158 -0
- package/src/shared/design-canvas-check-format.ts +69 -0
- package/src/shared/design-canvas-check.ts +148 -0
- package/src/shared/design-cdn-hosts.ts +17 -0
- package/src/shared/design-comment-types.ts +111 -0
- package/src/shared/design-slide-doc-parse.ts +140 -0
- package/src/shared/design-slide-doc.ts +91 -0
- package/src/shared/design-system-init-prompt.ts +35 -0
- package/src/shared/design-tweaks.ts +175 -0
- package/src/shared/design-types.ts +63 -0
- package/src/shared/untrusted-text.ts +15 -0
- package/src/types/chat.ts +22 -0
- package/src/types/config.ts +1 -1
- package/src/web/components/chat/chat-history-bar.tsx +18 -15
- package/src/web/components/chat/chat-history-panel.tsx +3 -9
- package/src/web/components/chat/chat-tab.tsx +74 -40
- package/src/web/components/chat/message-input.tsx +11 -4
- package/src/web/components/chat/session-history-list.tsx +5 -9
- package/src/web/components/design/canvas/canvas-geometry.ts +47 -0
- package/src/web/components/design/canvas/design-canvas-pane.tsx +192 -0
- package/src/web/components/design/canvas/design-issues-badge.tsx +71 -0
- package/src/web/components/design/canvas/device-frame-presets.ts +37 -0
- package/src/web/components/design/canvas/use-design-bridge.ts +169 -0
- package/src/web/components/design/canvas/use-design-canvas-check.ts +110 -0
- package/src/web/components/design/canvas/use-design-canvas.ts +107 -0
- package/src/web/components/design/canvas/use-design-live-reload.ts +86 -0
- package/src/web/components/design/canvas/use-design-preview-url.ts +74 -0
- package/src/web/components/design/canvas/use-expanded-canvas-escape.ts +29 -0
- package/src/web/components/design/comments/comment-composer.tsx +107 -0
- package/src/web/components/design/comments/comment-overlay-geometry.ts +50 -0
- package/src/web/components/design/comments/comment-pins-overlay.tsx +70 -0
- package/src/web/components/design/comments/comments-panel.tsx +118 -0
- package/src/web/components/design/comments/comments-send-preview.tsx +43 -0
- package/src/web/components/design/comments/design-comments-layer.tsx +73 -0
- package/src/web/components/design/comments/element-action-bar.tsx +105 -0
- package/src/web/components/design/comments/use-comment-pins.ts +118 -0
- package/src/web/components/design/comments/use-design-comments-feature.ts +124 -0
- package/src/web/components/design/comments/use-design-comments.ts +89 -0
- package/src/web/components/design/comments/use-element-picker.ts +87 -0
- package/src/web/components/design/design-chat-pane.tsx +51 -0
- package/src/web/components/design/design-layout-controls.tsx +84 -0
- package/src/web/components/design/design-mobile-layout.tsx +34 -0
- package/src/web/components/design/design-split-layout.tsx +99 -0
- package/src/web/components/design/design-tab-context.ts +44 -0
- package/src/web/components/design/design-tab.tsx +116 -0
- package/src/web/components/design/design-toolbar-list.tsx +36 -0
- package/src/web/components/design/design-toolbar.tsx +200 -0
- package/src/web/components/design/designs-sidebar-panel.tsx +117 -0
- package/src/web/components/design/dialogs/delete-design-dialog.tsx +69 -0
- package/src/web/components/design/dialogs/design-responsive-dialog.tsx +48 -0
- package/src/web/components/design/dialogs/new-design-dialog.tsx +113 -0
- package/src/web/components/design/dialogs/rename-design-dialog.tsx +56 -0
- package/src/web/components/design/export/export-menu.tsx +108 -0
- package/src/web/components/design/export/export-warnings-sheet.tsx +35 -0
- package/src/web/components/design/export/pptx-export.ts +38 -0
- package/src/web/components/design/export/use-design-export.ts +142 -0
- package/src/web/components/design/history/design-history-panel.tsx +119 -0
- package/src/web/components/design/transform/design-undo-stack.ts +90 -0
- package/src/web/components/design/transform/transform-readout.tsx +50 -0
- package/src/web/components/design/transform/use-canvas-transform.ts +181 -0
- package/src/web/components/design/tweaks/tweak-control.tsx +94 -0
- package/src/web/components/design/tweaks/tweaks-panel.tsx +99 -0
- package/src/web/components/design/tweaks/use-design-tweaks.ts +151 -0
- package/src/web/components/design/use-design-auto-check.ts +94 -0
- package/src/web/components/design/use-design-layout.ts +55 -0
- package/src/web/components/design/use-design-summary.ts +63 -0
- package/src/web/components/layout/command-palette-design-commands.tsx +75 -0
- package/src/web/components/layout/command-palette.tsx +12 -4
- package/src/web/components/layout/editor-panel.tsx +4 -10
- package/src/web/components/layout/mobile-drawer.tsx +9 -2
- package/src/web/components/layout/mobile-nav.tsx +3 -2
- package/src/web/components/layout/mobile-tab-switcher-sheet.tsx +4 -5
- package/src/web/components/layout/sidebar.tsx +8 -1
- package/src/web/components/layout/tab-bar.tsx +3 -2
- package/src/web/components/layout/tab-content.tsx +5 -0
- package/src/web/components/layout/tab-pool.tsx +1 -0
- package/src/web/components/onboarding/onboarding-quick-orientation.tsx +1 -0
- package/src/web/hooks/use-chat.ts +8 -4
- package/src/web/hooks/use-design-session-redirect.ts +39 -0
- package/src/web/hooks/use-design-session-state.ts +94 -0
- package/src/web/hooks/use-global-events.ts +4 -1
- package/src/web/hooks/use-session-history.ts +4 -10
- package/src/web/hooks/use-url-sync.ts +10 -2
- package/src/web/lib/design/api-design-comments.ts +42 -0
- package/src/web/lib/design/api-design-edits.ts +62 -0
- package/src/web/lib/design/api-design-tweaks.ts +64 -0
- package/src/web/lib/design/api-designs.ts +81 -0
- package/src/web/lib/design/deliver-to-design-chat.ts +63 -0
- package/src/web/lib/design/design-auto-check-rounds.ts +32 -0
- package/src/web/lib/design/design-change-filter.ts +27 -0
- package/src/web/lib/design/design-comments-prompt.ts +55 -0
- package/src/web/lib/design/design-export-client.ts +101 -0
- package/src/web/lib/design/design-handoff-prompt.ts +48 -0
- package/src/web/lib/design/design-layout-mode.ts +79 -0
- package/src/web/lib/design/design-tab-metadata.ts +41 -0
- package/src/web/lib/design/design-transform-proposal.ts +62 -0
- package/src/web/lib/design/design-tweaks-model.ts +76 -0
- package/src/web/lib/design/design-ui-events.ts +25 -0
- package/src/web/lib/design/design-view-prefs.ts +90 -0
- package/src/web/lib/design/open-design-tab.ts +78 -0
- package/src/web/lib/design/pptx-slide-mapper.ts +118 -0
- package/src/web/lib/feature-badges.ts +2 -0
- package/src/web/lib/fluent-icon.tsx +38 -2
- package/src/web/lib/icons.generated.tsx +17 -1
- package/src/web/lib/patch-tab-metadata.ts +30 -0
- package/src/web/lib/send-to-chat.ts +16 -2
- package/src/web/lib/sidebar-tabs/tab-registry.ts +2 -0
- package/src/web/lib/tab-session-id.ts +16 -0
- package/src/web/lib/tab-type-icons.ts +2 -1
- package/src/web/stores/panel-store.ts +29 -1
- package/src/web/stores/panel-utils.ts +8 -1
- package/src/web/stores/settings-store.ts +2 -2
- package/src/web/stores/tab-store.ts +2 -1
- package/src/web/stores/window-panel-persistence.ts +1 -0
- package/dist/web/assets/accounts-settings-section-BDXYG6tT.js +0 -1
- package/dist/web/assets/ai-resource-editor-C3rKcZKN.js +0 -1
- package/dist/web/assets/ai-settings-section-ArqD8Nlg.js +0 -1
- package/dist/web/assets/ai-settings-section-DeWoAdLc.js +0 -1
- package/dist/web/assets/angular-html-DnrsWZqK.js +0 -1
- package/dist/web/assets/angular-ts-BXEqA9t1.js +0 -1
- package/dist/web/assets/api-client-Jn3njtNw.js +0 -1
- package/dist/web/assets/api-client-rSFnnCj4.js +0 -1
- package/dist/web/assets/api-settings-BZFSteM_.js +0 -1
- package/dist/web/assets/api-themes-CvKtX6Hd.js +0 -1
- package/dist/web/assets/apl-DUQ6Oyth.js +0 -1
- package/dist/web/assets/appearance-settings-section-K5o_Di4V.js +0 -1
- package/dist/web/assets/architecture-PBZL5I3N-B9M_VqZI.js +0 -1
- package/dist/web/assets/astro-CakOjJ6X.js +0 -1
- package/dist/web/assets/audio-preview-CwCDCN-_.js +0 -1
- package/dist/web/assets/blade-C903KM82.js +0 -1
- package/dist/web/assets/branch-review-tab-BNpYiUhC.js +0 -1
- package/dist/web/assets/bsl-slfcE_kB.js +0 -1
- package/dist/web/assets/button-B9CTrsEf.js +0 -1
- package/dist/web/assets/c-BWO-aeyf.js +0 -1
- package/dist/web/assets/cairo-DRwEaH6w.js +0 -1
- package/dist/web/assets/chat-tab-CC8KANoK.js +0 -15
- package/dist/web/assets/cobol--n4m6b70.js +0 -1
- package/dist/web/assets/code-editor-Ccf0Egrc.js +0 -7
- package/dist/web/assets/codex-daily-guard-CKk2WFlV.js +0 -1
- package/dist/web/assets/coffee-CjyFmw8_.js +0 -1
- package/dist/web/assets/conflict-editor-BCKbdpXy.js +0 -19
- package/dist/web/assets/context-menu-C6pIsf83.js +0 -1
- package/dist/web/assets/cpp-D18jdQPZ.js +0 -1
- package/dist/web/assets/createLucideIcon-DoiEKeJ_.js +0 -1
- package/dist/web/assets/crystal-CySzfH-7.js +0 -1
- package/dist/web/assets/css-Ca_hTmU6.js +0 -1
- package/dist/web/assets/csv-preview-I3a2lGUx.js +0 -2
- package/dist/web/assets/data-grid-overlay-editor-BD9eJweQ.js +0 -1
- package/dist/web/assets/data-grid-types-C6UX8kgh.js +0 -1
- package/dist/web/assets/database-viewer-DCuBR-bZ.js +0 -1
- package/dist/web/assets/dialog-B84_DJQ8.js +0 -1
- package/dist/web/assets/diff-viewer-DGaBe_Ln.js +0 -4
- package/dist/web/assets/dist-BD2gbdy0.js +0 -1
- package/dist/web/assets/docx-preview-CeH6p2Oi.js +0 -12
- package/dist/web/assets/edge-B6b5FHmU.js +0 -1
- package/dist/web/assets/edit-diff-preview-BG5DsLJG.js +0 -7
- package/dist/web/assets/editor-language-service-BaocEaLc.js +0 -1
- package/dist/web/assets/elixir-Dpo1rvn2.js +0 -1
- package/dist/web/assets/elm-D9CNOsWT.js +0 -1
- package/dist/web/assets/erb-sY7Yee1W.js +0 -1
- package/dist/web/assets/erlang-CfyrBxyF.js +0 -1
- package/dist/web/assets/esm-5AhGJcV8.js +0 -2
- package/dist/web/assets/explorer-body-2GYIYmUh.js +0 -2
- package/dist/web/assets/explorer-window-content-CYQSEX-g.js +0 -1
- package/dist/web/assets/extension-manager-section-BFAGdy3G.js +0 -1
- package/dist/web/assets/extension-webview-D5TXIBMf.js +0 -12
- package/dist/web/assets/file-icons-wS-OmEVu.js +0 -1
- package/dist/web/assets/file-store-Ds3qJ4hC.js +0 -1
- package/dist/web/assets/files-settings-section-BE6o-oHu.js +0 -1
- package/dist/web/assets/format-file-meta-eKLstbCL.js +0 -1
- package/dist/web/assets/fortran-fixed-form-N67gM_wp.js +0 -1
- package/dist/web/assets/fs-api-orca76dV.js +0 -1
- package/dist/web/assets/fsharp-Dq0K01wX.js +0 -1
- package/dist/web/assets/gdresource-DkFbszqY.js +0 -1
- package/dist/web/assets/general-settings-section-mQiXM537.js +0 -1
- package/dist/web/assets/git-commit-Ddt_nerD.js +0 -1
- package/dist/web/assets/git-log-panel-DqbcM9eC.js +0 -1
- package/dist/web/assets/git-rebase-CVK5OA7i.js +0 -1
- package/dist/web/assets/git-repo-store-BCEPfUGT.js +0 -1
- package/dist/web/assets/gitGraph-HDMCJU4V-D3RB33aA.js +0 -1
- package/dist/web/assets/glide-data-grid-BjEF7M5i.js +0 -141
- package/dist/web/assets/glimmer-js-51jbYnyY.js +0 -1
- package/dist/web/assets/glimmer-ts-C5L1J32J.js +0 -1
- package/dist/web/assets/glsl-BcsfmwJZ.js +0 -1
- package/dist/web/assets/graphql-dv4wuJsK.js +0 -1
- package/dist/web/assets/group-chat-tab-aX2GEnkD.js +0 -1
- package/dist/web/assets/hack-DLE5d3bx.js +0 -1
- package/dist/web/assets/haml-CoKfcM3E.js +0 -1
- package/dist/web/assets/handlebars-Bn0jy8pD.js +0 -1
- package/dist/web/assets/html-DXzY5Cew.js +0 -1
- package/dist/web/assets/html-derivative-DhcVfYuw.js +0 -1
- package/dist/web/assets/http-DepeIWQ1.js +0 -1
- package/dist/web/assets/hurl-CfsP4sCj.js +0 -1
- package/dist/web/assets/hxml-IfVkY3HL.js +0 -1
- package/dist/web/assets/icons-DQjqk0lJ.js +0 -1
- package/dist/web/assets/image-preview-CWncz5iI.js +0 -1
- package/dist/web/assets/index-BoaecXhu.js +0 -52
- package/dist/web/assets/index-aXJy_SvC.css +0 -1
- package/dist/web/assets/info-3K5VOQVL-DDX-2VB7.js +0 -1
- package/dist/web/assets/input-QNG_gTHh.js +0 -1
- package/dist/web/assets/java-JWdrzVo8.js +0 -1
- package/dist/web/assets/javascript-5aQKJRxB.js +0 -1
- package/dist/web/assets/jinja-DcCmNDQ8.js +0 -1
- package/dist/web/assets/jira-watcher-section-BKn3A8zI.js +0 -1
- package/dist/web/assets/jison-Bt-5cKVZ.js +0 -1
- package/dist/web/assets/json-BOq7QblK.js +0 -1
- package/dist/web/assets/jsx-BSLWViGE.js +0 -1
- package/dist/web/assets/julia-DewYVRtE.js +0 -1
- package/dist/web/assets/just-CLT_ggBy.js +0 -1
- package/dist/web/assets/keybindings-store-Brz0qepi.js +0 -1
- package/dist/web/assets/keyboard-shortcuts-section-Ck8KIbJ8.js +0 -1
- package/dist/web/assets/latex-DXmcayW1.js +0 -1
- package/dist/web/assets/lib-BWyA9SvU.js +0 -4
- package/dist/web/assets/liquid-BVcHf0IA.js +0 -1
- package/dist/web/assets/lua-BYupsB1B.js +0 -1
- package/dist/web/assets/markdown-renderer-BGuM2PBI.js +0 -5
- package/dist/web/assets/markdown-renderer-Ddz8tPbb.js +0 -1
- package/dist/web/assets/marko-CsD0R5tv.js +0 -1
- package/dist/web/assets/mdc-DP2tC4Kc.js +0 -1
- package/dist/web/assets/media-url-CVO4m4zr.js +0 -1
- package/dist/web/assets/mobile-bottom-sheet-C3TniEP-.js +0 -1
- package/dist/web/assets/mobile-explorer-sheet-DpKfB6iF.js +0 -1
- package/dist/web/assets/monaco-dotenv-language-DD8_UQG7.js +0 -1
- package/dist/web/assets/nextflow-FQM6iZO2.js +0 -1
- package/dist/web/assets/nginx-Bg0TK_a9.js +0 -1
- package/dist/web/assets/nim-D1kSCHdq.js +0 -1
- package/dist/web/assets/notification-store-ByCdTvCC.js +0 -1
- package/dist/web/assets/notifications-settings-section-C5v8FoH9.js +0 -1
- package/dist/web/assets/number-overlay-editor-Bsr04yCI.js +0 -9
- package/dist/web/assets/onboarding-entry-C81awoR5.js +0 -1
- package/dist/web/assets/onboarding-quick-orientation-Dqmis-E5.js +0 -1
- package/dist/web/assets/overview-panel-9OdBcYJC.js +0 -1
- package/dist/web/assets/packet-RMMSAZCW-B0ZSm6VM.js +0 -1
- package/dist/web/assets/panel-store-D20Zuf3i.js +0 -1
- package/dist/web/assets/pdf-preview-DuR07OfN.js +0 -1
- package/dist/web/assets/perl-B6QNc69s.js +0 -1
- package/dist/web/assets/php-Bvwf1t96.js +0 -1
- package/dist/web/assets/pie-UPGHQEXC-DKM0oPn7.js +0 -1
- package/dist/web/assets/portal-container-context-BarKmT4S.js +0 -1
- package/dist/web/assets/postgres-viewer-CGf7_g6Z.js +0 -3
- package/dist/web/assets/ppmbot-settings-section-DeTFU1b-.js +0 -1
- package/dist/web/assets/problems-panel-Bgkcge5_.js +0 -1
- package/dist/web/assets/process-table-DH7pnH5I.js +0 -1
- package/dist/web/assets/project-framework-store-ViZgce6y.js +0 -1
- package/dist/web/assets/project-store-hNvwfqX3.js +0 -1
- package/dist/web/assets/proxy-settings-section-DMGMRHH-.js +0 -1
- package/dist/web/assets/pug-I8oitXP4.js +0 -1
- package/dist/web/assets/qml-LKb7CHg-.js +0 -1
- package/dist/web/assets/query-audit-section-CpiXQVcS.js +0 -1
- package/dist/web/assets/r-DHu15BOo.js +0 -1
- package/dist/web/assets/radar-KQ55EAFF-DKhtzXmy.js +0 -1
- package/dist/web/assets/razor-CIPT897U.js +0 -1
- package/dist/web/assets/react-Bghu0NUO.js +0 -1
- package/dist/web/assets/regexp-Vdt2OEkk.js +0 -1
- package/dist/web/assets/remote-desktop-clipboard-notice-Bj5FtU0O.js +0 -1
- package/dist/web/assets/remote-desktop-mobile-sheet-BhwVrKxv.js +0 -2
- package/dist/web/assets/remote-desktop-mobile-view-B1oAqbjG.js +0 -1
- package/dist/web/assets/remote-desktop-readiness-gate-2LE86aTu.js +0 -1
- package/dist/web/assets/remote-desktop-window-content-u8HwuzyN.js +0 -1
- package/dist/web/assets/rolldown-runtime-FhOqtrmT.js +0 -1
- package/dist/web/assets/rst-BpcmfJFA.js +0 -1
- package/dist/web/assets/ruby-Cx413jgE.js +0 -1
- package/dist/web/assets/run-in-terminal-BFR70TLU.js +0 -1
- package/dist/web/assets/sas-B3ui_NHy.js +0 -1
- package/dist/web/assets/schedules-settings-section-C8XNDdi9.js +0 -1
- package/dist/web/assets/scroll-area-C0fQWNnx.js +0 -1
- package/dist/web/assets/scss-V4NlXnGi.js +0 -1
- package/dist/web/assets/send-to-chat-C8l7AcV4.js +0 -1
- package/dist/web/assets/separator-DwDoQpxS.js +0 -1
- package/dist/web/assets/settings-body-DelxmiKf.js +0 -2
- package/dist/web/assets/settings-store-m6qOXoy4.js +0 -2
- package/dist/web/assets/settings-tab-Cb_dFdA6.js +0 -1
- package/dist/web/assets/settings-window-content-5EQQfC1t.js +0 -1
- package/dist/web/assets/shaderlab-Cf7qZ4DR.js +0 -1
- package/dist/web/assets/shellscript-DRxJLgrx.js +0 -1
- package/dist/web/assets/shellsession-BfA8Fmhb.js +0 -1
- package/dist/web/assets/soy-CGKN9rxg.js +0 -1
- package/dist/web/assets/sparql-CArCsIdI.js +0 -1
- package/dist/web/assets/sql-ljEiM8nf.js +0 -1
- package/dist/web/assets/sql-query-editor-B3wrPR6K.js +0 -1
- package/dist/web/assets/sqlite-viewer-iQXNp0kH.js +0 -1
- package/dist/web/assets/stata-CplvndbA.js +0 -1
- package/dist/web/assets/surrealql-DwX1PCpP.js +0 -1
- package/dist/web/assets/svelte-DYCNmQjy.js +0 -1
- package/dist/web/assets/system-monitor-body-5grJyA7C.js +0 -2
- package/dist/web/assets/system-monitor-tab-CJr797F8.js +0 -1
- package/dist/web/assets/system-monitor-window-content-OGAhFXXo.js +0 -1
- package/dist/web/assets/tab-host-window-content-C-eEo8I7.js +0 -1
- package/dist/web/assets/tab-store-krAuHQ6_.js +0 -1
- package/dist/web/assets/team-member-sheet-CRvJUtdh.js +0 -2
- package/dist/web/assets/team-member-window-content-C97N4RXb.js +0 -1
- package/dist/web/assets/templ-b_h2-Z9l.js +0 -1
- package/dist/web/assets/terminal-tab-eZwpkvEe.js +0 -3
- package/dist/web/assets/tex-022M3-MR.js +0 -1
- package/dist/web/assets/tool-cards-Bg4vjDYu.js +0 -9
- package/dist/web/assets/treemap-KZPCXAKY-CxqsD_6n.js +0 -1
- package/dist/web/assets/ts-tags-BUl0AdO6.js +0 -1
- package/dist/web/assets/tsx-CKaH7SzK.js +0 -1
- package/dist/web/assets/twig-CMzYUcSa.js +0 -1
- package/dist/web/assets/typescript-DZozDFsi.js +0 -1
- package/dist/web/assets/use-blob-url-C0VR6Uhh.js +0 -1
- package/dist/web/assets/use-inline-blame-CzR8CnOZ.js +0 -16
- package/dist/web/assets/use-is-mobile-TkcwP1Gx.js +0 -1
- package/dist/web/assets/use-lsp-BAoOSc-L.js +0 -6
- package/dist/web/assets/use-monaco-theme-Gd8cpt9n.js +0 -1
- package/dist/web/assets/use-open-team-member-y9sVhaNr.js +0 -1
- package/dist/web/assets/use-visual-viewport-Lp878uzs.js +0 -1
- package/dist/web/assets/use-websocket-CDfXkXo3.js +0 -1
- package/dist/web/assets/vendor-markdown-CuWCHIVb.js +0 -291
- package/dist/web/assets/vendor-mermaid-D6lgjvVE.js +0 -2921
- package/dist/web/assets/vendor-ui-DmZ-Mb-H.js +0 -45
- package/dist/web/assets/video-preview-BYJ3aVo1.js +0 -1
- package/dist/web/assets/vue-D83SsURi.js +0 -1
- package/dist/web/assets/vue-html-BGU-OYYb.js +0 -1
- package/dist/web/assets/vue-vine-1sHE1gZn.js +0 -1
- package/dist/web/assets/window-pip-registry-D1oXq-Dq.js +0 -1
- package/dist/web/assets/window-store-UC1jJeLM.js +0 -1
- package/dist/web/assets/ws-auth-CaxV807E.js +0 -1
- package/dist/web/assets/xml-bWQJszMK.js +0 -1
- package/dist/web/assets/xsl-DTMc1Tsm.js +0 -1
- package/dist/web/assets/yaml-4pzZq5KT.js +0 -1
- /package/dist/web/assets/{abap-DrxZXLHj.js → abap-DWbETETF.js} +0 -0
- /package/dist/web/assets/{actionscript-3-DOPR4pRC.js → actionscript-3-C278tgAF.js} +0 -0
- /package/dist/web/assets/{ada-DkqjEnDr.js → ada-C_5J29IC.js} +0 -0
- /package/dist/web/assets/{andromeeda-BSZjevw2.js → andromeeda-Ct0fb9Zo.js} +0 -0
- /package/dist/web/assets/{apache-DYwdQ5F_.js → apache-oMwCqc2o.js} +0 -0
- /package/dist/web/assets/{apex-Dohu7DfB.js → apex-n6XQQudq.js} +0 -0
- /package/dist/web/assets/{applescript-CdfGIVqp.js → applescript-QDMA6blY.js} +0 -0
- /package/dist/web/assets/{apply-theme-CbR31K6I.js → apply-theme-aVoqSG0I.js} +0 -0
- /package/dist/web/assets/{ara-i3_3TMnI.js → ara-D6rg_rTp.js} +0 -0
- /package/dist/web/assets/{asciidoc-DJFM-7vl.js → asciidoc-DVeBWv0S.js} +0 -0
- /package/dist/web/assets/{asm-bMFssizQ.js → asm-DzHQzzqu.js} +0 -0
- /package/dist/web/assets/{aurora-x-CetC7M8b.js → aurora-x-pJESoXa6.js} +0 -0
- /package/dist/web/assets/{awk-FFWx9ZrE.js → awk-BwfK4mzn.js} +0 -0
- /package/dist/web/assets/{ayu-dark-D4ION2wO.js → ayu-dark-CG-9c7ej.js} +0 -0
- /package/dist/web/assets/{ayu-light-BZN99P5A.js → ayu-light-BGUfMG6m.js} +0 -0
- /package/dist/web/assets/{ayu-mirage-B-IpsKiL.js → ayu-mirage-CMD89qy6.js} +0 -0
- /package/dist/web/assets/{ballerina-DhyJcKkq.js → ballerina-CP5gYaiB.js} +0 -0
- /package/dist/web/assets/{bat-GOVQY81F.js → bat-DCRdiK45.js} +0 -0
- /package/dist/web/assets/{beancount-BO749Rhc.js → beancount-DHkDiOKO.js} +0 -0
- /package/dist/web/assets/{berry-CHYYKXmK.js → berry-B6TPldKS.js} +0 -0
- /package/dist/web/assets/{bibtex-BnYiDnxT.js → bibtex-DIor8yh9.js} +0 -0
- /package/dist/web/assets/{bicep-kljgR_G3.js → bicep-BbIdLZZ_.js} +0 -0
- /package/dist/web/assets/{bird2-DnLtJGhV.js → bird2-C76TmOG1.js} +0 -0
- /package/dist/web/assets/{c3-fc_jio6D.js → c3-CqZ77xXr.js} +0 -0
- /package/dist/web/assets/{cadence-DopRCrdB.js → cadence-BlaAb6F6.js} +0 -0
- /package/dist/web/assets/{can-open-in-ppm-CUW3vVJg.js → can-open-in-ppm-D8T6Xca-.js} +0 -0
- /package/dist/web/assets/{catppuccin-frappe-DL6iCUa8.js → catppuccin-frappe-BuV7Zg67.js} +0 -0
- /package/dist/web/assets/{catppuccin-latte-DNF7n3uY.js → catppuccin-latte-B7HXEZf7.js} +0 -0
- /package/dist/web/assets/{catppuccin-macchiato-ByMic_k0.js → catppuccin-macchiato-B0KctcoC.js} +0 -0
- /package/dist/web/assets/{catppuccin-mocha-DcrJtZtv.js → catppuccin-mocha-Bofr5rzo.js} +0 -0
- /package/dist/web/assets/{clarity-0cRLlvQe.js → clarity-CerfZ3dW.js} +0 -0
- /package/dist/web/assets/{clojure-DPqZAcpI.js → clojure-BCEG1uj6.js} +0 -0
- /package/dist/web/assets/{cmake-Bx26bw5u.js → cmake-CRxSSKSr.js} +0 -0
- /package/dist/web/assets/{codeowners-BpgxIgxr.js → codeowners-BqW6DYSk.js} +0 -0
- /package/dist/web/assets/{codeql-TRoWjo5g.js → codeql-DlnOpgWF.js} +0 -0
- /package/dist/web/assets/{common-lisp-Ctohamsb.js → common-lisp-DgIX9jkq.js} +0 -0
- /package/dist/web/assets/{coq-BO6TJSED.js → coq-CFeLOER-.js} +0 -0
- /package/dist/web/assets/{csharp-DSy4nlrl.js → csharp-BGFGcV8G.js} +0 -0
- /package/dist/web/assets/{csv-DND7YJXD.js → csv-Cx126-fo.js} +0 -0
- /package/dist/web/assets/{csv-parser-DZ_75eCb.js → csv-parser-BXeH-yzY.js} +0 -0
- /package/dist/web/assets/{cue-BUnWK221.js → cue-Cd0PEGFL.js} +0 -0
- /package/dist/web/assets/{cypher-CInm9Etl.js → cypher-QS9S-1Nu.js} +0 -0
- /package/dist/web/assets/{d-BbsB8r6R.js → d-Bx6zK6J7.js} +0 -0
- /package/dist/web/assets/{dark-plus-DkzIiuQX.js → dark-plus-DLqXEd2I.js} +0 -0
- /package/dist/web/assets/{dart-BG2nw7Se.js → dart-BL2C2Z6E.js} +0 -0
- /package/dist/web/assets/{dax-j4h6VhlV.js → dax-ClxUDxvY.js} +0 -0
- /package/dist/web/assets/{desktop-Dg34JDlS.js → desktop-DLEkw1UR.js} +0 -0
- /package/dist/web/assets/{diff-CRrKo-mH.js → diff-Dlp9KQSL.js} +0 -0
- /package/dist/web/assets/{dist-D39GQICe.js → dist-CDpxSUMU.js} +0 -0
- /package/dist/web/assets/{docker-DAtcxZjt.js → docker-DVBsQYb-.js} +0 -0
- /package/dist/web/assets/{dotenv-DNUcgQCn.js → dotenv-DjBB7S8B.js} +0 -0
- /package/dist/web/assets/{dracula-bhhaShNC.js → dracula-Cu055q9D.js} +0 -0
- /package/dist/web/assets/{dracula-soft-CeHAoi-D.js → dracula-soft-BiX_luwV.js} +0 -0
- /package/dist/web/assets/{dream-maker-BMH1JI2G.js → dream-maker-S6ie6kFg.js} +0 -0
- /package/dist/web/assets/{editor-font-D_4aaSCa.js → editor-font-BOjGgYeg.js} +0 -0
- /package/dist/web/assets/{emacs-lisp-BaAYIdWN.js → emacs-lisp-DpOda430.js} +0 -0
- /package/dist/web/assets/{everforest-dark-Cs91gPa_.js → everforest-dark-BAfSXdLG.js} +0 -0
- /package/dist/web/assets/{everforest-light-lTkE6qWA.js → everforest-light-Dp59kp4R.js} +0 -0
- /package/dist/web/assets/{fennel-CmhYEhcM.js → fennel-CNaNUmMo.js} +0 -0
- /package/dist/web/assets/{fish-p1jauFum.js → fish-C8Z04ic7.js} +0 -0
- /package/dist/web/assets/{fluent-BsH-lUh2.js → fluent-Bugk01mf.js} +0 -0
- /package/dist/web/assets/{format-bytes-amUJ8Js8.js → format-bytes-DBBzVCYA.js} +0 -0
- /package/dist/web/assets/{fortran-free-form-CB6SdVKB.js → fortran-free-form-csIz6MQj.js} +0 -0
- /package/dist/web/assets/{gdscript--YoKuvEA.js → gdscript-fdzYQLfk.js} +0 -0
- /package/dist/web/assets/{gdshader-BRtMwf5z.js → gdshader-CfsEtDeZ.js} +0 -0
- /package/dist/web/assets/{genie-wrzVG2Z8.js → genie-CtHN5N2Q.js} +0 -0
- /package/dist/web/assets/{gherkin-HnpURN27.js → gherkin-gSp2ZJTf.js} +0 -0
- /package/dist/web/assets/{github-dark-XlZ3pGhn.js → github-dark-D7O9efii.js} +0 -0
- /package/dist/web/assets/{github-dark-default-D_R0hfJe.js → github-dark-default-Bv2wIhqD.js} +0 -0
- /package/dist/web/assets/{github-dark-dimmed-BHQgHLnK.js → github-dark-dimmed-BuY_SpCX.js} +0 -0
- /package/dist/web/assets/{github-dark-high-contrast-Pbl4mEFe.js → github-dark-high-contrast-Chv0f5Wu.js} +0 -0
- /package/dist/web/assets/{github-light-0P0VANJn.js → github-light-DV8f-W2f.js} +0 -0
- /package/dist/web/assets/{github-light-default-DTfsnyDq.js → github-light-default-CNBSU3dB.js} +0 -0
- /package/dist/web/assets/{github-light-high-contrast-DKITR-5Y.js → github-light-high-contrast-sg94tHwU.js} +0 -0
- /package/dist/web/assets/{gleam-refSZtkM.js → gleam-w7270-PJ.js} +0 -0
- /package/dist/web/assets/{gn-BZ9cGckR.js → gn-yo_iE_A_.js} +0 -0
- /package/dist/web/assets/{gnuplot-CMHqDcTW.js → gnuplot-DSBPrzl4.js} +0 -0
- /package/dist/web/assets/{go-bFdCrzvY.js → go-D1S7g97D.js} +0 -0
- /package/dist/web/assets/{groovy-Dvz5tluQ.js → groovy-C7xW-5IV.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-hard-D0Z-pclr.js → gruvbox-dark-hard-BZald7Z_.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-medium-BG6oIRQR.js → gruvbox-dark-medium-v6W4PZne.js} +0 -0
- /package/dist/web/assets/{gruvbox-dark-soft-ILJ-3tU6.js → gruvbox-dark-soft-CN5mIGkw.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-hard-Bl95khkz.js → gruvbox-light-hard-D3NIGRxd.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-medium-CdislFOh.js → gruvbox-light-medium-m4ShuCnD.js} +0 -0
- /package/dist/web/assets/{gruvbox-light-soft-CTcEyxlX.js → gruvbox-light-soft-BEEYNyk-.js} +0 -0
- /package/dist/web/assets/{haskell-D9jfkQuH.js → haskell-CgtdXIH3.js} +0 -0
- /package/dist/web/assets/{haxe-Ckfl4osD.js → haxe-D7HQqtIx.js} +0 -0
- /package/dist/web/assets/{hcl-t03N4k5N.js → hcl-C-YHDaXH.js} +0 -0
- /package/dist/web/assets/{hjson-B_TIVRki.js → hjson-BrgEMvJK.js} +0 -0
- /package/dist/web/assets/{hlsl-BBCTeANz.js → hlsl-BsDumu1j.js} +0 -0
- /package/dist/web/assets/{horizon-CRY-xdGU.js → horizon-D9Kre3KQ.js} +0 -0
- /package/dist/web/assets/{horizon-bright-BpUM2C5u.js → horizon-bright-DJq8c_Yq.js} +0 -0
- /package/dist/web/assets/{houston-RVyAGlyS.js → houston-B9tnxzX8.js} +0 -0
- /package/dist/web/assets/{hy-BHFJHuHd.js → hy-DUYVvXOj.js} +0 -0
- /package/dist/web/assets/{image-gallery-DdQblMAe.js → image-gallery-DvAgPQ3L.js} +0 -0
- /package/dist/web/assets/{image-preview-geometry-BFKR37Pj.js → image-preview-geometry-B-SdD7_D.js} +0 -0
- /package/dist/web/assets/{imba-DyG0_0MS.js → imba-CGW-TsRm.js} +0 -0
- /package/dist/web/assets/{ini-CsCTH-_o.js → ini-PqgYiEAV.js} +0 -0
- /package/dist/web/assets/{json5-g3g-IFTV.js → json5-sbkvqHou.js} +0 -0
- /package/dist/web/assets/{jsonc-DQHBJwib.js → jsonc-pnywfpws.js} +0 -0
- /package/dist/web/assets/{jsonl-zFLDm4eB.js → jsonl-ZPOQ0pRn.js} +0 -0
- /package/dist/web/assets/{jsonnet-DgNm2IGn.js → jsonnet-B_Q7j1YF.js} +0 -0
- /package/dist/web/assets/{jssm-BErkU0In.js → jssm-K-xYeQyp.js} +0 -0
- /package/dist/web/assets/{kanagawa-dragon-Dgymfjca.js → kanagawa-dragon-DAdLBtU8.js} +0 -0
- /package/dist/web/assets/{kanagawa-lotus-CWZEYd27.js → kanagawa-lotus-5BwvVGu8.js} +0 -0
- /package/dist/web/assets/{kanagawa-wave-CQg17ecf.js → kanagawa-wave-C0h9fsDT.js} +0 -0
- /package/dist/web/assets/{kdl-DY4GHmJC.js → kdl-DXSsFcms.js} +0 -0
- /package/dist/web/assets/{kotlin-DeGTz7bl.js → kotlin-BXNIvloo.js} +0 -0
- /package/dist/web/assets/{kusto-BN-OqpQj.js → kusto-wM3eio5V.js} +0 -0
- /package/dist/web/assets/{laserwave-bAqiAiOp.js → laserwave-FcbxdP2A.js} +0 -0
- /package/dist/web/assets/{lean-CAypLWCf.js → lean-RenzGeoM.js} +0 -0
- /package/dist/web/assets/{less-ikHAUlPb.js → less-CcUdtNJi.js} +0 -0
- /package/dist/web/assets/{libesm-cUHvIIuW.js → libesm-DMnQ3WlF.js} +0 -0
- /package/dist/web/assets/{light-plus-BamuTcT9.js → light-plus-BsMoOZJR.js} +0 -0
- /package/dist/web/assets/{llvm-CddObVkW.js → llvm-CyylMBuq.js} +0 -0
- /package/dist/web/assets/{log-CWbfGTTc.js → log-BOi0GB58.js} +0 -0
- /package/dist/web/assets/{logo-AHyhxX3Z.js → logo-BQUr3X2Y.js} +0 -0
- /package/dist/web/assets/{luau-y7she9L3.js → luau-3YZRDIsh.js} +0 -0
- /package/dist/web/assets/{make-DP3sQaP3.js → make-DEkKRDRU.js} +0 -0
- /package/dist/web/assets/{markdown-9Nuxib8a.js → markdown-BmFN0-A1.js} +0 -0
- /package/dist/web/assets/{material-theme-DDpm-uS7.js → material-theme-DqLHjEZ8.js} +0 -0
- /package/dist/web/assets/{material-theme-darker-CHk91wbm.js → material-theme-darker-DhbvULnI.js} +0 -0
- /package/dist/web/assets/{material-theme-lighter-LkmOI8KM.js → material-theme-lighter-C_aA4yVe.js} +0 -0
- /package/dist/web/assets/{material-theme-ocean-PpkUhB4-.js → material-theme-ocean-Pk5JltJS.js} +0 -0
- /package/dist/web/assets/{material-theme-palenight-DZAigXgW.js → material-theme-palenight-DNi3VguV.js} +0 -0
- /package/dist/web/assets/{matlab-CexKVVPc.js → matlab-BqUtv2ml.js} +0 -0
- /package/dist/web/assets/{mdx-BrcepHfI.js → mdx-DFMrnHBn.js} +0 -0
- /package/dist/web/assets/{mermaid-CNFhZZaG.js → mermaid-BpyuE0L_.js} +0 -0
- /package/dist/web/assets/{min-dark-hd3nbDV4.js → min-dark-DVfCMEPW.js} +0 -0
- /package/dist/web/assets/{min-light-AqA5jmks.js → min-light-B96aMADV.js} +0 -0
- /package/dist/web/assets/{mipsasm-B3x4L8Zk.js → mipsasm-DHhEcvKr.js} +0 -0
- /package/dist/web/assets/{mojo-CvfXy3YL.js → mojo-BQ6HsVIQ.js} +0 -0
- /package/dist/web/assets/{monokai-CdxwmnU_.js → monokai-amcXAKGG.js} +0 -0
- /package/dist/web/assets/{moonbit-6Z_VCO0_.js → moonbit-CGSXXQJI.js} +0 -0
- /package/dist/web/assets/{move-B2__B6Po.js → move-BOa4mq0q.js} +0 -0
- /package/dist/web/assets/{narrat-D6vL6wL-.js → narrat-dBYNSnhr.js} +0 -0
- /package/dist/web/assets/{nextflow-groovy-L-FBME4e.js → nextflow-groovy-Dm2Y_qgn.js} +0 -0
- /package/dist/web/assets/{night-owl-DjKrkDjv.js → night-owl-Dy9ibYHN.js} +0 -0
- /package/dist/web/assets/{night-owl-light-CeGjPuUQ.js → night-owl-light-DamYjQKi.js} +0 -0
- /package/dist/web/assets/{nix-dr279CcA.js → nix-C1LyoszC.js} +0 -0
- /package/dist/web/assets/{nord-Dxn-_H_Y.js → nord-LtGRYAFI.js} +0 -0
- /package/dist/web/assets/{nushell-DgeAQO7j.js → nushell-BMoOkt47.js} +0 -0
- /package/dist/web/assets/{objective-c-CO0-Pacn.js → objective-c-CILaOZJu.js} +0 -0
- /package/dist/web/assets/{objective-cpp-SkrjegYw.js → objective-cpp-D5Fo-SoM.js} +0 -0
- /package/dist/web/assets/{ocaml-CAihtkib.js → ocaml-D1TCTCEJ.js} +0 -0
- /package/dist/web/assets/{odin-D0XZbUDB.js → odin-CjdYcmpW.js} +0 -0
- /package/dist/web/assets/{one-dark-pro-BUMNMxjX.js → one-dark-pro-GpsZUGZl.js} +0 -0
- /package/dist/web/assets/{one-light-C0Ui69Bx.js → one-light-DlketcS4.js} +0 -0
- /package/dist/web/assets/{openscad-fZ9ggqM-.js → openscad-BoT8wwuI.js} +0 -0
- /package/dist/web/assets/{pascal-DvZm-eun.js → pascal-Cqy403Sf.js} +0 -0
- /package/dist/web/assets/{pkl-CQSIp_z8.js → pkl-D6gRI9qQ.js} +0 -0
- /package/dist/web/assets/{plastic-CMspsouJ.js → plastic-DgvX8DXX.js} +0 -0
- /package/dist/web/assets/{plsql-B_HL7UfT.js → plsql-CTDnCVE3.js} +0 -0
- /package/dist/web/assets/{po-DxAfbdfe.js → po-DDnzm7AQ.js} +0 -0
- /package/dist/web/assets/{poimandres-JGmqmwux.js → poimandres-C4HQwFp-.js} +0 -0
- /package/dist/web/assets/{polar-_mNmplk8.js → polar-WBTQdMzX.js} +0 -0
- /package/dist/web/assets/{postcss-GpU0Sjqc.js → postcss-CWxogTg1.js} +0 -0
- /package/dist/web/assets/{powerquery-B1IP1lCQ.js → powerquery-DVtReIRR.js} +0 -0
- /package/dist/web/assets/{powershell-BiSO9XmG.js → powershell-Cb_RNzSh.js} +0 -0
- /package/dist/web/assets/{prisma-4QqDYSnH.js → prisma-nKLUh3DY.js} +0 -0
- /package/dist/web/assets/{prolog-BNjvyRqT.js → prolog-BD9orEy4.js} +0 -0
- /package/dist/web/assets/{proto-RNOumnkw.js → proto-B-AFoz75.js} +0 -0
- /package/dist/web/assets/{puppet-CDfv5o8f.js → puppet-DDW6wWm4.js} +0 -0
- /package/dist/web/assets/{purescript-YTjSoifd.js → purescript-DXy49AJg.js} +0 -0
- /package/dist/web/assets/{python-Mh7JD25U.js → python-BQnvDlc7.js} +0 -0
- /package/dist/web/assets/{qmldir-Da_ZrqZy.js → qmldir-CboMQXQW.js} +0 -0
- /package/dist/web/assets/{qss-DANVkyhy.js → qss-8XaprLEt.js} +0 -0
- /package/dist/web/assets/{racket-CwPOn4T1.js → racket-ChcVp15M.js} +0 -0
- /package/dist/web/assets/{raku-B04lBsXd.js → raku-dEgEXW0A.js} +0 -0
- /package/dist/web/assets/{red-MW6Zm5pd.js → red-hmwjontD.js} +0 -0
- /package/dist/web/assets/{reg-44SURM-E.js → reg-CIkOufh2.js} +0 -0
- /package/dist/web/assets/{rel-Gu5Erhpm.js → rel-NXKKDiTi.js} +0 -0
- /package/dist/web/assets/{resolve-theme-BNubecVz.js → resolve-theme-B87m6l4i.js} +0 -0
- /package/dist/web/assets/{riscv-DZDP0Ce7.js → riscv-BEIzhPcg.js} +0 -0
- /package/dist/web/assets/{ron-BwLObbl6.js → ron-CW2Bt8rN.js} +0 -0
- /package/dist/web/assets/{rose-pine-Bz6ToXok.js → rose-pine-DhnBfr5a.js} +0 -0
- /package/dist/web/assets/{rose-pine-dawn-LyFogzAh.js → rose-pine-dawn-Jyj59rVs.js} +0 -0
- /package/dist/web/assets/{rose-pine-moon-CpjkefjD.js → rose-pine-moon-BMulxhJC.js} +0 -0
- /package/dist/web/assets/{rosmsg-BldDLaz1.js → rosmsg-DuctJm-Q.js} +0 -0
- /package/dist/web/assets/{rust-74skZ8CC.js → rust-FbJ2fCp9.js} +0 -0
- /package/dist/web/assets/{sass-CitUFDWl.js → sass-Dfxwdu2h.js} +0 -0
- /package/dist/web/assets/{scala-D2kl5ghT.js → scala-ClsSR0wG.js} +0 -0
- /package/dist/web/assets/{scheme-DZqhC9Xs.js → scheme-Jj_Cc-8H.js} +0 -0
- /package/dist/web/assets/{sdbl-D6a8sHP9.js → sdbl-Bi8D_DGN.js} +0 -0
- /package/dist/web/assets/{slack-dark-DrlPLUB_.js → slack-dark-B7gbmJT9.js} +0 -0
- /package/dist/web/assets/{slack-ochin-Djgychog.js → slack-ochin-O7j_c76D.js} +0 -0
- /package/dist/web/assets/{smalltalk-CYQHXftK.js → smalltalk-BD5-U3JK.js} +0 -0
- /package/dist/web/assets/{snazzy-light-BQAdF14K.js → snazzy-light-BbiRB69_.js} +0 -0
- /package/dist/web/assets/{solarized-dark-JDtJfY-g.js → solarized-dark-2OWHYEBu.js} +0 -0
- /package/dist/web/assets/{solarized-light-DHzVPLDD.js → solarized-light-Cew4YqT3.js} +0 -0
- /package/dist/web/assets/{solidity-CYCEiPu1.js → solidity-Bpbne2Tx.js} +0 -0
- /package/dist/web/assets/{splunk-B7RHmJY2.js → splunk-Dq86L1_O.js} +0 -0
- /package/dist/web/assets/{ssh-config-B74-n00O.js → ssh-config-j5hsMvbs.js} +0 -0
- /package/dist/web/assets/{stylus-xlRhcbpN.js → stylus-DWhCIBg0.js} +0 -0
- /package/dist/web/assets/{swift-DTFwWJtu.js → swift-29fG5ztW.js} +0 -0
- /package/dist/web/assets/{synthwave-84-BuCpuX2E.js → synthwave-84-DraIUmiw.js} +0 -0
- /package/dist/web/assets/{system-verilog-CgxJCrOK.js → system-verilog-DqcJAWq_.js} +0 -0
- /package/dist/web/assets/{systemd-D0x7_XYJ.js → systemd-BUPJrx1D.js} +0 -0
- /package/dist/web/assets/{talonscript-B50aQRuc.js → talonscript-BGYbnAKh.js} +0 -0
- /package/dist/web/assets/{tasl-Byv8gHCL.js → tasl-CwbSJqng.js} +0 -0
- /package/dist/web/assets/{tcl-CzMjCzWo.js → tcl-Ba9376wa.js} +0 -0
- /package/dist/web/assets/{terraform-D6GH4CXG.js → terraform-ChSasWu8.js} +0 -0
- /package/dist/web/assets/{tokyo-night-CQ4rTpHY.js → tokyo-night-Bbw1Yguv.js} +0 -0
- /package/dist/web/assets/{toml-D9W-BuJE.js → toml-CYb7zi5B.js} +0 -0
- /package/dist/web/assets/{tsv-BddanT8p.js → tsv-P2eVmwf9.js} +0 -0
- /package/dist/web/assets/{turtle-BddVklvD.js → turtle-DIoQTATC.js} +0 -0
- /package/dist/web/assets/{typespec-D60I2kfB.js → typespec-Dpr1bC2k.js} +0 -0
- /package/dist/web/assets/{typst-Bxvc-9ID.js → typst-D4WMCDMn.js} +0 -0
- /package/dist/web/assets/{utils-Bmf_8h7Y.js → utils-btZ8C8-R.js} +0 -0
- /package/dist/web/assets/{v-kVYZE10o.js → v-B1wY-VFU.js} +0 -0
- /package/dist/web/assets/{vala-B3zj44PV.js → vala-BKqhrirP.js} +0 -0
- /package/dist/web/assets/{vb-CHgWrFTj.js → vb-S9PHCa7-.js} +0 -0
- /package/dist/web/assets/{vendor-xterm-_yyu5n32.js → vendor-xterm-BHKF_Nsf.js} +0 -0
- /package/dist/web/assets/{verilog-zIMuE3hE.js → verilog-CrztYl3V.js} +0 -0
- /package/dist/web/assets/{vesper-BjqPTQr0.js → vesper-C5KfcyFv.js} +0 -0
- /package/dist/web/assets/{vhdl-Q2EtgpQN.js → vhdl-D0qMeIJu.js} +0 -0
- /package/dist/web/assets/{viml-CrtDZkFz.js → viml-Dsv9mRPK.js} +0 -0
- /package/dist/web/assets/{vitesse-black-D2VWO3oN.js → vitesse-black-rJvNN5GN.js} +0 -0
- /package/dist/web/assets/{vitesse-dark-lleZmHBJ.js → vitesse-dark-CYp0WWjf.js} +0 -0
- /package/dist/web/assets/{vitesse-light-utUY298S.js → vitesse-light-BczSAvzE.js} +0 -0
- /package/dist/web/assets/{vyper-LQ1KxOUo.js → vyper-DM7bKz7E.js} +0 -0
- /package/dist/web/assets/{wasm-CJ9U4zWg.js → wasm-BXCHhbrz.js} +0 -0
- /package/dist/web/assets/{wasm-B-mpMVDM.js → wasm-CAJoqhGc.js} +0 -0
- /package/dist/web/assets/{wenyan-LqMyA7px.js → wenyan-NQ8fdbEq.js} +0 -0
- /package/dist/web/assets/{wgsl-eI4U21sm.js → wgsl-C88C7vmC.js} +0 -0
- /package/dist/web/assets/{wikitext-CuWC2dfS.js → wikitext-D92r7uX8.js} +0 -0
- /package/dist/web/assets/{wit-CCPY0MNz.js → wit-DNvTfQjW.js} +0 -0
- /package/dist/web/assets/{wolfram-CXhjyJun.js → wolfram-CNS5lCGj.js} +0 -0
- /package/dist/web/assets/{zenscript-BzHPI08Q.js → zenscript-B_rGi-H_.js} +0 -0
- /package/dist/web/assets/{zig-CBuhKUve.js → zig-BRi9UYQa.js} +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Permission policy for a design session in `acceptEdits` mode: file reads, searches,
|
|
7
|
+
* writes and edits are auto-approved while their target resolves inside the project, and
|
|
8
|
+
* every other tool — shell, web, MCP, subagents, anything unknown — goes to the user.
|
|
9
|
+
*
|
|
10
|
+
* Fail-closed throughout: a missing project root, a path that is not a string, or a path
|
|
11
|
+
* that cannot be resolved all answer "ask". The check follows symlinks (realpath), so a
|
|
12
|
+
* link inside the project pointing outside it is treated as the outside path it is.
|
|
13
|
+
*/
|
|
14
|
+
export type DesignToolDecision = "allow" | "ask";
|
|
15
|
+
|
|
16
|
+
/** Tool → the input field naming its target, and whether that field may be omitted
|
|
17
|
+
* (Glob/Grep default to the session cwd, which is the project root). */
|
|
18
|
+
const FILE_TOOLS: Record<string, { field: string; optional: boolean }> = {
|
|
19
|
+
Read: { field: "file_path", optional: false },
|
|
20
|
+
Write: { field: "file_path", optional: false },
|
|
21
|
+
Edit: { field: "file_path", optional: false },
|
|
22
|
+
Glob: { field: "path", optional: true },
|
|
23
|
+
Grep: { field: "path", optional: true },
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export function designToolDecision(
|
|
27
|
+
toolName: string,
|
|
28
|
+
input: unknown,
|
|
29
|
+
projectPath: string | undefined,
|
|
30
|
+
): DesignToolDecision {
|
|
31
|
+
const spec = FILE_TOOLS[toolName];
|
|
32
|
+
if (!spec || !projectPath) return "ask";
|
|
33
|
+
if (!input || typeof input !== "object") return "ask";
|
|
34
|
+
const record = input as Record<string, unknown>;
|
|
35
|
+
|
|
36
|
+
const root = canonicalPath(projectPath);
|
|
37
|
+
if (!root) return "ask";
|
|
38
|
+
|
|
39
|
+
// Glob's pattern is itself a path expression: `../../**` or `/etc/*` would enumerate
|
|
40
|
+
// outside the project even with no `path` given.
|
|
41
|
+
if (toolName === "Glob") {
|
|
42
|
+
const pattern = record.pattern;
|
|
43
|
+
if (typeof pattern !== "string" || !pattern || patternLeavesRoot(pattern)) return "ask";
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const target = record[spec.field];
|
|
47
|
+
if (target === undefined || target === null || target === "") {
|
|
48
|
+
return spec.optional ? "allow" : "ask";
|
|
49
|
+
}
|
|
50
|
+
if (typeof target !== "string") return "ask";
|
|
51
|
+
|
|
52
|
+
const resolved = canonicalPath(resolve(projectPath, expandHome(target)));
|
|
53
|
+
if (!resolved) return "ask";
|
|
54
|
+
return isInside(resolved, root) ? "allow" : "ask";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** `~` is expanded the way a shell would, so `~/.ssh` is judged as the home directory it
|
|
58
|
+
* names rather than as a folder called `~` inside the project. */
|
|
59
|
+
function expandHome(path: string): string {
|
|
60
|
+
if (path === "~") return homedir();
|
|
61
|
+
if (path.startsWith("~/") || path.startsWith("~\\")) return join(homedir(), path.slice(2));
|
|
62
|
+
return path;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function patternLeavesRoot(pattern: string): boolean {
|
|
66
|
+
if (isAbsolute(pattern) || /^[a-zA-Z]:/.test(pattern) || pattern.startsWith("~")) return true;
|
|
67
|
+
return pattern.split(/[\\/]/).includes("..");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Realpath of the path, or of its nearest existing ancestor with the missing tail
|
|
72
|
+
* re-appended — a Write usually targets a file that does not exist yet, and its parent
|
|
73
|
+
* directories may not either. Null when nothing along the chain resolves.
|
|
74
|
+
*/
|
|
75
|
+
function canonicalPath(path: string): string | null {
|
|
76
|
+
const tail: string[] = [];
|
|
77
|
+
let current = resolve(path);
|
|
78
|
+
for (;;) {
|
|
79
|
+
try {
|
|
80
|
+
const real = realpathSync.native(current);
|
|
81
|
+
return tail.length ? join(real, ...tail.reverse()) : real;
|
|
82
|
+
} catch {
|
|
83
|
+
// Something is there but cannot be resolved — typically a dangling symlink, which
|
|
84
|
+
// a Write would follow to wherever it points. Only a truly absent entry may be
|
|
85
|
+
// replaced by its parent.
|
|
86
|
+
if (entryExists(current)) return null;
|
|
87
|
+
const parent = dirname(current);
|
|
88
|
+
if (parent === current) return null;
|
|
89
|
+
tail.push(basename(current));
|
|
90
|
+
current = parent;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function entryExists(path: string): boolean {
|
|
96
|
+
try {
|
|
97
|
+
lstatSync(path);
|
|
98
|
+
return true;
|
|
99
|
+
} catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function isInside(target: string, root: string): boolean {
|
|
105
|
+
const caseFold = process.platform === "win32" || process.platform === "darwin";
|
|
106
|
+
const a = caseFold ? target.toLowerCase() : target;
|
|
107
|
+
const b = caseFold ? root.toLowerCase() : root;
|
|
108
|
+
const rel = relative(b, a);
|
|
109
|
+
if (rel === "") return true;
|
|
110
|
+
return !isAbsolute(rel) && rel !== ".." && !rel.startsWith(`..${sep}`);
|
|
111
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { getSessionDesignSlug, getSessionProjectPath } from "../db.service.ts";
|
|
2
|
+
import { isValidDesignSlug } from "./design-slug.ts";
|
|
3
|
+
import { designLockKey, detachFromDesignLocks } from "./design-lock.ts";
|
|
4
|
+
import { snapshotDesign } from "./design-snapshots.service.ts";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Snapshot a design after each turn of its design session.
|
|
8
|
+
*
|
|
9
|
+
* Called from `chatService.sendMessage` on every `done` and on every terminal background
|
|
10
|
+
* task notification, so turns from the WebSocket, `ppm chat send`, the scheduler and the
|
|
11
|
+
* bots are all covered. Work an agent started in the background can keep writing after
|
|
12
|
+
* the turn's `done`, which is why its completion schedules a snapshot too.
|
|
13
|
+
*
|
|
14
|
+
* Debounced per design: a turn's `done` followed shortly by its background task finishing
|
|
15
|
+
* produces one snapshot of the final state, not two. The timer is deliberately left
|
|
16
|
+
* referenced so a one-shot CLI process stays alive long enough to take it.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export const TURN_SNAPSHOT_DEBOUNCE_MS = 2000;
|
|
20
|
+
|
|
21
|
+
interface Pending {
|
|
22
|
+
timer: ReturnType<typeof setTimeout>;
|
|
23
|
+
fire: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const pending = new Map<string, Pending>();
|
|
27
|
+
const inFlight = new Set<Promise<void>>();
|
|
28
|
+
let debounceMs = TURN_SNAPSHOT_DEBOUNCE_MS;
|
|
29
|
+
|
|
30
|
+
/** Test seam for the debounce interval. */
|
|
31
|
+
export function setTurnSnapshotDebounceForTests(ms: number | null): void {
|
|
32
|
+
debounceMs = ms ?? TURN_SNAPSHOT_DEBOUNCE_MS;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Schedule a `turn` snapshot for the session's design. A no-op for an ordinary session
|
|
37
|
+
* (no design slug) or one with no known project. Never throws: a snapshot problem must not
|
|
38
|
+
* disturb the turn that triggered it.
|
|
39
|
+
*/
|
|
40
|
+
export function scheduleTurnSnapshot(sessionId: string, projectPath?: string | null): void {
|
|
41
|
+
try {
|
|
42
|
+
const slug = getSessionDesignSlug(sessionId);
|
|
43
|
+
if (!slug || !isValidDesignSlug(slug)) return;
|
|
44
|
+
const project = projectPath || getSessionProjectPath(sessionId);
|
|
45
|
+
if (!project) return;
|
|
46
|
+
const key = designLockKey(project, slug);
|
|
47
|
+
const existing = pending.get(key);
|
|
48
|
+
if (existing) clearTimeout(existing.timer);
|
|
49
|
+
|
|
50
|
+
const run = async (): Promise<void> => {
|
|
51
|
+
pending.delete(key);
|
|
52
|
+
try {
|
|
53
|
+
await snapshotDesign(project, slug, "turn", { sessionId });
|
|
54
|
+
} catch (e) {
|
|
55
|
+
console.warn(`[design] turn snapshot of ${slug} failed: ${(e as Error).message}`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const fire = (): void => {
|
|
59
|
+
const job = detachFromDesignLocks(run);
|
|
60
|
+
inFlight.add(job);
|
|
61
|
+
void job.finally(() => inFlight.delete(job));
|
|
62
|
+
};
|
|
63
|
+
pending.set(key, { timer: setTimeout(fire, debounceMs), fire });
|
|
64
|
+
} catch (e) {
|
|
65
|
+
console.warn(`[design] could not schedule a turn snapshot for ${sessionId}: ${(e as Error).message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Run every pending snapshot now and wait for all of them, in flight ones included. */
|
|
70
|
+
export async function flushTurnSnapshots(): Promise<void> {
|
|
71
|
+
for (const job of [...pending.values()]) {
|
|
72
|
+
clearTimeout(job.timer);
|
|
73
|
+
job.fire();
|
|
74
|
+
}
|
|
75
|
+
await Promise.all([...inFlight]);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function pendingTurnSnapshotCount(): number {
|
|
79
|
+
return pending.size;
|
|
80
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { DESIGN_GEN_RE } from "../../shared/design-types.ts";
|
|
3
|
+
import {
|
|
4
|
+
MAX_TWEAKS, TWEAK_VAR_RE, parseTweaks, sanitizeTweakValue, type ParsedTweaks,
|
|
5
|
+
} from "../../shared/design-tweaks.ts";
|
|
6
|
+
import { withRecoveredDesign } from "./design-restore-journal.ts";
|
|
7
|
+
import { resolveDesignDir, lstatOrNull } from "./design-paths.ts";
|
|
8
|
+
import { MANIFEST_FILE, isSafeEntry, parseManifest } from "./design-manifest.ts";
|
|
9
|
+
import { snapshotDesign } from "./design-snapshots.service.ts";
|
|
10
|
+
import { DesignError } from "./design-error.ts";
|
|
11
|
+
import { readDesignSource, writeDesignSource } from "./source/design-source-file.ts";
|
|
12
|
+
import { styleSources } from "./source/design-style-sources.ts";
|
|
13
|
+
import { planTweakPatches, type PlannedTweak } from "./source/tweak-patch-plan.ts";
|
|
14
|
+
import { takeDesignWrite } from "./design-write-rate-limit.ts";
|
|
15
|
+
import { changedSpan, recordEdit, type EditSpan } from "./design-edit-undo-journal.ts";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* "Apply" in the Tweaks panel: write the chosen values into the design's stylesheets.
|
|
19
|
+
*
|
|
20
|
+
* The request carries only variable names and values, never a position or a file to write:
|
|
21
|
+
* the server re-reads the manifest, validates each value against its tweak's allowlist,
|
|
22
|
+
* works out which declaration wins on screen (see `tweak-patch-plan.ts`) and splices only
|
|
23
|
+
* that. Every design file it reads must still have the gen the canvas reported for it —
|
|
24
|
+
* the entry HTML and each linked stylesheet — or the whole commit is a 409 naming the file,
|
|
25
|
+
* so a canvas that is behind an agent's edit can never have its view written back over it.
|
|
26
|
+
* The `before-edit` snapshot is taken only once the commit is known to go through, and a
|
|
27
|
+
* commit that writes counts against the design's canvas write limit. Every file it changes
|
|
28
|
+
* is journaled as one undo entry, so Undo reverts this Apply and nothing an AI turn did since.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
const MAX_MANIFEST_BYTES = 256 * 1024;
|
|
32
|
+
|
|
33
|
+
export interface TweakCommitInput {
|
|
34
|
+
entry: string;
|
|
35
|
+
gens: Record<string, string>;
|
|
36
|
+
values: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface TweakCommitResult {
|
|
40
|
+
/** Current gen of every design file the commit read, rewritten ones included. */
|
|
41
|
+
gens: Record<string, string>;
|
|
42
|
+
/** Undoes this commit's writes; null when nothing was written or it was too large to journal. */
|
|
43
|
+
undoId: string | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface DesignTweaksInfo extends ParsedTweaks {
|
|
47
|
+
/** False when `design.json` is missing or not a JSON object; the panel is then hidden. */
|
|
48
|
+
manifestValid: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** A stale gen: the design changed since the canvas loaded it. */
|
|
52
|
+
export class StaleTweakGenError extends DesignError {
|
|
53
|
+
constructor(readonly file: string, readonly currentGen: string) {
|
|
54
|
+
super(409, "ESTALE", `${file} changed since the canvas loaded it`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const bad = (message: string): DesignError => new DesignError(400, "EBADTWEAK", message);
|
|
59
|
+
type Raw = Record<string, unknown>;
|
|
60
|
+
const isRaw = (v: unknown): v is Raw => !!v && typeof v === "object" && !Array.isArray(v);
|
|
61
|
+
|
|
62
|
+
async function readTweaksIn(designDir: string, slug: string): Promise<DesignTweaksInfo> {
|
|
63
|
+
const path = join(designDir, MANIFEST_FILE);
|
|
64
|
+
const st = await lstatOrNull(path);
|
|
65
|
+
if (!st?.isFile() || st.size > MAX_MANIFEST_BYTES) return { manifestValid: false, tweaks: [], errors: [] };
|
|
66
|
+
let raw: string;
|
|
67
|
+
try {
|
|
68
|
+
raw = (await readDesignSource(path, { maxBytes: MAX_MANIFEST_BYTES })).text;
|
|
69
|
+
} catch (e) {
|
|
70
|
+
if (e instanceof DesignError && e.status === 422) return { manifestValid: false, tweaks: [], errors: [] };
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
73
|
+
const parsed = parseManifest(raw, { slug, now: new Date(0).toISOString() });
|
|
74
|
+
return { manifestValid: parsed.valid, ...parseTweaks(parsed.manifest.extra.tweaks) };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** The tweak controls `design.json` declares, with the reasons any entry was skipped. */
|
|
78
|
+
export async function readDesignTweaks(projectPath: string, slug: string): Promise<DesignTweaksInfo> {
|
|
79
|
+
return readTweaksIn(await resolveDesignDir(projectPath, slug), slug);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function parseTweakCommitInput(input: unknown): TweakCommitInput {
|
|
83
|
+
if (!isRaw(input)) throw bad("Expected a JSON object");
|
|
84
|
+
if (!isSafeEntry(input.entry)) throw bad("entry must be an HTML file of the design");
|
|
85
|
+
if (!isRaw(input.gens) || Object.keys(input.gens).length > 64) throw bad("gens must map files to gens");
|
|
86
|
+
const gens: Record<string, string> = {};
|
|
87
|
+
for (const [file, gen] of Object.entries(input.gens)) {
|
|
88
|
+
if (file.length > 512 || typeof gen !== "string" || !DESIGN_GEN_RE.test(gen)) throw bad("gens must map files to gens");
|
|
89
|
+
gens[file] = gen;
|
|
90
|
+
}
|
|
91
|
+
if (!isRaw(input.values)) throw bad("values must map variables to values");
|
|
92
|
+
const entries = Object.entries(input.values);
|
|
93
|
+
if (entries.length === 0) throw bad("Nothing to apply");
|
|
94
|
+
if (entries.length > MAX_TWEAKS) throw bad(`At most ${MAX_TWEAKS} values per commit`);
|
|
95
|
+
const values: Record<string, string> = {};
|
|
96
|
+
for (const [name, value] of entries) {
|
|
97
|
+
if (!TWEAK_VAR_RE.test(name) || typeof value !== "string") throw bad(`Invalid value for ${name.slice(0, 60)}`);
|
|
98
|
+
values[name] = value;
|
|
99
|
+
}
|
|
100
|
+
return { entry: input.entry, gens, values };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function commitTweaks(projectPath: string, slug: string, raw: unknown): Promise<TweakCommitResult> {
|
|
104
|
+
const input = parseTweakCommitInput(raw);
|
|
105
|
+
return withRecoveredDesign(projectPath, slug, async (designDir) => {
|
|
106
|
+
const { tweaks } = await readTweaksIn(designDir, slug);
|
|
107
|
+
const planned: PlannedTweak[] = Object.entries(input.values).map(([name, value]) => {
|
|
108
|
+
const def = tweaks.find((t) => t.var === name);
|
|
109
|
+
if (!def) throw bad(`${name} is not a tweak of this design`);
|
|
110
|
+
const safe = sanitizeTweakValue(def, value);
|
|
111
|
+
if (safe === null) throw bad(`"${def.label}" cannot be set to that value`);
|
|
112
|
+
return { def, value: safe };
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
const loaded = await styleSources({ projectPath, slug }, input.entry);
|
|
116
|
+
for (const [file, { source, outside }] of loaded.files) {
|
|
117
|
+
// The shared tokens.css is never written and the canvas holds no gen for it.
|
|
118
|
+
if (!outside && input.gens[file] !== source.gen) throw new StaleTweakGenError(file, source.gen);
|
|
119
|
+
}
|
|
120
|
+
const texts = new Map([...loaded.files].map(([file, f]) => [file, f.source.text] as const));
|
|
121
|
+
const patches = planTweakPatches(input.entry, loaded.sources, texts, planned);
|
|
122
|
+
|
|
123
|
+
const gens: Record<string, string> = {};
|
|
124
|
+
for (const [file, { source, outside }] of loaded.files) if (!outside) gens[file] = source.gen;
|
|
125
|
+
if (patches.size === 0) return { gens, undoId: null };
|
|
126
|
+
takeDesignWrite(projectPath, slug);
|
|
127
|
+
await snapshotDesign(projectPath, slug, "before-edit");
|
|
128
|
+
const spans: EditSpan[] = [];
|
|
129
|
+
const written: Record<string, string> = {};
|
|
130
|
+
for (const [file, text] of patches) {
|
|
131
|
+
const f = loaded.files.get(file)!;
|
|
132
|
+
gens[file] = written[file] = await writeDesignSource(f.abs, text, { bom: f.source.bom });
|
|
133
|
+
const span = changedSpan(file, f.source.text, text);
|
|
134
|
+
if (span) spans.push(span);
|
|
135
|
+
}
|
|
136
|
+
return { gens, undoId: recordEdit(projectPath, slug, spans, written) };
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { DesignError } from "./design-error.ts";
|
|
2
|
+
import { designLockKey } from "./design-lock.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* How often the canvas may write into one design: at most one write per 500 ms and 30 per
|
|
6
|
+
* minute, counted per design across every device and tab.
|
|
7
|
+
*
|
|
8
|
+
* Canvas writes are proposed by a frame that runs the page's own scripts. The parent only
|
|
9
|
+
* forwards a proposal after a real user gesture, but a page that posts one on the back of
|
|
10
|
+
* every click the user makes would still get through, so the server caps the stream as
|
|
11
|
+
* well: whatever gets past the parent is bounded, and each write is undoable. Only writes
|
|
12
|
+
* that are about to happen are counted — a refused or stale request costs nothing — so the
|
|
13
|
+
* check runs under the design lock, right before the file is written.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const WRITE_MIN_INTERVAL_MS = 500;
|
|
17
|
+
export const WRITES_PER_MINUTE = 30;
|
|
18
|
+
const WINDOW_MS = 60_000;
|
|
19
|
+
|
|
20
|
+
/** Test seam: the clock the limiter reads. */
|
|
21
|
+
export const designWriteClock = { now: (): number => Date.now() };
|
|
22
|
+
|
|
23
|
+
const recent = new Map<string, number[]>();
|
|
24
|
+
|
|
25
|
+
function sweep(now: number): void {
|
|
26
|
+
for (const [key, times] of recent) {
|
|
27
|
+
if (times.length === 0 || now - times[times.length - 1]! >= WINDOW_MS) recent.delete(key);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Counts one write, or throws a 429 without counting it. */
|
|
32
|
+
export function takeDesignWrite(projectPath: string, slug: string): void {
|
|
33
|
+
const now = designWriteClock.now();
|
|
34
|
+
sweep(now);
|
|
35
|
+
const key = designLockKey(projectPath, slug);
|
|
36
|
+
const times = (recent.get(key) ?? []).filter((t) => now - t < WINDOW_MS);
|
|
37
|
+
const last = times[times.length - 1];
|
|
38
|
+
if (last !== undefined && now - last < WRITE_MIN_INTERVAL_MS) {
|
|
39
|
+
throw new DesignError(429, "rate-limited", "Too many canvas edits at once; wait a moment and try again");
|
|
40
|
+
}
|
|
41
|
+
if (times.length >= WRITES_PER_MINUTE) {
|
|
42
|
+
throw new DesignError(429, "rate-limited", `At most ${WRITES_PER_MINUTE} canvas edits a minute; wait a moment and try again`);
|
|
43
|
+
}
|
|
44
|
+
times.push(now);
|
|
45
|
+
recent.set(key, times);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Forget every count; for tests. */
|
|
49
|
+
export function resetDesignWriteLimits(): void {
|
|
50
|
+
recent.clear();
|
|
51
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { posix } from "node:path";
|
|
2
|
+
import { isLocalHref } from "../preview/html-instrument.ts";
|
|
3
|
+
import { TOKENS_CSS_REL, type ReadAsset } from "./design-export-asset-reader.ts";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Local asset inlining for the standalone-HTML export: CSS `url()`s and `@import`s become
|
|
7
|
+
* `data:` URIs, so the one exported file works offline.
|
|
8
|
+
*
|
|
9
|
+
* A reference resolves against the file it is written in — a stylesheet's `url()` against
|
|
10
|
+
* that stylesheet, not against the HTML — and must stay inside the design folder (the
|
|
11
|
+
* shared `../tokens.css` is the one allowed step out; it sits inside `designs/`). Absolute,
|
|
12
|
+
* scheme and fragment references are left exactly as they are: CDN links are allowed in a
|
|
13
|
+
* design and are not local. Every asset read is charged to one shared {@link InlineBudget};
|
|
14
|
+
* a missing, refused or over-budget asset keeps its original reference and adds a warning,
|
|
15
|
+
* so an export never fails because of one link.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export interface InlineBudget {
|
|
19
|
+
/** Largest single asset, in bytes. */
|
|
20
|
+
perAsset: number;
|
|
21
|
+
/** Bytes still allowed across the whole export; decremented as assets are inlined. */
|
|
22
|
+
remaining: number;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface InlineContext {
|
|
26
|
+
readAsset: ReadAsset;
|
|
27
|
+
budget: InlineBudget;
|
|
28
|
+
warnings: string[];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const MIME: Record<string, string> = {
|
|
32
|
+
".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp",
|
|
33
|
+
".avif": "image/avif", ".svg": "image/svg+xml", ".ico": "image/x-icon", ".mp4": "video/mp4", ".webm": "video/webm",
|
|
34
|
+
".mov": "video/quicktime", ".mp3": "audio/mpeg", ".wav": "audio/wav", ".ogg": "audio/ogg", ".m4a": "audio/mp4",
|
|
35
|
+
".woff": "font/woff", ".woff2": "font/woff2", ".ttf": "font/ttf", ".otf": "font/otf", ".css": "text/css",
|
|
36
|
+
".js": "text/javascript", ".mjs": "text/javascript", ".json": "application/json", ".vtt": "text/vtt",
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export function mimeForPath(rel: string): string {
|
|
40
|
+
return MIME[posix.extname(rel).toLowerCase()] ?? "application/octet-stream";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function toDataUri(rel: string, bytes: Uint8Array): string {
|
|
44
|
+
return `data:${mimeForPath(rel)};base64,${Buffer.from(bytes).toString("base64")}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type ResolvedRef = { rel: string; suffix: string } | { outside: true } | null;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A reference written in a file under `baseDir` (design-relative, `""` for the design root),
|
|
51
|
+
* as a design-relative path plus its `#fragment`. Null when it is not a local reference at all.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveDesignRef(ref: string, baseDir: string): ResolvedRef {
|
|
54
|
+
if (!isLocalHref(ref)) return null;
|
|
55
|
+
const hash = ref.indexOf("#");
|
|
56
|
+
const suffix = hash >= 0 ? ref.slice(hash) : "";
|
|
57
|
+
let path = (hash >= 0 ? ref.slice(0, hash) : ref).split("?")[0]!.trim();
|
|
58
|
+
try {
|
|
59
|
+
path = decodeURIComponent(path);
|
|
60
|
+
} catch {
|
|
61
|
+
return { outside: true };
|
|
62
|
+
}
|
|
63
|
+
if (!path || path.includes("\\") || path.includes("\0")) return { outside: true };
|
|
64
|
+
const rel = posix.normalize(posix.join(baseDir, path));
|
|
65
|
+
if (rel === TOKENS_CSS_REL) return { rel, suffix };
|
|
66
|
+
if (rel === ".." || rel.startsWith("../") || rel.startsWith("/") || rel.split("/").some((s) => s.startsWith("."))) {
|
|
67
|
+
return { outside: true };
|
|
68
|
+
}
|
|
69
|
+
return { rel, suffix };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const sizeLabel = (bytes: number): string =>
|
|
73
|
+
(bytes >= 1048576 ? `${Math.round(bytes / 1048576)} MB` : `${Math.max(1, Math.round(bytes / 1024))} KB`);
|
|
74
|
+
|
|
75
|
+
/** Reads one asset for inlining, charging the budget; null (with a warning) when it cannot be. */
|
|
76
|
+
export async function loadInlineAsset(rel: string, ctx: InlineContext): Promise<Uint8Array | null> {
|
|
77
|
+
const result = await ctx.readAsset(rel, ctx.budget.perAsset);
|
|
78
|
+
if (!result.ok) {
|
|
79
|
+
ctx.warnings.push(result.reason === "missing" ? `${rel}: not found, left linked`
|
|
80
|
+
: result.reason === "too-large" ? `${rel}: larger than ${sizeLabel(ctx.budget.perAsset)}, left linked`
|
|
81
|
+
: `${rel}: not readable from the design folder, left linked`);
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
if (result.bytes.byteLength > ctx.budget.remaining) {
|
|
85
|
+
ctx.warnings.push(`${rel}: the export's size limit is used up, left linked`);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
ctx.budget.remaining -= result.bytes.byteLength;
|
|
89
|
+
return result.bytes;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// `@import url(x)` / `@import "x"` first, so the url() of an import is inlined as CSS.
|
|
93
|
+
const REF_RE = /@import\s+(?:url\(\s*(["']?)([^"')]*)\1\s*\)|(["'])([^"']*)\3)|url\(\s*(["']?)([^"')]*?)\5\s*\)/gi;
|
|
94
|
+
const MAX_IMPORT_DEPTH = 4;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* `css` with every local `url()` turned into a data URI and every local `@import` replaced
|
|
98
|
+
* by a data URI of the imported sheet, itself inlined against its own folder.
|
|
99
|
+
*/
|
|
100
|
+
export async function inlineCssUrls(css: string, cssFileDir: string, ctx: InlineContext, depth = 0): Promise<string> {
|
|
101
|
+
const out: string[] = [];
|
|
102
|
+
let cursor = 0;
|
|
103
|
+
for (const m of css.matchAll(REF_RE)) {
|
|
104
|
+
const isImport = m[0].charAt(0) === "@";
|
|
105
|
+
const ref = isImport ? (m[2] ?? m[4] ?? "") : (m[6] ?? "");
|
|
106
|
+
const resolved = resolveDesignRef(ref, cssFileDir);
|
|
107
|
+
if (!resolved) continue;
|
|
108
|
+
if ("outside" in resolved) {
|
|
109
|
+
ctx.warnings.push(`${ref}: outside the design folder, left linked`);
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (isImport && depth >= MAX_IMPORT_DEPTH) {
|
|
113
|
+
ctx.warnings.push(`${resolved.rel}: @import nested too deeply, left linked`);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const bytes = await loadInlineAsset(resolved.rel, ctx);
|
|
117
|
+
if (!bytes) continue;
|
|
118
|
+
let replacement: string;
|
|
119
|
+
if (isImport) {
|
|
120
|
+
const inner = await inlineCssUrls(new TextDecoder().decode(bytes), posix.dirname(resolved.rel), ctx, depth + 1);
|
|
121
|
+
replacement = `@import url("${toDataUri(resolved.rel, new TextEncoder().encode(inner))}")`;
|
|
122
|
+
} else {
|
|
123
|
+
replacement = `url("${toDataUri(resolved.rel, bytes)}${resolved.suffix}")`;
|
|
124
|
+
}
|
|
125
|
+
out.push(css.slice(cursor, m.index), replacement);
|
|
126
|
+
cursor = m.index! + m[0].length;
|
|
127
|
+
}
|
|
128
|
+
out.push(css.slice(cursor));
|
|
129
|
+
return out.join("");
|
|
130
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { realpath } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { assertNotPpmDir, isCredentialPath } from "../../fs-path-guard.service.ts";
|
|
4
|
+
import { guardPreviewAsset, isInsideRoot } from "../../../server/helpers/preview-asset-guard.ts";
|
|
5
|
+
import { lstatOrNull } from "../design-paths.ts";
|
|
6
|
+
import { readDesignFileSafe, SafeWalkError } from "../design-safe-walk.ts";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* How the standalone-HTML export reads the files a page links: by path relative to the
|
|
10
|
+
* design folder, through the same guards as everything else that reads a design tree.
|
|
11
|
+
*
|
|
12
|
+
* A design is written by an agent, so a link in it can point anywhere. A file is read only
|
|
13
|
+
* when it is inside the design folder (or is the shared `../tokens.css`), is a web asset by
|
|
14
|
+
* extension, sits under no dot-directory, is a regular file and not a symlink, still resolves
|
|
15
|
+
* inside after `realpath`, is no credential path and not inside the PPM directory — and then
|
|
16
|
+
* through `readDesignFileSafe`, which re-checks the open handle. Everything else answers
|
|
17
|
+
* `refused`, never an exception, so one bad link costs one warning rather than the export.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export type ReadAssetResult =
|
|
21
|
+
| { ok: true; bytes: Uint8Array }
|
|
22
|
+
| { ok: false; reason: "missing" | "refused" | "too-large" };
|
|
23
|
+
|
|
24
|
+
/** `rel` is `/`-separated and relative to the design folder; `../tokens.css` is the one way out. */
|
|
25
|
+
export type ReadAsset = (rel: string, maxBytes: number) => Promise<ReadAssetResult>;
|
|
26
|
+
|
|
27
|
+
export const TOKENS_CSS_REL = "../tokens.css";
|
|
28
|
+
|
|
29
|
+
export function createDesignAssetReader(designDir: string, designsRoot: string): ReadAsset {
|
|
30
|
+
return async (rel, maxBytes) => {
|
|
31
|
+
const tokens = rel === TOKENS_CSS_REL;
|
|
32
|
+
const root = tokens ? designsRoot : designDir;
|
|
33
|
+
if (!tokens && (rel === "" || rel.includes("\0") || rel.includes("\\") || rel.split("/").some((s) => s === ".." || s.startsWith(".")))) {
|
|
34
|
+
return { ok: false, reason: "refused" };
|
|
35
|
+
}
|
|
36
|
+
const target = tokens ? join(designsRoot, "tokens.css") : resolve(designDir, ...rel.split("/"));
|
|
37
|
+
try {
|
|
38
|
+
if (!isInsideRoot(root, target)) return { ok: false, reason: "refused" };
|
|
39
|
+
guardPreviewAsset(target, root);
|
|
40
|
+
const st = await lstatOrNull(target);
|
|
41
|
+
if (!st) return { ok: false, reason: "missing" };
|
|
42
|
+
if (st.isSymbolicLink() || !st.isFile()) return { ok: false, reason: "refused" };
|
|
43
|
+
const real = await realpath(target);
|
|
44
|
+
if (!isInsideRoot(root, real) || isCredentialPath(target) || isCredentialPath(real)) return { ok: false, reason: "refused" };
|
|
45
|
+
assertNotPpmDir(real);
|
|
46
|
+
if (st.size > maxBytes) return { ok: false, reason: "too-large" };
|
|
47
|
+
return { ok: true, bytes: await readDesignFileSafe(target, maxBytes) };
|
|
48
|
+
} catch (e) {
|
|
49
|
+
if (e instanceof SafeWalkError && e.code === "ETOOBIG") return { ok: false, reason: "too-large" };
|
|
50
|
+
const code = (e as { code?: string }).code;
|
|
51
|
+
if (code === "ENOENT" || code === "ENOTDIR") return { ok: false, reason: "missing" };
|
|
52
|
+
const status = (e as { status?: number }).status;
|
|
53
|
+
if (status === 403 || code === "ELOOP" || code === "EACCES" || code === "EPERM") return { ok: false, reason: "refused" };
|
|
54
|
+
throw e;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
2
|
+
import { DesignError } from "../design-error.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Which page of a design `GET …/export/html?entry=` may export.
|
|
6
|
+
*
|
|
7
|
+
* Checked on the already-decoded query value, and deliberately stricter than a path join:
|
|
8
|
+
* a small character set (so `%`, `\`, `:` and NUL — the usual smuggling tools, including a
|
|
9
|
+
* second round of percent-encoding — are refused outright), no `..` and no segment starting
|
|
10
|
+
* with `.` (which rules out the design's own `.design/` working data), an `.html`/`.htm`
|
|
11
|
+
* name, and a result that still resolves inside the design folder. Pure: nothing touches
|
|
12
|
+
* the disk here; the export reads the file through the safe reader afterwards.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const EXPORT_ENTRY_RE = /^[A-Za-z0-9._/-]{1,200}\.html?$/;
|
|
16
|
+
|
|
17
|
+
export interface ExportEntry {
|
|
18
|
+
/** `/`-separated, relative to the design folder. */
|
|
19
|
+
rel: string;
|
|
20
|
+
abs: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const bad = (): DesignError => new DesignError(400, "EBADENTRY", "Invalid entry: expected an .html file inside the design");
|
|
24
|
+
|
|
25
|
+
export function validateExportEntry(raw: unknown, designDir: string): ExportEntry {
|
|
26
|
+
if (typeof raw !== "string" || !EXPORT_ENTRY_RE.test(raw)) throw bad();
|
|
27
|
+
const segments = raw.split("/");
|
|
28
|
+
if (segments.some((s) => s === "" || s === ".." || s.startsWith("."))) throw bad();
|
|
29
|
+
const abs = resolve(designDir, ...segments);
|
|
30
|
+
const rel = relative(designDir, abs);
|
|
31
|
+
if (rel === "" || rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) throw bad();
|
|
32
|
+
return { rel: rel.split(sep).join("/"), abs };
|
|
33
|
+
}
|