blun-king-cli 9.0.1 → 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 (193) hide show
  1. package/LIESMICH.txt +31 -6
  2. package/README.md +35 -4
  3. package/bin/launcher-mode.js +13 -2
  4. package/bin/launcher-runtime.js +103 -31
  5. package/bin/plugin-bootstrap.js +11 -4
  6. package/bin/private-paths.js +1577 -10
  7. package/bin/update-notice.js +197 -46
  8. package/blun.mjs +7422 -3448
  9. package/dist-web/assets/{CodeBlockNode-Bsvp6ZEy.js → CodeBlockNode-CXnTLMNr.js} +1 -1
  10. 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
  11. package/dist-web/assets/{DesignSystemView-BmDDe28A.js → DesignSystemView-BbMOu-XO.js} +1 -1
  12. package/dist-web/assets/{Tooltip-nEEfaYVY.js → Tooltip-CFQEzqC-.js} +1 -1
  13. package/dist-web/assets/abnfDiagram-N423BO3Z-CsByy-GW.js +1 -0
  14. package/dist-web/assets/abnfDiagram-N423BO3Z-Z1APZG5m.js +1 -0
  15. package/dist-web/assets/arc-C-LXCaja.js +1 -0
  16. package/dist-web/assets/arc-C4VyWloT.js +1 -0
  17. package/dist-web/assets/architectureDiagram-T3A2C74G-DZq4L18e.js +36 -0
  18. package/dist-web/assets/architectureDiagram-T3A2C74G-DpddbUcM.js +36 -0
  19. package/dist-web/assets/blockDiagram-VBNYF7ZC-BV4sIf98.js +132 -0
  20. package/dist-web/assets/blockDiagram-VBNYF7ZC-BqccOSMr.js +132 -0
  21. package/dist-web/assets/{c4Diagram-AAUBKEIU-DtzacMnD.js → c4Diagram-5PPSVZJV-0MRkZlgP.js} +1 -1
  22. package/dist-web/assets/{c4Diagram-AAUBKEIU-D1VdMx8d.js → c4Diagram-5PPSVZJV-OHAcJrTy.js} +1 -1
  23. package/dist-web/assets/channel-B2VOQOI-.js +1 -0
  24. package/dist-web/assets/channel-DKjwM05G.js +1 -0
  25. package/dist-web/assets/{chunk-ND2GUHAM-DJoY9wNJ.js → chunk-2GRJ4B5K-DqJHs8Fw.js} +1 -1
  26. package/dist-web/assets/{chunk-ND2GUHAM-C4-rwdcv.js → chunk-2GRJ4B5K-oO6nqeLA.js} +1 -1
  27. package/dist-web/assets/{chunk-QZHKN3VN-C7YGaShq.js → chunk-2Q5K7J3B-B1nCd91o.js} +1 -1
  28. package/dist-web/assets/{chunk-QZHKN3VN-_Rz9_NuS.js → chunk-2Q5K7J3B-BC0Hsfqy.js} +1 -1
  29. package/dist-web/assets/chunk-5RXB4S5H-BfZa4yDH.js +231 -0
  30. package/dist-web/assets/chunk-5RXB4S5H-neG70kZx.js +231 -0
  31. package/dist-web/assets/{chunk-FMBD7UC4-DlLNDUx6.js → chunk-5VM5RSS4-l7biGqeH.js} +1 -1
  32. package/dist-web/assets/{chunk-FMBD7UC4-B2zs_Y-d.js → chunk-5VM5RSS4-u00AcpiJ.js} +1 -1
  33. package/dist-web/assets/chunk-6Q2QTUOP-BO-F11Gs.js +88 -0
  34. package/dist-web/assets/chunk-6Q2QTUOP-RUVRPBzG.js +88 -0
  35. package/dist-web/assets/{chunk-727SXJPM-Dn5wkDO_.js → chunk-GF5L2VYU-Ba-86KTd.js} +5 -5
  36. package/dist-web/assets/{chunk-727SXJPM-Dk2Xa3bA.js → chunk-GF5L2VYU-BtC69fw0.js} +5 -5
  37. package/dist-web/assets/{chunk-4BX2VUAB-DxZViaHS.js → chunk-JWPE2WC7-DIOubEqr.js} +1 -1
  38. package/dist-web/assets/{chunk-4BX2VUAB-WqrE2gaw.js → chunk-JWPE2WC7-u8Pcfhwh.js} +1 -1
  39. package/dist-web/assets/{chunk-2J33WTMH-Dm_s0_4f.js → chunk-KBJHAD2P-DDUeH_Ba.js} +1 -1
  40. package/dist-web/assets/{chunk-2J33WTMH-w4sdiKFO.js → chunk-KBJHAD2P-DS3BL64y.js} +1 -1
  41. package/dist-web/assets/chunk-RYQCIY6F-B9gFMVbS.js +1 -0
  42. package/dist-web/assets/chunk-RYQCIY6F-xg3EO0le.js +1 -0
  43. package/dist-web/assets/{chunk-55IACEB6-B5dE1-Um.js → chunk-XXDRQBXY-B60H0rRC.js} +1 -1
  44. package/dist-web/assets/{chunk-55IACEB6-B12zGIFz.js → chunk-XXDRQBXY-Bn1Xz6TQ.js} +1 -1
  45. package/dist-web/assets/classDiagram-JCYQIIEL-BA1TjAxj.js +1 -0
  46. package/dist-web/assets/classDiagram-JCYQIIEL-BNU7Qn4k.js +1 -0
  47. package/dist-web/assets/classDiagram-v2-OCEON4UE-BA1TjAxj.js +1 -0
  48. package/dist-web/assets/classDiagram-v2-OCEON4UE-BNU7Qn4k.js +1 -0
  49. package/dist-web/assets/{cose-bilkent-S5V4N54A-Bi19n8m-.js → cose-bilkent-JH36ORCC-4Ybddg08.js} +1 -1
  50. package/dist-web/assets/{cose-bilkent-S5V4N54A-c8o8NFp5.js → cose-bilkent-JH36ORCC-DqigO3T4.js} +1 -1
  51. package/dist-web/assets/cynefin-VYW2F7L2-C-EfYT07.js +178 -0
  52. package/dist-web/assets/cynefin-VYW2F7L2-rpD93tQ-.js +178 -0
  53. package/dist-web/assets/cynefinDiagram-MW4NZA55-DWZPLJcD.js +62 -0
  54. package/dist-web/assets/cynefinDiagram-MW4NZA55-DbTqnkVJ.js +62 -0
  55. package/dist-web/assets/dagre-VZM6K2ZE-DcM8aEVY.js +4 -0
  56. package/dist-web/assets/dagre-VZM6K2ZE-M_HVNtqP.js +4 -0
  57. package/dist-web/assets/diagram-7IWD3JNH-DoNximNF.js +30 -0
  58. package/dist-web/assets/diagram-7IWD3JNH-UymgsBNa.js +30 -0
  59. package/dist-web/assets/{diagram-KO2AKTUF-CFQs13i5.js → diagram-B4RE2ZJO-BVA2EhnC.js} +3 -3
  60. package/dist-web/assets/{diagram-KO2AKTUF-agFIuPJW.js → diagram-B4RE2ZJO-BiYu5WPF.js} +3 -3
  61. package/dist-web/assets/{diagram-LMA3HP47-TMIXizxR.js → diagram-LBJQPF4R-BD3kkgOO.js} +2 -2
  62. package/dist-web/assets/{diagram-LMA3HP47-He5zlyMt.js → diagram-LBJQPF4R-m3a1Euj3.js} +2 -2
  63. package/dist-web/assets/diagram-Q27KOJAE-D1mYQ_cI.js +24 -0
  64. package/dist-web/assets/diagram-Q27KOJAE-hy_T73PK.js +24 -0
  65. package/dist-web/assets/diagram-UB23O5K3-BWkoQZ4A.js +41 -0
  66. package/dist-web/assets/diagram-UB23O5K3-BtX8u6HG.js +41 -0
  67. package/dist-web/assets/ebnfDiagram-BXEA7PRR-BKs9JUHW.js +1 -0
  68. package/dist-web/assets/ebnfDiagram-BXEA7PRR-CBAnFkRF.js +1 -0
  69. package/dist-web/assets/erDiagram-JOGREHBK-3vKcWsxm.js +85 -0
  70. package/dist-web/assets/erDiagram-JOGREHBK-BIpd6dTf.js +85 -0
  71. package/dist-web/assets/flowDiagram-UKHOOZJN-D9wBbHm2.js +156 -0
  72. package/dist-web/assets/flowDiagram-UKHOOZJN-Z83i2UWI.js +156 -0
  73. package/dist-web/assets/ganttDiagram-PKOTCBZU-Cd_dViF-.js +292 -0
  74. package/dist-web/assets/ganttDiagram-PKOTCBZU-DFrb_S1d.js +292 -0
  75. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-BSDFfwdY.js → gitGraphDiagram-DS77QQ5N-BiEEtTo7.js} +3 -3
  76. package/dist-web/assets/{gitGraphDiagram-PVQCEYII-DMbTATyw.js → gitGraphDiagram-DS77QQ5N-Dp3Ar-hi.js} +3 -3
  77. package/dist-web/assets/{graph-BwjfAU3j.js → graph-CAUpWmoK.js} +1 -1
  78. package/dist-web/assets/{graph--OzhPTMs.js → graph-DOmOIIwC.js} +1 -1
  79. package/dist-web/assets/{index-W6VnSrkB.js → index-Ba1OvLjf.js} +2 -2
  80. package/dist-web/assets/{index-CkVgGDpx.js → index-CiPA8Kex.js} +4 -4
  81. package/dist-web/assets/{index-BzK4vJBu.js → index-DdEakFJM.js} +1 -1
  82. package/dist-web/assets/{index10-Czg_oF-W.js → index10-CNr4U-Nw.js} +1 -1
  83. package/dist-web/assets/{index11-BjzCZuCr.js → index11-Dto_yZNz.js} +1 -1
  84. package/dist-web/assets/{index5-DlVoNkCD.js → index5-B2PldaO2.js} +1 -1
  85. package/dist-web/assets/{index6-BxiXA2yo.js → index6-CBdZmmyx.js} +1 -1
  86. package/dist-web/assets/{index7-BPdza6d1.js → index7-Dz9oCsUF.js} +1 -1
  87. package/dist-web/assets/{index8-Q_XzGC1Z.js → index8-B6k25jtU.js} +2 -2
  88. package/dist-web/assets/{infoDiagram-5YYISTIA-2JF3XEdD.js → infoDiagram-6WML65LV-BSa2g04G.js} +1 -1
  89. package/dist-web/assets/{infoDiagram-5YYISTIA-UrQusrJq.js → infoDiagram-6WML65LV-D4ph2sIH.js} +1 -1
  90. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-7RVUL-vB.js → ishikawaDiagram-WSZJBQD7-DjKjbMm9.js} +5 -5
  91. package/dist-web/assets/{ishikawaDiagram-YF4QCWOH-C5OstRVV.js → ishikawaDiagram-WSZJBQD7-Hm36UOQe.js} +5 -5
  92. package/dist-web/assets/{journeyDiagram-JHISSGLW-B34fCMu9.js → journeyDiagram-NVQOT4AX-DttHDfPQ.js} +1 -1
  93. package/dist-web/assets/{journeyDiagram-JHISSGLW-yctdo4bX.js → journeyDiagram-NVQOT4AX-MvWWPNDV.js} +1 -1
  94. package/dist-web/assets/{kanban-definition-UN3LZRKU-BS4FBZsQ.js → kanban-definition-27J2QSJJ-C5gB-W0d.js} +7 -7
  95. package/dist-web/assets/{kanban-definition-UN3LZRKU-CxBCv27E.js → kanban-definition-27J2QSJJ-Cu-E_cXA.js} +5 -5
  96. package/dist-web/assets/layout-CvP6o9AK.js +1 -0
  97. package/dist-web/assets/layout-D-LzfAck.js +1 -0
  98. package/dist-web/assets/{linear-3mB6q2-g.js → linear-B3HWgQI2.js} +1 -1
  99. package/dist-web/assets/{linear-BKCnUo31.js → linear-BRGe4-d6.js} +1 -1
  100. package/dist-web/assets/map-CWKZqZjr.js +1 -0
  101. package/dist-web/assets/map-DxJ2ADlA.js +1 -0
  102. package/dist-web/assets/mermaid.core-D-9Sx1No.js +314 -0
  103. package/dist-web/assets/mermaidParser.worker-PTFfzpoB.js +318 -0
  104. package/dist-web/assets/{mindmap-definition-RKZ34NQL-BmJZpjh6.js → mindmap-definition-FAOFIHXS-C4vnms3i.js} +2 -2
  105. package/dist-web/assets/{mindmap-definition-RKZ34NQL-1mjWUcf6.js → mindmap-definition-FAOFIHXS-Cg_hoVIq.js} +1 -1
  106. package/dist-web/assets/pegDiagram-VL7TDLO6-B2fFEFUH.js +1 -0
  107. package/dist-web/assets/pegDiagram-VL7TDLO6-CSX9hitD.js +1 -0
  108. package/dist-web/assets/pieDiagram-7S7Q4E2Y-0L0mxahZ.js +39 -0
  109. package/dist-web/assets/pieDiagram-7S7Q4E2Y-C7T0Cmw1.js +39 -0
  110. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-BmT_qM09.js → quadrantDiagram-CIZ2JOQS-BBy7w4kD.js} +3 -3
  111. package/dist-web/assets/{quadrantDiagram-W4KKPZXB-C0kPuyNP.js → quadrantDiagram-CIZ2JOQS-U483z0er.js} +3 -3
  112. package/dist-web/assets/railroadDiagram-AXF67PYL-D80a2_DJ.js +1 -0
  113. package/dist-web/assets/railroadDiagram-AXF67PYL-DX8y0MzW.js +1 -0
  114. package/dist-web/assets/{requirementDiagram-4Y6WPE33-C0YP_Amt.js → requirementDiagram-LRYGKXZP-CeyHfq8t.js} +3 -3
  115. package/dist-web/assets/{requirementDiagram-4Y6WPE33-CZrxH1Y2.js → requirementDiagram-LRYGKXZP-DGD5J_4k.js} +3 -3
  116. package/dist-web/assets/sankeyDiagram-W5VNT64P-CCISkkrR.js +40 -0
  117. package/dist-web/assets/sankeyDiagram-W5VNT64P-CT5PdZz2.js +40 -0
  118. package/dist-web/assets/sequenceDiagram-SI44F4Z6-BeMzHWXI.js +162 -0
  119. package/dist-web/assets/sequenceDiagram-SI44F4Z6-jQfm2XS7.js +162 -0
  120. package/dist-web/assets/sizeCapture-X5ZJPWSS-BQsTdtrv.js +1 -0
  121. package/dist-web/assets/sizeCapture-X5ZJPWSS-lRZsmCoS.js +1 -0
  122. package/dist-web/assets/stateDiagram-OKZ733FA-ClCgTdUm.js +1 -0
  123. package/dist-web/assets/stateDiagram-OKZ733FA-Cv59z5YT.js +1 -0
  124. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-R8jTc--F.js +1 -0
  125. package/dist-web/assets/stateDiagram-v2-UEYNNEHI-fi_lrTAx.js +1 -0
  126. package/dist-web/assets/swimlanes-SLNWSIFB-BCdOUN05.js +2 -0
  127. package/dist-web/assets/swimlanes-SLNWSIFB-Cu5l7SuR.js +1 -0
  128. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-BUd_uYK3.js +8 -0
  129. package/dist-web/assets/swimlanesDiagram-ULZ7WXOC-CalrsgPK.js +8 -0
  130. package/dist-web/assets/{timeline-definition-PNZ67QCA-DsVZdrZa.js → timeline-definition-Z64GVDOM-CMjnh4bu.js} +4 -4
  131. package/dist-web/assets/{timeline-definition-PNZ67QCA-DnB6Usl0.js → timeline-definition-Z64GVDOM-DpWutSKa.js} +4 -4
  132. package/dist-web/assets/vennDiagram-T6HMQDX7-DKJW_8oU.js +34 -0
  133. package/dist-web/assets/vennDiagram-T6HMQDX7-DVC5JVsc.js +34 -0
  134. package/dist-web/assets/{vue.runtime.esm-bundler-pgHGheCW.js → vue.runtime.esm-bundler-BwwRtQwQ.js} +1 -1
  135. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-oBauTCEw.js → wardleyDiagram-T6FBY63Y-BK2mrq7L.js} +3 -3
  136. package/dist-web/assets/{wardleyDiagram-YWT4CUSO-DCiyDQNB.js → wardleyDiagram-T6FBY63Y-oUvgepFn.js} +3 -3
  137. package/dist-web/assets/xychartDiagram-ELKLHX3M-DI6n79q0.js +7 -0
  138. package/dist-web/assets/xychartDiagram-ELKLHX3M-DUJu9F7-.js +7 -0
  139. package/dist-web/index.html +1 -1
  140. package/dist-web/vis/index.html.gz +0 -0
  141. package/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  142. package/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  143. package/package.json +7 -2
  144. package/telegram-plugin/dist/bridge.mjs +6 -4
  145. package/telegram-plugin/dist/mcp-server.mjs +236 -71
  146. package/dist-web/assets/arc-4xPfymbf.js +0 -1
  147. package/dist-web/assets/arc-Doj0wRZ0.js +0 -1
  148. package/dist-web/assets/architectureDiagram-3BPJPVTR-BGih283a.js +0 -36
  149. package/dist-web/assets/architectureDiagram-3BPJPVTR-CQ09RrbH.js +0 -36
  150. package/dist-web/assets/blockDiagram-GPEHLZMM-3ShMf1gu.js +0 -132
  151. package/dist-web/assets/blockDiagram-GPEHLZMM-CAtDjkJt.js +0 -132
  152. package/dist-web/assets/channel-DNkUo9e6.js +0 -1
  153. package/dist-web/assets/channel-DcnUTIGB.js +0 -1
  154. package/dist-web/assets/chunk-AQP2D5EJ-FS8-f8lF.js +0 -231
  155. package/dist-web/assets/chunk-AQP2D5EJ-UKhb4V4r.js +0 -231
  156. package/dist-web/assets/classDiagram-4FO5ZUOK-B1ZO8EbE.js +0 -1
  157. package/dist-web/assets/classDiagram-4FO5ZUOK-xk6cM9Kq.js +0 -1
  158. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-B1ZO8EbE.js +0 -1
  159. package/dist-web/assets/classDiagram-v2-Q7XG4LA2-xk6cM9Kq.js +0 -1
  160. package/dist-web/assets/dagre-BM42HDAG-CmUO9qKN.js +0 -4
  161. package/dist-web/assets/dagre-BM42HDAG-DLMfLCoV.js +0 -4
  162. package/dist-web/assets/diagram-2AECGRRQ-DQTst0OH.js +0 -43
  163. package/dist-web/assets/diagram-2AECGRRQ-L74iLMqd.js +0 -43
  164. package/dist-web/assets/diagram-5GNKFQAL-BiBm7CJR.js +0 -10
  165. package/dist-web/assets/diagram-5GNKFQAL-DoE6q7H1.js +0 -10
  166. package/dist-web/assets/diagram-OG6HWLK6-BHCt1E0n.js +0 -24
  167. package/dist-web/assets/diagram-OG6HWLK6-DRyxjFMa.js +0 -24
  168. package/dist-web/assets/erDiagram-TEJ5UH35-BoDczjGG.js +0 -85
  169. package/dist-web/assets/erDiagram-TEJ5UH35-yd6SOv_7.js +0 -85
  170. package/dist-web/assets/flowDiagram-I6XJVG4X-DHoceI7r.js +0 -162
  171. package/dist-web/assets/flowDiagram-I6XJVG4X-DkYNQv0R.js +0 -162
  172. package/dist-web/assets/ganttDiagram-6RSMTGT7-Cg1TQBc0.js +0 -292
  173. package/dist-web/assets/ganttDiagram-6RSMTGT7-Z6klo7KK.js +0 -292
  174. package/dist-web/assets/layout-C1ojF0zw.js +0 -1
  175. package/dist-web/assets/layout-SsrduOYp.js +0 -1
  176. package/dist-web/assets/mermaid.core-D_lKT0dR.js +0 -309
  177. package/dist-web/assets/mermaidParser.worker-Dx4jPi9z.js +0 -313
  178. package/dist-web/assets/pieDiagram-4H26LBE5-BU41t2A_.js +0 -30
  179. package/dist-web/assets/pieDiagram-4H26LBE5-BkwDAvbt.js +0 -30
  180. package/dist-web/assets/sankeyDiagram-5OEKKPKP-De_o7hDr.js +0 -40
  181. package/dist-web/assets/sankeyDiagram-5OEKKPKP-Dvuj6bMA.js +0 -40
  182. package/dist-web/assets/sequenceDiagram-3UESZ5HK-DuCrgPyA.js +0 -162
  183. package/dist-web/assets/sequenceDiagram-3UESZ5HK-VAxffBe7.js +0 -162
  184. package/dist-web/assets/stateDiagram-AJRCARHV-CYLupxM7.js +0 -1
  185. package/dist-web/assets/stateDiagram-AJRCARHV-nDExQydZ.js +0 -1
  186. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BhEc7Thx.js +0 -1
  187. package/dist-web/assets/stateDiagram-v2-BHNVJYJU-BzwD_BIl.js +0 -1
  188. package/dist-web/assets/vennDiagram-CIIHVFJN-BBHQmCFf.js +0 -34
  189. package/dist-web/assets/vennDiagram-CIIHVFJN-Cfj-K9NW.js +0 -34
  190. package/dist-web/assets/wardley-L42UT6IY-BJFn8eDD.js +0 -173
  191. package/dist-web/assets/wardley-L42UT6IY-BSu8-4hg.js +0 -173
  192. package/dist-web/assets/xychartDiagram-2RQKCTM6-C2iZpl9I.js +0 -7
  193. package/dist-web/assets/xychartDiagram-2RQKCTM6-Db_VoDBV.js +0 -7
