upfynai-code 0.1.0 → 2.2.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/client/dist/api-docs.html +879 -0
- package/client/dist/assets/AppContent-CTSHQdyq.js +513 -0
- package/client/dist/assets/CanvasPanel-Cig0Mo9s.js +6 -0
- package/client/dist/assets/CanvasPanel-q4HEqNtV.css +1 -0
- package/client/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/client/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/client/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/client/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/client/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/client/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/client/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/client/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/client/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/client/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/client/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/client/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/client/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/client/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/client/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/client/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/client/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/client/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/client/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/client/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/client/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/client/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/client/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/client/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/client/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/client/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/client/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/client/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/client/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/client/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/client/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/client/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/client/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/client/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/client/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/client/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/client/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/client/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/client/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/client/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/client/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/client/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/client/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/client/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/client/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/client/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/client/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/client/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/client/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/client/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/client/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/client/dist/assets/LoginModal-silya-zP.js +11 -0
- package/client/dist/assets/MarkdownPreview-B3c7OEj6.js +1 -0
- package/client/dist/assets/Onboarding-Coxo6mFA.js +1 -0
- package/client/dist/assets/SetupForm-BzYOsbji.js +1 -0
- package/client/dist/assets/Tableau10-B-NsZVaP.js +1 -0
- package/client/dist/assets/_commonjs-dynamic-modules-TDtrdbi3.js +1 -0
- package/client/dist/assets/ar-SA-G6X2FPQ2-Bmw2-hDt.js +10 -0
- package/client/dist/assets/arc-BMqY7_Ci.js +1 -0
- package/client/dist/assets/array-BKyUJesY.js +1 -0
- package/client/dist/assets/az-AZ-76LH7QW2-Dh1le_qs.js +1 -0
- package/client/dist/assets/bg-BG-XCXSNQG7-Cbav8Z9z.js +5 -0
- package/client/dist/assets/blockDiagram-38ab4fdb-ChHJxsXw.js +118 -0
- package/client/dist/assets/bn-BD-2XOGV67Q-DCNjOaWz.js +5 -0
- package/client/dist/assets/c4Diagram-3d4e48cf-b8Xue4Z6.js +10 -0
- package/client/dist/assets/ca-ES-6MX7JW3Y-Dl_vM7NS.js +8 -0
- package/client/dist/assets/channel-CSnvHe_M.js +1 -0
- package/client/dist/assets/classDiagram-70f12bd4-BheP7Ggo.js +2 -0
- package/client/dist/assets/classDiagram-v2-f2320105-xtym7GEZ.js +2 -0
- package/client/dist/assets/clone-B75abXxS.js +1 -0
- package/client/dist/assets/createText-2e5e7dd3-_n4jI_fO.js +5 -0
- package/client/dist/assets/cs-CZ-2BRQDIVT-ftsKDdz4.js +11 -0
- package/client/dist/assets/da-DK-5WZEPLOC-DAjdwGRO.js +5 -0
- package/client/dist/assets/de-DE-XR44H4JA-BJXczHGT.js +8 -0
- package/client/dist/assets/directory-open-01563666-DWU9wJ6I.js +1 -0
- package/client/dist/assets/directory-open-4ed118d0-CunoC1EB.js +1 -0
- package/client/dist/assets/edges-e0da2a9e-CfPZr4YM.js +4 -0
- package/client/dist/assets/el-GR-BZB4AONW-DW2p_uy7.js +10 -0
- package/client/dist/assets/erDiagram-9861fffd-CF33V-Of.js +51 -0
- package/client/dist/assets/es-ES-U4NZUMDT-DLOIGnrl.js +9 -0
- package/client/dist/assets/eu-ES-A7QVB2H4-LJXbf89m.js +11 -0
- package/client/dist/assets/fa-IR-HGAKTJCU-Dvx65fgW.js +8 -0
- package/client/dist/assets/fi-FI-Z5N7JZ37-EoL65BQh.js +6 -0
- package/client/dist/assets/file-open-002ab408-DIuFHtCF.js +1 -0
- package/client/dist/assets/file-open-7c801643-684qeFg4.js +1 -0
- package/client/dist/assets/file-save-3189631c-C1wFhQhH.js +1 -0
- package/client/dist/assets/file-save-745eba88-Bb9F9Kg7.js +1 -0
- package/client/dist/assets/flowDb-956e92f1-HgoXVy2H.js +10 -0
- package/client/dist/assets/flowDiagram-66a62f08-tffoET0H.js +4 -0
- package/client/dist/assets/flowDiagram-v2-96b9c2cf-Byc3JCHh.js +1 -0
- package/client/dist/assets/flowchart-elk-definition-4a651766-DJbI2dpv.js +139 -0
- package/client/dist/assets/fr-FR-RHASNOE6-DNk_jdDs.js +9 -0
- package/client/dist/assets/ganttDiagram-c361ad54-2XX670FU.js +257 -0
- package/client/dist/assets/gitGraphDiagram-72cf32ee-CcUfruAo.js +70 -0
- package/client/dist/assets/gl-ES-HMX3MZ6V-dxzFjZlG.js +10 -0
- package/client/dist/assets/graph-BSbiMSBC.js +1 -0
- package/client/dist/assets/he-IL-6SHJWFNN-Cogsfdt1.js +10 -0
- package/client/dist/assets/hi-IN-IWLTKZ5I-L6wbgi4F.js +4 -0
- package/client/dist/assets/hu-HU-A5ZG7DT2-DSA6ZDsH.js +7 -0
- package/client/dist/assets/id-ID-SAP4L64H-BK_vGGS6.js +10 -0
- package/client/dist/assets/image-blob-reduce.esm-BLtmMM_J.js +2 -0
- package/client/dist/assets/index-3862675e-Bv32HUgT.js +1 -0
- package/client/dist/assets/index-B8wwD_Xo.css +1 -0
- package/client/dist/assets/index-BPwf8Fw3.js +27 -0
- package/client/dist/assets/index-D1urGMYu.js +95 -0
- package/client/dist/assets/infoDiagram-f8f76790-w4mR4pxn.js +7 -0
- package/client/dist/assets/init-Gi6I4Gst.js +1 -0
- package/client/dist/assets/it-IT-JPQ66NNP-BLdHYMhn.js +11 -0
- package/client/dist/assets/ja-JP-DBVTYXUO-B_vmexl_.js +8 -0
- package/client/dist/assets/journeyDiagram-49397b02-D9nmO17e.js +139 -0
- package/client/dist/assets/kaa-6HZHGXH3-5s-3jl6F.js +1 -0
- package/client/dist/assets/kab-KAB-ZGHBKWFO-2QaVDuSf.js +8 -0
- package/client/dist/assets/kk-KZ-P5N5QNE5-CTC52Vbi.js +1 -0
- package/client/dist/assets/km-KH-HSX4SM5Z-DxawH8UZ.js +11 -0
- package/client/dist/assets/ko-KR-MTYHY66A-CmosEM8_.js +9 -0
- package/client/dist/assets/ku-TR-6OUDTVRD-DbiLen4y.js +9 -0
- package/client/dist/assets/layout-jmt3H9tA.js +1 -0
- package/client/dist/assets/line-JTlRayUJ.js +1 -0
- package/client/dist/assets/linear-DJeB5p7x.js +1 -0
- package/client/dist/assets/lt-LT-XHIRWOB4-CH15wrjA.js +3 -0
- package/client/dist/assets/lv-LV-5QDEKY6T-dhgfPuCQ.js +7 -0
- package/client/dist/assets/mindmap-definition-fc14e90a-BOOrexmz.js +415 -0
- package/client/dist/assets/mr-IN-CRQNXWMA-3Gi6iq7A.js +13 -0
- package/client/dist/assets/my-MM-5M5IBNSE-CpH4rdJj.js +1 -0
- package/client/dist/assets/nb-NO-T6EIAALU-Du6iiGql.js +10 -0
- package/client/dist/assets/nl-NL-IS3SIHDZ-BGvsd1MT.js +8 -0
- package/client/dist/assets/nn-NO-6E72VCQL-B-odvJZW.js +8 -0
- package/client/dist/assets/oc-FR-POXYY2M6-COC8xNjo.js +8 -0
- package/client/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/client/dist/assets/pa-IN-N4M65BXN-CE21PUQH.js +4 -0
- package/client/dist/assets/path-CbwjOpE9.js +1 -0
- package/client/dist/assets/pdf-TYrZqVzP.js +12 -0
- package/client/dist/assets/pdf.worker-BA9kU3Pw.mjs +61080 -0
- package/client/dist/assets/percentages-BXMCSKIN-C9GT0OD3.js +199 -0
- package/client/dist/assets/pica-VkdyTzi8.js +2 -0
- package/client/dist/assets/pieDiagram-8a3498a8-Cvfh7Qr5.js +35 -0
- package/client/dist/assets/pl-PL-T2D74RX3-D4xFVSoT.js +9 -0
- package/client/dist/assets/pt-BR-5N22H2LF-CCq257gA.js +9 -0
- package/client/dist/assets/pt-PT-UZXXM6DQ-1l8gt5vA.js +9 -0
- package/client/dist/assets/quadrantDiagram-120e2f19-BA0js1aD.js +7 -0
- package/client/dist/assets/requirementDiagram-deff3bca-B0QNFfIn.js +52 -0
- package/client/dist/assets/ro-RO-JPDTUUEW-yosBW01E.js +11 -0
- package/client/dist/assets/roundRect-mAH3dD0p.js +1 -0
- package/client/dist/assets/ru-RU-B4JR7IUQ-8LkEJUix.js +9 -0
- package/client/dist/assets/sankeyDiagram-04a897e0-D4T9eCXn.js +8 -0
- package/client/dist/assets/sequenceDiagram-704730f1-CfBUTCrO.js +122 -0
- package/client/dist/assets/si-LK-N5RQ5JYF-D8rjbqtd.js +1 -0
- package/client/dist/assets/sk-SK-C5VTKIMK-Bg14sAzN.js +6 -0
- package/client/dist/assets/sl-SI-NN7IZMDC-CMTib6Zs.js +6 -0
- package/client/dist/assets/stateDiagram-587899a1-BGgvmVSZ.js +1 -0
- package/client/dist/assets/stateDiagram-v2-d93cdb3a-Qn3DpYuO.js +1 -0
- package/client/dist/assets/styles-6aaf32cf-IdVZLPrD.js +207 -0
- package/client/dist/assets/styles-9a916d00-BAC3L45X.js +160 -0
- package/client/dist/assets/styles-c10674c1-COhXxX8c.js +116 -0
- package/client/dist/assets/subset-shared.chunk-BWHnFai4.js +22 -0
- package/client/dist/assets/subset-worker.chunk-C8QUSruZ.js +1 -0
- package/client/dist/assets/sv-SE-XGPEYMSR-C1425rOF.js +10 -0
- package/client/dist/assets/svgDrawCommon-08f97a94-Cfk-fgnN.js +1 -0
- package/client/dist/assets/ta-IN-2NMHFXQM-BHHo1zpF.js +9 -0
- package/client/dist/assets/th-TH-HPSO5L25-CZVzm_WT.js +2 -0
- package/client/dist/assets/timeline-definition-85554ec2-VAvuJith.js +61 -0
- package/client/dist/assets/tr-TR-DEFEU3FU-DE1lclCq.js +7 -0
- package/client/dist/assets/uk-UA-QMV73CPH-D4lJZ85O.js +6 -0
- package/client/dist/assets/vendor-codemirror-BARtJV1V.js +16 -0
- package/client/dist/assets/vendor-codemirror-langs-52_y1wip.js +20 -0
- package/client/dist/assets/vendor-i18n-ByAl-gdx.js +1 -0
- package/client/dist/assets/vendor-icons-D33IkSIf.js +1 -0
- package/client/dist/assets/vendor-markdown-CIVH08vJ.js +298 -0
- package/client/dist/assets/vendor-react-CHoMc7ka.js +8 -0
- package/client/dist/assets/vendor-syntax-Djb62v3a.js +9 -0
- package/client/dist/assets/vendor-xterm-DBb3RXlu.js +66 -0
- package/client/dist/assets/vendor-xterm-DrlLKa8f.css +1 -0
- package/client/dist/assets/vi-VN-M7AON7JQ-Dgc_SShk.js +5 -0
- package/client/dist/assets/xychartDiagram-e933f94c-BeyVBJhb.js +7 -0
- package/client/dist/assets/zh-CN-LNUGB5OW-MH4Yh8in.js +10 -0
- package/client/dist/assets/zh-HK-E62DVLB3-D4XHehjx.js +1 -0
- package/client/dist/assets/zh-TW-RAJ6MFWO--efj3evj.js +9 -0
- package/client/dist/clear-cache.html +85 -0
- package/client/dist/convert-icons.md +53 -0
- package/client/dist/favicon.png +0 -0
- package/client/dist/favicon.svg +9 -0
- package/client/dist/generate-icons.js +49 -0
- package/client/dist/icons/claude-ai-icon.svg +1 -0
- package/client/dist/icons/codex-white.svg +3 -0
- package/client/dist/icons/codex.svg +3 -0
- package/client/dist/icons/cursor-white.svg +12 -0
- package/client/dist/icons/cursor.svg +1 -0
- package/client/dist/icons/icon-128x128.png +0 -0
- package/client/dist/icons/icon-128x128.svg +12 -0
- package/client/dist/icons/icon-144x144.png +0 -0
- package/client/dist/icons/icon-144x144.svg +12 -0
- package/client/dist/icons/icon-152x152.png +0 -0
- package/client/dist/icons/icon-152x152.svg +12 -0
- package/client/dist/icons/icon-192x192.png +0 -0
- package/client/dist/icons/icon-192x192.svg +12 -0
- package/client/dist/icons/icon-384x384.png +0 -0
- package/client/dist/icons/icon-384x384.svg +12 -0
- package/client/dist/icons/icon-512x512.png +0 -0
- package/client/dist/icons/icon-512x512.svg +12 -0
- package/client/dist/icons/icon-72x72.png +0 -0
- package/client/dist/icons/icon-72x72.svg +12 -0
- package/client/dist/icons/icon-96x96.png +0 -0
- package/client/dist/icons/icon-96x96.svg +12 -0
- package/client/dist/icons/icon-template.svg +12 -0
- package/client/dist/index.html +128 -0
- package/client/dist/logo-128.png +0 -0
- package/client/dist/logo-256.png +0 -0
- package/client/dist/logo-32.png +0 -0
- package/client/dist/logo-512.png +0 -0
- package/client/dist/logo-64.png +0 -0
- package/client/dist/logo.svg +17 -0
- package/client/dist/manifest.json +61 -0
- package/client/dist/mcp-docs.html +119 -0
- package/client/dist/screenshots/cli-selection.png +0 -0
- package/client/dist/screenshots/desktop-main.png +0 -0
- package/client/dist/screenshots/mobile-chat.png +0 -0
- package/client/dist/screenshots/tools-modal.png +0 -0
- package/client/dist/sw.js +19 -0
- package/commands/upfynai-connect.md +46 -0
- package/commands/upfynai-disconnect.md +31 -0
- package/commands/upfynai-doctor.md +99 -0
- package/commands/upfynai-export.md +49 -0
- package/commands/upfynai-local.md +82 -0
- package/commands/upfynai-status.md +75 -0
- package/commands/upfynai-stop.md +49 -0
- package/commands/upfynai-uninstall.md +58 -0
- package/commands/upfynai.md +50 -0
- package/package.json +106 -47
- package/scripts/build-client.js +17 -0
- package/scripts/fix-node-pty.js +67 -0
- package/scripts/install-commands.js +78 -0
- package/server/claude-sdk.js +714 -0
- package/server/cli.js +419 -0
- package/server/constants/config.js +5 -0
- package/server/cursor-cli.js +270 -0
- package/server/database/auth.db +0 -0
- package/server/database/db.js +606 -0
- package/server/database/init.sql +70 -0
- package/server/index.js +2269 -0
- package/server/load-env.js +26 -0
- package/server/mcp-server.js +620 -0
- package/server/middleware/auth.js +158 -0
- package/server/openai-codex.js +403 -0
- package/server/projects.js +1849 -0
- package/server/relay-client.js +314 -0
- package/server/routes/agent.js +1231 -0
- package/server/routes/auth.js +220 -0
- package/server/routes/cli-auth.js +263 -0
- package/server/routes/codex.js +344 -0
- package/server/routes/commands.js +601 -0
- package/server/routes/cursor.js +808 -0
- package/server/routes/git.js +1165 -0
- package/server/routes/mcp-utils.js +48 -0
- package/server/routes/mcp.js +552 -0
- package/server/routes/payments.js +172 -0
- package/server/routes/projects.js +549 -0
- package/server/routes/settings.js +178 -0
- package/server/routes/taskmaster.js +1964 -0
- package/server/routes/user.js +106 -0
- package/server/utils/commandParser.js +303 -0
- package/server/utils/gitConfig.js +24 -0
- package/server/utils/mcp-detector.js +198 -0
- package/server/utils/taskmaster-websocket.js +129 -0
- package/shared/modelConstants.js +67 -0
- package/LICENSE +0 -22
- package/bin/cli.js +0 -86
- package/dist/assets/CanvasPanel-B48gAKVY.js +0 -538
- package/dist/assets/CanvasPanel-B48gAKVY.js.map +0 -1
- package/dist/assets/CanvasPanel-BsOG3EVs.css +0 -1
- package/dist/assets/index-CEhTwG68.css +0 -1
- package/dist/assets/index-GqAGWpJI.js +0 -70
- package/dist/assets/index-GqAGWpJI.js.map +0 -1
- package/dist/index.html +0 -18
- package/index.html +0 -17
- package/src/App.tsx +0 -226
- package/src/components/canvas/CanvasPanel.tsx +0 -62
- package/src/components/canvas/layout/graph-builder.ts +0 -136
- package/src/components/canvas/shapes/CompactionNodeShape.tsx +0 -76
- package/src/components/canvas/shapes/SessionNodeShape.tsx +0 -93
- package/src/components/canvas/shapes/StatuslineWidgetShape.tsx +0 -125
- package/src/components/canvas/shapes/TextResponseNodeShape.tsx +0 -86
- package/src/components/canvas/shapes/ToolCallNodeShape.tsx +0 -107
- package/src/components/canvas/shapes/ToolResultNodeShape.tsx +0 -87
- package/src/components/canvas/shapes/shared-styles.ts +0 -35
- package/src/components/chat/ChatPanel.tsx +0 -96
- package/src/components/chat/InputBar.tsx +0 -81
- package/src/components/chat/MessageList.tsx +0 -130
- package/src/components/chat/PermissionDialog.tsx +0 -70
- package/src/components/layout/FolderSelector.tsx +0 -152
- package/src/components/layout/ModelSelector.tsx +0 -65
- package/src/components/layout/SessionManager.tsx +0 -115
- package/src/components/statusline/StatuslineBar.tsx +0 -114
- package/src/main.tsx +0 -10
- package/src/server/claude-session.ts +0 -156
- package/src/server/index.ts +0 -149
- package/src/services/stream-consumer.ts +0 -330
- package/src/statusline-core/bin/statusline.sh +0 -121
- package/src/statusline-core/commands/sls-config.md +0 -42
- package/src/statusline-core/commands/sls-doctor.md +0 -35
- package/src/statusline-core/commands/sls-help.md +0 -48
- package/src/statusline-core/commands/sls-layout.md +0 -38
- package/src/statusline-core/commands/sls-preview.md +0 -34
- package/src/statusline-core/commands/sls-theme.md +0 -40
- package/src/statusline-core/installer.js +0 -228
- package/src/statusline-core/layouts/compact.sh +0 -21
- package/src/statusline-core/layouts/full.sh +0 -62
- package/src/statusline-core/layouts/standard.sh +0 -39
- package/src/statusline-core/lib/core.sh +0 -389
- package/src/statusline-core/lib/helpers.sh +0 -81
- package/src/statusline-core/lib/json-parser.sh +0 -71
- package/src/statusline-core/themes/catppuccin.sh +0 -32
- package/src/statusline-core/themes/default.sh +0 -37
- package/src/statusline-core/themes/gruvbox.sh +0 -32
- package/src/statusline-core/themes/nord.sh +0 -32
- package/src/statusline-core/themes/tokyo-night.sh +0 -32
- package/src/store/canvas-store.ts +0 -50
- package/src/store/chat-store.ts +0 -60
- package/src/store/permission-store.ts +0 -29
- package/src/store/session-store.ts +0 -52
- package/src/store/statusline-store.ts +0 -160
- package/src/styles/global.css +0 -117
- package/src/themes/index.ts +0 -149
- package/src/types/canvas-graph.ts +0 -24
- package/src/types/sdk-messages.ts +0 -156
- package/src/types/statusline-fields.ts +0 -67
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -26
- package/vite.config.ts +0 -24
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import matter from 'gray-matter';
|
|
7
|
+
import { CLAUDE_MODELS, CURSOR_MODELS, CODEX_MODELS } from '../../shared/modelConstants.js';
|
|
8
|
+
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = path.dirname(__filename);
|
|
11
|
+
|
|
12
|
+
const router = express.Router();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Recursively scan directory for command files (.md)
|
|
16
|
+
* @param {string} dir - Directory to scan
|
|
17
|
+
* @param {string} baseDir - Base directory for relative paths
|
|
18
|
+
* @param {string} namespace - Namespace for commands (e.g., 'project', 'user')
|
|
19
|
+
* @returns {Promise<Array>} Array of command objects
|
|
20
|
+
*/
|
|
21
|
+
async function scanCommandsDirectory(dir, baseDir, namespace) {
|
|
22
|
+
const commands = [];
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
// Check if directory exists
|
|
26
|
+
await fs.access(dir);
|
|
27
|
+
|
|
28
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
29
|
+
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
const fullPath = path.join(dir, entry.name);
|
|
32
|
+
|
|
33
|
+
if (entry.isDirectory()) {
|
|
34
|
+
// Recursively scan subdirectories
|
|
35
|
+
const subCommands = await scanCommandsDirectory(fullPath, baseDir, namespace);
|
|
36
|
+
commands.push(...subCommands);
|
|
37
|
+
} else if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
38
|
+
// Parse markdown file for metadata
|
|
39
|
+
try {
|
|
40
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
41
|
+
const { data: frontmatter, content: commandContent } = matter(content);
|
|
42
|
+
|
|
43
|
+
// Calculate relative path from baseDir for command name
|
|
44
|
+
const relativePath = path.relative(baseDir, fullPath);
|
|
45
|
+
// Remove .md extension and convert to command name
|
|
46
|
+
const commandName = '/' + relativePath.replace(/\.md$/, '').replace(/\\/g, '/');
|
|
47
|
+
|
|
48
|
+
// Extract description from frontmatter or first line of content
|
|
49
|
+
let description = frontmatter.description || '';
|
|
50
|
+
if (!description) {
|
|
51
|
+
const firstLine = commandContent.trim().split('\n')[0];
|
|
52
|
+
description = firstLine.replace(/^#+\s*/, '').trim();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
commands.push({
|
|
56
|
+
name: commandName,
|
|
57
|
+
path: fullPath,
|
|
58
|
+
relativePath,
|
|
59
|
+
description,
|
|
60
|
+
namespace,
|
|
61
|
+
metadata: frontmatter
|
|
62
|
+
});
|
|
63
|
+
} catch (err) {
|
|
64
|
+
console.error(`Error parsing command file ${fullPath}:`, err.message);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch (err) {
|
|
69
|
+
// Directory doesn't exist or can't be accessed - this is okay
|
|
70
|
+
if (err.code !== 'ENOENT' && err.code !== 'EACCES') {
|
|
71
|
+
console.error(`Error scanning directory ${dir}:`, err.message);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return commands;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Built-in commands that are always available
|
|
80
|
+
*/
|
|
81
|
+
const builtInCommands = [
|
|
82
|
+
{
|
|
83
|
+
name: '/help',
|
|
84
|
+
description: 'Show help documentation for Upfyn-Code',
|
|
85
|
+
namespace: 'builtin',
|
|
86
|
+
metadata: { type: 'builtin' }
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: '/clear',
|
|
90
|
+
description: 'Clear the conversation history',
|
|
91
|
+
namespace: 'builtin',
|
|
92
|
+
metadata: { type: 'builtin' }
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: '/model',
|
|
96
|
+
description: 'Switch or view the current AI model',
|
|
97
|
+
namespace: 'builtin',
|
|
98
|
+
metadata: { type: 'builtin' }
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: '/cost',
|
|
102
|
+
description: 'Display token usage and cost information',
|
|
103
|
+
namespace: 'builtin',
|
|
104
|
+
metadata: { type: 'builtin' }
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: '/memory',
|
|
108
|
+
description: 'Open CLAUDE.md memory file for editing',
|
|
109
|
+
namespace: 'builtin',
|
|
110
|
+
metadata: { type: 'builtin' }
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: '/config',
|
|
114
|
+
description: 'Open settings and configuration',
|
|
115
|
+
namespace: 'builtin',
|
|
116
|
+
metadata: { type: 'builtin' }
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: '/status',
|
|
120
|
+
description: 'Show system status and version information',
|
|
121
|
+
namespace: 'builtin',
|
|
122
|
+
metadata: { type: 'builtin' }
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: '/rewind',
|
|
126
|
+
description: 'Rewind the conversation to a previous state',
|
|
127
|
+
namespace: 'builtin',
|
|
128
|
+
metadata: { type: 'builtin' }
|
|
129
|
+
}
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Built-in command handlers
|
|
134
|
+
* Each handler returns { type: 'builtin', action: string, data: any }
|
|
135
|
+
*/
|
|
136
|
+
const builtInHandlers = {
|
|
137
|
+
'/help': async (args, context) => {
|
|
138
|
+
const helpText = `# Upfyn-Code Commands
|
|
139
|
+
|
|
140
|
+
## Built-in Commands
|
|
141
|
+
|
|
142
|
+
${builtInCommands.map(cmd => `### ${cmd.name}
|
|
143
|
+
${cmd.description}
|
|
144
|
+
`).join('\n')}
|
|
145
|
+
|
|
146
|
+
## Custom Commands
|
|
147
|
+
|
|
148
|
+
Custom commands can be created in:
|
|
149
|
+
- Project: \`.claude/commands/\` (project-specific)
|
|
150
|
+
- User: \`~/.claude/commands/\` (available in all projects)
|
|
151
|
+
|
|
152
|
+
### Command Syntax
|
|
153
|
+
|
|
154
|
+
- **Arguments**: Use \`$ARGUMENTS\` for all args or \`$1\`, \`$2\`, etc. for positional
|
|
155
|
+
- **File Includes**: Use \`@filename\` to include file contents
|
|
156
|
+
- **Bash Commands**: Use \`!command\` to execute bash commands
|
|
157
|
+
|
|
158
|
+
### Examples
|
|
159
|
+
|
|
160
|
+
\`\`\`markdown
|
|
161
|
+
/mycommand arg1 arg2
|
|
162
|
+
\`\`\`
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
type: 'builtin',
|
|
167
|
+
action: 'help',
|
|
168
|
+
data: {
|
|
169
|
+
content: helpText,
|
|
170
|
+
format: 'markdown'
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
'/clear': async (args, context) => {
|
|
176
|
+
return {
|
|
177
|
+
type: 'builtin',
|
|
178
|
+
action: 'clear',
|
|
179
|
+
data: {
|
|
180
|
+
message: 'Conversation history cleared'
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
'/model': async (args, context) => {
|
|
186
|
+
// Read available models from centralized constants
|
|
187
|
+
const availableModels = {
|
|
188
|
+
claude: CLAUDE_MODELS.OPTIONS.map(o => o.value),
|
|
189
|
+
cursor: CURSOR_MODELS.OPTIONS.map(o => o.value),
|
|
190
|
+
codex: CODEX_MODELS.OPTIONS.map(o => o.value)
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const currentProvider = context?.provider || 'claude';
|
|
194
|
+
const currentModel = context?.model || CLAUDE_MODELS.DEFAULT;
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
type: 'builtin',
|
|
198
|
+
action: 'model',
|
|
199
|
+
data: {
|
|
200
|
+
current: {
|
|
201
|
+
provider: currentProvider,
|
|
202
|
+
model: currentModel
|
|
203
|
+
},
|
|
204
|
+
available: availableModels,
|
|
205
|
+
message: args.length > 0
|
|
206
|
+
? `Switching to model: ${args[0]}`
|
|
207
|
+
: `Current model: ${currentModel}`
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
'/cost': async (args, context) => {
|
|
213
|
+
const tokenUsage = context?.tokenUsage || {};
|
|
214
|
+
const provider = context?.provider || 'claude';
|
|
215
|
+
const model =
|
|
216
|
+
context?.model ||
|
|
217
|
+
(provider === 'cursor'
|
|
218
|
+
? CURSOR_MODELS.DEFAULT
|
|
219
|
+
: provider === 'codex'
|
|
220
|
+
? CODEX_MODELS.DEFAULT
|
|
221
|
+
: CLAUDE_MODELS.DEFAULT);
|
|
222
|
+
|
|
223
|
+
const used = Number(tokenUsage.used ?? tokenUsage.totalUsed ?? tokenUsage.total_tokens ?? 0) || 0;
|
|
224
|
+
const total =
|
|
225
|
+
Number(
|
|
226
|
+
tokenUsage.total ??
|
|
227
|
+
tokenUsage.contextWindow ??
|
|
228
|
+
parseInt(process.env.CONTEXT_WINDOW || '160000', 10),
|
|
229
|
+
) || 160000;
|
|
230
|
+
const percentage = total > 0 ? Number(((used / total) * 100).toFixed(1)) : 0;
|
|
231
|
+
|
|
232
|
+
const inputTokensRaw =
|
|
233
|
+
Number(
|
|
234
|
+
tokenUsage.inputTokens ??
|
|
235
|
+
tokenUsage.input ??
|
|
236
|
+
tokenUsage.cumulativeInputTokens ??
|
|
237
|
+
tokenUsage.promptTokens ??
|
|
238
|
+
0,
|
|
239
|
+
) || 0;
|
|
240
|
+
const outputTokens =
|
|
241
|
+
Number(
|
|
242
|
+
tokenUsage.outputTokens ??
|
|
243
|
+
tokenUsage.output ??
|
|
244
|
+
tokenUsage.cumulativeOutputTokens ??
|
|
245
|
+
tokenUsage.completionTokens ??
|
|
246
|
+
0,
|
|
247
|
+
) || 0;
|
|
248
|
+
const cacheTokens =
|
|
249
|
+
Number(
|
|
250
|
+
tokenUsage.cacheReadTokens ??
|
|
251
|
+
tokenUsage.cacheCreationTokens ??
|
|
252
|
+
tokenUsage.cacheTokens ??
|
|
253
|
+
tokenUsage.cachedTokens ??
|
|
254
|
+
0,
|
|
255
|
+
) || 0;
|
|
256
|
+
|
|
257
|
+
// If we only have total used tokens, treat them as input for display/estimation.
|
|
258
|
+
const inputTokens =
|
|
259
|
+
inputTokensRaw > 0 || outputTokens > 0 || cacheTokens > 0 ? inputTokensRaw + cacheTokens : used;
|
|
260
|
+
|
|
261
|
+
// Rough default rates by provider (USD / 1M tokens).
|
|
262
|
+
const pricingByProvider = {
|
|
263
|
+
claude: { input: 3, output: 15 },
|
|
264
|
+
cursor: { input: 3, output: 15 },
|
|
265
|
+
codex: { input: 1.5, output: 6 },
|
|
266
|
+
};
|
|
267
|
+
const rates = pricingByProvider[provider] || pricingByProvider.claude;
|
|
268
|
+
|
|
269
|
+
const inputCost = (inputTokens / 1_000_000) * rates.input;
|
|
270
|
+
const outputCost = (outputTokens / 1_000_000) * rates.output;
|
|
271
|
+
const totalCost = inputCost + outputCost;
|
|
272
|
+
|
|
273
|
+
return {
|
|
274
|
+
type: 'builtin',
|
|
275
|
+
action: 'cost',
|
|
276
|
+
data: {
|
|
277
|
+
tokenUsage: {
|
|
278
|
+
used,
|
|
279
|
+
total,
|
|
280
|
+
percentage,
|
|
281
|
+
},
|
|
282
|
+
cost: {
|
|
283
|
+
input: inputCost.toFixed(4),
|
|
284
|
+
output: outputCost.toFixed(4),
|
|
285
|
+
total: totalCost.toFixed(4),
|
|
286
|
+
},
|
|
287
|
+
model,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
'/status': async (args, context) => {
|
|
293
|
+
// Read version from package.json
|
|
294
|
+
const packageJsonPath = path.join(path.dirname(__dirname), '..', 'package.json');
|
|
295
|
+
let version = 'unknown';
|
|
296
|
+
let packageName = 'upfyn-code';
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
300
|
+
version = packageJson.version;
|
|
301
|
+
packageName = packageJson.name;
|
|
302
|
+
} catch (err) {
|
|
303
|
+
console.error('Error reading package.json:', err);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const uptime = process.uptime();
|
|
307
|
+
const uptimeMinutes = Math.floor(uptime / 60);
|
|
308
|
+
const uptimeHours = Math.floor(uptimeMinutes / 60);
|
|
309
|
+
const uptimeFormatted = uptimeHours > 0
|
|
310
|
+
? `${uptimeHours}h ${uptimeMinutes % 60}m`
|
|
311
|
+
: `${uptimeMinutes}m`;
|
|
312
|
+
|
|
313
|
+
return {
|
|
314
|
+
type: 'builtin',
|
|
315
|
+
action: 'status',
|
|
316
|
+
data: {
|
|
317
|
+
version,
|
|
318
|
+
packageName,
|
|
319
|
+
uptime: uptimeFormatted,
|
|
320
|
+
uptimeSeconds: Math.floor(uptime),
|
|
321
|
+
model: context?.model || 'claude-sonnet-4.5',
|
|
322
|
+
provider: context?.provider || 'claude',
|
|
323
|
+
nodeVersion: process.version,
|
|
324
|
+
platform: process.platform
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
'/memory': async (args, context) => {
|
|
330
|
+
const projectPath = context?.projectPath;
|
|
331
|
+
|
|
332
|
+
if (!projectPath) {
|
|
333
|
+
return {
|
|
334
|
+
type: 'builtin',
|
|
335
|
+
action: 'memory',
|
|
336
|
+
data: {
|
|
337
|
+
error: 'No project selected',
|
|
338
|
+
message: 'Please select a project to access its CLAUDE.md file'
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const claudeMdPath = path.join(projectPath, 'CLAUDE.md');
|
|
344
|
+
|
|
345
|
+
// Check if CLAUDE.md exists
|
|
346
|
+
let exists = false;
|
|
347
|
+
try {
|
|
348
|
+
await fs.access(claudeMdPath);
|
|
349
|
+
exists = true;
|
|
350
|
+
} catch (err) {
|
|
351
|
+
// File doesn't exist
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return {
|
|
355
|
+
type: 'builtin',
|
|
356
|
+
action: 'memory',
|
|
357
|
+
data: {
|
|
358
|
+
path: claudeMdPath,
|
|
359
|
+
exists,
|
|
360
|
+
message: exists
|
|
361
|
+
? `Opening CLAUDE.md at ${claudeMdPath}`
|
|
362
|
+
: `CLAUDE.md not found at ${claudeMdPath}. Create it to store project-specific instructions.`
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
'/config': async (args, context) => {
|
|
368
|
+
return {
|
|
369
|
+
type: 'builtin',
|
|
370
|
+
action: 'config',
|
|
371
|
+
data: {
|
|
372
|
+
message: 'Opening settings...'
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
'/rewind': async (args, context) => {
|
|
378
|
+
const steps = args[0] ? parseInt(args[0]) : 1;
|
|
379
|
+
|
|
380
|
+
if (isNaN(steps) || steps < 1) {
|
|
381
|
+
return {
|
|
382
|
+
type: 'builtin',
|
|
383
|
+
action: 'rewind',
|
|
384
|
+
data: {
|
|
385
|
+
error: 'Invalid steps parameter',
|
|
386
|
+
message: 'Usage: /rewind [number] - Rewind conversation by N steps (default: 1)'
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
type: 'builtin',
|
|
393
|
+
action: 'rewind',
|
|
394
|
+
data: {
|
|
395
|
+
steps,
|
|
396
|
+
message: `Rewinding conversation by ${steps} step${steps > 1 ? 's' : ''}...`
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* POST /api/commands/list
|
|
404
|
+
* List all available commands from project and user directories
|
|
405
|
+
*/
|
|
406
|
+
router.post('/list', async (req, res) => {
|
|
407
|
+
try {
|
|
408
|
+
const { projectPath } = req.body;
|
|
409
|
+
const allCommands = [...builtInCommands];
|
|
410
|
+
|
|
411
|
+
// Scan project-level commands (.claude/commands/)
|
|
412
|
+
if (projectPath) {
|
|
413
|
+
const projectCommandsDir = path.join(projectPath, '.claude', 'commands');
|
|
414
|
+
const projectCommands = await scanCommandsDirectory(
|
|
415
|
+
projectCommandsDir,
|
|
416
|
+
projectCommandsDir,
|
|
417
|
+
'project'
|
|
418
|
+
);
|
|
419
|
+
allCommands.push(...projectCommands);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Scan user-level commands (~/.claude/commands/)
|
|
423
|
+
const homeDir = os.homedir();
|
|
424
|
+
const userCommandsDir = path.join(homeDir, '.claude', 'commands');
|
|
425
|
+
const userCommands = await scanCommandsDirectory(
|
|
426
|
+
userCommandsDir,
|
|
427
|
+
userCommandsDir,
|
|
428
|
+
'user'
|
|
429
|
+
);
|
|
430
|
+
allCommands.push(...userCommands);
|
|
431
|
+
|
|
432
|
+
// Separate built-in and custom commands
|
|
433
|
+
const customCommands = allCommands.filter(cmd => cmd.namespace !== 'builtin');
|
|
434
|
+
|
|
435
|
+
// Sort commands alphabetically by name
|
|
436
|
+
customCommands.sort((a, b) => a.name.localeCompare(b.name));
|
|
437
|
+
|
|
438
|
+
res.json({
|
|
439
|
+
builtIn: builtInCommands,
|
|
440
|
+
custom: customCommands,
|
|
441
|
+
count: allCommands.length
|
|
442
|
+
});
|
|
443
|
+
} catch (error) {
|
|
444
|
+
// command list error
|
|
445
|
+
res.status(500).json({
|
|
446
|
+
error: 'Failed to list commands',
|
|
447
|
+
message: 'An error occurred'
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* POST /api/commands/load
|
|
454
|
+
* Load a specific command file and return its content and metadata
|
|
455
|
+
*/
|
|
456
|
+
router.post('/load', async (req, res) => {
|
|
457
|
+
try {
|
|
458
|
+
const { commandPath } = req.body;
|
|
459
|
+
|
|
460
|
+
if (!commandPath) {
|
|
461
|
+
return res.status(400).json({
|
|
462
|
+
error: 'Command path is required'
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Security: Prevent path traversal
|
|
467
|
+
const resolvedPath = path.resolve(commandPath);
|
|
468
|
+
if (!resolvedPath.startsWith(path.resolve(os.homedir())) &&
|
|
469
|
+
!resolvedPath.includes('.claude/commands')) {
|
|
470
|
+
return res.status(403).json({
|
|
471
|
+
error: 'Access denied',
|
|
472
|
+
message: 'Command must be in .claude/commands directory'
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Read and parse the command file
|
|
477
|
+
const content = await fs.readFile(commandPath, 'utf8');
|
|
478
|
+
const { data: metadata, content: commandContent } = matter(content);
|
|
479
|
+
|
|
480
|
+
res.json({
|
|
481
|
+
path: commandPath,
|
|
482
|
+
metadata,
|
|
483
|
+
content: commandContent
|
|
484
|
+
});
|
|
485
|
+
} catch (error) {
|
|
486
|
+
if (error.code === 'ENOENT') {
|
|
487
|
+
return res.status(404).json({
|
|
488
|
+
error: 'Command not found',
|
|
489
|
+
message: `Command file not found: ${req.body.commandPath}`
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// command load error
|
|
494
|
+
res.status(500).json({
|
|
495
|
+
error: 'Failed to load command',
|
|
496
|
+
message: 'An error occurred'
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
/**
|
|
502
|
+
* POST /api/commands/execute
|
|
503
|
+
* Execute a command with argument replacement
|
|
504
|
+
* This endpoint prepares the command content but doesn't execute bash commands yet
|
|
505
|
+
* (that will be handled in the command parser utility)
|
|
506
|
+
*/
|
|
507
|
+
router.post('/execute', async (req, res) => {
|
|
508
|
+
try {
|
|
509
|
+
const { commandName, commandPath, args = [], context = {} } = req.body;
|
|
510
|
+
|
|
511
|
+
if (!commandName) {
|
|
512
|
+
return res.status(400).json({
|
|
513
|
+
error: 'Command name is required'
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Handle built-in commands
|
|
518
|
+
const handler = builtInHandlers[commandName];
|
|
519
|
+
if (handler) {
|
|
520
|
+
try {
|
|
521
|
+
const result = await handler(args, context);
|
|
522
|
+
return res.json({
|
|
523
|
+
...result,
|
|
524
|
+
command: commandName
|
|
525
|
+
});
|
|
526
|
+
} catch (error) {
|
|
527
|
+
// built-in command error
|
|
528
|
+
return res.status(500).json({
|
|
529
|
+
error: 'Command execution failed',
|
|
530
|
+
message: 'An error occurred',
|
|
531
|
+
command: commandName
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// Handle custom commands
|
|
537
|
+
if (!commandPath) {
|
|
538
|
+
return res.status(400).json({
|
|
539
|
+
error: 'Command path is required for custom commands'
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Load command content
|
|
544
|
+
// Security: validate commandPath is within allowed directories
|
|
545
|
+
{
|
|
546
|
+
const resolvedPath = path.resolve(commandPath);
|
|
547
|
+
const userBase = path.resolve(path.join(os.homedir(), '.claude', 'commands'));
|
|
548
|
+
const projectBase = context?.projectPath
|
|
549
|
+
? path.resolve(path.join(context.projectPath, '.claude', 'commands'))
|
|
550
|
+
: null;
|
|
551
|
+
const isUnder = (base) => {
|
|
552
|
+
const rel = path.relative(base, resolvedPath);
|
|
553
|
+
return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);
|
|
554
|
+
};
|
|
555
|
+
if (!(isUnder(userBase) || (projectBase && isUnder(projectBase)))) {
|
|
556
|
+
return res.status(403).json({
|
|
557
|
+
error: 'Access denied',
|
|
558
|
+
message: 'Command must be in .claude/commands directory'
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
const content = await fs.readFile(commandPath, 'utf8');
|
|
563
|
+
const { data: metadata, content: commandContent } = matter(content);
|
|
564
|
+
// Basic argument replacement (will be enhanced in command parser utility)
|
|
565
|
+
let processedContent = commandContent;
|
|
566
|
+
|
|
567
|
+
// Replace $ARGUMENTS with all arguments joined
|
|
568
|
+
const argsString = args.join(' ');
|
|
569
|
+
processedContent = processedContent.replace(/\$ARGUMENTS/g, argsString);
|
|
570
|
+
|
|
571
|
+
// Replace $1, $2, etc. with positional arguments
|
|
572
|
+
args.forEach((arg, index) => {
|
|
573
|
+
const placeholder = `$${index + 1}`;
|
|
574
|
+
processedContent = processedContent.replace(new RegExp(`\\${placeholder}\\b`, 'g'), arg);
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
res.json({
|
|
578
|
+
type: 'custom',
|
|
579
|
+
command: commandName,
|
|
580
|
+
content: processedContent,
|
|
581
|
+
metadata,
|
|
582
|
+
hasFileIncludes: processedContent.includes('@'),
|
|
583
|
+
hasBashCommands: processedContent.includes('!')
|
|
584
|
+
});
|
|
585
|
+
} catch (error) {
|
|
586
|
+
if (error.code === 'ENOENT') {
|
|
587
|
+
return res.status(404).json({
|
|
588
|
+
error: 'Command not found',
|
|
589
|
+
message: `Command file not found: ${req.body.commandPath}`
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
// command execution error
|
|
594
|
+
res.status(500).json({
|
|
595
|
+
error: 'Failed to execute command',
|
|
596
|
+
message: 'An error occurred'
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
export default router;
|