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
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// Client store for the dashboard layout (tile order + per-tile view mode,
|
|
2
|
+
// and per-row view-area heights for the favorites grid). Singleton module
|
|
3
|
+
// state shared across consumers, mirroring `useShortcuts`: persistence is
|
|
4
|
+
// server-side (`config/dashboard.json` via PUT /api/dashboard); the client
|
|
5
|
+
// owns the full layout and replaces it wholesale. Mutations are optimistic
|
|
6
|
+
// with rollback on failure and serialised so overlapping replace-all PUTs
|
|
7
|
+
// never land out of order.
|
|
8
|
+
//
|
|
9
|
+
// Membership (which collections appear) is NOT owned here — it derives
|
|
10
|
+
// from the user's pinned collection shortcuts (favorites). `reconcile`
|
|
11
|
+
// folds a fresh favorite-slug list into the stored layout: it appends
|
|
12
|
+
// newly-favorited collections and prunes ones that were unpinned, while
|
|
13
|
+
// preserving the user's dashboard order and per-tile view modes.
|
|
14
|
+
//
|
|
15
|
+
// Row heights are POSITIONAL: indexed by grid row (2 tiles/row), they stay
|
|
16
|
+
// with the slot when tiles are reordered, never with a specific tile.
|
|
17
|
+
|
|
18
|
+
import { computed, ref, type ComputedRef } from "vue";
|
|
19
|
+
import { API_ROUTES } from "../config/apiRoutes";
|
|
20
|
+
import { apiGet, apiPut } from "../utils/api";
|
|
21
|
+
import type { DashboardTile } from "../types/dashboard";
|
|
22
|
+
|
|
23
|
+
const tiles = ref<DashboardTile[]>([]);
|
|
24
|
+
const rowHeights = ref<Record<string, number[]>>({});
|
|
25
|
+
const loadError = ref<string | null>(null);
|
|
26
|
+
/** True only after a GET has authoritatively populated the layout. Until
|
|
27
|
+
* then, mutations refuse to persist — a replace-all PUT built on the
|
|
28
|
+
* empty default would clobber an existing `dashboard.json`. */
|
|
29
|
+
const loaded = ref(false);
|
|
30
|
+
let loadPromise: Promise<void> | null = null;
|
|
31
|
+
|
|
32
|
+
interface DashboardResponse {
|
|
33
|
+
tiles: DashboardTile[];
|
|
34
|
+
rowHeights?: Record<string, number[]>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Snapshot of the mutable layout, for optimistic rollback. */
|
|
38
|
+
interface LayoutSnapshot {
|
|
39
|
+
tiles: DashboardTile[];
|
|
40
|
+
rowHeights: Record<string, number[]>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function snapshot(): LayoutSnapshot {
|
|
44
|
+
return { tiles: tiles.value, rowHeights: rowHeights.value };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function apply(layout: LayoutSnapshot): void {
|
|
48
|
+
tiles.value = layout.tiles;
|
|
49
|
+
rowHeights.value = layout.rowHeights;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Load once per session (deduped). A FAILED load is not cached so the
|
|
53
|
+
* next call retries rather than permanently serving the failure. */
|
|
54
|
+
async function load(force = false): Promise<void> {
|
|
55
|
+
if (loadPromise && !force) return loadPromise;
|
|
56
|
+
loadPromise = (async () => {
|
|
57
|
+
const result = await apiGet<DashboardResponse>(API_ROUTES.dashboard);
|
|
58
|
+
if (!result.ok) {
|
|
59
|
+
loadError.value = result.error;
|
|
60
|
+
loadPromise = null; // allow retry on the next call
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
loadError.value = null;
|
|
64
|
+
apply({ tiles: result.data.tiles, rowHeights: result.data.rowHeights ?? {} });
|
|
65
|
+
loaded.value = true;
|
|
66
|
+
})();
|
|
67
|
+
return loadPromise;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Every mutation runs through this chain so the replace-all PUTs never
|
|
71
|
+
// overlap (the same race `useShortcuts` guards against).
|
|
72
|
+
let mutationChain: Promise<unknown> = Promise.resolve();
|
|
73
|
+
|
|
74
|
+
function enqueue<T>(task: () => Promise<T>): Promise<T> {
|
|
75
|
+
const run = mutationChain.then(task, task);
|
|
76
|
+
mutationChain = run.then(
|
|
77
|
+
() => undefined,
|
|
78
|
+
() => undefined,
|
|
79
|
+
);
|
|
80
|
+
return run;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Persist the given layout, rolling back to `previous` on failure.
|
|
84
|
+
* Returns true on success. Call only from inside `enqueue`. */
|
|
85
|
+
async function persist(next: LayoutSnapshot, previous: LayoutSnapshot): Promise<boolean> {
|
|
86
|
+
apply(next);
|
|
87
|
+
const result = await apiPut<DashboardResponse>(API_ROUTES.dashboard, { tiles: next.tiles, rowHeights: next.rowHeights });
|
|
88
|
+
if (!result.ok) {
|
|
89
|
+
apply(previous);
|
|
90
|
+
loadError.value = result.error;
|
|
91
|
+
console.error("[useDashboard] persist failed", result.error);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
// Adopt the server's canonical layout. If the response omits rowHeights
|
|
95
|
+
// (e.g. a version-skewed server), keep the heights we just sent rather
|
|
96
|
+
// than clearing them — otherwise a resize would visibly snap back.
|
|
97
|
+
apply({ tiles: result.data.tiles, rowHeights: result.data.rowHeights ?? next.rowHeights });
|
|
98
|
+
loadError.value = null;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Replace the full ordered tile list (used by drag-to-reorder). Row
|
|
103
|
+
* heights are positional, so they stay put. */
|
|
104
|
+
function setTiles(next: DashboardTile[]): Promise<boolean> {
|
|
105
|
+
return enqueue(async () => {
|
|
106
|
+
await load();
|
|
107
|
+
if (!loaded.value) return false; // never overwrite an unread layout
|
|
108
|
+
return persist({ tiles: next, rowHeights: rowHeights.value }, snapshot());
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Set (or, when null, clear) one tile's view mode. No-op if the slug
|
|
113
|
+
* isn't a tile. */
|
|
114
|
+
function setViewMode(slug: string, viewMode: string | null): Promise<boolean> {
|
|
115
|
+
return enqueue(async () => {
|
|
116
|
+
await load();
|
|
117
|
+
if (!loaded.value) return false;
|
|
118
|
+
if (!tiles.value.some((tile) => tile.slug === slug)) return true;
|
|
119
|
+
const previous = snapshot();
|
|
120
|
+
const next = previous.tiles.map((tile) => {
|
|
121
|
+
if (tile.slug !== slug) return tile;
|
|
122
|
+
if (viewMode === null) {
|
|
123
|
+
const { viewMode: __drop, ...rest } = tile;
|
|
124
|
+
return rest;
|
|
125
|
+
}
|
|
126
|
+
return { ...tile, viewMode };
|
|
127
|
+
});
|
|
128
|
+
return persist({ tiles: next, rowHeights: previous.rowHeights }, previous);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Set one grid row's view-area height (px) for the given column-count
|
|
133
|
+
* layout. Heights are kept per column count so the 1- and 2-column
|
|
134
|
+
* layouts stay independent. Pads with `0` (default) for earlier
|
|
135
|
+
* untouched rows. */
|
|
136
|
+
function setRowHeight(columns: number, row: number, height: number): Promise<boolean> {
|
|
137
|
+
return enqueue(async () => {
|
|
138
|
+
await load();
|
|
139
|
+
if (!loaded.value) return false;
|
|
140
|
+
if (columns < 1 || row < 0) return true;
|
|
141
|
+
const previous = snapshot();
|
|
142
|
+
const key = String(columns);
|
|
143
|
+
const heights = [...(previous.rowHeights[key] ?? [])];
|
|
144
|
+
while (heights.length <= row) heights.push(0);
|
|
145
|
+
heights[row] = height;
|
|
146
|
+
const next = { ...previous.rowHeights, [key]: heights };
|
|
147
|
+
return persist({ tiles: previous.tiles, rowHeights: next }, previous);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Fold a fresh favorite-slug list into the stored layout: keep stored
|
|
152
|
+
* tiles whose slug is still a favorite (preserving order + view mode),
|
|
153
|
+
* then append any favorites not yet present (in the favorites' order).
|
|
154
|
+
* Persists only when something drifted, so the file self-heals after a
|
|
155
|
+
* pin / unpin without a redundant PUT on every visit. */
|
|
156
|
+
function reconcile(favoriteSlugs: string[]): Promise<void> {
|
|
157
|
+
return enqueue(async () => {
|
|
158
|
+
await load();
|
|
159
|
+
if (!loaded.value) return; // never overwrite an unread layout
|
|
160
|
+
const favoriteSet = new Set(favoriteSlugs);
|
|
161
|
+
const kept = tiles.value.filter((tile) => favoriteSet.has(tile.slug));
|
|
162
|
+
const keptSlugs = new Set(kept.map((tile) => tile.slug));
|
|
163
|
+
const appended = favoriteSlugs.filter((slug) => !keptSlugs.has(slug)).map((slug) => ({ slug }) as DashboardTile);
|
|
164
|
+
const next = [...kept, ...appended];
|
|
165
|
+
const drifted = next.length !== tiles.value.length || next.some((tile, i) => tile.slug !== tiles.value[i]?.slug);
|
|
166
|
+
if (drifted) await persist({ tiles: next, rowHeights: rowHeights.value }, snapshot());
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function useDashboard(): {
|
|
171
|
+
tiles: ComputedRef<DashboardTile[]>;
|
|
172
|
+
rowHeights: ComputedRef<Record<string, number[]>>;
|
|
173
|
+
loadError: ComputedRef<string | null>;
|
|
174
|
+
load: (force?: boolean) => Promise<void>;
|
|
175
|
+
setTiles: (next: DashboardTile[]) => Promise<boolean>;
|
|
176
|
+
setViewMode: (slug: string, viewMode: string | null) => Promise<boolean>;
|
|
177
|
+
setRowHeight: (columns: number, row: number, height: number) => Promise<boolean>;
|
|
178
|
+
reconcile: (favoriteSlugs: string[]) => Promise<void>;
|
|
179
|
+
} {
|
|
180
|
+
void load();
|
|
181
|
+
return {
|
|
182
|
+
tiles: computed(() => tiles.value),
|
|
183
|
+
rowHeights: computed(() => rowHeights.value),
|
|
184
|
+
loadError: computed(() => loadError.value),
|
|
185
|
+
load,
|
|
186
|
+
setTiles,
|
|
187
|
+
setViewMode,
|
|
188
|
+
setRowHeight,
|
|
189
|
+
reconcile,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Download markdown / a wiki page as a self-contained HTML zip. Parallel
|
|
2
|
+
// to usePdfDownload, but hits POST /api/share/pack-markdown and receives
|
|
3
|
+
// a zip (index.html with CSS + images inlined). Failure sets `zipFailed`
|
|
4
|
+
// so callers render a localized message — the raw server body is never
|
|
5
|
+
// surfaced.
|
|
6
|
+
|
|
7
|
+
import { ref, type Ref } from "vue";
|
|
8
|
+
import { API_ROUTES } from "../config/apiRoutes";
|
|
9
|
+
import { apiFetchRaw } from "../utils/api";
|
|
10
|
+
import { saveBlob, filenameFromDisposition } from "../utils/blobDownload";
|
|
11
|
+
|
|
12
|
+
export interface DownloadMarkdownZipOptions {
|
|
13
|
+
/** Workspace-relative source dir for resolving relative `<img>` refs. */
|
|
14
|
+
baseDir?: string;
|
|
15
|
+
stripFrontmatter?: boolean;
|
|
16
|
+
marp?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UseMarkdownZipHandle {
|
|
20
|
+
zipDownloading: Ref<boolean>;
|
|
21
|
+
zipFailed: Ref<boolean>;
|
|
22
|
+
downloadZip: (markdown: string, filename: string, options?: DownloadMarkdownZipOptions) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useMarkdownZip(): UseMarkdownZipHandle {
|
|
26
|
+
const zipDownloading = ref(false);
|
|
27
|
+
const zipFailed = ref(false);
|
|
28
|
+
|
|
29
|
+
async function downloadZip(markdown: string, filename: string, options: DownloadMarkdownZipOptions = {}): Promise<void> {
|
|
30
|
+
zipFailed.value = false;
|
|
31
|
+
zipDownloading.value = true;
|
|
32
|
+
try {
|
|
33
|
+
const response = await apiFetchRaw(API_ROUTES.share.packMarkdown, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: { "Content-Type": "application/json" },
|
|
36
|
+
body: JSON.stringify({ markdown, filename, baseDir: options.baseDir, stripFrontmatter: options.stripFrontmatter, marp: options.marp }),
|
|
37
|
+
});
|
|
38
|
+
if (!response.ok) {
|
|
39
|
+
zipFailed.value = true;
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
saveBlob(await response.blob(), filenameFromDisposition(response.headers.get("content-disposition"), `${filename}.zip`));
|
|
43
|
+
} catch {
|
|
44
|
+
zipFailed.value = true;
|
|
45
|
+
} finally {
|
|
46
|
+
zipDownloading.value = false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return { zipDownloading, zipFailed, downloadZip };
|
|
51
|
+
}
|
|
@@ -40,10 +40,7 @@ export interface NotifierHistoryEntry extends NotifierEntry {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
type NotifierEvent =
|
|
43
|
-
| { type: "
|
|
44
|
-
| { type: "cleared"; id: string }
|
|
45
|
-
| { type: "cancelled"; id: string }
|
|
46
|
-
| { type: "updated"; entry: NotifierEntry };
|
|
43
|
+
{ type: "published"; entry: NotifierEntry } | { type: "cleared"; id: string } | { type: "cancelled"; id: string } | { type: "updated"; entry: NotifierEntry };
|
|
47
44
|
|
|
48
45
|
const HISTORY_CAP = 50;
|
|
49
46
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Download an artifacts/html page as a self-contained zip from the host
|
|
2
|
+
// UI (file explorer preview). Mirrors usePdfDownload: POST the workspace
|
|
3
|
+
// path to /api/share/pack, receive a binary zip, run the
|
|
4
|
+
// blob-to-download dance. Failure sets `packFailed` so the caller can
|
|
5
|
+
// render a localized message — the raw server body is never surfaced.
|
|
6
|
+
|
|
7
|
+
import { ref, type Ref } from "vue";
|
|
8
|
+
import { API_ROUTES } from "../config/apiRoutes";
|
|
9
|
+
import { apiFetchRaw } from "../utils/api";
|
|
10
|
+
import { saveBlob, filenameFromDisposition } from "../utils/blobDownload";
|
|
11
|
+
|
|
12
|
+
export interface UseSharePackHandle {
|
|
13
|
+
packing: Ref<boolean>;
|
|
14
|
+
packFailed: Ref<boolean>;
|
|
15
|
+
downloadZip: (htmlPath: string) => Promise<void>;
|
|
16
|
+
/** Clear the failed flag — call on navigation so a stale error banner
|
|
17
|
+
* doesn't carry over to the next file. */
|
|
18
|
+
reset: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function fallbackName(htmlPath: string): string {
|
|
22
|
+
const base =
|
|
23
|
+
htmlPath
|
|
24
|
+
.split("/")
|
|
25
|
+
.pop()
|
|
26
|
+
?.replace(/\.html?$/i, "") || "share";
|
|
27
|
+
return `${base}.zip`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function useSharePack(): UseSharePackHandle {
|
|
31
|
+
const packing = ref(false);
|
|
32
|
+
const packFailed = ref(false);
|
|
33
|
+
|
|
34
|
+
async function downloadZip(htmlPath: string): Promise<void> {
|
|
35
|
+
packFailed.value = false;
|
|
36
|
+
packing.value = true;
|
|
37
|
+
try {
|
|
38
|
+
const response = await apiFetchRaw(API_ROUTES.share.pack, {
|
|
39
|
+
method: "POST",
|
|
40
|
+
headers: { "Content-Type": "application/json" },
|
|
41
|
+
body: JSON.stringify({ path: htmlPath }),
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
packFailed.value = true;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
saveBlob(await response.blob(), filenameFromDisposition(response.headers.get("content-disposition"), fallbackName(htmlPath)));
|
|
48
|
+
} catch {
|
|
49
|
+
packFailed.value = true;
|
|
50
|
+
} finally {
|
|
51
|
+
packing.value = false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function reset(): void {
|
|
56
|
+
packFailed.value = false;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return { packing, packFailed, downloadZip, reset };
|
|
60
|
+
}
|
|
@@ -1,109 +1,29 @@
|
|
|
1
|
-
// Translates a role's suggested queries into the user's current
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Translates a role's suggested queries into the user's current browser locale.
|
|
2
|
+
// A thin wrapper over the generic `useTranslatedStrings` (namespace
|
|
3
|
+
// "role-queries"); all caching / de-dup / fallback logic lives there and in the
|
|
4
|
+
// host-agnostic `@mulmoclaude/core/translation/client` cache it wraps.
|
|
5
5
|
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// an in-flight Promise map.
|
|
9
|
-
//
|
|
10
|
-
// `locale` is taken as a Ref instead of being read from `useI18n()`
|
|
11
|
-
// internally so the composable can be unit-tested outside a Vue
|
|
12
|
-
// setup context.
|
|
6
|
+
// `locale` is taken as a Ref instead of being read from `useI18n()` internally
|
|
7
|
+
// so the composable can be unit-tested outside a Vue setup context.
|
|
13
8
|
|
|
14
|
-
import { computed,
|
|
15
|
-
import {
|
|
16
|
-
import { API_ROUTES } from "../config/apiRoutes";
|
|
9
|
+
import { computed, type ComputedRef, type Ref } from "vue";
|
|
10
|
+
import { useTranslatedStrings, __resetTranslatedStringsCacheForTests } from "./useTranslatedStrings";
|
|
17
11
|
import type { Role } from "../config/roles";
|
|
18
12
|
|
|
19
13
|
const TRANSLATION_NAMESPACE = "role-queries";
|
|
20
14
|
|
|
21
|
-
interface TranslateResponse {
|
|
22
|
-
translations: string[];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const cache = new Map<string, Ref<string[] | null>>();
|
|
26
|
-
const inflight = new Map<string, Promise<void>>();
|
|
27
|
-
|
|
28
|
-
function cacheKey(roleId: string, locale: string): string {
|
|
29
|
-
return `${roleId}:${locale}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function ensureSlot(key: string): Ref<string[] | null> {
|
|
33
|
-
let slot = cache.get(key);
|
|
34
|
-
if (!slot) {
|
|
35
|
-
slot = ref<string[] | null>(null);
|
|
36
|
-
cache.set(key, slot);
|
|
37
|
-
}
|
|
38
|
-
return slot;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async function runFetch(key: string, locale: string, sentences: string[]): Promise<void> {
|
|
42
|
-
const result = await apiPost<TranslateResponse>(API_ROUTES.translation.translate, {
|
|
43
|
-
namespace: TRANSLATION_NAMESPACE,
|
|
44
|
-
targetLanguage: locale,
|
|
45
|
-
sentences,
|
|
46
|
-
});
|
|
47
|
-
if (!result.ok) {
|
|
48
|
-
console.warn("[useTranslatedQueries] translate failed:", result.error);
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
const { translations } = result.data;
|
|
52
|
-
if (!Array.isArray(translations) || translations.length !== sentences.length) {
|
|
53
|
-
console.warn("[useTranslatedQueries] translate returned wrong length", {
|
|
54
|
-
expected: sentences.length,
|
|
55
|
-
got: Array.isArray(translations) ? translations.length : "(not array)",
|
|
56
|
-
});
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
ensureSlot(key).value = [...translations];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function ensureFetch(roleId: string, locale: string, sentences: string[]): void {
|
|
63
|
-
const key = cacheKey(roleId, locale);
|
|
64
|
-
if (inflight.has(key)) return;
|
|
65
|
-
if (ensureSlot(key).value !== null) return;
|
|
66
|
-
const pending = runFetch(key, locale, sentences).finally(() => {
|
|
67
|
-
inflight.delete(key);
|
|
68
|
-
});
|
|
69
|
-
inflight.set(key, pending);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
15
|
export interface UseTranslatedQueriesResult {
|
|
73
|
-
/** Translated queries when available, falling back to the role's
|
|
74
|
-
*
|
|
16
|
+
/** Translated queries when available, falling back to the role's English
|
|
17
|
+
* source while the request is in flight or fails. */
|
|
75
18
|
readonly queries: ComputedRef<string[]>;
|
|
76
19
|
}
|
|
77
20
|
|
|
78
21
|
export function useTranslatedQueries(role: Ref<Role | undefined>, locale: Ref<string>): UseTranslatedQueriesResult {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (!current) return;
|
|
82
|
-
const sources = current.queries;
|
|
83
|
-
if (!sources || sources.length === 0) return;
|
|
84
|
-
const lang = locale.value;
|
|
85
|
-
if (lang === "en") return;
|
|
86
|
-
ensureFetch(current.id, lang, [...sources]);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const queries = computed<string[]>(() => {
|
|
90
|
-
const current = role.value;
|
|
91
|
-
const sources = current?.queries ?? [];
|
|
92
|
-
if (sources.length === 0) return [];
|
|
93
|
-
const lang = locale.value;
|
|
94
|
-
if (lang === "en" || !current) return [...sources];
|
|
95
|
-
return cache.get(cacheKey(current.id, lang))?.value ?? [...sources];
|
|
96
|
-
});
|
|
97
|
-
|
|
22
|
+
const sentences = computed<readonly string[]>(() => role.value?.queries ?? []);
|
|
23
|
+
const queries = useTranslatedStrings(TRANSLATION_NAMESPACE, sentences, locale);
|
|
98
24
|
return { queries };
|
|
99
25
|
}
|
|
100
26
|
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
|
|
104
|
-
// share a worker can still reset between cases.
|
|
105
|
-
|
|
106
|
-
export function __resetTranslatedQueriesCacheForTests(): void {
|
|
107
|
-
cache.clear();
|
|
108
|
-
inflight.clear();
|
|
109
|
-
}
|
|
27
|
+
// Re-exported under the historical name so existing tests keep resetting the
|
|
28
|
+
// (now shared) translation cache between cases.
|
|
29
|
+
export const __resetTranslatedQueriesCacheForTests = __resetTranslatedStringsCacheForTests;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Generic runtime-translation composable: translate a reactive list of English
|
|
2
|
+
// UI strings into the user's locale via the host's /api/translation route. The
|
|
3
|
+
// host-agnostic cache (de-dup, memo, length validation) lives in
|
|
4
|
+
// `@mulmoclaude/core/translation/client`; this file is the thin Vue layer —
|
|
5
|
+
// reactivity + the `en`/empty fallback. `useTranslatedQueries` (role chips) and
|
|
6
|
+
// any future caller share the one module-singleton cache below.
|
|
7
|
+
//
|
|
8
|
+
// `locale` and `sentences` are taken as Refs (not read from `useI18n()`) so the
|
|
9
|
+
// composable can be unit-tested outside a Vue setup context.
|
|
10
|
+
|
|
11
|
+
import { computed, watchEffect, type ComputedRef, type Ref, ref } from "vue";
|
|
12
|
+
import { createTranslationCache, type TranslateRequest, type TranslateResponse } from "@mulmoclaude/core/translation/client";
|
|
13
|
+
import { apiPost } from "../utils/api";
|
|
14
|
+
import { API_ROUTES } from "../config/apiRoutes";
|
|
15
|
+
|
|
16
|
+
const cache = createTranslationCache((req) =>
|
|
17
|
+
apiPost<TranslateResponse>(API_ROUTES.translation.translate, req).then((result) => (result.ok ? result.data : null)),
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
/** Pure projection: the translated batch when present, else the English source. */
|
|
21
|
+
export function pickTranslated(translated: readonly string[] | null, sources: readonly string[]): string[] {
|
|
22
|
+
return [...(translated ?? sources)];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Resolve a request through the cache (peek-then-fetch) and hand the result to
|
|
26
|
+
* `apply`, but only while `isCurrent()` still holds — so a slow response can't
|
|
27
|
+
* overwrite a newer locale/input's translation. */
|
|
28
|
+
function loadInto(req: TranslateRequest, isCurrent: () => boolean, apply: (value: readonly string[]) => void): void {
|
|
29
|
+
const hit = cache.peek(req);
|
|
30
|
+
if (hit !== null) {
|
|
31
|
+
apply(hit);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
cache
|
|
35
|
+
.fetch(req)
|
|
36
|
+
.then((result) => {
|
|
37
|
+
if (result !== null && isCurrent()) apply(result);
|
|
38
|
+
})
|
|
39
|
+
.catch(() => {
|
|
40
|
+
/* transport rejected — keep the English fallback */
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Translated strings when available, falling back to the English source while
|
|
45
|
+
* the request is in flight or on failure. `en` and empty inputs never fetch. */
|
|
46
|
+
export function useTranslatedStrings(namespace: string, sentences: Ref<readonly string[]>, locale: Ref<string>): ComputedRef<string[]> {
|
|
47
|
+
const translated = ref<readonly string[] | null>(null);
|
|
48
|
+
watchEffect(() => {
|
|
49
|
+
const lang = locale.value;
|
|
50
|
+
const sources = sentences.value;
|
|
51
|
+
translated.value = null; // reset on any input change → source shows meanwhile
|
|
52
|
+
if (lang === "en" || sources.length === 0) return;
|
|
53
|
+
const req = { namespace, targetLanguage: lang, sentences: sources };
|
|
54
|
+
loadInto(
|
|
55
|
+
req,
|
|
56
|
+
() => locale.value === lang && sentences.value === sources,
|
|
57
|
+
(value) => (translated.value = value),
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
return computed<string[]>(() => pickTranslated(translated.value, sentences.value));
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ── Test-only hook ──────────────────────────────────────────────────
|
|
64
|
+
// Vitest / node:test usually gets a fresh worker per file, but suites that
|
|
65
|
+
// share a worker reset the singleton cache between cases through this.
|
|
66
|
+
export function __resetTranslatedStringsCacheForTests(): void {
|
|
67
|
+
cache.clear();
|
|
68
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// Thin Vue wrapper over the framework-neutral capture controller in
|
|
2
|
-
// `@mulmoclaude/whisper/client` (shared with MulmoTerminal). This file supplies
|
|
2
|
+
// `@mulmoclaude/core/whisper/client` (shared with MulmoTerminal). This file supplies
|
|
3
3
|
// the MulmoClaude-specific transport (api client + route constants) and language
|
|
4
4
|
// mapping, and mirrors the controller's pushed state into Vue refs. The capture
|
|
5
5
|
// logic itself (MediaRecorder + VAD + segment queue) lives in the package.
|
|
6
|
-
// See plans/feat-extract-whisper-package.md.
|
|
6
|
+
// See plans/done/feat-extract-whisper-package.md.
|
|
7
7
|
|
|
8
8
|
import { onScopeDispose, ref, type Ref } from "vue";
|
|
9
|
-
import { createVoiceCapture, localeToWhisperLanguage, type VoiceCaptureTransport } from "@mulmoclaude/whisper/client";
|
|
9
|
+
import { createVoiceCapture, localeToWhisperLanguage, type VoiceCaptureTransport } from "@mulmoclaude/core/whisper/client";
|
|
10
10
|
import { API_ROUTES } from "../config/apiRoutes";
|
|
11
11
|
import { apiGet, apiPost } from "../utils/api";
|
|
12
12
|
|
package/src/config/apiRoutes.ts
CHANGED
|
@@ -33,11 +33,13 @@ type ResolveRoutes<R extends Readonly<Record<string, RouteSpec>>> = {
|
|
|
33
33
|
readonly [K in keyof R]: ResolvedRoute;
|
|
34
34
|
};
|
|
35
35
|
type PluginApiRoutesMap<T extends BuiltInPluginMetas> = {
|
|
36
|
-
readonly [
|
|
37
|
-
|
|
38
|
-
? K
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
readonly [
|
|
37
|
+
M in T[number] as M extends { readonly apiRoutes: Readonly<Record<string, RouteSpec>> }
|
|
38
|
+
? M extends { readonly apiNamespace: infer K extends string }
|
|
39
|
+
? K
|
|
40
|
+
: M["toolName"]
|
|
41
|
+
: never
|
|
42
|
+
]: M extends { readonly apiRoutes: infer R extends Readonly<Record<string, RouteSpec>> } ? ResolveRoutes<R> : never;
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
/** Resolve every plugin route into a `ResolvedRoute` keyed by the
|
|
@@ -61,6 +63,11 @@ const HOST_API_ROUTES = {
|
|
|
61
63
|
// order). Single replace-endpoint — no add/remove route sprawl.
|
|
62
64
|
shortcuts: "/api/shortcuts",
|
|
63
65
|
|
|
66
|
+
// Dashboard layout (per-tile view mode + order for the favorites grid).
|
|
67
|
+
// GET reads the list; PUT replaces it wholesale (client owns order /
|
|
68
|
+
// view mode). Single replace-endpoint, mirroring `shortcuts`.
|
|
69
|
+
dashboard: "/api/dashboard",
|
|
70
|
+
|
|
64
71
|
agent: {
|
|
65
72
|
run: "/api/agent",
|
|
66
73
|
cancel: "/api/agent/cancel",
|
|
@@ -133,6 +140,25 @@ const HOST_API_ROUTES = {
|
|
|
133
140
|
upload: "/api/attachments",
|
|
134
141
|
},
|
|
135
142
|
|
|
143
|
+
// Sharing: pack an HTML artifact + its referenced local assets into a
|
|
144
|
+
// self-contained zip (index.html + assets/), streamed as a download.
|
|
145
|
+
// `packMarkdown` renders markdown / a wiki page to a self-contained
|
|
146
|
+
// HTML (images inlined) and zips that.
|
|
147
|
+
share: {
|
|
148
|
+
pack: "/api/share/pack",
|
|
149
|
+
packMarkdown: "/api/share/pack-markdown",
|
|
150
|
+
},
|
|
151
|
+
|
|
152
|
+
// Remote host over Firestore (phase 1). The server signs in to Firebase as
|
|
153
|
+
// the user (connect, body carries a browser-minted Google idToken), runs the
|
|
154
|
+
// command-loop + presence heartbeat, and exposes its running state. See
|
|
155
|
+
// plans/feat-remote-host-firestore-list-collections.md.
|
|
156
|
+
remoteHost: {
|
|
157
|
+
connect: "/api/remote-host/connect",
|
|
158
|
+
disconnect: "/api/remote-host/disconnect",
|
|
159
|
+
status: "/api/remote-host/status",
|
|
160
|
+
},
|
|
161
|
+
|
|
136
162
|
mcpTools: {
|
|
137
163
|
list: "/api/mcp-tools",
|
|
138
164
|
invoke: "/api/mcp-tools/:tool",
|
|
@@ -167,7 +193,7 @@ const HOST_API_ROUTES = {
|
|
|
167
193
|
// Local voice input (Mac-only, whisper.cpp). `run` transcribes one
|
|
168
194
|
// audio clip; `model` reports capability + download status; `modelDownload`
|
|
169
195
|
// is the opt-in trigger fired by the Settings → Voice enable toggle.
|
|
170
|
-
// See plans/feat-voice-input.md.
|
|
196
|
+
// See plans/done/feat-voice-input.md.
|
|
171
197
|
transcribe: {
|
|
172
198
|
run: "/api/transcribe",
|
|
173
199
|
model: "/api/transcribe/model",
|
|
@@ -267,6 +293,14 @@ const HOST_API_ROUTES = {
|
|
|
267
293
|
/** GET ?id=<viewId> → the custom view's HTML file (global-bearer auth),
|
|
268
294
|
* read from data/skills/:slug/views/. The parent renders it sandboxed. */
|
|
269
295
|
viewFile: "/api/collections/:slug/view-file",
|
|
296
|
+
/** GET ?id=<viewId>&locale=<tag> → translation dict for one custom view
|
|
297
|
+
* (global-bearer auth) → { locale, dict }. `dict` is the host-picked
|
|
298
|
+
* flat map for the requested locale (fallback `"en"`, else `{}`); the
|
|
299
|
+
* host never streams other locales' strings. Empty dict + `locale: ""`
|
|
300
|
+
* when the view declares no `i18n` file or the file is missing /
|
|
301
|
+
* malformed — the view keeps working via `__MC_VIEW.t()`'s key
|
|
302
|
+
* fallback. */
|
|
303
|
+
viewI18n: "/api/collections/:slug/view-i18n",
|
|
270
304
|
/** POST → mint a slug- and capability-scoped token for a custom view
|
|
271
305
|
* (global-bearer auth) → { token, exp, dataUrl, capabilities }. */
|
|
272
306
|
viewToken: "/api/collections/:slug/view-token",
|
|
@@ -280,6 +314,22 @@ const HOST_API_ROUTES = {
|
|
|
280
314
|
viewDelete: "/api/collections/:slug/views/:viewId",
|
|
281
315
|
},
|
|
282
316
|
|
|
317
|
+
// Curated collection registry (receptron/mulmoclaude-collections). The host
|
|
318
|
+
// server-fetches the published index.json (GitHub Pages) and proxies it to the
|
|
319
|
+
// /collections Discover tab — the upstream URL is never exposed to the client.
|
|
320
|
+
collectionsRegistry: {
|
|
321
|
+
list: "/api/collections-registry",
|
|
322
|
+
/** GET ?author=&slug= → { entry, schema, meta } for one in-index collection. */
|
|
323
|
+
preview: "/api/collections-registry/preview",
|
|
324
|
+
/** POST { author, slug } → fetch + re-validate + install into .claude/skills/,
|
|
325
|
+
* normalize dataPath, materialize seed, record provenance. */
|
|
326
|
+
import: "/api/collections-registry/import",
|
|
327
|
+
/** POST { slug, author, license?, includeSeed? } → write a registry-contribution
|
|
328
|
+
* bundle (collections/<author>/<slug>/ + meta.json + optional seed) under
|
|
329
|
+
* data/registry-export/ for the user to open a PR. */
|
|
330
|
+
export: "/api/collections-registry/export",
|
|
331
|
+
},
|
|
332
|
+
|
|
283
333
|
// `scheduler` group migrated to META — see `src/plugins/scheduler/automationsMeta.ts`.
|
|
284
334
|
// Auto-merged via `apiNamespace: "scheduler"`.
|
|
285
335
|
|
|
@@ -345,9 +395,7 @@ const HOST_API_ROUTES = {
|
|
|
345
395
|
// `defineHostAggregate` is runtime-generic; the cast on the merged
|
|
346
396
|
// result narrows it back to the literal-preserving shape above.
|
|
347
397
|
type ApiRoutesAggregateValue =
|
|
348
|
-
|
|
349
|
-
| Readonly<Record<string, string>>
|
|
350
|
-
| Readonly<Record<string, ResolvedRoute>>;
|
|
398
|
+
(typeof HOST_API_ROUTES)[keyof typeof HOST_API_ROUTES] | Readonly<Record<string, string>> | Readonly<Record<string, ResolvedRoute>>;
|
|
351
399
|
|
|
352
400
|
const API_ROUTES_AGGREGATE = defineHostAggregate<ApiRoutesAggregateValue>(BUILT_IN_PLUGIN_METAS, {
|
|
353
401
|
label: "API_ROUTES",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// a workspace-relative POSIX string matching `TreeNode.path` for the
|
|
17
17
|
// folder row that should expose the menu.
|
|
18
18
|
|
|
19
|
-
import { isSafeSlug } from "
|
|
19
|
+
import { isSafeSlug } from "@mulmoclaude/core/wiki";
|
|
20
20
|
|
|
21
21
|
export interface CreateFilePolicy {
|
|
22
22
|
/** Workspace-relative POSIX folder path. Matched verbatim against
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Browser-side Firebase init for the remote-host settings page.
|
|
2
|
+
//
|
|
3
|
+
// Initializes the Firebase web app and exposes the Auth instance used by the
|
|
4
|
+
// SettingsRemoteHostTab to run the Google sign-in popup and extract the Google
|
|
5
|
+
// OAuth idToken (which is then POSTed to the server's /connect route).
|
|
6
|
+
import { initializeApp } from "firebase/app";
|
|
7
|
+
import { getAuth } from "firebase/auth";
|
|
8
|
+
|
|
9
|
+
import { firebaseConfig } from "./firebaseConfig";
|
|
10
|
+
|
|
11
|
+
export const firebaseApp = initializeApp(firebaseConfig);
|
|
12
|
+
export const auth = getAuth(firebaseApp);
|