@greppleai/grip 0.1.5 → 0.1.7

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 (587) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -1
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/bun/embedded-assets.d.ts.map +1 -1
  6. package/dist/bun/embedded-assets.js.map +1 -1
  7. package/dist/bun/register-bedrock.d.ts.map +1 -1
  8. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  9. package/dist/bun/restore-sandbox-env.js.map +1 -1
  10. package/dist/cli/args.d.ts.map +1 -1
  11. package/dist/cli/args.js.map +1 -1
  12. package/dist/cli/config-selector.d.ts.map +1 -1
  13. package/dist/cli/config-selector.js.map +1 -1
  14. package/dist/cli/file-processor.d.ts.map +1 -1
  15. package/dist/cli/file-processor.js.map +1 -1
  16. package/dist/cli/initial-message.d.ts +1 -1
  17. package/dist/cli/initial-message.d.ts.map +1 -1
  18. package/dist/cli/initial-message.js.map +1 -1
  19. package/dist/cli/list-models.d.ts.map +1 -1
  20. package/dist/cli/list-models.js.map +1 -1
  21. package/dist/cli/session-picker.d.ts.map +1 -1
  22. package/dist/cli/session-picker.js.map +1 -1
  23. package/dist/cli.d.ts.map +1 -1
  24. package/dist/cli.js.map +1 -1
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js +2 -0
  27. package/dist/config.js.map +1 -1
  28. package/dist/core/agent-session.d.ts +38 -1
  29. package/dist/core/agent-session.d.ts.map +1 -1
  30. package/dist/core/agent-session.js +289 -154
  31. package/dist/core/agent-session.js.map +1 -1
  32. package/dist/core/auth-guidance.d.ts.map +1 -1
  33. package/dist/core/auth-guidance.js.map +1 -1
  34. package/dist/core/auth-storage.d.ts +4 -0
  35. package/dist/core/auth-storage.d.ts.map +1 -1
  36. package/dist/core/auth-storage.js +3 -10
  37. package/dist/core/auth-storage.js.map +1 -1
  38. package/dist/core/bash-executor.d.ts.map +1 -1
  39. package/dist/core/bash-executor.js +19 -23
  40. package/dist/core/bash-executor.js.map +1 -1
  41. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  42. package/dist/core/compaction/branch-summarization.js.map +1 -1
  43. package/dist/core/compaction/compaction.d.ts.map +1 -1
  44. package/dist/core/compaction/compaction.js +9 -2
  45. package/dist/core/compaction/compaction.js.map +1 -1
  46. package/dist/core/compaction/compression-detection-ledger.d.ts.map +1 -1
  47. package/dist/core/compaction/compression-detection-ledger.js.map +1 -1
  48. package/dist/core/compaction/compression-detector.d.ts +1 -0
  49. package/dist/core/compaction/compression-detector.d.ts.map +1 -1
  50. package/dist/core/compaction/compression-detector.js +10 -21
  51. package/dist/core/compaction/compression-detector.js.map +1 -1
  52. package/dist/core/compaction/compression-economics.d.ts.map +1 -1
  53. package/dist/core/compaction/compression-economics.js.map +1 -1
  54. package/dist/core/compaction/utils.d.ts.map +1 -1
  55. package/dist/core/compaction/utils.js.map +1 -1
  56. package/dist/core/defaults.d.ts.map +1 -1
  57. package/dist/core/diagnostics.d.ts.map +1 -1
  58. package/dist/core/event-bus.d.ts.map +1 -1
  59. package/dist/core/event-bus.js.map +1 -1
  60. package/dist/core/exec.d.ts.map +1 -1
  61. package/dist/core/exec.js.map +1 -1
  62. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  63. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  64. package/dist/core/export-html/index.d.ts.map +1 -1
  65. package/dist/core/export-html/index.js.map +1 -1
  66. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  67. package/dist/core/export-html/tool-renderer.js.map +1 -1
  68. package/dist/core/extensions/loader.d.ts.map +1 -1
  69. package/dist/core/extensions/loader.js.map +1 -1
  70. package/dist/core/extensions/runner.d.ts +3 -0
  71. package/dist/core/extensions/runner.d.ts.map +1 -1
  72. package/dist/core/extensions/runner.js +40 -30
  73. package/dist/core/extensions/runner.js.map +1 -1
  74. package/dist/core/extensions/types.d.ts +21 -1
  75. package/dist/core/extensions/types.d.ts.map +1 -1
  76. package/dist/core/extensions/types.js.map +1 -1
  77. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  78. package/dist/core/extensions/wrapper.js.map +1 -1
  79. package/dist/core/footer-data-provider.d.ts.map +1 -1
  80. package/dist/core/footer-data-provider.js +15 -16
  81. package/dist/core/footer-data-provider.js.map +1 -1
  82. package/dist/core/grip-agent.d.ts.map +1 -1
  83. package/dist/core/grip-agent.js +7 -21
  84. package/dist/core/grip-agent.js.map +1 -1
  85. package/dist/core/grip-manifest.d.ts.map +1 -1
  86. package/dist/core/grip-manifest.js.map +1 -1
  87. package/dist/core/hooks/aggregate.d.ts.map +1 -1
  88. package/dist/core/hooks/aggregate.js.map +1 -1
  89. package/dist/core/hooks/config.d.ts.map +1 -1
  90. package/dist/core/hooks/config.js.map +1 -1
  91. package/dist/core/hooks/executor.d.ts.map +1 -1
  92. package/dist/core/hooks/executor.js.map +1 -1
  93. package/dist/core/hooks/index.d.ts.map +1 -1
  94. package/dist/core/hooks/index.js.map +1 -1
  95. package/dist/core/hooks/matcher.d.ts.map +1 -1
  96. package/dist/core/hooks/matcher.js.map +1 -1
  97. package/dist/core/hooks/trust-store.d.ts.map +1 -1
  98. package/dist/core/hooks/trust-store.js +0 -3
  99. package/dist/core/hooks/trust-store.js.map +1 -1
  100. package/dist/core/hooks/types.d.ts.map +1 -1
  101. package/dist/core/hooks/types.js.map +1 -1
  102. package/dist/core/http-dispatcher.d.ts.map +1 -1
  103. package/dist/core/http-dispatcher.js.map +1 -1
  104. package/dist/core/instruction-resource-loader.d.ts +1 -0
  105. package/dist/core/instruction-resource-loader.d.ts.map +1 -1
  106. package/dist/core/instruction-resource-loader.js +2 -4
  107. package/dist/core/instruction-resource-loader.js.map +1 -1
  108. package/dist/core/keybindings.d.ts.map +1 -1
  109. package/dist/core/keybindings.js +0 -1
  110. package/dist/core/keybindings.js.map +1 -1
  111. package/dist/core/lsp/abort.d.ts.map +1 -1
  112. package/dist/core/lsp/abort.js.map +1 -1
  113. package/dist/core/lsp/client.d.ts.map +1 -1
  114. package/dist/core/lsp/client.js +8 -22
  115. package/dist/core/lsp/client.js.map +1 -1
  116. package/dist/core/lsp/config-loader.d.ts.map +1 -1
  117. package/dist/core/lsp/config-loader.js.map +1 -1
  118. package/dist/core/lsp/config.d.ts.map +1 -1
  119. package/dist/core/lsp/config.js.map +1 -1
  120. package/dist/core/lsp/diagnostics.d.ts.map +1 -1
  121. package/dist/core/lsp/diagnostics.js.map +1 -1
  122. package/dist/core/lsp/file-sync.d.ts.map +1 -1
  123. package/dist/core/lsp/file-sync.js +7 -9
  124. package/dist/core/lsp/file-sync.js.map +1 -1
  125. package/dist/core/lsp/integration.d.ts.map +1 -1
  126. package/dist/core/lsp/integration.js.map +1 -1
  127. package/dist/core/lsp/language-map.d.ts.map +1 -1
  128. package/dist/core/lsp/language-map.js +2 -7
  129. package/dist/core/lsp/language-map.js.map +1 -1
  130. package/dist/core/lsp/manager.d.ts.map +1 -1
  131. package/dist/core/lsp/manager.js +18 -29
  132. package/dist/core/lsp/manager.js.map +1 -1
  133. package/dist/core/lsp/navigation.d.ts.map +1 -1
  134. package/dist/core/lsp/navigation.js.map +1 -1
  135. package/dist/core/lsp/portable-path.d.ts.map +1 -1
  136. package/dist/core/lsp/portable-path.js.map +1 -1
  137. package/dist/core/lsp/refactor.d.ts.map +1 -1
  138. package/dist/core/lsp/refactor.js.map +1 -1
  139. package/dist/core/lsp/transport.d.ts.map +1 -1
  140. package/dist/core/lsp/transport.js.map +1 -1
  141. package/dist/core/messages.d.ts.map +1 -1
  142. package/dist/core/messages.js +30 -1
  143. package/dist/core/messages.js.map +1 -1
  144. package/dist/core/model-registry.d.ts.map +1 -1
  145. package/dist/core/model-registry.js +5 -7
  146. package/dist/core/model-registry.js.map +1 -1
  147. package/dist/core/model-resolver.d.ts.map +1 -1
  148. package/dist/core/model-resolver.js.map +1 -1
  149. package/dist/core/output-guard.d.ts.map +1 -1
  150. package/dist/core/output-guard.js.map +1 -1
  151. package/dist/core/package-manager.d.ts.map +1 -1
  152. package/dist/core/package-manager.js +0 -6
  153. package/dist/core/package-manager.js.map +1 -1
  154. package/dist/core/prompt-templates.d.ts.map +1 -1
  155. package/dist/core/prompt-templates.js.map +1 -1
  156. package/dist/core/provider-display-names.d.ts.map +1 -1
  157. package/dist/core/remote-workspace-protocol/contract.d.ts.map +1 -1
  158. package/dist/core/remote-workspace-protocol/contract.js +4 -2
  159. package/dist/core/remote-workspace-protocol/contract.js.map +1 -1
  160. package/dist/core/remote-workspace-protocol/guest-shared-client.d.ts.map +1 -1
  161. package/dist/core/remote-workspace-protocol/guest-shared-client.js +1 -5
  162. package/dist/core/remote-workspace-protocol/guest-shared-client.js.map +1 -1
  163. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.d.ts.map +1 -1
  164. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js +5 -10
  165. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js.map +1 -1
  166. package/dist/core/remote-workspace-protocol/guest-shared-uplink.d.ts.map +1 -1
  167. package/dist/core/remote-workspace-protocol/guest-shared-uplink.js +2 -9
  168. package/dist/core/remote-workspace-protocol/guest-shared-uplink.js.map +1 -1
  169. package/dist/core/remote-workspace-protocol/lima-owner-directory.d.ts.map +1 -1
  170. package/dist/core/remote-workspace-protocol/lima-owner-directory.js.map +1 -1
  171. package/dist/core/remote-workspace-protocol/lima-owner-lock.d.ts.map +1 -1
  172. package/dist/core/remote-workspace-protocol/lima-owner-lock.js.map +1 -1
  173. package/dist/core/remote-workspace-protocol/session.d.ts.map +1 -1
  174. package/dist/core/remote-workspace-protocol/session.js +27 -65
  175. package/dist/core/remote-workspace-protocol/session.js.map +1 -1
  176. package/dist/core/remote-workspace-protocol/shared-transport.d.ts.map +1 -1
  177. package/dist/core/remote-workspace-protocol/shared-transport.js.map +1 -1
  178. package/dist/core/resolve-config-value.d.ts.map +1 -1
  179. package/dist/core/resolve-config-value.js.map +1 -1
  180. package/dist/core/resource-loader.d.ts.map +1 -1
  181. package/dist/core/resource-loader.js +0 -48
  182. package/dist/core/resource-loader.js.map +1 -1
  183. package/dist/core/rules.d.ts.map +1 -1
  184. package/dist/core/rules.js.map +1 -1
  185. package/dist/core/sandbox/command.d.ts.map +1 -1
  186. package/dist/core/sandbox/command.js.map +1 -1
  187. package/dist/core/sandbox/config.d.ts.map +1 -1
  188. package/dist/core/sandbox/config.js.map +1 -1
  189. package/dist/core/sandbox/lima-guest-binary.d.ts.map +1 -1
  190. package/dist/core/sandbox/lima-guest-binary.js.map +1 -1
  191. package/dist/core/sandbox/lima.d.ts +2 -0
  192. package/dist/core/sandbox/lima.d.ts.map +1 -1
  193. package/dist/core/sandbox/lima.js +3 -9
  194. package/dist/core/sandbox/lima.js.map +1 -1
  195. package/dist/core/sandbox/shared-lima-roots.d.ts.map +1 -1
  196. package/dist/core/sandbox/shared-lima-roots.js.map +1 -1
  197. package/dist/core/sandbox/update-shared-guest-binary.d.ts.map +1 -1
  198. package/dist/core/sandbox/update-shared-guest-binary.js.map +1 -1
  199. package/dist/core/session/constants.d.ts.map +1 -1
  200. package/dist/core/session/context-metadata.d.ts.map +1 -1
  201. package/dist/core/session/context-metadata.js.map +1 -1
  202. package/dist/core/session/context.d.ts.map +1 -1
  203. package/dist/core/session/context.js.map +1 -1
  204. package/dist/core/session/ids.d.ts.map +1 -1
  205. package/dist/core/session/ids.js.map +1 -1
  206. package/dist/core/session/in-memory-session-manager.d.ts.map +1 -1
  207. package/dist/core/session/in-memory-session-manager.js +0 -1
  208. package/dist/core/session/in-memory-session-manager.js.map +1 -1
  209. package/dist/core/session/in-memory-session.d.ts.map +1 -1
  210. package/dist/core/session/in-memory-session.js.map +1 -1
  211. package/dist/core/session/jsonl-errors.d.ts.map +1 -1
  212. package/dist/core/session/jsonl-errors.js +0 -11
  213. package/dist/core/session/jsonl-errors.js.map +1 -1
  214. package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
  215. package/dist/core/session/jsonl-helpers.js.map +1 -1
  216. package/dist/core/session/local-session-manager.d.ts.map +1 -1
  217. package/dist/core/session/local-session-manager.js +4 -6
  218. package/dist/core/session/local-session-manager.js.map +1 -1
  219. package/dist/core/session/local-session.d.ts.map +1 -1
  220. package/dist/core/session/local-session.js.map +1 -1
  221. package/dist/core/session/migrations.d.ts.map +1 -1
  222. package/dist/core/session/migrations.js.map +1 -1
  223. package/dist/core/session/remote-session-client.d.ts.map +1 -1
  224. package/dist/core/session/remote-session-client.js +0 -6
  225. package/dist/core/session/remote-session-client.js.map +1 -1
  226. package/dist/core/session/remote-session-manager.d.ts.map +1 -1
  227. package/dist/core/session/remote-session-manager.js +0 -3
  228. package/dist/core/session/remote-session-manager.js.map +1 -1
  229. package/dist/core/session/remote-session.d.ts.map +1 -1
  230. package/dist/core/session/remote-session.js +0 -1
  231. package/dist/core/session/remote-session.js.map +1 -1
  232. package/dist/core/session/session-manager.d.ts.map +1 -1
  233. package/dist/core/session/session.d.ts.map +1 -1
  234. package/dist/core/session/session.js +1 -5
  235. package/dist/core/session/session.js.map +1 -1
  236. package/dist/core/session/stores/in-memory-session-store.d.ts.map +1 -1
  237. package/dist/core/session/stores/in-memory-session-store.js +7 -6
  238. package/dist/core/session/stores/in-memory-session-store.js.map +1 -1
  239. package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
  240. package/dist/core/session/stores/jsonl-session-store.js +6 -14
  241. package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
  242. package/dist/core/session/stores/remote-session-store.d.ts.map +1 -1
  243. package/dist/core/session/stores/remote-session-store.js +3 -8
  244. package/dist/core/session/stores/remote-session-store.js.map +1 -1
  245. package/dist/core/session/stores/session-store.d.ts.map +1 -1
  246. package/dist/core/session/types.d.ts.map +1 -1
  247. package/dist/core/session/usage-ledger.d.ts.map +1 -1
  248. package/dist/core/session/usage-ledger.js.map +1 -1
  249. package/dist/core/session-cwd.d.ts.map +1 -1
  250. package/dist/core/session-cwd.js +0 -1
  251. package/dist/core/session-cwd.js.map +1 -1
  252. package/dist/core/settings-manager.d.ts.map +1 -1
  253. package/dist/core/settings-manager.js +9 -17
  254. package/dist/core/settings-manager.js.map +1 -1
  255. package/dist/core/skills.d.ts.map +1 -1
  256. package/dist/core/skills.js +3 -2
  257. package/dist/core/skills.js.map +1 -1
  258. package/dist/core/slash-commands.d.ts.map +1 -1
  259. package/dist/core/source-info.d.ts.map +1 -1
  260. package/dist/core/source-info.js.map +1 -1
  261. package/dist/core/system-prompt.d.ts +1 -1
  262. package/dist/core/system-prompt.d.ts.map +1 -1
  263. package/dist/core/system-prompt.js +3 -2
  264. package/dist/core/system-prompt.js.map +1 -1
  265. package/dist/core/telemetry.d.ts.map +1 -1
  266. package/dist/core/telemetry.js.map +1 -1
  267. package/dist/core/timings.d.ts.map +1 -1
  268. package/dist/core/timings.js.map +1 -1
  269. package/dist/core/tools/bash.d.ts +1 -0
  270. package/dist/core/tools/bash.d.ts.map +1 -1
  271. package/dist/core/tools/bash.js +34 -28
  272. package/dist/core/tools/bash.js.map +1 -1
  273. package/dist/core/tools/compress-context.d.ts.map +1 -1
  274. package/dist/core/tools/compress-context.js.map +1 -1
  275. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  276. package/dist/core/tools/edit-diff.js.map +1 -1
  277. package/dist/core/tools/edit.d.ts.map +1 -1
  278. package/dist/core/tools/edit.js.map +1 -1
  279. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  280. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  281. package/dist/core/tools/find.d.ts.map +1 -1
  282. package/dist/core/tools/find.js.map +1 -1
  283. package/dist/core/tools/grep.d.ts.map +1 -1
  284. package/dist/core/tools/grep.js.map +1 -1
  285. package/dist/core/tools/hash-store.d.ts.map +1 -1
  286. package/dist/core/tools/hash-store.js.map +1 -1
  287. package/dist/core/tools/hashline/apply.d.ts.map +1 -1
  288. package/dist/core/tools/hashline/apply.js.map +1 -1
  289. package/dist/core/tools/hashline/hash.d.ts.map +1 -1
  290. package/dist/core/tools/hashline/hash.js.map +1 -1
  291. package/dist/core/tools/hashline/parse.d.ts.map +1 -1
  292. package/dist/core/tools/hashline/parse.js.map +1 -1
  293. package/dist/core/tools/hashline/resolve.d.ts.map +1 -1
  294. package/dist/core/tools/hashline/resolve.js.map +1 -1
  295. package/dist/core/tools/hashline-utils.d.ts.map +1 -1
  296. package/dist/core/tools/hashline-utils.js.map +1 -1
  297. package/dist/core/tools/index.d.ts.map +1 -1
  298. package/dist/core/tools/index.js.map +1 -1
  299. package/dist/core/tools/ls.d.ts.map +1 -1
  300. package/dist/core/tools/ls.js.map +1 -1
  301. package/dist/core/tools/operations.d.ts +11 -0
  302. package/dist/core/tools/operations.d.ts.map +1 -1
  303. package/dist/core/tools/operations.js +54 -28
  304. package/dist/core/tools/operations.js.map +1 -1
  305. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  306. package/dist/core/tools/output-accumulator.js +12 -18
  307. package/dist/core/tools/output-accumulator.js.map +1 -1
  308. package/dist/core/tools/path-utils.d.ts.map +1 -1
  309. package/dist/core/tools/path-utils.js.map +1 -1
  310. package/dist/core/tools/read.d.ts.map +1 -1
  311. package/dist/core/tools/read.js.map +1 -1
  312. package/dist/core/tools/render-utils.d.ts.map +1 -1
  313. package/dist/core/tools/render-utils.js.map +1 -1
  314. package/dist/core/tools/replace-diff.d.ts.map +1 -1
  315. package/dist/core/tools/replace-diff.js.map +1 -1
  316. package/dist/core/tools/replace-normalize.d.ts.map +1 -1
  317. package/dist/core/tools/replace-normalize.js.map +1 -1
  318. package/dist/core/tools/replace-render.d.ts +1 -1
  319. package/dist/core/tools/replace-render.d.ts.map +1 -1
  320. package/dist/core/tools/replace-render.js.map +1 -1
  321. package/dist/core/tools/runtime.d.ts.map +1 -1
  322. package/dist/core/tools/runtime.js.map +1 -1
  323. package/dist/core/tools/session-history.d.ts.map +1 -1
  324. package/dist/core/tools/session-history.js.map +1 -1
  325. package/dist/core/tools/subagent-agents.d.ts.map +1 -1
  326. package/dist/core/tools/subagent-agents.js.map +1 -1
  327. package/dist/core/tools/subagent.d.ts.map +1 -1
  328. package/dist/core/tools/subagent.js.map +1 -1
  329. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  330. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  331. package/dist/core/tools/truncate.d.ts.map +1 -1
  332. package/dist/core/tools/truncate.js.map +1 -1
  333. package/dist/core/tools/websearch.d.ts.map +1 -1
  334. package/dist/core/tools/websearch.js.map +1 -1
  335. package/dist/core/tools/workspace-tool-host.d.ts +1 -0
  336. package/dist/core/tools/workspace-tool-host.d.ts.map +1 -1
  337. package/dist/core/tools/workspace-tool-host.js +36 -22
  338. package/dist/core/tools/workspace-tool-host.js.map +1 -1
  339. package/dist/core/tools/write.d.ts.map +1 -1
  340. package/dist/core/tools/write.js +0 -1
  341. package/dist/core/tools/write.js.map +1 -1
  342. package/dist/core/workspace-identity.d.ts.map +1 -1
  343. package/dist/daemon/activity-budget.d.ts.map +1 -1
  344. package/dist/daemon/activity-budget.js +2 -3
  345. package/dist/daemon/activity-budget.js.map +1 -1
  346. package/dist/daemon/command.d.ts.map +1 -1
  347. package/dist/daemon/command.js.map +1 -1
  348. package/dist/daemon/config.d.ts +2 -0
  349. package/dist/daemon/config.d.ts.map +1 -1
  350. package/dist/daemon/config.js +4 -0
  351. package/dist/daemon/config.js.map +1 -1
  352. package/dist/daemon/help.d.ts.map +1 -1
  353. package/dist/daemon/help.js +4 -3
  354. package/dist/daemon/help.js.map +1 -1
  355. package/dist/daemon/lsp-config.d.ts.map +1 -1
  356. package/dist/daemon/lsp-config.js.map +1 -1
  357. package/dist/daemon/outbound-budget.d.ts.map +1 -1
  358. package/dist/daemon/outbound-budget.js +2 -4
  359. package/dist/daemon/outbound-budget.js.map +1 -1
  360. package/dist/daemon/security.d.ts.map +1 -1
  361. package/dist/daemon/security.js.map +1 -1
  362. package/dist/daemon/server.d.ts.map +1 -1
  363. package/dist/daemon/server.js.map +1 -1
  364. package/dist/daemon/shared-connection.d.ts.map +1 -1
  365. package/dist/daemon/shared-connection.js +10 -15
  366. package/dist/daemon/shared-connection.js.map +1 -1
  367. package/dist/daemon/shared-revision.d.ts.map +1 -1
  368. package/dist/daemon/shared-revision.js +2 -1
  369. package/dist/daemon/shared-revision.js.map +1 -1
  370. package/dist/daemon/shared-roots.d.ts.map +1 -1
  371. package/dist/daemon/shared-roots.js +0 -1
  372. package/dist/daemon/shared-roots.js.map +1 -1
  373. package/dist/daemon/workspace-runtime.d.ts +2 -0
  374. package/dist/daemon/workspace-runtime.d.ts.map +1 -1
  375. package/dist/daemon/workspace-runtime.js +43 -15
  376. package/dist/daemon/workspace-runtime.js.map +1 -1
  377. package/dist/index.d.ts +1 -1
  378. package/dist/index.d.ts.map +1 -1
  379. package/dist/index.js.map +1 -1
  380. package/dist/main.d.ts.map +1 -1
  381. package/dist/main.js +8 -3
  382. package/dist/main.js.map +1 -1
  383. package/dist/migrations.d.ts.map +1 -1
  384. package/dist/migrations.js.map +1 -1
  385. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  386. package/dist/modes/interactive/components/assistant-message.js +3 -10
  387. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  388. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  389. package/dist/modes/interactive/components/bash-execution.js +4 -9
  390. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  391. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  392. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  393. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  394. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  395. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  396. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  397. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  398. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  399. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  400. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  401. package/dist/modes/interactive/components/config-selector.js +6 -16
  402. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  403. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  404. package/dist/modes/interactive/components/countdown-timer.js +0 -5
  405. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  406. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  407. package/dist/modes/interactive/components/custom-editor.js +1 -8
  408. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  409. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  410. package/dist/modes/interactive/components/custom-message.js +1 -6
  411. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  412. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  413. package/dist/modes/interactive/components/diff.js.map +1 -1
  414. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  415. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  416. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  417. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/extension-editor.js +1 -7
  419. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  420. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  421. package/dist/modes/interactive/components/extension-input.js +2 -8
  422. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  423. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  424. package/dist/modes/interactive/components/extension-selector.js +1 -9
  425. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  426. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/footer.js +8 -4
  428. package/dist/modes/interactive/components/footer.js.map +1 -1
  429. package/dist/modes/interactive/components/hook-execution.d.ts.map +1 -1
  430. package/dist/modes/interactive/components/hook-execution.js +2 -5
  431. package/dist/modes/interactive/components/hook-execution.js.map +1 -1
  432. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  434. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  435. package/dist/modes/interactive/components/login-dialog.js +3 -9
  436. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  437. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
  438. package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
  439. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  440. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  441. package/dist/modes/interactive/components/message-card.d.ts.map +1 -1
  442. package/dist/modes/interactive/components/message-card.js +0 -1
  443. package/dist/modes/interactive/components/message-card.js.map +1 -1
  444. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  445. package/dist/modes/interactive/components/model-selector.js +13 -28
  446. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  447. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  448. package/dist/modes/interactive/components/oauth-selector.js +3 -12
  449. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  450. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  451. package/dist/modes/interactive/components/scoped-models-selector.js +9 -13
  452. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  453. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  454. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  455. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  456. package/dist/modes/interactive/components/session-selector.js +33 -58
  457. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  458. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  459. package/dist/modes/interactive/components/settings-selector.js +0 -4
  460. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  461. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  463. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  464. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  465. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  466. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  467. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/theme-selector.js +0 -2
  469. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  470. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  472. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  473. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  474. package/dist/modes/interactive/components/tool-execution.js +9 -24
  475. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  476. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  477. package/dist/modes/interactive/components/tree-selector.js +18 -34
  478. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  479. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  480. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  481. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  482. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  483. package/dist/modes/interactive/components/user-message.js +0 -4
  484. package/dist/modes/interactive/components/user-message.js.map +1 -1
  485. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  486. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  487. package/dist/modes/interactive/interactive-mode.d.ts +13 -0
  488. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  489. package/dist/modes/interactive/interactive-mode.js +162 -136
  490. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  491. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  492. package/dist/modes/interactive/theme/theme.js +0 -7
  493. package/dist/modes/interactive/theme/theme.js.map +1 -1
  494. package/dist/modes/json-event.d.ts.map +1 -1
  495. package/dist/modes/json-event.js.map +1 -1
  496. package/dist/modes/print-mode.d.ts.map +1 -1
  497. package/dist/modes/print-mode.js.map +1 -1
  498. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  499. package/dist/modes/rpc/jsonl.js.map +1 -1
  500. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  501. package/dist/modes/rpc/rpc-client.js +10 -11
  502. package/dist/modes/rpc/rpc-client.js.map +1 -1
  503. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  504. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  505. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  506. package/dist/package-manager-cli.d.ts.map +1 -1
  507. package/dist/package-manager-cli.js +33 -2
  508. package/dist/package-manager-cli.js.map +1 -1
  509. package/dist/utils/ansi.d.ts.map +1 -1
  510. package/dist/utils/ansi.js.map +1 -1
  511. package/dist/utils/binary-self-update.d.ts +25 -0
  512. package/dist/utils/binary-self-update.d.ts.map +1 -0
  513. package/dist/utils/binary-self-update.js +159 -0
  514. package/dist/utils/binary-self-update.js.map +1 -0
  515. package/dist/utils/changelog.d.ts.map +1 -1
  516. package/dist/utils/changelog.js.map +1 -1
  517. package/dist/utils/child-process.d.ts.map +1 -1
  518. package/dist/utils/child-process.js.map +1 -1
  519. package/dist/utils/clipboard-image.d.ts.map +1 -1
  520. package/dist/utils/clipboard-image.js.map +1 -1
  521. package/dist/utils/clipboard-native.d.ts.map +1 -1
  522. package/dist/utils/clipboard-native.js.map +1 -1
  523. package/dist/utils/clipboard.d.ts.map +1 -1
  524. package/dist/utils/clipboard.js.map +1 -1
  525. package/dist/utils/deprecation.d.ts.map +1 -1
  526. package/dist/utils/deprecation.js.map +1 -1
  527. package/dist/utils/directory-completions.d.ts +8 -0
  528. package/dist/utils/directory-completions.d.ts.map +1 -1
  529. package/dist/utils/directory-completions.js +42 -1
  530. package/dist/utils/directory-completions.js.map +1 -1
  531. package/dist/utils/exif-orientation.d.ts.map +1 -1
  532. package/dist/utils/exif-orientation.js.map +1 -1
  533. package/dist/utils/frontmatter.d.ts.map +1 -1
  534. package/dist/utils/frontmatter.js.map +1 -1
  535. package/dist/utils/fs-watch.d.ts.map +1 -1
  536. package/dist/utils/fs-watch.js.map +1 -1
  537. package/dist/utils/git.d.ts.map +1 -1
  538. package/dist/utils/git.js.map +1 -1
  539. package/dist/utils/grip-user-agent.d.ts.map +1 -1
  540. package/dist/utils/grip-user-agent.js.map +1 -1
  541. package/dist/utils/html.d.ts.map +1 -1
  542. package/dist/utils/html.js.map +1 -1
  543. package/dist/utils/image-convert.d.ts.map +1 -1
  544. package/dist/utils/image-convert.js.map +1 -1
  545. package/dist/utils/image-process.d.ts.map +1 -1
  546. package/dist/utils/image-process.js.map +1 -1
  547. package/dist/utils/image-resize-core.d.ts.map +1 -1
  548. package/dist/utils/image-resize-core.js.map +1 -1
  549. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  550. package/dist/utils/image-resize-worker.js.map +1 -1
  551. package/dist/utils/image-resize.d.ts.map +1 -1
  552. package/dist/utils/image-resize.js.map +1 -1
  553. package/dist/utils/json.d.ts.map +1 -1
  554. package/dist/utils/json.js.map +1 -1
  555. package/dist/utils/mime.d.ts.map +1 -1
  556. package/dist/utils/mime.js.map +1 -1
  557. package/dist/utils/open-browser.d.ts.map +1 -1
  558. package/dist/utils/open-browser.js.map +1 -1
  559. package/dist/utils/paths.d.ts.map +1 -1
  560. package/dist/utils/paths.js.map +1 -1
  561. package/dist/utils/photon.d.ts.map +1 -1
  562. package/dist/utils/photon.js +10 -5
  563. package/dist/utils/photon.js.map +1 -1
  564. package/dist/utils/shell.d.ts.map +1 -1
  565. package/dist/utils/shell.js.map +1 -1
  566. package/dist/utils/sleep.d.ts.map +1 -1
  567. package/dist/utils/sleep.js.map +1 -1
  568. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  569. package/dist/utils/syntax-highlight.js +1 -1
  570. package/dist/utils/syntax-highlight.js.map +1 -1
  571. package/dist/utils/tools-manager.d.ts.map +1 -1
  572. package/dist/utils/tools-manager.js.map +1 -1
  573. package/dist/utils/version-check.d.ts.map +1 -1
  574. package/dist/utils/version-check.js.map +1 -1
  575. package/dist/utils/windows-self-update.d.ts.map +1 -1
  576. package/dist/utils/windows-self-update.js.map +1 -1
  577. package/docs/extensions.md +31 -1
  578. package/docs/sandbox.md +6 -0
  579. package/docs/sessions.md +1 -1
  580. package/docs/skills.md +4 -4
  581. package/docs/usage.md +2 -1
  582. package/examples/extensions/custom-provider-anthropic/package.json +2 -2
  583. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  584. package/examples/extensions/sandbox/package.json +2 -2
  585. package/examples/extensions/with-deps/package.json +1 -1
  586. package/npm-shrinkwrap.json +602 -834
  587. package/package.json +20 -21
