@shawnstack/quickforge 1.7.4 → 1.7.6

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 (258) hide show
  1. package/dist/assets/AgentProfilesPage-Dl5Peqov.js +1 -0
  2. package/dist/assets/ChatPanelHost-D3987TUJ.js +307 -0
  3. package/dist/assets/CloudAccountSettingsPage-BG5Nn3bq.js +1 -0
  4. package/dist/assets/PluginsPage-BDKYfLna.js +1 -0
  5. package/dist/assets/ScheduledTasksPage--GAki3lB.js +2 -0
  6. package/dist/assets/SettingsWorkspacePage-DSy66Tuw.js +1696 -0
  7. package/dist/assets/ShareLinksSettingsPage-BQQMsvJo.js +1 -0
  8. package/dist/assets/SharedConversationPage-B9BUVCri.js +1 -0
  9. package/dist/assets/TerminalDock-CT1nYo7P.js +2 -0
  10. package/dist/assets/WorkspaceInspector-BnfDLf9a.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/{dist-DLKC_odd.js → dist-yDHbi5ux.js} +1 -1
  69. package/dist/assets/{ebnfDiagram-CCIWWBDH-BTlnwneA.js → ebnfDiagram-CCIWWBDH-Cr1Y6lPu.js} +1 -1
  70. package/dist/assets/{erDiagram-Q63AITRT-C3fFWGCm.js → erDiagram-Q63AITRT-D3EgiVVH.js} +1 -1
  71. package/dist/assets/{esm-oa69b5u4.js → esm-sdsK6gaB.js} +2 -2
  72. package/dist/assets/eventmodeling-45OFAUF4-DO1vRTM0.js +1 -0
  73. package/dist/assets/flowDiagram-23GEKE2U-BS7KXcqn.js +1 -0
  74. package/dist/assets/{ganttDiagram-NO4QXBWP-DzAiojNi.js → ganttDiagram-NO4QXBWP-B0oyDIqK.js} +1 -1
  75. package/dist/assets/gitGraph-TEB2WS4Q-m5F5ef09.js +1 -0
  76. package/dist/assets/{gitGraphDiagram-IHSO6WYX-Cv57oNEA.js → gitGraphDiagram-IHSO6WYX-uQtr6IqK.js} +1 -1
  77. package/dist/assets/icons-2D18YbSI.js +1 -0
  78. package/dist/assets/index-1ei6nhs-.css +3 -0
  79. package/dist/assets/index-BivLuZvX.js +65 -0
  80. package/dist/assets/info-DKCQHKI2-CZxPlQJ0.js +1 -0
  81. package/dist/assets/{infoDiagram-FWYZ7A6U-B5Z_O3Ro.js → infoDiagram-FWYZ7A6U-B_GzlLIM.js} +1 -1
  82. package/dist/assets/{ishikawaDiagram-FXEZZL3T-CKTK_TKV.js → ishikawaDiagram-FXEZZL3T-CKQIsSdU.js} +1 -1
  83. package/dist/assets/{journeyDiagram-5HDEW3XC-Cm9k4ywW.js → journeyDiagram-5HDEW3XC-DrrvzZL1.js} +1 -1
  84. package/dist/assets/{kanban-definition-HUTT4EX6-DzNteLwx.js → kanban-definition-HUTT4EX6-CJQRTdXz.js} +1 -1
  85. package/dist/assets/{line-BG78c_WJ.js → line-B4DxX7tC.js} +1 -1
  86. package/dist/assets/{linear-1X20_EGu.js → linear-U-nKUhyW.js} +1 -1
  87. package/dist/assets/{map-CCI8WZkS.js → map-BneTM-ri.js} +1 -1
  88. package/dist/assets/{mcp-servers-dialog-GXXD9K0U.js → mcp-servers-dialog-BEV4_TXC.js} +2 -2
  89. package/dist/assets/{mermaid-parser.core-Bb8HI_OS.js → mermaid-parser.core-BlKWrEdZ.js} +2 -2
  90. package/dist/assets/{mermaid-renderer-PIaNiXAz.js → mermaid-renderer-jEbqFaTe.js} +2 -2
  91. package/dist/assets/{mermaid.core-DUHOIwL5.js → mermaid.core-DWpShXCs.js} +3 -3
  92. package/dist/assets/{mindmap-definition-LN4V7U3C-Tnbszo7b.js → mindmap-definition-LN4V7U3C-CEVwZD78.js} +1 -1
  93. package/dist/assets/{logger-8REuLPGK.js → model-display-label-C6-0eDxF.js} +1 -1
  94. package/dist/assets/model-identity-CgA6_Pbm.js +1 -0
  95. package/dist/assets/model-reference-o41fJ6jQ.js +1 -0
  96. package/dist/assets/{monaco-BVtCspYZ.js → monaco-DvXErxp2.js} +1 -1
  97. package/dist/assets/{ordinal-v4prQcuq.js → ordinal-B2r5L1v4.js} +1 -1
  98. package/dist/assets/{otel-D1LswXpM.js → otel-BFnphzjt.js} +1 -1
  99. package/dist/assets/packet-7NZHBO7P-zIioIZVN.js +1 -0
  100. package/dist/assets/{pegDiagram-2B236MQR-CX824Kd0.js → pegDiagram-2B236MQR-CBLkBdnQ.js} +1 -1
  101. package/dist/assets/{pi-ai-DAJlO9ZB.js → pi-ai-Cr2ee4a0.js} +2 -2
  102. package/dist/assets/{pi-web-ui-B-RJSxjR.js → pi-web-ui-DV5jKjSg.js} +1 -1
  103. package/dist/assets/pie-RZYD4A2V-GGWijBvB.js +1 -0
  104. package/dist/assets/{pieDiagram-ENE6RG2P-BT04VWPQ.js → pieDiagram-ENE6RG2P-8tCnwtWS.js} +1 -1
  105. package/dist/assets/{quadrantDiagram-ABIIQ3AL-BvOZxkBr.js → quadrantDiagram-ABIIQ3AL-CWd28cHF.js} +1 -1
  106. package/dist/assets/radar-I7S5WNFK-yvwFH3RV.js +1 -0
  107. package/dist/assets/railroad-3IZDKUUU-BVadlswB.js +1 -0
  108. package/dist/assets/railroad-abnf-AHOZXSZD-B7R-p_2-.js +1 -0
  109. package/dist/assets/railroad-ebnf-EBAXGLYW-BnbJxPug.js +1 -0
  110. package/dist/assets/railroad-peg-LSFZ7HO6-Ci3DcEuQ.js +1 -0
  111. package/dist/assets/{railroadDiagram-RFXS5EU6-DnTU--BV.js → railroadDiagram-RFXS5EU6-CI4ouOBs.js} +1 -1
  112. package/dist/assets/{react-vendor-eWH0QhNU.js → react-vendor-3UaA-C9W.js} +1 -1
  113. package/dist/assets/{requirementDiagram-TGXJPOKE--MZX_yEv.js → requirementDiagram-TGXJPOKE-DtFz7sw4.js} +1 -1
  114. package/dist/assets/{sankeyDiagram-HTMAVEWB-SEZkHhYn.js → sankeyDiagram-HTMAVEWB--VeOwwk9.js} +1 -1
  115. package/dist/assets/{sequenceDiagram-DBY2YBRQ-BhC2OHiz.js → sequenceDiagram-DBY2YBRQ-B8AHk5Oe.js} +1 -1
  116. package/dist/assets/{sizeCapture-X5ZJPWSS-Ci5LeToV.js → sizeCapture-X5ZJPWSS-vV_ArM8D.js} +1 -1
  117. package/dist/assets/{skills-dialog-DDh1h8eH.js → skills-dialog-BTJ7mzk_.js} +3 -3
  118. package/dist/assets/{src-CovulcRC.js → src-PYsDme0X.js} +1 -1
  119. package/dist/assets/{stateDiagram-2N3HPSRC-DKK5tFT4.js → stateDiagram-2N3HPSRC-etXnJ8X8.js} +1 -1
  120. package/dist/assets/stateDiagram-v2-6OUMAXLB-Dms3pICj.js +1 -0
  121. package/dist/assets/{swimlanes-5IMT3BWC-DxxGCk67.js → swimlanes-5IMT3BWC-pabIKAmn.js} +2 -2
  122. package/dist/assets/swimlanesDiagram-G3AALYLV-B14aWjv6.js +8 -0
  123. package/dist/assets/{timeline-definition-FHXFAJF6-BPXB3Sue.js → timeline-definition-FHXFAJF6-C55MKm3L.js} +1 -1
  124. package/dist/assets/treeView-QDETBFTQ-Cru9B2zv.js +1 -0
  125. package/dist/assets/treemap-6X3UGDF4-DNOVHFaJ.js +1 -0
  126. package/dist/assets/{vennDiagram-L72KCM5P-CxcBCKye.js → vennDiagram-L72KCM5P-CgNf1Q9W.js} +1 -1
  127. package/dist/assets/wardley-OPB4EBWU-E3m1BOJQ.js +1 -0
  128. package/dist/assets/{wardleyDiagram-EHGQE667-DEL6Yes5.js → wardleyDiagram-EHGQE667-Drt5ytec.js} +1 -1
  129. package/dist/assets/{web-RgX7H-OH.js → web-B5qgZJRv.js} +1 -1
  130. package/dist/assets/{xychartDiagram-FW5EYKEG-N8cPbcjC.js → xychartDiagram-FW5EYKEG-hhoEo_Ar.js} +1 -1
  131. package/dist/index.html +11 -10
  132. package/dist/sw.js +17 -0
  133. package/package.json +4 -1
  134. package/plugins/{openai-documents → documents}/plugin.json +2 -2
  135. package/plugins/{openai-presentations → presentations}/plugin.json +2 -2
  136. package/plugins/{openai-spreadsheets → spreadsheets}/plugin.json +2 -2
  137. package/runtime-assets/agent/darwin-arm64/qf-agent +0 -0
  138. package/runtime-assets/agent/darwin-x64/qf-agent +0 -0
  139. package/runtime-assets/agent/linux-arm64/qf-agent +0 -0
  140. package/runtime-assets/agent/linux-x64/qf-agent +0 -0
  141. package/runtime-assets/agent/win32-x64/qf-agent.exe +0 -0
  142. package/server/access-policy.mjs +11 -0
  143. package/server/acp/server.mjs +36 -26
  144. package/server/agent-manager.mjs +474 -71
  145. package/server/agent-profile-files.mjs +8 -4
  146. package/server/agent-profile-schema.mjs +47 -23
  147. package/server/agent-profiles.mjs +28 -9
  148. package/server/ai-http-logger.mjs +98 -12
  149. package/server/auto-compaction.mjs +35 -8
  150. package/server/cloud/chat-idempotency-store.mjs +96 -0
  151. package/server/cloud/client.mjs +99 -0
  152. package/server/cloud/config.mjs +54 -0
  153. package/server/cloud/credential-store.mjs +200 -0
  154. package/server/cloud/identity.mjs +312 -0
  155. package/server/cloud/index.mjs +7 -0
  156. package/server/cloud/models.mjs +80 -0
  157. package/server/cloud/qf-agent-process.mjs +571 -0
  158. package/server/cloud/runtime.mjs +135 -0
  159. package/server/cloud/service-config.mjs +81 -0
  160. package/server/index.mjs +124 -48
  161. package/server/mcp/registry.mjs +8 -7
  162. package/server/message-converters.mjs +40 -19
  163. package/server/model-catalog.mjs +269 -0
  164. package/server/opencode-acp-agent.mjs +1151 -0
  165. package/server/plugins/registry.mjs +29 -5
  166. package/server/public-api.mjs +11 -5
  167. package/server/routes/agent-profiles.mjs +46 -9
  168. package/server/routes/agent.mjs +60 -11
  169. package/server/routes/backup.mjs +8 -1
  170. package/server/routes/cloud.mjs +246 -0
  171. package/server/routes/models.mjs +7 -1
  172. package/server/routes/scheduled-tasks.mjs +38 -8
  173. package/server/routes/shared-conversation.mjs +62 -58
  174. package/server/routes/shares.mjs +75 -1
  175. package/server/routes/storage.mjs +9 -1
  176. package/server/routes/system.mjs +7 -4
  177. package/server/routes/workspace.mjs +6 -4
  178. package/server/share-store.mjs +168 -13
  179. package/server/skills.mjs +30 -3
  180. package/server/storage.mjs +7 -1
  181. package/server/subagents.mjs +3 -3
  182. package/server/tools/definitions.mjs +1 -1
  183. package/server/tools/index.mjs +2 -2
  184. package/server/utils/network.mjs +9 -0
  185. package/server/utils/process-tree.mjs +78 -0
  186. package/server/utils/response.mjs +8 -1
  187. package/skills/skill-creator/LICENSE.txt +202 -0
  188. package/skills/skill-creator/SKILL.md +485 -0
  189. package/skills/skill-creator/UPSTREAM.md +6 -0
  190. package/skills/skill-creator/agents/analyzer.md +274 -0
  191. package/skills/skill-creator/agents/comparator.md +202 -0
  192. package/skills/skill-creator/agents/grader.md +223 -0
  193. package/skills/skill-creator/assets/eval_review.html +146 -0
  194. package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  195. package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  196. package/skills/skill-creator/references/schemas.md +430 -0
  197. package/skills/skill-creator/scripts/__init__.py +0 -0
  198. package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  199. package/skills/skill-creator/scripts/generate_report.py +326 -0
  200. package/skills/skill-creator/scripts/improve_description.py +247 -0
  201. package/skills/skill-creator/scripts/package_skill.py +136 -0
  202. package/skills/skill-creator/scripts/quick_validate.py +103 -0
  203. package/skills/skill-creator/scripts/run_eval.py +310 -0
  204. package/skills/skill-creator/scripts/run_loop.py +328 -0
  205. package/skills/skill-creator/scripts/utils.py +47 -0
  206. package/dist/assets/AgentProfilesPage-B84w-r9S.js +0 -1
  207. package/dist/assets/ChatPanelHost-CyO8fEoj.js +0 -288
  208. package/dist/assets/PluginsPage-D2862wul.js +0 -1
  209. package/dist/assets/ScheduledTasksPage-GqbiJDPX.js +0 -2
  210. package/dist/assets/SettingsWorkspacePage-B53_eDf2.js +0 -1628
  211. package/dist/assets/SharedConversationPage-Cw2QFnbC.js +0 -1
  212. package/dist/assets/TerminalDock-Dgg-_ZmU.js +0 -2
  213. package/dist/assets/WorkspaceInspector-3uLiu6Bv.js +0 -13
  214. package/dist/assets/architecture-TIHT7OUA-7FQo5GbP.js +0 -1
  215. package/dist/assets/channel-DToA8d-4.js +0 -1
  216. package/dist/assets/chunk-2Q5K7J3B-D_Wxpk-T.js +0 -1
  217. package/dist/assets/chunk-VAUOI2AC-CIZseNLi.js +0 -1
  218. package/dist/assets/chunk-XXDRQBXY-Do-XYxat.js +0 -1
  219. package/dist/assets/classDiagram-OUVF2IWQ-Bu24Sy-k.js +0 -1
  220. package/dist/assets/classDiagram-v2-EOCWNBFH-DKhh5HSW.js +0 -1
  221. package/dist/assets/cynefin-VYW2F7L2-oyiAgYC4.js +0 -1
  222. package/dist/assets/eventmodeling-45OFAUF4-YB_0MefX.js +0 -1
  223. package/dist/assets/flowDiagram-23GEKE2U-Bc73xdBd.js +0 -1
  224. package/dist/assets/gitGraph-TEB2WS4Q-Bvp27L0n.js +0 -1
  225. package/dist/assets/icons-cTkqD_Gi.js +0 -1
  226. package/dist/assets/index-B48prgLL.js +0 -65
  227. package/dist/assets/index-DQhwHHer.css +0 -3
  228. package/dist/assets/info-DKCQHKI2-BsLOivgq.js +0 -1
  229. package/dist/assets/packet-7NZHBO7P-BKQkXRtk.js +0 -1
  230. package/dist/assets/pie-RZYD4A2V-BTiTN5Ge.js +0 -1
  231. package/dist/assets/radar-I7S5WNFK-BU-oVjKM.js +0 -1
  232. package/dist/assets/railroad-3IZDKUUU-7H2hxNbL.js +0 -1
  233. package/dist/assets/railroad-abnf-AHOZXSZD-Mx6wf6XQ.js +0 -1
  234. package/dist/assets/railroad-ebnf-EBAXGLYW-BgXSKhYy.js +0 -1
  235. package/dist/assets/railroad-peg-LSFZ7HO6-DTEl2rAC.js +0 -1
  236. package/dist/assets/stateDiagram-v2-6OUMAXLB-D8x3mkni.js +0 -1
  237. package/dist/assets/swimlanesDiagram-G3AALYLV-C4nOBNp8.js +0 -8
  238. package/dist/assets/treeView-QDETBFTQ-DOE6NSdf.js +0 -1
  239. package/dist/assets/treemap-6X3UGDF4-Ca7QD_b4.js +0 -1
  240. package/dist/assets/wardley-OPB4EBWU-D9O4RKRm.js +0 -1
  241. /package/dist/assets/{array-DqLCdDFv.js → array-B9UHiPd-.js} +0 -0
  242. /package/dist/assets/{chunk-KEIR6QF5-s7Qq-R3i.js → chunk-KEIR6QF5-jrz1pRUS.js} +0 -0
  243. /package/dist/assets/{chunk-Y2CYZVJY-BgISNSiw.js → chunk-Y2CYZVJY-D6N-CrJv.js} +0 -0
  244. /package/dist/assets/{cytoscape.esm-iekjSZ2n.js → cytoscape.esm-DyfqweF2.js} +0 -0
  245. /package/dist/assets/{defaultLocale-CrJzLgRD.js → defaultLocale-5eAKkKJC.js} +0 -0
  246. /package/dist/assets/{dist-zzfqk5hx.js → dist-CLg13NtV.js} +0 -0
  247. /package/dist/assets/{graphlib-CIz_CfxW.js → graphlib-DJkmx0Cq.js} +0 -0
  248. /package/dist/assets/{init-C0r9Gk5G.js → init-DlZdxViB.js} +0 -0
  249. /package/dist/assets/{path-DIKpVbHL.js → path-6uRLdFF7.js} +0 -0
  250. /package/dist/assets/{plugin-api-C8hMT5W6.js → plugin-api-Uu2xAB4d.js} +0 -0
  251. /package/dist/assets/{rough.esm-BMOtDaaS.js → rough.esm-Bud4g4fh.js} +0 -0
  252. /package/dist/assets/{xterm-BFzZ1FH4.js → xterm-Bm_IbozX.js} +0 -0
  253. /package/plugins/{openai-documents → documents}/commands/document.md +0 -0
  254. /package/plugins/{openai-documents → documents}/skills/documents/SKILL.md +0 -0
  255. /package/plugins/{openai-presentations → presentations}/commands/presentation.md +0 -0
  256. /package/plugins/{openai-presentations → presentations}/skills/presentations/SKILL.md +0 -0
  257. /package/plugins/{openai-spreadsheets → spreadsheets}/commands/spreadsheet.md +0 -0
  258. /package/plugins/{openai-spreadsheets → spreadsheets}/skills/spreadsheets/SKILL.md +0 -0
