mulmoclaude 0.9.0 → 0.9.2

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 (458) hide show
  1. package/README.md +95 -38
  2. package/bin/mulmoclaude.js +1 -2
  3. package/client/assets/JsonEditor-CPJfn76E.css +1 -0
  4. package/client/assets/JsonEditor-CoWGJG3Y.js +10 -0
  5. package/client/assets/abnfDiagram-VRR7QNED-6nNByj6v-By7GJ3xW.js +1 -0
  6. package/client/assets/abnfDiagram-VRR7QNED-BrQlVixL.js +1 -0
  7. package/client/assets/arc-BXutyUAX.js +1 -0
  8. package/client/assets/arc-zT0wd74V-DulGJNnb.js +1 -0
  9. package/client/assets/architecture-TIHT7OUA-CYMWc3UT-C7HoFzWN.js +1 -0
  10. package/client/assets/architecture-TIHT7OUA-aml8u-G9.js +1 -0
  11. package/client/assets/architectureDiagram-ZJ3FMSHR-Bgnyaj_i-CCpEsCHN.js +36 -0
  12. package/client/assets/architectureDiagram-ZJ3FMSHR-DJTFpPjB.js +36 -0
  13. package/client/assets/array-BifhSqXX.js +1 -0
  14. package/client/assets/array-CApNbSU9-BifhSqXX.js +1 -0
  15. package/client/assets/blockDiagram-677ZJIJ3-DQ35o5E4-BXS11D3J.js +132 -0
  16. package/client/assets/blockDiagram-677ZJIJ3-aYvCODxv.js +132 -0
  17. package/client/assets/c4Diagram-LMCZKHZV-Bau6RMBb.js +10 -0
  18. package/client/assets/c4Diagram-LMCZKHZV-ClWZeiWo-DXGnOOUf.js +10 -0
  19. package/client/assets/channel-D9VSi_QV.js +1 -0
  20. package/client/assets/channel-Di5rtkx0-C3gZcytF.js +1 -0
  21. package/client/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  22. package/client/assets/chunk-2Q5K7J3B-DfKpwyl9-DTxwf5E9.js +1 -0
  23. package/client/assets/chunk-32BRIVSS-CCt9wtYd-Cwa_IP35.js +1 -0
  24. package/client/assets/chunk-32BRIVSS-CxzHeys5.js +1 -0
  25. package/client/assets/chunk-52WLFC77-BtNjbTdw.js +10 -0
  26. package/client/assets/chunk-52WLFC77-FbBbR4uI-wsNC5d-f.js +10 -0
  27. package/client/assets/chunk-5VM5RSS4-BYnnUiN6-C4rOnu9A.js +15 -0
  28. package/client/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  29. package/client/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
  30. package/client/assets/chunk-7BUUIJ7U-hh8aCuGX-mGEpPzQy.js +1 -0
  31. package/client/assets/chunk-C7G6YPKG-BE8ehsnc.js +1 -0
  32. package/client/assets/chunk-C7G6YPKG-C87hlS9c-BitbJpTa.js +1 -0
  33. package/client/assets/{chunk-D8eiyYIV-BY16KEZc.js → chunk-D8eiyYIV-BeeEsA1B.js} +1 -1
  34. package/client/assets/chunk-EX3LRPZG-Bhgskzyy.js +231 -0
  35. package/client/assets/chunk-EX3LRPZG-BqGqMXLN-Cl2Eo1_u.js +231 -0
  36. package/client/assets/chunk-FWX5IMBZ-BkbSAAuW-C2r4AuAO.js +2 -0
  37. package/client/assets/chunk-FWX5IMBZ-D9sskZb_.js +2 -0
  38. package/client/assets/chunk-HOUHSVGY-CBCXk7rb.js +1 -0
  39. package/client/assets/chunk-HOUHSVGY-Cxu0eDlh-owg_DcY0.js +1 -0
  40. package/client/assets/chunk-ICXQ74PX-DTqPpDQ9.js +2 -0
  41. package/client/assets/chunk-ICXQ74PX-hiraF_Xj-CdaEwVin.js +2 -0
  42. package/client/assets/chunk-JWPE2WC7-BQ3zXr2k-DSd3Ct95.js +1 -0
  43. package/client/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  44. package/client/assets/chunk-KEIR6QF5-DNzq6p3w.js +161 -0
  45. package/client/assets/chunk-MOJQB5TN-CqxshQHA-Cn_EpDyZ.js +88 -0
  46. package/client/assets/chunk-MOJQB5TN-D1s_zUGz.js +88 -0
  47. package/client/assets/chunk-OGEWGWER-CjCr7ceX-Dfk5-70y.js +1 -0
  48. package/client/assets/chunk-OGEWGWER-DzfhxoQd.js +1 -0
  49. package/client/assets/chunk-PUDLZKDR-BZlebNhn.js +156 -0
  50. package/client/assets/chunk-PUDLZKDR-Dx6M-vz1-CLyVurOz.js +156 -0
  51. package/client/assets/chunk-Q4XR5HBZ-BcJb7mwA.js +70 -0
  52. package/client/assets/chunk-Q4XR5HBZ-CZd-9lTB-qPEYoRNc.js +11 -0
  53. package/client/assets/chunk-RYQCIY6F-B_IgMG7T.js +1 -0
  54. package/client/assets/chunk-RYQCIY6F-YkbemkCt-CX4fncTQ.js +1 -0
  55. package/client/assets/chunk-V7JOEXUC-Buce04o6.js +206 -0
  56. package/client/assets/chunk-V7JOEXUC-rI0xlC_O-C607vJXy.js +206 -0
  57. package/client/assets/chunk-VAUOI2AC-CxhkzXN0.js +1 -0
  58. package/client/assets/chunk-VAUOI2AC-DrcykVNK-CSROJWdE.js +1 -0
  59. package/client/assets/chunk-VR4S4FIN-D5afNrsS.js +1 -0
  60. package/client/assets/chunk-VR4S4FIN-O6iF8Yvf-CLIwrgqU.js +1 -0
  61. package/client/assets/chunk-WYO6CB5R-B83L_z6I-Cs8mg9If.js +127 -0
  62. package/client/assets/chunk-WYO6CB5R-BXTIdTMw.js +125 -0
  63. package/client/assets/chunk-XXDRQBXY-DFXH_lWn-B5HjCp2c.js +1 -0
  64. package/client/assets/chunk-XXDRQBXY-DXMD6ofA.js +1 -0
  65. package/client/assets/chunk-Y2CYZVJY-Bdt8pFDJ-DsF7k-Jl.js +1 -0
  66. package/client/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  67. package/client/assets/chunk-ZGVPDNZ5-BpFv9JSP-CHYySMjV.js +62 -0
  68. package/client/assets/chunk-ZGVPDNZ5-CYusI0J_.js +62 -0
  69. package/client/assets/chunk-ZIRB5QZD-Biy6ZNFG-D1maAiXb.js +32 -0
  70. package/client/assets/chunk-ZIRB5QZD-C6fEPe3t.js +32 -0
  71. package/client/assets/classDiagram-OUVF2IWQ-BgAZMSbT-BgxEE1D3.js +1 -0
  72. package/client/assets/classDiagram-OUVF2IWQ-CBD3Eidl.js +1 -0
  73. package/client/assets/classDiagram-v2-EOCWNBFH-CBD3Eidl.js +1 -0
  74. package/client/assets/classDiagram-v2-EOCWNBFH-DxHTyui1-BgxEE1D3.js +1 -0
  75. package/client/assets/cose-bilkent-JH36ORCC-CuSL2tA8-aMIqISfj.js +1 -0
  76. package/client/assets/cose-bilkent-JH36ORCC-WAJDBXv1.js +1 -0
  77. package/client/assets/cynefin-VYW2F7L2-DH2qkJKw.js +1 -0
  78. package/client/assets/cynefin-VYW2F7L2-DqA3n9nY-BNWhIK_n.js +1 -0
  79. package/client/assets/cynefinDiagram-TSTJHNR4-CUvPV9MV.js +62 -0
  80. package/client/assets/cynefinDiagram-TSTJHNR4-x0-0sQ15-Cq1gFcFu.js +62 -0
  81. package/client/assets/cytoscape.esm-CzdwbRaj-Djp6vQyU.js +321 -0
  82. package/client/assets/cytoscape.esm-Djp6vQyU.js +321 -0
  83. package/client/assets/dagre-CXRCoUWR.js +1 -0
  84. package/client/assets/dagre-VKFMJZFB-CQdfl-bx-CzZZuace.js +4 -0
  85. package/client/assets/dagre-VKFMJZFB-C_9IS7mB.js +4 -0
  86. package/client/assets/dagre-wczQIDso-CfevN9RO.js +1 -0
  87. package/client/assets/defaultLocale-C8Fc0cco.js +1 -0
  88. package/client/assets/defaultLocale-DUNguUWs-BbDo_yJX.js +1 -0
  89. package/client/assets/diagram-FQU43EPY-BOSB6VUb-isPdQ8WX.js +3 -0
  90. package/client/assets/diagram-FQU43EPY-BP8N00-b.js +3 -0
  91. package/client/assets/diagram-G47NLZAW-DLXrcXsN-BIqj7RKy.js +24 -0
  92. package/client/assets/diagram-G47NLZAW-ulE1JlWG.js +24 -0
  93. package/client/assets/diagram-NH7WQ7WH-BMQp1rkF-D6-fOq_v.js +24 -0
  94. package/client/assets/diagram-NH7WQ7WH-D_IXrL3i.js +24 -0
  95. package/client/assets/diagram-OA4YK3LP-C-pC6Eyu.js +30 -0
  96. package/client/assets/diagram-OA4YK3LP-D1wQ0vUj-BNi6QLCK.js +30 -0
  97. package/client/assets/diagram-WEI45ONY-Di9m35i-.js +41 -0
  98. package/client/assets/diagram-WEI45ONY-RR0DpF8R-BS3nrb3w.js +41 -0
  99. package/client/assets/dist-BQBs5pjy-BmtZ7Oc2.js +1 -0
  100. package/client/assets/dist-CQ3HaWOk.js +1 -0
  101. package/client/assets/ebnfDiagram-CCIWWBDH-Cbwnim2x.js +1 -0
  102. package/client/assets/ebnfDiagram-CCIWWBDH-M123uVJ8-9-dq55nQ.js +1 -0
  103. package/client/assets/erDiagram-Q63AITRT-BWx_-PXG-CWGfG4z5.js +85 -0
  104. package/client/assets/erDiagram-Q63AITRT-CMbtO3Sm.js +85 -0
  105. package/client/assets/eventmodeling-45OFAUF4--32SIpkL.js +1 -0
  106. package/client/assets/eventmodeling-45OFAUF4-_BVSjAXf-DQdL0Icr.js +1 -0
  107. package/client/assets/flowDiagram-23GEKE2U-BeOc_anm-CuVzKmmU.js +1 -0
  108. package/client/assets/flowDiagram-23GEKE2U-Dofa_qxG.js +1 -0
  109. package/client/assets/ganttDiagram-NO4QXBWP-BOoJ1eTw-TWoNmSvq.js +292 -0
  110. package/client/assets/ganttDiagram-NO4QXBWP-BgoAVKuc.js +292 -0
  111. package/client/assets/gitGraph-TEB2WS4Q-CH12KLTN-Bz4frAhV.js +1 -0
  112. package/client/assets/gitGraph-TEB2WS4Q-DIMvNvqt.js +1 -0
  113. package/client/assets/gitGraphDiagram-IHSO6WYX-B2CJhk_G-ClOKkjxw.js +106 -0
  114. package/client/assets/gitGraphDiagram-IHSO6WYX-Dmb6KnPz.js +106 -0
  115. package/client/assets/graphlib-B8gBHxth.js +1 -0
  116. package/client/assets/graphlib-hY-1btwe-DQjxxcnr.js +1 -0
  117. package/client/assets/{html2canvas-CDGcmOD3-CKJ6vKPo.js → html2canvas-CDGcmOD3-DRL9pFVl.js} +2 -2
  118. package/client/assets/{index-9lmYSaus.js → index-Dc0R-HW5.js} +129 -190
  119. package/client/assets/index-Dxo1Zdd-.css +2 -0
  120. package/client/assets/{index.es-DqtpmBm8-DFXjJgCa.js → index.es-DqtpmBm8-EQk3NgR8.js} +1 -1
  121. package/client/assets/info-DKCQHKI2-Cbw3mbiK-GsDZz9IO.js +1 -0
  122. package/client/assets/info-DKCQHKI2-ViCqobGo.js +1 -0
  123. package/client/assets/infoDiagram-FWYZ7A6U-HKV7LIG-.js +2 -0
  124. package/client/assets/infoDiagram-FWYZ7A6U-Mp1X3pBP-ATJv87Ur.js +2 -0
  125. package/client/assets/init-D6jRqBbL.js +1 -0
  126. package/client/assets/init-DEsX3bhM-D6jRqBbL.js +1 -0
  127. package/client/assets/ishikawaDiagram-FXEZZL3T-BNG7tkJu-CGCeOIlJ.js +70 -0
  128. package/client/assets/ishikawaDiagram-FXEZZL3T-CVDUj46f.js +70 -0
  129. package/client/assets/journeyDiagram-5HDEW3XC-BA-ESGLP.js +139 -0
  130. package/client/assets/journeyDiagram-5HDEW3XC-Dbp_hY9X-Bx-IoCe9.js +139 -0
  131. package/client/assets/kanban-definition-HUTT4EX6-Bqaet01L.js +89 -0
  132. package/client/assets/kanban-definition-HUTT4EX6-DSTc5u3q-C0JGckt1.js +89 -0
  133. package/client/assets/katex-CddkPoXu.js +257 -0
  134. package/client/assets/katex-M0IxphGf-CddkPoXu.js +257 -0
  135. package/client/assets/lib-4Tgx7rAy.js +114 -0
  136. package/client/assets/line-B1wBwzrY-f5wxpqoF.js +1 -0
  137. package/client/assets/line-CkyHfW7d.js +1 -0
  138. package/client/assets/linear-B9fuEF4c.js +1 -0
  139. package/client/assets/linear-lrGinF5_-CqNBync7.js +1 -0
  140. package/client/assets/map-CgrwEyH7-DWQFomlZ.js +1 -0
  141. package/client/assets/map-DsCK-0Cs.js +1 -0
  142. package/client/assets/marked.esm-CIU5FDdN.js +64 -0
  143. package/client/assets/marp-CSq0PPfK.js +3448 -0
  144. package/client/assets/material-symbols-outlined-DdRFxZLh.woff2 +0 -0
  145. package/client/assets/mermaid-parser.core-DC7NPJ_M-Ca6XzwfM.js +166 -0
  146. package/client/assets/mermaid-parser.core-SAwSf4_o.js +7 -0
  147. package/client/assets/mermaid.core-BBEQfkdJ.js +11 -0
  148. package/client/assets/mermaid.core-DZM3Ha-E-BxOo-RYG.js +11 -0
  149. package/client/assets/mindmap-definition-LN4V7U3C-B4BN0efL.js +96 -0
  150. package/client/assets/mindmap-definition-LN4V7U3C-DYtgcMsY-DynyLTNv.js +96 -0
  151. package/client/assets/ordinal-B9_Llu10-CU85fhaB.js +1 -0
  152. package/client/assets/ordinal-CopWnP7w.js +1 -0
  153. package/client/assets/packet-7NZHBO7P-CY4XRk9N.js +1 -0
  154. package/client/assets/packet-7NZHBO7P-lwb58iYx--vqSg65J.js +1 -0
  155. package/client/assets/path-BWPyau1x.js +1 -0
  156. package/client/assets/path-COivZ1Gw-C5riojK2.js +1 -0
  157. package/client/assets/pegDiagram-2B236MQR-BOKErjUu.js +1 -0
  158. package/client/assets/pegDiagram-2B236MQR-C43eIpKM-Bi_5Sxjt.js +1 -0
  159. package/client/assets/pie-RZYD4A2V-6BHB7bAx.js +1 -0
  160. package/client/assets/pie-RZYD4A2V-B1UWb4Gu-Dmn2hLWH.js +1 -0
  161. package/client/assets/pieDiagram-ENE6RG2P-BkTqgJyR-Bcdm19kR.js +39 -0
  162. package/client/assets/pieDiagram-ENE6RG2P-DtNjvz-U.js +39 -0
  163. package/client/assets/preload-helper-CZgWQFsJ.js +1 -0
  164. package/client/assets/purify.es-DY32g7DN.js +3 -0
  165. package/client/assets/quadrantDiagram-ABIIQ3AL-BQmAJL2v.js +7 -0
  166. package/client/assets/quadrantDiagram-ABIIQ3AL-Bm1Zjm45-B3orqx_f.js +7 -0
  167. package/client/assets/radar-I7S5WNFK-7CKcb_l--CqKdnR0v.js +1 -0
  168. package/client/assets/radar-I7S5WNFK-R7Jhjfdt.js +1 -0
  169. package/client/assets/railroad-3IZDKUUU-BepSPyHI.js +1 -0
  170. package/client/assets/railroad-3IZDKUUU-gCySKdnW-CKU26HTP.js +1 -0
  171. package/client/assets/railroad-abnf-AHOZXSZD-BlsHsp3c.js +1 -0
  172. package/client/assets/railroad-abnf-AHOZXSZD-BophH4r--CGkGHq54.js +1 -0
  173. package/client/assets/railroad-ebnf-EBAXGLYW-AZNjl_Zu-B7bn_PF3.js +1 -0
  174. package/client/assets/railroad-ebnf-EBAXGLYW-B4fMcGEH.js +1 -0
  175. package/client/assets/railroad-peg-LSFZ7HO6-B1ZrjJIu.js +1 -0
  176. package/client/assets/railroad-peg-LSFZ7HO6-BSiEEyeb-CP_B-N5g.js +1 -0
  177. package/client/assets/railroadDiagram-RFXS5EU6-8cz0Iby3.js +1 -0
  178. package/client/assets/railroadDiagram-RFXS5EU6-BkfbdeAs-Di6jH5I6.js +1 -0
  179. package/client/assets/requirementDiagram-TGXJPOKE-CrGTTjYg-DmIC7Shp.js +84 -0
  180. package/client/assets/requirementDiagram-TGXJPOKE-Dlqoe9TY.js +84 -0
  181. package/client/assets/rough.esm-CSKSodPl.js +1 -0
  182. package/client/assets/rough.esm-wVmwlXu7-CSKSodPl.js +1 -0
  183. package/client/assets/runtime-protocol-vue-WG3JLsjz.js +1 -0
  184. package/client/assets/runtime-vue-lHsY5zMj.js +1 -0
  185. package/client/assets/sankeyDiagram-HTMAVEWB-BkTKgu8Q.js +40 -0
  186. package/client/assets/sankeyDiagram-HTMAVEWB-rWXPf03Z-CjV9pCSJ.js +40 -0
  187. package/client/assets/{schemas-D_RbFtuQ.js → schemas-DGvl73AE.js} +3 -3
  188. package/client/assets/sequenceDiagram-DBY2YBRQ-BpuXUcFy.js +162 -0
  189. package/client/assets/sequenceDiagram-DBY2YBRQ-nkJYWO2m-BqS_sTCH.js +162 -0
  190. package/client/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
  191. package/client/assets/sizeCapture-X5ZJPWSS-F5SadAuT-VHIb4_NU.js +1 -0
  192. package/client/assets/src-Brzfja-q-DNc4Or4z.js +1 -0
  193. package/client/assets/src-Cqa3Jy1j.js +1 -0
  194. package/client/assets/stateDiagram-2N3HPSRC-CdlGXuo7.js +1 -0
  195. package/client/assets/stateDiagram-2N3HPSRC-T4-clK8b-DQRiB4va.js +1 -0
  196. package/client/assets/stateDiagram-v2-6OUMAXLB-BN8Jr3ZM.js +1 -0
  197. package/client/assets/stateDiagram-v2-6OUMAXLB-DIp7nhRd-DbrOhUn_.js +1 -0
  198. package/client/assets/swimlanes-5IMT3BWC-HmQNEntu-CNBgZdur.js +2 -0
  199. package/client/assets/swimlanes-5IMT3BWC-iEJg5gki.js +2 -0
  200. package/client/assets/swimlanesDiagram-G3AALYLV-BeoZhwg7-DpqgeNRA.js +8 -0
  201. package/client/assets/swimlanesDiagram-G3AALYLV-o-sS6aEP.js +8 -0
  202. package/client/assets/timeline-definition-FHXFAJF6-Bjh-7QmL.js +120 -0
  203. package/client/assets/timeline-definition-FHXFAJF6-CNc9jSTP-BKNSymgY.js +120 -0
  204. package/client/assets/treeView-QDETBFTQ-D3cqRl6k.js +1 -0
  205. package/client/assets/treeView-QDETBFTQ-nIQcG1h9-O_ri9HxD.js +1 -0
  206. package/client/assets/treemap-6X3UGDF4-BnsvC8yL-Cfsty1e3.js +1 -0
  207. package/client/assets/treemap-6X3UGDF4-DGkZcvDG.js +1 -0
  208. package/client/assets/v4-B29ayslu.js +1 -0
  209. package/client/assets/vennDiagram-L72KCM5P-Cz3dbe7b.js +34 -0
  210. package/client/assets/vennDiagram-L72KCM5P-Dr3pTJ_0-C38xwcVo.js +34 -0
  211. package/client/assets/vue-C6d2VveO.js +1 -0
  212. package/client/assets/vue-i18n-CL-ejuNu.js +3 -0
  213. package/client/assets/vue.runtime.esm-bundler-BeoTfMNc.js +4 -0
  214. package/client/assets/wardley-OPB4EBWU-8Odxkx6V-CCDIVuBs.js +1 -0
  215. package/client/assets/wardley-OPB4EBWU-CZsCDvKk.js +1 -0
  216. package/client/assets/wardleyDiagram-EHGQE667-DSFc7ZZa-mlWXRiWx.js +78 -0
  217. package/client/assets/wardleyDiagram-EHGQE667-DiyoyO_X.js +78 -0
  218. package/client/assets/xychartDiagram-FW5EYKEG-BP0Nn4Pp-DRRiStGZ.js +7 -0
  219. package/client/assets/xychartDiagram-FW5EYKEG-DhY1_UGM.js +7 -0
  220. package/client/index.html +16 -12
  221. package/package.json +17 -19
  222. package/server/agent/backend/types.ts +1 -1
  223. package/server/agent/backgroundSessions.ts +43 -0
  224. package/server/agent/config.ts +3 -2
  225. package/server/agent/mcp-tools/manageCollection.ts +4 -4
  226. package/server/agent/sandboxMounts.ts +1 -1
  227. package/server/agent/stream.ts +1 -3
  228. package/server/api/auth/viewToken.ts +1 -1
  229. package/server/api/bridge/sessionRole.ts +47 -0
  230. package/server/api/routes/agent.ts +79 -2
  231. package/server/api/routes/collections.ts +60 -7
  232. package/server/api/routes/collectionsRegistry.ts +113 -0
  233. package/server/api/routes/dashboard.ts +47 -0
  234. package/server/api/routes/feeds.ts +2 -2
  235. package/server/api/routes/files.ts +1 -2
  236. package/server/api/routes/pdf.ts +48 -9
  237. package/server/api/routes/plugins.ts +2 -2
  238. package/server/api/routes/remoteHost.ts +55 -0
  239. package/server/api/routes/sessions.ts +20 -11
  240. package/server/api/routes/share.ts +105 -0
  241. package/server/api/routes/transcribe.ts +1 -1
  242. package/server/api/routes/wiki/history.ts +2 -2
  243. package/server/api/routes/wiki.ts +29 -177
  244. package/server/api/sandboxStatus.ts +1 -1
  245. package/server/build/dispatcher.mjs +25 -14928
  246. package/server/events/collection-change.ts +4 -4
  247. package/server/events/file-change.ts +2 -2
  248. package/server/events/scheduler-adapter.ts +3 -3
  249. package/server/events/task-manager/index.ts +3 -3
  250. package/server/index.ts +53 -17
  251. package/server/notifier/engine.ts +3 -3
  252. package/server/notifier/types.ts +2 -2
  253. package/server/plugins/html-builtin.ts +15 -1
  254. package/server/prompts/system/system.md +4 -0
  255. package/server/remoteHost/auth.ts +29 -0
  256. package/server/remoteHost/commandChannel.ts +56 -0
  257. package/server/remoteHost/firebase.ts +16 -0
  258. package/server/remoteHost/handlers/collectionPage.ts +29 -0
  259. package/server/remoteHost/handlers/getCollection.ts +32 -0
  260. package/server/remoteHost/handlers/getFeed.ts +35 -0
  261. package/server/remoteHost/handlers/index.ts +19 -0
  262. package/server/remoteHost/handlers/listCollections.ts +29 -0
  263. package/server/remoteHost/handlers/listFeeds.ts +37 -0
  264. package/server/remoteHost/handlers/listShortcuts.ts +24 -0
  265. package/server/remoteHost/handlers/startChat.ts +78 -0
  266. package/server/remoteHost/hostRunner.ts +122 -0
  267. package/server/remoteHost/index.ts +117 -0
  268. package/server/system/config.ts +1 -1
  269. package/server/system/credentials.ts +2 -3
  270. package/server/system/docker.ts +9 -8
  271. package/server/system/env.ts +8 -0
  272. package/server/system/whisper/index.ts +4 -4
  273. package/server/utils/claudeConfigPath.ts +57 -0
  274. package/server/utils/files/dashboard-io.ts +87 -0
  275. package/server/utils/files/session-io.ts +11 -0
  276. package/server/utils/markdown/frontmatter.ts +8 -4
  277. package/server/utils/regex.ts +4 -3
  278. package/server/utils/share/packHtml.ts +108 -0
  279. package/server/utils/share/rewriteAssets.ts +178 -0
  280. package/server/workspace/chat-index/paths.ts +8 -2
  281. package/server/workspace/chat-index/summarizer.ts +23 -15
  282. package/server/workspace/collections/configure.ts +5 -3
  283. package/server/workspace/collections/index.ts +8 -6
  284. package/server/workspace/collections/notifications.ts +3 -3
  285. package/server/workspace/collections/types.ts +2 -2
  286. package/server/workspace/collections/watcher.ts +2 -2
  287. package/server/workspace/feeds/configure.ts +24 -0
  288. package/server/workspace/hooks/handlers/skillBridge.ts +2 -2
  289. package/server/workspace/hooks/handlers/wikiSnapshot.ts +1 -1
  290. package/server/workspace/paths.ts +8 -1
  291. package/server/workspace/skills/catalog.ts +1 -3
  292. package/server/workspace/skills/external/catalog.ts +1 -3
  293. package/server/workspace/skills/paths.ts +4 -3
  294. package/server/workspace/skills/writer.ts +1 -4
  295. package/server/workspace/skills-preset.ts +3 -3
  296. package/server/workspace/wiki-pages/io.ts +2 -2
  297. package/server/workspace/workspace.ts +2 -2
  298. package/src/App.vue +41 -18
  299. package/src/components/ChatInput.vue +1 -1
  300. package/src/components/DashboardView.vue +372 -0
  301. package/src/components/FileContentRenderer.vue +32 -7
  302. package/src/components/JsonEditor.vue +1 -1
  303. package/src/components/PluginLauncher.vue +122 -79
  304. package/src/components/RemoteHostControl.vue +159 -0
  305. package/src/components/SessionCountBadges.vue +32 -0
  306. package/src/components/SessionHeaderControls.vue +1 -8
  307. package/src/components/SessionHistoryPanel.vue +2 -0
  308. package/src/components/SessionHistoryToggleButton.vue +1 -15
  309. package/src/components/SidebarHeader.vue +2 -0
  310. package/src/components/collectionTypes.ts +2 -2
  311. package/src/composables/accountingHost.ts +24 -0
  312. package/src/composables/collections/uiHost.ts +17 -2
  313. package/src/composables/useDashboard.ts +191 -0
  314. package/src/composables/useMarkdownZip.ts +51 -0
  315. package/src/composables/useNotifications.ts +1 -4
  316. package/src/composables/useSharePack.ts +60 -0
  317. package/src/composables/useTranslatedQueries.ts +15 -95
  318. package/src/composables/useTranslatedStrings.ts +68 -0
  319. package/src/composables/useVoiceInput.ts +3 -3
  320. package/src/config/apiRoutes.ts +57 -9
  321. package/src/config/createFilePolicy.ts +1 -1
  322. package/src/config/firebase.ts +12 -0
  323. package/src/config/firebaseConfig.ts +18 -0
  324. package/src/config/historyFilters.ts +7 -0
  325. package/src/config/pubsubChannels.ts +7 -27
  326. package/src/config/roles.ts +12 -10
  327. package/src/config/workspacePaths.ts +10 -0
  328. package/src/index.css +1 -1
  329. package/src/lang/de.ts +39 -220
  330. package/src/lang/en.ts +39 -191
  331. package/src/lang/es.ts +39 -218
  332. package/src/lang/fr.ts +39 -220
  333. package/src/lang/ja.ts +39 -216
  334. package/src/lang/ko.ts +39 -216
  335. package/src/lang/pt-BR.ts +39 -217
  336. package/src/lang/zh.ts +39 -215
  337. package/src/main.ts +3 -0
  338. package/src/plugins/accounting/definition.ts +12 -8
  339. package/src/plugins/accounting/index.ts +7 -4
  340. package/src/plugins/accounting/meta.ts +23 -60
  341. package/src/plugins/manageSkills/View.vue +9 -1
  342. package/src/plugins/photoLocations/View.vue +2 -2
  343. package/src/plugins/presentCollection/definition.ts +2 -2
  344. package/src/plugins/presentCollection/plugin.ts +2 -2
  345. package/src/plugins/presentCollection/types.ts +2 -2
  346. package/src/plugins/presentHtml/definition.ts +1 -1
  347. package/src/plugins/presentMulmoScript/View.vue +2 -2
  348. package/src/plugins/presentMulmoScript/helpers.ts +1 -1
  349. package/src/plugins/presentSVG/View.vue +2 -2
  350. package/src/plugins/scheduler/TasksTab.vue +1 -2
  351. package/src/plugins/skill/View.vue +7 -3
  352. package/src/plugins/spreadsheet/View.vue +3 -3
  353. package/src/plugins/spreadsheet/engine/functions/logical.ts +8 -1
  354. package/src/plugins/textResponse/View.vue +43 -16
  355. package/src/plugins/wiki/View.vue +29 -2
  356. package/src/plugins/wiki/components/WikiGraphView.vue +1 -1
  357. package/src/plugins/wiki/components/WikiPageBody.vue +4 -1
  358. package/src/plugins/wiki/helpers.ts +13 -81
  359. package/src/plugins/wiki/index.ts +1 -1
  360. package/src/router/guards.ts +1 -1
  361. package/src/router/index.ts +12 -0
  362. package/src/router/pageRoutes.ts +2 -0
  363. package/src/types/dashboard.ts +40 -0
  364. package/src/types/session.ts +3 -0
  365. package/src/utils/blobDownload.ts +19 -0
  366. package/src/utils/collections/presentSeed.ts +1 -1
  367. package/src/utils/html/customViewSrcdoc.ts +31 -3
  368. package/src/utils/html/previewCsp.ts +1 -1
  369. package/src/utils/id.ts +1 -1
  370. package/src/utils/image/htmlSrcAttrs.ts +1 -1
  371. package/src/utils/markdown/frontmatter.ts +12 -7
  372. package/src/utils/markdown/highlight.ts +22 -0
  373. package/src/utils/markdown/marpCustomSize.ts +2 -2
  374. package/src/utils/markdown/mermaidExtension.ts +56 -0
  375. package/src/utils/markdown/mermaidRender.ts +147 -0
  376. package/src/utils/markdown/setup.ts +17 -4
  377. package/src/utils/markdown/useMermaid.ts +33 -0
  378. package/src/utils/session/longRunning.ts +33 -0
  379. package/src/utils/session/mergeSessions.ts +1 -1
  380. package/client/assets/JsonEditor-Di5xGeZY.css +0 -1
  381. package/client/assets/JsonEditor-o5--tPQH.js +0 -10
  382. package/client/assets/index-tOu5ArRZ.css +0 -2
  383. package/client/assets/lib-D6Xy0IFc.js +0 -114
  384. package/client/assets/marp-D6GXA-EB.js +0 -3452
  385. package/client/assets/material-symbols-outlined-DtIK7AQn.woff2 +0 -0
  386. package/client/assets/runtime-protocol-vue-pU0Mw7Zm.js +0 -1
  387. package/client/assets/runtime-vue-fFYhnNg3.js +0 -1
  388. package/client/assets/vue-UDIWDtr8.js +0 -1
  389. package/client/assets/vue-i18n-CQbxVmNs.js +0 -3
  390. package/client/assets/vue.runtime.esm-bundler-BTyIdNAI.js +0 -4
  391. package/server/accounting/accountNormalize.ts +0 -32
  392. package/server/accounting/defaultAccounts.ts +0 -87
  393. package/server/accounting/eventPublisher.ts +0 -52
  394. package/server/accounting/journal.ts +0 -252
  395. package/server/accounting/openingBalances.ts +0 -114
  396. package/server/accounting/report.ts +0 -237
  397. package/server/accounting/service.ts +0 -718
  398. package/server/accounting/snapshotCache.ts +0 -334
  399. package/server/accounting/timeSeries.ts +0 -265
  400. package/server/accounting/types.ts +0 -148
  401. package/server/api/routes/accounting.ts +0 -373
  402. package/server/api/routes/wiki/frontmatter.ts +0 -34
  403. package/server/api/routes/wiki/pageIndex.ts +0 -53
  404. package/server/system/logs/aaa +0 -737
  405. package/server/system/logs/bb +0 -446
  406. package/server/utils/files/accounting-io.ts +0 -294
  407. package/server/workspace/feeds/engine.ts +0 -143
  408. package/server/workspace/feeds/fetch/httpClient.ts +0 -127
  409. package/server/workspace/feeds/fetch/rssParser.ts +0 -117
  410. package/server/workspace/feeds/index.ts +0 -8
  411. package/server/workspace/feeds/ingestTypes.ts +0 -62
  412. package/server/workspace/feeds/pathResolver.ts +0 -74
  413. package/server/workspace/feeds/paths.ts +0 -30
  414. package/server/workspace/feeds/projectItem.ts +0 -92
  415. package/server/workspace/feeds/registry.ts +0 -43
  416. package/server/workspace/feeds/retrievers/httpJson.ts +0 -19
  417. package/server/workspace/feeds/retrievers/index.ts +0 -27
  418. package/server/workspace/feeds/retrievers/registerAll.ts +0 -5
  419. package/server/workspace/feeds/retrievers/rss.ts +0 -24
  420. package/server/workspace/feeds/state.ts +0 -55
  421. package/src/composables/useAccountingChannel.ts +0 -58
  422. package/src/lib/wiki-page/graph.ts +0 -108
  423. package/src/lib/wiki-page/index-parse.ts +0 -221
  424. package/src/lib/wiki-page/link.ts +0 -62
  425. package/src/lib/wiki-page/lint.ts +0 -105
  426. package/src/lib/wiki-page/paths.ts +0 -35
  427. package/src/lib/wiki-page/slug.ts +0 -54
  428. package/src/plugins/accounting/Preview.vue +0 -103
  429. package/src/plugins/accounting/View.vue +0 -633
  430. package/src/plugins/accounting/actions.ts +0 -34
  431. package/src/plugins/accounting/api.ts +0 -301
  432. package/src/plugins/accounting/components/AccountEditor.vue +0 -250
  433. package/src/plugins/accounting/components/AccountRow.vue +0 -50
  434. package/src/plugins/accounting/components/AccountsList.vue +0 -102
  435. package/src/plugins/accounting/components/AccountsModal.vue +0 -301
  436. package/src/plugins/accounting/components/BalanceSheet.vue +0 -186
  437. package/src/plugins/accounting/components/BookSettings.vue +0 -284
  438. package/src/plugins/accounting/components/BookSwitcher.vue +0 -78
  439. package/src/plugins/accounting/components/DateRangePicker.vue +0 -140
  440. package/src/plugins/accounting/components/JournalEntryForm.vue +0 -505
  441. package/src/plugins/accounting/components/JournalList.vue +0 -554
  442. package/src/plugins/accounting/components/Ledger.vue +0 -206
  443. package/src/plugins/accounting/components/NewBookForm.vue +0 -211
  444. package/src/plugins/accounting/components/OpeningBalancesForm.vue +0 -272
  445. package/src/plugins/accounting/components/ProfitLoss.vue +0 -160
  446. package/src/plugins/accounting/components/accountDraft.ts +0 -13
  447. package/src/plugins/accounting/components/accountNumbering.ts +0 -103
  448. package/src/plugins/accounting/components/accountValidation.ts +0 -75
  449. package/src/plugins/accounting/components/useLatestRequest.ts +0 -44
  450. package/src/plugins/accounting/countries.ts +0 -158
  451. package/src/plugins/accounting/currencies.ts +0 -77
  452. package/src/plugins/accounting/dates.ts +0 -51
  453. package/src/plugins/accounting/fiscalYear.ts +0 -136
  454. package/src/plugins/accounting/timeSeriesEnums.ts +0 -16
  455. package/src/plugins/wiki/route.ts +0 -137
  456. /package/client/assets/{_plugin-vue_export-helper-B67ILkmu.js → _plugin-vue_export-helper-BDNMzG2s.js} +0 -0
  457. /package/client/assets/{purify.es-B27wDFIb-51iYcXuK.js → purify.es-B27wDFIb-Bu4Grnl0.js} +0 -0
  458. /package/client/assets/{typeof-DBp4T-Ny-z2wCIsir.js → typeof-DBp4T-Ny-B5XbjTb1.js} +0 -0
