blun-king-cli 9.0.0 → 9.1.0
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/LIESMICH.txt +32 -13
- package/README.md +39 -20
- package/bin/blun.js +248 -160
- package/bin/core-bootstrap.js +47 -0
- package/bin/king.js +277 -1
- package/bin/launcher-mode.js +15 -3
- package/bin/launcher-runtime.js +293 -0
- package/bin/plugin-bootstrap.js +11 -4
- package/bin/private-paths.js +1577 -10
- package/bin/update-lease.js +399 -0
- package/bin/update-notice.js +1245 -0
- package/blun.mjs +26606 -25239
- package/dist-web/assets/{CodeBlockNode-Bsvp6ZEy.js → CodeBlockNode-CXnTLMNr.js} +1 -1
- package/dist-web/assets/{CodeBlockShell.vue_vue_type_style_index_0_lang-ta7hLjia.js → CodeBlockShell.vue_vue_type_style_index_0_lang-CCF8Ntnq.js} +1 -1
- package/dist-web/assets/{DesignSystemView-BmDDe28A.js → DesignSystemView-BbMOu-XO.js} +1 -1
- package/dist-web/assets/{Tooltip-nEEfaYVY.js → Tooltip-CFQEzqC-.js} +1 -1
- package/dist-web/assets/abnfDiagram-N423BO3Z-CsByy-GW.js +1 -0
- package/dist-web/assets/abnfDiagram-N423BO3Z-Z1APZG5m.js +1 -0
- package/dist-web/assets/arc-C-LXCaja.js +1 -0
- package/dist-web/assets/arc-C4VyWloT.js +1 -0
- package/dist-web/assets/architectureDiagram-T3A2C74G-DZq4L18e.js +36 -0
- package/dist-web/assets/architectureDiagram-T3A2C74G-DpddbUcM.js +36 -0
- package/dist-web/assets/blockDiagram-VBNYF7ZC-BV4sIf98.js +132 -0
- package/dist-web/assets/blockDiagram-VBNYF7ZC-BqccOSMr.js +132 -0
- package/dist-web/assets/{c4Diagram-AAUBKEIU-DtzacMnD.js → c4Diagram-5PPSVZJV-0MRkZlgP.js} +1 -1
- package/dist-web/assets/{c4Diagram-AAUBKEIU-D1VdMx8d.js → c4Diagram-5PPSVZJV-OHAcJrTy.js} +1 -1
- package/dist-web/assets/channel-B2VOQOI-.js +1 -0
- package/dist-web/assets/channel-DKjwM05G.js +1 -0
- package/dist-web/assets/{chunk-ND2GUHAM-DJoY9wNJ.js → chunk-2GRJ4B5K-DqJHs8Fw.js} +1 -1
- package/dist-web/assets/{chunk-ND2GUHAM-C4-rwdcv.js → chunk-2GRJ4B5K-oO6nqeLA.js} +1 -1
- package/dist-web/assets/{chunk-QZHKN3VN-C7YGaShq.js → chunk-2Q5K7J3B-B1nCd91o.js} +1 -1
- package/dist-web/assets/{chunk-QZHKN3VN-_Rz9_NuS.js → chunk-2Q5K7J3B-BC0Hsfqy.js} +1 -1
- package/dist-web/assets/chunk-5RXB4S5H-BfZa4yDH.js +231 -0
- package/dist-web/assets/chunk-5RXB4S5H-neG70kZx.js +231 -0
- package/dist-web/assets/{chunk-FMBD7UC4-DlLNDUx6.js → chunk-5VM5RSS4-l7biGqeH.js} +1 -1
- package/dist-web/assets/{chunk-FMBD7UC4-B2zs_Y-d.js → chunk-5VM5RSS4-u00AcpiJ.js} +1 -1
- package/dist-web/assets/chunk-6Q2QTUOP-BO-F11Gs.js +88 -0
- package/dist-web/assets/chunk-6Q2QTUOP-RUVRPBzG.js +88 -0
- package/dist-web/assets/{chunk-727SXJPM-Dn5wkDO_.js → chunk-GF5L2VYU-Ba-86KTd.js} +5 -5
- package/dist-web/assets/{chunk-727SXJPM-Dk2Xa3bA.js → chunk-GF5L2VYU-BtC69fw0.js} +5 -5
- package/dist-web/assets/{chunk-4BX2VUAB-DxZViaHS.js → chunk-JWPE2WC7-DIOubEqr.js} +1 -1
- package/dist-web/assets/{chunk-4BX2VUAB-WqrE2gaw.js → chunk-JWPE2WC7-u8Pcfhwh.js} +1 -1
- package/dist-web/assets/{chunk-2J33WTMH-Dm_s0_4f.js → chunk-KBJHAD2P-DDUeH_Ba.js} +1 -1
- package/dist-web/assets/{chunk-2J33WTMH-w4sdiKFO.js → chunk-KBJHAD2P-DS3BL64y.js} +1 -1
- package/dist-web/assets/chunk-RYQCIY6F-B9gFMVbS.js +1 -0
- package/dist-web/assets/chunk-RYQCIY6F-xg3EO0le.js +1 -0
- package/dist-web/assets/{chunk-55IACEB6-B5dE1-Um.js → chunk-XXDRQBXY-B60H0rRC.js} +1 -1
- package/dist-web/assets/{chunk-55IACEB6-B12zGIFz.js → chunk-XXDRQBXY-Bn1Xz6TQ.js} +1 -1
- package/dist-web/assets/classDiagram-JCYQIIEL-BA1TjAxj.js +1 -0
- package/dist-web/assets/classDiagram-JCYQIIEL-BNU7Qn4k.js +1 -0
- package/dist-web/assets/classDiagram-v2-OCEON4UE-BA1TjAxj.js +1 -0
- package/dist-web/assets/classDiagram-v2-OCEON4UE-BNU7Qn4k.js +1 -0
- package/dist-web/assets/{cose-bilkent-S5V4N54A-Bi19n8m-.js → cose-bilkent-JH36ORCC-4Ybddg08.js} +1 -1
- package/dist-web/assets/{cose-bilkent-S5V4N54A-c8o8NFp5.js → cose-bilkent-JH36ORCC-DqigO3T4.js} +1 -1
- package/dist-web/assets/cynefin-VYW2F7L2-C-EfYT07.js +178 -0
- package/dist-web/assets/cynefin-VYW2F7L2-rpD93tQ-.js +178 -0
- package/dist-web/assets/cynefinDiagram-MW4NZA55-DWZPLJcD.js +62 -0
- package/dist-web/assets/cynefinDiagram-MW4NZA55-DbTqnkVJ.js +62 -0
- package/dist-web/assets/dagre-VZM6K2ZE-DcM8aEVY.js +4 -0
- package/dist-web/assets/dagre-VZM6K2ZE-M_HVNtqP.js +4 -0
- package/dist-web/assets/diagram-7IWD3JNH-DoNximNF.js +30 -0
- package/dist-web/assets/diagram-7IWD3JNH-UymgsBNa.js +30 -0
- package/dist-web/assets/{diagram-KO2AKTUF-CFQs13i5.js → diagram-B4RE2ZJO-BVA2EhnC.js} +3 -3
- package/dist-web/assets/{diagram-KO2AKTUF-agFIuPJW.js → diagram-B4RE2ZJO-BiYu5WPF.js} +3 -3
- package/dist-web/assets/{diagram-LMA3HP47-TMIXizxR.js → diagram-LBJQPF4R-BD3kkgOO.js} +2 -2
- package/dist-web/assets/{diagram-LMA3HP47-He5zlyMt.js → diagram-LBJQPF4R-m3a1Euj3.js} +2 -2
- package/dist-web/assets/diagram-Q27KOJAE-D1mYQ_cI.js +24 -0
- package/dist-web/assets/diagram-Q27KOJAE-hy_T73PK.js +24 -0
- package/dist-web/assets/diagram-UB23O5K3-BWkoQZ4A.js +41 -0
- package/dist-web/assets/diagram-UB23O5K3-BtX8u6HG.js +41 -0
- package/dist-web/assets/ebnfDiagram-BXEA7PRR-BKs9JUHW.js +1 -0
- package/dist-web/assets/ebnfDiagram-BXEA7PRR-CBAnFkRF.js +1 -0
- package/dist-web/assets/erDiagram-JOGREHBK-3vKcWsxm.js +85 -0
- package/dist-web/assets/erDiagram-JOGREHBK-BIpd6dTf.js +85 -0
- package/dist-web/assets/flowDiagram-UKHOOZJN-D9wBbHm2.js +156 -0
- package/dist-web/assets/flowDiagram-UKHOOZJN-Z83i2UWI.js +156 -0
- package/dist-web/assets/ganttDiagram-PKOTCBZU-Cd_dViF-.js +292 -0
- package/dist-web/assets/ganttDiagram-PKOTCBZU-DFrb_S1d.js +292 -0
- package/dist-web/assets/{gitGraphDiagram-PVQCEYII-BSDFfwdY.js → gitGraphDiagram-DS77QQ5N-BiEEtTo7.js} +3 -3
- package/dist-web/assets/{gitGraphDiagram-PVQCEYII-DMbTATyw.js → gitGraphDiagram-DS77QQ5N-Dp3Ar-hi.js} +3 -3
- package/dist-web/assets/{graph-BwjfAU3j.js → graph-CAUpWmoK.js} +1 -1
- package/dist-web/assets/{graph--OzhPTMs.js → graph-DOmOIIwC.js} +1 -1
- package/dist-web/assets/{index-W6VnSrkB.js → index-Ba1OvLjf.js} +2 -2
- package/dist-web/assets/{index-CkVgGDpx.js → index-CiPA8Kex.js} +4 -4
- package/dist-web/assets/{index-BzK4vJBu.js → index-DdEakFJM.js} +1 -1
- package/dist-web/assets/{index10-Czg_oF-W.js → index10-CNr4U-Nw.js} +1 -1
- package/dist-web/assets/{index11-BjzCZuCr.js → index11-Dto_yZNz.js} +1 -1
- package/dist-web/assets/{index5-DlVoNkCD.js → index5-B2PldaO2.js} +1 -1
- package/dist-web/assets/{index6-BxiXA2yo.js → index6-CBdZmmyx.js} +1 -1
- package/dist-web/assets/{index7-BPdza6d1.js → index7-Dz9oCsUF.js} +1 -1
- package/dist-web/assets/{index8-Q_XzGC1Z.js → index8-B6k25jtU.js} +2 -2
- package/dist-web/assets/{infoDiagram-5YYISTIA-2JF3XEdD.js → infoDiagram-6WML65LV-BSa2g04G.js} +1 -1
- package/dist-web/assets/{infoDiagram-5YYISTIA-UrQusrJq.js → infoDiagram-6WML65LV-D4ph2sIH.js} +1 -1
- package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-7RVUL-vB.js → ishikawaDiagram-WSZJBQD7-DjKjbMm9.js} +5 -5
- package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-C5OstRVV.js → ishikawaDiagram-WSZJBQD7-Hm36UOQe.js} +5 -5
- package/dist-web/assets/{journeyDiagram-JHISSGLW-B34fCMu9.js → journeyDiagram-NVQOT4AX-DttHDfPQ.js} +1 -1
- package/dist-web/assets/{journeyDiagram-JHISSGLW-yctdo4bX.js → journeyDiagram-NVQOT4AX-MvWWPNDV.js} +1 -1
- package/dist-web/assets/{kanban-definition-UN3LZRKU-BS4FBZsQ.js → kanban-definition-27J2QSJJ-C5gB-W0d.js} +7 -7
- package/dist-web/assets/{kanban-definition-UN3LZRKU-CxBCv27E.js → kanban-definition-27J2QSJJ-Cu-E_cXA.js} +5 -5
- package/dist-web/assets/layout-CvP6o9AK.js +1 -0
- package/dist-web/assets/layout-D-LzfAck.js +1 -0
- package/dist-web/assets/{linear-3mB6q2-g.js → linear-B3HWgQI2.js} +1 -1
- package/dist-web/assets/{linear-BKCnUo31.js → linear-BRGe4-d6.js} +1 -1
- package/dist-web/assets/map-CWKZqZjr.js +1 -0
- package/dist-web/assets/map-DxJ2ADlA.js +1 -0
- package/dist-web/assets/mermaid.core-D-9Sx1No.js +314 -0
- package/dist-web/assets/mermaidParser.worker-PTFfzpoB.js +318 -0
- package/dist-web/assets/{mindmap-definition-RKZ34NQL-BmJZpjh6.js → mindmap-definition-FAOFIHXS-C4vnms3i.js} +2 -2
- package/dist-web/assets/{mindmap-definition-RKZ34NQL-1mjWUcf6.js → mindmap-definition-FAOFIHXS-Cg_hoVIq.js} +1 -1
- package/dist-web/assets/pegDiagram-VL7TDLO6-B2fFEFUH.js +1 -0
- package/dist-web/assets/pegDiagram-VL7TDLO6-CSX9hitD.js +1 -0
- package/dist-web/assets/pieDiagram-7S7Q4E2Y-0L0mxahZ.js +39 -0
- package/dist-web/assets/pieDiagram-7S7Q4E2Y-C7T0Cmw1.js +39 -0
- package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BmT_qM09.js → quadrantDiagram-CIZ2JOQS-BBy7w4kD.js} +3 -3
- package/dist-web/assets/{quadrantDiagram-W4KKPZXB-C0kPuyNP.js → quadrantDiagram-CIZ2JOQS-U483z0er.js} +3 -3
- package/dist-web/assets/railroadDiagram-AXF67PYL-D80a2_DJ.js +1 -0
- package/dist-web/assets/railroadDiagram-AXF67PYL-DX8y0MzW.js +1 -0
- package/dist-web/assets/{requirementDiagram-4Y6WPE33-C0YP_Amt.js → requirementDiagram-LRYGKXZP-CeyHfq8t.js} +3 -3
- package/dist-web/assets/{requirementDiagram-4Y6WPE33-CZrxH1Y2.js → requirementDiagram-LRYGKXZP-DGD5J_4k.js} +3 -3
- package/dist-web/assets/sankeyDiagram-W5VNT64P-CCISkkrR.js +40 -0
- package/dist-web/assets/sankeyDiagram-W5VNT64P-CT5PdZz2.js +40 -0
- package/dist-web/assets/sequenceDiagram-SI44F4Z6-BeMzHWXI.js +162 -0
- package/dist-web/assets/sequenceDiagram-SI44F4Z6-jQfm2XS7.js +162 -0
- package/dist-web/assets/sizeCapture-X5ZJPWSS-BQsTdtrv.js +1 -0
- package/dist-web/assets/sizeCapture-X5ZJPWSS-lRZsmCoS.js +1 -0
- package/dist-web/assets/stateDiagram-OKZ733FA-ClCgTdUm.js +1 -0
- package/dist-web/assets/stateDiagram-OKZ733FA-Cv59z5YT.js +1 -0
- package/dist-web/assets/stateDiagram-v2-UEYNNEHI-R8jTc--F.js +1 -0
- package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fi_lrTAx.js +1 -0
- package/dist-web/assets/swimlanes-SLNWSIFB-BCdOUN05.js +2 -0
- package/dist-web/assets/swimlanes-SLNWSIFB-Cu5l7SuR.js +1 -0
- package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-BUd_uYK3.js +8 -0
- package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-CalrsgPK.js +8 -0
- package/dist-web/assets/{timeline-definition-PNZ67QCA-DsVZdrZa.js → timeline-definition-Z64GVDOM-CMjnh4bu.js} +4 -4
- package/dist-web/assets/{timeline-definition-PNZ67QCA-DnB6Usl0.js → timeline-definition-Z64GVDOM-DpWutSKa.js} +4 -4
- package/dist-web/assets/vennDiagram-T6HMQDX7-DKJW_8oU.js +34 -0
- package/dist-web/assets/vennDiagram-T6HMQDX7-DVC5JVsc.js +34 -0
- package/dist-web/assets/{vue.runtime.esm-bundler-pgHGheCW.js → vue.runtime.esm-bundler-BwwRtQwQ.js} +1 -1
- package/dist-web/assets/{wardleyDiagram-YWT4CUSO-oBauTCEw.js → wardleyDiagram-T6FBY63Y-BK2mrq7L.js} +3 -3
- package/dist-web/assets/{wardleyDiagram-YWT4CUSO-DCiyDQNB.js → wardleyDiagram-T6FBY63Y-oUvgepFn.js} +3 -3
- package/dist-web/assets/xychartDiagram-ELKLHX3M-DI6n79q0.js +7 -0
- package/dist-web/assets/xychartDiagram-ELKLHX3M-DUJu9F7-.js +7 -0
- package/dist-web/index.html +1 -1
- package/dist-web/vis/index.html.gz +0 -0
- package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
- package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
- package/package.json +9 -11
- package/skills/screenshot-lesen/SKILL.md +0 -1
- package/skills/web-lesen/SKILL.md +0 -1
- package/telegram-plugin/dist/bridge.mjs +7 -25
- package/telegram-plugin/dist/mcp-server.mjs +236 -71
- package/dist-web/assets/arc-4xPfymbf.js +0 -1
- package/dist-web/assets/arc-Doj0wRZ0.js +0 -1
- package/dist-web/assets/architectureDiagram-3BPJPVTR-BGih283a.js +0 -36
- package/dist-web/assets/architectureDiagram-3BPJPVTR-CQ09RrbH.js +0 -36
- package/dist-web/assets/blockDiagram-GPEHLZMM-3ShMf1gu.js +0 -132
- package/dist-web/assets/blockDiagram-GPEHLZMM-CAtDjkJt.js +0 -132
- package/dist-web/assets/channel-DNkUo9e6.js +0 -1
- package/dist-web/assets/channel-DcnUTIGB.js +0 -1
- package/dist-web/assets/chunk-AQP2D5EJ-FS8-f8lF.js +0 -231
- package/dist-web/assets/chunk-AQP2D5EJ-UKhb4V4r.js +0 -231
- package/dist-web/assets/classDiagram-4FO5ZUOK-B1ZO8EbE.js +0 -1
- package/dist-web/assets/classDiagram-4FO5ZUOK-xk6cM9Kq.js +0 -1
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-B1ZO8EbE.js +0 -1
- package/dist-web/assets/classDiagram-v2-Q7XG4LA2-xk6cM9Kq.js +0 -1
- package/dist-web/assets/dagre-BM42HDAG-CmUO9qKN.js +0 -4
- package/dist-web/assets/dagre-BM42HDAG-DLMfLCoV.js +0 -4
- package/dist-web/assets/diagram-2AECGRRQ-DQTst0OH.js +0 -43
- package/dist-web/assets/diagram-2AECGRRQ-L74iLMqd.js +0 -43
- package/dist-web/assets/diagram-5GNKFQAL-BiBm7CJR.js +0 -10
- package/dist-web/assets/diagram-5GNKFQAL-DoE6q7H1.js +0 -10
- package/dist-web/assets/diagram-OG6HWLK6-BHCt1E0n.js +0 -24
- package/dist-web/assets/diagram-OG6HWLK6-DRyxjFMa.js +0 -24
- package/dist-web/assets/erDiagram-TEJ5UH35-BoDczjGG.js +0 -85
- package/dist-web/assets/erDiagram-TEJ5UH35-yd6SOv_7.js +0 -85
- package/dist-web/assets/flowDiagram-I6XJVG4X-DHoceI7r.js +0 -162
- package/dist-web/assets/flowDiagram-I6XJVG4X-DkYNQv0R.js +0 -162
- package/dist-web/assets/ganttDiagram-6RSMTGT7-Cg1TQBc0.js +0 -292
- package/dist-web/assets/ganttDiagram-6RSMTGT7-Z6klo7KK.js +0 -292
- package/dist-web/assets/layout-C1ojF0zw.js +0 -1
- package/dist-web/assets/layout-SsrduOYp.js +0 -1
- package/dist-web/assets/mermaid.core-D_lKT0dR.js +0 -309
- package/dist-web/assets/mermaidParser.worker-Dx4jPi9z.js +0 -313
- package/dist-web/assets/pieDiagram-4H26LBE5-BU41t2A_.js +0 -30
- package/dist-web/assets/pieDiagram-4H26LBE5-BkwDAvbt.js +0 -30
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-De_o7hDr.js +0 -40
- package/dist-web/assets/sankeyDiagram-5OEKKPKP-Dvuj6bMA.js +0 -40
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-DuCrgPyA.js +0 -162
- package/dist-web/assets/sequenceDiagram-3UESZ5HK-VAxffBe7.js +0 -162
- package/dist-web/assets/stateDiagram-AJRCARHV-CYLupxM7.js +0 -1
- package/dist-web/assets/stateDiagram-AJRCARHV-nDExQydZ.js +0 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BhEc7Thx.js +0 -1
- package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BzwD_BIl.js +0 -1
- package/dist-web/assets/vennDiagram-CIIHVFJN-BBHQmCFf.js +0 -34
- package/dist-web/assets/vennDiagram-CIIHVFJN-Cfj-K9NW.js +0 -34
- package/dist-web/assets/wardley-L42UT6IY-BJFn8eDD.js +0 -173
- package/dist-web/assets/wardley-L42UT6IY-BSu8-4hg.js +0 -173
- package/dist-web/assets/xychartDiagram-2RQKCTM6-C2iZpl9I.js +0 -7
- package/dist-web/assets/xychartDiagram-2RQKCTM6-Db_VoDBV.js +0 -7
- package/mnemo/access_routes.js +0 -692
- package/mnemo/agent_governance.js +0 -4242
- package/mnemo/agent_mail.js +0 -901
- package/mnemo/bootstrap_auto.js +0 -137
- package/mnemo/brief_coordination.js +0 -226
- package/mnemo/code_read_tools.js +0 -375
- package/mnemo/context_preview_tools.js +0 -603
- package/mnemo/embeddings.js +0 -66
- package/mnemo/external_repo_ops.js +0 -575
- package/mnemo/facts/example-project-rules.json +0 -90
- package/mnemo/facts/example.json +0 -34
- package/mnemo/identity_schema.sql +0 -139
- package/mnemo/journal_schema.js +0 -561
- package/mnemo/loop_doctor_tools.js +0 -661
- package/mnemo/mail_secret_refs.js +0 -150
- package/mnemo/mcp.js +0 -9309
- package/mnemo/memory_consolidation.js +0 -1914
- package/mnemo/memory_health_tools.js +0 -165
- package/mnemo/package.json +0 -79
- package/mnemo/protected_scope_gate.js +0 -627
- package/mnemo/resource_access_control.js +0 -684
- package/mnemo/runtime_governance.js +0 -1256
- package/mnemo/runtime_turn_gate.js +0 -862
- package/mnemo/sandbox.js +0 -143
- package/mnemo/schema.sql +0 -389
- package/mnemo/shared_utils.js +0 -763
- package/mnemo/skills/agent-auto-resume/SKILL.md +0 -56
- package/mnemo/skills/agent_hand/SKILL.md +0 -43
- package/mnemo/skills/agent_hand/run.js +0 -63
- package/mnemo/skills/book_flight/SKILL.md +0 -34
- package/mnemo/skills/external_repo_review/SKILL.md +0 -43
- package/mnemo/skills/external_repo_review/run.js +0 -73
- package/mnemo/skills/pay_invoice/SKILL.md +0 -34
- package/mnemo/team_quality_ops.js +0 -944
- package/mnemo/timeline_report_tools.js +0 -810
- package/mnemo/write_gate_risk.js +0 -80
- package/mnemo/writer_health.js +0 -152
- package/skills/doku-ingestion/SKILL.md +0 -48
- package/skills/doku-ingestion/ingest_docs.py +0 -133
package/bin/king.js
CHANGED
|
@@ -1,4 +1,280 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// This public entry must stay self-contained. Package-local modules are loaded
|
|
5
|
+
// only after the update owner proves that the package root is not being replaced.
|
|
6
|
+
const { createHash } = require('node:crypto');
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const net = require('node:net');
|
|
9
|
+
const os = require('node:os');
|
|
10
|
+
const path = require('node:path');
|
|
11
|
+
|
|
12
|
+
const LEASE_PROTOCOL_VERSION = 'BLUN_UPDATE_LEASE_V3';
|
|
13
|
+
const LEASE_PROBE_TIMEOUT_MS = 500;
|
|
14
|
+
const MAX_POSIX_SOCKET_PATH_BYTES = 96;
|
|
15
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
16
|
+
|
|
17
|
+
function deriveLeaseEndpoint(role) {
|
|
18
|
+
const realpath = fs.realpathSync.native || fs.realpathSync;
|
|
19
|
+
let identity = realpath(PACKAGE_ROOT);
|
|
20
|
+
if (!fs.statSync(identity).isDirectory()) throw new Error('INVALID_PACKAGE_ROOT');
|
|
21
|
+
identity = identity.replaceAll('\\', '/');
|
|
22
|
+
if (process.platform === 'win32') identity = identity.toLowerCase();
|
|
23
|
+
const digest = createHash('sha256')
|
|
24
|
+
.update(`blun-update-v3\0${role}\0${identity}`)
|
|
25
|
+
.digest('hex');
|
|
26
|
+
const magic = `${LEASE_PROTOCOL_VERSION} ${digest}\n`;
|
|
27
|
+
if (process.platform === 'win32') {
|
|
28
|
+
return {
|
|
29
|
+
magic,
|
|
30
|
+
path: `\\\\.\\pipe\\blun-update-v3-${digest.slice(0, 32)}`,
|
|
31
|
+
platform: 'win32',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const uid = typeof process.getuid === 'function' ? process.getuid() : undefined;
|
|
36
|
+
const directoryName = `blun-update-${uid ?? digest.slice(0, 12)}`;
|
|
37
|
+
let directory = path.posix.join(os.tmpdir().replaceAll('\\', '/'), directoryName);
|
|
38
|
+
let socketPath = path.posix.join(directory, `lease-${digest.slice(0, 24)}.sock`);
|
|
39
|
+
if (Buffer.byteLength(socketPath, 'utf8') > MAX_POSIX_SOCKET_PATH_BYTES) {
|
|
40
|
+
directory = path.posix.join('/tmp', directoryName);
|
|
41
|
+
socketPath = path.posix.join(directory, `lease-${digest.slice(0, 24)}.sock`);
|
|
42
|
+
}
|
|
43
|
+
if (Buffer.byteLength(socketPath, 'utf8') > MAX_POSIX_SOCKET_PATH_BYTES) {
|
|
44
|
+
throw new Error('UPDATE_LEASE_SOCKET_PATH_TOO_LONG');
|
|
45
|
+
}
|
|
46
|
+
return { directory, magic, path: socketPath, platform: process.platform };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function ensurePrivateSocketDirectory(endpoint) {
|
|
50
|
+
if (endpoint.platform === 'win32') return;
|
|
51
|
+
fs.mkdirSync(endpoint.directory, { recursive: true, mode: 0o700 });
|
|
52
|
+
const stat = fs.lstatSync(endpoint.directory);
|
|
53
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
54
|
+
throw new Error('INVALID_UPDATE_LEASE_DIRECTORY');
|
|
55
|
+
}
|
|
56
|
+
if (typeof process.getuid === 'function'
|
|
57
|
+
&& Number.isInteger(stat.uid)
|
|
58
|
+
&& stat.uid !== process.getuid()) {
|
|
59
|
+
throw new Error('INVALID_UPDATE_LEASE_DIRECTORY_OWNER');
|
|
60
|
+
}
|
|
61
|
+
fs.chmodSync(endpoint.directory, 0o700);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function closeServer(server) {
|
|
65
|
+
return new Promise((resolve) => {
|
|
66
|
+
if (!server.listening) {
|
|
67
|
+
resolve();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
server.close(() => resolve());
|
|
72
|
+
} catch {
|
|
73
|
+
resolve();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function listenForLease(endpoint) {
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const server = net.createServer((socket) => {
|
|
81
|
+
socket.on('error', () => {});
|
|
82
|
+
socket.end(endpoint.magic);
|
|
83
|
+
});
|
|
84
|
+
const onError = (error) => {
|
|
85
|
+
server.removeListener('error', onError);
|
|
86
|
+
reject(error);
|
|
87
|
+
};
|
|
88
|
+
server.once('error', onError);
|
|
89
|
+
server.listen({ path: endpoint.path, exclusive: true }, () => {
|
|
90
|
+
server.removeListener('error', onError);
|
|
91
|
+
resolve(server);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function probeLease(endpoint) {
|
|
97
|
+
return new Promise((resolve) => {
|
|
98
|
+
let received = '';
|
|
99
|
+
let settled = false;
|
|
100
|
+
let socket;
|
|
101
|
+
const finish = (state) => {
|
|
102
|
+
if (settled) return;
|
|
103
|
+
settled = true;
|
|
104
|
+
clearTimeout(timer);
|
|
105
|
+
try {
|
|
106
|
+
socket?.destroy();
|
|
107
|
+
} catch {}
|
|
108
|
+
// oxlint-disable-next-line promise/no-multiple-resolved -- settled is the idempotence guard.
|
|
109
|
+
resolve(state);
|
|
110
|
+
};
|
|
111
|
+
const timer = setTimeout(() => finish('foreign'), LEASE_PROBE_TIMEOUT_MS);
|
|
112
|
+
timer.unref?.();
|
|
113
|
+
try {
|
|
114
|
+
socket = net.createConnection({ path: endpoint.path });
|
|
115
|
+
socket.setEncoding('utf8');
|
|
116
|
+
socket.on('data', (chunk) => {
|
|
117
|
+
received += String(chunk);
|
|
118
|
+
if (Buffer.byteLength(received, 'utf8') > Buffer.byteLength(endpoint.magic, 'utf8')) {
|
|
119
|
+
finish('foreign');
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
socket.once('end', () => finish(received === endpoint.magic ? 'owner' : 'foreign'));
|
|
123
|
+
socket.once('error', (error) => {
|
|
124
|
+
finish(error?.code === 'ECONNREFUSED' || error?.code === 'ENOENT'
|
|
125
|
+
? 'stale'
|
|
126
|
+
: 'foreign');
|
|
127
|
+
});
|
|
128
|
+
socket.once('close', () => {
|
|
129
|
+
if (!settled) finish(received === endpoint.magic ? 'owner' : 'foreign');
|
|
130
|
+
});
|
|
131
|
+
} catch (error) {
|
|
132
|
+
finish(error?.code === 'ECONNREFUSED' || error?.code === 'ENOENT'
|
|
133
|
+
? 'stale'
|
|
134
|
+
: 'foreign');
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function observeSocket(endpoint) {
|
|
140
|
+
if (endpoint.platform === 'win32') return { state: 'not_applicable' };
|
|
141
|
+
try {
|
|
142
|
+
const stat = fs.lstatSync(endpoint.path);
|
|
143
|
+
if (!stat.isSocket() || stat.isSymbolicLink()) return { state: 'unsafe' };
|
|
144
|
+
return { dev: stat.dev, ino: stat.ino, state: 'socket' };
|
|
145
|
+
} catch (error) {
|
|
146
|
+
return error?.code === 'ENOENT' ? { state: 'missing' } : { state: 'unsafe' };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function removeObservedSocket(endpoint, observed) {
|
|
151
|
+
if (endpoint.platform === 'win32') return false;
|
|
152
|
+
try {
|
|
153
|
+
const stat = fs.lstatSync(endpoint.path);
|
|
154
|
+
if (observed.state !== 'socket'
|
|
155
|
+
|| !stat.isSocket()
|
|
156
|
+
|| stat.isSymbolicLink()
|
|
157
|
+
|| stat.dev !== observed.dev
|
|
158
|
+
|| stat.ino !== observed.ino) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
fs.unlinkSync(endpoint.path);
|
|
162
|
+
return true;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
return error?.code === 'ENOENT' && observed.state === 'missing';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function recordSocket(endpoint) {
|
|
169
|
+
if (endpoint.platform === 'win32') return undefined;
|
|
170
|
+
const stat = fs.lstatSync(endpoint.path);
|
|
171
|
+
if (!stat.isSocket() || stat.isSymbolicLink()) throw new Error('INVALID_UPDATE_LEASE_SOCKET');
|
|
172
|
+
fs.chmodSync(endpoint.path, 0o600);
|
|
173
|
+
return { dev: stat.dev, ino: stat.ino };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function removeOwnedSocket(endpoint, identity) {
|
|
177
|
+
if (endpoint.platform === 'win32' || !identity) return;
|
|
178
|
+
try {
|
|
179
|
+
const stat = fs.lstatSync(endpoint.path);
|
|
180
|
+
if (stat.isSocket()
|
|
181
|
+
&& !stat.isSymbolicLink()
|
|
182
|
+
&& stat.dev === identity.dev
|
|
183
|
+
&& stat.ino === identity.ino) {
|
|
184
|
+
fs.unlinkSync(endpoint.path);
|
|
185
|
+
}
|
|
186
|
+
} catch {}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function acquireNoticeLease() {
|
|
190
|
+
let endpoint;
|
|
191
|
+
try {
|
|
192
|
+
endpoint = deriveLeaseEndpoint('notice');
|
|
193
|
+
ensurePrivateSocketDirectory(endpoint);
|
|
194
|
+
} catch {
|
|
195
|
+
return { acquired: false, reason: 'unavailable' };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
let server;
|
|
199
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
200
|
+
try {
|
|
201
|
+
server = await listenForLease(endpoint);
|
|
202
|
+
break;
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (error?.code !== 'EADDRINUSE') return { acquired: false, reason: 'unavailable' };
|
|
205
|
+
const observed = observeSocket(endpoint);
|
|
206
|
+
const state = await probeLease(endpoint);
|
|
207
|
+
if (state === 'owner') return { acquired: false, reason: 'busy' };
|
|
208
|
+
if (state !== 'stale' || attempt > 0) return { acquired: false, reason: 'unavailable' };
|
|
209
|
+
if (endpoint.platform === 'win32') continue;
|
|
210
|
+
if (!removeObservedSocket(endpoint, observed)) {
|
|
211
|
+
return { acquired: false, reason: 'unavailable' };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (!server) return { acquired: false, reason: 'unavailable' };
|
|
216
|
+
|
|
217
|
+
let identity;
|
|
218
|
+
try {
|
|
219
|
+
identity = recordSocket(endpoint);
|
|
220
|
+
} catch {
|
|
221
|
+
await closeServer(server);
|
|
222
|
+
return { acquired: false, reason: 'unavailable' };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
let owned = true;
|
|
226
|
+
let released = false;
|
|
227
|
+
server.on('error', () => { owned = false; });
|
|
228
|
+
server.on('close', () => { owned = false; });
|
|
229
|
+
return {
|
|
230
|
+
acquired: true,
|
|
231
|
+
lease: Object.freeze({
|
|
232
|
+
assertOwned() {
|
|
233
|
+
if (!owned || !server.listening) throw new Error('UPDATE_LEASE_LOST');
|
|
234
|
+
},
|
|
235
|
+
async release() {
|
|
236
|
+
if (released) return;
|
|
237
|
+
released = true;
|
|
238
|
+
owned = false;
|
|
239
|
+
await closeServer(server);
|
|
240
|
+
removeOwnedSocket(endpoint, identity);
|
|
241
|
+
},
|
|
242
|
+
}),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
async function installLeaseIsClear() {
|
|
247
|
+
try {
|
|
248
|
+
const endpoint = deriveLeaseEndpoint('install');
|
|
249
|
+
ensurePrivateSocketDirectory(endpoint);
|
|
250
|
+
return await probeLease(endpoint) === 'stale';
|
|
251
|
+
} catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function main() {
|
|
257
|
+
const result = await acquireNoticeLease();
|
|
258
|
+
if (!result.acquired) return;
|
|
259
|
+
try {
|
|
260
|
+
if (!await installLeaseIsClear()) return;
|
|
261
|
+
result.lease.assertOwned();
|
|
262
|
+
const { runLauncher } = require('./launcher-runtime');
|
|
263
|
+
result.lease.assertOwned();
|
|
264
|
+
const filename = path.basename(__filename).toLowerCase();
|
|
265
|
+
await runLauncher({
|
|
266
|
+
mode: filename.startsWith('king') ? 'king' : 'blun',
|
|
267
|
+
noticeLease: result.lease,
|
|
268
|
+
});
|
|
269
|
+
} finally {
|
|
270
|
+
await result.lease.release();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// oxlint-disable-next-line unicorn/prefer-top-level-await -- Public npm bins are CommonJS.
|
|
275
|
+
void main().catch((error) => {
|
|
276
|
+
// oxlint-disable-next-line no-console -- Fatal launcher errors belong on stderr.
|
|
277
|
+
console.error('BLUN Start fehlgeschlagen: '
|
|
278
|
+
+ (error && error.message ? error.message : String(error)));
|
|
279
|
+
process.exitCode = 1;
|
|
280
|
+
});
|
package/bin/launcher-mode.js
CHANGED
|
@@ -5,7 +5,14 @@ const LAUNCHER_MODES = Object.freeze({
|
|
|
5
5
|
KING: 'king',
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const LAUNCHER_HELP_TEXT = [
|
|
9
|
+
'',
|
|
10
|
+
'Launchers:',
|
|
11
|
+
' blun Starts the CLI without automatically attaching Telegram.',
|
|
12
|
+
' king Starts the same CLI and automatically attaches the configured Telegram channel.',
|
|
13
|
+
' Both use the same version, account, model, and commands.',
|
|
14
|
+
'',
|
|
15
|
+
].join('\n');
|
|
9
16
|
|
|
10
17
|
function launcherModeFromArgv(argv) {
|
|
11
18
|
const entry = argv[1] || '';
|
|
@@ -14,10 +21,11 @@ function launcherModeFromArgv(argv) {
|
|
|
14
21
|
return command === LAUNCHER_MODES.KING ? LAUNCHER_MODES.KING : LAUNCHER_MODES.BLUN;
|
|
15
22
|
}
|
|
16
23
|
|
|
17
|
-
function createLauncherEnvironment(sourceEnv, mode) {
|
|
24
|
+
function createLauncherEnvironment(sourceEnv, mode, publicPackageVersion) {
|
|
18
25
|
return {
|
|
19
26
|
...sourceEnv,
|
|
20
27
|
BLUN_NO_AUTO_UPDATE: '1',
|
|
28
|
+
BLUN_PUBLIC_PACKAGE_VERSION: publicPackageVersion,
|
|
21
29
|
BLUN_TELEGRAM_ATTACH: mode === LAUNCHER_MODES.KING ? 'on' : 'off',
|
|
22
30
|
BLUN_TELEGRAM_HEADLESS: 'off',
|
|
23
31
|
};
|
|
@@ -29,10 +37,14 @@ function isNpmPackageUpdateRequest(args) {
|
|
|
29
37
|
return command === 'update' || command === 'upgrade';
|
|
30
38
|
}
|
|
31
39
|
|
|
40
|
+
function launcherHelpText() {
|
|
41
|
+
return LAUNCHER_HELP_TEXT;
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
module.exports = {
|
|
33
45
|
LAUNCHER_MODES,
|
|
34
|
-
NPM_PACKAGE_UPDATE_COMMAND,
|
|
35
46
|
createLauncherEnvironment,
|
|
36
47
|
isNpmPackageUpdateRequest,
|
|
48
|
+
launcherHelpText,
|
|
37
49
|
launcherModeFromArgv,
|
|
38
50
|
};
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* BLUN CLI Launcher (npm) — Erststart richtet alles ein:
|
|
4
|
+
* 1. King richtet das Telegram-Plugin im BLUN_HOME ein
|
|
5
|
+
* Danach: TUI starten. Anmeldung und Modellkatalog kommen ueber BLUN OAuth.
|
|
6
|
+
*/
|
|
7
|
+
const fs = require('node:fs');
|
|
8
|
+
const path = require('node:path');
|
|
9
|
+
const os = require('node:os');
|
|
10
|
+
const { spawn } = require('node:child_process');
|
|
11
|
+
const {
|
|
12
|
+
LAUNCHER_MODES,
|
|
13
|
+
createLauncherEnvironment,
|
|
14
|
+
isNpmPackageUpdateRequest,
|
|
15
|
+
launcherHelpText,
|
|
16
|
+
launcherModeFromArgv,
|
|
17
|
+
} = require('./launcher-mode');
|
|
18
|
+
const { installManagedTelegramPlugin } = require('./plugin-bootstrap');
|
|
19
|
+
const { CORE_LOADED_MESSAGE } = require('./core-bootstrap');
|
|
20
|
+
const { tryAcquireUpdateLease } = require('./update-lease');
|
|
21
|
+
const { runExplicitUpdate, runUpdateNotice } = require('./update-notice');
|
|
22
|
+
const {
|
|
23
|
+
ensurePrivateDirectory,
|
|
24
|
+
securePrivateFile,
|
|
25
|
+
securePrivateTree,
|
|
26
|
+
writePrivateFile,
|
|
27
|
+
} = require('./private-paths');
|
|
28
|
+
|
|
29
|
+
const PKG = path.resolve(__dirname, '..');
|
|
30
|
+
const ARGS = process.argv.slice(2);
|
|
31
|
+
const CORE_LOAD_TIMEOUT_MS = 30_000;
|
|
32
|
+
|
|
33
|
+
function normalizeWindowsPath(value) {
|
|
34
|
+
return path.win32.normalize(value).replace(/\\+$/u, '').toLowerCase();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function resolveLauncherPrivatePaths(options = {}) {
|
|
38
|
+
const env = options.env || process.env;
|
|
39
|
+
const platform = options.platform || process.platform;
|
|
40
|
+
const configuredHome = String(env.BLUN_HOME || '').trim();
|
|
41
|
+
if (platform !== 'win32') {
|
|
42
|
+
const userHome = (options.homedir || os.homedir)();
|
|
43
|
+
return {
|
|
44
|
+
blunHome: configuredHome ? path.resolve(configuredHome) : path.join(userHome, '.blun'),
|
|
45
|
+
userHome,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const fsImpl = options.fsImpl || fs;
|
|
50
|
+
const userInfo = (options.userInfo || os.userInfo)();
|
|
51
|
+
const reportedHome = String(userInfo?.homedir || '').trim();
|
|
52
|
+
if (!path.win32.isAbsolute(reportedHome) || reportedHome.startsWith('\\\\')) {
|
|
53
|
+
throw new Error('Das lokale Windows-Benutzerprofil konnte nicht sicher bestimmt werden.');
|
|
54
|
+
}
|
|
55
|
+
const resolvedHome = path.win32.resolve(reportedHome);
|
|
56
|
+
const stat = fsImpl.lstatSync(resolvedHome);
|
|
57
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
58
|
+
throw new Error('Das lokale Windows-Benutzerprofil ist kein vertrauenswuerdiges Verzeichnis.');
|
|
59
|
+
}
|
|
60
|
+
const realpath = fsImpl.realpathSync.native || fsImpl.realpathSync;
|
|
61
|
+
const userHome = path.win32.normalize(realpath(resolvedHome));
|
|
62
|
+
const volumeRoot = path.win32.parse(userHome).root;
|
|
63
|
+
if (!/^[A-Za-z]:\\$/u.test(volumeRoot)
|
|
64
|
+
|| normalizeWindowsPath(userHome) !== normalizeWindowsPath(resolvedHome)) {
|
|
65
|
+
throw new Error('Das lokale Windows-Benutzerprofil ist kein kanonischer lokaler Pfad.');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const blunHome = path.win32.join(userHome, '.blun');
|
|
69
|
+
if (configuredHome
|
|
70
|
+
&& normalizeWindowsPath(path.win32.resolve(configuredHome)) !== normalizeWindowsPath(blunHome)) {
|
|
71
|
+
throw new Error(`BLUN_HOME muss unter Windows exakt im Windows-Benutzerprofil liegen: ${blunHome}`);
|
|
72
|
+
}
|
|
73
|
+
return { blunHome, userHome };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function readPackageVersion() {
|
|
77
|
+
const { version } = JSON.parse(fs.readFileSync(path.join(PKG, 'package.json'), 'utf8'));
|
|
78
|
+
if (typeof version !== 'string' || version.length === 0) {
|
|
79
|
+
throw new Error('Ungueltige Paketversion in package.json');
|
|
80
|
+
}
|
|
81
|
+
return version;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function spawnProtectedCore(args, env, cwd) {
|
|
85
|
+
const child = spawn(
|
|
86
|
+
process.execPath,
|
|
87
|
+
[path.join(PKG, 'bin', 'core-bootstrap.js'), ...args],
|
|
88
|
+
{
|
|
89
|
+
cwd,
|
|
90
|
+
detached: true,
|
|
91
|
+
env,
|
|
92
|
+
stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
|
|
93
|
+
windowsHide: true,
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
let loadedSettled = false;
|
|
97
|
+
let completedSettled = false;
|
|
98
|
+
let resolveLoaded;
|
|
99
|
+
let resolveCompleted;
|
|
100
|
+
const loadTimer = setTimeout(() => {
|
|
101
|
+
try {
|
|
102
|
+
child.kill();
|
|
103
|
+
} catch {}
|
|
104
|
+
}, CORE_LOAD_TIMEOUT_MS);
|
|
105
|
+
const loaded = new Promise((resolve) => { resolveLoaded = resolve; });
|
|
106
|
+
const completed = new Promise((resolve) => { resolveCompleted = resolve; });
|
|
107
|
+
const settleLoaded = (value) => {
|
|
108
|
+
if (loadedSettled) return;
|
|
109
|
+
loadedSettled = true;
|
|
110
|
+
clearTimeout(loadTimer);
|
|
111
|
+
resolveLoaded(value);
|
|
112
|
+
};
|
|
113
|
+
const settleCompleted = (result) => {
|
|
114
|
+
if (completedSettled) return;
|
|
115
|
+
completedSettled = true;
|
|
116
|
+
for (const [signal, handler] of signalHandlers) process.removeListener(signal, handler);
|
|
117
|
+
settleLoaded(false);
|
|
118
|
+
resolveCompleted(result);
|
|
119
|
+
};
|
|
120
|
+
const signalHandlers = new Map();
|
|
121
|
+
for (const signal of ['SIGHUP', 'SIGINT', 'SIGTERM']) {
|
|
122
|
+
const handler = () => {
|
|
123
|
+
try {
|
|
124
|
+
child.kill(signal);
|
|
125
|
+
} catch {}
|
|
126
|
+
};
|
|
127
|
+
signalHandlers.set(signal, handler);
|
|
128
|
+
process.once(signal, handler);
|
|
129
|
+
}
|
|
130
|
+
child.on('message', (message) => {
|
|
131
|
+
if (message?.type !== CORE_LOADED_MESSAGE) return;
|
|
132
|
+
settleLoaded(true);
|
|
133
|
+
try {
|
|
134
|
+
child.disconnect();
|
|
135
|
+
} catch {}
|
|
136
|
+
});
|
|
137
|
+
child.once('error', (error) => settleCompleted({ error }));
|
|
138
|
+
child.once('exit', (code, signal) => settleCompleted({ code, signal }));
|
|
139
|
+
return { child, completed, loaded };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function superviseProtectedCore(args, env, cwd, releaseNotice) {
|
|
143
|
+
const core = spawnProtectedCore(args, env, cwd);
|
|
144
|
+
const loaded = await core.loaded;
|
|
145
|
+
await releaseNotice();
|
|
146
|
+
const result = await core.completed;
|
|
147
|
+
if (result.error) throw result.error;
|
|
148
|
+
return exitCodeForChild(result, loaded);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function exitCodeForChild(result, loaded) {
|
|
152
|
+
if (!loaded && result.code === 75) return 0;
|
|
153
|
+
if (Number.isInteger(result.code)) return result.code;
|
|
154
|
+
if (result.signal === 'SIGINT') return 130;
|
|
155
|
+
if (result.signal === 'SIGTERM') return 143;
|
|
156
|
+
return 1;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function runLauncher(options = {}) {
|
|
160
|
+
const callerCwd = process.cwd();
|
|
161
|
+
const mode = options.mode || launcherModeFromArgv(process.argv);
|
|
162
|
+
const explicitUpdateRequest = isNpmPackageUpdateRequest(ARGS);
|
|
163
|
+
const noticeResult = options.noticeLease
|
|
164
|
+
? { acquired: true, lease: options.noticeLease }
|
|
165
|
+
: await tryAcquireUpdateLease({ packageRoot: PKG, role: 'notice' });
|
|
166
|
+
if (!noticeResult.acquired) {
|
|
167
|
+
if (explicitUpdateRequest) {
|
|
168
|
+
process.stderr.write('Das Update konnte nicht verifiziert werden.\n');
|
|
169
|
+
process.exitCode = 1;
|
|
170
|
+
}
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const noticeLease = noticeResult.lease;
|
|
174
|
+
let noticeReleased = false;
|
|
175
|
+
const releaseNotice = async () => {
|
|
176
|
+
if (noticeReleased) return;
|
|
177
|
+
noticeReleased = true;
|
|
178
|
+
await noticeLease.release();
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const installProbe = await tryAcquireUpdateLease({ packageRoot: PKG, role: 'install' });
|
|
183
|
+
if (!installProbe.acquired) {
|
|
184
|
+
if (explicitUpdateRequest) {
|
|
185
|
+
process.stderr.write('Das Update konnte nicht verifiziert werden.\n');
|
|
186
|
+
process.exitCode = 1;
|
|
187
|
+
}
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
await installProbe.lease.release();
|
|
191
|
+
|
|
192
|
+
if (ARGS.some((arg) => arg === '--version' || arg === '-V')) {
|
|
193
|
+
process.stdout.write(`${readPackageVersion()}\n`);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (explicitUpdateRequest) {
|
|
198
|
+
const privatePaths = resolveLauncherPrivatePaths();
|
|
199
|
+
const result = await runExplicitUpdate({
|
|
200
|
+
currentVersion: readPackageVersion(),
|
|
201
|
+
env: process.env,
|
|
202
|
+
stdin: process.stdin,
|
|
203
|
+
stdout: process.stdout,
|
|
204
|
+
stderr: process.stderr,
|
|
205
|
+
blunDir: privatePaths.blunHome,
|
|
206
|
+
packageRoot: PKG,
|
|
207
|
+
noticeLease,
|
|
208
|
+
request: ARGS[0],
|
|
209
|
+
});
|
|
210
|
+
if (result.kind === 'failed') process.exitCode = result.exitCode || 1;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (ARGS.some((arg) => arg === '--help' || arg === '-h')) {
|
|
215
|
+
process.stdout.write(launcherHelpText());
|
|
216
|
+
const env = createLauncherEnvironment(process.env, mode, readPackageVersion());
|
|
217
|
+
const informationalEnv = { ...process.env };
|
|
218
|
+
delete informationalEnv.BLUN_HOME;
|
|
219
|
+
env.BLUN_HOME = resolveLauncherPrivatePaths({ env: informationalEnv }).blunHome;
|
|
220
|
+
process.exitCode = await superviseProtectedCore(ARGS, env, callerCwd, releaseNotice);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const privatePaths = resolveLauncherPrivatePaths();
|
|
225
|
+
const blunDir = privatePaths.blunHome;
|
|
226
|
+
ensurePrivateDirectory(blunDir);
|
|
227
|
+
|
|
228
|
+
// --- 1. Oeffentlicher npm-Update-Dialog. -------------------------------
|
|
229
|
+
const updateResult = await runUpdateNotice({
|
|
230
|
+
currentVersion: readPackageVersion(),
|
|
231
|
+
argv: ARGS,
|
|
232
|
+
env: process.env,
|
|
233
|
+
stdin: process.stdin,
|
|
234
|
+
stdout: process.stdout,
|
|
235
|
+
stderr: process.stderr,
|
|
236
|
+
blunDir,
|
|
237
|
+
packageRoot: PKG,
|
|
238
|
+
noticeLease,
|
|
239
|
+
});
|
|
240
|
+
if (updateResult.kind === 'installed' || updateResult.kind === 'update_in_progress') return;
|
|
241
|
+
|
|
242
|
+
// --- 2. Bestehende Konfiguration absichern -------------------------------
|
|
243
|
+
// Ein frischer Start bleibt absichtlich ohne statischen Anbieter. /login
|
|
244
|
+
// provisioniert King ueber den BLUN-OAuth-Server.
|
|
245
|
+
const cfgFile = path.join(blunDir, 'config.toml');
|
|
246
|
+
if (fs.existsSync(cfgFile)) securePrivateFile(cfgFile);
|
|
247
|
+
|
|
248
|
+
// --- 3. Telegram-Plugin + Token-Vorlage (nur King) -----------------------
|
|
249
|
+
if (mode === LAUNCHER_MODES.KING) {
|
|
250
|
+
installManagedTelegramPlugin({ packageRoot: PKG, blunDir });
|
|
251
|
+
const channelsDir = path.join(blunDir, 'channels');
|
|
252
|
+
const channelDir = path.join(channelsDir, 'telegram');
|
|
253
|
+
ensurePrivateDirectory(channelsDir);
|
|
254
|
+
ensurePrivateDirectory(channelDir);
|
|
255
|
+
const envFile = path.join(channelDir, '.env');
|
|
256
|
+
if (!fs.existsSync(envFile)) {
|
|
257
|
+
writePrivateFile(envFile, 'BLUN_TELEGRAM_BOT_TOKEN=HIER_DEIN_BOT_TOKEN_EINFUEGEN\n');
|
|
258
|
+
} else {
|
|
259
|
+
securePrivateFile(envFile);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// --- 3b. Built-in-Skills installieren (fehlende ergaenzen, nie
|
|
264
|
+
// vorhandene ueberschreiben — User-Anpassungen bleiben) -----------
|
|
265
|
+
const skillsSrc = path.join(PKG, 'skills');
|
|
266
|
+
const skillsDst = path.join(blunDir, 'skills');
|
|
267
|
+
if (fs.existsSync(skillsSrc)) {
|
|
268
|
+
if (fs.existsSync(skillsDst)) securePrivateTree(skillsDst);
|
|
269
|
+
else ensurePrivateDirectory(skillsDst);
|
|
270
|
+
for (const entry of fs.readdirSync(skillsSrc)) {
|
|
271
|
+
const dst = path.join(skillsDst, entry);
|
|
272
|
+
if (!fs.existsSync(dst)) {
|
|
273
|
+
fs.cpSync(path.join(skillsSrc, entry), dst, { recursive: true });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// --- 4. Start -----------------------------------------------------------
|
|
279
|
+
const env = createLauncherEnvironment(process.env, mode, readPackageVersion());
|
|
280
|
+
env.BLUN_HOME = blunDir;
|
|
281
|
+
env.BLUN_MODEL_MAX_COMPLETION_TOKENS = env.BLUN_MODEL_MAX_COMPLETION_TOKENS || '32768';
|
|
282
|
+
process.exitCode = await superviseProtectedCore(
|
|
283
|
+
['--yolo', ...ARGS],
|
|
284
|
+
env,
|
|
285
|
+
callerCwd,
|
|
286
|
+
releaseNotice,
|
|
287
|
+
);
|
|
288
|
+
} finally {
|
|
289
|
+
await releaseNotice();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
module.exports = { resolveLauncherPrivatePaths, runLauncher };
|
package/bin/plugin-bootstrap.js
CHANGED
|
@@ -4,7 +4,11 @@ const { randomUUID } = require('node:crypto');
|
|
|
4
4
|
const fs = require('node:fs');
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const {
|
|
8
|
+
ensurePrivateDirectory,
|
|
9
|
+
securePrivateFile,
|
|
10
|
+
writePrivateFile,
|
|
11
|
+
} = require('./private-paths');
|
|
8
12
|
|
|
9
13
|
function isObject(value) {
|
|
10
14
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
@@ -81,10 +85,10 @@ function installManagedTelegramPlugin({ packageRoot, blunDir, now = new Date().t
|
|
|
81
85
|
const pluginRoot = path.join(managedDir, 'telegram');
|
|
82
86
|
const installedFile = path.join(pluginsDir, 'installed.json');
|
|
83
87
|
|
|
88
|
+
ensurePrivateDirectory(pluginsDir);
|
|
89
|
+
if (fs.existsSync(installedFile)) securePrivateFile(installedFile);
|
|
84
90
|
const installed = readInstalledPlugins(installedFile);
|
|
85
91
|
const updatedInstalled = updatedInstalledPlugins(installed, pluginRoot, now);
|
|
86
|
-
|
|
87
|
-
ensurePrivateDirectory(pluginsDir);
|
|
88
92
|
ensurePrivateDirectory(managedDir);
|
|
89
93
|
const nonce = `${process.pid}-${randomUUID()}`;
|
|
90
94
|
const stagingRoot = path.join(managedDir, `.telegram-${nonce}.tmp`);
|
|
@@ -92,8 +96,11 @@ function installManagedTelegramPlugin({ packageRoot, blunDir, now = new Date().t
|
|
|
92
96
|
let hadPreviousPlugin = false;
|
|
93
97
|
let installedNewPlugin = false;
|
|
94
98
|
try {
|
|
99
|
+
if (fs.existsSync(pluginRoot)) {
|
|
100
|
+
ensurePrivateDirectory(pluginRoot);
|
|
101
|
+
hadPreviousPlugin = true;
|
|
102
|
+
}
|
|
95
103
|
fs.cpSync(sourceRoot, stagingRoot, { recursive: true, force: true });
|
|
96
|
-
hadPreviousPlugin = fs.existsSync(pluginRoot);
|
|
97
104
|
if (hadPreviousPlugin) fs.renameSync(pluginRoot, backupRoot);
|
|
98
105
|
try {
|
|
99
106
|
fs.renameSync(stagingRoot, pluginRoot);
|