openwork-server 0.18.49 → 0.18.56
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/README.md +31 -1
- package/bin/openwork-server.mjs +28 -20
- package/bin/platform.mjs +28 -0
- package/dist/opencode-plugin-deps-1.18.30.tgz +0 -0
- package/dist/opencode-plugins/agent-instruction-compose.js +81 -0
- package/dist/opencode-plugins/gmail-attachment-fulfillment.js +199 -0
- package/dist/opencode-plugins/managed-policy-client.js +39 -0
- package/dist/opencode-plugins/managed-policy-next.js +13894 -0
- package/dist/opencode-plugins/managed-policy.js +100 -0
- package/dist/opencode-plugins/openwork-anthropic-adaptive-thinking.js +83 -0
- package/dist/opencode-plugins/openwork-anthropic-tool-schema.js +154 -0
- package/dist/opencode-plugins/openwork-capabilities-knowledge.js +13842 -0
- package/dist/opencode-plugins/openwork-chrome-devtools.js +13690 -0
- package/dist/opencode-plugins/openwork-context-v2.js +84 -0
- package/dist/opencode-plugins/openwork-extensions-preview-steering.js +295 -0
- package/dist/opencode-plugins/openwork-extensions-preview.js +16388 -0
- package/dist/opencode-plugins/openwork-gateway-quota-v2.js +13816 -0
- package/dist/opencode-plugins/openwork-gateway-quota.js +14141 -0
- package/dist/opencode-plugins/openwork-mcp-results-v2.js +154 -0
- package/dist/opencode-plugins/openwork-office-attachments.js +3013 -0
- package/dist/opencode-plugins/openwork-pdf-attachments.js +23811 -0
- package/dist/opencode-plugins/openwork-provider-adapters.js +292 -0
- package/dist/opencode-plugins/openwork-provider-filters-v2.js +69 -0
- package/dist/opencode-plugins/openwork-read-transport.js +2 -0
- package/dist/opencode-plugins/openwork-spreadsheets.js +16582 -0
- package/dist/opencode-plugins/openwork-title-recovery.js +255 -0
- package/dist/opencode-plugins/openwork-ui-bridge.js +81 -0
- package/dist/opencode-plugins/pdfium.wasm +0 -0
- package/dist/opencode-plugins/session-activity.js +45 -0
- package/dist/opencode-plugins/workspace-file-identity.js +162 -0
- package/dist/openwork-server.mjs +114735 -0
- package/dist/pdfium.wasm +0 -0
- package/package.json +7 -1
- package/web/apple-touch-icon.png +0 -0
- package/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/web/assets/abap-BdImnpbu.js +1 -0
- package/web/assets/abnfDiagram-VCTEODGH-Dr1YMfll.js +1 -0
- package/web/assets/actionscript-3-CoDkCxhg.js +1 -0
- package/web/assets/ada-bCR0ucgS.js +1 -0
- package/web/assets/andromeeda-C4gqWexZ.js +1 -0
- package/web/assets/angular-html-DA-rfuFy.js +1 -0
- package/web/assets/angular-ts-BrjP3tb8.js +1 -0
- package/web/assets/apache-Pmp26Uib.js +1 -0
- package/web/assets/apex-D8_7TLub.js +1 -0
- package/web/assets/apl-CORt7UWP.js +1 -0
- package/web/assets/app-D9Nvta88.js +2631 -0
- package/web/assets/app-DOrYoP_4.css +32 -0
- package/web/assets/applescript-Co6uUVPk.js +1 -0
- package/web/assets/ara-BRHolxvo.js +1 -0
- package/web/assets/arc-7SoIBvT7.js +1 -0
- package/web/assets/architectureDiagram-5GKGNRK7-BZwevfH9.js +36 -0
- package/web/assets/artifact-code-view-WLwX_I1h.js +1906 -0
- package/web/assets/artifact-spreadsheet-editor-BvEnxKsm.js +11 -0
- package/web/assets/artifact-text-editor-BHyVrNyR.js +34 -0
- package/web/assets/asciidoc-Ve4PFQV2.js +1 -0
- package/web/assets/asm-D_Q5rh1f.js +1 -0
- package/web/assets/astro-HNnZUWAn.js +1 -0
- package/web/assets/aurora-x-D-2ljcwZ.js +1 -0
- package/web/assets/awk-DMzUqQB5.js +1 -0
- package/web/assets/ayu-dark-DYE7WIF3.js +1 -0
- package/web/assets/ayu-light-BA47KaF1.js +1 -0
- package/web/assets/ayu-mirage-32ctXXKs.js +1 -0
- package/web/assets/ballerina-BFfxhgS-.js +1 -0
- package/web/assets/bat-BkioyH1T.js +1 -0
- package/web/assets/beancount-k_qm7-4y.js +1 -0
- package/web/assets/berry-uYugtg8r.js +1 -0
- package/web/assets/bibtex-CHM0blh-.js +1 -0
- package/web/assets/bicep-Bmn6On1c.js +1 -0
- package/web/assets/bird2-BIv1doCn.js +1 -0
- package/web/assets/blade-BjGOyj-B.js +1 -0
- package/web/assets/blockDiagram-OSKFZWR5-Cvqr9DPi.js +129 -0
- package/web/assets/bsl-BO_Y6i37.js +1 -0
- package/web/assets/c-BIGW1oBm.js +1 -0
- package/web/assets/c3-eo99z4R2.js +1 -0
- package/web/assets/c4Diagram-7LVT6UL2-CWTWC9C1.js +38 -0
- package/web/assets/cadence-Bv_4Rxtq.js +1 -0
- package/web/assets/cairo-KRGpt6FW.js +1 -0
- package/web/assets/catppuccin-frappe-DFWUc33u.js +1 -0
- package/web/assets/catppuccin-latte-C9dUb6Cb.js +1 -0
- package/web/assets/catppuccin-macchiato-DQyhUUbL.js +1 -0
- package/web/assets/catppuccin-mocha-D87Tk5Gz.js +1 -0
- package/web/assets/channel-BkgEJbR-.js +1 -0
- package/web/assets/chunk-2Q5K7J3B-DpJkzZ5x.js +1 -0
- package/web/assets/chunk-5VM5RSS4-BtTBnr9m.js +15 -0
- package/web/assets/chunk-F27PBJKO-BbAvFJAg.js +1 -0
- package/web/assets/chunk-HLEWEB6X-DX5mKBrj.js +206 -0
- package/web/assets/chunk-JWPE2WC7-CugB1e5O.js +1 -0
- package/web/assets/chunk-POPQ4Y6H-BQ-bWmmo.js +1 -0
- package/web/assets/chunk-SVP7TREG-szCI_Kz9.js +88 -0
- package/web/assets/chunk-XXDRQBXY-C5UTO899.js +1 -0
- package/web/assets/chunk-ZLD2IHE6-D5v_jiDg.js +231 -0
- package/web/assets/clarity-D53aC0YG.js +1 -0
- package/web/assets/classDiagram-CYGNFDIV-BHINh3-f.js +1 -0
- package/web/assets/classDiagram-v2-TLXNO2FR-BHINh3-f.js +1 -0
- package/web/assets/clojure-P80f7IUj.js +1 -0
- package/web/assets/cmake-D1j8_8rp.js +1 -0
- package/web/assets/cobol-nBiQ_Alo.js +1 -0
- package/web/assets/codeowners-Bp6g37R7.js +1 -0
- package/web/assets/codeql-DsOJ9woJ.js +1 -0
- package/web/assets/coffee-Ch7k5sss.js +1 -0
- package/web/assets/common-lisp-Cg-RD9OK.js +1 -0
- package/web/assets/coq-DkFqJrB1.js +1 -0
- package/web/assets/cose-bilkent-JH36ORCC-BhG_zAfo.js +1 -0
- package/web/assets/cpp-CofmeUqb.js +1 -0
- package/web/assets/crystal-DNxU26gB.js +1 -0
- package/web/assets/csharp-COcwbKMJ.js +1 -0
- package/web/assets/css-CLj8gQPS.js +1 -0
- package/web/assets/csv-fuZLfV_i.js +1 -0
- package/web/assets/cue-D82EKSYY.js +1 -0
- package/web/assets/cynefin-OW5HDTMX-DSTjm6jO.js +178 -0
- package/web/assets/cynefinDiagram-5FMLGOSQ-Dqkgb6tF.js +62 -0
- package/web/assets/cypher-COkxafJQ.js +1 -0
- package/web/assets/cytoscape.esm-CNiYdHpY.js +331 -0
- package/web/assets/d-85-TOEBH.js +1 -0
- package/web/assets/dagre-OS7QT2EB-BZMseQyA.js +4 -0
- package/web/assets/dark-plus-C3mMm8J8.js +1 -0
- package/web/assets/dart-bE4Kk8sk.js +1 -0
- package/web/assets/dax-CEL-wOlO.js +1 -0
- package/web/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/web/assets/desktop-BmXAJ9_W.js +1 -0
- package/web/assets/diagram-S7CK7UJ4-Cs2hsmEJ.js +30 -0
- package/web/assets/diagram-UQ7AKVKN-CDnRP_yz.js +41 -0
- package/web/assets/diagram-VSXAHHWV-DxKXQXAC.js +3 -0
- package/web/assets/diagram-VX7I27RA-BJKoseDf.js +24 -0
- package/web/assets/diagram-Z3DM3KII-DDcMvRxo.js +24 -0
- package/web/assets/diff-D97Zzqfu.js +1 -0
- package/web/assets/docker-BcOcwvcX.js +1 -0
- package/web/assets/dotenv-Da5cRb03.js +1 -0
- package/web/assets/dracula-BzJJZx-M.js +1 -0
- package/web/assets/dracula-soft-BXkSAIEj.js +1 -0
- package/web/assets/dream-maker-BtqSS_iP.js +1 -0
- package/web/assets/ebnfDiagram-PWID7BFC-C2uUm-CC.js +1 -0
- package/web/assets/edge-FbVlp4U3.js +1 -0
- package/web/assets/elixir-CkH2-t6x.js +1 -0
- package/web/assets/elm-DbKCFpqz.js +1 -0
- package/web/assets/emacs-lisp-CXvaQtF9.js +1 -0
- package/web/assets/erDiagram-2YWLMYGG-B0Mdv5WO.js +99 -0
- package/web/assets/erb-BYCe7drp.js +1 -0
- package/web/assets/erlang-DsQrWhSR.js +1 -0
- package/web/assets/everforest-dark-BgDCqdQA.js +1 -0
- package/web/assets/everforest-light-C8M2exoo.js +1 -0
- package/web/assets/fennel-BYunw83y.js +1 -0
- package/web/assets/fish-BvzEVeQv.js +1 -0
- package/web/assets/flowDiagram-T62WH6J4-CUnt9AMo.js +168 -0
- package/web/assets/fluent-C4IJs8-o.js +1 -0
- package/web/assets/fortran-fixed-form-CkoXwp7k.js +1 -0
- package/web/assets/fortran-free-form-BxgE0vQu.js +1 -0
- package/web/assets/fsharp-CXgrBDvD.js +1 -0
- package/web/assets/ganttDiagram-EL5Y4UJY-CENsUToC.js +292 -0
- package/web/assets/gdresource-BOOCDP_w.js +1 -0
- package/web/assets/gdscript-C5YyOfLZ.js +1 -0
- package/web/assets/gdshader-DkwncUOv.js +1 -0
- package/web/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/web/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/web/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/web/assets/genie-D0YGMca9.js +1 -0
- package/web/assets/gherkin-DyxjwDmM.js +1 -0
- package/web/assets/git-commit-F4YmCXRG.js +1 -0
- package/web/assets/git-rebase-r7XF79zn.js +1 -0
- package/web/assets/gitGraphDiagram-WWUBYQGX-CrbKh94B.js +106 -0
- package/web/assets/github-dark-DHJKELXO.js +1 -0
- package/web/assets/github-dark-default-Cuk6v7N8.js +1 -0
- package/web/assets/github-dark-dimmed-DH5Ifo-i.js +1 -0
- package/web/assets/github-dark-high-contrast-E3gJ1_iC.js +1 -0
- package/web/assets/github-light-DAi9KRSo.js +1 -0
- package/web/assets/github-light-default-D7oLnXFd.js +1 -0
- package/web/assets/github-light-high-contrast-BfjtVDDH.js +1 -0
- package/web/assets/gleam-BspZqrRM.js +1 -0
- package/web/assets/glimmer-js-ByusRIyA.js +1 -0
- package/web/assets/glimmer-ts-BfAWNZQY.js +1 -0
- package/web/assets/glsl-DplSGwfg.js +1 -0
- package/web/assets/gn-n2N0HUVH.js +1 -0
- package/web/assets/gnuplot-DdkO51Og.js +1 -0
- package/web/assets/go-C27-OAKa.js +1 -0
- package/web/assets/graphql-ChdNCCLP.js +1 -0
- package/web/assets/groovy-gcz8RCvz.js +1 -0
- package/web/assets/gruvbox-dark-hard-CFHQjOhq.js +1 -0
- package/web/assets/gruvbox-dark-medium-GsRaNv29.js +1 -0
- package/web/assets/gruvbox-dark-soft-CVdnzihN.js +1 -0
- package/web/assets/gruvbox-light-hard-CH1njM8p.js +1 -0
- package/web/assets/gruvbox-light-medium-DRw_LuNl.js +1 -0
- package/web/assets/gruvbox-light-soft-hJgmCMqR.js +1 -0
- package/web/assets/hack-i7_Ulhet.js +1 -0
- package/web/assets/haml-D5jkg6IW.js +1 -0
- package/web/assets/handlebars-BpdQsYii.js +1 -0
- package/web/assets/haskell-Df6bDoY_.js +1 -0
- package/web/assets/haxe-CzTSHFRz.js +1 -0
- package/web/assets/hcl-BWvSN4gD.js +1 -0
- package/web/assets/hjson-D5-asLiD.js +1 -0
- package/web/assets/hlsl-D3lLCCz7.js +1 -0
- package/web/assets/horizon-BUw7H-hv.js +1 -0
- package/web/assets/horizon-bright-CUuTKBJd.js +1 -0
- package/web/assets/houston-DnULxvSX.js +1 -0
- package/web/assets/html-derivative-DlHx6ybY.js +1 -0
- package/web/assets/html-pp8916En.js +1 -0
- package/web/assets/http-jrhK8wxY.js +1 -0
- package/web/assets/hurl-irOxFIW8.js +1 -0
- package/web/assets/hxml-Bvhsp5Yf.js +1 -0
- package/web/assets/hy-DFXneXwc.js +1 -0
- package/web/assets/ibm-plex-sans-cyrillic-ext-wght-normal-d45eAU9y.woff2 +0 -0
- package/web/assets/ibm-plex-sans-cyrillic-wght-normal-BAAhND-U.woff2 +0 -0
- package/web/assets/ibm-plex-sans-greek-wght-normal-CmyJS8uq.woff2 +0 -0
- package/web/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
- package/web/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
- package/web/assets/ibm-plex-sans-vietnamese-wght-normal-Dg1JeJN0.woff2 +0 -0
- package/web/assets/imba-DGztddWO.js +1 -0
- package/web/assets/index-CyyMNIC_.css +1 -0
- package/web/assets/index-D6FUvVB1.js +49 -0
- package/web/assets/infoDiagram-FKFFQAWI-B-U-x_qU.js +2 -0
- package/web/assets/ini-BEwlwnbL.js +1 -0
- package/web/assets/init-Gi6I4Gst.js +1 -0
- package/web/assets/ishikawaDiagram-5VMMS53U-jNVSJSu1.js +70 -0
- package/web/assets/java-CylS5w8V.js +1 -0
- package/web/assets/javascript-wDzz0qaB.js +1 -0
- package/web/assets/jinja-f2NsQr07.js +1 -0
- package/web/assets/jison-wvAkD_A8.js +1 -0
- package/web/assets/journeyDiagram-EYS64GPL-De3j0gPh.js +139 -0
- package/web/assets/json-Cp-IABpG.js +1 -0
- package/web/assets/json5-C9tS-k6U.js +1 -0
- package/web/assets/jsonc-Des-eS-w.js +1 -0
- package/web/assets/jsonl-DcaNXYhu.js +1 -0
- package/web/assets/jsonnet-DFQXde-d.js +1 -0
- package/web/assets/jssm-C2t-YnRu.js +1 -0
- package/web/assets/jsx-g9-lgVsj.js +1 -0
- package/web/assets/julia-CxzCAyBv.js +1 -0
- package/web/assets/just-VxiPbLrw.js +1 -0
- package/web/assets/kanagawa-dragon-CkXjmgJE.js +1 -0
- package/web/assets/kanagawa-lotus-CfQXZHmo.js +1 -0
- package/web/assets/kanagawa-wave-DWedfzmr.js +1 -0
- package/web/assets/kanban-definition-UXKFOSKX-Bbc8wjhq.js +89 -0
- package/web/assets/katex-HP8lGamR.js +257 -0
- package/web/assets/kdl-DV7GczEv.js +1 -0
- package/web/assets/kotlin-BdnUsdx6.js +1 -0
- package/web/assets/kusto-wEQ09or8.js +1 -0
- package/web/assets/laserwave-DUszq2jm.js +1 -0
- package/web/assets/latex-CWtU0Tv5.js +1 -0
- package/web/assets/layout-BIjP2nup.js +1 -0
- package/web/assets/lean-BZvkOJ9d.js +1 -0
- package/web/assets/less-B1dDrJ26.js +1 -0
- package/web/assets/light-plus-B7mTdjB0.js +1 -0
- package/web/assets/linear-lvQZOiHM.js +1 -0
- package/web/assets/liquid-C0sCDyMI.js +1 -0
- package/web/assets/llvm-DjAJT7YJ.js +1 -0
- package/web/assets/log-2UxHyX5q.js +1 -0
- package/web/assets/logo-BtOb2qkB.js +1 -0
- package/web/assets/lua-BaeVxFsk.js +1 -0
- package/web/assets/luau-C-HG3fhB.js +1 -0
- package/web/assets/make-CHLpvVh8.js +1 -0
- package/web/assets/markdown-Cvjx9yec.js +1 -0
- package/web/assets/marko-DjSrsDqO.js +1 -0
- package/web/assets/material-theme-D5KoaKCx.js +1 -0
- package/web/assets/material-theme-darker-BfHTSMKl.js +1 -0
- package/web/assets/material-theme-lighter-B0m2ddpp.js +1 -0
- package/web/assets/material-theme-ocean-CyktbL80.js +1 -0
- package/web/assets/material-theme-palenight-Csfq5Kiy.js +1 -0
- package/web/assets/matlab-D7o27uSR.js +1 -0
- package/web/assets/mdc-DTYItulj.js +1 -0
- package/web/assets/mdx-Cmh6b_Ma.js +1 -0
- package/web/assets/mermaid-mWjccvbQ.js +1 -0
- package/web/assets/mermaid.core-LJPf4T7o.js +310 -0
- package/web/assets/min-dark-CafNBF8u.js +1 -0
- package/web/assets/min-light-CTRr51gU.js +1 -0
- package/web/assets/mindmap-definition-THT77NOG-DiboHsg8.js +96 -0
- package/web/assets/mipsasm-CKIfxQSi.js +1 -0
- package/web/assets/mojo-rZm6bMo-.js +1 -0
- package/web/assets/monokai-D4h5O-jR.js +1 -0
- package/web/assets/moonbit-_H4v1dQx.js +1 -0
- package/web/assets/move-IF9eRakj.js +1 -0
- package/web/assets/narrat-DRg8JJMk.js +1 -0
- package/web/assets/nextflow-C-mBbutL.js +1 -0
- package/web/assets/nextflow-groovy-vE_lwT2v.js +1 -0
- package/web/assets/nginx-BpAMiNFr.js +1 -0
- package/web/assets/night-owl-C39BiMTA.js +1 -0
- package/web/assets/night-owl-light-CMTm3GFP.js +1 -0
- package/web/assets/nim-BIad80T-.js +1 -0
- package/web/assets/nix-CwoSXNpI.js +1 -0
- package/web/assets/nord-Ddv68eIx.js +1 -0
- package/web/assets/nushell-Cz2AlsmD.js +1 -0
- package/web/assets/objective-c-DXmwc3jG.js +1 -0
- package/web/assets/objective-cpp-CLxacb5B.js +1 -0
- package/web/assets/ocaml-C0hk2d4L.js +1 -0
- package/web/assets/odin-BBf5iR-q.js +1 -0
- package/web/assets/one-dark-pro-DVMEJ2y_.js +1 -0
- package/web/assets/one-light-C3Wv6jpd.js +1 -0
- package/web/assets/openscad-C4EeE6gA.js +1 -0
- package/web/assets/ordinal-Cboi1Yqb.js +1 -0
- package/web/assets/overlay-DA5SOee-.js +1 -0
- package/web/assets/pascal-D93ZcfNL.js +1 -0
- package/web/assets/pegDiagram-XKGWAZYB-DO_edVtr.js +1 -0
- package/web/assets/perl-NvoQZIq0.js +1 -0
- package/web/assets/php-R6g_5hLQ.js +1 -0
- package/web/assets/pieDiagram-E7YTZNPT-bPvBuBuG.js +39 -0
- package/web/assets/pierre-dark-CyvmCCZW.js +1 -0
- package/web/assets/pierre-dark-protanopia-deuteranopia-Rgc0TwpF.js +1 -0
- package/web/assets/pierre-dark-soft-BHGpRqa4.js +1 -0
- package/web/assets/pierre-dark-tritanopia-Beq2gCRQ.js +1 -0
- package/web/assets/pierre-dark-vibrant-BWBVywrn.js +1 -0
- package/web/assets/pierre-light-480U9XYS.js +1 -0
- package/web/assets/pierre-light-protanopia-deuteranopia-CaVOBURG.js +1 -0
- package/web/assets/pierre-light-soft-CVdyfjmI.js +1 -0
- package/web/assets/pierre-light-tritanopia-B4_gpKOM.js +1 -0
- package/web/assets/pierre-light-vibrant-DdTDNdfJ.js +1 -0
- package/web/assets/pkl-u5AG7uiY.js +1 -0
- package/web/assets/plastic-3e1v2bzS.js +1 -0
- package/web/assets/plsql-ChMvpjG-.js +1 -0
- package/web/assets/po-BTJTHyun.js +1 -0
- package/web/assets/poimandres-CS3Unz2-.js +1 -0
- package/web/assets/polar-C0HS_06l.js +1 -0
- package/web/assets/postcss-CXtECtnM.js +1 -0
- package/web/assets/powerquery-CEu0bR-o.js +1 -0
- package/web/assets/powershell-Dpen1YoG.js +1 -0
- package/web/assets/prisma-Dd19v3D-.js +1 -0
- package/web/assets/prolog-CbFg5uaA.js +1 -0
- package/web/assets/proto-C7zT0LnQ.js +1 -0
- package/web/assets/pug-DKIMFp6K.js +1 -0
- package/web/assets/puppet-BMWR74SV.js +1 -0
- package/web/assets/purescript-CklMAg4u.js +1 -0
- package/web/assets/python-B6aJPvgy.js +1 -0
- package/web/assets/qml-3beO22l8.js +1 -0
- package/web/assets/qmldir-C8lEn-DE.js +1 -0
- package/web/assets/qss-IeuSbFQv.js +1 -0
- package/web/assets/quadrantDiagram-AXDQQJYC-BGyrQhlH.js +7 -0
- package/web/assets/r-Dspwwk_N.js +1 -0
- package/web/assets/racket-BqYA7rlc.js +1 -0
- package/web/assets/railroadDiagram-O6MQD6OU-XhPIuoOE.js +1 -0
- package/web/assets/raku-DXvB9xmW.js +1 -0
- package/web/assets/razor-BDqjjVU7.js +1 -0
- package/web/assets/red-bN70gL4F.js +1 -0
- package/web/assets/reg-C-SQnVFl.js +1 -0
- package/web/assets/regexp-CDVJQ6XC.js +1 -0
- package/web/assets/rel-C3B-1QV4.js +1 -0
- package/web/assets/requirementDiagram-IS5BZ75X-atdASt4G.js +84 -0
- package/web/assets/riscv-BM1_JUlF.js +1 -0
- package/web/assets/ron-D8l8udqQ.js +1 -0
- package/web/assets/rose-pine-dawn-DHQR4-dF.js +1 -0
- package/web/assets/rose-pine-moon-D4_iv3hh.js +1 -0
- package/web/assets/rose-pine-qdsjHGoJ.js +1 -0
- package/web/assets/rosmsg-BJDFO7_C.js +1 -0
- package/web/assets/rst-CRjBmOyv.js +1 -0
- package/web/assets/ruby-Wjq7vjNf.js +1 -0
- package/web/assets/rust-B1yitclQ.js +1 -0
- package/web/assets/sankeyDiagram-P5KCCOFB-BV9prEKy.js +40 -0
- package/web/assets/sas-cz2c8ADy.js +1 -0
- package/web/assets/sass-Cj5Yp3dK.js +1 -0
- package/web/assets/scala-C151Ov-r.js +1 -0
- package/web/assets/scheme-C98Dy4si.js +1 -0
- package/web/assets/scss-D5BDwBP9.js +1 -0
- package/web/assets/sdbl-DVxCFoDh.js +1 -0
- package/web/assets/sequenceDiagram-WJ2MYXX4-Csfm-fZ-.js +162 -0
- package/web/assets/shaderlab-Dg9Lc6iA.js +1 -0
- package/web/assets/shellscript-Yzrsuije.js +1 -0
- package/web/assets/shellsession-BADoaaVG.js +1 -0
- package/web/assets/sizeCapture-INFHLROL-CLmH-AjF.js +1 -0
- package/web/assets/slack-dark-BthQWCQV.js +1 -0
- package/web/assets/slack-ochin-DqwNpetd.js +1 -0
- package/web/assets/smalltalk-BERRCDM3.js +1 -0
- package/web/assets/snazzy-light-Bw305WKR.js +1 -0
- package/web/assets/solarized-dark-DXbdFlpD.js +1 -0
- package/web/assets/solarized-light-L9t79GZl.js +1 -0
- package/web/assets/solidity-rGO070M0.js +1 -0
- package/web/assets/soy-8wufbnw4.js +1 -0
- package/web/assets/sparql-rVzFXLq3.js +1 -0
- package/web/assets/splunk-BtCnVYZw.js +1 -0
- package/web/assets/sql-BLtJtn59.js +1 -0
- package/web/assets/ssh-config-_ykCGR6B.js +1 -0
- package/web/assets/stata-BH5u7GGu.js +1 -0
- package/web/assets/stateDiagram-XQSTLZYL-yiSt2fJK.js +1 -0
- package/web/assets/stateDiagram-v2-IH3M54BS-BEhxOujx.js +1 -0
- package/web/assets/stylus-BEDo0Tqx.js +1 -0
- package/web/assets/surrealql-Bq5Q-fJD.js +1 -0
- package/web/assets/svelte-Cy7k_4gC.js +1 -0
- package/web/assets/swift-D82vCrfD.js +1 -0
- package/web/assets/swimlanes-V6O3JKXN-BpXNggx9.js +1 -0
- package/web/assets/swimlanesDiagram-JKAHXJPX-DWqwFv9F.js +8 -0
- package/web/assets/synthwave-84-CbfX1IO0.js +1 -0
- package/web/assets/system-verilog-CnnmHF94.js +1 -0
- package/web/assets/systemd-4A_iFExJ.js +1 -0
- package/web/assets/talonscript-CkByrt1z.js +1 -0
- package/web/assets/tasl-QIJgUcNo.js +1 -0
- package/web/assets/tcl-dwOrl1Do.js +1 -0
- package/web/assets/templ-DhtptRzy.js +1 -0
- package/web/assets/terraform-BETggiCN.js +1 -0
- package/web/assets/tex-idrVyKtj.js +1 -0
- package/web/assets/timeline-definition-24CTP7MA-C8X71OnL.js +120 -0
- package/web/assets/tokyo-night-hegEt444.js +1 -0
- package/web/assets/toml-vGWfd6FD.js +1 -0
- package/web/assets/ts-tags-DQrlYJgV.js +1 -0
- package/web/assets/tsv-B_m7g4N7.js +1 -0
- package/web/assets/tsx-COt5Ahok.js +1 -0
- package/web/assets/turtle-BsS91CYL.js +1 -0
- package/web/assets/twig-xg9kU7Mw.js +1 -0
- package/web/assets/typescript-BPQ3VLAy.js +1 -0
- package/web/assets/typespec-CAFt9gP4.js +1 -0
- package/web/assets/typst-DHCkPAjA.js +1 -0
- package/web/assets/v-BcVCzyr7.js +1 -0
- package/web/assets/vala-CsfeWuGM.js +1 -0
- package/web/assets/vb-D17OF-Vu.js +1 -0
- package/web/assets/vennDiagram-4TSXK5OY-BZo-99ra.js +34 -0
- package/web/assets/verilog-BQ8w6xss.js +1 -0
- package/web/assets/vesper-DU1UobuO.js +1 -0
- package/web/assets/vhdl-CeAyd5Ju.js +1 -0
- package/web/assets/viml-CJc9bBzg.js +1 -0
- package/web/assets/vitesse-black-Bkuqu6BP.js +1 -0
- package/web/assets/vitesse-dark-D0r3Knsf.js +1 -0
- package/web/assets/vitesse-light-CVO1_9PV.js +1 -0
- package/web/assets/vue-D2xRrEX4.js +1 -0
- package/web/assets/vue-html-AaS7Mt5G.js +1 -0
- package/web/assets/vue-vine-BoDAl6tE.js +1 -0
- package/web/assets/vyper-CDx5xZoG.js +1 -0
- package/web/assets/wardleyDiagram-VM6X3IG4-BHwH6ZLg.js +78 -0
- package/web/assets/wasm-CG6Dc4jp.js +1 -0
- package/web/assets/wasm-MzD3tlZU.js +1 -0
- package/web/assets/wenyan-BV7otONQ.js +1 -0
- package/web/assets/wgsl-Dx-B1_4e.js +1 -0
- package/web/assets/wikitext-BhOHFoWU.js +1 -0
- package/web/assets/wit-5i3qLPDT.js +1 -0
- package/web/assets/wolfram-lXgVvXCa.js +1 -0
- package/web/assets/workspace-file-tree-C8iSfvPt.js +1278 -0
- package/web/assets/xml-sdJ4AIDG.js +1 -0
- package/web/assets/xsl-CtQFsRM5.js +1 -0
- package/web/assets/xychartDiagram-S5SC5T6Z-BieEi319.js +7 -0
- package/web/assets/yaml-Buea-lGh.js +1 -0
- package/web/assets/zenscript-DVFEvuxE.js +1 -0
- package/web/assets/zig-VOosw3JB.js +1 -0
- package/web/ext-context7.svg +1 -0
- package/web/ext-github.svg +1 -0
- package/web/ext-google-workspace.svg +6 -0
- package/web/ext-hubspot.svg +1 -0
- package/web/ext-linear.svg +1 -0
- package/web/ext-notion.svg +1 -0
- package/web/ext-ollama.svg +1 -0
- package/web/ext-openai.svg +1 -0
- package/web/ext-sentry.svg +1 -0
- package/web/ext-slack.svg +1 -0
- package/web/ext-stripe.svg +1 -0
- package/web/favicon-16x16.png +0 -0
- package/web/favicon-32x32.png +0 -0
- package/web/grain-art/extension/extension-001.png +0 -0
- package/web/grain-art/extension/extension-002.png +0 -0
- package/web/grain-art/extension/extension-003.png +0 -0
- package/web/grain-art/extension/extension-004.png +0 -0
- package/web/grain-art/extension/extension-005.png +0 -0
- package/web/grain-art/extension/extension-006.png +0 -0
- package/web/grain-art/extension/extension-007.png +0 -0
- package/web/grain-art/extension/extension-008.png +0 -0
- package/web/grain-art/extension/extension-009.png +0 -0
- package/web/grain-art/extension/extension-010.png +0 -0
- package/web/grain-art/extension/extension-011.png +0 -0
- package/web/grain-art/extension/extension-012.png +0 -0
- package/web/grain-art/extension/extension-013.png +0 -0
- package/web/grain-art/extension/extension-014.png +0 -0
- package/web/grain-art/extension/extension-015.png +0 -0
- package/web/grain-art/extension/extension-016.png +0 -0
- package/web/grain-art/extension/extension-017.png +0 -0
- package/web/grain-art/extension/extension-018.png +0 -0
- package/web/grain-art/extension/extension-019.png +0 -0
- package/web/grain-art/extension/extension-020.png +0 -0
- package/web/grain-art/extension/extension-021.png +0 -0
- package/web/grain-art/extension/extension-022.png +0 -0
- package/web/grain-art/extension/extension-023.png +0 -0
- package/web/grain-art/extension/extension-024.png +0 -0
- package/web/grain-art/extension/extension-025.png +0 -0
- package/web/grain-art/extension/extension-026.png +0 -0
- package/web/grain-art/extension/extension-027.png +0 -0
- package/web/grain-art/extension/extension-028.png +0 -0
- package/web/grain-art/extension/extension-029.png +0 -0
- package/web/grain-art/extension/extension-030.png +0 -0
- package/web/grain-art/extension/extension-031.png +0 -0
- package/web/grain-art/extension/extension-032.png +0 -0
- package/web/grain-art/fallback/fallback-001.png +0 -0
- package/web/grain-art/fallback/fallback-002.png +0 -0
- package/web/grain-art/fallback/fallback-003.png +0 -0
- package/web/grain-art/fallback/fallback-004.png +0 -0
- package/web/grain-art/fallback/fallback-005.png +0 -0
- package/web/grain-art/fallback/fallback-006.png +0 -0
- package/web/grain-art/fallback/fallback-007.png +0 -0
- package/web/grain-art/fallback/fallback-008.png +0 -0
- package/web/grain-art/fallback/fallback-009.png +0 -0
- package/web/grain-art/fallback/fallback-010.png +0 -0
- package/web/grain-art/fallback/fallback-011.png +0 -0
- package/web/grain-art/fallback/fallback-012.png +0 -0
- package/web/grain-art/fallback/fallback-013.png +0 -0
- package/web/grain-art/fallback/fallback-014.png +0 -0
- package/web/grain-art/fallback/fallback-015.png +0 -0
- package/web/grain-art/fallback/fallback-016.png +0 -0
- package/web/grain-art/fallback/fallback-017.png +0 -0
- package/web/grain-art/fallback/fallback-018.png +0 -0
- package/web/grain-art/fallback/fallback-019.png +0 -0
- package/web/grain-art/fallback/fallback-020.png +0 -0
- package/web/grain-art/fallback/fallback-021.png +0 -0
- package/web/grain-art/fallback/fallback-022.png +0 -0
- package/web/grain-art/fallback/fallback-023.png +0 -0
- package/web/grain-art/fallback/fallback-024.png +0 -0
- package/web/grain-art/fallback/fallback-025.png +0 -0
- package/web/grain-art/fallback/fallback-026.png +0 -0
- package/web/grain-art/fallback/fallback-027.png +0 -0
- package/web/grain-art/fallback/fallback-028.png +0 -0
- package/web/grain-art/fallback/fallback-029.png +0 -0
- package/web/grain-art/fallback/fallback-030.png +0 -0
- package/web/grain-art/fallback/fallback-031.png +0 -0
- package/web/grain-art/fallback/fallback-032.png +0 -0
- package/web/grain-art/mcps/mcps-001.png +0 -0
- package/web/grain-art/mcps/mcps-002.png +0 -0
- package/web/grain-art/mcps/mcps-003.png +0 -0
- package/web/grain-art/mcps/mcps-004.png +0 -0
- package/web/grain-art/mcps/mcps-005.png +0 -0
- package/web/grain-art/mcps/mcps-006.png +0 -0
- package/web/grain-art/mcps/mcps-007.png +0 -0
- package/web/grain-art/mcps/mcps-008.png +0 -0
- package/web/grain-art/mcps/mcps-009.png +0 -0
- package/web/grain-art/mcps/mcps-010.png +0 -0
- package/web/grain-art/mcps/mcps-011.png +0 -0
- package/web/grain-art/mcps/mcps-012.png +0 -0
- package/web/grain-art/mcps/mcps-013.png +0 -0
- package/web/grain-art/mcps/mcps-014.png +0 -0
- package/web/grain-art/mcps/mcps-015.png +0 -0
- package/web/grain-art/mcps/mcps-016.png +0 -0
- package/web/grain-art/mcps/mcps-017.png +0 -0
- package/web/grain-art/mcps/mcps-018.png +0 -0
- package/web/grain-art/mcps/mcps-019.png +0 -0
- package/web/grain-art/mcps/mcps-020.png +0 -0
- package/web/grain-art/mcps/mcps-021.png +0 -0
- package/web/grain-art/mcps/mcps-022.png +0 -0
- package/web/grain-art/mcps/mcps-023.png +0 -0
- package/web/grain-art/mcps/mcps-024.png +0 -0
- package/web/grain-art/mcps/mcps-025.png +0 -0
- package/web/grain-art/mcps/mcps-026.png +0 -0
- package/web/grain-art/mcps/mcps-027.png +0 -0
- package/web/grain-art/mcps/mcps-028.png +0 -0
- package/web/grain-art/mcps/mcps-029.png +0 -0
- package/web/grain-art/mcps/mcps-030.png +0 -0
- package/web/grain-art/mcps/mcps-031.png +0 -0
- package/web/grain-art/mcps/mcps-032.png +0 -0
- package/web/grain-art/plugins/plugins-001.png +0 -0
- package/web/grain-art/plugins/plugins-002.png +0 -0
- package/web/grain-art/plugins/plugins-003.png +0 -0
- package/web/grain-art/plugins/plugins-004.png +0 -0
- package/web/grain-art/plugins/plugins-005.png +0 -0
- package/web/grain-art/plugins/plugins-006.png +0 -0
- package/web/grain-art/plugins/plugins-007.png +0 -0
- package/web/grain-art/plugins/plugins-008.png +0 -0
- package/web/grain-art/plugins/plugins-009.png +0 -0
- package/web/grain-art/plugins/plugins-010.png +0 -0
- package/web/grain-art/plugins/plugins-011.png +0 -0
- package/web/grain-art/plugins/plugins-012.png +0 -0
- package/web/grain-art/plugins/plugins-013.png +0 -0
- package/web/grain-art/plugins/plugins-014.png +0 -0
- package/web/grain-art/plugins/plugins-015.png +0 -0
- package/web/grain-art/plugins/plugins-016.png +0 -0
- package/web/grain-art/plugins/plugins-017.png +0 -0
- package/web/grain-art/plugins/plugins-018.png +0 -0
- package/web/grain-art/plugins/plugins-019.png +0 -0
- package/web/grain-art/plugins/plugins-020.png +0 -0
- package/web/grain-art/plugins/plugins-021.png +0 -0
- package/web/grain-art/plugins/plugins-022.png +0 -0
- package/web/grain-art/plugins/plugins-023.png +0 -0
- package/web/grain-art/plugins/plugins-024.png +0 -0
- package/web/grain-art/plugins/plugins-025.png +0 -0
- package/web/grain-art/plugins/plugins-026.png +0 -0
- package/web/grain-art/plugins/plugins-027.png +0 -0
- package/web/grain-art/plugins/plugins-028.png +0 -0
- package/web/grain-art/plugins/plugins-029.png +0 -0
- package/web/grain-art/plugins/plugins-030.png +0 -0
- package/web/grain-art/plugins/plugins-031.png +0 -0
- package/web/grain-art/plugins/plugins-032.png +0 -0
- package/web/grain-art/skills/skills-001.png +0 -0
- package/web/grain-art/skills/skills-002.png +0 -0
- package/web/grain-art/skills/skills-003.png +0 -0
- package/web/grain-art/skills/skills-004.png +0 -0
- package/web/grain-art/skills/skills-005.png +0 -0
- package/web/grain-art/skills/skills-006.png +0 -0
- package/web/grain-art/skills/skills-007.png +0 -0
- package/web/grain-art/skills/skills-008.png +0 -0
- package/web/grain-art/skills/skills-009.png +0 -0
- package/web/grain-art/skills/skills-010.png +0 -0
- package/web/grain-art/skills/skills-011.png +0 -0
- package/web/grain-art/skills/skills-012.png +0 -0
- package/web/grain-art/skills/skills-013.png +0 -0
- package/web/grain-art/skills/skills-014.png +0 -0
- package/web/grain-art/skills/skills-015.png +0 -0
- package/web/grain-art/skills/skills-016.png +0 -0
- package/web/grain-art/skills/skills-017.png +0 -0
- package/web/grain-art/skills/skills-018.png +0 -0
- package/web/grain-art/skills/skills-019.png +0 -0
- package/web/grain-art/skills/skills-020.png +0 -0
- package/web/grain-art/skills/skills-021.png +0 -0
- package/web/grain-art/skills/skills-022.png +0 -0
- package/web/grain-art/skills/skills-023.png +0 -0
- package/web/grain-art/skills/skills-024.png +0 -0
- package/web/grain-art/skills/skills-025.png +0 -0
- package/web/grain-art/skills/skills-026.png +0 -0
- package/web/grain-art/skills/skills-027.png +0 -0
- package/web/grain-art/skills/skills-028.png +0 -0
- package/web/grain-art/skills/skills-029.png +0 -0
- package/web/grain-art/skills/skills-030.png +0 -0
- package/web/grain-art/skills/skills-031.png +0 -0
- package/web/grain-art/skills/skills-032.png +0 -0
- package/web/grain-art/workspaces/workspaces-001.png +0 -0
- package/web/grain-art/workspaces/workspaces-002.png +0 -0
- package/web/grain-art/workspaces/workspaces-003.png +0 -0
- package/web/grain-art/workspaces/workspaces-004.png +0 -0
- package/web/grain-art/workspaces/workspaces-005.png +0 -0
- package/web/grain-art/workspaces/workspaces-006.png +0 -0
- package/web/grain-art/workspaces/workspaces-007.png +0 -0
- package/web/grain-art/workspaces/workspaces-008.png +0 -0
- package/web/grain-art/workspaces/workspaces-009.png +0 -0
- package/web/grain-art/workspaces/workspaces-010.png +0 -0
- package/web/grain-art/workspaces/workspaces-011.png +0 -0
- package/web/grain-art/workspaces/workspaces-012.png +0 -0
- package/web/grain-art/workspaces/workspaces-013.png +0 -0
- package/web/grain-art/workspaces/workspaces-014.png +0 -0
- package/web/grain-art/workspaces/workspaces-015.png +0 -0
- package/web/grain-art/workspaces/workspaces-016.png +0 -0
- package/web/grain-art/workspaces/workspaces-017.png +0 -0
- package/web/grain-art/workspaces/workspaces-018.png +0 -0
- package/web/grain-art/workspaces/workspaces-019.png +0 -0
- package/web/grain-art/workspaces/workspaces-020.png +0 -0
- package/web/grain-art/workspaces/workspaces-021.png +0 -0
- package/web/grain-art/workspaces/workspaces-022.png +0 -0
- package/web/grain-art/workspaces/workspaces-023.png +0 -0
- package/web/grain-art/workspaces/workspaces-024.png +0 -0
- package/web/grain-art/workspaces/workspaces-025.png +0 -0
- package/web/grain-art/workspaces/workspaces-026.png +0 -0
- package/web/grain-art/workspaces/workspaces-027.png +0 -0
- package/web/grain-art/workspaces/workspaces-028.png +0 -0
- package/web/grain-art/workspaces/workspaces-029.png +0 -0
- package/web/grain-art/workspaces/workspaces-030.png +0 -0
- package/web/grain-art/workspaces/workspaces-031.png +0 -0
- package/web/grain-art/workspaces/workspaces-032.png +0 -0
- package/web/index.html +130 -0
- package/web/manifest.webmanifest +22 -0
- package/web/openwork-logo-square.svg +2 -0
- package/web/openwork-logo.svg +1 -0
- package/web/openwork-mark.svg +16 -0
- package/web/openwork-sidebar-mark.svg +17 -0
- package/web/overlay.html +29 -0
- package/dist/bin/openwork-server +0 -4
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toESMCache_node;
|
|
11
|
+
var __toESMCache_esm;
|
|
12
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
+
var canCache = mod != null && typeof mod === "object";
|
|
14
|
+
if (canCache) {
|
|
15
|
+
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
+
var cached = cache.get(mod);
|
|
17
|
+
if (cached)
|
|
18
|
+
return cached;
|
|
19
|
+
}
|
|
20
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
|
+
for (let key of __getOwnPropNames(mod))
|
|
23
|
+
if (!__hasOwnProp.call(to, key))
|
|
24
|
+
__defProp(to, key, {
|
|
25
|
+
get: __accessProp.bind(mod, key),
|
|
26
|
+
enumerable: true
|
|
27
|
+
});
|
|
28
|
+
if (canCache)
|
|
29
|
+
cache.set(mod, to);
|
|
30
|
+
return to;
|
|
31
|
+
};
|
|
32
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
+
var __returnValue = (v) => v;
|
|
34
|
+
function __exportSetter(name, newValue) {
|
|
35
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
36
|
+
}
|
|
37
|
+
var __export = (target, all) => {
|
|
38
|
+
for (var name in all)
|
|
39
|
+
__defProp(target, name, {
|
|
40
|
+
get: all[name],
|
|
41
|
+
enumerable: true,
|
|
42
|
+
configurable: true,
|
|
43
|
+
set: __exportSetter.bind(all, name)
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
47
|
+
|
|
48
|
+
// src/opencode-plugins/openwork-title-recovery.ts
|
|
49
|
+
var HEADER = "x-openwork-title-attempt";
|
|
50
|
+
var DEADLINE_MS = 60000;
|
|
51
|
+
var MAX_ERROR_BYTES = 16384;
|
|
52
|
+
var attempts = new Map;
|
|
53
|
+
var installed = false;
|
|
54
|
+
function record(value) {
|
|
55
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
56
|
+
}
|
|
57
|
+
function report(attempt, outcome, status, parameter) {
|
|
58
|
+
attempt.diagnostic = {
|
|
59
|
+
...attempt.diagnostic,
|
|
60
|
+
outcome,
|
|
61
|
+
recoveryAttempt: attempt.retried ? 2 : 1,
|
|
62
|
+
...status === undefined ? {} : { status },
|
|
63
|
+
...parameter === undefined ? {} : { parameter }
|
|
64
|
+
};
|
|
65
|
+
attempt.report(attempt.diagnostic);
|
|
66
|
+
}
|
|
67
|
+
function finish(id) {
|
|
68
|
+
const attempt = attempts.get(id);
|
|
69
|
+
if (attempt)
|
|
70
|
+
clearTimeout(attempt.timer);
|
|
71
|
+
attempts.delete(id);
|
|
72
|
+
}
|
|
73
|
+
async function errorBody(response) {
|
|
74
|
+
const reader = response.clone().body?.getReader();
|
|
75
|
+
if (!reader)
|
|
76
|
+
return null;
|
|
77
|
+
let size = 0;
|
|
78
|
+
let text = "";
|
|
79
|
+
const decoder = new TextDecoder;
|
|
80
|
+
try {
|
|
81
|
+
while (true) {
|
|
82
|
+
const chunk = await reader.read();
|
|
83
|
+
if (chunk.done)
|
|
84
|
+
break;
|
|
85
|
+
size += chunk.value.byteLength;
|
|
86
|
+
if (size > MAX_ERROR_BYTES)
|
|
87
|
+
return null;
|
|
88
|
+
text += decoder.decode(chunk.value, { stream: true });
|
|
89
|
+
}
|
|
90
|
+
return JSON.parse(text + decoder.decode());
|
|
91
|
+
} catch {
|
|
92
|
+
return null;
|
|
93
|
+
} finally {
|
|
94
|
+
reader.cancel().catch(() => {
|
|
95
|
+
return;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function correction(body, value) {
|
|
100
|
+
if (!record(value) || !record(value.error))
|
|
101
|
+
return null;
|
|
102
|
+
const error = value.error;
|
|
103
|
+
if (error.code !== "unsupported_value" && error.code !== "unsupported_parameter")
|
|
104
|
+
return null;
|
|
105
|
+
const parameter = error.param;
|
|
106
|
+
if (parameter !== "reasoning.effort" && parameter !== "reasoning_effort" && parameter !== "temperature" && parameter !== "top_p")
|
|
107
|
+
return null;
|
|
108
|
+
let parsed;
|
|
109
|
+
try {
|
|
110
|
+
parsed = JSON.parse(body);
|
|
111
|
+
} catch {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
if (!record(parsed))
|
|
115
|
+
return null;
|
|
116
|
+
const target = parameter === "reasoning.effort" ? parsed.reasoning : parsed;
|
|
117
|
+
const key = parameter === "reasoning.effort" ? "effort" : parameter;
|
|
118
|
+
if (!record(target) || !Object.hasOwn(target, key))
|
|
119
|
+
return null;
|
|
120
|
+
const message = typeof error.message === "string" ? error.message : "";
|
|
121
|
+
const supported = /Supported values are:\s*([^\n]+)/i.exec(message)?.[1] ?? "";
|
|
122
|
+
const efforts = new Set([...supported.matchAll(/['"](none|minimal|low|medium|high|xhigh|max)['"]/g)].map((match) => match[1]));
|
|
123
|
+
const effort = ["low", "minimal", "medium", "high", "xhigh", "max", "none"].find((candidate) => efforts.has(candidate) && candidate !== target[key]);
|
|
124
|
+
if ((parameter === "reasoning.effort" || parameter === "reasoning_effort") && effort)
|
|
125
|
+
target[key] = effort;
|
|
126
|
+
else
|
|
127
|
+
delete target[key];
|
|
128
|
+
return { body: JSON.stringify(parsed), parameter };
|
|
129
|
+
}
|
|
130
|
+
function failure(status) {
|
|
131
|
+
if (status === 401 || status === 403)
|
|
132
|
+
return "access_rejected";
|
|
133
|
+
if (status === 404)
|
|
134
|
+
return "model_or_endpoint_missing";
|
|
135
|
+
if (status === 429)
|
|
136
|
+
return "rate_or_quota_limited";
|
|
137
|
+
if (status === 400 || status === 422)
|
|
138
|
+
return "request_rejected";
|
|
139
|
+
return "provider_error";
|
|
140
|
+
}
|
|
141
|
+
function install() {
|
|
142
|
+
if (installed)
|
|
143
|
+
return;
|
|
144
|
+
installed = true;
|
|
145
|
+
const base = globalThis.fetch;
|
|
146
|
+
const patched = async (input, init) => {
|
|
147
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : undefined));
|
|
148
|
+
const id = headers.get(HEADER);
|
|
149
|
+
if (!id)
|
|
150
|
+
return base(input, init);
|
|
151
|
+
headers.delete(HEADER);
|
|
152
|
+
const externalSignal = init?.signal ?? (input instanceof Request ? input.signal : undefined);
|
|
153
|
+
const deadline = AbortSignal.timeout(DEADLINE_MS);
|
|
154
|
+
const options = { ...init, headers, signal: externalSignal ? AbortSignal.any([externalSignal, deadline]) : deadline };
|
|
155
|
+
const attempt = attempts.get(id);
|
|
156
|
+
if (!attempt)
|
|
157
|
+
return base(input, options);
|
|
158
|
+
try {
|
|
159
|
+
const response = await base(input, options);
|
|
160
|
+
if (!response.ok) {
|
|
161
|
+
report(attempt, failure(response.status), response.status);
|
|
162
|
+
if (!attempt.retried && response.status === 400 && typeof init?.body === "string") {
|
|
163
|
+
const recovered = correction(init.body, await errorBody(response));
|
|
164
|
+
if (recovered && attempts.get(id) === attempt && !options.signal.aborted) {
|
|
165
|
+
attempt.retried = true;
|
|
166
|
+
report(attempt, "retrying_parameter", response.status, recovered.parameter);
|
|
167
|
+
response.body?.cancel().catch(() => {
|
|
168
|
+
return;
|
|
169
|
+
});
|
|
170
|
+
const retryHeaders = new Headers(headers);
|
|
171
|
+
retryHeaders.delete("content-length");
|
|
172
|
+
const retry = await base(input, { ...options, headers: retryHeaders, body: recovered.body });
|
|
173
|
+
report(attempt, retry.ok ? "accepted_after_recovery" : failure(retry.status), retry.status);
|
|
174
|
+
return retry;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} else
|
|
178
|
+
report(attempt, "accepted", response.status);
|
|
179
|
+
return response;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
report(attempt, externalSignal?.aborted ? "cancelled" : deadline.aborted ? "timed_out" : "transport_failed");
|
|
182
|
+
throw error;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
globalThis.fetch = Object.assign(patched, base);
|
|
186
|
+
}
|
|
187
|
+
var OpenWorkTitleRecovery = async (input) => {
|
|
188
|
+
install();
|
|
189
|
+
const owned = new Set;
|
|
190
|
+
const emit = (diagnostic) => {
|
|
191
|
+
const level = ["started", "accepted", "accepted_after_recovery", "title_available"].includes(diagnostic.outcome) ? "info" : "warn";
|
|
192
|
+
input.client.app.log({ body: {
|
|
193
|
+
service: "openwork.title",
|
|
194
|
+
level,
|
|
195
|
+
message: "Automatic title generation",
|
|
196
|
+
extra: diagnostic
|
|
197
|
+
} }).catch(() => {
|
|
198
|
+
return;
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
return {
|
|
202
|
+
"chat.headers": async (request, output) => {
|
|
203
|
+
if (request.agent !== "title")
|
|
204
|
+
return;
|
|
205
|
+
const id = crypto.randomUUID();
|
|
206
|
+
const diagnostic = {
|
|
207
|
+
sessionID: request.sessionID,
|
|
208
|
+
providerID: request.model.providerID,
|
|
209
|
+
modelID: request.model.id,
|
|
210
|
+
outcome: "started",
|
|
211
|
+
recoveryAttempt: 1
|
|
212
|
+
};
|
|
213
|
+
if (attempts.size >= 512) {
|
|
214
|
+
emit({ ...diagnostic, outcome: "tracking_capacity_reached" });
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const timer = setTimeout(() => {
|
|
218
|
+
const attempt = attempts.get(id);
|
|
219
|
+
if (attempt && ["started", "accepted", "accepted_after_recovery"].includes(attempt.diagnostic.outcome)) {
|
|
220
|
+
report(attempt, "title_unconfirmed");
|
|
221
|
+
}
|
|
222
|
+
finish(id);
|
|
223
|
+
owned.delete(id);
|
|
224
|
+
}, DEADLINE_MS);
|
|
225
|
+
timer.unref?.();
|
|
226
|
+
attempts.set(id, { diagnostic, report: emit, timer, retried: false });
|
|
227
|
+
owned.add(id);
|
|
228
|
+
output.headers[HEADER] = id;
|
|
229
|
+
emit(diagnostic);
|
|
230
|
+
},
|
|
231
|
+
event: async ({ event }) => {
|
|
232
|
+
if (event.type !== "session.updated" || !record(event.properties) || !record(event.properties.info))
|
|
233
|
+
return;
|
|
234
|
+
const info = event.properties.info;
|
|
235
|
+
if (typeof info.title !== "string" || !info.title.trim() || info.title.startsWith("New session - "))
|
|
236
|
+
return;
|
|
237
|
+
for (const id of owned) {
|
|
238
|
+
const attempt = attempts.get(id);
|
|
239
|
+
if (!attempt || attempt.diagnostic.sessionID !== info.id)
|
|
240
|
+
continue;
|
|
241
|
+
report(attempt, "title_available");
|
|
242
|
+
finish(id);
|
|
243
|
+
owned.delete(id);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
dispose: async () => {
|
|
247
|
+
for (const id of owned)
|
|
248
|
+
finish(id);
|
|
249
|
+
owned.clear();
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
export {
|
|
254
|
+
OpenWorkTitleRecovery
|
|
255
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir, platform } from "node:os";
|
|
4
|
+
let cachedBridge = null;
|
|
5
|
+
let cachedBridgeAt = 0;
|
|
6
|
+
let cachedBridgeDiscovery;
|
|
7
|
+
const BRIDGE_CACHE_MS = 2_000;
|
|
8
|
+
const BRIDGE_TIMEOUT_MS = 5_000;
|
|
9
|
+
function userAppDataDir() {
|
|
10
|
+
if (platform() === "darwin")
|
|
11
|
+
return join(homedir(), "Library", "Application Support");
|
|
12
|
+
if (platform() === "win32")
|
|
13
|
+
return process.env.APPDATA || join(homedir(), "AppData", "Roaming");
|
|
14
|
+
return process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
15
|
+
}
|
|
16
|
+
function uiControlDiscoveryPaths() {
|
|
17
|
+
const explicit = process.env.OPENWORK_UI_CONTROL_DISCOVERY?.trim();
|
|
18
|
+
if (explicit)
|
|
19
|
+
return [explicit];
|
|
20
|
+
return [
|
|
21
|
+
join(userAppDataDir(), "com.differentai.openwork", "openwork-ui-control.json"),
|
|
22
|
+
join(userAppDataDir(), "com.differentai.openwork.dev", "openwork-ui-control.json"),
|
|
23
|
+
].filter((p) => Boolean(p));
|
|
24
|
+
}
|
|
25
|
+
async function discoverUiBridge() {
|
|
26
|
+
// A changed discovery override points at a different desktop; never reuse
|
|
27
|
+
// the bridge cached for the previous one.
|
|
28
|
+
const discovery = process.env.OPENWORK_UI_CONTROL_DISCOVERY?.trim();
|
|
29
|
+
if (cachedBridge && cachedBridgeDiscovery === discovery && Date.now() - cachedBridgeAt < BRIDGE_CACHE_MS)
|
|
30
|
+
return cachedBridge;
|
|
31
|
+
cachedBridge = null;
|
|
32
|
+
for (const candidate of uiControlDiscoveryPaths()) {
|
|
33
|
+
try {
|
|
34
|
+
const raw = await readFile(candidate, "utf8");
|
|
35
|
+
const parsed = JSON.parse(raw);
|
|
36
|
+
if (typeof parsed.baseUrl === "string" && typeof parsed.token === "string") {
|
|
37
|
+
const url = new URL(parsed.baseUrl);
|
|
38
|
+
if (url.protocol !== "http:" || !["127.0.0.1", "localhost", "[::1]"].includes(url.hostname) || url.username || url.password)
|
|
39
|
+
continue;
|
|
40
|
+
cachedBridge = { baseUrl: parsed.baseUrl, token: parsed.token };
|
|
41
|
+
cachedBridgeAt = Date.now();
|
|
42
|
+
cachedBridgeDiscovery = discovery;
|
|
43
|
+
return cachedBridge;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Try next
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
export async function uiBridgeRequest(path, options = {}) {
|
|
53
|
+
const bridge = await discoverUiBridge();
|
|
54
|
+
if (!bridge)
|
|
55
|
+
return { ok: false, code: "browser_unavailable", dispatched: false, error: "The built-in browser is unavailable. Open the desktop app on the same machine as this task's server." };
|
|
56
|
+
try {
|
|
57
|
+
const response = await fetch(`${bridge.baseUrl}${path}`, {
|
|
58
|
+
method: options.method || "GET",
|
|
59
|
+
redirect: "error",
|
|
60
|
+
signal: options.signal ? AbortSignal.any([options.signal, AbortSignal.timeout(options.timeoutMs ?? BRIDGE_TIMEOUT_MS)]) : AbortSignal.timeout(options.timeoutMs ?? BRIDGE_TIMEOUT_MS),
|
|
61
|
+
headers: {
|
|
62
|
+
Authorization: `Bearer ${bridge.token}`,
|
|
63
|
+
...(options.body ? { "Content-Type": "application/json" } : {}),
|
|
64
|
+
},
|
|
65
|
+
...(options.body ? { body: JSON.stringify(options.body) } : {}),
|
|
66
|
+
});
|
|
67
|
+
const text = await response.text();
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(text);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return { ok: false, code: "browser_disconnected", mayHaveChangedState: true, retrySafe: false, error: "The browser returned no readable receipt. Inspect the page before retrying an action." };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
cachedBridge = null;
|
|
77
|
+
cachedBridgeAt = 0;
|
|
78
|
+
cachedBridgeDiscovery = undefined;
|
|
79
|
+
return { ok: false, code: "browser_disconnected", mayHaveChangedState: true, retrySafe: false, error: "The browser connection was interrupted. An action may already have run. Reconnect, list this conversation's tabs and observe before deciding what remains." };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const engineSessionStatusesSchema = z.record(z.string(), z.object({ type: z.string() }).passthrough());
|
|
3
|
+
const enginePendingRequestsSchema = z.array(z.object({ sessionID: z.string() }).passthrough());
|
|
4
|
+
export function sessionActivityFrom(statuses, permissions, questions, sessionId, descendantIds = [], unknownDescendants = 0) {
|
|
5
|
+
const parsedStatuses = engineSessionStatusesSchema.safeParse(statuses);
|
|
6
|
+
const parsedPermissions = enginePendingRequestsSchema.safeParse(permissions);
|
|
7
|
+
const parsedQuestions = enginePendingRequestsSchema.safeParse(questions);
|
|
8
|
+
const probesComplete = parsedStatuses.success && parsedPermissions.success && parsedQuestions.success;
|
|
9
|
+
const waiting = new Set([
|
|
10
|
+
...parsedPermissions.success ? parsedPermissions.data.map((request) => request.sessionID) : [],
|
|
11
|
+
...parsedQuestions.success ? parsedQuestions.data.map((request) => request.sessionID) : [],
|
|
12
|
+
]);
|
|
13
|
+
const statusFor = (id) => {
|
|
14
|
+
const type = parsedStatuses.success ? parsedStatuses.data[id]?.type : undefined;
|
|
15
|
+
if (type === "error")
|
|
16
|
+
return "error";
|
|
17
|
+
if (waiting.has(id) || type === "waiting")
|
|
18
|
+
return "waiting";
|
|
19
|
+
if (type === "busy" || type === "running")
|
|
20
|
+
return "busy";
|
|
21
|
+
if (type === "retry" || type === "compacting" || type === "thinking" || type === "responding")
|
|
22
|
+
return type;
|
|
23
|
+
return probesComplete && (type === undefined || type === "idle") ? "idle" : "unknown";
|
|
24
|
+
};
|
|
25
|
+
const descendantActivity = { busy: 0, waiting: 0, unknown: unknownDescendants };
|
|
26
|
+
for (const id of new Set(descendantIds)) {
|
|
27
|
+
if (id === sessionId)
|
|
28
|
+
continue;
|
|
29
|
+
const status = statusFor(id);
|
|
30
|
+
if (status === "unknown")
|
|
31
|
+
descendantActivity.unknown += 1;
|
|
32
|
+
else if (status === "waiting")
|
|
33
|
+
descendantActivity.waiting += 1;
|
|
34
|
+
else if (status !== "idle" && status !== "error")
|
|
35
|
+
descendantActivity.busy += 1;
|
|
36
|
+
}
|
|
37
|
+
const own = statusFor(sessionId);
|
|
38
|
+
return {
|
|
39
|
+
status: own !== "error" && descendantActivity.waiting > 0 ? "waiting" : own,
|
|
40
|
+
working: own !== "idle" && own !== "error" && own !== "unknown"
|
|
41
|
+
|| descendantActivity.busy > 0 || descendantActivity.waiting > 0,
|
|
42
|
+
descendantActivity,
|
|
43
|
+
inventoryComplete: probesComplete && own !== "unknown" && descendantActivity.unknown === 0,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { lstat, open, realpath, rm } from "node:fs/promises";
|
|
3
|
+
import { dirname, isAbsolute, relative } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Open-then-verify access to files under the workspace, shared by the plugins
|
|
6
|
+
* that read attachments or read and write workbooks.
|
|
7
|
+
*
|
|
8
|
+
* Node exposes neither openat nor O_RESOLVE_BENEATH, so any pathname is
|
|
9
|
+
* resolved again by every syscall and a directory under the workspace could
|
|
10
|
+
* be swapped for a link between two of them. These helpers therefore never
|
|
11
|
+
* decide anything from a pathname check that precedes a syscall. They obtain
|
|
12
|
+
* the file handle FIRST, then prove — from the handle's own inode — that it
|
|
13
|
+
* is the regular file sitting at exactly the requested path inside the real
|
|
14
|
+
* workspace root, with no symbolic link in any component and a real directory
|
|
15
|
+
* as its parent. Only a handle that passes is ever read from or written to.
|
|
16
|
+
*
|
|
17
|
+
* The one pathname-dependent effect that can survive a concurrent swap is the
|
|
18
|
+
* exclusive creation of an EMPTY file: O_EXCL can never replace an existing
|
|
19
|
+
* file, no content is written before the proof passes, callers restrict the
|
|
20
|
+
* name to an inert extension, and a misplaced empty inode is removed by
|
|
21
|
+
* identity. Overwrites open without O_CREAT and without O_TRUNC, so nothing
|
|
22
|
+
* changes until the handle is proven to be the very inode the caller decided
|
|
23
|
+
* to overwrite.
|
|
24
|
+
*/
|
|
25
|
+
const NO_FOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
26
|
+
export class WorkspaceFileError extends Error {
|
|
27
|
+
code;
|
|
28
|
+
constructor(code, message) {
|
|
29
|
+
super(message);
|
|
30
|
+
this.code = code;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function sameFile(left, right) {
|
|
34
|
+
return left.dev === right.dev && left.ino === right.ino;
|
|
35
|
+
}
|
|
36
|
+
function isWithin(root, candidate) {
|
|
37
|
+
const rel = relative(root, candidate);
|
|
38
|
+
return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Prove that an already-open handle refers to the regular file at exactly
|
|
42
|
+
* `path`: the directory entry at `path` is the handle's inode, `path` resolves
|
|
43
|
+
* to itself (no link in any component), its parent is a real directory that
|
|
44
|
+
* also resolves to itself, and everything sits under `realRoot`. Evaluated
|
|
45
|
+
* after the open, so a swap before the open fails the proof and a swap after
|
|
46
|
+
* it cannot redirect the handle.
|
|
47
|
+
*/
|
|
48
|
+
export async function proveHandleInPlace(actual, path, realRoot) {
|
|
49
|
+
if (!actual.isFile() || !isWithin(realRoot, path))
|
|
50
|
+
return false;
|
|
51
|
+
const folder = dirname(path);
|
|
52
|
+
const [placed, placedReal, folderNow, folderReal] = await Promise.all([
|
|
53
|
+
lstat(path).catch(() => null),
|
|
54
|
+
realpath(path).catch(() => null),
|
|
55
|
+
lstat(folder).catch(() => null),
|
|
56
|
+
realpath(folder).catch(() => null),
|
|
57
|
+
]);
|
|
58
|
+
return placed !== null && sameFile(placed, actual) && placedReal === path
|
|
59
|
+
&& folderNow !== null && folderNow.isDirectory() && folderReal === folder;
|
|
60
|
+
}
|
|
61
|
+
function errorCode(error) {
|
|
62
|
+
return typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : "";
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Fast path before the open: refuse a folder that is missing or that already
|
|
66
|
+
* resolves through a link. This is not the safety boundary (a swap after it
|
|
67
|
+
* is caught by the post-open proof); it keeps the ordinary case from creating
|
|
68
|
+
* even a transient empty inode through a link.
|
|
69
|
+
*/
|
|
70
|
+
async function refuseLinkedFolder(path, label, missingCode) {
|
|
71
|
+
const folder = dirname(path);
|
|
72
|
+
const folderReal = await realpath(folder).catch(() => null);
|
|
73
|
+
if (folderReal === null) {
|
|
74
|
+
throw new WorkspaceFileError(missingCode, missingCode === "missing" ? `${label} was not found in the workspace.` : `${label}: its folder does not exist.`);
|
|
75
|
+
}
|
|
76
|
+
if (folderReal !== folder)
|
|
77
|
+
throw new WorkspaceFileError("link", `${label} passes through a symbolic link, which is not allowed.`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Open a regular file for reading without following a link at any level and
|
|
81
|
+
* prove it is in place before returning the handle. The caller must close it.
|
|
82
|
+
*/
|
|
83
|
+
export async function openWorkspaceFileForReading(realRoot, path, label) {
|
|
84
|
+
await refuseLinkedFolder(path, label, "missing");
|
|
85
|
+
let handle;
|
|
86
|
+
try {
|
|
87
|
+
handle = await open(path, constants.O_RDONLY | NO_FOLLOW);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
const code = errorCode(error);
|
|
91
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
92
|
+
throw new WorkspaceFileError("missing", `${label} was not found in the workspace.`);
|
|
93
|
+
if (code === "ELOOP" || code === "EMLINK")
|
|
94
|
+
throw new WorkspaceFileError("link", `${label} passes through a symbolic link, which is not allowed.`);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const info = await handle.stat();
|
|
99
|
+
if (!info.isFile())
|
|
100
|
+
throw new WorkspaceFileError("not-file", `${label} is not a regular file.`);
|
|
101
|
+
if (!(await proveHandleInPlace(info, path, realRoot))) {
|
|
102
|
+
const real = await realpath(path).catch(() => null);
|
|
103
|
+
if (real !== null && real !== path)
|
|
104
|
+
throw new WorkspaceFileError("link", `${label} passes through a symbolic link, which is not allowed.`);
|
|
105
|
+
throw new WorkspaceFileError("changed", `${label} changed on disk while it was being opened; nothing was read. Try again.`);
|
|
106
|
+
}
|
|
107
|
+
return { handle, info, created: false };
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
await handle.close();
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Open a regular file for writing and prove it is in place before returning
|
|
116
|
+
* the handle. An existing file is opened without O_CREAT and without O_TRUNC
|
|
117
|
+
* and must be the inode the caller observed (`expected`); a new file is
|
|
118
|
+
* created with O_EXCL, which can never replace anything, and is removed by
|
|
119
|
+
* identity if it proves to have landed anywhere but at `path`. The caller
|
|
120
|
+
* truncates and writes through the returned handle, then closes it.
|
|
121
|
+
*/
|
|
122
|
+
export async function openWorkspaceFileForWriting(realRoot, path, expected, label) {
|
|
123
|
+
await refuseLinkedFolder(path, label, "folder-missing");
|
|
124
|
+
let handle;
|
|
125
|
+
try {
|
|
126
|
+
handle = expected
|
|
127
|
+
? await open(path, constants.O_WRONLY | NO_FOLLOW)
|
|
128
|
+
: await open(path, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | NO_FOLLOW, 0o644);
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
const code = errorCode(error);
|
|
132
|
+
if (code === "ENOENT" || code === "ENOTDIR")
|
|
133
|
+
throw new WorkspaceFileError("folder-missing", `${label}: its folder does not exist.`);
|
|
134
|
+
if (code === "EEXIST")
|
|
135
|
+
throw new WorkspaceFileError("exists", `${label} appeared on disk while it was being created; nothing was written. Try again.`);
|
|
136
|
+
if (code === "ELOOP" || code === "EMLINK")
|
|
137
|
+
throw new WorkspaceFileError("link", `${label} passes through a symbolic link, which is not allowed.`);
|
|
138
|
+
throw error;
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
const info = await handle.stat();
|
|
142
|
+
const inPlace = await proveHandleInPlace(info, path, realRoot) && (expected === null || sameFile(info, expected));
|
|
143
|
+
if (!inPlace) {
|
|
144
|
+
const real = await realpath(path).catch(() => null);
|
|
145
|
+
if (expected === null) {
|
|
146
|
+
// Our own empty inode may have been created through a swapped folder:
|
|
147
|
+
// remove it wherever the path currently leads, but only if it is ours.
|
|
148
|
+
const placed = await lstat(path).catch(() => null);
|
|
149
|
+
if (placed && sameFile(placed, info))
|
|
150
|
+
await rm(path, { force: true }).catch(() => undefined);
|
|
151
|
+
}
|
|
152
|
+
if (real !== null && real !== path)
|
|
153
|
+
throw new WorkspaceFileError("link", `${label} passes through a symbolic link, which is not allowed.`);
|
|
154
|
+
throw new WorkspaceFileError("changed", `${label} changed on disk while it was being opened; nothing was written. Try again.`);
|
|
155
|
+
}
|
|
156
|
+
return { handle, info, created: expected === null };
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
await handle.close();
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|