@shawnstack/quickforge 1.7.2 → 1.7.4

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 (210) hide show
  1. package/README.md +1 -0
  2. package/bin/quickforge.mjs +2 -21
  3. package/dist/assets/AgentProfilesPage-B84w-r9S.js +1 -0
  4. package/dist/assets/{ChatPanelHost-Cld9HcVz.js → ChatPanelHost-CyO8fEoj.js} +98 -98
  5. package/dist/assets/{PluginsPage-DEMqwhOA.js → PluginsPage-D2862wul.js} +1 -1
  6. package/dist/assets/{ScheduledTasksPage-DTP_gedp.js → ScheduledTasksPage-GqbiJDPX.js} +2 -2
  7. package/dist/assets/SettingsWorkspacePage-B53_eDf2.js +1628 -0
  8. package/dist/assets/SharedConversationPage-Cw2QFnbC.js +1 -0
  9. package/dist/assets/TerminalDock-Dgg-_ZmU.js +2 -0
  10. package/dist/assets/WorkspaceInspector-3uLiu6Bv.js +13 -0
  11. package/dist/assets/{abnfDiagram-VRR7QNED-Dl_Fvlqg.js → abnfDiagram-VRR7QNED-Dy7veffk.js} +1 -1
  12. package/dist/assets/{arc-Bhg4c0ht.js → arc-Bo3p2lGy.js} +1 -1
  13. package/dist/assets/architecture-TIHT7OUA-7FQo5GbP.js +1 -0
  14. package/dist/assets/{architectureDiagram-ZJ3FMSHR-BuojN27B.js → architectureDiagram-ZJ3FMSHR-Cwx8qOvu.js} +1 -1
  15. package/dist/assets/{blockDiagram-677ZJIJ3-alDLbrR1.js → blockDiagram-677ZJIJ3-BiuaAOFa.js} +1 -1
  16. package/dist/assets/{c4Diagram-LMCZKHZV-D1lKa4VT.js → c4Diagram-LMCZKHZV-BTcGfhK2.js} +1 -1
  17. package/dist/assets/channel-DToA8d-4.js +1 -0
  18. package/dist/assets/chunk-2Q5K7J3B-D_Wxpk-T.js +1 -0
  19. package/dist/assets/{chunk-32BRIVSS-CwWLNjMZ.js → chunk-32BRIVSS-B9PuF_RF.js} +1 -1
  20. package/dist/assets/{chunk-52WLFC77-Be569m7d.js → chunk-52WLFC77-3zGItfIM.js} +1 -1
  21. package/dist/assets/{chunk-5FCAYU7R-BSvoiWV1.js → chunk-5FCAYU7R-DQ66qlmt.js} +1 -1
  22. package/dist/assets/{chunk-5HE753X5-CRgsy8WS.js → chunk-5HE753X5-CLqTO-VF.js} +1 -1
  23. package/dist/assets/{chunk-5JV3BV7I-CdW477UR.js → chunk-5JV3BV7I-Csxv1jr6.js} +1 -1
  24. package/dist/assets/{chunk-5TONJI2A-CdtKzSmp.js → chunk-5TONJI2A-BCQttpBr.js} +1 -1
  25. package/dist/assets/{chunk-5VM5RSS4-BKjjssLZ.js → chunk-5VM5RSS4-DEWJGSTb.js} +1 -1
  26. package/dist/assets/{chunk-7BUUIJ7U-ByAXiXdn.js → chunk-7BUUIJ7U-DNorm9MM.js} +1 -1
  27. package/dist/assets/{chunk-BIQX33UG-DeG8SCT1.js → chunk-BIQX33UG-DgvY_BOT.js} +1 -1
  28. package/dist/assets/{chunk-C7G6YPKG-D_zHT68Q.js → chunk-C7G6YPKG-DMvn9IPs.js} +1 -1
  29. package/dist/assets/{chunk-CQNSW5MT-CHpHoUSu.js → chunk-CQNSW5MT-Dq2duUgr.js} +1 -1
  30. package/dist/assets/{chunk-CYSBUYHQ-CRP50Vov.js → chunk-CYSBUYHQ-BovYyc4Y.js} +1 -1
  31. package/dist/assets/{chunk-EMLP6XTP-DX6uQQ2v.js → chunk-EMLP6XTP-BMDOpuYN.js} +1 -1
  32. package/dist/assets/{chunk-EX3LRPZG-DAJRNkHR.js → chunk-EX3LRPZG-6eP2UPOf.js} +1 -1
  33. package/dist/assets/{chunk-FWX5IMBZ-XbM5yomC.js → chunk-FWX5IMBZ-D4q-wTSy.js} +2 -2
  34. package/dist/assets/{chunk-HOUHSVGY-Ci0ljnb1.js → chunk-HOUHSVGY-XjIcuzH7.js} +1 -1
  35. package/dist/assets/{chunk-ICXQ74PX-Dy2WJ71z.js → chunk-ICXQ74PX-YBXbanq9.js} +1 -1
  36. package/dist/assets/{chunk-JG7HCLWE-2PrkzHkt.js → chunk-JG7HCLWE-CcN3uNXF.js} +1 -1
  37. package/dist/assets/{chunk-JWPE2WC7-D32uacSM.js → chunk-JWPE2WC7-Cwg6AUAt.js} +1 -1
  38. package/dist/assets/{chunk-MOJQB5TN-DIAFLtiS.js → chunk-MOJQB5TN-NNspcGIU.js} +1 -1
  39. package/dist/assets/{chunk-MOZMSUNE-BbscOaEz.js → chunk-MOZMSUNE-pMJ_jMos.js} +1 -1
  40. package/dist/assets/{chunk-OGEWGWER-ivBVxzKe.js → chunk-OGEWGWER-CJy-3Ldv.js} +1 -1
  41. package/dist/assets/{chunk-OSBZ3O6U-frD0hkdx.js → chunk-OSBZ3O6U-D7cLHHOA.js} +1 -1
  42. package/dist/assets/{chunk-PUDLZKDR-B-37Rxae.js → chunk-PUDLZKDR-D5YBi1Pi.js} +1 -1
  43. package/dist/assets/{chunk-Q4XR5HBZ-Y90m2RTe.js → chunk-Q4XR5HBZ-DYmqQdIf.js} +1 -1
  44. package/dist/assets/{chunk-QBLGF6JB-DixBqslB.js → chunk-QBLGF6JB-Bfcx00X0.js} +1 -1
  45. package/dist/assets/{chunk-R7FJI6CG-DXS1UXn_.js → chunk-R7FJI6CG-oXzadpZY.js} +1 -1
  46. package/dist/assets/{chunk-RYQCIY6F-n4JxhNd0.js → chunk-RYQCIY6F-Dt3-8yUh.js} +1 -1
  47. package/dist/assets/{chunk-U6XO7XAA-yHlgxMmn.js → chunk-U6XO7XAA-B55eSvpx.js} +1 -1
  48. package/dist/assets/{chunk-V7JOEXUC-Z6kuZfbl.js → chunk-V7JOEXUC-Btk4JwCt.js} +1 -1
  49. package/dist/assets/chunk-VAUOI2AC-CIZseNLi.js +1 -0
  50. package/dist/assets/{chunk-VR4S4FIN-Cs_SIQma.js → chunk-VR4S4FIN-DgaSiVOY.js} +1 -1
  51. package/dist/assets/{chunk-WYO6CB5R-CGExYbV-.js → chunk-WYO6CB5R-rRDZ_Tta.js} +3 -3
  52. package/dist/assets/chunk-XXDRQBXY-Do-XYxat.js +1 -0
  53. package/dist/assets/{chunk-YOTPTUD7-DopPXWSl.js → chunk-YOTPTUD7-BnFxj5o4.js} +1 -1
  54. package/dist/assets/{chunk-ZGVPDNZ5-CJHOeqMb.js → chunk-ZGVPDNZ5-CrnlPlmJ.js} +1 -1
  55. package/dist/assets/{chunk-ZIRB5QZD-BBVc5mf6.js → chunk-ZIRB5QZD-BYTiATIH.js} +1 -1
  56. package/dist/assets/classDiagram-OUVF2IWQ-Bu24Sy-k.js +1 -0
  57. package/dist/assets/classDiagram-v2-EOCWNBFH-DKhh5HSW.js +1 -0
  58. package/dist/assets/{cose-bilkent-JH36ORCC-DLjV-dTm.js → cose-bilkent-JH36ORCC-BORKJRwF.js} +1 -1
  59. package/dist/assets/cynefin-VYW2F7L2-oyiAgYC4.js +1 -0
  60. package/dist/assets/{cynefinDiagram-TSTJHNR4-BfH3zVS-.js → cynefinDiagram-TSTJHNR4-BXKeaSl8.js} +1 -1
  61. package/dist/assets/{dagre-CY3D84Cl.js → dagre-CrA0XVwJ.js} +1 -1
  62. package/dist/assets/{dagre-VKFMJZFB-BIhwZCIZ.js → dagre-VKFMJZFB-ouq_lA1a.js} +1 -1
  63. package/dist/assets/{diagram-FQU43EPY-BHnzNM2w.js → diagram-FQU43EPY-BxR5kUiQ.js} +1 -1
  64. package/dist/assets/{diagram-G47NLZAW-C7-ZlmFT.js → diagram-G47NLZAW-DWonk1sL.js} +1 -1
  65. package/dist/assets/{diagram-NH7WQ7WH-C-P9Y7IR.js → diagram-NH7WQ7WH-fmV_wV5e.js} +1 -1
  66. package/dist/assets/{diagram-OA4YK3LP-Ci5lZ_T5.js → diagram-OA4YK3LP-DvOSRRiV.js} +1 -1
  67. package/dist/assets/{diagram-WEI45ONY-C1xuK2bs.js → diagram-WEI45ONY-Bp-xb3uS.js} +1 -1
  68. package/dist/assets/dist-DLKC_odd.js +1 -0
  69. package/dist/assets/{ebnfDiagram-CCIWWBDH-DKQ5NWMD.js → ebnfDiagram-CCIWWBDH-BTlnwneA.js} +1 -1
  70. package/dist/assets/{erDiagram-Q63AITRT-HAWySadP.js → erDiagram-Q63AITRT-C3fFWGCm.js} +1 -1
  71. package/dist/assets/esm-oa69b5u4.js +2 -0
  72. package/dist/assets/eventmodeling-45OFAUF4-YB_0MefX.js +1 -0
  73. package/dist/assets/flowDiagram-23GEKE2U-Bc73xdBd.js +1 -0
  74. package/dist/assets/{ganttDiagram-NO4QXBWP-C1hwIcOA.js → ganttDiagram-NO4QXBWP-DzAiojNi.js} +1 -1
  75. package/dist/assets/gitGraph-TEB2WS4Q-Bvp27L0n.js +1 -0
  76. package/dist/assets/{gitGraphDiagram-IHSO6WYX-DYUYxs1R.js → gitGraphDiagram-IHSO6WYX-Cv57oNEA.js} +1 -1
  77. package/dist/assets/icons-cTkqD_Gi.js +1 -0
  78. package/dist/assets/index-B48prgLL.js +65 -0
  79. package/dist/assets/index-DQhwHHer.css +3 -0
  80. package/dist/assets/info-DKCQHKI2-BsLOivgq.js +1 -0
  81. package/dist/assets/{infoDiagram-FWYZ7A6U-CnIL6tv4.js → infoDiagram-FWYZ7A6U-B5Z_O3Ro.js} +1 -1
  82. package/dist/assets/{ishikawaDiagram-FXEZZL3T-B7WXNycQ.js → ishikawaDiagram-FXEZZL3T-CKTK_TKV.js} +1 -1
  83. package/dist/assets/{journeyDiagram-5HDEW3XC-D4HvioyY.js → journeyDiagram-5HDEW3XC-Cm9k4ywW.js} +1 -1
  84. package/dist/assets/{kanban-definition-HUTT4EX6-CDs763eS.js → kanban-definition-HUTT4EX6-DzNteLwx.js} +1 -1
  85. package/dist/assets/{line-ikKkQiFp.js → line-BG78c_WJ.js} +1 -1
  86. package/dist/assets/{linear-GqPyxQkN.js → linear-1X20_EGu.js} +1 -1
  87. package/dist/assets/{map-CJwjCvwr.js → map-CCI8WZkS.js} +1 -1
  88. package/dist/assets/{mcp-servers-dialog-Bp6kbIup.js → mcp-servers-dialog-GXXD9K0U.js} +2 -2
  89. package/dist/assets/{mermaid-parser.core-CoE8cccr.js → mermaid-parser.core-Bb8HI_OS.js} +2 -2
  90. package/dist/assets/{mermaid-renderer-BmbSAmpG.js → mermaid-renderer-PIaNiXAz.js} +2 -2
  91. package/dist/assets/{mermaid.core-DlFSL90j.js → mermaid.core-DUHOIwL5.js} +3 -3
  92. package/dist/assets/{mindmap-definition-LN4V7U3C-DLdq0K9C.js → mindmap-definition-LN4V7U3C-Tnbszo7b.js} +1 -1
  93. package/dist/assets/{monaco-BTsVCDWS.js → monaco-BVtCspYZ.js} +1 -1
  94. package/dist/assets/{ordinal-CibZU3PM.js → ordinal-v4prQcuq.js} +1 -1
  95. package/dist/assets/{otel-BNGM50C-.js → otel-D1LswXpM.js} +1 -1
  96. package/dist/assets/packet-7NZHBO7P-BKQkXRtk.js +1 -0
  97. package/dist/assets/{pegDiagram-2B236MQR-Cm1kPRC2.js → pegDiagram-2B236MQR-CX824Kd0.js} +1 -1
  98. package/dist/assets/{pi-ai-Cr3rpCXT.js → pi-ai-DAJlO9ZB.js} +2 -2
  99. package/dist/assets/{pi-web-ui-DoRGtREc.js → pi-web-ui-B-RJSxjR.js} +1 -1
  100. package/dist/assets/pie-RZYD4A2V-BTiTN5Ge.js +1 -0
  101. package/dist/assets/{pieDiagram-ENE6RG2P-Df05wjjo.js → pieDiagram-ENE6RG2P-BT04VWPQ.js} +1 -1
  102. package/dist/assets/{quadrantDiagram-ABIIQ3AL-BjCwGxJC.js → quadrantDiagram-ABIIQ3AL-BvOZxkBr.js} +1 -1
  103. package/dist/assets/radar-I7S5WNFK-BU-oVjKM.js +1 -0
  104. package/dist/assets/railroad-3IZDKUUU-7H2hxNbL.js +1 -0
  105. package/dist/assets/railroad-abnf-AHOZXSZD-Mx6wf6XQ.js +1 -0
  106. package/dist/assets/railroad-ebnf-EBAXGLYW-BgXSKhYy.js +1 -0
  107. package/dist/assets/railroad-peg-LSFZ7HO6-DTEl2rAC.js +1 -0
  108. package/dist/assets/{railroadDiagram-RFXS5EU6-CTUvpKkv.js → railroadDiagram-RFXS5EU6-DnTU--BV.js} +1 -1
  109. package/dist/assets/{react-vendor-Dr5xvL-e.js → react-vendor-eWH0QhNU.js} +1 -1
  110. package/dist/assets/{requirementDiagram-TGXJPOKE-BU1kvEku.js → requirementDiagram-TGXJPOKE--MZX_yEv.js} +1 -1
  111. package/dist/assets/{sankeyDiagram-HTMAVEWB-BHmvxVqH.js → sankeyDiagram-HTMAVEWB-SEZkHhYn.js} +1 -1
  112. package/dist/assets/{sequenceDiagram-DBY2YBRQ-CTpwICgg.js → sequenceDiagram-DBY2YBRQ-BhC2OHiz.js} +1 -1
  113. package/dist/assets/{sizeCapture-X5ZJPWSS-BbLhGaa4.js → sizeCapture-X5ZJPWSS-Ci5LeToV.js} +1 -1
  114. package/dist/assets/{skills-dialog-DiJAUfvW.js → skills-dialog-DDh1h8eH.js} +3 -1
  115. package/dist/assets/{src-B4Tvg3gT.js → src-CovulcRC.js} +1 -1
  116. package/dist/assets/{stateDiagram-2N3HPSRC-BxuDwIgT.js → stateDiagram-2N3HPSRC-DKK5tFT4.js} +1 -1
  117. package/dist/assets/stateDiagram-v2-6OUMAXLB-D8x3mkni.js +1 -0
  118. package/dist/assets/{swimlanes-5IMT3BWC-EkZsiylV.js → swimlanes-5IMT3BWC-DxxGCk67.js} +2 -2
  119. package/dist/assets/swimlanesDiagram-G3AALYLV-C4nOBNp8.js +8 -0
  120. package/dist/assets/{timeline-definition-FHXFAJF6-C9ewOCTa.js → timeline-definition-FHXFAJF6-BPXB3Sue.js} +1 -1
  121. package/dist/assets/treeView-QDETBFTQ-DOE6NSdf.js +1 -0
  122. package/dist/assets/treemap-6X3UGDF4-Ca7QD_b4.js +1 -0
  123. package/dist/assets/{vennDiagram-L72KCM5P-CR49Y4Lp.js → vennDiagram-L72KCM5P-CxcBCKye.js} +1 -1
  124. package/dist/assets/wardley-OPB4EBWU-D9O4RKRm.js +1 -0
  125. package/dist/assets/{wardleyDiagram-EHGQE667-Cn0GgwWi.js → wardleyDiagram-EHGQE667-DEL6Yes5.js} +1 -1
  126. package/dist/assets/web-RgX7H-OH.js +1 -0
  127. package/dist/assets/{xychartDiagram-FW5EYKEG-DlmPNAvd.js → xychartDiagram-FW5EYKEG-N8cPbcjC.js} +1 -1
  128. package/dist/index.html +12 -11
  129. package/dist/mobile-error.html +24 -0
  130. package/package.json +7 -1
  131. package/server/acp/server.mjs +14 -9
  132. package/server/agent-manager.mjs +215 -20
  133. package/server/ai-http-logger.mjs +69 -12
  134. package/server/ai-provider-options.mjs +11 -0
  135. package/server/channels/channel-logs.mjs +13 -0
  136. package/server/channels/event-relay.mjs +33 -0
  137. package/server/channels/process-channel.mjs +29 -0
  138. package/server/channels/providers/wechat.mjs +9 -3
  139. package/server/channels/registry.mjs +5 -1
  140. package/server/index.mjs +43 -25
  141. package/server/lan-access-store.mjs +93 -3
  142. package/server/network-proxy.mjs +449 -0
  143. package/server/plugins/registry.mjs +64 -4
  144. package/server/public-api.mjs +10 -2
  145. package/server/routes/agent-profiles.mjs +4 -2
  146. package/server/routes/agent.mjs +28 -0
  147. package/server/routes/channels.mjs +47 -0
  148. package/server/routes/lan-access.mjs +246 -21
  149. package/server/routes/models.mjs +7 -3
  150. package/server/routes/project.mjs +19 -1
  151. package/server/routes/scheduled-tasks.mjs +4 -2
  152. package/server/routes/static.mjs +26 -1
  153. package/server/routes/system.mjs +37 -0
  154. package/server/routes/terminal.mjs +7 -2
  155. package/server/routes/workspace.mjs +62 -9
  156. package/server/session-utils.mjs +4 -2
  157. package/server/subagents.mjs +1 -1
  158. package/server/terminal/terminal-manager.mjs +2 -4
  159. package/server/tools/definitions.mjs +2 -2
  160. package/server/tools/index.mjs +5 -3
  161. package/server/utils/package-update.mjs +70 -47
  162. package/server/utils/process-env.mjs +7 -0
  163. package/server/utils/response.mjs +2 -2
  164. package/dist/assets/AgentProfilesPage-BFgyFa5e.js +0 -1
  165. package/dist/assets/SettingsWorkspacePage-Dr9zT5Bs.js +0 -1495
  166. package/dist/assets/SharedConversationPage-op3DRwcw.js +0 -1
  167. package/dist/assets/TerminalDock-BL_UovwU.js +0 -2
  168. package/dist/assets/WorkspaceInspector-73dhAime.js +0 -13
  169. package/dist/assets/architecture-TIHT7OUA-BgP-IMeo.js +0 -1
  170. package/dist/assets/channel-Rz20dKTK.js +0 -1
  171. package/dist/assets/chunk-2Q5K7J3B-Cb14ZF_k.js +0 -1
  172. package/dist/assets/chunk-VAUOI2AC-BOZvd2Sn.js +0 -1
  173. package/dist/assets/chunk-XXDRQBXY-CD_EGCtT.js +0 -1
  174. package/dist/assets/classDiagram-OUVF2IWQ-C_ozTKCt.js +0 -1
  175. package/dist/assets/classDiagram-v2-EOCWNBFH-FOfFbbZF.js +0 -1
  176. package/dist/assets/cynefin-VYW2F7L2-BzPhLtd5.js +0 -1
  177. package/dist/assets/eventmodeling-45OFAUF4-BcgGbVJ-.js +0 -1
  178. package/dist/assets/flowDiagram-23GEKE2U-dtkzcC8E.js +0 -1
  179. package/dist/assets/gitGraph-TEB2WS4Q-VByWboBU.js +0 -1
  180. package/dist/assets/icons-BP8YOS-Z.js +0 -1
  181. package/dist/assets/index-Cu2bBHLv.css +0 -3
  182. package/dist/assets/index-yV1wtqTr.js +0 -66
  183. package/dist/assets/info-DKCQHKI2-CZeDLZxx.js +0 -1
  184. package/dist/assets/packet-7NZHBO7P-decrrxyX.js +0 -1
  185. package/dist/assets/pie-RZYD4A2V-J1CasQZl.js +0 -1
  186. package/dist/assets/radar-I7S5WNFK-B-sZytUA.js +0 -1
  187. package/dist/assets/railroad-3IZDKUUU-BSaqNPm8.js +0 -1
  188. package/dist/assets/railroad-abnf-AHOZXSZD-lzZR7PxT.js +0 -1
  189. package/dist/assets/railroad-ebnf-EBAXGLYW-DQtz1Fh9.js +0 -1
  190. package/dist/assets/railroad-peg-LSFZ7HO6-CpMsuGY3.js +0 -1
  191. package/dist/assets/stateDiagram-v2-6OUMAXLB-BGLshxcY.js +0 -1
  192. package/dist/assets/swimlanesDiagram-G3AALYLV-CqdqxA-b.js +0 -8
  193. package/dist/assets/treeView-QDETBFTQ-Byb71heW.js +0 -1
  194. package/dist/assets/treemap-6X3UGDF4-CMV1SJsq.js +0 -1
  195. package/dist/assets/wardley-OPB4EBWU-DtCHtr2V.js +0 -1
  196. /package/dist/assets/{array-CYkMkqnU.js → array-DqLCdDFv.js} +0 -0
  197. /package/dist/assets/{chunk-KEIR6QF5-77hsebd7.js → chunk-KEIR6QF5-s7Qq-R3i.js} +0 -0
  198. /package/dist/assets/{chunk-Y2CYZVJY-CQltPwYk.js → chunk-Y2CYZVJY-BgISNSiw.js} +0 -0
  199. /package/dist/assets/{css-utils-rkE68RDy.js → css-utils-31qzCXsk.js} +0 -0
  200. /package/dist/assets/{cytoscape.esm-DwdZnGOm.js → cytoscape.esm-iekjSZ2n.js} +0 -0
  201. /package/dist/assets/{defaultLocale-Beh6XjaL.js → defaultLocale-CrJzLgRD.js} +0 -0
  202. /package/dist/assets/{dist-DelZBZpK.js → dist-zzfqk5hx.js} +0 -0
  203. /package/dist/assets/{graphlib-CAISHZh4.js → graphlib-CIz_CfxW.js} +0 -0
  204. /package/dist/assets/{init-Rr1s_RiX.js → init-C0r9Gk5G.js} +0 -0
  205. /package/dist/assets/{lit-vendor-Dr3cpBGF.js → lit-vendor-DvaQX_UQ.js} +0 -0
  206. /package/dist/assets/{logger-B65Akg8A.js → logger-8REuLPGK.js} +0 -0
  207. /package/dist/assets/{path-BAQ3hXlG.js → path-DIKpVbHL.js} +0 -0
  208. /package/dist/assets/{plugin-api-BbUkYm3Y.js → plugin-api-C8hMT5W6.js} +0 -0
  209. /package/dist/assets/{rough.esm-Djo4Abte.js → rough.esm-BMOtDaaS.js} +0 -0
  210. /package/dist/assets/{xterm-CGiQzDiR.js → xterm-BFzZ1FH4.js} +0 -0
