pi-namespace-patch 0.85.1 → 0.86.0-namespace.1

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 (317) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +26 -705
  3. package/dist/bundle/chunks/anthropic-messages-MYU5ZMRF.js +6 -0
  4. package/dist/bundle/chunks/azure-openai-responses-HUSQ3GP2.js +2 -0
  5. package/dist/bundle/chunks/bedrock-converse-stream.js +47 -38
  6. package/dist/bundle/chunks/chunk-A3JYRWB6.js +2 -0
  7. package/dist/bundle/chunks/chunk-DTD7JQ7Y.js +42 -0
  8. package/dist/bundle/chunks/chunk-FUXEF6JQ.js +44 -0
  9. package/dist/bundle/chunks/chunk-IS2VY2NY.js +1561 -0
  10. package/dist/bundle/chunks/{chunk-IDDQWTHI.js → chunk-RCZIEVGO.js} +10 -1
  11. package/dist/bundle/chunks/chunk-S7SZN6Z3.js +2 -0
  12. package/dist/bundle/chunks/chunk-SXW7XMQG.js +2 -0
  13. package/dist/bundle/chunks/chunk-WIUZI2CJ.js +11 -0
  14. package/dist/bundle/chunks/github-copilot.js +1 -1
  15. package/dist/bundle/chunks/google-generative-ai-IMS5EK2Y.js +2 -0
  16. package/dist/bundle/chunks/google-vertex-O4YJEQUW.js +2 -0
  17. package/dist/bundle/chunks/jiti-loader-C3NU2SDH.js +21 -0
  18. package/dist/bundle/chunks/jiti-static-loader-E6ANQD5T.js +2 -0
  19. package/dist/bundle/chunks/mistral-conversations-NOSQHBEY.js +5 -0
  20. package/dist/bundle/chunks/{node-KG362ECQ.js → node-O3RIBJRH.js} +1 -1
  21. package/dist/bundle/chunks/openai-codex-responses-QDSOTBBO.js +10 -0
  22. package/dist/bundle/chunks/openai-completions-KQPOPEVM.js +7 -0
  23. package/dist/bundle/chunks/openai-responses-HWEUZ6WZ.js +2 -0
  24. package/dist/bundle/chunks/{pi-messages-PML4SPVJ.js → pi-messages-GFKBWJHZ.js} +1 -1
  25. package/dist/bundle/chunks/virtual-modules-UQVS3IVK.js +2 -0
  26. package/dist/bundle/cli.js +1 -1
  27. package/dist/bundle/index.js +1 -1
  28. package/dist/bundle/rpc-entry.js +1 -1
  29. package/dist/cli/session-picker.d.ts +1 -1
  30. package/dist/cli/session-picker.d.ts.map +1 -1
  31. package/dist/cli/session-picker.js.map +1 -1
  32. package/dist/config.d.ts.map +1 -1
  33. package/dist/config.js +1 -1
  34. package/dist/config.js.map +1 -1
  35. package/dist/core/agent-session.d.ts +56 -6
  36. package/dist/core/agent-session.d.ts.map +1 -1
  37. package/dist/core/agent-session.js +294 -157
  38. package/dist/core/agent-session.js.map +1 -1
  39. package/dist/core/bug-report-upload.d.ts +12 -0
  40. package/dist/core/bug-report-upload.d.ts.map +1 -0
  41. package/dist/core/bug-report-upload.js +22 -0
  42. package/dist/core/bug-report-upload.js.map +1 -0
  43. package/dist/core/bug-report.d.ts +176 -0
  44. package/dist/core/bug-report.d.ts.map +1 -0
  45. package/dist/core/bug-report.js +292 -0
  46. package/dist/core/bug-report.js.map +1 -0
  47. package/dist/core/cache-stats.d.ts.map +1 -1
  48. package/dist/core/cache-stats.js +12 -1
  49. package/dist/core/cache-stats.js.map +1 -1
  50. package/dist/core/cache-warmer.d.ts +102 -0
  51. package/dist/core/cache-warmer.d.ts.map +1 -0
  52. package/dist/core/cache-warmer.js +342 -0
  53. package/dist/core/cache-warmer.js.map +1 -0
  54. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  55. package/dist/core/compaction/branch-summarization.js +2 -2
  56. package/dist/core/compaction/branch-summarization.js.map +1 -1
  57. package/dist/core/compaction/compaction.d.ts +2 -2
  58. package/dist/core/compaction/compaction.d.ts.map +1 -1
  59. package/dist/core/compaction/compaction.js +11 -12
  60. package/dist/core/compaction/compaction.js.map +1 -1
  61. package/dist/core/crash-log.d.ts +22 -0
  62. package/dist/core/crash-log.d.ts.map +1 -0
  63. package/dist/core/crash-log.js +71 -0
  64. package/dist/core/crash-log.js.map +1 -0
  65. package/dist/core/experimental.d.ts +0 -4
  66. package/dist/core/experimental.d.ts.map +1 -1
  67. package/dist/core/experimental.js +0 -4
  68. package/dist/core/experimental.js.map +1 -1
  69. package/dist/core/extensions/index.d.ts +1 -1
  70. package/dist/core/extensions/index.d.ts.map +1 -1
  71. package/dist/core/extensions/index.js.map +1 -1
  72. package/dist/core/extensions/jiti-loader.d.ts +2 -0
  73. package/dist/core/extensions/jiti-loader.d.ts.map +1 -0
  74. package/dist/core/extensions/jiti-loader.js +4 -0
  75. package/dist/core/extensions/jiti-loader.js.map +1 -0
  76. package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
  77. package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
  78. package/dist/core/extensions/jiti-static-loader.js +4 -0
  79. package/dist/core/extensions/jiti-static-loader.js.map +1 -0
  80. package/dist/core/extensions/loader.d.ts.map +1 -1
  81. package/dist/core/extensions/loader.js +38 -51
  82. package/dist/core/extensions/loader.js.map +1 -1
  83. package/dist/core/extensions/runner.d.ts +10 -7
  84. package/dist/core/extensions/runner.d.ts.map +1 -1
  85. package/dist/core/extensions/runner.js +85 -67
  86. package/dist/core/extensions/runner.js.map +1 -1
  87. package/dist/core/extensions/types.d.ts +60 -50
  88. package/dist/core/extensions/types.d.ts.map +1 -1
  89. package/dist/core/extensions/types.js.map +1 -1
  90. package/dist/core/extensions/virtual-modules.d.ts +3 -0
  91. package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
  92. package/dist/core/extensions/virtual-modules.js +38 -0
  93. package/dist/core/extensions/virtual-modules.js.map +1 -0
  94. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  95. package/dist/core/extensions/wrapper.js +1 -20
  96. package/dist/core/extensions/wrapper.js.map +1 -1
  97. package/dist/core/index.d.ts +2 -1
  98. package/dist/core/index.d.ts.map +1 -1
  99. package/dist/core/index.js.map +1 -1
  100. package/dist/core/keybindings.d.ts +1 -1
  101. package/dist/core/keybindings.d.ts.map +1 -1
  102. package/dist/core/keybindings.js +1 -1
  103. package/dist/core/keybindings.js.map +1 -1
  104. package/dist/core/messages.d.ts.map +1 -1
  105. package/dist/core/messages.js +1 -0
  106. package/dist/core/messages.js.map +1 -1
  107. package/dist/core/model-config.d.ts +101 -20
  108. package/dist/core/model-config.d.ts.map +1 -1
  109. package/dist/core/model-config.js +25 -18
  110. package/dist/core/model-config.js.map +1 -1
  111. package/dist/core/model-registry.d.ts +5 -1
  112. package/dist/core/model-registry.d.ts.map +1 -1
  113. package/dist/core/model-registry.js +8 -0
  114. package/dist/core/model-registry.js.map +1 -1
  115. package/dist/core/model-resolver.d.ts.map +1 -1
  116. package/dist/core/model-resolver.js +1 -1
  117. package/dist/core/model-resolver.js.map +1 -1
  118. package/dist/core/model-runtime.d.ts.map +1 -1
  119. package/dist/core/model-runtime.js +5 -3
  120. package/dist/core/model-runtime.js.map +1 -1
  121. package/dist/core/provider-composer.d.ts +3 -2
  122. package/dist/core/provider-composer.d.ts.map +1 -1
  123. package/dist/core/provider-composer.js +2 -0
  124. package/dist/core/provider-composer.js.map +1 -1
  125. package/dist/core/radius.d.ts +3 -0
  126. package/dist/core/radius.d.ts.map +1 -1
  127. package/dist/core/radius.js +6 -0
  128. package/dist/core/radius.js.map +1 -1
  129. package/dist/core/sdk.d.ts.map +1 -1
  130. package/dist/core/sdk.js +60 -38
  131. package/dist/core/sdk.js.map +1 -1
  132. package/dist/core/session-export.d.ts +6 -2
  133. package/dist/core/session-export.d.ts.map +1 -1
  134. package/dist/core/session-export.js +14 -13
  135. package/dist/core/session-export.js.map +1 -1
  136. package/dist/core/session-manager.d.ts +29 -6
  137. package/dist/core/session-manager.d.ts.map +1 -1
  138. package/dist/core/session-manager.js +159 -96
  139. package/dist/core/session-manager.js.map +1 -1
  140. package/dist/core/settings-manager.d.ts +20 -4
  141. package/dist/core/settings-manager.d.ts.map +1 -1
  142. package/dist/core/settings-manager.js +43 -7
  143. package/dist/core/settings-manager.js.map +1 -1
  144. package/dist/core/slash-commands.d.ts.map +1 -1
  145. package/dist/core/slash-commands.js +1 -0
  146. package/dist/core/slash-commands.js.map +1 -1
  147. package/dist/core/system-prompt.d.ts +49 -6
  148. package/dist/core/system-prompt.d.ts.map +1 -1
  149. package/dist/core/system-prompt.js +121 -92
  150. package/dist/core/system-prompt.js.map +1 -1
  151. package/dist/core/tools/bash.d.ts +2 -1
  152. package/dist/core/tools/bash.d.ts.map +1 -1
  153. package/dist/core/tools/bash.js +10 -4
  154. package/dist/core/tools/bash.js.map +1 -1
  155. package/dist/core/tools/edit.d.ts.map +1 -1
  156. package/dist/core/tools/edit.js +1 -2
  157. package/dist/core/tools/edit.js.map +1 -1
  158. package/dist/core/tools/read.d.ts.map +1 -1
  159. package/dist/core/tools/read.js +1 -2
  160. package/dist/core/tools/read.js.map +1 -1
  161. package/dist/core/tools/renderers/bash.d.ts.map +1 -1
  162. package/dist/core/tools/renderers/bash.js +9 -1
  163. package/dist/core/tools/renderers/bash.js.map +1 -1
  164. package/dist/core/tools/write.d.ts.map +1 -1
  165. package/dist/core/tools/write.js +1 -2
  166. package/dist/core/tools/write.js.map +1 -1
  167. package/dist/core/usage-totals.d.ts +1 -1
  168. package/dist/core/usage-totals.d.ts.map +1 -1
  169. package/dist/core/usage-totals.js +5 -1
  170. package/dist/core/usage-totals.js.map +1 -1
  171. package/dist/extensions/llama/client.d.ts +2 -0
  172. package/dist/extensions/llama/client.d.ts.map +1 -1
  173. package/dist/extensions/llama/client.js +7 -3
  174. package/dist/extensions/llama/client.js.map +1 -1
  175. package/dist/extensions/llama/provider.d.ts.map +1 -1
  176. package/dist/extensions/llama/provider.js +20 -5
  177. package/dist/extensions/llama/provider.js.map +1 -1
  178. package/dist/index.d.ts +3 -2
  179. package/dist/index.d.ts.map +1 -1
  180. package/dist/index.js.map +1 -1
  181. package/dist/main.d.ts.map +1 -1
  182. package/dist/main.js +13 -9
  183. package/dist/main.js.map +1 -1
  184. package/dist/migrations.d.ts.map +1 -1
  185. package/dist/migrations.js +2 -2
  186. package/dist/migrations.js.map +1 -1
  187. package/dist/modes/interactive/bug-report.d.ts +14 -0
  188. package/dist/modes/interactive/bug-report.d.ts.map +1 -0
  189. package/dist/modes/interactive/bug-report.js +209 -0
  190. package/dist/modes/interactive/bug-report.js.map +1 -0
  191. package/dist/modes/interactive/chat-viewport.d.ts.map +1 -1
  192. package/dist/modes/interactive/chat-viewport.js +1 -1
  193. package/dist/modes/interactive/chat-viewport.js.map +1 -1
  194. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/branch-summary-message.js +12 -5
  196. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  197. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  198. package/dist/modes/interactive/components/compaction-summary-message.js +12 -5
  199. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  200. package/dist/modes/interactive/components/custom-editor.d.ts +3 -3
  201. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  203. package/dist/modes/interactive/components/extension-input.d.ts +2 -0
  204. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  205. package/dist/modes/interactive/components/extension-input.js +6 -0
  206. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  207. package/dist/modes/interactive/components/extension-selector.d.ts +1 -0
  208. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  209. package/dist/modes/interactive/components/extension-selector.js +4 -0
  210. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  211. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  212. package/dist/modes/interactive/components/footer.js +4 -1
  213. package/dist/modes/interactive/components/footer.js.map +1 -1
  214. package/dist/modes/interactive/components/session-selector.d.ts +5 -5
  215. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  216. package/dist/modes/interactive/components/session-selector.js +74 -48
  217. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  218. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  219. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  220. package/dist/modes/interactive/components/settings-selector.js +11 -0
  221. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  222. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  223. package/dist/modes/interactive/components/skill-invocation-message.js +11 -4
  224. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  225. package/dist/modes/interactive/components/status-indicator.d.ts +2 -2
  226. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  227. package/dist/modes/interactive/components/status-indicator.js +7 -7
  228. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  229. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  230. package/dist/modes/interactive/components/tool-execution.js +18 -9
  231. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  232. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  233. package/dist/modes/interactive/components/tree-selector.js +2 -0
  234. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  235. package/dist/modes/interactive/interactive-mode.d.ts +13 -1
  236. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  237. package/dist/modes/interactive/interactive-mode.js +220 -84
  238. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  239. package/dist/modes/interactive/session-share.d.ts +2 -0
  240. package/dist/modes/interactive/session-share.d.ts.map +1 -1
  241. package/dist/modes/interactive/session-share.js +8 -4
  242. package/dist/modes/interactive/session-share.js.map +1 -1
  243. package/dist/modes/interactive/tui-renderer.d.ts.map +1 -1
  244. package/dist/modes/interactive/tui-renderer.js +2 -2
  245. package/dist/modes/interactive/tui-renderer.js.map +1 -1
  246. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  247. package/dist/modes/rpc/rpc-mode.js +2 -2
  248. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  249. package/dist/utils/clipboard-command.d.ts +7 -0
  250. package/dist/utils/clipboard-command.d.ts.map +1 -0
  251. package/dist/utils/clipboard-command.js +45 -0
  252. package/dist/utils/clipboard-command.js.map +1 -0
  253. package/dist/utils/clipboard-image.d.ts.map +1 -1
  254. package/dist/utils/clipboard-image.js +52 -69
  255. package/dist/utils/clipboard-image.js.map +1 -1
  256. package/dist/utils/clipboard.d.ts.map +1 -1
  257. package/dist/utils/clipboard.js +61 -125
  258. package/dist/utils/clipboard.js.map +1 -1
  259. package/dist/utils/version-check.d.ts.map +1 -1
  260. package/dist/utils/version-check.js +11 -4
  261. package/dist/utils/version-check.js.map +1 -1
  262. package/dist/utils/zip.d.ts +7 -0
  263. package/dist/utils/zip.d.ts.map +1 -0
  264. package/dist/utils/zip.js +60 -0
  265. package/dist/utils/zip.js.map +1 -0
  266. package/docs/compaction.md +39 -13
  267. package/docs/custom-provider.md +22 -13
  268. package/docs/development.md +4 -4
  269. package/docs/docs.json +4 -0
  270. package/docs/environment-variables.md +1 -0
  271. package/docs/extensions.md +57 -43
  272. package/docs/json.md +4 -4
  273. package/docs/models.md +33 -2
  274. package/docs/providers.md +2 -2
  275. package/docs/sdk.md +4 -2
  276. package/docs/security.md +1 -1
  277. package/docs/session-format.md +82 -40
  278. package/docs/sessions.md +27 -0
  279. package/docs/settings.md +60 -1
  280. package/docs/termux.md +0 -1
  281. package/docs/tui.md +2 -2
  282. package/docs/usage.md +1 -0
  283. package/examples/extensions/README.md +0 -1
  284. package/examples/extensions/custom-provider-anthropic/index.ts +18 -12
  285. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  286. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  287. package/examples/extensions/custom-provider-gitlab-duo/index.ts +2 -2
  288. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  289. package/examples/extensions/gondolin/package-lock.json +2 -2
  290. package/examples/extensions/gondolin/package.json +1 -1
  291. package/examples/extensions/prompt-customizer.ts +19 -67
  292. package/examples/extensions/sandbox/package-lock.json +2 -2
  293. package/examples/extensions/sandbox/package.json +1 -1
  294. package/examples/extensions/with-deps/package-lock.json +2 -2
  295. package/examples/extensions/with-deps/package.json +1 -1
  296. package/npm-shrinkwrap.json +435 -762
  297. package/package.json +17 -23
  298. package/dist/bundle/chunks/anthropic-messages-VWZZOSJQ.js +0 -6
  299. package/dist/bundle/chunks/azure-openai-responses-BJLAM6CD.js +0 -2
  300. package/dist/bundle/chunks/chunk-AXIIZGTV.js +0 -2
  301. package/dist/bundle/chunks/chunk-CLNPYIDP.js +0 -42
  302. package/dist/bundle/chunks/chunk-GMWCTUPB.js +0 -2
  303. package/dist/bundle/chunks/chunk-JJ2YFCJF.js +0 -1547
  304. package/dist/bundle/chunks/chunk-OUXLLA64.js +0 -11
  305. package/dist/bundle/chunks/chunk-U6ZMQKGD.js +0 -50
  306. package/dist/bundle/chunks/chunk-UAQELI3K.js +0 -2
  307. package/dist/bundle/chunks/google-generative-ai-Q2K7FBDI.js +0 -2
  308. package/dist/bundle/chunks/google-vertex-7UJBF4S7.js +0 -2
  309. package/dist/bundle/chunks/mistral-conversations-4M6BZBX6.js +0 -5
  310. package/dist/bundle/chunks/openai-codex-responses-R6VYZTVY.js +0 -10
  311. package/dist/bundle/chunks/openai-completions-EKZT2IH2.js +0 -7
  312. package/dist/bundle/chunks/openai-responses-TFDINO6W.js +0 -2
  313. package/dist/utils/clipboard-native.d.ts +0 -11
  314. package/dist/utils/clipboard-native.d.ts.map +0 -1
  315. package/dist/utils/clipboard-native.js +0 -20
  316. package/dist/utils/clipboard-native.js.map +0 -1
  317. package/examples/extensions/kimi-deferred-tools.ts +0 -61
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard-image.js","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"child_process\";\nimport { randomUUID } from \"crypto\";\nimport { readFileSync, unlinkSync } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_READ_TIMEOUT_MS = 3000;\nconst DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\toptions?: { timeoutMs?: number; maxBufferBytes?: number; env?: NodeJS.ProcessEnv },\n): { stdout: Buffer; ok: boolean } {\n\tconst timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n\tconst maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n\n\tconst result = spawnSync(command, args, {\n\t\ttimeout: timeoutMs,\n\t\tmaxBuffer: maxBufferBytes,\n\t\tenv: options?.env,\n\t});\n\n\tif (result.error) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (result.status !== 0) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tconst stdout = Buffer.isBuffer(result.stdout)\n\t\t? result.stdout\n\t\t: Buffer.from(result.stdout ?? \"\", typeof result.stdout === \"string\" ? \"utf-8\" : undefined);\n\n\treturn { ok: true, stdout };\n}\n\nfunction readClipboardImageViaWlPaste(): ClipboardImage | null {\n\tconst list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (!list.ok) {\n\t\treturn null;\n\t}\n\n\tconst types = list.stdout\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (!data.ok || data.stdout.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn { bytes: data.stdout, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * On WSL, the Linux clipboard (Wayland/X11) does not receive image data from\n * Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard\n * directly, so we use it as a fallback.\n */\nfunction readClipboardImageViaPowerShell(): ClipboardImage | null {\n\tconst tmpFile = join(tmpdir(), `pi-wsl-clip-${randomUUID()}.png`);\n\n\ttry {\n\t\tconst winPathResult = runCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\t\tif (!winPathResult.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst winPath = winPathResult.stdout.toString(\"utf-8\").trim();\n\t\tif (!winPath) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst psQuotedWinPath = winPath.replaceAll(\"'\", \"''\");\n\t\tconst psScript = [\n\t\t\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\t\t\"Add-Type -AssemblyName System.Drawing\",\n\t\t\t`$path = '${psQuotedWinPath}'`,\n\t\t\t\"$img = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\t\t\"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }\",\n\t\t].join(\"; \");\n\n\t\tconst result = runCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", psScript], {\n\t\t\ttimeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,\n\t\t});\n\t\tif (!result.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst output = result.stdout.toString(\"utf-8\").trim();\n\t\tif (output !== \"ok\") {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst bytes = readFileSync(tmpFile);\n\t\tif (bytes.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn { bytes: new Uint8Array(bytes), mimeType: \"image/png\" };\n\t} catch {\n\t\treturn null;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors.\n\t\t}\n\t}\n}\n\nfunction readClipboardImageViaXclip(): ClipboardImage | null {\n\tconst targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets.ok) {\n\t\tcandidateTypes = targets.stdout\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n\tconst tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data.ok && data.stdout.length > 0) {\n\t\t\treturn { bytes: data.stdout, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn null;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null> {\n\tif (!clipboard || !clipboard.hasImage()) {\n\t\treturn null;\n\t}\n\n\tconst imageData = await clipboard.getImageBinary();\n\tif (!imageData || imageData.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n\treturn { bytes, mimeType: \"image/png\" };\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tlet image: ClipboardImage | null = null;\n\n\tif (platform === \"linux\") {\n\t\tconst wsl = isWSL(env);\n\t\tconst wayland = isWaylandSession(env);\n\n\t\tif (wayland || wsl) {\n\t\t\timage = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();\n\t\t}\n\n\t\tif (!image && wsl) {\n\t\t\timage = readClipboardImageViaPowerShell();\n\t\t}\n\n\t\tif (!image && !wayland) {\n\t\t\timage = (await readClipboardImageViaNativeClipboard()) ?? readClipboardImageViaXclip();\n\t\t}\n\t} else {\n\t\timage = await readClipboardImageViaNativeClipboard();\n\t}\n\n\tif (!image) {\n\t\treturn null;\n\t}\n\n\t// Convert unsupported formats (e.g., BMP from WSLg) to PNG\n\tif (!isSupportedImageMimeType(image.mimeType)) {\n\t\tconst pngBytes = await convertToPng(image.bytes);\n\t\tif (!pngBytes) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { bytes: pngBytes, mimeType: \"image/png\" };\n\t}\n\n\treturn image;\n}\n"]}
1
+ {"version":3,"file":"clipboard-image.js","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { getNativeClipboard } from \"@earendil-works/pi-tui\";\nimport { randomUUID } from \"crypto\";\nimport { readFileSync, unlinkSync } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { runClipboardCommand } from \"./clipboard-command.ts\";\nimport { detectSupportedImageMimeType } from \"./mime.ts\";\nimport { loadPhoton } from \"./photon.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n// Undefined means the backend failed; null means it has no image. An empty\n// Wayland clipboard must not fall through to stale X11 clipboard contents.\nasync function readClipboardImageViaWlPaste(): Promise<ClipboardImage | null | undefined> {\n\tconst list = await runClipboardCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (list === undefined) return undefined;\n\n\tconst types = list\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = await runClipboardCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (data === undefined) return undefined;\n\tif (data.length === 0) return null;\n\n\treturn { bytes: data, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * On WSL, the Linux clipboard (Wayland/X11) does not receive image data from\n * Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard\n * directly, so we use it as a fallback.\n */\nasync function readClipboardImageViaPowerShell(): Promise<ClipboardImage | null> {\n\tconst tmpFile = join(tmpdir(), `pi-wsl-clip-${randomUUID()}.png`);\n\n\ttry {\n\t\tconst winPathResult = await runClipboardCommand(\"wslpath\", [\"-w\", tmpFile], {\n\t\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t\t});\n\t\tif (winPathResult === undefined) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst winPath = winPathResult.toString(\"utf-8\").trim();\n\t\tif (!winPath) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst psQuotedWinPath = winPath.replaceAll(\"'\", \"''\");\n\t\tconst psScript = [\n\t\t\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\t\t\"Add-Type -AssemblyName System.Drawing\",\n\t\t\t`$path = '${psQuotedWinPath}'`,\n\t\t\t\"$img = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\t\t\"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }\",\n\t\t].join(\"; \");\n\n\t\tconst result = await runClipboardCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", psScript], {\n\t\t\ttimeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,\n\t\t});\n\t\tif (result === undefined) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst output = result.toString(\"utf-8\").trim();\n\t\tif (output !== \"ok\") {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst bytes = readFileSync(tmpFile);\n\t\tif (bytes.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn { bytes: new Uint8Array(bytes), mimeType: \"image/png\" };\n\t} catch {\n\t\treturn null;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors.\n\t\t}\n\t}\n}\n\nasync function readClipboardImageViaXclip(): Promise<ClipboardImage | null | undefined> {\n\tconst targets = await runClipboardCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets !== undefined) {\n\t\tcandidateTypes = targets\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = selectPreferredImageMimeType(candidateTypes);\n\tif (targets !== undefined && !preferred) return null;\n\tconst tryTypes = new Set(preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : SUPPORTED_IMAGE_MIME_TYPES);\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = await runClipboardCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data !== undefined && data.length > 0) {\n\t\t\treturn { bytes: data, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null | undefined> {\n\tconst bytes = await getNativeClipboard()?.getImage();\n\tif (bytes === undefined) return undefined;\n\tif (!bytes?.length) return null;\n\treturn { bytes, mimeType: detectSupportedImageMimeType(bytes) ?? \"application/octet-stream\" };\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tlet image: ClipboardImage | null | undefined;\n\n\tif (platform === \"linux\") {\n\t\tconst wsl = isWSL(env);\n\t\tif (isWaylandSession(env) || wsl) {\n\t\t\timage = await readClipboardImageViaWlPaste();\n\t\t}\n\t\tif (image === undefined) image = await readClipboardImageViaXclip();\n\t\t// Preserve Linux's empty/unavailable distinction if Windows has no image.\n\t\tif (!image && wsl) image = (await readClipboardImageViaPowerShell()) ?? image;\n\t\tif (image === undefined) image = await readClipboardImageViaNativeClipboard();\n\t} else {\n\t\timage = await readClipboardImageViaNativeClipboard();\n\t}\n\n\tif (!image) {\n\t\treturn null;\n\t}\n\n\t// Convert unsupported formats (e.g., Windows DIB data wrapped as BMP) to PNG\n\tif (!isSupportedImageMimeType(image.mimeType)) {\n\t\tconst pngBytes = await convertToPng(image.bytes);\n\t\tif (!pngBytes) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { bytes: pngBytes, mimeType: \"image/png\" };\n\t}\n\n\treturn image;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"AAmDA,iDAAiD;AACjD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBhE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsGjE","sourcesContent":["import { type ExecFileSyncOptionsWithStringEncoding, execFileSync, execSync, spawn } from \"child_process\";\nimport { platform } from \"os\";\nimport { isWaylandSession } from \"./clipboard-image.ts\";\nimport { clipboard } from \"./clipboard-native.ts\";\n\ntype NativeClipboardExecOptions = {\n\tinput: string;\n\ttimeout: number;\n\tstdio: [\"pipe\", \"ignore\", \"ignore\"];\n};\n\nfunction copyToX11Clipboard(options: NativeClipboardExecOptions): void {\n\ttry {\n\t\texecSync(\"xclip -selection clipboard\", options);\n\t} catch {\n\t\texecSync(\"xsel --clipboard --input\", options);\n\t}\n}\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\ntype ClipboardReadResult = { ok: true; text: string | null } | { ok: false };\n\nconst READ_CLIPBOARD_OPTIONS: ExecFileSyncOptionsWithStringEncoding = {\n\tencoding: \"utf8\",\n\tmaxBuffer: 50 * 1024 * 1024,\n\ttimeout: 5000,\n};\n\nfunction readWaylandClipboardText(): ClipboardReadResult {\n\ttry {\n\t\tconst text = execFileSync(\"wl-paste\", [\"--no-newline\", \"--type\", \"text\"], READ_CLIPBOARD_OPTIONS);\n\t\treturn { ok: true, text: text || null };\n\t} catch {\n\t\treturn { ok: false };\n\t}\n}\n\n/** Read plain text from the system clipboard. */\nexport async function readClipboardText(): Promise<string | null> {\n\tif (platform() === \"linux\" && isWaylandSession() && process.env.WAYLAND_DISPLAY) {\n\t\tconst result = readWaylandClipboardText();\n\t\tif (result.ok) {\n\t\t\treturn result.text;\n\t\t}\n\t}\n\n\tif (!clipboard) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst text = await clipboard.getText();\n\t\treturn text || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tlet copied = false;\n\n\tconst p = platform();\n\n\t// Prefer direct clipboard writes. Emitting OSC 52 first can make terminals\n\t// write the same native clipboard concurrently with the addon, and very large\n\t// OSC 52 payloads can desynchronize terminal rendering.\n\t//\n\t// On Linux, skip the native addon. The underlying `clipboard-rs` crate is\n\t// X11-only and does not retain selection ownership after `set_text`\n\t// resolves, so on Wayland-only compositors (Hyprland, Niri, ...) and even\n\t// some X11 sessions the call resolves successfully without populating the\n\t// clipboard. The platform tools below (wl-copy, xclip, xsel) properly\n\t// daemonize and keep ownership.\n\ttry {\n\t\tif (clipboard && p !== \"linux\") {\n\t\t\tawait clipboard.setText(text);\n\t\t\tcopied = true;\n\t\t}\n\t} catch {\n\t\t// Fall through to platform-specific clipboard tools.\n\t}\n\n\tconst remote = isRemoteSession();\n\tif (copied && !remote) {\n\t\treturn;\n\t}\n\n\tconst options: NativeClipboardExecOptions = { input: text, timeout: 5000, stdio: [\"pipe\", \"ignore\", \"ignore\"] };\n\n\tif (!copied) {\n\t\ttry {\n\t\t\tif (p === \"darwin\") {\n\t\t\t\texecSync(\"pbcopy\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else if (p === \"win32\") {\n\t\t\t\texecSync(\"clip\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else {\n\t\t\t\t// Linux. Try Termux, Wayland, or X11 clipboard tools.\n\t\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\texecSync(\"termux-clipboard-set\", options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to Wayland or X11 tools.\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!copied) {\n\t\t\t\t\tconst hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);\n\t\t\t\t\tconst hasX11Display = Boolean(process.env.DISPLAY);\n\t\t\t\t\tconst isWayland = isWaylandSession();\n\t\t\t\t\tif (isWayland && hasWaylandDisplay) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Verify wl-copy exists (spawn errors are async and won't be caught)\n\t\t\t\t\t\t\texecSync(\"which wl-copy\", { stdio: \"ignore\" });\n\t\t\t\t\t\t\t// wl-copy with execSync hangs due to fork behavior; use spawn instead.\n\t\t\t\t\t\t\t// Await the exit code and only claim success on a clean exit, so a\n\t\t\t\t\t\t\t// failed wl-copy falls through to the xclip/OSC 52 fallbacks.\n\t\t\t\t\t\t\tconst wlCopyExit = await new Promise<number>((resolve) => {\n\t\t\t\t\t\t\t\tconst proc = spawn(\"wl-copy\", [], { stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n\t\t\t\t\t\t\t\tproc.on(\"error\", () => resolve(1));\n\t\t\t\t\t\t\t\tproc.on(\"close\", (code) => resolve(code ?? 1));\n\t\t\t\t\t\t\t\tproc.stdin.on(\"error\", () => {\n\t\t\t\t\t\t\t\t\t// Ignore EPIPE errors if wl-copy exits early\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tproc.stdin.write(text);\n\t\t\t\t\t\t\t\tproc.stdin.end();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (wlCopyExit === 0) {\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tif (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to OSC 52 fallback.\n\t\t}\n\t}\n\n\tif (remote || !copied) {\n\t\tconst osc52Copied = emitOsc52(text);\n\t\tcopied = copied || osc52Copied;\n\t}\n\n\tif (!copied) {\n\t\tthrow new Error(\"Failed to copy to clipboard\");\n\t}\n}\n"]}
1
+ {"version":3,"file":"clipboard.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"AAmBA,iDAAiD;AACjD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBhE;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkDjE","sourcesContent":["import { platform } from \"node:os\";\nimport { getNativeClipboard } from \"@earendil-works/pi-tui\";\nimport { runClipboardCommand } from \"./clipboard-command.ts\";\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\n/** Read plain text from the system clipboard. */\nexport async function readClipboardText(): Promise<string | null> {\n\tif (platform() === \"linux\") {\n\t\tconst commands: [string, string[]][] = [];\n\t\tif (process.env.TERMUX_VERSION) commands.push([\"termux-clipboard-get\", []]);\n\t\tif (process.env.WAYLAND_DISPLAY) commands.push([\"wl-paste\", [\"--no-newline\", \"--type\", \"text\"]]);\n\t\tif (process.env.DISPLAY) {\n\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\", \"-out\"]], [\"xsel\", [\"--clipboard\", \"--output\"]]);\n\t\t}\n\t\tfor (const [command, args] of commands) {\n\t\t\tconst bytes = await runClipboardCommand(command, args, { timeoutMs: 5000 });\n\t\t\tif (bytes !== undefined) return bytes.toString(\"utf8\") || null;\n\t\t}\n\t}\n\ttry {\n\t\treturn (await getNativeClipboard()?.getText()) || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tconst p = platform();\n\tlet copied = false;\n\t// Direct writes precede OSC 52 so the terminal cannot race the native writer.\n\t// Linux tools retain clipboard selection ownership after this call returns.\n\tif (p !== \"linux\") {\n\t\ttry {\n\t\t\tconst clipboard = getNativeClipboard();\n\t\t\tif (clipboard?.setText) {\n\t\t\t\tawait clipboard.setText(text);\n\t\t\t\tcopied = true;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try platform commands next.\n\t\t}\n\t}\n\tif (!copied) {\n\t\tconst commands: [string, string[]][] = [];\n\t\tif (p === \"darwin\") commands.push([\"pbcopy\", []]);\n\t\telse if (p === \"win32\") commands.push([\"clip\", []]);\n\t\telse {\n\t\t\tif (process.env.TERMUX_VERSION) commands.push([\"termux-clipboard-set\", []]);\n\t\t\tif (process.env.WAYLAND_DISPLAY) commands.push([\"wl-copy\", []]);\n\t\t\tif (process.env.DISPLAY) {\n\t\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\"]], [\"xsel\", [\"--clipboard\", \"--input\"]]);\n\t\t\t}\n\t\t}\n\t\tfor (const [command, args] of commands) {\n\t\t\tif ((await runClipboardCommand(command, args, { input: text, timeoutMs: 5000 })) !== undefined) {\n\t\t\t\tcopied = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tif (isRemoteSession()) copied = emitOsc52(text) || copied;\n\tif (!copied) {\n\t\tif (p === \"linux\") {\n\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\tthrow new Error(\"Clipboard unavailable: install the Termux:API app and `termux-api` package\");\n\t\t\t}\n\t\t\tif (process.env.WAYLAND_DISPLAY) {\n\t\t\t\tthrow new Error(\"Clipboard unavailable: install `wl-clipboard` (`wl-copy`) or check Wayland access\");\n\t\t\t}\n\t\t\tif (process.env.DISPLAY) {\n\t\t\t\tthrow new Error(\"Clipboard unavailable: install `xclip` or `xsel`, or check X11 access\");\n\t\t\t}\n\t\t\tthrow new Error(\"Clipboard unavailable: no Wayland or X11 display detected\");\n\t\t}\n\t\tthrow new Error(\"Clipboard unavailable\");\n\t}\n}\n"]}
@@ -1,15 +1,6 @@
1
- import { execFileSync, execSync, spawn } from "child_process";
2
- import { platform } from "os";
3
- import { isWaylandSession } from "./clipboard-image.js";
4
- import { clipboard } from "./clipboard-native.js";
5
- function copyToX11Clipboard(options) {
6
- try {
7
- execSync("xclip -selection clipboard", options);
8
- }
9
- catch {
10
- execSync("xsel --clipboard --input", options);
11
- }
12
- }
1
+ import { platform } from "node:os";
2
+ import { getNativeClipboard } from "@earendil-works/pi-tui";
3
+ import { runClipboardCommand } from "./clipboard-command.js";
13
4
  const MAX_OSC52_ENCODED_LENGTH = 100_000;
