apex-code 0.0.1-alpha.0 → 0.0.1-alpha.2

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 (426) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +66 -681
  3. package/dist/cli/args.d.ts +5 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +45 -6
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/auth-command.d.ts.map +1 -1
  8. package/dist/cli/auth-command.js +3 -3
  9. package/dist/cli/auth-command.js.map +1 -1
  10. package/dist/cli/cost-command.d.ts +19 -0
  11. package/dist/cli/cost-command.d.ts.map +1 -0
  12. package/dist/cli/cost-command.js +107 -0
  13. package/dist/cli/cost-command.js.map +1 -0
  14. package/dist/cli/startup-ui.d.ts +1 -1
  15. package/dist/cli/startup-ui.d.ts.map +1 -1
  16. package/dist/cli/startup-ui.js +1 -2
  17. package/dist/cli/startup-ui.js.map +1 -1
  18. package/dist/cli.d.ts.map +1 -1
  19. package/dist/cli.js +45 -16
  20. package/dist/cli.js.map +1 -1
  21. package/dist/config.d.ts +2 -2
  22. package/dist/config.d.ts.map +1 -1
  23. package/dist/config.js +14 -7
  24. package/dist/config.js.map +1 -1
  25. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  26. package/dist/core/agent-session-runtime.js +2 -0
  27. package/dist/core/agent-session-runtime.js.map +1 -1
  28. package/dist/core/agent-session-services.d.ts +9 -0
  29. package/dist/core/agent-session-services.d.ts.map +1 -1
  30. package/dist/core/agent-session-services.js +30 -4
  31. package/dist/core/agent-session-services.js.map +1 -1
  32. package/dist/core/agent-session.d.ts +46 -0
  33. package/dist/core/agent-session.d.ts.map +1 -1
  34. package/dist/core/agent-session.js +137 -19
  35. package/dist/core/agent-session.js.map +1 -1
  36. package/dist/core/auth-storage.d.ts.map +1 -1
  37. package/dist/core/auth-storage.js +6 -6
  38. package/dist/core/auth-storage.js.map +1 -1
  39. package/dist/core/bash-executor.d.ts.map +1 -1
  40. package/dist/core/bash-executor.js +1 -1
  41. package/dist/core/bash-executor.js.map +1 -1
  42. package/dist/core/context/deferred-schemas.d.ts +92 -0
  43. package/dist/core/context/deferred-schemas.d.ts.map +1 -0
  44. package/dist/core/context/deferred-schemas.js +74 -0
  45. package/dist/core/context/deferred-schemas.js.map +1 -0
  46. package/dist/core/context/eviction.d.ts +47 -0
  47. package/dist/core/context/eviction.d.ts.map +1 -0
  48. package/dist/core/context/eviction.js +83 -0
  49. package/dist/core/context/eviction.js.map +1 -0
  50. package/dist/core/context/pipeline.d.ts +90 -0
  51. package/dist/core/context/pipeline.d.ts.map +1 -0
  52. package/dist/core/context/pipeline.js +109 -0
  53. package/dist/core/context/pipeline.js.map +1 -0
  54. package/dist/core/credential-failover.d.ts +30 -0
  55. package/dist/core/credential-failover.d.ts.map +1 -0
  56. package/dist/core/credential-failover.js +46 -0
  57. package/dist/core/credential-failover.js.map +1 -0
  58. package/dist/core/credential-pool.d.ts +60 -0
  59. package/dist/core/credential-pool.d.ts.map +1 -0
  60. package/dist/core/credential-pool.js +84 -0
  61. package/dist/core/credential-pool.js.map +1 -0
  62. package/dist/core/delegation/agents.d.ts +15 -0
  63. package/dist/core/delegation/agents.d.ts.map +1 -0
  64. package/dist/core/delegation/agents.js +55 -0
  65. package/dist/core/delegation/agents.js.map +1 -0
  66. package/dist/core/delegation/ceiling.d.ts +29 -0
  67. package/dist/core/delegation/ceiling.d.ts.map +1 -0
  68. package/dist/core/delegation/ceiling.js +34 -0
  69. package/dist/core/delegation/ceiling.js.map +1 -0
  70. package/dist/core/delegation/runtime.d.ts +94 -0
  71. package/dist/core/delegation/runtime.d.ts.map +1 -0
  72. package/dist/core/delegation/runtime.js +117 -0
  73. package/dist/core/delegation/runtime.js.map +1 -0
  74. package/dist/core/durable-state/daemon.d.ts +37 -0
  75. package/dist/core/durable-state/daemon.d.ts.map +1 -0
  76. package/dist/core/durable-state/daemon.js +62 -0
  77. package/dist/core/durable-state/daemon.js.map +1 -0
  78. package/dist/core/durable-state/provenance.d.ts +7 -0
  79. package/dist/core/durable-state/provenance.d.ts.map +1 -0
  80. package/dist/core/durable-state/provenance.js +24 -0
  81. package/dist/core/durable-state/provenance.js.map +1 -0
  82. package/dist/core/durable-state/sqlite.d.ts +84 -0
  83. package/dist/core/durable-state/sqlite.d.ts.map +1 -0
  84. package/dist/core/durable-state/sqlite.js +331 -0
  85. package/dist/core/durable-state/sqlite.js.map +1 -0
  86. package/dist/core/environment.d.ts +12 -0
  87. package/dist/core/environment.d.ts.map +1 -0
  88. package/dist/core/environment.js +69 -0
  89. package/dist/core/environment.js.map +1 -0
  90. package/dist/core/evidence-policy.d.ts +17 -0
  91. package/dist/core/evidence-policy.d.ts.map +1 -0
  92. package/dist/core/evidence-policy.js +25 -0
  93. package/dist/core/evidence-policy.js.map +1 -0
  94. package/dist/core/evidence.d.ts +16 -0
  95. package/dist/core/evidence.d.ts.map +1 -0
  96. package/dist/core/evidence.js +51 -0
  97. package/dist/core/evidence.js.map +1 -0
  98. package/dist/core/experimental.d.ts.map +1 -1
  99. package/dist/core/experimental.js +2 -1
  100. package/dist/core/experimental.js.map +1 -1
  101. package/dist/core/extensions/types.d.ts +2 -0
  102. package/dist/core/extensions/types.d.ts.map +1 -1
  103. package/dist/core/extensions/types.js.map +1 -1
  104. package/dist/core/index.d.ts +1 -0
  105. package/dist/core/index.d.ts.map +1 -1
  106. package/dist/core/index.js +1 -0
  107. package/dist/core/index.js.map +1 -1
  108. package/dist/core/model-config.d.ts +8 -0
  109. package/dist/core/model-config.d.ts.map +1 -1
  110. package/dist/core/model-config.js +21 -5
  111. package/dist/core/model-config.js.map +1 -1
  112. package/dist/core/model-resolver.d.ts +20 -0
  113. package/dist/core/model-resolver.d.ts.map +1 -1
  114. package/dist/core/model-resolver.js +59 -0
  115. package/dist/core/model-resolver.js.map +1 -1
  116. package/dist/core/model-runtime.d.ts +73 -0
  117. package/dist/core/model-runtime.d.ts.map +1 -1
  118. package/dist/core/model-runtime.js +225 -8
  119. package/dist/core/model-runtime.js.map +1 -1
  120. package/dist/core/observability/aggregate.d.ts +21 -0
  121. package/dist/core/observability/aggregate.d.ts.map +1 -0
  122. package/dist/core/observability/aggregate.js +36 -0
  123. package/dist/core/observability/aggregate.js.map +1 -0
  124. package/dist/core/observability/otlp.d.ts +66 -0
  125. package/dist/core/observability/otlp.d.ts.map +1 -0
  126. package/dist/core/observability/otlp.js +95 -0
  127. package/dist/core/observability/otlp.js.map +1 -0
  128. package/dist/core/package-manager.d.ts.map +1 -1
  129. package/dist/core/package-manager.js +3 -2
  130. package/dist/core/package-manager.js.map +1 -1
  131. package/dist/core/permissions/gate.d.ts +35 -0
  132. package/dist/core/permissions/gate.d.ts.map +1 -0
  133. package/dist/core/permissions/gate.js +72 -0
  134. package/dist/core/permissions/gate.js.map +1 -0
  135. package/dist/core/permissions/modes.d.ts +18 -0
  136. package/dist/core/permissions/modes.d.ts.map +1 -0
  137. package/dist/core/permissions/modes.js +57 -0
  138. package/dist/core/permissions/modes.js.map +1 -0
  139. package/dist/core/permissions/responder.d.ts +30 -0
  140. package/dist/core/permissions/responder.d.ts.map +1 -0
  141. package/dist/core/permissions/responder.js +32 -0
  142. package/dist/core/permissions/responder.js.map +1 -0
  143. package/dist/core/permissions/rules.d.ts +34 -0
  144. package/dist/core/permissions/rules.d.ts.map +1 -0
  145. package/dist/core/permissions/rules.js +74 -0
  146. package/dist/core/permissions/rules.js.map +1 -0
  147. package/dist/core/permissions/startup.d.ts +33 -0
  148. package/dist/core/permissions/startup.d.ts.map +1 -0
  149. package/dist/core/permissions/startup.js +55 -0
  150. package/dist/core/permissions/startup.js.map +1 -0
  151. package/dist/core/permissions/store.d.ts +114 -0
  152. package/dist/core/permissions/store.d.ts.map +1 -0
  153. package/dist/core/permissions/store.js +229 -0
  154. package/dist/core/permissions/store.js.map +1 -0
  155. package/dist/core/project-trust.d.ts.map +1 -1
  156. package/dist/core/project-trust.js +1 -1
  157. package/dist/core/project-trust.js.map +1 -1
  158. package/dist/core/provider-attribution.d.ts.map +1 -1
  159. package/dist/core/provider-attribution.js +6 -7
  160. package/dist/core/provider-attribution.js.map +1 -1
  161. package/dist/core/remote-catalog-provider.d.ts +2 -2
  162. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  163. package/dist/core/remote-catalog-provider.js +20 -16
  164. package/dist/core/remote-catalog-provider.js.map +1 -1
  165. package/dist/core/sandbox/child-entry.d.ts +2 -0
  166. package/dist/core/sandbox/child-entry.d.ts.map +1 -0
  167. package/dist/core/sandbox/child-entry.js +11 -0
  168. package/dist/core/sandbox/child-entry.js.map +1 -0
  169. package/dist/core/sandbox/cli-launch.d.ts +27 -0
  170. package/dist/core/sandbox/cli-launch.d.ts.map +1 -0
  171. package/dist/core/sandbox/cli-launch.js +133 -0
  172. package/dist/core/sandbox/cli-launch.js.map +1 -0
  173. package/dist/core/sandbox/cli-supervisor.d.ts +25 -0
  174. package/dist/core/sandbox/cli-supervisor.d.ts.map +1 -0
  175. package/dist/core/sandbox/cli-supervisor.js +57 -0
  176. package/dist/core/sandbox/cli-supervisor.js.map +1 -0
  177. package/dist/core/sandbox/linux-backend.d.ts +18 -0
  178. package/dist/core/sandbox/linux-backend.d.ts.map +1 -0
  179. package/dist/core/sandbox/linux-backend.js +186 -0
  180. package/dist/core/sandbox/linux-backend.js.map +1 -0
  181. package/dist/core/sandbox/macos-backend.d.ts +18 -0
  182. package/dist/core/sandbox/macos-backend.d.ts.map +1 -0
  183. package/dist/core/sandbox/macos-backend.js +195 -0
  184. package/dist/core/sandbox/macos-backend.js.map +1 -0
  185. package/dist/core/sandbox/network-proxy.d.ts +19 -0
  186. package/dist/core/sandbox/network-proxy.d.ts.map +1 -0
  187. package/dist/core/sandbox/network-proxy.js +79 -0
  188. package/dist/core/sandbox/network-proxy.js.map +1 -0
  189. package/dist/core/sandbox/policy.d.ts +32 -0
  190. package/dist/core/sandbox/policy.d.ts.map +1 -0
  191. package/dist/core/sandbox/policy.js +38 -0
  192. package/dist/core/sandbox/policy.js.map +1 -0
  193. package/dist/core/sandbox/supervisor.d.ts +31 -0
  194. package/dist/core/sandbox/supervisor.d.ts.map +1 -0
  195. package/dist/core/sandbox/supervisor.js +18 -0
  196. package/dist/core/sandbox/supervisor.js.map +1 -0
  197. package/dist/core/sandbox/violations.d.ts +23 -0
  198. package/dist/core/sandbox/violations.d.ts.map +1 -0
  199. package/dist/core/sandbox/violations.js +30 -0
  200. package/dist/core/sandbox/violations.js.map +1 -0
  201. package/dist/core/sdk.d.ts +20 -36
  202. package/dist/core/sdk.d.ts.map +1 -1
  203. package/dist/core/sdk.js +129 -2
  204. package/dist/core/sdk.js.map +1 -1
  205. package/dist/core/session-manager.d.ts +41 -2
  206. package/dist/core/session-manager.d.ts.map +1 -1
  207. package/dist/core/session-manager.js +57 -0
  208. package/dist/core/session-manager.js.map +1 -1
  209. package/dist/core/session-share.d.ts +16 -0
  210. package/dist/core/session-share.d.ts.map +1 -0
  211. package/dist/core/session-share.js +22 -0
  212. package/dist/core/session-share.js.map +1 -0
  213. package/dist/core/settings-manager.d.ts +38 -9
  214. package/dist/core/settings-manager.d.ts.map +1 -1
  215. package/dist/core/settings-manager.js +39 -24
  216. package/dist/core/settings-manager.js.map +1 -1
  217. package/dist/core/system-prompt.d.ts.map +1 -1
  218. package/dist/core/system-prompt.js +5 -5
  219. package/dist/core/system-prompt.js.map +1 -1
  220. package/dist/core/timings.d.ts +1 -1
  221. package/dist/core/timings.d.ts.map +1 -1
  222. package/dist/core/timings.js +3 -2
  223. package/dist/core/timings.js.map +1 -1
  224. package/dist/core/tools/ask-user.d.ts +25 -0
  225. package/dist/core/tools/ask-user.d.ts.map +1 -0
  226. package/dist/core/tools/ask-user.js +49 -0
  227. package/dist/core/tools/ask-user.js.map +1 -0
  228. package/dist/core/tools/bash-command-segments.d.ts +22 -0
  229. package/dist/core/tools/bash-command-segments.d.ts.map +1 -0
  230. package/dist/core/tools/bash-command-segments.js +128 -0
  231. package/dist/core/tools/bash-command-segments.js.map +1 -0
  232. package/dist/core/tools/bash.d.ts +26 -3
  233. package/dist/core/tools/bash.d.ts.map +1 -1
  234. package/dist/core/tools/bash.js +105 -16
  235. package/dist/core/tools/bash.js.map +1 -1
  236. package/dist/core/tools/contract.d.ts +156 -0
  237. package/dist/core/tools/contract.d.ts.map +1 -0
  238. package/dist/core/tools/contract.js +48 -0
  239. package/dist/core/tools/contract.js.map +1 -0
  240. package/dist/core/tools/delegate.d.ts +38 -0
  241. package/dist/core/tools/delegate.d.ts.map +1 -0
  242. package/dist/core/tools/delegate.js +66 -0
  243. package/dist/core/tools/delegate.js.map +1 -0
  244. package/dist/core/tools/edit.d.ts +2 -2
  245. package/dist/core/tools/edit.d.ts.map +1 -1
  246. package/dist/core/tools/edit.js +24 -0
  247. package/dist/core/tools/edit.js.map +1 -1
  248. package/dist/core/tools/find.d.ts +2 -2
  249. package/dist/core/tools/find.d.ts.map +1 -1
  250. package/dist/core/tools/find.js +12 -0
  251. package/dist/core/tools/find.js.map +1 -1
  252. package/dist/core/tools/grep.d.ts +2 -2
  253. package/dist/core/tools/grep.d.ts.map +1 -1
  254. package/dist/core/tools/grep.js +12 -0
  255. package/dist/core/tools/grep.js.map +1 -1
  256. package/dist/core/tools/index.d.ts +29 -4
  257. package/dist/core/tools/index.d.ts.map +1 -1
  258. package/dist/core/tools/index.js +118 -2
  259. package/dist/core/tools/index.js.map +1 -1
  260. package/dist/core/tools/ls.d.ts +2 -2
  261. package/dist/core/tools/ls.d.ts.map +1 -1
  262. package/dist/core/tools/ls.js +12 -0
  263. package/dist/core/tools/ls.js.map +1 -1
  264. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  265. package/dist/core/tools/output-accumulator.js +1 -1
  266. package/dist/core/tools/output-accumulator.js.map +1 -1
  267. package/dist/core/tools/path-permission.d.ts +18 -0
  268. package/dist/core/tools/path-permission.d.ts.map +1 -0
  269. package/dist/core/tools/path-permission.js +28 -0
  270. package/dist/core/tools/path-permission.js.map +1 -0
  271. package/dist/core/tools/plan-present.d.ts +27 -0
  272. package/dist/core/tools/plan-present.d.ts.map +1 -0
  273. package/dist/core/tools/plan-present.js +55 -0
  274. package/dist/core/tools/plan-present.js.map +1 -0
  275. package/dist/core/tools/read.d.ts +2 -2
  276. package/dist/core/tools/read.d.ts.map +1 -1
  277. package/dist/core/tools/read.js +12 -0
  278. package/dist/core/tools/read.js.map +1 -1
  279. package/dist/core/tools/test.d.ts +34 -0
  280. package/dist/core/tools/test.d.ts.map +1 -0
  281. package/dist/core/tools/test.js +75 -0
  282. package/dist/core/tools/test.js.map +1 -0
  283. package/dist/core/tools/todo-write.d.ts +31 -0
  284. package/dist/core/tools/todo-write.d.ts.map +1 -0
  285. package/dist/core/tools/todo-write.js +51 -0
  286. package/dist/core/tools/todo-write.js.map +1 -0
  287. package/dist/core/tools/tool-definition-wrapper.d.ts +13 -2
  288. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  289. package/dist/core/tools/tool-definition-wrapper.js +11 -1
  290. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  291. package/dist/core/tools/tool-schema.d.ts +22 -0
  292. package/dist/core/tools/tool-schema.d.ts.map +1 -0
  293. package/dist/core/tools/tool-schema.js +45 -0
  294. package/dist/core/tools/tool-schema.js.map +1 -0
  295. package/dist/core/tools/web-fetch.d.ts +26 -0
  296. package/dist/core/tools/web-fetch.d.ts.map +1 -0
  297. package/dist/core/tools/web-fetch.js +62 -0
  298. package/dist/core/tools/web-fetch.js.map +1 -0
  299. package/dist/core/tools/web-search.d.ts +26 -0
  300. package/dist/core/tools/web-search.d.ts.map +1 -0
  301. package/dist/core/tools/web-search.js +53 -0
  302. package/dist/core/tools/web-search.js.map +1 -0
  303. package/dist/core/tools/write.d.ts +6 -2
  304. package/dist/core/tools/write.d.ts.map +1 -1
  305. package/dist/core/tools/write.js +32 -1
  306. package/dist/core/tools/write.js.map +1 -1
  307. package/dist/core/usage-performance-store.d.ts +56 -0
  308. package/dist/core/usage-performance-store.d.ts.map +1 -0
  309. package/dist/core/usage-performance-store.js +85 -0
  310. package/dist/core/usage-performance-store.js.map +1 -0
  311. package/dist/index.d.ts +1 -0
  312. package/dist/index.d.ts.map +1 -1
  313. package/dist/index.js +1 -0
  314. package/dist/index.js.map +1 -1
  315. package/dist/main.d.ts.map +1 -1
  316. package/dist/main.js +48 -6
  317. package/dist/main.js.map +1 -1
  318. package/dist/migrations.d.ts.map +1 -1
  319. package/dist/migrations.js +2 -2
  320. package/dist/migrations.js.map +1 -1
  321. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  322. package/dist/modes/interactive/components/config-selector.js +9 -6
  323. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  324. package/dist/modes/interactive/components/first-time-setup.d.ts +1 -4
  325. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  326. package/dist/modes/interactive/components/first-time-setup.js +11 -39
  327. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  328. package/dist/modes/interactive/components/footer.d.ts +8 -1
  329. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  330. package/dist/modes/interactive/components/footer.js +49 -20
  331. package/dist/modes/interactive/components/footer.js.map +1 -1
  332. package/dist/modes/interactive/components/settings-selector.d.ts +2 -2
  333. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  334. package/dist/modes/interactive/components/settings-selector.js +6 -6
  335. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  336. package/dist/modes/interactive/components/tool-execution.d.ts +2 -1
  337. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  338. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  339. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  340. package/dist/modes/interactive/external-editor.js +58 -9
  341. package/dist/modes/interactive/external-editor.js.map +1 -1
  342. package/dist/modes/interactive/interactive-mode.d.ts +2 -3
  343. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  344. package/dist/modes/interactive/interactive-mode.js +92 -104
  345. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  346. package/dist/modes/interactive/theme/theme-schema.json +2 -2
  347. package/dist/package-manager-cli.d.ts.map +1 -1
  348. package/dist/package-manager-cli.js +15 -10
  349. package/dist/package-manager-cli.js.map +1 -1
  350. package/dist/rpc-entry.d.ts.map +1 -1
  351. package/dist/rpc-entry.js +2 -1
  352. package/dist/rpc-entry.js.map +1 -1
  353. package/dist/server/create-harness.d.ts +1 -1
  354. package/dist/server/create-harness.d.ts.map +1 -1
  355. package/dist/server/create-harness.js +6 -5
  356. package/dist/server/create-harness.js.map +1 -1
  357. package/dist/testing/replay/metrics.d.ts +24 -0
  358. package/dist/testing/replay/metrics.d.ts.map +1 -0
  359. package/dist/testing/replay/metrics.js +35 -0
  360. package/dist/testing/replay/metrics.js.map +1 -0
  361. package/dist/testing/replay/recorded-provider.d.ts +10 -0
  362. package/dist/testing/replay/recorded-provider.d.ts.map +1 -0
  363. package/dist/testing/replay/recorded-provider.js +108 -0
  364. package/dist/testing/replay/recorded-provider.js.map +1 -0
  365. package/dist/testing/replay/runner.d.ts +56 -0
  366. package/dist/testing/replay/runner.d.ts.map +1 -0
  367. package/dist/testing/replay/runner.js +406 -0
  368. package/dist/testing/replay/runner.js.map +1 -0
  369. package/dist/utils/apex-code-user-agent.d.ts +2 -0
  370. package/dist/utils/apex-code-user-agent.d.ts.map +1 -0
  371. package/dist/utils/apex-code-user-agent.js +5 -0
  372. package/dist/utils/apex-code-user-agent.js.map +1 -0
  373. package/dist/utils/clipboard-image.d.ts.map +1 -1
  374. package/dist/utils/clipboard-image.js +1 -1
  375. package/dist/utils/clipboard-image.js.map +1 -1
  376. package/dist/utils/tools-manager.d.ts +32 -0
  377. package/dist/utils/tools-manager.d.ts.map +1 -1
  378. package/dist/utils/tools-manager.js +198 -100
  379. package/dist/utils/tools-manager.js.map +1 -1
  380. package/dist/utils/version-check.d.ts +5 -5
  381. package/dist/utils/version-check.d.ts.map +1 -1
  382. package/dist/utils/version-check.js +23 -14
  383. package/dist/utils/version-check.js.map +1 -1
  384. package/dist/utils/windows-self-update.d.ts.map +1 -1
  385. package/dist/utils/windows-self-update.js +1 -1
  386. package/dist/utils/windows-self-update.js.map +1 -1
  387. package/docs/compaction.md +21 -21
  388. package/docs/containerization.md +24 -21
  389. package/docs/custom-provider.md +9 -9
  390. package/docs/development.md +11 -11
  391. package/docs/environment-variables.md +36 -77
  392. package/docs/extensions.md +47 -47
  393. package/docs/index.md +12 -24
  394. package/docs/json.md +6 -6
  395. package/docs/keybindings.md +3 -3
  396. package/docs/llama-cpp.md +7 -7
  397. package/docs/models.md +11 -11
  398. package/docs/packages.md +46 -42
  399. package/docs/prompt-templates.md +3 -3
  400. package/docs/providers.md +10 -10
  401. package/docs/quickstart.md +49 -32
  402. package/docs/rpc.md +11 -11
  403. package/docs/sdk.md +4 -4
  404. package/docs/security.md +18 -18
  405. package/docs/session-format.md +9 -9
  406. package/docs/sessions.md +13 -13
  407. package/docs/settings.md +10 -14
  408. package/docs/shell-aliases.md +1 -1
  409. package/docs/skills.md +8 -8
  410. package/docs/terminal-setup.md +12 -12
  411. package/docs/termux.md +4 -4
  412. package/docs/themes.md +8 -8
  413. package/docs/tmux.md +4 -4
  414. package/docs/tui.md +3 -3
  415. package/docs/usage.md +54 -51
  416. package/docs/windows.md +1 -1
  417. package/npm-shrinkwrap.json +5 -5
  418. package/package.json +2 -3
  419. package/dist/core/telemetry.d.ts +0 -3
  420. package/dist/core/telemetry.d.ts.map +0 -1
  421. package/dist/core/telemetry.js +0 -9
  422. package/dist/core/telemetry.js.map +0 -1
  423. package/dist/utils/pi-user-agent.d.ts +0 -2
  424. package/dist/utils/pi-user-agent.d.ts.map +0 -1
  425. package/dist/utils/pi-user-agent.js +0 -5
  426. package/dist/utils/pi-user-agent.js.map +0 -1