@@ -3,7 +3,6 @@
3
3
  const { randomUUID } = require('node:crypto');
4
4
  const fs = require('node:fs');
5
5
  const https = require('node:https');
6
- const os = require('node:os');
7
6
  const path = require('node:path');
8
7
  const { fork } = require('node:child_process');
9
8
  const { StringDecoder } = require('node:string_decoder');
@@ -24,6 +23,7 @@ const FALLBACK_MANIFEST_URL = 'https://chat.blun.ai/blun-code-version.json';
24
23
  const SNOOZE_MS = 7 * 24 * 60 * 60 * 1000;
25
24
  const REQUEST_TIMEOUT_MS = 2_500;
26
25
  const STATE_FILE = 'update-notice.json';
26
+ const UPDATE_DIRECTORY = 'updates';
27
27
  const UPDATE_KEY_ESCAPE_TIMEOUT_MS = 500;
28
28
  const UPDATE_SIGNAL_EXIT_CODES = Object.freeze({
29
29
  SIGHUP: 129,
@@ -135,7 +135,10 @@ function parseRegistryDocument(value) {
135
135
  const tags = readDataProperty(value, 'dist-tags');
136
136
  const latest = readDataProperty(tags, 'latest');
137
137
  if (!parseSemver(latest)) return undefined;
138
- return latest;
138
+ const parsed = { latest };
139
+ const next = readDataProperty(tags, 'next');
140
+ if (parseSemver(next)) parsed.next = next;
141
+ return Object.freeze(parsed);
139
142
  }
140
143
 
141
144
  function isBoundedText(value, maxBytes) {
@@ -203,24 +206,37 @@ function parseFallbackManifest(value) {
203
206
  });
204
207
  }
205
208
 
206
- function resolveEffectiveRelease(registryVersion, fallbackManifest) {
207
- const validRegistryVersion = parseSemver(registryVersion) ? registryVersion : undefined;
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;
208
215
  const validFallback = parseFallbackManifest(fallbackManifest);
209
- if (!validRegistryVersion && !validFallback) return undefined;
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
+ }
210
224
 
211
225
  let version;
212
- if (validRegistryVersion && validFallback) {
213
- version = compareSemver(validRegistryVersion, validFallback.latest) <= 0
214
- ? validRegistryVersion
226
+ if (validRegistryLatest && validFallback) {
227
+ version = compareSemver(validRegistryLatest, validFallback.latest) <= 0
228
+ ? validRegistryLatest
215
229
  : validFallback.latest;
216
230
  } else {
217
- version = validRegistryVersion || validFallback.latest;
231
+ version = validRegistryLatest || validFallback.latest;
218
232
  }
219
233
 
234
+ if (compareSemver(version, currentVersion) <= 0) return undefined;
235
+
220
236
  if (validFallback && compareSemver(validFallback.latest, version) === 0) {
221
- return { version, notesUrl: validFallback.notesUrl };
237
+ return { channel: 'stable', version, notesUrl: validFallback.notesUrl };
222
238
  }
223
- return { version };
239
+ return { channel: 'stable', version };
224
240
  }
225
241
 
226
242
  function requestTrustedJson(url, options = {}) {
@@ -319,6 +335,8 @@ function statePath(blunDir) {
319
335
  function readSnoozeState(blunDir, now = Date.now()) {
320
336
  try {
321
337
  const filePath = statePath(blunDir);
338
+ if (!fs.existsSync(filePath)) return false;
339
+ securePrivateFile(filePath);
322
340
  const stat = fs.lstatSync(filePath);
323
341
  if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1_024) return false;
324
342
  const record = exactDataRecord(JSON.parse(fs.readFileSync(filePath, 'utf8')), [
@@ -672,10 +690,50 @@ function createInstallEnvironment(sourceEnv, installDirectory, npmConfigPath) {
672
690
  return result;
673
691
  }
674
692
 
675
- function createPrivateInstallDirectory(tempRoot = os.tmpdir()) {
676
- const directory = fs.mkdtempSync(path.join(path.resolve(tempRoot), 'blun-update-'));
677
- ensurePrivateDirectory(directory);
678
- return directory;
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
+ }
679
737
  }
680
738
 
681
739
  function verifyInstalledPackageVersion(packageRoot, version) {
@@ -764,7 +822,6 @@ function preparePinnedInstaller(version, options = {}) {
764
822
  finishDisconnected,
765
823
  options.disconnectTimeoutMs || 1_000,
766
824
  );
767
- disconnectTimer.unref?.();
768
825
  };
769
826
  const sendControl = (type) => {
770
827
  if (selectedAction) return closePromise;
@@ -787,7 +844,10 @@ function preparePinnedInstaller(version, options = {}) {
787
844
  };
788
845
  let prepareTimeout;
789
846
  try {
790
- installDirectory = createPrivateInstallDirectory(options.tempRoot);
847
+ installDirectory = createPrivateInstallDirectory(
848
+ resolveInstallTempRoot(options),
849
+ options.blunDir,
850
+ );
791
851
  npmConfigPath = path.join(installDirectory, 'npmrc');
792
852
  writePrivateFile(npmConfigPath, '');
793
853
  invocation = createInstallInvocation(version, { ...options, npmConfigPath });
@@ -923,7 +983,39 @@ async function probeInstallLease(options, packageRoot) {
923
983
  return 'clear';
924
984
  }
925
985
 
926
- async function runUpdateNotice(options) {
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) {
927
1019
  const {
928
1020
  currentVersion,
929
1021
  argv,
@@ -933,15 +1025,17 @@ async function runUpdateNotice(options) {
933
1025
  stderr,
934
1026
  blunDir,
935
1027
  } = options;
936
- if (!isInteractiveUpdateStart({ argv, env, stdin, stdout })) {
1028
+ if (!explicitUpdate && !isInteractiveUpdateStart({ argv, env, stdin, stdout })) {
937
1029
  return { kind: 'continue', reason: 'not_interactive' };
938
1030
  }
939
1031
  if (!parseSemver(currentVersion)) {
940
- return { kind: 'continue', reason: 'invalid_current_version' };
1032
+ return explicitUpdate
1033
+ ? explicitFailure(stderr, 'invalid_current_version')
1034
+ : { kind: 'continue', reason: 'invalid_current_version' };
941
1035
  }
942
1036
 
943
1037
  const now = (options.now || Date.now)();
944
- if (readSnoozeState(blunDir, now)) {
1038
+ if (!explicitUpdate && readSnoozeState(blunDir, now)) {
945
1039
  return { kind: 'continue', reason: 'snoozed' };
946
1040
  }
947
1041
 
@@ -952,12 +1046,20 @@ async function runUpdateNotice(options) {
952
1046
  try {
953
1047
  leaseResult = await (options.acquireLease || tryAcquireUpdateLease)({ packageRoot });
954
1048
  } catch {
955
- return { kind: 'continue', reason: 'lease_unavailable' };
1049
+ return explicitUpdate
1050
+ ? explicitFailure(stderr, 'lease_unavailable')
1051
+ : { kind: 'continue', reason: 'lease_unavailable' };
956
1052
  }
957
1053
  } else {
958
1054
  leaseResult = { acquired: true, lease: options.noticeLease };
959
1055
  }
960
1056
  if (!leaseResult?.acquired) {
1057
+ if (explicitUpdate) {
1058
+ return explicitFailure(
1059
+ stderr,
1060
+ leaseResult?.reason === 'busy' ? 'update_in_progress' : 'lease_unavailable',
1061
+ );
1062
+ }
961
1063
  return leaseResult?.reason === 'busy'
962
1064
  ? { kind: 'update_in_progress' }
963
1065
  : { kind: 'continue', reason: 'lease_unavailable' };
@@ -966,58 +1068,90 @@ async function runUpdateNotice(options) {
966
1068
  let installerSession;
967
1069
 
968
1070
  try {
969
- if (readSnoozeState(blunDir, (options.now || Date.now)())) {
1071
+ if (!explicitUpdate && readSnoozeState(blunDir, (options.now || Date.now)())) {
970
1072
  return { kind: 'continue', reason: 'snoozed' };
971
1073
  }
972
1074
  const initialInstallLease = await probeInstallLease(options, packageRoot);
973
- if (initialInstallLease === 'busy') return { kind: 'update_in_progress' };
1075
+ if (initialInstallLease === 'busy') {
1076
+ return explicitUpdate
1077
+ ? explicitFailure(stderr, 'update_in_progress')
1078
+ : { kind: 'update_in_progress' };
1079
+ }
974
1080
  if (initialInstallLease !== 'clear') {
975
- return { kind: 'continue', reason: 'lease_unavailable' };
1081
+ return explicitUpdate
1082
+ ? explicitFailure(stderr, 'lease_unavailable')
1083
+ : { kind: 'continue', reason: 'lease_unavailable' };
976
1084
  }
977
1085
  let sources;
978
1086
  try {
979
1087
  sources = await (options.loadReleaseSources || loadReleaseSources)();
980
1088
  } catch {
981
- return { kind: 'continue', reason: 'unavailable' };
1089
+ return explicitUpdate
1090
+ ? explicitNoTarget(stdout, 'unavailable')
1091
+ : { kind: 'continue', reason: 'unavailable' };
982
1092
  }
983
- const registryVersion = parseRegistryDocument(sources?.registryDocument);
1093
+ const registryTags = parseRegistryDocument(sources?.registryDocument);
984
1094
  const fallbackManifest = parseFallbackManifest(sources?.fallbackDocument);
985
- const release = resolveEffectiveRelease(registryVersion, fallbackManifest);
986
- if (!release) return { kind: 'continue', reason: 'unavailable' };
987
- if (compareSemver(release.version, currentVersion) <= 0) {
988
- return { kind: 'continue', reason: 'current' };
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
+ }
989
1108
  }
990
1109
  try {
991
1110
  lease.assertOwned();
992
1111
  } catch {
993
- return { kind: 'update_in_progress' };
1112
+ return explicitUpdate
1113
+ ? explicitFailure(stderr, 'update_in_progress')
1114
+ : { kind: 'update_in_progress' };
994
1115
  }
995
1116
  const prePromptInstallLease = await probeInstallLease(options, packageRoot);
996
- if (prePromptInstallLease === 'busy') return { kind: 'update_in_progress' };
1117
+ if (prePromptInstallLease === 'busy') {
1118
+ return explicitUpdate
1119
+ ? explicitFailure(stderr, 'update_in_progress')
1120
+ : { kind: 'update_in_progress' };
1121
+ }
997
1122
  if (prePromptInstallLease !== 'clear') {
998
- return { kind: 'continue', reason: 'lease_unavailable' };
1123
+ return explicitUpdate
1124
+ ? explicitFailure(stderr, 'lease_unavailable')
1125
+ : { kind: 'continue', reason: 'lease_unavailable' };
999
1126
  }
1000
1127
  if (!options.installVersion) {
1001
1128
  installerSession = await (options.prepareInstaller || preparePinnedInstaller)(
1002
1129
  release.version,
1003
- { packageRoot },
1130
+ { blunDir, packageRoot },
1004
1131
  );
1005
1132
  if (!installerSession?.ready) {
1133
+ if (explicitUpdate) {
1134
+ return explicitFailure(stderr, 'installer_unavailable');
1135
+ }
1006
1136
  return installerSession?.reason === 'failed'
1007
1137
  ? { kind: 'continue', reason: 'installer_unavailable' }
1008
1138
  : { kind: 'update_in_progress' };
1009
1139
  }
1010
1140
  }
1011
1141
  let action;
1012
- try {
1013
- action = await (options.promptAction || promptUpdateAction)({
1014
- currentVersion,
1015
- release,
1016
- input: stdin,
1017
- output: stdout,
1018
- });
1019
- } catch {
1020
- return { kind: 'continue', reason: 'prompt_failed' };
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
+ }
1021
1155
  }
1022
1156
  if (action !== 'install') {
1023
1157
  if (installerSession?.ready) await installerSession.cancel();
@@ -1032,7 +1166,9 @@ async function runUpdateNotice(options) {
1032
1166
  try {
1033
1167
  lease.assertOwned();
1034
1168
  } catch {
1035
- return { kind: 'update_in_progress' };
1169
+ return explicitUpdate
1170
+ ? explicitFailure(stderr, 'update_in_progress')
1171
+ : { kind: 'update_in_progress' };
1036
1172
  }
1037
1173
  let installResult;
1038
1174
  try {
@@ -1045,7 +1181,9 @@ async function runUpdateNotice(options) {
1045
1181
  if (installResult?.leaseBusy === true
1046
1182
  || installResult?.leaseUnavailable === true
1047
1183
  || installResult?.unknownState === true) {
1048
- return { kind: 'update_in_progress' };
1184
+ return explicitUpdate
1185
+ ? explicitFailure(stderr, 'update_in_progress')
1186
+ : { kind: 'update_in_progress' };
1049
1187
  }
1050
1188
  if (installResult?.code === 0 && installResult?.verified === true) {
1051
1189
  stdout.write('Update erfolgreich installiert. Starte BLUN Code neu, um die neue Version zu verwenden.\n');
@@ -1053,9 +1191,13 @@ async function runUpdateNotice(options) {
1053
1191
  }
1054
1192
 
1055
1193
  if (Number.isInteger(installResult?.code) && installResult.code !== 0) {
1194
+ if (explicitUpdate) {
1195
+ return explicitFailure(stderr, 'install_failed', installResult.code);
1196
+ }
1056
1197
  stderr.write(`Update fehlgeschlagen (Code ${installResult.code}). Die vorhandene Version wird gestartet.\n`);
1057
1198
  return { kind: 'continue', reason: 'install_failed', exitCode: installResult.code };
1058
1199
  }
1200
+ if (explicitUpdate) return explicitFailure(stderr, 'verification_failed');
1059
1201
  stderr.write('Update konnte nicht verifiziert werden. Starte BLUN Code neu.\n');
1060
1202
  return { kind: 'update_in_progress' };
1061
1203
  } finally {
@@ -1072,6 +1214,14 @@ async function runUpdateNotice(options) {
1072
1214
  }
1073
1215
  }
1074
1216
 
1217
+ function runExplicitUpdate(options) {
1218
+ return runUpdateFlow(options, true);
1219
+ }
1220
+
1221
+ function runUpdateNotice(options) {
1222
+ return runUpdateFlow(options, false);
1223
+ }
1224
+
1075
1225
  module.exports = {
1076
1226
  FALLBACK_MANIFEST_URL,
1077
1227
  PACKAGE_NAME,
@@ -1089,6 +1239,7 @@ module.exports = {
1089
1239
  readSnoozeState,
1090
1240
  requestTrustedJson,
1091
1241
  resolveEffectiveRelease,
1242
+ runExplicitUpdate,
1092
1243
  runUpdateNotice,
1093
1244
  writeSnoozeState,
1094
1245
  };