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.
Files changed (238) hide show
  1. package/LIESMICH.txt +32 -13
  2. package/README.md +39 -20
  3. package/bin/blun.js +248 -160
  4. package/bin/core-bootstrap.js +47 -0
  5. package/bin/king.js +277 -1
  6. package/bin/launcher-mode.js +15 -3
  7. package/bin/launcher-runtime.js +293 -0
  8. package/bin/plugin-bootstrap.js +11 -4
  9. package/bin/private-paths.js +1577 -10
  10. package/bin/update-lease.js +399 -0
  11. package/bin/update-notice.js +1245 -0
  12. package/blun.mjs +26606 -25239
  13. package/dist-web/assets/{CodeBlockNode-Bsvp6ZEy.js → CodeBlockNode-CXnTLMNr.js} +1 -1
  14. 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
  15. package/dist-web/assets/{DesignSystemView-BmDDe28A.js → DesignSystemView-BbMOu-XO.js} +1 -1
  16. package/dist-web/assets/{Tooltip-nEEfaYVY.js → Tooltip-CFQEzqC-.js} +1 -1
  17. package/dist-web/assets/abnfDiagram-N423BO3Z-CsByy-GW.js +1 -0
  18. package/dist-web/assets/abnfDiagram-N423BO3Z-Z1APZG5m.js +1 -0
  19. package/dist-web/assets/arc-C-LXCaja.js +1 -0
  20. package/dist-web/assets/arc-C4VyWloT.js +1 -0
  21. package/dist-web/assets/architectureDiagram-T3A2C74G-DZq4L18e.js +36 -0
  22. package/dist-web/assets/architectureDiagram-T3A2C74G-DpddbUcM.js +36 -0
  23. package/dist-web/assets/blockDiagram-VBNYF7ZC-BV4sIf98.js +132 -0
  24. package/dist-web/assets/blockDiagram-VBNYF7ZC-BqccOSMr.js +132 -0
  25. package/dist-web/assets/{c4Diagram-AAUBKEIU-DtzacMnD.js → c4Diagram-5PPSVZJV-0MRkZlgP.js} +1 -1
  26. package/dist-web/assets/{c4Diagram-AAUBKEIU-D1VdMx8d.js → c4Diagram-5PPSVZJV-OHAcJrTy.js} +1 -1
  27. package/dist-web/assets/channel-B2VOQOI-.js +1 -0
  28. package/dist-web/assets/channel-DKjwM05G.js +1 -0
  29. package/dist-web/assets/{chunk-ND2GUHAM-DJoY9wNJ.js → chunk-2GRJ4B5K-DqJHs8Fw.js} +1 -1
  30. package/dist-web/assets/{chunk-ND2GUHAM-C4-rwdcv.js → chunk-2GRJ4B5K-oO6nqeLA.js} +1 -1
  31. package/dist-web/assets/{chunk-QZHKN3VN-C7YGaShq.js → chunk-2Q5K7J3B-B1nCd91o.js} +1 -1
  32. package/dist-web/assets/{chunk-QZHKN3VN-_Rz9_NuS.js → chunk-2Q5K7J3B-BC0Hsfqy.js} +1 -1
  33. package/dist-web/assets/chunk-5RXB4S5H-BfZa4yDH.js +231 -0
  34. package/dist-web/assets/chunk-5RXB4S5H-neG70kZx.js +231 -0
  35. package/dist-web/assets/{chunk-FMBD7UC4-DlLNDUx6.js → chunk-5VM5RSS4-l7biGqeH.js} +1 -1
  36. package/dist-web/assets/{chunk-FMBD7UC4-B2zs_Y-d.js → chunk-5VM5RSS4-u00AcpiJ.js} +1 -1
  37. package/dist-web/assets/chunk-6Q2QTUOP-BO-F11Gs.js +88 -0
  38. package/dist-web/assets/chunk-6Q2QTUOP-RUVRPBzG.js +88 -0
  39. package/dist-web/assets/{chunk-727SXJPM-Dn5wkDO_.js → chunk-GF5L2VYU-Ba-86KTd.js} +5 -5
  40. package/dist-web/assets/{chunk-727SXJPM-Dk2Xa3bA.js → chunk-GF5L2VYU-BtC69fw0.js} +5 -5
  41. package/dist-web/assets/{chunk-4BX2VUAB-DxZViaHS.js → chunk-JWPE2WC7-DIOubEqr.js} +1 -1
  42. package/dist-web/assets/{chunk-4BX2VUAB-WqrE2gaw.js → chunk-JWPE2WC7-u8Pcfhwh.js} +1 -1
  43. package/dist-web/assets/{chunk-2J33WTMH-Dm_s0_4f.js → chunk-KBJHAD2P-DDUeH_Ba.js} +1 -1
  44. package/dist-web/assets/{chunk-2J33WTMH-w4sdiKFO.js → chunk-KBJHAD2P-DS3BL64y.js} +1 -1
  45. package/dist-web/assets/chunk-RYQCIY6F-B9gFMVbS.js +1 -0
  46. package/dist-web/assets/chunk-RYQCIY6F-xg3EO0le.js +1 -0
  47. package/dist-web/assets/{chunk-55IACEB6-B5dE1-Um.js → chunk-XXDRQBXY-B60H0rRC.js} +1 -1
  48. package/dist-web/assets/{chunk-55IACEB6-B12zGIFz.js → chunk-XXDRQBXY-Bn1Xz6TQ.js} +1 -1
  49. package/dist-web/assets/classDiagram-JCYQIIEL-BA1TjAxj.js +1 -0
  50. package/dist-web/assets/classDiagram-JCYQIIEL-BNU7Qn4k.js +1 -0
  51. package/dist-web/assets/classDiagram-v2-OCEON4UE-BA1TjAxj.js +1 -0
  52. package/dist-web/assets/classDiagram-v2-OCEON4UE-BNU7Qn4k.js +1 -0
  53. package/dist-web/assets/{cose-bilkent-S5V4N54A-Bi19n8m-.js → cose-bilkent-JH36ORCC-4Ybddg08.js} +1 -1
  54. package/dist-web/assets/{cose-bilkent-S5V4N54A-c8o8NFp5.js → cose-bilkent-JH36ORCC-DqigO3T4.js} +1 -1
  55. package/dist-web/assets/cynefin-VYW2F7L2-C-EfYT07.js +178 -0
  56. package/dist-web/assets/cynefin-VYW2F7L2-rpD93tQ-.js +178 -0
  57. package/dist-web/assets/cynefinDiagram-MW4NZA55-DWZPLJcD.js +62 -0
  58. package/dist-web/assets/cynefinDiagram-MW4NZA55-DbTqnkVJ.js +62 -0
  59. package/dist-web/assets/dagre-VZM6K2ZE-DcM8aEVY.js +4 -0
  60. package/dist-web/assets/dagre-VZM6K2ZE-M_HVNtqP.js +4 -0
  61. package/dist-web/assets/diagram-7IWD3JNH-DoNximNF.js +30 -0
  62. package/dist-web/assets/diagram-7IWD3JNH-UymgsBNa.js +30 -0
  63. package/dist-web/assets/{diagram-KO2AKTUF-CFQs13i5.js → diagram-B4RE2ZJO-BVA2EhnC.js} +3 -3
  64. package/dist-web/assets/{diagram-KO2AKTUF-agFIuPJW.js → diagram-B4RE2ZJO-BiYu5WPF.js} +3 -3
  65. package/dist-web/assets/{diagram-LMA3HP47-TMIXizxR.js → diagram-LBJQPF4R-BD3kkgOO.js} +2 -2
  66. package/dist-web/assets/{diagram-LMA3HP47-He5zlyMt.js → diagram-LBJQPF4R-m3a1Euj3.js} +2 -2
  67. package/dist-web/assets/diagram-Q27KOJAE-D1mYQ_cI.js +24 -0
  68. package/dist-web/assets/diagram-Q27KOJAE-hy_T73PK.js +24 -0
  69. package/dist-web/assets/diagram-UB23O5K3-BWkoQZ4A.js +41 -0
  70. package/dist-web/assets/diagram-UB23O5K3-BtX8u6HG.js +41 -0
  71. package/dist-web/assets/ebnfDiagram-BXEA7PRR-BKs9JUHW.js +1 -0
  72. package/dist-web/assets/ebnfDiagram-BXEA7PRR-CBAnFkRF.js +1 -0
  73. package/dist-web/assets/erDiagram-JOGREHBK-3vKcWsxm.js +85 -0
  74. package/dist-web/assets/erDiagram-JOGREHBK-BIpd6dTf.js +85 -0
  75. package/dist-web/assets/flowDiagram-UKHOOZJN-D9wBbHm2.js +156 -0
  76. package/dist-web/assets/flowDiagram-UKHOOZJN-Z83i2UWI.js +156 -0
  77. package/dist-web/assets/ganttDiagram-PKOTCBZU-Cd_dViF-.js +292 -0
  78. package/dist-web/assets/ganttDiagram-PKOTCBZU-DFrb_S1d.js +292 -0
  79. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-BSDFfwdY.js → gitGraphDiagram-DS77QQ5N-BiEEtTo7.js} +3 -3
  80. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-DMbTATyw.js → gitGraphDiagram-DS77QQ5N-Dp3Ar-hi.js} +3 -3
  81. package/dist-web/assets/{graph-BwjfAU3j.js → graph-CAUpWmoK.js} +1 -1
  82. package/dist-web/assets/{graph--OzhPTMs.js → graph-DOmOIIwC.js} +1 -1
  83. package/dist-web/assets/{index-W6VnSrkB.js → index-Ba1OvLjf.js} +2 -2
  84. package/dist-web/assets/{index-CkVgGDpx.js → index-CiPA8Kex.js} +4 -4
  85. package/dist-web/assets/{index-BzK4vJBu.js → index-DdEakFJM.js} +1 -1
  86. package/dist-web/assets/{index10-Czg_oF-W.js → index10-CNr4U-Nw.js} +1 -1
  87. package/dist-web/assets/{index11-BjzCZuCr.js → index11-Dto_yZNz.js} +1 -1
  88. package/dist-web/assets/{index5-DlVoNkCD.js → index5-B2PldaO2.js} +1 -1
  89. package/dist-web/assets/{index6-BxiXA2yo.js → index6-CBdZmmyx.js} +1 -1
  90. package/dist-web/assets/{index7-BPdza6d1.js → index7-Dz9oCsUF.js} +1 -1
  91. package/dist-web/assets/{index8-Q_XzGC1Z.js → index8-B6k25jtU.js} +2 -2
  92. package/dist-web/assets/{infoDiagram-5YYISTIA-2JF3XEdD.js → infoDiagram-6WML65LV-BSa2g04G.js} +1 -1
  93. package/dist-web/assets/{infoDiagram-5YYISTIA-UrQusrJq.js → infoDiagram-6WML65LV-D4ph2sIH.js} +1 -1
  94. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-7RVUL-vB.js → ishikawaDiagram-WSZJBQD7-DjKjbMm9.js} +5 -5
  95. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-C5OstRVV.js → ishikawaDiagram-WSZJBQD7-Hm36UOQe.js} +5 -5
  96. package/dist-web/assets/{journeyDiagram-JHISSGLW-B34fCMu9.js → journeyDiagram-NVQOT4AX-DttHDfPQ.js} +1 -1
  97. package/dist-web/assets/{journeyDiagram-JHISSGLW-yctdo4bX.js → journeyDiagram-NVQOT4AX-MvWWPNDV.js} +1 -1
  98. package/dist-web/assets/{kanban-definition-UN3LZRKU-BS4FBZsQ.js → kanban-definition-27J2QSJJ-C5gB-W0d.js} +7 -7
  99. package/dist-web/assets/{kanban-definition-UN3LZRKU-CxBCv27E.js → kanban-definition-27J2QSJJ-Cu-E_cXA.js} +5 -5
  100. package/dist-web/assets/layout-CvP6o9AK.js +1 -0
  101. package/dist-web/assets/layout-D-LzfAck.js +1 -0
  102. package/dist-web/assets/{linear-3mB6q2-g.js → linear-B3HWgQI2.js} +1 -1
  103. package/dist-web/assets/{linear-BKCnUo31.js → linear-BRGe4-d6.js} +1 -1
  104. package/dist-web/assets/map-CWKZqZjr.js +1 -0
  105. package/dist-web/assets/map-DxJ2ADlA.js +1 -0
  106. package/dist-web/assets/mermaid.core-D-9Sx1No.js +314 -0
  107. package/dist-web/assets/mermaidParser.worker-PTFfzpoB.js +318 -0
  108. package/dist-web/assets/{mindmap-definition-RKZ34NQL-BmJZpjh6.js → mindmap-definition-FAOFIHXS-C4vnms3i.js} +2 -2
  109. package/dist-web/assets/{mindmap-definition-RKZ34NQL-1mjWUcf6.js → mindmap-definition-FAOFIHXS-Cg_hoVIq.js} +1 -1
  110. package/dist-web/assets/pegDiagram-VL7TDLO6-B2fFEFUH.js +1 -0
  111. package/dist-web/assets/pegDiagram-VL7TDLO6-CSX9hitD.js +1 -0
  112. package/dist-web/assets/pieDiagram-7S7Q4E2Y-0L0mxahZ.js +39 -0
  113. package/dist-web/assets/pieDiagram-7S7Q4E2Y-C7T0Cmw1.js +39 -0
  114. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BmT_qM09.js → quadrantDiagram-CIZ2JOQS-BBy7w4kD.js} +3 -3
  115. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-C0kPuyNP.js → quadrantDiagram-CIZ2JOQS-U483z0er.js} +3 -3
  116. package/dist-web/assets/railroadDiagram-AXF67PYL-D80a2_DJ.js +1 -0
  117. package/dist-web/assets/railroadDiagram-AXF67PYL-DX8y0MzW.js +1 -0
  118. package/dist-web/assets/{requirementDiagram-4Y6WPE33-C0YP_Amt.js → requirementDiagram-LRYGKXZP-CeyHfq8t.js} +3 -3
  119. package/dist-web/assets/{requirementDiagram-4Y6WPE33-CZrxH1Y2.js → requirementDiagram-LRYGKXZP-DGD5J_4k.js} +3 -3
  120. package/dist-web/assets/sankeyDiagram-W5VNT64P-CCISkkrR.js +40 -0
  121. package/dist-web/assets/sankeyDiagram-W5VNT64P-CT5PdZz2.js +40 -0
  122. package/dist-web/assets/sequenceDiagram-SI44F4Z6-BeMzHWXI.js +162 -0
  123. package/dist-web/assets/sequenceDiagram-SI44F4Z6-jQfm2XS7.js +162 -0
  124. package/dist-web/assets/sizeCapture-X5ZJPWSS-BQsTdtrv.js +1 -0
  125. package/dist-web/assets/sizeCapture-X5ZJPWSS-lRZsmCoS.js +1 -0
  126. package/dist-web/assets/stateDiagram-OKZ733FA-ClCgTdUm.js +1 -0
  127. package/dist-web/assets/stateDiagram-OKZ733FA-Cv59z5YT.js +1 -0
  128. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-R8jTc--F.js +1 -0
  129. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fi_lrTAx.js +1 -0
  130. package/dist-web/assets/swimlanes-SLNWSIFB-BCdOUN05.js +2 -0
  131. package/dist-web/assets/swimlanes-SLNWSIFB-Cu5l7SuR.js +1 -0
  132. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-BUd_uYK3.js +8 -0
  133. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-CalrsgPK.js +8 -0
  134. package/dist-web/assets/{timeline-definition-PNZ67QCA-DsVZdrZa.js → timeline-definition-Z64GVDOM-CMjnh4bu.js} +4 -4
  135. package/dist-web/assets/{timeline-definition-PNZ67QCA-DnB6Usl0.js → timeline-definition-Z64GVDOM-DpWutSKa.js} +4 -4
  136. package/dist-web/assets/vennDiagram-T6HMQDX7-DKJW_8oU.js +34 -0
  137. package/dist-web/assets/vennDiagram-T6HMQDX7-DVC5JVsc.js +34 -0
  138. package/dist-web/assets/{vue.runtime.esm-bundler-pgHGheCW.js → vue.runtime.esm-bundler-BwwRtQwQ.js} +1 -1
  139. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-oBauTCEw.js → wardleyDiagram-T6FBY63Y-BK2mrq7L.js} +3 -3
  140. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-DCiyDQNB.js → wardleyDiagram-T6FBY63Y-oUvgepFn.js} +3 -3
  141. package/dist-web/assets/xychartDiagram-ELKLHX3M-DI6n79q0.js +7 -0
  142. package/dist-web/assets/xychartDiagram-ELKLHX3M-DUJu9F7-.js +7 -0
  143. package/dist-web/index.html +1 -1
  144. package/dist-web/vis/index.html.gz +0 -0
  145. package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  146. package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  147. package/package.json +9 -11
  148. package/skills/screenshot-lesen/SKILL.md +0 -1
  149. package/skills/web-lesen/SKILL.md +0 -1
  150. package/telegram-plugin/dist/bridge.mjs +7 -25
  151. package/telegram-plugin/dist/mcp-server.mjs +236 -71
  152. package/dist-web/assets/arc-4xPfymbf.js +0 -1
  153. package/dist-web/assets/arc-Doj0wRZ0.js +0 -1
  154. package/dist-web/assets/architectureDiagram-3BPJPVTR-BGih283a.js +0 -36
  155. package/dist-web/assets/architectureDiagram-3BPJPVTR-CQ09RrbH.js +0 -36
  156. package/dist-web/assets/blockDiagram-GPEHLZMM-3ShMf1gu.js +0 -132
  157. package/dist-web/assets/blockDiagram-GPEHLZMM-CAtDjkJt.js +0 -132
  158. package/dist-web/assets/channel-DNkUo9e6.js +0 -1
  159. package/dist-web/assets/channel-DcnUTIGB.js +0 -1
  160. package/dist-web/assets/chunk-AQP2D5EJ-FS8-f8lF.js +0 -231
  161. package/dist-web/assets/chunk-AQP2D5EJ-UKhb4V4r.js +0 -231
  162. package/dist-web/assets/classDiagram-4FO5ZUOK-B1ZO8EbE.js +0 -1
  163. package/dist-web/assets/classDiagram-4FO5ZUOK-xk6cM9Kq.js +0 -1
  164. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-B1ZO8EbE.js +0 -1
  165. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-xk6cM9Kq.js +0 -1
  166. package/dist-web/assets/dagre-BM42HDAG-CmUO9qKN.js +0 -4
  167. package/dist-web/assets/dagre-BM42HDAG-DLMfLCoV.js +0 -4
  168. package/dist-web/assets/diagram-2AECGRRQ-DQTst0OH.js +0 -43
  169. package/dist-web/assets/diagram-2AECGRRQ-L74iLMqd.js +0 -43
  170. package/dist-web/assets/diagram-5GNKFQAL-BiBm7CJR.js +0 -10
  171. package/dist-web/assets/diagram-5GNKFQAL-DoE6q7H1.js +0 -10
  172. package/dist-web/assets/diagram-OG6HWLK6-BHCt1E0n.js +0 -24
  173. package/dist-web/assets/diagram-OG6HWLK6-DRyxjFMa.js +0 -24
  174. package/dist-web/assets/erDiagram-TEJ5UH35-BoDczjGG.js +0 -85
  175. package/dist-web/assets/erDiagram-TEJ5UH35-yd6SOv_7.js +0 -85
  176. package/dist-web/assets/flowDiagram-I6XJVG4X-DHoceI7r.js +0 -162
  177. package/dist-web/assets/flowDiagram-I6XJVG4X-DkYNQv0R.js +0 -162
  178. package/dist-web/assets/ganttDiagram-6RSMTGT7-Cg1TQBc0.js +0 -292
  179. package/dist-web/assets/ganttDiagram-6RSMTGT7-Z6klo7KK.js +0 -292
  180. package/dist-web/assets/layout-C1ojF0zw.js +0 -1
  181. package/dist-web/assets/layout-SsrduOYp.js +0 -1
  182. package/dist-web/assets/mermaid.core-D_lKT0dR.js +0 -309
  183. package/dist-web/assets/mermaidParser.worker-Dx4jPi9z.js +0 -313
  184. package/dist-web/assets/pieDiagram-4H26LBE5-BU41t2A_.js +0 -30
  185. package/dist-web/assets/pieDiagram-4H26LBE5-BkwDAvbt.js +0 -30
  186. package/dist-web/assets/sankeyDiagram-5OEKKPKP-De_o7hDr.js +0 -40
  187. package/dist-web/assets/sankeyDiagram-5OEKKPKP-Dvuj6bMA.js +0 -40
  188. package/dist-web/assets/sequenceDiagram-3UESZ5HK-DuCrgPyA.js +0 -162
  189. package/dist-web/assets/sequenceDiagram-3UESZ5HK-VAxffBe7.js +0 -162
  190. package/dist-web/assets/stateDiagram-AJRCARHV-CYLupxM7.js +0 -1
  191. package/dist-web/assets/stateDiagram-AJRCARHV-nDExQydZ.js +0 -1
  192. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BhEc7Thx.js +0 -1
  193. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BzwD_BIl.js +0 -1
  194. package/dist-web/assets/vennDiagram-CIIHVFJN-BBHQmCFf.js +0 -34
  195. package/dist-web/assets/vennDiagram-CIIHVFJN-Cfj-K9NW.js +0 -34
  196. package/dist-web/assets/wardley-L42UT6IY-BJFn8eDD.js +0 -173
  197. package/dist-web/assets/wardley-L42UT6IY-BSu8-4hg.js +0 -173
  198. package/dist-web/assets/xychartDiagram-2RQKCTM6-C2iZpl9I.js +0 -7
  199. package/dist-web/assets/xychartDiagram-2RQKCTM6-Db_VoDBV.js +0 -7
  200. package/mnemo/access_routes.js +0 -692
  201. package/mnemo/agent_governance.js +0 -4242
  202. package/mnemo/agent_mail.js +0 -901
  203. package/mnemo/bootstrap_auto.js +0 -137
  204. package/mnemo/brief_coordination.js +0 -226
  205. package/mnemo/code_read_tools.js +0 -375
  206. package/mnemo/context_preview_tools.js +0 -603
  207. package/mnemo/embeddings.js +0 -66
  208. package/mnemo/external_repo_ops.js +0 -575
  209. package/mnemo/facts/example-project-rules.json +0 -90
  210. package/mnemo/facts/example.json +0 -34
  211. package/mnemo/identity_schema.sql +0 -139
  212. package/mnemo/journal_schema.js +0 -561
  213. package/mnemo/loop_doctor_tools.js +0 -661
  214. package/mnemo/mail_secret_refs.js +0 -150
  215. package/mnemo/mcp.js +0 -9309
  216. package/mnemo/memory_consolidation.js +0 -1914
  217. package/mnemo/memory_health_tools.js +0 -165
  218. package/mnemo/package.json +0 -79
  219. package/mnemo/protected_scope_gate.js +0 -627
  220. package/mnemo/resource_access_control.js +0 -684
  221. package/mnemo/runtime_governance.js +0 -1256
  222. package/mnemo/runtime_turn_gate.js +0 -862
  223. package/mnemo/sandbox.js +0 -143
  224. package/mnemo/schema.sql +0 -389
  225. package/mnemo/shared_utils.js +0 -763
  226. package/mnemo/skills/agent-auto-resume/SKILL.md +0 -56
  227. package/mnemo/skills/agent_hand/SKILL.md +0 -43
  228. package/mnemo/skills/agent_hand/run.js +0 -63
  229. package/mnemo/skills/book_flight/SKILL.md +0 -34
  230. package/mnemo/skills/external_repo_review/SKILL.md +0 -43
  231. package/mnemo/skills/external_repo_review/run.js +0 -73
  232. package/mnemo/skills/pay_invoice/SKILL.md +0 -34
  233. package/mnemo/team_quality_ops.js +0 -944
  234. package/mnemo/timeline_report_tools.js +0 -810
  235. package/mnemo/write_gate_risk.js +0 -80
  236. package/mnemo/writer_health.js +0 -152
  237. package/skills/doku-ingestion/SKILL.md +0 -48
  238. package/skills/doku-ingestion/ingest_docs.py +0 -133
