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,221 +0,0 @@
1
- // Pure parsers for `data/wiki/index.md` content. Used by:
2
- // - server/api/routes/wiki.ts — page resolver + lint
3
- // - frontend lint preview (future) — same parser, no fork
4
- //
5
- // All exports here are pure string ops; no `node:*` imports allowed.
6
- // If a future caller needs to walk the filesystem, that wrapper goes
7
- // in a sibling Node-only file (today nothing under `src/lib/wiki-page/`
8
- // touches disk except `paths.ts`).
9
-
10
- import { parseWikiLink } from "./link.js";
11
- import { wikiSlugify } from "./slug.js";
12
-
13
- export interface WikiPageEntry {
14
- title: string;
15
- slug: string;
16
- description: string;
17
- tags: string[];
18
- }
19
-
20
- // ── Patterns ──────────────────────────────────────────────────
21
- // Bullet patterns live here (not server/utils/regex.ts) because the
22
- // index parser is the only consumer and the regexes are part of the
23
- // public surface that callers may want to reason about in tests.
24
- // Linear in line length: every `[^x]+` runs over a fixed exclusion
25
- // set with a hard delimiter; the optional summary group's `(.*)` is
26
- // a single greedy run with no nested overlap.
27
-
28
- // eslint-disable-next-line security/detect-unsafe-regex -- bullet-link parser; bounded captures with hard delimiters
29
- export const BULLET_LINK_PATTERN = /^[-*]\s+\[([^\]]+)\]\(([^)]*)\)(?:\s*[—–-]\s*(.*))?/;
30
- // eslint-disable-next-line security/detect-unsafe-regex -- same shape as BULLET_LINK_PATTERN
31
- export const BULLET_WIKI_LINK_PATTERN = /^[-*]\s+\[\[([^\]]+)\]\](?:\s*[—–-]\s*(.*))?/;
32
-
33
- const TABLE_SEPARATOR_PATTERN = /^\|[\s|:-]+\|$/;
34
-
35
- // Unicode-aware tag body: any letter or number in any script (so
36
- // Japanese / Chinese / Korean tags like `#クラウド` or `#可視化` work),
37
- // plus `-` and `_` as internal joiners. First char is a letter or
38
- // number only — no leading punctuation.
39
- const HASHTAG_PATTERN = /(?:^|\s)#([\p{L}\p{N}][\p{L}\p{N}_-]*)/gu;
40
-
41
- // ── Tag extraction ────────────────────────────────────────────
42
-
43
- /** Extract `#tag` tokens from a bullet description, returning the
44
- * stripped description and a sorted, deduped, lowercased tag list.
45
- * Only matches at word boundaries so mid-word `#` (e.g. anchor
46
- * URLs) is left alone. */
47
- export function extractHashTags(text: string): { description: string; tags: string[] } {
48
- const tags: string[] = [];
49
- HASHTAG_PATTERN.lastIndex = 0;
50
- let match: RegExpExecArray | null;
51
- while ((match = HASHTAG_PATTERN.exec(text)) !== null) {
52
- tags.push(match[1].toLowerCase());
53
- }
54
- const description = text.replace(HASHTAG_PATTERN, "").replace(/\s+/g, " ").trim();
55
- const deduped = [...new Set(tags)].sort();
56
- return { description, tags: deduped };
57
- }
58
-
59
- /** Split a table Tags cell — tolerates comma, whitespace, or `#`
60
- * prefixes. Empty cell yields an empty list. */
61
- export function parseTagsCell(cell: string): string[] {
62
- const tokens = cell
63
- .split(/[,\s]+/)
64
- .map((token) => token.trim().replace(/^#/, "").toLowerCase())
65
- .filter((token) => token.length > 0);
66
- return [...new Set(tokens)].sort();
67
- }
68
-
69
- // ── Table parser ──────────────────────────────────────────────
70
-
71
- /** Map header cell names → column indices, case- and whitespace-
72
- * tolerant. Used by the row parser to locate the Tags column (and
73
- * any other named column) without assuming a fixed position, so
74
- * older 3- and 4-column tables keep working. */
75
- export function buildTableColumnMap(headerRow: string): Map<string, number> {
76
- const cells = headerRow
77
- .split("|")
78
- .slice(1, -1)
79
- // Mirror parseTableRow's cell-normalising: strip the surrounding
80
- // backticks that commonly wrap cell values in wiki tables.
81
- // Without this, a `| \`tags\` |` header maps to the key "`tags`"
82
- // and the subsequent `columnMap.get("tags")` lookup silently
83
- // misses the column, falling back to `tags: []`.
84
- .map((cell) => cell.trim().replace(/^`|`$/g, "").toLowerCase());
85
- const map = new Map<string, number>();
86
- cells.forEach((cell, i) => {
87
- if (cell) map.set(cell, i);
88
- });
89
- return map;
90
- }
91
-
92
- interface TableColumnIndices {
93
- slug: number;
94
- title: number;
95
- summary: number;
96
- /** Undefined when the table has no `tags` column — caller skips
97
- * the tags lookup entirely and the row gets `tags: []`. */
98
- tags: number | undefined;
99
- }
100
-
101
- /** Resolve the per-column indices the row parser needs. Falls back
102
- * to positional defaults (0/1/2) when the table has no header map.
103
- * "summary" is the canonical column name; "description" is accepted
104
- * as a legacy alias used by older fixtures. */
105
- function resolveTableColumnIndices(columnMap: Map<string, number> | null): TableColumnIndices {
106
- return {
107
- slug: columnMap?.get("slug") ?? 0,
108
- title: columnMap?.get("title") ?? 1,
109
- summary: columnMap?.get("summary") ?? columnMap?.get("description") ?? 2,
110
- tags: columnMap?.get("tags"),
111
- };
112
- }
113
-
114
- function parseTableRow(trimmed: string, columnMap: Map<string, number> | null): WikiPageEntry | null {
115
- const cols = trimmed
116
- .split("|")
117
- .slice(1, -1)
118
- .map((column) => column.trim().replace(/^`|`$/g, ""));
119
- if (cols.length < 2) return null;
120
-
121
- const idx = resolveTableColumnIndices(columnMap);
122
- const slug = cols[idx.slug] ?? "";
123
- const title = cols[idx.title] || slug;
124
- if (!slug || !title) return null;
125
-
126
- const description = cols[idx.summary] ?? "";
127
- const tags = idx.tags !== undefined ? parseTagsCell(cols[idx.tags] ?? "") : [];
128
- return { title, slug, description, tags };
129
- }
130
-
131
- // ── Bullet-row parsers ────────────────────────────────────────
132
-
133
- /** Extract the slug segment from a bullet link's href. Accepts the
134
- * canonical `pages/<slug>.md`, a bare `<slug>.md`, or just `<slug>`
135
- * — the three forms produced by different historical writers of
136
- * index.md. Returns "" for hrefs that don't look like a wiki page
137
- * reference (e.g. `https://example.com`) so the caller can fall
138
- * back to title-based slugification. */
139
- export function extractSlugFromBulletHref(rawHref: string): string {
140
- const href = rawHref.trim();
141
- if (!href) return "";
142
- if (/^[a-z]+:\/\//i.test(href)) return "";
143
- const lastSegment = href.split("/").pop() ?? href;
144
- return lastSegment.replace(/\.md$/i, "");
145
- }
146
-
147
- function parseBulletLinkRow(trimmed: string): WikiPageEntry | null {
148
- const match = BULLET_LINK_PATTERN.exec(trimmed);
149
- if (!match) return null;
150
- const title = match[1].trim();
151
- const href = match[2] ?? "";
152
- const raw = match[3]?.trim() ?? "";
153
- const { description, tags } = extractHashTags(raw);
154
- // Prefer the slug embedded in the href so non-ASCII titles keep
155
- // a navigable slug. Fall back to slugifying the title only when
156
- // the href has no recognisable slug (rare — usually means the
157
- // author put an external URL here).
158
- const slug = extractSlugFromBulletHref(href) || wikiSlugify(title);
159
- return { title, slug, description, tags };
160
- }
161
-
162
- function parseBulletWikiLinkRow(trimmed: string): WikiPageEntry | null {
163
- const match = BULLET_WIKI_LINK_PATTERN.exec(trimmed);
164
- if (!match) return null;
165
- // Split `[[target|display]]` so the bullet entry's slug derives
166
- // from the TARGET (which is already a slug-shaped identifier
167
- // when the author wrote the alias form) and the title shows
168
- // the DISPLAY half. Pre-#1297 the parser slugified the full
169
- // `target|display` body, which collapses `|` to "" and
170
- // produces a wrong slug — Codex review on PR #1312.
171
- const { target, display } = parseWikiLink(match[1]);
172
- const title = (display || target).trim();
173
- const slug = target ? wikiSlugify(target) : wikiSlugify(title);
174
- const raw = match[2]?.trim() ?? "";
175
- const { description, tags } = extractHashTags(raw);
176
- return { title, slug, description, tags };
177
- }
178
-
179
- // ── Top-level parser ──────────────────────────────────────────
180
-
181
- /** Parse entries from index.md. Supports three formats:
182
- * 1. Table: `| slug | Title | Summary | (Tags) |`
183
- * 2. Bullet link: `- [Title](pages/slug.md) — description`
184
- * 3. Wiki link: `- [[Title]] — description`
185
- *
186
- * Returns entries in source order. Any unrecognised line is
187
- * silently skipped — index.md is freeform markdown otherwise. */
188
- export function parseIndexEntries(content: string): WikiPageEntry[] {
189
- const entries: WikiPageEntry[] = [];
190
- let inTable = false;
191
- let columnMap: Map<string, number> | null = null;
192
-
193
- for (const line of content.split("\n")) {
194
- const trimmed = line.trim();
195
-
196
- if (trimmed.startsWith("|")) {
197
- if (TABLE_SEPARATOR_PATTERN.test(trimmed)) {
198
- inTable = true;
199
- continue;
200
- }
201
- if (!inTable) {
202
- // First `|`-line before the separator is the header. Capture
203
- // the column map so parseTableRow can locate the Tags
204
- // column (if any) by name rather than position.
205
- columnMap = buildTableColumnMap(trimmed);
206
- inTable = true;
207
- continue;
208
- }
209
- const entry = parseTableRow(trimmed, columnMap);
210
- if (entry) entries.push(entry);
211
- continue;
212
- }
213
-
214
- inTable = false;
215
- columnMap = null;
216
-
217
- const bullet = parseBulletLinkRow(trimmed) ?? parseBulletWikiLinkRow(trimmed);
218
- if (bullet) entries.push(bullet);
219
- }
220
- return entries;
221
- }
@@ -1,62 +0,0 @@
1
- // Pure helpers for `[[wiki-link]]` syntax. Used by the lint
2
- // (`server/api/routes/wiki.ts`), the page resolver, and the
3
- // frontend renderer (`src/plugins/wiki/helpers.ts`) — before this
4
- // module the three sites each had their own implementation and
5
- // none of them handled the `[[target|display]]` form, producing
6
- // false-positive "broken link" warnings on slug-aliased links
7
- // (issue #1297).
8
- //
9
- // All functions are pure string operations; safe to import from
10
- // browser bundles. No `node:*` imports anywhere in this file.
11
-
12
- /** Inline `[[...]]` link pattern. The capture group is the raw
13
- * text between the brackets — the caller is expected to feed it
14
- * through `parseWikiLink` to split off any `|display` suffix.
15
- *
16
- * Body length is capped at 200 chars to keep the regex linear:
17
- * catastrophic backtracking isn't possible (no nested
18
- * alternation), but a malicious page with thousands of
19
- * unmatched `[[` could still pin the CPU. 200 is well above the
20
- * longest legitimate title we've seen and matches the cap the
21
- * server-side `WIKI_LINK_PATTERN` constant has carried since the
22
- * original implementation in #951. */
23
- export const WIKI_LINK_PATTERN = /\[\[([^\][\r\n]{1,200})\]\]/g;
24
-
25
- /** The structural shape of an inline `[[target|display]]` link.
26
- * `target` is what the resolver / lint compares against page
27
- * slugs; `display` is what the renderer shows to the user.
28
- * When the user writes `[[foo]]` (no pipe), both fields hold
29
- * `foo`. */
30
- export interface WikiLink {
31
- target: string;
32
- display: string;
33
- }
34
-
35
- /** Split the raw text inside `[[...]]` into target + display.
36
- *
37
- * - `[[foo|Bar Baz]]` → `{ target: "foo", display: "Bar Baz" }`
38
- * - `[[foo]]` → `{ target: "foo", display: "foo" }`
39
- * - `[[|empty target]]` → `{ target: "", display: "empty target" }`
40
- * (caller decides whether an empty target is meaningful;
41
- * typically lint flags it, renderer shows the display text raw)
42
- * - `[[foo|]]` → `{ target: "foo", display: "" }`
43
- * (same — caller decides)
44
- *
45
- * Whitespace around the pipe is preserved on the display side
46
- * (so the user can write `[[foo| ある記事 ]]` and get the
47
- * spacing intentionally) but TRIMMED on the target side, since
48
- * a slug-comparable target with leading/trailing whitespace is
49
- * always a typo.
50
- *
51
- * Only the FIRST pipe splits. `[[a|b|c]]` becomes
52
- * `{ target: "a", display: "b|c" }` so display strings can
53
- * legitimately contain a literal `|`. */
54
- export function parseWikiLink(inner: string): WikiLink {
55
- const pipeIdx = inner.indexOf("|");
56
- if (pipeIdx === -1) {
57
- return { target: inner, display: inner };
58
- }
59
- const target = inner.slice(0, pipeIdx).trim();
60
- const display = inner.slice(pipeIdx + 1);
61
- return { target, display };
62
- }
@@ -1,105 +0,0 @@
1
- // Pure wiki lint rules.
2
- //
3
- // Each rule takes plain inputs (Sets, page-entry arrays, raw file
4
- // contents) so the whole pipeline can be unit-tested without
5
- // filesystem fixtures. The Express route at
6
- // `server/api/routes/wiki.ts` is a thin shell that reads the disk,
7
- // calls these rules, formats the result. A future frontend "lint
8
- // preview before save" would call the same functions over an
9
- // in-memory snapshot.
10
-
11
- import type { WikiPageEntry } from "./index-parse.js";
12
- import { WIKI_LINK_PATTERN, parseWikiLink } from "./link.js";
13
- import { wikiSlugify } from "./slug.js";
14
-
15
- /** Files on disk that aren't referenced by index.md. */
16
- export function findOrphanPages(fileSlugs: ReadonlySet<string>, indexedSlugs: ReadonlySet<string>): string[] {
17
- const issues: string[] = [];
18
- for (const slug of fileSlugs) {
19
- if (!indexedSlugs.has(slug)) {
20
- issues.push(`- **Orphan page**: \`${slug}.md\` exists but is missing from index.md`);
21
- }
22
- }
23
- return issues;
24
- }
25
-
26
- /** Slugs referenced by index.md that have no corresponding file. */
27
- export function findMissingFiles(pageEntries: readonly WikiPageEntry[], fileSlugs: ReadonlySet<string>): string[] {
28
- const issues: string[] = [];
29
- for (const entry of pageEntries) {
30
- if (!fileSlugs.has(entry.slug)) {
31
- issues.push(`- **Missing file**: index.md references \`${entry.slug}\` but the file does not exist`);
32
- }
33
- }
34
- return issues;
35
- }
36
-
37
- /** Walk a page's body for `[[…]]` links and flag any whose
38
- * resolved slug doesn't exist in the file set.
39
- *
40
- * Critically: this routes through `parseWikiLink` so
41
- * `[[slug|display]]` is split correctly — the lint slugifies the
42
- * TARGET, not the full bracket body. Pre-#1297 the lint
43
- * slugified the entire content (`slug|display`), which collapsed
44
- * to a slug that always missed and produced ~168 false-positive
45
- * "broken link" warnings. */
46
- export function findBrokenLinksInPage(fileName: string, content: string, fileSlugs: ReadonlySet<string>): string[] {
47
- const issues: string[] = [];
48
- const matches = [...content.matchAll(WIKI_LINK_PATTERN)];
49
- for (const match of matches) {
50
- const { target } = parseWikiLink(match[1]);
51
- const linkSlug = wikiSlugify(target);
52
- // Empty target is its own diagnostic — `[[|display]]` or
53
- // `[[]]` slugifies to "" and would otherwise be flagged
54
- // identically to a real broken link. Keep the original raw
55
- // bracket body in the report so the user can grep their pages
56
- // for the malformed link.
57
- if (linkSlug.length === 0) {
58
- issues.push(`- **Broken link** in \`${fileName}\`: [[${match[1]}]] → empty target`);
59
- continue;
60
- }
61
- if (!fileSlugs.has(linkSlug)) {
62
- issues.push(`- **Broken link** in \`${fileName}\`: [[${match[1]}]] → \`${linkSlug}.md\` not found`);
63
- }
64
- }
65
- return issues;
66
- }
67
-
68
- function formatTagList(tags: readonly string[]): string {
69
- return `[${[...tags].sort().join(", ")}]`;
70
- }
71
-
72
- /** Flag any slug whose index.md tags differ from the page's own
73
- * frontmatter `tags:` field. Comparison is set-based and order-
74
- * insensitive; both sides are lowercased at parse time. Slugs
75
- * missing from `frontmatterTagsBySlug` are ignored here — the
76
- * missing file itself is already reported by `findMissingFiles`. */
77
- export function findTagDrift(pageEntries: readonly WikiPageEntry[], frontmatterTagsBySlug: ReadonlyMap<string, readonly string[]>): string[] {
78
- const issues: string[] = [];
79
- for (const entry of pageEntries) {
80
- // Lowercase on lookup — the caller keys the map with
81
- // lowercased slugs, so a `MyPage.md` filename still matches
82
- // an `entry.slug` of `mypage` produced by `wikiSlugify` on the
83
- // wiki-link parser path.
84
- const pageTags = frontmatterTagsBySlug.get(entry.slug.toLowerCase());
85
- if (pageTags === undefined) continue;
86
- const pageSet = new Set(pageTags);
87
- const indexSet = new Set(entry.tags);
88
- if (pageSet.size !== indexSet.size || [...pageSet].some((tag) => !indexSet.has(tag))) {
89
- issues.push(`- **Tag drift**: \`${entry.slug}.md\` frontmatter has ${formatTagList(pageTags)} but index.md has ${formatTagList(entry.tags)}`);
90
- }
91
- }
92
- return issues;
93
- }
94
-
95
- /** Render the final markdown report from the accumulated issues
96
- * list. Empty input yields the "wiki is healthy" sentinel so the
97
- * caller can write the same file every time without branching on
98
- * presence. */
99
- export function formatLintReport(issues: readonly string[]): string {
100
- if (issues.length === 0) {
101
- return "# Wiki Lint Report\n\n✓ No issues found. Wiki is healthy.";
102
- }
103
- const noun = `issue${issues.length !== 1 ? "s" : ""}`;
104
- return `# Wiki Lint Report\n\n${issues.length} ${noun} found:\n\n${issues.join("\n")}`;
105
- }
@@ -1,35 +0,0 @@
1
- // Node-only wiki-page helpers — anything that needs `node:path`
2
- // lives here so the rest of `src/lib/wiki-page/` stays pure
3
- // (string-only, importable from both browser and Node bundles).
4
- // Frontend code MUST NOT import this file directly; use the pure
5
- // modules instead.
6
-
7
- import path from "node:path";
8
- import { isSafeSlug } from "./slug.js";
9
-
10
- /** Given an absolute path and the absolute `pagesDir`, return the
11
- * slug if `absPath` is a direct `.md` child of `pagesDir`, else
12
- * null. Pure path-string math — no fs IO, no symlink resolution.
13
- *
14
- * Caller responsibility: pass already-realpath'd values for both
15
- * arguments. Mixing a realpath'd `absPath` with a symlinked
16
- * `pagesDir` (or vice versa) silently mismatches because
17
- * `path.relative` is plain string arithmetic. The trap caused
18
- * #883 review-iter-1 — a symlinked workspace silently routed
19
- * wiki writes through the generic writer. */
20
- export function wikiSlugFromAbsPath(absPath: string, pagesDir: string): string | null {
21
- const rel = path.relative(pagesDir, absPath);
22
- if (rel.length === 0) return null;
23
- if (path.isAbsolute(rel)) return null;
24
- // Direct child only — no nested layout today. Any separator
25
- // means the path either escapes (`../secret.md`) or descends
26
- // (`subdir/foo.md`). A literal page name like `..foo.md` is a
27
- // single segment without a separator and is allowed (codex
28
- // iter-3 #883 — the prior `startsWith("..")` rule wrongly
29
- // rejected it).
30
- if (rel.includes(path.sep)) return null;
31
- if (!rel.endsWith(".md")) return null;
32
- const slug = rel.slice(0, -".md".length);
33
- if (!isSafeSlug(slug)) return null;
34
- return slug;
35
- }
@@ -1,54 +0,0 @@
1
- // Pure wiki-page slug helpers — string-only, no Node / browser
2
- // dependencies, importable from any bundle.
3
- //
4
- // Used by:
5
- // - server/workspace/wiki-pages/io.ts (the write chokepoint)
6
- // - server/workspace/hooks/handlers/wikiSnapshot.ts (the
7
- // PostToolUse handler that fires on Write/Edit of a wiki page)
8
- // - server/api/routes/wiki.ts (page resolver + lint)
9
- // - server/api/routes/wiki/history.ts (history slug guard)
10
- // - src/plugins/wiki/route.ts (router slug guard — replaces the
11
- // local `isSafeWikiSlug` duplicate that existed before the
12
- // pure-lib refactor)
13
- // - src/plugins/wiki/helpers.ts (renderer slugify for [[…]] links)
14
- //
15
- // Any helper that needs `node:path` lives in `./paths.ts` so that
16
- // importing this file from frontend code never pulls in Node
17
- // builtins.
18
-
19
- /** Reject slugs that would escape `data/wiki/pages/` once
20
- * joined back into a path, or that are otherwise invalid as
21
- * page filenames. The chokepoint must defend itself even when
22
- * callers derive the slug from a trusted source — a typo or
23
- * future caller mistake should fail loud, not silently write
24
- * outside the wiki tree.
25
- *
26
- * The rule is intentionally narrow — separators / `..` / NUL /
27
- * empty — so it only rejects unambiguous violations. Aesthetic
28
- * concerns (e.g. dot-prefixed filenames) are out of scope: a
29
- * pre-existing `data/wiki/pages/.foo.md` should remain writable
30
- * through the chokepoint (codex review iter-2 #883). */
31
- export function isSafeSlug(slug: string): boolean {
32
- if (slug.length === 0) return false;
33
- if (slug === "." || slug === "..") return false;
34
- if (slug.includes("/") || slug.includes("\\")) return false;
35
- if (slug.includes("\0")) return false;
36
- return true;
37
- }
38
-
39
- /** Slug rules for `[[wiki link]]` text → slug derivation:
40
- * lowercase, spaces collapsed to hyphens, every non-ASCII /
41
- * non-alphanumeric / non-hyphen character stripped.
42
- *
43
- * Pure: no normalisation, no transliteration — this is the
44
- * same shape the index parser, page resolver, and frontend
45
- * renderer all need to agree on. Non-ASCII titles (e.g.
46
- * Japanese) collapse to an empty string here; callers fall back
47
- * to other strategies (title-match in the index, or the agent
48
- * pre-resolving to a slug-form target via `[[slug|display]]`). */
49
- export function wikiSlugify(text: string): string {
50
- return text
51
- .toLowerCase()
52
- .replace(/\s+/g, "-")
53
- .replace(/[^a-z0-9-]/g, "");
54
- }
@@ -1,103 +0,0 @@
1
- <template>
2
- <!-- Compact inline summary for non-openBook tool results. The
3
- openBook envelope routes to View.vue (full app) instead of
4
- this component; everything that lands here is a
5
- compact-result action (addEntries, getReport, …). -->
6
- <div class="text-sm text-gray-700" data-testid="accounting-preview">
7
- <span class="material-icons text-base align-middle mr-1">account_balance</span>
8
- <span>{{ summary }}</span>
9
- </div>
10
- </template>
11
-
12
- <script setup lang="ts">
13
- import { computed } from "vue";
14
- import { useI18n } from "vue-i18n";
15
- import { formatAmountNumeric } from "./currencies";
16
-
17
- const { t } = useI18n();
18
-
19
- const props = defineProps<{ data?: unknown; jsonData?: Record<string, unknown> }>();
20
-
21
- interface BalanceSheetSection {
22
- type: string;
23
- total?: number;
24
- }
25
- interface BalanceSheetLike {
26
- balanceSheet?: { asOf?: string; sections?: BalanceSheetSection[]; imbalance?: number };
27
- }
28
- interface ProfitLossLike {
29
- profitLoss?: { from?: string; to?: string; netIncome?: number };
30
- }
31
- interface EntriesLike {
32
- entries?: { id?: string; date?: string }[];
33
- }
34
- interface BookLike {
35
- book?: { id?: string; name?: string };
36
- }
37
-
38
- // Each summarise* helper returns null when its branch doesn't apply,
39
- // keeping the dispatch in `summary` linear (no nested if-trees).
40
-
41
- function summariseError(json: Record<string, unknown>): string | null {
42
- const { error } = json as { error?: unknown };
43
- if (typeof error !== "string") return null;
44
- return t("pluginAccounting.previewError", { error });
45
- }
46
-
47
- function summariseEntry(json: Record<string, unknown>): string | null {
48
- // addEntries returns `{ entries: [...] }`. The compact preview
49
- // card shows one date — use the first entry's so single-entry
50
- // batches (the common case from the manual UI) read naturally
51
- // and multi-entry batches still anchor to a meaningful date.
52
- const { entries } = json as EntriesLike;
53
- if (!Array.isArray(entries) || entries.length === 0) return null;
54
- const [first] = entries;
55
- if (!first?.id || !first?.date) return null;
56
- return t("pluginAccounting.preview.entry", { date: first.date });
57
- }
58
-
59
- function summarisePl(json: Record<string, unknown>): string | null {
60
- const { profitLoss } = json as ProfitLossLike;
61
- if (!profitLoss || typeof profitLoss.netIncome !== "number") return null;
62
- return t("pluginAccounting.preview.pl", {
63
- from: profitLoss.from ?? "?",
64
- to: profitLoss.to ?? "?",
65
- net: formatAmountNumeric(profitLoss.netIncome),
66
- });
67
- }
68
-
69
- function summariseBs(json: Record<string, unknown>): string | null {
70
- const { balanceSheet } = json as BalanceSheetLike;
71
- if (!balanceSheet?.asOf || !balanceSheet.sections) return null;
72
- const assets = balanceSheet.sections.find((section) => section.type === "asset");
73
- return t("pluginAccounting.preview.bs", {
74
- date: balanceSheet.asOf,
75
- assets: assets ? formatAmountNumeric(assets.total ?? 0) : "?",
76
- });
77
- }
78
-
79
- function summariseBook(json: Record<string, unknown>): string | null {
80
- const { book } = json as BookLike;
81
- if (!book?.id || !book?.name) return null;
82
- return t("pluginAccounting.preview.bookCreated", { name: book.name, id: book.id });
83
- }
84
-
85
- function summariseFallback(json: Record<string, unknown>): string {
86
- const { bookId } = json as { bookId?: unknown };
87
- if (typeof bookId === "string") return t("pluginAccounting.previewSummary", { bookId });
88
- return t("pluginAccounting.previewGeneric");
89
- }
90
-
91
- function asObject(value: unknown): Record<string, unknown> {
92
- // Some renderers pass the structured payload via `data`, others
93
- // via `jsonData`. Accept either so a tool-result like
94
- // `{ entry: ... }` resolves to the right summariser regardless
95
- // of which prop the host harness picks.
96
- return value && typeof value === "object" ? (value as Record<string, unknown>) : {};
97
- }
98
-
99
- const summary = computed<string>(() => {
100
- const json = { ...asObject(props.data), ...asObject(props.jsonData) };
101
- return summariseError(json) ?? summariseEntry(json) ?? summarisePl(json) ?? summariseBs(json) ?? summariseBook(json) ?? summariseFallback(json);
102
- });
103
- </script>