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,102 +0,0 @@
1
- <template>
2
- <!-- Full-tab chart-of-accounts list. Distinct from AccountsModal
3
- (called from the entry / opening forms): this one fills the
4
- canvas, surfaces a single "Manage accounts" button at the top,
5
- and emits `selectAccount` so the parent View can route the
6
- click into the Ledger tab pre-filtered to that account. -->
7
- <div class="flex flex-col gap-3" data-testid="accounting-accounts-list">
8
- <div class="flex flex-wrap items-center justify-end gap-2">
9
- <button
10
- type="button"
11
- class="h-8 px-2.5 flex items-center gap-1 rounded border border-gray-300 text-sm text-gray-600 hover:bg-gray-50"
12
- data-testid="accounting-accounts-manage"
13
- @click="showManageModal = true"
14
- >
15
- <span class="material-icons text-base">tune</span>
16
- <span>{{ t("pluginAccounting.accounts.manageButton") }}</span>
17
- </button>
18
- </div>
19
- <section v-for="group in groups" :key="group.type" class="flex flex-col gap-1">
20
- <h4 class="text-xs font-semibold text-gray-500 uppercase tracking-wide">{{ t(`pluginAccounting.accounts.sectionTitle.${group.type}`) }}</h4>
21
- <p v-if="group.accounts.length === 0" class="text-xs text-gray-400 italic px-1">{{ t("pluginAccounting.accounts.listEmpty") }}</p>
22
- <ul v-else class="flex flex-col">
23
- <li
24
- v-for="account in group.accounts"
25
- :key="account.code"
26
- tabindex="0"
27
- role="button"
28
- :aria-label="t('pluginAccounting.accounts.openLedgerAria', { code: account.code, name: account.name })"
29
- class="flex items-center gap-3 px-2 py-1.5 border-b border-gray-100 hover:bg-blue-50 cursor-pointer text-gray-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-400 rounded"
30
- :data-testid="`accounting-account-row-${account.code}`"
31
- @click="onSelect(account)"
32
- @keydown.enter.prevent.self="onKeyActivate($event, account)"
33
- @keydown.space.prevent.self="onKeyActivate($event, account)"
34
- >
35
- <span class="font-mono text-xs w-16 shrink-0">{{ account.code }}</span>
36
- <span class="text-sm flex-1 min-w-0 truncate">{{ account.name }}</span>
37
- </li>
38
- </ul>
39
- </section>
40
- <AccountsModal v-if="showManageModal" :book-id="bookId" :accounts="accounts" @close="showManageModal = false" @changed="onAccountsChanged" />
41
- </div>
42
- </template>
43
-
44
- <script setup lang="ts">
45
- import { computed, ref } from "vue";
46
- import { useI18n } from "vue-i18n";
47
- import type { Account, AccountType } from "../api";
48
- import AccountsModal from "./AccountsModal.vue";
49
-
50
- const { t } = useI18n();
51
-
52
- const props = defineProps<{ bookId: string; accounts: Account[] }>();
53
- const emit = defineEmits<{ selectAccount: [code: string]; changed: [] }>();
54
-
55
- const ACCOUNT_TYPES: readonly AccountType[] = ["asset", "liability", "equity", "income", "expense"];
56
-
57
- const showManageModal = ref(false);
58
-
59
- interface AccountGroup {
60
- type: AccountType;
61
- accounts: Account[];
62
- }
63
-
64
- function byCode(left: Account, right: Account): number {
65
- return left.code.localeCompare(right.code);
66
- }
67
-
68
- // Soft-deleted accounts (active === false) are hidden — managing
69
- // them lives in the Manage Accounts modal, where Reactivate is one
70
- // click away.
71
- const groups = computed<AccountGroup[]>(() =>
72
- ACCOUNT_TYPES.map((type) => ({
73
- type,
74
- accounts: props.accounts
75
- .filter((account) => account.type === type && account.active !== false)
76
- .slice()
77
- .sort(byCode),
78
- })),
79
- );
80
-
81
- function onSelect(account: Account): void {
82
- emit("selectAccount", account.code);
83
- }
84
-
85
- // Keyboard activation: Enter / Space on a focused row. The
86
- // `.prevent.self` modifiers in the template stop the default scroll
87
- // (Space) and ensure we don't fire when the event bubbles up from
88
- // a focused descendant (currently none, but defensive for future
89
- // row content).
90
- function onKeyActivate(event: KeyboardEvent, account: Account): void {
91
- if (event.repeat) return;
92
- emit("selectAccount", account.code);
93
- }
94
-
95
- function onAccountsChanged(): void {
96
- // Forward to the parent — `bookVersion` already drives the
97
- // accounts refetch in View.vue, so the list updates without us
98
- // doing anything extra. Bubble the event in case a future
99
- // consumer needs it.
100
- emit("changed");
101
- }
102
- </script>
@@ -1,301 +0,0 @@
1
- <template>
2
- <!-- Manage-accounts modal. Opened from JournalEntryForm and
3
- OpeningBalancesForm. Lists the current chart of accounts
4
- grouped by type, with inline add / edit. Stays open across
5
- saves so the user can fix several accounts in a row. -->
6
- <div
7
- class="fixed inset-0 z-50 bg-black/20 flex items-center justify-center"
8
- role="dialog"
9
- aria-modal="true"
10
- aria-labelledby="accounting-accounts-modal-title"
11
- data-testid="accounting-accounts-modal"
12
- @click.self="onBackdropClick"
13
- @keydown.esc="emit('close')"
14
- >
15
- <div class="bg-white rounded shadow-lg w-[32rem] max-h-[80vh] flex flex-col">
16
- <header class="flex items-center justify-between px-4 py-2 border-b border-gray-200 shrink-0">
17
- <h3 id="accounting-accounts-modal-title" class="text-base font-semibold">{{ t("pluginAccounting.accounts.modalTitle") }}</h3>
18
- <button
19
- ref="closeButton"
20
- type="button"
21
- class="h-8 w-8 flex items-center justify-center rounded text-gray-500 hover:bg-gray-100"
22
- data-testid="accounting-accounts-close"
23
- :aria-label="t('pluginAccounting.common.cancel')"
24
- @click="emit('close')"
25
- >
26
- <span class="material-icons text-base">close</span>
27
- </button>
28
- </header>
29
- <div class="flex-1 overflow-auto px-4 py-3 flex flex-col gap-3">
30
- <p v-if="successMessage" class="text-xs text-green-600" data-testid="accounting-accounts-success">{{ successMessage }}</p>
31
- <p v-if="toggleError" class="text-xs text-red-500" data-testid="accounting-accounts-toggle-error">{{ toggleError }}</p>
32
- <section v-for="group in groups" :key="group.type" class="flex flex-col gap-1">
33
- <h4 class="text-xs font-semibold text-gray-500 uppercase tracking-wide">{{ t(`pluginAccounting.accounts.sectionTitle.${group.type}`) }}</h4>
34
- <div v-if="group.accounts.length === 0" class="text-xs text-gray-400 italic px-1">{{ t("pluginAccounting.common.empty") }}</div>
35
- <template v-for="account in group.accounts" :key="account.code">
36
- <AccountRow v-if="editingCode !== account.code" :account="account" @edit="onEdit(account)" @toggle-active="onToggleActive(account)" />
37
- <AccountEditor
38
- v-else
39
- :draft="draft"
40
- :is-new="false"
41
- :busy="saving"
42
- :error="error"
43
- :existing-accounts="accounts"
44
- @save="onSave"
45
- @cancel="onCancelEditor"
46
- />
47
- </template>
48
- <div v-if="addingNew && draft.type === group.type" :ref="(node) => bindNewEditor(node, group.type)">
49
- <AccountEditor :draft="draft" is-new :busy="saving" :error="error" :existing-accounts="accounts" @save="onSave" @cancel="onCancelEditor" />
50
- </div>
51
- <button
52
- v-else
53
- type="button"
54
- class="self-start h-8 px-2.5 flex items-center gap-1 rounded text-xs text-gray-600 hover:bg-gray-100"
55
- :data-testid="`accounting-accounts-add-${group.type}`"
56
- @click="onAdd(group.type)"
57
- >
58
- <span class="material-icons text-sm">add</span>
59
- <span>{{ t("pluginAccounting.accounts.addToCategory", { type: t(`pluginAccounting.accounts.typeOption.${group.type}`) }) }}</span>
60
- </button>
61
- </section>
62
- </div>
63
- </div>
64
- </div>
65
- </template>
66
-
67
- <script setup lang="ts">
68
- import { computed, nextTick, onMounted, onUnmounted, ref } from "vue";
69
- import { useI18n } from "vue-i18n";
70
- import { upsertAccount, type Account, type AccountType } from "../api";
71
- import AccountRow from "./AccountRow.vue";
72
- import AccountEditor from "./AccountEditor.vue";
73
- import type { AccountDraft } from "./accountDraft";
74
- import { validateAccountDraft, type AccountValidationError } from "./accountValidation";
75
- import { suggestNextCode } from "./accountNumbering";
76
- import { errorMessage } from "../../../utils/errors";
77
-
78
- const { t } = useI18n();
79
-
80
- const props = defineProps<{ bookId: string; accounts: Account[] }>();
81
- const emit = defineEmits<{ close: []; changed: [] }>();
82
-
83
- // Order matches conventional financial-statement layout (B/S then
84
- // P/L). Section titles are pulled from i18n via the literal type
85
- // keys, so this array drives both ordering and visibility.
86
- const ACCOUNT_TYPES: readonly AccountType[] = ["asset", "liability", "equity", "income", "expense"];
87
- const SUCCESS_FADE_MS = 2500;
88
-
89
- const VALIDATION_MESSAGE_KEYS: Record<AccountValidationError, string> = {
90
- emptyCode: "pluginAccounting.accounts.errorEmptyCode",
91
- reservedCode: "pluginAccounting.accounts.errorReservedCode",
92
- invalidCodeFormat: "pluginAccounting.accounts.errorInvalidCodeFormat",
93
- codeTypeMismatch: "pluginAccounting.accounts.errorCodeTypeMismatch",
94
- emptyName: "pluginAccounting.accounts.errorEmptyName",
95
- duplicateCode: "pluginAccounting.accounts.errorDuplicateCode",
96
- duplicateName: "pluginAccounting.accounts.errorDuplicateName",
97
- };
98
-
99
- interface AccountGroup {
100
- type: AccountType;
101
- accounts: Account[];
102
- }
103
-
104
- const groups = computed<AccountGroup[]>(() =>
105
- ACCOUNT_TYPES.map((type) => ({
106
- type,
107
- accounts: props.accounts
108
- .filter((account) => account.type === type)
109
- .slice()
110
- .sort(byCode),
111
- })),
112
- );
113
-
114
- function byCode(left: Account, right: Account): number {
115
- return left.code.localeCompare(right.code);
116
- }
117
-
118
- const editingCode = ref<string | null>(null);
119
- const addingNew = ref(false);
120
- const draft = ref<AccountDraft>(emptyDraft("asset"));
121
- const saving = ref(false);
122
- const error = ref<string | null>(null);
123
- // Toggle (Deactivate / Reactivate) keeps its own state. Sharing
124
- // `saving` / `error` with the editor would (a) hide a toggle
125
- // failure when no editor is mounted to render `:error`, and (b)
126
- // blank out an in-progress editor's validation message and
127
- // freeze its Save button when the user fires a toggle on a
128
- // different row.
129
- const toggleSaving = ref(false);
130
- const toggleError = ref<string | null>(null);
131
- const successMessage = ref<string | null>(null);
132
- const closeButton = ref<HTMLButtonElement | null>(null);
133
- const newEditorWrapper = ref<HTMLDivElement | null>(null);
134
- let successTimer: ReturnType<typeof setTimeout> | null = null;
135
-
136
- function emptyDraft(type: AccountType): AccountDraft {
137
- return { code: "", name: "", type, note: "" };
138
- }
139
-
140
- function draftForNew(type: AccountType): AccountDraft {
141
- return { code: suggestNextCode(type, props.accounts), name: "", type, note: "" };
142
- }
143
-
144
- // Vue's `:ref` on a v-for-style element gives us back either the
145
- // node or null (on unmount). We only want to capture the editor
146
- // belonging to the section that owns the current draft, so the
147
- // section type is checked here rather than relying on the order
148
- // in which Vue invokes the function refs.
149
- function bindNewEditor(node: Element | object | null, sectionType: AccountType): void {
150
- if (sectionType !== draft.value.type) return;
151
- newEditorWrapper.value = (node as HTMLDivElement | null) ?? null;
152
- }
153
-
154
- function onEdit(account: Account): void {
155
- // Collapse any other editor first so only one is open at a time.
156
- addingNew.value = false;
157
- error.value = null;
158
- draft.value = { code: account.code, name: account.name, type: account.type, note: account.note ?? "" };
159
- editingCode.value = account.code;
160
- }
161
-
162
- function onAdd(type: AccountType): void {
163
- editingCode.value = null;
164
- error.value = null;
165
- draft.value = draftForNew(type);
166
- addingNew.value = true;
167
- // Scroll the new in-place editor into view in case the section
168
- // sits below the visible viewport — opening the editor without
169
- // scrolling would leave the user staring at unchanged content
170
- // above the fold.
171
- void nextTick(() => {
172
- newEditorWrapper.value?.scrollIntoView({ behavior: "smooth", block: "nearest" });
173
- });
174
- }
175
-
176
- function onCancelEditor(): void {
177
- editingCode.value = null;
178
- addingNew.value = false;
179
- error.value = null;
180
- draft.value = emptyDraft("asset");
181
- }
182
-
183
- function validateDraft(next: AccountDraft, isNew: boolean): string | null {
184
- const code = validateAccountDraft(next, props.accounts, isNew);
185
- return code === null ? null : t(VALIDATION_MESSAGE_KEYS[code]);
186
- }
187
-
188
- async function onSave(next: AccountDraft): Promise<void> {
189
- if (saving.value) return;
190
- const isNew = addingNew.value;
191
- const validation = validateDraft(next, isNew);
192
- if (validation !== null) {
193
- error.value = validation;
194
- return;
195
- }
196
- saving.value = true;
197
- error.value = null;
198
- try {
199
- const account: Account = {
200
- code: next.code.trim(),
201
- name: next.name.trim(),
202
- type: next.type,
203
- };
204
- const note = next.note.trim();
205
- if (note.length > 0) account.note = note;
206
- // Preserve the existing active flag on edit — the editor
207
- // doesn't surface the field, so reading from props.accounts
208
- // is the only place the truth lives.
209
- if (!isNew) {
210
- const existing = props.accounts.find((entry) => entry.code === account.code);
211
- if (existing?.active === false) account.active = false;
212
- }
213
- const result = await upsertAccount(account, props.bookId);
214
- if (!result.ok) {
215
- error.value = result.error;
216
- return;
217
- }
218
- onCancelEditor();
219
- showSuccess(t("pluginAccounting.accounts.success"));
220
- emit("changed");
221
- } catch (err) {
222
- // apiPost normally folds network / HTTP failures into
223
- // result.ok=false, so this is a belt-and-braces guard against
224
- // a runtime failure that would otherwise leave the Save button
225
- // stuck on "Saving…".
226
- error.value = errorMessage(err);
227
- } finally {
228
- saving.value = false;
229
- }
230
- }
231
-
232
- async function onToggleActive(account: Account): Promise<void> {
233
- // No confirm dialog: deactivation hides the account from the
234
- // entry/ledger dropdowns but is fully reversible via Reactivate
235
- // on the same row, and historical entries are unaffected. A
236
- // confirm prompt was over-protective for an action that's a
237
- // single click to undo.
238
- //
239
- // Toggle uses its own `toggleSaving` / `toggleError` refs rather
240
- // than the AccountEditor's shared `saving` / `error` so that a
241
- // toggle failure still surfaces (via the toggle banner) when no
242
- // editor is mounted to render `:error`.
243
- if (toggleSaving.value) return;
244
- // Dismiss any open editor — the row about to (de)activate may be
245
- // the same one being edited, and even when it isn't, the user has
246
- // shifted attention to the toggle. Unsaved edits are dropped per
247
- // product call: reopening Edit is one click.
248
- onCancelEditor();
249
- const willDeactivate = account.active !== false;
250
- toggleSaving.value = true;
251
- toggleError.value = null;
252
- try {
253
- const next: Account = {
254
- code: account.code,
255
- name: account.name,
256
- type: account.type,
257
- };
258
- if (account.note !== undefined && account.note.length > 0) next.note = account.note;
259
- // Send the active flag explicitly so the server can tell
260
- // "user wants to (de)activate" apart from "user is editing
261
- // and didn't mention active" — the latter inherits the
262
- // existing flag and would otherwise turn Reactivate into a
263
- // no-op.
264
- next.active = !willDeactivate;
265
- const result = await upsertAccount(next, props.bookId);
266
- if (!result.ok) {
267
- toggleError.value = result.error;
268
- return;
269
- }
270
- emit("changed");
271
- } catch (err) {
272
- toggleError.value = errorMessage(err);
273
- } finally {
274
- toggleSaving.value = false;
275
- }
276
- }
277
-
278
- function showSuccess(message: string): void {
279
- successMessage.value = message;
280
- if (successTimer !== null) clearTimeout(successTimer);
281
- successTimer = setTimeout(() => {
282
- successMessage.value = null;
283
- successTimer = null;
284
- }, SUCCESS_FADE_MS);
285
- }
286
-
287
- function onBackdropClick(): void {
288
- emit("close");
289
- }
290
-
291
- onMounted(() => {
292
- // Initial focus on the close button so Esc / Tab work
293
- // immediately and the user isn't dropped into an editor field
294
- // they didn't ask for.
295
- void nextTick(() => closeButton.value?.focus());
296
- });
297
-
298
- onUnmounted(() => {
299
- if (successTimer !== null) clearTimeout(successTimer);
300
- });
301
- </script>
@@ -1,186 +0,0 @@
1
- <template>
2
- <div class="flex flex-col gap-3" data-testid="accounting-balance-sheet">
3
- <div class="flex flex-wrap items-end gap-3">
4
- <label class="text-xs text-gray-500 flex flex-col gap-1">
5
- {{ t("pluginAccounting.balanceSheet.shortcutLabel") }}
6
- <select
7
- :value="selectedShortcut"
8
- class="h-8 px-2 rounded border border-gray-300 text-sm bg-white"
9
- data-testid="accounting-bs-shortcut"
10
- @change="onShortcutChange(($event.target as HTMLSelectElement).value)"
11
- >
12
- <option value="" hidden></option>
13
- <option value="thisMonth">{{ t("pluginAccounting.balanceSheet.thisMonth") }}</option>
14
- <option value="lastMonth">{{ t("pluginAccounting.balanceSheet.lastMonth") }}</option>
15
- <option value="lastQuarter">{{ t("pluginAccounting.balanceSheet.lastQuarter") }}</option>
16
- <option value="lastYear">{{ t("pluginAccounting.balanceSheet.lastYear") }}</option>
17
- </select>
18
- </label>
19
- <label class="text-xs text-gray-500 flex flex-col gap-1">
20
- {{ t("pluginAccounting.balanceSheet.asOfLabel") }}
21
- <input v-model="period" type="month" class="h-8 px-2 rounded border border-gray-300 text-sm" data-testid="accounting-bs-period" />
22
- </label>
23
- <button class="h-8 px-2.5 rounded border border-gray-300 text-sm text-gray-600 hover:bg-gray-50" @click="refresh">
24
- <span class="material-icons text-base align-middle">refresh</span>
25
- </button>
26
- </div>
27
- <p v-if="loading" class="text-xs text-gray-400">{{ t("pluginAccounting.common.loading") }}</p>
28
- <p v-else-if="error" class="text-xs text-red-500">{{ t("pluginAccounting.common.error", { error }) }}</p>
29
- <template v-else-if="balanceSheet">
30
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
31
- <section v-for="section in balanceSheet.sections" :key="section.type" class="border border-gray-200 rounded p-3">
32
- <h4 class="text-sm font-semibold mb-2">{{ sectionLabel(section.type) }}</h4>
33
- <table class="w-full text-sm">
34
- <tbody>
35
- <tr
36
- v-for="row in section.rows"
37
- :key="row.accountCode"
38
- class="border-b border-gray-100"
39
- :class="
40
- isEarningsRow(row)
41
- ? 'italic text-gray-600'
42
- : 'hover:bg-blue-50 cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-400'
43
- "
44
- :tabindex="isEarningsRow(row) ? -1 : 0"
45
- :role="isEarningsRow(row) ? undefined : 'button'"
46
- :aria-label="isEarningsRow(row) ? undefined : t('pluginAccounting.accounts.openLedgerAria', { code: row.accountCode, name: row.accountName })"
47
- :data-testid="isEarningsRow(row) ? undefined : `accounting-bs-row-${row.accountCode}`"
48
- @click="onRowClick(row)"
49
- @keydown.enter.prevent.self="onKeyActivate($event, row)"
50
- @keydown.space.prevent.self="onKeyActivate($event, row)"
51
- >
52
- <td class="py-1 px-1">
53
- <span v-if="!isEarningsRow(row)" class="font-mono text-[10px] text-gray-400 mr-2">{{ row.accountCode }}</span
54
- >{{ rowName(row) }}
55
- </td>
56
- <td class="py-1 px-1 text-right font-mono">{{ formatAmount(row.balance) }}</td>
57
- </tr>
58
- </tbody>
59
- <tfoot>
60
- <tr class="font-semibold border-t border-gray-300">
61
- <td class="py-1 px-1">{{ t("pluginAccounting.balanceSheet.total") }}</td>
62
- <td class="py-1 px-1 text-right">{{ formatAmount(section.total) }}</td>
63
- </tr>
64
- </tfoot>
65
- </table>
66
- </section>
67
- </div>
68
- <p :class="Math.abs(balanceSheet.imbalance) <= 0.01 ? 'text-green-600' : 'text-red-500'" class="text-xs" data-testid="accounting-bs-imbalance">
69
- {{ t("pluginAccounting.balanceSheet.imbalance", { amount: formatAmount(balanceSheet.imbalance) }) }}
70
- </p>
71
- </template>
72
- </div>
73
- </template>
74
-
75
- <script setup lang="ts">
76
- import { computed, ref, watch } from "vue";
77
- import { useI18n } from "vue-i18n";
78
- import { getBalanceSheet, type BalanceSheet } from "../api";
79
- import { formatAmount as formatAmountWithCurrency } from "../currencies";
80
- import { decemberOfPreviousYearString, lastMonthOfPreviousQuarterString, localMonthString, previousMonthString } from "../dates";
81
- import { useLatestRequest } from "./useLatestRequest";
82
-
83
- const { t } = useI18n();
84
-
85
- const props = defineProps<{ bookId: string; currency: string; version: number }>();
86
- const emit = defineEmits<{ selectAccount: [code: string] }>();
87
-
88
- const period = ref(localMonthString());
89
- const balanceSheet = ref<BalanceSheet | null>(null);
90
- const loading = ref(false);
91
- const error = ref<string | null>(null);
92
- const { begin: beginRequest, isCurrent } = useLatestRequest();
93
-
94
- function formatAmount(value: number): string {
95
- return formatAmountWithCurrency(value, props.currency);
96
- }
97
-
98
- function sectionLabel(type: string): string {
99
- if (type === "asset") return t("pluginAccounting.balanceSheet.sections.asset");
100
- if (type === "liability") return t("pluginAccounting.balanceSheet.sections.liability");
101
- if (type === "equity") return t("pluginAccounting.balanceSheet.sections.equity");
102
- return type;
103
- }
104
-
105
- // The server adds a synthetic "Current period earnings" row to the
106
- // Equity section so the B/S balances during the period (before
107
- // closing entries fold income/expense into Retained Earnings).
108
- // `_currentEarnings` is the sentinel accountCode emitted by the
109
- // server — see CURRENT_EARNINGS_ACCOUNT_CODE in
110
- // server/accounting/report.ts.
111
- const CURRENT_EARNINGS_ACCOUNT_CODE = "_currentEarnings";
112
-
113
- interface BSRow {
114
- accountCode: string;
115
- accountName: string;
116
- balance: number;
117
- }
118
-
119
- function isEarningsRow(row: BSRow): boolean {
120
- return row.accountCode === CURRENT_EARNINGS_ACCOUNT_CODE;
121
- }
122
-
123
- function rowName(row: BSRow): string {
124
- return isEarningsRow(row) ? t("pluginAccounting.balanceSheet.currentEarnings") : row.accountName;
125
- }
126
-
127
- // Earnings row is synthetic (no underlying account on file), so it
128
- // can't be drilled into. Real-account rows route to the Ledger tab
129
- // pre-filtered to that account — same pattern as AccountsList.
130
- function onRowClick(row: BSRow): void {
131
- if (isEarningsRow(row)) return;
132
- emit("selectAccount", row.accountCode);
133
- }
134
-
135
- function onKeyActivate(event: KeyboardEvent, row: BSRow): void {
136
- if (event.repeat) return;
137
- if (isEarningsRow(row)) return;
138
- emit("selectAccount", row.accountCode);
139
- }
140
-
141
- // Mirrors the DateRangePicker pattern: hidden "" sentinel for the
142
- // "no preset matches" custom state, otherwise the dropdown shows
143
- // whichever shortcut produces the current period. Re-evaluates `now`
144
- // on every read so the labels stay correct across midnight without
145
- // any cache-invalidation plumbing.
146
- type Shortcut = "thisMonth" | "lastMonth" | "lastQuarter" | "lastYear";
147
- type SelectedShortcut = Shortcut | "";
148
-
149
- const selectedShortcut = computed<SelectedShortcut>(() => {
150
- const { value } = period;
151
- const now = new Date();
152
- if (value === localMonthString(now)) return "thisMonth";
153
- if (value === previousMonthString(now)) return "lastMonth";
154
- if (value === lastMonthOfPreviousQuarterString(now)) return "lastQuarter";
155
- if (value === decemberOfPreviousYearString(now)) return "lastYear";
156
- return "";
157
- });
158
-
159
- function onShortcutChange(raw: string): void {
160
- const now = new Date();
161
- if (raw === "thisMonth") period.value = localMonthString(now);
162
- else if (raw === "lastMonth") period.value = previousMonthString(now);
163
- else if (raw === "lastQuarter") period.value = lastMonthOfPreviousQuarterString(now);
164
- else if (raw === "lastYear") period.value = decemberOfPreviousYearString(now);
165
- }
166
-
167
- async function refresh(): Promise<void> {
168
- const token = beginRequest();
169
- loading.value = true;
170
- error.value = null;
171
- try {
172
- const result = await getBalanceSheet({ kind: "month", period: period.value }, props.bookId);
173
- if (!isCurrent(token)) return;
174
- if (!result.ok) {
175
- error.value = result.error;
176
- balanceSheet.value = null;
177
- return;
178
- }
179
- balanceSheet.value = result.data.balanceSheet;
180
- } finally {
181
- if (isCurrent(token)) loading.value = false;
182
- }
183
- }
184
-
185
- watch(() => [props.bookId, props.version, period.value], refresh, { immediate: true });
186
- </script>