@@ -0,0 +1,191 @@
1
+ // Client store for the dashboard layout (tile order + per-tile view mode,
2
+ // and per-row view-area heights for the favorites grid). Singleton module
3
+ // state shared across consumers, mirroring `useShortcuts`: persistence is
4
+ // server-side (`config/dashboard.json` via PUT /api/dashboard); the client
5
+ // owns the full layout and replaces it wholesale. Mutations are optimistic
6
+ // with rollback on failure and serialised so overlapping replace-all PUTs
7
+ // never land out of order.
8
+ //
9
+ // Membership (which collections appear) is NOT owned here — it derives
10
+ // from the user's pinned collection shortcuts (favorites). `reconcile`
11
+ // folds a fresh favorite-slug list into the stored layout: it appends
12
+ // newly-favorited collections and prunes ones that were unpinned, while
13
+ // preserving the user's dashboard order and per-tile view modes.
14
+ //
15
+ // Row heights are POSITIONAL: indexed by grid row (2 tiles/row), they stay
16
+ // with the slot when tiles are reordered, never with a specific tile.
17
+
18
+ import { computed, ref, type ComputedRef } from "vue";
19
+ import { API_ROUTES } from "../config/apiRoutes";
20
+ import { apiGet, apiPut } from "../utils/api";
21
+ import type { DashboardTile } from "../types/dashboard";
22
+
23
+ const tiles = ref<DashboardTile[]>([]);
24
+ const rowHeights = ref<Record<string, number[]>>({});
25
+ const loadError = ref<string | null>(null);
26
+ /** True only after a GET has authoritatively populated the layout. Until
27
+ * then, mutations refuse to persist — a replace-all PUT built on the
28
+ * empty default would clobber an existing `dashboard.json`. */
29
+ const loaded = ref(false);
30
+ let loadPromise: Promise<void> | null = null;
31
+
32
+ interface DashboardResponse {
33
+ tiles: DashboardTile[];
34
+ rowHeights?: Record<string, number[]>;
35
+ }
36
+
37
+ /** Snapshot of the mutable layout, for optimistic rollback. */
38
+ interface LayoutSnapshot {
39
+ tiles: DashboardTile[];
40
+ rowHeights: Record<string, number[]>;
41
+ }
42
+
43
+ function snapshot(): LayoutSnapshot {
44
+ return { tiles: tiles.value, rowHeights: rowHeights.value };
45
+ }
46
+
47
+ function apply(layout: LayoutSnapshot): void {
48
+ tiles.value = layout.tiles;
49
+ rowHeights.value = layout.rowHeights;
50
+ }
51
+
52
+ /** Load once per session (deduped). A FAILED load is not cached so the
53
+ * next call retries rather than permanently serving the failure. */
54
+ async function load(force = false): Promise<void> {
55
+ if (loadPromise && !force) return loadPromise;
56
+ loadPromise = (async () => {
57
+ const result = await apiGet<DashboardResponse>(API_ROUTES.dashboard);
58
+ if (!result.ok) {
59
+ loadError.value = result.error;
60
+ loadPromise = null; // allow retry on the next call
61
+ return;
62
+ }
63
+ loadError.value = null;
64
+ apply({ tiles: result.data.tiles, rowHeights: result.data.rowHeights ?? {} });
65
+ loaded.value = true;
66
+ })();
67
+ return loadPromise;
68
+ }
69
+
70
+ // Every mutation runs through this chain so the replace-all PUTs never
71
+ // overlap (the same race `useShortcuts` guards against).
72
+ let mutationChain: Promise<unknown> = Promise.resolve();
73
+
74
+ function enqueue<T>(task: () => Promise<T>): Promise<T> {
75
+ const run = mutationChain.then(task, task);
76
+ mutationChain = run.then(
77
+ () => undefined,
78
+ () => undefined,
79
+ );
80
+ return run;
81
+ }
82
+
83
+ /** Persist the given layout, rolling back to `previous` on failure.
84
+ * Returns true on success. Call only from inside `enqueue`. */
85
+ async function persist(next: LayoutSnapshot, previous: LayoutSnapshot): Promise<boolean> {
86
+ apply(next);
87
+ const result = await apiPut<DashboardResponse>(API_ROUTES.dashboard, { tiles: next.tiles, rowHeights: next.rowHeights });
88
+ if (!result.ok) {
89
+ apply(previous);
90
+ loadError.value = result.error;
91
+ console.error("[useDashboard] persist failed", result.error);
92
+ return false;
93
+ }
94
+ // Adopt the server's canonical layout. If the response omits rowHeights
95
+ // (e.g. a version-skewed server), keep the heights we just sent rather
96
+ // than clearing them — otherwise a resize would visibly snap back.
97
+ apply({ tiles: result.data.tiles, rowHeights: result.data.rowHeights ?? next.rowHeights });
98
+ loadError.value = null;
99
+ return true;
100
+ }
101
+
102
+ /** Replace the full ordered tile list (used by drag-to-reorder). Row
103
+ * heights are positional, so they stay put. */
104
+ function setTiles(next: DashboardTile[]): Promise<boolean> {
105
+ return enqueue(async () => {
106
+ await load();
107
+ if (!loaded.value) return false; // never overwrite an unread layout
108
+ return persist({ tiles: next, rowHeights: rowHeights.value }, snapshot());
109
+ });
110
+ }
111
+
112
+ /** Set (or, when null, clear) one tile's view mode. No-op if the slug
113
+ * isn't a tile. */
114
+ function setViewMode(slug: string, viewMode: string | null): Promise<boolean> {
115
+ return enqueue(async () => {
116
+ await load();
117
+ if (!loaded.value) return false;
118
+ if (!tiles.value.some((tile) => tile.slug === slug)) return true;
119
+ const previous = snapshot();
120
+ const next = previous.tiles.map((tile) => {
121
+ if (tile.slug !== slug) return tile;
122
+ if (viewMode === null) {
123
+ const { viewMode: __drop, ...rest } = tile;
124
+ return rest;
125
+ }
126
+ return { ...tile, viewMode };
127
+ });
128
+ return persist({ tiles: next, rowHeights: previous.rowHeights }, previous);
129
+ });
130
+ }
131
+
132
+ /** Set one grid row's view-area height (px) for the given column-count
133
+ * layout. Heights are kept per column count so the 1- and 2-column
134
+ * layouts stay independent. Pads with `0` (default) for earlier
135
+ * untouched rows. */
136
+ function setRowHeight(columns: number, row: number, height: number): Promise<boolean> {
137
+ return enqueue(async () => {
138
+ await load();
139
+ if (!loaded.value) return false;
140
+ if (columns < 1 || row < 0) return true;
141
+ const previous = snapshot();
142
+ const key = String(columns);
143
+ const heights = [...(previous.rowHeights[key] ?? [])];
144
+ while (heights.length <= row) heights.push(0);
145
+ heights[row] = height;
146
+ const next = { ...previous.rowHeights, [key]: heights };
147
+ return persist({ tiles: previous.tiles, rowHeights: next }, previous);
148
+ });
149
+ }
150
+
151
+ /** Fold a fresh favorite-slug list into the stored layout: keep stored
152
+ * tiles whose slug is still a favorite (preserving order + view mode),
153
+ * then append any favorites not yet present (in the favorites' order).
154
+ * Persists only when something drifted, so the file self-heals after a
155
+ * pin / unpin without a redundant PUT on every visit. */
156
+ function reconcile(favoriteSlugs: string[]): Promise<void> {
157
+ return enqueue(async () => {
158
+ await load();
159
+ if (!loaded.value) return; // never overwrite an unread layout
160
+ const favoriteSet = new Set(favoriteSlugs);
161
+ const kept = tiles.value.filter((tile) => favoriteSet.has(tile.slug));
162
+ const keptSlugs = new Set(kept.map((tile) => tile.slug));
163
+ const appended = favoriteSlugs.filter((slug) => !keptSlugs.has(slug)).map((slug) => ({ slug }) as DashboardTile);
164
+ const next = [...kept, ...appended];
165
+ const drifted = next.length !== tiles.value.length || next.some((tile, i) => tile.slug !== tiles.value[i]?.slug);
166
+ if (drifted) await persist({ tiles: next, rowHeights: rowHeights.value }, snapshot());
167
+ });
168
+ }
169
+
170
+ export function useDashboard(): {
171
+ tiles: ComputedRef<DashboardTile[]>;
172
+ rowHeights: ComputedRef<Record<string, number[]>>;
173
+ loadError: ComputedRef<string | null>;
174
+ load: (force?: boolean) => Promise<void>;
175
+ setTiles: (next: DashboardTile[]) => Promise<boolean>;
176
+ setViewMode: (slug: string, viewMode: string | null) => Promise<boolean>;
177
+ setRowHeight: (columns: number, row: number, height: number) => Promise<boolean>;
178
+ reconcile: (favoriteSlugs: string[]) => Promise<void>;
179
+ } {
180
+ void load();
181
+ return {
182
+ tiles: computed(() => tiles.value),
183
+ rowHeights: computed(() => rowHeights.value),
184
+ loadError: computed(() => loadError.value),
185
+ load,
186
+ setTiles,
187
+ setViewMode,
188
+ setRowHeight,
189
+ reconcile,
190
+ };
191
+ }
@@ -0,0 +1,51 @@
1
+ // Download markdown / a wiki page as a self-contained HTML zip. Parallel
2
+ // to usePdfDownload, but hits POST /api/share/pack-markdown and receives
3
+ // a zip (index.html with CSS + images inlined). Failure sets `zipFailed`
4
+ // so callers render a localized message — the raw server body is never
5
+ // surfaced.
6
+
7
+ import { ref, type Ref } from "vue";
8
+ import { API_ROUTES } from "../config/apiRoutes";
9
+ import { apiFetchRaw } from "../utils/api";
10
+ import { saveBlob, filenameFromDisposition } from "../utils/blobDownload";
11
+
12
+ export interface DownloadMarkdownZipOptions {
13
+ /** Workspace-relative source dir for resolving relative `<img>` refs. */
14
+ baseDir?: string;
15
+ stripFrontmatter?: boolean;
16
+ marp?: boolean;
17
+ }
18
+
19
+ export interface UseMarkdownZipHandle {
20
+ zipDownloading: Ref<boolean>;
21
+ zipFailed: Ref<boolean>;
22
+ downloadZip: (markdown: string, filename: string, options?: DownloadMarkdownZipOptions) => Promise<void>;
23
+ }
24
+
25
+ export function useMarkdownZip(): UseMarkdownZipHandle {
26
+ const zipDownloading = ref(false);
27
+ const zipFailed = ref(false);
28
+
29
+ async function downloadZip(markdown: string, filename: string, options: DownloadMarkdownZipOptions = {}): Promise<void> {
30
+ zipFailed.value = false;
31
+ zipDownloading.value = true;
32
+ try {
33
+ const response = await apiFetchRaw(API_ROUTES.share.packMarkdown, {
34
+ method: "POST",
35
+ headers: { "Content-Type": "application/json" },
36
+ body: JSON.stringify({ markdown, filename, baseDir: options.baseDir, stripFrontmatter: options.stripFrontmatter, marp: options.marp }),
37
+ });
38
+ if (!response.ok) {
39
+ zipFailed.value = true;
40
+ return;
41
+ }
42
+ saveBlob(await response.blob(), filenameFromDisposition(response.headers.get("content-disposition"), `${filename}.zip`));
43
+ } catch {
44
+ zipFailed.value = true;
45
+ } finally {
46
+ zipDownloading.value = false;
47
+ }
48
+ }
49
+
50
+ return { zipDownloading, zipFailed, downloadZip };
51
+ }
@@ -40,10 +40,7 @@ export interface NotifierHistoryEntry extends NotifierEntry {
40
40
  }