@@ -1 +1 @@
1
- {"version":3,"file":"photon.js","sourceRoot":"","sources":["../../src/utils/photon.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Photon image processing wrapper.\n *\n * This module provides a unified interface to @silvia-odwyer/photon-node that works in:\n * 1. Node.js (development, npm run build)\n * 2. Bun compiled binaries (standalone distribution)\n *\n * The challenge: photon-node's CJS entry uses fs.readFileSync(__dirname + '/photon_rs_bg.wasm')\n * which bakes the build machine's absolute path into Bun compiled binaries.\n *\n * Solution:\n * 1. Patch fs.readFileSync to redirect missing photon_rs_bg.wasm reads\n * 2. Copy photon_rs_bg.wasm next to the executable in build:binary\n */\n\nimport type * as PhotonNode from \"@silvia-odwyer/photon-node\";\nimport type * as NodeFs from \"fs\";\nimport { createRequire } from \"module\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\n\nconst require = createRequire(import.meta.url);\nconst fs = require(\"fs\") as typeof NodeFs;\n\n// Re-export types from the main package\nexport type { PhotonImage as PhotonImageType } from \"@silvia-odwyer/photon-node\";\n\ninterface PatchedReadFileSyncObjectOptions extends NodeFs.ObjectEncodingOptions {\n\tflag?: string;\n}\n\ntype PatchedReadFileSyncOptions = PatchedReadFileSyncObjectOptions | BufferEncoding | null;\ntype ReadFileSync = typeof NodeFs.readFileSync;\ntype PatchedReadFileSyncResult = string | Buffer<ArrayBuffer>;\n\nconst WASM_FILENAME = \"photon_rs_bg.wasm\";\n\n// Lazy-loaded photon module\nlet photonModule: typeof PhotonNode | null = null;\nlet loadPromise: Promise<typeof PhotonNode | null> | null = null;\n\nfunction pathOrNull(file: NodeFs.PathOrFileDescriptor): string | null {\n\tif (typeof file === \"string\") {\n\t\treturn file;\n\t}\n\tif (file instanceof URL) {\n\t\treturn fileURLToPath(file);\n\t}\n\treturn null;\n}\n\nfunction getFallbackWasmPaths(): string[] {\n\tconst execDir = path.dirname(process.execPath);\n\treturn [\n\t\t...(process.env.GRIP_EMBEDDED_ASSET_DIR ? [path.join(process.env.GRIP_EMBEDDED_ASSET_DIR, WASM_FILENAME)] : []),\n\t\tpath.join(execDir, WASM_FILENAME),\n\t\tpath.join(execDir, \"photon\", WASM_FILENAME),\n\t\tpath.join(process.cwd(), WASM_FILENAME),\n\t];\n}\ninterface PhotonWasmReadContext {\n\treadFileSync: ReadFileSync;\n\tfallbackPaths: string[];\n}\n\nfunction readFallbackWasm(\n\tcontext: PhotonWasmReadContext,\n\toptions: PatchedReadFileSyncOptions | undefined,\n\toriginalError: unknown,\n): PatchedReadFileSyncResult {\n\tfor (const fallbackPath of context.fallbackPaths) {\n\t\tif (!fs.existsSync(fallbackPath)) continue;\n\t\tif (options === undefined) return context.readFileSync(fallbackPath);\n\t\treturn context.readFileSync(fallbackPath, options);\n\t}\n\tthrow originalError;\n}\n\nfunction readPhotonWasm(\n\tcontext: PhotonWasmReadContext,\n\tfile: NodeFs.PathOrFileDescriptor,\n\toptions: PatchedReadFileSyncOptions | undefined,\n): PatchedReadFileSyncResult {\n\ttry {\n\t\treturn context.readFileSync(file, options);\n\t} catch (error) {\n\t\tconst err = error as NodeJS.ErrnoException;\n\t\tif (err?.code && err.code !== \"ENOENT\") throw error;\n\t\treturn readFallbackWasm(context, options, error);\n\t}\n}\n\nfunction patchPhotonWasmRead(): () => void {\n\tconst originalReadFileSync: ReadFileSync = fs.readFileSync.bind(fs);\n\tconst context: PhotonWasmReadContext = {\n\t\treadFileSync: originalReadFileSync,\n\t\tfallbackPaths: getFallbackWasmPaths(),\n\t};\n\tconst mutableFs = fs as { readFileSync: ReadFileSync };\n\n\tconst patchedReadFileSync: ReadFileSync = ((\n\t\tfile: NodeFs.PathOrFileDescriptor,\n\t\toptions?: PatchedReadFileSyncOptions,\n\t) => {\n\t\tconst resolvedPath = pathOrNull(file);\n\t\tif (!resolvedPath?.endsWith(WASM_FILENAME)) return originalReadFileSync(file, options);\n\t\treturn readPhotonWasm(context, file, options);\n\t}) as ReadFileSync;\n\n\ttry {\n\t\tmutableFs.readFileSync = patchedReadFileSync;\n\t} catch {\n\t\tObject.defineProperty(fs, \"readFileSync\", {\n\t\t\tvalue: patchedReadFileSync,\n\t\t\twritable: true,\n\t\t\tconfigurable: true,\n\t\t});\n\t}\n\n\treturn () => {\n\t\ttry {\n\t\t\tmutableFs.readFileSync = originalReadFileSync;\n\t\t} catch {\n\t\t\tObject.defineProperty(fs, \"readFileSync\", {\n\t\t\t\tvalue: originalReadFileSync,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t}\n\t};\n}\n\n/**\n * Load the photon module asynchronously.\n * Returns cached module on subsequent calls.\n */\nexport async function loadPhoton(): Promise<typeof PhotonNode | null> {\n\tif (photonModule) {\n\t\treturn photonModule;\n\t}\n\n\tif (loadPromise) {\n\t\treturn loadPromise;\n\t}\n\n\tloadPromise = (async () => {\n\t\tconst restoreReadFileSync = patchPhotonWasmRead();\n\t\ttry {\n\t\t\tphotonModule = await import(\"@silvia-odwyer/photon-node\");\n\t\t\treturn photonModule;\n\t\t} catch {\n\t\t\tphotonModule = null;\n\t\t\treturn photonModule;\n\t\t} finally {\n\t\t\trestoreReadFileSync();\n\t\t}\n\t})();\n\n\treturn loadPromise;\n}\n"]}
1
+ {"version":3,"file":"photon.js","sourceRoot":"","sources":["../../src/utils/photon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAkB,CAAC;AAa1C,MAAM,aAAa,GAAG,mBAAmB,CAAC;AAE1C,4BAA4B;AAC5B,IAAI,YAAY,GAA6B,IAAI,CAAC;AAClD,IAAI,WAAW,GAA6C,IAAI,CAAC;AAEjE,SAAS,UAAU,CAAC,IAAiC;IACpD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC;IACb,CAAC;IACD,IAAI,IAAI,YAAY,GAAG,EAAE,CAAC;QACzB,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,oBAAoB;IAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/C,OAAO;QACN,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/G,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC;QACjC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,aAAa,CAAC;QAC3C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,CAAC;KACvC,CAAC;AACH,CAAC;AAMD,SAAS,mBAAmB,CAC3B,YAA0B,EAC1B,IAAiC,EACjC,OAA+C;IAE/C,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IACzE,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpE,OAAO,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,gBAAgB,CACxB,OAA8B,EAC9B,OAA+C,EAC/C,aAAsB;IAEtB,KAAK,MAAM,YAAY,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;QAClD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,SAAS;QAC3C,OAAO,mBAAmB,CAAC,OAAO,CAAC,YAAY,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,aAAa,CAAC;AACrB,CAAC;AAED,SAAS,cAAc,CACtB,OAA8B,EAC9B,IAAiC,EACjC,OAA+C;IAE/C,IAAI,CAAC;QACJ,OAAO,mBAAmB,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,KAA8B,CAAC;QAC3C,IAAI,GAAG,EAAE,IAAI,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;QACpD,OAAO,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IAClD,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB;IAC3B,MAAM,oBAAoB,GAAiB,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpE,MAAM,OAAO,GAA0B;QACtC,YAAY,EAAE,oBAAoB;QAClC,aAAa,EAAE,oBAAoB,EAAE;KACrC,CAAC;IACF,MAAM,SAAS,GAAG,EAAoC,CAAC;IAEvD,MAAM,mBAAmB,GAAiB,CAAC,CAC1C,IAAiC,EACjC,OAAoC,EACnC,EAAE;QACH,MAAM,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,aAAa,CAAC;YAAE,OAAO,mBAAmB,CAAC,oBAAoB,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC5G,OAAO,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC,CAAiB,CAAC;IAEnB,IAAI,CAAC;QACJ,SAAS,CAAC,YAAY,GAAG,mBAAmB,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE;YACzC,KAAK,EAAE,mBAAmB;YAC1B,QAAQ,EAAE,IAAI;YACd,YAAY,EAAE,IAAI;SAClB,CAAC,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,EAAE;QACX,IAAI,CAAC;YACJ,SAAS,CAAC,YAAY,GAAG,oBAAoB,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACR,MAAM,CAAC,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE;gBACzC,KAAK,EAAE,oBAAoB;gBAC3B,QAAQ,EAAE,IAAI;gBACd,YAAY,EAAE,IAAI;aAClB,CAAC,CAAC;QACJ,CAAC;IACF,CAAC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC/B,IAAI,YAAY,EAAE,CAAC;QAClB,OAAO,YAAY,CAAC;IACrB,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QACjB,OAAO,WAAW,CAAC;IACpB,CAAC;IAED,WAAW,GAAG,CAAC,KAAK,IAAI,EAAE;QACzB,MAAM,mBAAmB,GAAG,mBAAmB,EAAE,CAAC;QAClD,IAAI,CAAC;YACJ,YAAY,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;YAC1D,OAAO,YAAY,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACR,YAAY,GAAG,IAAI,CAAC;YACpB,OAAO,YAAY,CAAC;QACrB,CAAC;gBAAS,CAAC;YACV,mBAAmB,EAAE,CAAC;QACvB,CAAC;IACF,CAAC,CAAC,EAAE,CAAC;IAEL,OAAO,WAAW,CAAC;AACpB,CAAC","sourcesContent":["/**\n * Photon image processing wrapper.\n *\n * This module provides a unified interface to @silvia-odwyer/photon-node that works in:\n * 1. Node.js (development, npm run build)\n * 2. Bun compiled binaries (standalone distribution)\n *\n * The challenge: photon-node's CJS entry uses fs.readFileSync(__dirname + '/photon_rs_bg.wasm')\n * which bakes the build machine's absolute path into Bun compiled binaries.\n *\n * Solution:\n * 1. Patch fs.readFileSync to redirect missing photon_rs_bg.wasm reads\n * 2. Copy photon_rs_bg.wasm next to the executable in build:binary\n */\n\nimport type * as PhotonNode from \"@silvia-odwyer/photon-node\";\nimport type * as NodeFs from \"fs\";\nimport { createRequire } from \"module\";\nimport * as path from \"path\";\nimport { fileURLToPath } from \"url\";\n\nconst require = createRequire(import.meta.url);\nconst fs = require(\"fs\") as typeof NodeFs;\n\n// Re-export types from the main package\nexport type { PhotonImage as PhotonImageType } from \"@silvia-odwyer/photon-node\";\n\ninterface PatchedReadFileSyncObjectOptions extends NodeFs.ObjectEncodingOptions {\n\tflag?: string;\n}\n\ntype PatchedReadFileSyncOptions = PatchedReadFileSyncObjectOptions | BufferEncoding | null;\ntype ReadFileSync = typeof NodeFs.readFileSync;\ntype PatchedReadFileSyncResult = string | Buffer<ArrayBufferLike>;\n\nconst WASM_FILENAME = \"photon_rs_bg.wasm\";\n\n// Lazy-loaded photon module\nlet photonModule: typeof PhotonNode | null = null;\nlet loadPromise: Promise<typeof PhotonNode | null> | null = null;\n\nfunction pathOrNull(file: NodeFs.PathOrFileDescriptor): string | null {\n\tif (typeof file === \"string\") {\n\t\treturn file;\n\t}\n\tif (file instanceof URL) {\n\t\treturn fileURLToPath(file);\n\t}\n\treturn null;\n}\n\nfunction getFallbackWasmPaths(): string[] {\n\tconst execDir = path.dirname(process.execPath);\n\treturn [\n\t\t...(process.env.GRIP_EMBEDDED_ASSET_DIR ? [path.join(process.env.GRIP_EMBEDDED_ASSET_DIR, WASM_FILENAME)] : []),\n\t\tpath.join(execDir, WASM_FILENAME),\n\t\tpath.join(execDir, \"photon\", WASM_FILENAME),\n\t\tpath.join(process.cwd(), WASM_FILENAME),\n\t];\n}\ninterface PhotonWasmReadContext {\n\treadFileSync: ReadFileSync;\n\tfallbackPaths: string[];\n}\n\nfunction readFileWithOptions(\n\treadFileSync: ReadFileSync,\n\tfile: NodeFs.PathOrFileDescriptor,\n\toptions: PatchedReadFileSyncOptions | undefined,\n): PatchedReadFileSyncResult {\n\tif (options === undefined || options === null) return readFileSync(file);\n\tif (typeof options === \"string\") return readFileSync(file, options);\n\treturn readFileSync(file, options);\n}\n\nfunction readFallbackWasm(\n\tcontext: PhotonWasmReadContext,\n\toptions: PatchedReadFileSyncOptions | undefined,\n\toriginalError: unknown,\n): PatchedReadFileSyncResult {\n\tfor (const fallbackPath of context.fallbackPaths) {\n\t\tif (!fs.existsSync(fallbackPath)) continue;\n\t\treturn readFileWithOptions(context.readFileSync, fallbackPath, options);\n\t}\n\tthrow originalError;\n}\n\nfunction readPhotonWasm(\n\tcontext: PhotonWasmReadContext,\n\tfile: NodeFs.PathOrFileDescriptor,\n\toptions: PatchedReadFileSyncOptions | undefined,\n): PatchedReadFileSyncResult {\n\ttry {\n\t\treturn readFileWithOptions(context.readFileSync, file, options);\n\t} catch (error) {\n\t\tconst err = error as NodeJS.ErrnoException;\n\t\tif (err?.code && err.code !== \"ENOENT\") throw error;\n\t\treturn readFallbackWasm(context, options, error);\n\t}\n}\n\nfunction patchPhotonWasmRead(): () => void {\n\tconst originalReadFileSync: ReadFileSync = fs.readFileSync.bind(fs);\n\tconst context: PhotonWasmReadContext = {\n\t\treadFileSync: originalReadFileSync,\n\t\tfallbackPaths: getFallbackWasmPaths(),\n\t};\n\tconst mutableFs = fs as { readFileSync: ReadFileSync };\n\n\tconst patchedReadFileSync: ReadFileSync = ((\n\t\tfile: NodeFs.PathOrFileDescriptor,\n\t\toptions?: PatchedReadFileSyncOptions,\n\t) => {\n\t\tconst resolvedPath = pathOrNull(file);\n\t\tif (!resolvedPath?.endsWith(WASM_FILENAME)) return readFileWithOptions(originalReadFileSync, file, options);\n\t\treturn readPhotonWasm(context, file, options);\n\t}) as ReadFileSync;\n\n\ttry {\n\t\tmutableFs.readFileSync = patchedReadFileSync;\n\t} catch {\n\t\tObject.defineProperty(fs, \"readFileSync\", {\n\t\t\tvalue: patchedReadFileSync,\n\t\t\twritable: true,\n\t\t\tconfigurable: true,\n\t\t});\n\t}\n\n\treturn () => {\n\t\ttry {\n\t\t\tmutableFs.readFileSync = originalReadFileSync;\n\t\t} catch {\n\t\t\tObject.defineProperty(fs, \"readFileSync\", {\n\t\t\t\tvalue: originalReadFileSync,\n\t\t\t\twritable: true,\n\t\t\t\tconfigurable: true,\n\t\t\t});\n\t\t}\n\t};\n}\n\n/**\n * Load the photon module asynchronously.\n * Returns cached module on subsequent calls.\n */\nexport async function loadPhoton(): Promise<typeof PhotonNode | null> {\n\tif (photonModule) {\n\t\treturn photonModule;\n\t}\n\n\tif (loadPromise) {\n\t\treturn loadPromise;\n\t}\n\n\tloadPromise = (async () => {\n\t\tconst restoreReadFileSync = patchPhotonWasmRead();\n\t\ttry {\n\t\t\tphotonModule = await import(\"@silvia-odwyer/photon-node\");\n\t\t\treturn photonModule;\n\t\t} catch {\n\t\t\tphotonModule = null;\n\t\t\treturn photonModule;\n\t\t} finally {\n\t\t\trestoreReadFileSync();\n\t\t}\n\t})();\n\n\treturn loadPromise;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAInE,YAAY,EAAE,WAAW,EAAE,CAAC;AAoE5B;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,WAAW,CAQpE;AAED,wBAAgB,WAAW,IAAI,MAAM,CAAC,UAAU,CAY/C;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA8BxD;AAQD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAKlD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAyBjD","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { delimiter } from \"node:path\";\nimport type { ShellConfig } from \"@greppleai/grip-agent-core/node\";\nimport { spawn, spawnSync } from \"child_process\";\nimport { getBinDir } from \"../config.ts\";\n\nexport type { ShellConfig };\n\n/**\n * Find bash executable on PATH (cross-platform)\n */\nfunction findBashOnPath(): string | null {\n\tif (process.platform === \"win32\") {\n\t\t// Windows: Use 'where' and verify file exists (where can return non-existent paths)\n\t\ttry {\n\t\t\tconst result = spawnSync(\"where\", [\"bash.exe\"], {\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\ttimeout: 5000,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (result.status === 0 && result.stdout) {\n\t\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\t\tif (firstMatch && existsSync(firstMatch)) {\n\t\t\t\t\treturn firstMatch;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t\treturn null;\n\t}\n\n\t// Unix: Use 'which' and trust its output (handles Termux and special filesystems)\n\ttry {\n\t\tconst result = spawnSync(\"which\", [\"bash\"], { encoding: \"utf-8\", timeout: 5000 });\n\t\tif (result.status === 0 && result.stdout) {\n\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\tif (firstMatch) {\n\t\t\t\treturn firstMatch;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\treturn null;\n}\nfunction getWindowsShellConfig(): ShellConfig {\n\tconst paths: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) paths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\tif (programFilesX86) paths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\n\tfor (const path of paths) {\n\t\tif (existsSync(path)) return { shell: path, args: [\"-c\"] };\n\t}\n\tconst bashOnPath = findBashOnPath();\n\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\tthrow new Error(\n\t\t`No bash shell found. Options:\\n` +\n\t\t\t` 1. Install Git for Windows: https://git-scm.com/download/win\\n` +\n\t\t\t` 2. Add your bash to PATH (Cygwin, MSYS2, etc.)\\n` +\n\t\t\t\" 3. Set shellPath in settings.json\\n\\n\" +\n\t\t\t`Searched Git Bash in:\\n${paths.map((path) => ` ${path}`).join(\"\\n\")}`,\n\t);\n}\n\nfunction getUnixShellConfig(): ShellConfig {\n\tif (existsSync(\"/bin/bash\")) return { shell: \"/bin/bash\", args: [\"-c\"] };\n\tconst bashOnPath = findBashOnPath();\n\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\treturn { shell: \"sh\", args: [\"-c\"] };\n}\n\n/**\n * Resolve shell configuration based on platform and an optional explicit shell path.\n * Resolution order:\n * 1. User-specified shellPath\n * 2. On Windows: Git Bash in known locations, then bash on PATH\n * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh\n */\nexport function getShellConfig(customShellPath?: string): ShellConfig {\n\tif (!customShellPath) {\n\t\treturn process.platform === \"win32\" ? getWindowsShellConfig() : getUnixShellConfig();\n\t}\n\tif (!existsSync(customShellPath)) {\n\t\tthrow new Error(`Custom shell path not found: ${customShellPath}`);\n\t}\n\treturn { shell: customShellPath, args: [\"-c\"] };\n}\n\nexport function getShellEnv(): NodeJS.ProcessEnv {\n\tconst binDir = getBinDir();\n\tconst pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n\tconst currentPath = process.env[pathKey] ?? \"\";\n\tconst pathEntries = currentPath.split(delimiter).filter(Boolean);\n\tconst hasBinDir = pathEntries.includes(binDir);\n\tconst updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n\n\treturn {\n\t\t...process.env,\n\t\t[pathKey]: updatedPath,\n\t};\n}\n\n/**\n * Sanitize binary output for display/storage.\n * Removes characters that crash string-width or cause display issues:\n * - Control characters (except tab, newline, carriage return)\n * - Lone surrogates\n * - Unicode Format characters (crash string-width due to a bug)\n * - Characters with undefined code points\n */\nexport function sanitizeBinaryOutput(str: string): string {\n\t// Use Array.from to properly iterate over code points (not code units)\n\t// This handles surrogate pairs correctly and catches edge cases where\n\t// codePointAt() might return undefined\n\treturn Array.from(str)\n\t\t.filter((char) => {\n\t\t\t// Filter out characters that cause string-width to crash\n\t\t\t// This includes:\n\t\t\t// - Unicode format characters\n\t\t\t// - Lone surrogates (already filtered by Array.from)\n\t\t\t// - Control chars except \\t \\n \\r\n\t\t\t// - Characters with undefined code points\n\n\t\t\tconst code = char.codePointAt(0);\n\n\t\t\t// Skip if code point is undefined (edge case with invalid strings)\n\t\t\tif (code === undefined) return false;\n\n\t\t\t// Allow tab, newline, carriage return\n\t\t\tif (code === 0x09 || code === 0x0a || code === 0x0d) return true;\n\n\t\t\t// Filter out control characters (0x00-0x1F, except 0x09, 0x0a, 0x0x0d)\n\t\t\tif (code <= 0x1f) return false;\n\n\t\t\t// Filter out Unicode format characters\n\t\t\tif (code >= 0xfff9 && code <= 0xfffb) return false;\n\n\t\t\treturn true;\n\t\t})\n\t\t.join(\"\");\n}\n\n/**\n * Detached child processes must be tracked so they can be killed on parent\n * shutdown signals (SIGHUP/SIGTERM).\n */\nconst trackedDetachedChildPids = new Set<number>();\n\nexport function trackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.add(pid);\n}\n\nexport function untrackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.delete(pid);\n}\n\nexport function killTrackedDetachedChildren(): void {\n\tfor (const pid of trackedDetachedChildPids) {\n\t\tkillProcessTree(pid);\n\t}\n\ttrackedDetachedChildPids.clear();\n}\n\n/**\n * Kill a process and all its children (cross-platform)\n */\nexport function killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\t// Use taskkill on Windows to kill process tree\n\t\ttry {\n\t\t\tspawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\tdetached: true,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors if taskkill fails\n\t\t}\n\t} else {\n\t\t// Use SIGKILL on Unix/Linux/Mac\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Fallback to killing just the child if process group kill fails\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAInE,YAAY,EAAE,WAAW,EAAE,CAAC;AAoE5B;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,WAAW,CAQpE;AAED,wBAAgB,WAAW,IAAI,MAAM,CAAC,UAAU,CAY/C;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA8BxD;AAQD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAKlD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAyBjD"}
@@ -1 +1 @@
1
- {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { delimiter } from \"node:path\";\nimport type { ShellConfig } from \"@greppleai/grip-agent-core/node\";\nimport { spawn, spawnSync } from \"child_process\";\nimport { getBinDir } from \"../config.ts\";\n\nexport type { ShellConfig };\n\n/**\n * Find bash executable on PATH (cross-platform)\n */\nfunction findBashOnPath(): string | null {\n\tif (process.platform === \"win32\") {\n\t\t// Windows: Use 'where' and verify file exists (where can return non-existent paths)\n\t\ttry {\n\t\t\tconst result = spawnSync(\"where\", [\"bash.exe\"], {\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\ttimeout: 5000,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (result.status === 0 && result.stdout) {\n\t\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\t\tif (firstMatch && existsSync(firstMatch)) {\n\t\t\t\t\treturn firstMatch;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t\treturn null;\n\t}\n\n\t// Unix: Use 'which' and trust its output (handles Termux and special filesystems)\n\ttry {\n\t\tconst result = spawnSync(\"which\", [\"bash\"], { encoding: \"utf-8\", timeout: 5000 });\n\t\tif (result.status === 0 && result.stdout) {\n\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\tif (firstMatch) {\n\t\t\t\treturn firstMatch;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\treturn null;\n}\nfunction getWindowsShellConfig(): ShellConfig {\n\tconst paths: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) paths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\tif (programFilesX86) paths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\n\tfor (const path of paths) {\n\t\tif (existsSync(path)) return { shell: path, args: [\"-c\"] };\n\t}\n\tconst bashOnPath = findBashOnPath();\n\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\tthrow new Error(\n\t\t`No bash shell found. Options:\\n` +\n\t\t\t` 1. Install Git for Windows: https://git-scm.com/download/win\\n` +\n\t\t\t` 2. Add your bash to PATH (Cygwin, MSYS2, etc.)\\n` +\n\t\t\t\" 3. Set shellPath in settings.json\\n\\n\" +\n\t\t\t`Searched Git Bash in:\\n${paths.map((path) => ` ${path}`).join(\"\\n\")}`,\n\t);\n}\n\nfunction getUnixShellConfig(): ShellConfig {\n\tif (existsSync(\"/bin/bash\")) return { shell: \"/bin/bash\", args: [\"-c\"] };\n\tconst bashOnPath = findBashOnPath();\n\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\treturn { shell: \"sh\", args: [\"-c\"] };\n}\n\n/**\n * Resolve shell configuration based on platform and an optional explicit shell path.\n * Resolution order:\n * 1. User-specified shellPath\n * 2. On Windows: Git Bash in known locations, then bash on PATH\n * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh\n */\nexport function getShellConfig(customShellPath?: string): ShellConfig {\n\tif (!customShellPath) {\n\t\treturn process.platform === \"win32\" ? getWindowsShellConfig() : getUnixShellConfig();\n\t}\n\tif (!existsSync(customShellPath)) {\n\t\tthrow new Error(`Custom shell path not found: ${customShellPath}`);\n\t}\n\treturn { shell: customShellPath, args: [\"-c\"] };\n}\n\nexport function getShellEnv(): NodeJS.ProcessEnv {\n\tconst binDir = getBinDir();\n\tconst pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n\tconst currentPath = process.env[pathKey] ?? \"\";\n\tconst pathEntries = currentPath.split(delimiter).filter(Boolean);\n\tconst hasBinDir = pathEntries.includes(binDir);\n\tconst updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n\n\treturn {\n\t\t...process.env,\n\t\t[pathKey]: updatedPath,\n\t};\n}\n\n/**\n * Sanitize binary output for display/storage.\n * Removes characters that crash string-width or cause display issues:\n * - Control characters (except tab, newline, carriage return)\n * - Lone surrogates\n * - Unicode Format characters (crash string-width due to a bug)\n * - Characters with undefined code points\n */\nexport function sanitizeBinaryOutput(str: string): string {\n\t// Use Array.from to properly iterate over code points (not code units)\n\t// This handles surrogate pairs correctly and catches edge cases where\n\t// codePointAt() might return undefined\n\treturn Array.from(str)\n\t\t.filter((char) => {\n\t\t\t// Filter out characters that cause string-width to crash\n\t\t\t// This includes:\n\t\t\t// - Unicode format characters\n\t\t\t// - Lone surrogates (already filtered by Array.from)\n\t\t\t// - Control chars except \\t \\n \\r\n\t\t\t// - Characters with undefined code points\n\n\t\t\tconst code = char.codePointAt(0);\n\n\t\t\t// Skip if code point is undefined (edge case with invalid strings)\n\t\t\tif (code === undefined) return false;\n\n\t\t\t// Allow tab, newline, carriage return\n\t\t\tif (code === 0x09 || code === 0x0a || code === 0x0d) return true;\n\n\t\t\t// Filter out control characters (0x00-0x1F, except 0x09, 0x0a, 0x0x0d)\n\t\t\tif (code <= 0x1f) return false;\n\n\t\t\t// Filter out Unicode format characters\n\t\t\tif (code >= 0xfff9 && code <= 0xfffb) return false;\n\n\t\t\treturn true;\n\t\t})\n\t\t.join(\"\");\n}\n\n/**\n * Detached child processes must be tracked so they can be killed on parent\n * shutdown signals (SIGHUP/SIGTERM).\n */\nconst trackedDetachedChildPids = new Set<number>();\n\nexport function trackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.add(pid);\n}\n\nexport function untrackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.delete(pid);\n}\n\nexport function killTrackedDetachedChildren(): void {\n\tfor (const pid of trackedDetachedChildPids) {\n\t\tkillProcessTree(pid);\n\t}\n\ttrackedDetachedChildPids.clear();\n}\n\n/**\n * Kill a process and all its children (cross-platform)\n */\nexport function killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\t// Use taskkill on Windows to kill process tree\n\t\ttry {\n\t\t\tspawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\tdetached: true,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors if taskkill fails\n\t\t}\n\t} else {\n\t\t// Use SIGKILL on Unix/Linux/Mac\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Fallback to killing just the child if process group kill fails\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { delimiter } from \"node:path\";\nimport type { ShellConfig } from \"@greppleai/grip-agent-core/node\";\nimport { spawn, spawnSync } from \"child_process\";\nimport { getBinDir } from \"../config.ts\";\n\nexport type { ShellConfig };\n\n/**\n * Find bash executable on PATH (cross-platform)\n */\nfunction findBashOnPath(): string | null {\n\tif (process.platform === \"win32\") {\n\t\t// Windows: Use 'where' and verify file exists (where can return non-existent paths)\n\t\ttry {\n\t\t\tconst result = spawnSync(\"where\", [\"bash.exe\"], {\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\ttimeout: 5000,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tif (result.status === 0 && result.stdout) {\n\t\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\t\tif (firstMatch && existsSync(firstMatch)) {\n\t\t\t\t\treturn firstMatch;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors\n\t\t}\n\t\treturn null;\n\t}\n\n\t// Unix: Use 'which' and trust its output (handles Termux and special filesystems)\n\ttry {\n\t\tconst result = spawnSync(\"which\", [\"bash\"], { encoding: \"utf-8\", timeout: 5000 });\n\t\tif (result.status === 0 && result.stdout) {\n\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\tif (firstMatch) {\n\t\t\t\treturn firstMatch;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors\n\t}\n\treturn null;\n}\nfunction getWindowsShellConfig(): ShellConfig {\n\tconst paths: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) paths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\tif (programFilesX86) paths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\n\tfor (const path of paths) {\n\t\tif (existsSync(path)) return { shell: path, args: [\"-c\"] };\n\t}\n\tconst bashOnPath = findBashOnPath();\n\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\tthrow new Error(\n\t\t`No bash shell found. Options:\\n` +\n\t\t\t` 1. Install Git for Windows: https://git-scm.com/download/win\\n` +\n\t\t\t` 2. Add your bash to PATH (Cygwin, MSYS2, etc.)\\n` +\n\t\t\t\" 3. Set shellPath in settings.json\\n\\n\" +\n\t\t\t`Searched Git Bash in:\\n${paths.map((path) => ` ${path}`).join(\"\\n\")}`,\n\t);\n}\n\nfunction getUnixShellConfig(): ShellConfig {\n\tif (existsSync(\"/bin/bash\")) return { shell: \"/bin/bash\", args: [\"-c\"] };\n\tconst bashOnPath = findBashOnPath();\n\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\treturn { shell: \"sh\", args: [\"-c\"] };\n}\n\n/**\n * Resolve shell configuration based on platform and an optional explicit shell path.\n * Resolution order:\n * 1. User-specified shellPath\n * 2. On Windows: Git Bash in known locations, then bash on PATH\n * 3. On Unix: /bin/bash, then bash on PATH, then fallback to sh\n */\nexport function getShellConfig(customShellPath?: string): ShellConfig {\n\tif (!customShellPath) {\n\t\treturn process.platform === \"win32\" ? getWindowsShellConfig() : getUnixShellConfig();\n\t}\n\tif (!existsSync(customShellPath)) {\n\t\tthrow new Error(`Custom shell path not found: ${customShellPath}`);\n\t}\n\treturn { shell: customShellPath, args: [\"-c\"] };\n}\n\nexport function getShellEnv(): NodeJS.ProcessEnv {\n\tconst binDir = getBinDir();\n\tconst pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n\tconst currentPath = process.env[pathKey] ?? \"\";\n\tconst pathEntries = currentPath.split(delimiter).filter(Boolean);\n\tconst hasBinDir = pathEntries.includes(binDir);\n\tconst updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n\n\treturn {\n\t\t...process.env,\n\t\t[pathKey]: updatedPath,\n\t};\n}\n\n/**\n * Sanitize binary output for display/storage.\n * Removes characters that crash string-width or cause display issues:\n * - Control characters (except tab, newline, carriage return)\n * - Lone surrogates\n * - Unicode Format characters (crash string-width due to a bug)\n * - Characters with undefined code points\n */\nexport function sanitizeBinaryOutput(str: string): string {\n\t// Use Array.from to properly iterate over code points (not code units)\n\t// This handles surrogate pairs correctly and catches edge cases where\n\t// codePointAt() might return undefined\n\treturn Array.from(str)\n\t\t.filter((char) => {\n\t\t\t// Filter out characters that cause string-width to crash\n\t\t\t// This includes:\n\t\t\t// - Unicode format characters\n\t\t\t// - Lone surrogates (already filtered by Array.from)\n\t\t\t// - Control chars except \\t \\n \\r\n\t\t\t// - Characters with undefined code points\n\n\t\t\tconst code = char.codePointAt(0);\n\n\t\t\t// Skip if code point is undefined (edge case with invalid strings)\n\t\t\tif (code === undefined) return false;\n\n\t\t\t// Allow tab, newline, carriage return\n\t\t\tif (code === 0x09 || code === 0x0a || code === 0x0d) return true;\n\n\t\t\t// Filter out control characters (0x00-0x1F, except 0x09, 0x0a, 0x0x0d)\n\t\t\tif (code <= 0x1f) return false;\n\n\t\t\t// Filter out Unicode format characters\n\t\t\tif (code >= 0xfff9 && code <= 0xfffb) return false;\n\n\t\t\treturn true;\n\t\t})\n\t\t.join(\"\");\n}\n\n/**\n * Detached child processes must be tracked so they can be killed on parent\n * shutdown signals (SIGHUP/SIGTERM).\n */\nconst trackedDetachedChildPids = new Set<number>();\n\nexport function trackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.add(pid);\n}\n\nexport function untrackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.delete(pid);\n}\n\nexport function killTrackedDetachedChildren(): void {\n\tfor (const pid of trackedDetachedChildPids) {\n\t\tkillProcessTree(pid);\n\t}\n\ttrackedDetachedChildPids.clear();\n}\n\n/**\n * Kill a process and all its children (cross-platform)\n */\nexport function killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\t// Use taskkill on Windows to kill process tree\n\t\ttry {\n\t\t\tspawn(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\tdetached: true,\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors if taskkill fails\n\t\t}\n\t} else {\n\t\t// Use SIGKILL on Unix/Linux/Mac\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Fallback to killing just the child if process group kill fails\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrE","sourcesContent":["/**\n * Sleep helper that respects abort signal.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Aborted\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\"abort\", () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(new Error(\"Aborted\"));\n\t\t});\n\t});\n}\n"]}
1
+ {"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"sleep.js","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB,EAAiB;IACtE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC;QACvC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;YAC7B,OAAO;QACR,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAExC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC;YACvC,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAAA,CAC7B,CAAC,CAAC;IAAA,CACH,CAAC,CAAC;AAAA,CACH","sourcesContent":["/**\n * Sleep helper that respects abort signal.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Aborted\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\"abort\", () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(new Error(\"Aborted\"));\n\t\t});\n\t});\n}\n"]}
1
+ {"version":3,"file":"sleep.js","sourceRoot":"","sources":["../../src/utils/sleep.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,EAAU,EAAE,MAAoB;IACrD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YACrB,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;YAC7B,OAAO;QACR,CAAC;QAED,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAExC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;YACtC,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,MAAM,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Sleep helper that respects abort signal.\n */\nexport function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Aborted\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeout = setTimeout(resolve, ms);\n\n\t\tsignal?.addEventListener(\"abort\", () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(new Error(\"Aborted\"));\n\t\t});\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"syntax-highlight.d.ts","sourceRoot":"","sources":["../../src/utils/syntax-highlight.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,cAAc,CAAC;CACvB;AAkFD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,cAAmB,GAAG,MAAM,CAgDtF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAQ9E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD","sourcesContent":["import hljs from \"highlight.js/lib/index.js\";\nimport { decodeHtmlEntityAt } from \"./html.ts\";\n\nexport type HighlightFormatter = (text: string) => string;\nexport type HighlightTheme = Partial<Record<string, HighlightFormatter>>;\n\nexport interface HighlightOptions {\n\tlanguage?: string;\n\tignoreIllegals?: boolean;\n\tlanguageSubset?: string[];\n\ttheme?: HighlightTheme;\n}\n\nconst SPAN_CLOSE = \"</span>\";\nconst HIGHLIGHT_CLASS_PREFIX = \"hljs-\";\n\nfunction getScopeFromSpanTag(tag: string): string | undefined {\n\tconst match = /\\sclass\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/.exec(tag);\n\tconst classValue = match?.[1] ?? match?.[2];\n\tif (!classValue) {\n\t\treturn undefined;\n\t}\n\n\tfor (const className of classValue.split(/\\s+/)) {\n\t\tif (className.startsWith(HIGHLIGHT_CLASS_PREFIX)) {\n\t\t\treturn className.slice(HIGHLIGHT_CLASS_PREFIX.length);\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getScopeFormatter(scope: string, theme: HighlightTheme): HighlightFormatter | undefined {\n\tconst exact = theme[scope];\n\tif (exact) {\n\t\treturn exact;\n\t}\n\n\tconst dotIndex = scope.indexOf(\".\");\n\tif (dotIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dotIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\tconst dashIndex = scope.indexOf(\"-\");\n\tif (dashIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dashIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getActiveFormatter(scopes: Array<string | undefined>, theme: HighlightTheme): HighlightFormatter | undefined {\n\tfor (let i = scopes.length - 1; i >= 0; i--) {\n\t\tconst scope = scopes[i];\n\t\tif (!scope) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst formatter = getScopeFormatter(scope, theme);\n\t\tif (formatter) {\n\t\t\treturn formatter;\n\t\t}\n\t}\n\treturn theme.default;\n}\n\ninterface HighlightSpanOpenTag {\n\tendIndex: number;\n\tscope: string | undefined;\n}\n\nfunction isSpanOpenTagStart(html: string, index: number): boolean {\n\tif (!html.startsWith(\"<span\", index)) {\n\t\treturn false;\n\t}\n\tconst nextChar = html[index + \"<span\".length];\n\treturn nextChar === \">\" || nextChar === \" \" || nextChar === \"\\t\" || nextChar === \"\\n\" || nextChar === \"\\r\";\n}\nfunction parseSpanOpenTag(html: string, index: number): HighlightSpanOpenTag | null {\n\tif (!isSpanOpenTagStart(html, index)) return null;\n\tconst endIndex = html.indexOf(\">\", index + 5);\n\tif (endIndex === -1) return null;\n\treturn {\n\t\tendIndex,\n\t\tscope: getScopeFromSpanTag(html.slice(index, endIndex + 1)),\n\t};\n}\n\nexport function renderHighlightedHtml(html: string, theme: HighlightTheme = {}): string {\n\tlet output = \"\";\n\tlet textBuffer = \"\";\n\tconst scopes: Array<string | undefined> = [];\n\n\tconst flushText = () => {\n\t\tif (!textBuffer) {\n\t\t\treturn;\n\t\t}\n\t\tconst formatter = getActiveFormatter(scopes, theme);\n\t\toutput += formatter ? formatter(textBuffer) : textBuffer;\n\t\ttextBuffer = \"\";\n\t};\n\n\tlet index = 0;\n\twhile (index < html.length) {\n\t\tconst spanOpenTag = parseSpanOpenTag(html, index);\n\t\tif (spanOpenTag) {\n\t\t\tflushText();\n\t\t\tscopes.push(spanOpenTag.scope);\n\t\t\tindex = spanOpenTag.endIndex + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html.startsWith(SPAN_CLOSE, index)) {\n\t\t\tflushText();\n\t\t\tif (scopes.length > 0) {\n\t\t\t\tscopes.pop();\n\t\t\t}\n\t\t\tindex += SPAN_CLOSE.length;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html[index] === \"&\") {\n\t\t\tconst decoded = decodeHtmlEntityAt(html, index);\n\t\t\tif (decoded) {\n\t\t\t\ttextBuffer += decoded.text;\n\t\t\t\tindex += decoded.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\ttextBuffer += html[index];\n\t\tindex++;\n\t}\n\n\tflushText();\n\treturn output;\n}\n\nexport function highlight(code: string, options: HighlightOptions = {}): string {\n\tconst html = options.language\n\t\t? hljs.highlight(code, {\n\t\t\t\tlanguage: options.language,\n\t\t\t\tignoreIllegals: options.ignoreIllegals,\n\t\t\t}).value\n\t\t: hljs.highlightAuto(code, options.languageSubset).value;\n\treturn renderHighlightedHtml(html, options.theme);\n}\n\nexport function supportsLanguage(name: string): boolean {\n\treturn hljs.getLanguage(name) !== undefined;\n}\n"]}
1
+ {"version":3,"file":"syntax-highlight.d.ts","sourceRoot":"","sources":["../../src/utils/syntax-highlight.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAC1D,MAAM,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,KAAK,CAAC,EAAE,cAAc,CAAC;CACvB;AAkFD,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,GAAE,cAAmB,GAAG,MAAM,CAgDtF;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAQ9E;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD"}
@@ -1,4 +1,4 @@
1
- import hljs from "highlight.js/lib/index.js";
1
+ import hljs from "highlight.js";
2
2
  import { decodeHtmlEntityAt } from "./html.js";
3
3
  const SPAN_CLOSE = "</span>";
4
4
  const HIGHLIGHT_CLASS_PREFIX = "hljs-";
@@ -1 +1 @@
1
- {"version":3,"file":"syntax-highlight.js","sourceRoot":"","sources":["../../src/utils/syntax-highlight.ts"],"names":[],"mappings":"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","sourcesContent":["import hljs from \"highlight.js/lib/index.js\";\nimport { decodeHtmlEntityAt } from \"./html.ts\";\n\nexport type HighlightFormatter = (text: string) => string;\nexport type HighlightTheme = Partial<Record<string, HighlightFormatter>>;\n\nexport interface HighlightOptions {\n\tlanguage?: string;\n\tignoreIllegals?: boolean;\n\tlanguageSubset?: string[];\n\ttheme?: HighlightTheme;\n}\n\nconst SPAN_CLOSE = \"</span>\";\nconst HIGHLIGHT_CLASS_PREFIX = \"hljs-\";\n\nfunction getScopeFromSpanTag(tag: string): string | undefined {\n\tconst match = /\\sclass\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/.exec(tag);\n\tconst classValue = match?.[1] ?? match?.[2];\n\tif (!classValue) {\n\t\treturn undefined;\n\t}\n\n\tfor (const className of classValue.split(/\\s+/)) {\n\t\tif (className.startsWith(HIGHLIGHT_CLASS_PREFIX)) {\n\t\t\treturn className.slice(HIGHLIGHT_CLASS_PREFIX.length);\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getScopeFormatter(scope: string, theme: HighlightTheme): HighlightFormatter | undefined {\n\tconst exact = theme[scope];\n\tif (exact) {\n\t\treturn exact;\n\t}\n\n\tconst dotIndex = scope.indexOf(\".\");\n\tif (dotIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dotIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\tconst dashIndex = scope.indexOf(\"-\");\n\tif (dashIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dashIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getActiveFormatter(scopes: Array<string | undefined>, theme: HighlightTheme): HighlightFormatter | undefined {\n\tfor (let i = scopes.length - 1; i >= 0; i--) {\n\t\tconst scope = scopes[i];\n\t\tif (!scope) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst formatter = getScopeFormatter(scope, theme);\n\t\tif (formatter) {\n\t\t\treturn formatter;\n\t\t}\n\t}\n\treturn theme.default;\n}\n\ninterface HighlightSpanOpenTag {\n\tendIndex: number;\n\tscope: string | undefined;\n}\n\nfunction isSpanOpenTagStart(html: string, index: number): boolean {\n\tif (!html.startsWith(\"<span\", index)) {\n\t\treturn false;\n\t}\n\tconst nextChar = html[index + \"<span\".length];\n\treturn nextChar === \">\" || nextChar === \" \" || nextChar === \"\\t\" || nextChar === \"\\n\" || nextChar === \"\\r\";\n}\nfunction parseSpanOpenTag(html: string, index: number): HighlightSpanOpenTag | null {\n\tif (!isSpanOpenTagStart(html, index)) return null;\n\tconst endIndex = html.indexOf(\">\", index + 5);\n\tif (endIndex === -1) return null;\n\treturn {\n\t\tendIndex,\n\t\tscope: getScopeFromSpanTag(html.slice(index, endIndex + 1)),\n\t};\n}\n\nexport function renderHighlightedHtml(html: string, theme: HighlightTheme = {}): string {\n\tlet output = \"\";\n\tlet textBuffer = \"\";\n\tconst scopes: Array<string | undefined> = [];\n\n\tconst flushText = () => {\n\t\tif (!textBuffer) {\n\t\t\treturn;\n\t\t}\n\t\tconst formatter = getActiveFormatter(scopes, theme);\n\t\toutput += formatter ? formatter(textBuffer) : textBuffer;\n\t\ttextBuffer = \"\";\n\t};\n\n\tlet index = 0;\n\twhile (index < html.length) {\n\t\tconst spanOpenTag = parseSpanOpenTag(html, index);\n\t\tif (spanOpenTag) {\n\t\t\tflushText();\n\t\t\tscopes.push(spanOpenTag.scope);\n\t\t\tindex = spanOpenTag.endIndex + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html.startsWith(SPAN_CLOSE, index)) {\n\t\t\tflushText();\n\t\t\tif (scopes.length > 0) {\n\t\t\t\tscopes.pop();\n\t\t\t}\n\t\t\tindex += SPAN_CLOSE.length;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html[index] === \"&\") {\n\t\t\tconst decoded = decodeHtmlEntityAt(html, index);\n\t\t\tif (decoded) {\n\t\t\t\ttextBuffer += decoded.text;\n\t\t\t\tindex += decoded.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\ttextBuffer += html[index];\n\t\tindex++;\n\t}\n\n\tflushText();\n\treturn output;\n}\n\nexport function highlight(code: string, options: HighlightOptions = {}): string {\n\tconst html = options.language\n\t\t? hljs.highlight(code, {\n\t\t\t\tlanguage: options.language,\n\t\t\t\tignoreIllegals: options.ignoreIllegals,\n\t\t\t}).value\n\t\t: hljs.highlightAuto(code, options.languageSubset).value;\n\treturn renderHighlightedHtml(html, options.theme);\n}\n\nexport function supportsLanguage(name: string): boolean {\n\treturn hljs.getLanguage(name) !== undefined;\n}\n"]}
1
+ {"version":3,"file":"syntax-highlight.js","sourceRoot":"","sources":["../../src/utils/syntax-highlight.ts"],"names":[],"mappings":"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","sourcesContent":["import hljs from \"highlight.js\";\nimport { decodeHtmlEntityAt } from \"./html.ts\";\n\nexport type HighlightFormatter = (text: string) => string;\nexport type HighlightTheme = Partial<Record<string, HighlightFormatter>>;\n\nexport interface HighlightOptions {\n\tlanguage?: string;\n\tignoreIllegals?: boolean;\n\tlanguageSubset?: string[];\n\ttheme?: HighlightTheme;\n}\n\nconst SPAN_CLOSE = \"</span>\";\nconst HIGHLIGHT_CLASS_PREFIX = \"hljs-\";\n\nfunction getScopeFromSpanTag(tag: string): string | undefined {\n\tconst match = /\\sclass\\s*=\\s*(?:\"([^\"]*)\"|'([^']*)')/.exec(tag);\n\tconst classValue = match?.[1] ?? match?.[2];\n\tif (!classValue) {\n\t\treturn undefined;\n\t}\n\n\tfor (const className of classValue.split(/\\s+/)) {\n\t\tif (className.startsWith(HIGHLIGHT_CLASS_PREFIX)) {\n\t\t\treturn className.slice(HIGHLIGHT_CLASS_PREFIX.length);\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getScopeFormatter(scope: string, theme: HighlightTheme): HighlightFormatter | undefined {\n\tconst exact = theme[scope];\n\tif (exact) {\n\t\treturn exact;\n\t}\n\n\tconst dotIndex = scope.indexOf(\".\");\n\tif (dotIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dotIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\tconst dashIndex = scope.indexOf(\"-\");\n\tif (dashIndex !== -1) {\n\t\tconst prefixFormatter = theme[scope.slice(0, dashIndex)];\n\t\tif (prefixFormatter) {\n\t\t\treturn prefixFormatter;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction getActiveFormatter(scopes: Array<string | undefined>, theme: HighlightTheme): HighlightFormatter | undefined {\n\tfor (let i = scopes.length - 1; i >= 0; i--) {\n\t\tconst scope = scopes[i];\n\t\tif (!scope) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst formatter = getScopeFormatter(scope, theme);\n\t\tif (formatter) {\n\t\t\treturn formatter;\n\t\t}\n\t}\n\treturn theme.default;\n}\n\ninterface HighlightSpanOpenTag {\n\tendIndex: number;\n\tscope: string | undefined;\n}\n\nfunction isSpanOpenTagStart(html: string, index: number): boolean {\n\tif (!html.startsWith(\"<span\", index)) {\n\t\treturn false;\n\t}\n\tconst nextChar = html[index + \"<span\".length];\n\treturn nextChar === \">\" || nextChar === \" \" || nextChar === \"\\t\" || nextChar === \"\\n\" || nextChar === \"\\r\";\n}\nfunction parseSpanOpenTag(html: string, index: number): HighlightSpanOpenTag | null {\n\tif (!isSpanOpenTagStart(html, index)) return null;\n\tconst endIndex = html.indexOf(\">\", index + 5);\n\tif (endIndex === -1) return null;\n\treturn {\n\t\tendIndex,\n\t\tscope: getScopeFromSpanTag(html.slice(index, endIndex + 1)),\n\t};\n}\n\nexport function renderHighlightedHtml(html: string, theme: HighlightTheme = {}): string {\n\tlet output = \"\";\n\tlet textBuffer = \"\";\n\tconst scopes: Array<string | undefined> = [];\n\n\tconst flushText = () => {\n\t\tif (!textBuffer) {\n\t\t\treturn;\n\t\t}\n\t\tconst formatter = getActiveFormatter(scopes, theme);\n\t\toutput += formatter ? formatter(textBuffer) : textBuffer;\n\t\ttextBuffer = \"\";\n\t};\n\n\tlet index = 0;\n\twhile (index < html.length) {\n\t\tconst spanOpenTag = parseSpanOpenTag(html, index);\n\t\tif (spanOpenTag) {\n\t\t\tflushText();\n\t\t\tscopes.push(spanOpenTag.scope);\n\t\t\tindex = spanOpenTag.endIndex + 1;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html.startsWith(SPAN_CLOSE, index)) {\n\t\t\tflushText();\n\t\t\tif (scopes.length > 0) {\n\t\t\t\tscopes.pop();\n\t\t\t}\n\t\t\tindex += SPAN_CLOSE.length;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (html[index] === \"&\") {\n\t\t\tconst decoded = decodeHtmlEntityAt(html, index);\n\t\t\tif (decoded) {\n\t\t\t\ttextBuffer += decoded.text;\n\t\t\t\tindex += decoded.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\ttextBuffer += html[index];\n\t\tindex++;\n\t}\n\n\tflushText();\n\treturn output;\n}\n\nexport function highlight(code: string, options: HighlightOptions = {}): string {\n\tconst html = options.language\n\t\t? hljs.highlight(code, {\n\t\t\t\tlanguage: options.language,\n\t\t\t\tignoreIllegals: options.ignoreIllegals,\n\t\t\t}).value\n\t\t: hljs.highlightAuto(code, options.languageSubset).value;\n\treturn renderHighlightedHtml(html, options.theme);\n}\n\nexport function supportsLanguage(name: string): boolean {\n\treturn hljs.getLanguage(name) !== undefined;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"tools-manager.d.ts","sourceRoot":"","sources":["../../src/utils/tools-manager.ts"],"names":[],"mappings":"AAaA,KAAK,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;AAyEnC,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAmBhE;AAuOD,wBAAsB,UAAU,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,GAAE,OAAe,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgC5G","sourcesContent":["import chalk from \"chalk\";\nimport { type SpawnSyncReturns, spawnSync } from \"child_process\";\nimport { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from \"fs\";\nimport { arch, platform } from \"os\";\nimport { join } from \"path\";\nimport { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { APP_NAME, getBinDir } from \"../config.ts\";\n\nconst TOOLS_DIR = getBinDir();\nconst NETWORK_TIMEOUT_MS = 10_000;\nconst DOWNLOAD_TIMEOUT_MS = 120_000;\n\ntype ManagedToolName = \"fd\" | \"rg\";\n\nfunction isOfflineModeEnabled(): boolean {\n\tconst value = process.env.GRIP_OFFLINE;\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\ninterface ToolConfig {\n\tname: string;\n\trepo: string; // GitHub repo (e.g., \"sharkdp/fd\")\n\tbinaryName: string; // Name of the binary inside the archive\n\tsystemBinaryNames?: string[]; // Alternative system command names to try before downloading\n\ttagPrefix: string; // Prefix for tags (e.g., \"v\" for v1.0.0, \"\" for 1.0.0)\n\tgetAssetName: (version: string, plat: string, architecture: string) => string | null;\n}\n\nconst TOOLS: Record<string, ToolConfig> = {\n\tfd: {\n\t\tname: \"fd\",\n\t\trepo: \"sharkdp/fd\",\n\t\tbinaryName: \"fd\",\n\t\tsystemBinaryNames: [\"fd\", \"fdfind\"],\n\t\ttagPrefix: \"v\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-unknown-linux-gnu.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n\trg: {\n\t\tname: \"ripgrep\",\n\t\trepo: \"BurntSushi/ripgrep\",\n\t\tbinaryName: \"rg\",\n\t\ttagPrefix: \"\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tif (architecture === \"arm64\") {\n\t\t\t\t\treturn `ripgrep-${version}-aarch64-unknown-linux-gnu.tar.gz`;\n\t\t\t\t}\n\t\t\t\treturn `ripgrep-${version}-x86_64-unknown-linux-musl.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n};\n\n// Check if a command exists in PATH by trying to run it\nfunction commandExists(cmd: string): boolean {\n\ttry {\n\t\tconst result = spawnSync(cmd, [\"--version\"], { stdio: \"pipe\" });\n\t\t// Check for ENOENT error (command not found)\n\t\treturn result.error === undefined || result.error === null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Get the path to a tool (system-wide or in our tools dir)\nexport function getToolPath(tool: ManagedToolName): string | null {\n\tconst config = TOOLS[tool];\n\tif (!config) return null;\n\n\t// Check our tools directory first\n\tconst localPath = join(TOOLS_DIR, config.binaryName + (platform() === \"win32\" ? \".exe\" : \"\"));\n\tif (existsSync(localPath)) {\n\t\treturn localPath;\n\t}\n\n\t// Check system PATH - if found, just return the command name (it's in PATH)\n\tconst systemBinaryNames = config.systemBinaryNames ?? [config.binaryName];\n\tfor (const systemBinaryName of systemBinaryNames) {\n\t\tif (commandExists(systemBinaryName)) {\n\t\t\treturn systemBinaryName;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Fetch latest release version from GitHub\nasync function getLatestVersion(repo: string): Promise<string> {\n\tconst response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {\n\t\theaders: { \"User-Agent\": `${APP_NAME}-coding-agent` },\n\t\tsignal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`GitHub API error: ${response.status}`);\n\t}\n\n\tconst data = (await response.json()) as { tag_name: string };\n\treturn data.tag_name.replace(/^v/, \"\");\n}\n\n// Download a file from URL\nasync function downloadFile(url: string, dest: string): Promise<void> {\n\tconst response = await fetch(url, {\n\t\tsignal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to download: ${response.status}`);\n\t}\n\n\tif (!response.body) {\n\t\tthrow new Error(\"No response body\");\n\t}\n\n\tconst fileStream = createWriteStream(dest);\n\tawait pipeline(Readable.fromWeb(response.body as any), fileStream);\n}\n\n// grip-ignore noExcessiveCollectionIterations: Each discovered directory is visited once, so traversal is linear in archive entries.\nfunction findBinaryRecursively(rootDir: string, binaryFileName: string): string | null {\n\tconst stack: string[] = [rootDir];\n\n\twhile (stack.length > 0) {\n\t\tconst currentDir = stack.pop();\n\t\tif (!currentDir) continue;\n\n\t\tconst entries = readdirSync(currentDir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(currentDir, entry.name);\n\t\t\tif (entry.isFile() && entry.name === binaryFileName) {\n\t\t\t\treturn fullPath;\n\t\t\t}\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tstack.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction formatSpawnFailure(result: SpawnSyncReturns<Buffer>): string {\n\tif (result.error?.message) {\n\t\treturn result.error.message;\n\t}\n\tconst stderr = result.stderr?.toString().trim();\n\tif (stderr) {\n\t\treturn stderr;\n\t}\n\tconst stdout = result.stdout?.toString().trim();\n\tif (stdout) {\n\t\treturn stdout;\n\t}\n\treturn `exit status ${result.status ?? \"unknown\"}`;\n}\n\nfunction runExtractionCommand(command: string, args: string[]): string | null {\n\tconst result = spawnSync(command, args, { stdio: \"pipe\" });\n\tif (!result.error && result.status === 0) {\n\t\treturn null;\n\t}\n\treturn `${command}: ${formatSpawnFailure(result)}`;\n}\n\nfunction extractTarGzArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failure = runExtractionCommand(\"tar\", [\"xzf\", archivePath, \"-C\", extractDir]);\n\tif (failure) {\n\t\tthrow new Error(`Failed to extract ${assetName}: ${failure}`);\n\t}\n}\n\nfunction getWindowsTarCommand(): string {\n\tconst systemRoot = process.env.SystemRoot ?? process.env.WINDIR;\n\tif (systemRoot) {\n\t\tconst systemTar = join(systemRoot, \"System32\", \"tar.exe\");\n\t\tif (existsSync(systemTar)) {\n\t\t\treturn systemTar;\n\t\t}\n\t}\n\treturn \"tar.exe\";\n}\n\nfunction extractZipArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failures: string[] = [];\n\n\tif (platform() === \"win32\") {\n\t\t// Windows ships bsdtar as tar.exe, which supports zip files. Prefer the\n\t\t// System32 binary over Git Bash's GNU tar, which does not handle zip archives.\n\t\tconst tarFailure = runExtractionCommand(getWindowsTarCommand(), [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\n\t\tconst script =\n\t\t\t\"& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }\";\n\t\tconst powershellFailure = runExtractionCommand(\"powershell.exe\", [\n\t\t\t\"-NoLogo\",\n\t\t\t\"-NoProfile\",\n\t\t\t\"-NonInteractive\",\n\t\t\t\"-ExecutionPolicy\",\n\t\t\t\"Bypass\",\n\t\t\t\"-Command\",\n\t\t\tscript,\n\t\t\tarchivePath,\n\t\t\textractDir,\n\t\t]);\n\t\tif (!powershellFailure) return;\n\t\tfailures.push(powershellFailure);\n\t} else {\n\t\tconst unzipFailure = runExtractionCommand(\"unzip\", [\"-q\", archivePath, \"-d\", extractDir]);\n\t\tif (!unzipFailure) return;\n\t\tfailures.push(unzipFailure);\n\n\t\tconst tarFailure = runExtractionCommand(\"tar\", [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\t}\n\n\tthrow new Error(`Failed to extract ${assetName}: ${failures.join(\"; \")}`);\n}\n\n// Download and install a tool\nasync function downloadTool(tool: ManagedToolName): Promise<string> {\n\tconst config = TOOLS[tool];\n\tif (!config) throw new Error(`Unknown tool: ${tool}`);\n\n\tconst plat = platform();\n\tconst architecture = arch();\n\n\t// Get latest version\n\tlet version = await getLatestVersion(config.repo);\n\tif (tool === \"fd\" && plat === \"darwin\" && architecture === \"x64\") {\n\t\tversion = \"10.3.0\";\n\t}\n\n\t// Get asset name for this platform\n\tconst assetName = config.getAssetName(version, plat, architecture);\n\tif (!assetName) {\n\t\tthrow new Error(`Unsupported platform: ${plat}/${architecture}`);\n\t}\n\n\t// Create tools directory\n\tmkdirSync(TOOLS_DIR, { recursive: true });\n\n\tconst downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;\n\tconst archivePath = join(TOOLS_DIR, assetName);\n\tconst binaryExt = plat === \"win32\" ? \".exe\" : \"\";\n\tconst binaryPath = join(TOOLS_DIR, config.binaryName + binaryExt);\n\n\t// Download\n\tawait downloadFile(downloadUrl, archivePath);\n\n\t// Extract into a unique temp directory. fd and rg downloads can run concurrently\n\t// during startup, so sharing a fixed directory causes races.\n\tconst extractDir = join(\n\t\tTOOLS_DIR,\n\t\t`extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,\n\t);\n\tmkdirSync(extractDir, { recursive: true });\n\n\ttry {\n\t\tif (assetName.endsWith(\".tar.gz\")) {\n\t\t\textractTarGzArchive(archivePath, extractDir, assetName);\n\t\t} else if (assetName.endsWith(\".zip\")) {\n\t\t\textractZipArchive(archivePath, extractDir, assetName);\n\t\t} else {\n\t\t\tthrow new Error(`Unsupported archive format: ${assetName}`);\n\t\t}\n\n\t\t// Find the binary in extracted files. Some archives contain files directly\n\t\t// at root, others nest under a versioned subdirectory.\n\t\tconst binaryFileName = config.binaryName + binaryExt;\n\t\tconst extractedDir = join(extractDir, assetName.replace(/\\.(tar\\.gz|zip)$/, \"\"));\n\t\tconst extractedBinaryCandidates = [join(extractedDir, binaryFileName), join(extractDir, binaryFileName)];\n\t\tlet extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync(candidate));\n\n\t\tif (!extractedBinary) {\n\t\t\textractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? undefined;\n\t\t}\n\n\t\tif (extractedBinary) {\n\t\t\trenameSync(extractedBinary, binaryPath);\n\t\t} else {\n\t\t\tthrow new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);\n\t\t}\n\n\t\t// Make executable (Unix only)\n\t\tif (plat !== \"win32\") {\n\t\t\tchmodSync(binaryPath, 0o755);\n\t\t}\n\t} finally {\n\t\t// Cleanup\n\t\trmSync(archivePath, { force: true });\n\t\trmSync(extractDir, { recursive: true, force: true });\n\t}\n\n\treturn binaryPath;\n}\n\n// Termux package names for tools\nconst TERMUX_PACKAGES: Record<string, string> = {\n\tfd: \"fd\",\n\trg: \"ripgrep\",\n};\nfunction getToolUnavailableMessage(tool: ManagedToolName, config: ToolConfig): string | null {\n\tif (isOfflineModeEnabled()) {\n\t\treturn `${config.name} not found. Offline mode enabled, skipping download.`;\n\t}\n\tif (platform() !== \"android\") return null;\n\tconst pkgName = TERMUX_PACKAGES[tool] ?? tool;\n\treturn `${config.name} not found. Install with: pkg install ${pkgName}`;\n}\n\n// Ensure a tool is available, downloading if necessary\n// Returns the path to the tool, or null if unavailable\nexport async function ensureTool(tool: ManagedToolName, silent: boolean = false): Promise<string | undefined> {\n\tconst existingPath = getToolPath(tool);\n\tif (existingPath) {\n\t\treturn existingPath;\n\t}\n\n\tconst config = TOOLS[tool];\n\tif (!config) return undefined;\n\n\tconst unavailableMessage = getToolUnavailableMessage(tool, config);\n\tif (unavailableMessage) {\n\t\tif (!silent) console.log(chalk.yellow(unavailableMessage));\n\t\treturn undefined;\n\t}\n\n\t// Tool not found - download it\n\tif (!silent) {\n\t\tconsole.log(chalk.dim(`${config.name} not found. Downloading...`));\n\t}\n\n\ttry {\n\t\tconst path = await downloadTool(tool);\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.dim(`${config.name} installed to ${path}`));\n\t\t}\n\t\treturn path;\n\t} catch (e) {\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.yellow(`Failed to download ${config.name}: ${e instanceof Error ? e.message : e}`));\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"tools-manager.d.ts","sourceRoot":"","sources":["../../src/utils/tools-manager.ts"],"names":[],"mappings":"AAaA,KAAK,eAAe,GAAG,IAAI,GAAG,IAAI,CAAC;AAyEnC,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,GAAG,IAAI,CAmBhE;AAuOD,wBAAsB,UAAU,CAAC,IAAI,EAAE,eAAe,EAAE,MAAM,GAAE,OAAe,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAgC5G"}
@@ -1 +1 @@
1
- {"version":3,"file":"tools-manager.js","sourceRoot":"","sources":["../../src/utils/tools-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from \"chalk\";\nimport { type SpawnSyncReturns, spawnSync } from \"child_process\";\nimport { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from \"fs\";\nimport { arch, platform } from \"os\";\nimport { join } from \"path\";\nimport { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { APP_NAME, getBinDir } from \"../config.ts\";\n\nconst TOOLS_DIR = getBinDir();\nconst NETWORK_TIMEOUT_MS = 10_000;\nconst DOWNLOAD_TIMEOUT_MS = 120_000;\n\ntype ManagedToolName = \"fd\" | \"rg\";\n\nfunction isOfflineModeEnabled(): boolean {\n\tconst value = process.env.GRIP_OFFLINE;\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\ninterface ToolConfig {\n\tname: string;\n\trepo: string; // GitHub repo (e.g., \"sharkdp/fd\")\n\tbinaryName: string; // Name of the binary inside the archive\n\tsystemBinaryNames?: string[]; // Alternative system command names to try before downloading\n\ttagPrefix: string; // Prefix for tags (e.g., \"v\" for v1.0.0, \"\" for 1.0.0)\n\tgetAssetName: (version: string, plat: string, architecture: string) => string | null;\n}\n\nconst TOOLS: Record<string, ToolConfig> = {\n\tfd: {\n\t\tname: \"fd\",\n\t\trepo: \"sharkdp/fd\",\n\t\tbinaryName: \"fd\",\n\t\tsystemBinaryNames: [\"fd\", \"fdfind\"],\n\t\ttagPrefix: \"v\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-unknown-linux-gnu.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n\trg: {\n\t\tname: \"ripgrep\",\n\t\trepo: \"BurntSushi/ripgrep\",\n\t\tbinaryName: \"rg\",\n\t\ttagPrefix: \"\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tif (architecture === \"arm64\") {\n\t\t\t\t\treturn `ripgrep-${version}-aarch64-unknown-linux-gnu.tar.gz`;\n\t\t\t\t}\n\t\t\t\treturn `ripgrep-${version}-x86_64-unknown-linux-musl.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n};\n\n// Check if a command exists in PATH by trying to run it\nfunction commandExists(cmd: string): boolean {\n\ttry {\n\t\tconst result = spawnSync(cmd, [\"--version\"], { stdio: \"pipe\" });\n\t\t// Check for ENOENT error (command not found)\n\t\treturn result.error === undefined || result.error === null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Get the path to a tool (system-wide or in our tools dir)\nexport function getToolPath(tool: ManagedToolName): string | null {\n\tconst config = TOOLS[tool];\n\tif (!config) return null;\n\n\t// Check our tools directory first\n\tconst localPath = join(TOOLS_DIR, config.binaryName + (platform() === \"win32\" ? \".exe\" : \"\"));\n\tif (existsSync(localPath)) {\n\t\treturn localPath;\n\t}\n\n\t// Check system PATH - if found, just return the command name (it's in PATH)\n\tconst systemBinaryNames = config.systemBinaryNames ?? [config.binaryName];\n\tfor (const systemBinaryName of systemBinaryNames) {\n\t\tif (commandExists(systemBinaryName)) {\n\t\t\treturn systemBinaryName;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Fetch latest release version from GitHub\nasync function getLatestVersion(repo: string): Promise<string> {\n\tconst response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {\n\t\theaders: { \"User-Agent\": `${APP_NAME}-coding-agent` },\n\t\tsignal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`GitHub API error: ${response.status}`);\n\t}\n\n\tconst data = (await response.json()) as { tag_name: string };\n\treturn data.tag_name.replace(/^v/, \"\");\n}\n\n// Download a file from URL\nasync function downloadFile(url: string, dest: string): Promise<void> {\n\tconst response = await fetch(url, {\n\t\tsignal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to download: ${response.status}`);\n\t}\n\n\tif (!response.body) {\n\t\tthrow new Error(\"No response body\");\n\t}\n\n\tconst fileStream = createWriteStream(dest);\n\tawait pipeline(Readable.fromWeb(response.body as any), fileStream);\n}\n\n// grip-ignore noExcessiveCollectionIterations: Each discovered directory is visited once, so traversal is linear in archive entries.\nfunction findBinaryRecursively(rootDir: string, binaryFileName: string): string | null {\n\tconst stack: string[] = [rootDir];\n\n\twhile (stack.length > 0) {\n\t\tconst currentDir = stack.pop();\n\t\tif (!currentDir) continue;\n\n\t\tconst entries = readdirSync(currentDir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(currentDir, entry.name);\n\t\t\tif (entry.isFile() && entry.name === binaryFileName) {\n\t\t\t\treturn fullPath;\n\t\t\t}\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tstack.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction formatSpawnFailure(result: SpawnSyncReturns<Buffer>): string {\n\tif (result.error?.message) {\n\t\treturn result.error.message;\n\t}\n\tconst stderr = result.stderr?.toString().trim();\n\tif (stderr) {\n\t\treturn stderr;\n\t}\n\tconst stdout = result.stdout?.toString().trim();\n\tif (stdout) {\n\t\treturn stdout;\n\t}\n\treturn `exit status ${result.status ?? \"unknown\"}`;\n}\n\nfunction runExtractionCommand(command: string, args: string[]): string | null {\n\tconst result = spawnSync(command, args, { stdio: \"pipe\" });\n\tif (!result.error && result.status === 0) {\n\t\treturn null;\n\t}\n\treturn `${command}: ${formatSpawnFailure(result)}`;\n}\n\nfunction extractTarGzArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failure = runExtractionCommand(\"tar\", [\"xzf\", archivePath, \"-C\", extractDir]);\n\tif (failure) {\n\t\tthrow new Error(`Failed to extract ${assetName}: ${failure}`);\n\t}\n}\n\nfunction getWindowsTarCommand(): string {\n\tconst systemRoot = process.env.SystemRoot ?? process.env.WINDIR;\n\tif (systemRoot) {\n\t\tconst systemTar = join(systemRoot, \"System32\", \"tar.exe\");\n\t\tif (existsSync(systemTar)) {\n\t\t\treturn systemTar;\n\t\t}\n\t}\n\treturn \"tar.exe\";\n}\n\nfunction extractZipArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failures: string[] = [];\n\n\tif (platform() === \"win32\") {\n\t\t// Windows ships bsdtar as tar.exe, which supports zip files. Prefer the\n\t\t// System32 binary over Git Bash's GNU tar, which does not handle zip archives.\n\t\tconst tarFailure = runExtractionCommand(getWindowsTarCommand(), [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\n\t\tconst script =\n\t\t\t\"& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }\";\n\t\tconst powershellFailure = runExtractionCommand(\"powershell.exe\", [\n\t\t\t\"-NoLogo\",\n\t\t\t\"-NoProfile\",\n\t\t\t\"-NonInteractive\",\n\t\t\t\"-ExecutionPolicy\",\n\t\t\t\"Bypass\",\n\t\t\t\"-Command\",\n\t\t\tscript,\n\t\t\tarchivePath,\n\t\t\textractDir,\n\t\t]);\n\t\tif (!powershellFailure) return;\n\t\tfailures.push(powershellFailure);\n\t} else {\n\t\tconst unzipFailure = runExtractionCommand(\"unzip\", [\"-q\", archivePath, \"-d\", extractDir]);\n\t\tif (!unzipFailure) return;\n\t\tfailures.push(unzipFailure);\n\n\t\tconst tarFailure = runExtractionCommand(\"tar\", [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\t}\n\n\tthrow new Error(`Failed to extract ${assetName}: ${failures.join(\"; \")}`);\n}\n\n// Download and install a tool\nasync function downloadTool(tool: ManagedToolName): Promise<string> {\n\tconst config = TOOLS[tool];\n\tif (!config) throw new Error(`Unknown tool: ${tool}`);\n\n\tconst plat = platform();\n\tconst architecture = arch();\n\n\t// Get latest version\n\tlet version = await getLatestVersion(config.repo);\n\tif (tool === \"fd\" && plat === \"darwin\" && architecture === \"x64\") {\n\t\tversion = \"10.3.0\";\n\t}\n\n\t// Get asset name for this platform\n\tconst assetName = config.getAssetName(version, plat, architecture);\n\tif (!assetName) {\n\t\tthrow new Error(`Unsupported platform: ${plat}/${architecture}`);\n\t}\n\n\t// Create tools directory\n\tmkdirSync(TOOLS_DIR, { recursive: true });\n\n\tconst downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;\n\tconst archivePath = join(TOOLS_DIR, assetName);\n\tconst binaryExt = plat === \"win32\" ? \".exe\" : \"\";\n\tconst binaryPath = join(TOOLS_DIR, config.binaryName + binaryExt);\n\n\t// Download\n\tawait downloadFile(downloadUrl, archivePath);\n\n\t// Extract into a unique temp directory. fd and rg downloads can run concurrently\n\t// during startup, so sharing a fixed directory causes races.\n\tconst extractDir = join(\n\t\tTOOLS_DIR,\n\t\t`extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,\n\t);\n\tmkdirSync(extractDir, { recursive: true });\n\n\ttry {\n\t\tif (assetName.endsWith(\".tar.gz\")) {\n\t\t\textractTarGzArchive(archivePath, extractDir, assetName);\n\t\t} else if (assetName.endsWith(\".zip\")) {\n\t\t\textractZipArchive(archivePath, extractDir, assetName);\n\t\t} else {\n\t\t\tthrow new Error(`Unsupported archive format: ${assetName}`);\n\t\t}\n\n\t\t// Find the binary in extracted files. Some archives contain files directly\n\t\t// at root, others nest under a versioned subdirectory.\n\t\tconst binaryFileName = config.binaryName + binaryExt;\n\t\tconst extractedDir = join(extractDir, assetName.replace(/\\.(tar\\.gz|zip)$/, \"\"));\n\t\tconst extractedBinaryCandidates = [join(extractedDir, binaryFileName), join(extractDir, binaryFileName)];\n\t\tlet extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync(candidate));\n\n\t\tif (!extractedBinary) {\n\t\t\textractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? undefined;\n\t\t}\n\n\t\tif (extractedBinary) {\n\t\t\trenameSync(extractedBinary, binaryPath);\n\t\t} else {\n\t\t\tthrow new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);\n\t\t}\n\n\t\t// Make executable (Unix only)\n\t\tif (plat !== \"win32\") {\n\t\t\tchmodSync(binaryPath, 0o755);\n\t\t}\n\t} finally {\n\t\t// Cleanup\n\t\trmSync(archivePath, { force: true });\n\t\trmSync(extractDir, { recursive: true, force: true });\n\t}\n\n\treturn binaryPath;\n}\n\n// Termux package names for tools\nconst TERMUX_PACKAGES: Record<string, string> = {\n\tfd: \"fd\",\n\trg: \"ripgrep\",\n};\nfunction getToolUnavailableMessage(tool: ManagedToolName, config: ToolConfig): string | null {\n\tif (isOfflineModeEnabled()) {\n\t\treturn `${config.name} not found. Offline mode enabled, skipping download.`;\n\t}\n\tif (platform() !== \"android\") return null;\n\tconst pkgName = TERMUX_PACKAGES[tool] ?? tool;\n\treturn `${config.name} not found. Install with: pkg install ${pkgName}`;\n}\n\n// Ensure a tool is available, downloading if necessary\n// Returns the path to the tool, or null if unavailable\nexport async function ensureTool(tool: ManagedToolName, silent: boolean = false): Promise<string | undefined> {\n\tconst existingPath = getToolPath(tool);\n\tif (existingPath) {\n\t\treturn existingPath;\n\t}\n\n\tconst config = TOOLS[tool];\n\tif (!config) return undefined;\n\n\tconst unavailableMessage = getToolUnavailableMessage(tool, config);\n\tif (unavailableMessage) {\n\t\tif (!silent) console.log(chalk.yellow(unavailableMessage));\n\t\treturn undefined;\n\t}\n\n\t// Tool not found - download it\n\tif (!silent) {\n\t\tconsole.log(chalk.dim(`${config.name} not found. Downloading...`));\n\t}\n\n\ttry {\n\t\tconst path = await downloadTool(tool);\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.dim(`${config.name} installed to ${path}`));\n\t\t}\n\t\treturn path;\n\t} catch (e) {\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.yellow(`Failed to download ${config.name}: ${e instanceof Error ? e.message : e}`));\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"tools-manager.js","sourceRoot":"","sources":["../../src/utils/tools-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from \"chalk\";\nimport { type SpawnSyncReturns, spawnSync } from \"child_process\";\nimport { chmodSync, createWriteStream, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from \"fs\";\nimport { arch, platform } from \"os\";\nimport { join } from \"path\";\nimport { Readable } from \"stream\";\nimport { pipeline } from \"stream/promises\";\nimport { APP_NAME, getBinDir } from \"../config.ts\";\n\nconst TOOLS_DIR = getBinDir();\nconst NETWORK_TIMEOUT_MS = 10_000;\nconst DOWNLOAD_TIMEOUT_MS = 120_000;\n\ntype ManagedToolName = \"fd\" | \"rg\";\n\nfunction isOfflineModeEnabled(): boolean {\n\tconst value = process.env.GRIP_OFFLINE;\n\tif (!value) return false;\n\treturn value === \"1\" || value.toLowerCase() === \"true\" || value.toLowerCase() === \"yes\";\n}\n\ninterface ToolConfig {\n\tname: string;\n\trepo: string; // GitHub repo (e.g., \"sharkdp/fd\")\n\tbinaryName: string; // Name of the binary inside the archive\n\tsystemBinaryNames?: string[]; // Alternative system command names to try before downloading\n\ttagPrefix: string; // Prefix for tags (e.g., \"v\" for v1.0.0, \"\" for 1.0.0)\n\tgetAssetName: (version: string, plat: string, architecture: string) => string | null;\n}\n\nconst TOOLS: Record<string, ToolConfig> = {\n\tfd: {\n\t\tname: \"fd\",\n\t\trepo: \"sharkdp/fd\",\n\t\tbinaryName: \"fd\",\n\t\tsystemBinaryNames: [\"fd\", \"fdfind\"],\n\t\ttagPrefix: \"v\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-unknown-linux-gnu.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `fd-v${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n\trg: {\n\t\tname: \"ripgrep\",\n\t\trepo: \"BurntSushi/ripgrep\",\n\t\tbinaryName: \"rg\",\n\t\ttagPrefix: \"\",\n\t\tgetAssetName: (version, plat, architecture) => {\n\t\t\tif (plat === \"darwin\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-apple-darwin.tar.gz`;\n\t\t\t} else if (plat === \"linux\") {\n\t\t\t\tif (architecture === \"arm64\") {\n\t\t\t\t\treturn `ripgrep-${version}-aarch64-unknown-linux-gnu.tar.gz`;\n\t\t\t\t}\n\t\t\t\treturn `ripgrep-${version}-x86_64-unknown-linux-musl.tar.gz`;\n\t\t\t} else if (plat === \"win32\") {\n\t\t\t\tconst archStr = architecture === \"arm64\" ? \"aarch64\" : \"x86_64\";\n\t\t\t\treturn `ripgrep-${version}-${archStr}-pc-windows-msvc.zip`;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t},\n};\n\n// Check if a command exists in PATH by trying to run it\nfunction commandExists(cmd: string): boolean {\n\ttry {\n\t\tconst result = spawnSync(cmd, [\"--version\"], { stdio: \"pipe\" });\n\t\t// Check for ENOENT error (command not found)\n\t\treturn result.error === undefined || result.error === null;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n// Get the path to a tool (system-wide or in our tools dir)\nexport function getToolPath(tool: ManagedToolName): string | null {\n\tconst config = TOOLS[tool];\n\tif (!config) return null;\n\n\t// Check our tools directory first\n\tconst localPath = join(TOOLS_DIR, config.binaryName + (platform() === \"win32\" ? \".exe\" : \"\"));\n\tif (existsSync(localPath)) {\n\t\treturn localPath;\n\t}\n\n\t// Check system PATH - if found, just return the command name (it's in PATH)\n\tconst systemBinaryNames = config.systemBinaryNames ?? [config.binaryName];\n\tfor (const systemBinaryName of systemBinaryNames) {\n\t\tif (commandExists(systemBinaryName)) {\n\t\t\treturn systemBinaryName;\n\t\t}\n\t}\n\n\treturn null;\n}\n\n// Fetch latest release version from GitHub\nasync function getLatestVersion(repo: string): Promise<string> {\n\tconst response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {\n\t\theaders: { \"User-Agent\": `${APP_NAME}-coding-agent` },\n\t\tsignal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`GitHub API error: ${response.status}`);\n\t}\n\n\tconst data = (await response.json()) as { tag_name: string };\n\treturn data.tag_name.replace(/^v/, \"\");\n}\n\n// Download a file from URL\nasync function downloadFile(url: string, dest: string): Promise<void> {\n\tconst response = await fetch(url, {\n\t\tsignal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),\n\t});\n\n\tif (!response.ok) {\n\t\tthrow new Error(`Failed to download: ${response.status}`);\n\t}\n\n\tif (!response.body) {\n\t\tthrow new Error(\"No response body\");\n\t}\n\n\tconst fileStream = createWriteStream(dest);\n\tawait pipeline(Readable.fromWeb(response.body as any), fileStream);\n}\n\n// grip-ignore noExcessiveCollectionIterations: Each discovered directory is visited once, so traversal is linear in archive entries.\nfunction findBinaryRecursively(rootDir: string, binaryFileName: string): string | null {\n\tconst stack: string[] = [rootDir];\n\n\twhile (stack.length > 0) {\n\t\tconst currentDir = stack.pop();\n\t\tif (!currentDir) continue;\n\n\t\tconst entries = readdirSync(currentDir, { withFileTypes: true });\n\t\tfor (const entry of entries) {\n\t\t\tconst fullPath = join(currentDir, entry.name);\n\t\t\tif (entry.isFile() && entry.name === binaryFileName) {\n\t\t\t\treturn fullPath;\n\t\t\t}\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tstack.push(fullPath);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn null;\n}\n\nfunction formatSpawnFailure(result: SpawnSyncReturns<Buffer>): string {\n\tif (result.error?.message) {\n\t\treturn result.error.message;\n\t}\n\tconst stderr = result.stderr?.toString().trim();\n\tif (stderr) {\n\t\treturn stderr;\n\t}\n\tconst stdout = result.stdout?.toString().trim();\n\tif (stdout) {\n\t\treturn stdout;\n\t}\n\treturn `exit status ${result.status ?? \"unknown\"}`;\n}\n\nfunction runExtractionCommand(command: string, args: string[]): string | null {\n\tconst result = spawnSync(command, args, { stdio: \"pipe\" });\n\tif (!result.error && result.status === 0) {\n\t\treturn null;\n\t}\n\treturn `${command}: ${formatSpawnFailure(result)}`;\n}\n\nfunction extractTarGzArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failure = runExtractionCommand(\"tar\", [\"xzf\", archivePath, \"-C\", extractDir]);\n\tif (failure) {\n\t\tthrow new Error(`Failed to extract ${assetName}: ${failure}`);\n\t}\n}\n\nfunction getWindowsTarCommand(): string {\n\tconst systemRoot = process.env.SystemRoot ?? process.env.WINDIR;\n\tif (systemRoot) {\n\t\tconst systemTar = join(systemRoot, \"System32\", \"tar.exe\");\n\t\tif (existsSync(systemTar)) {\n\t\t\treturn systemTar;\n\t\t}\n\t}\n\treturn \"tar.exe\";\n}\n\nfunction extractZipArchive(archivePath: string, extractDir: string, assetName: string): void {\n\tconst failures: string[] = [];\n\n\tif (platform() === \"win32\") {\n\t\t// Windows ships bsdtar as tar.exe, which supports zip files. Prefer the\n\t\t// System32 binary over Git Bash's GNU tar, which does not handle zip archives.\n\t\tconst tarFailure = runExtractionCommand(getWindowsTarCommand(), [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\n\t\tconst script =\n\t\t\t\"& { param($archive, $destination) $ErrorActionPreference = 'Stop'; Expand-Archive -LiteralPath $archive -DestinationPath $destination -Force }\";\n\t\tconst powershellFailure = runExtractionCommand(\"powershell.exe\", [\n\t\t\t\"-NoLogo\",\n\t\t\t\"-NoProfile\",\n\t\t\t\"-NonInteractive\",\n\t\t\t\"-ExecutionPolicy\",\n\t\t\t\"Bypass\",\n\t\t\t\"-Command\",\n\t\t\tscript,\n\t\t\tarchivePath,\n\t\t\textractDir,\n\t\t]);\n\t\tif (!powershellFailure) return;\n\t\tfailures.push(powershellFailure);\n\t} else {\n\t\tconst unzipFailure = runExtractionCommand(\"unzip\", [\"-q\", archivePath, \"-d\", extractDir]);\n\t\tif (!unzipFailure) return;\n\t\tfailures.push(unzipFailure);\n\n\t\tconst tarFailure = runExtractionCommand(\"tar\", [\"xf\", archivePath, \"-C\", extractDir]);\n\t\tif (!tarFailure) return;\n\t\tfailures.push(tarFailure);\n\t}\n\n\tthrow new Error(`Failed to extract ${assetName}: ${failures.join(\"; \")}`);\n}\n\n// Download and install a tool\nasync function downloadTool(tool: ManagedToolName): Promise<string> {\n\tconst config = TOOLS[tool];\n\tif (!config) throw new Error(`Unknown tool: ${tool}`);\n\n\tconst plat = platform();\n\tconst architecture = arch();\n\n\t// Get latest version\n\tlet version = await getLatestVersion(config.repo);\n\tif (tool === \"fd\" && plat === \"darwin\" && architecture === \"x64\") {\n\t\tversion = \"10.3.0\";\n\t}\n\n\t// Get asset name for this platform\n\tconst assetName = config.getAssetName(version, plat, architecture);\n\tif (!assetName) {\n\t\tthrow new Error(`Unsupported platform: ${plat}/${architecture}`);\n\t}\n\n\t// Create tools directory\n\tmkdirSync(TOOLS_DIR, { recursive: true });\n\n\tconst downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;\n\tconst archivePath = join(TOOLS_DIR, assetName);\n\tconst binaryExt = plat === \"win32\" ? \".exe\" : \"\";\n\tconst binaryPath = join(TOOLS_DIR, config.binaryName + binaryExt);\n\n\t// Download\n\tawait downloadFile(downloadUrl, archivePath);\n\n\t// Extract into a unique temp directory. fd and rg downloads can run concurrently\n\t// during startup, so sharing a fixed directory causes races.\n\tconst extractDir = join(\n\t\tTOOLS_DIR,\n\t\t`extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,\n\t);\n\tmkdirSync(extractDir, { recursive: true });\n\n\ttry {\n\t\tif (assetName.endsWith(\".tar.gz\")) {\n\t\t\textractTarGzArchive(archivePath, extractDir, assetName);\n\t\t} else if (assetName.endsWith(\".zip\")) {\n\t\t\textractZipArchive(archivePath, extractDir, assetName);\n\t\t} else {\n\t\t\tthrow new Error(`Unsupported archive format: ${assetName}`);\n\t\t}\n\n\t\t// Find the binary in extracted files. Some archives contain files directly\n\t\t// at root, others nest under a versioned subdirectory.\n\t\tconst binaryFileName = config.binaryName + binaryExt;\n\t\tconst extractedDir = join(extractDir, assetName.replace(/\\.(tar\\.gz|zip)$/, \"\"));\n\t\tconst extractedBinaryCandidates = [join(extractedDir, binaryFileName), join(extractDir, binaryFileName)];\n\t\tlet extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync(candidate));\n\n\t\tif (!extractedBinary) {\n\t\t\textractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? undefined;\n\t\t}\n\n\t\tif (extractedBinary) {\n\t\t\trenameSync(extractedBinary, binaryPath);\n\t\t} else {\n\t\t\tthrow new Error(`Binary not found in archive: expected ${binaryFileName} under ${extractDir}`);\n\t\t}\n\n\t\t// Make executable (Unix only)\n\t\tif (plat !== \"win32\") {\n\t\t\tchmodSync(binaryPath, 0o755);\n\t\t}\n\t} finally {\n\t\t// Cleanup\n\t\trmSync(archivePath, { force: true });\n\t\trmSync(extractDir, { recursive: true, force: true });\n\t}\n\n\treturn binaryPath;\n}\n\n// Termux package names for tools\nconst TERMUX_PACKAGES: Record<string, string> = {\n\tfd: \"fd\",\n\trg: \"ripgrep\",\n};\nfunction getToolUnavailableMessage(tool: ManagedToolName, config: ToolConfig): string | null {\n\tif (isOfflineModeEnabled()) {\n\t\treturn `${config.name} not found. Offline mode enabled, skipping download.`;\n\t}\n\tif (platform() !== \"android\") return null;\n\tconst pkgName = TERMUX_PACKAGES[tool] ?? tool;\n\treturn `${config.name} not found. Install with: pkg install ${pkgName}`;\n}\n\n// Ensure a tool is available, downloading if necessary\n// Returns the path to the tool, or null if unavailable\nexport async function ensureTool(tool: ManagedToolName, silent: boolean = false): Promise<string | undefined> {\n\tconst existingPath = getToolPath(tool);\n\tif (existingPath) {\n\t\treturn existingPath;\n\t}\n\n\tconst config = TOOLS[tool];\n\tif (!config) return undefined;\n\n\tconst unavailableMessage = getToolUnavailableMessage(tool, config);\n\tif (unavailableMessage) {\n\t\tif (!silent) console.log(chalk.yellow(unavailableMessage));\n\t\treturn undefined;\n\t}\n\n\t// Tool not found - download it\n\tif (!silent) {\n\t\tconsole.log(chalk.dim(`${config.name} not found. Downloading...`));\n\t}\n\n\ttry {\n\t\tconst path = await downloadTool(tool);\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.dim(`${config.name} installed to ${path}`));\n\t\t}\n\t\treturn path;\n\t} catch (e) {\n\t\tif (!silent) {\n\t\t\tconsole.log(chalk.yellow(`Failed to download ${config.name}: ${e instanceof Error ? e.message : e}`));\n\t\t}\n\t\treturn undefined;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,uBAAuB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAoCD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAED,wBAAsB,oBAAoB,CACzC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CA4BxC;AAED,wBAAsB,oBAAoB,CACzC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAU3G","sourcesContent":["import { PACKAGE_NAME } from \"../config.ts\";\nimport { getGripUserAgent } from \"./grip-user-agent.ts\";\n\nconst LATEST_VERSION_URL = `https://registry.npmjs.org/${PACKAGE_NAME.replace(\"/\", \"%2f\")}`;\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestGripRelease {\n\tversion: string;\n\tnote?: string;\n}\n\ninterface GripVersionCheckOptions {\n\ttimeoutMs?: number;\n}\ninterface NpmRegistryDistributionTags {\n\tlatest?: unknown;\n}\n\ninterface NpmRegistryPackageMetadata {\n\t\"dist-tags\"?: NpmRegistryDistributionTags;\n\tnote?: unknown;\n\tversion?: unknown;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n\tif (value === undefined) return false;\n\treturn [\"1\", \"true\", \"yes\", \"on\"].includes(value.trim().toLowerCase());\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn left.prerelease.localeCompare(right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestGripRelease(\n\tcurrentVersion: string,\n\toptions: GripVersionCheckOptions = {},\n): Promise<LatestGripRelease | undefined> {\n\tif (isTruthyEnvFlag(process.env.GRIP_SKIP_VERSION_CHECK) || isTruthyEnvFlag(process.env.GRIP_OFFLINE))\n\t\treturn undefined;\n\n\tconst response = await fetch(LATEST_VERSION_URL, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getGripUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as NpmRegistryPackageMetadata;\n\tconst version =\n\t\ttypeof data[\"dist-tags\"]?.latest === \"string\" && data[\"dist-tags\"].latest.trim()\n\t\t\t? data[\"dist-tags\"].latest.trim()\n\t\t\t: typeof data.version === \"string\" && data.version.trim()\n\t\t\t\t? data.version.trim()\n\t\t\t\t: undefined;\n\tif (!version) {\n\t\treturn undefined;\n\t}\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestGripVersion(\n\tcurrentVersion: string,\n\toptions: GripVersionCheckOptions = {},\n): Promise<string | undefined> {\n\treturn (await getLatestGripRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewGripVersion(currentVersion: string): Promise<LatestGripRelease | undefined> {\n\ttry {\n\t\tconst latestRelease = await getLatestGripRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,iBAAiB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,uBAAuB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAoCD,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAcpG;AAED,wBAAgB,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAM/F;AAED,wBAAsB,oBAAoB,CACzC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CA4BxC;AAED,wBAAsB,oBAAoB,CACzC,cAAc,EAAE,MAAM,EACtB,OAAO,GAAE,uBAA4B,GACnC,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,wBAAsB,sBAAsB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,SAAS,CAAC,CAU3G"}
@@ -1 +1 @@
1
- {"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { PACKAGE_NAME } from \"../config.ts\";\nimport { getGripUserAgent } from \"./grip-user-agent.ts\";\n\nconst LATEST_VERSION_URL = `https://registry.npmjs.org/${PACKAGE_NAME.replace(\"/\", \"%2f\")}`;\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestGripRelease {\n\tversion: string;\n\tnote?: string;\n}\n\ninterface GripVersionCheckOptions {\n\ttimeoutMs?: number;\n}\ninterface NpmRegistryDistributionTags {\n\tlatest?: unknown;\n}\n\ninterface NpmRegistryPackageMetadata {\n\t\"dist-tags\"?: NpmRegistryDistributionTags;\n\tnote?: unknown;\n\tversion?: unknown;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n\tif (value === undefined) return false;\n\treturn [\"1\", \"true\", \"yes\", \"on\"].includes(value.trim().toLowerCase());\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn left.prerelease.localeCompare(right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestGripRelease(\n\tcurrentVersion: string,\n\toptions: GripVersionCheckOptions = {},\n): Promise<LatestGripRelease | undefined> {\n\tif (isTruthyEnvFlag(process.env.GRIP_SKIP_VERSION_CHECK) || isTruthyEnvFlag(process.env.GRIP_OFFLINE))\n\t\treturn undefined;\n\n\tconst response = await fetch(LATEST_VERSION_URL, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getGripUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as NpmRegistryPackageMetadata;\n\tconst version =\n\t\ttypeof data[\"dist-tags\"]?.latest === \"string\" && data[\"dist-tags\"].latest.trim()\n\t\t\t? data[\"dist-tags\"].latest.trim()\n\t\t\t: typeof data.version === \"string\" && data.version.trim()\n\t\t\t\t? data.version.trim()\n\t\t\t\t: undefined;\n\tif (!version) {\n\t\treturn undefined;\n\t}\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestGripVersion(\n\tcurrentVersion: string,\n\toptions: GripVersionCheckOptions = {},\n): Promise<string | undefined> {\n\treturn (await getLatestGripRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewGripVersion(currentVersion: string): Promise<LatestGripRelease | undefined> {\n\ttry {\n\t\tconst latestRelease = await getLatestGripRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/utils/version-check.ts"],"names":[],"mappings":"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","sourcesContent":["import { PACKAGE_NAME } from \"../config.ts\";\nimport { getGripUserAgent } from \"./grip-user-agent.ts\";\n\nconst LATEST_VERSION_URL = `https://registry.npmjs.org/${PACKAGE_NAME.replace(\"/\", \"%2f\")}`;\nconst DEFAULT_VERSION_CHECK_TIMEOUT_MS = 10000;\n\nexport interface LatestGripRelease {\n\tversion: string;\n\tnote?: string;\n}\n\ninterface GripVersionCheckOptions {\n\ttimeoutMs?: number;\n}\ninterface NpmRegistryDistributionTags {\n\tlatest?: unknown;\n}\n\ninterface NpmRegistryPackageMetadata {\n\t\"dist-tags\"?: NpmRegistryDistributionTags;\n\tnote?: unknown;\n\tversion?: unknown;\n}\n\ninterface ParsedVersion {\n\tmajor: number;\n\tminor: number;\n\tpatch: number;\n\tprerelease?: string;\n}\n\nfunction isTruthyEnvFlag(value: string | undefined): boolean {\n\tif (value === undefined) return false;\n\treturn [\"1\", \"true\", \"yes\", \"on\"].includes(value.trim().toLowerCase());\n}\n\nfunction parsePackageVersion(version: string): ParsedVersion | undefined {\n\tconst match = version.trim().match(/^v?(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+.*)?$/);\n\tif (!match) {\n\t\treturn undefined;\n\t}\n\treturn {\n\t\tmajor: Number.parseInt(match[1], 10),\n\t\tminor: Number.parseInt(match[2], 10),\n\t\tpatch: Number.parseInt(match[3], 10),\n\t\tprerelease: match[4],\n\t};\n}\n\nexport function comparePackageVersions(leftVersion: string, rightVersion: string): number | undefined {\n\tconst left = parsePackageVersion(leftVersion);\n\tconst right = parsePackageVersion(rightVersion);\n\tif (!left || !right) {\n\t\treturn undefined;\n\t}\n\n\tif (left.major !== right.major) return left.major - right.major;\n\tif (left.minor !== right.minor) return left.minor - right.minor;\n\tif (left.patch !== right.patch) return left.patch - right.patch;\n\tif (left.prerelease === right.prerelease) return 0;\n\tif (!left.prerelease) return 1;\n\tif (!right.prerelease) return -1;\n\treturn left.prerelease.localeCompare(right.prerelease);\n}\n\nexport function isNewerPackageVersion(candidateVersion: string, currentVersion: string): boolean {\n\tconst comparison = comparePackageVersions(candidateVersion, currentVersion);\n\tif (comparison !== undefined) {\n\t\treturn comparison > 0;\n\t}\n\treturn candidateVersion.trim() !== currentVersion.trim();\n}\n\nexport async function getLatestGripRelease(\n\tcurrentVersion: string,\n\toptions: GripVersionCheckOptions = {},\n): Promise<LatestGripRelease | undefined> {\n\tif (isTruthyEnvFlag(process.env.GRIP_SKIP_VERSION_CHECK) || isTruthyEnvFlag(process.env.GRIP_OFFLINE))\n\t\treturn undefined;\n\n\tconst response = await fetch(LATEST_VERSION_URL, {\n\t\theaders: {\n\t\t\t\"User-Agent\": getGripUserAgent(currentVersion),\n\t\t\taccept: \"application/json\",\n\t\t},\n\t\tsignal: AbortSignal.timeout(options.timeoutMs ?? DEFAULT_VERSION_CHECK_TIMEOUT_MS),\n\t});\n\tif (!response.ok) return undefined;\n\n\tconst data = (await response.json()) as NpmRegistryPackageMetadata;\n\tconst version =\n\t\ttypeof data[\"dist-tags\"]?.latest === \"string\" && data[\"dist-tags\"].latest.trim()\n\t\t\t? data[\"dist-tags\"].latest.trim()\n\t\t\t: typeof data.version === \"string\" && data.version.trim()\n\t\t\t\t? data.version.trim()\n\t\t\t\t: undefined;\n\tif (!version) {\n\t\treturn undefined;\n\t}\n\tconst note = typeof data.note === \"string\" && data.note.trim() ? data.note.trim() : undefined;\n\treturn {\n\t\tversion,\n\t\t...(note ? { note } : {}),\n\t};\n}\n\nexport async function getLatestGripVersion(\n\tcurrentVersion: string,\n\toptions: GripVersionCheckOptions = {},\n): Promise<string | undefined> {\n\treturn (await getLatestGripRelease(currentVersion, options))?.version;\n}\n\nexport async function checkForNewGripVersion(currentVersion: string): Promise<LatestGripRelease | undefined> {\n\ttry {\n\t\tconst latestRelease = await getLatestGripRelease(currentVersion);\n\t\tif (latestRelease && isNewerPackageVersion(latestRelease.version, currentVersion)) {\n\t\t\treturn latestRelease;\n\t\t}\n\t\treturn undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"windows-self-update.d.ts","sourceRoot":"","sources":["../../src/utils/windows-self-update.ts"],"names":[],"mappings":"AAiDA,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAU3E;AAED,wBAAgB,mCAAmC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAsB5E","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { copyFileSync, existsSync, mkdirSync, renameSync, rmSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve, toNamespacedPath } from \"node:path\";\nimport { getCwdRelativePath } from \"./paths.ts\";\n\nconst QUARANTINE_DIR_NAME = \".grip-native-quarantine\";\n\nfunction normalizePath(path: string): string {\n\treturn toNamespacedPath(resolve(path));\n}\n\nfunction getQuarantineRoot(packageDir: string): string | undefined {\n\tlet current = resolve(packageDir);\n\twhile (true) {\n\t\tif (basename(current).toLowerCase() === \"node_modules\") {\n\t\t\treturn join(current, QUARANTINE_DIR_NAME);\n\t\t}\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn undefined;\n\t\t}\n\t\tcurrent = parent;\n\t}\n}\n\nfunction getLoadedSharedObjectsInPackageDir(packageDir: string): string[] {\n\tconst sharedObjects = (process.report.getReport() as { sharedObjects?: unknown }).sharedObjects;\n\tif (!Array.isArray(sharedObjects)) {\n\t\treturn [];\n\t}\n\n\tconst root = normalizePath(packageDir).toLowerCase();\n\tconst seen = new Set<string>();\n\tconst loadedFiles: string[] = [];\n\tfor (const value of sharedObjects) {\n\t\tif (typeof value !== \"string\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst filePath = normalizePath(value);\n\t\tconst comparisonPath = filePath.toLowerCase();\n\t\tif (getCwdRelativePath(comparisonPath, root) === undefined || seen.has(comparisonPath)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(comparisonPath);\n\t\tloadedFiles.push(filePath);\n\t}\n\treturn loadedFiles;\n}\n\nexport function cleanupWindowsSelfUpdateQuarantine(packageDir: string): void {\n\tconst quarantineRoot = getQuarantineRoot(packageDir);\n\tif (!quarantineRoot) {\n\t\treturn;\n\t}\n\ttry {\n\t\trmSync(quarantineRoot, { recursive: true, force: true });\n\t} catch {\n\t\t// A previous grip process may still be exiting and holding a native addon.\n\t}\n}\n\nexport function quarantineWindowsNativeDependencies(packageDir: string): void {\n\tconst resolvedPackageDir = normalizePath(packageDir);\n\tconst quarantineRoot = getQuarantineRoot(resolvedPackageDir);\n\tif (!quarantineRoot) {\n\t\treturn;\n\t}\n\n\tconst loadedFiles = getLoadedSharedObjectsInPackageDir(resolvedPackageDir);\n\tif (loadedFiles.length === 0) {\n\t\treturn;\n\t}\n\n\tconst quarantineRunDir = join(quarantineRoot, `${Date.now()}-${process.pid}-${randomUUID()}`);\n\tfor (const loadedFile of loadedFiles) {\n\t\tif (!existsSync(loadedFile)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst quarantinePath = join(quarantineRunDir, relative(resolvedPackageDir, loadedFile));\n\t\tmkdirSync(dirname(quarantinePath), { recursive: true });\n\t\trenameSync(loadedFile, quarantinePath);\n\t\tcopyFileSync(quarantinePath, loadedFile);\n\t}\n}\n"]}
1
+ {"version":3,"file":"windows-self-update.d.ts","sourceRoot":"","sources":["../../src/utils/windows-self-update.ts"],"names":[],"mappings":"AAiDA,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAU3E;AAED,wBAAgB,mCAAmC,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAsB5E"}
@@ -1 +1 @@
1
- {"version":3,"file":"windows-self-update.js","sourceRoot":"","sources":["../../src/utils/windows-self-update.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { copyFileSync, existsSync, mkdirSync, renameSync, rmSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve, toNamespacedPath } from \"node:path\";\nimport { getCwdRelativePath } from \"./paths.ts\";\n\nconst QUARANTINE_DIR_NAME = \".grip-native-quarantine\";\n\nfunction normalizePath(path: string): string {\n\treturn toNamespacedPath(resolve(path));\n}\n\nfunction getQuarantineRoot(packageDir: string): string | undefined {\n\tlet current = resolve(packageDir);\n\twhile (true) {\n\t\tif (basename(current).toLowerCase() === \"node_modules\") {\n\t\t\treturn join(current, QUARANTINE_DIR_NAME);\n\t\t}\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn undefined;\n\t\t}\n\t\tcurrent = parent;\n\t}\n}\n\nfunction getLoadedSharedObjectsInPackageDir(packageDir: string): string[] {\n\tconst sharedObjects = (process.report.getReport() as { sharedObjects?: unknown }).sharedObjects;\n\tif (!Array.isArray(sharedObjects)) {\n\t\treturn [];\n\t}\n\n\tconst root = normalizePath(packageDir).toLowerCase();\n\tconst seen = new Set<string>();\n\tconst loadedFiles: string[] = [];\n\tfor (const value of sharedObjects) {\n\t\tif (typeof value !== \"string\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst filePath = normalizePath(value);\n\t\tconst comparisonPath = filePath.toLowerCase();\n\t\tif (getCwdRelativePath(comparisonPath, root) === undefined || seen.has(comparisonPath)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(comparisonPath);\n\t\tloadedFiles.push(filePath);\n\t}\n\treturn loadedFiles;\n}\n\nexport function cleanupWindowsSelfUpdateQuarantine(packageDir: string): void {\n\tconst quarantineRoot = getQuarantineRoot(packageDir);\n\tif (!quarantineRoot) {\n\t\treturn;\n\t}\n\ttry {\n\t\trmSync(quarantineRoot, { recursive: true, force: true });\n\t} catch {\n\t\t// A previous grip process may still be exiting and holding a native addon.\n\t}\n}\n\nexport function quarantineWindowsNativeDependencies(packageDir: string): void {\n\tconst resolvedPackageDir = normalizePath(packageDir);\n\tconst quarantineRoot = getQuarantineRoot(resolvedPackageDir);\n\tif (!quarantineRoot) {\n\t\treturn;\n\t}\n\n\tconst loadedFiles = getLoadedSharedObjectsInPackageDir(resolvedPackageDir);\n\tif (loadedFiles.length === 0) {\n\t\treturn;\n\t}\n\n\tconst quarantineRunDir = join(quarantineRoot, `${Date.now()}-${process.pid}-${randomUUID()}`);\n\tfor (const loadedFile of loadedFiles) {\n\t\tif (!existsSync(loadedFile)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst quarantinePath = join(quarantineRunDir, relative(resolvedPackageDir, loadedFile));\n\t\tmkdirSync(dirname(quarantinePath), { recursive: true });\n\t\trenameSync(loadedFile, quarantinePath);\n\t\tcopyFileSync(quarantinePath, loadedFile);\n\t}\n}\n"]}
1
+ {"version":3,"file":"windows-self-update.js","sourceRoot":"","sources":["../../src/utils/windows-self-update.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { copyFileSync, existsSync, mkdirSync, renameSync, rmSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve, toNamespacedPath } from \"node:path\";\nimport { getCwdRelativePath } from \"./paths.ts\";\n\nconst QUARANTINE_DIR_NAME = \".grip-native-quarantine\";\n\nfunction normalizePath(path: string): string {\n\treturn toNamespacedPath(resolve(path));\n}\n\nfunction getQuarantineRoot(packageDir: string): string | undefined {\n\tlet current = resolve(packageDir);\n\twhile (true) {\n\t\tif (basename(current).toLowerCase() === \"node_modules\") {\n\t\t\treturn join(current, QUARANTINE_DIR_NAME);\n\t\t}\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) {\n\t\t\treturn undefined;\n\t\t}\n\t\tcurrent = parent;\n\t}\n}\n\nfunction getLoadedSharedObjectsInPackageDir(packageDir: string): string[] {\n\tconst sharedObjects = (process.report.getReport() as { sharedObjects?: unknown }).sharedObjects;\n\tif (!Array.isArray(sharedObjects)) {\n\t\treturn [];\n\t}\n\n\tconst root = normalizePath(packageDir).toLowerCase();\n\tconst seen = new Set<string>();\n\tconst loadedFiles: string[] = [];\n\tfor (const value of sharedObjects) {\n\t\tif (typeof value !== \"string\") {\n\t\t\tcontinue;\n\t\t}\n\t\tconst filePath = normalizePath(value);\n\t\tconst comparisonPath = filePath.toLowerCase();\n\t\tif (getCwdRelativePath(comparisonPath, root) === undefined || seen.has(comparisonPath)) {\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(comparisonPath);\n\t\tloadedFiles.push(filePath);\n\t}\n\treturn loadedFiles;\n}\n\nexport function cleanupWindowsSelfUpdateQuarantine(packageDir: string): void {\n\tconst quarantineRoot = getQuarantineRoot(packageDir);\n\tif (!quarantineRoot) {\n\t\treturn;\n\t}\n\ttry {\n\t\trmSync(quarantineRoot, { recursive: true, force: true });\n\t} catch {\n\t\t// A previous grip process may still be exiting and holding a native addon.\n\t}\n}\n\nexport function quarantineWindowsNativeDependencies(packageDir: string): void {\n\tconst resolvedPackageDir = normalizePath(packageDir);\n\tconst quarantineRoot = getQuarantineRoot(resolvedPackageDir);\n\tif (!quarantineRoot) {\n\t\treturn;\n\t}\n\n\tconst loadedFiles = getLoadedSharedObjectsInPackageDir(resolvedPackageDir);\n\tif (loadedFiles.length === 0) {\n\t\treturn;\n\t}\n\n\tconst quarantineRunDir = join(quarantineRoot, `${Date.now()}-${process.pid}-${randomUUID()}`);\n\tfor (const loadedFile of loadedFiles) {\n\t\tif (!existsSync(loadedFile)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst quarantinePath = join(quarantineRunDir, relative(resolvedPackageDir, loadedFile));\n\t\tmkdirSync(dirname(quarantinePath), { recursive: true });\n\t\trenameSync(loadedFile, quarantinePath);\n\t\tcopyFileSync(quarantinePath, loadedFile);\n\t}\n}\n"]}
@@ -898,7 +898,7 @@ Current working directory.
898
898
 
899
899
  Backend-aware file and shell operations for extensions. These APIs use the same active backend as Grip's built-in tools: local by default, or a remote daemon when configured.
900
900
 
901
- Use these APIs for extension tools and extension-owned automation that reads files, writes files, lists directories, or executes shell commands. This is the only safe way for extension tools to run shell commands because it preserves Grip's active execution boundary. Direct local process APIs (`child_process`, `pi.exec`, shell libraries, etc.) bypass the configured tool backend and will run on the local machine even when Grip tools are remote.
901
+ Use these APIs for extension tools and extension-owned automation that reads files, writes files, lists directories, or executes shell commands in the active backend. For deliberate host execution from a managed sandbox, use the separately approved `ctx.execHostProcess()` (direct argv) or `ctx.execHostCommand()` (shell) below. Direct local process APIs (`child_process`, `pi.exec`, shell libraries, etc.) bypass the configured tool backend and will run on the local machine even when Grip tools are remote.
902
902
 
903
903
  ```typescript
904
904
  pi.registerTool({
@@ -941,6 +941,36 @@ Options:
941
941
 
942
942
  Use `ctx.toolOperations` directly when you need backend-aware file operations such as `readFile`, `writeFile`, `stat`, `readdir`, `glob`, or `grep`.
943
943
 
944
+ `ctx.isSandbox()` returns `true` while this session has an active sandbox daemon connection, whether started or attached; it updates when you switch sessions or disconnect. It is `false` for local sessions and other remote tool backends. This indicates where workspace tools run, **not** whether guest paths have a verified host mount: both approved host APIs still require a known mapping and per-command approval.
945
+
946
+ ### ctx.execHostProcess() (direct host argv)
947
+
948
+ `ctx.execHostProcess(executable, args, { question, explanation?, cwd?, signal?, timeout? })` uses the **same per-invocation approval and mount checks** as the shell API below, but runs a host executable with an argument array using `spawn(..., { shell: false })`. Grip displays the executable, argument array, and translated host cwd. When provided, `explanation` is displayed separately as **unverified** context alongside the extension's `question`; it can contain model-generated text and does not replace the exact argv or cwd. It returns `{ stdout, stderr, code, killed }`; `timeout` is in milliseconds. **Stdout and stderr are raw host output and may contain secrets; filter them before returning tool results to the model.** Use this for host Git when shell execution is not acceptable. This API is unavailable outside a connected mapped sandbox; use `pi.exec(file, args, options)` for direct local processes when no sandbox is active (no approval prompt).
949
+
950
+ ```typescript
951
+ await ctx.execHostProcess("git", ["pull", "--rebase", "origin", "main"], {
952
+ question: "Run Git pull using host credentials?",
953
+ explanation: params.explanation, // model input, clearly labeled unverified in the approval
954
+ signal: ctx.signal,
955
+ });
956
+ ```
957
+
958
+ ### ctx.execHostCommand() (managed sandboxes)
959
+
960
+ A reviewed extension can deliberately run a shell command on the host while a Lima-managed sandbox is active. Use `ctx.execHostCommand(command, { question, cwd?, signal?, timeout?, onChunk? })`. Grip prompts **for every invocation** in the editor area, with the extension's question plus the exact command and translated host cwd generated by Grip. "No", Escape, cancellation, or missing UI denies execution; there is no remember/always-allow option. In RPC mode, the client must answer the `select` dialog; print and JSON modes cannot approve.
961
+
962
+ ```typescript
963
+ const result = await ctx.execHostCommand("printf diagnostics", {
964
+ question: "Run diagnostics on the host?",
965
+ cwd: ctx.toolOperations.cwd, // guest path, e.g. /workspace/project
966
+ signal: ctx.signal,
967
+ });
968
+ ```
969
+
970
+ The optional `cwd` is a **guest** directory, defaulting to the active guest working directory. `ctx.toolOperations.mapWorkspaceDirectoryToHost?.(guestPath)` maps an existing directory within a verified mount to its host counterpart, without executing anything. Host commands run in that translated directory; they do not change the guest cwd or run the configured backend shell prefix. Grip automatically supplies a mount mapping only for sandboxes it starts with a known host source. Arbitrarily attached daemons and remote backends without a verified mapping fail closed, even if their paths look similar to host paths. Guest paths outside the mount and host symlinks escaping the mount are rejected.
971
+
972
+ **Trust boundary:** Extensions run as host-side JavaScript and can still use Node `fs`, `child_process`, or legacy `pi.exec` directly without this prompt. The approval is mandatory for `ctx.execHostCommand()` and `ctx.execHostProcess()`, **not** a process-wide restriction on extension code. Review extensions before loading them; use `ctx.execToolBackend()` for ordinary sandbox work. Host Git can load repository-controlled config, remotes, credential helpers or filters from a writable mount; unrestricted Git argv can also select remote URLs or programs to run on the host. An approved direct Git process and a model-provided explanation alone are not isolation for host credentials.
973
+
944
974
  ### ctx.getLspStatus() / ctx.configureLsp()
945
975
 
946
976
  Normal Grip extensions share the single `AgentSession`-owned LSP runtime. Inspect it without creating a parallel manager:
package/docs/sandbox.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  The command appears in slash-command completion but not in model-visible catalogs, system prompts, tool definitions, templates, skills, or rules. This is not a permission boundary: a model with host shell access may still invoke Lima directly.
6
6
 
7
+ `/new` starts a fresh conversation in the same connected sandbox (started or attached) without starting another VM. When no sandbox is connected, `/new` starts a local session. Sandbox connections are remembered in memory only while Grip remains running.
8
+
9
+ Inside a connected sandbox, `/cd <directory>` changes the guest working directory for subsequent tools within the existing mounted workspace; completion lists directories from the guest, and the footer displays the guest working directory. `/cd` without an argument returns to the guest workspace root. It does not change the host session directory, remount the workspace, or reconnect the daemon. In a VM that mounts one host project at `/workspace`, `/workspace/planner` is not another mounted host project; open that project as a separate workspace, or attach a daemon whose workspace root contains both projects. The guest working directory resets to the mount root after a session switch or reconnection. Reviewed extensions may explicitly call `ctx.execHostProcess()` (direct argv) or `ctx.execHostCommand()` (shell) to run on the host after per-operation user approval; only managed sandboxes with a verified mount can translate guest directories to host directories. See [Extensions](extensions.md#ctxexechostprocess-direct-host-argv).
10
+
11
+ Lima-managed sandboxes allow workspace tools (`read`, `write`, `edit`, `ls`, `find`, and `grep`) to access paths anywhere in the guest filesystem, including outside the mounted workspace. This does not mount additional host directories; guest OS permissions still apply. `/cd` remains within the mounted workspace. An attached daemon stays workspace-confined by default: only enable `--daemon-allow-full-filesystem` when the daemon runs inside an intentionally isolated guest, never on an untrusted host. Existing guest daemons need an update or restart to enable this access.
12
+
7
13
  ## Commands
8
14
 
9
15
  ```text
package/docs/sessions.md CHANGED
@@ -23,7 +23,7 @@ For the JSONL file format, active `Session` API, and `SessionManager` lifecycle
23
23
  | Command | Description |
24
24
  |---------|-------------|
25
25
  | `/resume` | Browse and select previous sessions |
26
- | `/new` | Start a new session |
26
+ | `/new` | Start a new session, reusing the active sandbox connection if connected |
27
27
  | `/name <name>` | Set the current session display name |
28
28
  | `/session` | Show session info |
29
29
  | `/tree` | Navigate the current session tree |
package/docs/skills.md CHANGED
@@ -64,11 +64,11 @@ For project-level Claude Code skills, add to `.grip/settings.json`:
64
64
  ## How Skills Work
65
65
 
66
66
  1. At startup, Grip scans skill locations and extracts names and descriptions
67
- 2. The system prompt includes available skills in XML format per the [specification](https://agentskills.io/integrate-skills)
68
- 3. When a task matches, the agent uses `read` to load the full SKILL.md (models don't always do this; use prompting or `/skill:name` to force it)
67
+ 2. The system prompt includes available skill names and descriptions in XML, without file locations
68
+ 3. When a task matches, the agent calls `load_skill` with a skill name (or an array of names) to load the full instructions. The tool reports the skill directory for resolving relative references. Use `/skill:name` to force a skill from the UI.
69
69
  4. The agent follows the instructions, using relative paths to reference scripts and assets
70
70
 
71
- This is progressive disclosure: only descriptions are always in context, full instructions load on-demand.
71
+ This is progressive disclosure: only descriptions are always in context, full instructions load on-demand. For example, use `load_skill({"name":"pdf-processing"})` for one skill or `load_skill({"name":["pdf-processing","data-analysis"]})` for several. Skills with `disable-model-invocation: true` remain user-only via `/skill:name`.
72
72
 
73
73
  ## Skill Commands
74
74
 
@@ -146,7 +146,7 @@ Per the [Agent Skills specification](https://agentskills.io/specification#frontm
146
146
  | `compatibility` | No | Max 500 chars. Environment requirements. |
147
147
  | `metadata` | No | Arbitrary key-value mapping. |
148
148
  | `allowed-tools` | No | Space-delimited list of pre-approved tools (experimental). |
149
- | `tools` | No | Tool name or YAML list of lazy tools to load automatically when the skill is loaded via `read` or `/skill:name`. |
149
+ | `tools` | No | Tool name or YAML list of lazy tools to load automatically when the skill is loaded via `load_skill`, `read`, or `/skill:name`. |
150
150
  | `disable-model-invocation` | No | When `true`, skill is hidden from system prompt. Users must use `/skill:name`. |
151
151
 
152
152
  Example with associated lazy tools: