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