41
41
 
42
42
  type NotifierEvent =
43
- | { type: "published"; entry: NotifierEntry }
44
- | { type: "cleared"; id: string }
45
- | { type: "cancelled"; id: string }
46
- | { type: "updated"; entry: NotifierEntry };
43
+ { type: "published"; entry: NotifierEntry } | { type: "cleared"; id: string } | { type: "cancelled"; id: string } | { type: "updated"; entry: NotifierEntry };
47
44
 
48
45
  const HISTORY_CAP = 50;
49
46
 
@@ -0,0 +1,60 @@
1
+ // Download an artifacts/html page as a self-contained zip from the host
2
+ // UI (file explorer preview). Mirrors usePdfDownload: POST the workspace
3
+ // path to /api/share/pack, receive a binary zip, run the
4
+ // blob-to-download dance. Failure sets `packFailed` so the caller can
5
+ // render a localized message — the raw server body is never surfaced.
6
+
7
+ import { ref, type Ref } from "vue";
8
+ import { API_ROUTES } from "../config/apiRoutes";
9
+ import { apiFetchRaw } from "../utils/api";
10
+ import { saveBlob, filenameFromDisposition } from "../utils/blobDownload";
11
+
12
+ export interface UseSharePackHandle {
13
+ packing: Ref<boolean>;
14
+ packFailed: Ref<boolean>;
15
+ downloadZip: (htmlPath: string) => Promise<void>;
16
+ /** Clear the failed flag — call on navigation so a stale error banner
17
+ * doesn't carry over to the next file. */
18
+ reset: () => void;
19
+ }
20
+
21
+ function fallbackName(htmlPath: string): string {
22
+ const base =
23
+ htmlPath
24
+ .split("/")
25
+ .pop()
26
+ ?.replace(/\.html?$/i, "") || "share";
27
+ return `${base}.zip`;
28
+ }
29
+
30
+ export function useSharePack(): UseSharePackHandle {
31
+ const packing = ref(false);
32
+ const packFailed = ref(false);
33
+
34
+ async function downloadZip(htmlPath: string): Promise<void> {
35
+ packFailed.value = false;
36
+ packing.value = true;
37
+ try {
38
+ const response = await apiFetchRaw(API_ROUTES.share.pack, {
39
+ method: "POST",
40
+ headers: { "Content-Type": "application/json" },
41
+ body: JSON.stringify({ path: htmlPath }),
42
+ });
43
+ if (!response.ok) {
44
+ packFailed.value = true;
45
+ return;
46
+ }
47
+ saveBlob(await response.blob(), filenameFromDisposition(response.headers.get("content-disposition"), fallbackName(htmlPath)));
48
+ } catch {
49
+ packFailed.value = true;
50
+ } finally {
51
+ packing.value = false;
52
+ }
53
+ }
54
+
55
+ function reset(): void {
56
+ packFailed.value = false;
57
+ }
58
+
59
+ return { packing, packFailed, downloadZip, reset };
60
+ }
@@ -1,109 +1,29 @@
1
- // Translates a role's suggested queries into the user's current
2
- // browser locale via /api/translation. Until the response lands the
3
- // caller keeps seeing the English source the swap is reactive
4
- // (Vue updates the SuggestionsPanel when the cache slot fills in).
1
+ // Translates a role's suggested queries into the user's current browser locale.
2
+ // A thin wrapper over the generic `useTranslatedStrings` (namespace
3
+ // "role-queries"); all caching / de-dup / fallback logic lives there and in the
4
+ // host-agnostic `@mulmoclaude/core/translation/client` cache it wraps.
5
5
  //