@@ -0,0 +1,406 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { InMemoryModelsStore, Type, } from "@earendil-works/pi-ai";
4
+ import { Agent } from "apex-code-agent-core";
5
+ import { AuthStorage } from "../../core/auth-storage.js";
6
+ import { estimateTokens } from "../../core/compaction/compaction.js";
7
+ import { installContextPipeline } from "../../core/context/pipeline.js";
8
+ import { ModelRuntime } from "../../core/model-runtime.js";
9
+ import { buildSessionContext, loadEntriesFromFile, SessionManager, } from "../../core/session-manager.js";
10
+ import { buildSystemPrompt } from "../../core/system-prompt.js";
11
+ import { createAllToolDefinitions } from "../../core/tools/index.js";
12
+ import { buildReplayMetrics } from "./metrics.js";
13
+ import { registerRecordedProvider } from "./recorded-provider.js";
14
+ /**
15
+ * Dedicated eviction budget for the replay harness — deliberately **not** derived
16
+ * from the fixture model's `contextWindow` (`recorded-provider.ts` hardcodes
17
+ * `1_000_000` for unrelated reasons predating this pipeline, shared by every
18
+ * fixture in the corpus, and is not to be changed here). Feeding that real
19
+ * `contextWindow` through production's `evictionBudget` formula
20
+ * (`../../core/context/pipeline.ts`) would yield a budget of roughly 490,000 tokens
21
+ * — orders of magnitude above anything in this corpus, so eviction would never
22
+ * observably fire and the gate it is meant to measure would stay blind, which is
23
+ * exactly the gap this task closes.
24
+ *
25
+ * `1_000` was chosen empirically — measured directly against `replayCorpus()`, not
26
+ * estimated — against three constraints that all have to hold simultaneously:
27
+ *
28
+ * - `tool-error-recovery.jsonl`'s single turn carries its entire ~759 tokens
29
+ * (mostly the static system prompt/tool-schema prefix) under budget, so its
30
+ * recorded `contextTokensByTurn: [759]` (`test/replay-runner.test.ts`) is
31
+ * unaffected — confirmed unchanged at this budget.
32
+ * - `heavy-tool-output.jsonl` carries a single ~8,400-token recoverable `read`
33
+ * result — comfortably over budget, so it evicts, which is the fixture's
34
+ * documented purpose ("Large deterministic result for eviction measurements",
35
+ * `fixtures/corpus/README.md`). Measured post-eviction turn: 748 tokens.
36
+ * - `long-tool-heavy.jsonl` accumulates roughly 14,300 evictable tokens by turn 20
37
+ * across ten interleaved `read`/`grep` results. `1_000` was verified against
38
+ * `REPLAY_EVICTION_BUDGET: 0` (the theoretical floor — evict every eligible
39
+ * result unconditionally) and produces the *same* turn-20 result, 1,769 tokens
40
+ * — an 88.4% drop from the pre-pipeline baseline of 15,272 — confirming `1_000`
41
+ * already reaches that floor rather than under-evicting. A first pass at
42
+ * `3_000` measured 3,195 (79.1%, just short of the phase's 80% per-fixture
43
+ * goal); `1_000` was chosen after confirming the floor is actually lower.
44
+ *
45
+ * This constant governs replay measurement only; it has no effect on production,
46
+ * which always calls `evictionBudget` with the real model's `contextWindow`.
47
+ */
48
+ export const REPLAY_EVICTION_BUDGET = 1_000;
49
+ /**
50
+ * Builds a `ContractLookup` from the real production tool definitions — a second,
51
+ * independent call to `createAllToolDefinitions` alongside the one
52
+ * `productionPromptAndSchemas` already makes for the static-prompt baseline. Kept
53
+ * separate rather than threading that function's `definitions` out: the two
54
+ * concerns (building the static prompt/schema baseline vs. resolving a tool's
55
+ * contract for the pipeline) are unrelated, and `createAllToolDefinitions` is cheap
56
+ * and pure, so a second call costs nothing and keeps both call sites simple.
57
+ */
58
+ function replayContractLookup(cwd) {
59
+ const definitions = createAllToolDefinitions(cwd);
60
+ return (name) => Reflect.get(definitions, name)?.contract;
61
+ }
62
+ function isVersionThreeHeader(entry) {
63
+ if (entry === null || typeof entry !== "object")
64
+ return false;
65
+ return Reflect.get(entry, "type") === "session" && Reflect.get(entry, "version") === 3;
66
+ }
67
+ function isSessionEntry(entry) {
68
+ if (entry === null || typeof entry !== "object")
69
+ return false;
70
+ const type = Reflect.get(entry, "type");
71
+ const id = Reflect.get(entry, "id");
72
+ const parentId = Reflect.get(entry, "parentId");
73
+ return (type !== "session" &&
74
+ typeof type === "string" &&
75
+ typeof id === "string" &&
76
+ (parentId === null || typeof parentId === "string"));
77
+ }
78
+ function validateSessionTree(entries) {
79
+ const ids = new Set();
80
+ const parentById = new Map();
81
+ let roots = 0;
82
+ for (const entry of entries) {
83
+ if (!entry || typeof entry.id !== "string" || ids.has(entry.id))
84
+ throw new Error("Replay session contains invalid or duplicate entry ids");
85
+ ids.add(entry.id);
86
+ parentById.set(entry.id, entry.parentId);
87
+ if (entry.parentId === null)
88
+ roots++;
89
+ else if (typeof entry.parentId !== "string")
90
+ throw new Error("Replay session contains an invalid parentId");
91
+ }
92
+ if (roots !== 1)
93
+ throw new Error("Replay session must contain exactly one tree root");
94
+ for (const entry of entries) {
95
+ if (entry.parentId !== null && !ids.has(entry.parentId))
96
+ throw new Error(`Replay session has missing parent ${entry.parentId}`);
97
+ const seen = new Set();
98
+ let current = entry.id;
99
+ while (current !== null) {
100
+ if (seen.has(current))
101
+ throw new Error("Replay session contains a parent cycle");
102
+ seen.add(current);
103
+ current = parentById.get(current) ?? null;
104
+ }
105
+ }
106
+ }
107
+ function isMessageEntry(entry) {
108
+ return entry.type === "message";
109
+ }
110
+ function selectedResponses(entries) {
111
+ return entries
112
+ .filter(isMessageEntry)
113
+ .map((entry) => entry.message)
114
+ .filter((message) => message.role === "assistant");
115
+ }
116
+ function selectedToolResults(entries) {
117
+ return entries
118
+ .filter(isMessageEntry)
119
+ .map((entry) => entry.message)
120
+ .filter((message) => message.role === "toolResult");
121
+ }
122
+ function selectedUserEntries(entries) {
123
+ return entries.filter(isMessageEntry).filter((entry) => entry.message.role === "user");
124
+ }
125
+ function toolCalls(responses) {
126
+ return responses.flatMap((message) => message.content.filter((part) => part.type === "toolCall"));
127
+ }
128
+ function createRecordedTools(calls, results) {
129
+ const resultByCallId = new Map(results.map((result) => [result.toolCallId, structuredClone(result)]));
130
+ const unconsumed = new Set(resultByCallId.keys());
131
+ const tools = [...new Set(calls.map((call) => call.name))].map((name) => ({
132
+ name,
133
+ label: `Recorded ${name}`,
134
+ description: "Replays a recorded tool result without external side effects.",
135
+ parameters: Type.Any(),
136
+ execute: async (toolCallId) => {
137
+ const result = resultByCallId.get(toolCallId);
138
+ if (!result)
139
+ throw new Error(`Missing recorded tool result for ${toolCallId}`);
140
+ unconsumed.delete(toolCallId);
141
+ if (result.isError) {
142
+ const text = result.content.find((part) => part.type === "text")?.text ?? "Recorded tool error";
143
+ throw new Error(text);
144
+ }
145
+ return {
146
+ content: structuredClone(result.content),
147
+ details: structuredClone(result.details),
148
+ usage: structuredClone(result.usage),
149
+ addedToolNames: structuredClone(result.addedToolNames),
150
+ };
151
+ },
152
+ }));
153
+ return {
154
+ tools,
155
+ assertExhausted() {
156
+ if (unconsumed.size > 0)
157
+ throw new Error(`Replay left ${unconsumed.size} tool result(s) unused`);
158
+ },
159
+ };
160
+ }
161
+ function assertResponsesMatch(actual, expected) {
162
+ if (actual.length !== expected.length) {
163
+ throw new Error(`Replayed ${actual.length} assistant response(s), expected ${expected.length}`);
164
+ }
165
+ for (const [index, response] of actual.entries()) {
166
+ if (JSON.stringify(response) !== JSON.stringify(expected[index])) {
167
+ throw new Error(`Replayed assistant response ${index + 1} does not match the recording`);
168
+ }
169
+ }
170
+ }
171
+ function assertToolResultsMatch(actual, expected) {
172
+ if (actual.length !== expected.length) {
173
+ throw new Error(`Replayed ${actual.length} tool result(s), expected ${expected.length}`);
174
+ }
175
+ for (const [index, result] of actual.entries()) {
176
+ const recorded = expected[index];
177
+ if (!recorded)
178
+ throw new Error(`Missing recorded tool result ${index + 1}`);
179
+ const { timestamp: _actualTimestamp, ...actualStable } = result;
180
+ const { timestamp: _recordedTimestamp, ...recordedStable } = recorded;
181
+ const actualComparable = { ...actualStable };
182
+ const recordedComparable = { ...recordedStable };
183
+ if (actualComparable.details === undefined ||
184
+ (typeof actualComparable.details === "object" && Object.keys(actualComparable.details ?? {}).length === 0))
185
+ delete actualComparable.details;
186
+ if (recordedComparable.details === undefined ||
187
+ (typeof recordedComparable.details === "object" && Object.keys(recordedComparable.details ?? {}).length === 0))
188
+ delete recordedComparable.details;
189
+ if (JSON.stringify(actualComparable) !== JSON.stringify(recordedComparable)) {
190
+ throw new Error(`Replayed tool result ${index + 1} does not match the recording`);
191
+ }
192
+ }
193
+ }
194
+ function productionPromptAndSchemas(toolNames) {
195
+ const definitions = createAllToolDefinitions("$HOME/replay-fixtures");
196
+ const defaultToolNames = ["read", "bash", "edit", "write"];
197
+ const selected = [...new Set([...defaultToolNames, ...toolNames])].sort().flatMap((name) => {
198
+ const definition = Reflect.get(definitions, name);
199
+ return definition && typeof definition === "object" ? [definition] : [];
200
+ });
201
+ const toolSnippets = Object.fromEntries(selected.flatMap((definition) => typeof definition.promptSnippet === "string" ? [[definition.name, definition.promptSnippet]] : []));
202
+ const promptGuidelines = selected.flatMap((definition) => definition.promptGuidelines ?? []);
203
+ return {
204
+ systemPrompt: buildSystemPrompt({
205
+ cwd: "$HOME/replay-fixtures",
206
+ customPrompt: "You are an expert coding assistant operating inside Apex Code.",
207
+ selectedTools: selected.map((definition) => definition.name),
208
+ toolSnippets,
209
+ promptGuidelines,
210
+ }),
211
+ tools: selected.map((definition) => ({
212
+ name: definition.name,
213
+ description: definition.description,
214
+ parameters: definition.parameters,
215
+ })),
216
+ };
217
+ }
218
+ export async function replay(filePath) {
219
+ let physicalLines;
220
+ try {
221
+ physicalLines = readFileSync(filePath, "utf8")
222
+ .split("\n")
223
+ .filter((line) => line.trim().length > 0)
224
+ .map((line) => JSON.parse(line));
225
+ }
226
+ catch (error) {
227
+ throw new Error(`Replay requires valid JSONL: ${filePath}`, { cause: error });
228
+ }
229
+ const fileEntries = loadEntriesFromFile(filePath);
230
+ if (physicalLines.length !== fileEntries.length)
231
+ throw new Error("Replay session contains an invalid physical line");
232
+ if (!isVersionThreeHeader(fileEntries[0])) {
233
+ throw new Error(`Replay requires a native version 3 session: ${filePath}`);
234
+ }
235
+ const rawEntries = fileEntries.slice(1);
236
+ const rawSessionEntries = rawEntries.filter(isSessionEntry);
237
+ if (rawSessionEntries.length !== rawEntries.length)
238
+ throw new Error("Replay session contains an invalid entry");
239
+ validateSessionTree(rawSessionEntries);
240
+ const sessionManager = SessionManager.open(filePath);
241
+ const entries = sessionManager.getBranch();
242
+ validateSessionTree(entries);
243
+ const responses = selectedResponses(entries);
244
+ const recordedToolResults = selectedToolResults(entries);
245
+ const users = selectedUserEntries(entries);
246
+ if (users.length === 0 || responses.length === 0)
247
+ throw new Error("Replay session must contain user and assistant messages");
248
+ const runtime = await ModelRuntime.create({
249
+ credentials: AuthStorage.inMemory(),
250
+ modelsPath: null,
251
+ modelsStore: new InMemoryModelsStore(),
252
+ allowModelNetwork: false,
253
+ refreshOnCreate: false,
254
+ });
255
+ const recorded = registerRecordedProvider(runtime, responses);
256
+ const recordedTools = createRecordedTools(toolCalls(responses), recordedToolResults);
257
+ const replayedResponses = [];
258
+ const replayedToolResults = [];
259
+ const contextTokensByTurn = [];
260
+ let turnsCompleted = 0;
261
+ const promptBaseline = productionPromptAndSchemas(recordedTools.tools.map((tool) => tool.name));
262
+ let networkCalls = 0;
263
+ const rejectNetwork = async () => {
264
+ networkCalls++;
265
+ throw new Error("Network access is disabled during replay");
266
+ };
267
+ const firstContext = buildSessionContext(entries, users[0]?.id);
268
+ const firstResponse = responses[0];
269
+ if (!firstResponse)
270
+ throw new Error("Replay session has no recorded response");
271
+ const agent = new Agent({
272
+ initialState: {
273
+ model: recorded.getModel(firstContext.model?.modelId ?? firstResponse.model),
274
+ systemPrompt: promptBaseline.systemPrompt,
275
+ tools: recordedTools.tools,
276
+ },
277
+ streamFn: (model, context, options) => runtime.streamSimple(model, context, { ...options, fetch: rejectNetwork }),
278
+ getApiKey: () => "offline-replay",
279
+ convertToLlm: (messages) => {
280
+ const converted = [];
281
+ for (const message of messages) {
282
+ if (message.role === "user") {
283
+ converted.push({ role: "user", content: message.content, timestamp: message.timestamp });
284
+ continue;
285
+ }
286
+ if (message.role === "assistant") {
287
+ converted.push(message);
288
+ continue;
289
+ }
290
+ if (message.role !== "toolResult")
291
+ continue;
292
+ // Validate the call id is one this replay actually recorded, but send the
293
+ // *incoming* message — not a fresh lookup by id — so that whatever the
294
+ // context pipeline's eviction stage did to `message.content` upstream
295
+ // (in `transformContext`) is what reaches the provider request. Re-fetching
296
+ // the original recorded content here would silently discard eviction,
297
+ // since eviction never touches `recordedToolResults` itself (see
298
+ // `assertToolResultsMatch`, which intentionally still compares against the
299
+ // untouched recording).
300
+ const recordedResult = recordedToolResults.find((result) => result.toolCallId === message.toolCallId);
301
+ if (!recordedResult)
302
+ throw new Error(`Missing recorded tool result for ${message.toolCallId}`);
303
+ converted.push(structuredClone(message));
304
+ }
305
+ return converted;
306
+ },
307
+ afterToolCall: async ({ toolCall }) => {
308
+ const result = recordedToolResults.find((candidate) => candidate.toolCallId === toolCall.id);
309
+ if (!result)
310
+ throw new Error(`Missing recorded tool result for ${toolCall.id}`);
311
+ return {
312
+ content: structuredClone(result.content),
313
+ details: result.details,
314
+ usage: result.usage,
315
+ isError: result.isError,
316
+ };
317
+ },
318
+ toolExecution: "sequential",
319
+ });
320
+ // Same pipeline `AgentSession` installs in production (`_installContextPipeline`
321
+ // in `core/agent-session.ts`), via the shared `installContextPipeline` — deferred
322
+ // -schema resolution ahead of every request, then tool-result eviction — so the
323
+ // replay gate can observe both. The contract lookup is built from the real
324
+ // production tool definitions; the budget is `REPLAY_EVICTION_BUDGET`, a
325
+ // dedicated constant documented above (not derived from the fixture model's
326
+ // `contextWindow`; see that constant's comment for why).
327
+ installContextPipeline(agent, {
328
+ contractLookup: replayContractLookup("$HOME/replay-fixtures"),
329
+ evictionBudget: () => REPLAY_EVICTION_BUDGET,
330
+ });
331
+ const contextsByTurn = [];
332
+ for (const user of users) {
333
+ const historical = buildSessionContext(entries, user.id);
334
+ const nextResponse = responses[recorded.requestCount];
335
+ if (!nextResponse)
336
+ throw new Error(`Missing recorded response for user turn ${contextTokensByTurn.length + 1}`);
337
+ agent.state.model = recorded.getModel(historical.model?.modelId ?? nextResponse.model);
338
+ agent.state.messages = historical.messages.slice(0, -1);
339
+ const requestStart = recorded.requestCount;
340
+ await agent.prompt(user.message);
341
+ const turnContexts = recorded.contexts.slice(requestStart);
342
+ const lastContext = turnContexts.at(-1);
343
+ if (!lastContext)
344
+ throw new Error(`User turn ${contextTokensByTurn.length + 1} made no provider request`);
345
+ const staticInputTokens = Math.ceil(`${promptBaseline.systemPrompt}\n${JSON.stringify(promptBaseline.tools)}`.length / 4);
346
+ contextTokensByTurn.push(staticInputTokens + lastContext.messages.reduce((total, message) => total + estimateTokens(message), 0));
347
+ // Normalize toolResult timestamps to the recorded value before exposing this
348
+ // turn's context, mirroring the same normalization the `toolResults` field
349
+ // below already does and for the same reason: a toolResult's timestamp is
350
+ // stamped live (via `agent.state.messages`) rather than replayed from the
351
+ // fixture, so leaving it as-is would make `contextsByTurn` — and anything
352
+ // that serializes it, like the determinism test below — flaky across runs.
353
+ // Content (what eviction may have rewritten) is untouched.
354
+ contextsByTurn.push(lastContext.messages.map((message) => message.role === "toolResult"
355
+ ? {
356
+ ...message,
357
+ timestamp: recordedToolResults.find((result) => result.toolCallId === message.toolCallId)?.timestamp ??
358
+ message.timestamp,
359
+ }
360
+ : message));
361
+ for (const message of agent.state.messages.slice(historical.messages.length - 1)) {
362
+ if (message.role === "assistant")
363
+ replayedResponses.push(message);
364
+ if (message.role === "toolResult")
365
+ replayedToolResults.push(message);
366
+ }
367
+ const terminalResponse = replayedResponses.at(-1);
368
+ if (terminalResponse && terminalResponse.stopReason !== "error" && terminalResponse.stopReason !== "aborted") {
369
+ turnsCompleted++;
370
+ }
371
+ }
372
+ recorded.assertExhausted();
373
+ recordedTools.assertExhausted();
374
+ assertResponsesMatch(replayedResponses, responses);
375
+ assertToolResultsMatch(replayedToolResults, recordedToolResults);
376
+ return {
377
+ turns: users.length,
378
+ requests: recorded.requestCount,
379
+ networkCalls,
380
+ responses: replayedResponses,
381
+ toolResults: replayedToolResults.map((result, index) => ({
382
+ ...structuredClone(result),
383
+ timestamp: recordedToolResults[index]?.timestamp ?? result.timestamp,
384
+ })),
385
+ contextsByTurn,
386
+ metrics: buildReplayMetrics({
387
+ systemPrompt: promptBaseline.systemPrompt,
388
+ tools: promptBaseline.tools,
389
+ recordedResponses: responses,
390
+ replayedResponses,
391
+ contextTokensByTurn,
392
+ turnsCompleted,
393
+ }),
394
+ };
395
+ }
396
+ /** Replay every JSONL fixture in lexical order for byte-stable corpus output. */
397
+ export async function replayCorpus(directory) {
398
+ const metrics = {};
399
+ for (const name of readdirSync(directory)
400
+ .filter((entry) => entry.endsWith(".jsonl"))
401
+ .sort()) {
402
+ metrics[name] = (await replay(join(directory, name))).metrics;
403
+ }
404
+ return metrics;
405
+ }
406
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/testing/replay/runner.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n\ttype AssistantMessage,\n\tInMemoryModelsStore,\n\ttype Message,\n\ttype Tool,\n\ttype ToolCall,\n\ttype ToolResultMessage,\n\tType,\n} from \"@earendil-works/pi-ai\";\nimport { Agent, type AgentTool, type AgentToolResult } from \"apex-code-agent-core\";\nimport { AuthStorage } from \"../../core/auth-storage.ts\";\nimport { estimateTokens } from \"../../core/compaction/compaction.ts\";\nimport type { ContractLookup } from \"../../core/context/eviction.ts\";\nimport { installContextPipeline } from \"../../core/context/pipeline.ts\";\nimport { ModelRuntime } from \"../../core/model-runtime.ts\";\nimport {\n\tbuildSessionContext,\n\tloadEntriesFromFile,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\tSessionManager,\n\ttype SessionMessageEntry,\n} from \"../../core/session-manager.ts\";\nimport { buildSystemPrompt } from \"../../core/system-prompt.ts\";\nimport { createAllToolDefinitions, type ToolDef } from \"../../core/tools/index.ts\";\nimport { buildReplayMetrics, type ReplayMetrics } from \"./metrics.ts\";\nimport { registerRecordedProvider } from \"./recorded-provider.ts\";\n\nexport interface ReplayResult {\n\tturns: number;\n\trequests: number;\n\tnetworkCalls: number;\n\tresponses: AssistantMessage[];\n\ttoolResults: ToolResultMessage[];\n\tmetrics: ReplayMetrics;\n\t/**\n\t * The final outbound provider request's messages for each user turn — the same\n\t * array `contextTokensByTurn` is measured from, exposed so tests can assert\n\t * directly on context-pipeline effects (eviction markers, deferred schemas)\n\t * without reaching into `RecordedProvider` internals.\n\t */\n\tcontextsByTurn: Message[][];\n}\n\n/**\n * Dedicated eviction budget for the replay harness — deliberately **not** derived\n * from the fixture model's `contextWindow` (`recorded-provider.ts` hardcodes\n * `1_000_000` for unrelated reasons predating this pipeline, shared by every\n * fixture in the corpus, and is not to be changed here). Feeding that real\n * `contextWindow` through production's `evictionBudget` formula\n * (`../../core/context/pipeline.ts`) would yield a budget of roughly 490,000 tokens\n * — orders of magnitude above anything in this corpus, so eviction would never\n * observably fire and the gate it is meant to measure would stay blind, which is\n * exactly the gap this task closes.\n *\n * `1_000` was chosen empirically — measured directly against `replayCorpus()`, not\n * estimated — against three constraints that all have to hold simultaneously:\n *\n * - `tool-error-recovery.jsonl`'s single turn carries its entire ~759 tokens\n * (mostly the static system prompt/tool-schema prefix) under budget, so its\n * recorded `contextTokensByTurn: [759]` (`test/replay-runner.test.ts`) is\n * unaffected — confirmed unchanged at this budget.\n * - `heavy-tool-output.jsonl` carries a single ~8,400-token recoverable `read`\n * result — comfortably over budget, so it evicts, which is the fixture's\n * documented purpose (\"Large deterministic result for eviction measurements\",\n * `fixtures/corpus/README.md`). Measured post-eviction turn: 748 tokens.\n * - `long-tool-heavy.jsonl` accumulates roughly 14,300 evictable tokens by turn 20\n * across ten interleaved `read`/`grep` results. `1_000` was verified against\n * `REPLAY_EVICTION_BUDGET: 0` (the theoretical floor — evict every eligible\n * result unconditionally) and produces the *same* turn-20 result, 1,769 tokens\n * — an 88.4% drop from the pre-pipeline baseline of 15,272 — confirming `1_000`\n * already reaches that floor rather than under-evicting. A first pass at\n * `3_000` measured 3,195 (79.1%, just short of the phase's 80% per-fixture\n * goal); `1_000` was chosen after confirming the floor is actually lower.\n *\n * This constant governs replay measurement only; it has no effect on production,\n * which always calls `evictionBudget` with the real model's `contextWindow`.\n */\nexport const REPLAY_EVICTION_BUDGET = 1_000;\n\n/**\n * Builds a `ContractLookup` from the real production tool definitions — a second,\n * independent call to `createAllToolDefinitions` alongside the one\n * `productionPromptAndSchemas` already makes for the static-prompt baseline. Kept\n * separate rather than threading that function's `definitions` out: the two\n * concerns (building the static prompt/schema baseline vs. resolving a tool's\n * contract for the pipeline) are unrelated, and `createAllToolDefinitions` is cheap\n * and pure, so a second call costs nothing and keeps both call sites simple.\n */\nfunction replayContractLookup(cwd: string): ContractLookup {\n\tconst definitions = createAllToolDefinitions(cwd);\n\treturn (name) => (Reflect.get(definitions, name) as Partial<ToolDef> | undefined)?.contract;\n}\n\nfunction isVersionThreeHeader(entry: unknown): entry is SessionHeader & { version: 3 } {\n\tif (entry === null || typeof entry !== \"object\") return false;\n\treturn Reflect.get(entry, \"type\") === \"session\" && Reflect.get(entry, \"version\") === 3;\n}\n\nfunction isSessionEntry(entry: unknown): entry is SessionEntry {\n\tif (entry === null || typeof entry !== \"object\") return false;\n\tconst type = Reflect.get(entry, \"type\");\n\tconst id = Reflect.get(entry, \"id\");\n\tconst parentId = Reflect.get(entry, \"parentId\");\n\treturn (\n\t\ttype !== \"session\" &&\n\t\ttypeof type === \"string\" &&\n\t\ttypeof id === \"string\" &&\n\t\t(parentId === null || typeof parentId === \"string\")\n\t);\n}\n\nfunction validateSessionTree(entries: readonly SessionEntry[]): void {\n\tconst ids = new Set<string>();\n\tconst parentById = new Map<string, string | null>();\n\tlet roots = 0;\n\tfor (const entry of entries) {\n\t\tif (!entry || typeof entry.id !== \"string\" || ids.has(entry.id))\n\t\t\tthrow new Error(\"Replay session contains invalid or duplicate entry ids\");\n\t\tids.add(entry.id);\n\t\tparentById.set(entry.id, entry.parentId);\n\t\tif (entry.parentId === null) roots++;\n\t\telse if (typeof entry.parentId !== \"string\") throw new Error(\"Replay session contains an invalid parentId\");\n\t}\n\tif (roots !== 1) throw new Error(\"Replay session must contain exactly one tree root\");\n\tfor (const entry of entries) {\n\t\tif (entry.parentId !== null && !ids.has(entry.parentId))\n\t\t\tthrow new Error(`Replay session has missing parent ${entry.parentId}`);\n\t\tconst seen = new Set<string>();\n\t\tlet current: string | null = entry.id;\n\t\twhile (current !== null) {\n\t\t\tif (seen.has(current)) throw new Error(\"Replay session contains a parent cycle\");\n\t\t\tseen.add(current);\n\t\t\tcurrent = parentById.get(current) ?? null;\n\t\t}\n\t}\n}\n\nfunction isMessageEntry(entry: SessionEntry): entry is SessionMessageEntry {\n\treturn entry.type === \"message\";\n}\n\nfunction selectedResponses(entries: readonly SessionEntry[]): AssistantMessage[] {\n\treturn entries\n\t\t.filter(isMessageEntry)\n\t\t.map((entry) => entry.message)\n\t\t.filter((message): message is AssistantMessage => message.role === \"assistant\");\n}\n\nfunction selectedToolResults(entries: readonly SessionEntry[]): ToolResultMessage[] {\n\treturn entries\n\t\t.filter(isMessageEntry)\n\t\t.map((entry) => entry.message)\n\t\t.filter((message): message is ToolResultMessage => message.role === \"toolResult\");\n}\n\nfunction selectedUserEntries(entries: readonly SessionEntry[]): SessionMessageEntry[] {\n\treturn entries.filter(isMessageEntry).filter((entry) => entry.message.role === \"user\");\n}\n\nfunction toolCalls(responses: readonly AssistantMessage[]): ToolCall[] {\n\treturn responses.flatMap((message) => message.content.filter((part): part is ToolCall => part.type === \"toolCall\"));\n}\n\nfunction createRecordedTools(\n\tcalls: readonly ToolCall[],\n\tresults: readonly ToolResultMessage[],\n): { tools: AgentTool[]; assertExhausted(): void } {\n\tconst resultByCallId = new Map(results.map((result) => [result.toolCallId, structuredClone(result)]));\n\tconst unconsumed = new Set(resultByCallId.keys());\n\tconst tools = [...new Set(calls.map((call) => call.name))].map(\n\t\t(name): AgentTool => ({\n\t\t\tname,\n\t\t\tlabel: `Recorded ${name}`,\n\t\t\tdescription: \"Replays a recorded tool result without external side effects.\",\n\t\t\tparameters: Type.Any(),\n\t\t\texecute: async (toolCallId): Promise<AgentToolResult<unknown>> => {\n\t\t\t\tconst result = resultByCallId.get(toolCallId);\n\t\t\t\tif (!result) throw new Error(`Missing recorded tool result for ${toolCallId}`);\n\t\t\t\tunconsumed.delete(toolCallId);\n\t\t\t\tif (result.isError) {\n\t\t\t\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"Recorded tool error\";\n\t\t\t\t\tthrow new Error(text);\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tcontent: structuredClone(result.content),\n\t\t\t\t\tdetails: structuredClone(result.details),\n\t\t\t\t\tusage: structuredClone(result.usage),\n\t\t\t\t\taddedToolNames: structuredClone(result.addedToolNames),\n\t\t\t\t};\n\t\t\t},\n\t\t}),\n\t);\n\treturn {\n\t\ttools,\n\t\tassertExhausted() {\n\t\t\tif (unconsumed.size > 0) throw new Error(`Replay left ${unconsumed.size} tool result(s) unused`);\n\t\t},\n\t};\n}\n\nfunction assertResponsesMatch(actual: readonly AssistantMessage[], expected: readonly AssistantMessage[]): void {\n\tif (actual.length !== expected.length) {\n\t\tthrow new Error(`Replayed ${actual.length} assistant response(s), expected ${expected.length}`);\n\t}\n\tfor (const [index, response] of actual.entries()) {\n\t\tif (JSON.stringify(response) !== JSON.stringify(expected[index])) {\n\t\t\tthrow new Error(`Replayed assistant response ${index + 1} does not match the recording`);\n\t\t}\n\t}\n}\n\nfunction assertToolResultsMatch(actual: readonly ToolResultMessage[], expected: readonly ToolResultMessage[]): void {\n\tif (actual.length !== expected.length) {\n\t\tthrow new Error(`Replayed ${actual.length} tool result(s), expected ${expected.length}`);\n\t}\n\tfor (const [index, result] of actual.entries()) {\n\t\tconst recorded = expected[index];\n\t\tif (!recorded) throw new Error(`Missing recorded tool result ${index + 1}`);\n\t\tconst { timestamp: _actualTimestamp, ...actualStable } = result;\n\t\tconst { timestamp: _recordedTimestamp, ...recordedStable } = recorded;\n\t\tconst actualComparable = { ...actualStable };\n\t\tconst recordedComparable = { ...recordedStable };\n\t\tif (\n\t\t\tactualComparable.details === undefined ||\n\t\t\t(typeof actualComparable.details === \"object\" && Object.keys(actualComparable.details ?? {}).length === 0)\n\t\t)\n\t\t\tdelete actualComparable.details;\n\t\tif (\n\t\t\trecordedComparable.details === undefined ||\n\t\t\t(typeof recordedComparable.details === \"object\" && Object.keys(recordedComparable.details ?? {}).length === 0)\n\t\t)\n\t\t\tdelete recordedComparable.details;\n\t\tif (JSON.stringify(actualComparable) !== JSON.stringify(recordedComparable)) {\n\t\t\tthrow new Error(`Replayed tool result ${index + 1} does not match the recording`);\n\t\t}\n\t}\n}\n\nfunction productionPromptAndSchemas(toolNames: readonly string[]): { systemPrompt: string; tools: Tool[] } {\n\tconst definitions = createAllToolDefinitions(\"$HOME/replay-fixtures\");\n\tconst defaultToolNames = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst selected = [...new Set([...defaultToolNames, ...toolNames])].sort().flatMap((name) => {\n\t\tconst definition = Reflect.get(definitions, name);\n\t\treturn definition && typeof definition === \"object\" ? [definition] : [];\n\t});\n\tconst toolSnippets = Object.fromEntries(\n\t\tselected.flatMap((definition) =>\n\t\t\ttypeof definition.promptSnippet === \"string\" ? [[definition.name, definition.promptSnippet]] : [],\n\t\t),\n\t);\n\tconst promptGuidelines = selected.flatMap((definition) => definition.promptGuidelines ?? []);\n\treturn {\n\t\tsystemPrompt: buildSystemPrompt({\n\t\t\tcwd: \"$HOME/replay-fixtures\",\n\t\t\tcustomPrompt: \"You are an expert coding assistant operating inside Apex Code.\",\n\t\t\tselectedTools: selected.map((definition) => definition.name),\n\t\t\ttoolSnippets,\n\t\t\tpromptGuidelines,\n\t\t}),\n\t\ttools: selected.map((definition) => ({\n\t\t\tname: definition.name,\n\t\t\tdescription: definition.description,\n\t\t\tparameters: definition.parameters,\n\t\t})),\n\t};\n}\n\nexport async function replay(filePath: string): Promise<ReplayResult> {\n\tlet physicalLines: unknown[];\n\ttry {\n\t\tphysicalLines = readFileSync(filePath, \"utf8\")\n\t\t\t.split(\"\\n\")\n\t\t\t.filter((line) => line.trim().length > 0)\n\t\t\t.map((line) => JSON.parse(line));\n\t} catch (error) {\n\t\tthrow new Error(`Replay requires valid JSONL: ${filePath}`, { cause: error });\n\t}\n\tconst fileEntries = loadEntriesFromFile(filePath);\n\tif (physicalLines.length !== fileEntries.length) throw new Error(\"Replay session contains an invalid physical line\");\n\tif (!isVersionThreeHeader(fileEntries[0])) {\n\t\tthrow new Error(`Replay requires a native version 3 session: ${filePath}`);\n\t}\n\tconst rawEntries = fileEntries.slice(1);\n\tconst rawSessionEntries = rawEntries.filter(isSessionEntry);\n\tif (rawSessionEntries.length !== rawEntries.length) throw new Error(\"Replay session contains an invalid entry\");\n\tvalidateSessionTree(rawSessionEntries);\n\tconst sessionManager = SessionManager.open(filePath);\n\tconst entries = sessionManager.getBranch();\n\tvalidateSessionTree(entries);\n\tconst responses = selectedResponses(entries);\n\tconst recordedToolResults = selectedToolResults(entries);\n\tconst users = selectedUserEntries(entries);\n\tif (users.length === 0 || responses.length === 0)\n\t\tthrow new Error(\"Replay session must contain user and assistant messages\");\n\n\tconst runtime = await ModelRuntime.create({\n\t\tcredentials: AuthStorage.inMemory(),\n\t\tmodelsPath: null,\n\t\tmodelsStore: new InMemoryModelsStore(),\n\t\tallowModelNetwork: false,\n\t\trefreshOnCreate: false,\n\t});\n\tconst recorded = registerRecordedProvider(runtime, responses);\n\tconst recordedTools = createRecordedTools(toolCalls(responses), recordedToolResults);\n\tconst replayedResponses: AssistantMessage[] = [];\n\tconst replayedToolResults: ToolResultMessage[] = [];\n\tconst contextTokensByTurn: number[] = [];\n\tlet turnsCompleted = 0;\n\tconst promptBaseline = productionPromptAndSchemas(recordedTools.tools.map((tool) => tool.name));\n\tlet networkCalls = 0;\n\tconst rejectNetwork: typeof globalThis.fetch = async () => {\n\t\tnetworkCalls++;\n\t\tthrow new Error(\"Network access is disabled during replay\");\n\t};\n\tconst firstContext = buildSessionContext(entries, users[0]?.id);\n\tconst firstResponse = responses[0];\n\tif (!firstResponse) throw new Error(\"Replay session has no recorded response\");\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tmodel: recorded.getModel(firstContext.model?.modelId ?? firstResponse.model),\n\t\t\tsystemPrompt: promptBaseline.systemPrompt,\n\t\t\ttools: recordedTools.tools,\n\t\t},\n\t\tstreamFn: (model, context, options) => runtime.streamSimple(model, context, { ...options, fetch: rejectNetwork }),\n\t\tgetApiKey: () => \"offline-replay\",\n\t\tconvertToLlm: (messages) => {\n\t\t\tconst converted: Message[] = [];\n\t\t\tfor (const message of messages) {\n\t\t\t\tif (message.role === \"user\") {\n\t\t\t\t\tconverted.push({ role: \"user\", content: message.content, timestamp: message.timestamp });\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (message.role === \"assistant\") {\n\t\t\t\t\tconverted.push(message);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (message.role !== \"toolResult\") continue;\n\t\t\t\t// Validate the call id is one this replay actually recorded, but send the\n\t\t\t\t// *incoming* message — not a fresh lookup by id — so that whatever the\n\t\t\t\t// context pipeline's eviction stage did to `message.content` upstream\n\t\t\t\t// (in `transformContext`) is what reaches the provider request. Re-fetching\n\t\t\t\t// the original recorded content here would silently discard eviction,\n\t\t\t\t// since eviction never touches `recordedToolResults` itself (see\n\t\t\t\t// `assertToolResultsMatch`, which intentionally still compares against the\n\t\t\t\t// untouched recording).\n\t\t\t\tconst recordedResult = recordedToolResults.find((result) => result.toolCallId === message.toolCallId);\n\t\t\t\tif (!recordedResult) throw new Error(`Missing recorded tool result for ${message.toolCallId}`);\n\t\t\t\tconverted.push(structuredClone(message));\n\t\t\t}\n\t\t\treturn converted;\n\t\t},\n\t\tafterToolCall: async ({ toolCall }) => {\n\t\t\tconst result = recordedToolResults.find((candidate) => candidate.toolCallId === toolCall.id);\n\t\t\tif (!result) throw new Error(`Missing recorded tool result for ${toolCall.id}`);\n\t\t\treturn {\n\t\t\t\tcontent: structuredClone(result.content),\n\t\t\t\tdetails: result.details,\n\t\t\t\tusage: result.usage,\n\t\t\t\tisError: result.isError,\n\t\t\t};\n\t\t},\n\t\ttoolExecution: \"sequential\",\n\t});\n\n\t// Same pipeline `AgentSession` installs in production (`_installContextPipeline`\n\t// in `core/agent-session.ts`), via the shared `installContextPipeline` — deferred\n\t// -schema resolution ahead of every request, then tool-result eviction — so the\n\t// replay gate can observe both. The contract lookup is built from the real\n\t// production tool definitions; the budget is `REPLAY_EVICTION_BUDGET`, a\n\t// dedicated constant documented above (not derived from the fixture model's\n\t// `contextWindow`; see that constant's comment for why).\n\tinstallContextPipeline(agent, {\n\t\tcontractLookup: replayContractLookup(\"$HOME/replay-fixtures\"),\n\t\tevictionBudget: () => REPLAY_EVICTION_BUDGET,\n\t});\n\n\tconst contextsByTurn: Message[][] = [];\n\tfor (const user of users) {\n\t\tconst historical = buildSessionContext(entries, user.id);\n\t\tconst nextResponse = responses[recorded.requestCount];\n\t\tif (!nextResponse) throw new Error(`Missing recorded response for user turn ${contextTokensByTurn.length + 1}`);\n\t\tagent.state.model = recorded.getModel(historical.model?.modelId ?? nextResponse.model);\n\t\tagent.state.messages = historical.messages.slice(0, -1);\n\t\tconst requestStart = recorded.requestCount;\n\t\tawait agent.prompt(user.message);\n\t\tconst turnContexts = recorded.contexts.slice(requestStart);\n\t\tconst lastContext = turnContexts.at(-1);\n\t\tif (!lastContext) throw new Error(`User turn ${contextTokensByTurn.length + 1} made no provider request`);\n\t\tconst staticInputTokens = Math.ceil(\n\t\t\t`${promptBaseline.systemPrompt}\\n${JSON.stringify(promptBaseline.tools)}`.length / 4,\n\t\t);\n\t\tcontextTokensByTurn.push(\n\t\t\tstaticInputTokens + lastContext.messages.reduce((total, message) => total + estimateTokens(message), 0),\n\t\t);\n\t\t// Normalize toolResult timestamps to the recorded value before exposing this\n\t\t// turn's context, mirroring the same normalization the `toolResults` field\n\t\t// below already does and for the same reason: a toolResult's timestamp is\n\t\t// stamped live (via `agent.state.messages`) rather than replayed from the\n\t\t// fixture, so leaving it as-is would make `contextsByTurn` — and anything\n\t\t// that serializes it, like the determinism test below — flaky across runs.\n\t\t// Content (what eviction may have rewritten) is untouched.\n\t\tcontextsByTurn.push(\n\t\t\tlastContext.messages.map((message) =>\n\t\t\t\tmessage.role === \"toolResult\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...message,\n\t\t\t\t\t\t\ttimestamp:\n\t\t\t\t\t\t\t\trecordedToolResults.find((result) => result.toolCallId === message.toolCallId)?.timestamp ??\n\t\t\t\t\t\t\t\tmessage.timestamp,\n\t\t\t\t\t\t}\n\t\t\t\t\t: message,\n\t\t\t),\n\t\t);\n\t\tfor (const message of agent.state.messages.slice(historical.messages.length - 1)) {\n\t\t\tif (message.role === \"assistant\") replayedResponses.push(message);\n\t\t\tif (message.role === \"toolResult\") replayedToolResults.push(message);\n\t\t}\n\t\tconst terminalResponse = replayedResponses.at(-1);\n\t\tif (terminalResponse && terminalResponse.stopReason !== \"error\" && terminalResponse.stopReason !== \"aborted\") {\n\t\t\tturnsCompleted++;\n\t\t}\n\t}\n\trecorded.assertExhausted();\n\trecordedTools.assertExhausted();\n\tassertResponsesMatch(replayedResponses, responses);\n\tassertToolResultsMatch(replayedToolResults, recordedToolResults);\n\n\treturn {\n\t\tturns: users.length,\n\t\trequests: recorded.requestCount,\n\t\tnetworkCalls,\n\t\tresponses: replayedResponses,\n\t\ttoolResults: replayedToolResults.map((result, index) => ({\n\t\t\t...structuredClone(result),\n\t\t\ttimestamp: recordedToolResults[index]?.timestamp ?? result.timestamp,\n\t\t})),\n\t\tcontextsByTurn,\n\t\tmetrics: buildReplayMetrics({\n\t\t\tsystemPrompt: promptBaseline.systemPrompt,\n\t\t\ttools: promptBaseline.tools,\n\t\t\trecordedResponses: responses,\n\t\t\treplayedResponses,\n\t\t\tcontextTokensByTurn,\n\t\t\tturnsCompleted,\n\t\t}),\n\t};\n}\n\n/** Replay every JSONL fixture in lexical order for byte-stable corpus output. */\nexport async function replayCorpus(directory: string): Promise<Record<string, ReplayMetrics>> {\n\tconst metrics: Record<string, ReplayMetrics> = {};\n\tfor (const name of readdirSync(directory)\n\t\t.filter((entry) => entry.endsWith(\".jsonl\"))\n\t\t.sort()) {\n\t\tmetrics[name] = (await replay(join(directory, name))).metrics;\n\t}\n\treturn metrics;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export declare function getApexCodeUserAgent(version: string): string;
2
+ //# sourceMappingURL=apex-code-user-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apex-code-user-agent.d.ts","sourceRoot":"","sources":["../../src/utils/apex-code-user-agent.ts"],"names":[],"mappings":"AAAA,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAG5D","sourcesContent":["export function getApexCodeUserAgent(version: string): string {\n\tconst runtime = process.versions.bun ? `bun/${process.versions.bun}` : `node/${process.version}`;\n\treturn `apex-code/${version} (${process.platform}; ${runtime}; ${process.arch})`;\n}\n"]}
@@ -0,0 +1,5 @@
1
+ export function getApexCodeUserAgent(version) {
2
+ const runtime = process.versions.bun ? `bun/${process.versions.bun}` : `node/${process.version}`;
3
+ return `apex-code/${version} (${process.platform}; ${runtime}; ${process.arch})`;
4
+ }
5
+ //# sourceMappingURL=apex-code-user-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apex-code-user-agent.js","sourceRoot":"","sources":["../../src/utils/apex-code-user-agent.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAU;IAC7D,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;IACjG,OAAO,aAAa,OAAO,KAAK,OAAO,CAAC,QAAQ,KAAK,OAAO,KAAK,OAAO,CAAC,IAAI,GAAG,CAAC;AAAA,CACjF","sourcesContent":["export function getApexCodeUserAgent(version: string): string {\n\tconst runtime = process.versions.bun ? `bun/${process.versions.bun}` : `node/${process.version}`;\n\treturn `apex-code/${version} (${process.platform}; ${runtime}; ${process.arch})`;\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;AAmND,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,CA2CjC","sourcesContent":["import { spawnSync } from \"child_process\";\nimport { randomUUID } from \"crypto\";\nimport { readFileSync, unlinkSync } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_READ_TIMEOUT_MS = 3000;\nconst DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\toptions?: { timeoutMs?: number; maxBufferBytes?: number; env?: NodeJS.ProcessEnv },\n): { stdout: Buffer; ok: boolean } {\n\tconst timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n\tconst maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n\n\tconst result = spawnSync(command, args, {\n\t\ttimeout: timeoutMs,\n\t\tmaxBuffer: maxBufferBytes,\n\t\tenv: options?.env,\n\t});\n\n\tif (result.error) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (result.status !== 0) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tconst stdout = Buffer.isBuffer(result.stdout)\n\t\t? result.stdout\n\t\t: Buffer.from(result.stdout ?? \"\", typeof result.stdout === \"string\" ? \"utf-8\" : undefined);\n\n\treturn { ok: true, stdout };\n}\n\nfunction readClipboardImageViaWlPaste(): ClipboardImage | null {\n\tconst list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (!list.ok) {\n\t\treturn null;\n\t}\n\n\tconst types = list.stdout\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (!data.ok || data.stdout.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn { bytes: data.stdout, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * On WSL, the Linux clipboard (Wayland/X11) does not receive image data from\n * Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard\n * directly, so we use it as a fallback.\n */\nfunction readClipboardImageViaPowerShell(): ClipboardImage | null {\n\tconst tmpFile = join(tmpdir(), `pi-wsl-clip-${randomUUID()}.png`);\n\n\ttry {\n\t\tconst winPathResult = runCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\t\tif (!winPathResult.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst winPath = winPathResult.stdout.toString(\"utf-8\").trim();\n\t\tif (!winPath) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst psQuotedWinPath = winPath.replaceAll(\"'\", \"''\");\n\t\tconst psScript = [\n\t\t\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\t\t\"Add-Type -AssemblyName System.Drawing\",\n\t\t\t`$path = '${psQuotedWinPath}'`,\n\t\t\t\"$img = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\t\t\"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }\",\n\t\t].join(\"; \");\n\n\t\tconst result = runCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", psScript], {\n\t\t\ttimeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,\n\t\t});\n\t\tif (!result.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst output = result.stdout.toString(\"utf-8\").trim();\n\t\tif (output !== \"ok\") {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst bytes = readFileSync(tmpFile);\n\t\tif (bytes.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn { bytes: new Uint8Array(bytes), mimeType: \"image/png\" };\n\t} catch {\n\t\treturn null;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors.\n\t\t}\n\t}\n}\n\nfunction readClipboardImageViaXclip(): ClipboardImage | null {\n\tconst targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets.ok) {\n\t\tcandidateTypes = targets.stdout\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n\tconst tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data.ok && data.stdout.length > 0) {\n\t\t\treturn { bytes: data.stdout, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn null;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null> {\n\tif (!clipboard || !clipboard.hasImage()) {\n\t\treturn null;\n\t}\n\n\tconst imageData = await clipboard.getImageBinary();\n\tif (!imageData || imageData.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n\treturn { bytes, mimeType: \"image/png\" };\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tlet image: ClipboardImage | null = null;\n\n\tif (platform === \"linux\") {\n\t\tconst wsl = isWSL(env);\n\t\tconst wayland = isWaylandSession(env);\n\n\t\tif (wayland || wsl) {\n\t\t\timage = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();\n\t\t}\n\n\t\tif (!image && wsl) {\n\t\t\timage = readClipboardImageViaPowerShell();\n\t\t}\n\n\t\tif (!image && !wayland) {\n\t\t\timage = (await readClipboardImageViaNativeClipboard()) ?? readClipboardImageViaXclip();\n\t\t}\n\t} else {\n\t\timage = await readClipboardImageViaNativeClipboard();\n\t}\n\n\tif (!image) {\n\t\treturn null;\n\t}\n\n\t// Convert unsupported formats (e.g., BMP from WSLg) to PNG\n\tif (!isSupportedImageMimeType(image.mimeType)) {\n\t\tconst pngBytes = await convertToPng(image.bytes);\n\t\tif (!pngBytes) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { bytes: pngBytes, mimeType: \"image/png\" };\n\t}\n\n\treturn image;\n}\n"]}
1
+ {"version":3,"file":"clipboard-image.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;AAmND,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,CA2CjC","sourcesContent":["import { spawnSync } from \"child_process\";\nimport { randomUUID } from \"crypto\";\nimport { readFileSync, unlinkSync } from \"fs\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\n\nimport { clipboard } from \"./clipboard-native.ts\";\nimport { loadPhoton } from \"./photon.ts\";\n\nexport type ClipboardImage = {\n\tbytes: Uint8Array;\n\tmimeType: string;\n};\n\nconst SUPPORTED_IMAGE_MIME_TYPES = [\"image/png\", \"image/jpeg\", \"image/webp\", \"image/gif\"] as const;\n\nconst DEFAULT_LIST_TIMEOUT_MS = 1000;\nconst DEFAULT_READ_TIMEOUT_MS = 3000;\nconst DEFAULT_POWERSHELL_TIMEOUT_MS = 5000;\nconst DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;\n\nexport function isWaylandSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn Boolean(env.WAYLAND_DISPLAY) || env.XDG_SESSION_TYPE === \"wayland\";\n}\n\nfunction baseMimeType(mimeType: string): string {\n\treturn mimeType.split(\";\")[0]?.trim().toLowerCase() ?? mimeType.toLowerCase();\n}\n\nexport function extensionForImageMimeType(mimeType: string): string | null {\n\tswitch (baseMimeType(mimeType)) {\n\t\tcase \"image/png\":\n\t\t\treturn \"png\";\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction selectPreferredImageMimeType(mimeTypes: string[]): string | null {\n\tconst normalized = mimeTypes\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean)\n\t\t.map((t) => ({ raw: t, base: baseMimeType(t) }));\n\n\tfor (const preferred of SUPPORTED_IMAGE_MIME_TYPES) {\n\t\tconst match = normalized.find((t) => t.base === preferred);\n\t\tif (match) {\n\t\t\treturn match.raw;\n\t\t}\n\t}\n\n\tconst anyImage = normalized.find((t) => t.base.startsWith(\"image/\"));\n\treturn anyImage?.raw ?? null;\n}\n\nfunction isSupportedImageMimeType(mimeType: string): boolean {\n\tconst base = baseMimeType(mimeType);\n\treturn SUPPORTED_IMAGE_MIME_TYPES.some((t) => t === base);\n}\n\n/**\n * Convert unsupported image formats to PNG using Photon.\n * Returns null if conversion is unavailable or fails.\n */\nasync function convertToPng(bytes: Uint8Array): Promise<Uint8Array | null> {\n\tconst photon = await loadPhoton();\n\tif (!photon) {\n\t\treturn null;\n\t}\n\n\ttry {\n\t\tconst image = photon.PhotonImage.new_from_byteslice(bytes);\n\t\ttry {\n\t\t\treturn image.get_bytes();\n\t\t} finally {\n\t\t\timage.free();\n\t\t}\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\toptions?: { timeoutMs?: number; maxBufferBytes?: number; env?: NodeJS.ProcessEnv },\n): { stdout: Buffer; ok: boolean } {\n\tconst timeoutMs = options?.timeoutMs ?? DEFAULT_READ_TIMEOUT_MS;\n\tconst maxBufferBytes = options?.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES;\n\n\tconst result = spawnSync(command, args, {\n\t\ttimeout: timeoutMs,\n\t\tmaxBuffer: maxBufferBytes,\n\t\tenv: options?.env,\n\t});\n\n\tif (result.error) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tif (result.status !== 0) {\n\t\treturn { ok: false, stdout: Buffer.alloc(0) };\n\t}\n\n\tconst stdout = Buffer.isBuffer(result.stdout)\n\t\t? result.stdout\n\t\t: Buffer.from(result.stdout ?? \"\", typeof result.stdout === \"string\" ? \"utf-8\" : undefined);\n\n\treturn { ok: true, stdout };\n}\n\nfunction readClipboardImageViaWlPaste(): ClipboardImage | null {\n\tconst list = runCommand(\"wl-paste\", [\"--list-types\"], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\tif (!list.ok) {\n\t\treturn null;\n\t}\n\n\tconst types = list.stdout\n\t\t.toString(\"utf-8\")\n\t\t.split(/\\r?\\n/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\n\tconst selectedType = selectPreferredImageMimeType(types);\n\tif (!selectedType) {\n\t\treturn null;\n\t}\n\n\tconst data = runCommand(\"wl-paste\", [\"--type\", selectedType, \"--no-newline\"]);\n\tif (!data.ok || data.stdout.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn { bytes: data.stdout, mimeType: baseMimeType(selectedType) };\n}\n\nfunction isWSL(env: NodeJS.ProcessEnv = process.env): boolean {\n\tif (env.WSL_DISTRO_NAME || env.WSLENV) {\n\t\treturn true;\n\t}\n\n\ttry {\n\t\tconst release = readFileSync(\"/proc/version\", \"utf-8\");\n\t\treturn /microsoft|wsl/i.test(release);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * On WSL, the Linux clipboard (Wayland/X11) does not receive image data from\n * Windows screenshots (Win+Shift+S). PowerShell can access the Windows clipboard\n * directly, so we use it as a fallback.\n */\nfunction readClipboardImageViaPowerShell(): ClipboardImage | null {\n\tconst tmpFile = join(tmpdir(), `apex-code-wsl-clip-${randomUUID()}.png`);\n\n\ttry {\n\t\tconst winPathResult = runCommand(\"wslpath\", [\"-w\", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });\n\t\tif (!winPathResult.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst winPath = winPathResult.stdout.toString(\"utf-8\").trim();\n\t\tif (!winPath) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst psQuotedWinPath = winPath.replaceAll(\"'\", \"''\");\n\t\tconst psScript = [\n\t\t\t\"Add-Type -AssemblyName System.Windows.Forms\",\n\t\t\t\"Add-Type -AssemblyName System.Drawing\",\n\t\t\t`$path = '${psQuotedWinPath}'`,\n\t\t\t\"$img = [System.Windows.Forms.Clipboard]::GetImage()\",\n\t\t\t\"if ($img) { $img.Save($path, [System.Drawing.Imaging.ImageFormat]::Png); Write-Output 'ok' } else { Write-Output 'empty' }\",\n\t\t].join(\"; \");\n\n\t\tconst result = runCommand(\"powershell.exe\", [\"-NoProfile\", \"-Command\", psScript], {\n\t\t\ttimeoutMs: DEFAULT_POWERSHELL_TIMEOUT_MS,\n\t\t});\n\t\tif (!result.ok) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst output = result.stdout.toString(\"utf-8\").trim();\n\t\tif (output !== \"ok\") {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst bytes = readFileSync(tmpFile);\n\t\tif (bytes.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn { bytes: new Uint8Array(bytes), mimeType: \"image/png\" };\n\t} catch {\n\t\treturn null;\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(tmpFile);\n\t\t} catch {\n\t\t\t// Ignore cleanup errors.\n\t\t}\n\t}\n}\n\nfunction readClipboardImageViaXclip(): ClipboardImage | null {\n\tconst targets = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", \"TARGETS\", \"-o\"], {\n\t\ttimeoutMs: DEFAULT_LIST_TIMEOUT_MS,\n\t});\n\n\tlet candidateTypes: string[] = [];\n\tif (targets.ok) {\n\t\tcandidateTypes = targets.stdout\n\t\t\t.toString(\"utf-8\")\n\t\t\t.split(/\\r?\\n/)\n\t\t\t.map((t) => t.trim())\n\t\t\t.filter(Boolean);\n\t}\n\n\tconst preferred = candidateTypes.length > 0 ? selectPreferredImageMimeType(candidateTypes) : null;\n\tconst tryTypes = preferred ? [preferred, ...SUPPORTED_IMAGE_MIME_TYPES] : [...SUPPORTED_IMAGE_MIME_TYPES];\n\n\tfor (const mimeType of tryTypes) {\n\t\tconst data = runCommand(\"xclip\", [\"-selection\", \"clipboard\", \"-t\", mimeType, \"-o\"]);\n\t\tif (data.ok && data.stdout.length > 0) {\n\t\t\treturn { bytes: data.stdout, mimeType: baseMimeType(mimeType) };\n\t\t}\n\t}\n\n\treturn null;\n}\n\nasync function readClipboardImageViaNativeClipboard(): Promise<ClipboardImage | null> {\n\tif (!clipboard || !clipboard.hasImage()) {\n\t\treturn null;\n\t}\n\n\tconst imageData = await clipboard.getImageBinary();\n\tif (!imageData || imageData.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst bytes = imageData instanceof Uint8Array ? imageData : Uint8Array.from(imageData);\n\treturn { bytes, mimeType: \"image/png\" };\n}\n\nexport async function readClipboardImage(options?: {\n\tenv?: NodeJS.ProcessEnv;\n\tplatform?: NodeJS.Platform;\n}): Promise<ClipboardImage | null> {\n\tconst env = options?.env ?? process.env;\n\tconst platform = options?.platform ?? process.platform;\n\n\tif (env.TERMUX_VERSION) {\n\t\treturn null;\n\t}\n\n\tlet image: ClipboardImage | null = null;\n\n\tif (platform === \"linux\") {\n\t\tconst wsl = isWSL(env);\n\t\tconst wayland = isWaylandSession(env);\n\n\t\tif (wayland || wsl) {\n\t\t\timage = readClipboardImageViaWlPaste() ?? readClipboardImageViaXclip();\n\t\t}\n\n\t\tif (!image && wsl) {\n\t\t\timage = readClipboardImageViaPowerShell();\n\t\t}\n\n\t\tif (!image && !wayland) {\n\t\t\timage = (await readClipboardImageViaNativeClipboard()) ?? readClipboardImageViaXclip();\n\t\t}\n\t} else {\n\t\timage = await readClipboardImageViaNativeClipboard();\n\t}\n\n\tif (!image) {\n\t\treturn null;\n\t}\n\n\t// Convert unsupported formats (e.g., BMP from WSLg) to PNG\n\tif (!isSupportedImageMimeType(image.mimeType)) {\n\t\tconst pngBytes = await convertToPng(image.bytes);\n\t\tif (!pngBytes) {\n\t\t\treturn null;\n\t\t}\n\t\treturn { bytes: pngBytes, mimeType: \"image/png\" };\n\t}\n\n\treturn image;\n}\n"]}
@@ -127,7 +127,7 @@ function isWSL(env = process.env) {
127
127
  * directly, so we use it as a fallback.
128
128
  */
129
129
  function readClipboardImageViaPowerShell() {
130
- const tmpFile = join(tmpdir(), `pi-wsl-clip-${randomUUID()}.png`);
130
+ const tmpFile = join(tmpdir(), `apex-code-wsl-clip-${randomUUID()}.png`);
131
131
  try {
132
132
  const winPathResult = runCommand("wslpath", ["-w", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
133
133
  if (!winPathResult.ok) {