@shawnstack/quickforge 1.7.3 → 1.7.5
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 +1 -1
- package/bin/quickforge.mjs +0 -21
- package/dist/assets/AgentProfilesPage-XNjuqJs7.js +1 -0
- package/dist/assets/ChatPanelHost-CuF-PZpc.js +292 -0
- package/dist/assets/CloudAccountSettingsPage-GJSoi6sO.js +1 -0
- package/dist/assets/PluginsPage-BQgp0qN-.js +1 -0
- package/dist/assets/ScheduledTasksPage-DdekATzq.js +2 -0
- package/dist/assets/SettingsWorkspacePage-Cb54Ic91.js +1639 -0
- package/dist/assets/ShareLinksSettingsPage-C75WJpaF.js +1 -0
- package/dist/assets/SharedConversationPage-CjMtSQTW.js +1 -0
- package/dist/assets/TerminalDock-D4zJBJc4.js +2 -0
- package/dist/assets/WorkspaceInspector-D9kdnLDd.js +36 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-Dl_Fvlqg.js → abnfDiagram-VRR7QNED-CMhVoYUh.js} +1 -1
- package/dist/assets/{arc-Bhg4c0ht.js → arc-w21O0TLn.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-DMwFMHxq.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-BuojN27B.js → architectureDiagram-ZJ3FMSHR-C52qL6Hg.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-alDLbrR1.js → blockDiagram-677ZJIJ3-CM3XbLol.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-D1lKa4VT.js → c4Diagram-LMCZKHZV-D7Bh1ui1.js} +1 -1
- package/dist/assets/channel-Duu1CuH9.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-B6rHWc4S.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-CwWLNjMZ.js → chunk-32BRIVSS-xgrtbT8e.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-Be569m7d.js → chunk-52WLFC77-CDbaHw80.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-BSvoiWV1.js → chunk-5FCAYU7R-CcSvVbPc.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-CRgsy8WS.js → chunk-5HE753X5-erFpzzgx.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CdW477UR.js → chunk-5JV3BV7I-rEhN9F6G.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CdtKzSmp.js → chunk-5TONJI2A-D8L-QTwD.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-BKjjssLZ.js → chunk-5VM5RSS4-CjlfMBbM.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-ByAXiXdn.js → chunk-7BUUIJ7U-CCcsI9XE.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DeG8SCT1.js → chunk-BIQX33UG-FSqFbmb3.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-D_zHT68Q.js → chunk-C7G6YPKG-ZMLUvfLy.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-CHpHoUSu.js → chunk-CQNSW5MT-DZuBpk25.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-CRP50Vov.js → chunk-CYSBUYHQ-CB26wsG0.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-DX6uQQ2v.js → chunk-EMLP6XTP-BbsM8oRw.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-DAJRNkHR.js → chunk-EX3LRPZG-BcQhaqt7.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-XbM5yomC.js → chunk-FWX5IMBZ-DrnrdrSu.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-Ci0ljnb1.js → chunk-HOUHSVGY-tdc-Z9eW.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-Dy2WJ71z.js → chunk-ICXQ74PX-Cd7igVGt.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-2PrkzHkt.js → chunk-JG7HCLWE-iXXGW8nf.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-D32uacSM.js → chunk-JWPE2WC7-BZ87mXEv.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-DIAFLtiS.js → chunk-MOJQB5TN-CLTjV5ov.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-BbscOaEz.js → chunk-MOZMSUNE-B3SCBrRH.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-ivBVxzKe.js → chunk-OGEWGWER-TgvkXkFX.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-frD0hkdx.js → chunk-OSBZ3O6U-B9E2E5v1.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-B-37Rxae.js → chunk-PUDLZKDR-C5GMVYup.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-Y90m2RTe.js → chunk-Q4XR5HBZ-fo5-HsqY.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-DixBqslB.js → chunk-QBLGF6JB-Dwfg8sKc.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-DXS1UXn_.js → chunk-R7FJI6CG-DpBrv4ni.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-n4JxhNd0.js → chunk-RYQCIY6F-DzzmTl11.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-yHlgxMmn.js → chunk-U6XO7XAA-Dw6aviKa.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-Z6kuZfbl.js → chunk-V7JOEXUC-CEDazV6w.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-CWYjg8zE.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-Cs_SIQma.js → chunk-VR4S4FIN-C_-eEj-9.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-CGExYbV-.js → chunk-WYO6CB5R-NF-MsJJR.js} +3 -3
- package/dist/assets/chunk-XXDRQBXY-DzTwx8ZH.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-DopPXWSl.js → chunk-YOTPTUD7-DqzqtdII.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-CJHOeqMb.js → chunk-ZGVPDNZ5-CRrAYi4g.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-BBVc5mf6.js → chunk-ZIRB5QZD-Dc1s5bLM.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Cc63fLWP.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-CoXU0qT6.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-DLjV-dTm.js → cose-bilkent-JH36ORCC-cL247pHg.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-C8yCvH_o.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-BfH3zVS-.js → cynefinDiagram-TSTJHNR4-D4sZ7LYI.js} +1 -1
- package/dist/assets/{dagre-CY3D84Cl.js → dagre-DmHb3Ctt.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-BIhwZCIZ.js → dagre-VKFMJZFB-BlsnSh-Q.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-BHnzNM2w.js → diagram-FQU43EPY-DW1yQiRO.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-C7-ZlmFT.js → diagram-G47NLZAW-BTUAsFjb.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-C-P9Y7IR.js → diagram-NH7WQ7WH-BcaomqSd.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-Ci5lZ_T5.js → diagram-OA4YK3LP-DDLX7Xwr.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-C1xuK2bs.js → diagram-WEI45ONY-CIave0An.js} +1 -1
- package/dist/assets/dist-DLKC_odd.js +1 -0
- package/dist/assets/{ebnfDiagram-CCIWWBDH-DKQ5NWMD.js → ebnfDiagram-CCIWWBDH-Cr1Y6lPu.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-HAWySadP.js → erDiagram-Q63AITRT-D3EgiVVH.js} +1 -1
- package/dist/assets/esm-Df4edDpj.js +2 -0
- package/dist/assets/eventmodeling-45OFAUF4-DO1vRTM0.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-BS7KXcqn.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-C1hwIcOA.js → ganttDiagram-NO4QXBWP-B0oyDIqK.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-m5F5ef09.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-DYUYxs1R.js → gitGraphDiagram-IHSO6WYX-uQtr6IqK.js} +1 -1
- package/dist/assets/icons-CXPP1fFT.js +1 -0
- package/dist/assets/index-_ZhK6bvp.js +65 -0
- package/dist/assets/index-iVV2bP_f.css +3 -0
- package/dist/assets/info-DKCQHKI2-CZxPlQJ0.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-CnIL6tv4.js → infoDiagram-FWYZ7A6U-B_GzlLIM.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-B7WXNycQ.js → ishikawaDiagram-FXEZZL3T-CKQIsSdU.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-D4HvioyY.js → journeyDiagram-5HDEW3XC-DrrvzZL1.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-CDs763eS.js → kanban-definition-HUTT4EX6-CJQRTdXz.js} +1 -1
- package/dist/assets/{line-ikKkQiFp.js → line-B4DxX7tC.js} +1 -1
- package/dist/assets/{linear-GqPyxQkN.js → linear-U-nKUhyW.js} +1 -1
- package/dist/assets/{map-CJwjCvwr.js → map-BneTM-ri.js} +1 -1
- package/dist/assets/{mcp-servers-dialog-BQbFywVL.js → mcp-servers-dialog-BUSPvaqI.js} +2 -2
- package/dist/assets/{mermaid-parser.core-CoE8cccr.js → mermaid-parser.core-BlKWrEdZ.js} +2 -2
- package/dist/assets/{mermaid-renderer-BmbSAmpG.js → mermaid-renderer-jEbqFaTe.js} +2 -2
- package/dist/assets/{mermaid.core-DlFSL90j.js → mermaid.core-DWpShXCs.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-DLdq0K9C.js → mindmap-definition-LN4V7U3C-CEVwZD78.js} +1 -1
- package/dist/assets/model-identity-CgA6_Pbm.js +1 -0
- package/dist/assets/model-reference-o41fJ6jQ.js +1 -0
- package/dist/assets/{monaco-BTsVCDWS.js → monaco-D6OhXgjg.js} +1 -1
- package/dist/assets/{ordinal-CibZU3PM.js → ordinal-B2r5L1v4.js} +1 -1
- package/dist/assets/{otel-BNGM50C-.js → otel-BFnphzjt.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-zIioIZVN.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-Cm1kPRC2.js → pegDiagram-2B236MQR-CBLkBdnQ.js} +1 -1
- package/dist/assets/{pi-ai-Cr3rpCXT.js → pi-ai-Cr2ee4a0.js} +2 -2
- package/dist/assets/{pi-web-ui-DoRGtREc.js → pi-web-ui-DV5jKjSg.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-GGWijBvB.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-Df05wjjo.js → pieDiagram-ENE6RG2P-8tCnwtWS.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-BjCwGxJC.js → quadrantDiagram-ABIIQ3AL-CWd28cHF.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-yvwFH3RV.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-BVadlswB.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-B7R-p_2-.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-BnbJxPug.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-Ci3DcEuQ.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-CTUvpKkv.js → railroadDiagram-RFXS5EU6-CI4ouOBs.js} +1 -1
- package/dist/assets/{react-vendor-Dr5xvL-e.js → react-vendor-1KC5PyRx.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE-BU1kvEku.js → requirementDiagram-TGXJPOKE-DtFz7sw4.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-BHmvxVqH.js → sankeyDiagram-HTMAVEWB--VeOwwk9.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-CTpwICgg.js → sequenceDiagram-DBY2YBRQ-B8AHk5Oe.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-BbLhGaa4.js → sizeCapture-X5ZJPWSS-vV_ArM8D.js} +1 -1
- package/dist/assets/{skills-dialog-REBeTFSH.js → skills-dialog-BThnIUBs.js} +3 -1
- package/dist/assets/{src-B4Tvg3gT.js → src-PYsDme0X.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-BxuDwIgT.js → stateDiagram-2N3HPSRC-etXnJ8X8.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-Dms3pICj.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-EkZsiylV.js → swimlanes-5IMT3BWC-pabIKAmn.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-B14aWjv6.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-C9ewOCTa.js → timeline-definition-FHXFAJF6-C55MKm3L.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-Cru9B2zv.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-DNOVHFaJ.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-CR49Y4Lp.js → vennDiagram-L72KCM5P-CgNf1Q9W.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-E3m1BOJQ.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-Cn0GgwWi.js → wardleyDiagram-EHGQE667-Drt5ytec.js} +1 -1
- package/dist/assets/web-DoV8MSMn.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-DlmPNAvd.js → xychartDiagram-FW5EYKEG-hhoEo_Ar.js} +1 -1
- package/dist/index.html +13 -11
- package/dist/mobile-error.html +24 -0
- package/package.json +6 -1
- package/plugins/{openai-documents → documents}/plugin.json +2 -2
- package/plugins/{openai-presentations → presentations}/plugin.json +2 -2
- package/plugins/{openai-spreadsheets → spreadsheets}/plugin.json +2 -2
- package/server/acp/server.mjs +50 -35
- package/server/agent-manager.mjs +343 -46
- package/server/agent-profile-files.mjs +8 -4
- package/server/agent-profile-schema.mjs +47 -23
- package/server/agent-profiles.mjs +1 -1
- package/server/ai-http-logger.mjs +156 -13
- package/server/ai-provider-options.mjs +3 -0
- package/server/channels/channel-logs.mjs +13 -0
- package/server/channels/event-relay.mjs +33 -0
- package/server/channels/process-channel.mjs +29 -0
- package/server/channels/providers/wechat.mjs +9 -3
- package/server/channels/registry.mjs +5 -1
- package/server/cloud/chat-idempotency-store.mjs +96 -0
- package/server/cloud/client.mjs +102 -0
- package/server/cloud/config.mjs +53 -0
- package/server/cloud/credential-store.mjs +193 -0
- package/server/cloud/identity.mjs +355 -0
- package/server/cloud/index.mjs +7 -0
- package/server/cloud/models.mjs +80 -0
- package/server/cloud/runtime.mjs +129 -0
- package/server/cloud/service-config.mjs +77 -0
- package/server/index.mjs +63 -33
- package/server/lan-access-store.mjs +93 -3
- package/server/model-catalog.mjs +262 -0
- package/server/network-proxy.mjs +68 -3
- package/server/plugins/registry.mjs +93 -9
- package/server/public-api.mjs +6 -2
- package/server/routes/agent-profiles.mjs +43 -9
- package/server/routes/agent.mjs +48 -11
- package/server/routes/backup.mjs +7 -1
- package/server/routes/channels.mjs +47 -0
- package/server/routes/cloud.mjs +227 -0
- package/server/routes/lan-access.mjs +246 -21
- package/server/routes/models.mjs +13 -4
- package/server/routes/project.mjs +19 -1
- package/server/routes/scheduled-tasks.mjs +40 -10
- package/server/routes/shared-conversation.mjs +62 -58
- package/server/routes/shares.mjs +76 -1
- package/server/routes/static.mjs +26 -1
- package/server/routes/storage.mjs +24 -1
- package/server/routes/system.mjs +11 -0
- package/server/routes/terminal.mjs +7 -2
- package/server/routes/workspace.mjs +66 -13
- package/server/session-utils.mjs +2 -2
- package/server/share-store.mjs +168 -13
- package/server/skills.mjs +30 -3
- package/server/storage.mjs +7 -1
- package/server/subagents.mjs +4 -4
- package/server/terminal/terminal-manager.mjs +2 -4
- package/server/tools/definitions.mjs +3 -3
- package/server/tools/index.mjs +7 -5
- package/server/utils/network.mjs +9 -0
- package/server/utils/package-update.mjs +70 -47
- package/server/utils/process-env.mjs +7 -0
- package/server/utils/response.mjs +10 -3
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +485 -0
- package/skills/skill-creator/UPSTREAM.md +6 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +247 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +328 -0
- package/skills/skill-creator/scripts/utils.py +47 -0
- package/dist/assets/AgentProfilesPage-D7pbg8nm.js +0 -1
- package/dist/assets/ChatPanelHost-wfGCaCzD.js +0 -288
- package/dist/assets/PluginsPage-NAGroBm3.js +0 -1
- package/dist/assets/ScheduledTasksPage-Bp0MNfQD.js +0 -2
- package/dist/assets/SettingsWorkspacePage-BtJZMIsZ.js +0 -1576
- package/dist/assets/SharedConversationPage-Ce3KoVZt.js +0 -1
- package/dist/assets/TerminalDock-4eUuXP7X.js +0 -2
- package/dist/assets/WorkspaceInspector-kM3BRPjY.js +0 -13
- package/dist/assets/architecture-TIHT7OUA-BgP-IMeo.js +0 -1
- package/dist/assets/channel-Rz20dKTK.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-Cb14ZF_k.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-BOZvd2Sn.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-CD_EGCtT.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-C_ozTKCt.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-FOfFbbZF.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-BzPhLtd5.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-BcgGbVJ-.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-dtkzcC8E.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-VByWboBU.js +0 -1
- package/dist/assets/icons-BP8YOS-Z.js +0 -1
- package/dist/assets/index-C6k5taeb.js +0 -66
- package/dist/assets/index-CzN8NSKC.css +0 -3
- package/dist/assets/info-DKCQHKI2-CZeDLZxx.js +0 -1
- package/dist/assets/packet-7NZHBO7P-decrrxyX.js +0 -1
- package/dist/assets/pie-RZYD4A2V-J1CasQZl.js +0 -1
- package/dist/assets/radar-I7S5WNFK-B-sZytUA.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-BSaqNPm8.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-lzZR7PxT.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-DQtz1Fh9.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-CpMsuGY3.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BGLshxcY.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CqdqxA-b.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-Byb71heW.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-CMV1SJsq.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-DtCHtr2V.js +0 -1
- /package/dist/assets/{array-CYkMkqnU.js → array-B9UHiPd-.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-77hsebd7.js → chunk-KEIR6QF5-jrz1pRUS.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-CQltPwYk.js → chunk-Y2CYZVJY-D6N-CrJv.js} +0 -0
- /package/dist/assets/{css-utils-rkE68RDy.js → css-utils-31qzCXsk.js} +0 -0
- /package/dist/assets/{cytoscape.esm-DwdZnGOm.js → cytoscape.esm-DyfqweF2.js} +0 -0
- /package/dist/assets/{defaultLocale-Beh6XjaL.js → defaultLocale-5eAKkKJC.js} +0 -0
- /package/dist/assets/{dist-DelZBZpK.js → dist-CLg13NtV.js} +0 -0
- /package/dist/assets/{graphlib-CAISHZh4.js → graphlib-DJkmx0Cq.js} +0 -0
- /package/dist/assets/{init-Rr1s_RiX.js → init-DlZdxViB.js} +0 -0
- /package/dist/assets/{lit-vendor-Dr3cpBGF.js → lit-vendor-DvaQX_UQ.js} +0 -0
- /package/dist/assets/{logger-B65Akg8A.js → logger-8REuLPGK.js} +0 -0
- /package/dist/assets/{path-BAQ3hXlG.js → path-6uRLdFF7.js} +0 -0
- /package/dist/assets/{plugin-api-BbUkYm3Y.js → plugin-api-Uu2xAB4d.js} +0 -0
- /package/dist/assets/{rough.esm-Djo4Abte.js → rough.esm-Bud4g4fh.js} +0 -0
- /package/dist/assets/{xterm-CGiQzDiR.js → xterm-Bm_IbozX.js} +0 -0
- /package/plugins/{openai-documents → documents}/commands/document.md +0 -0
- /package/plugins/{openai-documents → documents}/skills/documents/SKILL.md +0 -0
- /package/plugins/{openai-presentations → presentations}/commands/presentation.md +0 -0
- /package/plugins/{openai-presentations → presentations}/skills/presentations/SKILL.md +0 -0
- /package/plugins/{openai-spreadsheets → spreadsheets}/commands/spreadsheet.md +0 -0
- /package/plugins/{openai-spreadsheets → spreadsheets}/skills/spreadsheets/SKILL.md +0 -0
package/server/network-proxy.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { SocksClient } from 'socks'
|
|
|
4
4
|
import { atomicUpdate, readStore } from './storage.mjs'
|
|
5
5
|
|
|
6
6
|
const SETTINGS_KEY = 'network-proxy'
|
|
7
|
-
const VALID_MODES = new Set(['direct', 'system', 'manual'])
|
|
7
|
+
const VALID_MODES = new Set(['direct', 'system', 'manual', 'pac'])
|
|
8
8
|
const PROXY_ENV_KEYS = [
|
|
9
9
|
'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'NO_PROXY',
|
|
10
10
|
'http_proxy', 'https_proxy', 'all_proxy', 'no_proxy',
|
|
@@ -60,6 +60,40 @@ export function validateManualProxyUrl(value) {
|
|
|
60
60
|
return `${url.protocol}//${url.host}`
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
export function validatePacUrl(value) {
|
|
64
|
+
let url
|
|
65
|
+
try {
|
|
66
|
+
url = new URL(String(value || '').trim())
|
|
67
|
+
} catch {
|
|
68
|
+
const error = new Error('PAC URL must be a valid HTTP or HTTPS URL')
|
|
69
|
+
error.statusCode = 400
|
|
70
|
+
throw error
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
|
74
|
+
const error = new Error('Only HTTP and HTTPS PAC URLs are supported')
|
|
75
|
+
error.statusCode = 400
|
|
76
|
+
throw error
|
|
77
|
+
}
|
|
78
|
+
if (!url.hostname) {
|
|
79
|
+
const error = new Error('PAC URL must include a host')
|
|
80
|
+
error.statusCode = 400
|
|
81
|
+
throw error
|
|
82
|
+
}
|
|
83
|
+
if (url.username || url.password) {
|
|
84
|
+
const error = new Error('Credentials are not supported in the PAC URL')
|
|
85
|
+
error.statusCode = 400
|
|
86
|
+
throw error
|
|
87
|
+
}
|
|
88
|
+
if (url.hash) {
|
|
89
|
+
const error = new Error('PAC URL cannot include a fragment')
|
|
90
|
+
error.statusCode = 400
|
|
91
|
+
throw error
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return url.href
|
|
95
|
+
}
|
|
96
|
+
|
|
63
97
|
function isLoopbackUrl(input) {
|
|
64
98
|
let url
|
|
65
99
|
try {
|
|
@@ -251,9 +285,27 @@ class SystemProxyDispatcher extends Dispatcher {
|
|
|
251
285
|
}
|
|
252
286
|
}
|
|
253
287
|
|
|
288
|
+
class UnsupportedProxyDispatcher extends Dispatcher {
|
|
289
|
+
constructor(message) {
|
|
290
|
+
super()
|
|
291
|
+
this.error = new Error(message)
|
|
292
|
+
this.error.code = 'QUICKFORGE_PROXY_UNSUPPORTED'
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
dispatch(_options, handler) {
|
|
296
|
+
queueMicrotask(() => handler.onResponseError?.(null, this.error))
|
|
297
|
+
return true
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
async close() {}
|
|
301
|
+
|
|
302
|
+
async destroy() {}
|
|
303
|
+
}
|
|
304
|
+
|
|
254
305
|
async function createNetworkDispatcher(config) {
|
|
255
306
|
if (config.mode === 'manual') return new ProxyAgent(config.proxyUrl)
|
|
256
307
|
if (config.mode === 'system') return new SystemProxyDispatcher(await getNativeResolver())
|
|
308
|
+
if (config.mode === 'pac') return new UnsupportedProxyDispatcher('Custom PAC URLs are not supported by this runtime')
|
|
257
309
|
return new Agent()
|
|
258
310
|
}
|
|
259
311
|
|
|
@@ -291,6 +343,7 @@ async function persistConfig(config) {
|
|
|
291
343
|
async function applyConfig(config) {
|
|
292
344
|
const normalized = normalizeNetworkProxyConfig(config)
|
|
293
345
|
if (normalized.mode === 'manual') normalized.proxyUrl = validateManualProxyUrl(normalized.proxyUrl)
|
|
346
|
+
if (normalized.mode === 'pac') normalized.proxyUrl = validatePacUrl(normalized.proxyUrl)
|
|
294
347
|
|
|
295
348
|
if (hostRuntime) await hostRuntime.apply(normalized)
|
|
296
349
|
else await replaceNetworkDispatcher(normalized)
|
|
@@ -310,6 +363,7 @@ async function nativeStatus() {
|
|
|
310
363
|
source,
|
|
311
364
|
features: {
|
|
312
365
|
pac: config.configuredPac?.state !== 'unsupported',
|
|
366
|
+
pacUrl: false,
|
|
313
367
|
wpad: config.wpadDns?.state !== 'unsupported' || config.wpadDhcp?.state !== 'unsupported',
|
|
314
368
|
httpProxy: true,
|
|
315
369
|
httpsProxy: true,
|
|
@@ -320,7 +374,7 @@ async function nativeStatus() {
|
|
|
320
374
|
return {
|
|
321
375
|
supported: false,
|
|
322
376
|
source: 'none',
|
|
323
|
-
features: { pac: false, wpad: false, httpProxy: false, httpsProxy: false, socks: false },
|
|
377
|
+
features: { pac: false, pacUrl: false, wpad: false, httpProxy: false, httpsProxy: false, socks: false },
|
|
324
378
|
error: error instanceof Error ? error.message : String(error),
|
|
325
379
|
}
|
|
326
380
|
}
|
|
@@ -331,7 +385,9 @@ export async function getNetworkProxyStatus() {
|
|
|
331
385
|
? await hostRuntime.getStatus()
|
|
332
386
|
: await nativeStatus()
|
|
333
387
|
const configuredMode = currentConfig.mode
|
|
334
|
-
const modeSupported = configuredMode
|
|
388
|
+
const modeSupported = configuredMode === 'system'
|
|
389
|
+
? runtimeStatus.supported
|
|
390
|
+
: configuredMode !== 'pac' || runtimeStatus.features?.pacUrl === true
|
|
335
391
|
return {
|
|
336
392
|
configuredMode,
|
|
337
393
|
effectiveMode: modeSupported ? configuredMode : 'unsupported',
|
|
@@ -361,6 +417,15 @@ export async function updateNetworkProxyConfig(value) {
|
|
|
361
417
|
const previous = currentConfig
|
|
362
418
|
const next = normalizeNetworkProxyConfig(value)
|
|
363
419
|
if (next.mode === 'manual') next.proxyUrl = validateManualProxyUrl(next.proxyUrl)
|
|
420
|
+
if (next.mode === 'pac') {
|
|
421
|
+
next.proxyUrl = validatePacUrl(next.proxyUrl)
|
|
422
|
+
const runtimeStatus = hostRuntime ? await hostRuntime.getStatus() : await nativeStatus()
|
|
423
|
+
if (runtimeStatus.features?.pacUrl !== true) {
|
|
424
|
+
const error = new Error('Custom PAC URLs are not supported by this runtime')
|
|
425
|
+
error.statusCode = 400
|
|
426
|
+
throw error
|
|
427
|
+
}
|
|
428
|
+
}
|
|
364
429
|
|
|
365
430
|
await applyConfig(next)
|
|
366
431
|
try {
|
|
@@ -16,6 +16,13 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
|
16
16
|
const bundledPluginDir = path.resolve(__dirname, '..', '..', 'plugins')
|
|
17
17
|
const globalPluginDir = path.join(dataDir, 'plugins')
|
|
18
18
|
const legacyGlobalPluginDir = path.join(os.homedir(), '.agents', 'plugins')
|
|
19
|
+
const PLUGIN_STORE_SCHEMA_VERSION = 2
|
|
20
|
+
const LEGACY_BUNDLED_PLUGIN_NAMES = {
|
|
21
|
+
'openai-documents': 'documents',
|
|
22
|
+
'openai-presentations': 'presentations',
|
|
23
|
+
'openai-spreadsheets': 'spreadsheets',
|
|
24
|
+
}
|
|
25
|
+
export const DEFAULT_PLUGIN_TOOL_TIMEOUT_MS = 2 * 60 * 1000
|
|
19
26
|
let cachedCatalog = null
|
|
20
27
|
let cachedCatalogKey = null
|
|
21
28
|
let catalogDirty = false
|
|
@@ -29,6 +36,56 @@ function isPlainObject(value) {
|
|
|
29
36
|
return Boolean(value && typeof value === 'object' && !Array.isArray(value))
|
|
30
37
|
}
|
|
31
38
|
|
|
39
|
+
function withTimeout(promise, timeoutMs, message, onTimeout, signal) {
|
|
40
|
+
let timer
|
|
41
|
+
let timedOut = false
|
|
42
|
+
let abortHandler
|
|
43
|
+
const guardedPromise = promise.catch((error) => {
|
|
44
|
+
if (timedOut) return new Promise(() => {})
|
|
45
|
+
throw error
|
|
46
|
+
})
|
|
47
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
48
|
+
const rejectForAbort = () => {
|
|
49
|
+
timedOut = true
|
|
50
|
+
reject(new Error('Plugin tool call aborted'))
|
|
51
|
+
}
|
|
52
|
+
if (signal?.aborted) {
|
|
53
|
+
rejectForAbort()
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
if (signal) {
|
|
57
|
+
abortHandler = rejectForAbort
|
|
58
|
+
signal.addEventListener('abort', abortHandler, { once: true })
|
|
59
|
+
}
|
|
60
|
+
timer = setTimeout(() => {
|
|
61
|
+
timedOut = true
|
|
62
|
+
try {
|
|
63
|
+
onTimeout?.()
|
|
64
|
+
} finally {
|
|
65
|
+
reject(new Error(message))
|
|
66
|
+
}
|
|
67
|
+
}, timeoutMs)
|
|
68
|
+
})
|
|
69
|
+
return Promise.race([guardedPromise, timeoutPromise]).finally(() => {
|
|
70
|
+
clearTimeout(timer)
|
|
71
|
+
if (abortHandler) signal?.removeEventListener('abort', abortHandler)
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function combineAbortSignals(parentSignal, timeoutSignal) {
|
|
76
|
+
if (!parentSignal) return timeoutSignal
|
|
77
|
+
if (typeof AbortSignal.any === 'function') return AbortSignal.any([parentSignal, timeoutSignal])
|
|
78
|
+
|
|
79
|
+
const controller = new AbortController()
|
|
80
|
+
const abort = () => controller.abort()
|
|
81
|
+
if (parentSignal.aborted || timeoutSignal.aborted) controller.abort()
|
|
82
|
+
else {
|
|
83
|
+
parentSignal.addEventListener('abort', abort, { once: true })
|
|
84
|
+
timeoutSignal.addEventListener('abort', abort, { once: true })
|
|
85
|
+
}
|
|
86
|
+
return controller.signal
|
|
87
|
+
}
|
|
88
|
+
|
|
32
89
|
async function exists(filePath) {
|
|
33
90
|
try {
|
|
34
91
|
await fs.access(filePath)
|
|
@@ -57,13 +114,31 @@ async function listPluginDirs(root) {
|
|
|
57
114
|
function normalizePluginStore(store) {
|
|
58
115
|
const source = isPlainObject(store) ? store : {}
|
|
59
116
|
return {
|
|
60
|
-
|
|
61
|
-
|
|
117
|
+
schemaVersion: Number.isInteger(source.schemaVersion) ? source.schemaVersion : 1,
|
|
118
|
+
enabled: isPlainObject(source.enabled) ? { ...source.enabled } : {},
|
|
119
|
+
config: isPlainObject(source.config) ? { ...source.config } : {},
|
|
62
120
|
}
|
|
63
121
|
}
|
|
64
122
|
|
|
123
|
+
function migratePluginStore(store) {
|
|
124
|
+
const next = normalizePluginStore(store)
|
|
125
|
+
if (next.schemaVersion >= PLUGIN_STORE_SCHEMA_VERSION) return { store: next, changed: false }
|
|
126
|
+
|
|
127
|
+
for (const [legacyName, name] of Object.entries(LEGACY_BUNDLED_PLUGIN_NAMES)) {
|
|
128
|
+
if (!(name in next.enabled) && legacyName in next.enabled) next.enabled[name] = next.enabled[legacyName]
|
|
129
|
+
if (!(name in next.config) && legacyName in next.config) next.config[name] = next.config[legacyName]
|
|
130
|
+
delete next.enabled[legacyName]
|
|
131
|
+
delete next.config[legacyName]
|
|
132
|
+
}
|
|
133
|
+
next.schemaVersion = PLUGIN_STORE_SCHEMA_VERSION
|
|
134
|
+
return { store: next, changed: true }
|
|
135
|
+
}
|
|
136
|
+
|
|
65
137
|
async function readPluginStore() {
|
|
66
|
-
|
|
138
|
+
const current = await readStore('plugins')
|
|
139
|
+
const migration = migratePluginStore(current)
|
|
140
|
+
if (!migration.changed) return migration.store
|
|
141
|
+
return atomicUpdate('plugins', (store) => migratePluginStore(store).store)
|
|
67
142
|
}
|
|
68
143
|
|
|
69
144
|
function contributionSummary(contribution) {
|
|
@@ -241,7 +316,7 @@ export async function getPluginStatus(projectContext = null) {
|
|
|
241
316
|
|
|
242
317
|
export async function setPluginEnabled(name, enabled) {
|
|
243
318
|
await atomicUpdate('plugins', (store) => {
|
|
244
|
-
const next =
|
|
319
|
+
const next = migratePluginStore(store).store
|
|
245
320
|
next.enabled[name] = enabled === true
|
|
246
321
|
return next
|
|
247
322
|
})
|
|
@@ -250,7 +325,7 @@ export async function setPluginEnabled(name, enabled) {
|
|
|
250
325
|
|
|
251
326
|
export async function setPluginConfig(name, config) {
|
|
252
327
|
await atomicUpdate('plugins', (store) => {
|
|
253
|
-
const next =
|
|
328
|
+
const next = migratePluginStore(store).store
|
|
254
329
|
next.config[name] = isPlainObject(config) ? config : {}
|
|
255
330
|
return next
|
|
256
331
|
})
|
|
@@ -308,10 +383,19 @@ export async function callPluginTool(toolName, params = {}, toolContext = {}) {
|
|
|
308
383
|
throw error
|
|
309
384
|
}
|
|
310
385
|
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
386
|
+
const timeoutController = new AbortController()
|
|
387
|
+
const signal = combineAbortSignals(toolContext.signal, timeoutController.signal)
|
|
388
|
+
const result = await withTimeout(
|
|
389
|
+
Promise.resolve().then(() => handler.callTool(tool.name, params, {
|
|
390
|
+
...toolContext,
|
|
391
|
+
signal,
|
|
392
|
+
plugin: { name: plugin.name, dir: plugin.dir, config: plugin.config },
|
|
393
|
+
})),
|
|
394
|
+
DEFAULT_PLUGIN_TOOL_TIMEOUT_MS,
|
|
395
|
+
`Plugin tool ${toolName} timed out after ${DEFAULT_PLUGIN_TOOL_TIMEOUT_MS}ms`,
|
|
396
|
+
() => timeoutController.abort(),
|
|
397
|
+
toolContext.signal,
|
|
398
|
+
)
|
|
315
399
|
|
|
316
400
|
return {
|
|
317
401
|
isError: Boolean(result.isError),
|
package/server/public-api.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
4
|
+
import { createNodeProcessEnv } from './utils/process-env.mjs'
|
|
4
5
|
|
|
5
6
|
const __filename = fileURLToPath(import.meta.url)
|
|
6
7
|
const __dirname = path.dirname(__filename)
|
|
@@ -83,13 +84,16 @@ function buildEnv(options = {}) {
|
|
|
83
84
|
if (options.workspaceDir) env.QUICKFORGE_WORKSPACE_DIR = path.resolve(options.workspaceDir)
|
|
84
85
|
if (options.vitePort) env.QUICKFORGE_VITE_PORT = String(options.vitePort)
|
|
85
86
|
if (options.terminal === false) env.QUICKFORGE_TERMINAL = '0'
|
|
86
|
-
if (process.versions.electron) env.ELECTRON_RUN_AS_NODE = '1'
|
|
87
87
|
if (options.allowRemote || shareLan) env.QUICKFORGE_ALLOW_REMOTE = '1'
|
|
88
|
+
delete env.ELECTRON_RUN_AS_NODE
|
|
89
|
+
delete env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
|
88
90
|
|
|
89
91
|
return env
|
|
90
92
|
}
|
|
91
93
|
|
|
92
94
|
export function prepareQuickForgeEnv(options = {}) {
|
|
95
|
+
delete process.env.ELECTRON_RUN_AS_NODE
|
|
96
|
+
delete process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE
|
|
93
97
|
Object.assign(process.env, buildEnv(options))
|
|
94
98
|
}
|
|
95
99
|
|
|
@@ -191,7 +195,7 @@ export async function startQuickForge(options = {}) {
|
|
|
191
195
|
stdio: options.stdio || 'ignore',
|
|
192
196
|
windowsHide: true,
|
|
193
197
|
shell: false,
|
|
194
|
-
env: buildEnv(options),
|
|
198
|
+
env: createNodeProcessEnv(buildEnv(options)),
|
|
195
199
|
})
|
|
196
200
|
|
|
197
201
|
let exitInfo = null
|
|
@@ -1,8 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { streamSimpleWithAiHttpLogging } from '../ai-http-logger.mjs'
|
|
2
2
|
import { DEFAULT_AI_MAX_RETRIES } from '../ai-provider-options.mjs'
|
|
3
3
|
import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
|
|
4
4
|
import { readStore } from '../storage.mjs'
|
|
5
5
|
import { logger } from '../utils/logger.mjs'
|
|
6
|
+
import { resolveModelBinding } from '../model-catalog.mjs'
|
|
7
|
+
|
|
8
|
+
function profileModelReference(model) {
|
|
9
|
+
if (!model || model.mode !== 'fixed') return null
|
|
10
|
+
if (model.source === 'cloud') return { version: 1, source: 'cloud', catalogId: model.catalogId || model.modelId }
|
|
11
|
+
if (model.source === 'custom') return { version: 1, source: 'custom', providerId: model.providerId, modelId: model.modelId }
|
|
12
|
+
return {
|
|
13
|
+
version: 1,
|
|
14
|
+
source: 'legacy-custom',
|
|
15
|
+
provider: model.provider,
|
|
16
|
+
modelId: model.modelId,
|
|
17
|
+
...(model.api ? { api: model.api } : {}),
|
|
18
|
+
...(model.baseUrl ? { baseUrl: model.baseUrl } : {}),
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function canonicalizeProfileModel(body, current, context) {
|
|
23
|
+
if (!body || !Object.prototype.hasOwnProperty.call(body, 'model')) return body
|
|
24
|
+
const model = body.model
|
|
25
|
+
if (!model || model.mode !== 'fixed') return body
|
|
26
|
+
if (current?.model && JSON.stringify(current.model) === JSON.stringify(model)) return body
|
|
27
|
+
const binding = await resolveModelBinding({ modelRef: profileModelReference(model) }, { context })
|
|
28
|
+
const ref = binding.modelRef
|
|
29
|
+
return {
|
|
30
|
+
...body,
|
|
31
|
+
model: ref.source === 'cloud'
|
|
32
|
+
? { mode: 'fixed', source: 'cloud', catalogId: ref.catalogId }
|
|
33
|
+
: { mode: 'fixed', source: 'custom', providerId: ref.providerId, modelId: ref.modelId },
|
|
34
|
+
}
|
|
35
|
+
}
|
|
6
36
|
import {
|
|
7
37
|
agentProfileSnapshot,
|
|
8
38
|
createCustomAgentProfile,
|
|
@@ -65,10 +95,14 @@ function normalizeGeneratedAgentProfile(value) {
|
|
|
65
95
|
return { name, label, description, systemPrompt }
|
|
66
96
|
}
|
|
67
97
|
|
|
68
|
-
async function generateAgentProfileWithAi(instruction,
|
|
98
|
+
async function generateAgentProfileWithAi(instruction, modelInput, thinkingLevel = 'off', context = {}) {
|
|
69
99
|
const text = String(instruction || '').trim()
|
|
70
100
|
if (!text) throw requestError('Please describe the agent you want to create')
|
|
71
|
-
if (!
|
|
101
|
+
if (!modelInput) throw requestError('Please configure a default model first')
|
|
102
|
+
const { model } = await resolveModelBinding(
|
|
103
|
+
modelInput?.modelRef || modelInput?.model ? modelInput : { model: modelInput },
|
|
104
|
+
{ context, legacySnapshot: modelInput?.model || modelInput },
|
|
105
|
+
)
|
|
72
106
|
|
|
73
107
|
const systemPrompt = `You are a QuickForge Agent Profile generator.
|
|
74
108
|
Generate only the basic definition fields for a custom Agent Profile from the user's request.
|
|
@@ -90,7 +124,7 @@ Rules:
|
|
|
90
124
|
- If the user requests Chinese, write label, description, and systemPrompt in Chinese; otherwise match the user's language.`
|
|
91
125
|
|
|
92
126
|
try {
|
|
93
|
-
const stream =
|
|
127
|
+
const stream = streamSimpleWithAiHttpLogging(
|
|
94
128
|
model,
|
|
95
129
|
{
|
|
96
130
|
systemPrompt,
|
|
@@ -120,7 +154,7 @@ Rules:
|
|
|
120
154
|
}
|
|
121
155
|
}
|
|
122
156
|
|
|
123
|
-
export async function handleAgentProfilesApi(req, res, url) {
|
|
157
|
+
export async function handleAgentProfilesApi(req, res, url, context = {}) {
|
|
124
158
|
const parts = url.pathname.split('/').filter(Boolean)
|
|
125
159
|
|
|
126
160
|
if (req.method === 'GET' && url.pathname === '/api/agent-profiles') {
|
|
@@ -136,13 +170,13 @@ export async function handleAgentProfilesApi(req, res, url) {
|
|
|
136
170
|
|
|
137
171
|
if (req.method === 'POST' && url.pathname === '/api/agent-profiles/ai-fill') {
|
|
138
172
|
const body = await readJsonBody(req)
|
|
139
|
-
sendJson(res, 200, { agent: await generateAgentProfileWithAi(body?.instruction, body?.model, body?.thinkingLevel) })
|
|
173
|
+
sendJson(res, 200, { agent: await generateAgentProfileWithAi(body?.instruction, body?.modelRef ? body : body?.model, body?.thinkingLevel, context) })
|
|
140
174
|
return
|
|
141
175
|
}
|
|
142
176
|
|
|
143
177
|
if (req.method === 'POST' && url.pathname === '/api/agent-profiles') {
|
|
144
178
|
const body = await readJsonBody(req)
|
|
145
|
-
sendJson(res, 200, { agent: await createCustomAgentProfile(body || {}) })
|
|
179
|
+
sendJson(res, 200, { agent: await createCustomAgentProfile(await canonicalizeProfileModel(body || {}, null, context)) })
|
|
146
180
|
return
|
|
147
181
|
}
|
|
148
182
|
|
|
@@ -162,11 +196,11 @@ export async function handleAgentProfilesApi(req, res, url) {
|
|
|
162
196
|
if (current?.builtin) {
|
|
163
197
|
const keys = Object.keys(body || {})
|
|
164
198
|
if (keys.length !== 1 || keys[0] !== 'model') throw requestError('Built-in agents only allow model updates', 403)
|
|
165
|
-
sendJson(res, 200, { agent: agentProfileSnapshot(await updateBuiltinAgentModelOverride(id, body.model)) })
|
|
199
|
+
sendJson(res, 200, { agent: agentProfileSnapshot(await updateBuiltinAgentModelOverride(id, (await canonicalizeProfileModel(body, current, context)).model)) })
|
|
166
200
|
return
|
|
167
201
|
}
|
|
168
202
|
if (current?.readonly) throw requestError('Read-only agents cannot be modified from the API', 403)
|
|
169
|
-
sendJson(res, 200, { agent: await updateCustomAgentProfile(id, body || {}) })
|
|
203
|
+
sendJson(res, 200, { agent: await updateCustomAgentProfile(id, await canonicalizeProfileModel(body || {}, current, context)) })
|
|
170
204
|
return
|
|
171
205
|
}
|
|
172
206
|
|
package/server/routes/agent.mjs
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
|
|
2
|
+
import { logger } from '../utils/logger.mjs'
|
|
3
|
+
import { resolveModelBinding } from '../model-catalog.mjs'
|
|
2
4
|
import {
|
|
3
5
|
createAgent,
|
|
4
6
|
runPrompt,
|
|
@@ -30,7 +32,7 @@ import {
|
|
|
30
32
|
agentEvents,
|
|
31
33
|
} from '../agent-manager.mjs'
|
|
32
34
|
|
|
33
|
-
export async function handleAgentApi(req, res, url) {
|
|
35
|
+
export async function handleAgentApi(req, res, url, context = {}) {
|
|
34
36
|
const pathname = url.pathname
|
|
35
37
|
const parts = pathname.split('/').filter(Boolean)
|
|
36
38
|
|
|
@@ -84,7 +86,7 @@ export async function handleAgentApi(req, res, url) {
|
|
|
84
86
|
error.statusCode = 400
|
|
85
87
|
throw error
|
|
86
88
|
}
|
|
87
|
-
const result = await runPrompt(sessionId, message, body?.selectedCapabilities, body?.command)
|
|
89
|
+
const result = await runPrompt(sessionId, message, body?.selectedCapabilities, body?.command, null, context)
|
|
88
90
|
sendJson(res, 200, result)
|
|
89
91
|
return
|
|
90
92
|
}
|
|
@@ -96,6 +98,30 @@ export async function handleAgentApi(req, res, url) {
|
|
|
96
98
|
return
|
|
97
99
|
}
|
|
98
100
|
|
|
101
|
+
// POST /api/agents/:sessionId/restore — restore once and return the authoritative state
|
|
102
|
+
if (req.method === 'POST' && subPath === 'restore') {
|
|
103
|
+
const startedAt = performance.now()
|
|
104
|
+
const session = await restoreAgent(sessionId)
|
|
105
|
+
if (!session) {
|
|
106
|
+
const error = new Error('Session not found')
|
|
107
|
+
error.statusCode = 404
|
|
108
|
+
throw error
|
|
109
|
+
}
|
|
110
|
+
const state = getSessionState(sessionId)
|
|
111
|
+
if (!state) {
|
|
112
|
+
const error = new Error('Session not found')
|
|
113
|
+
error.statusCode = 404
|
|
114
|
+
throw error
|
|
115
|
+
}
|
|
116
|
+
logger.debug(`Restored session ${sessionId} for client`, {
|
|
117
|
+
sessionId,
|
|
118
|
+
messageCount: state.messages?.length ?? 0,
|
|
119
|
+
durationMs: Math.round((performance.now() - startedAt) * 10) / 10,
|
|
120
|
+
})
|
|
121
|
+
sendJson(res, 200, state)
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
99
125
|
// GET /api/agents/:sessionId/state — get session state
|
|
100
126
|
if (req.method === 'GET' && subPath === 'state') {
|
|
101
127
|
let state = getSessionState(sessionId)
|
|
@@ -135,12 +161,22 @@ export async function handleAgentApi(req, res, url) {
|
|
|
135
161
|
// POST /api/agents/:sessionId — create/ensure agent
|
|
136
162
|
if (req.method === 'POST' && parts.length === 3) {
|
|
137
163
|
const body = await readJsonBody(req)
|
|
138
|
-
|
|
164
|
+
let config
|
|
165
|
+
if (body?.modelRef || body?.model) {
|
|
166
|
+
const binding = await resolveModelBinding(body, { context, legacySnapshot: body?.model })
|
|
167
|
+
config = { ...body, model: binding.model, modelRef: binding.modelRef, modelAccessContext: context, resolvePersistedModel: true }
|
|
168
|
+
} else {
|
|
169
|
+
config = { ...body, modelAccessContext: context, resolvePersistedModel: true }
|
|
170
|
+
}
|
|
171
|
+
const session = await createAgent(sessionId, config)
|
|
139
172
|
sendJson(res, 200, {
|
|
140
173
|
sessionId: session.sessionId,
|
|
141
174
|
status: session.status,
|
|
142
175
|
scope: session.scope,
|
|
143
176
|
title: session.title,
|
|
177
|
+
source: session.source || undefined,
|
|
178
|
+
channelId: session.channelId || undefined,
|
|
179
|
+
channelName: session.channelName || undefined,
|
|
144
180
|
accessMode: session.accessMode,
|
|
145
181
|
yoloMode: session.yoloMode,
|
|
146
182
|
})
|
|
@@ -181,13 +217,14 @@ export async function handleAgentApi(req, res, url) {
|
|
|
181
217
|
// POST /api/agents/:sessionId/model — update session model
|
|
182
218
|
if (req.method === 'POST' && subPath === 'model') {
|
|
183
219
|
const body = await readJsonBody(req)
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
220
|
+
const currentModel = getSessionState(sessionId)?.model
|
|
221
|
+
const binding = await resolveModelBinding(body, {
|
|
222
|
+
context,
|
|
223
|
+
currentModel,
|
|
224
|
+
allowCurrentHidden: true,
|
|
225
|
+
legacySnapshot: body?.model,
|
|
226
|
+
})
|
|
227
|
+
const result = updateSessionModel(sessionId, binding.model, binding.modelRef)
|
|
191
228
|
sendJson(res, 200, result)
|
|
192
229
|
return
|
|
193
230
|
}
|
|
@@ -216,7 +253,7 @@ export async function handleAgentApi(req, res, url) {
|
|
|
216
253
|
|
|
217
254
|
// POST /api/agents/:sessionId/continue — continue generation from last message (retry)
|
|
218
255
|
if (req.method === 'POST' && subPath === 'continue') {
|
|
219
|
-
const result = await continueSession(sessionId)
|
|
256
|
+
const result = await continueSession(sessionId, context)
|
|
220
257
|
sendJson(res, 200, result)
|
|
221
258
|
return
|
|
222
259
|
}
|
package/server/routes/backup.mjs
CHANGED
|
@@ -580,7 +580,13 @@ async function restoreValidatedBackup(backup, mode = 'replace') {
|
|
|
580
580
|
return summary
|
|
581
581
|
}
|
|
582
582
|
|
|
583
|
-
export async function handleBackupApi(req, res, url) {
|
|
583
|
+
export async function handleBackupApi(req, res, url, context = {}) {
|
|
584
|
+
if (context.isLocalRequest === false) {
|
|
585
|
+
const error = new Error('Backup import and export are available only on this computer.')
|
|
586
|
+
error.statusCode = 403
|
|
587
|
+
error.errorCode = 'backup_local_only'
|
|
588
|
+
throw error
|
|
589
|
+
}
|
|
584
590
|
if (req.method === 'GET' && url.pathname === '/api/backup/export') {
|
|
585
591
|
await ensureStorage()
|
|
586
592
|
sendJson(res, 200, await buildBackup(url.searchParams.get('scope'), {
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs'
|
|
2
|
+
import { logger } from '../utils/logger.mjs'
|
|
1
3
|
import { sendJson, decodeSegment, readJsonBody } from '../utils/response.mjs'
|
|
4
|
+
import { channelLogsDirectory } from '../channels/channel-logs.mjs'
|
|
5
|
+
import { openPathInFileManager } from '../utils/platform.mjs'
|
|
2
6
|
import {
|
|
3
7
|
channelEvents,
|
|
4
8
|
getChannelStatus,
|
|
@@ -25,6 +29,24 @@ function assertActionHeader(req) {
|
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
|
|
32
|
+
function assertEventHeader(req) {
|
|
33
|
+
if (req.headers['x-quickforge-action'] !== 'channel-event') {
|
|
34
|
+
const error = new Error('Forbidden event')
|
|
35
|
+
error.statusCode = 403
|
|
36
|
+
throw error
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function readChannelEvent(req) {
|
|
41
|
+
const event = await readJsonBody(req, 256 * 1024)
|
|
42
|
+
if (!event || event.type !== 'sessions-changed' || typeof event.sessionId !== 'string' || !event.sessionId.trim()) {
|
|
43
|
+
const error = new Error('Invalid channel event')
|
|
44
|
+
error.statusCode = 400
|
|
45
|
+
throw error
|
|
46
|
+
}
|
|
47
|
+
return event
|
|
48
|
+
}
|
|
49
|
+
|
|
28
50
|
async function readActionOptions(req) {
|
|
29
51
|
if (!['POST', 'PUT', 'PATCH'].includes(req.method || '')) return {}
|
|
30
52
|
const contentType = String(req.headers['content-type'] || '')
|
|
@@ -46,6 +68,15 @@ export async function handleChannelsApi(req, res, url, context = {}) {
|
|
|
46
68
|
return
|
|
47
69
|
}
|
|
48
70
|
|
|
71
|
+
if (req.method === 'POST' && pathname === '/api/channels/events') {
|
|
72
|
+
assertLocal(context)
|
|
73
|
+
assertEventHeader(req)
|
|
74
|
+
const event = await readChannelEvent(req)
|
|
75
|
+
channelEvents.emit('channel_event', event)
|
|
76
|
+
sendJson(res, 202, { ok: true })
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
49
80
|
if (parts.length < 3 || parts[0] !== 'api' || parts[1] !== 'channels') {
|
|
50
81
|
const error = new Error('Not found')
|
|
51
82
|
error.statusCode = 404
|
|
@@ -67,6 +98,22 @@ export async function handleChannelsApi(req, res, url, context = {}) {
|
|
|
67
98
|
|
|
68
99
|
assertLocal(context)
|
|
69
100
|
|
|
101
|
+
if (req.method === 'POST' && subPath.length === 1 && subPath[0] === 'open-logs') {
|
|
102
|
+
assertActionHeader(req)
|
|
103
|
+
getChannelStatus(channelId)
|
|
104
|
+
if (!context.logsDir) {
|
|
105
|
+
const error = new Error('Channel log directory is unavailable')
|
|
106
|
+
error.statusCode = 500
|
|
107
|
+
throw error
|
|
108
|
+
}
|
|
109
|
+
const directory = channelLogsDirectory(context.logsDir, channelId)
|
|
110
|
+
await fs.mkdir(directory, { recursive: true })
|
|
111
|
+
await (context.openPathInFileManager ?? openPathInFileManager)(directory)
|
|
112
|
+
logger.info('Opened channel log directory.', { channelId })
|
|
113
|
+
sendJson(res, 200, { ok: true })
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
70
117
|
if (req.method === 'POST' && subPath[0] === 'start') {
|
|
71
118
|
assertActionHeader(req)
|
|
72
119
|
sendJson(res, 202, await startChannel(channelId, await readActionOptions(req)))
|