6
- // Cache keyed by `${roleId}:${locale}` and shared across all
7
- // consumers. Concurrent requests for the same key are deduped via
8
- // an in-flight Promise map.
9
- //
10
- // `locale` is taken as a Ref instead of being read from `useI18n()`
11
- // internally so the composable can be unit-tested outside a Vue
12
- // setup context.
6
+ // `locale` is taken as a Ref instead of being read from `useI18n()` internally
7
+ // so the composable can be unit-tested outside a Vue setup context.
13
8
 
14
- import { computed, watchEffect, type ComputedRef, type Ref, ref } from "vue";
15
- import { apiPost } from "../utils/api";
16
- import { API_ROUTES } from "../config/apiRoutes";
9
+ import { computed, type ComputedRef, type Ref } from "vue";
10
+ import { useTranslatedStrings, __resetTranslatedStringsCacheForTests } from "./useTranslatedStrings";
17
11
  import type { Role } from "../config/roles";
18
12
 
19
13
  const TRANSLATION_NAMESPACE = "role-queries";
20
14
 
21
- interface TranslateResponse {
22
- translations: string[];
23
- }
24
-
25
- const cache = new Map<string, Ref<string[] | null>>();
26
- const inflight = new Map<string, Promise<void>>();
27
-
28
- function cacheKey(roleId: string, locale: string): string {
29
- return `${roleId}:${locale}`;
30
- }
31
-
32
- function ensureSlot(key: string): Ref<string[] | null> {
33
- let slot = cache.get(key);
34
- if (!slot) {
35
- slot = ref<string[] | null>(null);
36
- cache.set(key, slot);
37
- }
38
- return slot;
39
- }
40
-
41
- async function runFetch(key: string, locale: string, sentences: string[]): Promise<void> {
42
- const result = await apiPost<TranslateResponse>(API_ROUTES.translation.translate, {
43
- namespace: TRANSLATION_NAMESPACE,
44
- targetLanguage: locale,
45
- sentences,
46
- });
47
- if (!result.ok) {
48
- console.warn("[useTranslatedQueries] translate failed:", result.error);
49
- return;
50
- }
51
- const { translations } = result.data;
52
- if (!Array.isArray(translations) || translations.length !== sentences.length) {
53
- console.warn("[useTranslatedQueries] translate returned wrong length", {
54
- expected: sentences.length,
55
- got: Array.isArray(translations) ? translations.length : "(not array)",
56
- });
57
- return;
58
- }
59
- ensureSlot(key).value = [...translations];
60
- }
61
-
62
- function ensureFetch(roleId: string, locale: string, sentences: string[]): void {
63
- const key = cacheKey(roleId, locale);
64
- if (inflight.has(key)) return;
65
- if (ensureSlot(key).value !== null) return;
66
- const pending = runFetch(key, locale, sentences).finally(() => {
67
- inflight.delete(key);
68
- });
69
- inflight.set(key, pending);
70
- }
71
-
72
15
  export interface UseTranslatedQueriesResult {
73
- /** Translated queries when available, falling back to the role's
74
- * English source while the request is in flight or fails. */
16
+ /** Translated queries when available, falling back to the role's English
17
+ * source while the request is in flight or fails. */
75
18
  readonly queries: ComputedRef<string[]>;
76
19
  }
