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,554 +0,0 @@
1
- <template>
2
- <div class="flex flex-col h-full gap-3">
3
- <!-- Top-row toolbar slot. Renders the embedded entry form
4
- in "+ New entry" mode here; Edit-mode for a row's existing
5
- entry is rendered IN-PLACE inside that row's expanded
6
- detail panel below. The date picker / account filter /
7
- table below stay visible in either state. -->
8
- <div v-if="showNewForm" class="border border-gray-200 rounded p-3" data-testid="accounting-journal-inline-form">
9
- <JournalEntryForm
10
- :book-id="bookId"
11
- :accounts="accounts"
12
- :currency="currency"
13
- :country="country"
14
- :entry-to-edit="null"
15
- @submitted="onFormSubmitted"
16
- @cancel="onFormCancel"
17
- />
18
- </div>
19
- <div v-else class="flex items-center justify-end">
20
- <button
21
- type="button"
22
- 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"
23
- data-testid="accounting-journal-new-entry"
24
- @click="onOpenNewEntry"
25
- >
26
- <span class="material-icons text-base">add</span>
27
- <span>{{ t("pluginAccounting.tabs.newEntry") }}</span>
28
- </button>
29
- </div>
30
- <div class="flex flex-wrap items-end gap-2">
31
- <DateRangePicker v-model="range" :fiscal-year-end="resolvedFiscalYearEnd" :opening-date="openingDate" />
32
- <label class="text-xs text-gray-500 flex flex-col gap-1">
33
- {{ t("pluginAccounting.journalList.accountLabel") }}
34
- <select v-model="accountCode" class="h-8 px-2 rounded border border-gray-300 text-sm bg-white" data-testid="accounting-journal-account">
35
- <option value="">{{ t("pluginAccounting.journalList.allAccounts") }}</option>
36
- <option v-for="account in accounts" :key="account.code" :value="account.code">{{ formatAccountLabel(account) }}</option>
37
- </select>
38
- </label>
39
- <button class="h-8 px-2.5 rounded border border-gray-300 text-sm text-gray-600 hover:bg-gray-50" @click="refresh">
40
- <span class="material-icons text-base align-middle">refresh</span>
41
- </button>
42
- </div>
43
- <!-- Scrollable list area: only the entries list scrolls below
44
- this point. The new-entry slot + filter bar above stay
45
- pinned by virtue of NOT being inside this scroll container,
46
- and the column-header row stays visible via `position:
47
- sticky` on its <th>s. `min-h-0` is required for the flex-1
48
- child to actually shrink below its content height in a
49
- flex-col parent. -->
50
- <div class="flex-1 min-h-0 overflow-auto">
51
- <p v-if="loading" class="text-xs text-gray-400">{{ t("pluginAccounting.common.loading") }}</p>
52
- <p v-else-if="error" class="text-xs text-red-500">{{ t("pluginAccounting.common.error", { error }) }}</p>
53
- <p v-else-if="visibleEntries.length === 0" class="text-xs text-gray-400">{{ t("pluginAccounting.common.empty") }}</p>
54
- <table v-else class="w-full text-sm" data-testid="accounting-journal-table">
55
- <thead>
56
- <tr class="text-xs text-gray-500 border-b border-gray-200">
57
- <!-- Per-<th> sticky (rather than `<thead class="sticky">`)
58
- for compatibility — `position: sticky` on the
59
- table-header-group display is brittle in some
60
- browsers, but on `<th>` it's universally supported.
61
- `bg-white` is required so the scrolled rows beneath
62
- don't bleed through. -->
63
- <th class="sticky top-0 bg-white text-left py-1 px-2">{{ t("pluginAccounting.journalList.columns.date") }}</th>
64
- <th class="sticky top-0 bg-white text-left py-1 px-2">{{ t("pluginAccounting.journalList.columns.kind") }}</th>
65
- <th class="sticky top-0 bg-white text-left py-1 px-2">{{ t("pluginAccounting.journalList.columns.memo") }}</th>
66
- <th class="sticky top-0 bg-white text-left py-1 px-2">{{ t("pluginAccounting.journalList.columns.lines") }}</th>
67
- </tr>
68
- </thead>
69
- <tbody>
70
- <template v-for="entry in visibleEntries" :key="entry.id">
71
- <tr
72
- :class="[
73
- voidedEntryIds.has(entry.id) ? 'text-gray-400 line-through' : '',
74
- expandedEntryId === entry.id ? 'row-selected' : '',
75
- 'border-b border-gray-100 align-top cursor-pointer hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-400',
76
- ]"
77
- :data-testid="voidedEntryIds.has(entry.id) ? `accounting-journal-row-voided-${entry.id}` : `accounting-journal-row-${entry.id}`"
78
- tabindex="0"
79
- role="button"
80
- :aria-expanded="expandedEntryId === entry.id"
81
- @click="toggleExpanded(entry.id)"
82
- @keydown.enter.prevent.self="onKeyToggle($event, entry.id)"
83
- @keydown.space.prevent.self="onKeyToggle($event, entry.id)"
84
- >
85
- <td class="py-1 px-2 whitespace-nowrap">{{ entry.date }}</td>
86
- <td class="py-1 px-2 text-xs">{{ kindLabel(entry.kind) }}</td>
87
- <td class="py-1 px-2">
88
- <span v-if="entry.memo">{{ entry.memo }}</span>
89
- </td>
90
- <td class="py-1 px-2">
91
- <template v-if="expandedEntryId !== entry.id">
92
- <div v-for="(line, idx) in entry.lines" :key="idx" class="text-xs flex gap-2 items-baseline">
93
- <span class="font-mono text-[10px] text-gray-400">{{ line.accountCode }}</span>
94
- <span v-if="accountNameFor(line.accountCode)">{{ accountNameFor(line.accountCode) }}</span>
95
- <span v-if="line.debit">{{ formatDebit(line.debit) }}</span>
96
- <span v-if="line.credit">{{ formatCredit(line.credit) }}</span>
97
- </div>
98
- </template>
99
- <div v-else class="flex items-center justify-between gap-2">
100
- <span class="text-xs text-gray-400 font-mono">{{ formatCreatedAt(entry.createdAt) }}</span>
101
- <button
102
- type="button"
103
- class="h-6 w-6 flex items-center justify-center rounded text-gray-500 hover:bg-gray-100"
104
- :data-testid="`accounting-journal-detail-close-${entry.id}`"
105
- :aria-label="t('common.close')"
106
- @click.stop="onCloseDetail"
107
- >
108
- <span class="material-icons text-base">close</span>
109
- </button>
110
- </div>
111
- </td>
112
- </tr>
113
- <tr v-if="expandedEntryId === entry.id" class="bg-gray-50 detail-selected" :data-testid="`accounting-journal-detail-${entry.id}`">
114
- <td :colspan="4" class="px-6 py-2">
115
- <!-- Edit-in-place: the JournalEntryForm replaces the
116
- read-only detail content for this row when the
117
- user clicks Edit. Submit / cancel collapses back
118
- (submit also voids the original, so we clear the
119
- selection); top-bar "+ New entry" stays a separate
120
- path that opens the same form above the table. -->
121
- <div v-if="entryBeingEdited?.id === entry.id" :data-testid="`accounting-journal-detail-edit-${entry.id}`">
122
- <JournalEntryForm
123
- :book-id="bookId"
124
- :accounts="accounts"
125
- :currency="currency"
126
- :country="country"
127
- :entry-to-edit="entryBeingEdited"
128
- @submitted="onFormSubmitted"
129
- @cancel="onFormCancel"
130
- />
131
- </div>
132
- <template v-else>
133
- <div class="flex items-center gap-3 mb-2">
134
- <template v-if="entry.kind === 'normal' && !voidedEntryIds.has(entry.id)">
135
- <button class="text-xs text-blue-600 hover:underline" :data-testid="`accounting-edit-${entry.id}`" @click="onEditEntry(entry)">
136
- {{ t("pluginAccounting.journalList.edit") }}
137
- </button>
138
- <button class="text-xs text-red-500 hover:underline" :data-testid="`accounting-void-${entry.id}`" @click="onVoid(entry)">
139
- {{ t("pluginAccounting.journalList.void") }}
140
- </button>
141
- </template>
142
- <button
143
- v-else-if="entry.kind === 'opening' && !voidedEntryIds.has(entry.id)"
144
- class="text-xs text-blue-600 hover:underline"
145
- :data-testid="`accounting-edit-opening-${entry.id}`"
146
- @click="emit('editOpening')"
147
- >
148
- {{ t("pluginAccounting.journalList.edit") }}
149
- </button>
150
- </div>
151
- <table class="w-full text-xs">
152
- <thead>
153
- <tr class="text-gray-500 border-b border-gray-200">
154
- <th class="text-left py-1 px-2">{{ t("pluginAccounting.entryForm.accountLabel") }}</th>
155
- <th class="text-right py-1 px-2">{{ t("pluginAccounting.entryForm.debitLabel") }}</th>
156
- <th class="text-right py-1 px-2">{{ t("pluginAccounting.entryForm.creditLabel") }}</th>
157
- <th class="text-left py-1 px-2">{{ t("pluginAccounting.entryForm.memoLabel") }}</th>
158
- <th v-if="entryHasTaxIds(entry)" class="text-left py-1 px-2">{{ t("pluginAccounting.entryForm.taxRegistrationIdLabel") }}</th>
159
- </tr>
160
- </thead>
161
- <tbody>
162
- <tr v-for="(line, idx) in entry.lines" :key="idx" class="border-b border-gray-100 text-gray-700">
163
- <td class="py-1 px-2">
164
- <span class="font-mono text-[10px] text-gray-400 mr-2">{{ line.accountCode }}</span>
165
- <span v-if="accountNameFor(line.accountCode)">{{ accountNameFor(line.accountCode) }}</span>
166
- </td>
167
- <td class="py-1 px-2 text-right font-mono">
168
- <template v-if="line.debit">{{ formatAmount(line.debit, currency) }}</template>
169
- </td>
170
- <td class="py-1 px-2 text-right font-mono">
171
- <template v-if="line.credit">{{ formatAmount(line.credit, currency) }}</template>
172
- </td>
173
- <td class="py-1 px-2">
174
- <template v-if="line.memo">{{ line.memo }}</template>
175
- </td>
176
- <td v-if="entryHasTaxIds(entry)" class="py-1 px-2 font-mono text-[10px]">
177
- <template v-if="line.taxRegistrationId">{{ line.taxRegistrationId }}</template>
178
- </td>
179
- </tr>
180
- </tbody>
181
- <tfoot>
182
- <tr class="font-semibold border-t border-gray-300 text-gray-700">
183
- <td class="py-1 px-2 text-gray-500">{{ t("pluginAccounting.balanceSheet.total") }}</td>
184
- <td class="py-1 px-2 text-right font-mono">{{ formatAmount(entryDebitTotal(entry), currency) }}</td>
185
- <td class="py-1 px-2 text-right font-mono">{{ formatAmount(entryCreditTotal(entry), currency) }}</td>
186
- <td :colspan="entryHasTaxIds(entry) ? 2 : 1"></td>
187
- </tr>
188
- </tfoot>
189
- </table>
190
- </template>
191
- </td>
192
- </tr>
193
- </template>
194
- </tbody>
195
- </table>
196
- </div>
197
- </div>
198
- </template>
199
-
200
- <script setup lang="ts">
201
- import { computed, nextTick, ref, watch } from "vue";
202
- import { useI18n } from "vue-i18n";
203
- import { getJournalEntries, voidEntry, type Account, type JournalEntry, type JournalEntryKind, type JournalLine } from "../api";
204
- import { formatAmount } from "../currencies";
205
- import { currentFiscalYearRange, resolveFiscalYearEnd, type DateRange, type FiscalYearEnd } from "../fiscalYear";
206
- import type { SupportedCountryCode } from "../countries";
207
- import { useLatestRequest } from "./useLatestRequest";
208
- import DateRangePicker from "./DateRangePicker.vue";
209
- import JournalEntryForm from "./JournalEntryForm.vue";
210
- import { errorMessage } from "../../../utils/errors";
211
-
212
- const { t } = useI18n();
213
-
214
- const props = defineProps<{
215
- bookId: string;
216
- accounts: Account[];
217
- currency: string;
218
- country?: SupportedCountryCode;
219
- version: number;
220
- fiscalYearEnd?: FiscalYearEnd;
221
- /** Opening-balance date for the active book — drives the "Lifetime"
222
- * shortcut in the date picker (from = openingDate, to = today).
223
- * When absent, the picker hides Lifetime; "All" still works. */
224
- openingDate?: string;
225
- /** Entry id to auto-expand and scroll into view. Surfaced by the
226
- * parent when an `addEntries` tool result lands so the user sees
227
- * the freshly-posted row highlighted. Captured into
228
- * `pendingPreselectId` and consumed once the entry actually
229
- * appears in the fetched list — refetch can race the prop. */
230
- preselectEntryId?: string;
231
- }>();
232
- const emit = defineEmits<{ editOpening: []; preselectConsumed: [] }>();
233
-
234
- // Inline-form state. Two distinct surfaces, one component:
235
- // • showNewForm = true → blank draft, rendered above the table
236
- // where the "+ New entry" button used to be.
237
- // • entryBeingEdited != null → edit mode, rendered IN-PLACE inside
238
- // the matching row's expanded detail panel (replacing the read-
239
- // only debit/credit table for that row).
240
- // `<JournalEntryForm>` looks at `entryToEdit` to decide its title /
241
- // submit label; the top-bar instance always passes null.
242
- const showNewForm = ref(false);
243
- const entryBeingEdited = ref<JournalEntry | null>(null);
244
- // Single-selection detail expansion. Clicking a row swaps the
245
- // selection (or collapses if it's already the selected row).
246
- // Cleared on book switch via the closeForm watcher; entries deleted
247
- // between fetches simply drop out of filteredEntries, so a stale id
248
- // here just renders no detail row. Declared early so the
249
- // onFormSubmitted / bookId-watcher callbacks below can reference it.
250
- const expandedEntryId = ref<string | null>(null);
251
-
252
- function onOpenNewEntry(): void {
253
- entryBeingEdited.value = null;
254
- showNewForm.value = true;
255
- }
256
-
257
- function onEditEntry(entry: JournalEntry): void {
258
- showNewForm.value = false;
259
- entryBeingEdited.value = entry;
260
- }
261
-
262
- function closeForm(): void {
263
- showNewForm.value = false;
264
- entryBeingEdited.value = null;
265
- }
266
-
267
- function onFormSubmitted(): void {
268
- // Submit posts via the form. In production the server-side
269
- // publishBookChange round-trips an SSE event that bumps
270
- // `bookVersion` and re-runs `refresh` via the watcher below.
271
- // We also kick a synchronous refetch here so the freshly-posted
272
- // row shows up immediately — the SSE round-trip can race the
273
- // tab repaint, and skipping it here also makes the e2e mock
274
- // path (no pubsub replay) deterministic.
275
- closeForm();
276
- // After an in-place edit submit, the original entry is voided
277
- // and replaced. Collapse the detail panel since it was pointing
278
- // at an entry that's now superseded.
279
- expandedEntryId.value = null;
280
- void refresh();
281
- }
282
-
283
- function onFormCancel(): void {
284
- closeForm();
285
- }
286
-
287
- // Switching books mid-edit would carry the prior book's draft into
288
- // the new book. Force the panel closed so the next visit starts
289
- // from a blank toolbar — the form's own bookId watcher would also
290
- // reset its internal state, but we want the user back in the
291
- // neutral "+ New entry" surface.
292
- watch(
293
- () => props.bookId,
294
- () => {
295
- closeForm();
296
- expandedEntryId.value = null;
297
- },
298
- );
299
-
300
- const resolvedFiscalYearEnd = computed<FiscalYearEnd>(() => resolveFiscalYearEnd(props.fiscalYearEnd));
301
-
302
- // Default = current fiscal year. Reset by the bookId/fiscalYearEnd
303
- // watcher so switching books or changing the FY-end in settings
304
- // drops a stale custom range from the prior book.
305
- const range = ref<DateRange>(currentFiscalYearRange(resolvedFiscalYearEnd.value));
306
- const accountCode = ref("");
307
- const entries = ref<JournalEntry[]>([]);
308
- const serverVoidedIds = ref<string[]>([]);
309
- const loading = ref(false);
310
- const error = ref<string | null>(null);
311
- const { begin: beginRequest, isCurrent } = useLatestRequest();
312
-
313
- function kindLabel(kind: JournalEntryKind): string {
314
- if (kind === "opening") return t("pluginAccounting.journalList.kind.opening");
315
- if (kind === "void") return t("pluginAccounting.journalList.kind.void");
316
- if (kind === "void-marker") return t("pluginAccounting.journalList.kind.voidMarker");
317
- return t("pluginAccounting.journalList.kind.normal");
318
- }
319
-
320
- function formatDebit(value: number): string {
321
- return `DR ${formatAmount(value, props.currency)}`;
322
- }
323
- function formatCredit(value: number): string {
324
- return `CR ${formatAmount(value, props.currency)}`;
325
- }
326
- function formatAccountLabel(account: Account): string {
327
- // Name first so type-to-search in the <select> matches the
328
- // human-meaningful word; the code goes in trailing parens.
329
- // Same convention used by JournalEntryForm and Ledger pickers.
330
- return `${account.name} (${account.code})`;
331
- }
332
- // `entry.createdAt` is server-stamped ISO 8601. We render local
333
- // date+time (no seconds, no timezone) in YYYY-MM-DD HH:MM form to
334
- // match `entry.date`'s style and keep the line compact. Parens are
335
- // baked in here so the template doesn't carry raw text (the
336
- // vue-i18n/no-raw-text rule flags literal strings in mustache).
337
- function formatCreatedAt(iso: string): string {
338
- const date = new Date(iso);
339
- if (Number.isNaN(date.getTime())) return `(${iso})`;
340
- const pad = (num: number): string => String(num).padStart(2, "0");
341
- return `(${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())})`;
342
- }
343
- const accountNameByCode = computed(() => {
344
- const map = new Map<string, string>();
345
- for (const account of props.accounts) map.set(account.code, account.name);
346
- return map;
347
- });
348
- function accountNameFor(code: string): string | null {
349
- return accountNameByCode.value.get(code) ?? null;
350
- }
351
-
352
- // Close button on the selected row's lines cell. Has to clear BOTH
353
- // expandedEntryId AND entryBeingEdited — if the user clicks Edit
354
- // (which sets entryBeingEdited) and then clicks Close, leaving
355
- // entryBeingEdited stale would block reopening: toggleExpanded's
356
- // edit-mode guard early-returns when entryBeingEdited.id matches the
357
- // clicked row, so the user could never reopen that entry from the
358
- // list. Issue surfaced by the CodeRabbit review on PR #1161.
359
- function onCloseDetail(): void {
360
- expandedEntryId.value = null;
361
- entryBeingEdited.value = null;
362
- }
363
-
364
- function toggleExpanded(entryId: string): void {
365
- // While the row is in edit mode for itself, ignore clicks on the
366
- // row chrome (date / kind / memo / lines cells) — the user is
367
- // actively typing into the form below and a stray cell click
368
- // shouldn't collapse the panel. Cancel / Submit on the form, or
369
- // clicking a different row, are the deliberate exits.
370
- if (entryBeingEdited.value?.id === entryId) return;
371
- expandedEntryId.value = expandedEntryId.value === entryId ? null : entryId;
372
- // Switching to a different row (or collapsing) drops any
373
- // in-progress edit on the prior row.
374
- entryBeingEdited.value = null;
375
- }
376
-
377
- function onKeyToggle(event: KeyboardEvent, entryId: string): void {
378
- if (event.repeat) return;
379
- toggleExpanded(entryId);
380
- }
381
-
382
- function entryHasTaxIds(entry: JournalEntry): boolean {
383
- return entry.lines.some((line) => Boolean(line.taxRegistrationId));
384
- }
385
-
386
- function sumLines(lines: JournalLine[], pick: (line: JournalLine) => number | undefined): number {
387
- return lines.reduce((acc, line) => acc + (pick(line) ?? 0), 0);
388
- }
389
-
390
- function entryDebitTotal(entry: JournalEntry): number {
391
- return sumLines(entry.lines, (line) => line.debit);
392
- }
393
-
394
- function entryCreditTotal(entry: JournalEntry): number {
395
- return sumLines(entry.lines, (line) => line.credit);
396
- }
397
-
398
- async function refresh(): Promise<void> {
399
- const token = beginRequest();
400
- loading.value = true;
401
- error.value = null;
402
- try {
403
- const result = await getJournalEntries({
404
- bookId: props.bookId,
405
- from: range.value.from || undefined,
406
- to: range.value.to || undefined,
407
- accountCode: accountCode.value || undefined,
408
- });
409
- if (!isCurrent(token)) return;
410
- if (!result.ok) {
411
- error.value = result.error;
412
- entries.value = [];
413
- serverVoidedIds.value = [];
414
- return;
415
- }
416
- entries.value = result.data.entries;
417
- serverVoidedIds.value = result.data.voidedEntryIds;
418
- } finally {
419
- if (isCurrent(token)) loading.value = false;
420
- }
421
- }
422
-
423
- const filteredEntries = computed(() => entries.value);
424
-
425
- // Visible-list view that pins the entry currently being edited at
426
- // the top when a filter change or pubsub-driven refetch would
427
- // otherwise drop it from `filteredEntries`. Without this, the
428
- // in-place edit form (which is nested under the row's v-if /
429
- // v-for) would unmount and silently discard the user's draft when:
430
- // • the user adjusts the date range or account filter,
431
- // • a sibling tab / LLM tool voids the entry out-of-band and the
432
- // SSE pubsub bumps `bookVersion`, refetching this list,
433
- // • or a sibling tab / LLM tool deletes the underlying book.
434
- // Pinning the editing entry from the local snapshot (entryBeingEdited)
435
- // keeps the form mounted across all three. The pinned row sits at
436
- // the top of the table while editing; on submit / cancel the
437
- // snapshot clears and the list reverts to filteredEntries.
438
- const visibleEntries = computed<JournalEntry[]>(() => {
439
- const list = filteredEntries.value;
440
- const editing = entryBeingEdited.value;
441
- if (editing && !list.some((entry) => entry.id === editing.id)) {
442
- return [editing, ...list];
443
- }
444
- return list;
445
- });
446
-
447
- // Set of original entry ids that have been voided. The server
448
- // computes this from the *unfiltered* journal (so an account-filtered
449
- // query — which drops void-marker rows because they have no lines —
450
- // still strikes out the cancelled original). Source of truth on the
451
- // server is `voidedIdSet()` in journal.ts.
452
- const voidedEntryIds = computed(() => new Set(serverVoidedIds.value));
453
-
454
- async function onVoid(entry: JournalEntry): Promise<void> {
455
- // Single dialog: the prompt is the confirmation. Cancelling
456
- // (returning null) cancels the void; entering empty text or a
457
- // reason proceeds.
458
- const reason = window.prompt(t("pluginAccounting.journalList.voidReason"));
459
- if (reason === null) return;
460
- try {
461
- const result = await voidEntry({ entryId: entry.id, reason: reason || undefined, bookId: props.bookId });
462
- if (!result.ok) error.value = result.error;
463
- } catch (err) {
464
- error.value = errorMessage(err);
465
- }
466
- }
467
-
468
- // Reset to current-year window whenever the active book or its
469
- // fiscal-year end changes. Keeps a custom range from leaking across
470
- // books and follows a settings-driven shift in fiscalYearEnd.
471
- watch(
472
- () => [props.bookId, resolvedFiscalYearEnd.value],
473
- () => {
474
- range.value = currentFiscalYearRange(resolvedFiscalYearEnd.value);
475
- },
476
- );
477
-
478
- watch(() => [props.bookId, props.version, range.value.from, range.value.to, accountCode.value], refresh, { immediate: true });
479
-
480
- // Pending preselect: the parent hands us an id via `preselectEntryId`,
481
- // but the matching entry may not be in `entries` yet (the SSE-driven
482
- // refetch lands on its own clock). Stash it here, then the
483
- // [pendingPreselectId, entries] watcher below consumes it once the
484
- // row actually exists in the list — and clears it so subsequent
485
- // unrelated refetches (void events, sibling-tab edits) don't
486
- // re-expand a stale target.
487
- const pendingPreselectId = ref<string | null>(null);
488
-
489
- watch(
490
- () => props.preselectEntryId,
491
- (incoming) => {
492
- if (incoming) pendingPreselectId.value = incoming;
493
- },
494
- // immediate: true so a late JournalList mount (the View defers our
495
- // mount until refetchBooks resolves activeBookId) still captures
496
- // a preselect the parent had already set — without this, a normal
497
- // watcher misses the "initial value is the target value" case.
498
- { immediate: true },
499
- );
500
-
501
- watch([pendingPreselectId, entries], async ([targetId, list]) => {
502
- if (!targetId) return;
503
- if (!list.some((entry) => entry.id === targetId)) return;
504
- // Always emit `preselectConsumed` (whether we expand or bail) so
505
- // the parent can drop its `journalPreselectEntryId` ref. Without
506
- // this one-shot signal, leaving and returning to the journal tab
507
- // (v-if remount) replays the immediate prop watcher against the
508
- // stale value, re-expanding an old row the user has already moved
509
- // past. Issue raised by the Codex automated review on PR #1158.
510
- if (entryBeingEdited.value) {
511
- // Don't overwrite an in-progress edit on another row — the
512
- // user's draft matters more than the highlight. Drop pending so
513
- // we don't keep retrying every refetch, and signal consumed so
514
- // the parent doesn't keep re-handing us the same id.
515
- pendingPreselectId.value = null;
516
- emit("preselectConsumed");
517
- return;
518
- }
519
- expandedEntryId.value = targetId;
520
- await nextTick();
521
- const row =
522
- document.querySelector(`[data-testid="accounting-journal-row-${targetId}"]`) ??
523
- document.querySelector(`[data-testid="accounting-journal-row-voided-${targetId}"]`);
524
- row?.scrollIntoView({ behavior: "smooth", block: "center" });
525
- pendingPreselectId.value = null;
526
- emit("preselectConsumed");
527
- });
528
- </script>
529
-
530
- <style scoped>
531
- /* Selection frame for the expanded entry. Borders go on the cells
532
- (not the <tr>) because border-collapse: collapse — Tailwind's
533
- default — eats <tr>-level borders/box-shadows. The entry row owns
534
- top/left/right; the detail-panel row directly below owns
535
- left/right/bottom, so together they read as one rectangle around
536
- the selection. Color matches the focus-ring blue used elsewhere
537
- in this list. */
538
- .row-selected > td {
539
- background-color: rgb(239 246 255); /* tailwind blue-50 */
540
- border-top: 2px solid rgb(59 130 246); /* tailwind blue-500 */
541
- }
542
- .row-selected > td:first-child {
543
- border-left: 2px solid rgb(59 130 246);
544
- }
545
- .row-selected > td:last-child {
546
- border-right: 2px solid rgb(59 130 246);
547
- }
548
- .detail-selected > td {
549
- background-color: rgb(239 246 255);
550
- border-left: 2px solid rgb(59 130 246);
551
- border-right: 2px solid rgb(59 130 246);
552
- border-bottom: 2px solid rgb(59 130 246);
553
- }
554
- </style>