@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.
Files changed (239) hide show
  1. package/dist/assets/AgentProfilesPage-XNjuqJs7.js +1 -0
  2. package/dist/assets/ChatPanelHost-CuF-PZpc.js +292 -0
  3. package/dist/assets/CloudAccountSettingsPage-GJSoi6sO.js +1 -0
  4. package/dist/assets/PluginsPage-BQgp0qN-.js +1 -0
  5. package/dist/assets/ScheduledTasksPage-DdekATzq.js +2 -0
  6. package/dist/assets/{SettingsWorkspacePage-B53_eDf2.js → SettingsWorkspacePage-Cb54Ic91.js} +389 -378
  7. package/dist/assets/ShareLinksSettingsPage-C75WJpaF.js +1 -0
  8. package/dist/assets/SharedConversationPage-CjMtSQTW.js +1 -0
  9. package/dist/assets/{TerminalDock-Dgg-_ZmU.js → TerminalDock-D4zJBJc4.js} +2 -2
  10. package/dist/assets/WorkspaceInspector-D9kdnLDd.js +36 -0
  11. package/dist/assets/{abnfDiagram-VRR7QNED-Dy7veffk.js → abnfDiagram-VRR7QNED-CMhVoYUh.js} +1 -1
  12. package/dist/assets/{arc-Bo3p2lGy.js → arc-w21O0TLn.js} +1 -1
  13. package/dist/assets/architecture-TIHT7OUA-DMwFMHxq.js +1 -0
  14. package/dist/assets/{architectureDiagram-ZJ3FMSHR-Cwx8qOvu.js → architectureDiagram-ZJ3FMSHR-C52qL6Hg.js} +1 -1
  15. package/dist/assets/{blockDiagram-677ZJIJ3-BiuaAOFa.js → blockDiagram-677ZJIJ3-CM3XbLol.js} +1 -1
  16. package/dist/assets/{c4Diagram-LMCZKHZV-BTcGfhK2.js → c4Diagram-LMCZKHZV-D7Bh1ui1.js} +1 -1
  17. package/dist/assets/channel-Duu1CuH9.js +1 -0
  18. package/dist/assets/chunk-2Q5K7J3B-B6rHWc4S.js +1 -0
  19. package/dist/assets/{chunk-32BRIVSS-B9PuF_RF.js → chunk-32BRIVSS-xgrtbT8e.js} +1 -1
  20. package/dist/assets/{chunk-52WLFC77-3zGItfIM.js → chunk-52WLFC77-CDbaHw80.js} +1 -1
  21. package/dist/assets/{chunk-5FCAYU7R-DQ66qlmt.js → chunk-5FCAYU7R-CcSvVbPc.js} +1 -1
  22. package/dist/assets/{chunk-5HE753X5-CLqTO-VF.js → chunk-5HE753X5-erFpzzgx.js} +1 -1
  23. package/dist/assets/{chunk-5JV3BV7I-Csxv1jr6.js → chunk-5JV3BV7I-rEhN9F6G.js} +1 -1
  24. package/dist/assets/{chunk-5TONJI2A-BCQttpBr.js → chunk-5TONJI2A-D8L-QTwD.js} +1 -1
  25. package/dist/assets/{chunk-5VM5RSS4-DEWJGSTb.js → chunk-5VM5RSS4-CjlfMBbM.js} +1 -1
  26. package/dist/assets/{chunk-7BUUIJ7U-DNorm9MM.js → chunk-7BUUIJ7U-CCcsI9XE.js} +1 -1
  27. package/dist/assets/{chunk-BIQX33UG-DgvY_BOT.js → chunk-BIQX33UG-FSqFbmb3.js} +1 -1
  28. package/dist/assets/{chunk-C7G6YPKG-DMvn9IPs.js → chunk-C7G6YPKG-ZMLUvfLy.js} +1 -1
  29. package/dist/assets/{chunk-CQNSW5MT-Dq2duUgr.js → chunk-CQNSW5MT-DZuBpk25.js} +1 -1
  30. package/dist/assets/{chunk-CYSBUYHQ-BovYyc4Y.js → chunk-CYSBUYHQ-CB26wsG0.js} +1 -1
  31. package/dist/assets/{chunk-EMLP6XTP-BMDOpuYN.js → chunk-EMLP6XTP-BbsM8oRw.js} +1 -1
  32. package/dist/assets/{chunk-EX3LRPZG-6eP2UPOf.js → chunk-EX3LRPZG-BcQhaqt7.js} +1 -1
  33. package/dist/assets/{chunk-FWX5IMBZ-D4q-wTSy.js → chunk-FWX5IMBZ-DrnrdrSu.js} +2 -2
  34. package/dist/assets/{chunk-HOUHSVGY-XjIcuzH7.js → chunk-HOUHSVGY-tdc-Z9eW.js} +1 -1
  35. package/dist/assets/{chunk-ICXQ74PX-YBXbanq9.js → chunk-ICXQ74PX-Cd7igVGt.js} +1 -1
  36. package/dist/assets/{chunk-JG7HCLWE-CcN3uNXF.js → chunk-JG7HCLWE-iXXGW8nf.js} +1 -1
  37. package/dist/assets/{chunk-JWPE2WC7-Cwg6AUAt.js → chunk-JWPE2WC7-BZ87mXEv.js} +1 -1
  38. package/dist/assets/{chunk-MOJQB5TN-NNspcGIU.js → chunk-MOJQB5TN-CLTjV5ov.js} +1 -1
  39. package/dist/assets/{chunk-MOZMSUNE-pMJ_jMos.js → chunk-MOZMSUNE-B3SCBrRH.js} +1 -1
  40. package/dist/assets/{chunk-OGEWGWER-CJy-3Ldv.js → chunk-OGEWGWER-TgvkXkFX.js} +1 -1
  41. package/dist/assets/{chunk-OSBZ3O6U-D7cLHHOA.js → chunk-OSBZ3O6U-B9E2E5v1.js} +1 -1
  42. package/dist/assets/{chunk-PUDLZKDR-D5YBi1Pi.js → chunk-PUDLZKDR-C5GMVYup.js} +1 -1
  43. package/dist/assets/{chunk-Q4XR5HBZ-DYmqQdIf.js → chunk-Q4XR5HBZ-fo5-HsqY.js} +1 -1
  44. package/dist/assets/{chunk-QBLGF6JB-Bfcx00X0.js → chunk-QBLGF6JB-Dwfg8sKc.js} +1 -1
  45. package/dist/assets/{chunk-R7FJI6CG-oXzadpZY.js → chunk-R7FJI6CG-DpBrv4ni.js} +1 -1
  46. package/dist/assets/{chunk-RYQCIY6F-Dt3-8yUh.js → chunk-RYQCIY6F-DzzmTl11.js} +1 -1
  47. package/dist/assets/{chunk-U6XO7XAA-B55eSvpx.js → chunk-U6XO7XAA-Dw6aviKa.js} +1 -1
  48. package/dist/assets/{chunk-V7JOEXUC-Btk4JwCt.js → chunk-V7JOEXUC-CEDazV6w.js} +1 -1
  49. package/dist/assets/chunk-VAUOI2AC-CWYjg8zE.js +1 -0
  50. package/dist/assets/{chunk-VR4S4FIN-DgaSiVOY.js → chunk-VR4S4FIN-C_-eEj-9.js} +1 -1
  51. package/dist/assets/{chunk-WYO6CB5R-rRDZ_Tta.js → chunk-WYO6CB5R-NF-MsJJR.js} +3 -3
  52. package/dist/assets/chunk-XXDRQBXY-DzTwx8ZH.js +1 -0
  53. package/dist/assets/{chunk-YOTPTUD7-BnFxj5o4.js → chunk-YOTPTUD7-DqzqtdII.js} +1 -1
  54. package/dist/assets/{chunk-ZGVPDNZ5-CrnlPlmJ.js → chunk-ZGVPDNZ5-CRrAYi4g.js} +1 -1
  55. package/dist/assets/{chunk-ZIRB5QZD-BYTiATIH.js → chunk-ZIRB5QZD-Dc1s5bLM.js} +1 -1
  56. package/dist/assets/classDiagram-OUVF2IWQ-Cc63fLWP.js +1 -0
  57. package/dist/assets/classDiagram-v2-EOCWNBFH-CoXU0qT6.js +1 -0
  58. package/dist/assets/{cose-bilkent-JH36ORCC-BORKJRwF.js → cose-bilkent-JH36ORCC-cL247pHg.js} +1 -1
  59. package/dist/assets/cynefin-VYW2F7L2-C8yCvH_o.js +1 -0
  60. package/dist/assets/{cynefinDiagram-TSTJHNR4-BXKeaSl8.js → cynefinDiagram-TSTJHNR4-D4sZ7LYI.js} +1 -1
  61. package/dist/assets/{dagre-CrA0XVwJ.js → dagre-DmHb3Ctt.js} +1 -1
  62. package/dist/assets/{dagre-VKFMJZFB-ouq_lA1a.js → dagre-VKFMJZFB-BlsnSh-Q.js} +1 -1
  63. package/dist/assets/{diagram-FQU43EPY-BxR5kUiQ.js → diagram-FQU43EPY-DW1yQiRO.js} +1 -1
  64. package/dist/assets/{diagram-G47NLZAW-DWonk1sL.js → diagram-G47NLZAW-BTUAsFjb.js} +1 -1
  65. package/dist/assets/{diagram-NH7WQ7WH-fmV_wV5e.js → diagram-NH7WQ7WH-BcaomqSd.js} +1 -1
  66. package/dist/assets/{diagram-OA4YK3LP-DvOSRRiV.js → diagram-OA4YK3LP-DDLX7Xwr.js} +1 -1
  67. package/dist/assets/{diagram-WEI45ONY-Bp-xb3uS.js → diagram-WEI45ONY-CIave0An.js} +1 -1
  68. package/dist/assets/{ebnfDiagram-CCIWWBDH-BTlnwneA.js → ebnfDiagram-CCIWWBDH-Cr1Y6lPu.js} +1 -1
  69. package/dist/assets/{erDiagram-Q63AITRT-C3fFWGCm.js → erDiagram-Q63AITRT-D3EgiVVH.js} +1 -1
  70. package/dist/assets/{esm-oa69b5u4.js → esm-Df4edDpj.js} +2 -2
  71. package/dist/assets/eventmodeling-45OFAUF4-DO1vRTM0.js +1 -0
  72. package/dist/assets/flowDiagram-23GEKE2U-BS7KXcqn.js +1 -0
  73. package/dist/assets/{ganttDiagram-NO4QXBWP-DzAiojNi.js → ganttDiagram-NO4QXBWP-B0oyDIqK.js} +1 -1
  74. package/dist/assets/gitGraph-TEB2WS4Q-m5F5ef09.js +1 -0
  75. package/dist/assets/{gitGraphDiagram-IHSO6WYX-Cv57oNEA.js → gitGraphDiagram-IHSO6WYX-uQtr6IqK.js} +1 -1
  76. package/dist/assets/icons-CXPP1fFT.js +1 -0
  77. package/dist/assets/index-_ZhK6bvp.js +65 -0
  78. package/dist/assets/index-iVV2bP_f.css +3 -0
  79. package/dist/assets/info-DKCQHKI2-CZxPlQJ0.js +1 -0
  80. package/dist/assets/{infoDiagram-FWYZ7A6U-B5Z_O3Ro.js → infoDiagram-FWYZ7A6U-B_GzlLIM.js} +1 -1
  81. package/dist/assets/{ishikawaDiagram-FXEZZL3T-CKTK_TKV.js → ishikawaDiagram-FXEZZL3T-CKQIsSdU.js} +1 -1
  82. package/dist/assets/{journeyDiagram-5HDEW3XC-Cm9k4ywW.js → journeyDiagram-5HDEW3XC-DrrvzZL1.js} +1 -1
  83. package/dist/assets/{kanban-definition-HUTT4EX6-DzNteLwx.js → kanban-definition-HUTT4EX6-CJQRTdXz.js} +1 -1
  84. package/dist/assets/{line-BG78c_WJ.js → line-B4DxX7tC.js} +1 -1
  85. package/dist/assets/{linear-1X20_EGu.js → linear-U-nKUhyW.js} +1 -1
  86. package/dist/assets/{map-CCI8WZkS.js → map-BneTM-ri.js} +1 -1
  87. package/dist/assets/{mcp-servers-dialog-GXXD9K0U.js → mcp-servers-dialog-BUSPvaqI.js} +2 -2
  88. package/dist/assets/{mermaid-parser.core-Bb8HI_OS.js → mermaid-parser.core-BlKWrEdZ.js} +2 -2
  89. package/dist/assets/{mermaid-renderer-PIaNiXAz.js → mermaid-renderer-jEbqFaTe.js} +2 -2
  90. package/dist/assets/{mermaid.core-DUHOIwL5.js → mermaid.core-DWpShXCs.js} +3 -3
  91. package/dist/assets/{mindmap-definition-LN4V7U3C-Tnbszo7b.js → mindmap-definition-LN4V7U3C-CEVwZD78.js} +1 -1
  92. package/dist/assets/model-identity-CgA6_Pbm.js +1 -0
  93. package/dist/assets/model-reference-o41fJ6jQ.js +1 -0
  94. package/dist/assets/{monaco-BVtCspYZ.js → monaco-D6OhXgjg.js} +1 -1
  95. package/dist/assets/{ordinal-v4prQcuq.js → ordinal-B2r5L1v4.js} +1 -1
  96. package/dist/assets/{otel-D1LswXpM.js → otel-BFnphzjt.js} +1 -1
  97. package/dist/assets/packet-7NZHBO7P-zIioIZVN.js +1 -0
  98. package/dist/assets/{pegDiagram-2B236MQR-CX824Kd0.js → pegDiagram-2B236MQR-CBLkBdnQ.js} +1 -1
  99. package/dist/assets/{pi-ai-DAJlO9ZB.js → pi-ai-Cr2ee4a0.js} +2 -2
  100. package/dist/assets/{pi-web-ui-B-RJSxjR.js → pi-web-ui-DV5jKjSg.js} +1 -1
  101. package/dist/assets/pie-RZYD4A2V-GGWijBvB.js +1 -0
  102. package/dist/assets/{pieDiagram-ENE6RG2P-BT04VWPQ.js → pieDiagram-ENE6RG2P-8tCnwtWS.js} +1 -1
  103. package/dist/assets/{quadrantDiagram-ABIIQ3AL-BvOZxkBr.js → quadrantDiagram-ABIIQ3AL-CWd28cHF.js} +1 -1
  104. package/dist/assets/radar-I7S5WNFK-yvwFH3RV.js +1 -0
  105. package/dist/assets/railroad-3IZDKUUU-BVadlswB.js +1 -0
  106. package/dist/assets/railroad-abnf-AHOZXSZD-B7R-p_2-.js +1 -0
  107. package/dist/assets/railroad-ebnf-EBAXGLYW-BnbJxPug.js +1 -0
  108. package/dist/assets/railroad-peg-LSFZ7HO6-Ci3DcEuQ.js +1 -0
  109. package/dist/assets/{railroadDiagram-RFXS5EU6-DnTU--BV.js → railroadDiagram-RFXS5EU6-CI4ouOBs.js} +1 -1
  110. package/dist/assets/{react-vendor-eWH0QhNU.js → react-vendor-1KC5PyRx.js} +1 -1
  111. package/dist/assets/{requirementDiagram-TGXJPOKE--MZX_yEv.js → requirementDiagram-TGXJPOKE-DtFz7sw4.js} +1 -1
  112. package/dist/assets/{sankeyDiagram-HTMAVEWB-SEZkHhYn.js → sankeyDiagram-HTMAVEWB--VeOwwk9.js} +1 -1
  113. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BhC2OHiz.js → sequenceDiagram-DBY2YBRQ-B8AHk5Oe.js} +1 -1
  114. package/dist/assets/{sizeCapture-X5ZJPWSS-Ci5LeToV.js → sizeCapture-X5ZJPWSS-vV_ArM8D.js} +1 -1
  115. package/dist/assets/{skills-dialog-DDh1h8eH.js → skills-dialog-BThnIUBs.js} +3 -3
  116. package/dist/assets/{src-CovulcRC.js → src-PYsDme0X.js} +1 -1
  117. package/dist/assets/{stateDiagram-2N3HPSRC-DKK5tFT4.js → stateDiagram-2N3HPSRC-etXnJ8X8.js} +1 -1
  118. package/dist/assets/stateDiagram-v2-6OUMAXLB-Dms3pICj.js +1 -0
  119. package/dist/assets/{swimlanes-5IMT3BWC-DxxGCk67.js → swimlanes-5IMT3BWC-pabIKAmn.js} +2 -2
  120. package/dist/assets/swimlanesDiagram-G3AALYLV-B14aWjv6.js +8 -0
  121. package/dist/assets/{timeline-definition-FHXFAJF6-BPXB3Sue.js → timeline-definition-FHXFAJF6-C55MKm3L.js} +1 -1
  122. package/dist/assets/treeView-QDETBFTQ-Cru9B2zv.js +1 -0
  123. package/dist/assets/treemap-6X3UGDF4-DNOVHFaJ.js +1 -0
  124. package/dist/assets/{vennDiagram-L72KCM5P-CxcBCKye.js → vennDiagram-L72KCM5P-CgNf1Q9W.js} +1 -1
  125. package/dist/assets/wardley-OPB4EBWU-E3m1BOJQ.js +1 -0
  126. package/dist/assets/{wardleyDiagram-EHGQE667-DEL6Yes5.js → wardleyDiagram-EHGQE667-Drt5ytec.js} +1 -1
  127. package/dist/assets/{xychartDiagram-FW5EYKEG-N8cPbcjC.js → xychartDiagram-FW5EYKEG-hhoEo_Ar.js} +1 -1
  128. package/dist/index.html +9 -8
  129. package/package.json +3 -1
  130. package/plugins/{openai-documents → documents}/plugin.json +2 -2
  131. package/plugins/{openai-presentations → presentations}/plugin.json +2 -2
  132. package/plugins/{openai-spreadsheets → spreadsheets}/plugin.json +2 -2
  133. package/server/acp/server.mjs +36 -26
  134. package/server/agent-manager.mjs +130 -28
  135. package/server/agent-profile-files.mjs +8 -4
  136. package/server/agent-profile-schema.mjs +47 -23
  137. package/server/agent-profiles.mjs +1 -1
  138. package/server/ai-http-logger.mjs +98 -12
  139. package/server/cloud/chat-idempotency-store.mjs +96 -0
  140. package/server/cloud/client.mjs +102 -0
  141. package/server/cloud/config.mjs +53 -0
  142. package/server/cloud/credential-store.mjs +193 -0
  143. package/server/cloud/identity.mjs +355 -0
  144. package/server/cloud/index.mjs +7 -0
  145. package/server/cloud/models.mjs +80 -0
  146. package/server/cloud/runtime.mjs +129 -0
  147. package/server/cloud/service-config.mjs +77 -0
  148. package/server/index.mjs +28 -11
  149. package/server/model-catalog.mjs +262 -0
  150. package/server/plugins/registry.mjs +29 -5
  151. package/server/routes/agent-profiles.mjs +41 -7
  152. package/server/routes/agent.mjs +20 -11
  153. package/server/routes/backup.mjs +7 -1
  154. package/server/routes/cloud.mjs +227 -0
  155. package/server/routes/models.mjs +7 -1
  156. package/server/routes/scheduled-tasks.mjs +38 -8
  157. package/server/routes/shared-conversation.mjs +62 -58
  158. package/server/routes/shares.mjs +76 -1
  159. package/server/routes/storage.mjs +24 -1
  160. package/server/routes/workspace.mjs +6 -4
  161. package/server/share-store.mjs +168 -13
  162. package/server/skills.mjs +30 -3
  163. package/server/storage.mjs +7 -1
  164. package/server/subagents.mjs +3 -3
  165. package/server/tools/definitions.mjs +1 -1
  166. package/server/tools/index.mjs +2 -2
  167. package/server/utils/network.mjs +9 -0
  168. package/server/utils/response.mjs +8 -1
  169. package/skills/skill-creator/LICENSE.txt +202 -0
  170. package/skills/skill-creator/SKILL.md +485 -0
  171. package/skills/skill-creator/UPSTREAM.md +6 -0
  172. package/skills/skill-creator/agents/analyzer.md +274 -0
  173. package/skills/skill-creator/agents/comparator.md +202 -0
  174. package/skills/skill-creator/agents/grader.md +223 -0
  175. package/skills/skill-creator/assets/eval_review.html +146 -0
  176. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  177. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  178. package/skills/skill-creator/references/schemas.md +430 -0
  179. package/skills/skill-creator/scripts/__init__.py +0 -0
  180. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  181. package/skills/skill-creator/scripts/generate_report.py +326 -0
  182. package/skills/skill-creator/scripts/improve_description.py +247 -0
  183. package/skills/skill-creator/scripts/package_skill.py +136 -0
  184. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  185. package/skills/skill-creator/scripts/run_eval.py +310 -0
  186. package/skills/skill-creator/scripts/run_loop.py +328 -0
  187. package/skills/skill-creator/scripts/utils.py +47 -0
  188. package/dist/assets/AgentProfilesPage-B84w-r9S.js +0 -1
  189. package/dist/assets/ChatPanelHost-CyO8fEoj.js +0 -288
  190. package/dist/assets/PluginsPage-D2862wul.js +0 -1
  191. package/dist/assets/ScheduledTasksPage-GqbiJDPX.js +0 -2
  192. package/dist/assets/SharedConversationPage-Cw2QFnbC.js +0 -1
  193. package/dist/assets/WorkspaceInspector-3uLiu6Bv.js +0 -13
  194. package/dist/assets/architecture-TIHT7OUA-7FQo5GbP.js +0 -1
  195. package/dist/assets/channel-DToA8d-4.js +0 -1
  196. package/dist/assets/chunk-2Q5K7J3B-D_Wxpk-T.js +0 -1
  197. package/dist/assets/chunk-VAUOI2AC-CIZseNLi.js +0 -1
  198. package/dist/assets/chunk-XXDRQBXY-Do-XYxat.js +0 -1
  199. package/dist/assets/classDiagram-OUVF2IWQ-Bu24Sy-k.js +0 -1
  200. package/dist/assets/classDiagram-v2-EOCWNBFH-DKhh5HSW.js +0 -1
  201. package/dist/assets/cynefin-VYW2F7L2-oyiAgYC4.js +0 -1
  202. package/dist/assets/eventmodeling-45OFAUF4-YB_0MefX.js +0 -1
  203. package/dist/assets/flowDiagram-23GEKE2U-Bc73xdBd.js +0 -1
  204. package/dist/assets/gitGraph-TEB2WS4Q-Bvp27L0n.js +0 -1
  205. package/dist/assets/icons-cTkqD_Gi.js +0 -1
  206. package/dist/assets/index-B48prgLL.js +0 -65
  207. package/dist/assets/index-DQhwHHer.css +0 -3
  208. package/dist/assets/info-DKCQHKI2-BsLOivgq.js +0 -1
  209. package/dist/assets/packet-7NZHBO7P-BKQkXRtk.js +0 -1
  210. package/dist/assets/pie-RZYD4A2V-BTiTN5Ge.js +0 -1
  211. package/dist/assets/radar-I7S5WNFK-BU-oVjKM.js +0 -1
  212. package/dist/assets/railroad-3IZDKUUU-7H2hxNbL.js +0 -1
  213. package/dist/assets/railroad-abnf-AHOZXSZD-Mx6wf6XQ.js +0 -1
  214. package/dist/assets/railroad-ebnf-EBAXGLYW-BgXSKhYy.js +0 -1
  215. package/dist/assets/railroad-peg-LSFZ7HO6-DTEl2rAC.js +0 -1
  216. package/dist/assets/stateDiagram-v2-6OUMAXLB-D8x3mkni.js +0 -1
  217. package/dist/assets/swimlanesDiagram-G3AALYLV-C4nOBNp8.js +0 -8
  218. package/dist/assets/treeView-QDETBFTQ-DOE6NSdf.js +0 -1
  219. package/dist/assets/treemap-6X3UGDF4-Ca7QD_b4.js +0 -1
  220. package/dist/assets/wardley-OPB4EBWU-D9O4RKRm.js +0 -1
  221. /package/dist/assets/{array-DqLCdDFv.js → array-B9UHiPd-.js} +0 -0
  222. /package/dist/assets/{chunk-KEIR6QF5-s7Qq-R3i.js → chunk-KEIR6QF5-jrz1pRUS.js} +0 -0
  223. /package/dist/assets/{chunk-Y2CYZVJY-BgISNSiw.js → chunk-Y2CYZVJY-D6N-CrJv.js} +0 -0
  224. /package/dist/assets/{cytoscape.esm-iekjSZ2n.js → cytoscape.esm-DyfqweF2.js} +0 -0
  225. /package/dist/assets/{defaultLocale-CrJzLgRD.js → defaultLocale-5eAKkKJC.js} +0 -0
  226. /package/dist/assets/{dist-zzfqk5hx.js → dist-CLg13NtV.js} +0 -0
  227. /package/dist/assets/{graphlib-CIz_CfxW.js → graphlib-DJkmx0Cq.js} +0 -0
  228. /package/dist/assets/{init-C0r9Gk5G.js → init-DlZdxViB.js} +0 -0
  229. /package/dist/assets/{path-DIKpVbHL.js → path-6uRLdFF7.js} +0 -0
  230. /package/dist/assets/{plugin-api-C8hMT5W6.js → plugin-api-Uu2xAB4d.js} +0 -0
  231. /package/dist/assets/{rough.esm-BMOtDaaS.js → rough.esm-Bud4g4fh.js} +0 -0
  232. /package/dist/assets/{web-RgX7H-OH.js → web-DoV8MSMn.js} +0 -0
  233. /package/dist/assets/{xterm-BFzZ1FH4.js → xterm-Bm_IbozX.js} +0 -0
  234. /package/plugins/{openai-documents → documents}/commands/document.md +0 -0
  235. /package/plugins/{openai-documents → documents}/skills/documents/SKILL.md +0 -0
  236. /package/plugins/{openai-presentations → presentations}/commands/presentation.md +0 -0
  237. /package/plugins/{openai-presentations → presentations}/skills/presentations/SKILL.md +0 -0
  238. /package/plugins/{openai-spreadsheets → spreadsheets}/commands/spreadsheet.md +0 -0
  239. /package/plugins/{openai-spreadsheets → spreadsheets}/skills/spreadsheets/SKILL.md +0 -0