77
20
 
78
21
  export function useTranslatedQueries(role: Ref<Role | undefined>, locale: Ref<string>): UseTranslatedQueriesResult {
79
- watchEffect(() => {
80
- const current = role.value;
81
- if (!current) return;
82
- const sources = current.queries;
83
- if (!sources || sources.length === 0) return;
84
- const lang = locale.value;
85
- if (lang === "en") return;
86
- ensureFetch(current.id, lang, [...sources]);
87
- });
88
-
89
- const queries = computed<string[]>(() => {
90
- const current = role.value;
91
- const sources = current?.queries ?? [];
92
- if (sources.length === 0) return [];
93
- const lang = locale.value;
94
- if (lang === "en" || !current) return [...sources];
95
- return cache.get(cacheKey(current.id, lang))?.value ?? [...sources];
96
- });
97
-
22
+ const sentences = computed<readonly string[]>(() => role.value?.queries ?? []);
23
+ const queries = useTranslatedStrings(TRANSLATION_NAMESPACE, sentences, locale);
98
24
  return { queries };
99
25
  }
100
26
 
101
- // ── Test-only hooks ─────────────────────────────────────────────────
102
- // Vitest / node:test lives in a fresh worker per file, so module
103
- // state usually cleans itself up. These helpers exist so suites that
104
- // share a worker can still reset between cases.
105
-
106
- export function __resetTranslatedQueriesCacheForTests(): void {
107
- cache.clear();
108
- inflight.clear();
109
- }
27
+ // Re-exported under the historical name so existing tests keep resetting the
28
+ // (now shared) translation cache between cases.
29
+ export const __resetTranslatedQueriesCacheForTests = __resetTranslatedStringsCacheForTests;
@@ -0,0 +1,68 @@
1
+ // Generic runtime-translation composable: translate a reactive list of English
2
+ // UI strings into the user's locale via the host's /api/translation route. The
3
+ // host-agnostic cache (de-dup, memo, length validation) lives in
4
+ // `@mulmoclaude/core/translation/client`; this file is the thin Vue layer —
5
+ // reactivity + the `en`/empty fallback. `useTranslatedQueries` (role chips) and
6
+ // any future caller share the one module-singleton cache below.
7
+ //
8
+ // `locale` and `sentences` are taken as Refs (not read from `useI18n()`) so the
9
+ // composable can be unit-tested outside a Vue setup context.
10
+
11
+ import { computed, watchEffect, type ComputedRef, type Ref, ref } from "vue";
12
+ import { createTranslationCache, type TranslateRequest, type TranslateResponse } from "@mulmoclaude/core/translation/client";
13
+ import { apiPost } from "../utils/api";
14
+ import { API_ROUTES } from "../config/apiRoutes";
15
+
16
+ const cache = createTranslationCache((req) =>
17
+ apiPost<TranslateResponse>(API_ROUTES.translation.translate, req).then((result) => (result.ok ? result.data : null)),
18
+ );
19
+
20
+ /** Pure projection: the translated batch when present, else the English source. */
21
+ export function pickTranslated(translated: readonly string[] | null, sources: readonly string[]): string[] {
22
+ return [...(translated ?? sources)];
23
+ }
24
+
25
+ /** Resolve a request through the cache (peek-then-fetch) and hand the result to
26
+ * `apply`, but only while `isCurrent()` still holds — so a slow response can't
27
+ * overwrite a newer locale/input's translation. */
28
+ function loadInto(req: TranslateRequest, isCurrent: () => boolean, apply: (value: readonly string[]) => void): void {
29
+ const hit = cache.peek(req);
30
+ if (hit !== null) {
31
+ apply(hit);
32
+ return;
33
+ }
34
+ cache
35
+ .fetch(req)
36
+ .then((result) => {
37
+ if (result !== null && isCurrent()) apply(result);
38
+ })
39
+ .catch(() => {
40
+ /* transport rejected — keep the English fallback */
41
+ });
42
+ }
43
+
44
+ /** Translated strings when available, falling back to the English source while
45
+ * the request is in flight or on failure. `en` and empty inputs never fetch. */
46
+ export function useTranslatedStrings(namespace: string, sentences: Ref<readonly string[]>, locale: Ref<string>): ComputedRef<string[]> {
47
+ const translated = ref<readonly string[] | null>(null);
48
+ watchEffect(() => {
49
+ const lang = locale.value;
50
+ const sources = sentences.value;
51
+ translated.value = null; // reset on any input change → source shows meanwhile
52
+ if (lang === "en" || sources.length === 0) return;
53
+ const req = { namespace, targetLanguage: lang, sentences: sources };
54
+ loadInto(
55
+ req,
56
+ () => locale.value === lang && sentences.value === sources,
57
+ (value) => (translated.value = value),
58
+ );
59
+ });
60
+ return computed<string[]>(() => pickTranslated(translated.value, sentences.value));
61
+ }
62
+
63
+ // ── Test-only hook ──────────────────────────────────────────────────
64
+ // Vitest / node:test usually gets a fresh worker per file, but suites that
65
+ // share a worker reset the singleton cache between cases through this.
66
+ export function __resetTranslatedStringsCacheForTests(): void {
67
+ cache.clear();
68
+ }
@@ -1,12 +1,12 @@
1
1
  // Thin Vue wrapper over the framework-neutral capture controller in
