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,334 +0,0 @@
|
|
|
1
|
-
// Monthly balance snapshot cache.
|
|
2
|
-
//
|
|
3
|
-
// Source of truth: the journal JSONL files. Snapshots are derived
|
|
4
|
-
// state — `data/accounting/books/<id>/snapshots/YYYY-MM.json` is
|
|
5
|
-
// only ever a perf optimization. The invariant we maintain:
|
|
6
|
-
//
|
|
7
|
-
// for any (book, period) pair,
|
|
8
|
-
// getOrBuildSnapshot(book, period)
|
|
9
|
-
// ===
|
|
10
|
-
// aggregateBalances(<all entries up to period end>)
|
|
11
|
-
//
|
|
12
|
-
// I.e. running with snapshots and running without snapshots must
|
|
13
|
-
// produce byte-identical results. The unit test for this lives in
|
|
14
|
-
// `test/accounting/test_snapshotCache.ts`.
|
|
15
|
-
//
|
|
16
|
-
// Rebuild policy: writes call `scheduleRebuild(bookId, fromPeriod)`
|
|
17
|
-
// after invalidating stale snapshot files. Each book has at most one
|
|
18
|
-
// rebuild in flight; additional writes during a running rebuild merge
|
|
19
|
-
// into a single queued follow-up (so a burst of N writes runs at most
|
|
20
|
-
// two rebuilds). `getOrBuildSnapshot` keeps a lazy fallback so a
|
|
21
|
-
// report requested before the rebuild reaches that month is still
|
|
22
|
-
// correct — it just builds inline.
|
|
23
|
-
//
|
|
24
|
-
// Test API: `awaitRebuildIdle(bookId)` and `inspectRebuildQueue(bookId)`
|
|
25
|
-
// are diagnostics that let tests assert on queue state without
|
|
26
|
-
// sleep-and-poll. Production code never needs them.
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
invalidateSnapshotsFrom as ioInvalidateFrom,
|
|
30
|
-
invalidateAllSnapshots as ioInvalidateAll,
|
|
31
|
-
listJournalPeriods,
|
|
32
|
-
readJournalMonth,
|
|
33
|
-
readSnapshot,
|
|
34
|
-
writeSnapshot,
|
|
35
|
-
} from "../utils/files/accounting-io.js";
|
|
36
|
-
import { aggregateBalances } from "./report.js";
|
|
37
|
-
import { publishBookChange } from "./eventPublisher.js";
|
|
38
|
-
import { log } from "../system/logger/index.js";
|
|
39
|
-
import { errorMessage } from "../utils/errors.js";
|
|
40
|
-
import { ACCOUNTING_BOOK_EVENT_KINDS } from "../../src/config/pubsubChannels.js";
|
|
41
|
-
import type { AccountBalance, JournalEntry, MonthSnapshot } from "./types.js";
|
|
42
|
-
|
|
43
|
-
function previousPeriod(period: string): string {
|
|
44
|
-
// YYYY-MM → previous YYYY-MM. December rolls back to the previous
|
|
45
|
-
// year's December.
|
|
46
|
-
const [year, month] = period.split("-").map((segment) => parseInt(segment, 10));
|
|
47
|
-
if (month === 1) return `${(year - 1).toString().padStart(4, "0")}-12`;
|
|
48
|
-
return `${year.toString().padStart(4, "0")}-${(month - 1).toString().padStart(2, "0")}`;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function mergeBalances(base: readonly AccountBalance[], delta: readonly AccountBalance[]): AccountBalance[] {
|
|
52
|
-
const map = new Map<string, number>();
|
|
53
|
-
for (const row of base) map.set(row.accountCode, row.netDebit);
|
|
54
|
-
for (const row of delta) {
|
|
55
|
-
map.set(row.accountCode, (map.get(row.accountCode) ?? 0) + row.netDebit);
|
|
56
|
-
}
|
|
57
|
-
return Array.from(map.entries())
|
|
58
|
-
.map(([accountCode, netDebit]) => ({ accountCode, netDebit }))
|
|
59
|
-
.sort((lhs, rhs) => lhs.accountCode.localeCompare(rhs.accountCode));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async function buildEmptySnapshot(bookId: string, period: string, workspaceRoot?: string): Promise<MonthSnapshot> {
|
|
63
|
-
const empty: MonthSnapshot = { period, balances: [], builtAt: new Date().toISOString() };
|
|
64
|
-
await writeSnapshot(bookId, empty, workspaceRoot);
|
|
65
|
-
return empty;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Build a snapshot at end-of-`period` for one book, lazily relying
|
|
69
|
-
* on the previous month's snapshot if it exists. Falls all the way
|
|
70
|
-
* back to the earliest journal month if no upstream snapshot is
|
|
71
|
-
* available. Always writes the result to disk before returning. */
|
|
72
|
-
export async function getOrBuildSnapshot(bookId: string, period: string, workspaceRoot?: string): Promise<MonthSnapshot> {
|
|
73
|
-
const cached = await readSnapshot(bookId, period, workspaceRoot);
|
|
74
|
-
if (cached) return cached;
|
|
75
|
-
|
|
76
|
-
// Earliest journal month determines where the recursion stops.
|
|
77
|
-
// If the book has no journal at all, return an empty snapshot.
|
|
78
|
-
const periods = await listJournalPeriods(bookId, workspaceRoot);
|
|
79
|
-
if (periods.length === 0 || period < periods[0]) {
|
|
80
|
-
return buildEmptySnapshot(bookId, period, workspaceRoot);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const { entries } = await readJournalMonth(bookId, period, workspaceRoot);
|
|
84
|
-
const monthDelta = aggregateBalances(entries);
|
|
85
|
-
|
|
86
|
-
// Get the prior month's closing snapshot — recurse, which will
|
|
87
|
-
// either hit cache or build the chain back to the start.
|
|
88
|
-
let priorBalances: readonly AccountBalance[] = [];
|
|
89
|
-
if (period > periods[0]) {
|
|
90
|
-
const prior = previousPeriod(period);
|
|
91
|
-
const priorSnap = await getOrBuildSnapshot(bookId, prior, workspaceRoot);
|
|
92
|
-
priorBalances = priorSnap.balances;
|
|
93
|
-
}
|
|
94
|
-
const merged = mergeBalances(priorBalances, monthDelta);
|
|
95
|
-
const snap: MonthSnapshot = {
|
|
96
|
-
period,
|
|
97
|
-
balances: merged,
|
|
98
|
-
builtAt: new Date().toISOString(),
|
|
99
|
-
};
|
|
100
|
-
await writeSnapshot(bookId, snap, workspaceRoot);
|
|
101
|
-
return snap;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/** Compute closing balances at end-of-`period` from journal alone,
|
|
105
|
-
* bypassing the snapshot cache. Used by the byte-equality
|
|
106
|
-
* invariant test, and as a safety net for "compute without
|
|
107
|
-
* trusting cache" paths. */
|
|
108
|
-
export async function balancesAtEndOf(bookId: string, period: string, workspaceRoot?: string): Promise<AccountBalance[]> {
|
|
109
|
-
const periods = await listJournalPeriods(bookId, workspaceRoot);
|
|
110
|
-
const all: JournalEntry[] = [];
|
|
111
|
-
for (const monthKey of periods) {
|
|
112
|
-
if (period < monthKey) break;
|
|
113
|
-
const { entries } = await readJournalMonth(bookId, monthKey, workspaceRoot);
|
|
114
|
-
for (const entry of entries) all.push(entry);
|
|
115
|
-
}
|
|
116
|
-
return aggregateBalances(all);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** Drop snapshots for `fromPeriod` and later. Re-export from
|
|
120
|
-
* accounting-io for callers that conceptually live in the cache
|
|
121
|
-
* layer (so they don't reach into the IO module). */
|
|
122
|
-
export async function invalidateSnapshotsFrom(bookId: string, fromPeriod: string, workspaceRoot?: string): Promise<{ removed: string[] }> {
|
|
123
|
-
return ioInvalidateFrom(bookId, fromPeriod, workspaceRoot);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/** Drop all snapshots and rebuild from scratch. Used by the
|
|
127
|
-
* `rebuildSnapshots` admin action. Returns the periods that were
|
|
128
|
-
* rebuilt. */
|
|
129
|
-
export async function rebuildAllSnapshots(bookId: string, workspaceRoot?: string): Promise<{ rebuilt: string[] }> {
|
|
130
|
-
await ioInvalidateAll(bookId, workspaceRoot);
|
|
131
|
-
const periods = await listJournalPeriods(bookId, workspaceRoot);
|
|
132
|
-
for (const monthKey of periods) {
|
|
133
|
-
await getOrBuildSnapshot(bookId, monthKey, workspaceRoot);
|
|
134
|
-
}
|
|
135
|
-
return { rebuilt: periods };
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ── async rebuild queue ────────────────────────────────────────────
|
|
139
|
-
//
|
|
140
|
-
// Per-book queue. A `running` promise represents the in-flight
|
|
141
|
-
// rebuild. While it's running, additional `scheduleRebuild` calls
|
|
142
|
-
// merge their `fromPeriod` into `pendingFromPeriod` (taking the
|
|
143
|
-
// minimum so the next pass covers everyone's invalidation), and we
|
|
144
|
-
// kick off a follow-up once the current one resolves.
|
|
145
|
-
|
|
146
|
-
interface RebuildQueueEntry {
|
|
147
|
-
running: Promise<void>;
|
|
148
|
-
pendingFromPeriod: string | null;
|
|
149
|
-
pendingWorkspaceRoot: string | undefined;
|
|
150
|
-
coalescedWriteCount: number;
|
|
151
|
-
runningFromPeriod: string;
|
|
152
|
-
/** Set by `cancelRebuild` (called from `deleteBook`). The runRebuild
|
|
153
|
-
* loop checks before each write so a rebuild cannot resurrect the
|
|
154
|
-
* book directory after `removeBookDir` has run. */
|
|
155
|
-
cancelled: boolean;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const rebuildQueues = new Map<string, RebuildQueueEntry>();
|
|
159
|
-
|
|
160
|
-
function minPeriod(lhs: string | null, rhs: string): string {
|
|
161
|
-
if (lhs === null) return rhs;
|
|
162
|
-
return lhs < rhs ? lhs : rhs;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function isInvalidatedDuringRebuild(bookId: string, period: string): boolean {
|
|
166
|
-
// A pending invalidation that covers `period` means the queued
|
|
167
|
-
// follow-up rebuild will redo this period. Skip the in-flight
|
|
168
|
-
// write so we don't pollute the cache with stale data while a
|
|
169
|
-
// fresher computation is queued. Without this guard, the
|
|
170
|
-
// sequence "rebuild reads journal → caller writes a new entry →
|
|
171
|
-
// caller invalidates → rebuild writes (stale) snapshot" leaves
|
|
172
|
-
// the cache lying about the latest state.
|
|
173
|
-
const queue = rebuildQueues.get(bookId);
|
|
174
|
-
return queue !== undefined && queue.pendingFromPeriod !== null && period >= queue.pendingFromPeriod;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function isCancelled(bookId: string): boolean {
|
|
178
|
-
return rebuildQueues.get(bookId)?.cancelled === true;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async function runRebuild(bookId: string, fromPeriod: string, workspaceRoot: string | undefined): Promise<void> {
|
|
182
|
-
const startedAt = Date.now();
|
|
183
|
-
log.info("accounting", "snapshot rebuild started", { bookId, fromPeriod });
|
|
184
|
-
publishBookChange(bookId, { kind: ACCOUNTING_BOOK_EVENT_KINDS.snapshotsRebuilding, period: fromPeriod });
|
|
185
|
-
const periods = await listJournalPeriods(bookId, workspaceRoot);
|
|
186
|
-
const targets = periods.filter((monthKey) => monthKey >= fromPeriod);
|
|
187
|
-
let written = 0;
|
|
188
|
-
for (const monthKey of targets) {
|
|
189
|
-
if (isCancelled(bookId)) break;
|
|
190
|
-
if (isInvalidatedDuringRebuild(bookId, monthKey)) break;
|
|
191
|
-
// Compute fresh from journal — bypasses getOrBuildSnapshot's
|
|
192
|
-
// own write side-effect so the staleness check below is the
|
|
193
|
-
// only writer in the rebuild path.
|
|
194
|
-
const balances = await balancesAtEndOf(bookId, monthKey, workspaceRoot);
|
|
195
|
-
if (isCancelled(bookId)) break;
|
|
196
|
-
if (isInvalidatedDuringRebuild(bookId, monthKey)) break;
|
|
197
|
-
await writeSnapshot(bookId, { period: monthKey, balances, builtAt: new Date().toISOString() }, workspaceRoot);
|
|
198
|
-
if (isCancelled(bookId)) {
|
|
199
|
-
// The book was deleted between our last check and the write —
|
|
200
|
-
// `writeSnapshot` will have re-created the book directory tree
|
|
201
|
-
// via mkdir-recursive. Undo it so we don't leave an orphaned
|
|
202
|
-
// directory after `deleteBook` has run.
|
|
203
|
-
await ioInvalidateFrom(bookId, monthKey, workspaceRoot);
|
|
204
|
-
break;
|
|
205
|
-
}
|
|
206
|
-
if (isInvalidatedDuringRebuild(bookId, monthKey)) {
|
|
207
|
-
// A concurrent invalidate raced ahead between our last check
|
|
208
|
-
// and the disk write. The data we just wrote may be stale
|
|
209
|
-
// relative to the latest journal — undo so the queued
|
|
210
|
-
// follow-up rebuild starts from a clean slate.
|
|
211
|
-
await ioInvalidateFrom(bookId, monthKey, workspaceRoot);
|
|
212
|
-
break;
|
|
213
|
-
}
|
|
214
|
-
written += 1;
|
|
215
|
-
publishBookChange(bookId, { kind: ACCOUNTING_BOOK_EVENT_KINDS.snapshotsReady, period: monthKey });
|
|
216
|
-
}
|
|
217
|
-
log.info("accounting", "snapshot rebuild done", { bookId, periods: written, durationMs: Date.now() - startedAt });
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function startRebuild(bookId: string, fromPeriod: string, workspaceRoot: string | undefined): RebuildQueueEntry {
|
|
221
|
-
const entry: RebuildQueueEntry = {
|
|
222
|
-
running: Promise.resolve(),
|
|
223
|
-
pendingFromPeriod: null,
|
|
224
|
-
pendingWorkspaceRoot: undefined,
|
|
225
|
-
coalescedWriteCount: 1,
|
|
226
|
-
runningFromPeriod: fromPeriod,
|
|
227
|
-
cancelled: false,
|
|
228
|
-
};
|
|
229
|
-
entry.running = runRebuild(bookId, fromPeriod, workspaceRoot)
|
|
230
|
-
.catch((err) => {
|
|
231
|
-
// A rebuild failure is logged but does not poison the queue —
|
|
232
|
-
// the next `scheduleRebuild` call will start a fresh promise.
|
|
233
|
-
log.error("accounting", "snapshot rebuild failed", { bookId, fromPeriod, error: errorMessage(err) });
|
|
234
|
-
})
|
|
235
|
-
.then(() => {
|
|
236
|
-
// Drain any work that piled up while we were running.
|
|
237
|
-
const current = rebuildQueues.get(bookId);
|
|
238
|
-
if (!current) return;
|
|
239
|
-
// If the book was cancelled mid-rebuild (e.g. deleteBook ran),
|
|
240
|
-
// drop the queue entry entirely — we must not start a successor
|
|
241
|
-
// that would re-create the deleted book directory.
|
|
242
|
-
if (current.cancelled) {
|
|
243
|
-
rebuildQueues.delete(bookId);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (current.pendingFromPeriod !== null) {
|
|
247
|
-
const nextFrom = current.pendingFromPeriod;
|
|
248
|
-
const nextRoot = current.pendingWorkspaceRoot;
|
|
249
|
-
const carriedCount = current.coalescedWriteCount;
|
|
250
|
-
const successor = startRebuild(bookId, nextFrom, nextRoot);
|
|
251
|
-
successor.coalescedWriteCount += carriedCount;
|
|
252
|
-
rebuildQueues.set(bookId, successor);
|
|
253
|
-
} else {
|
|
254
|
-
rebuildQueues.delete(bookId);
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
return entry;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/** Schedule a background rebuild for `bookId` starting at `fromPeriod`.
|
|
261
|
-
* Multiple calls during an in-flight rebuild coalesce into a single
|
|
262
|
-
* follow-up rebuild that covers the minimum `fromPeriod` seen.
|
|
263
|
-
* Returns immediately — the rebuild runs on its own promise chain. */
|
|
264
|
-
export function scheduleRebuild(bookId: string, fromPeriod: string, workspaceRoot?: string): void {
|
|
265
|
-
const existing = rebuildQueues.get(bookId);
|
|
266
|
-
if (!existing) {
|
|
267
|
-
rebuildQueues.set(bookId, startRebuild(bookId, fromPeriod, workspaceRoot));
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
existing.pendingFromPeriod = minPeriod(existing.pendingFromPeriod, fromPeriod);
|
|
271
|
-
existing.pendingWorkspaceRoot = workspaceRoot;
|
|
272
|
-
existing.coalescedWriteCount += 1;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/** Test/diagnostic: resolves when no rebuild is running or queued for
|
|
276
|
-
* `bookId`. Also called by `deleteBook` after `cancelRebuild` to
|
|
277
|
-
* ensure a previously running rebuild has fully stopped before the
|
|
278
|
-
* caller removes the book's directory on disk. */
|
|
279
|
-
export async function awaitRebuildIdle(bookId: string): Promise<void> {
|
|
280
|
-
while (rebuildQueues.has(bookId)) {
|
|
281
|
-
const entry = rebuildQueues.get(bookId);
|
|
282
|
-
if (!entry) return;
|
|
283
|
-
await entry.running;
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/** Mark the book's in-flight rebuild as cancelled. The runRebuild
|
|
288
|
-
* loop checks before each write and bails out, so a subsequent
|
|
289
|
-
* `removeBookDir` cannot race with a `writeSnapshot` that would
|
|
290
|
-
* re-create the directory tree. Pair with `awaitRebuildIdle(bookId)`
|
|
291
|
-
* to wait for the in-flight rebuild to finish bailing. */
|
|
292
|
-
export function cancelRebuild(bookId: string): void {
|
|
293
|
-
const entry = rebuildQueues.get(bookId);
|
|
294
|
-
if (!entry) return;
|
|
295
|
-
entry.cancelled = true;
|
|
296
|
-
// Drop pending too — a cancelled book should not get a successor
|
|
297
|
-
// rebuild after the in-flight one drains.
|
|
298
|
-
entry.pendingFromPeriod = null;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/** Test/diagnostic: snapshot of the per-book queue state. Stable
|
|
302
|
-
* enough to assert against; fields may grow over time. */
|
|
303
|
-
export function inspectRebuildQueue(bookId: string): {
|
|
304
|
-
running: boolean;
|
|
305
|
-
runningFromPeriod: string | null;
|
|
306
|
-
pendingFromPeriod: string | null;
|
|
307
|
-
coalescedWriteCount: number;
|
|
308
|
-
} {
|
|
309
|
-
const entry = rebuildQueues.get(bookId);
|
|
310
|
-
if (!entry) {
|
|
311
|
-
return { running: false, runningFromPeriod: null, pendingFromPeriod: null, coalescedWriteCount: 0 };
|
|
312
|
-
}
|
|
313
|
-
return {
|
|
314
|
-
running: true,
|
|
315
|
-
runningFromPeriod: entry.runningFromPeriod,
|
|
316
|
-
pendingFromPeriod: entry.pendingFromPeriod,
|
|
317
|
-
coalescedWriteCount: entry.coalescedWriteCount,
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/** Test-only — drain all in-flight rebuilds, then drop queue state.
|
|
322
|
-
* Awaiting first means a leftover rebuild can't continue writing
|
|
323
|
-
* into the next test's tmp dir after we clear the bookkeeping. */
|
|
324
|
-
export async function _resetRebuildQueueForTesting(): Promise<void> {
|
|
325
|
-
// Mark everything cancelled so loops bail at their next checkpoint
|
|
326
|
-
// instead of continuing through every period.
|
|
327
|
-
for (const entry of rebuildQueues.values()) {
|
|
328
|
-
entry.cancelled = true;
|
|
329
|
-
entry.pendingFromPeriod = null;
|
|
330
|
-
}
|
|
331
|
-
const pending = Array.from(rebuildQueues.values()).map((entry) => entry.running);
|
|
332
|
-
await Promise.allSettled(pending);
|
|
333
|
-
rebuildQueues.clear();
|
|
334
|
-
}
|
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
// Time-series aggregation for the accounting plugin: bucketise a
|
|
2
|
-
// date range by month / fiscal quarter / fiscal year and roll up a
|
|
3
|
-
// metric (revenue / expense / net income / closing balance of a
|
|
4
|
-
// specific account) into a chart-ready `(label, value)[]` series.
|
|
5
|
-
//
|
|
6
|
-
// LLM-facing only — the in-canvas Accounting `<View>` keeps using
|
|
7
|
-
// `getReport` for its tab-driven UI. `getTimeSeries` exists so a
|
|
8
|
-
// single tool round-trip can answer "chart my quarterly revenue
|
|
9
|
-
// over the last two years" without the LLM fanning out N calls and
|
|
10
|
-
// stitching the buckets itself.
|
|
11
|
-
//
|
|
12
|
-
// Pure module: no I/O, no service-layer awareness. Caller hands in
|
|
13
|
-
// the entries / accounts already loaded; we return the points.
|
|
14
|
-
|
|
15
|
-
import type { Account, AccountType, JournalEntry } from "./types.js";
|
|
16
|
-
import { aggregateBalances } from "./report.js";
|
|
17
|
-
import { fiscalYearEndMonth, type FiscalYearEnd } from "../../src/plugins/accounting/fiscalYear.js";
|
|
18
|
-
import {
|
|
19
|
-
TIME_SERIES_GRANULARITIES,
|
|
20
|
-
TIME_SERIES_METRICS,
|
|
21
|
-
type TimeSeriesGranularity,
|
|
22
|
-
type TimeSeriesMetric,
|
|
23
|
-
} from "../../src/plugins/accounting/timeSeriesEnums.js";
|
|
24
|
-
|
|
25
|
-
export { TIME_SERIES_GRANULARITIES, TIME_SERIES_METRICS };
|
|
26
|
-
export type { TimeSeriesGranularity, TimeSeriesMetric };
|
|
27
|
-
|
|
28
|
-
export interface Bucket {
|
|
29
|
-
/** Inclusive YYYY-MM-DD lower bound. */
|
|
30
|
-
from: string;
|
|
31
|
-
/** Inclusive YYYY-MM-DD upper bound. */
|
|
32
|
-
to: string;
|
|
33
|
-
/** Chart x-axis label. Format depends on granularity:
|
|
34
|
-
* "YYYY-MM" / "FY{endYear}-Q{1..4}" / "FY{endYear}". For fiscal
|
|
35
|
-
* years that don't align with the calendar year (Q1/Q2/Q3 books)
|
|
36
|
-
* the FY is named by its END calendar year — matches Japanese
|
|
37
|
-
* "令和7年度" convention (Apr 2025 - Mar 2026 = FY2026). */
|
|
38
|
-
label: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export interface TimeSeriesPoint {
|
|
42
|
-
label: string;
|
|
43
|
-
from: string;
|
|
44
|
-
to: string;
|
|
45
|
-
/** Single number, natural-sign per metric. Revenue and net income
|
|
46
|
-
* positive when income exceeds expense; expense reported as a
|
|
47
|
-
* positive cost; account balance follows the account's display
|
|
48
|
-
* sign (assets debit-positive, liabilities/equity credit-positive). */
|
|
49
|
-
value: number;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ── date arithmetic (pure, no Date for parsing/formatting) ─────────
|
|
53
|
-
|
|
54
|
-
function pad2(num: number): string {
|
|
55
|
-
return String(num).padStart(2, "0");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function fmtYmd(year: number, month: number, day: number): string {
|
|
59
|
-
return `${year}-${pad2(month)}-${pad2(day)}`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface YmdParts {
|
|
63
|
-
year: number;
|
|
64
|
-
month: number;
|
|
65
|
-
day: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function parseYmd(value: string): YmdParts {
|
|
69
|
-
const [year, month, day] = value.split("-").map((segment) => parseInt(segment, 10));
|
|
70
|
-
return { year, month, day };
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function lastDayOf(year: number, month: number): number {
|
|
74
|
-
// UTC day 0 of next month = last day of this month, immune to TZ.
|
|
75
|
-
return new Date(Date.UTC(year, month, 0)).getUTCDate();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function addDay(date: YmdParts): YmdParts {
|
|
79
|
-
const stepped = new Date(Date.UTC(date.year, date.month - 1, date.day + 1));
|
|
80
|
-
return {
|
|
81
|
-
year: stepped.getUTCFullYear(),
|
|
82
|
-
month: stepped.getUTCMonth() + 1,
|
|
83
|
-
day: stepped.getUTCDate(),
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ── fiscal-year arithmetic (year-month, no Date) ───────────────────
|
|
88
|
-
|
|
89
|
-
interface FyAnchor {
|
|
90
|
-
/** Calendar year the fiscal year STARTED in. */
|
|
91
|
-
fyStartYear: number;
|
|
92
|
-
/** Calendar year the fiscal year ENDS in (used for labelling). */
|
|
93
|
-
fyEndYear: number;
|
|
94
|
-
/** First calendar month of the fiscal year (1-based). */
|
|
95
|
-
startMonth: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function fyAnchorFor(date: YmdParts, end: FiscalYearEnd): FyAnchor {
|
|
99
|
-
const closingMonth = fiscalYearEndMonth(end);
|
|
100
|
-
const startMonth = (closingMonth % 12) + 1; // month after the close
|
|
101
|
-
// FY containing date: started this calendar year if date.month is
|
|
102
|
-
// at-or-after startMonth, else previous calendar year. Q4 books
|
|
103
|
-
// (startMonth = 1) always land in the same calendar year — covered
|
|
104
|
-
// by the same predicate.
|
|
105
|
-
const fyStartYear = date.month >= startMonth ? date.year : date.year - 1;
|
|
106
|
-
const fyEndYear = closingMonth === 12 ? fyStartYear : fyStartYear + 1;
|
|
107
|
-
return { fyStartYear, fyEndYear, startMonth };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ── per-granularity bucket lookup ──────────────────────────────────
|
|
111
|
-
|
|
112
|
-
function monthBucketContaining(date: YmdParts): Bucket {
|
|
113
|
-
return {
|
|
114
|
-
from: fmtYmd(date.year, date.month, 1),
|
|
115
|
-
to: fmtYmd(date.year, date.month, lastDayOf(date.year, date.month)),
|
|
116
|
-
label: `${date.year}-${pad2(date.month)}`,
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function quarterBucketContaining(date: YmdParts, end: FiscalYearEnd): Bucket {
|
|
121
|
-
const anchor = fyAnchorFor(date, end);
|
|
122
|
-
const offset = (date.month - anchor.startMonth + 12) % 12; // 0..11
|
|
123
|
-
const qIdx = Math.floor(offset / 3); // 0..3
|
|
124
|
-
// Flat month-index from the calendar epoch makes year rollover
|
|
125
|
-
// arithmetic trivial.
|
|
126
|
-
const startFlat = anchor.fyStartYear * 12 + (anchor.startMonth - 1) + qIdx * 3;
|
|
127
|
-
const endFlat = startFlat + 2;
|
|
128
|
-
const qStartYear = Math.floor(startFlat / 12);
|
|
129
|
-
const qStartMonth = (startFlat % 12) + 1;
|
|
130
|
-
const qEndYear = Math.floor(endFlat / 12);
|
|
131
|
-
const qEndMonth = (endFlat % 12) + 1;
|
|
132
|
-
return {
|
|
133
|
-
from: fmtYmd(qStartYear, qStartMonth, 1),
|
|
134
|
-
to: fmtYmd(qEndYear, qEndMonth, lastDayOf(qEndYear, qEndMonth)),
|
|
135
|
-
label: `FY${anchor.fyEndYear}-Q${qIdx + 1}`,
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function yearBucketContaining(date: YmdParts, end: FiscalYearEnd): Bucket {
|
|
140
|
-
const anchor = fyAnchorFor(date, end);
|
|
141
|
-
const startFlat = anchor.fyStartYear * 12 + (anchor.startMonth - 1);
|
|
142
|
-
const endFlat = startFlat + 11;
|
|
143
|
-
const yStartYear = Math.floor(startFlat / 12);
|
|
144
|
-
const yStartMonth = (startFlat % 12) + 1;
|
|
145
|
-
const yEndYear = Math.floor(endFlat / 12);
|
|
146
|
-
const yEndMonth = (endFlat % 12) + 1;
|
|
147
|
-
return {
|
|
148
|
-
from: fmtYmd(yStartYear, yStartMonth, 1),
|
|
149
|
-
to: fmtYmd(yEndYear, yEndMonth, lastDayOf(yEndYear, yEndMonth)),
|
|
150
|
-
label: `FY${anchor.fyEndYear}`,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function bucketContaining(date: YmdParts, granularity: TimeSeriesGranularity, end: FiscalYearEnd): Bucket {
|
|
155
|
-
if (granularity === "month") return monthBucketContaining(date);
|
|
156
|
-
if (granularity === "quarter") return quarterBucketContaining(date, end);
|
|
157
|
-
return yearBucketContaining(date, end);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/** Walk inclusive `[from, to]` and return every bucket that overlaps
|
|
161
|
-
* it, ordered ascending by `from`. The first bucket is the one
|
|
162
|
-
* CONTAINING `from` — it can extend earlier than `from`; the last
|
|
163
|
-
* bucket is the one CONTAINING `to` — it can extend past `to`. The
|
|
164
|
-
* caller's response echoes the input range so the LLM can label the
|
|
165
|
-
* chart truthfully ("Revenue Apr 2025 – Sep 2026" even though the
|
|
166
|
-
* outermost buckets cover Apr-Jun 2025 and Jul-Sep 2026). */
|
|
167
|
-
export function bucketize(input: { from: string; to: string; granularity: TimeSeriesGranularity; fiscalYearEnd: FiscalYearEnd }): Bucket[] {
|
|
168
|
-
if (input.from > input.to) return [];
|
|
169
|
-
const start = parseYmd(input.from);
|
|
170
|
-
const result: Bucket[] = [];
|
|
171
|
-
let bucket = bucketContaining(start, input.granularity, input.fiscalYearEnd);
|
|
172
|
-
// Buckets are contiguous; once a bucket's `from` is past `input.to`
|
|
173
|
-
// every subsequent bucket is too.
|
|
174
|
-
while (bucket.from <= input.to) {
|
|
175
|
-
result.push(bucket);
|
|
176
|
-
const next = addDay(parseYmd(bucket.to));
|
|
177
|
-
bucket = bucketContaining(next, input.granularity, input.fiscalYearEnd);
|
|
178
|
-
}
|
|
179
|
-
return result;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// ── value computation ──────────────────────────────────────────────
|
|
183
|
-
|
|
184
|
-
/** Convert raw netDebit to natural-sign presentation per account
|
|
185
|
-
* type. Mirrors the helper in `report.ts` (kept private there). */
|
|
186
|
-
function naturalSign(type: AccountType, netDebit: number): number {
|
|
187
|
-
if (type === "asset" || type === "expense") return netDebit;
|
|
188
|
-
return -netDebit;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
interface PresentationTotals {
|
|
192
|
-
income: number;
|
|
193
|
-
expense: number;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/** Sum presented income and expense values across the supplied
|
|
197
|
-
* entries. Used for window-based metrics (revenue / expense /
|
|
198
|
-
* netIncome). Opening entries reference B/S accounts only and so
|
|
199
|
-
* contribute zero to either total — including them is harmless. */
|
|
200
|
-
function presentedPlTotals(entries: readonly JournalEntry[], accountTypeByCode: ReadonlyMap<string, AccountType>): PresentationTotals {
|
|
201
|
-
const balances = aggregateBalances(entries);
|
|
202
|
-
let income = 0;
|
|
203
|
-
let expense = 0;
|
|
204
|
-
for (const row of balances) {
|
|
205
|
-
const type = accountTypeByCode.get(row.accountCode);
|
|
206
|
-
if (!type) continue;
|
|
207
|
-
if (type === "income") income += naturalSign(type, row.netDebit);
|
|
208
|
-
else if (type === "expense") expense += naturalSign(type, row.netDebit);
|
|
209
|
-
}
|
|
210
|
-
return { income, expense };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function entriesInWindow(entries: readonly JournalEntry[], from: string, toDate: string): JournalEntry[] {
|
|
214
|
-
return entries.filter((entry) => entry.date >= from && entry.date <= toDate);
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function entriesUpTo(entries: readonly JournalEntry[], toDate: string): JournalEntry[] {
|
|
218
|
-
return entries.filter((entry) => entry.date <= toDate);
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function valueForBucket(input: {
|
|
222
|
-
bucket: Bucket;
|
|
223
|
-
entries: readonly JournalEntry[];
|
|
224
|
-
accounts: readonly Account[];
|
|
225
|
-
metric: TimeSeriesMetric;
|
|
226
|
-
accountCode?: string;
|
|
227
|
-
}): number {
|
|
228
|
-
const accountTypeByCode = new Map(input.accounts.map((acct) => [acct.code, acct.type]));
|
|
229
|
-
if (input.metric === "accountBalance") {
|
|
230
|
-
const code = input.accountCode;
|
|
231
|
-
if (!code) return 0; // guarded at the route — defensive zero.
|
|
232
|
-
const type = accountTypeByCode.get(code);
|
|
233
|
-
if (!type) return 0;
|
|
234
|
-
const cumulative = entriesUpTo(input.entries, input.bucket.to);
|
|
235
|
-
const balances = aggregateBalances(cumulative);
|
|
236
|
-
const row = balances.find((balance) => balance.accountCode === code);
|
|
237
|
-
return row ? naturalSign(type, row.netDebit) : 0;
|
|
238
|
-
}
|
|
239
|
-
const window = entriesInWindow(input.entries, input.bucket.from, input.bucket.to);
|
|
240
|
-
const totals = presentedPlTotals(window, accountTypeByCode);
|
|
241
|
-
if (input.metric === "revenue") return totals.income;
|
|
242
|
-
if (input.metric === "expense") return totals.expense;
|
|
243
|
-
return totals.income - totals.expense; // netIncome
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
export function buildTimeSeries(input: {
|
|
247
|
-
buckets: readonly Bucket[];
|
|
248
|
-
entries: readonly JournalEntry[];
|
|
249
|
-
accounts: readonly Account[];
|
|
250
|
-
metric: TimeSeriesMetric;
|
|
251
|
-
accountCode?: string;
|
|
252
|
-
}): TimeSeriesPoint[] {
|
|
253
|
-
return input.buckets.map((bucket) => ({
|
|
254
|
-
label: bucket.label,
|
|
255
|
-
from: bucket.from,
|
|
256
|
-
to: bucket.to,
|
|
257
|
-
value: valueForBucket({
|
|
258
|
-
bucket,
|
|
259
|
-
entries: input.entries,
|
|
260
|
-
accounts: input.accounts,
|
|
261
|
-
metric: input.metric,
|
|
262
|
-
accountCode: input.accountCode,
|
|
263
|
-
}),
|
|
264
|
-
}));
|
|
265
|
-
}
|