@@ -6,6 +6,7 @@ import { createAgent, getSessionEventBus, agentEvents, persistSessionState, abor
6
6
  import { agentProfileSnapshot, getAgentProfile } from '../agent-profiles.mjs'
7
7
  import { projectContextFromId, readProjectConfig } from '../project-config.mjs'
8
8
  import { logger } from '../utils/logger.mjs'
9
+ import { resolveModelBinding } from '../model-catalog.mjs'
9
10
  import {
10
11
  dayMs,
11
12
  formatLocalDateTime,
@@ -133,10 +134,14 @@ async function getApiKey(provider) {
133
134
  }
134
135
  }
135
136
 
136
- async function parseScheduledTaskInstructionWithAi(instruction, model, thinkingLevel = 'off') {
137
+ async function parseScheduledTaskInstructionWithAi(instruction, modelInput, thinkingLevel = 'off', context = {}) {
137
138
  const text = String(instruction || '').trim()
138
139
  if (!text) return { needMoreInfo: true, question: '请输入要创建的定时任务。' }
139
- if (!model) return { needMoreInfo: true, question: '请先选择用于解析任务的大模型。' }
140
+ if (!modelInput) return { needMoreInfo: true, question: '请先选择用于解析任务的大模型。' }
141
+ const { model } = await resolveModelBinding(
142
+ modelInput?.modelRef || modelInput?.model ? modelInput : { model: modelInput },
143
+ { context, legacySnapshot: modelInput?.model || modelInput },
144
+ )
140
145
 
141
146
  const now = new Date()
142
147
  const systemPrompt = `你是定时任务解析器。把用户的中文自然语言定时任务解析为 JSON。
@@ -529,6 +534,18 @@ async function executeTask(task, trigger = 'schedule', onStarted) {
529
534
 
530
535
  try {
531
536
  const executionProject = await resolveExecutionProject(task)
537
+ const binding = task.modelRef || task.model
538
+ ? await resolveModelBinding(
539
+ task.modelRef ? { modelRef: task.modelRef } : { model: task.model },
540
+ {
541
+ context: { source: 'scheduled', allowCloud: true },
542
+ currentModel: task.model,
543
+ allowCurrentHidden: true,
544
+ forExecution: true,
545
+ legacySnapshot: task.model,
546
+ },
547
+ )
548
+ : null
532
549
  if (task.agentId) {
533
550
  executionAgent = await getAgentProfile(task.agentId, { projectId: executionProject?.id || null, workspaceRoot: executionProject?.path })
534
551
  if (!executionAgent) agentWarning = `Configured agent not found: ${task.agentId}`
@@ -541,7 +558,9 @@ async function executeTask(task, trigger = 'schedule', onStarted) {
541
558
  scope: executionProject ? 'project' : 'global',
542
559
  projectId: executionProject?.id || null,
543
560
  yoloMode,
544
- model: task.model,
561
+ model: binding?.model || task.model,
562
+ modelRef: binding?.modelRef || task.modelRef || null,
563
+ modelAccessContext: { source: 'scheduled', allowCloud: true },
545
564
  thinkingLevel: task.thinkingLevel,
546
565
  title: `[定时任务] ${task.title}`,
547
566
  agentProfile: executionAgent,
@@ -577,7 +596,7 @@ async function executeTask(task, trigger = 'schedule', onStarted) {
577
596
  onStarted?.({ taskId: task.id, runId, sessionId })
578
597
 
579
598
  const eventBus = getSessionEventBus(sessionId)
580
- const runtimeLimitMs = Math.max(1000, Math.min(Number(executionAgent?.maxRuntimeMs || 30 * 60 * 1000), 30 * 60 * 1000))
599
+ const runtimeLimitMs = Math.max(1000, Math.min(Number(executionAgent?.maxRuntimeMs || 60 * 60 * 1000), 60 * 60 * 1000))
581
600
  let timeout = null
582
601
  let handler = null
583
602
  let timedOut = false
@@ -770,12 +789,12 @@ export function stopScheduledTaskRunner() {
770
789
  runningTaskRunIds.clear()
771
790
  }
772
791
 
773
- export async function handleScheduledTasksApi(req, res, url) {
792
+ export async function handleScheduledTasksApi(req, res, url, context = {}) {
774
793
  const parts = url.pathname.split('/').filter(Boolean)
775
794
 
776
795
  if (req.method === 'POST' && url.pathname === '/api/scheduled-tasks/parse') {
777
796
  const body = await readJsonBody(req)
778
- sendJson(res, 200, await parseScheduledTaskInstructionWithAi(body?.instruction, body?.model, body?.thinkingLevel))
797
+ sendJson(res, 200, await parseScheduledTaskInstructionWithAi(body?.instruction, body?.modelRef ? body : body?.model, body?.thinkingLevel, context))
779
798
  return
780
799
  }
781
800
 
@@ -796,12 +815,14 @@ export async function handleScheduledTasksApi(req, res, url) {
796
815
  const now = new Date().toISOString()
797
816
  const normalized = normalizeTaskInput(parsed)
798
817
  const enabled = parsed.enabled !== false && parsed.status !== 'paused'
818
+ const binding = await resolveModelBinding(body, { context, legacySnapshot: body?.model })
799
819
  const task = {
800
820
  id: createId(),
801
821
  ...normalized,
802
822
  scheduleRule: normalized.scheduleRule || scheduleRuleFor(normalized),
803
823
  executionMode: normalized.executionMode || 'serial',
804
- model: body?.model,
824
+ model: binding.model,
825
+ modelRef: binding.modelRef,
805
826
  thinkingLevel: body?.thinkingLevel || (body?.model?.reasoning ? 'medium' : 'off'),
806
827
  projectId: body?.projectId || null,
807
828
  projectName: body?.projectName || null,
@@ -830,6 +851,14 @@ export async function handleScheduledTasksApi(req, res, url) {
830
851
  const parsed = body?.task
831
852
  if (!parsed) throw requestError('Missing task')
832
853
  const normalized = normalizeTaskInput(parsed, existing)
854
+ const binding = body?.modelRef || body?.model
855
+ ? await resolveModelBinding(body, {
856
+ context,
857
+ currentModel: existing.model,
858
+ allowCurrentHidden: true,
859
+ legacySnapshot: body?.model,
860
+ })
861
+ : null
833
862
  const now = new Date().toISOString()
834
863
  const hasProject = Object.prototype.hasOwnProperty.call(body, 'projectId')
835
864
  const task = await updateTask(taskId, (current) => ({
@@ -837,7 +866,8 @@ export async function handleScheduledTasksApi(req, res, url) {
837
866
  ...normalized,
838
867
  scheduleRule: normalized.scheduleRule || scheduleRuleFor(normalized),
839
868
  executionMode: normalized.executionMode || 'serial',
840
- model: body?.model ?? current.model,
869
+ model: binding?.model ?? current.model,
870
+ modelRef: binding?.modelRef ?? current.modelRef,
841
871
  thinkingLevel: body?.thinkingLevel ?? current.thinkingLevel,
842
872
  projectId: hasProject ? (body.projectId || null) : current.projectId,
843
873
  projectName: hasProject ? (body.projectName || null) : current.projectName,
@@ -1,10 +1,12 @@
1
1
  import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
2
- import { readSessionValue, readStore } from '../storage.mjs'
2
+ import { readSessionValue } from '../storage.mjs'
3
+ import { listModelCatalog, resolveModelBinding } from '../model-catalog.mjs'
3
4
  import { sendSessionAsset } from './session-assets.mjs'
4
5
  import { abortRun, restoreAgent, runPrompt, getSessionState, getSessionEventBus, updateSessionModel, updateSessionThinkingLevel } from '../agent-manager.mjs'
5
6
  import {
6
7
  assertShareActive,
7
8
  issueConversationShareToken,
9
+ onConversationShareInvalidated,
8
10
  parseCookies,
9
11
  readConversationShare,
10
12
  rollbackSharedSessionMessages,
@@ -49,6 +51,7 @@ function publicSharePayload(record) {
49
51
  scope: record.scope,
50
52
  projectId: record.projectId,
51
53
  hasPassword: Boolean(record.passwordHash),
54
+ allowCloudUsage: record.allowCloudUsage === true,
52
55
  }
53
56
  }
54
57
 
@@ -101,13 +104,6 @@ function sanitizeModel(model) {
101
104
  }
102
105
  }
103
106
 
104
- function sanitizeIncomingModel(model) {
105
- if (!model || typeof model !== 'object') return null
106
- const sanitized = sanitizeModel(model)
107
- if (!sanitized.id || !sanitized.provider) return null
108
- return sanitized
109
- }
110
-
111
107
  function sanitizeEvent(event) {
112
108
  if (!event || typeof event !== 'object') return event
113
109
  const next = { ...event }
@@ -147,6 +143,20 @@ async function handleSharedEvents(req, res, record) {
147
143
 
148
144
  writeSseEvent(res, 'state', await sharedSessionPayload(record))
149
145
 
146
+ let cleanedUp = false
147
+ let expirationTimeout
148
+ let removeShareInvalidationListener = () => undefined
149
+
150
+ const cleanup = () => {
151
+ if (cleanedUp) return
152
+ cleanedUp = true
153
+ clearInterval(keepAlive)
154
+ if (expirationTimeout) clearTimeout(expirationTimeout)
155
+ removeShareInvalidationListener()
156
+ eventBus.removeListener('agent_event', onAgentEvent)
157
+ if (!res.writableEnded) res.end()
158
+ }
159
+
150
160
  const keepAlive = setInterval(() => {
151
161
  try {
152
162
  res.write(': ping\n\n')
@@ -164,11 +174,19 @@ async function handleSharedEvents(req, res, record) {
164
174
  }
165
175
  }
166
176
 
167
- const cleanup = () => {
168
- clearInterval(keepAlive)
169
- eventBus.removeListener('agent_event', onAgentEvent)
170
- if (!res.writableEnded) res.end()
177
+ removeShareInvalidationListener = onConversationShareInvalidated(({ shareId }) => {
178
+ if (shareId === record.id) cleanup()
179
+ })
180
+ const scheduleExpiration = () => {
181
+ if (!record.expiresAt || cleanedUp) return
182
+ const delay = Date.parse(record.expiresAt) - Date.now()
183
+ if (delay <= 0) {
184
+ cleanup()
185
+ return
186
+ }
187
+ expirationTimeout = setTimeout(scheduleExpiration, Math.min(delay, 2_147_483_647))
171
188
  }
189
+ scheduleExpiration()
172
190
 
173
191
  eventBus.on('agent_event', onAgentEvent)
174
192
  req.on('close', cleanup)
@@ -269,42 +287,7 @@ async function sharedSessionPayload(record) {
269
287
  return sanitizeSession(session, record)
270
288
  }
271
289
 
272
- function sanitizeProvider(provider) {
273
- if (!provider || typeof provider !== 'object') return null
274
- const models = Array.isArray(provider.models)
275
- ? provider.models.map(sanitizeModel).filter((model) => model?.id && model?.provider && model?.api)
276
- : []
277
- if (!models.length) return null
278
- return {
279
- id: provider.id || provider.name || models[0].provider,
280
- name: provider.name || models[0].provider,
281
- type: provider.type || models[0].api,
282
- baseUrl: provider.baseUrl,
283
- models,
284
- }
285
- }
286
-
287
- async function listSharedModelProviders() {
288
- const providers = await readStore('custom-providers')
289
- return Object.values(providers || {}).map(sanitizeProvider).filter(Boolean)
290
- }
291
-
292
- async function readConfiguredModel(model) {
293
- if (!model || typeof model !== 'object') return null
294
- const providers = await readStore('custom-providers')
295
- for (const provider of Object.values(providers || {})) {
296
- if (!provider || typeof provider !== 'object') continue
297
- const matched = Array.isArray(provider.models)
298
- ? provider.models.find((candidate) => {
299
- return candidate?.id === model.id && candidate?.provider === model.provider && candidate?.api === model.api
300
- })
301
- : undefined
302
- if (matched) return matched
303
- }
304
- return null
305
- }
306
-
307
- export async function handleSharedConversationApi(req, res, url) {
290
+ export async function handleSharedConversationApi(req, res, url, context = {}) {
308
291
  const parts = url.pathname.split('/').filter(Boolean)
309
292
  const shareId = decodeSegment(parts[2])
310
293
  const action = parts[3]
@@ -360,7 +343,21 @@ export async function handleSharedConversationApi(req, res, url) {
360
343
 
361
344
  if (req.method === 'GET' && action === 'models') {
362
345
  assertOperate(record)
363
- sendJson(res, 200, { providers: await listSharedModelProviders() })
346
+ const session = await sharedSessionPayload(record)
347
+ const models = await listModelCatalog({
348
+ context: { ...context, allowCloud: record.allowCloudUsage === true },
349
+ currentModel: session.model,
350
+ })
351
+ const providers = []
352
+ for (const model of models) {
353
+ let provider = providers.find((item) => item.id === model.provider)
354
+ if (!provider) {
355
+ provider = { id: model.provider, name: model.provider, type: model.api, baseUrl: model.baseUrl, models: [] }
356
+ providers.push(provider)
357
+ }
358
+ provider.models.push(sanitizeModel(model))
359
+ }
360
+ sendJson(res, 200, { providers })
364
361
  return
365
362
  }
366
363
 
@@ -373,7 +370,14 @@ export async function handleSharedConversationApi(req, res, url) {
373
370
  assertOperate(record)
374
371
  const body = await readJsonBody(req)
375
372
  await restoreAgent(record.sessionId)
376
- const result = await runPrompt(record.sessionId, messageFromBody(body, record, req), [], body?.command)
373
+ const result = await runPrompt(
374
+ record.sessionId,
375
+ messageFromBody(body, record, req),
376
+ [],
377
+ body?.command,
378
+ null,
379
+ { ...context, allowCloud: record.allowCloudUsage === true, source: 'shared' },
380
+ )
377
381
  sendJson(res, 200, result)
378
382
  return
379
383
  }
@@ -381,15 +385,15 @@ export async function handleSharedConversationApi(req, res, url) {
381
385
  if (req.method === 'POST' && action === 'model') {
382
386
  assertOperate(record)
383
387
  const body = await readJsonBody(req)
384
- const model = sanitizeIncomingModel(body?.model)
385
- if (!model) {
386
- const error = new Error('Missing model in request body')
387
- error.statusCode = 400
388
- throw error
389
- }
390
388
  await restoreAgent(record.sessionId)
391
- const configured = await readConfiguredModel(model)
392
- sendJson(res, 200, updateSessionModel(record.sessionId, configured ? sanitizeModel(configured) : model))
389
+ const currentModel = getSessionState(record.sessionId)?.model
390
+ const binding = await resolveModelBinding(body, {
391
+ context: { ...context, allowCloud: record.allowCloudUsage === true, source: 'shared' },
392
+ currentModel,
393
+ allowCurrentHidden: true,
394
+ legacySnapshot: body?.model,
395
+ })
396
+ sendJson(res, 200, updateSessionModel(record.sessionId, sanitizeModel(binding.model), binding.modelRef))
393
397
  return
394
398
  }
395
399
 
@@ -1,10 +1,15 @@
1
1
  import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
2
2
  import { readSessionValue } from '../storage.mjs'
3
3
  import { getLanUrls } from '../utils/network.mjs'
4
+ import { isAuthenticatedAppClient } from '../access-policy.mjs'
4
5
  import {
5
6
  createConversationShare,
7
+ deleteConversationShare,
6
8
  listConversationShares,
9
+ restoreConversationShare,
7
10
  revokeConversationShare,
11
+ updateConversationShare,
12
+ updateConversationShareExpiration,
8
13
  } from '../share-store.mjs'
9
14
 
10
15
  function localBaseUrl(req, port) {
@@ -24,7 +29,7 @@ function shareUrlForRequest(req, shareId, port) {
24
29
  return `${baseUrl}/share/${encodeURIComponent(shareId)}`
25
30
  }
26
31
 
27
- export async function handleSharesApi(req, res, url, context = {}) {
32
+ export async function handleSharesApi(req, res, url, context = { isLocalRequest: true }) {
28
33
  const parts = url.pathname.split('/').filter(Boolean)
29
34
 
30
35
  if (req.method === 'GET' && url.pathname === '/api/shares') {
@@ -46,6 +51,12 @@ export async function handleSharesApi(req, res, url, context = {}) {
46
51
  const passwordProvided = typeof body?.password === 'string'
47
52
  const password = passwordProvided ? body.password.trim() : undefined
48
53
  const expiresAt = typeof body?.expiresAt === 'string' && body.expiresAt ? body.expiresAt : undefined
54
+ const allowCloudUsage = permission === 'operate' && body?.allowCloudUsage === true
55
+ if (allowCloudUsage && !isAuthenticatedAppClient(context)) {
56
+ const error = new Error('QuickForge Cloud sharing can only be enabled locally or from an authenticated remote client.')
57
+ error.statusCode = 403
58
+ throw error
59
+ }
49
60
 
50
61
  const session = sessionId ? await readSessionValue(sessionId) : null
51
62
  if (!session) {
@@ -59,6 +70,7 @@ export async function handleSharesApi(req, res, url, context = {}) {
59
70
  permission,
60
71
  password: passwordProvided ? password : undefined,
61
72
  expiresAt,
73
+ allowCloudUsage,
62
74
  titleSnapshot: session.title,
63
75
  scope: session.scope,
64
76
  projectId: session.projectId,
@@ -77,6 +89,68 @@ export async function handleSharesApi(req, res, url, context = {}) {
77
89
  return
78
90
  }
79
91
 
92
+ if (parts.length === 4 && parts[0] === 'api' && parts[1] === 'shares') {
93
+ const shareId = decodeSegment(parts[2])
94
+ const action = parts[3]
95
+
96
+ if (req.method === 'POST' && action === 'disable') {
97
+ const share = await revokeConversationShare(shareId)
98
+ sendJson(res, 200, { ok: true, share })
99
+ return
100
+ }
101
+
102
+ if (req.method === 'POST' && action === 'restore') {
103
+ const body = await readJsonBody(req)
104
+ const expiresAt = typeof body?.expiresAt === 'string' && body.expiresAt ? body.expiresAt : undefined
105
+ const currentShares = await listConversationShares()
106
+ const current = currentShares.find((share) => share.id === shareId)
107
+ if (!current) {
108
+ const error = new Error('Share not found')
109
+ error.statusCode = 404
110
+ throw error
111
+ }
112
+ const session = current.sessionId ? await readSessionValue(current.sessionId) : null
113
+ if (!session) {
114
+ const error = new Error('Session not found')
115
+ error.statusCode = 404
116
+ throw error
117
+ }
118
+ const share = await restoreConversationShare(shareId, expiresAt)
119
+ sendJson(res, 200, { ok: true, share })
120
+ return
121
+ }
122
+
123
+ if (req.method === 'POST' && action === 'expiration') {
124
+ const body = await readJsonBody(req)
125
+ const expiresAt = typeof body?.expiresAt === 'string' && body.expiresAt ? body.expiresAt : undefined
126
+ const share = await updateConversationShareExpiration(shareId, expiresAt)
127
+ sendJson(res, 200, { ok: true, share })
128
+ return
129
+ }
130
+
131
+ if (req.method === 'POST' && action === 'update') {
132
+ const body = await readJsonBody(req)
133
+ const permission = body?.permission
134
+ const password = typeof body?.password === 'string' ? body.password : undefined
135
+ const expiresAt = typeof body?.expiresAt === 'string' && body.expiresAt ? body.expiresAt : undefined
136
+ const allowCloudUsage = body?.allowCloudUsage
137
+ if (allowCloudUsage === true && !isAuthenticatedAppClient(context)) {
138
+ const error = new Error('QuickForge Cloud sharing can only be enabled locally or from an authenticated remote client.')
139
+ error.statusCode = 403
140
+ throw error
141
+ }
142
+ const share = await updateConversationShare(shareId, { permission, password, expiresAt, allowCloudUsage })
143
+ sendJson(res, 200, { ok: true, share })
144
+ return
145
+ }
146
+
147
+ if (req.method === 'DELETE' && action === 'permanent') {
148
+ const share = await deleteConversationShare(shareId)
149
+ sendJson(res, 200, { ok: true, share })
150
+ return
151
+ }
152
+ }
153
+
80
154
  if (req.method === 'DELETE' && parts.length === 3 && parts[0] === 'api' && parts[1] === 'shares') {
81
155
  const shareId = decodeSegment(parts[2])
82
156
  const share = await revokeConversationShare(shareId)
@@ -2,6 +2,7 @@ import { sendJson, readJsonBody, decodeSegment } from '../utils/response.mjs'
2
2
  import { readStore, writeStore, atomicUpdate, getComparable, getStoreRevision, readSessionStoreScoped, readSessionValue, writeSessionValue, deleteSessionValue, ensureStorage, dataDir, configDir, storageDir, cacheDir, logsDir } from '../storage.mjs'
3
3
  import { AUTO_ARCHIVE_SETTINGS_KEY, archiveInactiveSessions, normalizeAutoArchiveSettings } from '../auto-archive.mjs'
4
4
  import { directorySize } from '../utils/workspace.mjs'
5
+ import { isAuthenticatedAppClient } from '../access-policy.mjs'
5
6
 
6
7
  const metadataIndexCache = new Map()
7
8
  const MAX_METADATA_INDEX_CACHE_ENTRIES = 50
@@ -94,7 +95,14 @@ async function readIndexedValues(store, indexName, direction, scope, projectId,
94
95
  return values
95
96
  }
96
97
 
97
- export async function handleStorageApi(req, res, url) {
98
+ export async function handleStorageApi(req, res, url, context = { isLocalRequest: true }) {
99
+ if (!isAuthenticatedAppClient(context)) {
100
+ const error = new Error('Storage access requires a local or authenticated remote client.')
101
+ error.statusCode = 403
102
+ error.errorCode = 'storage_auth_required'
103
+ throw error
104
+ }
105
+
98
106
  const parts = url.pathname.split('/').filter(Boolean)
99
107
 
100
108
  if (req.method === 'GET' && url.pathname === '/api/storage/quota') {
@@ -1,5 +1,6 @@
1
1
  import { sendJson, readJsonBody } from '../utils/response.mjs'
2
2
  import { getLanUrls } from '../utils/network.mjs'
3
+ import { isAuthenticatedAppClient } from '../access-policy.mjs'
3
4
 
4
5
  export async function handleSystemApi(req, res, url, context) {
5
6
  if (req.method === 'GET' && url.pathname === '/api/system/about') {
@@ -18,9 +19,10 @@ export async function handleSystemApi(req, res, url, context) {
18
19
  }
19
20
 
20
21
  if (req.method === 'POST' && url.pathname === '/api/system/update') {
21
- if (!context.isLocalRequest) {
22
- const error = new Error('Update is only allowed from this computer')
22
+ if (!isAuthenticatedAppClient(context)) {
23
+ const error = new Error('Update requires a local or authenticated remote client')
23
24
  error.statusCode = 403
25
+ error.errorCode = 'system_update_requires_auth'
24
26
  throw error
25
27
  }
26
28
 
@@ -36,9 +38,10 @@ export async function handleSystemApi(req, res, url, context) {
36
38
  }
37
39
 
38
40
  if (req.method === 'POST' && url.pathname === '/api/system/restart') {
39
- if (!context.isLocalRequest) {
40
- const error = new Error('Restart is only allowed from this computer')
41
+ if (!isAuthenticatedAppClient(context)) {
42
+ const error = new Error('Restart requires a local or authenticated remote client')
41
43
  error.statusCode = 403
44
+ error.errorCode = 'system_restart_requires_auth'
42
45
  throw error
43
46
  }
44
47
 
@@ -2,6 +2,7 @@ import { promises as fs } from 'node:fs'
2
2
  import path from 'node:path'
3
3
  import { spawn } from 'node:child_process'
4
4
  import { streamSimpleWithAiHttpLogging } from '../ai-http-logger.mjs'
5
+ import { resolveModelBinding } from '../model-catalog.mjs'
5
6
  import { DEFAULT_AI_MAX_RETRIES } from '../ai-provider-options.mjs'
6
7
  import { sendJson, readJsonBody } from '../utils/response.mjs'
7
8
  import { projectContextFromId } from '../project-config.mjs'
@@ -1080,9 +1081,10 @@ async function contextFromGitBody(req) {
1080
1081
  return { context: await projectContextFromId(projectId), body }
1081
1082
  }
1082
1083
 
1083
- async function handleGitGenerateCommitMessage(req, res) {
1084
+ async function handleGitGenerateCommitMessage(req, res, requestContext = {}) {
1084
1085
  const { context, body } = await contextFromGitBody(req)
1085
- const message = await generateGitCommitMessage(context, body?.model, body?.thinkingLevel, Boolean(body?.includeUnstaged))
1086
+ const binding = await resolveModelBinding(body, { context: requestContext, legacySnapshot: body?.model })
1087
+ const message = await generateGitCommitMessage(context, binding.model, body?.thinkingLevel, Boolean(body?.includeUnstaged))
1086
1088
  sendJson(res, 200, { message })
1087
1089
  }
1088
1090
 
@@ -1178,7 +1180,7 @@ export async function handleWorkspaceApi(req, res, url, requestContext = {}) {
1178
1180
  throw error
1179
1181
  }
1180
1182
 
1181
- export async function handleGitApi(req, res, url) {
1183
+ export async function handleGitApi(req, res, url, requestContext = {}) {
1182
1184
  if (req.method === 'GET' && url.pathname === '/api/git/status') {
1183
1185
  await handleGitStatus(req, res, url)
1184
1186
  return
@@ -1204,7 +1206,7 @@ export async function handleGitApi(req, res, url) {
1204
1206
  return
1205
1207
  }
1206
1208
  if (req.method === 'POST' && url.pathname === '/api/git/generate-commit-message') {
1207
- await handleGitGenerateCommitMessage(req, res)
1209
+ await handleGitGenerateCommitMessage(req, res, requestContext)
1208
1210
  return
1209
1211
  }
1210
1212
  if (req.method === 'POST' && url.pathname === '/api/git/stage') {