@@ -0,0 +1,1245 @@
1
+ 'use strict';
2
+
3
+ const { randomUUID } = require('node:crypto');
4
+ const fs = require('node:fs');
5
+ const https = require('node:https');
6
+ const path = require('node:path');
7
+ const { fork } = require('node:child_process');
8
+ const { StringDecoder } = require('node:string_decoder');
9
+ const { types } = require('node:util');
10
+
11
+ const { tryAcquireUpdateLease } = require('./update-lease');
12
+
13
+ const {
14
+ ensurePrivateDirectory,
15
+ securePrivateFile,
16
+ writePrivateFile,
17
+ } = require('./private-paths');
18
+
19
+ const PACKAGE_NAME = 'blun-king-cli';
20
+ const REGISTRY_URL = 'https://registry.npmjs.org/blun-king-cli';
21
+ const INSTALL_REGISTRY_URL = 'https://registry.npmjs.org/';
22
+ const FALLBACK_MANIFEST_URL = 'https://chat.blun.ai/blun-code-version.json';
23
+ const SNOOZE_MS = 7 * 24 * 60 * 60 * 1000;
24
+ const REQUEST_TIMEOUT_MS = 2_500;
25
+ const STATE_FILE = 'update-notice.json';
26
+ const UPDATE_DIRECTORY = 'updates';
27
+ const UPDATE_KEY_ESCAPE_TIMEOUT_MS = 500;
28
+ const UPDATE_SIGNAL_EXIT_CODES = Object.freeze({
29
+ SIGHUP: 129,
30
+ SIGINT: 130,
31
+ SIGTERM: 143,
32
+ });
33
+ const SEMVER_IDENTIFIER = '(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)';
34
+ const SEMVER_PATTERN = new RegExp(
35
+ `^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)`
36
+ + `(?:-(${SEMVER_IDENTIFIER}(?:\\.${SEMVER_IDENTIFIER})*))?`
37
+ + '(?:\\+([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?$',
38
+ );
39
+ const MANIFEST_KEYS = Object.freeze([
40
+ 'install',
41
+ 'latest',
42
+ 'minSupported',
43
+ 'name',
44
+ 'notesUrl',
45
+ 'releasedAt',
46
+ ]);
47
+ const ENDPOINT_LIMITS = new Map([
48
+ [REGISTRY_URL, 1024 * 1024],
49
+ [FALLBACK_MANIFEST_URL, 64 * 1024],
50
+ ]);
51
+
52
+ function parseSemver(value) {
53
+ if (typeof value !== 'string' || value.length > 128) return undefined;
54
+ const match = SEMVER_PATTERN.exec(value);
55
+ if (!match) return undefined;
56
+ return {
57
+ raw: value,
58
+ core: [match[1], match[2], match[3]],
59
+ prerelease: match[4] === undefined ? undefined : match[4].split('.'),
60
+ };
61
+ }
62
+
63
+ function compareNumericIdentifier(left, right) {
64
+ if (left.length !== right.length) return left.length < right.length ? -1 : 1;
65
+ return left < right ? -1 : left > right ? 1 : 0;
66
+ }
67
+
68
+ function comparePrerelease(left, right) {
69
+ if (left === undefined && right === undefined) return 0;
70
+ if (left === undefined) return 1;
71
+ if (right === undefined) return -1;
72
+ const length = Math.max(left.length, right.length);
73
+ for (let index = 0; index < length; index += 1) {
74
+ if (left[index] === undefined) return -1;
75
+ if (right[index] === undefined) return 1;
76
+ const leftNumeric = /^\d+$/.test(left[index]);
77
+ const rightNumeric = /^\d+$/.test(right[index]);
78
+ if (leftNumeric && rightNumeric) {
79
+ const comparison = compareNumericIdentifier(left[index], right[index]);
80
+ if (comparison !== 0) return comparison;
81
+ } else if (leftNumeric !== rightNumeric) {
82
+ return leftNumeric ? -1 : 1;
83
+ } else if (left[index] !== right[index]) {
84
+ return left[index] < right[index] ? -1 : 1;
85
+ }
86
+ }
87
+ return 0;
88
+ }
89
+
90
+ function compareSemver(leftValue, rightValue) {
91
+ const left = parseSemver(leftValue);
92
+ const right = parseSemver(rightValue);
93
+ if (!left || !right) return undefined;
94
+ for (let index = 0; index < left.core.length; index += 1) {
95
+ const comparison = compareNumericIdentifier(left.core[index], right.core[index]);
96
+ if (comparison !== 0) return comparison;
97
+ }
98
+ return comparePrerelease(left.prerelease, right.prerelease);
99
+ }
100
+
101
+ function exactDataRecord(value, expectedKeys) {
102
+ if (typeof value !== 'object' || value === null || Array.isArray(value) || types.isProxy(value)) {
103
+ return undefined;
104
+ }
105
+ const prototype = Object.getPrototypeOf(value);
106
+ if (prototype !== Object.prototype && prototype !== null) return undefined;
107
+ const descriptors = Object.getOwnPropertyDescriptors(value);
108
+ const keys = Object.keys(descriptors).toSorted();
109
+ if (keys.length !== expectedKeys.length
110
+ || keys.some((key, index) => key !== expectedKeys[index])) {
111
+ return undefined;
112
+ }
113
+ for (const key of keys) {
114
+ if (!Object.hasOwn(descriptors[key], 'value') || descriptors[key].enumerable !== true) {
115
+ return undefined;
116
+ }
117
+ }
118
+ return Object.fromEntries(keys.map((key) => [key, descriptors[key].value]));
119
+ }
120
+
121
+ function readDataProperty(value, key) {
122
+ if (typeof value !== 'object' || value === null || Array.isArray(value) || types.isProxy(value)) {
123
+ return undefined;
124
+ }
125
+ const prototype = Object.getPrototypeOf(value);
126
+ if (prototype !== Object.prototype && prototype !== null) return undefined;
127
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
128
+ if (!descriptor || !Object.hasOwn(descriptor, 'value') || descriptor.enumerable !== true) {
129
+ return undefined;
130
+ }
131
+ return descriptor.value;
132
+ }
133
+
134
+ function parseRegistryDocument(value) {
135
+ const tags = readDataProperty(value, 'dist-tags');
136
+ const latest = readDataProperty(tags, 'latest');
137
+ if (!parseSemver(latest)) return undefined;
138
+ const parsed = { latest };
139
+ const next = readDataProperty(tags, 'next');
140
+ if (parseSemver(next)) parsed.next = next;
141
+ return Object.freeze(parsed);
142
+ }
143
+
144
+ function isBoundedText(value, maxBytes) {
145
+ return typeof value === 'string'
146
+ && value.length > 0
147
+ && Buffer.byteLength(value, 'utf8') <= maxBytes
148
+ && !/[\u0000-\u001F\u007F-\u009F\u061C\u200B-\u200F\u202A-\u202E\u2060-\u206F\uFEFF]/u.test(value);
149
+ }
150
+
151
+ function canonicalOfficialNotesUrl(value) {
152
+ if (!isBoundedText(value, 2_048)) return undefined;
153
+ try {
154
+ const url = new URL(value);
155
+ const officialHost = url.hostname === 'blun.ai' || url.hostname.endsWith('.blun.ai');
156
+ if (url.protocol !== 'https:'
157
+ || !officialHost
158
+ || url.username !== ''
159
+ || url.password !== ''
160
+ || url.port !== '') {
161
+ return undefined;
162
+ }
163
+ return url.href;
164
+ } catch {
165
+ return undefined;
166
+ }
167
+ }
168
+
169
+ function isIsoTimestamp(value) {
170
+ if (typeof value !== 'string') return false;
171
+ const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,3})?Z$/.exec(value);
172
+ if (!match) {
173
+ return false;
174
+ }
175
+ const timestamp = Date.parse(value);
176
+ if (!Number.isFinite(timestamp)) return false;
177
+ const date = new Date(timestamp);
178
+ return date.getUTCFullYear() === Number(match[1])
179
+ && date.getUTCMonth() + 1 === Number(match[2])
180
+ && date.getUTCDate() === Number(match[3])
181
+ && date.getUTCHours() === Number(match[4])
182
+ && date.getUTCMinutes() === Number(match[5])
183
+ && date.getUTCSeconds() === Number(match[6]);
184
+ }
185
+
186
+ function parseFallbackManifest(value) {
187
+ const record = exactDataRecord(value, MANIFEST_KEYS);
188
+ const notesUrl = record ? canonicalOfficialNotesUrl(record.notesUrl) : undefined;
189
+ if (!record
190
+ || record.name !== PACKAGE_NAME
191
+ || !parseSemver(record.latest)
192
+ || !parseSemver(record.minSupported)
193
+ || compareSemver(record.minSupported, record.latest) === 1
194
+ || !isIsoTimestamp(record.releasedAt)
195
+ || !notesUrl
196
+ || !isBoundedText(record.install, 256)) {
197
+ return undefined;
198
+ }
199
+ return Object.freeze({
200
+ name: record.name,
201
+ latest: record.latest,
202
+ minSupported: record.minSupported,
203
+ releasedAt: record.releasedAt,
204
+ notesUrl,
205
+ install: record.install,
206
+ });
207
+ }
208
+
209
+ function resolveEffectiveRelease(currentVersion, registryTags, fallbackManifest) {
210
+ if (!parseSemver(currentVersion)) return undefined;
211
+ const registryLatest = readDataProperty(registryTags, 'latest');
212
+ const validRegistryLatest = parseSemver(registryLatest) ? registryLatest : undefined;
213
+ const registryNext = readDataProperty(registryTags, 'next');
214
+ const validRegistryNext = parseSemver(registryNext) ? registryNext : undefined;
215
+ const validFallback = parseFallbackManifest(fallbackManifest);
216
+ if (!validRegistryLatest && !validFallback) return undefined;
217
+
218
+ if (validRegistryLatest && compareSemver(currentVersion, validRegistryLatest) > 0) {
219
+ if (!validRegistryNext || compareSemver(validRegistryNext, currentVersion) <= 0) {
220
+ return undefined;
221
+ }
222
+ return { channel: 'next', version: validRegistryNext };
223
+ }
224
+
225
+ let version;
226
+ if (validRegistryLatest && validFallback) {
227
+ version = compareSemver(validRegistryLatest, validFallback.latest) <= 0
228
+ ? validRegistryLatest
229
+ : validFallback.latest;
230
+ } else {
231
+ version = validRegistryLatest || validFallback.latest;
232
+ }
233
+
234
+ if (compareSemver(version, currentVersion) <= 0) return undefined;
235
+
236
+ if (validFallback && compareSemver(validFallback.latest, version) === 0) {
237
+ return { channel: 'stable', version, notesUrl: validFallback.notesUrl };
238
+ }
239
+ return { channel: 'stable', version };
240
+ }
241
+
242
+ function requestTrustedJson(url, options = {}) {
243
+ const maxBytes = ENDPOINT_LIMITS.get(url);
244
+ if (maxBytes === undefined) {
245
+ return Promise.reject(new Error('UNTRUSTED_UPDATE_ENDPOINT'));
246
+ }
247
+ const httpsImpl = options.httpsImpl || https;
248
+ const timeoutMs = options.timeoutMs || REQUEST_TIMEOUT_MS;
249
+
250
+ return new Promise((resolve, reject) => {
251
+ let request;
252
+ let response;
253
+ let settled = false;
254
+ const finish = (error, value) => {
255
+ if (settled) return;
256
+ settled = true;
257
+ clearTimeout(timer);
258
+ if (error) reject(error);
259
+ else resolve(value);
260
+ };
261
+ const timer = setTimeout(() => {
262
+ const error = new Error('UPDATE_REQUEST_TIMEOUT');
263
+ finish(error);
264
+ if (response && typeof response.destroy === 'function') response.destroy();
265
+ if (request && typeof request.destroy === 'function') request.destroy();
266
+ }, timeoutMs);
267
+
268
+ try {
269
+ request = httpsImpl.get(url, {
270
+ headers: { accept: 'application/vnd.npm.install-v1+json, application/json' },
271
+ }, (incoming) => {
272
+ response = incoming;
273
+ if (incoming.statusCode !== 200) {
274
+ finish(new Error(`UPDATE_HTTP_STATUS_${incoming.statusCode || 0}`));
275
+ if (typeof incoming.destroy === 'function') incoming.destroy();
276
+ if (request && typeof request.destroy === 'function') request.destroy();
277
+ return;
278
+ }
279
+
280
+ const rawLength = incoming.headers && incoming.headers['content-length'];
281
+ const declaredLength = typeof rawLength === 'string' && /^\d+$/.test(rawLength)
282
+ ? Number(rawLength)
283
+ : undefined;
284
+ if (declaredLength !== undefined && declaredLength > maxBytes) {
285
+ finish(new Error('UPDATE_BODY_TOO_LARGE'));
286
+ if (typeof incoming.destroy === 'function') incoming.destroy();
287
+ return;
288
+ }
289
+
290
+ const chunks = [];
291
+ let total = 0;
292
+ incoming.on('data', (chunk) => {
293
+ if (settled) return;
294
+ const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
295
+ total += buffer.length;
296
+ if (total > maxBytes) {
297
+ finish(new Error('UPDATE_BODY_TOO_LARGE'));
298
+ if (typeof incoming.destroy === 'function') incoming.destroy();
299
+ return;
300
+ }
301
+ chunks.push(buffer);
302
+ });
303
+ incoming.on('error', (error) => finish(error));
304
+ incoming.on('end', () => {
305
+ if (settled) return;
306
+ try {
307
+ finish(undefined, JSON.parse(Buffer.concat(chunks).toString('utf8')));
308
+ } catch {
309
+ finish(new Error('UPDATE_INVALID_JSON'));
310
+ }
311
+ });
312
+ });
313
+ request.on('error', (error) => finish(error));
314
+ } catch (error) {
315
+ finish(error);
316
+ }
317
+ });
318
+ }
319
+
320
+ async function loadReleaseSources() {
321
+ const [registry, fallback] = await Promise.allSettled([
322
+ requestTrustedJson(REGISTRY_URL),
323
+ requestTrustedJson(FALLBACK_MANIFEST_URL),
324
+ ]);
325
+ return {
326
+ registryDocument: registry.status === 'fulfilled' ? registry.value : undefined,
327
+ fallbackDocument: fallback.status === 'fulfilled' ? fallback.value : undefined,
328
+ };
329
+ }
330
+
331
+ function statePath(blunDir) {
332
+ return path.join(blunDir, STATE_FILE);
333
+ }
334
+
335
+ function readSnoozeState(blunDir, now = Date.now()) {
336
+ try {
337
+ const filePath = statePath(blunDir);
338
+ if (!fs.existsSync(filePath)) return false;
339
+ securePrivateFile(filePath);
340
+ const stat = fs.lstatSync(filePath);
341
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1_024) return false;
342
+ const record = exactDataRecord(JSON.parse(fs.readFileSync(filePath, 'utf8')), [
343
+ 'snoozedUntil',
344
+ 'version',
345
+ ]);
346
+ if (!record
347
+ || record.version !== 1
348
+ || !Number.isSafeInteger(record.snoozedUntil)
349
+ || record.snoozedUntil <= now
350
+ || record.snoozedUntil > now + SNOOZE_MS) {
351
+ return false;
352
+ }
353
+ return true;
354
+ } catch {
355
+ return false;
356
+ }
357
+ }
358
+
359
+ function writeSnoozeState(blunDir, now = Date.now()) {
360
+ ensurePrivateDirectory(blunDir);
361
+ const filePath = statePath(blunDir);
362
+ const temporaryPath = path.join(
363
+ blunDir,
364
+ `.${STATE_FILE}.${process.pid}.${randomUUID()}.tmp`,
365
+ );
366
+ try {
367
+ writePrivateFile(temporaryPath, `${JSON.stringify({
368
+ version: 1,
369
+ snoozedUntil: now + SNOOZE_MS,
370
+ })}\n`);
371
+ const handle = fs.openSync(temporaryPath, 'r+');
372
+ try {
373
+ fs.fsyncSync(handle);
374
+ } finally {
375
+ fs.closeSync(handle);
376
+ }
377
+ fs.renameSync(temporaryPath, filePath);
378
+ securePrivateFile(filePath);
379
+ } catch (error) {
380
+ fs.rmSync(temporaryPath, { force: true });
381
+ throw error;
382
+ }
383
+ }
384
+
385
+ function isInteractiveUpdateStart({ argv, env, stdin, stdout }) {
386
+ return Array.isArray(argv)
387
+ && argv.length === 0
388
+ && (!env || env.BLUN_NO_AUTO_UPDATE !== '1')
389
+ && stdin?.isTTY === true
390
+ && stdout?.isTTY === true;
391
+ }
392
+
393
+ function installCommandText(version) {
394
+ return `npm i -g ${PACKAGE_NAME}@${version}`;
395
+ }
396
+
397
+ function promptUpdateAction({ currentVersion, release, input, output, processRef = process }) {
398
+ return new Promise((resolve, reject) => {
399
+ let selected = 1;
400
+ let settled = false;
401
+ let cursorHidden = false;
402
+ let escapeTimer;
403
+ let pendingInput = '';
404
+ const decoder = new StringDecoder('utf8');
405
+ const wasRaw = input.isRaw === true;
406
+ const actions = ['Herunterladen und installieren', 'Aussetzen'];
407
+ const signalHandlers = new Map();
408
+
409
+ const renderActions = (refresh) => {
410
+ if (refresh) output.write('\u001B[2F');
411
+ for (let index = 0; index < actions.length; index += 1) {
412
+ output.write(`\r\u001B[2K ${selected === index ? '>' : ' '} ${actions[index]}\n`);
413
+ }
414
+ };
415
+ const cleanup = () => {
416
+ if (escapeTimer !== undefined) clearTimeout(escapeTimer);
417
+ input.removeListener('data', onData);
418
+ input.removeListener('end', postpone);
419
+ input.removeListener('close', postpone);
420
+ input.removeListener('error', postpone);
421
+ for (const [signal, handler] of signalHandlers) {
422
+ processRef.removeListener(signal, handler);
423
+ }
424
+ signalHandlers.clear();
425
+ try {
426
+ if (typeof input.setRawMode === 'function') input.setRawMode(wasRaw);
427
+ } catch {}
428
+ try {
429
+ if (typeof input.pause === 'function') input.pause();
430
+ } catch {}
431
+ if (cursorHidden) {
432
+ try {
433
+ output.write('\u001B[?25h');
434
+ } catch {}
435
+ cursorHidden = false;
436
+ }
437
+ };
438
+ const finish = (choice) => {
439
+ if (settled) return;
440
+ settled = true;
441
+ cleanup();
442
+ try {
443
+ output.write('\n');
444
+ } catch {}
445
+ resolve(choice);
446
+ };
447
+ const fail = (error) => {
448
+ if (settled) return;
449
+ settled = true;
450
+ cleanup();
451
+ reject(error);
452
+ };
453
+ const handleSignal = (signal) => {
454
+ if (settled) return;
455
+ settled = true;
456
+ cleanup();
457
+ try {
458
+ output.write('\n');
459
+ } catch {}
460
+ const error = new Error(`UPDATE_PROMPT_${signal}`);
461
+ error.code = `UPDATE_PROMPT_${signal}`;
462
+ const exitCode = UPDATE_SIGNAL_EXIT_CODES[signal];
463
+ processRef.exitCode = exitCode;
464
+ if (typeof processRef.exit === 'function') processRef.exit(exitCode);
465
+ reject(error);
466
+ };
467
+ function postpone() {
468
+ finish('postpone');
469
+ }
470
+ const waitForEscapeSuffix = () => {
471
+ if (escapeTimer !== undefined) return;
472
+ escapeTimer = setTimeout(() => {
473
+ escapeTimer = undefined;
474
+ postpone();
475
+ }, UPDATE_KEY_ESCAPE_TIMEOUT_MS);
476
+ };
477
+ const clearEscapeTimer = () => {
478
+ if (escapeTimer === undefined) return;
479
+ clearTimeout(escapeTimer);
480
+ escapeTimer = undefined;
481
+ };
482
+ const readEscapeSequence = () => {
483
+ if (pendingInput.length < 2) return undefined;
484
+ if (pendingInput[1] === '[') {
485
+ for (let index = 2; index < pendingInput.length; index += 1) {
486
+ const code = pendingInput.codePointAt(index);
487
+ if (code >= 0x40 && code <= 0x7e) return pendingInput.slice(0, index + 1);
488
+ const isParameter = code >= 0x30 && code <= 0x3f;
489
+ const isIntermediate = code >= 0x20 && code <= 0x2f;
490
+ if (!isParameter && !isIntermediate) return pendingInput.slice(0, index + 1);
491
+ }
492
+ return pendingInput.length > 64 ? pendingInput : undefined;
493
+ }
494
+ if (pendingInput[1] === 'O') {
495
+ return pendingInput.length >= 3 ? pendingInput.slice(0, 3) : undefined;
496
+ }
497
+ return pendingInput.slice(0, 2);
498
+ };
499
+ const processPendingInput = () => {
500
+ while (pendingInput.length > 0) {
501
+ const first = pendingInput[0];
502
+ if (first === '\u0003') {
503
+ postpone();
504
+ return;
505
+ }
506
+ if (first === '\r' || first === '\n') {
507
+ pendingInput = pendingInput.slice(1);
508
+ finish(selected === 0 ? 'install' : 'postpone');
509
+ return;
510
+ }
511
+ if (first !== '\u001B') {
512
+ pendingInput = pendingInput.slice(1);
513
+ continue;
514
+ }
515
+ if (pendingInput.length > 1
516
+ && (pendingInput[1] === '\r'
517
+ || pendingInput[1] === '\n'
518
+ || pendingInput[1] === '\u0003')) {
519
+ postpone();
520
+ return;
521
+ }
522
+ const sequence = readEscapeSequence();
523
+ if (sequence === undefined) {
524
+ waitForEscapeSuffix();
525
+ return;
526
+ }
527
+ clearEscapeTimer();
528
+ if (sequence === '\u001B[A' || sequence === '\u001B[D') {
529
+ selected = 0;
530
+ pendingInput = pendingInput.slice(sequence.length);
531
+ renderActions(true);
532
+ continue;
533
+ }
534
+ if (sequence === '\u001B[B' || sequence === '\u001B[C') {
535
+ selected = 1;
536
+ pendingInput = pendingInput.slice(sequence.length);
537
+ renderActions(true);
538
+ continue;
539
+ }
540
+ pendingInput = pendingInput.slice(sequence.length);
541
+ }
542
+ };
543
+ const onData = (chunk) => {
544
+ try {
545
+ pendingInput += Buffer.isBuffer(chunk) ? decoder.write(chunk) : String(chunk);
546
+ processPendingInput();
547
+ } catch (error) {
548
+ fail(error);
549
+ }
550
+ };
551
+
552
+ try {
553
+ const supportedSignals = processRef.platform === 'win32'
554
+ ? ['SIGINT', 'SIGTERM']
555
+ : Object.keys(UPDATE_SIGNAL_EXIT_CODES);
556
+ for (const signal of supportedSignals) {
557
+ const handler = () => handleSignal(signal);
558
+ signalHandlers.set(signal, handler);
559
+ processRef.once(signal, handler);
560
+ }
561
+ output.write(`\nNeues Update verfügbar (${currentVersion} -> ${release.version})\n`);
562
+ if (release.notesUrl) output.write(`Versionshinweise: ${release.notesUrl}\n`);
563
+ output.write(`Installationsbefehl: ${installCommandText(release.version)}\n\n`);
564
+ cursorHidden = true;
565
+ output.write('\u001B[?25l');
566
+ renderActions(false);
567
+ input.on('data', onData);
568
+ input.once('end', postpone);
569
+ input.once('close', postpone);
570
+ input.once('error', postpone);
571
+ if (typeof input.setRawMode === 'function') input.setRawMode(true);
572
+ if (typeof input.resume === 'function') input.resume();
573
+ } catch (error) {
574
+ fail(error);
575
+ }
576
+ });
577
+ }
578
+
579
+ function resolveTrustedNpmCliPath(options = {}) {
580
+ const execPath = path.resolve(options.execPath || process.execPath);
581
+ const executableDirectory = path.dirname(execPath);
582
+ const packageRoot = path.resolve(__dirname, '..');
583
+ const candidates = options.npmCliPath ? [options.npmCliPath] : [
584
+ path.join(executableDirectory, 'node_modules', 'npm', 'bin', 'npm-cli.js'),
585
+ path.resolve(executableDirectory, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
586
+ path.resolve(executableDirectory, '..', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
587
+ path.resolve(packageRoot, '..', 'npm', 'bin', 'npm-cli.js'),
588
+ ];
589
+ for (const candidate of candidates) {
590
+ try {
591
+ if (!path.isAbsolute(candidate)) continue;
592
+ const resolved = fs.realpathSync(candidate);
593
+ const parts = resolved.replaceAll('\\', '/').split('/');
594
+ const npmIndex = parts.length - 3;
595
+ if (parts.at(-1) !== 'npm-cli.js'
596
+ || parts.at(-2) !== 'bin'
597
+ || parts[npmIndex]?.toLowerCase() !== 'npm'
598
+ || !fs.statSync(resolved).isFile()) {
599
+ continue;
600
+ }
601
+ return resolved;
602
+ } catch {}
603
+ }
604
+ throw new Error('TRUSTED_NPM_CLI_NOT_FOUND');
605
+ }
606
+
607
+ function createInstallInvocation(version, options = {}) {
608
+ if (!parseSemver(version)) throw new Error('INVALID_UPDATE_VERSION');
609
+ const packageSpec = `${PACKAGE_NAME}@${version}`;
610
+ const execPath = fs.realpathSync(path.resolve(options.execPath || process.execPath));
611
+ if (!fs.statSync(execPath).isFile()) throw new Error('INVALID_NODE_EXECUTABLE');
612
+ const npmCliPath = resolveTrustedNpmCliPath(options);
613
+ const packageRoot = fs.realpathSync(path.resolve(options.packageRoot));
614
+ const modulesRoot = path.dirname(packageRoot);
615
+ if (path.basename(modulesRoot).toLowerCase() !== 'node_modules') {
616
+ throw new Error('INVALID_GLOBAL_PACKAGE_ROOT');
617
+ }
618
+ let installPrefix = path.dirname(modulesRoot);
619
+ const platform = options.platform || process.platform;
620
+ if (platform !== 'win32' && path.basename(installPrefix) === 'lib') {
621
+ installPrefix = path.dirname(installPrefix);
622
+ }
623
+ let npmConfigPath;
624
+ if (options.npmConfigPath) {
625
+ npmConfigPath = fs.realpathSync(path.resolve(options.npmConfigPath));
626
+ if (!fs.statSync(npmConfigPath).isFile()) throw new Error('INVALID_NPM_CONFIG_PATH');
627
+ }
628
+ return {
629
+ command: execPath,
630
+ args: [
631
+ npmCliPath,
632
+ 'i',
633
+ '-g',
634
+ packageSpec,
635
+ `--registry=${INSTALL_REGISTRY_URL}`,
636
+ '--strict-ssl=true',
637
+ '--dry-run=false',
638
+ '--ignore-scripts=false',
639
+ '--package-lock-only=false',
640
+ `--prefix=${installPrefix}`,
641
+ ...(npmConfigPath ? [
642
+ `--userconfig=${npmConfigPath}`,
643
+ `--globalconfig=${npmConfigPath}`,
644
+ ] : []),
645
+ ],
646
+ windowsVerbatimArguments: false,
647
+ };
648
+ }
649
+
650
+ function createInstallEnvironment(sourceEnv, installDirectory, npmConfigPath) {
651
+ const allowedKeys = new Set([
652
+ 'appdata',
653
+ 'comspec',
654
+ 'home',
655
+ 'homedrive',
656
+ 'homepath',
657
+ 'lang',
658
+ 'lc_all',
659
+ 'lc_ctype',
660
+ 'localappdata',
661
+ 'logname',
662
+ 'path',
663
+ 'pathext',
664
+ 'programdata',
665
+ 'programfiles',
666
+ 'programfiles(x86)',
667
+ 'systemroot',
668
+ 'term',
669
+ 'tz',
670
+ 'user',
671
+ 'userprofile',
672
+ 'windir',
673
+ ]);
674
+ const result = {};
675
+ for (const [key, value] of Object.entries(sourceEnv || {})) {
676
+ const normalized = key.toLowerCase();
677
+ if (!allowedKeys.has(normalized) && !key.startsWith('BLUN_TEST_')) continue;
678
+ result[key] = value;
679
+ }
680
+ result.TEMP = installDirectory;
681
+ result.TMP = installDirectory;
682
+ result.TMPDIR = installDirectory;
683
+ result.npm_config_registry = INSTALL_REGISTRY_URL;
684
+ result.npm_config_strict_ssl = 'true';
685
+ result.npm_config_dry_run = 'false';
686
+ result.npm_config_ignore_scripts = 'false';
687
+ result.npm_config_package_lock_only = 'false';
688
+ result.npm_config_userconfig = npmConfigPath;
689
+ result.npm_config_globalconfig = npmConfigPath;
690
+ return result;
691
+ }
692
+
693
+ function pathIsWithin(root, candidate) {
694
+ const relative = path.relative(root, candidate);
695
+ return relative === '' || (!relative.startsWith(`..${path.sep}`)
696
+ && relative !== '..'
697
+ && !path.isAbsolute(relative));
698
+ }
699
+
700
+ function resolveInstallTempRoot(options) {
701
+ if (typeof options.blunDir !== 'string' || options.blunDir.trim().length === 0) {
702
+ throw new Error('INVALID_UPDATE_BLUN_HOME');
703
+ }
704
+ const updateRoot = path.join(path.resolve(options.blunDir), UPDATE_DIRECTORY);
705
+ if (options.tempRoot === undefined) return updateRoot;
706
+ const explicitRoot = path.resolve(options.tempRoot);
707
+ if (!pathIsWithin(updateRoot, explicitRoot)) {
708
+ throw new Error('INVALID_UPDATE_TEMP_ROOT');
709
+ }
710
+ return explicitRoot;
711
+ }
712
+
713
+ function createPrivateInstallDirectory(tempRoot, blunDir) {
714
+ const updateRoot = path.join(path.resolve(blunDir), UPDATE_DIRECTORY);
715
+ let current = updateRoot;
716
+ ensurePrivateDirectory(current);
717
+ const relative = path.relative(updateRoot, tempRoot);
718
+ if (relative !== '') {
719
+ for (const segment of relative.split(path.sep)) {
720
+ current = path.join(current, segment);
721
+ ensurePrivateDirectory(current);
722
+ }
723
+ }
724
+ let directory;
725
+ try {
726
+ directory = fs.mkdtempSync(path.join(tempRoot, 'blun-update-'));
727
+ ensurePrivateDirectory(directory);
728
+ return directory;
729
+ } catch (error) {
730
+ if (directory) {
731
+ try {
732
+ fs.rmSync(directory, { recursive: true, force: true });
733
+ } catch {}
734
+ }
735
+ throw error;
736
+ }
737
+ }
738
+
739
+ function verifyInstalledPackageVersion(packageRoot, version) {
740
+ try {
741
+ const manifestPath = path.join(packageRoot, 'package.json');
742
+ const stat = fs.lstatSync(manifestPath);
743
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 64 * 1024) return false;
744
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
745
+ return readDataProperty(manifest, 'name') === PACKAGE_NAME
746
+ && readDataProperty(manifest, 'version') === version;
747
+ } catch {
748
+ return false;
749
+ }
750
+ }
751
+
752
+ function preparePinnedInstaller(version, options = {}) {
753
+ const forkImpl = options.forkImpl || fork;
754
+ const preparation = Promise.withResolvers();
755
+ const resolvePreparation = preparation.resolve;
756
+ let child;
757
+ let invocation;
758
+ let leaseBusy = false;
759
+ let leaseUnavailable = false;
760
+ let sendError;
761
+ let childError;
762
+ let preparationSettled = false;
763
+ let closeSettled = false;
764
+ let selectedAction;
765
+ let installDirectory;
766
+ let npmConfigPath;
767
+ let disconnectTimer;
768
+ const close = Promise.withResolvers();
769
+ const closePromise = close.promise;
770
+ const resolveClose = close.resolve;
771
+ const cleanupDirectory = () => {
772
+ try {
773
+ if (installDirectory) {
774
+ (options.removeDirectory || fs.rmSync)(installDirectory, {
775
+ recursive: true,
776
+ force: true,
777
+ });
778
+ }
779
+ } catch {
780
+ // Cleanup cannot change a completed npm result.
781
+ }
782
+ };
783
+ const settlePreparation = (result) => {
784
+ if (preparationSettled) return;
785
+ preparationSettled = true;
786
+ clearTimeout(prepareTimeout);
787
+ resolvePreparation(result);
788
+ };
789
+ const finishClose = (result) => {
790
+ if (closeSettled) return;
791
+ closeSettled = true;
792
+ clearTimeout(disconnectTimer);
793
+ cleanupDirectory();
794
+ resolveClose(result);
795
+ if (!preparationSettled) {
796
+ settlePreparation({
797
+ ready: false,
798
+ reason: leaseBusy
799
+ ? 'busy'
800
+ : leaseUnavailable
801
+ ? 'unavailable'
802
+ : result.code === 75 || result.unknownState === true
803
+ ? 'unknown'
804
+ : 'failed',
805
+ result,
806
+ });
807
+ }
808
+ };
809
+ const finishDisconnected = () => {
810
+ if (closeSettled) return;
811
+ closeSettled = true;
812
+ const result = { code: undefined, error: childError, unknownState: true };
813
+ resolveClose(result);
814
+ if (!preparationSettled) {
815
+ settlePreparation({ ready: false, reason: 'unknown', result });
816
+ }
817
+ };
818
+ const scheduleUnknownState = (error) => {
819
+ if (error && childError === undefined) childError = error;
820
+ if (disconnectTimer !== undefined) return;
821
+ disconnectTimer = setTimeout(
822
+ finishDisconnected,
823
+ options.disconnectTimeoutMs || 1_000,
824
+ );
825
+ };
826
+ const sendControl = (type) => {
827
+ if (selectedAction) return closePromise;
828
+ selectedAction = type;
829
+ try {
830
+ child.send({ type }, (error) => {
831
+ if (!error) return;
832
+ sendError = error;
833
+ try {
834
+ child.kill();
835
+ } catch {}
836
+ });
837
+ } catch (error) {
838
+ sendError = error;
839
+ try {
840
+ child.kill();
841
+ } catch {}
842
+ }
843
+ return closePromise;
844
+ };
845
+ let prepareTimeout;
846
+ try {
847
+ installDirectory = createPrivateInstallDirectory(
848
+ resolveInstallTempRoot(options),
849
+ options.blunDir,
850
+ );
851
+ npmConfigPath = path.join(installDirectory, 'npmrc');
852
+ writePrivateFile(npmConfigPath, '');
853
+ invocation = createInstallInvocation(version, { ...options, npmConfigPath });
854
+ child = forkImpl(path.join(__dirname, 'update-lease.js'), ['--installer-worker'], {
855
+ detached: true,
856
+ execPath: invocation.command,
857
+ cwd: installDirectory,
858
+ env: createInstallEnvironment(
859
+ options.env || process.env,
860
+ installDirectory,
861
+ npmConfigPath,
862
+ ),
863
+ stdio: ['inherit', 'inherit', 'inherit', 'ipc'],
864
+ windowsHide: true,
865
+ });
866
+ } catch (error) {
867
+ cleanupDirectory();
868
+ settlePreparation({ ready: false, reason: 'failed', result: { error } });
869
+ return preparation.promise;
870
+ }
871
+ prepareTimeout = setTimeout(() => {
872
+ sendError = new Error('UPDATE_INSTALLER_PREPARE_TIMEOUT');
873
+ settlePreparation({ ready: false, reason: 'unknown', result: { error: sendError } });
874
+ try {
875
+ child.kill();
876
+ } catch {}
877
+ }, options.prepareTimeoutMs || 5_000);
878
+ prepareTimeout.unref?.();
879
+ child.once('error', (error) => {
880
+ if (!preparationSettled && child.pid === undefined) {
881
+ finishClose({ code: undefined, error });
882
+ return;
883
+ }
884
+ scheduleUnknownState(error);
885
+ });
886
+ child.on('message', (message) => {
887
+ if (message?.type === 'blun-update-lease-busy') leaseBusy = true;
888
+ if (message?.type === 'blun-update-lease-unavailable') leaseUnavailable = true;
889
+ if (message?.type === 'blun-update-lease-adopted') {
890
+ settlePreparation(Object.freeze({
891
+ ready: true,
892
+ commit: () => sendControl('blun-update-lease-commit'),
893
+ cancel: () => sendControl('blun-update-lease-cancel'),
894
+ }));
895
+ }
896
+ });
897
+ const finishInstallerProcess = (code, signal) => {
898
+ if (sendError || childError) {
899
+ finishClose({
900
+ code: undefined,
901
+ error: sendError || childError,
902
+ unknownState: true,
903
+ });
904
+ return;
905
+ }
906
+ finishClose({
907
+ code: Number.isInteger(code) ? code : undefined,
908
+ signal: typeof signal === 'string' ? signal : undefined,
909
+ leaseBusy,
910
+ leaseUnavailable,
911
+ unknownState: !Number.isInteger(code),
912
+ verified: !leaseBusy
913
+ && !leaseUnavailable
914
+ && code === 0
915
+ && verifyInstalledPackageVersion(options.packageRoot, version),
916
+ });
917
+ };
918
+ child.once('exit', finishInstallerProcess);
919
+ child.once('close', finishInstallerProcess);
920
+ child.once('disconnect', () => scheduleUnknownState());
921
+ try {
922
+ child.send({
923
+ type: 'blun-update-lease-handoff',
924
+ packageRoot: path.resolve(options.packageRoot),
925
+ installer: {
926
+ npmCliPath: invocation.args[0],
927
+ npmArgs: invocation.args.slice(1),
928
+ installCwd: installDirectory,
929
+ },
930
+ }, (error) => {
931
+ if (!error) return;
932
+ sendError = error;
933
+ try {
934
+ child.kill();
935
+ } catch {
936
+ finishClose({ code: undefined, error, unknownState: true });
937
+ }
938
+ });
939
+ } catch (error) {
940
+ sendError = error;
941
+ try {
942
+ child.kill();
943
+ } catch {
944
+ finishClose({ code: undefined, error, unknownState: true });
945
+ }
946
+ }
947
+ return preparation.promise;
948
+ }
949
+
950
+ async function installPinnedVersion(version, options = {}) {
951
+ const prepared = await preparePinnedInstaller(version, options);
952
+ if (!prepared.ready) {
953
+ return {
954
+ ...prepared.result,
955
+ leaseBusy: prepared.reason === 'busy',
956
+ leaseUnavailable: prepared.reason === 'unavailable',
957
+ unknownState: prepared.reason === 'unknown' || prepared.result?.unknownState === true,
958
+ };
959
+ }
960
+ return prepared.commit();
961
+ }
962
+
963
+ async function probeInstallLease(options, packageRoot) {
964
+ let result;
965
+ try {
966
+ result = await (options.acquireInstallLease || tryAcquireUpdateLease)({
967
+ packageRoot,
968
+ role: 'install',
969
+ });
970
+ } catch {
971
+ return 'unavailable';
972
+ }
973
+ if (!result?.acquired) return result?.reason === 'busy' ? 'busy' : 'unavailable';
974
+ try {
975
+ result.lease.assertOwned();
976
+ } catch {
977
+ return 'busy';
978
+ } finally {
979
+ try {
980
+ await result.lease.release();
981
+ } catch {}
982
+ }
983
+ return 'clear';
984
+ }
985
+
986
+ function noReleaseReason(currentVersion, registryTags, fallbackManifest) {
987
+ const latest = readDataProperty(registryTags, 'latest');
988
+ if (parseSemver(latest) && compareSemver(currentVersion, latest) > 0) {
989
+ const next = readDataProperty(registryTags, 'next');
990
+ return parseSemver(next) && compareSemver(next, currentVersion) === 0
991
+ ? 'current'
992
+ : 'unavailable';
993
+ }
994
+ return parseSemver(latest) || fallbackManifest ? 'current' : 'unavailable';
995
+ }
996
+
997
+ function explicitNoTarget(stdout, reason) {
998
+ stdout.write(reason === 'current'
999
+ ? 'Kein Update verfügbar. BLUN Code ist auf dem aktuellen Updatekanal.\n'
1000
+ : 'Kein sicherer Update-Zielstand verfügbar.\n');
1001
+ return { kind: 'current', reason };
1002
+ }
1003
+
1004
+ function explicitFailure(stderr, reason, exitCode) {
1005
+ const hasExitCode = Number.isInteger(exitCode) && exitCode !== 0;
1006
+ if (hasExitCode) {
1007
+ stderr.write(`Update fehlgeschlagen (Code ${exitCode}).\n`);
1008
+ } else {
1009
+ stderr.write('Das Update konnte nicht verifiziert werden.\n');
1010
+ }
1011
+ return {
1012
+ kind: 'failed',
1013
+ reason,
1014
+ exitCode: hasExitCode ? exitCode : 1,
1015
+ };
1016
+ }
1017
+
1018
+ async function runUpdateFlow(options, explicitUpdate) {
1019
+ const {
1020
+ currentVersion,
1021
+ argv,
1022
+ env,
1023
+ stdin,
1024
+ stdout,
1025
+ stderr,
1026
+ blunDir,
1027
+ } = options;
1028
+ if (!explicitUpdate && !isInteractiveUpdateStart({ argv, env, stdin, stdout })) {
1029
+ return { kind: 'continue', reason: 'not_interactive' };
1030
+ }
1031
+ if (!parseSemver(currentVersion)) {
1032
+ return explicitUpdate
1033
+ ? explicitFailure(stderr, 'invalid_current_version')
1034
+ : { kind: 'continue', reason: 'invalid_current_version' };
1035
+ }
1036
+
1037
+ const now = (options.now || Date.now)();
1038
+ if (!explicitUpdate && readSnoozeState(blunDir, now)) {
1039
+ return { kind: 'continue', reason: 'snoozed' };
1040
+ }
1041
+
1042
+ const packageRoot = path.resolve(options.packageRoot || path.resolve(__dirname, '..'));
1043
+ let leaseResult;
1044
+ const ownsNoticeLease = options.noticeLease === undefined;
1045
+ if (ownsNoticeLease) {
1046
+ try {
1047
+ leaseResult = await (options.acquireLease || tryAcquireUpdateLease)({ packageRoot });
1048
+ } catch {
1049
+ return explicitUpdate
1050
+ ? explicitFailure(stderr, 'lease_unavailable')
1051
+ : { kind: 'continue', reason: 'lease_unavailable' };
1052
+ }
1053
+ } else {
1054
+ leaseResult = { acquired: true, lease: options.noticeLease };
1055
+ }
1056
+ if (!leaseResult?.acquired) {
1057
+ if (explicitUpdate) {
1058
+ return explicitFailure(
1059
+ stderr,
1060
+ leaseResult?.reason === 'busy' ? 'update_in_progress' : 'lease_unavailable',
1061
+ );
1062
+ }
1063
+ return leaseResult?.reason === 'busy'
1064
+ ? { kind: 'update_in_progress' }
1065
+ : { kind: 'continue', reason: 'lease_unavailable' };
1066
+ }
1067
+ const { lease } = leaseResult;
1068
+ let installerSession;
1069
+
1070
+ try {
1071
+ if (!explicitUpdate && readSnoozeState(blunDir, (options.now || Date.now)())) {
1072
+ return { kind: 'continue', reason: 'snoozed' };
1073
+ }
1074
+ const initialInstallLease = await probeInstallLease(options, packageRoot);
1075
+ if (initialInstallLease === 'busy') {
1076
+ return explicitUpdate
1077
+ ? explicitFailure(stderr, 'update_in_progress')
1078
+ : { kind: 'update_in_progress' };
1079
+ }
1080
+ if (initialInstallLease !== 'clear') {
1081
+ return explicitUpdate
1082
+ ? explicitFailure(stderr, 'lease_unavailable')
1083
+ : { kind: 'continue', reason: 'lease_unavailable' };
1084
+ }
1085
+ let sources;
1086
+ try {
1087
+ sources = await (options.loadReleaseSources || loadReleaseSources)();
1088
+ } catch {
1089
+ return explicitUpdate
1090
+ ? explicitNoTarget(stdout, 'unavailable')
1091
+ : { kind: 'continue', reason: 'unavailable' };
1092
+ }
1093
+ const registryTags = parseRegistryDocument(sources?.registryDocument);
1094
+ const fallbackManifest = parseFallbackManifest(sources?.fallbackDocument);
1095
+ const release = resolveEffectiveRelease(currentVersion, registryTags, fallbackManifest);
1096
+ if (!release) {
1097
+ const reason = noReleaseReason(currentVersion, registryTags, fallbackManifest);
1098
+ return explicitUpdate
1099
+ ? explicitNoTarget(stdout, reason)
1100
+ : { kind: 'continue', reason };
1101
+ }
1102
+ if (explicitUpdate) {
1103
+ try {
1104
+ ensurePrivateDirectory(blunDir);
1105
+ } catch {
1106
+ return explicitFailure(stderr, 'private_home_unavailable');
1107
+ }
1108
+ }
1109
+ try {
1110
+ lease.assertOwned();
1111
+ } catch {
1112
+ return explicitUpdate
1113
+ ? explicitFailure(stderr, 'update_in_progress')
1114
+ : { kind: 'update_in_progress' };
1115
+ }
1116
+ const prePromptInstallLease = await probeInstallLease(options, packageRoot);
1117
+ if (prePromptInstallLease === 'busy') {
1118
+ return explicitUpdate
1119
+ ? explicitFailure(stderr, 'update_in_progress')
1120
+ : { kind: 'update_in_progress' };
1121
+ }
1122
+ if (prePromptInstallLease !== 'clear') {
1123
+ return explicitUpdate
1124
+ ? explicitFailure(stderr, 'lease_unavailable')
1125
+ : { kind: 'continue', reason: 'lease_unavailable' };
1126
+ }
1127
+ if (!options.installVersion) {
1128
+ installerSession = await (options.prepareInstaller || preparePinnedInstaller)(
1129
+ release.version,
1130
+ { blunDir, packageRoot },
1131
+ );
1132
+ if (!installerSession?.ready) {
1133
+ if (explicitUpdate) {
1134
+ return explicitFailure(stderr, 'installer_unavailable');
1135
+ }
1136
+ return installerSession?.reason === 'failed'
1137
+ ? { kind: 'continue', reason: 'installer_unavailable' }
1138
+ : { kind: 'update_in_progress' };
1139
+ }
1140
+ }
1141
+ let action;
1142
+ if (explicitUpdate) {
1143
+ action = 'install';
1144
+ } else {
1145
+ try {
1146
+ action = await (options.promptAction || promptUpdateAction)({
1147
+ currentVersion,
1148
+ release,
1149
+ input: stdin,
1150
+ output: stdout,
1151
+ });
1152
+ } catch {
1153
+ return { kind: 'continue', reason: 'prompt_failed' };
1154
+ }
1155
+ }
1156
+ if (action !== 'install') {
1157
+ if (installerSession?.ready) await installerSession.cancel();
1158
+ try {
1159
+ writeSnoozeState(blunDir, (options.now || Date.now)());
1160
+ } catch {
1161
+ // A failed preference write must not block the existing console.
1162
+ }
1163
+ return { kind: 'continue', reason: 'postponed' };
1164
+ }
1165
+
1166
+ try {
1167
+ lease.assertOwned();
1168
+ } catch {
1169
+ return explicitUpdate
1170
+ ? explicitFailure(stderr, 'update_in_progress')
1171
+ : { kind: 'update_in_progress' };
1172
+ }
1173
+ let installResult;
1174
+ try {
1175
+ installResult = options.installVersion
1176
+ ? await options.installVersion(release.version)
1177
+ : await installerSession.commit();
1178
+ } catch {
1179
+ installResult = { code: undefined };
1180
+ }
1181
+ if (installResult?.leaseBusy === true
1182
+ || installResult?.leaseUnavailable === true
1183
+ || installResult?.unknownState === true) {
1184
+ return explicitUpdate
1185
+ ? explicitFailure(stderr, 'update_in_progress')
1186
+ : { kind: 'update_in_progress' };
1187
+ }
1188
+ if (installResult?.code === 0 && installResult?.verified === true) {
1189
+ stdout.write('Update erfolgreich installiert. Starte BLUN Code neu, um die neue Version zu verwenden.\n');
1190
+ return { kind: 'installed', version: release.version };
1191
+ }
1192
+
1193
+ if (Number.isInteger(installResult?.code) && installResult.code !== 0) {
1194
+ if (explicitUpdate) {
1195
+ return explicitFailure(stderr, 'install_failed', installResult.code);
1196
+ }
1197
+ stderr.write(`Update fehlgeschlagen (Code ${installResult.code}). Die vorhandene Version wird gestartet.\n`);
1198
+ return { kind: 'continue', reason: 'install_failed', exitCode: installResult.code };
1199
+ }
1200
+ if (explicitUpdate) return explicitFailure(stderr, 'verification_failed');
1201
+ stderr.write('Update konnte nicht verifiziert werden. Starte BLUN Code neu.\n');
1202
+ return { kind: 'update_in_progress' };
1203
+ } finally {
1204
+ if (installerSession?.ready) {
1205
+ try {
1206
+ await installerSession.cancel();
1207
+ } catch {}
1208
+ }
1209
+ if (ownsNoticeLease) {
1210
+ try {
1211
+ await lease.release();
1212
+ } catch {}
1213
+ }
1214
+ }
1215
+ }
1216
+
1217
+ function runExplicitUpdate(options) {
1218
+ return runUpdateFlow(options, true);
1219
+ }
1220
+
1221
+ function runUpdateNotice(options) {
1222
+ return runUpdateFlow(options, false);
1223
+ }
1224
+
1225
+ module.exports = {
1226
+ FALLBACK_MANIFEST_URL,
1227
+ PACKAGE_NAME,
1228
+ REGISTRY_URL,
1229
+ SNOOZE_MS,
1230
+ compareSemver,
1231
+ createInstallInvocation,
1232
+ installPinnedVersion,
1233
+ preparePinnedInstaller,
1234
+ isInteractiveUpdateStart,
1235
+ loadReleaseSources,
1236
+ parseFallbackManifest,
1237
+ parseRegistryDocument,
1238
+ promptUpdateAction,
1239
+ readSnoozeState,
1240
+ requestTrustedJson,
1241
+ resolveEffectiveRelease,
1242
+ runExplicitUpdate,
1243
+ runUpdateNotice,
1244
+ writeSnoozeState,
1245
+ };