2
- // `@mulmoclaude/whisper/client` (shared with MulmoTerminal). This file supplies
2
+ // `@mulmoclaude/core/whisper/client` (shared with MulmoTerminal). This file supplies
3
3
  // the MulmoClaude-specific transport (api client + route constants) and language
4
4
  // mapping, and mirrors the controller's pushed state into Vue refs. The capture
5
5
  // logic itself (MediaRecorder + VAD + segment queue) lives in the package.
6
- // See plans/feat-extract-whisper-package.md.
6
+ // See plans/done/feat-extract-whisper-package.md.
7
7
 
8
8
  import { onScopeDispose, ref, type Ref } from "vue";
9
- import { createVoiceCapture, localeToWhisperLanguage, type VoiceCaptureTransport } from "@mulmoclaude/whisper/client";
9
+ import { createVoiceCapture, localeToWhisperLanguage, type VoiceCaptureTransport } from "@mulmoclaude/core/whisper/client";
10
10
  import { API_ROUTES } from "../config/apiRoutes";
11
11
  import { apiGet, apiPost } from "../utils/api";
12
12
 
@@ -33,11 +33,13 @@ type ResolveRoutes<R extends Readonly<Record<string, RouteSpec>>> = {
33
33
  readonly [K in keyof R]: ResolvedRoute;
34
34
  };
