pisper 0.5.43-linux-x64.0 → 0.5.43

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 (318) hide show
  1. package/README.en.md +67 -0
  2. package/README.md +53 -53
  3. package/bin/pisper.mjs +48 -0
  4. package/lib/install.mjs +392 -0
  5. package/lib/npm-platform.mjs +41 -0
  6. package/lib/npm-update.mjs +165 -0
  7. package/lib/platform.mjs +43 -0
  8. package/lib/postinstall.mjs +3 -0
  9. package/package.json +36 -14
  10. package/updater.pubkey +1 -0
  11. package/web/.vite/manifest.json +2609 -0
  12. package/web/assets/AnimatedList-_pbK4tS3.js +1 -0
  13. package/web/assets/AppOverlays-DLzwC2I0.js +1 -0
  14. package/web/assets/AppSelect-dnApQF-_.js +1 -0
  15. package/web/assets/AppShortcuts-D66c2bOM.js +1 -0
  16. package/web/assets/AssetsPage-CVhMy0Xs.js +1 -0
  17. package/web/assets/ChannelsPage-BLb4OGAr.js +1 -0
  18. package/web/assets/ChatDockView-r-A5dR7e.js +2 -0
  19. package/web/assets/ChatHistoryPage-DzRZRgEx.js +1 -0
  20. package/web/assets/ChatPage-D-it_7gs.js +4 -0
  21. package/web/assets/ClickSpark-BhxL8WOQ.js +1 -0
  22. package/web/assets/ConfigPage-CrQzN_9b.js +1 -0
  23. package/web/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  24. package/web/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  25. package/web/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  26. package/web/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  27. package/web/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  28. package/web/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  29. package/web/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  30. package/web/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  31. package/web/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  32. package/web/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  33. package/web/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  34. package/web/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  35. package/web/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  36. package/web/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  37. package/web/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  38. package/web/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  39. package/web/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  40. package/web/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  41. package/web/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  42. package/web/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  43. package/web/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  44. package/web/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  45. package/web/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  46. package/web/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  47. package/web/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  48. package/web/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  49. package/web/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  50. package/web/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  51. package/web/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  52. package/web/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  53. package/web/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  54. package/web/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  55. package/web/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  56. package/web/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  57. package/web/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  58. package/web/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  59. package/web/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  60. package/web/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  61. package/web/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  62. package/web/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  63. package/web/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  64. package/web/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  65. package/web/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  66. package/web/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  67. package/web/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  68. package/web/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  69. package/web/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  70. package/web/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  71. package/web/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  72. package/web/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  73. package/web/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  74. package/web/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  75. package/web/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  76. package/web/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  77. package/web/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  78. package/web/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  79. package/web/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  80. package/web/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  81. package/web/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  82. package/web/assets/MarkdownMessage-CkBtRWR5.js +2 -0
  83. package/web/assets/MemoryPage-D3vu8LKz.js +1 -0
  84. package/web/assets/MobileViewportStabilizer-CYh5obIv.js +1 -0
  85. package/web/assets/PageHeader-DyMV-V9T.js +1 -0
  86. package/web/assets/PluginsPage-C9-941d6.js +1 -0
  87. package/web/assets/PreviewPages-CXzJvTvB.js +1 -0
  88. package/web/assets/SchedulesPage-CxbsUOo-.js +1 -0
  89. package/web/assets/ShinyText-fuaKxKqJ.js +1 -0
  90. package/web/assets/SkillsPage-CZxRxnFi.js +1 -0
  91. package/web/assets/StarOrbit-BlI6MhVr.js +1 -0
  92. package/web/assets/TerminalPanel-BrP-ENHg.css +1 -0
  93. package/web/assets/TerminalPanel-C8-Sxh60.js +18 -0
  94. package/web/assets/Threads-DPFx-jxG.js +1 -0
  95. package/web/assets/WelcomeEffects-Daf0-AuD.js +1 -0
  96. package/web/assets/WorkflowsPage-eg8LnhvF.js +1 -0
  97. package/web/assets/WorkspacePicker-BcCUtCIE.js +1 -0
  98. package/web/assets/abort-signal-f4JsiYKX.js +1 -0
  99. package/web/assets/alert-B7D8joCd.js +1 -0
  100. package/web/assets/andromeeda-vGVdxbeo.js +1 -0
  101. package/web/assets/angular-html-17rlCfBS.js +1 -0
  102. package/web/assets/angular-ts-it3MaXWH.js +1 -0
  103. package/web/assets/api-B6CluO7V.js +3 -0
  104. package/web/assets/arrow-right-KWvgbo3p.js +1 -0
  105. package/web/assets/astro-BEVDzCov.js +1 -0
  106. package/web/assets/aurora-x-CDeNXAV0.js +1 -0
  107. package/web/assets/ayu-dark-DluEY0Gj.js +1 -0
  108. package/web/assets/ayu-light-C3h-C4tm.js +1 -0
  109. package/web/assets/ayu-mirage-Bqwy1Gya.js +1 -0
  110. package/web/assets/blade-B3yUZIOx.js +1 -0
  111. package/web/assets/brand-DIEc3fK8.js +1 -0
  112. package/web/assets/button-XhIEgIsg.js +1 -0
  113. package/web/assets/c-aGSZMVdM.js +1 -0
  114. package/web/assets/catppuccin-frappe-C9Q5zVZY.js +1 -0
  115. package/web/assets/catppuccin-latte-CtsyrtPq.js +1 -0
  116. package/web/assets/catppuccin-macchiato-R8nAf1vR.js +1 -0
  117. package/web/assets/catppuccin-mocha-DjuaAJKi.js +1 -0
  118. package/web/assets/chat-api-0EuN5Xt-.js +1 -0
  119. package/web/assets/check-jIXqkGKr.js +1 -0
  120. package/web/assets/chevron-down-DT6AXwTP.js +1 -0
  121. package/web/assets/circle-dot-rl11gaty.js +1 -0
  122. package/web/assets/client-store-BSV7t02b.js +1 -0
  123. package/web/assets/code-xml-Z4K2ea1N.js +1 -0
  124. package/web/assets/coffee-ouOQ86EC.js +1 -0
  125. package/web/assets/collapsible-BkGRCQoD.js +1 -0
  126. package/web/assets/config-search-ZUe1JGjE.js +1 -0
  127. package/web/assets/copy-DS-8Hh_R.js +1 -0
  128. package/web/assets/cpp-Bm3vm43L.js +1 -0
  129. package/web/assets/css-CWcS1xXm.js +1 -0
  130. package/web/assets/csv-Dx-8-gkx.js +1 -0
  131. package/web/assets/dark-plus-Cs2F2srj.js +1 -0
  132. package/web/assets/dist-CTIxUW4c.js +1 -0
  133. package/web/assets/dist-QYO1_009.js +1 -0
  134. package/web/assets/dracula-BHWKrbxM.js +1 -0
  135. package/web/assets/dracula-soft-5eyTD99u.js +1 -0
  136. package/web/assets/earth-DR_clkZ9.js +1 -0
  137. package/web/assets/embedded-D2rqyswH.js +269 -0
  138. package/web/assets/es2015-hBiYtHUi.js +41 -0
  139. package/web/assets/everforest-dark-sB-x3p7T.js +1 -0
  140. package/web/assets/everforest-light-Df2xbC6M.js +1 -0
  141. package/web/assets/field-DWDpdE1D.js +1 -0
  142. package/web/assets/file-C8GNXmhJ.js +1 -0
  143. package/web/assets/file-code-corner-BKkXAMHR.js +1 -0
  144. package/web/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
  145. package/web/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
  146. package/web/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
  147. package/web/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
  148. package/web/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
  149. package/web/assets/github-dark-C-LZuMrd.js +1 -0
  150. package/web/assets/github-dark-default-DXG-b-1a.js +1 -0
  151. package/web/assets/github-dark-dimmed-Bx1FflLF.js +1 -0
  152. package/web/assets/github-dark-high-contrast-B_tTalzw.js +1 -0
  153. package/web/assets/github-light-EUqPIrTm.js +1 -0
  154. package/web/assets/github-light-default-BXViO-2h.js +1 -0
  155. package/web/assets/github-light-high-contrast-B68TUdTA.js +1 -0
  156. package/web/assets/glsl-TOBAB6bO.js +1 -0
  157. package/web/assets/graphql-BEmIBNve.js +1 -0
  158. package/web/assets/gruvbox-dark-hard-C820rvS2.js +1 -0
  159. package/web/assets/gruvbox-dark-medium-BPjhmG05.js +1 -0
  160. package/web/assets/gruvbox-dark-soft-MrdJrrXF.js +1 -0
  161. package/web/assets/gruvbox-light-hard-BC_s9l72.js +1 -0
  162. package/web/assets/gruvbox-light-medium-BAWPOn9u.js +1 -0
  163. package/web/assets/gruvbox-light-soft-BSMLrYjP.js +1 -0
  164. package/web/assets/haml-CDWtFtU9.js +1 -0
  165. package/web/assets/handlebars-BNtjo3pL.js +1 -0
  166. package/web/assets/horizon-CE9ld1lL.js +1 -0
  167. package/web/assets/horizon-bright-DSNQnXHK.js +1 -0
  168. package/web/assets/houston-CsvMBhTu.js +1 -0
  169. package/web/assets/html-BVyvp26C.js +1 -0
  170. package/web/assets/html-derivative-BseLpURQ.js +1 -0
  171. package/web/assets/http-CkCfSMV9.js +1 -0
  172. package/web/assets/hurl-syYMt6Rn.js +1 -0
  173. package/web/assets/image-Dh7-wI1d.js +1 -0
  174. package/web/assets/imba-DsUTQ-LC.js +1 -0
  175. package/web/assets/index-CBJH-887.js +40 -0
  176. package/web/assets/index-CcaHNzVW.css +2 -0
  177. package/web/assets/input-D1QFzNMx.js +1 -0
  178. package/web/assets/java-duG_UTKe.js +1 -0
  179. package/web/assets/javascript-DWVbOe4X.js +1 -0
  180. package/web/assets/jinja-Boj4niAz.js +1 -0
  181. package/web/assets/jison-CHwnC1Pv.js +1 -0
  182. package/web/assets/json-qhed-kSA.js +1 -0
  183. package/web/assets/json5-BR5RXkoi.js +1 -0
  184. package/web/assets/jsonc-CYpm1nAK.js +1 -0
  185. package/web/assets/jsonl-CmCQp5Yx.js +1 -0
  186. package/web/assets/jsx-fcCEM_-L.js +1 -0
  187. package/web/assets/julia-VoF7UKfw.js +1 -0
  188. package/web/assets/kanagawa-dragon-Bozd7klA.js +1 -0
  189. package/web/assets/kanagawa-lotus-BmuOG9ZW.js +1 -0
  190. package/web/assets/kanagawa-wave-BML5mF2J.js +1 -0
  191. package/web/assets/laserwave-C_8bwKvT.js +1 -0
  192. package/web/assets/less-DVTAwKKz.js +1 -0
  193. package/web/assets/light-plus-DVQuIRkW.js +1 -0
  194. package/web/assets/link-2-CaZP6GWi.js +1 -0
  195. package/web/assets/loader-circle-72TYCcVQ.js +1 -0
  196. package/web/assets/markdown-BYOwaDjH.js +1 -0
  197. package/web/assets/marko-Cupn1xhw.js +1 -0
  198. package/web/assets/material-theme-Bm3Qr25_.js +1 -0
  199. package/web/assets/material-theme-darker-2IIEA8gg.js +1 -0
  200. package/web/assets/material-theme-lighter-uhdI0v04.js +1 -0
  201. package/web/assets/material-theme-ocean-CHQ94UKr.js +1 -0
  202. package/web/assets/material-theme-palenight-B5W6OYN7.js +1 -0
  203. package/web/assets/mdc-4FfK5iWR.js +1 -0
  204. package/web/assets/mdx-DQZ5AkYe.js +1 -0
  205. package/web/assets/message-circle-Bc_EzZop.js +1 -0
  206. package/web/assets/min-dark-BSWPekZh.js +1 -0
  207. package/web/assets/min-light-DDpmG2fV.js +1 -0
  208. package/web/assets/mobile-remote-fallback-JvG4VcPg.js +1 -0
  209. package/web/assets/mobile-runtime-recovery-tbTyacip.js +1 -0
  210. package/web/assets/monokai-B_bV9PQ9.js +1 -0
  211. package/web/assets/night-owl-DhmEMT88.js +1 -0
  212. package/web/assets/night-owl-light-eJ-hLW7d.js +1 -0
  213. package/web/assets/nord-Cb4Vim4T.js +1 -0
  214. package/web/assets/one-dark-pro-CLwyXe_n.js +1 -0
  215. package/web/assets/one-light-D7Lr4KcI.js +1 -0
  216. package/web/assets/panel-left-CVuoi3zo.js +1 -0
  217. package/web/assets/panel-top-CA2GX1Rj.js +1 -0
  218. package/web/assets/paperclip-BMRj9kRG.js +1 -0
  219. package/web/assets/pencil-CxA1IK0x.js +1 -0
  220. package/web/assets/php-CUREQQ7f.js +1 -0
  221. package/web/assets/pick-system-directory-BnIFt85A.js +1 -0
  222. package/web/assets/plastic-DQwYfKfQ.js +1 -0
  223. package/web/assets/play-N6mg4pFl.js +1 -0
  224. package/web/assets/poimandres-DRFjx7u4.js +1 -0
  225. package/web/assets/postcss-BXeXVLqQ.js +1 -0
  226. package/web/assets/progress-yDx4w8vZ.js +6 -0
  227. package/web/assets/pug-CQyGKZpv.js +1 -0
  228. package/web/assets/python-gzcpVVnB.js +1 -0
  229. package/web/assets/r-C5FwQflr.js +1 -0
  230. package/web/assets/react-bits-DQli9s7O.css +1 -0
  231. package/web/assets/red-DX1BQOs8.js +1 -0
  232. package/web/assets/regexp--aR2_iz7.js +1 -0
  233. package/web/assets/rolldown-runtime-B0Z9INg1.js +1 -0
  234. package/web/assets/rose-pine-aMsaMD1D.js +1 -0
  235. package/web/assets/rose-pine-dawn-8PwUyIlP.js +1 -0
  236. package/web/assets/rose-pine-moon-DO-qXg-I.js +1 -0
  237. package/web/assets/sass-DXrisJhu.js +1 -0
  238. package/web/assets/save-CVL5N6eP.js +1 -0
  239. package/web/assets/scroll-area-DvbSijRt.js +1 -0
  240. package/web/assets/scss-Davl4E3T.js +1 -0
  241. package/web/assets/send-DcLH_sg0.js +1 -0
  242. package/web/assets/separator-h84bQyva.js +1 -0
  243. package/web/assets/shellscript-CLZ0U2zV.js +1 -0
  244. package/web/assets/shield-check-BQHFfxVy.js +1 -0
  245. package/web/assets/shortcuts-BIzphxhz.js +1 -0
  246. package/web/assets/slack-dark-DnToyrRv.js +1 -0
  247. package/web/assets/slack-ochin-B2OO5cIa.js +1 -0
  248. package/web/assets/smithy-Dgaz7aur.js +1 -0
  249. package/web/assets/snazzy-light-4G7pJPwS.js +1 -0
  250. package/web/assets/solarized-dark-UdsmMDCL.js +1 -0
  251. package/web/assets/solarized-light-C1IUL_tW.js +1 -0
  252. package/web/assets/speech-session-C_LNwJvG.js +3 -0
  253. package/web/assets/speech-stream-text-Bf0UhZti.js +2 -0
  254. package/web/assets/speech-text-Js_tr4qo.js +1 -0
  255. package/web/assets/sql-b92rrcVl.js +1 -0
  256. package/web/assets/square-BZ3Bi3O-.js +1 -0
  257. package/web/assets/square-terminal-DpCa0gzM.js +1 -0
  258. package/web/assets/storage-BE5DCCG3.js +1 -0
  259. package/web/assets/stylus-B6D30XZt.js +1 -0
  260. package/web/assets/svelte-BfstjgUc.js +1 -0
  261. package/web/assets/synthwave-84-nFMaYfgc.js +1 -0
  262. package/web/assets/tag-Csd134FL.js +1 -0
  263. package/web/assets/tokyo-night-oM2G3aXe.js +1 -0
  264. package/web/assets/tool-labels-BJhLig5u.js +1 -0
  265. package/web/assets/tooltip-DDjQDSyD.js +1 -0
  266. package/web/assets/trash-2-mhzzyC6i.js +1 -0
  267. package/web/assets/ts-tags-Cckpt1jI.js +1 -0
  268. package/web/assets/tsx-JMDX3aQ7.js +1 -0
  269. package/web/assets/typescript-BAz-bF8J.js +1 -0
  270. package/web/assets/use-animation-visibility-C-GENY2Z.js +1 -0
  271. package/web/assets/use-i18n-DLGAytLG.js +1 -0
  272. package/web/assets/use-mobile-HqNwaleh.js +1 -0
  273. package/web/assets/usePagePrimaryAction-Bw0OFTDZ.js +1 -0
  274. package/web/assets/utils-C8uzG5AZ.js +1 -0
  275. package/web/assets/vendor-dockview-D5adAaCg.css +1 -0
  276. package/web/assets/vendor-dockview-yY5mBM3U.js +1 -0
  277. package/web/assets/vendor-markdown-K9KdiImV.js +130 -0
  278. package/web/assets/vendor-markdown-plugins-DEcVZfaU.css +1 -0
  279. package/web/assets/vendor-markdown-plugins-Wv1dLaAO.js +263 -0
  280. package/web/assets/vendor-motion-XxgxfZSY.js +9 -0
  281. package/web/assets/vendor-react-CHuvPdJE.js +9 -0
  282. package/web/assets/vendor-router-Bw2aAdMs.js +4 -0
  283. package/web/assets/vendor-shiki-runtime-CxE5QolQ.js +153 -0
  284. package/web/assets/vendor-state-DE1O_s6m.js +1 -0
  285. package/web/assets/vendor-ui-DvrYggeS.js +1 -0
  286. package/web/assets/vendor-xyflow-CnjXtcyK.js +7 -0
  287. package/web/assets/vendor-xyflow-DLioOiRN.css +1 -0
  288. package/web/assets/vesper-DdrHHSXu.js +1 -0
  289. package/web/assets/vitesse-black-fwtXNY1n.js +1 -0
  290. package/web/assets/vitesse-dark-BZCL-v6S.js +1 -0
  291. package/web/assets/vitesse-light-VbXTXTou.js +1 -0
  292. package/web/assets/vue-3H7P6ncC.js +1 -0
  293. package/web/assets/vue-html-DZGW9MGR.js +1 -0
  294. package/web/assets/vue-vine-BECt67gq.js +1 -0
  295. package/web/assets/wasm-BnjxR4X6.js +1 -0
  296. package/web/assets/wasm-ByWQv1Qj.js +1 -0
  297. package/web/assets/web-preview-panel-BtR5My_9.js +556 -0
  298. package/web/assets/welcome-brand-BSU1m0Qt.js +1 -0
  299. package/web/assets/wgsl-BsKzXJz4.js +1 -0
  300. package/web/assets/wit-DdvCle-K.js +1 -0
  301. package/web/assets/wrench-BqeVhocX.js +1 -0
  302. package/web/assets/x-bw26XDZM.js +1 -0
  303. package/web/assets/xml-CNfvW5JP.js +1 -0
  304. package/web/assets/yaml-rwi0_p6S.js +1 -0
  305. package/web/assets/zap-CFsp4Y1u.js +1 -0
  306. package/web/favicon.svg +25 -0
  307. package/web/icons.svg +24 -0
  308. package/web/index.html +83 -0
  309. package/web/memory-galaxy-background.webp +0 -0
  310. package/web/mobile-startup.html +322 -0
  311. package/web/notification-sw.js +13 -0
  312. package/web/tauri-pet.css +117 -0
  313. package/web/tauri-pet.html +16 -0
  314. package/web/tauri-pet.js +149 -0
  315. package/components/runtime/Pisper_Runtime_Node_0.5.41_linux_x86_64.tar.gz +0 -0
  316. package/components/runtime/Pisper_Runtime_Node_0.5.41_linux_x86_64.tar.gz.sig +0 -1
  317. package/components/tui/Pisper_TUI_Component_0.5.24_linux_x86_64.tar.gz +0 -0
  318. package/components/tui/Pisper_TUI_Component_0.5.24_linux_x86_64.tar.gz.sig +0 -1