@@ -4,6 +4,7 @@ import { promises as fs } from 'node:fs'
4
4
  import path from 'node:path'
5
5
  import { ProcessChannelProvider } from '../process-channel.mjs'
6
6
  import { getDefaultWorkspaceRoot, readProjectConfig } from '../../project-config.mjs'
7
+ import { createNodeProcessEnv } from '../../utils/process-env.mjs'
7
8
 
8
9
  const WEIXIN_ACP_PACKAGE = 'weixin-acp'
9
10
  const MIN_NODE_MAJOR = 22
@@ -134,7 +135,7 @@ function runCommand(command, args, options = {}) {
134
135
  }
135
136
 
136
137
  export class WechatChannelProvider extends ProcessChannelProvider {
137
- constructor({ projectRoot }) {
138
+ constructor({ projectRoot, channelEventsUrl, logsDir }) {
138
139
  super({
139
140
  id: 'wechat',
140
141
  name: '微信',
@@ -149,8 +150,9 @@ export class WechatChannelProvider extends ProcessChannelProvider {
149
150
  { id: 'relogin', label: '重新登录' },
150
151
  ],
151
152
  requirements: [`Node.js >= ${MIN_NODE_MAJOR}`, 'npm/npx 可用', '首次启动需要微信扫码登录'],
152
- })
153
+ }, { logsDir })
153
154
  this.projectRoot = projectRoot
155
+ this.channelEventsUrl = channelEventsUrl
154
156
  this.launchWorkspace = null
155
157
  }
