open-multi-agent-kit 0.98.3 → 0.98.5

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 (468) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +12 -2
  3. package/dist/cli/args.d.ts +1 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +14 -0
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/help.d.ts.map +1 -1
  8. package/dist/cli/help.js +3 -0
  9. package/dist/cli/help.js.map +1 -1
  10. package/dist/cli/mcp-attach.d.ts +3 -3
  11. package/dist/cli/mcp-attach.d.ts.map +1 -1
  12. package/dist/cli/mcp-attach.js +5 -4
  13. package/dist/cli/mcp-attach.js.map +1 -1
  14. package/dist/cli/model-contract.d.ts +5 -0
  15. package/dist/cli/model-contract.d.ts.map +1 -0
  16. package/dist/cli/model-contract.js +45 -0
  17. package/dist/cli/model-contract.js.map +1 -0
  18. package/dist/commands/adaptorch-doctor-cli.d.ts.map +1 -1
  19. package/dist/commands/adaptorch-doctor-cli.js +32 -10
  20. package/dist/commands/adaptorch-doctor-cli.js.map +1 -1
  21. package/dist/commands/init-cli.d.ts +12 -0
  22. package/dist/commands/init-cli.d.ts.map +1 -0
  23. package/dist/commands/init-cli.js +76 -0
  24. package/dist/commands/init-cli.js.map +1 -0
  25. package/dist/commands/provider-sync-cli.d.ts +27 -0
  26. package/dist/commands/provider-sync-cli.d.ts.map +1 -0
  27. package/dist/commands/provider-sync-cli.js +177 -0
  28. package/dist/commands/provider-sync-cli.js.map +1 -0
  29. package/dist/commands/run-command.d.ts +9 -0
  30. package/dist/commands/run-command.d.ts.map +1 -0
  31. package/dist/commands/run-command.js +34 -0
  32. package/dist/commands/run-command.js.map +1 -0
  33. package/dist/commands/verified-run-cli.d.ts +6 -0
  34. package/dist/commands/verified-run-cli.d.ts.map +1 -0
  35. package/dist/commands/verified-run-cli.js +190 -0
  36. package/dist/commands/verified-run-cli.js.map +1 -0
  37. package/dist/core/active-skill-state.d.ts +7 -0
  38. package/dist/core/active-skill-state.d.ts.map +1 -0
  39. package/dist/core/active-skill-state.js +25 -0
  40. package/dist/core/active-skill-state.js.map +1 -0
  41. package/dist/core/agent-session-services.d.ts +10 -1
  42. package/dist/core/agent-session-services.d.ts.map +1 -1
  43. package/dist/core/agent-session-services.js +43 -0
  44. package/dist/core/agent-session-services.js.map +1 -1
  45. package/dist/core/agent-session.d.ts +7 -9
  46. package/dist/core/agent-session.d.ts.map +1 -1
  47. package/dist/core/agent-session.js +91 -126
  48. package/dist/core/agent-session.js.map +1 -1
  49. package/dist/core/codex-chatgpt-web-bridge.d.ts +99 -0
  50. package/dist/core/codex-chatgpt-web-bridge.d.ts.map +1 -0
  51. package/dist/core/codex-chatgpt-web-bridge.js +192 -0
  52. package/dist/core/codex-chatgpt-web-bridge.js.map +1 -0
  53. package/dist/core/codex-chatgpt-web-sync.d.ts +50 -0
  54. package/dist/core/codex-chatgpt-web-sync.d.ts.map +1 -0
  55. package/dist/core/codex-chatgpt-web-sync.js +119 -0
  56. package/dist/core/codex-chatgpt-web-sync.js.map +1 -0
  57. package/dist/core/compaction/compaction-headroom.d.ts +30 -0
  58. package/dist/core/compaction/compaction-headroom.d.ts.map +1 -0
  59. package/dist/core/compaction/compaction-headroom.js +48 -0
  60. package/dist/core/compaction/compaction-headroom.js.map +1 -0
  61. package/dist/core/compaction/compaction.d.ts +2 -29
  62. package/dist/core/compaction/compaction.d.ts.map +1 -1
  63. package/dist/core/compaction/compaction.js +19 -47
  64. package/dist/core/compaction/compaction.js.map +1 -1
  65. package/dist/core/compaction/overflow-retry-guard.d.ts +20 -0
  66. package/dist/core/compaction/overflow-retry-guard.d.ts.map +1 -0
  67. package/dist/core/compaction/overflow-retry-guard.js +38 -0
  68. package/dist/core/compaction/overflow-retry-guard.js.map +1 -0
  69. package/dist/core/context-budget-headroom-types.d.ts.map +1 -1
  70. package/dist/core/context-budget-headroom-types.js +1 -1
  71. package/dist/core/context-budget-headroom-types.js.map +1 -1
  72. package/dist/core/context-budget-token-counter-types.d.ts +27 -0
  73. package/dist/core/context-budget-token-counter-types.d.ts.map +1 -0
  74. package/dist/core/context-budget-token-counter-types.js +2 -0
  75. package/dist/core/context-budget-token-counter-types.js.map +1 -0
  76. package/dist/core/context-budget-token-counter.d.ts +2 -26
  77. package/dist/core/context-budget-token-counter.d.ts.map +1 -1
  78. package/dist/core/context-budget-token-counter.js +2 -0
  79. package/dist/core/context-budget-token-counter.js.map +1 -1
  80. package/dist/core/context-budget-v2-scoring.d.ts.map +1 -1
  81. package/dist/core/context-budget-v2-scoring.js +14 -10
  82. package/dist/core/context-budget-v2-scoring.js.map +1 -1
  83. package/dist/core/domain-router.d.ts.map +1 -1
  84. package/dist/core/domain-router.js +1 -1
  85. package/dist/core/domain-router.js.map +1 -1
  86. package/dist/core/grok-harness-dispatch.d.ts +4 -0
  87. package/dist/core/grok-harness-dispatch.d.ts.map +1 -1
  88. package/dist/core/grok-harness-dispatch.js +20 -3
  89. package/dist/core/grok-harness-dispatch.js.map +1 -1
  90. package/dist/core/grok-harness.d.ts +15 -9
  91. package/dist/core/grok-harness.d.ts.map +1 -1
  92. package/dist/core/grok-harness.js +34 -8
  93. package/dist/core/grok-harness.js.map +1 -1
  94. package/dist/core/mcp/tools.d.ts +2 -2
  95. package/dist/core/mcp/tools.d.ts.map +1 -1
  96. package/dist/core/mcp/tools.js +29 -3
  97. package/dist/core/mcp/tools.js.map +1 -1
  98. package/dist/core/model-registry-schema.d.ts +1081 -0
  99. package/dist/core/model-registry-schema.d.ts.map +1 -0
  100. package/dist/core/model-registry-schema.js +148 -0
  101. package/dist/core/model-registry-schema.js.map +1 -0
  102. package/dist/core/model-registry.d.ts.map +1 -1
  103. package/dist/core/model-registry.js +1 -146
  104. package/dist/core/model-registry.js.map +1 -1
  105. package/dist/core/model-resolver.d.ts +2 -1
  106. package/dist/core/model-resolver.d.ts.map +1 -1
  107. package/dist/core/model-resolver.js +2 -1
  108. package/dist/core/model-resolver.js.map +1 -1
  109. package/dist/core/prompt-preset.d.ts +1 -1
  110. package/dist/core/prompt-preset.d.ts.map +1 -1
  111. package/dist/core/prompt-preset.js +16 -1
  112. package/dist/core/prompt-preset.js.map +1 -1
  113. package/dist/core/prompt-settlement.d.ts +4 -3
  114. package/dist/core/prompt-settlement.d.ts.map +1 -1
  115. package/dist/core/prompt-settlement.js.map +1 -1
  116. package/dist/core/provider-display-names.d.ts.map +1 -1
  117. package/dist/core/provider-display-names.js +1 -0
  118. package/dist/core/provider-display-names.js.map +1 -1
  119. package/dist/core/provider-resilience.d.ts +8 -0
  120. package/dist/core/provider-resilience.d.ts.map +1 -1
  121. package/dist/core/provider-resilience.js +20 -3
  122. package/dist/core/provider-resilience.js.map +1 -1
  123. package/dist/core/provider-usage-types.d.ts +42 -0
  124. package/dist/core/provider-usage-types.d.ts.map +1 -0
  125. package/dist/core/provider-usage-types.js +2 -0
  126. package/dist/core/provider-usage-types.js.map +1 -0
  127. package/dist/core/provider-usage.d.ts +2 -31
  128. package/dist/core/provider-usage.d.ts.map +1 -1
  129. package/dist/core/provider-usage.js +4 -0
  130. package/dist/core/provider-usage.js.map +1 -1
  131. package/dist/core/redaction.d.ts.map +1 -1
  132. package/dist/core/redaction.js +18 -2
  133. package/dist/core/redaction.js.map +1 -1
  134. package/dist/core/run-budget-policy.d.ts +18 -0
  135. package/dist/core/run-budget-policy.d.ts.map +1 -0
  136. package/dist/core/run-budget-policy.js +52 -0
  137. package/dist/core/run-budget-policy.js.map +1 -0
  138. package/dist/core/run-budget.d.ts +33 -0
  139. package/dist/core/run-budget.d.ts.map +1 -0
  140. package/dist/core/run-budget.js +89 -0
  141. package/dist/core/run-budget.js.map +1 -0
  142. package/dist/core/run-execution-api.d.ts +15 -0
  143. package/dist/core/run-execution-api.d.ts.map +1 -0
  144. package/dist/core/run-execution-api.js +7 -0
  145. package/dist/core/run-execution-api.js.map +1 -0
  146. package/dist/core/run-journal.d.ts.map +1 -1
  147. package/dist/core/run-journal.js +30 -208
  148. package/dist/core/run-journal.js.map +1 -1
  149. package/dist/core/sandbox/policy-merge.d.ts +6 -0
  150. package/dist/core/sandbox/policy-merge.d.ts.map +1 -0
  151. package/dist/core/sandbox/policy-merge.js +74 -0
  152. package/dist/core/sandbox/policy-merge.js.map +1 -0
  153. package/dist/core/sandbox/policy-paths.d.ts +4 -0
  154. package/dist/core/sandbox/policy-paths.d.ts.map +1 -0
  155. package/dist/core/sandbox/policy-paths.js +21 -0
  156. package/dist/core/sandbox/policy-paths.js.map +1 -0
  157. package/dist/core/sandbox/policy-types.d.ts +75 -0
  158. package/dist/core/sandbox/policy-types.d.ts.map +1 -0
  159. package/dist/core/sandbox/policy-types.js +2 -0
  160. package/dist/core/sandbox/policy-types.js.map +1 -0
  161. package/dist/core/sandbox/policy.d.ts +3 -77
  162. package/dist/core/sandbox/policy.d.ts.map +1 -1
  163. package/dist/core/sandbox/policy.js +3 -98
  164. package/dist/core/sandbox/policy.js.map +1 -1
  165. package/dist/core/sdk-provider-stream.d.ts +14 -0
  166. package/dist/core/sdk-provider-stream.d.ts.map +1 -0
  167. package/dist/core/sdk-provider-stream.js +38 -0
  168. package/dist/core/sdk-provider-stream.js.map +1 -0
  169. package/dist/core/sdk.d.ts +5 -1
  170. package/dist/core/sdk.d.ts.map +1 -1
  171. package/dist/core/sdk.js +17 -33
  172. package/dist/core/sdk.js.map +1 -1
  173. package/dist/core/session-bash-service.d.ts +2 -2
  174. package/dist/core/session-bash-service.d.ts.map +1 -1
  175. package/dist/core/session-bash-service.js +21 -9
  176. package/dist/core/session-bash-service.js.map +1 -1
  177. package/dist/core/session-failure-cause.d.ts.map +1 -1
  178. package/dist/core/session-failure-cause.js +15 -3
  179. package/dist/core/session-failure-cause.js.map +1 -1
  180. package/dist/core/session-prompt-lifecycle.d.ts +25 -0
  181. package/dist/core/session-prompt-lifecycle.d.ts.map +1 -0
  182. package/dist/core/session-prompt-lifecycle.js +87 -0
  183. package/dist/core/session-prompt-lifecycle.js.map +1 -0
  184. package/dist/core/session-run-budget.d.ts +28 -0
  185. package/dist/core/session-run-budget.d.ts.map +1 -0
  186. package/dist/core/session-run-budget.js +127 -0
  187. package/dist/core/session-run-budget.js.map +1 -0
  188. package/dist/core/session-run-termination.d.ts +18 -0
  189. package/dist/core/session-run-termination.d.ts.map +1 -0
  190. package/dist/core/session-run-termination.js +72 -0
  191. package/dist/core/session-run-termination.js.map +1 -0
  192. package/dist/core/session-termination-types.d.ts +97 -0
  193. package/dist/core/session-termination-types.d.ts.map +1 -0
  194. package/dist/core/session-termination-types.js +26 -0
  195. package/dist/core/session-termination-types.js.map +1 -0
  196. package/dist/core/session-termination.d.ts +3 -97
  197. package/dist/core/session-termination.d.ts.map +1 -1
  198. package/dist/core/session-termination.js +25 -29
  199. package/dist/core/session-termination.js.map +1 -1
  200. package/dist/core/skill-selector.d.ts +40 -0
  201. package/dist/core/skill-selector.d.ts.map +1 -0
  202. package/dist/core/skill-selector.js +102 -0
  203. package/dist/core/skill-selector.js.map +1 -0
  204. package/dist/core/slash-commands.d.ts.map +1 -1
  205. package/dist/core/slash-commands.js +1 -0
  206. package/dist/core/slash-commands.js.map +1 -1
  207. package/dist/core/subagent-lane-launcher.d.ts +3 -2
  208. package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
  209. package/dist/core/subagent-lane-launcher.js +24 -13
  210. package/dist/core/subagent-lane-launcher.js.map +1 -1
  211. package/dist/core/tools/render-utils.d.ts.map +1 -1
  212. package/dist/core/tools/render-utils.js +2 -4
  213. package/dist/core/tools/render-utils.js.map +1 -1
  214. package/dist/core/turn-metrics-record.d.ts +55 -0
  215. package/dist/core/turn-metrics-record.d.ts.map +1 -0
  216. package/dist/core/turn-metrics-record.js +149 -0
  217. package/dist/core/turn-metrics-record.js.map +1 -0
  218. package/dist/core/turn-metrics.d.ts +4 -56
  219. package/dist/core/turn-metrics.d.ts.map +1 -1
  220. package/dist/core/turn-metrics.js +12 -60
  221. package/dist/core/turn-metrics.js.map +1 -1
  222. package/dist/core/verified-run/broker.d.ts +26 -0
  223. package/dist/core/verified-run/broker.d.ts.map +1 -0
  224. package/dist/core/verified-run/broker.js +210 -0
  225. package/dist/core/verified-run/broker.js.map +1 -0
  226. package/dist/core/verified-run/candidate.d.ts +24 -0
  227. package/dist/core/verified-run/candidate.d.ts.map +1 -0
  228. package/dist/core/verified-run/candidate.js +167 -0
  229. package/dist/core/verified-run/candidate.js.map +1 -0
  230. package/dist/core/verified-run/check-receipt.d.ts +18 -0
  231. package/dist/core/verified-run/check-receipt.d.ts.map +1 -0
  232. package/dist/core/verified-run/check-receipt.js +92 -0
  233. package/dist/core/verified-run/check-receipt.js.map +1 -0
  234. package/dist/core/verified-run/coordinator.d.ts +39 -0
  235. package/dist/core/verified-run/coordinator.d.ts.map +1 -0
  236. package/dist/core/verified-run/coordinator.js +190 -0
  237. package/dist/core/verified-run/coordinator.js.map +1 -0
  238. package/dist/core/verified-run/dag-candidates.d.ts +8 -0
  239. package/dist/core/verified-run/dag-candidates.d.ts.map +1 -0
  240. package/dist/core/verified-run/dag-candidates.js +65 -0
  241. package/dist/core/verified-run/dag-candidates.js.map +1 -0
  242. package/dist/core/verified-run/dag-phase.d.ts +7 -0
  243. package/dist/core/verified-run/dag-phase.d.ts.map +1 -0
  244. package/dist/core/verified-run/dag-phase.js +92 -0
  245. package/dist/core/verified-run/dag-phase.js.map +1 -0
  246. package/dist/core/verified-run/dag-projection.d.ts +7 -0
  247. package/dist/core/verified-run/dag-projection.d.ts.map +1 -0
  248. package/dist/core/verified-run/dag-projection.js +90 -0
  249. package/dist/core/verified-run/dag-projection.js.map +1 -0
  250. package/dist/core/verified-run/dag-recovery.d.ts +13 -0
  251. package/dist/core/verified-run/dag-recovery.d.ts.map +1 -0
  252. package/dist/core/verified-run/dag-recovery.js +98 -0
  253. package/dist/core/verified-run/dag-recovery.js.map +1 -0
  254. package/dist/core/verified-run/dag-retry-projection.d.ts +9 -0
  255. package/dist/core/verified-run/dag-retry-projection.d.ts.map +1 -0
  256. package/dist/core/verified-run/dag-retry-projection.js +43 -0
  257. package/dist/core/verified-run/dag-retry-projection.js.map +1 -0
  258. package/dist/core/verified-run/dag-types.d.ts +47 -0
  259. package/dist/core/verified-run/dag-types.d.ts.map +1 -0
  260. package/dist/core/verified-run/dag-types.js +2 -0
  261. package/dist/core/verified-run/dag-types.js.map +1 -0
  262. package/dist/core/verified-run/event-parser.d.ts +3 -0
  263. package/dist/core/verified-run/event-parser.d.ts.map +1 -0
  264. package/dist/core/verified-run/event-parser.js +153 -0
  265. package/dist/core/verified-run/event-parser.js.map +1 -0
  266. package/dist/core/verified-run/events.d.ts +4 -0
  267. package/dist/core/verified-run/events.d.ts.map +1 -0
  268. package/dist/core/verified-run/events.js +3 -0
  269. package/dist/core/verified-run/events.js.map +1 -0
  270. package/dist/core/verified-run/evidence-binding.d.ts +18 -0
  271. package/dist/core/verified-run/evidence-binding.d.ts.map +1 -0
  272. package/dist/core/verified-run/evidence-binding.js +81 -0
  273. package/dist/core/verified-run/evidence-binding.js.map +1 -0
  274. package/dist/core/verified-run/evidence.d.ts +27 -0
  275. package/dist/core/verified-run/evidence.d.ts.map +1 -0
  276. package/dist/core/verified-run/evidence.js +100 -0
  277. package/dist/core/verified-run/evidence.js.map +1 -0
  278. package/dist/core/verified-run/journal.d.ts +32 -0
  279. package/dist/core/verified-run/journal.d.ts.map +1 -0
  280. package/dist/core/verified-run/journal.js +103 -0
  281. package/dist/core/verified-run/journal.js.map +1 -0
  282. package/dist/core/verified-run/namespace-identity.d.ts +11 -0
  283. package/dist/core/verified-run/namespace-identity.d.ts.map +1 -0
  284. package/dist/core/verified-run/namespace-identity.js +77 -0
  285. package/dist/core/verified-run/namespace-identity.js.map +1 -0
  286. package/dist/core/verified-run/owned-execution.d.ts +21 -0
  287. package/dist/core/verified-run/owned-execution.d.ts.map +1 -0
  288. package/dist/core/verified-run/owned-execution.js +43 -0
  289. package/dist/core/verified-run/owned-execution.js.map +1 -0
  290. package/dist/core/verified-run/phase-context.d.ts +9 -0
  291. package/dist/core/verified-run/phase-context.d.ts.map +1 -0
  292. package/dist/core/verified-run/phase-context.js +2 -0
  293. package/dist/core/verified-run/phase-context.js.map +1 -0
  294. package/dist/core/verified-run/process-gate.d.ts +5 -0
  295. package/dist/core/verified-run/process-gate.d.ts.map +1 -0
  296. package/dist/core/verified-run/process-gate.js +31 -0
  297. package/dist/core/verified-run/process-gate.js.map +1 -0
  298. package/dist/core/verified-run/projection.d.ts +4 -0
  299. package/dist/core/verified-run/projection.d.ts.map +1 -0
  300. package/dist/core/verified-run/projection.js +219 -0
  301. package/dist/core/verified-run/projection.js.map +1 -0
  302. package/dist/core/verified-run/recovery-clock.d.ts +19 -0
  303. package/dist/core/verified-run/recovery-clock.d.ts.map +1 -0
  304. package/dist/core/verified-run/recovery-clock.js +69 -0
  305. package/dist/core/verified-run/recovery-clock.js.map +1 -0
  306. package/dist/core/verified-run/recovery-command.d.ts +11 -0
  307. package/dist/core/verified-run/recovery-command.d.ts.map +1 -0
  308. package/dist/core/verified-run/recovery-command.js +73 -0
  309. package/dist/core/verified-run/recovery-command.js.map +1 -0
  310. package/dist/core/verified-run/recovery-projection.d.ts +12 -0
  311. package/dist/core/verified-run/recovery-projection.d.ts.map +1 -0
  312. package/dist/core/verified-run/recovery-projection.js +88 -0
  313. package/dist/core/verified-run/recovery-projection.js.map +1 -0
  314. package/dist/core/verified-run/recovery.d.ts +12 -0
  315. package/dist/core/verified-run/recovery.d.ts.map +1 -0
  316. package/dist/core/verified-run/recovery.js +115 -0
  317. package/dist/core/verified-run/recovery.js.map +1 -0
  318. package/dist/core/verified-run/run-types.d.ts +103 -0
  319. package/dist/core/verified-run/run-types.d.ts.map +1 -0
  320. package/dist/core/verified-run/run-types.js +2 -0
  321. package/dist/core/verified-run/run-types.js.map +1 -0
  322. package/dist/core/verified-run/scripted-writer.d.ts +15 -0
  323. package/dist/core/verified-run/scripted-writer.d.ts.map +1 -0
  324. package/dist/core/verified-run/scripted-writer.js +94 -0
  325. package/dist/core/verified-run/scripted-writer.js.map +1 -0
  326. package/dist/core/verified-run/session-port.d.ts +27 -0
  327. package/dist/core/verified-run/session-port.d.ts.map +1 -0
  328. package/dist/core/verified-run/session-port.js +2 -0
  329. package/dist/core/verified-run/session-port.js.map +1 -0
  330. package/dist/core/verified-run/storage.d.ts +15 -0
  331. package/dist/core/verified-run/storage.d.ts.map +1 -0
  332. package/dist/core/verified-run/storage.js +96 -0
  333. package/dist/core/verified-run/storage.js.map +1 -0
  334. package/dist/core/verified-run/verification-phase.d.ts +5 -0
  335. package/dist/core/verified-run/verification-phase.d.ts.map +1 -0
  336. package/dist/core/verified-run/verification-phase.js +56 -0
  337. package/dist/core/verified-run/verification-phase.js.map +1 -0
  338. package/dist/core/verified-run/work-recovery.d.ts +8 -0
  339. package/dist/core/verified-run/work-recovery.d.ts.map +1 -0
  340. package/dist/core/verified-run/work-recovery.js +44 -0
  341. package/dist/core/verified-run/work-recovery.js.map +1 -0
  342. package/dist/core/verified-run/writer-completion.d.ts +4 -0
  343. package/dist/core/verified-run/writer-completion.d.ts.map +1 -0
  344. package/dist/core/verified-run/writer-completion.js +27 -0
  345. package/dist/core/verified-run/writer-completion.js.map +1 -0
  346. package/dist/core/verified-run/writer-phase.d.ts +8 -0
  347. package/dist/core/verified-run/writer-phase.d.ts.map +1 -0
  348. package/dist/core/verified-run/writer-phase.js +76 -0
  349. package/dist/core/verified-run/writer-phase.js.map +1 -0
  350. package/dist/core/verified-run/writer-projection.d.ts +11 -0
  351. package/dist/core/verified-run/writer-projection.d.ts.map +1 -0
  352. package/dist/core/verified-run/writer-projection.js +70 -0
  353. package/dist/core/verified-run/writer-projection.js.map +1 -0
  354. package/dist/core/verified-run/writer-recovery.d.ts +16 -0
  355. package/dist/core/verified-run/writer-recovery.d.ts.map +1 -0
  356. package/dist/core/verified-run/writer-recovery.js +107 -0
  357. package/dist/core/verified-run/writer-recovery.js.map +1 -0
  358. package/dist/core/workload-permit-pool.d.ts +1 -3
  359. package/dist/core/workload-permit-pool.d.ts.map +1 -1
  360. package/dist/core/workload-permit-pool.js +11 -11
  361. package/dist/core/workload-permit-pool.js.map +1 -1
  362. package/dist/guardrails/evidence-system.d.ts +1 -1
  363. package/dist/guardrails/evidence-system.d.ts.map +1 -1
  364. package/dist/guardrails/evidence-system.js +18 -29
  365. package/dist/guardrails/evidence-system.js.map +1 -1
  366. package/dist/guardrails/merge-gate-result.d.ts +4 -0
  367. package/dist/guardrails/merge-gate-result.d.ts.map +1 -0
  368. package/dist/guardrails/merge-gate-result.js +32 -0
  369. package/dist/guardrails/merge-gate-result.js.map +1 -0
  370. package/dist/index.d.ts +3 -2
  371. package/dist/index.d.ts.map +1 -1
  372. package/dist/index.js +2 -2
  373. package/dist/index.js.map +1 -1
  374. package/dist/main.d.ts.map +1 -1
  375. package/dist/main.js +17 -23
  376. package/dist/main.js.map +1 -1
  377. package/dist/modes/interactive/components/session-failure.d.ts +13 -0
  378. package/dist/modes/interactive/components/session-failure.d.ts.map +1 -0
  379. package/dist/modes/interactive/components/session-failure.js +81 -0
  380. package/dist/modes/interactive/components/session-failure.js.map +1 -0
  381. package/dist/modes/interactive/interactive-login-options.d.ts +27 -0
  382. package/dist/modes/interactive/interactive-login-options.d.ts.map +1 -0
  383. package/dist/modes/interactive/interactive-login-options.js +54 -0
  384. package/dist/modes/interactive/interactive-login-options.js.map +1 -0
  385. package/dist/modes/interactive/interactive-mode.d.ts +8 -4
  386. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  387. package/dist/modes/interactive/interactive-mode.js +183 -171
  388. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  389. package/dist/modes/interactive/interactive-resume-command.d.ts +3 -0
  390. package/dist/modes/interactive/interactive-resume-command.d.ts.map +1 -0
  391. package/dist/modes/interactive/interactive-resume-command.js +24 -0
  392. package/dist/modes/interactive/interactive-resume-command.js.map +1 -0
  393. package/dist/modes/interactive/interactive-tool-result.d.ts +32 -0
  394. package/dist/modes/interactive/interactive-tool-result.d.ts.map +1 -0
  395. package/dist/modes/interactive/interactive-tool-result.js +59 -0
  396. package/dist/modes/interactive/interactive-tool-result.js.map +1 -0
  397. package/dist/modes/interactive/tui-diagnostics.d.ts +36 -0
  398. package/dist/modes/interactive/tui-diagnostics.d.ts.map +1 -0
  399. package/dist/modes/interactive/tui-diagnostics.js +105 -0
  400. package/dist/modes/interactive/tui-diagnostics.js.map +1 -0
  401. package/dist/modes/interactive/tui-runtime-info.d.ts +20 -0
  402. package/dist/modes/interactive/tui-runtime-info.d.ts.map +1 -0
  403. package/dist/modes/interactive/tui-runtime-info.js +76 -0
  404. package/dist/modes/interactive/tui-runtime-info.js.map +1 -0
  405. package/dist/modes/print-mode.d.ts.map +1 -1
  406. package/dist/modes/print-mode.js +22 -0
  407. package/dist/modes/print-mode.js.map +1 -1
  408. package/dist/utils/clipboard-image.d.ts.map +1 -1
  409. package/dist/utils/clipboard-image.js +10 -60
  410. package/dist/utils/clipboard-image.js.map +1 -1
  411. package/dist/utils/terminal-links.d.ts +13 -0
  412. package/dist/utils/terminal-links.d.ts.map +1 -0
  413. package/dist/utils/terminal-links.js +68 -0
  414. package/dist/utils/terminal-links.js.map +1 -0
  415. package/dist/utils/windows-clipboard-image.d.ts +16 -0
  416. package/dist/utils/windows-clipboard-image.d.ts.map +1 -0
  417. package/dist/utils/windows-clipboard-image.js +87 -0
  418. package/dist/utils/windows-clipboard-image.js.map +1 -0
  419. package/docs/adaptorch-onboarding.md +80 -0
  420. package/docs/containerization.md +12 -0
  421. package/docs/context-files.md +97 -0
  422. package/docs/correctness-wall.md +8 -0
  423. package/docs/custom-provider.md +35 -0
  424. package/docs/development.md +28 -3
  425. package/docs/environment-variables.md +2 -0
  426. package/docs/grok-harness.md +4 -0
  427. package/docs/harness-boundaries.md +154 -0
  428. package/docs/harness-improvements.md +90 -0
  429. package/docs/json.md +19 -0
  430. package/docs/keybindings.md +2 -2
  431. package/docs/mcp.md +22 -2
  432. package/docs/metrics.md +66 -16
  433. package/docs/model-catalog-refresh.md +190 -0
  434. package/docs/model-contract.md +168 -0
  435. package/docs/models.md +21 -4
  436. package/docs/provider-resilience.md +5 -3
  437. package/docs/providers.md +68 -1
  438. package/docs/quickstart.md +4 -0
  439. package/docs/release-audit-0.98.4.md +112 -0
  440. package/docs/release-audit-0.98.5.md +84 -0
  441. package/docs/review-bundle-followup.md +195 -0
  442. package/docs/run-protocol.md +33 -1
  443. package/docs/runtime-algorithms.md +45 -0
  444. package/docs/sdk.md +204 -2
  445. package/docs/sessions.md +1 -1
  446. package/docs/settings.md +17 -1
  447. package/docs/skills.md +2 -0
  448. package/docs/tb21-audit.md +131 -0
  449. package/docs/terminal-setup.md +20 -0
  450. package/docs/usage.md +77 -1
  451. package/docs/verified-run-testing.md +417 -0
  452. package/docs/verified-run.md +388 -0
  453. package/docs/windows.md +48 -0
  454. package/examples/README.md +4 -0
  455. package/examples/context/AGENTS.md +64 -0
  456. package/examples/context/CLAUDE.md +17 -0
  457. package/examples/context/INTERNET.md +42 -0
  458. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  459. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  460. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  461. package/examples/extensions/gondolin/package-lock.json +2 -2
  462. package/examples/extensions/gondolin/package.json +1 -1
  463. package/examples/extensions/sandbox/package-lock.json +2 -2
  464. package/examples/extensions/sandbox/package.json +1 -1
  465. package/examples/extensions/with-deps/package-lock.json +2 -2
  466. package/examples/extensions/with-deps/package.json +1 -1
  467. package/npm-shrinkwrap.json +18 -18
  468. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `omk -p \"prompt\"` - text output\n * - `omk --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { AssistantMessage, ImageContent } from \"omk-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.ts\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.ts\";\nimport { formatSessionTermination, type SessionTermination } from \"../core/session-termination.ts\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.ts\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet session = runtimeHost.session;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet disposed = false;\n\tlet promptStarted = false;\n\tlet latestTermination: SessionTermination | undefined;\n\tlet renderedTermination: SessionTermination | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst renderTermination = (termination: SessionTermination): void => {\n\t\tif (termination.kind === \"completed\" || renderedTermination === termination) return;\n\t\trenderedTermination = termination;\n\t\tif (mode === \"json\") {\n\t\t\twriteRawStdout(`${JSON.stringify({ type: \"session_termination\", termination })}\\n`);\n\t\t} else {\n\t\t\tconsole.error(formatSessionTermination(termination));\n\t\t}\n\t};\n\n\tconst renderFailure = (fallback: string): void => {\n\t\tconst termination = latestTermination ?? (!promptStarted ? session.lastTermination : undefined);\n\t\tif (termination && termination.kind !== \"completed\") {\n\t\t\trenderTermination(termination);\n\t\t\treturn;\n\t\t}\n\t\tconsole.error(fallback);\n\t};\n\n\tconst disposeRuntime = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait runtimeHost.dispose();\n\t};\n\n\tconst registerSignalHandlers = (): void => {\n\t\tconst signals: Array<\"SIGTERM\" | \"SIGHUP\"> = [\"SIGTERM\"];\n\t\tif (process.platform !== \"win32\") {\n\t\t\tsignals.push(\"SIGHUP\");\n\t\t}\n\n\t\tfor (const signal of signals) {\n\t\t\tconst handler = () => {\n\t\t\t\tsession.recordProcessSignal(signal);\n\t\t\t\tkillTrackedDetachedChildren();\n\t\t\t\tvoid disposeRuntime().finally(() => {\n\t\t\t\t\tprocess.exit(signal === \"SIGHUP\" ? 129 : 143);\n\t\t\t\t});\n\t\t\t};\n\t\t\tprocess.on(signal, handler);\n\t\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t\t}\n\t};\n\n\tregisterSignalHandlers();\n\n\truntimeHost.setRebindSession(async () => {\n\t\tawait rebindSession();\n\t});\n\n\tconst rebindSession = async (): Promise<void> => {\n\t\tsession = runtimeHost.session;\n\t\tpromptStarted = false;\n\t\tlatestTermination = undefined;\n\t\tawait session.bindExtensions({\n\t\t\tmode: mode === \"json\" ? \"json\" : \"print\",\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.agent.waitForIdle(),\n\t\t\t\tnewSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n\t\t\t\tfork: async (entryId, forkOptions) => {\n\t\t\t\t\tconst result = await runtimeHost.fork(entryId, forkOptions);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, navigateOptions) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: navigateOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: navigateOptions?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: navigateOptions?.replaceInstructions,\n\t\t\t\t\t\tlabel: navigateOptions?.label,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath, switchOptions) => {\n\t\t\t\t\treturn runtimeHost.switchSession(sessionPath, switchOptions);\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\tunsubscribe?.();\n\t\tunsubscribe = session.subscribe((event) => {\n\t\t\tif (event.type === \"session_termination\") {\n\t\t\t\tlatestTermination = event.termination;\n\t\t\t\tif (mode === \"text\") {\n\t\t\t\t\trenderTermination(event.termination);\n\t\t\t\t} else {\n\t\t\t\t\trenderedTermination = event.termination;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event)}\\n`);\n\t\t\t}\n\t\t});\n\n\t\tconst startupTermination = session.lastTermination;\n\t\tif (startupTermination?.kind === \"process_crash\" && startupTermination.source === \"inferred_on_resume\") {\n\t\t\trenderTermination(startupTermination);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tawait rebindSession();\n\n\t\tconst hasPrompt =\n\t\t\t!!initialMessage?.trim() ||\n\t\t\tmessages.some((m) => typeof m === \"string\" && m.trim().length > 0) ||\n\t\t\t!!(initialImages && initialImages.length > 0);\n\t\tif (!hasPrompt) {\n\t\t\t// Bare `omk` with no prompt used to exit silently in print mode.\n\t\t\tconsole.error('No prompt provided. Use: omk -p \"...\" or run `omk` in an interactive terminal.');\n\t\t\texitCode = 2;\n\t\t\treturn exitCode;\n\t\t}\n\n\t\tif (initialMessage) {\n\t\t\tpromptStarted = true;\n\t\t\tawait session.prompt(initialMessage, { images: initialImages });\n\t\t}\n\n\t\tfor (const message of messages) {\n\t\t\tpromptStarted = true;\n\t\t\tawait session.prompt(message);\n\t\t}\n\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages[state.messages.length - 1];\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage as AssistantMessage;\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\trenderFailure(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\trenderFailure(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeRuntime();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
1
+ {"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `omk -p \"prompt\"` - text output\n * - `omk --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { AssistantMessage, ImageContent } from \"omk-ai\";\nimport type { AgentSessionRuntime } from \"../core/agent-session-runtime.ts\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.ts\";\nimport type { PromptSettlementOutcome } from \"../core/prompt-settlement.ts\";\nimport { formatSessionTermination, type SessionTermination } from \"../core/session-termination.ts\";\nimport { killTrackedDetachedChildren } from \"../utils/shell.ts\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(runtimeHost: AgentSessionRuntime, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\tlet session = runtimeHost.session;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet disposed = false;\n\tlet promptStarted = false;\n\tlet latestTermination: SessionTermination | undefined;\n\tlet latestOutcome: PromptSettlementOutcome | undefined;\n\tlet renderedTermination: SessionTermination | undefined;\n\tconst signalCleanupHandlers: Array<() => void> = [];\n\n\tconst renderTermination = (termination: SessionTermination): void => {\n\t\tif (termination.kind === \"completed\" || renderedTermination === termination) return;\n\t\trenderedTermination = termination;\n\t\tif (mode === \"json\") {\n\t\t\twriteRawStdout(`${JSON.stringify({ type: \"session_termination\", termination })}\\n`);\n\t\t} else {\n\t\t\tconsole.error(formatSessionTermination(termination));\n\t\t}\n\t};\n\n\tconst renderFailure = (fallback: string): void => {\n\t\tconst termination = latestTermination ?? (!promptStarted ? session.lastTermination : undefined);\n\t\tif (termination && termination.kind !== \"completed\") {\n\t\t\trenderTermination(termination);\n\t\t\treturn;\n\t\t}\n\t\tconsole.error(fallback);\n\t};\n\n\tconst promptFailed = (): boolean => {\n\t\tconst last = session.state.messages.at(-1);\n\t\tconst assistantFailed =\n\t\t\tlast?.role === \"assistant\" && (last.stopReason === \"error\" || last.stopReason === \"aborted\");\n\t\tconst failed =\n\t\t\tlatestOutcome !== undefined\n\t\t\t\t? latestOutcome !== \"completed\"\n\t\t\t\t: assistantFailed || (latestTermination !== undefined && latestTermination.kind !== \"completed\");\n\t\tif (failed)\n\t\t\trenderFailure(\n\t\t\t\tassistantFailed ? last.errorMessage || `Request ${last.stopReason}` : \"Prompt did not complete.\",\n\t\t\t);\n\t\treturn failed;\n\t};\n\n\tconst disposeRuntime = async (): Promise<void> => {\n\t\tif (disposed) return;\n\t\tdisposed = true;\n\t\tunsubscribe?.();\n\t\tawait runtimeHost.dispose();\n\t};\n\n\tconst registerSignalHandlers = (): void => {\n\t\tconst signals: Array<\"SIGTERM\" | \"SIGHUP\"> = [\"SIGTERM\"];\n\t\tif (process.platform !== \"win32\") {\n\t\t\tsignals.push(\"SIGHUP\");\n\t\t}\n\n\t\tfor (const signal of signals) {\n\t\t\tconst handler = () => {\n\t\t\t\tsession.recordProcessSignal(signal);\n\t\t\t\tkillTrackedDetachedChildren();\n\t\t\t\tvoid disposeRuntime().finally(() => {\n\t\t\t\t\tprocess.exit(signal === \"SIGHUP\" ? 129 : 143);\n\t\t\t\t});\n\t\t\t};\n\t\t\tprocess.on(signal, handler);\n\t\t\tsignalCleanupHandlers.push(() => process.off(signal, handler));\n\t\t}\n\t};\n\n\tregisterSignalHandlers();\n\n\truntimeHost.setRebindSession(async () => {\n\t\tawait rebindSession();\n\t});\n\n\tconst rebindSession = async (): Promise<void> => {\n\t\tsession = runtimeHost.session;\n\t\tpromptStarted = false;\n\t\tlatestTermination = undefined;\n\t\tlatestOutcome = undefined;\n\t\tawait session.bindExtensions({\n\t\t\tmode: mode === \"json\" ? \"json\" : \"print\",\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.agent.waitForIdle(),\n\t\t\t\tnewSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),\n\t\t\t\tfork: async (entryId, forkOptions) => {\n\t\t\t\t\tconst result = await runtimeHost.fork(entryId, forkOptions);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, navigateOptions) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: navigateOptions?.summarize,\n\t\t\t\t\t\tcustomInstructions: navigateOptions?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: navigateOptions?.replaceInstructions,\n\t\t\t\t\t\tlabel: navigateOptions?.label,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath, switchOptions) => {\n\t\t\t\t\treturn runtimeHost.switchSession(sessionPath, switchOptions);\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\tunsubscribe?.();\n\t\tunsubscribe = session.subscribe((event) => {\n\t\t\tif (event.type === \"prompt_settled\") latestOutcome = event.outcome;\n\t\t\tif (event.type === \"session_termination\") {\n\t\t\t\tlatestTermination = event.termination;\n\t\t\t\tif (mode === \"text\") {\n\t\t\t\t\trenderTermination(event.termination);\n\t\t\t\t} else {\n\t\t\t\t\trenderedTermination = event.termination;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event)}\\n`);\n\t\t\t}\n\t\t});\n\n\t\tconst startupTermination = session.lastTermination;\n\t\tif (startupTermination?.kind === \"process_crash\" && startupTermination.source === \"inferred_on_resume\") {\n\t\t\trenderTermination(startupTermination);\n\t\t}\n\t};\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\n\t\tawait rebindSession();\n\n\t\tconst hasPrompt =\n\t\t\t!!initialMessage?.trim() ||\n\t\t\tmessages.some((m) => typeof m === \"string\" && m.trim().length > 0) ||\n\t\t\t!!(initialImages && initialImages.length > 0);\n\t\tif (!hasPrompt) {\n\t\t\t// Bare `omk` with no prompt used to exit silently in print mode.\n\t\t\tconsole.error('No prompt provided. Use: omk -p \"...\" or run `omk` in an interactive terminal.');\n\t\t\texitCode = 2;\n\t\t\treturn exitCode;\n\t\t}\n\n\t\tif (initialMessage) {\n\t\t\tpromptStarted = true;\n\t\t\tlatestTermination = undefined;\n\t\t\tlatestOutcome = undefined;\n\t\t\tawait session.prompt(initialMessage, { images: initialImages });\n\t\t\tif (promptFailed()) return 1;\n\t\t}\n\n\t\tfor (const message of messages) {\n\t\t\tpromptStarted = true;\n\t\t\tlatestTermination = undefined;\n\t\t\tlatestOutcome = undefined;\n\t\t\tawait session.prompt(message);\n\t\t\tif (promptFailed()) return 1;\n\t\t}\n\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages[state.messages.length - 1];\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage as AssistantMessage;\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\trenderFailure(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t} catch (error: unknown) {\n\t\trenderFailure(error instanceof Error ? error.message : String(error));\n\t\treturn 1;\n\t} finally {\n\t\tfor (const cleanup of signalCleanupHandlers) {\n\t\t\tcleanup();\n\t\t}\n\t\tawait disposeRuntime();\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"clipboard-image.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AASF,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE9E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAazE;AA6OD,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC3B,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA+BjC","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { readFileSync, unlinkSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node: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\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\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, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\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(), `omk-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\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\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\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaPowerShell());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\treturn image;\n}\n"]}
1
+ {"version":3,"file":"clipboard-image.d.ts","sourceRoot":"","sources":["../../src/utils/clipboard-image.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAQF,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE9E;AAMD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAazE;AAoLD,wBAAsB,kBAAkB,CAAC,OAAO,CAAC,EAAE;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC3B,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAmCjC","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\nimport { readWindowsClipboardImage, WindowsClipboardError } from \"./windows-clipboard-image.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_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\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\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, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\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\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\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\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\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst windows = wsl ? await readWindowsClipboardImage(env) : undefined;\n\tif (windows?.kind === \"image\") return { bytes: windows.bytes, mimeType: windows.mimeType };\n\tif (windows?.kind === \"empty\") return null;\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tif (!image && windows?.kind === \"unavailable\") {\n\t\tthrow new WindowsClipboardError(\n\t\t\t`Windows clipboard unavailable (${windows.reason}). Check WSL interop and Windows PowerShell, or drop an image file.`,\n\t\t);\n\t}\n\treturn image;\n}\n"]}
@@ -1,14 +1,11 @@
1
1
  import { spawnSync } from "node:child_process";
2
- import { randomUUID } from "node:crypto";
3
- import { readFileSync, unlinkSync } from "node:fs";
4
- import { tmpdir } from "node:os";
5
- import { join } from "node:path";
2
+ import { readFileSync } from "node:fs";
6
3
  import { clipboard } from "./clipboard-native.js";
7
4
  import { loadPhoton } from "./photon.js";
5
+ import { readWindowsClipboardImage, WindowsClipboardError } from "./windows-clipboard-image.js";
8
6
  const SUPPORTED_IMAGE_MIME_TYPES = ["image/png", "image/jpeg", "image/webp", "image/gif"];
9
7
  const DEFAULT_LIST_TIMEOUT_MS = 1000;
10
8
  const DEFAULT_READ_TIMEOUT_MS = 3000;
11
- const DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;
12
9
  const DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
13
10
  export function isWaylandSession(env = process.env) {
14
11
  return Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === "wayland";
@@ -125,58 +122,6 @@ function isWSL(env = process.env, inspectProcVersion = true) {
125
122
  return false;
126
123
  }
127
124
  }
128
- /**
129
- * On WSL, the Linux clipboard (Wayland/X11) does not receive image data from
130
- * Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard
131
- * directly, so we use it as a fallback.
132
- */
133
- function readClipboardImageViaPowerShell() {
134
- const tmpFile = join(tmpdir(), `omk-wsl-clip-${randomUUID()}.png`);
135
- try {
136
- const winPathResult = runCommand("wslpath", ["-w", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
137
- if (!winPathResult.ok) {
138
- return null;
139
- }
140
- const winPath = winPathResult.stdout.toString("utf-8").trim();
141
- if (!winPath) {
142
- return null;
143
- }
144
- const psQuotedWinPath = winPath.replaceAll("'", "''");
145
- const psScript = [
146
- "Add-Type -AssemblyName System.Windows.Forms",
147
- "Add-Type -AssemblyName System.Drawing",
148
- `$path = '${psQuotedWinPath}'`,
149
- "$img = [System.Windows.Forms.Clipboard]::GetImage()",
150
- "if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }",
151
- ].join("; ");
152
- const result = runCommand("powershell.exe", ["-NoProfile", "-Command", psScript], {
153
- timeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,
154
- });
155
- if (!result.ok) {
156
- return null;
157
- }
158
- const output = result.stdout.toString("utf-8").trim();
159
- if (output !== "ok") {
160
- return null;
161
- }
162
- const bytes = readFileSync(tmpFile);
163
- if (bytes.length === 0) {
164
- return null;
165
- }
166
- return { bytes: new Uint8Array(bytes), mimeType: "image/png" };
167
- }
168
- catch {
169
- return null;
170
- }
171
- finally {
172
- try {
173
- unlinkSync(tmpFile);
174
- }
175
- catch {
176
- // Ignore cleanup errors.
177
- }
178
- }
179
- }
180
125
  function readClipboardImageViaXclip() {
181
126
  const targets = runCommand("xclip", ["-selection", "clipboard", "-t", "TARGETS", "-o"], {
182
127
  timeoutMs: DEFAULT_LIST_TIMEOUT_MS,
@@ -241,18 +186,23 @@ export async function readClipboardImage(options) {
241
186
  return toSupportedImage(await readClipboardImageViaNativeClipboard());
242
187
  }
243
188
  const wsl = isWSL(env, !hasExplicitEnv);
189
+ const windows = wsl ? await readWindowsClipboardImage(env) : undefined;
190
+ if (windows?.kind === "image")
191
+ return { bytes: windows.bytes, mimeType: windows.mimeType };
192
+ if (windows?.kind === "empty")
193
+ return null;
244
194
  const wayland = isWaylandSession(env);
245
195
  let image = null;
246
196
  if (wayland || wsl) {
247
197
  image = await toSupportedImage(readClipboardImageViaWlPaste());
248
198
  image ??= await toSupportedImage(readClipboardImageViaXclip());
249
199
  }
250
- if (!image && wsl) {
251
- image = await toSupportedImage(readClipboardImageViaPowerShell());
252
- }
253
200
  if (!image && !wayland) {
254
201
  image = await toSupportedImage(await readClipboardImageViaNativeClipboard());
255
202
  }
203
+ if (!image && windows?.kind === "unavailable") {
204
+ throw new WindowsClipboardError(`Windows clipboard unavailable (${windows.reason}). Check WSL interop and Windows PowerShell, or drop an image file.`);
205
+ }
256
206
  return image;
257
207
  }
258
208
  //# sourceMappingURL=clipboard-image.js.map
@@ -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 \"node:child_process\";\nimport { randomUUID } from \"node:crypto\";\nimport { readFileSync, unlinkSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node: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\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\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, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\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(), `omk-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\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\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\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaPowerShell());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\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 { spawnSync } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\nimport { readWindowsClipboardImage, WindowsClipboardError } from \"./windows-clipboard-image.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_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\tif (Buffer.isBuffer(result.stdout)) {\n\t\treturn { ok: true, stdout: result.stdout };\n\t}\n\n\tconst encoding = typeof result.stdout === \"string\" ? \"utf-8\" : undefined;\n\treturn { ok: true, stdout: Buffer.from(result.stdout ?? \"\", encoding) };\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, inspectProcVersion = true): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\tif (!inspectProcVersion) {\n\t\treturn false;\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\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\n/**\n * Normalize one source's read into a supported format, or reject that read.\n *\n * Applied per source rather than once after the chain, because a source can\n * succeed at reading bytes yet still be unusable: WSLg publishes a Windows\n * screenshot as `image/bmp`, which needs conversion. Folding the conversion\n * into the source attempt keeps an unconvertible read from disqualifying the\n * sources behind it — notably the PowerShell reader, which returns PNG\n * directly and needs no converter at all.\n */\nasync function toSupportedImage(image: ClipboardImage | null): Promise<ClipboardImage | null> {\n\tif (!image) {\n\t\treturn null;\n\t}\n\tif (isSupportedImageMimeType(image.mimeType)) {\n\t\treturn image;\n\t}\n\tconst pngBytes = await convertToPng(image.bytes);\n\treturn pngBytes ? { bytes: pngBytes, mimeType: \"image/png\" } : null;\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\tconst hasExplicitEnv = options?.env !== undefined;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tif (platform !== \"linux\") {\n\t\treturn toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tconst wsl = isWSL(env, !hasExplicitEnv);\n\tconst windows = wsl ? await readWindowsClipboardImage(env) : undefined;\n\tif (windows?.kind === \"image\") return { bytes: windows.bytes, mimeType: windows.mimeType };\n\tif (windows?.kind === \"empty\") return null;\n\tconst wayland = isWaylandSession(env);\n\tlet image: ClipboardImage | null = null;\n\n\tif (wayland || wsl) {\n\t\timage = await toSupportedImage(readClipboardImageViaWlPaste());\n\t\timage ??= await toSupportedImage(readClipboardImageViaXclip());\n\t}\n\n\tif (!image && !wayland) {\n\t\timage = await toSupportedImage(await readClipboardImageViaNativeClipboard());\n\t}\n\n\tif (!image && windows?.kind === \"unavailable\") {\n\t\tthrow new WindowsClipboardError(\n\t\t\t`Windows clipboard unavailable (${windows.reason}). Check WSL interop and Windows PowerShell, or drop an image file.`,\n\t\t);\n\t}\n\treturn image;\n}\n"]}
@@ -0,0 +1,13 @@
1
+ interface TerminalLinkEnvironment {
2
+ readonly env?: NodeJS.ProcessEnv;
3
+ readonly platform?: NodeJS.Platform;
4
+ }
5
+ /** File URLs are opened by the host terminal, not by a Linux process inside WSL. */
6
+ export declare function terminalFileUrl(path: string, cwd: string, options?: TerminalLinkEnvironment): string;
7
+ /** Bind destinations to the active project so resumed sessions do not use the launch cwd. */
8
+ export declare function terminalMarkdownLinks(cwd: string, options?: TerminalLinkEnvironment): {
9
+ resolveLink(href: string): string | undefined;
10
+ resolveFileLink(text: string): string | undefined;
11
+ };
12
+ export {};
13
+ //# sourceMappingURL=terminal-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-links.d.ts","sourceRoot":"","sources":["../../src/utils/terminal-links.ts"],"names":[],"mappings":"AAKA,UAAU,uBAAuB;IAChC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CACpC;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B,GAAG,MAAM,CAcxG;AAED,6FAA6F;AAC7F,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,uBAA4B;;;EAkCvF","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { win32 } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { normalizePath, resolvePath } from \"./paths.ts\";\n\ninterface TerminalLinkEnvironment {\n\treadonly env?: NodeJS.ProcessEnv;\n\treadonly platform?: NodeJS.Platform;\n}\n\n/** File URLs are opened by the host terminal, not by a Linux process inside WSL. */\nexport function terminalFileUrl(path: string, cwd: string, options: TerminalLinkEnvironment = {}): string {\n\tconst env = options.env ?? process.env;\n\tconst platform = options.platform ?? process.platform;\n\tif (/^[a-z]:[\\\\/]|^\\\\\\\\/i.test(path)) return pathToFileURL(path, { windows: true }).href;\n\tconst absolute = platform === \"win32\" ? win32.resolve(cwd, normalizePath(path)) : resolvePath(path, cwd);\n\tconst distro = env.WSL_DISTRO_NAME;\n\tif (platform === \"linux\" && distro && !env.SSH_CONNECTION && !env.SSH_TTY && !/[\\\\/\\x00-\\x1f]/.test(distro)) {\n\t\tconst drive = /^\\/mnt\\/([a-z])(?:\\/|$)/i.exec(absolute);\n\t\tconst windowsPath = drive\n\t\t\t? `${drive[1].toUpperCase()}:\\\\${absolute.slice(drive[0].length).replaceAll(\"/\", \"\\\\\")}`\n\t\t\t: `\\\\\\\\wsl.localhost\\\\${distro}${absolute.replaceAll(\"/\", \"\\\\\")}`;\n\t\treturn pathToFileURL(windowsPath, { windows: true }).href;\n\t}\n\treturn pathToFileURL(absolute, { windows: platform === \"win32\" }).href;\n}\n\n/** Bind destinations to the active project so resumed sessions do not use the launch cwd. */\nexport function terminalMarkdownLinks(cwd: string, options: TerminalLinkEnvironment = {}) {\n\treturn {\n\t\tresolveLink(href: string): string | undefined {\n\t\t\tif (/[\\x00-\\x1f\\x7f]/.test(href)) return undefined;\n\t\t\tif (/^[a-z]:[\\\\/]|^\\\\\\\\/i.test(href)) return terminalFileUrl(href, cwd, options);\n\t\t\tif (href.startsWith(\"#\")) return href;\n\t\t\tif (/^file:/i.test(href)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = new URL(href);\n\t\t\t\t\tif (url.hostname && url.hostname !== \"localhost\") return href;\n\t\t\t\t\tconst windows = /^\\/[a-z]:\\//i.test(url.pathname);\n\t\t\t\t\treturn terminalFileUrl(fileURLToPath(url, { windows }), cwd, options) + url.search + url.hash;\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (/^[a-z][a-z\\d+.-]*:/i.test(href) || href.startsWith(\"//\")) return href;\n\t\t\tconst boundary = href.search(/[?#]/);\n\t\t\tconst pathname = boundary < 0 ? href : href.slice(0, boundary);\n\t\t\tconst suffix = boundary < 0 ? \"\" : href.slice(boundary);\n\t\t\ttry {\n\t\t\t\treturn terminalFileUrl(decodeURIComponent(pathname), cwd, options) + suffix;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof URIError) return terminalFileUrl(pathname, cwd, options) + suffix;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tresolveFileLink(text: string): string | undefined {\n\t\t\tif (/^[a-z][a-z\\d+.-]*:/i.test(text) && !/^[a-z]:[\\\\/]/i.test(text)) return undefined;\n\t\t\tif (/[\\x00-\\x1f\\x7f]/.test(text) || (!/[\\\\/]/.test(text) && !/\\.[a-z\\d]{1,10}$/i.test(text))) return undefined;\n\t\t\tconst path = resolvePath(text, cwd);\n\t\t\treturn existsSync(path) ? terminalFileUrl(text, cwd, options) : undefined;\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,68 @@
1
+ import { existsSync } from "node:fs";
2
+ import { win32 } from "node:path";
3
+ import { fileURLToPath, pathToFileURL } from "node:url";
4
+ import { normalizePath, resolvePath } from "./paths.js";
5
+ /** File URLs are opened by the host terminal, not by a Linux process inside WSL. */
6
+ export function terminalFileUrl(path, cwd, options = {}) {
7
+ const env = options.env ?? process.env;
8
+ const platform = options.platform ?? process.platform;
9
+ if (/^[a-z]:[\\/]|^\\\\/i.test(path))
10
+ return pathToFileURL(path, { windows: true }).href;
11
+ const absolute = platform === "win32" ? win32.resolve(cwd, normalizePath(path)) : resolvePath(path, cwd);
12
+ const distro = env.WSL_DISTRO_NAME;
13
+ if (platform === "linux" && distro && !env.SSH_CONNECTION && !env.SSH_TTY && !/[\\/\x00-\x1f]/.test(distro)) {
14
+ const drive = /^\/mnt\/([a-z])(?:\/|$)/i.exec(absolute);
15
+ const windowsPath = drive
16
+ ? `${drive[1].toUpperCase()}:\\${absolute.slice(drive[0].length).replaceAll("/", "\\")}`
17
+ : `\\\\wsl.localhost\\${distro}${absolute.replaceAll("/", "\\")}`;
18
+ return pathToFileURL(windowsPath, { windows: true }).href;
19
+ }
20
+ return pathToFileURL(absolute, { windows: platform === "win32" }).href;
21
+ }
22
+ /** Bind destinations to the active project so resumed sessions do not use the launch cwd. */
23
+ export function terminalMarkdownLinks(cwd, options = {}) {
24
+ return {
25
+ resolveLink(href) {
26
+ if (/[\x00-\x1f\x7f]/.test(href))
27
+ return undefined;
28
+ if (/^[a-z]:[\\/]|^\\\\/i.test(href))
29
+ return terminalFileUrl(href, cwd, options);
30
+ if (href.startsWith("#"))
31
+ return href;
32
+ if (/^file:/i.test(href)) {
33
+ try {
34
+ const url = new URL(href);
35
+ if (url.hostname && url.hostname !== "localhost")
36
+ return href;
37
+ const windows = /^\/[a-z]:\//i.test(url.pathname);
38
+ return terminalFileUrl(fileURLToPath(url, { windows }), cwd, options) + url.search + url.hash;
39
+ }
40
+ catch {
41
+ return undefined;
42
+ }
43
+ }
44
+ if (/^[a-z][a-z\d+.-]*:/i.test(href) || href.startsWith("//"))
45
+ return href;
46
+ const boundary = href.search(/[?#]/);
47
+ const pathname = boundary < 0 ? href : href.slice(0, boundary);
48
+ const suffix = boundary < 0 ? "" : href.slice(boundary);
49
+ try {
50
+ return terminalFileUrl(decodeURIComponent(pathname), cwd, options) + suffix;
51
+ }
52
+ catch (error) {
53
+ if (error instanceof URIError)
54
+ return terminalFileUrl(pathname, cwd, options) + suffix;
55
+ throw error;
56
+ }
57
+ },
58
+ resolveFileLink(text) {
59
+ if (/^[a-z][a-z\d+.-]*:/i.test(text) && !/^[a-z]:[\\/]/i.test(text))
60
+ return undefined;
61
+ if (/[\x00-\x1f\x7f]/.test(text) || (!/[\\/]/.test(text) && !/\.[a-z\d]{1,10}$/i.test(text)))
62
+ return undefined;
63
+ const path = resolvePath(text, cwd);
64
+ return existsSync(path) ? terminalFileUrl(text, cwd, options) : undefined;
65
+ },
66
+ };
67
+ }
68
+ //# sourceMappingURL=terminal-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-links.js","sourceRoot":"","sources":["../../src/utils/terminal-links.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { win32 } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { normalizePath, resolvePath } from \"./paths.ts\";\n\ninterface TerminalLinkEnvironment {\n\treadonly env?: NodeJS.ProcessEnv;\n\treadonly platform?: NodeJS.Platform;\n}\n\n/** File URLs are opened by the host terminal, not by a Linux process inside WSL. */\nexport function terminalFileUrl(path: string, cwd: string, options: TerminalLinkEnvironment = {}): string {\n\tconst env = options.env ?? process.env;\n\tconst platform = options.platform ?? process.platform;\n\tif (/^[a-z]:[\\\\/]|^\\\\\\\\/i.test(path)) return pathToFileURL(path, { windows: true }).href;\n\tconst absolute = platform === \"win32\" ? win32.resolve(cwd, normalizePath(path)) : resolvePath(path, cwd);\n\tconst distro = env.WSL_DISTRO_NAME;\n\tif (platform === \"linux\" && distro && !env.SSH_CONNECTION && !env.SSH_TTY && !/[\\\\/\\x00-\\x1f]/.test(distro)) {\n\t\tconst drive = /^\\/mnt\\/([a-z])(?:\\/|$)/i.exec(absolute);\n\t\tconst windowsPath = drive\n\t\t\t? `${drive[1].toUpperCase()}:\\\\${absolute.slice(drive[0].length).replaceAll(\"/\", \"\\\\\")}`\n\t\t\t: `\\\\\\\\wsl.localhost\\\\${distro}${absolute.replaceAll(\"/\", \"\\\\\")}`;\n\t\treturn pathToFileURL(windowsPath, { windows: true }).href;\n\t}\n\treturn pathToFileURL(absolute, { windows: platform === \"win32\" }).href;\n}\n\n/** Bind destinations to the active project so resumed sessions do not use the launch cwd. */\nexport function terminalMarkdownLinks(cwd: string, options: TerminalLinkEnvironment = {}) {\n\treturn {\n\t\tresolveLink(href: string): string | undefined {\n\t\t\tif (/[\\x00-\\x1f\\x7f]/.test(href)) return undefined;\n\t\t\tif (/^[a-z]:[\\\\/]|^\\\\\\\\/i.test(href)) return terminalFileUrl(href, cwd, options);\n\t\t\tif (href.startsWith(\"#\")) return href;\n\t\t\tif (/^file:/i.test(href)) {\n\t\t\t\ttry {\n\t\t\t\t\tconst url = new URL(href);\n\t\t\t\t\tif (url.hostname && url.hostname !== \"localhost\") return href;\n\t\t\t\t\tconst windows = /^\\/[a-z]:\\//i.test(url.pathname);\n\t\t\t\t\treturn terminalFileUrl(fileURLToPath(url, { windows }), cwd, options) + url.search + url.hash;\n\t\t\t\t} catch {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (/^[a-z][a-z\\d+.-]*:/i.test(href) || href.startsWith(\"//\")) return href;\n\t\t\tconst boundary = href.search(/[?#]/);\n\t\t\tconst pathname = boundary < 0 ? href : href.slice(0, boundary);\n\t\t\tconst suffix = boundary < 0 ? \"\" : href.slice(boundary);\n\t\t\ttry {\n\t\t\t\treturn terminalFileUrl(decodeURIComponent(pathname), cwd, options) + suffix;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof URIError) return terminalFileUrl(pathname, cwd, options) + suffix;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\t\tresolveFileLink(text: string): string | undefined {\n\t\t\tif (/^[a-z][a-z\\d+.-]*:/i.test(text) && !/^[a-z]:[\\\\/]/i.test(text)) return undefined;\n\t\t\tif (/[\\x00-\\x1f\\x7f]/.test(text) || (!/[\\\\/]/.test(text) && !/\\.[a-z\\d]{1,10}$/i.test(text))) return undefined;\n\t\t\tconst path = resolvePath(text, cwd);\n\t\t\treturn existsSync(path) ? terminalFileUrl(text, cwd, options) : undefined;\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,16 @@
1
+ export type WindowsClipboardResult = {
2
+ readonly kind: "image";
3
+ readonly bytes: Uint8Array;
4
+ readonly mimeType: "image/png";
5
+ } | {
6
+ readonly kind: "empty";
7
+ } | {
8
+ readonly kind: "unavailable";
9
+ readonly reason: "not-found" | "timeout" | "failed";
10
+ };
11
+ export declare class WindowsClipboardError extends Error {
12
+ constructor(message: string);
13
+ }
14
+ /** Read only image data. No clipboard writes, temporary screenshots, profiles, or policy bypass. */
15
+ export declare function readWindowsClipboardImage(env?: NodeJS.ProcessEnv): Promise<WindowsClipboardResult>;
16
+ //# sourceMappingURL=windows-clipboard-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-clipboard-image.d.ts","sourceRoot":"","sources":["../../src/utils/windows-clipboard-image.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,sBAAsB,GAC/B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAA;CAAE,GACtF;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC;AAEzF,qBAAa,qBAAsB,SAAQ,KAAK;IAC/C,YAAY,OAAO,EAAE,MAAM,EAG1B;CACD;AA2DD,oGAAoG;AACpG,wBAAsB,yBAAyB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAqBrH","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { dirname, isAbsolute } from \"node:path\";\nimport { PROMPT_ATTACHMENT_LIMITS, sniffImageMimeType } from \"../core/prompt-attachment.ts\";\n\nexport type WindowsClipboardResult =\n\t| { readonly kind: \"image\"; readonly bytes: Uint8Array; readonly mimeType: \"image/png\" }\n\t| { readonly kind: \"empty\" }\n\t| { readonly kind: \"unavailable\"; readonly reason: \"not-found\" | \"timeout\" | \"failed\" };\n\nexport class WindowsClipboardError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"WindowsClipboardError\";\n\t}\n}\n\nconst PREFIX = \"OMK_CLIPBOARD_PNG:\";\nconst SCRIPT = [\n\t\"$ErrorActionPreference = 'Stop'\",\n\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\"Add-Type -AssemblyName System.Drawing\",\n\t\"$image = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\"if ($null -eq $image) { [Console]::Write('OMK_CLIPBOARD_EMPTY'); exit 0 }\",\n\t\"$stream = New-Object System.IO.MemoryStream\",\n\t\"try {\",\n\t`if ([long]$image.Width * $image.Height -gt ${PROMPT_ATTACHMENT_LIMITS.maxPixels}) { [Console]::Write('OMK_CLIPBOARD_TOO_LARGE'); exit 0 };`,\n\t\"$image.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png);\",\n\t`if ($stream.Length -gt ${PROMPT_ATTACHMENT_LIMITS.maxImageBytes}) { [Console]::Write('OMK_CLIPBOARD_TOO_LARGE'); exit 0 };`,\n\t`[Console]::Write('${PREFIX}' + [Convert]::ToBase64String($stream.ToArray()))`,\n\t\"} finally { $stream.Dispose(); $image.Dispose() }\",\n].join(\"\\n\");\n\nfunction readCommand(command: string, env: NodeJS.ProcessEnv): Promise<string | WindowsClipboardResult> {\n\tconst childEnv: NodeJS.ProcessEnv = {};\n\tfor (const key of [\n\t\t\"PATH\",\n\t\t\"Path\",\n\t\t\"SystemRoot\",\n\t\t\"SYSTEMROOT\",\n\t\t\"WINDIR\",\n\t\t\"TEMP\",\n\t\t\"TMP\",\n\t\t\"USERPROFILE\",\n\t\t\"WSL_INTEROP\",\n\t\t\"WSL_DISTRO_NAME\",\n\t]) {\n\t\tif (env[key] !== undefined) childEnv[key] = env[key];\n\t}\n\treturn new Promise((resolve) => {\n\t\texecFile(\n\t\t\tcommand,\n\t\t\t[\"-NoProfile\", \"-NonInteractive\", \"-STA\", \"-Command\", SCRIPT],\n\t\t\t{\n\t\t\t\tencoding: \"utf8\",\n\t\t\t\twindowsHide: true,\n\t\t\t\t// Avoid launching Windows in a project UNC directory across the WSL filesystem bridge.\n\t\t\t\tcwd: isAbsolute(command) ? dirname(command) : undefined,\n\t\t\t\tenv: childEnv,\n\t\t\t\ttimeout: 5000,\n\t\t\t\tmaxBuffer: Math.ceil(PROMPT_ATTACHMENT_LIMITS.maxImageBytes / 3) * 4 + 1024,\n\t\t\t},\n\t\t\t(error, stdout) => {\n\t\t\t\tif (!error) resolve(stdout.trim());\n\t\t\t\telse\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tkind: \"unavailable\",\n\t\t\t\t\t\treason: error.code === \"ENOENT\" ? \"not-found\" : error.killed ? \"timeout\" : \"failed\",\n\t\t\t\t\t});\n\t\t\t},\n\t\t);\n\t});\n}\n\n/** Read only image data. No clipboard writes, temporary screenshots, profiles, or policy bypass. */\nexport async function readWindowsClipboardImage(env: NodeJS.ProcessEnv = process.env): Promise<WindowsClipboardResult> {\n\tfor (const command of [\"/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe\", \"powershell.exe\"]) {\n\t\tconst result = await readCommand(command, env);\n\t\tif (typeof result !== \"string\") {\n\t\t\tif (result.kind === \"unavailable\" && result.reason === \"not-found\") continue;\n\t\t\treturn result;\n\t\t}\n\t\tif (result === \"OMK_CLIPBOARD_EMPTY\") return { kind: \"empty\" };\n\t\tif (result === \"OMK_CLIPBOARD_TOO_LARGE\")\n\t\t\tthrow new WindowsClipboardError(\"Windows clipboard image exceeds the prompt image size limit.\");\n\t\tconst encoded = result.startsWith(PREFIX) ? result.slice(PREFIX.length) : \"\";\n\t\tif (!encoded || encoded.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {\n\t\t\tthrow new WindowsClipboardError(\"Windows clipboard returned invalid PNG data.\");\n\t\t}\n\t\tconst bytes = Buffer.from(encoded, \"base64\");\n\t\tif (bytes.length > PROMPT_ATTACHMENT_LIMITS.maxImageBytes || sniffImageMimeType(bytes) !== \"image/png\") {\n\t\t\tthrow new WindowsClipboardError(\"Windows clipboard returned invalid or oversized PNG data.\");\n\t\t}\n\t\treturn { kind: \"image\", bytes, mimeType: \"image/png\" };\n\t}\n\treturn { kind: \"unavailable\", reason: \"not-found\" };\n}\n"]}
@@ -0,0 +1,87 @@
1
+ import { execFile } from "node:child_process";
2
+ import { dirname, isAbsolute } from "node:path";
3
+ import { PROMPT_ATTACHMENT_LIMITS, sniffImageMimeType } from "../core/prompt-attachment.js";
4
+ export class WindowsClipboardError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "WindowsClipboardError";
8
+ }
9
+ }
10
+ const PREFIX = "OMK_CLIPBOARD_PNG:";
11
+ const SCRIPT = [
12
+ "$ErrorActionPreference = 'Stop'",
13
+ "Add-Type -AssemblyName System.Windows.Forms",
14
+ "Add-Type -AssemblyName System.Drawing",
15
+ "$image = [System.Windows.Forms.Clipboard]::GetImage()",
16
+ "if ($null -eq $image) { [Console]::Write('OMK_CLIPBOARD_EMPTY'); exit 0 }",
17
+ "$stream = New-Object System.IO.MemoryStream",
18
+ "try {",
19
+ `if ([long]$image.Width * $image.Height -gt ${PROMPT_ATTACHMENT_LIMITS.maxPixels}) { [Console]::Write('OMK_CLIPBOARD_TOO_LARGE'); exit 0 };`,
20
+ "$image.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png);",
21
+ `if ($stream.Length -gt ${PROMPT_ATTACHMENT_LIMITS.maxImageBytes}) { [Console]::Write('OMK_CLIPBOARD_TOO_LARGE'); exit 0 };`,
22
+ `[Console]::Write('${PREFIX}' + [Convert]::ToBase64String($stream.ToArray()))`,
23
+ "} finally { $stream.Dispose(); $image.Dispose() }",
24
+ ].join("\n");
25
+ function readCommand(command, env) {
26
+ const childEnv = {};
27
+ for (const key of [
28
+ "PATH",
29
+ "Path",
30
+ "SystemRoot",
31
+ "SYSTEMROOT",
32
+ "WINDIR",
33
+ "TEMP",
34
+ "TMP",
35
+ "USERPROFILE",
36
+ "WSL_INTEROP",
37
+ "WSL_DISTRO_NAME",
38
+ ]) {
39
+ if (env[key] !== undefined)
40
+ childEnv[key] = env[key];
41
+ }
42
+ return new Promise((resolve) => {
43
+ execFile(command, ["-NoProfile", "-NonInteractive", "-STA", "-Command", SCRIPT], {
44
+ encoding: "utf8",
45
+ windowsHide: true,
46
+ // Avoid launching Windows in a project UNC directory across the WSL filesystem bridge.
47
+ cwd: isAbsolute(command) ? dirname(command) : undefined,
48
+ env: childEnv,
49
+ timeout: 5000,
50
+ maxBuffer: Math.ceil(PROMPT_ATTACHMENT_LIMITS.maxImageBytes / 3) * 4 + 1024,
51
+ }, (error, stdout) => {
52
+ if (!error)
53
+ resolve(stdout.trim());
54
+ else
55
+ resolve({
56
+ kind: "unavailable",
57
+ reason: error.code === "ENOENT" ? "not-found" : error.killed ? "timeout" : "failed",
58
+ });
59
+ });
60
+ });
61
+ }
62
+ /** Read only image data. No clipboard writes, temporary screenshots, profiles, or policy bypass. */
63
+ export async function readWindowsClipboardImage(env = process.env) {
64
+ for (const command of ["/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe", "powershell.exe"]) {
65
+ const result = await readCommand(command, env);
66
+ if (typeof result !== "string") {
67
+ if (result.kind === "unavailable" && result.reason === "not-found")
68
+ continue;
69
+ return result;
70
+ }
71
+ if (result === "OMK_CLIPBOARD_EMPTY")
72
+ return { kind: "empty" };
73
+ if (result === "OMK_CLIPBOARD_TOO_LARGE")
74
+ throw new WindowsClipboardError("Windows clipboard image exceeds the prompt image size limit.");
75
+ const encoded = result.startsWith(PREFIX) ? result.slice(PREFIX.length) : "";
76
+ if (!encoded || encoded.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {
77
+ throw new WindowsClipboardError("Windows clipboard returned invalid PNG data.");
78
+ }
79
+ const bytes = Buffer.from(encoded, "base64");
80
+ if (bytes.length > PROMPT_ATTACHMENT_LIMITS.maxImageBytes || sniffImageMimeType(bytes) !== "image/png") {
81
+ throw new WindowsClipboardError("Windows clipboard returned invalid or oversized PNG data.");
82
+ }
83
+ return { kind: "image", bytes, mimeType: "image/png" };
84
+ }
85
+ return { kind: "unavailable", reason: "not-found" };
86
+ }
87
+ //# sourceMappingURL=windows-clipboard-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windows-clipboard-image.js","sourceRoot":"","sources":["../../src/utils/windows-clipboard-image.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { dirname, isAbsolute } from \"node:path\";\nimport { PROMPT_ATTACHMENT_LIMITS, sniffImageMimeType } from \"../core/prompt-attachment.ts\";\n\nexport type WindowsClipboardResult =\n\t| { readonly kind: \"image\"; readonly bytes: Uint8Array; readonly mimeType: \"image/png\" }\n\t| { readonly kind: \"empty\" }\n\t| { readonly kind: \"unavailable\"; readonly reason: \"not-found\" | \"timeout\" | \"failed\" };\n\nexport class WindowsClipboardError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"WindowsClipboardError\";\n\t}\n}\n\nconst PREFIX = \"OMK_CLIPBOARD_PNG:\";\nconst SCRIPT = [\n\t\"$ErrorActionPreference = 'Stop'\",\n\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\"Add-Type -AssemblyName System.Drawing\",\n\t\"$image = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\"if ($null -eq $image) { [Console]::Write('OMK_CLIPBOARD_EMPTY'); exit 0 }\",\n\t\"$stream = New-Object System.IO.MemoryStream\",\n\t\"try {\",\n\t`if ([long]$image.Width * $image.Height -gt ${PROMPT_ATTACHMENT_LIMITS.maxPixels}) { [Console]::Write('OMK_CLIPBOARD_TOO_LARGE'); exit 0 };`,\n\t\"$image.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png);\",\n\t`if ($stream.Length -gt ${PROMPT_ATTACHMENT_LIMITS.maxImageBytes}) { [Console]::Write('OMK_CLIPBOARD_TOO_LARGE'); exit 0 };`,\n\t`[Console]::Write('${PREFIX}' + [Convert]::ToBase64String($stream.ToArray()))`,\n\t\"} finally { $stream.Dispose(); $image.Dispose() }\",\n].join(\"\\n\");\n\nfunction readCommand(command: string, env: NodeJS.ProcessEnv): Promise<string | WindowsClipboardResult> {\n\tconst childEnv: NodeJS.ProcessEnv = {};\n\tfor (const key of [\n\t\t\"PATH\",\n\t\t\"Path\",\n\t\t\"SystemRoot\",\n\t\t\"SYSTEMROOT\",\n\t\t\"WINDIR\",\n\t\t\"TEMP\",\n\t\t\"TMP\",\n\t\t\"USERPROFILE\",\n\t\t\"WSL_INTEROP\",\n\t\t\"WSL_DISTRO_NAME\",\n\t]) {\n\t\tif (env[key] !== undefined) childEnv[key] = env[key];\n\t}\n\treturn new Promise((resolve) => {\n\t\texecFile(\n\t\t\tcommand,\n\t\t\t[\"-NoProfile\", \"-NonInteractive\", \"-STA\", \"-Command\", SCRIPT],\n\t\t\t{\n\t\t\t\tencoding: \"utf8\",\n\t\t\t\twindowsHide: true,\n\t\t\t\t// Avoid launching Windows in a project UNC directory across the WSL filesystem bridge.\n\t\t\t\tcwd: isAbsolute(command) ? dirname(command) : undefined,\n\t\t\t\tenv: childEnv,\n\t\t\t\ttimeout: 5000,\n\t\t\t\tmaxBuffer: Math.ceil(PROMPT_ATTACHMENT_LIMITS.maxImageBytes / 3) * 4 + 1024,\n\t\t\t},\n\t\t\t(error, stdout) => {\n\t\t\t\tif (!error) resolve(stdout.trim());\n\t\t\t\telse\n\t\t\t\t\tresolve({\n\t\t\t\t\t\tkind: \"unavailable\",\n\t\t\t\t\t\treason: error.code === \"ENOENT\" ? \"not-found\" : error.killed ? \"timeout\" : \"failed\",\n\t\t\t\t\t});\n\t\t\t},\n\t\t);\n\t});\n}\n\n/** Read only image data. No clipboard writes, temporary screenshots, profiles, or policy bypass. */\nexport async function readWindowsClipboardImage(env: NodeJS.ProcessEnv = process.env): Promise<WindowsClipboardResult> {\n\tfor (const command of [\"/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe\", \"powershell.exe\"]) {\n\t\tconst result = await readCommand(command, env);\n\t\tif (typeof result !== \"string\") {\n\t\t\tif (result.kind === \"unavailable\" && result.reason === \"not-found\") continue;\n\t\t\treturn result;\n\t\t}\n\t\tif (result === \"OMK_CLIPBOARD_EMPTY\") return { kind: \"empty\" };\n\t\tif (result === \"OMK_CLIPBOARD_TOO_LARGE\")\n\t\t\tthrow new WindowsClipboardError(\"Windows clipboard image exceeds the prompt image size limit.\");\n\t\tconst encoded = result.startsWith(PREFIX) ? result.slice(PREFIX.length) : \"\";\n\t\tif (!encoded || encoded.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(encoded)) {\n\t\t\tthrow new WindowsClipboardError(\"Windows clipboard returned invalid PNG data.\");\n\t\t}\n\t\tconst bytes = Buffer.from(encoded, \"base64\");\n\t\tif (bytes.length > PROMPT_ATTACHMENT_LIMITS.maxImageBytes || sniffImageMimeType(bytes) !== \"image/png\") {\n\t\t\tthrow new WindowsClipboardError(\"Windows clipboard returned invalid or oversized PNG data.\");\n\t\t}\n\t\treturn { kind: \"image\", bytes, mimeType: \"image/png\" };\n\t}\n\treturn { kind: \"unavailable\", reason: \"not-found\" };\n}\n"]}