@@ -13,6 +13,7 @@ import {
13
13
  formatSubagentTask,
14
14
  } from './subagents.mjs'
15
15
  import { agentProfileSnapshot, getAgentProfile } from './agent-profiles.mjs'
16
+ import { modelBindingFromModel, resolveImplicitModelPreference, resolveModelBinding } from './model-catalog.mjs'
16
17
  import { agentProfileFromMarkdown } from './agent-profile-files.mjs'
17
18
  import {
18
19
  applyCapabilityPolicy,
@@ -200,7 +201,7 @@ function hasFullAccess(session) {
200
201
 
201
202
  const IDLE_TIMEOUT_MS = 30 * 60 * 1000 // 30 minutes
202
203
  const ABORT_IDLE_WAIT_TIMEOUT_MS = 3000
203
- const SUBAGENT_DEFAULT_TIMEOUT_MS = 30 * 60 * 1000
204
+ const SUBAGENT_DEFAULT_TIMEOUT_MS = 60 * 60 * 1000
204
205
  const SUBAGENT_TRACE_THROTTLE_MS = 150
205
206
 
206
207
  /**
@@ -515,6 +516,37 @@ function updateSessionMessages(session, messages) {
515
516
  session.agent.state.messages = messages
516
517
  }
517
518
 
519
+ const CLIENT_MESSAGE_ID_FIELD = 'quickforgeClientMessageId'
520
+
521
+ function isManagedCloudModel(model) {
522
+ return model?.provider === 'quickforge-cloud' && model?.quickforgeModelSource === 'cloud'
523
+ }
524
+
525
+ function objectMetadata(message) {
526
+ const metadata = message?.metadata
527
+ return metadata && typeof metadata === 'object' && !Array.isArray(metadata) ? metadata : {}
528
+ }
529
+
530
+ function logicalMessageId(message) {
531
+ const value = objectMetadata(message)[CLIENT_MESSAGE_ID_FIELD]
532
+ return typeof value === 'string' && /^[A-Za-z0-9._:-]{1,128}$/.test(value) ? value : undefined
533
+ }
534
+
535
+ function messageWithLogicalId(message) {
536
+ if (!message || typeof message !== 'object' || logicalMessageId(message)) return message
537
+ return {
538
+ ...message,
539
+ metadata: {
540
+ ...objectMetadata(message),
541
+ [CLIENT_MESSAGE_ID_FIELD]: `qfcm_${randomUUID()}`,
542
+ },
543
+ }
544
+ }
545
+
546
+ function prepareCloudUserMessage(session, message) {
547
+ return isManagedCloudModel(session?.model) ? messageWithLogicalId(message) : message
548
+ }
549
+
518
550
  function resetSessionCompaction(session) {
519
551
  session.contextCompaction = null
520
552
  session.lastAutoCompactAt = null
@@ -627,6 +659,9 @@ async function summarySession(session, initialUserMessage, summaryOptions) {
627
659
  accessMode: session.accessMode,
628
660
  yoloMode: session.yoloMode,
629
661
  model: session.model,
662
+ modelRef: session.modelRef,
663
+ modelAccessContext: session.modelAccessContext,
664
+ resolvePersistedModel: true,
630
665
  thinkingLevel: session.thinkingLevel,
631
666
  messages: compactedMessages,
632
667
  title: compactedTitle,
@@ -1081,7 +1116,7 @@ model:
1081
1116
  modelId: ${frontmatterString(spec.model.modelId)}${spec.model.api ? `
1082
1117
  api: ${frontmatterString(spec.model.api)}` : ''}${spec.model.baseUrl ? `
1083
1118
  baseUrl: ${frontmatterString(spec.model.baseUrl)}` : ''}` : ''}
1084
- max-runtime-ms: ${Math.max(1000, Math.min(Number(spec.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS), 30 * 60 * 1000))}
1119
+ max-runtime-ms: ${Math.max(1000, Math.min(Number(spec.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS), 60 * 60 * 1000))}
1085
1120
  max-tool-calls: ${Math.max(1, Math.min(Number(spec.maxToolCalls || 300), 300))}
1086
1121
  ---
1087
1122
  ${spec.systemPrompt}
@@ -1135,10 +1170,15 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
1135
1170
  throw new Error('No active model is configured for the parent session.')
1136
1171
  }
1137
1172
 
1138
- const timeoutMs = Math.max(1000, Math.min(Number(definition.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS), 30 * 60 * 1000))
1173
+ const timeoutMs = Math.max(1000, Math.min(Number(definition.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS), 60 * 60 * 1000))
1139
1174
  definition.capabilityPolicy ||= inferCapabilityPolicy(definition.allowedTools || [])
1140
1175
  definition.allowedTools = applyCapabilityPolicy(definition.allowedTools || [], definition.capabilityPolicy)
1141
- const { model: subagentModel, info: subagentModelInfo } = await resolveAgentProfileModel(definition, parentSession.model, readStore)
1176
+ const { model: subagentModel, info: subagentModelInfo } = await resolveAgentProfileModel(
1177
+ definition,
1178
+ parentSession.model,
1179
+ readStore,
1180
+ parentSession.modelAccessContext || {},
1181
+ )
1142
1182
  const subagentThinkingLevel = resolveAgentProfileThinkingLevel(definition, parentSession.thinkingLevel, subagentModel)
1143
1183
  const subagentSessionId = `${parentSession.sessionId}:subagent:${definition.name}:${randomUUID()}`
1144
1184
  const startedAt = Date.now()
@@ -1511,6 +1551,9 @@ export async function createAgent(sessionId, config = {}) {
1511
1551
  accessMode: rawAccessMode,
1512
1552
  yoloMode = false,
1513
1553
  model = null,
1554
+ modelRef = null,
1555
+ modelAccessContext = null,
1556
+ resolvePersistedModel = false,
1514
1557
  thinkingLevel = 'off',
1515
1558
  messages = [],
1516
1559
  systemPrompt = null,
@@ -1555,24 +1598,36 @@ export async function createAgent(sessionId, config = {}) {
1555
1598
 
1556
1599
  // Resolve model
1557
1600
  let resolvedModel = model
1601
+ let resolvedModelRef = modelRef
1558
1602
  if (!resolvedModel) {
1559
- // Try to load from storage
1603
+ // Try to load the active preference from storage. A stale/hidden implicit
1604
+ // preference may fall back, while an explicit session binding never does.
1560
1605
  try {
1561
1606
  const settings = await readStore('settings')
1562
1607
  const raw = settings?.['active-model']
1563
- if (raw) resolvedModel = typeof raw === 'string' ? JSON.parse(raw) : raw
1608
+ resolvedModel = await resolveImplicitModelPreference(raw, modelAccessContext || {})
1564
1609
  } catch {
1565
1610
  // ignore
1566
1611
  }
1567
1612
  }
1568
1613
  if (agentProfile?.model?.mode === 'fixed') {
1569
- resolvedModel = (await resolveAgentProfileModel(agentProfile, resolvedModel, readStore)).model
1614
+ const profileBinding = await resolveAgentProfileModel(agentProfile, resolvedModel, readStore, modelAccessContext || {})
1615
+ resolvedModel = profileBinding.model
1616
+ resolvedModelRef = profileBinding.modelRef || null
1570
1617
  resolvedAgentProfile = {
1571
1618
  ...agentProfile,
1572
1619
  model: modelReferenceSnapshot(agentProfile.model),
1573
1620
  }
1574
1621
  }
1575
1622
  if (resolvedAgentProfile && !resolvedModel) throw new Error('No active model is configured for the agent session.')
1623
+ const resolvedBinding = resolvedModel
1624
+ ? (resolvedModelRef
1625
+ ? { model: resolvedModel, modelRef: resolvedModelRef }
1626
+ : model
1627
+ ? { model: resolvedModel, modelRef: null }
1628
+ : await modelBindingFromModel(resolvedModel))
1629
+ : { model: resolvedModel, modelRef: null }
1630
+ resolvedModel = resolvedBinding.model
1576
1631
  const resolvedThinkingLevel = agentProfile
1577
1632
  ? resolveAgentProfileThinkingLevel(agentProfile, thinkingLevel, resolvedModel)
1578
1633
  : thinkingLevel
@@ -1682,6 +1737,9 @@ export async function createAgent(sessionId, config = {}) {
1682
1737
  accessMode,
1683
1738
  yoloMode: resolvedYoloMode,
1684
1739
  model: resolvedModel,
1740
+ modelRef: resolvedBinding.modelRef,
1741
+ modelAccessContext: modelAccessContext || null,
1742
+ resolvePersistedModel: resolvePersistedModel === true || Boolean(resolvedBinding.modelRef),
1685
1743
  thinkingLevel: resolvedThinkingLevel,
1686
1744
  scope,
1687
1745
  title,
@@ -1789,14 +1847,15 @@ export async function createAgent(sessionId, config = {}) {
1789
1847
  }
1790
1848
 
1791
1849
  if (event.type === 'message_end') {
1792
- const isInitialUserMessage = (event.message?.role === 'user' || event.message?.role === 'user-with-attachments')
1793
- && session.agent.state.messages.length === 1
1794
- if (isInitialUserMessage) {
1795
- // Persist the first user message before announcing the session or
1796
- // starting the asynchronous AI title request.
1850
+ const isUserMessage = event.message?.role === 'user' || event.message?.role === 'user-with-attachments'
1851
+ const isInitialUserMessage = isUserMessage && session.agent.state.messages.length === 1
1852
+ const requiresDurableCloudMessage = isUserMessage && isManagedCloudModel(session.model) && Boolean(logicalMessageId(event.message))
1853
+ if (isInitialUserMessage || requiresDurableCloudMessage) {
1854
+ // Persist every managed Cloud user message before the provider stream starts,
1855
+ // so its logical ID survives a process restart and resolves to the same private key.
1797
1856
  try {
1798
1857
  const metadata = await flushSessionPersist(session)
1799
- if (metadata) {
1858
+ if (metadata && isInitialUserMessage) {
1800
1859
  if (!session.sessionCreatedEmitted) {
1801
1860
  session.sessionCreatedEmitted = true
1802
1861
  emitSessionEvent(session, { type: 'session_created', metadata })
@@ -1804,7 +1863,7 @@ export async function createAgent(sessionId, config = {}) {
1804
1863
  scheduleSessionTitleGeneration(session, event.message)
1805
1864
  }
1806
1865
  } catch (err) {
1807
- logger.error(`Failed to persist initial user message for session ${sessionId}:`, err, { sessionId })
1866
+ logger.error(`Failed to persist user message for session ${sessionId}:`, err, { sessionId })
1808
1867
  }
1809
1868
  } else {
1810
1869
  // Debounced persist for crash recovery; coalesces the many message_end
@@ -1848,7 +1907,7 @@ function sessionLastModifiedFromMessages(messages, fallback) {
1848
1907
  * Persist session data to storage.
1849
1908
  */
1850
1909
  async function persistSessionUnlocked(session) {
1851
- const { sessionId, agent, scope, projectId, source, channelId, channelName, title, titleSource, createdAt, lastModified: storedLastModified, status, startedAt, finishedAt, model, thinkingLevel, accessMode, yoloMode, contextCompaction } = session
1910
+ const { sessionId, agent, scope, projectId, source, channelId, channelName, title, titleSource, createdAt, lastModified: storedLastModified, status, startedAt, finishedAt, model, modelRef, thinkingLevel, accessMode, yoloMode, contextCompaction } = session
1852
1911
  const messages = agent.state.messages
1853
1912
 
1854
1913
  if (messages.length === 0) {
@@ -1871,6 +1930,7 @@ async function persistSessionUnlocked(session) {
1871
1930
  title,
1872
1931
  titleSource,
1873
1932
  model,
1933
+ modelRef: modelRef || undefined,
1874
1934
  thinkingLevel,
1875
1935
  accessMode,
1876
1936
  yoloMode,
@@ -2063,7 +2123,10 @@ export async function rollbackSessionMessages(sessionId, rollbackMessageIndex) {
2063
2123
  throw Object.assign(new Error('Session not found'), { statusCode: 404 })
2064
2124
  }
2065
2125
  if (session.agent.state.isStreaming) {
2066
- throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes before rolling back.'), { statusCode: 409 })
2126
+ throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes before rolling back.'), {
2127
+ statusCode: 409,
2128
+ errorCode: 'GENERATION_STILL_RUNNING_BEFORE_ROLLBACK',
2129
+ })
2067
2130
  }
2068
2131
 
2069
2132
  const messages = Array.isArray(session.agent.state.messages) ? session.agent.state.messages : []
@@ -2127,18 +2190,42 @@ function scheduleSessionTitleGeneration(session, userMessage) {
2127
2190
  session.titleGenerationPromiseId = generationId
2128
2191
  }
2129
2192
 
2193
+ async function refreshSessionModelBinding(session) {
2194
+ if (!session?.model || (!session.modelRef && session.resolvePersistedModel !== true)) return session
2195
+ const binding = await resolveModelBinding(
2196
+ session.modelRef ? { modelRef: session.modelRef } : { model: session.model },
2197
+ {
2198
+ context: session.modelAccessContext || {},
2199
+ currentModel: session.model,
2200
+ allowCurrentHidden: true,
2201
+ forExecution: true,
2202
+ legacySnapshot: session.model,
2203
+ },
2204
+ )
2205
+ session.model = binding.model
2206
+ session.modelRef = binding.modelRef
2207
+ session.resolvePersistedModel = true
2208
+ session.agent.state.model = binding.model
2209
+ return session
2210
+ }
2211
+
2130
2212
  /**
2131
2213
  * Send a user message to the agent and start the agent loop.
2132
2214
  * Returns immediately; events are streamed via the event bus.
2133
2215
  */
2134
- export async function runPrompt(sessionId, message, selectedCapabilities = [], promptCommand = null, transientContextPrompt = null) {
2216
+ export async function runPrompt(sessionId, message, selectedCapabilities = [], promptCommand = null, transientContextPrompt = null, modelAccessContext = null) {
2135
2217
  let session = await syncSessionFromStorage(sessionId)
2136
2218
  if (!session) {
2137
2219
  throw Object.assign(new Error('Session not found'), { statusCode: 404 })
2138
2220
  }
2221
+ if (modelAccessContext) session.modelAccessContext = modelAccessContext
2222
+ await refreshSessionModelBinding(session)
2139
2223
 
2140
2224
  if (session.agent.state.isStreaming || session.abortPending) {
2141
- throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), { statusCode: 409 })
2225
+ throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), {
2226
+ statusCode: 409,
2227
+ errorCode: 'GENERATION_ALREADY_RUNNING',
2228
+ })
2142
2229
  }
2143
2230
 
2144
2231
  await refreshMemoryState(session)
@@ -2149,7 +2236,7 @@ export async function runPrompt(sessionId, message, selectedCapabilities = [], p
2149
2236
  ? { role: 'user', content: message, timestamp: new Date().toISOString() }
2150
2237
  : message
2151
2238
  const commandState = await resolveCommandState(session, initialUserMessage, promptCommand)
2152
- const userMessage = commandState.userMessage ?? initialUserMessage
2239
+ const resolvedUserMessage = commandState.userMessage ?? initialUserMessage
2153
2240
 
2154
2241
  if (commandState.textResponse) {
2155
2242
  session.agent.state.messages = [
@@ -2176,6 +2263,8 @@ export async function runPrompt(sessionId, message, selectedCapabilities = [], p
2176
2263
  return compactSession(session, initialUserMessage, commandState.compact)
2177
2264
  }
2178
2265
 
2266
+ const userMessage = prepareCloudUserMessage(session, resolvedUserMessage)
2267
+
2179
2268
  // Set a meaningful fallback immediately. The AI title request starts only
2180
2269
  // after the first user message has been persisted by the message_end handler.
2181
2270
  if (session.titleSource === 'default' && session.title === 'New chat') {
@@ -2221,14 +2310,19 @@ export async function runPrompt(sessionId, message, selectedCapabilities = [], p
2221
2310
  * Trims messages to keep up to and including the last user message,
2222
2311
  * removing the assistant response that follows it.
2223
2312
  */
2224
- export async function continueSession(sessionId) {
2313
+ export async function continueSession(sessionId, modelAccessContext = null) {
2225
2314
  const session = agentSessions.get(sessionId)
2226
2315
  if (!session) {
2227
2316
  throw Object.assign(new Error('Session not found'), { statusCode: 404 })
2228
2317
  }
2229
2318
  if (session.agent.state.isStreaming) {
2230
- throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), { statusCode: 409 })
2319
+ throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), {
2320
+ statusCode: 409,
2321
+ errorCode: 'GENERATION_ALREADY_RUNNING',
2322
+ })
2231
2323
  }
2324
+ if (modelAccessContext) session.modelAccessContext = modelAccessContext
2325
+ await refreshSessionModelBinding(session)
2232
2326
 
2233
2327
  const messages = Array.isArray(session.agent.state.messages) ? session.agent.state.messages : []
2234
2328
 
@@ -2246,10 +2340,13 @@ export async function continueSession(sessionId) {
2246
2340
 
2247
2341
  const lastUserMessage = messages[lastUserIndex]
2248
2342
  const commandState = await resolveCommandState(session, lastUserMessage)
2249
- const continuedUserMessage = commandState.userMessage ?? lastUserMessage
2343
+ const continuedUserMessage = prepareCloudUserMessage(session, commandState.userMessage ?? lastUserMessage)
2250
2344
  const trimmedMessages = messages.slice(0, lastUserIndex).concat(continuedUserMessage)
2251
2345
  updateSessionMessages(session, trimmedMessages)
2252
2346
  resetSessionCompaction(session)
2347
+ if (isManagedCloudModel(session.model) && logicalMessageId(continuedUserMessage)) {
2348
+ await flushSessionPersist(session)
2349
+ }
2253
2350
 
2254
2351
  resetIdleTimer(session)
2255
2352
  session.activeCommandName = commandState.commandName ?? null
@@ -2334,9 +2431,9 @@ export function steerAgent(sessionId, message) {
2334
2431
  throw Object.assign(new Error('Session not found'), { statusCode: 404 })
2335
2432
  }
2336
2433
 
2337
- const agentMessage = typeof message === 'string'
2434
+ const agentMessage = prepareCloudUserMessage(session, typeof message === 'string'
2338
2435
  ? { role: 'user', content: message, timestamp: Date.now() }
2339
- : message
2436
+ : message)
2340
2437
 
2341
2438
  session.agent.steer(agentMessage)
2342
2439
  return { sessionId, steered: true }
@@ -2351,9 +2448,9 @@ export function followUpAgent(sessionId, message) {
2351
2448
  throw Object.assign(new Error('Session not found'), { statusCode: 404 })
2352
2449
  }
2353
2450
 
2354
- const agentMessage = typeof message === 'string'
2451
+ const agentMessage = prepareCloudUserMessage(session, typeof message === 'string'
2355
2452
  ? { role: 'user', content: message, timestamp: Date.now() }
2356
- : message
2453
+ : message)
2357
2454
 
2358
2455
  session.agent.followUp(agentMessage)
2359
2456
  return { sessionId, followUp: true }
@@ -2443,6 +2540,7 @@ export function getSessionState(sessionId) {
2443
2540
  yoloMode: session.yoloMode,
2444
2541
  systemPrompt: session.agent.state.systemPrompt,
2445
2542
  model: session.model,
2543
+ modelRef: session.modelRef || undefined,
2446
2544
  thinkingLevel: session.thinkingLevel,
2447
2545
  title: session.title,
2448
2546
  titleSource: session.titleSource,
@@ -2597,6 +2695,8 @@ export async function restoreAgent(sessionId) {
2597
2695
  accessMode: normalizeAccessMode(sessionData.accessMode, sessionData.yoloMode),
2598
2696
  yoloMode: sessionData.yoloMode || false,
2599
2697
  model: sessionData.model,
2698
+ modelRef: sessionData.modelRef || null,
2699
+ resolvePersistedModel: true,
2600
2700
  thinkingLevel: sessionData.thinkingLevel || 'off',
2601
2701
  messages: sessionData.messages || [],
2602
2702
  title: sessionData.title || 'New chat',
@@ -2752,7 +2852,7 @@ export async function updateSessionYoloMode(sessionId, yoloMode) {
2752
2852
  * Does NOT force persistence — normal lifecycle events (message_end, agent_end) will persist
2753
2853
  * the updated model.
2754
2854
  */
2755
- export function updateSessionModel(sessionId, model) {
2855
+ export function updateSessionModel(sessionId, model, modelRef = null) {
2756
2856
  const session = agentSessions.get(sessionId)
2757
2857
  if (!session) {
2758
2858
  throw Object.assign(new Error('Session not found'), { statusCode: 404 })
@@ -2762,9 +2862,11 @@ export function updateSessionModel(sessionId, model) {
2762
2862
  }
2763
2863
 
2764
2864
  session.model = model
2865
+ session.modelRef = modelRef
2866
+ session.resolvePersistedModel = true
2765
2867
  session.agent.state.model = model
2766
2868
 
2767
- return { sessionId, model }
2869
+ return { sessionId, model, modelRef: modelRef || undefined }
2768
2870
  }
2769
2871
 
2770
2872
  /**
@@ -6,7 +6,7 @@ import { logger } from './utils/logger.mjs'
6
6
  import { firstOptionalBoolean, firstString, parseFrontmatter, splitDelimitedList } from './frontmatter.mjs'
7
7
  import { normalizeAgentProfileThinkingLevel, normalizeCapabilityPolicy, normalizeModelReference, validateAgentProfileTools, validateModelReference } from './agent-profile-schema.mjs'
8
8
 
9
- const DEFAULT_MAX_RUNTIME_MS = 30 * 60 * 1000
9
+ const DEFAULT_MAX_RUNTIME_MS = 60 * 60 * 1000
10
10
  const DEFAULT_MAX_TOOL_CALLS = 300
11
11
  const nameRegex = /^[a-z][a-z0-9_-]{1,39}$/
12
12
  const allowedToolNames = new Set(['read_file', 'grep_files', 'write_file', 'edit_file', 'run_command'])
@@ -66,14 +66,18 @@ function quoteFrontmatter(value) {
66
66
 
67
67
  function formatModelFrontmatter(model) {
68
68
  if (!model || model.mode !== 'fixed') return 'model:\n mode: inherit'
69
- return [
69
+ const result = [
70
70
  'model:',
71
71
  ' mode: fixed',
72
- ` provider: ${quoteFrontmatter(model.provider)}`,
73
- ` modelId: ${quoteFrontmatter(model.modelId)}`,
72
+ model.source && model.source !== 'legacy-custom' ? ` source: ${quoteFrontmatter(model.source)}` : '',
73
+ model.providerId ? ` providerId: ${quoteFrontmatter(model.providerId)}` : '',
74
+ model.catalogId ? ` catalogId: ${quoteFrontmatter(model.catalogId)}` : '',
75
+ model.provider ? ` provider: ${quoteFrontmatter(model.provider)}` : '',
76
+ model.modelId ? ` modelId: ${quoteFrontmatter(model.modelId)}` : '',
74
77
  model.api ? ` api: ${quoteFrontmatter(model.api)}` : '',
75
78
  model.baseUrl ? ` baseUrl: ${quoteFrontmatter(model.baseUrl)}` : '',
76
79
  ].filter(Boolean).join('\n')
80
+ return result
77
81
  }
78
82
 
79
83
  export function userAgentProfileFilePath(name) {
@@ -1,3 +1,5 @@
1
+ import { resolveModelBinding } from './model-catalog.mjs'
2
+
1
3
  export const AGENT_PROFILE_TOOL_NAMES = ['read_file', 'grep_files', 'write_file', 'edit_file', 'run_command']
2
4
  export const AGENT_PROFILE_MODEL_INHERIT = { mode: 'inherit' }
3
5
  export const AGENT_PROFILE_THINKING_LEVELS = ['inherit', 'off', 'low', 'medium', 'high', 'xhigh']
@@ -41,10 +43,6 @@ function normalizeString(value) {
41
43
  return typeof value === 'string' && value.trim() ? value.trim() : undefined
42
44
  }
43
45
 
44
- function sameBaseUrl(a, b) {
45
- return String(a || '').trim().replace(/\/$/, '') === String(b || '').trim().replace(/\/$/, '')
46
- }
47
-
48
46
  function readModelField(value, ...keys) {
49
47
  if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined
50
48
  for (const key of keys) {
@@ -90,10 +88,16 @@ export function normalizeModelReference(input, metadata = {}) {
90
88
  const flatModelId = normalizeString(metadata['model-id'] ?? metadata.model_id ?? metadata.modelId)
91
89
  const flatApi = normalizeString(metadata['model-api'] ?? metadata.modelApi ?? metadata.api)
92
90
  const flatBaseUrl = normalizeString(metadata['model-base-url'] ?? metadata.modelBaseUrl ?? metadata.baseUrl)
91
+ const flatSource = normalizeString(metadata['model-source'] ?? metadata.modelSource)?.toLowerCase()
92
+ const flatProviderId = normalizeString(metadata['model-provider-id'] ?? metadata.modelProviderId ?? metadata.providerId)
93
+ const flatCatalogId = normalizeString(metadata['model-catalog-id'] ?? metadata.modelCatalogId ?? metadata.catalogId)
93
94
 
94
- if (flatMode === 'fixed' || flatProvider || flatModelId) {
95
+ if (flatMode === 'fixed' || flatSource || flatProvider || flatModelId || flatProviderId || flatCatalogId) {
95
96
  return {
96
97
  mode: 'fixed',
98
+ source: flatSource,
99
+ providerId: flatProviderId,
100
+ catalogId: flatCatalogId,
97
101
  provider: flatProvider,
98
102
  modelId: flatModelId,
99
103
  api: flatApi,
@@ -123,6 +127,9 @@ export function normalizeModelReference(input, metadata = {}) {
123
127
 
124
128
  return {
125
129
  mode: 'fixed',
130
+ source: readModelField(modelValue, 'source'),
131
+ providerId: readModelField(modelValue, 'providerId', 'provider-id', 'provider_id'),
132
+ catalogId: readModelField(modelValue, 'catalogId', 'catalog-id', 'catalog_id', 'quickforgeCatalogId'),
126
133
  provider: readModelField(modelValue, 'provider'),
127
134
  modelId: readModelField(modelValue, 'modelId', 'model-id', 'model_id', 'id', 'model'),
128
135
  api: readModelField(modelValue, 'api'),
@@ -133,9 +140,19 @@ export function normalizeModelReference(input, metadata = {}) {
133
140
  export function validateModelReference(modelRef) {
134
141
  const ref = modelRef || AGENT_PROFILE_MODEL_INHERIT
135
142
  if (ref.mode !== 'fixed') return { ...AGENT_PROFILE_MODEL_INHERIT }
143
+ if (ref.source === 'cloud') {
144
+ const catalogId = ref.catalogId || ref.modelId
145
+ if (!catalogId) throw requestError('Fixed Cloud agent model requires catalogId')
146
+ return { mode: 'fixed', source: 'cloud', catalogId }
147
+ }
148
+ if (ref.source === 'custom') {
149
+ if (!ref.providerId || !ref.modelId) throw requestError('Fixed custom agent model requires providerId and modelId')
150
+ return { mode: 'fixed', source: 'custom', providerId: ref.providerId, modelId: ref.modelId }
151
+ }
136
152
  if (!ref.provider || !ref.modelId) throw requestError('Fixed agent model requires provider and modelId')
137
153
  return {
138
154
  mode: 'fixed',
155
+ source: 'legacy-custom',
139
156
  provider: ref.provider,
140
157
  modelId: ref.modelId,
141
158
  api: ref.api,
@@ -164,14 +181,17 @@ export function modelReferenceSnapshot(modelRef) {
164
181
  if (ref.mode !== 'fixed') return { ...AGENT_PROFILE_MODEL_INHERIT }
165
182
  return {
166
183
  mode: 'fixed',
167
- provider: ref.provider,
168
- modelId: ref.modelId,
184
+ ...(ref.source && ref.source !== 'legacy-custom' ? { source: ref.source } : {}),
185
+ ...(ref.providerId ? { providerId: ref.providerId } : {}),
186
+ ...(ref.catalogId ? { catalogId: ref.catalogId } : {}),
187
+ ...(ref.provider ? { provider: ref.provider } : {}),
188
+ ...(ref.modelId ? { modelId: ref.modelId } : {}),
169
189
  ...(ref.api ? { api: ref.api } : {}),
170
190
  ...(ref.baseUrl ? { baseUrl: ref.baseUrl } : {}),
171
191
  }
172
192
  }
173
193
 
174
- export async function resolveAgentProfileModel(profile, parentModel, readStore) {
194
+ export async function resolveAgentProfileModel(profile, parentModel, _readStore, context = {}) {
175
195
  const ref = profile?.model || AGENT_PROFILE_MODEL_INHERIT
176
196
  if (!ref || ref.mode !== 'fixed') {
177
197
  if (!parentModel) throw requestError('No active model is configured for the parent session.')
@@ -179,19 +199,23 @@ export async function resolveAgentProfileModel(profile, parentModel, readStore)
179
199
  }
180
200
 
181
201
  const validRef = validateModelReference(ref)
182
- const store = await readStore('custom-providers').catch(() => ({}))
183
- const providers = Array.isArray(store) ? store : Object.values(store || {})
184
- const configuredModels = providers
185
- .flatMap((provider) => Array.isArray(provider?.models) ? provider.models : [])
186
- .filter((model) => model && typeof model === 'object')
187
- const model = configuredModels.find((candidate) => (
188
- candidate.provider === validRef.provider &&
189
- candidate.id === validRef.modelId &&
190
- (!validRef.api || candidate.api === validRef.api) &&
191
- (!validRef.baseUrl || sameBaseUrl(candidate.baseUrl, validRef.baseUrl))
192
- ))
193
- if (!model) {
194
- throw requestError(`Agent profile ${profile?.name || ''} requested model ${validRef.provider}/${validRef.modelId}, but it is not configured.`)
195
- }
196
- return { model, info: { ...modelReferenceSnapshot(validRef), inherited: false } }
202
+ const modelRef = validRef.source === 'cloud'
203
+ ? { version: 1, source: 'cloud', catalogId: validRef.catalogId }
204
+ : validRef.source === 'custom'
205
+ ? { version: 1, source: 'custom', providerId: validRef.providerId, modelId: validRef.modelId }
206
+ : {
207
+ version: 1,
208
+ source: 'legacy-custom',
209
+ provider: validRef.provider,
210
+ modelId: validRef.modelId,
211
+ ...(validRef.api ? { api: validRef.api } : {}),
212
+ ...(validRef.baseUrl ? { baseUrl: validRef.baseUrl } : {}),
213
+ }
214
+ const binding = await resolveModelBinding({ modelRef }, {
215
+ context,
216
+ currentModel: parentModel,
217
+ allowCurrentHidden: true,
218
+ forExecution: true,
219
+ })
220
+ return { model: binding.model, modelRef: binding.modelRef, info: { ...modelReferenceSnapshot(validRef), inherited: false } }
197
221
  }
@@ -27,7 +27,7 @@ const BUILTIN_OVERRIDES_STORE = 'agent-profile-overrides'
27
27
  const RESERVED_NAMES = new Set(subagentDefinitions.map((definition) => definition.name))
28
28
  const allowedToolNames = new Set(AGENT_PROFILE_TOOL_NAMES)
29
29
  const nameRegex = /^[a-z][a-z0-9_-]{1,39}$/
30
- const DEFAULT_MAX_RUNTIME_MS = 30 * 60 * 1000
30
+ const DEFAULT_MAX_RUNTIME_MS = 60 * 60 * 1000
31
31
  const DEFAULT_MAX_TOOL_CALLS = 300
32
32
  const MIGRATION_MARKER_FILE = path.join(userAgentsDir, '.custom-agents-migrated.json')
33
33
  let customAgentMigrationPromise = null