35
35
  type PluginApiRoutesMap<T extends BuiltInPluginMetas> = {
36
- readonly [M in T[number] as M extends { readonly apiRoutes: Readonly<Record<string, RouteSpec>> }
37
- ? M extends { readonly apiNamespace: infer K extends string }
38
- ? K
39
- : M["toolName"]
40
- : never]: M extends { readonly apiRoutes: infer R extends Readonly<Record<string, RouteSpec>> } ? ResolveRoutes<R> : never;
36
+ readonly [
37
+ M in T[number] as M extends { readonly apiRoutes: Readonly<Record<string, RouteSpec>> }
38
+ ? M extends { readonly apiNamespace: infer K extends string }
39
+ ? K
40
+ : M["toolName"]
41
+ : never
42
+ ]: M extends { readonly apiRoutes: infer R extends Readonly<Record<string, RouteSpec>> } ? ResolveRoutes<R> : never;
41
43
  };
42
44
 
43
45
  /** Resolve every plugin route into a `ResolvedRoute` keyed by the
@@ -61,6 +63,11 @@ const HOST_API_ROUTES = {
61
63
  // order). Single replace-endpoint — no add/remove route sprawl.
62
64
  shortcuts: "/api/shortcuts",
63
65
 
66
+ // Dashboard layout (per-tile view mode + order for the favorites grid).
67
+ // GET reads the list; PUT replaces it wholesale (client owns order /
68
+ // view mode). Single replace-endpoint, mirroring `shortcuts`.
69
+ dashboard: "/api/dashboard",
70
+
64
71
  agent: {
65
72
  run: "/api/agent",
66
73
  cancel: "/api/agent/cancel",
@@ -133,6 +140,25 @@ const HOST_API_ROUTES = {
133
140
  upload: "/api/attachments",
134
141
  },
135
142
 
143
+ // Sharing: pack an HTML artifact + its referenced local assets into a
144
+ // self-contained zip (index.html + assets/), streamed as a download.
145
+ // `packMarkdown` renders markdown / a wiki page to a self-contained
146
+ // HTML (images inlined) and zips that.
147
+ share: {
148
+ pack: "/api/share/pack",
149
+ packMarkdown: "/api/share/pack-markdown",
150
+ },
151
+
152
+ // Remote host over Firestore (phase 1). The server signs in to Firebase as
153
+ // the user (connect, body carries a browser-minted Google idToken), runs the
154
+ // command-loop + presence heartbeat, and exposes its running state. See
155
+ // plans/feat-remote-host-firestore-list-collections.md.
156
+ remoteHost: {
157
+ connect: "/api/remote-host/connect",
158
+ disconnect: "/api/remote-host/disconnect",
159
+ status: "/api/remote-host/status",
160
+ },
161
+
136
162
  mcpTools: {
137
163
  list: "/api/mcp-tools",
138
164
  invoke: "/api/mcp-tools/:tool",
@@ -167,7 +193,7 @@ const HOST_API_ROUTES = {
167
193
  // Local voice input (Mac-only, whisper.cpp). `run` transcribes one
168
194
  // audio clip; `model` reports capability + download status; `modelDownload`
169
195
  // is the opt-in trigger fired by the Settings → Voice enable toggle.
170
- // See plans/feat-voice-input.md.
196
+ // See plans/done/feat-voice-input.md.
171
197
  transcribe: {
172
198
  run: "/api/transcribe",
173
199
  model: "/api/transcribe/model",
@@ -267,6 +293,14 @@ const HOST_API_ROUTES = {
267
293
  /** GET ?id=<viewId> → the custom view's HTML file (global-bearer auth),
268
294
  * read from data/skills/:slug/views/. The parent renders it sandboxed. */
