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.
- package/README.md +95 -38
- package/bin/mulmoclaude.js +1 -2
- package/client/assets/JsonEditor-CPJfn76E.css +1 -0
- package/client/assets/JsonEditor-CoWGJG3Y.js +10 -0
- package/client/assets/abnfDiagram-VRR7QNED-6nNByj6v-By7GJ3xW.js +1 -0
- package/client/assets/abnfDiagram-VRR7QNED-BrQlVixL.js +1 -0
- package/client/assets/arc-BXutyUAX.js +1 -0
- package/client/assets/arc-zT0wd74V-DulGJNnb.js +1 -0
- package/client/assets/architecture-TIHT7OUA-CYMWc3UT-C7HoFzWN.js +1 -0
- package/client/assets/architecture-TIHT7OUA-aml8u-G9.js +1 -0
- package/client/assets/architectureDiagram-ZJ3FMSHR-Bgnyaj_i-CCpEsCHN.js +36 -0
- package/client/assets/architectureDiagram-ZJ3FMSHR-DJTFpPjB.js +36 -0
- package/client/assets/array-BifhSqXX.js +1 -0
- package/client/assets/array-CApNbSU9-BifhSqXX.js +1 -0
- package/client/assets/blockDiagram-677ZJIJ3-DQ35o5E4-BXS11D3J.js +132 -0
- package/client/assets/blockDiagram-677ZJIJ3-aYvCODxv.js +132 -0
- package/client/assets/c4Diagram-LMCZKHZV-Bau6RMBb.js +10 -0
- package/client/assets/c4Diagram-LMCZKHZV-ClWZeiWo-DXGnOOUf.js +10 -0
- package/client/assets/channel-D9VSi_QV.js +1 -0
- package/client/assets/channel-Di5rtkx0-C3gZcytF.js +1 -0
- package/client/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/client/assets/chunk-2Q5K7J3B-DfKpwyl9-DTxwf5E9.js +1 -0
- package/client/assets/chunk-32BRIVSS-CCt9wtYd-Cwa_IP35.js +1 -0
- package/client/assets/chunk-32BRIVSS-CxzHeys5.js +1 -0
- package/client/assets/chunk-52WLFC77-BtNjbTdw.js +10 -0
- package/client/assets/chunk-52WLFC77-FbBbR4uI-wsNC5d-f.js +10 -0
- package/client/assets/chunk-5VM5RSS4-BYnnUiN6-C4rOnu9A.js +15 -0
- package/client/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- package/client/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
- package/client/assets/chunk-7BUUIJ7U-hh8aCuGX-mGEpPzQy.js +1 -0
- package/client/assets/chunk-C7G6YPKG-BE8ehsnc.js +1 -0
- package/client/assets/chunk-C7G6YPKG-C87hlS9c-BitbJpTa.js +1 -0
- package/client/assets/{chunk-D8eiyYIV-BY16KEZc.js → chunk-D8eiyYIV-BeeEsA1B.js} +1 -1
- package/client/assets/chunk-EX3LRPZG-Bhgskzyy.js +231 -0
- package/client/assets/chunk-EX3LRPZG-BqGqMXLN-Cl2Eo1_u.js +231 -0
- package/client/assets/chunk-FWX5IMBZ-BkbSAAuW-C2r4AuAO.js +2 -0
- package/client/assets/chunk-FWX5IMBZ-D9sskZb_.js +2 -0
- package/client/assets/chunk-HOUHSVGY-CBCXk7rb.js +1 -0
- package/client/assets/chunk-HOUHSVGY-Cxu0eDlh-owg_DcY0.js +1 -0
- package/client/assets/chunk-ICXQ74PX-DTqPpDQ9.js +2 -0
- package/client/assets/chunk-ICXQ74PX-hiraF_Xj-CdaEwVin.js +2 -0
- package/client/assets/chunk-JWPE2WC7-BQ3zXr2k-DSd3Ct95.js +1 -0
- package/client/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/client/assets/chunk-KEIR6QF5-DNzq6p3w.js +161 -0
- package/client/assets/chunk-MOJQB5TN-CqxshQHA-Cn_EpDyZ.js +88 -0
- package/client/assets/chunk-MOJQB5TN-D1s_zUGz.js +88 -0
- package/client/assets/chunk-OGEWGWER-CjCr7ceX-Dfk5-70y.js +1 -0
- package/client/assets/chunk-OGEWGWER-DzfhxoQd.js +1 -0
- package/client/assets/chunk-PUDLZKDR-BZlebNhn.js +156 -0
- package/client/assets/chunk-PUDLZKDR-Dx6M-vz1-CLyVurOz.js +156 -0
- package/client/assets/chunk-Q4XR5HBZ-BcJb7mwA.js +70 -0
- package/client/assets/chunk-Q4XR5HBZ-CZd-9lTB-qPEYoRNc.js +11 -0
- package/client/assets/chunk-RYQCIY6F-B_IgMG7T.js +1 -0
- package/client/assets/chunk-RYQCIY6F-YkbemkCt-CX4fncTQ.js +1 -0
- package/client/assets/chunk-V7JOEXUC-Buce04o6.js +206 -0
- package/client/assets/chunk-V7JOEXUC-rI0xlC_O-C607vJXy.js +206 -0
- package/client/assets/chunk-VAUOI2AC-CxhkzXN0.js +1 -0
- package/client/assets/chunk-VAUOI2AC-DrcykVNK-CSROJWdE.js +1 -0
- package/client/assets/chunk-VR4S4FIN-D5afNrsS.js +1 -0
- package/client/assets/chunk-VR4S4FIN-O6iF8Yvf-CLIwrgqU.js +1 -0
- package/client/assets/chunk-WYO6CB5R-B83L_z6I-Cs8mg9If.js +127 -0
- package/client/assets/chunk-WYO6CB5R-BXTIdTMw.js +125 -0
- package/client/assets/chunk-XXDRQBXY-DFXH_lWn-B5HjCp2c.js +1 -0
- package/client/assets/chunk-XXDRQBXY-DXMD6ofA.js +1 -0
- package/client/assets/chunk-Y2CYZVJY-Bdt8pFDJ-DsF7k-Jl.js +1 -0
- package/client/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/client/assets/chunk-ZGVPDNZ5-BpFv9JSP-CHYySMjV.js +62 -0
- package/client/assets/chunk-ZGVPDNZ5-CYusI0J_.js +62 -0
- package/client/assets/chunk-ZIRB5QZD-Biy6ZNFG-D1maAiXb.js +32 -0
- package/client/assets/chunk-ZIRB5QZD-C6fEPe3t.js +32 -0
- package/client/assets/classDiagram-OUVF2IWQ-BgAZMSbT-BgxEE1D3.js +1 -0
- package/client/assets/classDiagram-OUVF2IWQ-CBD3Eidl.js +1 -0
- package/client/assets/classDiagram-v2-EOCWNBFH-CBD3Eidl.js +1 -0
- package/client/assets/classDiagram-v2-EOCWNBFH-DxHTyui1-BgxEE1D3.js +1 -0
- package/client/assets/cose-bilkent-JH36ORCC-CuSL2tA8-aMIqISfj.js +1 -0
- package/client/assets/cose-bilkent-JH36ORCC-WAJDBXv1.js +1 -0
- package/client/assets/cynefin-VYW2F7L2-DH2qkJKw.js +1 -0
- package/client/assets/cynefin-VYW2F7L2-DqA3n9nY-BNWhIK_n.js +1 -0
- package/client/assets/cynefinDiagram-TSTJHNR4-CUvPV9MV.js +62 -0
- package/client/assets/cynefinDiagram-TSTJHNR4-x0-0sQ15-Cq1gFcFu.js +62 -0
- package/client/assets/cytoscape.esm-CzdwbRaj-Djp6vQyU.js +321 -0
- package/client/assets/cytoscape.esm-Djp6vQyU.js +321 -0
- package/client/assets/dagre-CXRCoUWR.js +1 -0
- package/client/assets/dagre-VKFMJZFB-CQdfl-bx-CzZZuace.js +4 -0
- package/client/assets/dagre-VKFMJZFB-C_9IS7mB.js +4 -0
- package/client/assets/dagre-wczQIDso-CfevN9RO.js +1 -0
- package/client/assets/defaultLocale-C8Fc0cco.js +1 -0
- package/client/assets/defaultLocale-DUNguUWs-BbDo_yJX.js +1 -0
- package/client/assets/diagram-FQU43EPY-BOSB6VUb-isPdQ8WX.js +3 -0
- package/client/assets/diagram-FQU43EPY-BP8N00-b.js +3 -0
- package/client/assets/diagram-G47NLZAW-DLXrcXsN-BIqj7RKy.js +24 -0
- package/client/assets/diagram-G47NLZAW-ulE1JlWG.js +24 -0
- package/client/assets/diagram-NH7WQ7WH-BMQp1rkF-D6-fOq_v.js +24 -0
- package/client/assets/diagram-NH7WQ7WH-D_IXrL3i.js +24 -0
- package/client/assets/diagram-OA4YK3LP-C-pC6Eyu.js +30 -0
- package/client/assets/diagram-OA4YK3LP-D1wQ0vUj-BNi6QLCK.js +30 -0
- package/client/assets/diagram-WEI45ONY-Di9m35i-.js +41 -0
- package/client/assets/diagram-WEI45ONY-RR0DpF8R-BS3nrb3w.js +41 -0
- package/client/assets/dist-BQBs5pjy-BmtZ7Oc2.js +1 -0
- package/client/assets/dist-CQ3HaWOk.js +1 -0
- package/client/assets/ebnfDiagram-CCIWWBDH-Cbwnim2x.js +1 -0
- package/client/assets/ebnfDiagram-CCIWWBDH-M123uVJ8-9-dq55nQ.js +1 -0
- package/client/assets/erDiagram-Q63AITRT-BWx_-PXG-CWGfG4z5.js +85 -0
- package/client/assets/erDiagram-Q63AITRT-CMbtO3Sm.js +85 -0
- package/client/assets/eventmodeling-45OFAUF4--32SIpkL.js +1 -0
- package/client/assets/eventmodeling-45OFAUF4-_BVSjAXf-DQdL0Icr.js +1 -0
- package/client/assets/flowDiagram-23GEKE2U-BeOc_anm-CuVzKmmU.js +1 -0
- package/client/assets/flowDiagram-23GEKE2U-Dofa_qxG.js +1 -0
- package/client/assets/ganttDiagram-NO4QXBWP-BOoJ1eTw-TWoNmSvq.js +292 -0
- package/client/assets/ganttDiagram-NO4QXBWP-BgoAVKuc.js +292 -0
- package/client/assets/gitGraph-TEB2WS4Q-CH12KLTN-Bz4frAhV.js +1 -0
- package/client/assets/gitGraph-TEB2WS4Q-DIMvNvqt.js +1 -0
- package/client/assets/gitGraphDiagram-IHSO6WYX-B2CJhk_G-ClOKkjxw.js +106 -0
- package/client/assets/gitGraphDiagram-IHSO6WYX-Dmb6KnPz.js +106 -0
- package/client/assets/graphlib-B8gBHxth.js +1 -0
- package/client/assets/graphlib-hY-1btwe-DQjxxcnr.js +1 -0
- package/client/assets/{html2canvas-CDGcmOD3-CKJ6vKPo.js → html2canvas-CDGcmOD3-DRL9pFVl.js} +2 -2
- package/client/assets/{index-9lmYSaus.js → index-Dc0R-HW5.js} +129 -190
- package/client/assets/index-Dxo1Zdd-.css +2 -0
- package/client/assets/{index.es-DqtpmBm8-DFXjJgCa.js → index.es-DqtpmBm8-EQk3NgR8.js} +1 -1
- package/client/assets/info-DKCQHKI2-Cbw3mbiK-GsDZz9IO.js +1 -0
- package/client/assets/info-DKCQHKI2-ViCqobGo.js +1 -0
- package/client/assets/infoDiagram-FWYZ7A6U-HKV7LIG-.js +2 -0
- package/client/assets/infoDiagram-FWYZ7A6U-Mp1X3pBP-ATJv87Ur.js +2 -0
- package/client/assets/init-D6jRqBbL.js +1 -0
- package/client/assets/init-DEsX3bhM-D6jRqBbL.js +1 -0
- package/client/assets/ishikawaDiagram-FXEZZL3T-BNG7tkJu-CGCeOIlJ.js +70 -0
- package/client/assets/ishikawaDiagram-FXEZZL3T-CVDUj46f.js +70 -0
- package/client/assets/journeyDiagram-5HDEW3XC-BA-ESGLP.js +139 -0
- package/client/assets/journeyDiagram-5HDEW3XC-Dbp_hY9X-Bx-IoCe9.js +139 -0
- package/client/assets/kanban-definition-HUTT4EX6-Bqaet01L.js +89 -0
- package/client/assets/kanban-definition-HUTT4EX6-DSTc5u3q-C0JGckt1.js +89 -0
- package/client/assets/katex-CddkPoXu.js +257 -0
- package/client/assets/katex-M0IxphGf-CddkPoXu.js +257 -0
- package/client/assets/lib-4Tgx7rAy.js +114 -0
- package/client/assets/line-B1wBwzrY-f5wxpqoF.js +1 -0
- package/client/assets/line-CkyHfW7d.js +1 -0
- package/client/assets/linear-B9fuEF4c.js +1 -0
- package/client/assets/linear-lrGinF5_-CqNBync7.js +1 -0
- package/client/assets/map-CgrwEyH7-DWQFomlZ.js +1 -0
- package/client/assets/map-DsCK-0Cs.js +1 -0
- package/client/assets/marked.esm-CIU5FDdN.js +64 -0
- package/client/assets/marp-CSq0PPfK.js +3448 -0
- package/client/assets/material-symbols-outlined-DdRFxZLh.woff2 +0 -0
- package/client/assets/mermaid-parser.core-DC7NPJ_M-Ca6XzwfM.js +166 -0
- package/client/assets/mermaid-parser.core-SAwSf4_o.js +7 -0
- package/client/assets/mermaid.core-BBEQfkdJ.js +11 -0
- package/client/assets/mermaid.core-DZM3Ha-E-BxOo-RYG.js +11 -0
- package/client/assets/mindmap-definition-LN4V7U3C-B4BN0efL.js +96 -0
- package/client/assets/mindmap-definition-LN4V7U3C-DYtgcMsY-DynyLTNv.js +96 -0
- package/client/assets/ordinal-B9_Llu10-CU85fhaB.js +1 -0
- package/client/assets/ordinal-CopWnP7w.js +1 -0
- package/client/assets/packet-7NZHBO7P-CY4XRk9N.js +1 -0
- package/client/assets/packet-7NZHBO7P-lwb58iYx--vqSg65J.js +1 -0
- package/client/assets/path-BWPyau1x.js +1 -0
- package/client/assets/path-COivZ1Gw-C5riojK2.js +1 -0
- package/client/assets/pegDiagram-2B236MQR-BOKErjUu.js +1 -0
- package/client/assets/pegDiagram-2B236MQR-C43eIpKM-Bi_5Sxjt.js +1 -0
- package/client/assets/pie-RZYD4A2V-6BHB7bAx.js +1 -0
- package/client/assets/pie-RZYD4A2V-B1UWb4Gu-Dmn2hLWH.js +1 -0
- package/client/assets/pieDiagram-ENE6RG2P-BkTqgJyR-Bcdm19kR.js +39 -0
- package/client/assets/pieDiagram-ENE6RG2P-DtNjvz-U.js +39 -0
- package/client/assets/preload-helper-CZgWQFsJ.js +1 -0
- package/client/assets/purify.es-DY32g7DN.js +3 -0
- package/client/assets/quadrantDiagram-ABIIQ3AL-BQmAJL2v.js +7 -0
- package/client/assets/quadrantDiagram-ABIIQ3AL-Bm1Zjm45-B3orqx_f.js +7 -0
- package/client/assets/radar-I7S5WNFK-7CKcb_l--CqKdnR0v.js +1 -0
- package/client/assets/radar-I7S5WNFK-R7Jhjfdt.js +1 -0
- package/client/assets/railroad-3IZDKUUU-BepSPyHI.js +1 -0
- package/client/assets/railroad-3IZDKUUU-gCySKdnW-CKU26HTP.js +1 -0
- package/client/assets/railroad-abnf-AHOZXSZD-BlsHsp3c.js +1 -0
- package/client/assets/railroad-abnf-AHOZXSZD-BophH4r--CGkGHq54.js +1 -0
- package/client/assets/railroad-ebnf-EBAXGLYW-AZNjl_Zu-B7bn_PF3.js +1 -0
- package/client/assets/railroad-ebnf-EBAXGLYW-B4fMcGEH.js +1 -0
- package/client/assets/railroad-peg-LSFZ7HO6-B1ZrjJIu.js +1 -0
- package/client/assets/railroad-peg-LSFZ7HO6-BSiEEyeb-CP_B-N5g.js +1 -0
- package/client/assets/railroadDiagram-RFXS5EU6-8cz0Iby3.js +1 -0
- package/client/assets/railroadDiagram-RFXS5EU6-BkfbdeAs-Di6jH5I6.js +1 -0
- package/client/assets/requirementDiagram-TGXJPOKE-CrGTTjYg-DmIC7Shp.js +84 -0
- package/client/assets/requirementDiagram-TGXJPOKE-Dlqoe9TY.js +84 -0
- package/client/assets/rough.esm-CSKSodPl.js +1 -0
- package/client/assets/rough.esm-wVmwlXu7-CSKSodPl.js +1 -0
- package/client/assets/runtime-protocol-vue-WG3JLsjz.js +1 -0
- package/client/assets/runtime-vue-lHsY5zMj.js +1 -0
- package/client/assets/sankeyDiagram-HTMAVEWB-BkTKgu8Q.js +40 -0
- package/client/assets/sankeyDiagram-HTMAVEWB-rWXPf03Z-CjV9pCSJ.js +40 -0
- package/client/assets/{schemas-D_RbFtuQ.js → schemas-DGvl73AE.js} +3 -3
- package/client/assets/sequenceDiagram-DBY2YBRQ-BpuXUcFy.js +162 -0
- package/client/assets/sequenceDiagram-DBY2YBRQ-nkJYWO2m-BqS_sTCH.js +162 -0
- package/client/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
- package/client/assets/sizeCapture-X5ZJPWSS-F5SadAuT-VHIb4_NU.js +1 -0
- package/client/assets/src-Brzfja-q-DNc4Or4z.js +1 -0
- package/client/assets/src-Cqa3Jy1j.js +1 -0
- package/client/assets/stateDiagram-2N3HPSRC-CdlGXuo7.js +1 -0
- package/client/assets/stateDiagram-2N3HPSRC-T4-clK8b-DQRiB4va.js +1 -0
- package/client/assets/stateDiagram-v2-6OUMAXLB-BN8Jr3ZM.js +1 -0
- package/client/assets/stateDiagram-v2-6OUMAXLB-DIp7nhRd-DbrOhUn_.js +1 -0
- package/client/assets/swimlanes-5IMT3BWC-HmQNEntu-CNBgZdur.js +2 -0
- package/client/assets/swimlanes-5IMT3BWC-iEJg5gki.js +2 -0
- package/client/assets/swimlanesDiagram-G3AALYLV-BeoZhwg7-DpqgeNRA.js +8 -0
- package/client/assets/swimlanesDiagram-G3AALYLV-o-sS6aEP.js +8 -0
- package/client/assets/timeline-definition-FHXFAJF6-Bjh-7QmL.js +120 -0
- package/client/assets/timeline-definition-FHXFAJF6-CNc9jSTP-BKNSymgY.js +120 -0
- package/client/assets/treeView-QDETBFTQ-D3cqRl6k.js +1 -0
- package/client/assets/treeView-QDETBFTQ-nIQcG1h9-O_ri9HxD.js +1 -0
- package/client/assets/treemap-6X3UGDF4-BnsvC8yL-Cfsty1e3.js +1 -0
- package/client/assets/treemap-6X3UGDF4-DGkZcvDG.js +1 -0
- package/client/assets/v4-B29ayslu.js +1 -0
- package/client/assets/vennDiagram-L72KCM5P-Cz3dbe7b.js +34 -0
- package/client/assets/vennDiagram-L72KCM5P-Dr3pTJ_0-C38xwcVo.js +34 -0
- package/client/assets/vue-C6d2VveO.js +1 -0
- package/client/assets/vue-i18n-CL-ejuNu.js +3 -0
- package/client/assets/vue.runtime.esm-bundler-BeoTfMNc.js +4 -0
- package/client/assets/wardley-OPB4EBWU-8Odxkx6V-CCDIVuBs.js +1 -0
- package/client/assets/wardley-OPB4EBWU-CZsCDvKk.js +1 -0
- package/client/assets/wardleyDiagram-EHGQE667-DSFc7ZZa-mlWXRiWx.js +78 -0
- package/client/assets/wardleyDiagram-EHGQE667-DiyoyO_X.js +78 -0
- package/client/assets/xychartDiagram-FW5EYKEG-BP0Nn4Pp-DRRiStGZ.js +7 -0
- package/client/assets/xychartDiagram-FW5EYKEG-DhY1_UGM.js +7 -0
- package/client/index.html +16 -12
- package/package.json +17 -19
- package/server/agent/backend/types.ts +1 -1
- package/server/agent/backgroundSessions.ts +43 -0
- package/server/agent/config.ts +3 -2
- package/server/agent/mcp-tools/manageCollection.ts +4 -4
- package/server/agent/sandboxMounts.ts +1 -1
- package/server/agent/stream.ts +1 -3
- package/server/api/auth/viewToken.ts +1 -1
- package/server/api/bridge/sessionRole.ts +47 -0
- package/server/api/routes/agent.ts +79 -2
- package/server/api/routes/collections.ts +60 -7
- package/server/api/routes/collectionsRegistry.ts +113 -0
- package/server/api/routes/dashboard.ts +47 -0
- package/server/api/routes/feeds.ts +2 -2
- package/server/api/routes/files.ts +1 -2
- package/server/api/routes/pdf.ts +48 -9
- package/server/api/routes/plugins.ts +2 -2
- package/server/api/routes/remoteHost.ts +55 -0
- package/server/api/routes/sessions.ts +20 -11
- package/server/api/routes/share.ts +105 -0
- package/server/api/routes/transcribe.ts +1 -1
- package/server/api/routes/wiki/history.ts +2 -2
- package/server/api/routes/wiki.ts +29 -177
- package/server/api/sandboxStatus.ts +1 -1
- package/server/build/dispatcher.mjs +25 -14928
- package/server/events/collection-change.ts +4 -4
- package/server/events/file-change.ts +2 -2
- package/server/events/scheduler-adapter.ts +3 -3
- package/server/events/task-manager/index.ts +3 -3
- package/server/index.ts +53 -17
- package/server/notifier/engine.ts +3 -3
- package/server/notifier/types.ts +2 -2
- package/server/plugins/html-builtin.ts +15 -1
- package/server/prompts/system/system.md +4 -0
- package/server/remoteHost/auth.ts +29 -0
- package/server/remoteHost/commandChannel.ts +56 -0
- package/server/remoteHost/firebase.ts +16 -0
- package/server/remoteHost/handlers/collectionPage.ts +29 -0
- package/server/remoteHost/handlers/getCollection.ts +32 -0
- package/server/remoteHost/handlers/getFeed.ts +35 -0
- package/server/remoteHost/handlers/index.ts +19 -0
- package/server/remoteHost/handlers/listCollections.ts +29 -0
- package/server/remoteHost/handlers/listFeeds.ts +37 -0
- package/server/remoteHost/handlers/listShortcuts.ts +24 -0
- package/server/remoteHost/handlers/startChat.ts +78 -0
- package/server/remoteHost/hostRunner.ts +122 -0
- package/server/remoteHost/index.ts +117 -0
- package/server/system/config.ts +1 -1
- package/server/system/credentials.ts +2 -3
- package/server/system/docker.ts +9 -8
- package/server/system/env.ts +8 -0
- package/server/system/whisper/index.ts +4 -4
- package/server/utils/claudeConfigPath.ts +57 -0
- package/server/utils/files/dashboard-io.ts +87 -0
- package/server/utils/files/session-io.ts +11 -0
- package/server/utils/markdown/frontmatter.ts +8 -4
- package/server/utils/regex.ts +4 -3
- package/server/utils/share/packHtml.ts +108 -0
- package/server/utils/share/rewriteAssets.ts +178 -0
- package/server/workspace/chat-index/paths.ts +8 -2
- package/server/workspace/chat-index/summarizer.ts +23 -15
- package/server/workspace/collections/configure.ts +5 -3
- package/server/workspace/collections/index.ts +8 -6
- package/server/workspace/collections/notifications.ts +3 -3
- package/server/workspace/collections/types.ts +2 -2
- package/server/workspace/collections/watcher.ts +2 -2
- package/server/workspace/feeds/configure.ts +24 -0
- package/server/workspace/hooks/handlers/skillBridge.ts +2 -2
- package/server/workspace/hooks/handlers/wikiSnapshot.ts +1 -1
- package/server/workspace/paths.ts +8 -1
- package/server/workspace/skills/catalog.ts +1 -3
- package/server/workspace/skills/external/catalog.ts +1 -3
- package/server/workspace/skills/paths.ts +4 -3
- package/server/workspace/skills/writer.ts +1 -4
- package/server/workspace/skills-preset.ts +3 -3
- package/server/workspace/wiki-pages/io.ts +2 -2
- package/server/workspace/workspace.ts +2 -2
- package/src/App.vue +41 -18
- package/src/components/ChatInput.vue +1 -1
- package/src/components/DashboardView.vue +372 -0
- package/src/components/FileContentRenderer.vue +32 -7
- package/src/components/JsonEditor.vue +1 -1
- package/src/components/PluginLauncher.vue +122 -79
- package/src/components/RemoteHostControl.vue +159 -0
- package/src/components/SessionCountBadges.vue +32 -0
- package/src/components/SessionHeaderControls.vue +1 -8
- package/src/components/SessionHistoryPanel.vue +2 -0
- package/src/components/SessionHistoryToggleButton.vue +1 -15
- package/src/components/SidebarHeader.vue +2 -0
- package/src/components/collectionTypes.ts +2 -2
- package/src/composables/accountingHost.ts +24 -0
- package/src/composables/collections/uiHost.ts +17 -2
- package/src/composables/useDashboard.ts +191 -0
- package/src/composables/useMarkdownZip.ts +51 -0
- package/src/composables/useNotifications.ts +1 -4
- package/src/composables/useSharePack.ts +60 -0
- package/src/composables/useTranslatedQueries.ts +15 -95
- package/src/composables/useTranslatedStrings.ts +68 -0
- package/src/composables/useVoiceInput.ts +3 -3
- package/src/config/apiRoutes.ts +57 -9
- package/src/config/createFilePolicy.ts +1 -1
- package/src/config/firebase.ts +12 -0
- package/src/config/firebaseConfig.ts +18 -0
- package/src/config/historyFilters.ts +7 -0
- package/src/config/pubsubChannels.ts +7 -27
- package/src/config/roles.ts +12 -10
- package/src/config/workspacePaths.ts +10 -0
- package/src/index.css +1 -1
- package/src/lang/de.ts +39 -220
- package/src/lang/en.ts +39 -191
- package/src/lang/es.ts +39 -218
- package/src/lang/fr.ts +39 -220
- package/src/lang/ja.ts +39 -216
- package/src/lang/ko.ts +39 -216
- package/src/lang/pt-BR.ts +39 -217
- package/src/lang/zh.ts +39 -215
- package/src/main.ts +3 -0
- package/src/plugins/accounting/definition.ts +12 -8
- package/src/plugins/accounting/index.ts +7 -4
- package/src/plugins/accounting/meta.ts +23 -60
- package/src/plugins/manageSkills/View.vue +9 -1
- package/src/plugins/photoLocations/View.vue +2 -2
- package/src/plugins/presentCollection/definition.ts +2 -2
- package/src/plugins/presentCollection/plugin.ts +2 -2
- package/src/plugins/presentCollection/types.ts +2 -2
- package/src/plugins/presentHtml/definition.ts +1 -1
- package/src/plugins/presentMulmoScript/View.vue +2 -2
- package/src/plugins/presentMulmoScript/helpers.ts +1 -1
- package/src/plugins/presentSVG/View.vue +2 -2
- package/src/plugins/scheduler/TasksTab.vue +1 -2
- package/src/plugins/skill/View.vue +7 -3
- package/src/plugins/spreadsheet/View.vue +3 -3
- package/src/plugins/spreadsheet/engine/functions/logical.ts +8 -1
- package/src/plugins/textResponse/View.vue +43 -16
- package/src/plugins/wiki/View.vue +29 -2
- package/src/plugins/wiki/components/WikiGraphView.vue +1 -1
- package/src/plugins/wiki/components/WikiPageBody.vue +4 -1
- package/src/plugins/wiki/helpers.ts +13 -81
- package/src/plugins/wiki/index.ts +1 -1
- package/src/router/guards.ts +1 -1
- package/src/router/index.ts +12 -0
- package/src/router/pageRoutes.ts +2 -0
- package/src/types/dashboard.ts +40 -0
- package/src/types/session.ts +3 -0
- package/src/utils/blobDownload.ts +19 -0
- package/src/utils/collections/presentSeed.ts +1 -1
- package/src/utils/html/customViewSrcdoc.ts +31 -3
- package/src/utils/html/previewCsp.ts +1 -1
- package/src/utils/id.ts +1 -1
- package/src/utils/image/htmlSrcAttrs.ts +1 -1
- package/src/utils/markdown/frontmatter.ts +12 -7
- package/src/utils/markdown/highlight.ts +22 -0
- package/src/utils/markdown/marpCustomSize.ts +2 -2
- package/src/utils/markdown/mermaidExtension.ts +56 -0
- package/src/utils/markdown/mermaidRender.ts +147 -0
- package/src/utils/markdown/setup.ts +17 -4
- package/src/utils/markdown/useMermaid.ts +33 -0
- package/src/utils/session/longRunning.ts +33 -0
- package/src/utils/session/mergeSessions.ts +1 -1
- package/client/assets/JsonEditor-Di5xGeZY.css +0 -1
- package/client/assets/JsonEditor-o5--tPQH.js +0 -10
- package/client/assets/index-tOu5ArRZ.css +0 -2
- package/client/assets/lib-D6Xy0IFc.js +0 -114
- package/client/assets/marp-D6GXA-EB.js +0 -3452
- package/client/assets/material-symbols-outlined-DtIK7AQn.woff2 +0 -0
- package/client/assets/runtime-protocol-vue-pU0Mw7Zm.js +0 -1
- package/client/assets/runtime-vue-fFYhnNg3.js +0 -1
- package/client/assets/vue-UDIWDtr8.js +0 -1
- package/client/assets/vue-i18n-CQbxVmNs.js +0 -3
- package/client/assets/vue.runtime.esm-bundler-BTyIdNAI.js +0 -4
- package/server/accounting/accountNormalize.ts +0 -32
- package/server/accounting/defaultAccounts.ts +0 -87
- package/server/accounting/eventPublisher.ts +0 -52
- package/server/accounting/journal.ts +0 -252
- package/server/accounting/openingBalances.ts +0 -114
- package/server/accounting/report.ts +0 -237
- package/server/accounting/service.ts +0 -718
- package/server/accounting/snapshotCache.ts +0 -334
- package/server/accounting/timeSeries.ts +0 -265
- package/server/accounting/types.ts +0 -148
- package/server/api/routes/accounting.ts +0 -373
- package/server/api/routes/wiki/frontmatter.ts +0 -34
- package/server/api/routes/wiki/pageIndex.ts +0 -53
- package/server/system/logs/aaa +0 -737
- package/server/system/logs/bb +0 -446
- package/server/utils/files/accounting-io.ts +0 -294
- package/server/workspace/feeds/engine.ts +0 -143
- package/server/workspace/feeds/fetch/httpClient.ts +0 -127
- package/server/workspace/feeds/fetch/rssParser.ts +0 -117
- package/server/workspace/feeds/index.ts +0 -8
- package/server/workspace/feeds/ingestTypes.ts +0 -62
- package/server/workspace/feeds/pathResolver.ts +0 -74
- package/server/workspace/feeds/paths.ts +0 -30
- package/server/workspace/feeds/projectItem.ts +0 -92
- package/server/workspace/feeds/registry.ts +0 -43
- package/server/workspace/feeds/retrievers/httpJson.ts +0 -19
- package/server/workspace/feeds/retrievers/index.ts +0 -27
- package/server/workspace/feeds/retrievers/registerAll.ts +0 -5
- package/server/workspace/feeds/retrievers/rss.ts +0 -24
- package/server/workspace/feeds/state.ts +0 -55
- package/src/composables/useAccountingChannel.ts +0 -58
- package/src/lib/wiki-page/graph.ts +0 -108
- package/src/lib/wiki-page/index-parse.ts +0 -221
- package/src/lib/wiki-page/link.ts +0 -62
- package/src/lib/wiki-page/lint.ts +0 -105
- package/src/lib/wiki-page/paths.ts +0 -35
- package/src/lib/wiki-page/slug.ts +0 -54
- package/src/plugins/accounting/Preview.vue +0 -103
- package/src/plugins/accounting/View.vue +0 -633
- package/src/plugins/accounting/actions.ts +0 -34
- package/src/plugins/accounting/api.ts +0 -301
- package/src/plugins/accounting/components/AccountEditor.vue +0 -250
- package/src/plugins/accounting/components/AccountRow.vue +0 -50
- package/src/plugins/accounting/components/AccountsList.vue +0 -102
- package/src/plugins/accounting/components/AccountsModal.vue +0 -301
- package/src/plugins/accounting/components/BalanceSheet.vue +0 -186
- package/src/plugins/accounting/components/BookSettings.vue +0 -284
- package/src/plugins/accounting/components/BookSwitcher.vue +0 -78
- package/src/plugins/accounting/components/DateRangePicker.vue +0 -140
- package/src/plugins/accounting/components/JournalEntryForm.vue +0 -505
- package/src/plugins/accounting/components/JournalList.vue +0 -554
- package/src/plugins/accounting/components/Ledger.vue +0 -206
- package/src/plugins/accounting/components/NewBookForm.vue +0 -211
- package/src/plugins/accounting/components/OpeningBalancesForm.vue +0 -272
- package/src/plugins/accounting/components/ProfitLoss.vue +0 -160
- package/src/plugins/accounting/components/accountDraft.ts +0 -13
- package/src/plugins/accounting/components/accountNumbering.ts +0 -103
- package/src/plugins/accounting/components/accountValidation.ts +0 -75
- package/src/plugins/accounting/components/useLatestRequest.ts +0 -44
- package/src/plugins/accounting/countries.ts +0 -158
- package/src/plugins/accounting/currencies.ts +0 -77
- package/src/plugins/accounting/dates.ts +0 -51
- package/src/plugins/accounting/fiscalYear.ts +0 -136
- package/src/plugins/accounting/timeSeriesEnums.ts +0 -16
- package/src/plugins/wiki/route.ts +0 -137
- /package/client/assets/{_plugin-vue_export-helper-B67ILkmu.js → _plugin-vue_export-helper-BDNMzG2s.js} +0 -0
- /package/client/assets/{purify.es-B27wDFIb-51iYcXuK.js → purify.es-B27wDFIb-Bu4Grnl0.js} +0 -0
- /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>
|