156
158
 
@@ -179,7 +181,11 @@ export class WechatChannelProvider extends ProcessChannelProvider {
179
181
  command: npxCommand(),
180
182
  args: ['-y', WEIXIN_ACP_PACKAGE, 'start', '--', acpCommand, ...acpArgs],
181
183
  cwd: this.launchWorkspace?.path || getDefaultWorkspaceRoot() || this.projectRoot,
182
- env: process.env,
184
+ env: createNodeProcessEnv(process.env, {
185
+ QUICKFORGE_ACP_CHANNEL_ID: this.definition.id,
186
+ QUICKFORGE_ACP_CHANNEL_NAME: this.definition.name,
187
+ ...(this.channelEventsUrl ? { QUICKFORGE_CHANNEL_EVENTS_URL: this.channelEventsUrl } : {}),
188
+ }),
183
189
  shell: shouldUseShellForNpx(),
184
190
  }
185
191
  }
@@ -16,7 +16,11 @@ function attachProvider(provider) {
16
16
  export function initializeChannels(options = {}) {
17
17
  if (initialized) return
18
18
  initialized = true
19
- attachProvider(createWechatChannelProvider({ projectRoot: options.projectRoot }))
19
+ attachProvider(createWechatChannelProvider({
20
+ projectRoot: options.projectRoot,
21
+ channelEventsUrl: options.channelEventsUrl,
22
+ logsDir: options.logsDir,
23
+ }))
20
24
  }
21
25
 
22
26
  function requireProvider(id) {
package/server/index.mjs CHANGED
@@ -5,8 +5,9 @@ import path from 'node:path'
5
5
  import { randomUUID } from 'node:crypto'
6
6
  import { fileURLToPath } from 'node:url'
7
7
  import { sendJson, sendError } from './utils/response.mjs'
8
- import { openBrowser } from './utils/platform.mjs'
8
+ import { openBrowser, openPathInFileManager } from './utils/platform.mjs'
9
9
  import { ensureStorage, dataDir, configDir, storageDir, cacheDir, logsDir } from './storage.mjs'
10
+ import { getNetworkProxyConfig, initializeNetworkProxy, refreshSystemProxy, updateNetworkProxyConfig } from './network-proxy.mjs'
10
11
  import { setDefaultWorkspaceRoot, initializeActiveProject, readProjectConfig, getActiveProject, readTerminalShellSetting, updateTerminalShellSetting, readTerminalShellConfig, updateTerminalShellConfig } from './project-config.mjs'
11
12
  import { getWorkspaceRoot } from './utils/workspace.mjs'
12
13
  import { handleStorageApi } from './routes/storage.mjs'
@@ -43,6 +44,7 @@ import { shutdown as shutdownAgentManager, resetStaleTaskStatuses } from './agen
43
44
  import { initializeChannels, shutdownChannels } from './channels/registry.mjs'
44
45
  import { shutdownMcpConnections } from './mcp/registry.mjs'
45
46
  import { shutdownTerminalSessions } from './terminal/terminal-manager.mjs'
47
+ import { createNodeProcessEnv } from './utils/process-env.mjs'
46
48
 
47
49
  const __filename = fileURLToPath(import.meta.url)
48
50
  const __dirname = path.dirname(__filename)
@@ -65,16 +67,16 @@ let restartInProgress = false
65
67
  let updateInProgress = false
66
68
 
67
69
  setDefaultWorkspaceRoot(process.env.QUICKFORGE_WORKSPACE_DIR || path.join(dataDir, 'workspace'))
68
- installAiHttpLogger()
69
70
 
70
71
  function getRestartSupport() {
71
72
  return { supported: true, reason: null }
72
73
  }
73
74
 
74
- async function getSystemStatus() {
75
+ async function getSystemStatus({ isLocalRequest = true } = {}) {
75
76
  const config = await readProjectConfig()
76
77
  const restartSupport = getRestartSupport()
77
78
  const packageInfo = await getPackageInfo(projectRoot)
79
+ const restartSupported = isLocalRequest && restartSupport.supported
78
80
  return {
79
81
  ok: true,
80
82
  mode: isDev ? 'development' : 'production',
@@ -83,8 +85,14 @@ async function getSystemStatus() {
83
85
  startedAt,
84
86
  version: packageInfo.version,
85
87
  package: packageInfo,
86
- restartSupported: restartSupport.supported,
87
- restartUnsupportedReason: restartSupport.reason,
88
+ isLocalRequest,
89
+ capabilities: {
90
+ restart: restartSupported,
91
+ openLocalApps: isLocalRequest,
92
+ terminal: isLocalRequest,
93
+ },
94
+ restartSupported,
95
+ restartUnsupportedReason: isLocalRequest ? restartSupport.reason : 'Restart is only allowed from this computer',
88
96
  dataDir,
89
97
  configDir,
90
98
  storageDir,
@@ -113,10 +121,9 @@ function spawnRestartSupervisor() {
113
121
  stdio: 'ignore',
114
122
  windowsHide: true,
115
123
  shell: false,
116
- env: {
117
- ...process.env,
124
+ env: createNodeProcessEnv(process.env, {
118
125
  QUICKFORGE_NO_OPEN: '1',
119
- },
126
+ }),
120
127
  })
121
128
 
122
129
  child.once('error', reject)
@@ -206,10 +213,9 @@ function spawnUpdateSupervisor(update) {
206
213
  stdio: 'ignore',
207
214
  windowsHide: true,
208
215
  shell: false,
209
- env: {
210
- ...process.env,
216
+ env: createNodeProcessEnv(process.env, {
211
217
  QUICKFORGE_NO_OPEN: '1',
212
- },
218
+ }),
213
219
  })
214
220
 
215
221
  child.once('error', reject)
@@ -277,7 +283,7 @@ async function updateQuickForge() {
277
283
  }
278
284
 
279
285
  // --- Route dispatching ---
280
- async function handleApi(req, res, url) {
286
+ async function handleApi(req, res, url, requestContext = {}) {
281
287
  const pathname = url.pathname
282
288
  const parts = pathname.split('/').filter(Boolean)
283
289
 
@@ -297,22 +303,22 @@ async function handleApi(req, res, url) {
297
303
  return
298
304
  }
299
305
 
300
- if (pathname === '/api/lan-access/status' || pathname === '/api/lan-access/settings' || pathname === '/api/lan-access/unlock' || pathname === '/api/lan-access/logout' || pathname === '/api/lan-access/revoke-all') {
306
+ if (pathname.startsWith('/api/lan-access/')) {
301
307
  await handleLanAccessApi(req, res, url, {
302
308
  port,
303
- isLocalRequest: isLoopbackAddress(req.socket.remoteAddress),
309
+ isLocalRequest: requestContext.isLocalRequest === true,
304
310
  })
305
311
  return
306
312
  }
307
313
 
308
314
  // Health check
309
315
  if (req.method === 'GET' && pathname === '/api/health') {
310
- sendJson(res, 200, await getSystemStatus())
316
+ sendJson(res, 200, await getSystemStatus(requestContext))
311
317
  return
312
318
  }
313
319
 
314
320
  if (req.method === 'GET' && pathname === '/api/project/commands') {
315
- await handleProjectApi(req, res, url)
321
+ await handleProjectApi(req, res, url, requestContext)
316
322
  return
317
323
  }
318
324
 
@@ -355,7 +361,9 @@ async function handleApi(req, res, url) {
355
361
  // Channels
356
362
  if (pathname === '/api/channels' || pathname.startsWith('/api/channels/')) {
357
363
  await handleChannelsApi(req, res, url, {
358
- isLocalRequest: isLoopbackAddress(req.socket.remoteAddress),
364
+ isLocalRequest: requestContext.isLocalRequest === true,
365
+ logsDir,
366
+ openPathInFileManager,
359
367
  })
360
368
  return
361
369
  }
@@ -368,13 +376,13 @@ async function handleApi(req, res, url) {
368
376
 
369
377
  // Project routes
370
378
  if (pathname === '/api/project' || pathname.startsWith('/api/project/')) {
371
- await handleProjectApi(req, res, url)
379
+ await handleProjectApi(req, res, url, requestContext)
372
380
  return
373
381
  }
374
382
 
375
383
  // Project workspace inspector routes
376
384
  if (pathname === '/api/workspace/tree' || pathname === '/api/workspace/file' || pathname === '/api/workspace/resolve-path' || pathname === '/api/workspace/open-external' || pathname.startsWith('/api/workspace/preview/')) {
377
- await handleWorkspaceApi(req, res, url)
385
+ await handleWorkspaceApi(req, res, url, requestContext)
378
386
  return
379
387
  }
380
388
 
@@ -420,19 +428,22 @@ async function handleApi(req, res, url) {
420
428
  }
421
429
 
422
430
  // System routes
423
- if (pathname === '/api/system/status' || pathname === '/api/system/restart' || pathname === '/api/system/network' || pathname === '/api/system/terminal-shell' || pathname === '/api/system/about' || pathname === '/api/system/update/check' || pathname === '/api/system/update/desktop' || pathname === '/api/system/update') {
431
+ if (pathname === '/api/system/status' || pathname === '/api/system/restart' || pathname === '/api/system/network' || pathname === '/api/system/network-proxy' || pathname === '/api/system/network-proxy/refresh' || pathname === '/api/system/terminal-shell' || pathname === '/api/system/about' || pathname === '/api/system/update/check' || pathname === '/api/system/update/desktop' || pathname === '/api/system/update') {
424
432
  await handleSystemApi(req, res, url, {
425
- getSystemStatus,
433
+ getSystemStatus: () => getSystemStatus(requestContext),
426
434
  requestRestart,
427
435
  getPackageInfo: () => getPackageInfo(projectRoot),
428
436
  checkForUpdates: () => checkForUpdates(projectRoot),
429
437
  checkDesktopRelease: () => checkDesktopRelease(projectRoot),
430
438
  updateQuickForge,
431
- isLocalRequest: isLoopbackAddress(req.socket.remoteAddress),
439
+ isLocalRequest: requestContext.isLocalRequest === true,
432
440
  getTerminalShellSetting: readTerminalShellSetting,
433
441
  updateTerminalShellSetting,
434
442
  getTerminalShellConfig: readTerminalShellConfig,
435
443
  updateTerminalShellConfig,
444
+ getNetworkProxyConfig,
445
+ updateNetworkProxyConfig,
446
+ refreshSystemProxy,
436
447
  host,
437
448
  port,
438
449
  remoteEnabled: host !== '127.0.0.1' && host !== 'localhost',
@@ -443,7 +454,7 @@ async function handleApi(req, res, url) {
443
454
  // Terminal routes (local-only; real shell access)
444
455
  if (pathname === '/api/terminal/capabilities' || pathname === '/api/terminal/sessions' || pathname.startsWith('/api/terminal/sessions/')) {
445
456
  await handleTerminalApi(req, res, url, {
446
- isLocalRequest: isLoopbackAddress(req.socket.remoteAddress),
457
+ isLocalRequest: requestContext.isLocalRequest === true,
447
458
  })
448
459
  return
449
460
  }
@@ -529,6 +540,7 @@ function isLanAccessBootstrapPath(pathname) {
529
540
 
530
541
  function isStaticAssetPath(pathname) {
531
542
  return pathname.startsWith('/assets/')
543
+ || pathname.startsWith('/downloads/')
532
544
  || pathname === '/favicon.svg'
533
545
  || pathname === '/vite.svg'
534
546
  || pathname === '/manifest.webmanifest'
@@ -607,7 +619,7 @@ const server = createServer(async (req, res) => {
607
619
  }
608
620
 
609
621
  if (url.pathname.startsWith('/api/')) {
610
- await handleApi(req, res, url)
622
+ await handleApi(req, res, url, { isLocalRequest: !isRemoteRequest })
611
623
  return
612
624
  }
613
625
 
@@ -669,7 +681,13 @@ server.on('upgrade', (req, socket, head) => {
669
681
  })
670
682
 
671
683
  await ensureStorage()
672
- initializeChannels({ projectRoot })
684
+ await initializeNetworkProxy()
685
+ installAiHttpLogger()
686
+ initializeChannels({
687
+ projectRoot,
688
+ channelEventsUrl: `http://127.0.0.1:${port}/api/channels/events`,
689
+ logsDir,
690
+ })
673
691
  await resetStaleTaskStatuses()
674
692
  await initializeActiveProject()
675
693
  setActiveWorkspaceRootForFilesystem(getWorkspaceRoot())
@@ -80,13 +80,41 @@ async function writeLanAccessFile(config) {
80
80
  await fs.writeFile(LAN_ACCESS_FILE, `${JSON.stringify(normalizeConfig(config), null, 2)}\n`, 'utf8')
81
81
  }
82
82
 
83
+ function normalizeText(value, maxLength) {
84
+ if (typeof value !== 'string') return undefined
85
+ const text = value.trim()
86
+ return text ? text.slice(0, maxLength) : undefined
87
+ }
88
+
89
+ function normalizeRemoteAddress(value) {
90
+ const address = normalizeText(value, 128)
91
+ return address?.startsWith('::ffff:') ? address.slice(7) : address
92
+ }
93
+
94
+ function tokenRecordId(tokenRecord) {
95
+ const id = normalizeText(tokenRecord?.id, 128)
96
+ return id || `legacy_${sha256Base64Url(tokenRecord?.tokenHash || '').slice(0, 24)}`
97
+ }
98
+
99
+ function publicTokenRecord(tokenRecord) {
100
+ return {
101
+ id: tokenRecordId(tokenRecord),
102
+ address: normalizeRemoteAddress(tokenRecord.remoteAddress),
103
+ userAgent: normalizeText(tokenRecord.userAgent, 300),
104
+ issuedAt: tokenRecord.issuedAt,
105
+ expiresAt: tokenRecord.expiresAt,
106
+ }
107
+ }
108
+
83
109
  function publicStatus(config) {
110
+ const activeTokens = pruneTokens(config.tokens)
84
111
  return {
85
112
  enabled: Boolean(config.enabled),
86
113
  hasPassword: Boolean(config.passwordHash),
87
114
  sessionTtlHours: config.sessionTtlHours,
88
115
  authVersion: config.authVersion || 1,
89
- activeTokenCount: pruneTokens(config.tokens).length,
116
+ activeTokenCount: activeTokens.length,
117
+ activeDevices: activeTokens.map(publicTokenRecord),
90
118
  updatedAt: config.updatedAt,
91
119
  }
92
120
  }
@@ -98,6 +126,12 @@ function pruneTokens(tokens, now = Date.now()) {
98
126
  if (!tokenRecord.expiresAt) return true
99
127
  return Date.parse(tokenRecord.expiresAt) > now
100
128
  })
129
+ .map((tokenRecord) => ({
130
+ ...tokenRecord,
131
+ id: tokenRecordId(tokenRecord),
132
+ remoteAddress: normalizeRemoteAddress(tokenRecord.remoteAddress),
133
+ userAgent: normalizeText(tokenRecord.userAgent, 300),
134
+ }))
101
135
  .slice(-LAN_TOKEN_MAX_COUNT)
102
136
  }
103
137
 
@@ -162,11 +196,58 @@ export async function revokeLanAccessTokens() {
162
196
  })
163
197
  }
164
198
 
199
+ export async function revokeLanAccessTokenById(id) {
200
+ const normalizedId = normalizeText(id, 128)
201
+ if (!normalizedId) {
202
+ const error = new Error('LAN access session id is required.')
203
+ error.statusCode = 400
204
+ throw error
205
+ }
206
+ return enqueueWrite(writeQueueName, async () => {
207
+ const current = await readLanAccessFile()
208
+ const tokens = pruneTokens(current.tokens)
209
+ const nextTokens = tokens.filter((tokenRecord) => tokenRecordId(tokenRecord) !== normalizedId)
210
+ if (nextTokens.length === tokens.length) {
211
+ const error = new Error('LAN access session not found.')
212
+ error.statusCode = 404
213
+ throw error
214
+ }
215
+ const next = normalizeConfig({
216
+ ...current,
217
+ tokens: nextTokens,
218
+ updatedAt: new Date().toISOString(),
219
+ })
220
+ await writeLanAccessFile(next)
221
+ return publicStatus(next)
222
+ })
223
+ }
224
+
225
+ export async function revokeLanAccessToken(token) {
226
+ if (!token || typeof token !== 'string') return false
227
+ const [versionText, secret] = token.split('.')
228
+ if (!secret) return false
229
+ const actualHash = sha256Base64Url(secret)
230
+ return enqueueWrite(writeQueueName, async () => {
231
+ const current = await readLanAccessFile()
232
+ if (Number(versionText) !== (current.authVersion || 1)) return false
233
+ const tokens = pruneTokens(current.tokens)
234
+ const nextTokens = tokens.filter((tokenRecord) => !safeHashEqual(tokenRecord.tokenHash, actualHash))
235
+ if (nextTokens.length === tokens.length) return false
236
+ const next = normalizeConfig({
237
+ ...current,
238
+ tokens: nextTokens,
239
+ updatedAt: new Date().toISOString(),
240
+ })
241
+ await writeLanAccessFile(next)
242
+ return true
243
+ })
244
+ }
245
+
165
246
  export function lanAccessCookieName() {
166
247
  return 'qf_lan_access'
167
248
  }
168
249
 
169
- export async function issueLanAccessToken(password) {
250
+ export async function issueLanAccessToken(password, metadata = {}) {
170
251
  return enqueueWrite(writeQueueName, async () => {
171
252
  const current = await readLanAccessFile()
172
253
  if (!current.enabled || !current.passwordHash) {
@@ -185,11 +266,20 @@ export async function issueLanAccessToken(password) {
185
266
  const issuedAt = new Date().toISOString()
186
267
  const ttlMs = normalizeSessionTtlHours(current.sessionTtlHours) * 60 * 60 * 1000
187
268
  const expiresAt = new Date(Date.now() + ttlMs).toISOString()
269
+ const tokenRecord = {
270
+ id: createRandomToken(18),
271
+ tokenHash,
272
+ issuedAt,
273
+ expiresAt,
274
+ authVersion: current.authVersion || 1,
275
+ remoteAddress: normalizeRemoteAddress(metadata.remoteAddress),
276
+ userAgent: normalizeText(metadata.userAgent, 300),
277
+ }
188
278
  const next = normalizeConfig({
189
279
  ...current,
190
280
  tokens: [
191
281
  ...pruneTokens(current.tokens),
192
- { tokenHash, issuedAt, expiresAt, authVersion: current.authVersion || 1 },
282
+ tokenRecord,
193
283
  ].slice(-LAN_TOKEN_MAX_COUNT),
194
284
  updatedAt: issuedAt,
195
285
  })