269
295
  viewFile: "/api/collections/:slug/view-file",
296
+ /** GET ?id=<viewId>&locale=<tag> → translation dict for one custom view
297
+ * (global-bearer auth) → { locale, dict }. `dict` is the host-picked
298
+ * flat map for the requested locale (fallback `"en"`, else `{}`); the
299
+ * host never streams other locales' strings. Empty dict + `locale: ""`
300
+ * when the view declares no `i18n` file or the file is missing /
301
+ * malformed — the view keeps working via `__MC_VIEW.t()`'s key
302
+ * fallback. */
303
+ viewI18n: "/api/collections/:slug/view-i18n",
270
304
  /** POST → mint a slug- and capability-scoped token for a custom view
271
305
  * (global-bearer auth) → { token, exp, dataUrl, capabilities }. */
272
306
  viewToken: "/api/collections/:slug/view-token",
@@ -280,6 +314,22 @@ const HOST_API_ROUTES = {
280
314
  viewDelete: "/api/collections/:slug/views/:viewId",
281
315
  },
282
316
 
317
+ // Curated collection registry (receptron/mulmoclaude-collections). The host
318
+ // server-fetches the published index.json (GitHub Pages) and proxies it to the
319
+ // /collections Discover tab — the upstream URL is never exposed to the client.
320
+ collectionsRegistry: {
321
+ list: "/api/collections-registry",
322
+ /** GET ?author=&slug= → { entry, schema, meta } for one in-index collection. */
323
+ preview: "/api/collections-registry/preview",
324
+ /** POST { author, slug } → fetch + re-validate + install into .claude/skills/,
325
+ * normalize dataPath, materialize seed, record provenance. */
326
+ import: "/api/collections-registry/import",
327
+ /** POST { slug, author, license?, includeSeed? } → write a registry-contribution
328
+ * bundle (collections/<author>/<slug>/ + meta.json + optional seed) under
329
+ * data/registry-export/ for the user to open a PR. */
330
+ export: "/api/collections-registry/export",
331
+ },
332
+
283
333
  // `scheduler` group migrated to META — see `src/plugins/scheduler/automationsMeta.ts`.
284
334
  // Auto-merged via `apiNamespace: "scheduler"`.
285
335
 
@@ -345,9 +395,7 @@ const HOST_API_ROUTES = {
345
395
  // `defineHostAggregate` is runtime-generic; the cast on the merged
346
396
  // result narrows it back to the literal-preserving shape above.
347
397
  type ApiRoutesAggregateValue =
348
- | (typeof HOST_API_ROUTES)[keyof typeof HOST_API_ROUTES]
349
- | Readonly<Record<string, string>>
350
- | Readonly<Record<string, ResolvedRoute>>;
398
+ (typeof HOST_API_ROUTES)[keyof typeof HOST_API_ROUTES] | Readonly<Record<string, string>> | Readonly<Record<string, ResolvedRoute>>;
351
399
 
352
400
  const API_ROUTES_AGGREGATE = defineHostAggregate<ApiRoutesAggregateValue>(BUILT_IN_PLUGIN_METAS, {
353
401
  label: "API_ROUTES",
@@ -16,7 +16,7 @@
16
16
  // a workspace-relative POSIX string matching `TreeNode.path` for the
17
17
  // folder row that should expose the menu.
18
18
 
19
- import { isSafeSlug } from "../lib/wiki-page/slug";
19
+ import { isSafeSlug } from "@mulmoclaude/core/wiki";
20
20
 
21
21
  export interface CreateFilePolicy {
22
22
  /** Workspace-relative POSIX folder path. Matched verbatim against
@@ -0,0 +1,12 @@
1
+ // Browser-side Firebase init for the remote-host settings page.
2
+ //
3
+ // Initializes the Firebase web app and exposes the Auth instance used by the
4
+ // SettingsRemoteHostTab to run the Google sign-in popup and extract the Google
5
+ // OAuth idToken (which is then POSTed to the server's /connect route).
6
+ import { initializeApp } from "firebase/app";
7
+ import { getAuth } from "firebase/auth";
8
+
9
+ import { firebaseConfig } from "./firebaseConfig";
10
+
11
+ export const firebaseApp = initializeApp(firebaseConfig);
12
+ export const auth = getAuth(firebaseApp);