@shawnstack/quickforge 1.7.4 → 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/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-B53_eDf2.js → SettingsWorkspacePage-Cb54Ic91.js} +389 -378
- package/dist/assets/ShareLinksSettingsPage-C75WJpaF.js +1 -0
- package/dist/assets/SharedConversationPage-CjMtSQTW.js +1 -0
- package/dist/assets/{TerminalDock-Dgg-_ZmU.js → TerminalDock-D4zJBJc4.js} +2 -2
- package/dist/assets/WorkspaceInspector-D9kdnLDd.js +36 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-Dy7veffk.js → abnfDiagram-VRR7QNED-CMhVoYUh.js} +1 -1
- package/dist/assets/{arc-Bo3p2lGy.js → arc-w21O0TLn.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-DMwFMHxq.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-Cwx8qOvu.js → architectureDiagram-ZJ3FMSHR-C52qL6Hg.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-BiuaAOFa.js → blockDiagram-677ZJIJ3-CM3XbLol.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-BTcGfhK2.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-B9PuF_RF.js → chunk-32BRIVSS-xgrtbT8e.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-3zGItfIM.js → chunk-52WLFC77-CDbaHw80.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DQ66qlmt.js → chunk-5FCAYU7R-CcSvVbPc.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-CLqTO-VF.js → chunk-5HE753X5-erFpzzgx.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-Csxv1jr6.js → chunk-5JV3BV7I-rEhN9F6G.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-BCQttpBr.js → chunk-5TONJI2A-D8L-QTwD.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DEWJGSTb.js → chunk-5VM5RSS4-CjlfMBbM.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-DNorm9MM.js → chunk-7BUUIJ7U-CCcsI9XE.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DgvY_BOT.js → chunk-BIQX33UG-FSqFbmb3.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-DMvn9IPs.js → chunk-C7G6YPKG-ZMLUvfLy.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-Dq2duUgr.js → chunk-CQNSW5MT-DZuBpk25.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-BovYyc4Y.js → chunk-CYSBUYHQ-CB26wsG0.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-BMDOpuYN.js → chunk-EMLP6XTP-BbsM8oRw.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-6eP2UPOf.js → chunk-EX3LRPZG-BcQhaqt7.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-D4q-wTSy.js → chunk-FWX5IMBZ-DrnrdrSu.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-XjIcuzH7.js → chunk-HOUHSVGY-tdc-Z9eW.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-YBXbanq9.js → chunk-ICXQ74PX-Cd7igVGt.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-CcN3uNXF.js → chunk-JG7HCLWE-iXXGW8nf.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-Cwg6AUAt.js → chunk-JWPE2WC7-BZ87mXEv.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-NNspcGIU.js → chunk-MOJQB5TN-CLTjV5ov.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-pMJ_jMos.js → chunk-MOZMSUNE-B3SCBrRH.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-CJy-3Ldv.js → chunk-OGEWGWER-TgvkXkFX.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-D7cLHHOA.js → chunk-OSBZ3O6U-B9E2E5v1.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-D5YBi1Pi.js → chunk-PUDLZKDR-C5GMVYup.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DYmqQdIf.js → chunk-Q4XR5HBZ-fo5-HsqY.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-Bfcx00X0.js → chunk-QBLGF6JB-Dwfg8sKc.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-oXzadpZY.js → chunk-R7FJI6CG-DpBrv4ni.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-Dt3-8yUh.js → chunk-RYQCIY6F-DzzmTl11.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-B55eSvpx.js → chunk-U6XO7XAA-Dw6aviKa.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-Btk4JwCt.js → chunk-V7JOEXUC-CEDazV6w.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-CWYjg8zE.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-DgaSiVOY.js → chunk-VR4S4FIN-C_-eEj-9.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-rRDZ_Tta.js → chunk-WYO6CB5R-NF-MsJJR.js} +3 -3
- package/dist/assets/chunk-XXDRQBXY-DzTwx8ZH.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-BnFxj5o4.js → chunk-YOTPTUD7-DqzqtdII.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-CrnlPlmJ.js → chunk-ZGVPDNZ5-CRrAYi4g.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-BYTiATIH.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-BORKJRwF.js → cose-bilkent-JH36ORCC-cL247pHg.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-C8yCvH_o.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-BXKeaSl8.js → cynefinDiagram-TSTJHNR4-D4sZ7LYI.js} +1 -1
- package/dist/assets/{dagre-CrA0XVwJ.js → dagre-DmHb3Ctt.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-ouq_lA1a.js → dagre-VKFMJZFB-BlsnSh-Q.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-BxR5kUiQ.js → diagram-FQU43EPY-DW1yQiRO.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-DWonk1sL.js → diagram-G47NLZAW-BTUAsFjb.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-fmV_wV5e.js → diagram-NH7WQ7WH-BcaomqSd.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-DvOSRRiV.js → diagram-OA4YK3LP-DDLX7Xwr.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-Bp-xb3uS.js → diagram-WEI45ONY-CIave0An.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BTlnwneA.js → ebnfDiagram-CCIWWBDH-Cr1Y6lPu.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-C3fFWGCm.js → erDiagram-Q63AITRT-D3EgiVVH.js} +1 -1
- package/dist/assets/{esm-oa69b5u4.js → esm-Df4edDpj.js} +2 -2
- package/dist/assets/eventmodeling-45OFAUF4-DO1vRTM0.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-BS7KXcqn.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DzAiojNi.js → ganttDiagram-NO4QXBWP-B0oyDIqK.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-m5F5ef09.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-Cv57oNEA.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-B5Z_O3Ro.js → infoDiagram-FWYZ7A6U-B_GzlLIM.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-CKTK_TKV.js → ishikawaDiagram-FXEZZL3T-CKQIsSdU.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-Cm9k4ywW.js → journeyDiagram-5HDEW3XC-DrrvzZL1.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-DzNteLwx.js → kanban-definition-HUTT4EX6-CJQRTdXz.js} +1 -1
- package/dist/assets/{line-BG78c_WJ.js → line-B4DxX7tC.js} +1 -1
- package/dist/assets/{linear-1X20_EGu.js → linear-U-nKUhyW.js} +1 -1
- package/dist/assets/{map-CCI8WZkS.js → map-BneTM-ri.js} +1 -1
- package/dist/assets/{mcp-servers-dialog-GXXD9K0U.js → mcp-servers-dialog-BUSPvaqI.js} +2 -2
- package/dist/assets/{mermaid-parser.core-Bb8HI_OS.js → mermaid-parser.core-BlKWrEdZ.js} +2 -2
- package/dist/assets/{mermaid-renderer-PIaNiXAz.js → mermaid-renderer-jEbqFaTe.js} +2 -2
- package/dist/assets/{mermaid.core-DUHOIwL5.js → mermaid.core-DWpShXCs.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-Tnbszo7b.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-BVtCspYZ.js → monaco-D6OhXgjg.js} +1 -1
- package/dist/assets/{ordinal-v4prQcuq.js → ordinal-B2r5L1v4.js} +1 -1
- package/dist/assets/{otel-D1LswXpM.js → otel-BFnphzjt.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-zIioIZVN.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-CX824Kd0.js → pegDiagram-2B236MQR-CBLkBdnQ.js} +1 -1
- package/dist/assets/{pi-ai-DAJlO9ZB.js → pi-ai-Cr2ee4a0.js} +2 -2
- package/dist/assets/{pi-web-ui-B-RJSxjR.js → pi-web-ui-DV5jKjSg.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-GGWijBvB.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-BT04VWPQ.js → pieDiagram-ENE6RG2P-8tCnwtWS.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-BvOZxkBr.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-DnTU--BV.js → railroadDiagram-RFXS5EU6-CI4ouOBs.js} +1 -1
- package/dist/assets/{react-vendor-eWH0QhNU.js → react-vendor-1KC5PyRx.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE--MZX_yEv.js → requirementDiagram-TGXJPOKE-DtFz7sw4.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-SEZkHhYn.js → sankeyDiagram-HTMAVEWB--VeOwwk9.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BhC2OHiz.js → sequenceDiagram-DBY2YBRQ-B8AHk5Oe.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-Ci5LeToV.js → sizeCapture-X5ZJPWSS-vV_ArM8D.js} +1 -1
- package/dist/assets/{skills-dialog-DDh1h8eH.js → skills-dialog-BThnIUBs.js} +3 -3
- package/dist/assets/{src-CovulcRC.js → src-PYsDme0X.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-DKK5tFT4.js → stateDiagram-2N3HPSRC-etXnJ8X8.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-Dms3pICj.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-DxxGCk67.js → swimlanes-5IMT3BWC-pabIKAmn.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-B14aWjv6.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-BPXB3Sue.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-CxcBCKye.js → vennDiagram-L72KCM5P-CgNf1Q9W.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-E3m1BOJQ.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-DEL6Yes5.js → wardleyDiagram-EHGQE667-Drt5ytec.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-N8cPbcjC.js → xychartDiagram-FW5EYKEG-hhoEo_Ar.js} +1 -1
- package/dist/index.html +9 -8
- package/package.json +3 -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 +36 -26
- package/server/agent-manager.mjs +130 -28
- 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 +98 -12
- 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 +28 -11
- package/server/model-catalog.mjs +262 -0
- package/server/plugins/registry.mjs +29 -5
- package/server/routes/agent-profiles.mjs +41 -7
- package/server/routes/agent.mjs +20 -11
- package/server/routes/backup.mjs +7 -1
- package/server/routes/cloud.mjs +227 -0
- package/server/routes/models.mjs +7 -1
- package/server/routes/scheduled-tasks.mjs +38 -8
- package/server/routes/shared-conversation.mjs +62 -58
- package/server/routes/shares.mjs +76 -1
- package/server/routes/storage.mjs +24 -1
- package/server/routes/workspace.mjs +6 -4
- package/server/share-store.mjs +168 -13
- package/server/skills.mjs +30 -3
- package/server/storage.mjs +7 -1
- package/server/subagents.mjs +3 -3
- package/server/tools/definitions.mjs +1 -1
- package/server/tools/index.mjs +2 -2
- package/server/utils/network.mjs +9 -0
- package/server/utils/response.mjs +8 -1
- 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-B84w-r9S.js +0 -1
- package/dist/assets/ChatPanelHost-CyO8fEoj.js +0 -288
- package/dist/assets/PluginsPage-D2862wul.js +0 -1
- package/dist/assets/ScheduledTasksPage-GqbiJDPX.js +0 -2
- package/dist/assets/SharedConversationPage-Cw2QFnbC.js +0 -1
- package/dist/assets/WorkspaceInspector-3uLiu6Bv.js +0 -13
- package/dist/assets/architecture-TIHT7OUA-7FQo5GbP.js +0 -1
- package/dist/assets/channel-DToA8d-4.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-D_Wxpk-T.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-CIZseNLi.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Do-XYxat.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Bu24Sy-k.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-DKhh5HSW.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-oyiAgYC4.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-YB_0MefX.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-Bc73xdBd.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-Bvp27L0n.js +0 -1
- package/dist/assets/icons-cTkqD_Gi.js +0 -1
- package/dist/assets/index-B48prgLL.js +0 -65
- package/dist/assets/index-DQhwHHer.css +0 -3
- package/dist/assets/info-DKCQHKI2-BsLOivgq.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BKQkXRtk.js +0 -1
- package/dist/assets/pie-RZYD4A2V-BTiTN5Ge.js +0 -1
- package/dist/assets/radar-I7S5WNFK-BU-oVjKM.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-7H2hxNbL.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-Mx6wf6XQ.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-BgXSKhYy.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-DTEl2rAC.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-D8x3mkni.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-C4nOBNp8.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-DOE6NSdf.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-Ca7QD_b4.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-D9O4RKRm.js +0 -1
- /package/dist/assets/{array-DqLCdDFv.js → array-B9UHiPd-.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-s7Qq-R3i.js → chunk-KEIR6QF5-jrz1pRUS.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-BgISNSiw.js → chunk-Y2CYZVJY-D6N-CrJv.js} +0 -0
- /package/dist/assets/{cytoscape.esm-iekjSZ2n.js → cytoscape.esm-DyfqweF2.js} +0 -0
- /package/dist/assets/{defaultLocale-CrJzLgRD.js → defaultLocale-5eAKkKJC.js} +0 -0
- /package/dist/assets/{dist-zzfqk5hx.js → dist-CLg13NtV.js} +0 -0
- /package/dist/assets/{graphlib-CIz_CfxW.js → graphlib-DJkmx0Cq.js} +0 -0
- /package/dist/assets/{init-C0r9Gk5G.js → init-DlZdxViB.js} +0 -0
- /package/dist/assets/{path-DIKpVbHL.js → path-6uRLdFF7.js} +0 -0
- /package/dist/assets/{plugin-api-C8hMT5W6.js → plugin-api-Uu2xAB4d.js} +0 -0
- /package/dist/assets/{rough.esm-BMOtDaaS.js → rough.esm-Bud4g4fh.js} +0 -0
- /package/dist/assets/{web-RgX7H-OH.js → web-DoV8MSMn.js} +0 -0
- /package/dist/assets/{xterm-BFzZ1FH4.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/index.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import { handleToolApi, handleGetTools } from './routes/tools.mjs'
|
|
|
17
17
|
import { handleInstructionsApi } from './routes/instructions.mjs'
|
|
18
18
|
import { handleMemoryApi } from './routes/memory.mjs'
|
|
19
19
|
import { handleSkillsApi } from './routes/skills.mjs'
|
|
20
|
+
import { ensureDefaultGlobalSkills } from './skills.mjs'
|
|
20
21
|
import { handleAgentApi } from './routes/agent.mjs'
|
|
21
22
|
import { handleAgentProfilesApi } from './routes/agent-profiles.mjs'
|
|
22
23
|
import { handleScheduledTasksApi, startScheduledTaskRunner, stopScheduledTaskRunner } from './routes/scheduled-tasks.mjs'
|
|
@@ -33,6 +34,7 @@ import { handleWorkspaceApi, handleGitApi } from './routes/workspace.mjs'
|
|
|
33
34
|
import { handleTerminalApi, handleTerminalUpgrade } from './routes/terminal.mjs'
|
|
34
35
|
import { handleChannelsApi } from './routes/channels.mjs'
|
|
35
36
|
import { handleModelsApi } from './routes/models.mjs'
|
|
37
|
+
import { handleCloudApi } from './routes/cloud.mjs'
|
|
36
38
|
import { serveStatic } from './routes/static.mjs'
|
|
37
39
|
import { logger, flushLogger } from './utils/logger.mjs'
|
|
38
40
|
import { getPackageInfo, checkForUpdates, checkDesktopRelease } from './utils/package-update.mjs'
|
|
@@ -289,12 +291,12 @@ async function handleApi(req, res, url, requestContext = {}) {
|
|
|
289
291
|
|
|
290
292
|
// Conversation share routes (management + public LAN access)
|
|
291
293
|
if (pathname === '/api/shares' || pathname.startsWith('/api/shares/')) {
|
|
292
|
-
await handleSharesApi(req, res, url, { port })
|
|
294
|
+
await handleSharesApi(req, res, url, { ...requestContext, port })
|
|
293
295
|
return
|
|
294
296
|
}
|
|
295
297
|
|
|
296
298
|
if (pathname.startsWith('/api/shared/')) {
|
|
297
|
-
await handleSharedConversationApi(req, res, url)
|
|
299
|
+
await handleSharedConversationApi(req, res, url, requestContext)
|
|
298
300
|
return
|
|
299
301
|
}
|
|
300
302
|
|
|
@@ -336,13 +338,23 @@ async function handleApi(req, res, url, requestContext = {}) {
|
|
|
336
338
|
|
|
337
339
|
// Agent profiles
|
|
338
340
|
if (pathname === '/api/agent-profiles' || pathname.startsWith('/api/agent-profiles/')) {
|
|
339
|
-
await handleAgentProfilesApi(req, res, url)
|
|
341
|
+
await handleAgentProfilesApi(req, res, url, requestContext)
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// QuickForge Cloud account and managed models (local or authenticated Tailscale requests).
|
|
346
|
+
if (pathname === '/api/cloud' || pathname.startsWith('/api/cloud/')) {
|
|
347
|
+
await handleCloudApi(req, res, url, {
|
|
348
|
+
isLocalRequest: requestContext.isLocalRequest === true,
|
|
349
|
+
remoteAddress: requestContext.remoteAddress,
|
|
350
|
+
remoteAuthorized: requestContext.remoteAuthorized === true,
|
|
351
|
+
})
|
|
340
352
|
return
|
|
341
353
|
}
|
|
342
354
|
|
|
343
355
|
// Custom model management (connection test)
|
|
344
|
-
if (pathname === '/api/models/test-connection') {
|
|
345
|
-
await handleModelsApi(req, res, url)
|
|
356
|
+
if (pathname === '/api/models/catalog' || pathname === '/api/models/test-connection') {
|
|
357
|
+
await handleModelsApi(req, res, url, requestContext)
|
|
346
358
|
return
|
|
347
359
|
}
|
|
348
360
|
|
|
@@ -387,7 +399,7 @@ async function handleApi(req, res, url, requestContext = {}) {
|
|
|
387
399
|
}
|
|
388
400
|
|
|
389
401
|
if (pathname.startsWith('/api/git/')) {
|
|
390
|
-
await handleGitApi(req, res, url)
|
|
402
|
+
await handleGitApi(req, res, url, requestContext)
|
|
391
403
|
return
|
|
392
404
|
}
|
|
393
405
|
|
|
@@ -411,19 +423,19 @@ async function handleApi(req, res, url, requestContext = {}) {
|
|
|
411
423
|
|
|
412
424
|
// Agent routes
|
|
413
425
|
if (parts[0] === 'api' && parts[1] === 'agents') {
|
|
414
|
-
await handleAgentApi(req, res, url)
|
|
426
|
+
await handleAgentApi(req, res, url, requestContext)
|
|
415
427
|
return
|
|
416
428
|
}
|
|
417
429
|
|
|
418
430
|
// Scheduled task routes
|
|
419
431
|
if (pathname === '/api/scheduled-tasks' || pathname.startsWith('/api/scheduled-tasks/')) {
|
|
420
|
-
await handleScheduledTasksApi(req, res, url)
|
|
432
|
+
await handleScheduledTasksApi(req, res, url, requestContext)
|
|
421
433
|
return
|
|
422
434
|
}
|
|
423
435
|
|
|
424
436
|
// Backup / import-export routes
|
|
425
437
|
if (pathname === '/api/backup/export' || pathname === '/api/backup/import' || pathname === '/api/backup/inspect' || pathname === '/api/backup/inspect-file') {
|
|
426
|
-
await handleBackupApi(req, res, url)
|
|
438
|
+
await handleBackupApi(req, res, url, requestContext)
|
|
427
439
|
return
|
|
428
440
|
}
|
|
429
441
|
|
|
@@ -461,7 +473,7 @@ async function handleApi(req, res, url, requestContext = {}) {
|
|
|
461
473
|
|
|
462
474
|
// Storage routes (catch-all)
|
|
463
475
|
if (parts[0] === 'api' && parts[1] === 'storage') {
|
|
464
|
-
await handleStorageApi(req, res, url)
|
|
476
|
+
await handleStorageApi(req, res, url, requestContext)
|
|
465
477
|
return
|
|
466
478
|
}
|
|
467
479
|
|
|
@@ -619,7 +631,11 @@ const server = createServer(async (req, res) => {
|
|
|
619
631
|
}
|
|
620
632
|
|
|
621
633
|
if (url.pathname.startsWith('/api/')) {
|
|
622
|
-
await handleApi(req, res, url, {
|
|
634
|
+
await handleApi(req, res, url, {
|
|
635
|
+
isLocalRequest: !isRemoteRequest,
|
|
636
|
+
remoteAddress,
|
|
637
|
+
remoteAuthorized,
|
|
638
|
+
})
|
|
623
639
|
return
|
|
624
640
|
}
|
|
625
641
|
|
|
@@ -681,6 +697,7 @@ server.on('upgrade', (req, socket, head) => {
|
|
|
681
697
|
})
|
|
682
698
|
|
|
683
699
|
await ensureStorage()
|
|
700
|
+
await ensureDefaultGlobalSkills()
|
|
684
701
|
await initializeNetworkProxy()
|
|
685
702
|
installAiHttpLogger()
|
|
686
703
|
initializeChannels({
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { getCloudRuntime } from './cloud/runtime.mjs'
|
|
2
|
+
import { isManagedCloudModel } from './cloud/models.mjs'
|
|
3
|
+
import { readStore } from './storage.mjs'
|
|
4
|
+
import { isTailscaleAddress } from './utils/network.mjs'
|
|
5
|
+
|
|
6
|
+
export const MODEL_REFERENCE_VERSION = 1
|
|
7
|
+
|
|
8
|
+
function requestError(message, statusCode = 400, code) {
|
|
9
|
+
const error = new Error(message)
|
|
10
|
+
error.statusCode = statusCode
|
|
11
|
+
if (code) {
|
|
12
|
+
error.code = code
|
|
13
|
+
error.errorCode = code
|
|
14
|
+
}
|
|
15
|
+
return error
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function normalizedBaseUrl(value) {
|
|
19
|
+
return String(value || '').trim().replace(/\/$/, '')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isUsableModel(model) {
|
|
23
|
+
return Boolean(model && typeof model === 'object' && model.id && model.provider && model.api && model.baseUrl)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function sameModel(left, right) {
|
|
27
|
+
return Boolean(left && right
|
|
28
|
+
&& left.id === right.id
|
|
29
|
+
&& left.provider === right.provider
|
|
30
|
+
&& left.api === right.api
|
|
31
|
+
&& normalizedBaseUrl(left.baseUrl) === normalizedBaseUrl(right.baseUrl))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function publicModel(model, modelRef) {
|
|
35
|
+
const result = {
|
|
36
|
+
...model,
|
|
37
|
+
quickforgeModelRef: modelRef,
|
|
38
|
+
}
|
|
39
|
+
delete result.apiKey
|
|
40
|
+
delete result.key
|
|
41
|
+
delete result.headers
|
|
42
|
+
return result
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async function configuredProviders() {
|
|
46
|
+
const store = await readStore('custom-providers').catch(() => ({}))
|
|
47
|
+
return Array.isArray(store) ? store : Object.values(store || {})
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function configuredEntries(providers) {
|
|
51
|
+
return providers.flatMap((provider) => {
|
|
52
|
+
const providerId = String(provider?.id || '').trim()
|
|
53
|
+
return (Array.isArray(provider?.models) ? provider.models : [])
|
|
54
|
+
.filter(isUsableModel)
|
|
55
|
+
.map((model) => ({ provider, providerId, model }))
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function cloudAllowedForContext(context = {}) {
|
|
60
|
+
if (context.allowCloud === false) return false
|
|
61
|
+
if (context.allowCloud === true || context.source === 'acp' || context.source === 'scheduled') return true
|
|
62
|
+
if (context.isLocalRequest !== false) return true
|
|
63
|
+
return context.remoteAuthorized === true && isTailscaleAddress(context.remoteAddress)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function modelReferenceFromSnapshot(model, providers = []) {
|
|
67
|
+
if (!model || typeof model !== 'object') return null
|
|
68
|
+
if (isManagedCloudModel(model)) {
|
|
69
|
+
const catalogId = String(model.quickforgeCatalogId || model.id || '').trim()
|
|
70
|
+
return catalogId ? { version: MODEL_REFERENCE_VERSION, source: 'cloud', catalogId } : null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const matched = configuredEntries(providers).find((entry) => sameModel(entry.model, model))
|
|
74
|
+
if (matched?.providerId) {
|
|
75
|
+
return {
|
|
76
|
+
version: MODEL_REFERENCE_VERSION,
|
|
77
|
+
source: 'custom',
|
|
78
|
+
providerId: matched.providerId,
|
|
79
|
+
modelId: matched.model.id,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (model.provider && model.id) {
|
|
84
|
+
return {
|
|
85
|
+
version: MODEL_REFERENCE_VERSION,
|
|
86
|
+
source: 'legacy-custom',
|
|
87
|
+
provider: String(model.provider),
|
|
88
|
+
modelId: String(model.id),
|
|
89
|
+
...(model.api ? { api: String(model.api) } : {}),
|
|
90
|
+
...(model.baseUrl ? { baseUrl: String(model.baseUrl) } : {}),
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return null
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function normalizeModelReference(value) {
|
|
97
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return null
|
|
98
|
+
const source = String(value.source || '').trim()
|
|
99
|
+
if (source === 'cloud') {
|
|
100
|
+
const catalogId = String(value.catalogId || value.quickforgeCatalogId || value.modelId || '').trim()
|
|
101
|
+
return catalogId ? { version: MODEL_REFERENCE_VERSION, source: 'cloud', catalogId } : null
|
|
102
|
+
}
|
|
103
|
+
if (source === 'custom') {
|
|
104
|
+
const providerId = String(value.providerId || '').trim()
|
|
105
|
+
const modelId = String(value.modelId || value.id || '').trim()
|
|
106
|
+
return providerId && modelId
|
|
107
|
+
? { version: MODEL_REFERENCE_VERSION, source: 'custom', providerId, modelId }
|
|
108
|
+
: null
|
|
109
|
+
}
|
|
110
|
+
if (source === 'legacy-custom') {
|
|
111
|
+
const provider = String(value.provider || '').trim()
|
|
112
|
+
const modelId = String(value.modelId || value.id || '').trim()
|
|
113
|
+
return provider && modelId
|
|
114
|
+
? {
|
|
115
|
+
version: MODEL_REFERENCE_VERSION,
|
|
116
|
+
source: 'legacy-custom',
|
|
117
|
+
provider,
|
|
118
|
+
modelId,
|
|
119
|
+
...(value.api ? { api: String(value.api) } : {}),
|
|
120
|
+
...(value.baseUrl ? { baseUrl: String(value.baseUrl) } : {}),
|
|
121
|
+
}
|
|
122
|
+
: null
|
|
123
|
+
}
|
|
124
|
+
return null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function listCloudModels(context, { refresh = false } = {}) {
|
|
128
|
+
if (!cloudAllowedForContext(context)) return []
|
|
129
|
+
try {
|
|
130
|
+
const runtime = await getCloudRuntime()
|
|
131
|
+
if (!runtime?.enabled) return []
|
|
132
|
+
const models = await runtime.models.list(undefined, { refresh })
|
|
133
|
+
return models.filter((model) => model?.quickforgeCatalogId)
|
|
134
|
+
} catch {
|
|
135
|
+
return []
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function listModelCatalog({
|
|
140
|
+
context = {},
|
|
141
|
+
includeHidden = false,
|
|
142
|
+
currentModel = null,
|
|
143
|
+
refreshCloud = false,
|
|
144
|
+
} = {}) {
|
|
145
|
+
const providers = await configuredProviders()
|
|
146
|
+
const custom = configuredEntries(providers)
|
|
147
|
+
.filter(({ model }) => includeHidden || model.quickforgeHidden !== true || sameModel(model, currentModel))
|
|
148
|
+
.map(({ providerId, model }) => publicModel(model, {
|
|
149
|
+
version: MODEL_REFERENCE_VERSION,
|
|
150
|
+
source: 'custom',
|
|
151
|
+
providerId,
|
|
152
|
+
modelId: model.id,
|
|
153
|
+
}))
|
|
154
|
+
if (currentModel) {
|
|
155
|
+
const currentIndex = custom.findIndex((model) => sameModel(model, currentModel))
|
|
156
|
+
if (currentIndex > 0 && custom[currentIndex].quickforgeHidden === true) {
|
|
157
|
+
custom.unshift(custom.splice(currentIndex, 1)[0])
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const cloud = (await listCloudModels(context, { refresh: refreshCloud }))
|
|
161
|
+
.map((model) => publicModel(model, {
|
|
162
|
+
version: MODEL_REFERENCE_VERSION,
|
|
163
|
+
source: 'cloud',
|
|
164
|
+
catalogId: model.quickforgeCatalogId,
|
|
165
|
+
}))
|
|
166
|
+
|
|
167
|
+
if (currentModel && ![...custom, ...cloud].some((model) => sameModel(model, currentModel))) {
|
|
168
|
+
const ref = modelReferenceFromSnapshot(currentModel, providers)
|
|
169
|
+
if (ref) return [publicModel(currentModel, ref), ...custom, ...cloud]
|
|
170
|
+
}
|
|
171
|
+
return [...custom, ...cloud]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async function resolveCloud(ref, context) {
|
|
175
|
+
if (!cloudAllowedForContext(context)) {
|
|
176
|
+
throw requestError('QuickForge Cloud is not available from this client.', 403, 'cloud_access_denied')
|
|
177
|
+
}
|
|
178
|
+
const runtime = await getCloudRuntime()
|
|
179
|
+
if (!runtime?.enabled) throw requestError('QuickForge Cloud is not configured.', 503, 'cloud_not_configured')
|
|
180
|
+
return (await runtime.models.resolve({
|
|
181
|
+
provider: 'quickforge-cloud',
|
|
182
|
+
quickforgeModelSource: 'cloud',
|
|
183
|
+
quickforgeCatalogId: ref.catalogId,
|
|
184
|
+
})).publicModel
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function findCustomByReference(ref, entries) {
|
|
188
|
+
if (ref.source === 'custom') {
|
|
189
|
+
return entries.find(({ providerId, model }) => providerId === ref.providerId && model.id === ref.modelId)?.model
|
|
190
|
+
}
|
|
191
|
+
if (ref.source === 'legacy-custom') {
|
|
192
|
+
return entries.find(({ model }) => model.provider === ref.provider
|
|
193
|
+
&& model.id === ref.modelId
|
|
194
|
+
&& (!ref.api || model.api === ref.api)
|
|
195
|
+
&& (!ref.baseUrl || normalizedBaseUrl(model.baseUrl) === normalizedBaseUrl(ref.baseUrl)))?.model
|
|
196
|
+
}
|
|
197
|
+
return null
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export async function resolveModelBinding(input, {
|
|
201
|
+
context = {},
|
|
202
|
+
currentModel = null,
|
|
203
|
+
allowCurrentHidden = false,
|
|
204
|
+
forExecution = false,
|
|
205
|
+
legacySnapshot = null,
|
|
206
|
+
} = {}) {
|
|
207
|
+
const providers = await configuredProviders()
|
|
208
|
+
const entries = configuredEntries(providers)
|
|
209
|
+
const explicitRef = normalizeModelReference(input?.modelRef || input?.quickforgeModelRef || input)
|
|
210
|
+
const snapshot = input?.model && typeof input.model === 'object'
|
|
211
|
+
? input.model
|
|
212
|
+
: (!explicitRef && input && typeof input === 'object' && input.id ? input : legacySnapshot)
|
|
213
|
+
const ref = explicitRef || modelReferenceFromSnapshot(snapshot, providers)
|
|
214
|
+
if (!ref) throw requestError('A valid model reference is required.', 400, 'invalid_model_reference')
|
|
215
|
+
|
|
216
|
+
if (ref.source === 'cloud') {
|
|
217
|
+
const model = await resolveCloud(ref, context)
|
|
218
|
+
return { model, modelRef: ref }
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const configured = findCustomByReference(ref, entries)
|
|
222
|
+
if (configured) {
|
|
223
|
+
const hidden = configured.quickforgeHidden === true
|
|
224
|
+
if (hidden && !forExecution && !(allowCurrentHidden && sameModel(configured, currentModel))) {
|
|
225
|
+
throw requestError('Selected model is not available for new selection.', 400, 'model_not_selectable')
|
|
226
|
+
}
|
|
227
|
+
const canonicalRef = modelReferenceFromSnapshot(configured, providers)
|
|
228
|
+
return { model: configured, modelRef: canonicalRef }
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
throw requestError('Selected model is not configured in QuickForge.', 400, 'model_not_configured')
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export async function resolveImplicitModelPreference(value, context = {}) {
|
|
235
|
+
let stored = value
|
|
236
|
+
if (typeof stored === 'string') {
|
|
237
|
+
try { stored = JSON.parse(stored) } catch { stored = null }
|
|
238
|
+
}
|
|
239
|
+
const ref = normalizeModelReference(stored?.modelRef || stored?.quickforgeModelRef)
|
|
240
|
+
const snapshot = stored?.modelSnapshot || stored?.model || (stored?.id ? stored : null)
|
|
241
|
+
const catalog = await listModelCatalog({ context })
|
|
242
|
+
if (ref) {
|
|
243
|
+
const matched = catalog.find((model) => {
|
|
244
|
+
const candidate = normalizeModelReference(model.quickforgeModelRef)
|
|
245
|
+
if (!candidate || candidate.source !== ref.source) return false
|
|
246
|
+
if (ref.source === 'cloud') return candidate.catalogId === ref.catalogId
|
|
247
|
+
if (ref.source === 'custom') return candidate.providerId === ref.providerId && candidate.modelId === ref.modelId
|
|
248
|
+
return false
|
|
249
|
+
})
|
|
250
|
+
if (matched) return matched
|
|
251
|
+
}
|
|
252
|
+
if (snapshot) {
|
|
253
|
+
const matched = catalog.find((model) => sameModel(model, snapshot))
|
|
254
|
+
if (matched) return matched
|
|
255
|
+
}
|
|
256
|
+
return catalog[0] || null
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
export async function modelBindingFromModel(model) {
|
|
260
|
+
const providers = await configuredProviders()
|
|
261
|
+
return { model, modelRef: modelReferenceFromSnapshot(model, providers) }
|
|
262
|
+
}
|
|
@@ -16,6 +16,12 @@ 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
|
+
}
|
|
19
25
|
export const DEFAULT_PLUGIN_TOOL_TIMEOUT_MS = 2 * 60 * 1000
|
|
20
26
|
let cachedCatalog = null
|
|
21
27
|
let cachedCatalogKey = null
|
|
@@ -108,13 +114,31 @@ async function listPluginDirs(root) {
|
|
|
108
114
|
function normalizePluginStore(store) {
|
|
109
115
|
const source = isPlainObject(store) ? store : {}
|
|
110
116
|
return {
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
schemaVersion: Number.isInteger(source.schemaVersion) ? source.schemaVersion : 1,
|
|
118
|
+
enabled: isPlainObject(source.enabled) ? { ...source.enabled } : {},
|
|
119
|
+
config: isPlainObject(source.config) ? { ...source.config } : {},
|
|
120
|
+
}
|
|
121
|
+
}
|
|
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]
|
|
113
132
|
}
|
|
133
|
+
next.schemaVersion = PLUGIN_STORE_SCHEMA_VERSION
|
|
134
|
+
return { store: next, changed: true }
|
|
114
135
|
}
|
|
115
136
|
|
|
116
137
|
async function readPluginStore() {
|
|
117
|
-
|
|
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)
|
|
118
142
|
}
|
|
119
143
|
|
|
120
144
|
function contributionSummary(contribution) {
|
|
@@ -292,7 +316,7 @@ export async function getPluginStatus(projectContext = null) {
|
|
|
292
316
|
|
|
293
317
|
export async function setPluginEnabled(name, enabled) {
|
|
294
318
|
await atomicUpdate('plugins', (store) => {
|
|
295
|
-
const next =
|
|
319
|
+
const next = migratePluginStore(store).store
|
|
296
320
|
next.enabled[name] = enabled === true
|
|
297
321
|
return next
|
|
298
322
|
})
|
|
@@ -301,7 +325,7 @@ export async function setPluginEnabled(name, enabled) {
|
|
|
301
325
|
|
|
302
326
|
export async function setPluginConfig(name, config) {
|
|
303
327
|
await atomicUpdate('plugins', (store) => {
|
|
304
|
-
const next =
|
|
328
|
+
const next = migratePluginStore(store).store
|
|
305
329
|
next.config[name] = isPlainObject(config) ? config : {}
|
|
306
330
|
return next
|
|
307
331
|
})
|
|
@@ -3,6 +3,36 @@ 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.
|
|
@@ -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,5 +1,6 @@
|
|
|
1
1
|
import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
|
|
2
2
|
import { logger } from '../utils/logger.mjs'
|
|
3
|
+
import { resolveModelBinding } from '../model-catalog.mjs'
|
|
3
4
|
import {
|
|
4
5
|
createAgent,
|
|
5
6
|
runPrompt,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
agentEvents,
|
|
32
33
|
} from '../agent-manager.mjs'
|
|
33
34
|
|
|
34
|
-
export async function handleAgentApi(req, res, url) {
|
|
35
|
+
export async function handleAgentApi(req, res, url, context = {}) {
|
|
35
36
|
const pathname = url.pathname
|
|
36
37
|
const parts = pathname.split('/').filter(Boolean)
|
|
37
38
|
|
|
@@ -85,7 +86,7 @@ export async function handleAgentApi(req, res, url) {
|
|
|
85
86
|
error.statusCode = 400
|
|
86
87
|
throw error
|
|
87
88
|
}
|
|
88
|
-
const result = await runPrompt(sessionId, message, body?.selectedCapabilities, body?.command)
|
|
89
|
+
const result = await runPrompt(sessionId, message, body?.selectedCapabilities, body?.command, null, context)
|
|
89
90
|
sendJson(res, 200, result)
|
|
90
91
|
return
|
|
91
92
|
}
|
|
@@ -160,7 +161,14 @@ export async function handleAgentApi(req, res, url) {
|
|
|
160
161
|
// POST /api/agents/:sessionId — create/ensure agent
|
|
161
162
|
if (req.method === 'POST' && parts.length === 3) {
|
|
162
163
|
const body = await readJsonBody(req)
|
|
163
|
-
|
|
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)
|
|
164
172
|
sendJson(res, 200, {
|
|
165
173
|
sessionId: session.sessionId,
|
|
166
174
|
status: session.status,
|
|
@@ -209,13 +217,14 @@ export async function handleAgentApi(req, res, url) {
|
|
|
209
217
|
// POST /api/agents/:sessionId/model — update session model
|
|
210
218
|
if (req.method === 'POST' && subPath === 'model') {
|
|
211
219
|
const body = await readJsonBody(req)
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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)
|
|
219
228
|
sendJson(res, 200, result)
|
|
220
229
|
return
|
|
221
230
|
}
|
|
@@ -244,7 +253,7 @@ export async function handleAgentApi(req, res, url) {
|
|
|
244
253
|
|
|
245
254
|
// POST /api/agents/:sessionId/continue — continue generation from last message (retry)
|
|
246
255
|
if (req.method === 'POST' && subPath === 'continue') {
|
|
247
|
-
const result = await continueSession(sessionId)
|
|
256
|
+
const result = await continueSession(sessionId, context)
|
|
248
257
|
sendJson(res, 200, result)
|
|
249
258
|
return
|
|
250
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'), {
|