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
@@ -10,7 +10,7 @@
10
10
  // that's not worth it for so little glue. js-yaml does the heavy
11
11
  // lifting in both places, identically.
12
12
 
13
- import yaml from "js-yaml";
13
+ import { FAILSAFE_SCHEMA, dump as yamlDump, load as yamlLoad } from "js-yaml";
14
14
 
15
15
  export interface ParsedMarkdown {
16
16
  /** Parsed YAML object. Empty `{}` when the document has no
@@ -71,7 +71,7 @@ export function serializeWithFrontmatter(meta: Record<string, unknown>, body: st
71
71
  // one line. `noRefs: true` avoids YAML anchor syntax (`&id001`)
72
72
  // which is technically valid but visually noisy in plain-text
73
73
  // markdown.
74
- const yamlText = yaml.dump(meta, { lineWidth: -1, noRefs: true }).trimEnd();
74
+ const yamlText = yamlDump(meta, { lineWidth: -1, noRefs: true }).trimEnd();
75
75
  return `---\n${yamlText}\n---\n\n${body}`;
76
76
  }
77
77
 
@@ -93,16 +93,20 @@ export function mergeFrontmatter(existing: Record<string, unknown>, patch: Recor
93
93
  }
94
94
 
95
95
  function safeYamlLoad(text: string): Record<string, unknown> | null {
96
+ // js-yaml 5.x throws on empty / whitespace-only input where 4.x
97
+ // returned `undefined`. An empty frontmatter block is "no metadata",
98
+ // not "malformed", so handle it before the loader.
99
+ if (text.trim() === "") return {};
96
100
  try {
97
101
  // `FAILSAFE_SCHEMA` keeps every scalar as a string and skips
98
102
  // type coercion. Two motivating cases:
99
103
  // - YAML 1.1 dates (`created: 2026-04-27`) would become a
100
- // `Date` object under DEFAULT_SCHEMA, breaking round-trip.
104
+ // `Date` object under CORE_SCHEMA, breaking round-trip.
101
105
  // - Numeric-looking strings (`version: 1.20` → 1.2 under
102
106
  // JSON_SCHEMA) drop trailing zeros on save.
103
107
  // For the wiki-history use case — title / created / updated /
104
108
  // tags / editor — every value that should be a string IS one.
105
- const loaded = yaml.load(text, { schema: yaml.FAILSAFE_SCHEMA });
109
+ const loaded = yamlLoad(text, { schema: FAILSAFE_SCHEMA });
106
110
  if (loaded === null || loaded === undefined) return {};
107
111
  if (typeof loaded !== "object" || Array.isArray(loaded)) return null;
108
112
  return loaded as Record<string, unknown>;
@@ -30,9 +30,10 @@ export const SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
30
30
 
31
31
  // ── Wiki bullet-link parsers ──────────────────────────────────────
32
32
  //
33
- // Moved to `src/lib/wiki-page/index-parse.ts` as part of the pure-
34
- // lib extraction (#1297). The patterns are still bounded with hard
35
- // delimiters; the ReDoS-safety rationale travelled with them.
33
+ // Moved to `@mulmoclaude/core/wiki` (`index-parse.ts`) as part of the
34
+ // pure-lib extraction (#1297, then promoted to shared core). The
35
+ // patterns are still bounded with hard delimiters; the ReDoS-safety
36
+ // rationale travelled with them.
36
37
 
37
38
  // ── Skills body blank-line stripper ───────────────────────────────
38
39
  //
@@ -0,0 +1,108 @@
1
+ import { readFile } from "fs/promises";
2
+ import { realpathSync } from "fs";
3
+ import path from "path";
4
+ import JSZip from "jszip";
5
+ import { resolveWorkspacePath } from "../files/workspace-io.js";
6
+ import { resolveWithinRoot } from "../files/safe.js";
7
+ import { rewriteHtmlAssets } from "./rewriteAssets.js";
8
+ import { log } from "../../system/logger/index.js";
9
+
10
+ const LOG_PREFIX = "share";
11
+
12
+ export interface PackedFile {
13
+ bundlePath: string;
14
+ bytes: Buffer;
15
+ }
16
+
17
+ // A self-contained bundle: the rewritten entry document plus every
18
+ // referenced local asset, ready to zip. `name` is a suggested base
19
+ // filename (no extension) derived from the source page.
20
+ export interface PackedBundle {
21
+ name: string;
22
+ files: PackedFile[];
23
+ }
24
+
25
+ // `resolveWithinRoot` requires an already-realpath'd root. Resolved
26
+ // lazily (not at import) so loading this module never depends on the
27
+ // workspace dir existing yet; the location doesn't change during a run.
28
+ let workspaceRealCache: string | null = null;
29
+ function workspaceReal(): string {
30
+ if (workspaceRealCache === null) workspaceRealCache = realpathSync(resolveWorkspacePath("."));
31
+ return workspaceRealCache;
32
+ }
33
+
34
+ function stripQueryHash(ref: string): string {
35
+ const cut = ref.search(/[?#]/);
36
+ return cut === -1 ? ref : ref.slice(0, cut);
37
+ }
38
+
39
+ // Resolve a workspace-relative path to a contained absolute path, or
40
+ // null if it escapes the workspace / doesn't exist. `resolveWithinRoot`
41
+ // already realpath-checks containment; the extra `path.relative` guard
42
+ // is the form CodeQL's js/path-injection analysis recognizes as a
43
+ // sanitizer (its `startsWith` form isn't), and is redundant at runtime.
44
+ function safeWorkspaceAbs(relFromRoot: string): string | null {
45
+ const root = workspaceReal();
46
+ const abs = resolveWithinRoot(root, relFromRoot);
47
+ if (!abs) return null;
48
+ const rel = path.relative(root, abs);
49
+ if (rel.startsWith("..") || path.isAbsolute(rel)) return null;
50
+ return abs;
51
+ }
52
+
53
+ // Resolve a ref (relative to the HTML file's dir) to workspace bytes.
54
+ // Returns null when the ref escapes the workspace or the file is
55
+ // missing — the caller warns and leaves the (now dangling) link.
56
+ async function readAsset(htmlDir: string, originalRef: string): Promise<Buffer | null> {
57
+ const relFromRoot = path.posix.normalize(path.posix.join(htmlDir, stripQueryHash(originalRef)));
58
+ const abs = safeWorkspaceAbs(relFromRoot);
59
+ if (!abs) return null;
60
+ try {
61
+ return await readFile(abs);
62
+ } catch {
63
+ return null;
64
+ }
65
+ }
66
+
67
+ export async function packHtmlBundle(htmlRelPath: string): Promise<PackedBundle> {
68
+ const abs = safeWorkspaceAbs(htmlRelPath);
69
+ if (!abs) throw new Error(`HTML not found or outside workspace: ${htmlRelPath}`);
70
+ const html = await readFile(abs, "utf-8");
71
+
72
+ const { html: rewritten, assets } = rewriteHtmlAssets(html);
73
+ const htmlDir = path.posix.dirname(htmlRelPath);
74
+
75
+ const files: PackedFile[] = [{ bundlePath: "index.html", bytes: Buffer.from(rewritten, "utf-8") }];
76
+ for (const asset of assets) {
77
+ const bytes = await readAsset(htmlDir, asset.originalRef);
78
+ if (bytes === null) {
79
+ log.warn(LOG_PREFIX, "asset missing or outside workspace; skipped", { ref: asset.originalRef });
80
+ continue;
81
+ }
82
+ files.push({ bundlePath: asset.bundlePath, bytes });
83
+ }
84
+
85
+ const name = path.posix.basename(htmlRelPath).replace(/\.html?$/i, "") || "share";
86
+ return { name, files };
87
+ }
88
+
89
+ // Zip a bundle in memory. Bundles are small (one page + a few assets),
90
+ // so an in-memory buffer is simpler than streaming and stays testable.
91
+ export function zipBundle(files: PackedFile[]): Promise<Buffer> {
92
+ const zip = new JSZip();
93
+ for (const file of files) zip.file(file.bundlePath, file.bytes);
94
+ return zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE", compressionOptions: { level: 9 } });
95
+ }
96
+
97
+ export function safeZipName(name: string): string {
98
+ const cleaned = name.replace(/[^\w.-]+/g, "_");
99
+ return `${cleaned || "share"}.zip`;
100
+ }
101
+
102
+ // One-call pack: bundle → zip → suggested download filename. Shared by
103
+ // the HTTP route (streams the buffer) and the View dispatch (base64).
104
+ export async function packHtmlZip(htmlRelPath: string): Promise<{ filename: string; zip: Buffer }> {
105
+ const bundle = await packHtmlBundle(htmlRelPath);
106
+ const zip = await zipBundle(bundle.files);
107
+ return { filename: safeZipName(bundle.name), zip };
108
+ }
@@ -0,0 +1,178 @@
1
+ import { parse, type HTMLElement } from "node-html-parser";
2
+
3
+ // A local resource referenced by the HTML that must be copied into the
4
+ // bundle. `originalRef` is the reference verbatim as it appears in the
5
+ // source (relative to the HTML file); `bundlePath` is where it lands in
6
+ // the self-contained bundle (always under `assets/`).
7
+ export interface AssetRef {
8
+ originalRef: string;
9
+ bundlePath: string;
10
+ }
11
+
12
+ export interface RewriteResult {
13
+ html: string;
14
+ assets: AssetRef[];
15
+ }
16
+
17
+ const ASSETS_DIR = "assets";
18
+
19
+ // Refs we never bundle: absolute URLs, protocol-relative, data/blob,
20
+ // in-page anchors, and non-navigational schemes. Everything else is a
21
+ // workspace-relative path the bundle must localize. Root-absolute
22
+ // (`/foo`) is left alone too — without a known base it can't be mapped.
23
+ function isLocalRef(ref: string): boolean {
24
+ const value = ref.trim();
25
+ if (value === "") return false;
26
+ if (value.startsWith("#") || value.startsWith("//") || value.startsWith("/")) return false;
27
+ return !/^[a-z][a-z0-9+.-]*:/i.test(value);
28
+ }
29
+
30
+ function stripQueryHash(ref: string): string {
31
+ const cut = ref.search(/[?#]/);
32
+ return cut === -1 ? ref : ref.slice(0, cut);
33
+ }
34
+
35
+ // Safe single-segment filename for a bundle entry. Splits on BOTH path
36
+ // separators — a crafted `..\..\evil.png` must not survive into a zip
37
+ // entry name, where a Windows unzip tool treats `\` as a separator
38
+ // (zip-slip). `.`/`..`/empty collapse to a neutral name.
39
+ function safeAssetName(ref: string): string {
40
+ const segment = stripQueryHash(ref).split(/[/\\]/).pop() ?? "";
41
+ return segment === "" || segment === "." || segment === ".." ? "asset" : segment;
42
+ }
43
+
44
+ function splitSuffix(ref: string): { filePath: string; suffix: string } {
45
+ const cut = ref.search(/[?#]/);
46
+ return cut === -1 ? { filePath: ref, suffix: "" } : { filePath: ref.slice(0, cut), suffix: ref.slice(cut) };
47
+ }
48
+
49
+ // Maps a local ref to its `assets/<name>` slot. The bundled FILE is
50
+ // keyed by the path with `?query`/`#fragment` stripped, so `a.png?v=1`
51
+ // and `a.png?v=2` share one copy; but the rewritten URL keeps each
52
+ // ref's suffix (an SVG `sprite.svg#icon` fragment must survive). A
53
+ // basename collision across different dirs is disambiguated by a short
54
+ // hash of the file path so two `logo.png` don't clobber each other.
55
+ function createAssetMapper() {
56
+ const byPath = new Map<string, string>();
57
+ const usedNames = new Set<string>();
58
+ const assets: AssetRef[] = [];
59
+
60
+ const hash = (value: string): string => {
61
+ let acc = 0;
62
+ for (const char of value) acc = (acc * 31 + char.charCodeAt(0)) | 0;
63
+ return (acc >>> 0).toString(36);
64
+ };
65
+
66
+ const bundlePathFor = (filePath: string): string => {
67
+ const existing = byPath.get(filePath);
68
+ if (existing) return existing;
69
+ const base = safeAssetName(filePath);
70
+ const name = usedNames.has(base) ? `${hash(filePath)}-${base}` : base;
71
+ usedNames.add(name);
72
+ const bundlePath = `${ASSETS_DIR}/${name}`;
73
+ byPath.set(filePath, bundlePath);
74
+ assets.push({ originalRef: filePath, bundlePath });
75
+ return bundlePath;
76
+ };
77
+
78
+ const map = (originalRef: string): string => {
79
+ const { filePath, suffix } = splitSuffix(originalRef);
80
+ return bundlePathFor(filePath) + suffix;
81
+ };
82
+
83
+ return { map, assets };
84
+ }
85
+
86
+ function rewriteCssUrls(css: string, map: (ref: string) => string): string {
87
+ return css.replace(/url\(([^)]*)\)/gi, (whole, inner: string) => {
88
+ const raw = inner.trim();
89
+ const quote = raw.startsWith('"') || raw.startsWith("'") ? raw[0] : "";
90
+ const ref = quote ? raw.slice(1, -1) : raw;
91
+ if (!isLocalRef(ref)) return whole;
92
+ return `url(${quote}${map(ref)}${quote})`;
93
+ });
94
+ }
95
+
96
+ function isSrcsetWs(char: string): boolean {
97
+ return char === " " || char === "\t" || char === "\n" || char === "\r" || char === "\f";
98
+ }
99
+
100
+ // One srcset candidate: a URL (a run of non-whitespace, so a data: URI's
101
+ // internal commas stay intact) whose trailing commas are separators, then
102
+ // an optional descriptor up to the next comma. Only local URLs are
103
+ // rewritten; everything else is emitted verbatim. Returns the new cursor.
104
+ function rewriteSrcsetCandidate(value: string, start: number, map: (ref: string) => string, out: string[]): number {
105
+ let index = start;
106
+ while (index < value.length && !isSrcsetWs(value[index])) index++;
107
+ let url = value.slice(start, index);
108
+ let trailing = "";
109
+ while (url.endsWith(",")) {
110
+ url = url.slice(0, -1);
111
+ trailing += ",";
112
+ }
113
+ out.push(isLocalRef(url) ? map(url) : url, trailing);
114
+ if (trailing !== "") return index;
115
+ const descStart = index;
116
+ while (index < value.length && value[index] !== ",") index++;
117
+ out.push(value.slice(descStart, index));
118
+ return index;
119
+ }
120
+
121
+ // WHATWG-style srcset walk: candidates are comma-separated, but because a
122
+ // URL is a non-whitespace run, `data:` URIs (whose payload contains commas)
123
+ // are never split. Separators / whitespace / descriptors are preserved.
124
+ function rewriteSrcset(value: string, map: (ref: string) => string): string {
125
+ const out: string[] = [];
126
+ let index = 0;
127
+ while (index < value.length) {
128
+ const sepStart = index;
129
+ while (index < value.length && (isSrcsetWs(value[index]) || value[index] === ",")) index++;
130
+ out.push(value.slice(sepStart, index));
131
+ if (index < value.length) index = rewriteSrcsetCandidate(value, index, map, out);
132
+ }
133
+ return out.join("");
134
+ }
135
+
136
+ // Embedded resources only. `a[href]` is intentionally excluded — it is
137
+ // navigation, not an inlined asset, and rewriting it would point at a
138
+ // file the single-page bundle doesn't carry.
139
+ const URL_ATTRS: readonly { selector: string; attr: string }[] = [
140
+ { selector: "img[src]", attr: "src" },
141
+ { selector: "script[src]", attr: "src" },
142
+ { selector: "source[src]", attr: "src" },
143
+ { selector: "link[href]", attr: "href" },
144
+ { selector: "audio[src]", attr: "src" },
145
+ { selector: "video[src]", attr: "src" },
146
+ { selector: "video[poster]", attr: "poster" },
147
+ { selector: "use[href]", attr: "href" },
148
+ ];
149
+
150
+ function rewriteAttrs(root: HTMLElement, map: (ref: string) => string): void {
151
+ for (const { selector, attr } of URL_ATTRS) {
152
+ for (const element of root.querySelectorAll(selector)) {
153
+ const ref = element.getAttribute(attr);
154
+ if (ref && isLocalRef(ref)) element.setAttribute(attr, map(ref));
155
+ }
156
+ }
157
+ for (const element of root.querySelectorAll("[srcset]")) {
158
+ const value = element.getAttribute("srcset");
159
+ if (value) element.setAttribute("srcset", rewriteSrcset(value, map));
160
+ }
161
+ for (const element of root.querySelectorAll("style")) {
162
+ element.set_content(rewriteCssUrls(element.textContent, map));
163
+ }
164
+ for (const element of root.querySelectorAll("[style]")) {
165
+ const value = element.getAttribute("style");
166
+ if (value) element.setAttribute("style", rewriteCssUrls(value, map));
167
+ }
168
+ }
169
+
170
+ // Rewrites every local resource reference in `html` to point at a
171
+ // co-located `assets/<name>`, returning the rewritten document plus the
172
+ // list of refs to copy. Pure: no filesystem or network.
173
+ export function rewriteHtmlAssets(html: string): RewriteResult {
174
+ const root = parse(html, { comment: true });
175
+ const mapper = createAssetMapper();
176
+ rewriteAttrs(root, mapper.map);
177
+ return { html: root.toString(), assets: mapper.assets };
178
+ }
@@ -4,8 +4,14 @@
4
4
  // claude CLI spawn code).
5
5
 
6
6
  import path from "node:path";
7
-
8
- export const CHAT_DIR = "chat";
7
+ import { WORKSPACE_DIRS } from "../paths.js";
8
+
9
+ // Sourced from WORKSPACE_DIRS so the layout move in #284
10
+ // (`chat/` → `conversations/chat/`) can't drift again — a hardcoded
11
+ // literal here silently detached the indexer from the real session
12
+ // tree between Apr and Jul 2026, leaving every session listing
13
+ // preview to fall back to `meta.firstUserMessage` (issue #1902).
14
+ export const CHAT_DIR = WORKSPACE_DIRS.chat;
9
15
  export const INDEX_DIR = "index";
10
16
  export const MANIFEST_FILE = "manifest.json";
11
17
 
@@ -39,23 +39,31 @@ const SUMMARY_SCHEMA = {
39
39
  required: ["title", "summary", "keywords"],
40
40
  };
41
41
 
42
- // Prompt-building constants.
43
- const MAX_INPUT_CHARS = 8000;
44
- const HEAD_CHARS = 3000;
45
- const TAIL_CHARS = 5000;
46
- const PER_MESSAGE_MAX = 500;
42
+ // Model used for summarization. Sonnet, not haiku: the title is the
43
+ // primary way a user finds a past chat, so a weak title makes the
44
+ // history list unusable. One cheap structured call per session is
45
+ // negligible next to the agent turns it summarizes.
46
+ const SUMMARY_MODEL = "sonnet";
47
+
48
+ // Prompt-building constants. Sized for Sonnet's large context: the
49
+ // window is wide enough to carry a long, topic-shifting session's
50
+ // middle (not just head + tail), and per-message clipping keeps the
51
+ // substance of long turns. Exported so the summarizer tests derive
52
+ // their fixtures from them rather than hard-coding sizes that rot.
53
+ export const MAX_INPUT_CHARS = 30000;
54
+ export const HEAD_CHARS = 12000;
55
+ export const TAIL_CHARS = 16000;
56
+ export const PER_MESSAGE_MAX = 1500;
47
57
 
48
58
  // Spawn / budget constants.
49
59
  const DEFAULT_TIMEOUT_MS = 2 * ONE_MINUTE_MS;
50
60
  // Budget cap per summarization call, forwarded to `claude
51
- // --max-budget-usd`. Previously 0.05 but that was tight enough
52
- // that a first-burst call which pays a one-time cache creation
53
- // cost on haiku (~28k cache-creation tokens) would trip the cap
54
- // and fail with `error_max_budget_usd` even for tiny 600-char
55
- // transcripts. 0.15 leaves comfortable headroom for cache
56
- // creation + a generous output allowance while still capping a
57
- // full 100-session backfill to well under $20.
58
- const MAX_BUDGET_USD = 0.15;
61
+ // --max-budget-usd`. A first-burst call pays a one-time cache-creation
62
+ // cost (~28k tokens) that on Sonnet's pricing would trip a tighter cap
63
+ // and fail with `error_max_budget_usd` yielding NO title at all.
64
+ // 0.40 leaves headroom for cache creation plus the wider input window
65
+ // while still bounding a full backfill.
66
+ const MAX_BUDGET_USD = 0.4;
59
67
 
60
68
  // Any module that wants to drive the summarizer — including the
61
69
  // indexer — takes a SummarizeFn so tests can supply a deterministic
@@ -95,7 +103,7 @@ export function extractText(jsonlContent: string): string {
95
103
  return parts.join("\n\n");
96
104
  }
97
105
 
98
- // Long sessions are clipped to first ~3000 + last ~5000 chars so
106
+ // Long sessions are clipped to first ~12000 + last ~16000 chars so
99
107
  // claude sees both the original topic and the most recent state.
100
108
  // Distinct from the simple-tail `truncate()` in `server/utils/text.ts`
101
109
  // — the summarizer needs context from both ends, not just the head.
@@ -184,7 +192,7 @@ function spawnClaudeSummarize(input: string, timeoutMs: number): Promise<string>
184
192
  "--output-format",
185
193
  "json",
186
194
  "--model",
187
- "haiku",
195
+ SUMMARY_MODEL,
188
196
  "--max-budget-usd",
189
197
  String(MAX_BUDGET_USD),
190
198
  "--json-schema",
@@ -1,14 +1,15 @@
1
- // Wire @mulmoclaude/collection-plugin/server to MulmoClaude's workspace,
1
+ // Wire @mulmoclaude/core/collection/server to MulmoClaude's workspace,
2
2
  // logger, and path layout. Imported for side effect at the very top of
3
3
  // server/index.ts so the binding is set before any collection storage
4
4
  // operation runs. MulmoTerminal has its own equivalent shim.
5
5
  import path from "node:path";
6
- import { configureCollectionHost } from "@mulmoclaude/collection-plugin/server";
6
+ import { configureCollectionHost } from "@mulmoclaude/core/collection/server";
7
7
  import { workspacePath } from "../workspace.js";
8
8
  import { log } from "../../system/logger/index.js";
9
9
  import { WORKSPACE_DIRS } from "../paths.js";
10
+ import { WORKSPACE_FILES } from "../../../src/config/workspacePaths.js";
10
11
  import { USER_SKILLS_DIR, projectSkillsDir } from "../skills/paths.js";
11
- import { feedsRoot } from "../feeds/paths.js";
12
+ import { feedsRoot } from "@mulmoclaude/core/feeds/paths";
12
13
  import { isPresetSlug } from "../skills-preset.js";
13
14
 
14
15
  configureCollectionHost({
@@ -20,6 +21,7 @@ configureCollectionHost({
20
21
  feedsRoot,
21
22
  skillsStagingDir: (root) => path.join(root, WORKSPACE_DIRS.skillsStaging),
22
23
  archiveDir: WORKSPACE_DIRS.archive,
24
+ collectionsRegistriesConfig: (root) => path.join(root, ...WORKSPACE_FILES.collectionsRegistries.split("/")),
23
25
  },
24
26
  isPresetSlug,
25
27
  });
@@ -6,11 +6,11 @@ export {
6
6
  CollectionSchemaZ,
7
7
  resolveDataDir,
8
8
  type LoadedCollection,
9
- } from "@mulmoclaude/collection-plugin/server";
10
- export { validateCollectionRecords, validateRecordObject, COMPUTED_TYPES, type RecordIssue } from "@mulmoclaude/collection-plugin/server";
11
- export { enrichItems } from "@mulmoclaude/collection-plugin/server";
12
- export { deleteCollection, deleteCollectionRefusalMessage, type DeleteCollectionResult } from "@mulmoclaude/collection-plugin/server";
13
- export { deleteCustomView, type DeleteViewResult } from "@mulmoclaude/collection-plugin/server";
9
+ } from "@mulmoclaude/core/collection/server";
10
+ export { validateCollectionRecords, validateRecordObject, COMPUTED_TYPES, type RecordIssue } from "@mulmoclaude/core/collection/server";
11
+ export { enrichItems } from "@mulmoclaude/core/collection/server";
12
+ export { deleteCollection, deleteCollectionRefusalMessage, type DeleteCollectionResult } from "@mulmoclaude/core/collection/server";
13
+ export { deleteCustomView, type DeleteViewResult } from "@mulmoclaude/core/collection/server";
14
14
  export {
15
15
  listItems,
16
16
  readItem,
@@ -20,11 +20,13 @@ export {
20
20
  resolveCreateItemId,
21
21
  readSkillTemplate,
22
22
  readCustomViewHtml,
23
+ readCustomViewI18n,
23
24
  buildActionSeedPrompt,
24
25
  buildCollectionActionSeedPrompt,
26
+ promptPathsFor,
25
27
  type WriteItemResult,
26
28
  type DeleteItemResult,
27
- } from "@mulmoclaude/collection-plugin/server";
29
+ } from "@mulmoclaude/core/collection/server";
28
30
  export type {
29
31
  CollectionSchema,
30
32
  CollectionAction,
@@ -1,5 +1,5 @@
1
1
  // Collection-completion bell reconciler — thin host binding over
2
- // @mulmoclaude/collection-watchers. The convergent reconcile logic lives
2
+ // @mulmoclaude/core/collection-watchers. The convergent reconcile logic lives
3
3
  // in the shared package; this file supplies MulmoClaude's notification
4
4
  // taxonomy (publish under "todo", priority→severity mapping) and in-app
5
5
  // routing (the `/collections/<slug>?selected=<itemId>` deep-link) via a
@@ -21,7 +21,7 @@ import {
21
21
  type LegacyNotifierPluginData,
22
22
  } from "../../events/notifications.js";
23
23
  import { log } from "../../system/logger/index.js";
24
- import { configureCollectionWatchers, type CollectionNotificationAdapter, type CompletionPriority } from "@mulmoclaude/collection-watchers";
24
+ import { configureCollectionWatchers, type CollectionNotificationAdapter, type CompletionPriority } from "@mulmoclaude/core/collection-watchers";
25
25
 
26
26
  // Re-export the reconciler surface verbatim from the package.
27
27
  export {
@@ -31,7 +31,7 @@ export {
31
31
  clearItemNotification,
32
32
  resolveDisplayLabel,
33
33
  itemIsDone,
34
- } from "@mulmoclaude/collection-watchers";
34
+ } from "@mulmoclaude/core/collection-watchers";
35
35
 
36
36
  const COLLECTION_PLUGIN_PKG = legacyKindToPluginPkg(NOTIFICATION_KINDS.todo);
37
37
 
@@ -1,6 +1,6 @@
1
1
  // The canonical collection schema types now live in
2
- // @mulmoclaude/collection-plugin (single source of truth, also consumed by
2
+ // @mulmoclaude/core/collection (single source of truth, also consumed by
3
3
  // the host frontend via src/components/collectionTypes.ts and by
4
4
  // MulmoTerminal). Re-exported here so the many `./types.js` importers under
5
5
  // server/workspace/collections keep compiling unchanged.
6
- export * from "@mulmoclaude/collection-plugin";
6
+ export * from "@mulmoclaude/core/collection";
@@ -1,5 +1,5 @@
1
1
  // Collection watchers — thin host binding over
2
- // @mulmoclaude/collection-watchers. The fs.watch plumbing lives in the
2
+ // @mulmoclaude/core/collection-watchers. The fs.watch plumbing lives in the
3
3
  // shared package; this file just ensures the host's notification adapter
4
4
  // is configured (the `./notifications.js` side-effect import) and
5
5
  // re-exports the watcher surface existing callers + tests import from
@@ -16,4 +16,4 @@ export {
16
16
  _tickTimeTriggersForTesting,
17
17
  _scheduleItemReconcileForTesting,
18
18
  type CollectionWatcherOptions,
19
- } from "@mulmoclaude/collection-watchers";
19
+ } from "@mulmoclaude/core/collection-watchers";
@@ -0,0 +1,24 @@
1
+ // Wire @mulmoclaude/core/feeds/server to this host's workspace, logger, atomic
2
+ // writer, and agent-ingest worker launcher. Called once from server/index.ts
3
+ // BEFORE scheduler init (catch-up can fire `system:feed-refresh` immediately, so
4
+ // wiring after would make those first refreshes fail "host not configured").
5
+ //
6
+ // The worker launcher (`spawnSystemWorker`) is INJECTED by the caller rather
7
+ // than imported here: it lives in the routes layer, and workspace code must not
8
+ // import routes (a workspace→routes cycle is exactly what the old
9
+ // `setAgentWorkerRunner` seam — now folded into `spawnWorker` — existed to
10
+ // avoid). `server/index.ts` (the host entry) is allowed to bridge the two.
11
+ import { configureFeedsHost, type AgentWorkerRunner } from "@mulmoclaude/core/feeds/server";
12
+ import { workspacePath } from "../workspace.js";
13
+ import { log } from "../../system/logger/index.js";
14
+ import { writeFileAtomic } from "../../utils/files/atomic.js";
15
+
16
+ export function configureFeeds(spawnWorker: AgentWorkerRunner): void {
17
+ configureFeedsHost({
18
+ workspaceRoot: workspacePath,
19
+ log,
20
+ // Feed state files use the plain (non-uniqueTmp) atomic write, as before.
21
+ writeFileAtomic: (filePath, content) => writeFileAtomic(filePath, content),
22
+ spawnWorker,
23
+ });
24
+ }
@@ -1,4 +1,4 @@
1
- // Skill-bridge HOST adapter — thin wiring over @mulmoclaude/skill-bridge.
1
+ // Skill-bridge HOST adapter — thin wiring over @mulmoclaude/core/skill-bridge.
2
2
  //
3
3
  // The agent writes skill drafts under `data/skills/<slug>/` (a plain data dir, no
4
4
  // `.claude/` permission special-case); the shared package decides which writes are
@@ -26,7 +26,7 @@ import {
26
26
  mirrorSkillWrite,
27
27
  mirrorSkillDelete,
28
28
  type BridgeTarget,
29
- } from "@mulmoclaude/skill-bridge";
29
+ } from "@mulmoclaude/core/skill-bridge";
30
30
  import { buildAuthPost, safePost, serverLog } from "../shared/sidecar.js";
31
31
  import type { HookPayload } from "../shared/stdin.js";
32
32
  import { extractCommand, extractFilePath, extractToolName } from "../shared/stdin.js";
@@ -6,7 +6,7 @@
6
6
  // carries a single PostToolUse entry instead of one per hook source.
7
7
 
8
8
  import path from "node:path";
9
- import { wikiSlugFromAbsPath } from "../../../../src/lib/wiki-page/paths.js";
9
+ import { wikiSlugFromAbsPath } from "@mulmoclaude/core/wiki/paths";
10
10
  import { buildAuthPost, safePost } from "../shared/sidecar.js";
11
11
  import type { HookPayload } from "../shared/stdin.js";
12
12
  import { extractFilePath, extractSessionId, extractToolName } from "../shared/stdin.js";
@@ -119,6 +119,13 @@ const HOST_WORKSPACE_DIRS = {
119
119
  // Non-skill data-source feed registry: feeds/<slug>/schema.json (+
120
120
  // _state.json). Records land under each schema's dataPath (data/feeds/*).
121
121
  feeds: "feeds",
122
+ // Retrieval state for NON-feed collections with an `ingest` block
123
+ // (`kind: "agent"` on a skill-backed collection). Feeds keep their state
124
+ // at feeds/<slug>/_state.json; skill collections can't (a feeds/<slug>/
125
+ // dir without schema.json confuses feed discovery, and _state.json must
126
+ // never live in a collection's dataDir where listItems would read it as a
127
+ // record). One file per collection: data/ingest-state/<slug>.json.
128
+ ingestState: "data/ingest-state",
122
129
  translation: "data/translation",
123
130
  // Pasted/dropped chat attachments — saved at upload time so the
124
131
  // LLM can be handed a stable workspace path instead of inline
@@ -216,7 +223,7 @@ const HOST_WORKSPACE_DIRS = {
216
223
  // git) — since model files are large binaries that must stay out of
217
224
  // the git-tracked tree. Created lazily on first download, never
218
225
  // eagerly (most users never enable voice input). See
219
- // plans/feat-voice-input.md.
226
+ // plans/done/feat-voice-input.md.
220
227
  models: "models",
221
228
  // Runtime-loaded plugins (#1043 C-2). The `plugins/` directory holds
222
229
  // user-installed npm-published plugin tarballs; `.cache/<name>/<ver>/`
@@ -187,9 +187,7 @@ export interface CatalogEntryDetail {
187
187
  }
188
188
 
189
189
  export type CatalogDetailResult =
190
- | { kind: "ok"; detail: CatalogEntryDetail }
191
- | { kind: "not-found"; source: CatalogSource; slug: string }
192
- | { kind: "invalid-slug"; slug: string };
190
+ { kind: "ok"; detail: CatalogEntryDetail } | { kind: "not-found"; source: CatalogSource; slug: string } | { kind: "invalid-slug"; slug: string };
193
191
 
194
192
  /** Read one catalog entry's SKILL.md and return the description +
195
193
  * body. The same `safeSlugName` taint-launder used by the star
@@ -159,9 +159,7 @@ export interface ExternalCatalogDetail {
159
159
  }
160
160
 
161
161
  export type ExternalCatalogDetailResult =
162
- | { kind: "ok"; detail: ExternalCatalogDetail }
163
- | { kind: "invalid-id" }
164
- | { kind: "not-found"; repoId: string; skillFolder: string };
162
+ { kind: "ok"; detail: ExternalCatalogDetail } | { kind: "invalid-id" } | { kind: "not-found"; repoId: string; skillFolder: string };
165
163
 
166
164
  interface ResolvedSource {
167
165
  repoId: string;
@@ -10,13 +10,14 @@
10
10
  // chars. Same rule as `server/sources/paths.ts#isValidSlug` — keep
11
11
  // them in sync manually.
12
12
 
13
- import { homedir } from "node:os";
14
13
  import { join } from "node:path";
14
+ import { claudeSkillsDir } from "../../utils/claudeConfigPath.js";
15
15
 
16
16
  export const SKILL_FILE = "SKILL.md";
17
17
 
18
- /** `~/.claude/skills/` — user scope, read-only from MulmoClaude. */
19
- export const USER_SKILLS_DIR = join(homedir(), ".claude", "skills");
18
+ /** `<claudeConfigDir>/skills/` — user scope, read-only from MulmoClaude.
19
+ * Default `~/.claude/skills/`; override via `CLAUDE_CONFIG_DIR` (issue #87 §2). */
20
+ export const USER_SKILLS_DIR = claudeSkillsDir();
20
21
 
21
22
  /** `<workspaceRoot>/.claude/skills/` — project scope, writable. */
22
23
  export function projectSkillsDir(workspaceRoot: string): string {