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
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// that's not worth it for so little glue. js-yaml does the heavy
|
|
11
11
|
// lifting in both places, identically.
|
|
12
12
|
|
|
13
|
-
import
|
|
13
|
+
import { FAILSAFE_SCHEMA, dump as yamlDump, load as yamlLoad } from "js-yaml";
|
|
14
14
|
|
|
15
15
|
export interface ParsedMarkdown {
|
|
16
16
|
/** Parsed YAML object. Empty `{}` when the document has no
|
|
@@ -71,7 +71,7 @@ export function serializeWithFrontmatter(meta: Record<string, unknown>, body: st
|
|
|
71
71
|
// one line. `noRefs: true` avoids YAML anchor syntax (`&id001`)
|
|
72
72
|
// which is technically valid but visually noisy in plain-text
|
|
73
73
|
// markdown.
|
|
74
|
-
const yamlText =
|
|
74
|
+
const yamlText = yamlDump(meta, { lineWidth: -1, noRefs: true }).trimEnd();
|
|
75
75
|
return `---\n${yamlText}\n---\n\n${body}`;
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -93,16 +93,20 @@ export function mergeFrontmatter(existing: Record<string, unknown>, patch: Recor
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function safeYamlLoad(text: string): Record<string, unknown> | null {
|
|
96
|
+
// js-yaml 5.x throws on empty / whitespace-only input where 4.x
|
|
97
|
+
// returned `undefined`. An empty frontmatter block is "no metadata",
|
|
98
|
+
// not "malformed", so handle it before the loader.
|
|
99
|
+
if (text.trim() === "") return {};
|
|
96
100
|
try {
|
|
97
101
|
// `FAILSAFE_SCHEMA` keeps every scalar as a string and skips
|
|
98
102
|
// type coercion. Two motivating cases:
|
|
99
103
|
// - YAML 1.1 dates (`created: 2026-04-27`) would become a
|
|
100
|
-
// `Date` object under
|
|
104
|
+
// `Date` object under CORE_SCHEMA, breaking round-trip.
|
|
101
105
|
// - Numeric-looking strings (`version: 1.20` → 1.2 under
|
|
102
106
|
// JSON_SCHEMA) drop trailing zeros on save.
|
|
103
107
|
// For the wiki-history use case — title / created / updated /
|
|
104
108
|
// tags / editor — every value that should be a string IS one.
|
|
105
|
-
const loaded =
|
|
109
|
+
const loaded = yamlLoad(text, { schema: FAILSAFE_SCHEMA });
|
|
106
110
|
if (loaded === null || loaded === undefined) return {};
|
|
107
111
|
if (typeof loaded !== "object" || Array.isArray(loaded)) return null;
|
|
108
112
|
return loaded as Record<string, unknown>;
|
package/server/utils/regex.ts
CHANGED
|
@@ -30,9 +30,10 @@ export const SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
|
30
30
|
|
|
31
31
|
// ── Wiki bullet-link parsers ──────────────────────────────────────
|
|
32
32
|
//
|
|
33
|
-
// Moved to
|
|
34
|
-
// lib extraction (#1297
|
|
35
|
-
// delimiters; the ReDoS-safety
|
|
33
|
+
// Moved to `@mulmoclaude/core/wiki` (`index-parse.ts`) as part of the
|
|
34
|
+
// pure-lib extraction (#1297, then promoted to shared core). The
|
|
35
|
+
// patterns are still bounded with hard delimiters; the ReDoS-safety
|
|
36
|
+
// rationale travelled with them.
|
|
36
37
|
|
|
37
38
|
// ── Skills body blank-line stripper ───────────────────────────────
|
|
38
39
|
//
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import { realpathSync } from "fs";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import JSZip from "jszip";
|
|
5
|
+
import { resolveWorkspacePath } from "../files/workspace-io.js";
|
|
6
|
+
import { resolveWithinRoot } from "../files/safe.js";
|
|
7
|
+
import { rewriteHtmlAssets } from "./rewriteAssets.js";
|
|
8
|
+
import { log } from "../../system/logger/index.js";
|
|
9
|
+
|
|
10
|
+
const LOG_PREFIX = "share";
|
|
11
|
+
|
|
12
|
+
export interface PackedFile {
|
|
13
|
+
bundlePath: string;
|
|
14
|
+
bytes: Buffer;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// A self-contained bundle: the rewritten entry document plus every
|
|
18
|
+
// referenced local asset, ready to zip. `name` is a suggested base
|
|
19
|
+
// filename (no extension) derived from the source page.
|
|
20
|
+
export interface PackedBundle {
|
|
21
|
+
name: string;
|
|
22
|
+
files: PackedFile[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// `resolveWithinRoot` requires an already-realpath'd root. Resolved
|
|
26
|
+
// lazily (not at import) so loading this module never depends on the
|
|
27
|
+
// workspace dir existing yet; the location doesn't change during a run.
|
|
28
|
+
let workspaceRealCache: string | null = null;
|
|
29
|
+
function workspaceReal(): string {
|
|
30
|
+
if (workspaceRealCache === null) workspaceRealCache = realpathSync(resolveWorkspacePath("."));
|
|
31
|
+
return workspaceRealCache;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function stripQueryHash(ref: string): string {
|
|
35
|
+
const cut = ref.search(/[?#]/);
|
|
36
|
+
return cut === -1 ? ref : ref.slice(0, cut);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Resolve a workspace-relative path to a contained absolute path, or
|
|
40
|
+
// null if it escapes the workspace / doesn't exist. `resolveWithinRoot`
|
|
41
|
+
// already realpath-checks containment; the extra `path.relative` guard
|
|
42
|
+
// is the form CodeQL's js/path-injection analysis recognizes as a
|
|
43
|
+
// sanitizer (its `startsWith` form isn't), and is redundant at runtime.
|
|
44
|
+
function safeWorkspaceAbs(relFromRoot: string): string | null {
|
|
45
|
+
const root = workspaceReal();
|
|
46
|
+
const abs = resolveWithinRoot(root, relFromRoot);
|
|
47
|
+
if (!abs) return null;
|
|
48
|
+
const rel = path.relative(root, abs);
|
|
49
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) return null;
|
|
50
|
+
return abs;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Resolve a ref (relative to the HTML file's dir) to workspace bytes.
|
|
54
|
+
// Returns null when the ref escapes the workspace or the file is
|
|
55
|
+
// missing — the caller warns and leaves the (now dangling) link.
|
|
56
|
+
async function readAsset(htmlDir: string, originalRef: string): Promise<Buffer | null> {
|
|
57
|
+
const relFromRoot = path.posix.normalize(path.posix.join(htmlDir, stripQueryHash(originalRef)));
|
|
58
|
+
const abs = safeWorkspaceAbs(relFromRoot);
|
|
59
|
+
if (!abs) return null;
|
|
60
|
+
try {
|
|
61
|
+
return await readFile(abs);
|
|
62
|
+
} catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function packHtmlBundle(htmlRelPath: string): Promise<PackedBundle> {
|
|
68
|
+
const abs = safeWorkspaceAbs(htmlRelPath);
|
|
69
|
+
if (!abs) throw new Error(`HTML not found or outside workspace: ${htmlRelPath}`);
|
|
70
|
+
const html = await readFile(abs, "utf-8");
|
|
71
|
+
|
|
72
|
+
const { html: rewritten, assets } = rewriteHtmlAssets(html);
|
|
73
|
+
const htmlDir = path.posix.dirname(htmlRelPath);
|
|
74
|
+
|
|
75
|
+
const files: PackedFile[] = [{ bundlePath: "index.html", bytes: Buffer.from(rewritten, "utf-8") }];
|
|
76
|
+
for (const asset of assets) {
|
|
77
|
+
const bytes = await readAsset(htmlDir, asset.originalRef);
|
|
78
|
+
if (bytes === null) {
|
|
79
|
+
log.warn(LOG_PREFIX, "asset missing or outside workspace; skipped", { ref: asset.originalRef });
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
files.push({ bundlePath: asset.bundlePath, bytes });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const name = path.posix.basename(htmlRelPath).replace(/\.html?$/i, "") || "share";
|
|
86
|
+
return { name, files };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Zip a bundle in memory. Bundles are small (one page + a few assets),
|
|
90
|
+
// so an in-memory buffer is simpler than streaming and stays testable.
|
|
91
|
+
export function zipBundle(files: PackedFile[]): Promise<Buffer> {
|
|
92
|
+
const zip = new JSZip();
|
|
93
|
+
for (const file of files) zip.file(file.bundlePath, file.bytes);
|
|
94
|
+
return zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE", compressionOptions: { level: 9 } });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function safeZipName(name: string): string {
|
|
98
|
+
const cleaned = name.replace(/[^\w.-]+/g, "_");
|
|
99
|
+
return `${cleaned || "share"}.zip`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// One-call pack: bundle → zip → suggested download filename. Shared by
|
|
103
|
+
// the HTTP route (streams the buffer) and the View dispatch (base64).
|
|
104
|
+
export async function packHtmlZip(htmlRelPath: string): Promise<{ filename: string; zip: Buffer }> {
|
|
105
|
+
const bundle = await packHtmlBundle(htmlRelPath);
|
|
106
|
+
const zip = await zipBundle(bundle.files);
|
|
107
|
+
return { filename: safeZipName(bundle.name), zip };
|
|
108
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { parse, type HTMLElement } from "node-html-parser";
|
|
2
|
+
|
|
3
|
+
// A local resource referenced by the HTML that must be copied into the
|
|
4
|
+
// bundle. `originalRef` is the reference verbatim as it appears in the
|
|
5
|
+
// source (relative to the HTML file); `bundlePath` is where it lands in
|
|
6
|
+
// the self-contained bundle (always under `assets/`).
|
|
7
|
+
export interface AssetRef {
|
|
8
|
+
originalRef: string;
|
|
9
|
+
bundlePath: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface RewriteResult {
|
|
13
|
+
html: string;
|
|
14
|
+
assets: AssetRef[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ASSETS_DIR = "assets";
|
|
18
|
+
|
|
19
|
+
// Refs we never bundle: absolute URLs, protocol-relative, data/blob,
|
|
20
|
+
// in-page anchors, and non-navigational schemes. Everything else is a
|
|
21
|
+
// workspace-relative path the bundle must localize. Root-absolute
|
|
22
|
+
// (`/foo`) is left alone too — without a known base it can't be mapped.
|
|
23
|
+
function isLocalRef(ref: string): boolean {
|
|
24
|
+
const value = ref.trim();
|
|
25
|
+
if (value === "") return false;
|
|
26
|
+
if (value.startsWith("#") || value.startsWith("//") || value.startsWith("/")) return false;
|
|
27
|
+
return !/^[a-z][a-z0-9+.-]*:/i.test(value);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function stripQueryHash(ref: string): string {
|
|
31
|
+
const cut = ref.search(/[?#]/);
|
|
32
|
+
return cut === -1 ? ref : ref.slice(0, cut);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Safe single-segment filename for a bundle entry. Splits on BOTH path
|
|
36
|
+
// separators — a crafted `..\..\evil.png` must not survive into a zip
|
|
37
|
+
// entry name, where a Windows unzip tool treats `\` as a separator
|
|
38
|
+
// (zip-slip). `.`/`..`/empty collapse to a neutral name.
|
|
39
|
+
function safeAssetName(ref: string): string {
|
|
40
|
+
const segment = stripQueryHash(ref).split(/[/\\]/).pop() ?? "";
|
|
41
|
+
return segment === "" || segment === "." || segment === ".." ? "asset" : segment;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function splitSuffix(ref: string): { filePath: string; suffix: string } {
|
|
45
|
+
const cut = ref.search(/[?#]/);
|
|
46
|
+
return cut === -1 ? { filePath: ref, suffix: "" } : { filePath: ref.slice(0, cut), suffix: ref.slice(cut) };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Maps a local ref to its `assets/<name>` slot. The bundled FILE is
|
|
50
|
+
// keyed by the path with `?query`/`#fragment` stripped, so `a.png?v=1`
|
|
51
|
+
// and `a.png?v=2` share one copy; but the rewritten URL keeps each
|
|
52
|
+
// ref's suffix (an SVG `sprite.svg#icon` fragment must survive). A
|
|
53
|
+
// basename collision across different dirs is disambiguated by a short
|
|
54
|
+
// hash of the file path so two `logo.png` don't clobber each other.
|
|
55
|
+
function createAssetMapper() {
|
|
56
|
+
const byPath = new Map<string, string>();
|
|
57
|
+
const usedNames = new Set<string>();
|
|
58
|
+
const assets: AssetRef[] = [];
|
|
59
|
+
|
|
60
|
+
const hash = (value: string): string => {
|
|
61
|
+
let acc = 0;
|
|
62
|
+
for (const char of value) acc = (acc * 31 + char.charCodeAt(0)) | 0;
|
|
63
|
+
return (acc >>> 0).toString(36);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const bundlePathFor = (filePath: string): string => {
|
|
67
|
+
const existing = byPath.get(filePath);
|
|
68
|
+
if (existing) return existing;
|
|
69
|
+
const base = safeAssetName(filePath);
|
|
70
|
+
const name = usedNames.has(base) ? `${hash(filePath)}-${base}` : base;
|
|
71
|
+
usedNames.add(name);
|
|
72
|
+
const bundlePath = `${ASSETS_DIR}/${name}`;
|
|
73
|
+
byPath.set(filePath, bundlePath);
|
|
74
|
+
assets.push({ originalRef: filePath, bundlePath });
|
|
75
|
+
return bundlePath;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const map = (originalRef: string): string => {
|
|
79
|
+
const { filePath, suffix } = splitSuffix(originalRef);
|
|
80
|
+
return bundlePathFor(filePath) + suffix;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return { map, assets };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function rewriteCssUrls(css: string, map: (ref: string) => string): string {
|
|
87
|
+
return css.replace(/url\(([^)]*)\)/gi, (whole, inner: string) => {
|
|
88
|
+
const raw = inner.trim();
|
|
89
|
+
const quote = raw.startsWith('"') || raw.startsWith("'") ? raw[0] : "";
|
|
90
|
+
const ref = quote ? raw.slice(1, -1) : raw;
|
|
91
|
+
if (!isLocalRef(ref)) return whole;
|
|
92
|
+
return `url(${quote}${map(ref)}${quote})`;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isSrcsetWs(char: string): boolean {
|
|
97
|
+
return char === " " || char === "\t" || char === "\n" || char === "\r" || char === "\f";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// One srcset candidate: a URL (a run of non-whitespace, so a data: URI's
|
|
101
|
+
// internal commas stay intact) whose trailing commas are separators, then
|
|
102
|
+
// an optional descriptor up to the next comma. Only local URLs are
|
|
103
|
+
// rewritten; everything else is emitted verbatim. Returns the new cursor.
|
|
104
|
+
function rewriteSrcsetCandidate(value: string, start: number, map: (ref: string) => string, out: string[]): number {
|
|
105
|
+
let index = start;
|
|
106
|
+
while (index < value.length && !isSrcsetWs(value[index])) index++;
|
|
107
|
+
let url = value.slice(start, index);
|
|
108
|
+
let trailing = "";
|
|
109
|
+
while (url.endsWith(",")) {
|
|
110
|
+
url = url.slice(0, -1);
|
|
111
|
+
trailing += ",";
|
|
112
|
+
}
|
|
113
|
+
out.push(isLocalRef(url) ? map(url) : url, trailing);
|
|
114
|
+
if (trailing !== "") return index;
|
|
115
|
+
const descStart = index;
|
|
116
|
+
while (index < value.length && value[index] !== ",") index++;
|
|
117
|
+
out.push(value.slice(descStart, index));
|
|
118
|
+
return index;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// WHATWG-style srcset walk: candidates are comma-separated, but because a
|
|
122
|
+
// URL is a non-whitespace run, `data:` URIs (whose payload contains commas)
|
|
123
|
+
// are never split. Separators / whitespace / descriptors are preserved.
|
|
124
|
+
function rewriteSrcset(value: string, map: (ref: string) => string): string {
|
|
125
|
+
const out: string[] = [];
|
|
126
|
+
let index = 0;
|
|
127
|
+
while (index < value.length) {
|
|
128
|
+
const sepStart = index;
|
|
129
|
+
while (index < value.length && (isSrcsetWs(value[index]) || value[index] === ",")) index++;
|
|
130
|
+
out.push(value.slice(sepStart, index));
|
|
131
|
+
if (index < value.length) index = rewriteSrcsetCandidate(value, index, map, out);
|
|
132
|
+
}
|
|
133
|
+
return out.join("");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Embedded resources only. `a[href]` is intentionally excluded — it is
|
|
137
|
+
// navigation, not an inlined asset, and rewriting it would point at a
|
|
138
|
+
// file the single-page bundle doesn't carry.
|
|
139
|
+
const URL_ATTRS: readonly { selector: string; attr: string }[] = [
|
|
140
|
+
{ selector: "img[src]", attr: "src" },
|
|
141
|
+
{ selector: "script[src]", attr: "src" },
|
|
142
|
+
{ selector: "source[src]", attr: "src" },
|
|
143
|
+
{ selector: "link[href]", attr: "href" },
|
|
144
|
+
{ selector: "audio[src]", attr: "src" },
|
|
145
|
+
{ selector: "video[src]", attr: "src" },
|
|
146
|
+
{ selector: "video[poster]", attr: "poster" },
|
|
147
|
+
{ selector: "use[href]", attr: "href" },
|
|
148
|
+
];
|
|
149
|
+
|
|
150
|
+
function rewriteAttrs(root: HTMLElement, map: (ref: string) => string): void {
|
|
151
|
+
for (const { selector, attr } of URL_ATTRS) {
|
|
152
|
+
for (const element of root.querySelectorAll(selector)) {
|
|
153
|
+
const ref = element.getAttribute(attr);
|
|
154
|
+
if (ref && isLocalRef(ref)) element.setAttribute(attr, map(ref));
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (const element of root.querySelectorAll("[srcset]")) {
|
|
158
|
+
const value = element.getAttribute("srcset");
|
|
159
|
+
if (value) element.setAttribute("srcset", rewriteSrcset(value, map));
|
|
160
|
+
}
|
|
161
|
+
for (const element of root.querySelectorAll("style")) {
|
|
162
|
+
element.set_content(rewriteCssUrls(element.textContent, map));
|
|
163
|
+
}
|
|
164
|
+
for (const element of root.querySelectorAll("[style]")) {
|
|
165
|
+
const value = element.getAttribute("style");
|
|
166
|
+
if (value) element.setAttribute("style", rewriteCssUrls(value, map));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Rewrites every local resource reference in `html` to point at a
|
|
171
|
+
// co-located `assets/<name>`, returning the rewritten document plus the
|
|
172
|
+
// list of refs to copy. Pure: no filesystem or network.
|
|
173
|
+
export function rewriteHtmlAssets(html: string): RewriteResult {
|
|
174
|
+
const root = parse(html, { comment: true });
|
|
175
|
+
const mapper = createAssetMapper();
|
|
176
|
+
rewriteAttrs(root, mapper.map);
|
|
177
|
+
return { html: root.toString(), assets: mapper.assets };
|
|
178
|
+
}
|
|
@@ -4,8 +4,14 @@
|
|
|
4
4
|
// claude CLI spawn code).
|
|
5
5
|
|
|
6
6
|
import path from "node:path";
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { WORKSPACE_DIRS } from "../paths.js";
|
|
8
|
+
|
|
9
|
+
// Sourced from WORKSPACE_DIRS so the layout move in #284
|
|
10
|
+
// (`chat/` → `conversations/chat/`) can't drift again — a hardcoded
|
|
11
|
+
// literal here silently detached the indexer from the real session
|
|
12
|
+
// tree between Apr and Jul 2026, leaving every session listing
|
|
13
|
+
// preview to fall back to `meta.firstUserMessage` (issue #1902).
|
|
14
|
+
export const CHAT_DIR = WORKSPACE_DIRS.chat;
|
|
9
15
|
export const INDEX_DIR = "index";
|
|
10
16
|
export const MANIFEST_FILE = "manifest.json";
|
|
11
17
|
|
|
@@ -39,23 +39,31 @@ const SUMMARY_SCHEMA = {
|
|
|
39
39
|
required: ["title", "summary", "keywords"],
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
42
|
+
// Model used for summarization. Sonnet, not haiku: the title is the
|
|
43
|
+
// primary way a user finds a past chat, so a weak title makes the
|
|
44
|
+
// history list unusable. One cheap structured call per session is
|
|
45
|
+
// negligible next to the agent turns it summarizes.
|
|
46
|
+
const SUMMARY_MODEL = "sonnet";
|
|
47
|
+
|
|
48
|
+
// Prompt-building constants. Sized for Sonnet's large context: the
|
|
49
|
+
// window is wide enough to carry a long, topic-shifting session's
|
|
50
|
+
// middle (not just head + tail), and per-message clipping keeps the
|
|
51
|
+
// substance of long turns. Exported so the summarizer tests derive
|
|
52
|
+
// their fixtures from them rather than hard-coding sizes that rot.
|
|
53
|
+
export const MAX_INPUT_CHARS = 30000;
|
|
54
|
+
export const HEAD_CHARS = 12000;
|
|
55
|
+
export const TAIL_CHARS = 16000;
|
|
56
|
+
export const PER_MESSAGE_MAX = 1500;
|
|
47
57
|
|
|
48
58
|
// Spawn / budget constants.
|
|
49
59
|
const DEFAULT_TIMEOUT_MS = 2 * ONE_MINUTE_MS;
|
|
50
60
|
// Budget cap per summarization call, forwarded to `claude
|
|
51
|
-
// --max-budget-usd`.
|
|
52
|
-
// that
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
// full 100-session backfill to well under $20.
|
|
58
|
-
const MAX_BUDGET_USD = 0.15;
|
|
61
|
+
// --max-budget-usd`. A first-burst call pays a one-time cache-creation
|
|
62
|
+
// cost (~28k tokens) that on Sonnet's pricing would trip a tighter cap
|
|
63
|
+
// and fail with `error_max_budget_usd` — yielding NO title at all.
|
|
64
|
+
// 0.40 leaves headroom for cache creation plus the wider input window
|
|
65
|
+
// while still bounding a full backfill.
|
|
66
|
+
const MAX_BUDGET_USD = 0.4;
|
|
59
67
|
|
|
60
68
|
// Any module that wants to drive the summarizer — including the
|
|
61
69
|
// indexer — takes a SummarizeFn so tests can supply a deterministic
|
|
@@ -95,7 +103,7 @@ export function extractText(jsonlContent: string): string {
|
|
|
95
103
|
return parts.join("\n\n");
|
|
96
104
|
}
|
|
97
105
|
|
|
98
|
-
// Long sessions are clipped to first ~
|
|
106
|
+
// Long sessions are clipped to first ~12000 + last ~16000 chars so
|
|
99
107
|
// claude sees both the original topic and the most recent state.
|
|
100
108
|
// Distinct from the simple-tail `truncate()` in `server/utils/text.ts`
|
|
101
109
|
// — the summarizer needs context from both ends, not just the head.
|
|
@@ -184,7 +192,7 @@ function spawnClaudeSummarize(input: string, timeoutMs: number): Promise<string>
|
|
|
184
192
|
"--output-format",
|
|
185
193
|
"json",
|
|
186
194
|
"--model",
|
|
187
|
-
|
|
195
|
+
SUMMARY_MODEL,
|
|
188
196
|
"--max-budget-usd",
|
|
189
197
|
String(MAX_BUDGET_USD),
|
|
190
198
|
"--json-schema",
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
// Wire @mulmoclaude/collection
|
|
1
|
+
// Wire @mulmoclaude/core/collection/server to MulmoClaude's workspace,
|
|
2
2
|
// logger, and path layout. Imported for side effect at the very top of
|
|
3
3
|
// server/index.ts so the binding is set before any collection storage
|
|
4
4
|
// operation runs. MulmoTerminal has its own equivalent shim.
|
|
5
5
|
import path from "node:path";
|
|
6
|
-
import { configureCollectionHost } from "@mulmoclaude/collection
|
|
6
|
+
import { configureCollectionHost } from "@mulmoclaude/core/collection/server";
|
|
7
7
|
import { workspacePath } from "../workspace.js";
|
|
8
8
|
import { log } from "../../system/logger/index.js";
|
|
9
9
|
import { WORKSPACE_DIRS } from "../paths.js";
|
|
10
|
+
import { WORKSPACE_FILES } from "../../../src/config/workspacePaths.js";
|
|
10
11
|
import { USER_SKILLS_DIR, projectSkillsDir } from "../skills/paths.js";
|
|
11
|
-
import { feedsRoot } from "
|
|
12
|
+
import { feedsRoot } from "@mulmoclaude/core/feeds/paths";
|
|
12
13
|
import { isPresetSlug } from "../skills-preset.js";
|
|
13
14
|
|
|
14
15
|
configureCollectionHost({
|
|
@@ -20,6 +21,7 @@ configureCollectionHost({
|
|
|
20
21
|
feedsRoot,
|
|
21
22
|
skillsStagingDir: (root) => path.join(root, WORKSPACE_DIRS.skillsStaging),
|
|
22
23
|
archiveDir: WORKSPACE_DIRS.archive,
|
|
24
|
+
collectionsRegistriesConfig: (root) => path.join(root, ...WORKSPACE_FILES.collectionsRegistries.split("/")),
|
|
23
25
|
},
|
|
24
26
|
isPresetSlug,
|
|
25
27
|
});
|
|
@@ -6,11 +6,11 @@ export {
|
|
|
6
6
|
CollectionSchemaZ,
|
|
7
7
|
resolveDataDir,
|
|
8
8
|
type LoadedCollection,
|
|
9
|
-
} from "@mulmoclaude/collection
|
|
10
|
-
export { validateCollectionRecords, validateRecordObject, COMPUTED_TYPES, type RecordIssue } from "@mulmoclaude/collection
|
|
11
|
-
export { enrichItems } from "@mulmoclaude/collection
|
|
12
|
-
export { deleteCollection, deleteCollectionRefusalMessage, type DeleteCollectionResult } from "@mulmoclaude/collection
|
|
13
|
-
export { deleteCustomView, type DeleteViewResult } from "@mulmoclaude/collection
|
|
9
|
+
} from "@mulmoclaude/core/collection/server";
|
|
10
|
+
export { validateCollectionRecords, validateRecordObject, COMPUTED_TYPES, type RecordIssue } from "@mulmoclaude/core/collection/server";
|
|
11
|
+
export { enrichItems } from "@mulmoclaude/core/collection/server";
|
|
12
|
+
export { deleteCollection, deleteCollectionRefusalMessage, type DeleteCollectionResult } from "@mulmoclaude/core/collection/server";
|
|
13
|
+
export { deleteCustomView, type DeleteViewResult } from "@mulmoclaude/core/collection/server";
|
|
14
14
|
export {
|
|
15
15
|
listItems,
|
|
16
16
|
readItem,
|
|
@@ -20,11 +20,13 @@ export {
|
|
|
20
20
|
resolveCreateItemId,
|
|
21
21
|
readSkillTemplate,
|
|
22
22
|
readCustomViewHtml,
|
|
23
|
+
readCustomViewI18n,
|
|
23
24
|
buildActionSeedPrompt,
|
|
24
25
|
buildCollectionActionSeedPrompt,
|
|
26
|
+
promptPathsFor,
|
|
25
27
|
type WriteItemResult,
|
|
26
28
|
type DeleteItemResult,
|
|
27
|
-
} from "@mulmoclaude/collection
|
|
29
|
+
} from "@mulmoclaude/core/collection/server";
|
|
28
30
|
export type {
|
|
29
31
|
CollectionSchema,
|
|
30
32
|
CollectionAction,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Collection-completion bell reconciler — thin host binding over
|
|
2
|
-
// @mulmoclaude/collection-watchers. The convergent reconcile logic lives
|
|
2
|
+
// @mulmoclaude/core/collection-watchers. The convergent reconcile logic lives
|
|
3
3
|
// in the shared package; this file supplies MulmoClaude's notification
|
|
4
4
|
// taxonomy (publish under "todo", priority→severity mapping) and in-app
|
|
5
5
|
// routing (the `/collections/<slug>?selected=<itemId>` deep-link) via a
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
type LegacyNotifierPluginData,
|
|
22
22
|
} from "../../events/notifications.js";
|
|
23
23
|
import { log } from "../../system/logger/index.js";
|
|
24
|
-
import { configureCollectionWatchers, type CollectionNotificationAdapter, type CompletionPriority } from "@mulmoclaude/collection-watchers";
|
|
24
|
+
import { configureCollectionWatchers, type CollectionNotificationAdapter, type CompletionPriority } from "@mulmoclaude/core/collection-watchers";
|
|
25
25
|
|
|
26
26
|
// Re-export the reconciler surface verbatim from the package.
|
|
27
27
|
export {
|
|
@@ -31,7 +31,7 @@ export {
|
|
|
31
31
|
clearItemNotification,
|
|
32
32
|
resolveDisplayLabel,
|
|
33
33
|
itemIsDone,
|
|
34
|
-
} from "@mulmoclaude/collection-watchers";
|
|
34
|
+
} from "@mulmoclaude/core/collection-watchers";
|
|
35
35
|
|
|
36
36
|
const COLLECTION_PLUGIN_PKG = legacyKindToPluginPkg(NOTIFICATION_KINDS.todo);
|
|
37
37
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The canonical collection schema types now live in
|
|
2
|
-
// @mulmoclaude/collection
|
|
2
|
+
// @mulmoclaude/core/collection (single source of truth, also consumed by
|
|
3
3
|
// the host frontend via src/components/collectionTypes.ts and by
|
|
4
4
|
// MulmoTerminal). Re-exported here so the many `./types.js` importers under
|
|
5
5
|
// server/workspace/collections keep compiling unchanged.
|
|
6
|
-
export * from "@mulmoclaude/collection
|
|
6
|
+
export * from "@mulmoclaude/core/collection";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Collection watchers — thin host binding over
|
|
2
|
-
// @mulmoclaude/collection-watchers. The fs.watch plumbing lives in the
|
|
2
|
+
// @mulmoclaude/core/collection-watchers. The fs.watch plumbing lives in the
|
|
3
3
|
// shared package; this file just ensures the host's notification adapter
|
|
4
4
|
// is configured (the `./notifications.js` side-effect import) and
|
|
5
5
|
// re-exports the watcher surface existing callers + tests import from
|
|
@@ -16,4 +16,4 @@ export {
|
|
|
16
16
|
_tickTimeTriggersForTesting,
|
|
17
17
|
_scheduleItemReconcileForTesting,
|
|
18
18
|
type CollectionWatcherOptions,
|
|
19
|
-
} from "@mulmoclaude/collection-watchers";
|
|
19
|
+
} from "@mulmoclaude/core/collection-watchers";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Wire @mulmoclaude/core/feeds/server to this host's workspace, logger, atomic
|
|
2
|
+
// writer, and agent-ingest worker launcher. Called once from server/index.ts
|
|
3
|
+
// BEFORE scheduler init (catch-up can fire `system:feed-refresh` immediately, so
|
|
4
|
+
// wiring after would make those first refreshes fail "host not configured").
|
|
5
|
+
//
|
|
6
|
+
// The worker launcher (`spawnSystemWorker`) is INJECTED by the caller rather
|
|
7
|
+
// than imported here: it lives in the routes layer, and workspace code must not
|
|
8
|
+
// import routes (a workspace→routes cycle is exactly what the old
|
|
9
|
+
// `setAgentWorkerRunner` seam — now folded into `spawnWorker` — existed to
|
|
10
|
+
// avoid). `server/index.ts` (the host entry) is allowed to bridge the two.
|
|
11
|
+
import { configureFeedsHost, type AgentWorkerRunner } from "@mulmoclaude/core/feeds/server";
|
|
12
|
+
import { workspacePath } from "../workspace.js";
|
|
13
|
+
import { log } from "../../system/logger/index.js";
|
|
14
|
+
import { writeFileAtomic } from "../../utils/files/atomic.js";
|
|
15
|
+
|
|
16
|
+
export function configureFeeds(spawnWorker: AgentWorkerRunner): void {
|
|
17
|
+
configureFeedsHost({
|
|
18
|
+
workspaceRoot: workspacePath,
|
|
19
|
+
log,
|
|
20
|
+
// Feed state files use the plain (non-uniqueTmp) atomic write, as before.
|
|
21
|
+
writeFileAtomic: (filePath, content) => writeFileAtomic(filePath, content),
|
|
22
|
+
spawnWorker,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Skill-bridge HOST adapter — thin wiring over @mulmoclaude/skill-bridge.
|
|
1
|
+
// Skill-bridge HOST adapter — thin wiring over @mulmoclaude/core/skill-bridge.
|
|
2
2
|
//
|
|
3
3
|
// The agent writes skill drafts under `data/skills/<slug>/` (a plain data dir, no
|
|
4
4
|
// `.claude/` permission special-case); the shared package decides which writes are
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
mirrorSkillWrite,
|
|
27
27
|
mirrorSkillDelete,
|
|
28
28
|
type BridgeTarget,
|
|
29
|
-
} from "@mulmoclaude/skill-bridge";
|
|
29
|
+
} from "@mulmoclaude/core/skill-bridge";
|
|
30
30
|
import { buildAuthPost, safePost, serverLog } from "../shared/sidecar.js";
|
|
31
31
|
import type { HookPayload } from "../shared/stdin.js";
|
|
32
32
|
import { extractCommand, extractFilePath, extractToolName } from "../shared/stdin.js";
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// carries a single PostToolUse entry instead of one per hook source.
|
|
7
7
|
|
|
8
8
|
import path from "node:path";
|
|
9
|
-
import { wikiSlugFromAbsPath } from "
|
|
9
|
+
import { wikiSlugFromAbsPath } from "@mulmoclaude/core/wiki/paths";
|
|
10
10
|
import { buildAuthPost, safePost } from "../shared/sidecar.js";
|
|
11
11
|
import type { HookPayload } from "../shared/stdin.js";
|
|
12
12
|
import { extractFilePath, extractSessionId, extractToolName } from "../shared/stdin.js";
|
|
@@ -119,6 +119,13 @@ const HOST_WORKSPACE_DIRS = {
|
|
|
119
119
|
// Non-skill data-source feed registry: feeds/<slug>/schema.json (+
|
|
120
120
|
// _state.json). Records land under each schema's dataPath (data/feeds/*).
|
|
121
121
|
feeds: "feeds",
|
|
122
|
+
// Retrieval state for NON-feed collections with an `ingest` block
|
|
123
|
+
// (`kind: "agent"` on a skill-backed collection). Feeds keep their state
|
|
124
|
+
// at feeds/<slug>/_state.json; skill collections can't (a feeds/<slug>/
|
|
125
|
+
// dir without schema.json confuses feed discovery, and _state.json must
|
|
126
|
+
// never live in a collection's dataDir where listItems would read it as a
|
|
127
|
+
// record). One file per collection: data/ingest-state/<slug>.json.
|
|
128
|
+
ingestState: "data/ingest-state",
|
|
122
129
|
translation: "data/translation",
|
|
123
130
|
// Pasted/dropped chat attachments — saved at upload time so the
|
|
124
131
|
// LLM can be handed a stable workspace path instead of inline
|
|
@@ -216,7 +223,7 @@ const HOST_WORKSPACE_DIRS = {
|
|
|
216
223
|
// git) — since model files are large binaries that must stay out of
|
|
217
224
|
// the git-tracked tree. Created lazily on first download, never
|
|
218
225
|
// eagerly (most users never enable voice input). See
|
|
219
|
-
// plans/feat-voice-input.md.
|
|
226
|
+
// plans/done/feat-voice-input.md.
|
|
220
227
|
models: "models",
|
|
221
228
|
// Runtime-loaded plugins (#1043 C-2). The `plugins/` directory holds
|
|
222
229
|
// user-installed npm-published plugin tarballs; `.cache/<name>/<ver>/`
|
|
@@ -187,9 +187,7 @@ export interface CatalogEntryDetail {
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
export type CatalogDetailResult =
|
|
190
|
-
|
|
191
|
-
| { kind: "not-found"; source: CatalogSource; slug: string }
|
|
192
|
-
| { kind: "invalid-slug"; slug: string };
|
|
190
|
+
{ kind: "ok"; detail: CatalogEntryDetail } | { kind: "not-found"; source: CatalogSource; slug: string } | { kind: "invalid-slug"; slug: string };
|
|
193
191
|
|
|
194
192
|
/** Read one catalog entry's SKILL.md and return the description +
|
|
195
193
|
* body. The same `safeSlugName` taint-launder used by the star
|
|
@@ -159,9 +159,7 @@ export interface ExternalCatalogDetail {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
export type ExternalCatalogDetailResult =
|
|
162
|
-
|
|
163
|
-
| { kind: "invalid-id" }
|
|
164
|
-
| { kind: "not-found"; repoId: string; skillFolder: string };
|
|
162
|
+
{ kind: "ok"; detail: ExternalCatalogDetail } | { kind: "invalid-id" } | { kind: "not-found"; repoId: string; skillFolder: string };
|
|
165
163
|
|
|
166
164
|
interface ResolvedSource {
|
|
167
165
|
repoId: string;
|
|
@@ -10,13 +10,14 @@
|
|
|
10
10
|
// chars. Same rule as `server/sources/paths.ts#isValidSlug` — keep
|
|
11
11
|
// them in sync manually.
|
|
12
12
|
|
|
13
|
-
import { homedir } from "node:os";
|
|
14
13
|
import { join } from "node:path";
|
|
14
|
+
import { claudeSkillsDir } from "../../utils/claudeConfigPath.js";
|
|
15
15
|
|
|
16
16
|
export const SKILL_FILE = "SKILL.md";
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
18
|
+
/** `<claudeConfigDir>/skills/` — user scope, read-only from MulmoClaude.
|
|
19
|
+
* Default `~/.claude/skills/`; override via `CLAUDE_CONFIG_DIR` (issue #87 §2). */
|
|
20
|
+
export const USER_SKILLS_DIR = claudeSkillsDir();
|
|
20
21
|
|
|
21
22
|
/** `<workspaceRoot>/.claude/skills/` — project scope, writable. */
|
|
22
23
|
export function projectSkillsDir(workspaceRoot: string): string {
|