@youweichen/pi-harness 0.0.0-stage → 1.0.0
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/LICENSE +21 -0
- package/README.md +74 -2
- package/bin/pi-harness.mjs +1819 -0
- package/deploy/com.youweichen.pi-harness.plist +48 -0
- package/deploy/nginx-subpath.conf +88 -0
- package/deploy/pi-harness-task.xml +71 -0
- package/deploy/pi-harness.service +31 -0
- package/dist/server/agent-service.js +3051 -0
- package/dist/server/app-version.js +19 -0
- package/dist/server/attachments.js +526 -0
- package/dist/server/auth-file.js +61 -0
- package/dist/server/bg-servers.js +154 -0
- package/dist/server/client-eviction.js +19 -0
- package/dist/server/client-id.js +9 -0
- package/dist/server/client-state.js +202 -0
- package/dist/server/codemode-image-routes.js +36 -0
- package/dist/server/codemode-presentation.js +19 -0
- package/dist/server/component-updates.js +135 -0
- package/dist/server/context-breakdown.js +56 -0
- package/dist/server/control-socket.js +177 -0
- package/dist/server/conversation.js +65 -0
- package/dist/server/dir-browser.js +77 -0
- package/dist/server/editor-snapshot.js +38 -0
- package/dist/server/ensure-bash.js +80 -0
- package/dist/server/extension-display.js +23 -0
- package/dist/server/extensions-catalog.js +64 -0
- package/dist/server/extensions-model.js +46 -0
- package/dist/server/extensions-routes.js +255 -0
- package/dist/server/extensions-worker.js +187 -0
- package/dist/server/files-service.js +795 -0
- package/dist/server/index.js +1029 -0
- package/dist/server/markdown-images.js +42 -0
- package/dist/server/model-admin.js +801 -0
- package/dist/server/model-config-merge.js +32 -0
- package/dist/server/native-mcp-config.js +103 -0
- package/dist/server/native-mcp-presentation.js +12 -0
- package/dist/server/native-prompt-template.js +12 -0
- package/dist/server/native-tools.js +32 -0
- package/dist/server/node-sources.js +142 -0
- package/dist/server/node-workbench.js +668 -0
- package/dist/server/origin-policy.js +50 -0
- package/dist/server/patch-node-pty.js +96 -0
- package/dist/server/pi-environment.js +203 -0
- package/dist/server/plan/extension.js +74 -0
- package/dist/server/plan/progress.js +90 -0
- package/dist/server/plan/settings.js +41 -0
- package/dist/server/plan/state.js +113 -0
- package/dist/server/plugin-facilities.js +304 -0
- package/dist/server/plugin-updater.js +245 -0
- package/dist/server/plugins.js +712 -0
- package/dist/server/private-file.js +28 -0
- package/dist/server/process-utils.js +112 -0
- package/dist/server/prompt-delivery.js +80 -0
- package/dist/server/protocol-version.js +11 -0
- package/dist/server/protocol.js +6 -0
- package/dist/server/provider-auth.js +99 -0
- package/dist/server/query-cache.js +45 -0
- package/dist/server/recovery-state.js +37 -0
- package/dist/server/scm.js +459 -0
- package/dist/server/security-headers.js +24 -0
- package/dist/server/serialize.js +254 -0
- package/dist/server/session-file-read.js +225 -0
- package/dist/server/session-record-worker.js +21 -0
- package/dist/server/session-reload.js +13 -0
- package/dist/server/session-tree-controller.js +250 -0
- package/dist/server/session-tree.js +191 -0
- package/dist/server/settings-service.js +53 -0
- package/dist/server/skills-service.js +87 -0
- package/dist/server/slash-commands.js +280 -0
- package/dist/server/sqlite-preview.js +58 -0
- package/dist/server/sqlite-query.js +67 -0
- package/dist/server/sqlite-worker.js +12 -0
- package/dist/server/system-prompt-files.js +158 -0
- package/dist/server/system-prompt-routes.js +40 -0
- package/dist/server/system-prompt-view.js +49 -0
- package/dist/server/task-progress.js +233 -0
- package/dist/server/terminals.js +833 -0
- package/dist/server/text-sniff.js +269 -0
- package/dist/server/thinking-timing.js +91 -0
- package/dist/server/token-auth.js +37 -0
- package/dist/server/tool-output.js +97 -0
- package/dist/server/tool-text-incidents.js +82 -0
- package/dist/server/tool-text.js +67 -0
- package/dist/server/uploads.js +112 -0
- package/dist/server/user-attachments.js +96 -0
- package/dist/server/webui-context.js +257 -0
- package/dist/server/wiki-links.js +136 -0
- package/dist/server/wiki-pdf-worker.js +23 -0
- package/dist/server/wiki-pdf.js +36 -0
- package/dist/server/wiki-routes.js +177 -0
- package/dist/server/wiki-service.js +511 -0
- package/electron/main.mjs +607 -0
- package/extensions/webui.ts +192 -0
- package/package.json +122 -4
- package/web/dist/apple-touch-icon.png +0 -0
- package/web/dist/assets/NodeWorkbench-C4U1PldE.js +3 -0
- package/web/dist/assets/TerminalPanel-CWh6vw_N.js +2 -0
- package/web/dist/assets/abnfDiagram-VCTEODGH-D5Ti0Kpa.js +1 -0
- package/web/dist/assets/arc-DKJilLd6.js +1 -0
- package/web/dist/assets/architectureDiagram-5GKGNRK7-Cf0w38g-.js +36 -0
- package/web/dist/assets/blockDiagram-I7D4REHJ-BOTLWLIL.js +129 -0
- package/web/dist/assets/c4Diagram-7LVT6UL2-CLCCoJs3.js +38 -0
- package/web/dist/assets/channel-D8Hd7T4P.js +1 -0
- package/web/dist/assets/chunk-2Q5K7J3B-BHjga2Ge.js +1 -0
- package/web/dist/assets/chunk-5VM5RSS4-CQJ5VfDZ.js +15 -0
- package/web/dist/assets/chunk-F27PBJKO-C67qoPJH.js +1 -0
- package/web/dist/assets/chunk-IMKFNOWR-CgXXGwI8.js +231 -0
- package/web/dist/assets/chunk-JWPE2WC7-D0RPyByP.js +1 -0
- package/web/dist/assets/chunk-POPQ4Y6H-BeYC9s9x.js +1 -0
- package/web/dist/assets/chunk-SVP7TREG-eQPl4UBQ.js +88 -0
- package/web/dist/assets/chunk-TICWLB2K-DT73arPU.js +206 -0
- package/web/dist/assets/chunk-XXDRQBXY-B4FwQcP-.js +1 -0
- package/web/dist/assets/classDiagram-ZZMXUADV-B_btgYRB.js +1 -0
- package/web/dist/assets/classDiagram-v2-VYDZK3BY-B_btgYRB.js +1 -0
- package/web/dist/assets/cose-bilkent-JH36ORCC-Bnn5nlQN.js +1 -0
- package/web/dist/assets/cynefin-OW5HDTMX-CStWX9kE.js +178 -0
- package/web/dist/assets/cynefinDiagram-5FMLGOSQ-BMVHC03f.js +62 -0
- package/web/dist/assets/cytoscape.esm-Bch-eiPH.js +331 -0
- package/web/dist/assets/dagre-GXQ25YYZ-ClSaO4ml.js +4 -0
- package/web/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/web/dist/assets/diagram-S7CK7UJ4-C43LL08C.js +30 -0
- package/web/dist/assets/diagram-UQ7AKVKN-BPVn_ySW.js +41 -0
- package/web/dist/assets/diagram-VSXAHHWV-C34FFhRi.js +3 -0
- package/web/dist/assets/diagram-VX7I27RA-BRk4bncf.js +24 -0
- package/web/dist/assets/diagram-Z3DM3KII-O5hYPLEd.js +24 -0
- package/web/dist/assets/ebnfDiagram-PWID7BFC-DVGEBm99.js +1 -0
- package/web/dist/assets/erDiagram-RLTQ6QDP-M-BLpTEV.js +99 -0
- package/web/dist/assets/flowDiagram-HODETNUW-BwdLopEx.js +168 -0
- package/web/dist/assets/ganttDiagram-EL5Y4UJY-DYxx2ppA.js +292 -0
- package/web/dist/assets/gitGraphDiagram-WWUBYQGX-DUU0wMYB.js +106 -0
- package/web/dist/assets/index-CI2KfVSr.css +10 -0
- package/web/dist/assets/index-DQcpggFU.js +275 -0
- package/web/dist/assets/infoDiagram-27XIBGKW-CFaW5C0C.js +2 -0
- package/web/dist/assets/init-Gi6I4Gst.js +1 -0
- package/web/dist/assets/ishikawaDiagram-5VMMS53U--ENP1MTB.js +70 -0
- package/web/dist/assets/journeyDiagram-3NMN7TZE-DgnAzSTj.js +139 -0
- package/web/dist/assets/kanban-definition-UXKFOSKX-_STZN1vU.js +89 -0
- package/web/dist/assets/katex-C5jXJg4s.js +257 -0
- package/web/dist/assets/layout-CkUClkXt.js +1 -0
- package/web/dist/assets/linear-sYHiUOxa.js +1 -0
- package/web/dist/assets/markdown-vNTCZJ6d.js +51 -0
- package/web/dist/assets/mermaid.core-B8fKGWsc.js +312 -0
- package/web/dist/assets/mindmap-definition-YA3MSWOX-DP0BYOEx.js +96 -0
- package/web/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/web/dist/assets/pegDiagram-XKGWAZYB-DkWTmZre.js +1 -0
- package/web/dist/assets/pieDiagram-E7YTZNPT-DfZgMV4u.js +39 -0
- package/web/dist/assets/quadrantDiagram-AXDQQJYC-Djl4TT7q.js +7 -0
- package/web/dist/assets/railroadDiagram-O6MQD6OU-DbKF6zXn.js +1 -0
- package/web/dist/assets/react-BNj3n7jX.js +24 -0
- package/web/dist/assets/requirementDiagram-BXWQKSXE-idola5qb.js +84 -0
- package/web/dist/assets/sankeyDiagram-P5KCCOFB-KA0hQOle.js +40 -0
- package/web/dist/assets/sequenceDiagram-WJ2MYXX4-BXSKvxzP.js +162 -0
- package/web/dist/assets/sizeCapture-INFHLROL-C_Ewv3S5.js +1 -0
- package/web/dist/assets/stateDiagram-D77RDMKH-DIf5X8oo.js +1 -0
- package/web/dist/assets/stateDiagram-v2-MP3YSRHH-DYwe_2mB.js +1 -0
- package/web/dist/assets/swimlanes-42K2YHIH-Cx_Rc8M2.js +1 -0
- package/web/dist/assets/swimlanesDiagram-VR7AAH4N-52Y8tgRV.js +8 -0
- package/web/dist/assets/timeline-definition-24CTP7MA-BRrDhWVz.js +120 -0
- package/web/dist/assets/vennDiagram-4TSXK5OY-Ad6G0YwD.js +34 -0
- package/web/dist/assets/wardleyDiagram-VM6X3IG4-X6-ENpSi.js +78 -0
- package/web/dist/assets/xterm-6GBZ9nXN.css +32 -0
- package/web/dist/assets/xterm-D1D2FVe3.js +38 -0
- package/web/dist/assets/xychartDiagram-S5SC5T6Z-DhegNS6d.js +7 -0
- package/web/dist/brand-mark.svg +5 -0
- package/web/dist/favicon-32.png +0 -0
- package/web/dist/favicon.svg +5 -0
- package/web/dist/fonts/WIKI-FONTS.md +5 -0
- package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-600-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-sans/LICENSE +93 -0
- package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
- package/web/dist/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-400-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-500-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-600-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-700-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-800-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-ext-400-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-ext-500-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-ext-600-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-ext-700-normal.woff2 +0 -0
- package/web/dist/fonts/inter/inter-latin-ext-800-normal.woff2 +0 -0
- package/web/dist/fonts/jetbrains-mono/LICENSE +93 -0
- package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-500-normal.woff2 +0 -0
- package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-600-normal.woff2 +0 -0
- package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-ext-400-normal.woff2 +0 -0
- package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-ext-500-normal.woff2 +0 -0
- package/web/dist/fonts/jetbrains-mono/jetbrains-mono-latin-ext-600-normal.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/LICENSE +94 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-0.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-1.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-10.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-100.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-11.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-12.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-13.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-14.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-15.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-16.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-17.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-18.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-19.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-2.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-20.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-21.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-22.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-23.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-24.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-25.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-26.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-27.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-28.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-29.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-3.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-30.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-31.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-32.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-33.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-34.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-35.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-36.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-37.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-38.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-39.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-4.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-40.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-41.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-42.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-43.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-44.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-45.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-46.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-47.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-48.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-49.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-5.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-50.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-51.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-52.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-53.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-54.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-55.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-56.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-57.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-58.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-59.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-6.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-60.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-61.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-62.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-63.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-64.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-65.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-66.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-67.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-68.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-69.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-7.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-70.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-71.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-72.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-73.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-74.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-75.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-76.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-77.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-78.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-79.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-8.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-80.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-81.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-82.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-83.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-84.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-85.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-86.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-87.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-88.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-89.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-9.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-90.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-91.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-92.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-93.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-94.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-95.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-96.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-97.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-98.woff2 +0 -0
- package/web/dist/fonts/noto-serif-sc/noto-serif-sc-500-99.woff2 +0 -0
- package/web/dist/fonts/source-serif-4/LICENSE +93 -0
- package/web/dist/fonts/source-serif-4/source-serif-4-500-0.woff2 +0 -0
- package/web/dist/fonts/source-serif-4/source-serif-4-500-1.woff2 +0 -0
- package/web/dist/fonts/source-serif-4/source-serif-4-500-2.woff2 +0 -0
- package/web/dist/fonts/source-serif-4/source-serif-4-500-3.woff2 +0 -0
- package/web/dist/fonts/source-serif-4/source-serif-4-500-4.woff2 +0 -0
- package/web/dist/fonts/source-serif-4/source-serif-4-500-5.woff2 +0 -0
- package/web/dist/icon/1a-mark.svg +1 -0
- package/web/dist/icon.ico +0 -0
- package/web/dist/index.html +18 -0
- package/web/public/apple-touch-icon.png +0 -0
- package/web/public/brand-mark.svg +5 -0
- package/web/public/favicon-32.png +0 -0
- package/web/public/favicon.svg +5 -0
- package/web/public/fonts/WIKI-FONTS.md +5 -0
- package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-400-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-500-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-600-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-400-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-500-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-mono/ibm-plex-mono-latin-ext-600-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-sans/LICENSE +93 -0
- package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-400-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-500-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-600-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-400-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-500-normal.woff2 +0 -0
- package/web/public/fonts/ibm-plex-sans/ibm-plex-sans-latin-ext-600-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-400-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-500-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-600-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-700-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-800-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-ext-400-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-ext-500-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-ext-600-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-ext-700-normal.woff2 +0 -0
- package/web/public/fonts/inter/inter-latin-ext-800-normal.woff2 +0 -0
- package/web/public/fonts/jetbrains-mono/LICENSE +93 -0
- package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-500-normal.woff2 +0 -0
- package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-600-normal.woff2 +0 -0
- package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-ext-400-normal.woff2 +0 -0
- package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-ext-500-normal.woff2 +0 -0
- package/web/public/fonts/jetbrains-mono/jetbrains-mono-latin-ext-600-normal.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/LICENSE +94 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-0.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-1.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-10.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-100.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-11.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-12.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-13.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-14.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-15.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-16.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-17.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-18.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-19.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-2.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-20.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-21.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-22.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-23.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-24.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-25.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-26.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-27.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-28.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-29.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-3.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-30.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-31.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-32.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-33.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-34.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-35.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-36.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-37.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-38.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-39.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-4.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-40.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-41.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-42.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-43.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-44.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-45.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-46.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-47.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-48.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-49.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-5.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-50.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-51.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-52.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-53.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-54.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-55.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-56.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-57.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-58.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-59.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-6.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-60.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-61.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-62.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-63.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-64.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-65.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-66.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-67.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-68.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-69.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-7.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-70.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-71.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-72.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-73.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-74.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-75.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-76.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-77.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-78.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-79.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-8.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-80.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-81.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-82.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-83.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-84.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-85.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-86.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-87.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-88.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-89.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-9.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-90.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-91.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-92.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-93.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-94.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-95.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-96.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-97.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-98.woff2 +0 -0
- package/web/public/fonts/noto-serif-sc/noto-serif-sc-500-99.woff2 +0 -0
- package/web/public/fonts/source-serif-4/LICENSE +93 -0
- package/web/public/fonts/source-serif-4/source-serif-4-500-0.woff2 +0 -0
- package/web/public/fonts/source-serif-4/source-serif-4-500-1.woff2 +0 -0
- package/web/public/fonts/source-serif-4/source-serif-4-500-2.woff2 +0 -0
- package/web/public/fonts/source-serif-4/source-serif-4-500-3.woff2 +0 -0
- package/web/public/fonts/source-serif-4/source-serif-4-500-4.woff2 +0 -0
- package/web/public/fonts/source-serif-4/source-serif-4-500-5.woff2 +0 -0
- package/web/public/icon/1a-mark.svg +1 -0
- package/web/public/icon.ico +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export const isChatModelConfig = (model) => model.type === undefined || model.type === "chat";
|
|
2
|
+
/** A chat editor owns chat fields only; keep provider operations and typed models intact. */
|
|
3
|
+
export function mergeChatProvider(previous, config) {
|
|
4
|
+
const existing = Array.isArray(previous.models) ? previous.models : [];
|
|
5
|
+
const typed = existing.filter(model => !isChatModelConfig(model));
|
|
6
|
+
const ids = new Set();
|
|
7
|
+
const models = config.models.filter(model => model.id.trim()).map(model => {
|
|
8
|
+
const id = model.id.trim();
|
|
9
|
+
if (ids.has(id))
|
|
10
|
+
throw new Error(`Duplicate chat model ID: ${id}`);
|
|
11
|
+
ids.add(id);
|
|
12
|
+
const result = { ...existing.find(entry => entry.id === id && isChatModelConfig(entry)), id };
|
|
13
|
+
for (const key of ["name", "reasoning", "input", "contextWindow", "maxTokens"]) {
|
|
14
|
+
delete result[key];
|
|
15
|
+
const value = model[key];
|
|
16
|
+
if (value !== undefined && value !== "")
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
});
|
|
21
|
+
const result = { ...previous, models: [...models, ...typed] };
|
|
22
|
+
for (const key of ["name", "api", "baseUrl", "authHeader"]) {
|
|
23
|
+
delete result[key];
|
|
24
|
+
const value = config[key];
|
|
25
|
+
if (value !== undefined && value !== "")
|
|
26
|
+
result[key] = value;
|
|
27
|
+
}
|
|
28
|
+
// An empty key in an existing editor means retain the server-owned credential.
|
|
29
|
+
if (config.apiKey?.trim())
|
|
30
|
+
result.apiKey = config.apiKey.trim();
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { pathToFileURL } from "node:url";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, renameSync } from "node:fs";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { getAgentDir, ProjectTrustStore } from "@earendil-works/pi-coding-agent";
|
|
7
|
+
const sdkDirectory = createRequire(import.meta.url).resolve.paths("@earendil-works/pi-coding-agent")?.map(path => join(path, "@earendil-works/pi-coding-agent/dist/core/mcp-servers.js")).find(path => existsSync(path));
|
|
8
|
+
if (!sdkDirectory)
|
|
9
|
+
throw new Error("Pi MCP configuration validator missing");
|
|
10
|
+
const { validateMcpServerConfig } = await import(pathToFileURL(sdkDirectory).href);
|
|
11
|
+
const MASK = "••••••••";
|
|
12
|
+
function read(path) { try {
|
|
13
|
+
return readFileSync(path, "utf8");
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error.code === "ENOENT")
|
|
17
|
+
return "{}";
|
|
18
|
+
throw error;
|
|
19
|
+
} }
|
|
20
|
+
function version(raw) { return createHash("sha256").update(raw).digest("hex"); }
|
|
21
|
+
function transform(value, old, mask, secret = false) {
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return value.map((v, i) => transform(v, Array.isArray(old) ? old[i] : undefined, mask, secret));
|
|
24
|
+
if (value && typeof value === "object")
|
|
25
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, transform(v, old && typeof old === "object" ? old[k] : undefined, mask, secret || /secret|token|password|apiKey|headers|env/i.test(k))]));
|
|
26
|
+
if (secret && typeof value === "string") {
|
|
27
|
+
if (mask)
|
|
28
|
+
return value ? MASK : "";
|
|
29
|
+
if (value === MASK) {
|
|
30
|
+
if (typeof old !== "string")
|
|
31
|
+
throw new Error("Masked value has no existing secret");
|
|
32
|
+
return old;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
export class NativeMcpConfigService {
|
|
38
|
+
isTrusted(cwd) { return new ProjectTrustStore(getAgentDir()).get(cwd) === true; }
|
|
39
|
+
path(cwd, scope) { if (scope !== "global" && scope !== "project")
|
|
40
|
+
throw new Error("Invalid MCP configuration scope"); return scope === "global" ? join(getAgentDir(), "mcp.json") : join(cwd, ".pi", "mcp.json"); }
|
|
41
|
+
get(cwd, scope) {
|
|
42
|
+
const path = this.path(cwd, scope), raw = read(path), document = JSON.parse(raw);
|
|
43
|
+
if (!document || typeof document !== "object" || Array.isArray(document))
|
|
44
|
+
throw new Error("MCP configuration must be an object");
|
|
45
|
+
const inheritedAutoEnableCodemode = scope === "global" || JSON.parse(read(this.path(cwd, "global")))?.autoEnableCodemode !== false;
|
|
46
|
+
return { path, paths: { global: this.path(cwd, "global"), project: this.path(cwd, "project") }, scope, version: version(raw), document: transform(document, undefined, true), trusted: this.isTrusted(cwd), inheritedAutoEnableCodemode };
|
|
47
|
+
}
|
|
48
|
+
save(cwd, scope, expected, incoming) {
|
|
49
|
+
if (!incoming || typeof incoming !== "object" || Array.isArray(incoming))
|
|
50
|
+
throw new Error("MCP configuration must be an object");
|
|
51
|
+
const path = this.path(cwd, scope), raw = read(path);
|
|
52
|
+
if (version(raw) !== expected)
|
|
53
|
+
throw new Error("MCP configuration changed externally; refresh before saving");
|
|
54
|
+
const old = JSON.parse(raw);
|
|
55
|
+
const document = transform({ ...old, ...incoming }, old, false);
|
|
56
|
+
document.mcpServers ??= {};
|
|
57
|
+
if (!document.mcpServers || Array.isArray(document.mcpServers) || typeof document.mcpServers !== "object")
|
|
58
|
+
throw new Error("mcpServers must be an object");
|
|
59
|
+
if (document.autoEnableCodemode !== undefined && typeof document.autoEnableCodemode !== "boolean")
|
|
60
|
+
throw new Error("autoEnableCodemode must be a boolean");
|
|
61
|
+
for (const [name, config] of Object.entries(document.mcpServers)) {
|
|
62
|
+
let candidate = config;
|
|
63
|
+
if (scope === "project" && config && typeof config === "object" && !Array.isArray(config) && !["command", "url", "type"].some(key => Object.hasOwn(config, key))) {
|
|
64
|
+
if (Object.keys(config).some(key => !["enabled", "exposure", "toolExposure"].includes(key)))
|
|
65
|
+
throw new Error("Project overrides only allow enabled, exposure, and toolExposure");
|
|
66
|
+
const base = JSON.parse(read(this.path(cwd, "global"))).mcpServers?.[name];
|
|
67
|
+
if (!base)
|
|
68
|
+
throw new Error(`No global MCP server to override: ${name}`);
|
|
69
|
+
candidate = { ...base, ...config };
|
|
70
|
+
}
|
|
71
|
+
const result = validateMcpServerConfig(name, candidate);
|
|
72
|
+
if (typeof result === "string")
|
|
73
|
+
throw new Error(result);
|
|
74
|
+
if (scope === "project" && config.auth)
|
|
75
|
+
throw new Error("Provider authentication is allowed only in global MCP configuration");
|
|
76
|
+
}
|
|
77
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
78
|
+
writeFileSync(`${path}.webui.tmp`, JSON.stringify(document, null, 2) + "\n", { mode: 0o600 });
|
|
79
|
+
renameSync(`${path}.webui.tmp`, path);
|
|
80
|
+
return this.get(cwd, scope);
|
|
81
|
+
}
|
|
82
|
+
codemode(cwd, scope, effective = {}) {
|
|
83
|
+
const path = join(scope === "global" ? getAgentDir() : join(cwd, ".pi"), "settings.json"), raw = read(path);
|
|
84
|
+
const settings = JSON.parse(raw).codemode ?? {};
|
|
85
|
+
return { path, version: version(raw), mode: settings.mode ?? "on", inlineBudget: settings.inlineBudget ?? 3000, effectiveMode: effective.mode ?? "on", effectiveInlineBudget: effective.inlineBudget ?? 3000 };
|
|
86
|
+
}
|
|
87
|
+
saveCodemode(cwd, scope, expected, value) {
|
|
88
|
+
this.path(cwd, scope);
|
|
89
|
+
const path = this.codemode(cwd, scope).path, raw = read(path);
|
|
90
|
+
if (version(raw) !== expected)
|
|
91
|
+
throw new Error("Pi settings changed externally; refresh before saving");
|
|
92
|
+
const patch = value;
|
|
93
|
+
if (!patch || !["on", "only"].includes(String(patch.mode)) || !Number.isInteger(patch.inlineBudget) || Number(patch.inlineBudget) < 0 || Number(patch.inlineBudget) > 100000)
|
|
94
|
+
throw new Error("Invalid codemode settings");
|
|
95
|
+
const document = JSON.parse(raw);
|
|
96
|
+
document.codemode = { ...document.codemode, mode: patch.mode, inlineBudget: patch.inlineBudget };
|
|
97
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
98
|
+
writeFileSync(`${path}.webui.tmp`, JSON.stringify(document, null, 2) + "\n", { mode: 0o600 });
|
|
99
|
+
renameSync(`${path}.webui.tmp`, path);
|
|
100
|
+
}
|
|
101
|
+
log() { const path = join(getAgentDir(), "mcp.log"); return existsSync(path) ? read(path).slice(-32000) : ""; }
|
|
102
|
+
trust(cwd) { new ProjectTrustStore(getAgentDir()).set(cwd, true); }
|
|
103
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Pi's official non-TUI /mcp output is the status API in 1.0.4. Keep unknown lines visible. */
|
|
2
|
+
export function parseNativeMcpStatus(text) {
|
|
3
|
+
const servers = [];
|
|
4
|
+
for (const line of text.split("\n")) {
|
|
5
|
+
const match = /^([\w-]+): (needs sign-in|disabled|disconnected|connecting|connected|starting|failed|error)(.*)$/.exec(line);
|
|
6
|
+
if (match)
|
|
7
|
+
servers.push({ name: match[1], state: match[2] === "needs sign-in" ? "needs-auth" : match[2], toolCount: Number(/, (\d+) tools/.exec(match[3])?.[1] ?? 0), detail: line });
|
|
8
|
+
else if (/^\s+/.test(line) && servers.length)
|
|
9
|
+
servers[servers.length - 1].detail += `\n${line.trim()}`;
|
|
10
|
+
}
|
|
11
|
+
return servers;
|
|
12
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { getPackageDir, VERSION } from "@earendil-works/pi-coding-agent";
|
|
4
|
+
/** Internal API of pinned 1.0.4, located by the SDK itself in npm and desktop layouts. */
|
|
5
|
+
export async function expandNativeTemplate(text, templates) {
|
|
6
|
+
if (VERSION !== "1.0.4")
|
|
7
|
+
throw new Error("Unsupported native prompt template contract");
|
|
8
|
+
const module = await import(pathToFileURL(join(getPackageDir(), "dist/core/prompt-templates.js")).href);
|
|
9
|
+
if (typeof module.expandPromptTemplate !== "function")
|
|
10
|
+
throw new Error("Native prompt template adapter unavailable");
|
|
11
|
+
return module.expandPromptTemplate(text, templates);
|
|
12
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createPlanExtension } from "./plan/extension.js";
|
|
2
|
+
import { SettingsManager, createCodemodeExtension, createMcpExtension, createToolSearchExtension } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
const runOverrides = new WeakMap();
|
|
4
|
+
export function setConversationRunSettings(settings, values) {
|
|
5
|
+
const overrides = { ...runOverrides.get(settings), ...(typeof values.autoCompaction === "boolean" ? { compaction: { enabled: values.autoCompaction } } : {}), ...(typeof values.autoRetry === "boolean" ? { retry: { enabled: values.autoRetry } } : {}) };
|
|
6
|
+
runOverrides.set(settings, overrides);
|
|
7
|
+
}
|
|
8
|
+
/** A native manager with conversation-local overrides; native writes stay native. */
|
|
9
|
+
export function conversationSettings(cwd, agentDir) {
|
|
10
|
+
const settings = SettingsManager.create(cwd, agentDir);
|
|
11
|
+
const getCompactionEnabled = settings.getCompactionEnabled.bind(settings);
|
|
12
|
+
const getRetryEnabled = settings.getRetryEnabled.bind(settings);
|
|
13
|
+
const getDefaultTools = settings.getDefaultTools.bind(settings);
|
|
14
|
+
const defaultTools = SettingsManager.inMemory({ defaultTools: ["+codemode", "+tool_search"] }).getDefaultTools();
|
|
15
|
+
settings.getCompactionEnabled = () => runOverrides.get(settings)?.compaction?.enabled ?? getCompactionEnabled();
|
|
16
|
+
settings.getRetryEnabled = () => runOverrides.get(settings)?.retry?.enabled ?? getRetryEnabled();
|
|
17
|
+
settings.getDefaultTools = () => [...(getDefaultTools() ?? defaultTools)];
|
|
18
|
+
return settings;
|
|
19
|
+
}
|
|
20
|
+
/** Same native extensions as the Pi CLI; activation follows the user's settings. */
|
|
21
|
+
export function nativeToolExtensions() {
|
|
22
|
+
return [
|
|
23
|
+
{ name: "pi-harness-plan", replaceable: true, factory: createPlanExtension() },
|
|
24
|
+
{ name: "codemode", builtin: true, replaceable: true, factory: createCodemodeExtension() },
|
|
25
|
+
{ name: "tool-search", builtin: true, replaceable: true, factory: createToolSearchExtension() },
|
|
26
|
+
{ name: "mcp", builtin: true, replaceable: true, factory: createMcpExtension() },
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
/** Stable settings aliases for the SDK's named inline extension paths. */
|
|
30
|
+
export function nativeExtensionPath(path) {
|
|
31
|
+
return /^builtin:(mcp|tool-search|codemode)$/.test(path) ? `<inline:${path.slice(8)}>` : path;
|
|
32
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/** Read-only source adapters. Never read saved passwords or execute SSH config commands. */
|
|
2
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join, relative, resolve, isAbsolute } from "node:path";
|
|
4
|
+
import { homedir, userInfo } from "node:os";
|
|
5
|
+
import { decodeText } from "./text-sniff.js";
|
|
6
|
+
export function parseXshell(text, file) {
|
|
7
|
+
const sections = {};
|
|
8
|
+
let section = "";
|
|
9
|
+
for (const line of text.replace(/^\uFEFF/, "").split(/\r?\n/)) {
|
|
10
|
+
const header = line.trim().match(/^\[([^\]]+)\]$/);
|
|
11
|
+
if (header) {
|
|
12
|
+
section = header[1].toUpperCase();
|
|
13
|
+
sections[section] ??= {};
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
const pair = line.match(/^\s*([^=;#]+?)\s*=(.*)$/);
|
|
17
|
+
if (pair)
|
|
18
|
+
(sections[section] ??= {})[pair[1].toUpperCase()] = pair[2].trim();
|
|
19
|
+
}
|
|
20
|
+
const c = sections.CONNECTION ?? {}, a = sections["CONNECTION:AUTHENTICATION"] ?? {};
|
|
21
|
+
const host = c.HOST ?? "", port = Number(c.PORT || 22);
|
|
22
|
+
if (!host || /[\r\n\0]/.test(host) || !Number.isInteger(port) || port < 1 || port > 65535)
|
|
23
|
+
throw new Error(`${file}: 地址或端口无效`);
|
|
24
|
+
const unsupported = [];
|
|
25
|
+
if (c.PROTOCOL?.toUpperCase() !== "SSH")
|
|
26
|
+
unsupported.push("protocol");
|
|
27
|
+
for (const [name, values] of Object.entries(sections)) {
|
|
28
|
+
for (const [key, value] of Object.entries(values)) {
|
|
29
|
+
if ((/PROXY|JUMPHOST/.test(key) || /PROXY|JUMPHOST/.test(name)) && value && !/^(0|-1|none|false)$/i.test(value))
|
|
30
|
+
unsupported.push("proxy");
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (Object.entries(a).some(([key, value]) => /AUTH.*PROFILE/.test(key) && value && !/^(0|false|none)$/i.test(value)))
|
|
34
|
+
unsupported.push("authentication-profile");
|
|
35
|
+
const keyPath = a.USERKEY || a.PUBLICKEYFILE || a.PRIVATEKEY || undefined;
|
|
36
|
+
const auth = a.METHOD === "1" || keyPath ? "key" : "password";
|
|
37
|
+
if (a.METHOD && !["0", "1"].includes(a.METHOD))
|
|
38
|
+
unsupported.push("authentication");
|
|
39
|
+
if (!a.USERNAME)
|
|
40
|
+
unsupported.push("username");
|
|
41
|
+
if (auth === "key" && !keyPath)
|
|
42
|
+
unsupported.push("key");
|
|
43
|
+
return { name: basename(file).replace(/\.xsh$/i, ""), group: dirname(file) === "." ? "Xshell" : dirname(file), host, port, username: a.USERNAME || "", auth, keyPath, defaultDir: "/", sourceKey: file, unsupported: [...new Set(unsupported)] };
|
|
44
|
+
}
|
|
45
|
+
/** First obtained value wins, matching OpenSSH's Host ordering. Complex directives are blocked. */
|
|
46
|
+
export function parseSshConfig(text) {
|
|
47
|
+
const blocks = [{ patterns: ["*"], values: {} }];
|
|
48
|
+
let current = blocks[0];
|
|
49
|
+
const unsupported = new Set();
|
|
50
|
+
for (const line of text.split(/\r?\n/)) {
|
|
51
|
+
const m = line.trim().match(/^([^\s=#]+)(?:\s*=\s*|\s+)(.*)$/);
|
|
52
|
+
if (!m || m[1].startsWith("#"))
|
|
53
|
+
continue;
|
|
54
|
+
const key = m[1].toLowerCase();
|
|
55
|
+
const value = m[2].replace(/\s+#.*$/, "").trim().replace(/^"(.*)"$/, "$1");
|
|
56
|
+
if (key === "host") {
|
|
57
|
+
current = { patterns: value.split(/\s+/), values: {} };
|
|
58
|
+
blocks.push(current);
|
|
59
|
+
}
|
|
60
|
+
else if (key === "match" || key === "include")
|
|
61
|
+
unsupported.add(key);
|
|
62
|
+
else
|
|
63
|
+
current.values[key] ??= value;
|
|
64
|
+
}
|
|
65
|
+
const match = (pattern, alias) => new RegExp(`^${pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replaceAll("*", ".*").replaceAll("?", ".")}$`, "i").test(alias);
|
|
66
|
+
const aliases = [...new Set(blocks.flatMap((b) => b.patterns).filter((p) => !/[*!?]/.test(p)))];
|
|
67
|
+
return aliases.map((alias) => {
|
|
68
|
+
const v = {};
|
|
69
|
+
for (const b of blocks)
|
|
70
|
+
if (b.patterns.some((p) => !p.startsWith("!") && match(p, alias)) && !b.patterns.some((p) => p.startsWith("!") && match(p.slice(1), alias)))
|
|
71
|
+
for (const [k, val] of Object.entries(b.values))
|
|
72
|
+
v[k] ??= val;
|
|
73
|
+
const blocked = [...unsupported];
|
|
74
|
+
for (const key of ["proxyjump", "proxycommand", "localcommand", "remotecommand", "identityagent", "certificatefile", "localforward", "remoteforward", "dynamicforward"])
|
|
75
|
+
if (v[key] && v[key] !== "none")
|
|
76
|
+
blocked.push(key);
|
|
77
|
+
const port = Number(v.port || 22), host = v.hostname || alias;
|
|
78
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
79
|
+
throw new Error(`${alias}: 端口无效`);
|
|
80
|
+
if (host.includes("%") || v.identityfile?.includes("%"))
|
|
81
|
+
blocked.push("tokens");
|
|
82
|
+
return { name: alias, group: "SSH config", host, port, username: v.user || userInfo().username, auth: v.identityfile ? "key" : "agent", keyPath: v.identityfile, defaultDir: "/", sourceKey: alias, unsupported: blocked };
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async function readBounded(path) {
|
|
86
|
+
if ((await stat(path)).size > 1024 * 1024)
|
|
87
|
+
throw new Error("配置文件超过 1 MiB");
|
|
88
|
+
const bytes = await readFile(path);
|
|
89
|
+
if (bytes[0] === 0xff && bytes[1] === 0xfe)
|
|
90
|
+
return bytes.subarray(2).toString("utf16le");
|
|
91
|
+
return decodeText(bytes);
|
|
92
|
+
}
|
|
93
|
+
export async function scanSource(source) {
|
|
94
|
+
if (source.kind === "ssh") {
|
|
95
|
+
const nodes = parseSshConfig(await readBounded(source.path));
|
|
96
|
+
if (nodes.length > 200)
|
|
97
|
+
throw new Error("每个来源最多 200 个节点");
|
|
98
|
+
return nodes;
|
|
99
|
+
}
|
|
100
|
+
const nodes = [];
|
|
101
|
+
let visited = 0;
|
|
102
|
+
async function walk(dir, depth) {
|
|
103
|
+
if (depth > 12)
|
|
104
|
+
throw new Error("会话目录层级过深");
|
|
105
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
106
|
+
if (++visited > 4000)
|
|
107
|
+
throw new Error("会话目录文件过多");
|
|
108
|
+
const path = join(dir, entry.name);
|
|
109
|
+
if (entry.isDirectory())
|
|
110
|
+
await walk(path, depth + 1);
|
|
111
|
+
else if (entry.isFile() && /\.xsh$/i.test(entry.name)) {
|
|
112
|
+
const node = parseXshell(await readBounded(path), relative(source.path, path));
|
|
113
|
+
if (node.keyPath) {
|
|
114
|
+
node.keyPath = node.keyPath.replace(/%([^%]+)%/g, (original, name) => process.env[name] ?? original);
|
|
115
|
+
if (!isAbsolute(node.keyPath) && !node.keyPath.startsWith("~/"))
|
|
116
|
+
node.unsupported = [...node.unsupported ?? [], "key"];
|
|
117
|
+
}
|
|
118
|
+
nodes.push(node);
|
|
119
|
+
if (nodes.length > 200)
|
|
120
|
+
throw new Error("每个来源最多 200 个节点");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
await walk(source.path, 0);
|
|
125
|
+
return nodes;
|
|
126
|
+
}
|
|
127
|
+
export async function detectSources() {
|
|
128
|
+
const home = homedir();
|
|
129
|
+
const candidates = [{ kind: "ssh", path: join(home, ".ssh", "config") }];
|
|
130
|
+
if (process.platform === "win32")
|
|
131
|
+
for (const base of [join(home, "Documents"), ...(process.env.OneDrive ? [join(process.env.OneDrive, "Documents")] : [])])
|
|
132
|
+
candidates.unshift({ kind: "xshell", path: join(base, "NetSarang Computer", "8", "Xshell", "Sessions") });
|
|
133
|
+
const found = await Promise.all(candidates.map(async (source) => { try {
|
|
134
|
+
const nodes = await scanSource(source);
|
|
135
|
+
return { ...source, count: nodes.length, groups: new Set(nodes.map((n) => n.group)).size };
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null;
|
|
139
|
+
} }));
|
|
140
|
+
return found.filter((s) => s !== null);
|
|
141
|
+
}
|
|
142
|
+
export function sourcePath(value) { return resolve(value.startsWith("~/") ? join(homedir(), value.slice(2)) : value); }
|