14
5
  function isRemoteSession(env = process.env) {
15
6
  return Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);
@@ -22,140 +13,85 @@ function emitOsc52(text) {
22
13
  process.stdout.write(`\x1b]52;c;${encoded}\x07`);
23
14
  return true;
24
15
  }
25
- const READ_CLIPBOARD_OPTIONS = {
26
- encoding: "utf8",
27
- maxBuffer: 50 * 1024 * 1024,
28
- timeout: 5000,
29
- };
30
- function readWaylandClipboardText() {
31
- try {
32
- const text = execFileSync("wl-paste", ["--no-newline", "--type", "text"], READ_CLIPBOARD_OPTIONS);
33
- return { ok: true, text: text || null };
34
- }
35
- catch {
36
- return { ok: false };
37
- }
38
- }
39
16
  /** Read plain text from the system clipboard. */
40
17
  export async function readClipboardText() {
41
- if (platform() === "linux" && isWaylandSession() && process.env.WAYLAND_DISPLAY) {
42
- const result = readWaylandClipboardText();
43
- if (result.ok) {
44
- return result.text;
18
+ if (platform() === "linux") {
19
+ const commands = [];
20
+ if (process.env.TERMUX_VERSION)
21
+ commands.push(["termux-clipboard-get", []]);
22
+ if (process.env.WAYLAND_DISPLAY)
23
+ commands.push(["wl-paste", ["--no-newline", "--type", "text"]]);
24
+ if (process.env.DISPLAY) {
25
+ commands.push(["xclip", ["-selection", "clipboard", "-out"]], ["xsel", ["--clipboard", "--output"]]);
26
+ }
27
+ for (const [command, args] of commands) {
28
+ const bytes = await runClipboardCommand(command, args, { timeoutMs: 5000 });
29
+ if (bytes !== undefined)
30
+ return bytes.toString("utf8") || null;
45
31
  }
46
- }
47
- if (!clipboard) {
48
- return null;
49
32
  }
50
33
  try {
51
- const text = await clipboard.getText();
52
- return text || null;
34
+ return (await getNativeClipboard()?.getText()) || null;
53
35
  }
54
36
  catch {
55
37
  return null;
56
38
  }
57
39
  }
58
40
  export async function copyToClipboard(text) {
59
- let copied = false;
60
41
  const p = platform();
61
- // Prefer direct clipboard writes. Emitting OSC 52 first can make terminals
62
- // write the same native clipboard concurrently with the addon, and very large
63
- // OSC 52 payloads can desynchronize terminal rendering.
64
- //
65
- // On Linux, skip the native addon. The underlying `clipboard-rs` crate is
66
- // X11-only and does not retain selection ownership after `set_text`
67
- // resolves, so on Wayland-only compositors (Hyprland, Niri, ...) and even
68
- // some X11 sessions the call resolves successfully without populating the
69
- // clipboard. The platform tools below (wl-copy, xclip, xsel) properly
70
- // daemonize and keep ownership.
71
- try {
72
- if (clipboard && p !== "linux") {
73
- await clipboard.setText(text);
74
- copied = true;
75
- }
76
- }
77
- catch {
78
- // Fall through to platform-specific clipboard tools.
79
- }
80
- const remote = isRemoteSession();
81
- if (copied && !remote) {
82
- return;
83
- }
84
- const options = { input: text, timeout: 5000, stdio: ["pipe", "ignore", "ignore"] };
85
- if (!copied) {
42
+ let copied = false;
43
+ // Direct writes precede OSC 52 so the terminal cannot race the native writer.
44
+ // Linux tools retain clipboard selection ownership after this call returns.
45
+ if (p !== "linux") {
86
46
  try {
87
- if (p === "darwin") {
88
- execSync("pbcopy", options);
47
+ const clipboard = getNativeClipboard();
48
+ if (clipboard?.setText) {
49
+ await clipboard.setText(text);
89
50
  copied = true;
90
51
  }
91
- else if (p === "win32") {
92
- execSync("clip", options);
93
- copied = true;
94
- }
95
- else {
96
- // Linux. Try Termux, Wayland, or X11 clipboard tools.
97
- if (process.env.TERMUX_VERSION) {
98
- try {
99
- execSync("termux-clipboard-set", options);
100
- copied = true;
101
- }
102
- catch {
103
- // Fall back to Wayland or X11 tools.
104
- }
105
- }
106
- if (!copied) {
107
- const hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);
108
- const hasX11Display = Boolean(process.env.DISPLAY);
109
- const isWayland = isWaylandSession();
110
- if (isWayland && hasWaylandDisplay) {
111
- try {
112
- // Verify wl-copy exists (spawn errors are async and won't be caught)
113
- execSync("which wl-copy", { stdio: "ignore" });
114
- // wl-copy with execSync hangs due to fork behavior; use spawn instead.
115
- // Await the exit code and only claim success on a clean exit, so a
116
- // failed wl-copy falls through to the xclip/OSC 52 fallbacks.
117
- const wlCopyExit = await new Promise((resolve) => {
118
- const proc = spawn("wl-copy", [], { stdio: ["pipe", "ignore", "ignore"] });
119
- proc.on("error", () => resolve(1));
120
- proc.on("close", (code) => resolve(code ?? 1));
121
- proc.stdin.on("error", () => {
122
- // Ignore EPIPE errors if wl-copy exits early
123
- });
124
- proc.stdin.write(text);
125
- proc.stdin.end();
126
- });
127
- if (wlCopyExit === 0) {
128
- copied = true;
129
- }
130
- else if (hasX11Display) {
131
- copyToX11Clipboard(options);
132
- copied = true;
133
- }
134
- }
135
- catch {
136
- if (hasX11Display) {
137
- copyToX11Clipboard(options);
138
- copied = true;
139
- }
140
- }
141
- }
142
- else if (hasX11Display) {
143
- copyToX11Clipboard(options);
144
- copied = true;
145
- }
146
- }
147
- }
148
52
  }
149
53
  catch {
150
- // Fall through to OSC 52 fallback.
54
+ // Try platform commands next.
151
55
  }
152
56
  }
153
- if (remote || !copied) {
154
- const osc52Copied = emitOsc52(text);
155
- copied = copied || osc52Copied;
57
+ if (!copied) {
58
+ const commands = [];
59
+ if (p === "darwin")
60
+ commands.push(["pbcopy", []]);
61
+ else if (p === "win32")
62
+ commands.push(["clip", []]);
63
+ else {
64
+ if (process.env.TERMUX_VERSION)
65
+ commands.push(["termux-clipboard-set", []]);
66
+ if (process.env.WAYLAND_DISPLAY)
67
+ commands.push(["wl-copy", []]);
68
+ if (process.env.DISPLAY) {
69
+ commands.push(["xclip", ["-selection", "clipboard"]], ["xsel", ["--clipboard", "--input"]]);
70
+ }
71
+ }
72
+ for (const [command, args] of commands) {
73
+ if ((await runClipboardCommand(command, args, { input: text, timeoutMs: 5000 })) !== undefined) {
74
+ copied = true;
75
+ break;
76
+ }
77
+ }
156
78
  }
79
+ if (isRemoteSession())
80
+ copied = emitOsc52(text) || copied;
157
81
  if (!copied) {
158
- throw new Error("Failed to copy to clipboard");
82
+ if (p === "linux") {
83
+ if (process.env.TERMUX_VERSION) {
84
+ throw new Error("Clipboard unavailable: install the Termux:API app and `termux-api` package");
85
+ }
86
+ if (process.env.WAYLAND_DISPLAY) {
87
+ throw new Error("Clipboard unavailable: install `wl-clipboard` (`wl-copy`) or check Wayland access");
88
+ }
89
+ if (process.env.DISPLAY) {
90
+ throw new Error("Clipboard unavailable: install `xclip` or `xsel`, or check X11 access");
91
+ }
92
+ throw new Error("Clipboard unavailable: no Wayland or X11 display detected");
93
+ }
94
+ throw new Error("Clipboard unavailable");
159
95
  }
160
96
  }
161
97
  //# sourceMappingURL=clipboard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8C,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC1G,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAC;AAC9B,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAQlD,SAAS,kBAAkB,CAAC,OAAmC,EAAQ;IACtE,IAAI,CAAC;QACJ,QAAQ,CAAC,4BAA4B,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACR,QAAQ,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;AAAA,CACD;AAED,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAEzC,SAAS,eAAe,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAAW;IACvE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC;AAAA,CAC5E;AAED,SAAS,SAAS,CAAC,IAAY,EAAW;IACzC,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrD,IAAI,OAAO,CAAC,MAAM,GAAG,wBAAwB,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACd,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,OAAO,MAAM,CAAC,CAAC;IACjD,OAAO,IAAI,CAAC;AAAA,CACZ;AAID,MAAM,sBAAsB,GAA0C;IACrE,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;IAC3B,OAAO,EAAE,IAAI;CACb,CAAC;AAEF,SAAS,wBAAwB,GAAwB;IACxD,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,EAAE,CAAC,cAAc,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,sBAAsB,CAAC,CAAC;QAClG,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;IACtB,CAAC;AAAA,CACD;AAED,iDAAiD;AACjD,MAAM,CAAC,KAAK,UAAU,iBAAiB,GAA2B;IACjE,IAAI,QAAQ,EAAE,KAAK,OAAO,IAAI,gBAAgB,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC;QACjF,MAAM,MAAM,GAAG,wBAAwB,EAAE,CAAC;QAC1C,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,MAAM,CAAC,IAAI,CAAC;QACpB,CAAC;IACF,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE,CAAC;QACvC,OAAO,IAAI,IAAI,IAAI,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AAAA,CACD;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAiB;IAClE,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IAErB,2EAA2E;IAC3E,8EAA8E;IAC9E,wDAAwD;IACxD,EAAE;IACF,0EAA0E;IAC1E,oEAAoE;IACpE,0EAA0E;IAC1E,0EAA0E;IAC1E,sEAAsE;IACtE,gCAAgC;IAChC,IAAI,CAAC;QACJ,IAAI,SAAS,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;YAChC,MAAM,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAC9B,MAAM,GAAG,IAAI,CAAC;QACf,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,qDAAqD;IACtD,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO;IACR,CAAC;IAED,MAAM,OAAO,GAA+B,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC;IAEhH,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,IAAI,CAAC;YACJ,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;gBACpB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;gBAC5B,MAAM,GAAG,IAAI,CAAC;YACf,CAAC;iBAAM,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;gBAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAC1B,MAAM,GAAG,IAAI,CAAC;YACf,CAAC;iBAAM,CAAC;gBACP,sDAAsD;gBACtD,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC;oBAChC,IAAI,CAAC;wBACJ,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;wBAC1C,MAAM,GAAG,IAAI,CAAC;oBACf,CAAC;oBAAC,MAAM,CAAC;wBACR,qCAAqC;oBACtC,CAAC;gBACF,CAAC;gBAED,IAAI,CAAC,MAAM,EAAE,CAAC;oBACb,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;oBAC/D,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;oBACnD,MAAM,SAAS,GAAG,gBAAgB,EAAE,CAAC;oBACrC,IAAI,SAAS,IAAI,iBAAiB,EAAE,CAAC;wBACpC,IAAI,CAAC;4BACJ,qEAAqE;4BACrE,QAAQ,CAAC,eAAe,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;4BAC/C,uEAAuE;4BACvE,mEAAmE;4BACnE,8DAA8D;4BAC9D,MAAM,UAAU,GAAG,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE,CAAC;gCACzD,MAAM,IAAI,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;gCAC3E,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gCACnC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;gCAC/C,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;oCAC5B,6CAA6C;gCADhB,CAE7B,CAAC,CAAC;gCACH,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gCACvB,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;4BAAA,CACjB,CAAC,CAAC;4BACH,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;gCACtB,MAAM,GAAG,IAAI,CAAC;4BACf,CAAC;iCAAM,IAAI,aAAa,EAAE,CAAC;gCAC1B,kBAAkB,CAAC,OAAO,CAAC,CAAC;gCAC5B,MAAM,GAAG,IAAI,CAAC;4BACf,CAAC;wBACF,CAAC;wBAAC,MAAM,CAAC;4BACR,IAAI,aAAa,EAAE,CAAC;gCACnB,kBAAkB,CAAC,OAAO,CAAC,CAAC;gCAC5B,MAAM,GAAG,IAAI,CAAC;4BACf,CAAC;wBACF,CAAC;oBACF,CAAC;yBAAM,IAAI,aAAa,EAAE,CAAC;wBAC1B,kBAAkB,CAAC,OAAO,CAAC,CAAC;wBAC5B,MAAM,GAAG,IAAI,CAAC;oBACf,CAAC;gBACF,CAAC;YACF,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,mCAAmC;QACpC,CAAC;IACF,CAAC;IAED,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,GAAG,MAAM,IAAI,WAAW,CAAC;IAChC,CAAC;IAED,IAAI,CAAC,MAAM,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IAChD,CAAC;AAAA,CACD","sourcesContent":["import { type ExecFileSyncOptionsWithStringEncoding, execFileSync, execSync, spawn } from \"child_process\";\nimport { platform } from \"os\";\nimport { isWaylandSession } from \"./clipboard-image.ts\";\nimport { clipboard } from \"./clipboard-native.ts\";\n\ntype NativeClipboardExecOptions = {\n\tinput: string;\n\ttimeout: number;\n\tstdio: [\"pipe\", \"ignore\", \"ignore\"];\n};\n\nfunction copyToX11Clipboard(options: NativeClipboardExecOptions): void {\n\ttry {\n\t\texecSync(\"xclip -selection clipboard\", options);\n\t} catch {\n\t\texecSync(\"xsel --clipboard --input\", options);\n\t}\n}\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\ntype ClipboardReadResult = { ok: true; text: string | null } | { ok: false };\n\nconst READ_CLIPBOARD_OPTIONS: ExecFileSyncOptionsWithStringEncoding = {\n\tencoding: \"utf8\",\n\tmaxBuffer: 50 * 1024 * 1024,\n\ttimeout: 5000,\n};\n\nfunction readWaylandClipboardText(): ClipboardReadResult {\n\ttry {\n\t\tconst text = execFileSync(\"wl-paste\", [\"--no-newline\", \"--type\", \"text\"], READ_CLIPBOARD_OPTIONS);\n\t\treturn { ok: true, text: text || null };\n\t} catch {\n\t\treturn { ok: false };\n\t}\n}\n\n/** Read plain text from the system clipboard. */\nexport async function readClipboardText(): Promise<string | null> {\n\tif (platform() === \"linux\" && isWaylandSession() && process.env.WAYLAND_DISPLAY) {\n\t\tconst result = readWaylandClipboardText();\n\t\tif (result.ok) {\n\t\t\treturn result.text;\n\t\t}\n\t}\n\n\tif (!clipboard) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst text = await clipboard.getText();\n\t\treturn text || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tlet copied = false;\n\n\tconst p = platform();\n\n\t// Prefer direct clipboard writes. Emitting OSC 52 first can make terminals\n\t// write the same native clipboard concurrently with the addon, and very large\n\t// OSC 52 payloads can desynchronize terminal rendering.\n\t//\n\t// On Linux, skip the native addon. The underlying `clipboard-rs` crate is\n\t// X11-only and does not retain selection ownership after `set_text`\n\t// resolves, so on Wayland-only compositors (Hyprland, Niri, ...) and even\n\t// some X11 sessions the call resolves successfully without populating the\n\t// clipboard. The platform tools below (wl-copy, xclip, xsel) properly\n\t// daemonize and keep ownership.\n\ttry {\n\t\tif (clipboard && p !== \"linux\") {\n\t\t\tawait clipboard.setText(text);\n\t\t\tcopied = true;\n\t\t}\n\t} catch {\n\t\t// Fall through to platform-specific clipboard tools.\n\t}\n\n\tconst remote = isRemoteSession();\n\tif (copied && !remote) {\n\t\treturn;\n\t}\n\n\tconst options: NativeClipboardExecOptions = { input: text, timeout: 5000, stdio: [\"pipe\", \"ignore\", \"ignore\"] };\n\n\tif (!copied) {\n\t\ttry {\n\t\t\tif (p === \"darwin\") {\n\t\t\t\texecSync(\"pbcopy\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else if (p === \"win32\") {\n\t\t\t\texecSync(\"clip\", options);\n\t\t\t\tcopied = true;\n\t\t\t} else {\n\t\t\t\t// Linux. Try Termux, Wayland, or X11 clipboard tools.\n\t\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\texecSync(\"termux-clipboard-set\", options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Fall back to Wayland or X11 tools.\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!copied) {\n\t\t\t\t\tconst hasWaylandDisplay = Boolean(process.env.WAYLAND_DISPLAY);\n\t\t\t\t\tconst hasX11Display = Boolean(process.env.DISPLAY);\n\t\t\t\t\tconst isWayland = isWaylandSession();\n\t\t\t\t\tif (isWayland && hasWaylandDisplay) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// Verify wl-copy exists (spawn errors are async and won't be caught)\n\t\t\t\t\t\t\texecSync(\"which wl-copy\", { stdio: \"ignore\" });\n\t\t\t\t\t\t\t// wl-copy with execSync hangs due to fork behavior; use spawn instead.\n\t\t\t\t\t\t\t// Await the exit code and only claim success on a clean exit, so a\n\t\t\t\t\t\t\t// failed wl-copy falls through to the xclip/OSC 52 fallbacks.\n\t\t\t\t\t\t\tconst wlCopyExit = await new Promise<number>((resolve) => {\n\t\t\t\t\t\t\t\tconst proc = spawn(\"wl-copy\", [], { stdio: [\"pipe\", \"ignore\", \"ignore\"] });\n\t\t\t\t\t\t\t\tproc.on(\"error\", () => resolve(1));\n\t\t\t\t\t\t\t\tproc.on(\"close\", (code) => resolve(code ?? 1));\n\t\t\t\t\t\t\t\tproc.stdin.on(\"error\", () => {\n\t\t\t\t\t\t\t\t\t// Ignore EPIPE errors if wl-copy exits early\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\tproc.stdin.write(text);\n\t\t\t\t\t\t\t\tproc.stdin.end();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (wlCopyExit === 0) {\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tif (hasX11Display) {\n\t\t\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (hasX11Display) {\n\t\t\t\t\t\tcopyToX11Clipboard(options);\n\t\t\t\t\t\tcopied = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through to OSC 52 fallback.\n\t\t}\n\t}\n\n\tif (remote || !copied) {\n\t\tconst osc52Copied = emitOsc52(text);\n\t\tcopied = copied || osc52Copied;\n\t}\n\n\tif (!copied) {\n\t\tthrow new Error(\"Failed to copy to clipboard\");\n\t}\n}\n"]}
1
+ {"version":3,"file":"clipboard.js","sourceRoot":"","sources":["../../src/utils/clipboard.ts"],"names":[],"mappings":"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","sourcesContent":["import { platform } from \"node:os\";\nimport { getNativeClipboard } from \"@earendil-works/pi-tui\";\nimport { runClipboardCommand } from \"./clipboard-command.ts\";\n\nconst MAX_OSC52_ENCODED_LENGTH = 100_000;\n\nfunction isRemoteSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.SSH_CONNECTION || env.SSH_CLIENT || env.MOSH_CONNECTION);\n}\n\nfunction emitOsc52(text: string): boolean {\n\tconst encoded = Buffer.from(text).toString(\"base64\");\n\tif (encoded.length > MAX_OSC52_ENCODED_LENGTH) {\n\t\treturn false;\n\t}\n\tprocess.stdout.write(`\\x1b]52;c;${encoded}\\x07`);\n\treturn true;\n}\n\n/** Read plain text from the system clipboard. */\nexport async function readClipboardText(): Promise<string | null> {\n\tif (platform() === \"linux\") {\n\t\tconst commands: [string, string[]][] = [];\n\t\tif (process.env.TERMUX_VERSION) commands.push([\"termux-clipboard-get\", []]);\n\t\tif (process.env.WAYLAND_DISPLAY) commands.push([\"wl-paste\", [\"--no-newline\", \"--type\", \"text\"]]);\n\t\tif (process.env.DISPLAY) {\n\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\", \"-out\"]], [\"xsel\", [\"--clipboard\", \"--output\"]]);\n\t\t}\n\t\tfor (const [command, args] of commands) {\n\t\t\tconst bytes = await runClipboardCommand(command, args, { timeoutMs: 5000 });\n\t\t\tif (bytes !== undefined) return bytes.toString(\"utf8\") || null;\n\t\t}\n\t}\n\ttry {\n\t\treturn (await getNativeClipboard()?.getText()) || null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function copyToClipboard(text: string): Promise<void> {\n\tconst p = platform();\n\tlet copied = false;\n\t// Direct writes precede OSC 52 so the terminal cannot race the native writer.\n\t// Linux tools retain clipboard selection ownership after this call returns.\n\tif (p !== \"linux\") {\n\t\ttry {\n\t\t\tconst clipboard = getNativeClipboard();\n\t\t\tif (clipboard?.setText) {\n\t\t\t\tawait clipboard.setText(text);\n\t\t\t\tcopied = true;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Try platform commands next.\n\t\t}\n\t}\n\tif (!copied) {\n\t\tconst commands: [string, string[]][] = [];\n\t\tif (p === \"darwin\") commands.push([\"pbcopy\", []]);\n\t\telse if (p === \"win32\") commands.push([\"clip\", []]);\n\t\telse {\n\t\t\tif (process.env.TERMUX_VERSION) commands.push([\"termux-clipboard-set\", []]);\n\t\t\tif (process.env.WAYLAND_DISPLAY) commands.push([\"wl-copy\", []]);\n\t\t\tif (process.env.DISPLAY) {\n\t\t\t\tcommands.push([\"xclip\", [\"-selection\", \"clipboard\"]], [\"xsel\", [\"--clipboard\", \"--input\"]]);\n\t\t\t}\n\t\t}\n\t\tfor (const [command, args] of commands) {\n\t\t\tif ((await runClipboardCommand(command, args, { input: text, timeoutMs: 5000 })) !== undefined) {\n\t\t\t\tcopied = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tif (isRemoteSession()) copied = emitOsc52(text) || copied;\n\tif (!copied) {\n\t\tif (p === \"linux\") {\n\t\t\tif (process.env.TERMUX_VERSION) {\n\t\t\t\tthrow new Error(\"Clipboard unavailable: install the Termux:API app and `termux-api` package\");\n\t\t\t}\n\t\t\tif (process.env.WAYLAND_DISPLAY) {\n\t\t\t\tthrow new Error(\"Clipboard unavailable: install `wl-clipboard` (`wl-copy`) or check Wayland access\");\n\t\t\t}\n\t\t\tif (process.env.DISPLAY) {\n\t\t\t\tthrow new Error(\"Clipboard unavailable: install `xclip` or `xsel`, or check X11 access\");\n\t\t\t}\n\t\t\tthrow new Error(\"Clipboard unavailable: no Wayland or X11 display detected\");\n\t\t}\n\t\tthrow new Error(\"Clipboard unavailable\");\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAiB9D;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAkCtC;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAYvG","sourcesContent":["import { compare, valid } from \"semver\";\nimport { fetchWithRetry } from \"./management-http.ts\";\nimport { getPiUserAgent } from \"./pi-user-agent.ts\";\n\nconst LATEST_VERSION_URL = \"https://pi.dev/api/latest-version\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\n/** Include useful errno details hidden behind Node's generic \"fetch failed\" error. */\nexport function formatVersionCheckError(error: unknown): string {\n\tconst rootMessage = error instanceof Error && error.message ? error.message : String(error);\n\tconst cause = error instanceof Error ? error.cause : undefined;\n\tconst causes = cause instanceof AggregateError ? cause.errors : cause === undefined ? [] : [cause];\n\tconst codes = causes\n\t\t.map((value) =>\n\t\t\ttypeof value === \"object\" && value !== null && \"code\" in value && typeof value.code === \"string\"\n\t\t\t\t? value.code\n\t\t\t\t: undefined,\n\t\t)\n\t\t.filter((code): code is string => code !== undefined);\n\n\tif (codes.length > 0) return `${rootMessage} (${[...new Set(codes)].join(\", \")})`;\n\tconst causeMessage = causes.find(\n\t\t(value): value is Error => value instanceof Error && Boolean(value.message),\n\t)?.message;\n\treturn causeMessage ? `${rootMessage} (cause: ${causeMessage})` : rootMessage;\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = valid(leftVersion.trim());\n\tconst right = valid(rightVersion.trim());\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\treturn compare(left, right);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_OFFLINE) return undefined;\n\n\tconst response = await fetchWithRetry(\n\t\tLATEST_VERSION_URL,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\t\taccept: \"application/json\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmaxRetries: options.retry ? 2 : 0,\n\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS,\n\t\t},\n\t);\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackageName?: unknown;\n\t\tversion?: unknown;\n\t\tnote?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.packageName === \"string\" && data.packageName.trim() ? data.packageName.trim() : undefined;\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\tpackageName,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestPiRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,sFAAsF;AACtF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAiB9D;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAOpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAa/F;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAkCtC;AAED,wBAAsB,kBAAkB,CACvC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACnD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAYvG","sourcesContent":["import { compare, major, minor, patch, valid } from \"semver\";\nimport { fetchWithRetry } from \"./management-http.ts\";\nimport { getPiUserAgent } from \"./pi-user-agent.ts\";\n\nconst LATEST_VERSION_URL = \"https://pi.dev/api/latest-version\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\n/** Include useful errno details hidden behind Node's generic \"fetch failed\" error. */\nexport function formatVersionCheckError(error: unknown): string {\n\tconst rootMessage = error instanceof Error && error.message ? error.message : String(error);\n\tconst cause = error instanceof Error ? error.cause : undefined;\n\tconst causes = cause instanceof AggregateError ? cause.errors : cause === undefined ? [] : [cause];\n\tconst codes = causes\n\t\t.map((value) =>\n\t\t\ttypeof value === \"object\" && value !== null && \"code\" in value && typeof value.code === \"string\"\n\t\t\t\t? value.code\n\t\t\t\t: undefined,\n\t\t)\n\t\t.filter((code): code is string => code !== undefined);\n\n\tif (codes.length > 0) return `${rootMessage} (${[...new Set(codes)].join(\", \")})`;\n\tconst causeMessage = causes.find(\n\t\t(value): value is Error => value instanceof Error && Boolean(value.message),\n\t)?.message;\n\treturn causeMessage ? `${rootMessage} (cause: ${causeMessage})` : rootMessage;\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = valid(leftVersion.trim());\n\tconst right = valid(rightVersion.trim());\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\treturn compare(left, right);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst left = valid(candidateVersion.trim());\n\tconst right = valid(currentVersion.trim());\n\tif (left !== null && right !== null) {\n\t\t// Compare core versions only: fork builds stamp the base release with a\n\t\t// namespace suffix (0.85.1+namespace.1 in the workspace, 0.85.1-namespace.N\n\t\t// on the npm alias), and semver orders any prerelease below its release —\n\t\t// so the same upstream release must not count as newer than the fork\n\t\t// build of it.\n\t\tconst core = (version: string) => `${major(version)}.${minor(version)}.${patch(version)}`;\n\t\treturn compare(core(left), core(right)) > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_OFFLINE) return undefined;\n\n\tconst response = await fetchWithRetry(\n\t\tLATEST_VERSION_URL,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\t\taccept: \"application/json\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmaxRetries: options.retry ? 2 : 0,\n\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS,\n\t\t},\n\t);\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackageName?: unknown;\n\t\tversion?: unknown;\n\t\tnote?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.packageName === \"string\" && data.packageName.trim() ? data.packageName.trim() : undefined;\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\tpackageName,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestPiRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { compare, valid } from "semver";
1
+ import { compare, major, minor, patch, valid } from "semver";
2
2
  import { fetchWithRetry } from "./management-http.js";
3
3
  import { getPiUserAgent } from "./pi-user-agent.js";
4
4
  const LATEST_VERSION_URL = "https://pi.dev/api/latest-version";
@@ -27,9 +27,16 @@ export function comparePackageVersions(leftVersion, rightVersion) {
27
27
  return compare(left, right);
28
28
  }
29
29
  export function isNewerPackageVersion(candidateVersion, currentVersion) {
30
- const comparison = comparePackageVersions(candidateVersion, currentVersion);
31
- if (comparison !== undefined) {
32
- return comparison > 0;
30
+ const left = valid(candidateVersion.trim());
31
+ const right = valid(currentVersion.trim());
32
+ if (left !== null && right !== null) {
33
+ // Compare core versions only: fork builds stamp the base release with a
34
+ // namespace suffix (0.85.1+namespace.1 in the workspace, 0.85.1-namespace.N
35
+ // on the npm alias), and semver orders any prerelease below its release —
36
+ // so the same upstream release must not count as newer than the fork
37
+ // build of it.
38
+ const core = (version) => `${major(version)}.${minor(version)}.${patch(version)}`;
39
+ return compare(core(left), core(right)) > 0;
33
40
  }
34
41
  return candidateVersion.trim() !== currentVersion.trim();
35
42
  }
@@ -1 +1 @@
1
- {"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,kBAAkB,GAAG,mCAAmC,CAAC;AAC/D,MAAM,gCAAgC,GAAG,KAAK,CAAC;AAQ/C,sFAAsF;AACtF,MAAM,UAAU,uBAAuB,CAAC,KAAc,EAAU;IAC/D,MAAM,WAAW,GAAG,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5F,MAAM,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,MAAM,MAAM,GAAG,KAAK,YAAY,cAAc,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACnG,MAAM,KAAK,GAAG,MAAM;SAClB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CACd,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC/F,CAAC,CAAC,KAAK,CAAC,IAAI;QACZ,CAAC,CAAC,SAAS,CACZ;SACA,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC;IAEvD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,GAAG,WAAW,KAAK,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;IAClF,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAC/B,CAAC,KAAK,EAAkB,EAAE,CAAC,KAAK,YAAY,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAC3E,EAAE,OAAO,CAAC;IACX,OAAO,YAAY,CAAC,CAAC,CAAC,GAAG,WAAW,YAAY,YAAY,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC;AAAA,CAC9E;AAED,MAAM,UAAU,sBAAsB,CAAC,WAAmB,EAAE,YAAoB,EAAsB;IACrG,MAAM,IAAI,GAAG,KAAK,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAAA,CAC5B;AAED,MAAM,UAAU,qBAAqB,CAAC,gBAAwB,EAAE,cAAsB,EAAW;IAChG,MAAM,UAAU,GAAG,sBAAsB,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;IAC5E,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,UAAU,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,gBAAgB,CAAC,IAAI,EAAE,KAAK,cAAc,CAAC,IAAI,EAAE,CAAC;AAAA,CACzD;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,cAAsB,EACtB,OAAO,GAA4C,EAAE,EACd;IACvC,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU;QAAE,OAAO,SAAS,CAAC;IAE7C,MAAM,QAAQ,GAAG,MAAM,cAAc,CACpC,kBAAkB,EAClB;QACC,OAAO,EAAE;YACR,YAAY,EAAE,cAAc,CAAC,cAAc,CAAC;YAC5C,MAAM,EAAE,kBAAkB;SAC1B;KACD,EACD;QACC,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,gCAAgC;KAChE,CACD,CAAC;IACF,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAEnC,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAIlC,CAAC;IACF,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9D,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,MAAM,WAAW,GAChB,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACvG,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9F,OAAO;QACN,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;QAC5B,WAAW;QACX,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzB,CAAC;AAAA,CACF;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACvC,cAAsB,EACtB,OAAO,GAA4C,EAAE,EACvB;IAC9B,OAAO,CAAC,MAAM,kBAAkB,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC;AAAA,CACpE;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,cAAsB,EAAwC;IACxG,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB;QAAE,OAAO,SAAS,CAAC;IAExD,IAAI,CAAC;QACJ,MAAM,aAAa,GAAG,MAAM,kBAAkB,CAAC,cAAc,CAAC,CAAC;QAC/D,IAAI,aAAa,IAAI,qBAAqB,CAAC,aAAa,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,CAAC;YACnF,OAAO,aAAa,CAAC;QACtB,CAAC;QACD,OAAO,SAAS,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AAAA,CACD","sourcesContent":["import { compare, valid } from \"semver\";\nimport { fetchWithRetry } from \"./management-http.ts\";\nimport { getPiUserAgent } from \"./pi-user-agent.ts\";\n\nconst LATEST_VERSION_URL = \"https://pi.dev/api/latest-version\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\n/** Include useful errno details hidden behind Node's generic \"fetch failed\" error. */\nexport function formatVersionCheckError(error: unknown): string {\n\tconst rootMessage = error instanceof Error && error.message ? error.message : String(error);\n\tconst cause = error instanceof Error ? error.cause : undefined;\n\tconst causes = cause instanceof AggregateError ? cause.errors : cause === undefined ? [] : [cause];\n\tconst codes = causes\n\t\t.map((value) =>\n\t\t\ttypeof value === \"object\" && value !== null && \"code\" in value && typeof value.code === \"string\"\n\t\t\t\t? value.code\n\t\t\t\t: undefined,\n\t\t)\n\t\t.filter((code): code is string => code !== undefined);\n\n\tif (codes.length > 0) return `${rootMessage} (${[...new Set(codes)].join(\", \")})`;\n\tconst causeMessage = causes.find(\n\t\t(value): value is Error => value instanceof Error && Boolean(value.message),\n\t)?.message;\n\treturn causeMessage ? `${rootMessage} (cause: ${causeMessage})` : rootMessage;\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = valid(leftVersion.trim());\n\tconst right = valid(rightVersion.trim());\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\treturn compare(left, right);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_OFFLINE) return undefined;\n\n\tconst response = await fetchWithRetry(\n\t\tLATEST_VERSION_URL,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\t\taccept: \"application/json\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmaxRetries: options.retry ? 2 : 0,\n\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS,\n\t\t},\n\t);\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackageName?: unknown;\n\t\tversion?: unknown;\n\t\tnote?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.packageName === \"string\" && data.packageName.trim() ? data.packageName.trim() : undefined;\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\tpackageName,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestPiRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { compare, major, minor, patch, valid } from \"semver\";\nimport { fetchWithRetry } from \"./management-http.ts\";\nimport { getPiUserAgent } from \"./pi-user-agent.ts\";\n\nconst LATEST_VERSION_URL = \"https://pi.dev/api/latest-version\";\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestPiRelease {\n\tversion: string;\n\tpackageName?: string;\n\tnote?: string;\n}\n\n/** Include useful errno details hidden behind Node's generic \"fetch failed\" error. */\nexport function formatVersionCheckError(error: unknown): string {\n\tconst rootMessage = error instanceof Error && error.message ? error.message : String(error);\n\tconst cause = error instanceof Error ? error.cause : undefined;\n\tconst causes = cause instanceof AggregateError ? cause.errors : cause === undefined ? [] : [cause];\n\tconst codes = causes\n\t\t.map((value) =>\n\t\t\ttypeof value === \"object\" && value !== null && \"code\" in value && typeof value.code === \"string\"\n\t\t\t\t? value.code\n\t\t\t\t: undefined,\n\t\t)\n\t\t.filter((code): code is string => code !== undefined);\n\n\tif (codes.length > 0) return `${rootMessage} (${[...new Set(codes)].join(\", \")})`;\n\tconst causeMessage = causes.find(\n\t\t(value): value is Error => value instanceof Error && Boolean(value.message),\n\t)?.message;\n\treturn causeMessage ? `${rootMessage} (cause: ${causeMessage})` : rootMessage;\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = valid(leftVersion.trim());\n\tconst right = valid(rightVersion.trim());\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\treturn compare(left, right);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst left = valid(candidateVersion.trim());\n\tconst right = valid(currentVersion.trim());\n\tif (left !== null && right !== null) {\n\t\t// Compare core versions only: fork builds stamp the base release with a\n\t\t// namespace suffix (0.85.1+namespace.1 in the workspace, 0.85.1-namespace.N\n\t\t// on the npm alias), and semver orders any prerelease below its release —\n\t\t// so the same upstream release must not count as newer than the fork\n\t\t// build of it.\n\t\tconst core = (version: string) => `${major(version)}.${minor(version)}.${patch(version)}`;\n\t\treturn compare(core(left), core(right)) > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestPiRelease(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_OFFLINE) return undefined;\n\n\tconst response = await fetchWithRetry(\n\t\tLATEST_VERSION_URL,\n\t\t{\n\t\t\theaders: {\n\t\t\t\t\"User-Agent\": getPiUserAgent(currentVersion),\n\t\t\t\taccept: \"application/json\",\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tmaxRetries: options.retry ? 2 : 0,\n\t\t\ttimeoutMs: options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS,\n\t\t},\n\t);\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as {\n\t\tpackageName?: unknown;\n\t\tversion?: unknown;\n\t\tnote?: unknown;\n\t};\n\tif (typeof data.version !== \"string\" || !data.version.trim()) {\n\t\treturn undefined;\n\t}\n\tconst packageName =\n\t\ttypeof data.packageName === \"string\" && data.packageName.trim() ? data.packageName.trim() : undefined;\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion: data.version.trim(),\n\t\tpackageName,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestPiVersion(\n\tcurrentVersion: string,\n\toptions: { timeoutMs?: number; retry?: boolean } = {},\n): Promise<string | undefined> {\n\treturn (await getLatestPiRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewPiVersion(currentVersion: string): Promise<LatestPiRelease | undefined> {\n\tif (process.env.PI_SKIP_VERSION_CHECK) return undefined;\n\n\ttry {\n\t\tconst latestRelease = await getLatestPiRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
@@ -0,0 +1,7 @@
1
+ interface ZipEntry {
2
+ name: string;
3
+ data: string | Uint8Array;
4
+ }
5
+ export declare function writeZipArchive(filePath: string, entries: readonly ZipEntry[]): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=zip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/utils/zip.ts"],"names":[],"mappings":"AAGA,UAAU,QAAQ;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;CAC1B;AA+DD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7F","sourcesContent":["import { writeFile } from \"node:fs/promises\";\nimport { crc32, deflateRawSync } from \"node:zlib\";\n\ninterface ZipEntry {\n\tname: string;\n\tdata: string | Uint8Array;\n}\n\nfunction dosDateTime(date: Date): { time: number; day: number } {\n\treturn {\n\t\ttime: (date.getHours() << 11) | (date.getMinutes() << 5) | (date.getSeconds() >> 1),\n\t\tday: ((Math.max(1980, date.getFullYear()) - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(),\n\t};\n}\n\n/** Create the small, classic ZIP archives used by bug reports. */\nfunction createZipArchive(entries: readonly ZipEntry[]): Buffer {\n\tconst files: Buffer[] = [];\n\tconst directory: Buffer[] = [];\n\tconst { time, day } = dosDateTime(new Date());\n\tlet offset = 0;\n\n\tfor (const entry of entries) {\n\t\tconst name = Buffer.from(entry.name);\n\t\tconst data = typeof entry.data === \"string\" ? Buffer.from(entry.data) : Buffer.from(entry.data);\n\t\tconst compressed = deflateRawSync(data);\n\t\tconst checksum = crc32(data);\n\n\t\tconst local = Buffer.alloc(30);\n\t\tlocal.writeUInt32LE(0x04034b50, 0);\n\t\tlocal.writeUInt16LE(20, 4);\n\t\tlocal.writeUInt16LE(0x0800, 6);\n\t\tlocal.writeUInt16LE(8, 8);\n\t\tlocal.writeUInt16LE(time, 10);\n\t\tlocal.writeUInt16LE(day, 12);\n\t\tlocal.writeUInt32LE(checksum, 14);\n\t\tlocal.writeUInt32LE(compressed.length, 18);\n\t\tlocal.writeUInt32LE(data.length, 22);\n\t\tlocal.writeUInt16LE(name.length, 26);\n\n\t\tconst central = Buffer.alloc(46);\n\t\tcentral.writeUInt32LE(0x02014b50, 0);\n\t\tcentral.writeUInt16LE(20, 4);\n\t\tcentral.writeUInt16LE(20, 6);\n\t\tcentral.writeUInt16LE(0x0800, 8);\n\t\tcentral.writeUInt16LE(8, 10);\n\t\tcentral.writeUInt16LE(time, 12);\n\t\tcentral.writeUInt16LE(day, 14);\n\t\tcentral.writeUInt32LE(checksum, 16);\n\t\tcentral.writeUInt32LE(compressed.length, 20);\n\t\tcentral.writeUInt32LE(data.length, 24);\n\t\tcentral.writeUInt16LE(name.length, 28);\n\t\tcentral.writeUInt32LE(offset, 42);\n\n\t\tfiles.push(local, name, compressed);\n\t\tdirectory.push(central, name);\n\t\toffset += local.length + name.length + compressed.length;\n\t}\n\n\tconst centralDirectory = Buffer.concat(directory);\n\tconst end = Buffer.alloc(22);\n\tend.writeUInt32LE(0x06054b50, 0);\n\tend.writeUInt16LE(entries.length, 8);\n\tend.writeUInt16LE(entries.length, 10);\n\tend.writeUInt32LE(centralDirectory.length, 12);\n\tend.writeUInt32LE(offset, 16);\n\treturn Buffer.concat([...files, centralDirectory, end]);\n}\n\nexport function writeZipArchive(filePath: string, entries: readonly ZipEntry[]): Promise<void> {\n\treturn writeFile(filePath, createZipArchive(entries));\n}\n"]}
@@ -0,0 +1,60 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { crc32, deflateRawSync } from "node:zlib";
3
+ function dosDateTime(date) {
4
+ return {
5
+ time: (date.getHours() << 11) | (date.getMinutes() << 5) | (date.getSeconds() >> 1),
6
+ day: ((Math.max(1980, date.getFullYear()) - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(),
7
+ };
8
+ }
9
+ /** Create the small, classic ZIP archives used by bug reports. */
10
+ function createZipArchive(entries) {
11
+ const files = [];
12
+ const directory = [];
13
+ const { time, day } = dosDateTime(new Date());
14
+ let offset = 0;
15
+ for (const entry of entries) {
16
+ const name = Buffer.from(entry.name);
17
+ const data = typeof entry.data === "string" ? Buffer.from(entry.data) : Buffer.from(entry.data);
18
+ const compressed = deflateRawSync(data);
19
+ const checksum = crc32(data);
20
+ const local = Buffer.alloc(30);
21
+ local.writeUInt32LE(0x04034b50, 0);
22
+ local.writeUInt16LE(20, 4);
23
+ local.writeUInt16LE(0x0800, 6);
24
+ local.writeUInt16LE(8, 8);
25
+ local.writeUInt16LE(time, 10);
26
+ local.writeUInt16LE(day, 12);
27
+ local.writeUInt32LE(checksum, 14);
28
+ local.writeUInt32LE(compressed.length, 18);
29
+ local.writeUInt32LE(data.length, 22);
30
+ local.writeUInt16LE(name.length, 26);
31
+ const central = Buffer.alloc(46);
32
+ central.writeUInt32LE(0x02014b50, 0);
33
+ central.writeUInt16LE(20, 4);
34
+ central.writeUInt16LE(20, 6);
35
+ central.writeUInt16LE(0x0800, 8);
36
+ central.writeUInt16LE(8, 10);
37
+ central.writeUInt16LE(time, 12);
38
+ central.writeUInt16LE(day, 14);
39
+ central.writeUInt32LE(checksum, 16);
40
+ central.writeUInt32LE(compressed.length, 20);
41
+ central.writeUInt32LE(data.length, 24);
42
+ central.writeUInt16LE(name.length, 28);
43
+ central.writeUInt32LE(offset, 42);
44
+ files.push(local, name, compressed);
45
+ directory.push(central, name);
46
+ offset += local.length + name.length + compressed.length;
47
+ }
48
+ const centralDirectory = Buffer.concat(directory);
49
+ const end = Buffer.alloc(22);
50
+ end.writeUInt32LE(0x06054b50, 0);
51
+ end.writeUInt16LE(entries.length, 8);
52
+ end.writeUInt16LE(entries.length, 10);
53
+ end.writeUInt32LE(centralDirectory.length, 12);
54
+ end.writeUInt32LE(offset, 16);
55
+ return Buffer.concat([...files, centralDirectory, end]);
56
+ }
57
+ export function writeZipArchive(filePath, entries) {
58
+ return writeFile(filePath, createZipArchive(entries));
59
+ }
60
+ //# sourceMappingURL=zip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/utils/zip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAOlD,SAAS,WAAW,CAAC,IAAU,EAAiC;IAC/D,OAAO;QACN,IAAI,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QACnF,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE;KACvG,CAAC;AAAA,CACF;AAED,kEAAkE;AAClE,SAAS,gBAAgB,CAAC,OAA4B,EAAU;IAC/D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,WAAW,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9C,IAAI,MAAM,GAAG,CAAC,CAAC;IAEf,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChG,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QAE7B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC/B,KAAK,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QACnC,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC3B,KAAK,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC/B,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1B,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9B,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC7B,KAAK,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAClC,KAAK,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3C,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACrC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAErC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjC,OAAO,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QACrC,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC7B,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC7B,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACjC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7B,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAChC,OAAO,CAAC,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC/B,OAAO,CAAC,aAAa,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAElC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;QACpC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC1D,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAClD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7B,GAAG,CAAC,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;IACjC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACrC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACtC,GAAG,CAAC,aAAa,CAAC,gBAAgB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC/C,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC9B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,EAAE,gBAAgB,EAAE,GAAG,CAAC,CAAC,CAAC;AAAA,CACxD;AAED,MAAM,UAAU,eAAe,CAAC,QAAgB,EAAE,OAA4B,EAAiB;IAC9F,OAAO,SAAS,CAAC,QAAQ,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;AAAA,CACtD","sourcesContent":["import { writeFile } from \"node:fs/promises\";\nimport { crc32, deflateRawSync } from \"node:zlib\";\n\ninterface ZipEntry {\n\tname: string;\n\tdata: string | Uint8Array;\n}\n\nfunction dosDateTime(date: Date): { time: number; day: number } {\n\treturn {\n\t\ttime: (date.getHours() << 11) | (date.getMinutes() << 5) | (date.getSeconds() >> 1),\n\t\tday: ((Math.max(1980, date.getFullYear()) - 1980) << 9) | ((date.getMonth() + 1) << 5) | date.getDate(),\n\t};\n}\n\n/** Create the small, classic ZIP archives used by bug reports. */\nfunction createZipArchive(entries: readonly ZipEntry[]): Buffer {\n\tconst files: Buffer[] = [];\n\tconst directory: Buffer[] = [];\n\tconst { time, day } = dosDateTime(new Date());\n\tlet offset = 0;\n\n\tfor (const entry of entries) {\n\t\tconst name = Buffer.from(entry.name);\n\t\tconst data = typeof entry.data === \"string\" ? Buffer.from(entry.data) : Buffer.from(entry.data);\n\t\tconst compressed = deflateRawSync(data);\n\t\tconst checksum = crc32(data);\n\n\t\tconst local = Buffer.alloc(30);\n\t\tlocal.writeUInt32LE(0x04034b50, 0);\n\t\tlocal.writeUInt16LE(20, 4);\n\t\tlocal.writeUInt16LE(0x0800, 6);\n\t\tlocal.writeUInt16LE(8, 8);\n\t\tlocal.writeUInt16LE(time, 10);\n\t\tlocal.writeUInt16LE(day, 12);\n\t\tlocal.writeUInt32LE(checksum, 14);\n\t\tlocal.writeUInt32LE(compressed.length, 18);\n\t\tlocal.writeUInt32LE(data.length, 22);\n\t\tlocal.writeUInt16LE(name.length, 26);\n\n\t\tconst central = Buffer.alloc(46);\n\t\tcentral.writeUInt32LE(0x02014b50, 0);\n\t\tcentral.writeUInt16LE(20, 4);\n\t\tcentral.writeUInt16LE(20, 6);\n\t\tcentral.writeUInt16LE(0x0800, 8);\n\t\tcentral.writeUInt16LE(8, 10);\n\t\tcentral.writeUInt16LE(time, 12);\n\t\tcentral.writeUInt16LE(day, 14);\n\t\tcentral.writeUInt32LE(checksum, 16);\n\t\tcentral.writeUInt32LE(compressed.length, 20);\n\t\tcentral.writeUInt32LE(data.length, 24);\n\t\tcentral.writeUInt16LE(name.length, 28);\n\t\tcentral.writeUInt32LE(offset, 42);\n\n\t\tfiles.push(local, name, compressed);\n\t\tdirectory.push(central, name);\n\t\toffset += local.length + name.length + compressed.length;\n\t}\n\n\tconst centralDirectory = Buffer.concat(directory);\n\tconst end = Buffer.alloc(22);\n\tend.writeUInt32LE(0x06054b50, 0);\n\tend.writeUInt16LE(entries.length, 8);\n\tend.writeUInt16LE(entries.length, 10);\n\tend.writeUInt32LE(centralDirectory.length, 12);\n\tend.writeUInt32LE(offset, 16);\n\treturn Buffer.concat([...files, centralDirectory, end]);\n}\n\nexport function writeZipArchive(filePath: string, entries: readonly ZipEntry[]): Promise<void> {\n\treturn writeFile(filePath, createZipArchive(entries));\n}\n"]}