package/README.en.md ADDED
@@ -0,0 +1,67 @@
1
+ # Pisper TUI Command Reference
2
+
3
+ [Project home](https://ling-kong-ran.github.io/pisper/) · [GitHub repository](https://github.com/ling-kong-ran/pisper) · [中文](./README.md)
4
+
5
+ Argument notation: `<argument>` is required; `[argument]` is optional.
6
+
7
+ ## CLI Commands
8
+
9
+ | Command | Explanation |
10
+ | :--- | :--- |
11
+ | `pisper` | Start the TUI in the current directory with a new empty conversation. History is not resumed automatically. |
12
+ | `pisper --cwd <directory>` | Start the TUI with a new empty conversation in the specified workspace. |
13
+ | `pisper resume` | Open the conversation picker across all workspaces. If no history exists, report it and exit. |
14
+ | `pisper resume --cwd <directory>` | Open the conversation picker from a specified launch directory. A resumed conversation keeps its own saved working directory. |
15
+ | `pisper doctor` | Diagnose the TUI, Runtime connection, and capability catalogs (conversations/tools/skills), then print a summary and exit. |
16
+ | `pisper doctor --cwd <directory>` | Run diagnostics with the specified launch workspace. |
17
+ | `pisper web` | Install (if missing) or use the Web frontend and open its authenticated local settings page in the default browser. The page is served by the Runtime started with this command and stops working once the TUI exits. |
18
+ | `pisper web --cwd <directory>` | Start the Runtime for a specified directory and open the Web settings page. |
19
+ | `pisper help [COMMAND]` | Show global help. `pisper help web` shows help for the Web subcommand. |
20
+ | `pisper -h` / `pisper --help` | Show command help without starting the Runtime. |
21
+ | `pisper -V` / `pisper --version` | Print the installed TUI version. |
22
+ | `pisper update --check` | Check an npm-installed Pisper for updates without installing them. |
23
+ | `pisper update` | Update an npm-installed Pisper through the active npm registry and verify the components again. |
24
+
25
+ ## Environment Variables
26
+
27
+ | Variable | Description |
28
+ | :--- | :--- |
29
+ | `PISPER_TUI_MOUSE=1` | Enable mouse wheel scrolling in the transcript; mouse capture replaces the terminal's native text selection. |
30
+ | `PISPER_TUI_REDUCED_MOTION=1` | Disable the typewriter reveal and status animations (streaming text appears immediately); useful on low-end terminals and SSH sessions. |
31
+
32
+ ## Slash Commands
33
+
34
+ | Command | Explanation |
35
+ | :--- | :--- |
36
+ | `/init` | Analyze the current project and create or improve `AGENTS.md` at the project root. Existing useful guidance is preserved, and no other project files are changed. |
37
+ | `/new` | Create an empty conversation in the TUI launch directory. Unavailable during an Agent run. |
38
+ | `/sessions` | Open the conversation picker across all directories. Switching is unavailable during an Agent run. |
39
+ | `/dir <directory>` | Change the active conversation's working directory. Relative paths resolve from its current directory. Unavailable during an Agent run. |
40
+ | `/changes` | Open the Git or SVN changes view. In that view, `R` refreshes, `C` commits, `P` pushes Git, and pressing `V` twice reverts. SVN has no Push operation. |
41
+ | `/changes commit <message>` | Commit the current Git or SVN changes with an explicit message. |
42
+ | `/chat` | Return to the Chat message stream from another view. |
43
+ | `/model` | Open the model picker and switch the active conversation model. Only configured Provider models are listed. Unavailable during an Agent run. |
44
+ | `/thinking` | Refresh and select thinking levels supported by the active model. Unavailable during an Agent run. |
45
+ | `/provider [id]` | Edit a Provider's protocol, effective Base URL, and masked API key. Pass `id` to open a known Provider directly. |
46
+ | `/apikey [id]` | Compatibility alias for `/provider`. |
47
+ | `/web` | Open the authenticated local settings page in the default browser using the installed Web frontend. |
48
+ | `/compact` | Summarize older context immediately. Available only for idle conversations with enough history. |
49
+ | `/attach` | Open the attachment picker rooted at the active conversation directory. |
50
+ | `/mode` | Open the approval mode picker. Unavailable during an Agent run; use `/mode <mode>` directly instead. |
51
+ | `/mode approval-required` | Ask before writes, Shell commands, and high-risk tools. |
52
+ | `/mode workspace-write` | Auto-approve workspace edits and routine commands. |
53
+ | `/mode full-access` | Allow local files, network access, and Shell commands as the current operating-system user. |
54
+ | `/run` | Open the run mode picker (plan / goal / team). Unavailable during an Agent run. |
55
+ | `/run plan` | Plan mode (default): drive the current message by plan, then wait for the next instruction. |
56
+ | `/run goal` | Goal mode: one agent keeps pursuing the objective autonomously until done or paused. |
57
+ | `/run team` | Team mode: a lead agent dynamically coordinates subagents on the objective. |
58
+ | `/run budget <tokens>` | Set the Goal/Team token budget; `off` or an omitted value clears it. Submitted with the message. |
59
+ | `/run pause` | Pause the active goal of the current conversation. |
60
+ | `/quit` | Exit the TUI. |
61
+
62
+ ## Tool and Skill Commands
63
+
64
+ | Form | Explanation |
65
+ | :--- | :--- |
66
+ | `/<tool> [request]` | Request a Runtime Tool, for example `/read README.md`, `/bash npm test`, or `/web_search Pisper`. The Agent still generates arguments and calls the Tool; the active execution mode and Tool settings remain enforced. |
67
+ | `/skill:<name> [request]` | Request an enabled Skill, for example `/skill:docs-search find signing requirements`. Runtime resources load on demand, and Tools invoked by the Skill follow the same permission chain. |
package/README.md CHANGED
@@ -1,67 +1,67 @@
1
- # Pisper TUI Command Reference
1
+ # Pisper TUI 命令参考
2
2
 
3
- [Project home](https://ling-kong-ran.github.io/pisper/) · [GitHub repository](https://github.com/ling-kong-ran/pisper) · [中文](./README.md)
3
+ [项目主页](https://ling-kong-ran.github.io/pisper/) · [GitHub 仓库](https://github.com/ling-kong-ran/pisper) · [English](./README.en.md)
4
4
 
5
- Argument notation: `<argument>` is required; `[argument]` is optional.
5
+ 参数约定:`<参数>` 必填,`[参数]` 可选。
6
6
 
7
- ## CLI Commands
7
+ ## CLI 命令
8
8
 
9
- | Command | Explanation |
9
+ | 命令 | 解释 |
10
10
  | :--- | :--- |
11
- | `pisper` | Start the TUI in the current directory with a new empty conversation. History is not resumed automatically. |
12
- | `pisper --cwd <directory>` | Start the TUI with a new empty conversation in the specified workspace. |
13
- | `pisper resume` | Open the conversation picker across all workspaces. If no history exists, report it and exit. |
14
- | `pisper resume --cwd <directory>` | Open the conversation picker from a specified launch directory. A resumed conversation keeps its own saved working directory. |
15
- | `pisper doctor` | Diagnose the TUI, Runtime connection, and capability catalogs (conversations/tools/skills), then print a summary and exit. |
16
- | `pisper doctor --cwd <directory>` | Run diagnostics with the specified launch workspace. |
17
- | `pisper web` | Install (if missing) or use the Web frontend and open its authenticated local settings page in the default browser. The page is served by the Runtime started with this command and stops working once the TUI exits. |
18
- | `pisper web --cwd <directory>` | Start the Runtime for a specified directory and open the Web settings page. |
19
- | `pisper help [COMMAND]` | Show global help. `pisper help web` shows help for the Web subcommand. |
20
- | `pisper -h` / `pisper --help` | Show command help without starting the Runtime. |
21
- | `pisper -V` / `pisper --version` | Print the installed TUI version. |
22
- | `pisper update --check` | Check an npm-installed Pisper for updates without installing them. |
23
- | `pisper update` | Update an npm-installed Pisper through the active npm registry and verify the components again. |
11
+ | `pisper` | 在当前目录启动 TUI 并创建空会话;不会自动恢复历史会话。 |
12
+ | `pisper --cwd <目录>` | 以指定目录为工作区启动 TUI 并创建空会话。 |
13
+ | `pisper resume` | 打开跨工作目录的历史会话选择器;没有历史会话时提示后退出。 |
14
+ | `pisper resume --cwd <目录>` | 从指定启动目录进入会话选择器;恢复的会话仍使用其自身保存的工作目录。 |
15
+ | `pisper doctor` | 诊断 TUI、Runtime 连接与能力目录(会话/工具/技能),输出摘要后退出。 |
16
+ | `pisper doctor --cwd <目录>` | 以指定目录作为启动工作区执行诊断。 |
17
+ | `pisper web` | 安装(如缺失)或使用 Web 前端,并在默认浏览器打开本机认证配置页;页面由该命令启动的 Runtime 提供,退出 TUI 后不可用。 |
18
+ | `pisper web --cwd <目录>` | 以指定目录启动 Runtime 并打开 Web 配置页。 |
19
+ | `pisper help [COMMAND]` | 显示全局帮助;`pisper help web` 显示 Web 子命令帮助。 |
20
+ | `pisper -h` / `pisper --help` | 显示命令帮助,不启动 Runtime。 |
21
+ | `pisper -V` / `pisper --version` | 显示已安装的 TUI 版本。 |
22
+ | `pisper update --check` | 检查 npm 安装的 Pisper 是否有更新,不执行安装。 |
23
+ | `pisper update` | 通过当前 npm registry 更新 npm 安装的 Pisper,并重新校验组件。 |
24
24
 
25
- ## Environment Variables
25
+ ## 环境变量
26
26
 
27
- | Variable | Description |
27
+ | 变量 | 解释 |
28
28
  | :--- | :--- |
29
- | `PISPER_TUI_MOUSE=1` | Enable mouse wheel scrolling in the transcript; mouse capture replaces the terminal's native text selection. |
30
- | `PISPER_TUI_REDUCED_MOTION=1` | Disable the typewriter reveal and status animations (streaming text appears immediately); useful on low-end terminals and SSH sessions. |
29
+ | `PISPER_TUI_MOUSE=1` | 启用鼠标滚轮滚动聊天记录;鼠标捕获会接管终端原生文本选择。 |
30
+ | `PISPER_TUI_REDUCED_MOTION=1` | 关闭打字机逐字显现与状态动画(流式文本立即完整显示),适合低配终端与 SSH 会话。 |
31
31
 
32
- ## Slash Commands
32
+ ## Slash Command
33
33
 
34
- | Command | Explanation |
34
+ | 命令 | 解释 |
35
35
  | :--- | :--- |
36
- | `/init` | Analyze the current project and create or improve `AGENTS.md` at the project root. Existing useful guidance is preserved, and no other project files are changed. |
37
- | `/new` | Create an empty conversation in the TUI launch directory. Unavailable during an Agent run. |
38
- | `/sessions` | Open the conversation picker across all directories. Switching is unavailable during an Agent run. |
39
- | `/dir <directory>` | Change the active conversation's working directory. Relative paths resolve from its current directory. Unavailable during an Agent run. |
40
- | `/changes` | Open the Git or SVN changes view. In that view, `R` refreshes, `C` commits, `P` pushes Git, and pressing `V` twice reverts. SVN has no Push operation. |
41
- | `/changes commit <message>` | Commit the current Git or SVN changes with an explicit message. |
42
- | `/chat` | Return to the Chat message stream from another view. |
43
- | `/model` | Open the model picker and switch the active conversation model. Only configured Provider models are listed. Unavailable during an Agent run. |
44
- | `/thinking` | Refresh and select thinking levels supported by the active model. Unavailable during an Agent run. |
45
- | `/provider [id]` | Edit a Provider's protocol, effective Base URL, and masked API key. Pass `id` to open a known Provider directly. |
46
- | `/apikey [id]` | Compatibility alias for `/provider`. |
47
- | `/web` | Open the authenticated local settings page in the default browser using the installed Web frontend. |
48
- | `/compact` | Summarize older context immediately. Available only for idle conversations with enough history. |
49
- | `/attach` | Open the attachment picker rooted at the active conversation directory. |
50
- | `/mode` | Open the approval mode picker. Unavailable during an Agent run; use `/mode <mode>` directly instead. |
51
- | `/mode approval-required` | Ask before writes, Shell commands, and high-risk tools. |
52
- | `/mode workspace-write` | Auto-approve workspace edits and routine commands. |
53
- | `/mode full-access` | Allow local files, network access, and Shell commands as the current operating-system user. |
54
- | `/run` | Open the run mode picker (plan / goal / team). Unavailable during an Agent run. |
55
- | `/run plan` | Plan mode (default): drive the current message by plan, then wait for the next instruction. |
56
- | `/run goal` | Goal mode: one agent keeps pursuing the objective autonomously until done or paused. |
57
- | `/run team` | Team mode: a lead agent dynamically coordinates subagents on the objective. |
58
- | `/run budget <tokens>` | Set the Goal/Team token budget; `off` or an omitted value clears it. Submitted with the message. |
59
- | `/run pause` | Pause the active goal of the current conversation. |
60
- | `/quit` | Exit the TUI. |
36
+ | `/init` | 分析当前项目并创建或完善项目根目录的 `AGENTS.md`;保留已有有效说明,不修改其他项目文件。 |
37
+ | `/new` | 在 TUI 启动目录创建空会话;Agent 运行期间不可执行。 |
38
+ | `/sessions` | 打开跨所有目录的历史会话选择器;Agent 运行期间不可切换会话。 |
39
+ | `/dir <目录>` | 修改当前会话的工作目录;相对路径以当前会话目录为基准,Agent 运行期间不可修改。 |
40
+ | `/changes` | 打开 Git 或 SVN 改动视图。视图内 `R` 刷新、`C` 提交、`P` 推送 Git、连续两次 `V` 撤销;SVN 不提供 Push。 |
41
+ | `/changes commit <message>` | 使用指定提交信息提交当前 Git 或 SVN 工作区改动。 |
42
+ | `/chat` | 从其他视图返回 Chat 消息流。 |
43
+ | `/model` | 打开模型选择器并切换当前会话模型;只列出已配置 Provider 的模型,Agent 运行期间不可切换。 |
44
+ | `/thinking` | 刷新并选择当前模型支持的思考等级;Agent 运行期间不可切换。 |
45
+ | `/provider [id]` | 编辑 Provider 协议、当前生效 Base URL 与掩码 API Key;传入 `id` 可直达指定 Provider。 |
46
+ | `/apikey [id]` | `/provider` 的兼容别名。 |
47
+ | `/web` | 使用已安装的 Web 前端,在默认浏览器打开本机认证配置页。 |
48
+ | `/compact` | 立即摘要较早上下文;仅适用于有足够历史且当前空闲的会话。 |
49
+ | `/attach` | 打开当前会话目录的附件选择器。 |
50
+ | `/mode` | 打开审批模式选择器;Agent 运行期间不可打开,此时可改用 `/mode <模式>` 直接切换。 |
51
+ | `/mode approval-required` | 写入、Shell 和高风险工具执行前请求授权。 |
52
+ | `/mode workspace-write` | 自动批准工作区修改和常规命令。 |
53
+ | `/mode full-access` | 允许以当前系统用户权限访问本机文件、网络与 Shell。 |
54
+ | `/run` | 打开运行模式选择器(plan / goal / team);Agent 运行期间不可打开。 |
55
+ | `/run plan` | 计划模式(默认):按计划推进当前消息,完成本轮后等待下一条指令。 |
56
+ | `/run goal` | 目标模式:单个 Agent 围绕目标持续自主推进,直到完成或暂停。 |
57
+ | `/run team` | 团队模式:主 Agent 动态组织多个子 Agent 分工协同。 |
58
+ | `/run budget <tokens>` | 设置 Goal/Team 的 Token 预算,`off` 或缺省清除,随消息一起提交。 |
59
+ | `/run pause` | 暂停当前会话的活动目标。 |
60
+ | `/quit` | 退出 TUI。 |
61
61
 
62
- ## Tool and Skill Commands
62
+ ## Tool 与 Skill 命令
63
63
 
64
- | Form | Explanation |
64
+ | 形式 | 解释 |
65
65
  | :--- | :--- |
66
- | `/<tool> [request]` | Request a Runtime Tool, for example `/read README.md`, `/bash npm test`, or `/web_search Pisper`. The Agent still generates arguments and calls the Tool; the active execution mode and Tool settings remain enforced. |
67
- | `/skill:<name> [request]` | Request an enabled Skill, for example `/skill:docs-search find signing requirements`. Runtime resources load on demand, and Tools invoked by the Skill follow the same permission chain. |
66
+ | `/<tool> [请求]` | 请求 Runtime Tool,例如 `/read README.md`、`/bash npm test` 或 `/web_search Pisper`。Agent 仍负责生成参数并调用 Tool,当前执行模式与 Tool 开关继续生效。 |
67
+ | `/skill:<name> [请求]` | 请求已启用 Skill,例如 `/skill:docs-search 查找签名要求`。Runtime 按需加载 Skill 资源,其中触发的 Tool 继续经过同一权限链。 |
package/bin/pisper.mjs ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'node:child_process'
4
+ import process from 'node:process'
5
+ import { fileURLToPath } from 'node:url'
6
+ import { ensurePisperInstallation } from '../lib/install.mjs'
7
+ import { handleNpmHelp, handleNpmUpdate } from '../lib/npm-update.mjs'
8
+
9
+ const frontendRoot = fileURLToPath(new URL('../web', import.meta.url))
10
+
11
+ try {
12
+ const arguments_ = process.argv.slice(2)
13
+ if (!handleNpmHelp(arguments_) && !(await handleNpmUpdate(arguments_))) {
14
+ const installation = await ensurePisperInstallation()
15
+ const child = spawn(installation.executable, arguments_, {
16
+ env: {
17
+ ...process.env,
18
+ PISPER_APP_ROOT: installation.appRoot,
19
+ PISPER_DISTRIBUTION: 'npm',
20
+ PISPER_FRONTEND_ROOT: frontendRoot,
21
+ PISPER_RUNTIME_NODE: process.execPath,
22
+ },
23
+ stdio: 'inherit',
24
+ windowsHide: false,
25
+ })
26
+
27
+ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
28
+ process.on(signal, () => {
29
+ if (!child.killed) child.kill(signal)
30
+ })
31
+ }
32
+
33
+ child.once('error', (error) => {
34
+ console.error(`pisper: failed to start the terminal client: ${error.message}`)
35
+ process.exitCode = 1
36
+ })
37
+ child.once('exit', (code, signal) => {
38
+ if (signal) {
39
+ process.kill(process.pid, signal)
40
+ return
41
+ }
42
+ process.exitCode = code ?? 1
43
+ })
44
+ }
45
+ } catch (error) {
46
+ console.error(`pisper: ${error instanceof Error ? error.message : String(error)}`)
47
+ process.exitCode = 1
48
+ }
@@ -0,0 +1,392 @@
1
+ import { execFile } from 'node:child_process'
2
+ import { chmod, mkdir, open, readFile, rename, rm, stat, writeFile } from 'node:fs/promises'
3
+ import { createRequire } from 'node:module'
4
+ import { dirname, join } from 'node:path'
5
+ import process from 'node:process'
6
+ import { promisify } from 'node:util'
7
+ import { fileURLToPath } from 'node:url'
8
+ import { PublicKey, Signature } from '@threema/wasm-minisign-verify'
9
+ import { x as extractTar } from 'tar'
10
+ import { npmPlatformAlias, npmPlatformTarget, npmPlatformVersion } from './npm-platform.mjs'
11
+ import {
12
+ componentsRoot,
13
+ executableName,
14
+ releaseArchitecture,
15
+ releasePlatform,
16
+ supportedTarget,
17
+ } from './platform.mjs'
18
+
19
+ const execFileAsync = promisify(execFile)
20
+ const require = createRequire(import.meta.url)
21
+ const packageRoot = fileURLToPath(new URL('..', import.meta.url))
22
+ const packageManifest = JSON.parse(await readFile(join(packageRoot, 'package.json'), 'utf8'))
23
+ const tuiVersion = packageManifest.pisper?.tuiVersion
24
+ const runtimeVersion = packageManifest.pisper?.runtimeVersion
25
+ const MAX_ARCHIVE_BYTES = 128 * 1024 * 1024
26
+ const INSTALL_WAIT_MS = 600_000
27
+ const LEGACY_LOCK_GRACE_MS = 300_000
28
+
29
+ for (const [label, value] of [
30
+ ['TUI', tuiVersion],
31
+ ['Runtime', runtimeVersion],
32
+ ]) {
33
+ if (!/^\d+\.\d+\.\d+$/.test(value || '')) {
34
+ throw new Error(`pisper package metadata does not contain a valid ${label} version`)
35
+ }
36
+ }
37
+
38
+ function decodeWrapped(value) {
39
+ const trimmed = String(value).trim()
40
+ if (trimmed.startsWith('untrusted comment:')) return trimmed
41
+ if (!/^[A-Za-z0-9+/=\r\n]+$/.test(trimmed)) return trimmed
42
+ const decoded = Buffer.from(trimmed.replace(/\s/g, ''), 'base64').toString('utf8').trim()
43
+ return decoded.startsWith('untrusted comment:') ? decoded : trimmed
44
+ }
45
+
46
+ function componentAsset(component, version, platform = process.platform, arch = process.arch) {
47
+ const target = supportedTarget(platform, arch)
48
+ const label = component === 'tui' ? 'TUI_Component' : 'Runtime_Node'
49
+ return `Pisper_${label}_${version}_${target}.tar.gz`
50
+ }
51
+
52
+ export function releaseAsset(
53
+ version = tuiVersion,
54
+ platform = process.platform,
55
+ arch = process.arch,
56
+ ) {
57
+ return componentAsset('tui', version, platform, arch)
58
+ }
59
+
60
+ function compareVersions(left, right) {
61
+ const a = left.split('.').map(Number)
62
+ const b = right.split('.').map(Number)
63
+ for (let index = 0; index < 3; index += 1) {
64
+ if (a[index] !== b[index]) return a[index] - b[index]
65
+ }
66
+ return 0
67
+ }
68
+
69
+ async function isFile(path) {
70
+ try {
71
+ return (await stat(path)).isFile()
72
+ } catch (error) {
73
+ if (error?.code === 'ENOENT') return false
74
+ throw error
75
+ }
76
+ }
77
+
78
+ function commandName(component) {
79
+ if (component === 'tui') return executableName()
80
+ return 'sidecar-runtime/runtime/sidecar.mjs'
81
+ }
82
+
83
+ async function validateComponent(component, version, destination) {
84
+ const executable = join(destination, commandName(component))
85
+ if (!(await isFile(executable))) return ''
86
+ if (
87
+ component === 'runtime' &&
88
+ !(await isFile(join(destination, 'sidecar-runtime', 'package.json')))
89
+ ) {
90
+ return ''
91
+ }
92
+ try {
93
+ const manifest = JSON.parse(await readFile(join(destination, 'manifest.json'), 'utf8'))
94
+ if (
95
+ manifest.version !== version ||
96
+ manifest.platform !== releasePlatform() ||
97
+ manifest.arch !== releaseArchitecture() ||
98
+ manifest.command !== commandName(component)
99
+ ) {
100
+ return ''
101
+ }
102
+ } catch {
103
+ return ''
104
+ }
105
+ return executable
106
+ }
107
+
108
+ async function installedComponent(component, version, destination) {
109
+ const executable = await validateComponent(component, version, destination)
110
+ return executable ? { version, destination, executable } : null
111
+ }
112
+
113
+ async function resolveCurrentComponent(root, component, minimumVersion) {
114
+ try {
115
+ const pointer = JSON.parse(await readFile(join(root, component, 'current.json'), 'utf8'))
116
+ if (!/^\d+\.\d+\.\d+$/.test(pointer.version || '')) return null
117
+ if (compareVersions(pointer.version, minimumVersion) < 0) return null
118
+ const destination = join(root, component, 'versions', pointer.version)
119
+ return installedComponent(component, pointer.version, destination)
120
+ } catch (error) {
121
+ if (error?.code === 'ENOENT' || error instanceof SyntaxError) return null
122
+ throw error
123
+ }
124
+ }
125
+
126
+ async function resolvePlatformBundle() {
127
+ const target = npmPlatformTarget()
128
+ const alias = npmPlatformAlias()
129
+ let manifestPath
130
+ try {
131
+ manifestPath = require.resolve(`${alias}/package.json`)
132
+ } catch (error) {
133
+ throw new Error(
134
+ `the npm platform package ${alias} is missing; reinstall pisper without --omit=optional`,
135
+ { cause: error },
136
+ )
137
+ }
138
+ const manifest = JSON.parse(await readFile(manifestPath, 'utf8'))
139
+ const metadata = manifest.pisperBundle
140
+ const expectedVersion = npmPlatformVersion(packageManifest.version)
141
+ if (
142
+ manifest.name !== 'pisper' ||
143
+ manifest.version !== expectedVersion ||
144
+ metadata?.target !== target.release ||
145
+ metadata?.tuiVersion !== tuiVersion ||
146
+ metadata?.runtimeVersion !== runtimeVersion
147
+ ) {
148
+ throw new Error(
149
+ `npm platform package ${alias} does not match pisper@${packageManifest.version}`,
150
+ )
151
+ }
152
+ return dirname(manifestPath)
153
+ }
154
+
155
+ async function readBundledAsset(bundleRoot, component, version) {
156
+ const asset = componentAsset(component, version)
157
+ const archivePath = join(bundleRoot, 'components', component, asset)
158
+ const signaturePath = `${archivePath}.sig`
159
+ let size
160
+ try {
161
+ size = (await stat(archivePath)).size
162
+ } catch (error) {
163
+ throw new Error(`npm platform package is missing ${component} archive ${asset}`, {
164
+ cause: error,
165
+ })
166
+ }
167
+ if (size <= 0 || size > MAX_ARCHIVE_BYTES) {
168
+ throw new Error(`npm platform package contains an invalid ${component} archive size: ${size}`)
169
+ }
170
+ const [archive, signature] = await Promise.all([readFile(archivePath), readFile(signaturePath)])
171
+ return { archive, signature }
172
+ }
173
+
174
+ async function verifyArchive(component, archive, signatureBytes) {
175
+ const publicKeyText = await readFile(join(packageRoot, 'updater.pubkey'), 'utf8')
176
+ const publicKey = PublicKey.decode(decodeWrapped(publicKeyText))
177
+ const signature = Signature.decode(decodeWrapped(signatureBytes.toString('utf8')))
178
+ try {
179
+ if (!publicKey.verify(archive, signature)) {
180
+ throw new Error('signature verification returned false')
181
+ }
182
+ } catch (error) {
183
+ throw new Error(`${component} archive signature verification failed: ${error.message}`, {
184
+ cause: error,
185
+ })
186
+ } finally {
187
+ signature.free()
188
+ publicKey.free()
189
+ }
190
+ }
191
+
192
+ function nativeTarCommand() {
193
+ if (process.platform === 'win32') {
194
+ return join(
195
+ process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows',
196
+ 'System32',
197
+ 'tar.exe',
198
+ )
199
+ }
200
+ if (process.platform === 'darwin') return '/usr/bin/tar'
201
+ return 'tar'
202
+ }
203
+
204
+ async function extractWithNodeTar(archivePath, extractionRoot) {
205
+ await extractTar({
206
+ cwd: extractionRoot,
207
+ file: archivePath,
208
+ preservePaths: false,
209
+ strict: true,
210
+ strip: 1,
211
+ filter: (_path, entry) => entry.type === 'File' || entry.type === 'Directory',
212
+ })
213
+ }
214
+
215
+ export async function extractComponentArchive(
216
+ archivePath,
217
+ extractionRoot,
218
+ tarCommand = nativeTarCommand(),
219
+ ) {
220
+ try {
221
+ await execFileAsync(
222
+ tarCommand,
223
+ ['-xzf', archivePath, '-C', extractionRoot, '--strip-components=1'],
224
+ { windowsHide: true },
225
+ )
226
+ } catch {
227
+ await rm(extractionRoot, { recursive: true, force: true })
228
+ await mkdir(extractionRoot, { recursive: true })
229
+ await extractWithNodeTar(archivePath, extractionRoot)
230
+ }
231
+ }
232
+
233
+ async function wait(milliseconds) {
234
+ await new Promise((resolve) => setTimeout(resolve, milliseconds))
235
+ }
236
+
237
+ async function installerLockIsActive(lockPath) {
238
+ try {
239
+ const [raw, details] = await Promise.all([readFile(lockPath, 'utf8'), stat(lockPath)])
240
+ const age = Math.max(0, Date.now() - details.mtimeMs)
241
+ if (age >= INSTALL_WAIT_MS) return false
242
+
243
+ let metadata
244
+ try {
245
+ metadata = JSON.parse(raw)
246
+ } catch {
247
+ // Older installers created empty locks. Give a live legacy install time to finish.
248
+ return age < LEGACY_LOCK_GRACE_MS
249
+ }
250
+ if (!Number.isSafeInteger(metadata?.pid) || metadata.pid <= 0) {
251
+ return age < LEGACY_LOCK_GRACE_MS
252
+ }
253
+ try {
254
+ process.kill(metadata.pid, 0)
255
+ return true
256
+ } catch (error) {
257
+ if (error?.code === 'ESRCH') return false
258
+ if (error?.code === 'EPERM') return true
259
+ throw error
260
+ }
261
+ } catch (error) {
262
+ if (error?.code === 'ENOENT') return false
263
+ throw error
264
+ }
265
+ }
266
+
267
+ export async function acquireInstallLock(lockPath, validate) {
268
+ const deadline = Date.now() + INSTALL_WAIT_MS
269
+ while (true) {
270
+ try {
271
+ const lock = await open(lockPath, 'wx')
272
+ try {
273
+ await lock.writeFile(`${JSON.stringify({ pid: process.pid, createdAt: Date.now() })}\n`)
274
+ return lock
275
+ } catch (error) {
276
+ await lock.close()
277
+ await rm(lockPath, { force: true })
278
+ throw error
279
+ }
280
+ } catch (error) {
281
+ if (error?.code !== 'EEXIST') throw error
282
+ if (await validate()) return null
283
+ if (!(await installerLockIsActive(lockPath))) {
284
+ try {
285
+ await rm(lockPath, { force: true })
286
+ continue
287
+ } catch (removeError) {
288
+ if (!['EACCES', 'EBUSY', 'EPERM'].includes(removeError?.code)) throw removeError
289
+ }
290
+ }
291
+ if (Date.now() >= deadline) {
292
+ throw new Error('timed out waiting for another Pisper installer')
293
+ }
294
+ await wait(250)
295
+ }
296
+ }
297
+ }
298
+
299
+ async function installComponent({ root, bundleRoot, component, version, destination }) {
300
+ const lockRoot = join(root, 'npm')
301
+ await mkdir(lockRoot, { recursive: true })
302
+ const lockPath = join(lockRoot, `${component}-install.lock`)
303
+ const validate = () => validateComponent(component, version, destination)
304
+ const lock = await acquireInstallLock(lockPath, validate)
305
+ if (!lock) return { version, destination, executable: await validate() }
306
+
307
+ const staging = `${destination}.tmp-${process.pid}-${Date.now()}`
308
+ // Renaming a tree with paths over MAX_PATH fails on Windows even though tar can extract it.
309
+ const extractionRoot = process.platform === 'win32' ? destination : staging
310
+ const archivePath = `${staging}.tar.gz`
311
+ try {
312
+ const existing = await validate()
313
+ if (existing) return { version, destination, executable: existing }
314
+
315
+ console.log(`pisper: installing ${component} ${version} from the npm platform package`)
316
+ await mkdir(dirname(destination), { recursive: true })
317
+ await rm(extractionRoot, { recursive: true, force: true })
318
+ await mkdir(extractionRoot, { recursive: true })
319
+ const { archive, signature } = await readBundledAsset(bundleRoot, component, version)
320
+ console.log(`pisper: verifying ${component} ${version} signature`)
321
+ await verifyArchive(component, archive, signature)
322
+ console.log(`pisper: extracting ${component} ${version}`)
323
+ await writeFile(archivePath, archive, { mode: 0o600 })
324
+ await extractComponentArchive(archivePath, extractionRoot)
325
+ if (process.platform !== 'win32') {
326
+ await chmod(join(extractionRoot, commandName(component)), 0o755)
327
+ }
328
+ const stagedExecutable = await validateComponent(component, version, extractionRoot)
329
+ if (!stagedExecutable) {
330
+ throw new Error(`bundled ${component} archive has an invalid package layout`)
331
+ }
332
+ if (extractionRoot !== destination) {
333
+ await rm(destination, { recursive: true, force: true })
334
+ await rename(staging, destination)
335
+ }
336
+ console.log(`pisper: ${component} ${version} is ready`)
337
+ return { version, destination, executable: join(destination, commandName(component)) }
338
+ } finally {
339
+ await lock.close()
340
+ await Promise.all([
341
+ rm(lockPath, { force: true }),
342
+ rm(staging, { recursive: true, force: true }),
343
+ rm(archivePath, { force: true }),
344
+ ])
345
+ }
346
+ }
347
+
348
+ export async function ensurePisperInstallation() {
349
+ const root = componentsRoot()
350
+ const npmTuiDestination = join(root, 'npm', 'versions', tuiVersion)
351
+ const runtimeDestination = join(root, 'npm-runtime', 'versions', runtimeVersion)
352
+ const [tui, runtime] = await Promise.all([
353
+ resolveCurrentComponent(root, 'tui', tuiVersion).then(
354
+ (current) => current || installedComponent('tui', tuiVersion, npmTuiDestination),
355
+ ),
356
+ installedComponent('runtime', runtimeVersion, runtimeDestination),
357
+ ])
358
+ if (tui && runtime) {
359
+ return {
360
+ executable: tui.executable,
361
+ appRoot: join(runtime.destination, 'sidecar-runtime'),
362
+ }
363
+ }
364
+
365
+ const bundleRoot = await resolvePlatformBundle()
366
+ const [installedTui, installedRuntime] = await Promise.all([
367
+ tui ||
368
+ installComponent({
369
+ root,
370
+ bundleRoot,
371
+ component: 'tui',
372
+ version: tuiVersion,
373
+ destination: npmTuiDestination,
374
+ }),
375
+ runtime ||
376
+ installComponent({
377
+ root,
378
+ bundleRoot,
379
+ component: 'runtime',
380
+ version: runtimeVersion,
381
+ destination: runtimeDestination,
382
+ }),
383
+ ])
384
+ return {
385
+ executable: installedTui.executable,
386
+ appRoot: join(installedRuntime.destination, 'sidecar-runtime'),
387
+ }
388
+ }
389
+
390
+ export async function ensurePisperExecutable() {
391
+ return (await ensurePisperInstallation()).executable
392
+ }