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
@@ -1,8 +0,0 @@
1
- // Public surface of the Feeds module. Routes + the scheduler import
2
- // from here.
3
-
4
- export { listFeeds, removeFeed } from "./registry.js";
5
- export { refreshOne, refreshDue, type RefreshResult } from "./engine.js";
6
- export { feedsRoot, feedDir, feedStatePath, FEEDS_DIR } from "./paths.js";
7
- export { readFeedState, type FeedState } from "./state.js";
8
- export { INGEST_KINDS, FEED_SCHEDULES, isFeedSchedule, type IngestSpec, type IngestKind, type FeedSchedule } from "./ingestTypes.js";
@@ -1,62 +0,0 @@
1
- // Declarative retrieval config for the "Feeds" mechanism. A Feed is a
2
- // CollectionSchema plus this `ingest` block, registered as data (NOT as
3
- // a skill) under `<workspace>/feeds/<slug>/schema.json`. The host's
4
- // retrieval engine reads it to periodically refill the collection's
5
- // records via the shared collections io layer.
6
- //
7
- // The ingest vocab (INGEST_KINDS / FEED_SCHEDULES + their literal-union types)
8
- // now lives in @mulmoclaude/collection-plugin alongside the schema contract, so
9
- // the package's schema validator can enforce it. Re-exported here so the feeds
10
- // engine's existing importers resolve them unchanged.
11
- import { type CollectionIngest, INGEST_KINDS, FEED_SCHEDULES, type IngestKind, type FeedSchedule } from "@mulmoclaude/collection-plugin";
12
- //
13
- // Declarative-only for now; the `kind` enum reserves room for future
14
- // "code" (LLM-generated transform) and "prompt" (LLM-performed fetch)
15
- // retrievers without reshaping the engine.
16
-
17
- export { INGEST_KINDS, FEED_SCHEDULES, type IngestKind, type FeedSchedule };
18
-
19
- const FEED_SCHEDULE_SET: ReadonlySet<string> = new Set(FEED_SCHEDULES);
20
-
21
- export function isFeedSchedule(value: unknown): value is FeedSchedule {
22
- return typeof value === "string" && FEED_SCHEDULE_SET.has(value);
23
- }
24
-
25
- /** Default cap on stored records per feed when `ingest.maxItems` is
26
- * omitted. Keeps high-volume feeds (news / podcasts) bounded. */
27
- export const DEFAULT_FEED_MAX_ITEMS = 100;
28
-
29
- /** Declarative field map: target collection field name → source path
30
- * into the raw item (dot/bracket path, e.g. `"title"` or
31
- * `"data.name"`). */
32
- export type IngestFieldMap = Record<string, string>;
33
-
34
- /** The `ingest` block carried on a Feed's `CollectionSchema`. The canonical
35
- * schema (in @mulmoclaude/collection-plugin) only promises the minimal
36
- * `CollectionIngest` (kind/url/schedule as plain strings); this feeds-only
37
- * subtype narrows those + adds the retrieval fields the engine needs. */
38
- export interface IngestSpec extends CollectionIngest {
39
- /** Which retriever handles this feed. */
40
- kind: IngestKind;
41
- /** Endpoint to fetch (http/https). */
42
- url: string;
43
- /** Refresh cadence. */
44
- schedule: FeedSchedule;
45
- /** `http-json` only: dot/bracket path to the array of items in the
46
- * response (e.g. `"hourly[]"` or `"data.results[]"`). Ignored for
47
- * `rss`/`atom`, which yield items natively. */
48
- itemsAt?: string;
49
- /** target field → source path. Projects each raw item into a record
50
- * whose keys match the schema's `fields`. */
51
- map: IngestFieldMap;
52
- /** Optional source path used to derive the primaryKey value when the
53
- * mapped record's primaryKey is empty (e.g. `"feedId"`). Falls back
54
- * to a content hash of the record. */
55
- idFrom?: string;
56
- /** Cap on stored records. After each fetch the feed keeps only the
57
- * newest `maxItems` (ordered by the schema's first `date` field) and
58
- * deletes the rest. Defaults to {@link DEFAULT_FEED_MAX_ITEMS} when
59
- * omitted; `0` disables the cap (keep everything). Pruning is skipped
60
- * when the schema has no `date` field to order by. */
61
- maxItems?: number;
62
- }
@@ -1,74 +0,0 @@
1
- // Tiny dot/bracket path resolver used by the declarative `ingest.map`
2
- // and `ingest.itemsAt`. Pure, no I/O, exhaustively unit-testable.
3
- //
4
- // Supported syntax:
5
- // "title" → root.title
6
- // "data.name" → root.data.name
7
- // "results[0].id" → root.results[0].id
8
- // "hourly[]" → root.hourly (trailing [] = "the array
9
- // here"; the marker is a no-op for value reads)
10
- // "data.results[]" → root.data.results
11
- //
12
- // Any miss (wrong type, out-of-range index, absent key) yields
13
- // `undefined` rather than throwing — declarative configs fail soft.
14
-
15
- interface KeyToken {
16
- kind: "key";
17
- key: string;
18
- }
19
- interface IndexToken {
20
- kind: "index";
21
- index: number;
22
- }
23
- type PathToken = KeyToken | IndexToken;
24
-
25
- const BRACKET_RE = /\[(\d*)\]/g;
26
-
27
- /** Split one dot-segment (`results[0]`, `hourly[]`, `name`) into tokens.
28
- * An empty `[]` is an array-identity marker and emits no token — the
29
- * array value is read by the preceding key. */
30
- function parseSegment(segment: string, tokens: PathToken[]): void {
31
- const bracketStart = segment.indexOf("[");
32
- const name = bracketStart === -1 ? segment : segment.slice(0, bracketStart);
33
- if (name.length > 0) tokens.push({ kind: "key", key: name });
34
- if (bracketStart === -1) return;
35
- for (const match of segment.slice(bracketStart).matchAll(BRACKET_RE)) {
36
- const [, inner] = match;
37
- if (inner.length > 0) tokens.push({ kind: "index", index: Number(inner) });
38
- }
39
- }
40
-
41
- function tokenize(path: string): PathToken[] {
42
- const tokens: PathToken[] = [];
43
- for (const segment of path.split(".")) {
44
- if (segment.length > 0) parseSegment(segment, tokens);
45
- }
46
- return tokens;
47
- }
48
-
49
- function step(current: unknown, token: PathToken): unknown {
50
- if (current === null || current === undefined) return undefined;
51
- if (token.kind === "key") {
52
- if (typeof current !== "object" || Array.isArray(current)) return undefined;
53
- return (current as Record<string, unknown>)[token.key];
54
- }
55
- return Array.isArray(current) ? current[token.index] : undefined;
56
- }
57
-
58
- /** Resolve a dot/bracket path against `root`, or `undefined` on any miss. */
59
- export function getByPath(root: unknown, path: string): unknown {
60
- let current: unknown = root;
61
- for (const token of tokenize(path)) {
62
- current = step(current, token);
63
- }
64
- return current;
65
- }
66
-
67
- /** Locate the array of raw items for a fetch. With `itemsAt` set, walk
68
- * to it; without it, the response itself must be the array. Non-arrays
69
- * yield `[]` so a malformed response is a no-op, not a crash. */
70
- export function getItemsArray(root: unknown, itemsAt: string | undefined): unknown[] {
71
- if (!itemsAt) return Array.isArray(root) ? root : [];
72
- const value = getByPath(root, itemsAt);
73
- return Array.isArray(value) ? value : [];
74
- }
@@ -1,30 +0,0 @@
1
- // Path helpers for the non-skill Feeds registry. Each feed lives at
2
- // `<workspace>/feeds/<slug>/schema.json` (a CollectionSchema + `ingest`
3
- // block) with its retrieval state alongside at
4
- // `<workspace>/feeds/<slug>/_state.json`. Records land wherever the
5
- // schema's `dataPath` points (validated by `resolveDataDir`), exactly
6
- // like every other collection.
7
- //
8
- // Slugs reaching these helpers must already have passed `safeSlugName`
9
- // (from `../collections/paths.js`) — these joins do not re-sanitize.
10
-
11
- import path from "node:path";
12
- import { workspacePath } from "../workspace.js";
13
-
14
- export const FEEDS_DIR = "feeds";
15
- export const FEED_STATE_FILE = "_state.json";
16
-
17
- /** Absolute path to the feeds registry root for a workspace. */
18
- export function feedsRoot(workspaceRoot: string = workspacePath): string {
19
- return path.join(workspaceRoot, FEEDS_DIR);
20
- }
21
-
22
- /** Absolute path to one feed's directory (`<root>/<slug>/`). */
23
- export function feedDir(slug: string, workspaceRoot: string = workspacePath): string {
24
- return path.join(feedsRoot(workspaceRoot), slug);
25
- }
26
-
27
- /** Absolute path to one feed's retrieval-state file. */
28
- export function feedStatePath(slug: string, workspaceRoot: string = workspacePath): string {
29
- return path.join(feedsRoot(workspaceRoot), slug, FEED_STATE_FILE);
30
- }
@@ -1,92 +0,0 @@
1
- // Project one raw retrieved item (a parsed RSS entry, or a JSON object)
2
- // into a CollectionItem whose keys match the schema's fields, using the
3
- // declarative `ingest.map`. Also derives the record's id.
4
- //
5
- // Id rule: a collection record's filename IS its primaryKey value, and
6
- // that value must be a safe slug. Feed-native keys (RSS guids/URLs,
7
- // ISO datetimes) usually are NOT slug-safe, so we slugify the natural
8
- // key into a deterministic, stable id — same natural key → same id, so
9
- // re-fetches upsert in place. The natural key comes from the mapped
10
- // primaryKey value, then `ingest.idFrom`, then a content hash.
11
-
12
- import { createHash } from "node:crypto";
13
- import { getByPath } from "./pathResolver.js";
14
- import type { CollectionItem, CollectionSchema } from "../collections/index.js";
15
- import type { IngestSpec } from "./ingestTypes.js";
16
-
17
- function asKeyString(value: unknown): string | null {
18
- if (typeof value === "string" && value.trim().length > 0) return value.trim();
19
- if (typeof value === "number" && Number.isFinite(value)) return String(value);
20
- return null;
21
- }
22
-
23
- /** Collapse an XML element object that carries body text alongside
24
- * attributes (`{ "#text": "v", "@_x": "..." }`) or CDATA to its text.
25
- * Generic — the host knows no field names, only this fast-xml-parser
26
- * shape — so a tag like `<guid isPermaLink="false">id</guid>` maps to
27
- * its text without the caller needing to write `.#text`. */
28
- function unwrapTextNode(value: unknown): unknown {
29
- if (value && typeof value === "object" && !Array.isArray(value)) {
30
- const obj = value as Record<string, unknown>;
31
- if (typeof obj["#text"] === "string") return obj["#text"];
32
- if (typeof obj["#cdata"] === "string") return obj["#cdata"];
33
- }
34
- return value;
35
- }
36
-
37
- /** Normalize a mapped value generically — driven by the SCHEMA's declared
38
- * field type, never by the source field name. Today: unwrap XML text
39
- * nodes, and coerce anything mapped into a `date` field to a `YYYY-MM-DD`
40
- * civil date (the collection `date` type + calendar are day-granularity
41
- * and parse strictly — a full RFC-3339 timestamp would be rejected). */
42
- function normalizeValue(value: unknown, fieldType: string | undefined): unknown {
43
- const unwrapped = unwrapTextNode(value);
44
- if (fieldType === "date" && typeof unwrapped === "string") {
45
- const millis = Date.parse(unwrapped);
46
- if (Number.isFinite(millis)) return new Date(millis).toISOString().slice(0, 10);
47
- }
48
- return unwrapped;
49
- }
50
-
51
- /** Slugify a natural key into a stable, filename-safe id. Short, safe
52
- * keys pass through (lowercased); long or unsafe keys collapse to a
53
- * hash so the filename stays bounded and valid. */
54
- function toSafeId(natural: string): string {
55
- const collapsed = natural
56
- .trim()
57
- .toLowerCase()
58
- .replace(/[^a-z0-9]+/g, "-");
59
- // eslint-disable-next-line sonarjs/slow-regex -- anchored hyphen trim, linear, no catastrophic backtracking
60
- const slug = collapsed.replace(/^-+|-+$/g, "");
61
- if (slug.length > 0 && slug.length <= 80) return slug;
62
- const hash = createHash("sha256")
63
- .update(natural || "item", "utf-8")
64
- .digest("hex")
65
- .slice(0, 16);
66
- return slug.length > 80 ? `${slug.slice(0, 60)}-${hash}` : `feed-${hash}`;
67
- }
68
-
69
- function naturalKey(record: CollectionItem, rawItem: unknown, ingest: IngestSpec, schema: CollectionSchema): string {
70
- const fromMapped = asKeyString(record[schema.primaryKey]);
71
- if (fromMapped) return fromMapped;
72
- if (ingest.idFrom) {
73
- const fromId = asKeyString(unwrapTextNode(getByPath(rawItem, ingest.idFrom)));
74
- if (fromId) return fromId;
75
- }
76
- return JSON.stringify(record);
77
- }
78
-
79
- /** Build a record from a raw fetched item (a parsed RSS/Atom element or a
80
- * JSON object) using `ingest.map`. Each source path is resolved against
81
- * the raw item and normalized per the target field's declared type. The
82
- * returned record's primaryKey is set to the derived safe id (so it
83
- * doubles as the filename). */
84
- export function projectRecord(rawItem: unknown, ingest: IngestSpec, schema: CollectionSchema): CollectionItem {
85
- const record: CollectionItem = {};
86
- for (const [targetField, sourcePath] of Object.entries(ingest.map)) {
87
- const value = normalizeValue(getByPath(rawItem, sourcePath), schema.fields?.[targetField]?.type);
88
- if (value !== undefined) record[targetField] = value;
89
- }
90
- record[schema.primaryKey] = toSafeId(naturalKey(record, rawItem, ingest, schema));
91
- return record;
92
- }
@@ -1,43 +0,0 @@
1
- // List the registered data-source feeds. Feeds are CREATED / REMOVED by
2
- // the agent writing / deleting `feeds/<slug>/schema.json` directly (see
3
- // config/helps/feeds.md) — the host only discovers + retrieves them.
4
- // icon / dataPath defaults for agent-authored feed schemas are applied in
5
- // `collections/discovery.ts` (source === "feed").
6
-
7
- import { rm } from "node:fs/promises";
8
- import { workspacePath } from "../workspace.js";
9
- import { log } from "../../system/logger/index.js";
10
- import { discoverCollections, type LoadedCollection } from "../collections/index.js";
11
- import { resolveDataDir, safeSlugName } from "@mulmoclaude/collection-plugin/server";
12
- import { feedDir } from "./paths.js";
13
-
14
- /** Every registered feed, as a discovered collection (carrying its
15
- * validated schema, `ingest`, and resolved `dataDir`). */
16
- export async function listFeeds(workspaceRoot: string = workspacePath): Promise<LoadedCollection[]> {
17
- const all = await discoverCollections({ workspaceRoot });
18
- return all.filter((collection) => collection.source === "feed");
19
- }
20
-
21
- /** Delete a feed entirely: its records AND its `feeds/<slug>/` directory
22
- * (schema + state). Idempotent. Host-side only (backs the UI delete
23
- * button); the agent removes a feed by deleting both directories itself.
24
- *
25
- * The records dir is derived from the SLUG (`data/feeds/<slug>`), never
26
- * from the schema's `dataPath` — feeds are forced into that namespace at
27
- * discovery, so a malformed/hostile `dataPath` can't redirect this delete
28
- * at another app's data (e.g. `data/wiki`). `resolveDataDir` also rejects
29
- * any path that escapes the workspace. */
30
- export async function removeFeed(workspaceRoot: string, slug: string): Promise<boolean> {
31
- const safe = safeSlugName(slug);
32
- if (safe === null) return false;
33
- const recordsDir = resolveDataDir(`data/feeds/${safe}`, workspaceRoot);
34
- try {
35
- if (recordsDir) await rm(recordsDir, { recursive: true, force: true });
36
- await rm(feedDir(safe, workspaceRoot), { recursive: true, force: true });
37
- log.info("feeds", "feed + records removed", { slug: safe });
38
- return true;
39
- } catch (error) {
40
- log.warn("feeds", "feed remove failed", { slug: safe, error: String(error) });
41
- return false;
42
- }
43
- }
@@ -1,19 +0,0 @@
1
- // Generic JSON-API retriever. Fetches JSON, walks `ingest.itemsAt` to
2
- // the array of raw items, and projects each through `ingest.map` (whose
3
- // source paths are dot/bracket paths into each raw item).
4
-
5
- import { fetchJson } from "../fetch/httpClient.js";
6
- import { getItemsArray } from "../pathResolver.js";
7
- import { projectRecord } from "../projectItem.js";
8
- import { registerRetriever, type RetrieveFn } from "./index.js";
9
-
10
- const retrieveHttpJson: RetrieveFn = async (ingest, schema) => {
11
- const json = await fetchJson(ingest.url);
12
- const rawItems = getItemsArray(json, ingest.itemsAt);
13
- const items = rawItems.map((raw) => projectRecord(raw, ingest, schema));
14
- return { items, cursor: {} };
15
- };
16
-
17
- registerRetriever("http-json", retrieveHttpJson);
18
-
19
- export { retrieveHttpJson };
@@ -1,27 +0,0 @@
1
- // Pluggable retriever registry. Each `ingest.kind` maps to one
2
- // RetrieveFn that fetches the endpoint and returns projected records.
3
- // Side-effect registration keeps the engine decoupled from the kinds.
4
- // New kinds (`code`, `prompt`) register here without touching the engine.
5
-
6
- import type { CollectionItem, CollectionSchema } from "../../collections/index.js";
7
- import type { IngestSpec } from "../ingestTypes.js";
8
- import type { FeedState } from "../state.js";
9
-
10
- export interface RetrieveResult {
11
- /** Projected records, keyed by primaryKey (the engine upserts them). */
12
- items: CollectionItem[];
13
- /** Updated retriever cursor to persist (incremental fetches). */
14
- cursor: Record<string, string>;
15
- }
16
-
17
- export type RetrieveFn = (ingest: IngestSpec, schema: CollectionSchema, state: FeedState) => Promise<RetrieveResult>;
18
-
19
- const registry = new Map<string, RetrieveFn>();
20
-
21
- export function registerRetriever(kind: string, retriever: RetrieveFn): void {
22
- registry.set(kind, retriever);
23
- }
24
-
25
- export function getRetriever(kind: string): RetrieveFn | undefined {
26
- return registry.get(kind);
27
- }
@@ -1,5 +0,0 @@
1
- // Side-effect import that registers every built-in retriever. Import
2
- // this once (the engine does) before dispatching on `ingest.kind`.
3
-
4
- import "./rss.js";
5
- import "./httpJson.js";
@@ -1,24 +0,0 @@
1
- // RSS / Atom retriever. Fetches the feed, parses it, and projects each
2
- // item's RAW parsed XML element through `ingest.map`. The map's source
3
- // paths are the item's own tags/attributes (e.g. `title`, `pubDate`,
4
- // `enclosure.@_url`, `itunes:duration`) — the host hard-codes no field
5
- // list; the caller inspects the feed and maps what it carries.
6
-
7
- import { fetchText } from "../fetch/httpClient.js";
8
- import { parseFeed } from "../fetch/rssParser.js";
9
- import { projectRecord } from "../projectItem.js";
10
- import { registerRetriever, type RetrieveFn } from "./index.js";
11
-
12
- const retrieveRss: RetrieveFn = async (ingest, schema) => {
13
- const body = await fetchText(ingest.url);
14
- const feed = parseFeed(body);
15
- if (!feed) return { items: [], cursor: {} };
16
- const items = feed.items.map((item) => projectRecord(item.raw, ingest, schema));
17
- return { items, cursor: {} };
18
- };
19
-
20
- // Atom shares the same parser + projection path.
21
- registerRetriever("rss", retrieveRss);
22
- registerRetriever("atom", retrieveRss);
23
-
24
- export { retrieveRss };
@@ -1,55 +0,0 @@
1
- // Per-feed retrieval state — when we last fetched, the retriever's
2
- // cursor (for incremental fetches), and a consecutive-failure counter.
3
- // NOT committed to git; lives at `<workspace>/feeds/<slug>/_state.json`.
4
- // Deliberately minimal: the legacy `sources` tree carries richer backoff
5
- // state, but the Feeds engine starts simple and grows on real need.
6
-
7
- import { mkdir, readFile } from "node:fs/promises";
8
- import { writeFileAtomic } from "../../utils/files/atomic.js";
9
- import { log } from "../../system/logger/index.js";
10
- import { feedDir, feedStatePath } from "./paths.js";
11
-
12
- export interface FeedState {
13
- slug: string;
14
- /** ISO timestamp of the last successful fetch, or null if never. */
15
- lastFetchedAt: string | null;
16
- /** Free-form retriever cursor (e.g. last-seen id / etag). */
17
- cursor: Record<string, string>;
18
- /** Consecutive failed fetches; reset to 0 on success. */
19
- consecutiveFailures: number;
20
- }
21
-
22
- export function defaultFeedState(slug: string): FeedState {
23
- return { slug, lastFetchedAt: null, cursor: {}, consecutiveFailures: 0 };
24
- }
25
-
26
- function normalizeState(slug: string, parsed: Partial<FeedState>): FeedState {
27
- const base = defaultFeedState(slug);
28
- const cursor = parsed.cursor && typeof parsed.cursor === "object" ? (parsed.cursor as Record<string, string>) : base.cursor;
29
- return {
30
- slug,
31
- lastFetchedAt: typeof parsed.lastFetchedAt === "string" ? parsed.lastFetchedAt : base.lastFetchedAt,
32
- cursor,
33
- consecutiveFailures: typeof parsed.consecutiveFailures === "number" ? parsed.consecutiveFailures : base.consecutiveFailures,
34
- };
35
- }
36
-
37
- /** Read a feed's state, tolerating a missing file (first run → default). */
38
- export async function readFeedState(workspaceRoot: string, slug: string): Promise<FeedState> {
39
- try {
40
- const raw = await readFile(feedStatePath(slug, workspaceRoot), "utf-8");
41
- return normalizeState(slug, JSON.parse(raw) as Partial<FeedState>);
42
- } catch (err) {
43
- const error = err as { code?: string };
44
- if (error.code !== "ENOENT") {
45
- log.warn("feeds", "failed to read feed state, using default", { slug, error: String(err) });
46
- }
47
- return defaultFeedState(slug);
48
- }
49
- }
50
-
51
- /** Persist a feed's state atomically (creating the feed dir if needed). */
52
- export async function writeFeedState(workspaceRoot: string, slug: string, state: FeedState): Promise<void> {
53
- await mkdir(feedDir(slug, workspaceRoot), { recursive: true });
54
- await writeFileAtomic(feedStatePath(slug, workspaceRoot), `${JSON.stringify(state, null, 2)}\n`);
55
- }
@@ -1,58 +0,0 @@
1
- // Subscribe to per-book accounting events.
2
- //
3
- // Returns a `version` ref that bumps every time the server publishes a
4
- // change for the given bookId — addEntries, voidEntry,
5
- // setOpeningBalances, upsertAccount, snapshot rebuild completion. View
6
- // components watch `version` to drive `refetch` calls.
7
- //
8
- // `bookId` is reactive: switching the active book in BookSwitcher
9
- // flips it; the composable unsubscribes from the old channel and
10
- // subscribes to the new one.
11
- //
12
- // `onPayload` is an optional fine-grained hook for callers that want to
13
- // inspect the event kind (e.g. show a "rebuilding…" indicator on
14
- // `kind: "snapshots-rebuilding"`).
15
-
16
- import { ref, watch, onUnmounted, type Ref } from "vue";
17
- import { usePubSub } from "./usePubSub";
18
- import { accountingBookChannel, PUBSUB_CHANNELS, type AccountingBookChannelPayload } from "../config/pubsubChannels";
19
-
20
- export interface UseAccountingChannelReturn {
21
- /** Bumps on every accountingBookChannel event for the current
22
- * bookId. Resets to 0 when bookId changes. */
23
- version: Ref<number>;
24
- }
25
-
26
- export function useAccountingChannel(bookId: Ref<string | null>, onPayload?: (payload: AccountingBookChannelPayload) => void): UseAccountingChannelReturn {
27
- const version = ref(0);
28
- const { subscribe } = usePubSub();
29
- let unsubscribe: (() => void) | null = null;
30
-
31
- function bind(nextBookId: string | null): void {
32
- unsubscribe?.();
33
- unsubscribe = null;
34
- version.value = 0;
35
- if (!nextBookId) return;
36
- unsubscribe = subscribe(accountingBookChannel(nextBookId), (data) => {
37
- const event = data as AccountingBookChannelPayload;
38
- version.value += 1;
39
- onPayload?.(event);
40
- });
41
- }
42
-
43
- watch(bookId, bind, { immediate: true });
44
- onUnmounted(() => {
45
- unsubscribe?.();
46
- unsubscribe = null;
47
- });
48
- return { version };
49
- }
50
-
51
- /** Subscribe to "the list of books changed" events. Use in
52
- * BookSwitcher.vue to refetch the dropdown contents when a sibling
53
- * tab adds / deletes a book. */
54
- export function useAccountingBooksChannel(onChange: () => void): void {
55
- const { subscribe } = usePubSub();
56
- const unsubscribe = subscribe(PUBSUB_CHANNELS.accountingBooks, onChange);
57
- onUnmounted(() => unsubscribe());
58
- }
@@ -1,108 +0,0 @@
1
- // Pure builder for the wiki page→page link graph. Used by:
2
- // - server/api/routes/wiki.ts — the `graph` action endpoint
3
- // - src/plugins/wiki/View.vue — backlinks ("linked references") +
4
- // the Graph tab
5
- //
6
- // All functions are pure string / collection ops; no `node:*` imports,
7
- // so the frontend bundle can import them directly (same discipline as
8
- // the sibling `link.ts` / `lint.ts` / `index-parse.ts` modules).
9
- //
10
- // NOTE: this is page→page link structure, distinct from the
11
- // `server/workspace/wiki-backlinks/` module, which appends *session*
12
- // backlinks (a page → the chat that edited it, #109). Different concept
13
- // — do not conflate.
14
-
15
- import { WIKI_LINK_PATTERN, parseWikiLink } from "./link.js";
16
- import { wikiSlugify } from "./slug.js";
17
- import type { WikiPageEntry } from "./index-parse.js";
18
-
19
- export interface WikiGraphNode {
20
- slug: string;
21
- title: string;
22
- }
23
-
24
- export interface WikiGraphEdge {
25
- from: string;
26
- to: string;
27
- }
28
-
29
- export interface WikiGraph {
30
- nodes: WikiGraphNode[];
31
- edges: WikiGraphEdge[];
32
- }
33
-
34
- /** One page's raw body plus its canonical (file-derived) slug. */
35
- export interface WikiPageContent {
36
- slug: string;
37
- content: string;
38
- }
39
-
40
- /** Resolve a raw `[[link]]` target to an existing page slug, or null.
41
- * Mirrors the route resolver's strategy: slugify first, then fall
42
- * back to matching an index entry title so non-ASCII targets like
43
- * `[[さくらインターネット]]` resolve to their ASCII file slug. */
44
- export function resolveLinkTarget(target: string, fileSlugs: ReadonlySet<string>, slugByTitle: ReadonlyMap<string, string>): string | null {
45
- const slug = wikiSlugify(target);
46
- if (slug.length > 0 && fileSlugs.has(slug)) return slug;
47
- const byTitle = slugByTitle.get(target.trim());
48
- if (byTitle !== undefined && fileSlugs.has(byTitle)) return byTitle;
49
- return null;
50
- }
51
-
52
- /** Resolved, deduped outgoing slugs for one page body. Self-links and
53
- * links to non-existent pages are dropped (the latter are already a
54
- * lint "broken link", not a graph edge). */
55
- export function pageOutgoingSlugs(fromSlug: string, content: string, fileSlugs: ReadonlySet<string>, slugByTitle: ReadonlyMap<string, string>): string[] {
56
- const out = new Set<string>();
57
- for (const match of content.matchAll(WIKI_LINK_PATTERN)) {
58
- const { target } = parseWikiLink(match[1]);
59
- const resolved = resolveLinkTarget(target, fileSlugs, slugByTitle);
60
- if (resolved !== null && resolved !== fromSlug) out.add(resolved);
61
- }
62
- return [...out];
63
- }
64
-
65
- function buildTitleMaps(entries: readonly WikiPageEntry[]): { titleBySlug: Map<string, string>; slugByTitle: Map<string, string> } {
66
- const titleBySlug = new Map<string, string>();
67
- const slugByTitle = new Map<string, string>();
68
- for (const entry of entries) {
69
- if (!titleBySlug.has(entry.slug)) titleBySlug.set(entry.slug, entry.title);
70
- if (entry.title.length > 0 && !slugByTitle.has(entry.title)) slugByTitle.set(entry.title, entry.slug);
71
- }
72
- return { titleBySlug, slugByTitle };
73
- }
74
-
75
- /** Build the full page→page graph. Nodes are the existing page files
76
- * (titled from index.md, falling back to the slug for un-indexed
77
- * pages); edges are the resolved `[[links]]`, deduped per (from,to). */
78
- export function buildWikiGraph(pages: readonly WikiPageContent[], entries: readonly WikiPageEntry[]): WikiGraph {
79
- const fileSlugs = new Set(pages.map((page) => page.slug));
80
- const { titleBySlug, slugByTitle } = buildTitleMaps(entries);
81
- const nodes: WikiGraphNode[] = pages.map((page) => ({ slug: page.slug, title: titleBySlug.get(page.slug) ?? page.slug }));
82
- const edges: WikiGraphEdge[] = [];
83
- const seen = new Set<string>();
84
- for (const page of pages) {
85
- for (const toSlug of pageOutgoingSlugs(page.slug, page.content, fileSlugs, slugByTitle)) {
86
- // Newline cannot appear in a wiki slug, so it is a safe pair key.
87
- const key = [page.slug, toSlug].join("\n");
88
- if (seen.has(key)) continue;
89
- seen.add(key);
90
- edges.push({ from: page.slug, to: toSlug });
91
- }
92
- }
93
- return { nodes, edges };
94
- }
95
-
96
- /** Pages that link TO `slug` (incoming edges), deduped, as nodes. */
97
- export function incomingLinks(graph: WikiGraph, slug: string): WikiGraphNode[] {
98
- const nodeBySlug = new Map(graph.nodes.map((node) => [node.slug, node]));
99
- const result: WikiGraphNode[] = [];
100
- const seen = new Set<string>();
101
- for (const edge of graph.edges) {
102
- if (edge.to !== slug || seen.has(edge.from)) continue;
103
- seen.add(edge.from);
104
- const node = nodeBySlug.get(edge.from);
105
- if (node) result.push(node);
106
- }
107
- return result;
108
- }