@gajae-code/coding-agent 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1775) hide show
  1. package/CHANGELOG.md +8662 -0
  2. package/README.md +37 -0
  3. package/dist/types/async/index.d.ts +2 -0
  4. package/dist/types/async/job-manager.d.ts +101 -0
  5. package/dist/types/async/support.d.ts +2 -0
  6. package/dist/types/autoresearch/dashboard.d.ts +4 -0
  7. package/dist/types/autoresearch/git.d.ts +36 -0
  8. package/dist/types/autoresearch/helpers.d.ts +24 -0
  9. package/dist/types/autoresearch/index.d.ts +2 -0
  10. package/dist/types/autoresearch/state.d.ts +17 -0
  11. package/dist/types/autoresearch/storage.d.ts +142 -0
  12. package/dist/types/autoresearch/tools/init-experiment.d.ts +31 -0
  13. package/dist/types/autoresearch/tools/log-experiment.d.ts +23 -0
  14. package/dist/types/autoresearch/tools/run-experiment.d.ts +8 -0
  15. package/dist/types/autoresearch/tools/update-notes.d.ts +12 -0
  16. package/dist/types/autoresearch/types.d.ts +154 -0
  17. package/dist/types/capability/context-file.d.ts +17 -0
  18. package/dist/types/capability/extension-module.d.ts +15 -0
  19. package/dist/types/capability/extension.d.ts +28 -0
  20. package/dist/types/capability/fs.d.ts +20 -0
  21. package/dist/types/capability/hook.d.ts +19 -0
  22. package/dist/types/capability/index.d.ts +80 -0
  23. package/dist/types/capability/instruction.d.ts +17 -0
  24. package/dist/types/capability/mcp.d.ts +45 -0
  25. package/dist/types/capability/prompt.d.ts +15 -0
  26. package/dist/types/capability/rule.d.ts +61 -0
  27. package/dist/types/capability/settings.d.ts +15 -0
  28. package/dist/types/capability/skill.d.ts +36 -0
  29. package/dist/types/capability/slash-command.d.ts +17 -0
  30. package/dist/types/capability/ssh.d.ts +23 -0
  31. package/dist/types/capability/system-prompt.d.ts +15 -0
  32. package/dist/types/capability/tool.d.ts +19 -0
  33. package/dist/types/capability/types.d.ts +154 -0
  34. package/dist/types/cli/agents-cli.d.ts +12 -0
  35. package/dist/types/cli/args.d.ts +53 -0
  36. package/dist/types/cli/auth-broker-cli.d.ts +25 -0
  37. package/dist/types/cli/auth-gateway-cli.d.ts +18 -0
  38. package/dist/types/cli/classify-install-target.d.ts +18 -0
  39. package/dist/types/cli/commands/init-xdg.d.ts +1 -0
  40. package/dist/types/cli/config-cli.d.ts +22 -0
  41. package/dist/types/cli/file-processor.d.ts +11 -0
  42. package/dist/types/cli/grep-cli.d.ts +17 -0
  43. package/dist/types/cli/initial-message.d.ts +17 -0
  44. package/dist/types/cli/list-models.d.ts +30 -0
  45. package/dist/types/cli/plugin-cli.d.ts +32 -0
  46. package/dist/types/cli/read-cli.d.ts +4 -0
  47. package/dist/types/cli/session-picker.d.ts +3 -0
  48. package/dist/types/cli/setup-cli.d.ts +31 -0
  49. package/dist/types/cli/shell-cli.d.ts +8 -0
  50. package/dist/types/cli/ssh-cli.d.ts +21 -0
  51. package/dist/types/cli/stats-cli.d.ts +17 -0
  52. package/dist/types/cli/update-cli.d.ts +38 -0
  53. package/dist/types/cli/web-search-cli.d.ts +20 -0
  54. package/dist/types/cli/worktree-cli.d.ts +26 -0
  55. package/dist/types/cli.d.ts +3 -0
  56. package/dist/types/commands/acp.d.ts +12 -0
  57. package/dist/types/commands/agents.d.ts +34 -0
  58. package/dist/types/commands/auth-broker.d.ts +54 -0
  59. package/dist/types/commands/auth-gateway.d.ts +32 -0
  60. package/dist/types/commands/codex-native-hook.d.ts +6 -0
  61. package/dist/types/commands/commit.d.ts +27 -0
  62. package/dist/types/commands/config.d.ts +30 -0
  63. package/dist/types/commands/deep-interview.d.ts +7 -0
  64. package/dist/types/commands/gjc-runtime-bridge.d.ts +6 -0
  65. package/dist/types/commands/grep.d.ts +42 -0
  66. package/dist/types/commands/launch.d.ts +121 -0
  67. package/dist/types/commands/plugin.d.ts +52 -0
  68. package/dist/types/commands/question.d.ts +7 -0
  69. package/dist/types/commands/ralplan.d.ts +7 -0
  70. package/dist/types/commands/read.d.ts +15 -0
  71. package/dist/types/commands/setup.d.ts +48 -0
  72. package/dist/types/commands/shell.d.ts +21 -0
  73. package/dist/types/commands/ssh.d.ts +48 -0
  74. package/dist/types/commands/state.d.ts +7 -0
  75. package/dist/types/commands/stats.d.ts +25 -0
  76. package/dist/types/commands/team.d.ts +24 -0
  77. package/dist/types/commands/ultragoal.d.ts +7 -0
  78. package/dist/types/commands/update.d.ts +20 -0
  79. package/dist/types/commands/web-search.d.ts +33 -0
  80. package/dist/types/commands/worktree.d.ts +34 -0
  81. package/dist/types/commit/agentic/agent.d.ts +31 -0
  82. package/dist/types/commit/agentic/fallback.d.ts +5 -0
  83. package/dist/types/commit/agentic/index.d.ts +2 -0
  84. package/dist/types/commit/agentic/state.d.ts +58 -0
  85. package/dist/types/commit/agentic/tools/analyze-file.d.ts +19 -0
  86. package/dist/types/commit/agentic/tools/git-file-diff.d.ts +10 -0
  87. package/dist/types/commit/agentic/tools/git-hunk.d.ts +9 -0
  88. package/dist/types/commit/agentic/tools/git-overview.d.ts +9 -0
  89. package/dist/types/commit/agentic/tools/index.d.ts +16 -0
  90. package/dist/types/commit/agentic/tools/propose-changelog.d.ts +28 -0
  91. package/dist/types/commit/agentic/tools/propose-commit.d.ts +36 -0
  92. package/dist/types/commit/agentic/tools/recent-commits.d.ts +7 -0
  93. package/dist/types/commit/agentic/tools/schemas.d.ts +27 -0
  94. package/dist/types/commit/agentic/tools/split-commit.d.ts +53 -0
  95. package/dist/types/commit/agentic/topo-sort.d.ts +4 -0
  96. package/dist/types/commit/agentic/trivial.d.ts +7 -0
  97. package/dist/types/commit/agentic/validation.d.ts +20 -0
  98. package/dist/types/commit/analysis/conventional.d.ts +22 -0
  99. package/dist/types/commit/analysis/index.d.ts +4 -0
  100. package/dist/types/commit/analysis/scope.d.ts +6 -0
  101. package/dist/types/commit/analysis/summary.d.ts +19 -0
  102. package/dist/types/commit/analysis/validation.d.ts +8 -0
  103. package/dist/types/commit/changelog/detect.d.ts +2 -0
  104. package/dist/types/commit/changelog/generate.d.ts +30 -0
  105. package/dist/types/commit/changelog/index.d.ts +30 -0
  106. package/dist/types/commit/changelog/parse.d.ts +2 -0
  107. package/dist/types/commit/cli.d.ts +3 -0
  108. package/dist/types/commit/git/diff.d.ts +5 -0
  109. package/dist/types/commit/index.d.ts +4 -0
  110. package/dist/types/commit/map-reduce/index.d.ts +28 -0
  111. package/dist/types/commit/map-reduce/map-phase.d.ts +17 -0
  112. package/dist/types/commit/map-reduce/reduce-phase.d.ts +13 -0
  113. package/dist/types/commit/map-reduce/utils.d.ts +2 -0
  114. package/dist/types/commit/message.d.ts +2 -0
  115. package/dist/types/commit/model-selection.d.ts +15 -0
  116. package/dist/types/commit/pipeline.d.ts +5 -0
  117. package/dist/types/commit/shared-llm.d.ts +54 -0
  118. package/dist/types/commit/types.d.ts +78 -0
  119. package/dist/types/commit/utils/exclusions.d.ts +4 -0
  120. package/dist/types/commit/utils.d.ts +20 -0
  121. package/dist/types/config/config-file.d.ts +58 -0
  122. package/dist/types/config/file-lock.d.ts +6 -0
  123. package/dist/types/config/keybindings.d.ts +334 -0
  124. package/dist/types/config/model-equivalence.d.ts +24 -0
  125. package/dist/types/config/model-registry.d.ts +390 -0
  126. package/dist/types/config/model-resolver.d.ts +230 -0
  127. package/dist/types/config/models-config-schema.d.ts +504 -0
  128. package/dist/types/config/prompt-templates.d.ts +32 -0
  129. package/dist/types/config/resolve-config-value.d.ts +17 -0
  130. package/dist/types/config/settings-schema.d.ts +3337 -0
  131. package/dist/types/config/settings.d.ts +132 -0
  132. package/dist/types/config/skill-settings-defaults.d.ts +14 -0
  133. package/dist/types/config.d.ts +66 -0
  134. package/dist/types/cursor.d.ts +24 -0
  135. package/dist/types/dap/client.d.ts +38 -0
  136. package/dist/types/dap/config.d.ts +6 -0
  137. package/dist/types/dap/index.d.ts +4 -0
  138. package/dist/types/dap/session.d.ts +108 -0
  139. package/dist/types/dap/types.d.ts +524 -0
  140. package/dist/types/debug/index.d.ts +15 -0
  141. package/dist/types/debug/log-formatting.d.ts +4 -0
  142. package/dist/types/debug/log-viewer.d.ts +68 -0
  143. package/dist/types/debug/profiler.d.ts +24 -0
  144. package/dist/types/debug/raw-sse-buffer.d.ts +44 -0
  145. package/dist/types/debug/raw-sse.d.ts +16 -0
  146. package/dist/types/debug/report-bundle.d.ts +55 -0
  147. package/dist/types/debug/system-info.d.ts +26 -0
  148. package/dist/types/defaults/gjc-defaults.d.ts +44 -0
  149. package/dist/types/discovery/agents-md.d.ts +1 -0
  150. package/dist/types/discovery/agents.d.ts +12 -0
  151. package/dist/types/discovery/builtin.d.ts +1 -0
  152. package/dist/types/discovery/claude-plugins.d.ts +1 -0
  153. package/dist/types/discovery/claude.d.ts +1 -0
  154. package/dist/types/discovery/cline.d.ts +1 -0
  155. package/dist/types/discovery/codex.d.ts +1 -0
  156. package/dist/types/discovery/cursor.d.ts +16 -0
  157. package/dist/types/discovery/gemini.d.ts +1 -0
  158. package/dist/types/discovery/github.d.ts +1 -0
  159. package/dist/types/discovery/helpers.d.ts +268 -0
  160. package/dist/types/discovery/index.d.ts +48 -0
  161. package/dist/types/discovery/mcp-json.d.ts +1 -0
  162. package/dist/types/discovery/opencode.d.ts +1 -0
  163. package/dist/types/discovery/plugin-dir-roots.d.ts +15 -0
  164. package/dist/types/discovery/ssh.d.ts +1 -0
  165. package/dist/types/discovery/substitute-plugin-root.d.ts +5 -0
  166. package/dist/types/discovery/vscode.d.ts +1 -0
  167. package/dist/types/discovery/windsurf.d.ts +13 -0
  168. package/dist/types/edit/apply-patch/index.d.ts +35 -0
  169. package/dist/types/edit/apply-patch/parser.d.ts +34 -0
  170. package/dist/types/edit/diff.d.ts +59 -0
  171. package/dist/types/edit/file-read-cache.d.ts +25 -0
  172. package/dist/types/edit/index.d.ts +58 -0
  173. package/dist/types/edit/modes/apply-patch.d.ts +24 -0
  174. package/dist/types/edit/modes/patch.d.ts +99 -0
  175. package/dist/types/edit/modes/replace.d.ts +142 -0
  176. package/dist/types/edit/normalize.d.ts +43 -0
  177. package/dist/types/edit/notebook.d.ts +23 -0
  178. package/dist/types/edit/read-file.d.ts +2 -0
  179. package/dist/types/edit/renderer.d.ts +110 -0
  180. package/dist/types/edit/streaming.d.ts +66 -0
  181. package/dist/types/eval/backend.d.ts +40 -0
  182. package/dist/types/eval/index.d.ts +4 -0
  183. package/dist/types/eval/js/context-manager.d.ts +24 -0
  184. package/dist/types/eval/js/executor.d.ts +28 -0
  185. package/dist/types/eval/js/index.d.ts +10 -0
  186. package/dist/types/eval/js/shared/helpers.d.ts +38 -0
  187. package/dist/types/eval/js/shared/indirect-eval.d.ts +14 -0
  188. package/dist/types/eval/js/shared/prelude.d.ts +1 -0
  189. package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -0
  190. package/dist/types/eval/js/shared/runtime.d.ts +47 -0
  191. package/dist/types/eval/js/shared/types.d.ts +24 -0
  192. package/dist/types/eval/js/tool-bridge.d.ts +18 -0
  193. package/dist/types/eval/js/worker-core.d.ts +5 -0
  194. package/dist/types/eval/js/worker-entry.d.ts +1 -0
  195. package/dist/types/eval/js/worker-protocol.d.ts +77 -0
  196. package/dist/types/eval/py/display.d.ts +25 -0
  197. package/dist/types/eval/py/executor.d.ts +83 -0
  198. package/dist/types/eval/py/index.d.ts +10 -0
  199. package/dist/types/eval/py/kernel.d.ts +61 -0
  200. package/dist/types/eval/py/prelude.d.ts +1 -0
  201. package/dist/types/eval/py/runtime.d.ts +21 -0
  202. package/dist/types/eval/py/tool-bridge.d.ts +20 -0
  203. package/dist/types/eval/types.d.ts +52 -0
  204. package/dist/types/exa/factory.d.ts +13 -0
  205. package/dist/types/exa/index.d.ts +20 -0
  206. package/dist/types/exa/mcp-client.d.ts +45 -0
  207. package/dist/types/exa/render.d.ts +19 -0
  208. package/dist/types/exa/researcher.d.ts +9 -0
  209. package/dist/types/exa/search.d.ts +9 -0
  210. package/dist/types/exa/types.d.ts +155 -0
  211. package/dist/types/exa/websets.d.ts +9 -0
  212. package/dist/types/exec/bash-executor.d.ts +41 -0
  213. package/dist/types/exec/exec.d.ts +25 -0
  214. package/dist/types/exec/idle-timeout-watchdog.d.ts +18 -0
  215. package/dist/types/exec/non-interactive-env.d.ts +1 -0
  216. package/dist/types/export/custom-share.d.ts +20 -0
  217. package/dist/types/export/html/index.d.ts +10 -0
  218. package/dist/types/export/html/template.generated.d.ts +1 -0
  219. package/dist/types/export/html/template.macro.d.ts +5 -0
  220. package/dist/types/export/ttsr.d.ts +44 -0
  221. package/dist/types/extensibility/custom-commands/bundled/ci-green/index.d.ts +9 -0
  222. package/dist/types/extensibility/custom-commands/bundled/review/index.d.ts +10 -0
  223. package/dist/types/extensibility/custom-commands/index.d.ts +2 -0
  224. package/dist/types/extensibility/custom-commands/loader.d.ts +29 -0
  225. package/dist/types/extensibility/custom-commands/types.d.ts +106 -0
  226. package/dist/types/extensibility/custom-tools/index.d.ts +6 -0
  227. package/dist/types/extensibility/custom-tools/loader.d.ts +69 -0
  228. package/dist/types/extensibility/custom-tools/types.d.ts +226 -0
  229. package/dist/types/extensibility/custom-tools/wrapper.d.ts +23 -0
  230. package/dist/types/extensibility/extensions/compact-handler.d.ts +26 -0
  231. package/dist/types/extensibility/extensions/get-commands-handler.d.ts +29 -0
  232. package/dist/types/extensibility/extensions/index.d.ts +8 -0
  233. package/dist/types/extensibility/extensions/loader.d.ts +43 -0
  234. package/dist/types/extensibility/extensions/runner.d.ts +134 -0
  235. package/dist/types/extensibility/extensions/types.d.ts +864 -0
  236. package/dist/types/extensibility/extensions/wrapper.d.ts +54 -0
  237. package/dist/types/extensibility/hooks/index.d.ts +5 -0
  238. package/dist/types/extensibility/hooks/loader.d.ts +89 -0
  239. package/dist/types/extensibility/hooks/runner.d.ts +126 -0
  240. package/dist/types/extensibility/hooks/tool-wrapper.d.ts +25 -0
  241. package/dist/types/extensibility/hooks/types.d.ts +431 -0
  242. package/dist/types/extensibility/plugins/doctor.d.ts +3 -0
  243. package/dist/types/extensibility/plugins/git-url.d.ts +34 -0
  244. package/dist/types/extensibility/plugins/index.d.ts +7 -0
  245. package/dist/types/extensibility/plugins/installer.d.ts +5 -0
  246. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
  247. package/dist/types/extensibility/plugins/loader.d.ts +31 -0
  248. package/dist/types/extensibility/plugins/manager.d.ts +65 -0
  249. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +41 -0
  250. package/dist/types/extensibility/plugins/marketplace/fetcher.d.ts +48 -0
  251. package/dist/types/extensibility/plugins/marketplace/index.d.ts +6 -0
  252. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +57 -0
  253. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +34 -0
  254. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +28 -0
  255. package/dist/types/extensibility/plugins/marketplace/types.d.ts +130 -0
  256. package/dist/types/extensibility/plugins/parser.d.ts +52 -0
  257. package/dist/types/extensibility/plugins/types.d.ts +149 -0
  258. package/dist/types/extensibility/shared-events.d.ts +279 -0
  259. package/dist/types/extensibility/skills.d.ts +74 -0
  260. package/dist/types/extensibility/slash-commands.d.ts +48 -0
  261. package/dist/types/extensibility/tool-proxy.d.ts +4 -0
  262. package/dist/types/extensibility/typebox.d.ts +155 -0
  263. package/dist/types/extensibility/utils.d.ts +12 -0
  264. package/dist/types/gjc-runtime/goal-mode-request.d.ts +46 -0
  265. package/dist/types/gjc-runtime/launch-tmux.d.ts +45 -0
  266. package/dist/types/gjc-runtime/launch-worktree.d.ts +46 -0
  267. package/dist/types/gjc-runtime/team-runtime.d.ts +204 -0
  268. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +85 -0
  269. package/dist/types/goals/index.d.ts +3 -0
  270. package/dist/types/goals/runtime.d.ts +68 -0
  271. package/dist/types/goals/state.d.ts +35 -0
  272. package/dist/types/goals/tools/goal-tool.d.ts +128 -0
  273. package/dist/types/hashline/anchors.d.ts +20 -0
  274. package/dist/types/hashline/apply.d.ts +14 -0
  275. package/dist/types/hashline/constants.d.ts +19 -0
  276. package/dist/types/hashline/diff-preview.d.ts +2 -0
  277. package/dist/types/hashline/diff.d.ts +17 -0
  278. package/dist/types/hashline/execute.d.ts +4 -0
  279. package/dist/types/hashline/hash.d.ts +123 -0
  280. package/dist/types/hashline/index.d.ts +13 -0
  281. package/dist/types/hashline/input.d.ts +11 -0
  282. package/dist/types/hashline/parser.d.ts +7 -0
  283. package/dist/types/hashline/prefixes.d.ts +7 -0
  284. package/dist/types/hashline/recovery.d.ts +27 -0
  285. package/dist/types/hashline/stream.d.ts +2 -0
  286. package/dist/types/hashline/types.d.ts +77 -0
  287. package/dist/types/hindsight/backend.d.ts +13 -0
  288. package/dist/types/hindsight/bank.d.ts +54 -0
  289. package/dist/types/hindsight/client.d.ts +224 -0
  290. package/dist/types/hindsight/config.d.ts +51 -0
  291. package/dist/types/hindsight/content.d.ts +70 -0
  292. package/dist/types/hindsight/index.d.ts +8 -0
  293. package/dist/types/hindsight/mental-models.d.ts +125 -0
  294. package/dist/types/hindsight/state.d.ts +99 -0
  295. package/dist/types/hindsight/transcript.d.ts +28 -0
  296. package/dist/types/hooks/codex-native-hooks-config.d.ts +29 -0
  297. package/dist/types/hooks/native-skill-hook.d.ts +16 -0
  298. package/dist/types/hooks/skill-keywords.d.ts +17 -0
  299. package/dist/types/hooks/skill-state.d.ts +80 -0
  300. package/dist/types/index.d.ts +33 -0
  301. package/dist/types/internal-urls/agent-protocol.d.ts +12 -0
  302. package/dist/types/internal-urls/artifact-protocol.d.ts +6 -0
  303. package/dist/types/internal-urls/docs-index.generated.d.ts +2 -0
  304. package/dist/types/internal-urls/gjc-protocol.d.ts +12 -0
  305. package/dist/types/internal-urls/index.d.ts +20 -0
  306. package/dist/types/internal-urls/issue-pr-protocol.d.ts +17 -0
  307. package/dist/types/internal-urls/json-query.d.ts +30 -0
  308. package/dist/types/internal-urls/local-protocol.d.ts +39 -0
  309. package/dist/types/internal-urls/mcp-protocol.d.ts +12 -0
  310. package/dist/types/internal-urls/memory-protocol.d.ts +23 -0
  311. package/dist/types/internal-urls/parse.d.ts +19 -0
  312. package/dist/types/internal-urls/registry-helpers.d.ts +10 -0
  313. package/dist/types/internal-urls/router.d.ts +14 -0
  314. package/dist/types/internal-urls/rule-protocol.d.ts +6 -0
  315. package/dist/types/internal-urls/skill-protocol.d.ts +13 -0
  316. package/dist/types/internal-urls/types.d.ts +105 -0
  317. package/dist/types/lsp/client.d.ts +65 -0
  318. package/dist/types/lsp/clients/biome-client.d.ts +16 -0
  319. package/dist/types/lsp/clients/index.d.ts +19 -0
  320. package/dist/types/lsp/clients/lsp-linter-client.d.ts +16 -0
  321. package/dist/types/lsp/clients/swiftlint-client.d.ts +20 -0
  322. package/dist/types/lsp/config.d.ts +65 -0
  323. package/dist/types/lsp/edits.d.ts +23 -0
  324. package/dist/types/lsp/index.d.ts +130 -0
  325. package/dist/types/lsp/lspmux.d.ts +58 -0
  326. package/dist/types/lsp/render.d.ts +32 -0
  327. package/dist/types/lsp/startup-events.d.ts +11 -0
  328. package/dist/types/lsp/types.d.ts +302 -0
  329. package/dist/types/lsp/utils.d.ts +108 -0
  330. package/dist/types/main.d.ts +50 -0
  331. package/dist/types/memories/index.d.ts +28 -0
  332. package/dist/types/memories/storage.d.ts +110 -0
  333. package/dist/types/memory-backend/index.d.ts +4 -0
  334. package/dist/types/memory-backend/local-backend.d.ts +9 -0
  335. package/dist/types/memory-backend/off-backend.d.ts +7 -0
  336. package/dist/types/memory-backend/resolve.d.ts +15 -0
  337. package/dist/types/memory-backend/types.d.ts +61 -0
  338. package/dist/types/modes/acp/acp-agent.d.ts +61 -0
  339. package/dist/types/modes/acp/acp-client-bridge.d.ts +9 -0
  340. package/dist/types/modes/acp/acp-event-mapper.d.ts +32 -0
  341. package/dist/types/modes/acp/acp-mode.d.ts +5 -0
  342. package/dist/types/modes/acp/index.d.ts +2 -0
  343. package/dist/types/modes/acp/terminal-auth.d.ts +6 -0
  344. package/dist/types/modes/components/agent-dashboard.d.ts +21 -0
  345. package/dist/types/modes/components/assistant-message.d.ts +16 -0
  346. package/dist/types/modes/components/bash-execution.d.ts +29 -0
  347. package/dist/types/modes/components/bordered-loader.d.ts +11 -0
  348. package/dist/types/modes/components/branch-summary-message.d.ts +13 -0
  349. package/dist/types/modes/components/btw-panel.d.ts +16 -0
  350. package/dist/types/modes/components/compaction-summary-message.d.ts +13 -0
  351. package/dist/types/modes/components/countdown-timer.d.ts +14 -0
  352. package/dist/types/modes/components/custom-editor.d.ts +47 -0
  353. package/dist/types/modes/components/custom-message.d.ts +15 -0
  354. package/dist/types/modes/components/diff.d.ts +11 -0
  355. package/dist/types/modes/components/dynamic-border.d.ts +14 -0
  356. package/dist/types/modes/components/eval-execution.d.ts +23 -0
  357. package/dist/types/modes/components/execution-shared.d.ts +46 -0
  358. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +26 -0
  359. package/dist/types/modes/components/extensions/extension-list.d.ts +39 -0
  360. package/dist/types/modes/components/extensions/index.d.ts +8 -0
  361. package/dist/types/modes/components/extensions/inspector-panel.d.ts +8 -0
  362. package/dist/types/modes/components/extensions/state-manager.d.ts +50 -0
  363. package/dist/types/modes/components/extensions/types.d.ts +151 -0
  364. package/dist/types/modes/components/footer.d.ts +30 -0
  365. package/dist/types/modes/components/history-search.d.ts +7 -0
  366. package/dist/types/modes/components/hook-editor.d.ts +18 -0
  367. package/dist/types/modes/components/hook-input.d.ts +15 -0
  368. package/dist/types/modes/components/hook-message.d.ts +15 -0
  369. package/dist/types/modes/components/hook-selector.d.ts +23 -0
  370. package/dist/types/modes/components/index.d.ts +35 -0
  371. package/dist/types/modes/components/keybinding-hints.d.ts +40 -0
  372. package/dist/types/modes/components/login-dialog.d.ts +32 -0
  373. package/dist/types/modes/components/message-frame.d.ts +42 -0
  374. package/dist/types/modes/components/model-selector.d.ts +26 -0
  375. package/dist/types/modes/components/oauth-selector.d.ts +14 -0
  376. package/dist/types/modes/components/plugin-selector.d.ts +26 -0
  377. package/dist/types/modes/components/plugin-settings.d.ts +66 -0
  378. package/dist/types/modes/components/provider-onboarding-selector.d.ts +7 -0
  379. package/dist/types/modes/components/queue-mode-selector.d.ts +9 -0
  380. package/dist/types/modes/components/read-tool-group.d.ts +30 -0
  381. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +25 -0
  382. package/dist/types/modes/components/session-observer-overlay.d.ts +11 -0
  383. package/dist/types/modes/components/session-selector.d.ts +30 -0
  384. package/dist/types/modes/components/settings-defs.d.ts +50 -0
  385. package/dist/types/modes/components/settings-selector.d.ts +54 -0
  386. package/dist/types/modes/components/show-images-selector.d.ts +9 -0
  387. package/dist/types/modes/components/skill-hud/render.d.ts +2 -0
  388. package/dist/types/modes/components/skill-message.d.ts +9 -0
  389. package/dist/types/modes/components/status-line/context-thresholds.d.ts +4 -0
  390. package/dist/types/modes/components/status-line/git-utils.d.ts +22 -0
  391. package/dist/types/modes/components/status-line/index.d.ts +4 -0
  392. package/dist/types/modes/components/status-line/presets.d.ts +3 -0
  393. package/dist/types/modes/components/status-line/segments.d.ts +5 -0
  394. package/dist/types/modes/components/status-line/separators.d.ts +3 -0
  395. package/dist/types/modes/components/status-line/token-rate.d.ts +10 -0
  396. package/dist/types/modes/components/status-line/types.d.ts +80 -0
  397. package/dist/types/modes/components/status-line.d.ts +80 -0
  398. package/dist/types/modes/components/theme-selector.d.ts +10 -0
  399. package/dist/types/modes/components/thinking-selector.d.ts +10 -0
  400. package/dist/types/modes/components/todo-reminder.d.ts +13 -0
  401. package/dist/types/modes/components/tool-execution.d.ts +53 -0
  402. package/dist/types/modes/components/tree-selector.d.ts +31 -0
  403. package/dist/types/modes/components/ttsr-notification.d.ts +13 -0
  404. package/dist/types/modes/components/user-message-selector.d.ts +28 -0
  405. package/dist/types/modes/components/user-message.d.ts +7 -0
  406. package/dist/types/modes/components/visual-truncate.d.ts +19 -0
  407. package/dist/types/modes/components/welcome.d.ts +34 -0
  408. package/dist/types/modes/controllers/btw-controller.d.ts +10 -0
  409. package/dist/types/modes/controllers/command-controller-shared.d.ts +47 -0
  410. package/dist/types/modes/controllers/command-controller.d.ts +36 -0
  411. package/dist/types/modes/controllers/event-controller.d.ts +12 -0
  412. package/dist/types/modes/controllers/extension-ui-controller.d.ts +80 -0
  413. package/dist/types/modes/controllers/input-controller.d.ts +35 -0
  414. package/dist/types/modes/controllers/runtime-mcp-command-controller.d.ts +10 -0
  415. package/dist/types/modes/controllers/selector-controller.d.ts +46 -0
  416. package/dist/types/modes/controllers/ssh-command-controller.d.ts +10 -0
  417. package/dist/types/modes/controllers/todo-command-controller.d.ts +7 -0
  418. package/dist/types/modes/emoji-autocomplete.d.ts +16 -0
  419. package/dist/types/modes/index.d.ts +9 -0
  420. package/dist/types/modes/interactive-mode.d.ts +271 -0
  421. package/dist/types/modes/loop-limit.d.ts +22 -0
  422. package/dist/types/modes/oauth-manual-input.d.ts +8 -0
  423. package/dist/types/modes/print-mode.d.ts +27 -0
  424. package/dist/types/modes/prompt-action-autocomplete.d.ts +46 -0
  425. package/dist/types/modes/rpc/host-tools.d.ts +16 -0
  426. package/dist/types/modes/rpc/host-uris.d.ts +38 -0
  427. package/dist/types/modes/rpc/rpc-client.d.ts +249 -0
  428. package/dist/types/modes/rpc/rpc-mode.d.ts +17 -0
  429. package/dist/types/modes/rpc/rpc-types.d.ts +586 -0
  430. package/dist/types/modes/runtime-init.d.ts +21 -0
  431. package/dist/types/modes/session-observer-registry.d.ts +26 -0
  432. package/dist/types/modes/shared.d.ts +15 -0
  433. package/dist/types/modes/theme/defaults/index.d.ts +9559 -0
  434. package/dist/types/modes/theme/mermaid-cache.d.ts +9 -0
  435. package/dist/types/modes/theme/shimmer.d.ts +38 -0
  436. package/dist/types/modes/theme/theme.d.ts +273 -0
  437. package/dist/types/modes/types.d.ts +278 -0
  438. package/dist/types/modes/utils/context-usage.d.ts +47 -0
  439. package/dist/types/modes/utils/hotkeys-markdown.d.ts +5 -0
  440. package/dist/types/modes/utils/keybinding-matchers.d.ts +10 -0
  441. package/dist/types/modes/utils/tools-markdown.d.ts +5 -0
  442. package/dist/types/modes/utils/ui-helpers.d.ts +53 -0
  443. package/dist/types/plan-mode/approved-plan.d.ts +49 -0
  444. package/dist/types/plan-mode/state.d.ts +6 -0
  445. package/dist/types/registry/agent-registry.d.ts +62 -0
  446. package/dist/types/runtime-mcp/client.d.ts +74 -0
  447. package/dist/types/runtime-mcp/config-writer.d.ts +53 -0
  448. package/dist/types/runtime-mcp/config.d.ts +75 -0
  449. package/dist/types/runtime-mcp/discoverable-tool-metadata.d.ts +7 -0
  450. package/dist/types/runtime-mcp/index.d.ts +18 -0
  451. package/dist/types/runtime-mcp/json-rpc.d.ts +22 -0
  452. package/dist/types/runtime-mcp/loader.d.ts +43 -0
  453. package/dist/types/runtime-mcp/manager.d.ts +193 -0
  454. package/dist/types/runtime-mcp/oauth-discovery.d.ts +40 -0
  455. package/dist/types/runtime-mcp/oauth-flow.d.ts +59 -0
  456. package/dist/types/runtime-mcp/render.d.ts +25 -0
  457. package/dist/types/runtime-mcp/smithery-auth.d.ts +16 -0
  458. package/dist/types/runtime-mcp/smithery-connect.d.ts +38 -0
  459. package/dist/types/runtime-mcp/smithery-registry.d.ts +51 -0
  460. package/dist/types/runtime-mcp/tool-bridge.d.ts +86 -0
  461. package/dist/types/runtime-mcp/tool-cache.d.ts +8 -0
  462. package/dist/types/runtime-mcp/transports/http.d.ts +36 -0
  463. package/dist/types/runtime-mcp/transports/index.d.ts +5 -0
  464. package/dist/types/runtime-mcp/transports/stdio.d.ts +32 -0
  465. package/dist/types/runtime-mcp/types.d.ts +333 -0
  466. package/dist/types/sdk.d.ts +216 -0
  467. package/dist/types/secrets/index.d.ts +9 -0
  468. package/dist/types/secrets/obfuscator.d.ts +23 -0
  469. package/dist/types/secrets/regex.d.ts +2 -0
  470. package/dist/types/session/agent-session.d.ts +930 -0
  471. package/dist/types/session/agent-storage.d.ts +100 -0
  472. package/dist/types/session/artifacts.d.ts +61 -0
  473. package/dist/types/session/auth-broker-config.d.ts +13 -0
  474. package/dist/types/session/auth-storage.d.ts +6 -0
  475. package/dist/types/session/blob-store.d.ts +63 -0
  476. package/dist/types/session/client-bridge.d.ts +88 -0
  477. package/dist/types/session/history-storage.d.ts +16 -0
  478. package/dist/types/session/messages.d.ts +162 -0
  479. package/dist/types/session/session-dump-format.d.ts +22 -0
  480. package/dist/types/session/session-manager.d.ts +549 -0
  481. package/dist/types/session/session-storage.d.ts +82 -0
  482. package/dist/types/session/streaming-output.d.ts +185 -0
  483. package/dist/types/session/tool-choice-queue.d.ts +78 -0
  484. package/dist/types/session/yield-queue.d.ts +24 -0
  485. package/dist/types/setup/model-onboarding-guidance.d.ts +8 -0
  486. package/dist/types/setup/provider-onboarding.d.ts +28 -0
  487. package/dist/types/skill-state/active-state.d.ts +50 -0
  488. package/dist/types/slash-commands/acp-builtins.d.ts +18 -0
  489. package/dist/types/slash-commands/builtin-registry.d.ts +23 -0
  490. package/dist/types/slash-commands/helpers/context-report.d.ts +7 -0
  491. package/dist/types/slash-commands/helpers/format.d.ts +10 -0
  492. package/dist/types/slash-commands/helpers/mcp.d.ts +3 -0
  493. package/dist/types/slash-commands/helpers/parse.d.ts +33 -0
  494. package/dist/types/slash-commands/helpers/ssh.d.ts +3 -0
  495. package/dist/types/slash-commands/helpers/todo.d.ts +3 -0
  496. package/dist/types/slash-commands/helpers/usage-report.d.ts +7 -0
  497. package/dist/types/slash-commands/types.d.ts +118 -0
  498. package/dist/types/ssh/config-writer.d.ts +49 -0
  499. package/dist/types/ssh/connection-manager.d.ts +33 -0
  500. package/dist/types/ssh/ssh-executor.d.ts +37 -0
  501. package/dist/types/ssh/sshfs-mount.d.ts +6 -0
  502. package/dist/types/ssh/utils.d.ts +2 -0
  503. package/dist/types/stt/downloader.d.ts +9 -0
  504. package/dist/types/stt/index.d.ts +3 -0
  505. package/dist/types/stt/recorder.d.ts +13 -0
  506. package/dist/types/stt/setup.d.ts +18 -0
  507. package/dist/types/stt/stt-controller.d.ts +16 -0
  508. package/dist/types/stt/transcriber.d.ts +16 -0
  509. package/dist/types/system-prompt.d.ts +93 -0
  510. package/dist/types/task/agents.d.ts +28 -0
  511. package/dist/types/task/commands.d.ts +35 -0
  512. package/dist/types/task/discovery.d.ts +19 -0
  513. package/dist/types/task/executor.d.ts +106 -0
  514. package/dist/types/task/gjc-command.d.ts +7 -0
  515. package/dist/types/task/index.d.ts +38 -0
  516. package/dist/types/task/name-generator.d.ts +16 -0
  517. package/dist/types/task/output-manager.d.ts +36 -0
  518. package/dist/types/task/parallel.d.ts +34 -0
  519. package/dist/types/task/render.d.ts +22 -0
  520. package/dist/types/task/simple-mode.d.ts +8 -0
  521. package/dist/types/task/subprocess-tool-registry.d.ts +72 -0
  522. package/dist/types/task/types.d.ts +295 -0
  523. package/dist/types/task/worktree.d.ts +94 -0
  524. package/dist/types/thinking.d.ts +30 -0
  525. package/dist/types/tool-discovery/tool-index.d.ts +112 -0
  526. package/dist/types/tools/archive-reader.d.ts +40 -0
  527. package/dist/types/tools/ask.d.ts +109 -0
  528. package/dist/types/tools/ast-edit.d.ts +77 -0
  529. package/dist/types/tools/ast-grep.d.ts +69 -0
  530. package/dist/types/tools/auto-generated-guard.d.ts +17 -0
  531. package/dist/types/tools/bash-command-fixup.d.ts +11 -0
  532. package/dist/types/tools/bash-interactive.d.ts +16 -0
  533. package/dist/types/tools/bash-interceptor.d.ts +24 -0
  534. package/dist/types/tools/bash-pty-selection.d.ts +7 -0
  535. package/dist/types/tools/bash-skill-urls.d.ts +31 -0
  536. package/dist/types/tools/bash.d.ts +130 -0
  537. package/dist/types/tools/browser/attach.d.ts +34 -0
  538. package/dist/types/tools/browser/launch.d.ts +62 -0
  539. package/dist/types/tools/browser/readable.d.ts +17 -0
  540. package/dist/types/tools/browser/registry.d.ts +42 -0
  541. package/dist/types/tools/browser/render.d.ts +50 -0
  542. package/dist/types/tools/browser/tab-protocol.d.ts +144 -0
  543. package/dist/types/tools/browser/tab-supervisor.d.ts +63 -0
  544. package/dist/types/tools/browser/tab-worker-entry.d.ts +1 -0
  545. package/dist/types/tools/browser/tab-worker.d.ts +19 -0
  546. package/dist/types/tools/browser.d.ts +114 -0
  547. package/dist/types/tools/calculator.d.ts +76 -0
  548. package/dist/types/tools/checkpoint.d.ts +63 -0
  549. package/dist/types/tools/conflict-detect.d.ts +205 -0
  550. package/dist/types/tools/context.d.ts +19 -0
  551. package/dist/types/tools/debug.d.ts +209 -0
  552. package/dist/types/tools/eval.d.ts +108 -0
  553. package/dist/types/tools/fetch.d.ts +61 -0
  554. package/dist/types/tools/file-recorder.d.ts +13 -0
  555. package/dist/types/tools/find.d.ts +95 -0
  556. package/dist/types/tools/fs-cache-invalidation.d.ts +15 -0
  557. package/dist/types/tools/gh-format.d.ts +6 -0
  558. package/dist/types/tools/gh-renderer.d.ts +25 -0
  559. package/dist/types/tools/gh.d.ts +356 -0
  560. package/dist/types/tools/github-cache.d.ts +103 -0
  561. package/dist/types/tools/grouped-file-output.d.ts +36 -0
  562. package/dist/types/tools/hindsight-recall.d.ts +23 -0
  563. package/dist/types/tools/hindsight-reflect.d.ts +25 -0
  564. package/dist/types/tools/hindsight-retain.d.ts +29 -0
  565. package/dist/types/tools/image-gen.d.ts +78 -0
  566. package/dist/types/tools/index.d.ts +242 -0
  567. package/dist/types/tools/inspect-image-renderer.d.ts +26 -0
  568. package/dist/types/tools/inspect-image.d.ts +31 -0
  569. package/dist/types/tools/irc.d.ts +79 -0
  570. package/dist/types/tools/job.d.ts +65 -0
  571. package/dist/types/tools/json-tree.d.ts +23 -0
  572. package/dist/types/tools/jtd-to-json-schema.d.ts +29 -0
  573. package/dist/types/tools/jtd-to-typescript.d.ts +26 -0
  574. package/dist/types/tools/jtd-utils.d.ts +42 -0
  575. package/dist/types/tools/list-limit.d.ts +12 -0
  576. package/dist/types/tools/match-line-format.d.ts +11 -0
  577. package/dist/types/tools/output-meta.d.ts +204 -0
  578. package/dist/types/tools/path-utils.d.ts +146 -0
  579. package/dist/types/tools/plan-mode-guard.d.ts +18 -0
  580. package/dist/types/tools/read.d.ts +85 -0
  581. package/dist/types/tools/recipe/index.d.ts +45 -0
  582. package/dist/types/tools/recipe/render.d.ts +36 -0
  583. package/dist/types/tools/recipe/runner.d.ts +60 -0
  584. package/dist/types/tools/recipe/runners/cargo.d.ts +16 -0
  585. package/dist/types/tools/recipe/runners/index.d.ts +2 -0
  586. package/dist/types/tools/recipe/runners/just.d.ts +2 -0
  587. package/dist/types/tools/recipe/runners/make.d.ts +2 -0
  588. package/dist/types/tools/recipe/runners/pkg.d.ts +2 -0
  589. package/dist/types/tools/recipe/runners/task.d.ts +2 -0
  590. package/dist/types/tools/render-mermaid.d.ts +37 -0
  591. package/dist/types/tools/render-utils.d.ts +158 -0
  592. package/dist/types/tools/renderers.d.ts +26 -0
  593. package/dist/types/tools/resolve.d.ts +90 -0
  594. package/dist/types/tools/review.d.ts +63 -0
  595. package/dist/types/tools/search-tool-bm25.d.ts +65 -0
  596. package/dist/types/tools/search.d.ts +93 -0
  597. package/dist/types/tools/sqlite-reader.d.ts +93 -0
  598. package/dist/types/tools/ssh.d.ts +67 -0
  599. package/dist/types/tools/subagent.d.ts +58 -0
  600. package/dist/types/tools/todo-write.d.ts +120 -0
  601. package/dist/types/tools/tool-errors.d.ts +33 -0
  602. package/dist/types/tools/tool-result.d.ts +30 -0
  603. package/dist/types/tools/tool-timeouts.d.ts +51 -0
  604. package/dist/types/tools/vim.d.ts +58 -0
  605. package/dist/types/tools/write.d.ts +59 -0
  606. package/dist/types/tools/yield.d.ts +25 -0
  607. package/dist/types/tui/code-cell.d.ts +32 -0
  608. package/dist/types/tui/file-list.d.ts +22 -0
  609. package/dist/types/tui/hyperlink.d.ts +42 -0
  610. package/dist/types/tui/index.d.ts +11 -0
  611. package/dist/types/tui/output-block.d.ts +28 -0
  612. package/dist/types/tui/status-line.d.ts +18 -0
  613. package/dist/types/tui/tree-list.d.ts +19 -0
  614. package/dist/types/tui/types.d.ts +13 -0
  615. package/dist/types/tui/utils.d.ts +36 -0
  616. package/dist/types/utils/changelog.d.ts +20 -0
  617. package/dist/types/utils/clipboard.d.ts +22 -0
  618. package/dist/types/utils/command-args.d.ts +9 -0
  619. package/dist/types/utils/commit-message-generator.d.ts +7 -0
  620. package/dist/types/utils/edit-mode.d.ts +13 -0
  621. package/dist/types/utils/event-bus.d.ts +6 -0
  622. package/dist/types/utils/external-editor.d.ts +17 -0
  623. package/dist/types/utils/file-display-mode.d.ts +27 -0
  624. package/dist/types/utils/file-mentions.d.ts +11 -0
  625. package/dist/types/utils/git.d.ts +361 -0
  626. package/dist/types/utils/image-loading.d.ts +26 -0
  627. package/dist/types/utils/image-resize.d.ts +39 -0
  628. package/dist/types/utils/lang-from-path.d.ts +8 -0
  629. package/dist/types/utils/markit.d.ts +7 -0
  630. package/dist/types/utils/open.d.ts +2 -0
  631. package/dist/types/utils/session-color.d.ts +10 -0
  632. package/dist/types/utils/shell-snapshot.d.ts +5 -0
  633. package/dist/types/utils/sixel.d.ts +21 -0
  634. package/dist/types/utils/title-generator.d.ts +31 -0
  635. package/dist/types/utils/tool-choice.d.ts +7 -0
  636. package/dist/types/utils/tools-manager.d.ts +9 -0
  637. package/dist/types/vim/buffer.d.ts +41 -0
  638. package/dist/types/vim/commands.d.ts +6 -0
  639. package/dist/types/vim/engine.d.ts +47 -0
  640. package/dist/types/vim/parser.d.ts +3 -0
  641. package/dist/types/vim/render.d.ts +25 -0
  642. package/dist/types/vim/types.d.ts +182 -0
  643. package/dist/types/web/kagi.d.ts +23 -0
  644. package/dist/types/web/parallel.d.ts +58 -0
  645. package/dist/types/web/scrapers/artifacthub.d.ts +6 -0
  646. package/dist/types/web/scrapers/arxiv.d.ts +5 -0
  647. package/dist/types/web/scrapers/aur.d.ts +5 -0
  648. package/dist/types/web/scrapers/biorxiv.d.ts +5 -0
  649. package/dist/types/web/scrapers/bluesky.d.ts +5 -0
  650. package/dist/types/web/scrapers/brew.d.ts +5 -0
  651. package/dist/types/web/scrapers/cheatsh.d.ts +8 -0
  652. package/dist/types/web/scrapers/chocolatey.d.ts +5 -0
  653. package/dist/types/web/scrapers/choosealicense.d.ts +2 -0
  654. package/dist/types/web/scrapers/cisa-kev.d.ts +5 -0
  655. package/dist/types/web/scrapers/clojars.d.ts +5 -0
  656. package/dist/types/web/scrapers/coingecko.d.ts +5 -0
  657. package/dist/types/web/scrapers/crates-io.d.ts +5 -0
  658. package/dist/types/web/scrapers/crossref.d.ts +2 -0
  659. package/dist/types/web/scrapers/devto.d.ts +5 -0
  660. package/dist/types/web/scrapers/discogs.d.ts +8 -0
  661. package/dist/types/web/scrapers/discourse.d.ts +5 -0
  662. package/dist/types/web/scrapers/dockerhub.d.ts +5 -0
  663. package/dist/types/web/scrapers/docs-rs.d.ts +2 -0
  664. package/dist/types/web/scrapers/fdroid.d.ts +5 -0
  665. package/dist/types/web/scrapers/firefox-addons.d.ts +2 -0
  666. package/dist/types/web/scrapers/flathub.d.ts +2 -0
  667. package/dist/types/web/scrapers/github-gist.d.ts +5 -0
  668. package/dist/types/web/scrapers/github.d.ts +12 -0
  669. package/dist/types/web/scrapers/gitlab.d.ts +5 -0
  670. package/dist/types/web/scrapers/go-pkg.d.ts +5 -0
  671. package/dist/types/web/scrapers/hackage.d.ts +5 -0
  672. package/dist/types/web/scrapers/hackernews.d.ts +2 -0
  673. package/dist/types/web/scrapers/hex.d.ts +5 -0
  674. package/dist/types/web/scrapers/huggingface.d.ts +2 -0
  675. package/dist/types/web/scrapers/iacr.d.ts +5 -0
  676. package/dist/types/web/scrapers/index.d.ts +84 -0
  677. package/dist/types/web/scrapers/jetbrains-marketplace.d.ts +2 -0
  678. package/dist/types/web/scrapers/lemmy.d.ts +2 -0
  679. package/dist/types/web/scrapers/lobsters.d.ts +5 -0
  680. package/dist/types/web/scrapers/mastodon.d.ts +5 -0
  681. package/dist/types/web/scrapers/maven.d.ts +6 -0
  682. package/dist/types/web/scrapers/mdn.d.ts +2 -0
  683. package/dist/types/web/scrapers/metacpan.d.ts +5 -0
  684. package/dist/types/web/scrapers/musicbrainz.d.ts +5 -0
  685. package/dist/types/web/scrapers/npm.d.ts +5 -0
  686. package/dist/types/web/scrapers/nuget.d.ts +5 -0
  687. package/dist/types/web/scrapers/nvd.d.ts +5 -0
  688. package/dist/types/web/scrapers/ollama.d.ts +2 -0
  689. package/dist/types/web/scrapers/open-vsx.d.ts +5 -0
  690. package/dist/types/web/scrapers/opencorporates.d.ts +5 -0
  691. package/dist/types/web/scrapers/openlibrary.d.ts +5 -0
  692. package/dist/types/web/scrapers/orcid.d.ts +5 -0
  693. package/dist/types/web/scrapers/osv.d.ts +5 -0
  694. package/dist/types/web/scrapers/packagist.d.ts +5 -0
  695. package/dist/types/web/scrapers/pub-dev.d.ts +5 -0
  696. package/dist/types/web/scrapers/pubmed.d.ts +5 -0
  697. package/dist/types/web/scrapers/pypi.d.ts +5 -0
  698. package/dist/types/web/scrapers/rawg.d.ts +2 -0
  699. package/dist/types/web/scrapers/readthedocs.d.ts +2 -0
  700. package/dist/types/web/scrapers/reddit.d.ts +5 -0
  701. package/dist/types/web/scrapers/repology.d.ts +5 -0
  702. package/dist/types/web/scrapers/rfc.d.ts +5 -0
  703. package/dist/types/web/scrapers/rubygems.d.ts +5 -0
  704. package/dist/types/web/scrapers/searchcode.d.ts +2 -0
  705. package/dist/types/web/scrapers/sec-edgar.d.ts +5 -0
  706. package/dist/types/web/scrapers/semantic-scholar.d.ts +2 -0
  707. package/dist/types/web/scrapers/snapcraft.d.ts +2 -0
  708. package/dist/types/web/scrapers/sourcegraph.d.ts +2 -0
  709. package/dist/types/web/scrapers/spdx.d.ts +5 -0
  710. package/dist/types/web/scrapers/spotify.d.ts +8 -0
  711. package/dist/types/web/scrapers/stackoverflow.d.ts +6 -0
  712. package/dist/types/web/scrapers/terraform.d.ts +5 -0
  713. package/dist/types/web/scrapers/tldr.d.ts +7 -0
  714. package/dist/types/web/scrapers/twitter.d.ts +5 -0
  715. package/dist/types/web/scrapers/types.d.ts +78 -0
  716. package/dist/types/web/scrapers/utils.d.ts +26 -0
  717. package/dist/types/web/scrapers/vimeo.d.ts +5 -0
  718. package/dist/types/web/scrapers/vscode-marketplace.d.ts +5 -0
  719. package/dist/types/web/scrapers/w3c.d.ts +2 -0
  720. package/dist/types/web/scrapers/wikidata.d.ts +5 -0
  721. package/dist/types/web/scrapers/wikipedia.d.ts +5 -0
  722. package/dist/types/web/scrapers/youtube.d.ts +5 -0
  723. package/dist/types/web/search/index.d.ts +84 -0
  724. package/dist/types/web/search/provider.d.ts +21 -0
  725. package/dist/types/web/search/providers/anthropic.d.ts +32 -0
  726. package/dist/types/web/search/providers/base.d.ts +67 -0
  727. package/dist/types/web/search/providers/brave.d.ts +27 -0
  728. package/dist/types/web/search/providers/codex.d.ts +35 -0
  729. package/dist/types/web/search/providers/exa.d.ts +52 -0
  730. package/dist/types/web/search/providers/gemini.d.ts +57 -0
  731. package/dist/types/web/search/providers/jina.d.ts +26 -0
  732. package/dist/types/web/search/providers/kagi.d.ts +24 -0
  733. package/dist/types/web/search/providers/kimi.d.ts +27 -0
  734. package/dist/types/web/search/providers/parallel.d.ts +15 -0
  735. package/dist/types/web/search/providers/perplexity.d.ts +38 -0
  736. package/dist/types/web/search/providers/searxng.d.ts +44 -0
  737. package/dist/types/web/search/providers/synthetic.d.ts +21 -0
  738. package/dist/types/web/search/providers/tavily.d.ts +29 -0
  739. package/dist/types/web/search/providers/utils.d.ts +52 -0
  740. package/dist/types/web/search/providers/zai.d.ts +28 -0
  741. package/dist/types/web/search/render.d.ts +35 -0
  742. package/dist/types/web/search/types.d.ts +344 -0
  743. package/dist/types/web/search/utils.d.ts +4 -0
  744. package/dist/types/workspace-tree.d.ts +42 -0
  745. package/examples/README.md +21 -0
  746. package/examples/custom-tools/README.md +104 -0
  747. package/examples/custom-tools/hello/index.ts +20 -0
  748. package/examples/extensions/README.md +141 -0
  749. package/examples/extensions/api-demo.ts +79 -0
  750. package/examples/extensions/chalk-logger.ts +25 -0
  751. package/examples/extensions/hello.ts +31 -0
  752. package/examples/extensions/pirate.ts +43 -0
  753. package/examples/extensions/plan-mode.ts +549 -0
  754. package/examples/extensions/reload-runtime.ts +38 -0
  755. package/examples/extensions/tools.ts +144 -0
  756. package/examples/extensions/with-deps/index.ts +36 -0
  757. package/examples/extensions/with-deps/package-lock.json +31 -0
  758. package/examples/extensions/with-deps/package.json +16 -0
  759. package/examples/hooks/README.md +56 -0
  760. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  761. package/examples/hooks/confirm-destructive.ts +58 -0
  762. package/examples/hooks/custom-compaction.ts +115 -0
  763. package/examples/hooks/dirty-repo-guard.ts +51 -0
  764. package/examples/hooks/file-trigger.ts +40 -0
  765. package/examples/hooks/git-checkpoint.ts +52 -0
  766. package/examples/hooks/handoff.ts +149 -0
  767. package/examples/hooks/permission-gate.ts +33 -0
  768. package/examples/hooks/protected-paths.ts +29 -0
  769. package/examples/hooks/qna.ts +118 -0
  770. package/examples/hooks/status-line.ts +39 -0
  771. package/examples/sdk/01-minimal.ts +21 -0
  772. package/examples/sdk/02-custom-model.ts +49 -0
  773. package/examples/sdk/03-custom-prompt.ts +46 -0
  774. package/examples/sdk/04-skills.ts +43 -0
  775. package/examples/sdk/06-extensions.ts +82 -0
  776. package/examples/sdk/06-hooks.ts +61 -0
  777. package/examples/sdk/07-context-files.ts +35 -0
  778. package/examples/sdk/08-prompt-templates.ts +41 -0
  779. package/examples/sdk/08-slash-commands.ts +46 -0
  780. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  781. package/examples/sdk/11-sessions.ts +47 -0
  782. package/examples/sdk/README.md +172 -0
  783. package/package.json +533 -0
  784. package/scripts/build-binary.ts +77 -0
  785. package/scripts/format-prompts.ts +68 -0
  786. package/scripts/generate-docs-index.ts +71 -0
  787. package/scripts/generate-template.ts +33 -0
  788. package/src/async/index.ts +2 -0
  789. package/src/async/job-manager.ts +586 -0
  790. package/src/async/support.ts +6 -0
  791. package/src/autoresearch/command-resume.md +14 -0
  792. package/src/autoresearch/dashboard.ts +446 -0
  793. package/src/autoresearch/git.ts +319 -0
  794. package/src/autoresearch/helpers.ts +218 -0
  795. package/src/autoresearch/index.ts +536 -0
  796. package/src/autoresearch/prompt-setup.md +43 -0
  797. package/src/autoresearch/prompt.md +103 -0
  798. package/src/autoresearch/resume-message.md +10 -0
  799. package/src/autoresearch/state.ts +273 -0
  800. package/src/autoresearch/storage.ts +699 -0
  801. package/src/autoresearch/tools/init-experiment.ts +272 -0
  802. package/src/autoresearch/tools/log-experiment.ts +524 -0
  803. package/src/autoresearch/tools/run-experiment.ts +475 -0
  804. package/src/autoresearch/tools/update-notes.ts +109 -0
  805. package/src/autoresearch/types.ts +168 -0
  806. package/src/bun-imports.d.ts +28 -0
  807. package/src/capability/context-file.ts +44 -0
  808. package/src/capability/extension-module.ts +34 -0
  809. package/src/capability/extension.ts +47 -0
  810. package/src/capability/fs.ts +107 -0
  811. package/src/capability/hook.ts +40 -0
  812. package/src/capability/index.ts +436 -0
  813. package/src/capability/instruction.ts +37 -0
  814. package/src/capability/mcp.ts +74 -0
  815. package/src/capability/prompt.ts +35 -0
  816. package/src/capability/rule.ts +244 -0
  817. package/src/capability/settings.ts +34 -0
  818. package/src/capability/skill.ts +56 -0
  819. package/src/capability/slash-command.ts +40 -0
  820. package/src/capability/ssh.ts +41 -0
  821. package/src/capability/system-prompt.ts +34 -0
  822. package/src/capability/tool.ts +38 -0
  823. package/src/capability/types.ts +168 -0
  824. package/src/cli/agents-cli.ts +138 -0
  825. package/src/cli/args.ts +269 -0
  826. package/src/cli/auth-broker-cli.ts +746 -0
  827. package/src/cli/auth-gateway-cli.ts +411 -0
  828. package/src/cli/classify-install-target.ts +50 -0
  829. package/src/cli/commands/init-xdg.ts +27 -0
  830. package/src/cli/config-cli.ts +418 -0
  831. package/src/cli/file-processor.ts +123 -0
  832. package/src/cli/grep-cli.ts +160 -0
  833. package/src/cli/initial-message.ts +58 -0
  834. package/src/cli/list-models.ts +194 -0
  835. package/src/cli/plugin-cli.ts +942 -0
  836. package/src/cli/read-cli.ts +57 -0
  837. package/src/cli/session-picker.ts +52 -0
  838. package/src/cli/setup-cli.ts +433 -0
  839. package/src/cli/shell-cli.ts +176 -0
  840. package/src/cli/ssh-cli.ts +179 -0
  841. package/src/cli/stats-cli.ts +238 -0
  842. package/src/cli/update-cli.ts +408 -0
  843. package/src/cli/web-search-cli.ts +133 -0
  844. package/src/cli/worktree-cli.ts +291 -0
  845. package/src/cli.ts +99 -0
  846. package/src/commands/acp.ts +24 -0
  847. package/src/commands/agents.ts +57 -0
  848. package/src/commands/auth-broker.ts +96 -0
  849. package/src/commands/auth-gateway.ts +63 -0
  850. package/src/commands/codex-native-hook.ts +11 -0
  851. package/src/commands/commit.ts +46 -0
  852. package/src/commands/config.ts +51 -0
  853. package/src/commands/deep-interview.ts +12 -0
  854. package/src/commands/gjc-runtime-bridge.ts +81 -0
  855. package/src/commands/grep.ts +48 -0
  856. package/src/commands/launch.ts +161 -0
  857. package/src/commands/plugin.ts +78 -0
  858. package/src/commands/question.ts +12 -0
  859. package/src/commands/ralplan.ts +12 -0
  860. package/src/commands/read.ts +35 -0
  861. package/src/commands/setup.ts +52 -0
  862. package/src/commands/shell.ts +29 -0
  863. package/src/commands/ssh.ts +60 -0
  864. package/src/commands/state.ts +12 -0
  865. package/src/commands/stats.ts +29 -0
  866. package/src/commands/team.ts +130 -0
  867. package/src/commands/ultragoal.ts +32 -0
  868. package/src/commands/update.ts +21 -0
  869. package/src/commands/web-search.ts +42 -0
  870. package/src/commands/worktree.ts +56 -0
  871. package/src/commit/agentic/agent.ts +316 -0
  872. package/src/commit/agentic/fallback.ts +96 -0
  873. package/src/commit/agentic/index.ts +355 -0
  874. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  875. package/src/commit/agentic/prompts/session-user.md +25 -0
  876. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  877. package/src/commit/agentic/prompts/system.md +38 -0
  878. package/src/commit/agentic/state.ts +60 -0
  879. package/src/commit/agentic/tools/analyze-file.ts +127 -0
  880. package/src/commit/agentic/tools/git-file-diff.ts +191 -0
  881. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  882. package/src/commit/agentic/tools/git-overview.ts +81 -0
  883. package/src/commit/agentic/tools/index.ts +54 -0
  884. package/src/commit/agentic/tools/propose-changelog.ts +144 -0
  885. package/src/commit/agentic/tools/propose-commit.ts +109 -0
  886. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  887. package/src/commit/agentic/tools/schemas.ts +23 -0
  888. package/src/commit/agentic/tools/split-commit.ts +238 -0
  889. package/src/commit/agentic/topo-sort.ts +44 -0
  890. package/src/commit/agentic/trivial.ts +51 -0
  891. package/src/commit/agentic/validation.ts +183 -0
  892. package/src/commit/analysis/conventional.ts +64 -0
  893. package/src/commit/analysis/index.ts +4 -0
  894. package/src/commit/analysis/scope.ts +242 -0
  895. package/src/commit/analysis/summary.ts +105 -0
  896. package/src/commit/analysis/validation.ts +66 -0
  897. package/src/commit/changelog/detect.ts +40 -0
  898. package/src/commit/changelog/generate.ts +97 -0
  899. package/src/commit/changelog/index.ts +234 -0
  900. package/src/commit/changelog/parse.ts +44 -0
  901. package/src/commit/cli.ts +85 -0
  902. package/src/commit/git/diff.ts +148 -0
  903. package/src/commit/index.ts +5 -0
  904. package/src/commit/map-reduce/index.ts +69 -0
  905. package/src/commit/map-reduce/map-phase.ts +193 -0
  906. package/src/commit/map-reduce/reduce-phase.ts +49 -0
  907. package/src/commit/map-reduce/utils.ts +9 -0
  908. package/src/commit/message.ts +11 -0
  909. package/src/commit/model-selection.ts +66 -0
  910. package/src/commit/pipeline.ts +243 -0
  911. package/src/commit/prompts/analysis-system.md +148 -0
  912. package/src/commit/prompts/analysis-user.md +38 -0
  913. package/src/commit/prompts/changelog-system.md +50 -0
  914. package/src/commit/prompts/changelog-user.md +18 -0
  915. package/src/commit/prompts/file-observer-system.md +24 -0
  916. package/src/commit/prompts/file-observer-user.md +8 -0
  917. package/src/commit/prompts/reduce-system.md +50 -0
  918. package/src/commit/prompts/reduce-user.md +17 -0
  919. package/src/commit/prompts/summary-retry.md +3 -0
  920. package/src/commit/prompts/summary-system.md +38 -0
  921. package/src/commit/prompts/summary-user.md +13 -0
  922. package/src/commit/prompts/types-description.md +2 -0
  923. package/src/commit/shared-llm.ts +77 -0
  924. package/src/commit/types.ts +118 -0
  925. package/src/commit/utils/exclusions.ts +42 -0
  926. package/src/commit/utils.ts +58 -0
  927. package/src/config/config-file.ts +232 -0
  928. package/src/config/file-lock.ts +121 -0
  929. package/src/config/keybindings.ts +493 -0
  930. package/src/config/mcp-schema.json +230 -0
  931. package/src/config/model-equivalence.ts +811 -0
  932. package/src/config/model-registry.ts +2384 -0
  933. package/src/config/model-resolver.ts +1398 -0
  934. package/src/config/models-config-schema.ts +175 -0
  935. package/src/config/prompt-templates.ts +310 -0
  936. package/src/config/resolve-config-value.ts +94 -0
  937. package/src/config/settings-schema.ts +2939 -0
  938. package/src/config/settings.ts +919 -0
  939. package/src/config/skill-settings-defaults.ts +27 -0
  940. package/src/config.ts +212 -0
  941. package/src/cursor.ts +350 -0
  942. package/src/dap/client.ts +675 -0
  943. package/src/dap/config.ts +150 -0
  944. package/src/dap/defaults.json +211 -0
  945. package/src/dap/index.ts +4 -0
  946. package/src/dap/session.ts +1306 -0
  947. package/src/dap/types.ts +600 -0
  948. package/src/debug/index.ts +459 -0
  949. package/src/debug/log-formatting.ts +58 -0
  950. package/src/debug/log-viewer.ts +908 -0
  951. package/src/debug/profiler.ts +162 -0
  952. package/src/debug/raw-sse-buffer.ts +270 -0
  953. package/src/debug/raw-sse.ts +213 -0
  954. package/src/debug/report-bundle.ts +365 -0
  955. package/src/debug/system-info.ts +111 -0
  956. package/src/defaults/gjc/skills/deep-interview/SKILL.md +795 -0
  957. package/src/defaults/gjc/skills/ralplan/SKILL.md +142 -0
  958. package/src/defaults/gjc/skills/team/SKILL.md +373 -0
  959. package/src/defaults/gjc/skills/ultragoal/SKILL.md +176 -0
  960. package/src/defaults/gjc-defaults.ts +151 -0
  961. package/src/discovery/agents-md.ts +67 -0
  962. package/src/discovery/agents.ts +230 -0
  963. package/src/discovery/builtin.ts +932 -0
  964. package/src/discovery/claude-plugins.ts +387 -0
  965. package/src/discovery/claude.ts +313 -0
  966. package/src/discovery/cline.ts +83 -0
  967. package/src/discovery/codex.ts +330 -0
  968. package/src/discovery/cursor.ts +220 -0
  969. package/src/discovery/gemini.ts +383 -0
  970. package/src/discovery/github.ts +118 -0
  971. package/src/discovery/helpers.ts +964 -0
  972. package/src/discovery/index.ts +76 -0
  973. package/src/discovery/mcp-json.ts +171 -0
  974. package/src/discovery/opencode.ts +398 -0
  975. package/src/discovery/plugin-dir-roots.ts +28 -0
  976. package/src/discovery/ssh.ts +153 -0
  977. package/src/discovery/substitute-plugin-root.ts +29 -0
  978. package/src/discovery/vscode.ts +105 -0
  979. package/src/discovery/windsurf.ts +147 -0
  980. package/src/edit/apply-patch/index.ts +87 -0
  981. package/src/edit/apply-patch/parser.ts +174 -0
  982. package/src/edit/diff.ts +810 -0
  983. package/src/edit/file-read-cache.ts +95 -0
  984. package/src/edit/index.ts +528 -0
  985. package/src/edit/modes/apply-patch.lark +19 -0
  986. package/src/edit/modes/apply-patch.ts +53 -0
  987. package/src/edit/modes/patch.ts +1835 -0
  988. package/src/edit/modes/replace.ts +1103 -0
  989. package/src/edit/normalize.ts +375 -0
  990. package/src/edit/notebook.ts +222 -0
  991. package/src/edit/read-file.ts +25 -0
  992. package/src/edit/renderer.ts +683 -0
  993. package/src/edit/streaming.ts +561 -0
  994. package/src/eval/backend.ts +43 -0
  995. package/src/eval/index.ts +4 -0
  996. package/src/eval/js/context-manager.ts +414 -0
  997. package/src/eval/js/executor.ts +134 -0
  998. package/src/eval/js/index.ts +46 -0
  999. package/src/eval/js/shared/helpers.ts +237 -0
  1000. package/src/eval/js/shared/indirect-eval.ts +30 -0
  1001. package/src/eval/js/shared/prelude.ts +2 -0
  1002. package/src/eval/js/shared/prelude.txt +70 -0
  1003. package/src/eval/js/shared/rewrite-imports.ts +416 -0
  1004. package/src/eval/js/shared/runtime.ts +301 -0
  1005. package/src/eval/js/shared/types.ts +18 -0
  1006. package/src/eval/js/tool-bridge.ts +144 -0
  1007. package/src/eval/js/worker-core.ts +146 -0
  1008. package/src/eval/js/worker-entry.ts +24 -0
  1009. package/src/eval/js/worker-protocol.ts +41 -0
  1010. package/src/eval/py/display.ts +71 -0
  1011. package/src/eval/py/executor.ts +602 -0
  1012. package/src/eval/py/index.ts +58 -0
  1013. package/src/eval/py/kernel.ts +668 -0
  1014. package/src/eval/py/prelude.py +462 -0
  1015. package/src/eval/py/prelude.ts +3 -0
  1016. package/src/eval/py/runner.py +910 -0
  1017. package/src/eval/py/runtime.ts +210 -0
  1018. package/src/eval/py/tool-bridge.ts +137 -0
  1019. package/src/eval/types.ts +48 -0
  1020. package/src/exa/factory.ts +60 -0
  1021. package/src/exa/index.ts +27 -0
  1022. package/src/exa/mcp-client.ts +364 -0
  1023. package/src/exa/render.ts +244 -0
  1024. package/src/exa/researcher.ts +36 -0
  1025. package/src/exa/search.ts +47 -0
  1026. package/src/exa/types.ts +166 -0
  1027. package/src/exa/websets.ts +248 -0
  1028. package/src/exec/bash-executor.ts +309 -0
  1029. package/src/exec/exec.ts +53 -0
  1030. package/src/exec/idle-timeout-watchdog.ts +126 -0
  1031. package/src/exec/non-interactive-env.ts +48 -0
  1032. package/src/export/custom-share.ts +65 -0
  1033. package/src/export/html/index.ts +164 -0
  1034. package/src/export/html/template.css +1060 -0
  1035. package/src/export/html/template.generated.ts +2 -0
  1036. package/src/export/html/template.html +47 -0
  1037. package/src/export/html/template.js +2268 -0
  1038. package/src/export/html/template.macro.ts +25 -0
  1039. package/src/export/html/vendor/highlight.min.js +1213 -0
  1040. package/src/export/html/vendor/marked.min.js +6 -0
  1041. package/src/export/ttsr.ts +434 -0
  1042. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +25 -0
  1043. package/src/extensibility/custom-commands/bundled/review/index.ts +456 -0
  1044. package/src/extensibility/custom-commands/index.ts +2 -0
  1045. package/src/extensibility/custom-commands/loader.ts +238 -0
  1046. package/src/extensibility/custom-commands/types.ts +113 -0
  1047. package/src/extensibility/custom-tools/index.ts +7 -0
  1048. package/src/extensibility/custom-tools/loader.ts +245 -0
  1049. package/src/extensibility/custom-tools/types.ts +254 -0
  1050. package/src/extensibility/custom-tools/wrapper.ts +47 -0
  1051. package/src/extensibility/extensions/compact-handler.ts +40 -0
  1052. package/src/extensibility/extensions/get-commands-handler.ts +80 -0
  1053. package/src/extensibility/extensions/index.ts +15 -0
  1054. package/src/extensibility/extensions/loader.ts +545 -0
  1055. package/src/extensibility/extensions/runner.ts +900 -0
  1056. package/src/extensibility/extensions/types.ts +1259 -0
  1057. package/src/extensibility/extensions/wrapper.ts +189 -0
  1058. package/src/extensibility/hooks/index.ts +5 -0
  1059. package/src/extensibility/hooks/loader.ts +257 -0
  1060. package/src/extensibility/hooks/runner.ts +425 -0
  1061. package/src/extensibility/hooks/tool-wrapper.ts +107 -0
  1062. package/src/extensibility/hooks/types.ts +599 -0
  1063. package/src/extensibility/plugins/doctor.ts +66 -0
  1064. package/src/extensibility/plugins/git-url.ts +281 -0
  1065. package/src/extensibility/plugins/index.ts +9 -0
  1066. package/src/extensibility/plugins/installer.ts +192 -0
  1067. package/src/extensibility/plugins/legacy-pi-compat.ts +336 -0
  1068. package/src/extensibility/plugins/loader.ts +288 -0
  1069. package/src/extensibility/plugins/manager.ts +731 -0
  1070. package/src/extensibility/plugins/marketplace/cache.ts +136 -0
  1071. package/src/extensibility/plugins/marketplace/fetcher.ts +317 -0
  1072. package/src/extensibility/plugins/marketplace/index.ts +6 -0
  1073. package/src/extensibility/plugins/marketplace/manager.ts +770 -0
  1074. package/src/extensibility/plugins/marketplace/registry.ts +196 -0
  1075. package/src/extensibility/plugins/marketplace/source-resolver.ts +147 -0
  1076. package/src/extensibility/plugins/marketplace/types.ts +191 -0
  1077. package/src/extensibility/plugins/parser.ts +105 -0
  1078. package/src/extensibility/plugins/types.ts +194 -0
  1079. package/src/extensibility/shared-events.ts +343 -0
  1080. package/src/extensibility/skills.ts +391 -0
  1081. package/src/extensibility/slash-commands.ts +227 -0
  1082. package/src/extensibility/tool-proxy.ts +25 -0
  1083. package/src/extensibility/typebox.ts +418 -0
  1084. package/src/extensibility/utils.ts +44 -0
  1085. package/src/gjc-runtime/goal-mode-request.ts +212 -0
  1086. package/src/gjc-runtime/launch-tmux.ts +162 -0
  1087. package/src/gjc-runtime/launch-worktree.ts +291 -0
  1088. package/src/gjc-runtime/team-runtime.ts +2025 -0
  1089. package/src/gjc-runtime/ultragoal-runtime.ts +564 -0
  1090. package/src/goals/index.ts +3 -0
  1091. package/src/goals/runtime.ts +524 -0
  1092. package/src/goals/state.ts +37 -0
  1093. package/src/goals/tools/goal-tool.ts +371 -0
  1094. package/src/hashline/anchors.ts +113 -0
  1095. package/src/hashline/apply.ts +737 -0
  1096. package/src/hashline/bigrams.json +649 -0
  1097. package/src/hashline/constants.ts +25 -0
  1098. package/src/hashline/diff-preview.ts +43 -0
  1099. package/src/hashline/diff.ts +56 -0
  1100. package/src/hashline/execute.ts +267 -0
  1101. package/src/hashline/grammar.lark +21 -0
  1102. package/src/hashline/hash.ts +173 -0
  1103. package/src/hashline/index.ts +13 -0
  1104. package/src/hashline/input.ts +130 -0
  1105. package/src/hashline/parser.ts +246 -0
  1106. package/src/hashline/prefixes.ts +101 -0
  1107. package/src/hashline/recovery.ts +113 -0
  1108. package/src/hashline/stream.ts +123 -0
  1109. package/src/hashline/types.ts +68 -0
  1110. package/src/hindsight/backend.ts +205 -0
  1111. package/src/hindsight/bank.ts +131 -0
  1112. package/src/hindsight/client.ts +598 -0
  1113. package/src/hindsight/config.ts +175 -0
  1114. package/src/hindsight/content.ts +210 -0
  1115. package/src/hindsight/index.ts +8 -0
  1116. package/src/hindsight/mental-models.ts +382 -0
  1117. package/src/hindsight/seeds.json +32 -0
  1118. package/src/hindsight/state.ts +469 -0
  1119. package/src/hindsight/transcript.ts +71 -0
  1120. package/src/hooks/codex-native-hooks-config.ts +143 -0
  1121. package/src/hooks/native-skill-hook.ts +279 -0
  1122. package/src/hooks/skill-keywords.ts +86 -0
  1123. package/src/hooks/skill-state.ts +416 -0
  1124. package/src/index.ts +56 -0
  1125. package/src/internal-urls/agent-protocol.ts +129 -0
  1126. package/src/internal-urls/artifact-protocol.ts +80 -0
  1127. package/src/internal-urls/docs-index.generated.ts +81 -0
  1128. package/src/internal-urls/gjc-protocol.ts +83 -0
  1129. package/src/internal-urls/index.ts +21 -0
  1130. package/src/internal-urls/issue-pr-protocol.ts +577 -0
  1131. package/src/internal-urls/json-query.ts +126 -0
  1132. package/src/internal-urls/local-protocol.ts +249 -0
  1133. package/src/internal-urls/mcp-protocol.ts +151 -0
  1134. package/src/internal-urls/memory-protocol.ts +164 -0
  1135. package/src/internal-urls/parse.ts +72 -0
  1136. package/src/internal-urls/registry-helpers.ts +25 -0
  1137. package/src/internal-urls/router.ts +78 -0
  1138. package/src/internal-urls/rule-protocol.ts +38 -0
  1139. package/src/internal-urls/skill-protocol.ts +103 -0
  1140. package/src/internal-urls/types.ts +110 -0
  1141. package/src/lsp/client.ts +951 -0
  1142. package/src/lsp/clients/biome-client.ts +202 -0
  1143. package/src/lsp/clients/index.ts +50 -0
  1144. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  1145. package/src/lsp/clients/swiftlint-client.ts +120 -0
  1146. package/src/lsp/config.ts +492 -0
  1147. package/src/lsp/defaults.json +493 -0
  1148. package/src/lsp/edits.ts +166 -0
  1149. package/src/lsp/index.ts +2282 -0
  1150. package/src/lsp/lspmux.ts +233 -0
  1151. package/src/lsp/render.ts +692 -0
  1152. package/src/lsp/startup-events.ts +13 -0
  1153. package/src/lsp/types.ts +443 -0
  1154. package/src/lsp/utils.ts +678 -0
  1155. package/src/main.ts +961 -0
  1156. package/src/memories/index.ts +1135 -0
  1157. package/src/memories/storage.ts +577 -0
  1158. package/src/memory-backend/index.ts +4 -0
  1159. package/src/memory-backend/local-backend.ts +30 -0
  1160. package/src/memory-backend/off-backend.ts +16 -0
  1161. package/src/memory-backend/resolve.ts +24 -0
  1162. package/src/memory-backend/types.ts +79 -0
  1163. package/src/modes/acp/acp-agent.ts +2170 -0
  1164. package/src/modes/acp/acp-client-bridge.ts +154 -0
  1165. package/src/modes/acp/acp-event-mapper.ts +879 -0
  1166. package/src/modes/acp/acp-mode.ts +23 -0
  1167. package/src/modes/acp/index.ts +2 -0
  1168. package/src/modes/acp/terminal-auth.ts +37 -0
  1169. package/src/modes/components/agent-dashboard.ts +1120 -0
  1170. package/src/modes/components/assistant-message.ts +231 -0
  1171. package/src/modes/components/bash-execution.ts +228 -0
  1172. package/src/modes/components/bordered-loader.ts +41 -0
  1173. package/src/modes/components/branch-summary-message.ts +45 -0
  1174. package/src/modes/components/btw-panel.ts +104 -0
  1175. package/src/modes/components/compaction-summary-message.ts +51 -0
  1176. package/src/modes/components/countdown-timer.ts +75 -0
  1177. package/src/modes/components/custom-editor.ts +237 -0
  1178. package/src/modes/components/custom-message.ts +65 -0
  1179. package/src/modes/components/diff.ts +266 -0
  1180. package/src/modes/components/dynamic-border.ts +25 -0
  1181. package/src/modes/components/eval-execution.ts +164 -0
  1182. package/src/modes/components/execution-shared.ts +102 -0
  1183. package/src/modes/components/extensions/extension-dashboard.ts +350 -0
  1184. package/src/modes/components/extensions/extension-list.ts +492 -0
  1185. package/src/modes/components/extensions/index.ts +9 -0
  1186. package/src/modes/components/extensions/inspector-panel.ts +317 -0
  1187. package/src/modes/components/extensions/state-manager.ts +628 -0
  1188. package/src/modes/components/extensions/types.ts +191 -0
  1189. package/src/modes/components/footer.ts +270 -0
  1190. package/src/modes/components/history-search.ts +158 -0
  1191. package/src/modes/components/hook-editor.ts +151 -0
  1192. package/src/modes/components/hook-input.ts +79 -0
  1193. package/src/modes/components/hook-message.ts +68 -0
  1194. package/src/modes/components/hook-selector.ts +190 -0
  1195. package/src/modes/components/index.ts +36 -0
  1196. package/src/modes/components/keybinding-hints.ts +65 -0
  1197. package/src/modes/components/login-dialog.ts +164 -0
  1198. package/src/modes/components/message-frame.ts +88 -0
  1199. package/src/modes/components/model-selector.ts +794 -0
  1200. package/src/modes/components/oauth-selector.ts +248 -0
  1201. package/src/modes/components/plugin-selector.ts +95 -0
  1202. package/src/modes/components/plugin-settings.ts +488 -0
  1203. package/src/modes/components/provider-onboarding-selector.ts +88 -0
  1204. package/src/modes/components/queue-mode-selector.ts +56 -0
  1205. package/src/modes/components/read-tool-group.ts +267 -0
  1206. package/src/modes/components/runtime-mcp-add-wizard.ts +1341 -0
  1207. package/src/modes/components/session-observer-overlay.ts +839 -0
  1208. package/src/modes/components/session-selector.ts +343 -0
  1209. package/src/modes/components/settings-defs.ts +175 -0
  1210. package/src/modes/components/settings-selector.ts +635 -0
  1211. package/src/modes/components/show-images-selector.ts +45 -0
  1212. package/src/modes/components/skill-hud/render.ts +47 -0
  1213. package/src/modes/components/skill-message.ts +90 -0
  1214. package/src/modes/components/status-line/context-thresholds.ts +68 -0
  1215. package/src/modes/components/status-line/git-utils.ts +42 -0
  1216. package/src/modes/components/status-line/index.ts +4 -0
  1217. package/src/modes/components/status-line/presets.ts +105 -0
  1218. package/src/modes/components/status-line/segments.ts +560 -0
  1219. package/src/modes/components/status-line/separators.ts +55 -0
  1220. package/src/modes/components/status-line/token-rate.ts +66 -0
  1221. package/src/modes/components/status-line/types.ts +93 -0
  1222. package/src/modes/components/status-line.ts +839 -0
  1223. package/src/modes/components/theme-selector.ts +63 -0
  1224. package/src/modes/components/thinking-selector.ts +52 -0
  1225. package/src/modes/components/todo-reminder.ts +40 -0
  1226. package/src/modes/components/tool-execution.ts +830 -0
  1227. package/src/modes/components/tree-selector.ts +930 -0
  1228. package/src/modes/components/ttsr-notification.ts +80 -0
  1229. package/src/modes/components/user-message-selector.ts +141 -0
  1230. package/src/modes/components/user-message.ts +51 -0
  1231. package/src/modes/components/visual-truncate.ts +63 -0
  1232. package/src/modes/components/welcome.ts +389 -0
  1233. package/src/modes/controllers/btw-controller.ts +105 -0
  1234. package/src/modes/controllers/command-controller-shared.ts +108 -0
  1235. package/src/modes/controllers/command-controller.ts +1630 -0
  1236. package/src/modes/controllers/event-controller.ts +786 -0
  1237. package/src/modes/controllers/extension-ui-controller.ts +927 -0
  1238. package/src/modes/controllers/input-controller.ts +858 -0
  1239. package/src/modes/controllers/runtime-mcp-command-controller.ts +1934 -0
  1240. package/src/modes/controllers/selector-controller.ts +1039 -0
  1241. package/src/modes/controllers/ssh-command-controller.ts +384 -0
  1242. package/src/modes/controllers/todo-command-controller.ts +485 -0
  1243. package/src/modes/data/emojis.json +1 -0
  1244. package/src/modes/emoji-autocomplete.ts +285 -0
  1245. package/src/modes/index.ts +34 -0
  1246. package/src/modes/interactive-mode.ts +2756 -0
  1247. package/src/modes/loop-limit.ts +140 -0
  1248. package/src/modes/oauth-manual-input.ts +42 -0
  1249. package/src/modes/print-mode.ts +121 -0
  1250. package/src/modes/prompt-action-autocomplete.ts +345 -0
  1251. package/src/modes/rpc/host-tools.ts +186 -0
  1252. package/src/modes/rpc/host-uris.ts +235 -0
  1253. package/src/modes/rpc/rpc-client.ts +810 -0
  1254. package/src/modes/rpc/rpc-mode.ts +851 -0
  1255. package/src/modes/rpc/rpc-types.ts +378 -0
  1256. package/src/modes/runtime-init.ts +116 -0
  1257. package/src/modes/session-observer-registry.ts +146 -0
  1258. package/src/modes/shared.ts +55 -0
  1259. package/src/modes/theme/dark.json +95 -0
  1260. package/src/modes/theme/defaults/alabaster.json +93 -0
  1261. package/src/modes/theme/defaults/amethyst.json +96 -0
  1262. package/src/modes/theme/defaults/anthracite.json +93 -0
  1263. package/src/modes/theme/defaults/basalt.json +91 -0
  1264. package/src/modes/theme/defaults/birch.json +95 -0
  1265. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  1266. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  1267. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  1268. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  1269. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  1270. package/src/modes/theme/defaults/dark-copper.json +95 -0
  1271. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  1272. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  1273. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  1274. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  1275. package/src/modes/theme/defaults/dark-ember.json +95 -0
  1276. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  1277. package/src/modes/theme/defaults/dark-forest.json +96 -0
  1278. package/src/modes/theme/defaults/dark-github.json +105 -0
  1279. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  1280. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  1281. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  1282. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  1283. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  1284. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  1285. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  1286. package/src/modes/theme/defaults/dark-nord.json +97 -0
  1287. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  1288. package/src/modes/theme/defaults/dark-one.json +100 -0
  1289. package/src/modes/theme/defaults/dark-poimandres.json +142 -0
  1290. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  1291. package/src/modes/theme/defaults/dark-reef.json +91 -0
  1292. package/src/modes/theme/defaults/dark-retro.json +92 -0
  1293. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  1294. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  1295. package/src/modes/theme/defaults/dark-slate.json +95 -0
  1296. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  1297. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  1298. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  1299. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  1300. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  1301. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  1302. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  1303. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  1304. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  1305. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  1306. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  1307. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  1308. package/src/modes/theme/defaults/graphite.json +92 -0
  1309. package/src/modes/theme/defaults/index.ts +201 -0
  1310. package/src/modes/theme/defaults/light-arctic.json +107 -0
  1311. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  1312. package/src/modes/theme/defaults/light-canyon.json +91 -0
  1313. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  1314. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  1315. package/src/modes/theme/defaults/light-coral.json +95 -0
  1316. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  1317. package/src/modes/theme/defaults/light-dawn.json +90 -0
  1318. package/src/modes/theme/defaults/light-dunes.json +91 -0
  1319. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  1320. package/src/modes/theme/defaults/light-forest.json +100 -0
  1321. package/src/modes/theme/defaults/light-frost.json +95 -0
  1322. package/src/modes/theme/defaults/light-github.json +115 -0
  1323. package/src/modes/theme/defaults/light-glacier.json +91 -0
  1324. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  1325. package/src/modes/theme/defaults/light-haze.json +90 -0
  1326. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  1327. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  1328. package/src/modes/theme/defaults/light-lavender.json +95 -0
  1329. package/src/modes/theme/defaults/light-meadow.json +91 -0
  1330. package/src/modes/theme/defaults/light-mint.json +95 -0
  1331. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  1332. package/src/modes/theme/defaults/light-ocean.json +99 -0
  1333. package/src/modes/theme/defaults/light-one.json +99 -0
  1334. package/src/modes/theme/defaults/light-opal.json +91 -0
  1335. package/src/modes/theme/defaults/light-orchard.json +91 -0
  1336. package/src/modes/theme/defaults/light-paper.json +95 -0
  1337. package/src/modes/theme/defaults/light-poimandres.json +142 -0
  1338. package/src/modes/theme/defaults/light-prism.json +90 -0
  1339. package/src/modes/theme/defaults/light-retro.json +98 -0
  1340. package/src/modes/theme/defaults/light-sand.json +95 -0
  1341. package/src/modes/theme/defaults/light-savanna.json +91 -0
  1342. package/src/modes/theme/defaults/light-solarized.json +102 -0
  1343. package/src/modes/theme/defaults/light-soleil.json +90 -0
  1344. package/src/modes/theme/defaults/light-sunset.json +99 -0
  1345. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  1346. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  1347. package/src/modes/theme/defaults/light-wetland.json +91 -0
  1348. package/src/modes/theme/defaults/light-zenith.json +89 -0
  1349. package/src/modes/theme/defaults/limestone.json +94 -0
  1350. package/src/modes/theme/defaults/mahogany.json +97 -0
  1351. package/src/modes/theme/defaults/marble.json +93 -0
  1352. package/src/modes/theme/defaults/obsidian.json +91 -0
  1353. package/src/modes/theme/defaults/onyx.json +91 -0
  1354. package/src/modes/theme/defaults/pearl.json +93 -0
  1355. package/src/modes/theme/defaults/porcelain.json +91 -0
  1356. package/src/modes/theme/defaults/quartz.json +96 -0
  1357. package/src/modes/theme/defaults/red-claw.json +123 -0
  1358. package/src/modes/theme/defaults/sandstone.json +95 -0
  1359. package/src/modes/theme/defaults/titanium.json +90 -0
  1360. package/src/modes/theme/light.json +93 -0
  1361. package/src/modes/theme/mermaid-cache.ts +29 -0
  1362. package/src/modes/theme/shimmer.ts +219 -0
  1363. package/src/modes/theme/theme-schema.json +429 -0
  1364. package/src/modes/theme/theme.ts +2413 -0
  1365. package/src/modes/types.ts +313 -0
  1366. package/src/modes/utils/context-usage.ts +335 -0
  1367. package/src/modes/utils/hotkeys-markdown.ts +59 -0
  1368. package/src/modes/utils/keybinding-matchers.ts +30 -0
  1369. package/src/modes/utils/tools-markdown.ts +27 -0
  1370. package/src/modes/utils/ui-helpers.ts +741 -0
  1371. package/src/plan-mode/approved-plan.ts +163 -0
  1372. package/src/plan-mode/state.ts +6 -0
  1373. package/src/priority.json +37 -0
  1374. package/src/prompts/agents/architect.md +79 -0
  1375. package/src/prompts/agents/critic.md +55 -0
  1376. package/src/prompts/agents/executor.md +45 -0
  1377. package/src/prompts/agents/explore.md +58 -0
  1378. package/src/prompts/agents/frontmatter.md +12 -0
  1379. package/src/prompts/agents/init.md +34 -0
  1380. package/src/prompts/agents/plan.md +49 -0
  1381. package/src/prompts/agents/planner.md +49 -0
  1382. package/src/prompts/agents/reviewer.md +141 -0
  1383. package/src/prompts/agents/task.md +16 -0
  1384. package/src/prompts/ci-green-request.md +36 -0
  1385. package/src/prompts/commands/orchestrate.md +49 -0
  1386. package/src/prompts/goals/goal-budget-limit.md +16 -0
  1387. package/src/prompts/goals/goal-continuation.md +28 -0
  1388. package/src/prompts/goals/goal-mode-active.md +23 -0
  1389. package/src/prompts/memories/consolidation.md +30 -0
  1390. package/src/prompts/memories/read-path.md +11 -0
  1391. package/src/prompts/memories/stage_one_input.md +6 -0
  1392. package/src/prompts/memories/stage_one_system.md +21 -0
  1393. package/src/prompts/review-request.md +70 -0
  1394. package/src/prompts/system/agent-creation-architect.md +75 -0
  1395. package/src/prompts/system/agent-creation-user.md +6 -0
  1396. package/src/prompts/system/auto-continue.md +1 -0
  1397. package/src/prompts/system/btw-user.md +8 -0
  1398. package/src/prompts/system/commit-message-system.md +2 -0
  1399. package/src/prompts/system/custom-system-prompt.md +64 -0
  1400. package/src/prompts/system/eager-todo.md +13 -0
  1401. package/src/prompts/system/irc-incoming.md +8 -0
  1402. package/src/prompts/system/plan-mode-active.md +116 -0
  1403. package/src/prompts/system/plan-mode-approved.md +28 -0
  1404. package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
  1405. package/src/prompts/system/plan-mode-reference.md +14 -0
  1406. package/src/prompts/system/plan-mode-subagent.md +34 -0
  1407. package/src/prompts/system/plan-mode-tool-decision-reminder.md +9 -0
  1408. package/src/prompts/system/project-prompt.md +46 -0
  1409. package/src/prompts/system/subagent-system-prompt.md +54 -0
  1410. package/src/prompts/system/subagent-user-prompt.md +3 -0
  1411. package/src/prompts/system/subagent-yield-reminder.md +12 -0
  1412. package/src/prompts/system/system-prompt.md +267 -0
  1413. package/src/prompts/system/title-system.md +2 -0
  1414. package/src/prompts/system/ttsr-interrupt.md +7 -0
  1415. package/src/prompts/system/ttsr-tool-reminder.md +5 -0
  1416. package/src/prompts/system/web-search.md +25 -0
  1417. package/src/prompts/tools/apply-patch.md +65 -0
  1418. package/src/prompts/tools/ask.md +29 -0
  1419. package/src/prompts/tools/ast-edit.md +39 -0
  1420. package/src/prompts/tools/ast-grep.md +42 -0
  1421. package/src/prompts/tools/async-result.md +8 -0
  1422. package/src/prompts/tools/bash.md +39 -0
  1423. package/src/prompts/tools/browser.md +70 -0
  1424. package/src/prompts/tools/calculator.md +10 -0
  1425. package/src/prompts/tools/checkpoint.md +16 -0
  1426. package/src/prompts/tools/create-goal.md +3 -0
  1427. package/src/prompts/tools/debug.md +33 -0
  1428. package/src/prompts/tools/eval.md +75 -0
  1429. package/src/prompts/tools/find.md +34 -0
  1430. package/src/prompts/tools/get-goal.md +3 -0
  1431. package/src/prompts/tools/github.md +20 -0
  1432. package/src/prompts/tools/goal.md +18 -0
  1433. package/src/prompts/tools/hashline.md +130 -0
  1434. package/src/prompts/tools/image-gen.md +7 -0
  1435. package/src/prompts/tools/inspect-image-system.md +20 -0
  1436. package/src/prompts/tools/inspect-image.md +32 -0
  1437. package/src/prompts/tools/irc.md +49 -0
  1438. package/src/prompts/tools/job.md +19 -0
  1439. package/src/prompts/tools/lsp.md +42 -0
  1440. package/src/prompts/tools/patch.md +70 -0
  1441. package/src/prompts/tools/read.md +82 -0
  1442. package/src/prompts/tools/recall.md +5 -0
  1443. package/src/prompts/tools/recipe.md +16 -0
  1444. package/src/prompts/tools/reflect.md +5 -0
  1445. package/src/prompts/tools/render-mermaid.md +9 -0
  1446. package/src/prompts/tools/replace.md +36 -0
  1447. package/src/prompts/tools/resolve.md +9 -0
  1448. package/src/prompts/tools/retain.md +6 -0
  1449. package/src/prompts/tools/rewind.md +13 -0
  1450. package/src/prompts/tools/search-tool-bm25.md +33 -0
  1451. package/src/prompts/tools/search.md +25 -0
  1452. package/src/prompts/tools/ssh.md +35 -0
  1453. package/src/prompts/tools/subagent.md +21 -0
  1454. package/src/prompts/tools/task-summary.md +28 -0
  1455. package/src/prompts/tools/task.md +79 -0
  1456. package/src/prompts/tools/todo-write.md +50 -0
  1457. package/src/prompts/tools/update-goal.md +3 -0
  1458. package/src/prompts/tools/vim.md +98 -0
  1459. package/src/prompts/tools/web-search.md +10 -0
  1460. package/src/prompts/tools/write.md +14 -0
  1461. package/src/registry/agent-registry.ts +140 -0
  1462. package/src/runtime-mcp/client.ts +482 -0
  1463. package/src/runtime-mcp/config-writer.ts +225 -0
  1464. package/src/runtime-mcp/config.ts +365 -0
  1465. package/src/runtime-mcp/discoverable-tool-metadata.ts +25 -0
  1466. package/src/runtime-mcp/index.ts +29 -0
  1467. package/src/runtime-mcp/json-rpc.ts +84 -0
  1468. package/src/runtime-mcp/loader.ts +124 -0
  1469. package/src/runtime-mcp/manager.ts +1172 -0
  1470. package/src/runtime-mcp/oauth-discovery.ts +349 -0
  1471. package/src/runtime-mcp/oauth-flow.ts +407 -0
  1472. package/src/runtime-mcp/render.ts +123 -0
  1473. package/src/runtime-mcp/smithery-auth.ts +104 -0
  1474. package/src/runtime-mcp/smithery-connect.ts +145 -0
  1475. package/src/runtime-mcp/smithery-registry.ts +477 -0
  1476. package/src/runtime-mcp/tool-bridge.ts +416 -0
  1477. package/src/runtime-mcp/tool-cache.ts +117 -0
  1478. package/src/runtime-mcp/transports/http.ts +477 -0
  1479. package/src/runtime-mcp/transports/index.ts +6 -0
  1480. package/src/runtime-mcp/transports/stdio.ts +325 -0
  1481. package/src/runtime-mcp/types.ts +423 -0
  1482. package/src/sdk.ts +2064 -0
  1483. package/src/secrets/index.ts +116 -0
  1484. package/src/secrets/obfuscator.ts +277 -0
  1485. package/src/secrets/regex.ts +21 -0
  1486. package/src/session/agent-session.ts +8794 -0
  1487. package/src/session/agent-storage.ts +466 -0
  1488. package/src/session/artifacts.ts +135 -0
  1489. package/src/session/auth-broker-config.ts +102 -0
  1490. package/src/session/auth-storage.ts +23 -0
  1491. package/src/session/blob-store.ts +168 -0
  1492. package/src/session/client-bridge.ts +85 -0
  1493. package/src/session/history-storage.ts +311 -0
  1494. package/src/session/messages.ts +403 -0
  1495. package/src/session/session-dump-format.ts +209 -0
  1496. package/src/session/session-manager.ts +3333 -0
  1497. package/src/session/session-storage.ts +389 -0
  1498. package/src/session/streaming-output.ts +1093 -0
  1499. package/src/session/tool-choice-queue.ts +213 -0
  1500. package/src/session/yield-queue.ts +155 -0
  1501. package/src/setup/model-onboarding-guidance.ts +36 -0
  1502. package/src/setup/provider-onboarding.ts +195 -0
  1503. package/src/skill-state/active-state.ts +272 -0
  1504. package/src/slash-commands/acp-builtins.ts +46 -0
  1505. package/src/slash-commands/builtin-registry.ts +955 -0
  1506. package/src/slash-commands/helpers/context-report.ts +39 -0
  1507. package/src/slash-commands/helpers/format.ts +46 -0
  1508. package/src/slash-commands/helpers/mcp.ts +532 -0
  1509. package/src/slash-commands/helpers/parse.ts +85 -0
  1510. package/src/slash-commands/helpers/ssh.ts +195 -0
  1511. package/src/slash-commands/helpers/todo.ts +279 -0
  1512. package/src/slash-commands/helpers/usage-report.ts +91 -0
  1513. package/src/slash-commands/types.ts +125 -0
  1514. package/src/ssh/config-writer.ts +183 -0
  1515. package/src/ssh/connection-manager.ts +482 -0
  1516. package/src/ssh/ssh-executor.ts +133 -0
  1517. package/src/ssh/sshfs-mount.ts +140 -0
  1518. package/src/ssh/utils.ts +8 -0
  1519. package/src/stt/downloader.ts +71 -0
  1520. package/src/stt/index.ts +3 -0
  1521. package/src/stt/recorder.ts +351 -0
  1522. package/src/stt/setup.ts +52 -0
  1523. package/src/stt/stt-controller.ts +160 -0
  1524. package/src/stt/transcribe.py +70 -0
  1525. package/src/stt/transcriber.ts +91 -0
  1526. package/src/system-prompt.ts +581 -0
  1527. package/src/task/agents.ts +162 -0
  1528. package/src/task/commands.ts +135 -0
  1529. package/src/task/discovery.ts +130 -0
  1530. package/src/task/executor.ts +1564 -0
  1531. package/src/task/gjc-command.ts +26 -0
  1532. package/src/task/index.ts +1366 -0
  1533. package/src/task/name-generator.ts +1577 -0
  1534. package/src/task/output-manager.ts +107 -0
  1535. package/src/task/parallel.ts +116 -0
  1536. package/src/task/render.ts +1136 -0
  1537. package/src/task/simple-mode.ts +27 -0
  1538. package/src/task/subprocess-tool-registry.ts +88 -0
  1539. package/src/task/types.ts +315 -0
  1540. package/src/task/worktree.ts +506 -0
  1541. package/src/thinking.ts +87 -0
  1542. package/src/tool-discovery/tool-index.ts +400 -0
  1543. package/src/tools/archive-reader.ts +321 -0
  1544. package/src/tools/ask.ts +790 -0
  1545. package/src/tools/ast-edit.ts +542 -0
  1546. package/src/tools/ast-grep.ts +423 -0
  1547. package/src/tools/auto-generated-guard.ts +305 -0
  1548. package/src/tools/bash-command-fixup.ts +37 -0
  1549. package/src/tools/bash-interactive.ts +388 -0
  1550. package/src/tools/bash-interceptor.ts +67 -0
  1551. package/src/tools/bash-pty-selection.ts +14 -0
  1552. package/src/tools/bash-skill-urls.ts +248 -0
  1553. package/src/tools/bash.ts +1061 -0
  1554. package/src/tools/browser/attach.ts +175 -0
  1555. package/src/tools/browser/launch.ts +651 -0
  1556. package/src/tools/browser/readable.ts +95 -0
  1557. package/src/tools/browser/registry.ts +194 -0
  1558. package/src/tools/browser/render.ts +212 -0
  1559. package/src/tools/browser/tab-protocol.ts +105 -0
  1560. package/src/tools/browser/tab-supervisor.ts +577 -0
  1561. package/src/tools/browser/tab-worker-entry.ts +21 -0
  1562. package/src/tools/browser/tab-worker.ts +1054 -0
  1563. package/src/tools/browser.ts +301 -0
  1564. package/src/tools/calculator.ts +540 -0
  1565. package/src/tools/checkpoint.ts +134 -0
  1566. package/src/tools/conflict-detect.ts +672 -0
  1567. package/src/tools/context.ts +39 -0
  1568. package/src/tools/debug.ts +1014 -0
  1569. package/src/tools/eval.ts +1101 -0
  1570. package/src/tools/fetch.ts +1482 -0
  1571. package/src/tools/file-recorder.ts +35 -0
  1572. package/src/tools/find.ts +540 -0
  1573. package/src/tools/fs-cache-invalidation.ts +28 -0
  1574. package/src/tools/gh-format.ts +12 -0
  1575. package/src/tools/gh-renderer.ts +428 -0
  1576. package/src/tools/gh.ts +3499 -0
  1577. package/src/tools/github-cache.ts +548 -0
  1578. package/src/tools/grouped-file-output.ts +96 -0
  1579. package/src/tools/hindsight-recall.ts +68 -0
  1580. package/src/tools/hindsight-reflect.ts +57 -0
  1581. package/src/tools/hindsight-retain.ts +56 -0
  1582. package/src/tools/image-gen.ts +1248 -0
  1583. package/src/tools/index.ts +519 -0
  1584. package/src/tools/inspect-image-renderer.ts +103 -0
  1585. package/src/tools/inspect-image.ts +165 -0
  1586. package/src/tools/irc.ts +239 -0
  1587. package/src/tools/job.ts +520 -0
  1588. package/src/tools/json-tree.ts +243 -0
  1589. package/src/tools/jtd-to-json-schema.ts +219 -0
  1590. package/src/tools/jtd-to-typescript.ts +136 -0
  1591. package/src/tools/jtd-utils.ts +102 -0
  1592. package/src/tools/list-limit.ts +40 -0
  1593. package/src/tools/match-line-format.ts +22 -0
  1594. package/src/tools/output-meta.ts +754 -0
  1595. package/src/tools/path-utils.ts +739 -0
  1596. package/src/tools/plan-mode-guard.ts +68 -0
  1597. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  1598. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  1599. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  1600. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  1601. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  1602. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  1603. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  1604. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  1605. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  1606. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  1607. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  1608. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  1609. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  1610. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  1611. package/src/tools/read.ts +2332 -0
  1612. package/src/tools/recipe/index.ts +80 -0
  1613. package/src/tools/recipe/render.ts +19 -0
  1614. package/src/tools/recipe/runner.ts +219 -0
  1615. package/src/tools/recipe/runners/cargo.ts +131 -0
  1616. package/src/tools/recipe/runners/index.ts +8 -0
  1617. package/src/tools/recipe/runners/just.ts +73 -0
  1618. package/src/tools/recipe/runners/make.ts +101 -0
  1619. package/src/tools/recipe/runners/pkg.ts +167 -0
  1620. package/src/tools/recipe/runners/task.ts +72 -0
  1621. package/src/tools/render-mermaid.ts +68 -0
  1622. package/src/tools/render-utils.ts +774 -0
  1623. package/src/tools/renderers.ts +75 -0
  1624. package/src/tools/resolve.ts +258 -0
  1625. package/src/tools/review.ts +252 -0
  1626. package/src/tools/search-tool-bm25.ts +360 -0
  1627. package/src/tools/search.ts +786 -0
  1628. package/src/tools/sqlite-reader.ts +736 -0
  1629. package/src/tools/ssh.ts +310 -0
  1630. package/src/tools/subagent.ts +312 -0
  1631. package/src/tools/todo-write.ts +695 -0
  1632. package/src/tools/tool-errors.ts +62 -0
  1633. package/src/tools/tool-result.ts +86 -0
  1634. package/src/tools/tool-timeouts.ts +30 -0
  1635. package/src/tools/vim.ts +949 -0
  1636. package/src/tools/write.ts +953 -0
  1637. package/src/tools/yield.ts +268 -0
  1638. package/src/tui/code-cell.ts +201 -0
  1639. package/src/tui/file-list.ts +55 -0
  1640. package/src/tui/hyperlink.ts +126 -0
  1641. package/src/tui/index.ts +12 -0
  1642. package/src/tui/output-block.ts +150 -0
  1643. package/src/tui/status-line.ts +39 -0
  1644. package/src/tui/tree-list.ts +84 -0
  1645. package/src/tui/types.ts +15 -0
  1646. package/src/tui/utils.ts +103 -0
  1647. package/src/utils/changelog.ts +98 -0
  1648. package/src/utils/clipboard.ts +156 -0
  1649. package/src/utils/command-args.ts +76 -0
  1650. package/src/utils/commit-message-generator.ts +142 -0
  1651. package/src/utils/edit-mode.ts +42 -0
  1652. package/src/utils/event-bus.ts +33 -0
  1653. package/src/utils/external-editor.ts +65 -0
  1654. package/src/utils/file-display-mode.ts +45 -0
  1655. package/src/utils/file-mentions.ts +376 -0
  1656. package/src/utils/git.ts +1536 -0
  1657. package/src/utils/image-loading.ts +102 -0
  1658. package/src/utils/image-resize.ts +309 -0
  1659. package/src/utils/lang-from-path.ts +239 -0
  1660. package/src/utils/markit.ts +89 -0
  1661. package/src/utils/open.ts +20 -0
  1662. package/src/utils/session-color.ts +43 -0
  1663. package/src/utils/shell-snapshot.ts +187 -0
  1664. package/src/utils/sixel.ts +69 -0
  1665. package/src/utils/title-generator.ts +223 -0
  1666. package/src/utils/tool-choice.ts +33 -0
  1667. package/src/utils/tools-manager.ts +363 -0
  1668. package/src/vim/buffer.ts +309 -0
  1669. package/src/vim/commands.ts +382 -0
  1670. package/src/vim/engine.ts +2409 -0
  1671. package/src/vim/parser.ts +134 -0
  1672. package/src/vim/render.ts +252 -0
  1673. package/src/vim/types.ts +197 -0
  1674. package/src/web/kagi.ts +183 -0
  1675. package/src/web/parallel.ts +349 -0
  1676. package/src/web/scrapers/artifacthub.ts +207 -0
  1677. package/src/web/scrapers/arxiv.ts +83 -0
  1678. package/src/web/scrapers/aur.ts +162 -0
  1679. package/src/web/scrapers/biorxiv.ts +133 -0
  1680. package/src/web/scrapers/bluesky.ts +262 -0
  1681. package/src/web/scrapers/brew.ts +172 -0
  1682. package/src/web/scrapers/cheatsh.ts +68 -0
  1683. package/src/web/scrapers/chocolatey.ts +196 -0
  1684. package/src/web/scrapers/choosealicense.ts +95 -0
  1685. package/src/web/scrapers/cisa-kev.ts +87 -0
  1686. package/src/web/scrapers/clojars.ts +154 -0
  1687. package/src/web/scrapers/coingecko.ts +177 -0
  1688. package/src/web/scrapers/crates-io.ts +97 -0
  1689. package/src/web/scrapers/crossref.ts +136 -0
  1690. package/src/web/scrapers/devto.ts +147 -0
  1691. package/src/web/scrapers/discogs.ts +306 -0
  1692. package/src/web/scrapers/discourse.ts +197 -0
  1693. package/src/web/scrapers/dockerhub.ts +138 -0
  1694. package/src/web/scrapers/docs-rs.ts +653 -0
  1695. package/src/web/scrapers/fdroid.ts +134 -0
  1696. package/src/web/scrapers/firefox-addons.ts +191 -0
  1697. package/src/web/scrapers/flathub.ts +223 -0
  1698. package/src/web/scrapers/github-gist.ts +58 -0
  1699. package/src/web/scrapers/github.ts +452 -0
  1700. package/src/web/scrapers/gitlab.ts +401 -0
  1701. package/src/web/scrapers/go-pkg.ts +266 -0
  1702. package/src/web/scrapers/hackage.ts +140 -0
  1703. package/src/web/scrapers/hackernews.ts +189 -0
  1704. package/src/web/scrapers/hex.ts +105 -0
  1705. package/src/web/scrapers/huggingface.ts +321 -0
  1706. package/src/web/scrapers/iacr.ts +89 -0
  1707. package/src/web/scrapers/index.ts +252 -0
  1708. package/src/web/scrapers/jetbrains-marketplace.ts +159 -0
  1709. package/src/web/scrapers/lemmy.ts +203 -0
  1710. package/src/web/scrapers/lobsters.ts +175 -0
  1711. package/src/web/scrapers/mastodon.ts +292 -0
  1712. package/src/web/scrapers/maven.ts +138 -0
  1713. package/src/web/scrapers/mdn.ts +173 -0
  1714. package/src/web/scrapers/metacpan.ts +222 -0
  1715. package/src/web/scrapers/musicbrainz.ts +250 -0
  1716. package/src/web/scrapers/npm.ts +98 -0
  1717. package/src/web/scrapers/nuget.ts +183 -0
  1718. package/src/web/scrapers/nvd.ts +222 -0
  1719. package/src/web/scrapers/ollama.ts +239 -0
  1720. package/src/web/scrapers/open-vsx.ts +106 -0
  1721. package/src/web/scrapers/opencorporates.ts +292 -0
  1722. package/src/web/scrapers/openlibrary.ts +336 -0
  1723. package/src/web/scrapers/orcid.ts +286 -0
  1724. package/src/web/scrapers/osv.ts +176 -0
  1725. package/src/web/scrapers/packagist.ts +160 -0
  1726. package/src/web/scrapers/pub-dev.ts +143 -0
  1727. package/src/web/scrapers/pubmed.ts +211 -0
  1728. package/src/web/scrapers/pypi.ts +112 -0
  1729. package/src/web/scrapers/rawg.ts +110 -0
  1730. package/src/web/scrapers/readthedocs.ts +120 -0
  1731. package/src/web/scrapers/reddit.ts +95 -0
  1732. package/src/web/scrapers/repology.ts +251 -0
  1733. package/src/web/scrapers/rfc.ts +201 -0
  1734. package/src/web/scrapers/rubygems.ts +103 -0
  1735. package/src/web/scrapers/searchcode.ts +189 -0
  1736. package/src/web/scrapers/sec-edgar.ts +261 -0
  1737. package/src/web/scrapers/semantic-scholar.ts +171 -0
  1738. package/src/web/scrapers/snapcraft.ts +187 -0
  1739. package/src/web/scrapers/sourcegraph.ts +336 -0
  1740. package/src/web/scrapers/spdx.ts +108 -0
  1741. package/src/web/scrapers/spotify.ts +198 -0
  1742. package/src/web/scrapers/stackoverflow.ts +120 -0
  1743. package/src/web/scrapers/terraform.ts +277 -0
  1744. package/src/web/scrapers/tldr.ts +47 -0
  1745. package/src/web/scrapers/twitter.ts +93 -0
  1746. package/src/web/scrapers/types.ts +318 -0
  1747. package/src/web/scrapers/utils.ts +109 -0
  1748. package/src/web/scrapers/vimeo.ts +133 -0
  1749. package/src/web/scrapers/vscode-marketplace.ts +187 -0
  1750. package/src/web/scrapers/w3c.ts +156 -0
  1751. package/src/web/scrapers/wikidata.ts +344 -0
  1752. package/src/web/scrapers/wikipedia.ts +84 -0
  1753. package/src/web/scrapers/youtube.ts +319 -0
  1754. package/src/web/search/index.ts +288 -0
  1755. package/src/web/search/provider.ts +173 -0
  1756. package/src/web/search/providers/anthropic.ts +302 -0
  1757. package/src/web/search/providers/base.ts +71 -0
  1758. package/src/web/search/providers/brave.ts +149 -0
  1759. package/src/web/search/providers/codex.ts +556 -0
  1760. package/src/web/search/providers/exa.ts +193 -0
  1761. package/src/web/search/providers/gemini.ts +455 -0
  1762. package/src/web/search/providers/jina.ts +101 -0
  1763. package/src/web/search/providers/kagi.ts +75 -0
  1764. package/src/web/search/providers/kimi.ts +171 -0
  1765. package/src/web/search/providers/parallel.ts +210 -0
  1766. package/src/web/search/providers/perplexity.ts +575 -0
  1767. package/src/web/search/providers/searxng.ts +309 -0
  1768. package/src/web/search/providers/synthetic.ts +108 -0
  1769. package/src/web/search/providers/tavily.ts +173 -0
  1770. package/src/web/search/providers/utils.ts +128 -0
  1771. package/src/web/search/providers/zai.ts +320 -0
  1772. package/src/web/search/render.ts +299 -0
  1773. package/src/web/search/types.ts +436 -0
  1774. package/src/web/search/utils.ts +17 -0
  1775. package/src/workspace-tree.ts +286 -0
@@ -0,0 +1,3499 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { scheduler } from "node:timers/promises";
5
+ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@gajae-code/agent-core";
6
+
7
+ import { getWorktreeDir, hashPath, isEnoent, prompt, untilAborted } from "@gajae-code/utils";
8
+ import * as z from "zod/v4";
9
+ import type { Settings } from "../config/settings";
10
+ import githubDescription from "../prompts/tools/github.md" with { type: "text" };
11
+ import * as git from "../utils/git";
12
+ import type { ToolSession } from ".";
13
+ import { formatShortSha } from "./gh-format";
14
+ import { type CacheStatus, getOrFetchView, resolveGithubCacheAuthKey } from "./github-cache";
15
+ import type { OutputMeta } from "./output-meta";
16
+ import { ToolError, throwIfAborted } from "./tool-errors";
17
+ import { toolResult } from "./tool-result";
18
+
19
+ const GH_REPO_FIELDS = [
20
+ "nameWithOwner",
21
+ "description",
22
+ "url",
23
+ "defaultBranchRef",
24
+ "homepageUrl",
25
+ "forkCount",
26
+ "isArchived",
27
+ "isFork",
28
+ "primaryLanguage",
29
+ "repositoryTopics",
30
+ "stargazerCount",
31
+ "updatedAt",
32
+ "viewerPermission",
33
+ "visibility",
34
+ ];
35
+ const GH_ISSUE_FIELDS = [
36
+ "author",
37
+ "body",
38
+ "comments",
39
+ "createdAt",
40
+ "labels",
41
+ "number",
42
+ "state",
43
+ "stateReason",
44
+ "title",
45
+ "updatedAt",
46
+ "url",
47
+ ];
48
+ const GH_ISSUE_FIELDS_NO_COMMENTS = [
49
+ "author",
50
+ "body",
51
+ "createdAt",
52
+ "labels",
53
+ "number",
54
+ "state",
55
+ "stateReason",
56
+ "title",
57
+ "updatedAt",
58
+ "url",
59
+ ];
60
+ const GH_PR_FIELDS = [
61
+ "author",
62
+ "baseRefName",
63
+ "body",
64
+ "comments",
65
+ "createdAt",
66
+ "files",
67
+ "headRefName",
68
+ "isDraft",
69
+ "labels",
70
+ "mergeStateStatus",
71
+ "number",
72
+ "reviewDecision",
73
+ "state",
74
+ "title",
75
+ "updatedAt",
76
+ "url",
77
+ ];
78
+ const GH_PR_FIELDS_NO_COMMENTS = [
79
+ "author",
80
+ "baseRefName",
81
+ "body",
82
+ "createdAt",
83
+ "files",
84
+ "headRefName",
85
+ "isDraft",
86
+ "labels",
87
+ "mergeStateStatus",
88
+ "number",
89
+ "reviews",
90
+ "reviewDecision",
91
+ "state",
92
+ "title",
93
+ "updatedAt",
94
+ "url",
95
+ ];
96
+ const GH_REPO_CLONE_FIELDS = ["nameWithOwner", "sshUrl", "url"];
97
+ const GH_PR_CHECKOUT_FIELDS = [
98
+ "baseRefName",
99
+ "headRefName",
100
+ "headRefOid",
101
+ "headRepository",
102
+ "headRepositoryOwner",
103
+ "isCrossRepository",
104
+ "maintainerCanModify",
105
+ "number",
106
+ "title",
107
+ "url",
108
+ ];
109
+ // /search/<endpoint> API response shapes (subset). Used when projecting raw
110
+ // REST results into the normalized `GhSearch*Result` shapes the formatters
111
+ // consume. We talk to the API directly because `gh search prs`/`issues`
112
+ // quotes multi-token positional queries (`is:"merged is:pr"`) and returns 0
113
+ // hits — see https://github.com/cli/cli for the upstream regression.
114
+ interface GhApiSearchResponse<T> {
115
+ total_count?: number;
116
+ incomplete_results?: boolean;
117
+ items?: T[];
118
+ }
119
+ interface GhApiUser {
120
+ login?: string;
121
+ name?: string | null;
122
+ }
123
+ interface GhApiLabel {
124
+ name?: string;
125
+ }
126
+ interface GhApiPullRequestRef {
127
+ merged_at?: string | null;
128
+ }
129
+ interface GhApiSearchIssueItem {
130
+ number?: number;
131
+ title?: string;
132
+ state?: string;
133
+ state_reason?: string | null;
134
+ user?: GhApiUser | null;
135
+ labels?: GhApiLabel[];
136
+ created_at?: string;
137
+ updated_at?: string;
138
+ html_url?: string;
139
+ repository_url?: string;
140
+ pull_request?: GhApiPullRequestRef | null;
141
+ }
142
+ interface GhApiSearchCodeItem {
143
+ name?: string;
144
+ path?: string;
145
+ sha?: string;
146
+ html_url?: string;
147
+ repository?: { full_name?: string } | null;
148
+ text_matches?: Array<{ fragment?: string; property?: string }>;
149
+ }
150
+ interface GhApiSearchCommitGitActor {
151
+ name?: string;
152
+ email?: string;
153
+ date?: string;
154
+ }
155
+ interface GhApiSearchCommitItem {
156
+ sha?: string;
157
+ node_id?: string;
158
+ html_url?: string;
159
+ author?: GhApiUser | null;
160
+ committer?: GhApiUser | null;
161
+ commit?: {
162
+ author?: GhApiSearchCommitGitActor | null;
163
+ committer?: GhApiSearchCommitGitActor | null;
164
+ message?: string;
165
+ } | null;
166
+ repository?: { full_name?: string } | null;
167
+ }
168
+ interface GhApiSearchRepoItem {
169
+ full_name?: string;
170
+ description?: string | null;
171
+ language?: string | null;
172
+ stargazers_count?: number;
173
+ forks_count?: number;
174
+ open_issues_count?: number;
175
+ archived?: boolean;
176
+ fork?: boolean;
177
+ private?: boolean;
178
+ visibility?: string | null;
179
+ updated_at?: string;
180
+ created_at?: string;
181
+ html_url?: string;
182
+ owner?: GhApiUser | null;
183
+ }
184
+ const SEARCH_LIMIT_DEFAULT = 10;
185
+ const SEARCH_LIMIT_MAX = 50;
186
+ const FILE_PREVIEW_LIMIT = 50;
187
+ const RUN_WATCH_INTERVAL_DEFAULT = 3;
188
+ const RUN_WATCH_GRACE_DEFAULT = 5;
189
+ const RUN_WATCH_TAIL_DEFAULT = 15;
190
+ const RUN_WATCH_TAIL_MAX = 200;
191
+ const REVIEW_COMMENTS_PAGE_SIZE = 100;
192
+ const RUN_JOBS_PAGE_SIZE = 100;
193
+ const PR_URL_PATTERN = /^https:\/\/github\.com\/([^/]+\/[^/]+)\/pull\/(\d+)(?:\/.*)?$/;
194
+ const ISSUE_URL_PATTERN = /^https:\/\/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)(?:\/.*)?$/;
195
+ const RUN_URL_PATTERN = /^https:\/\/github\.com\/([^/]+\/[^/]+)\/actions\/runs\/(\d+)(?:\/.*)?$/;
196
+ const RUN_SUCCESS_CONCLUSIONS = new Set(["success", "neutral", "skipped"]);
197
+ const RUN_FAILURE_CONCLUSIONS = new Set(["failure", "timed_out", "cancelled", "action_required", "startup_failure"]);
198
+ const JOB_FAILURE_CONCLUSIONS = new Set(["failure", "timed_out", "cancelled", "action_required"]);
199
+
200
+ const githubSchema = z
201
+ .object({
202
+ op: z
203
+ .enum([
204
+ "repo_view",
205
+ "pr_create",
206
+ "pr_checkout",
207
+ "pr_push",
208
+ "search_issues",
209
+ "search_prs",
210
+ "search_code",
211
+ "search_commits",
212
+ "search_repos",
213
+ "run_watch",
214
+ ] as const)
215
+ .describe("github operation"),
216
+ repo: z.string().describe("owner/repo").optional(),
217
+ branch: z.string().describe("branch").optional(),
218
+ pr: z
219
+ .union([z.string(), z.array(z.string())])
220
+ .describe("pr number, url, or branch")
221
+ .optional(),
222
+ force: z.boolean().describe("reset existing local branch").optional(),
223
+ forceWithLease: z.boolean().describe("force-with-lease push").optional(),
224
+ title: z.string().describe("pr title").optional(),
225
+ body: z.string().describe("pr body markdown").optional(),
226
+ base: z.string().describe("pr base branch").optional(),
227
+ head: z.string().describe("pr head branch").optional(),
228
+ draft: z.boolean().describe("open pr as draft").optional(),
229
+ fill: z.boolean().describe("auto-fill pr title/body from commits").optional(),
230
+ reviewer: z.array(z.string()).describe("reviewers").optional(),
231
+ assignee: z.array(z.string()).describe("assignees").optional(),
232
+ label: z.array(z.string()).describe("labels").optional(),
233
+ query: z.string().describe("search query").optional(),
234
+ since: z.string().describe("lower-bound date filter").optional(),
235
+ until: z.string().describe("upper-bound date filter").optional(),
236
+ dateField: z
237
+ .enum(["created", "updated"] as const)
238
+ .describe("date field")
239
+ .default("created")
240
+ .optional(),
241
+ limit: z.number().default(10).describe("max results").optional(),
242
+ run: z.string().describe("actions run id or url").optional(),
243
+ tail: z.number().default(15).describe("log lines per failed job").optional(),
244
+ })
245
+ .strict();
246
+
247
+ type GithubInput = z.infer<typeof githubSchema>;
248
+
249
+ export interface GhToolDetails {
250
+ meta?: OutputMeta;
251
+ artifactId?: string;
252
+ repo?: string;
253
+ branch?: string;
254
+ worktreePath?: string;
255
+ remote?: string;
256
+ remoteBranch?: string;
257
+ headSha?: string;
258
+ runId?: number;
259
+ runIds?: number[];
260
+ status?: string;
261
+ conclusion?: string;
262
+ failedJobs?: string[];
263
+ watch?: GhRunWatchViewDetails;
264
+ checkouts?: GhPrCheckoutSummary[];
265
+ }
266
+
267
+ export interface GhPrCheckoutSummary {
268
+ prNumber?: number;
269
+ url?: string;
270
+ branch: string;
271
+ worktreePath: string;
272
+ remote: string;
273
+ remoteBranch: string;
274
+ reused: boolean;
275
+ }
276
+
277
+ export interface GhRunWatchJobDetails {
278
+ id: number;
279
+ name: string;
280
+ status?: string;
281
+ conclusion?: string;
282
+ durationSeconds?: number;
283
+ url?: string;
284
+ }
285
+
286
+ export interface GhRunWatchRunDetails {
287
+ id: number;
288
+ workflowName?: string;
289
+ displayTitle?: string;
290
+ status?: string;
291
+ conclusion?: string;
292
+ branch?: string;
293
+ headSha?: string;
294
+ url?: string;
295
+ jobs: GhRunWatchJobDetails[];
296
+ }
297
+
298
+ export interface GhRunWatchFailedLogDetails {
299
+ runId: number;
300
+ workflowName?: string;
301
+ jobName: string;
302
+ conclusion?: string;
303
+ tail?: string;
304
+ available: boolean;
305
+ }
306
+
307
+ export interface GhRunWatchViewDetails {
308
+ mode: "run" | "commit";
309
+ state: "watching" | "completed";
310
+ repo: string;
311
+ branch?: string;
312
+ headSha?: string;
313
+ pollCount?: number;
314
+ note?: string;
315
+ run?: GhRunWatchRunDetails;
316
+ runs?: GhRunWatchRunDetails[];
317
+ failedLogs?: GhRunWatchFailedLogDetails[];
318
+ }
319
+
320
+ interface GhUser {
321
+ login?: string;
322
+ name?: string | null;
323
+ }
324
+
325
+ interface GhLabel {
326
+ name?: string;
327
+ }
328
+
329
+ interface GhComment {
330
+ author?: GhUser | null;
331
+ body?: string;
332
+ createdAt?: string;
333
+ url?: string;
334
+ isMinimized?: boolean;
335
+ minimizedReason?: string | null;
336
+ }
337
+
338
+ interface GhRepoTopic {
339
+ name?: string;
340
+ topic?: { name?: string };
341
+ }
342
+
343
+ interface GhRepoLanguage {
344
+ name?: string;
345
+ }
346
+
347
+ interface GhRepoBranch {
348
+ name?: string;
349
+ }
350
+
351
+ interface GhRepoViewData {
352
+ nameWithOwner?: string;
353
+ description?: string | null;
354
+ url?: string;
355
+ sshUrl?: string;
356
+ defaultBranchRef?: GhRepoBranch | null;
357
+ homepageUrl?: string | null;
358
+ forkCount?: number;
359
+ isArchived?: boolean;
360
+ isFork?: boolean;
361
+ primaryLanguage?: GhRepoLanguage | null;
362
+ repositoryTopics?: GhRepoTopic[];
363
+ stargazerCount?: number;
364
+ updatedAt?: string;
365
+ viewerPermission?: string | null;
366
+ visibility?: string | null;
367
+ }
368
+
369
+ interface GhIssueViewData {
370
+ author?: GhUser | null;
371
+ body?: string | null;
372
+ comments?: GhComment[];
373
+ createdAt?: string;
374
+ labels?: GhLabel[];
375
+ number?: number;
376
+ state?: string;
377
+ stateReason?: string | null;
378
+ title?: string;
379
+ updatedAt?: string;
380
+ url?: string;
381
+ }
382
+
383
+ interface GhPrFile {
384
+ path?: string;
385
+ additions?: number;
386
+ deletions?: number;
387
+ changeType?: string;
388
+ }
389
+
390
+ interface GhPrViewData extends GhIssueViewData {
391
+ baseRefName?: string;
392
+ files?: GhPrFile[];
393
+ headRefName?: string;
394
+ headRefOid?: string;
395
+ headRepository?: GhRepoViewData | null;
396
+ headRepositoryOwner?: GhUser | null;
397
+ isCrossRepository?: boolean;
398
+ isDraft?: boolean;
399
+ maintainerCanModify?: boolean;
400
+ mergeStateStatus?: string;
401
+ reviewComments?: GhPrReviewComment[];
402
+ reviews?: GhPrReview[];
403
+ reviewDecision?: string;
404
+ }
405
+
406
+ interface GhPrReviewCommit {
407
+ oid?: string | null;
408
+ }
409
+
410
+ interface GhPrReview {
411
+ author?: GhUser | null;
412
+ body?: string | null;
413
+ commit?: GhPrReviewCommit | null;
414
+ state?: string | null;
415
+ submittedAt?: string | null;
416
+ }
417
+
418
+ interface GhPrReviewCommentApi {
419
+ body?: string | null;
420
+ created_at?: string | null;
421
+ html_url?: string | null;
422
+ id?: number;
423
+ in_reply_to_id?: number | null;
424
+ line?: number | null;
425
+ original_line?: number | null;
426
+ path?: string | null;
427
+ side?: string | null;
428
+ user?: GhUser | null;
429
+ }
430
+
431
+ interface GhPrReviewComment {
432
+ author?: GhUser | null;
433
+ body?: string | null;
434
+ createdAt?: string;
435
+ id: number;
436
+ inReplyToId?: number;
437
+ line?: number;
438
+ originalLine?: number;
439
+ path?: string;
440
+ side?: string;
441
+ url?: string;
442
+ }
443
+
444
+ interface GhBranchApiResponse {
445
+ commit?: {
446
+ sha?: string | null;
447
+ } | null;
448
+ }
449
+
450
+ interface GhSearchRepository {
451
+ nameWithOwner?: string;
452
+ }
453
+
454
+ interface GhSearchResult {
455
+ author?: GhUser | null;
456
+ createdAt?: string;
457
+ labels?: GhLabel[];
458
+ number?: number;
459
+ repository?: GhSearchRepository | null;
460
+ state?: string;
461
+ title?: string;
462
+ updatedAt?: string;
463
+ url?: string;
464
+ }
465
+
466
+ interface GhSearchCodeTextMatch {
467
+ fragment?: string;
468
+ property?: string;
469
+ }
470
+
471
+ interface GhSearchCodeResult {
472
+ path?: string;
473
+ repository?: GhSearchRepository | null;
474
+ sha?: string;
475
+ textMatches?: GhSearchCodeTextMatch[];
476
+ url?: string;
477
+ }
478
+
479
+ interface GhSearchCommitGitActor {
480
+ name?: string;
481
+ email?: string;
482
+ date?: string;
483
+ }
484
+
485
+ interface GhSearchCommitDetail {
486
+ author?: GhSearchCommitGitActor | null;
487
+ committer?: GhSearchCommitGitActor | null;
488
+ message?: string;
489
+ }
490
+
491
+ interface GhSearchCommitResult {
492
+ author?: GhUser | null;
493
+ commit?: GhSearchCommitDetail | null;
494
+ committer?: GhUser | null;
495
+ id?: string;
496
+ repository?: GhSearchRepository | null;
497
+ sha?: string;
498
+ url?: string;
499
+ }
500
+
501
+ interface GhSearchRepoResult {
502
+ createdAt?: string;
503
+ description?: string | null;
504
+ forksCount?: number;
505
+ fullName?: string;
506
+ isArchived?: boolean;
507
+ isFork?: boolean;
508
+ isPrivate?: boolean;
509
+ language?: string | null;
510
+ openIssuesCount?: number;
511
+ owner?: GhUser | null;
512
+ stargazersCount?: number;
513
+ updatedAt?: string;
514
+ url?: string;
515
+ visibility?: string | null;
516
+ }
517
+
518
+ interface GhRunReference {
519
+ repo?: string;
520
+ runId?: number;
521
+ }
522
+
523
+ interface GhActionsRunListResponse {
524
+ workflow_runs?: GhActionsRunApi[];
525
+ }
526
+
527
+ interface GhActionsRunApi {
528
+ id?: number;
529
+ name?: string | null;
530
+ display_title?: string | null;
531
+ status?: string | null;
532
+ conclusion?: string | null;
533
+ head_branch?: string | null;
534
+ head_sha?: string | null;
535
+ created_at?: string | null;
536
+ updated_at?: string | null;
537
+ html_url?: string | null;
538
+ }
539
+
540
+ interface GhActionsJobsResponse {
541
+ total_count?: number;
542
+ jobs?: GhActionsJobApi[];
543
+ }
544
+
545
+ interface GhActionsJobApi {
546
+ id?: number;
547
+ name?: string | null;
548
+ status?: string | null;
549
+ conclusion?: string | null;
550
+ started_at?: string | null;
551
+ completed_at?: string | null;
552
+ html_url?: string | null;
553
+ }
554
+
555
+ interface GhRunJobSnapshot {
556
+ id: number;
557
+ name: string;
558
+ status?: string;
559
+ conclusion?: string;
560
+ startedAt?: string;
561
+ completedAt?: string;
562
+ url?: string;
563
+ }
564
+
565
+ interface GhRunSnapshot {
566
+ id: number;
567
+ workflowName?: string;
568
+ displayTitle?: string;
569
+ status?: string;
570
+ conclusion?: string;
571
+ branch?: string;
572
+ headSha?: string;
573
+ createdAt?: string;
574
+ updatedAt?: string;
575
+ url?: string;
576
+ jobs: GhRunJobSnapshot[];
577
+ }
578
+
579
+ interface GhFailedJobLog {
580
+ run: GhRunSnapshot;
581
+ job: GhRunJobSnapshot;
582
+ full?: string;
583
+ tail?: string;
584
+ available: boolean;
585
+ }
586
+
587
+ function normalizeText(value: string | null | undefined): string {
588
+ return (value ?? "").replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("\t", " ").trim();
589
+ }
590
+
591
+ function normalizeBlock(value: string | null | undefined): string {
592
+ return (value ?? "").replaceAll("\r\n", "\n").replaceAll("\r", "\n").replaceAll("\t", " ").trimEnd();
593
+ }
594
+
595
+ function looksLikeGitHubUrl(value: string | undefined): boolean {
596
+ return value?.startsWith("https://github.com/") ?? false;
597
+ }
598
+
599
+ function normalizeOptionalString(value: string | null | undefined): string | undefined {
600
+ const normalized = value?.trim();
601
+ return normalized ? normalized : undefined;
602
+ }
603
+
604
+ function normalizePrIdentifierList(value: string | string[] | undefined): string[] {
605
+ if (value === undefined) return [];
606
+ const raw = typeof value === "string" ? [value] : value;
607
+ const cleaned: string[] = [];
608
+ for (const entry of raw) {
609
+ const trimmed = entry?.trim();
610
+ if (trimmed) cleaned.push(trimmed);
611
+ }
612
+ return cleaned;
613
+ }
614
+
615
+ function requireNonEmpty(value: string | null | undefined, label: string): string {
616
+ const normalized = normalizeOptionalString(value);
617
+ if (!normalized) {
618
+ throw new ToolError(`${label} must not be empty`);
619
+ }
620
+ return normalized;
621
+ }
622
+
623
+ function resolveSearchLimit(value: number | undefined): number {
624
+ if (value === undefined) {
625
+ return SEARCH_LIMIT_DEFAULT;
626
+ }
627
+
628
+ if (!Number.isFinite(value) || value <= 0) {
629
+ throw new ToolError("limit must be a positive number");
630
+ }
631
+
632
+ return Math.min(Math.floor(value), SEARCH_LIMIT_MAX);
633
+ }
634
+
635
+ function resolveTailLimit(value: number | undefined): number {
636
+ if (value === undefined) {
637
+ return RUN_WATCH_TAIL_DEFAULT;
638
+ }
639
+
640
+ if (!Number.isFinite(value) || value <= 0) {
641
+ throw new ToolError("tail must be a positive number");
642
+ }
643
+
644
+ return Math.min(Math.floor(value), RUN_WATCH_TAIL_MAX);
645
+ }
646
+
647
+ function appendRepoFlag(args: string[], repo: string | undefined, identifier?: string): void {
648
+ if (!repo || looksLikeGitHubUrl(identifier)) {
649
+ return;
650
+ }
651
+
652
+ args.push("--repo", repo);
653
+ }
654
+
655
+ const REPO_API_URL_PREFIX = "https://api.github.com/repos/";
656
+
657
+ const RELATIVE_DURATION_PATTERN = /^(\d+)\s*(m|h|d|w|mo|y)$/i;
658
+ const ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
659
+ const FIXED_UNIT_MS: Record<string, number> = {
660
+ m: 60_000,
661
+ h: 3_600_000,
662
+ d: 86_400_000,
663
+ w: 7 * 86_400_000,
664
+ };
665
+
666
+ /**
667
+ * Resolve a search date bound to a GitHub-search-compatible literal. Returns
668
+ * either a `YYYY-MM-DD` date (relative durations and date-only inputs) or a
669
+ * full ISO 8601 datetime string (datetime inputs), so the caller can drop it
670
+ * straight into a qualifier like `created:>=<value>`.
671
+ */
672
+ export function parseSearchDateBound(raw: string, now: Date = new Date()): string {
673
+ const trimmed = raw.trim();
674
+ if (!trimmed) {
675
+ throw new ToolError("date bound must not be empty");
676
+ }
677
+
678
+ const relMatch = trimmed.match(RELATIVE_DURATION_PATTERN);
679
+ if (relMatch) {
680
+ const count = Number(relMatch[1]);
681
+ const unit = relMatch[2].toLowerCase();
682
+ const fixedMs = FIXED_UNIT_MS[unit];
683
+ let bound: Date;
684
+ if (fixedMs !== undefined) {
685
+ bound = new Date(now.getTime() - count * fixedMs);
686
+ } else {
687
+ bound = new Date(now);
688
+ if (unit === "mo") {
689
+ bound.setUTCMonth(bound.getUTCMonth() - count);
690
+ } else {
691
+ bound.setUTCFullYear(bound.getUTCFullYear() - count);
692
+ }
693
+ }
694
+ return bound.toISOString().slice(0, 10);
695
+ }
696
+
697
+ if (ISO_DATE_PATTERN.test(trimmed)) {
698
+ return trimmed;
699
+ }
700
+
701
+ const parsedMs = Date.parse(trimmed);
702
+ if (!Number.isNaN(parsedMs)) {
703
+ return new Date(parsedMs).toISOString();
704
+ }
705
+
706
+ throw new ToolError(
707
+ `invalid date bound: ${raw}. Expected a relative duration like "3d", "12h", "2w", an ISO date "YYYY-MM-DD", or an ISO datetime.`,
708
+ );
709
+ }
710
+
711
+ /**
712
+ * Build the GitHub-search qualifier (e.g. `created:>=2026-05-09`) for the
713
+ * provided bounds, or `undefined` if neither bound is set.
714
+ */
715
+ export function buildSearchDateQualifier(
716
+ field: string,
717
+ since: string | undefined,
718
+ until: string | undefined,
719
+ now?: Date,
720
+ ): string | undefined {
721
+ const sinceVal = since ? parseSearchDateBound(since, now) : undefined;
722
+ const untilVal = until ? parseSearchDateBound(until, now) : undefined;
723
+ if (sinceVal && untilVal) {
724
+ return `${field}:${sinceVal}..${untilVal}`;
725
+ }
726
+ if (sinceVal) {
727
+ return `${field}:>=${sinceVal}`;
728
+ }
729
+ if (untilVal) {
730
+ return `${field}:<=${untilVal}`;
731
+ }
732
+ return undefined;
733
+ }
734
+
735
+ function resolveSearchDateField(
736
+ command: "issues" | "prs" | "commits" | "repos",
737
+ requested: "created" | "updated" | undefined,
738
+ ): string {
739
+ if (command === "commits") {
740
+ return "committer-date";
741
+ }
742
+ const dateField = requested ?? "created";
743
+ if (command === "repos" && dateField === "updated") {
744
+ return "pushed";
745
+ }
746
+ return dateField;
747
+ }
748
+
749
+ function composeSearchQuery(parts: ReadonlyArray<string | undefined>): string {
750
+ const cleaned: string[] = [];
751
+ for (const part of parts) {
752
+ const trimmed = part?.trim();
753
+ if (trimmed) cleaned.push(trimmed);
754
+ }
755
+ if (cleaned.length === 0) {
756
+ throw new ToolError("query is required (or pass since/until to filter by date)");
757
+ }
758
+ return cleaned.join(" ");
759
+ }
760
+
761
+ function buildGhApiSearchArgs(
762
+ endpoint: "issues" | "code" | "commits" | "repositories",
763
+ query: string,
764
+ limit: number,
765
+ extraHeaders?: ReadonlyArray<string>,
766
+ ): string[] {
767
+ const args = ["api", "-X", "GET", `/search/${endpoint}`, "-f", `q=${query}`, "-F", `per_page=${limit}`];
768
+ for (const header of extraHeaders ?? []) {
769
+ args.push("-H", header);
770
+ }
771
+ return args;
772
+ }
773
+
774
+ function repoFromRepositoryUrl(value: string | undefined): string | undefined {
775
+ if (!value?.startsWith(REPO_API_URL_PREFIX)) return undefined;
776
+ return value.slice(REPO_API_URL_PREFIX.length);
777
+ }
778
+
779
+ function apiUserToGhUser(user: GhApiUser | null | undefined): GhUser | undefined {
780
+ if (!user) return undefined;
781
+ const login = user.login ?? undefined;
782
+ const name = user.name ?? undefined;
783
+ if (login === undefined && name === undefined) return undefined;
784
+ return { login, name };
785
+ }
786
+
787
+ function apiLabelsToGhLabels(labels: GhApiLabel[] | undefined): GhLabel[] {
788
+ return labels?.map(label => ({ name: label.name })) ?? [];
789
+ }
790
+
791
+ function apiIssueToSearchResult(item: GhApiSearchIssueItem): GhSearchResult {
792
+ const merged = Boolean(item.pull_request?.merged_at);
793
+ return {
794
+ author: apiUserToGhUser(item.user) ?? null,
795
+ createdAt: item.created_at,
796
+ labels: apiLabelsToGhLabels(item.labels),
797
+ number: item.number,
798
+ repository: { nameWithOwner: repoFromRepositoryUrl(item.repository_url) },
799
+ state: merged ? "merged" : item.state,
800
+ title: item.title,
801
+ updatedAt: item.updated_at,
802
+ url: item.html_url,
803
+ };
804
+ }
805
+
806
+ function apiCodeToSearchResult(item: GhApiSearchCodeItem): GhSearchCodeResult {
807
+ return {
808
+ path: item.path,
809
+ repository: { nameWithOwner: item.repository?.full_name },
810
+ sha: item.sha,
811
+ textMatches: item.text_matches?.map(match => ({ fragment: match.fragment, property: match.property })),
812
+ url: item.html_url,
813
+ };
814
+ }
815
+
816
+ function apiCommitToSearchResult(item: GhApiSearchCommitItem): GhSearchCommitResult {
817
+ return {
818
+ author: apiUserToGhUser(item.author) ?? null,
819
+ commit: item.commit
820
+ ? {
821
+ author: item.commit.author ?? null,
822
+ committer: item.commit.committer ?? null,
823
+ message: item.commit.message,
824
+ }
825
+ : null,
826
+ committer: apiUserToGhUser(item.committer) ?? null,
827
+ id: item.node_id,
828
+ repository: { nameWithOwner: item.repository?.full_name },
829
+ sha: item.sha,
830
+ url: item.html_url,
831
+ };
832
+ }
833
+
834
+ function apiRepoToSearchResult(item: GhApiSearchRepoItem): GhSearchRepoResult {
835
+ return {
836
+ createdAt: item.created_at,
837
+ description: item.description,
838
+ forksCount: item.forks_count,
839
+ fullName: item.full_name,
840
+ isArchived: item.archived,
841
+ isFork: item.fork,
842
+ isPrivate: item.private,
843
+ language: item.language,
844
+ openIssuesCount: item.open_issues_count,
845
+ owner: apiUserToGhUser(item.owner) ?? null,
846
+ stargazersCount: item.stargazers_count,
847
+ updatedAt: item.updated_at,
848
+ url: item.html_url,
849
+ visibility: item.visibility ?? null,
850
+ };
851
+ }
852
+
853
+ function sanitizeRemoteName(value: string): string {
854
+ const sanitized = value
855
+ .toLowerCase()
856
+ .replace(/[^a-z0-9]+/g, "-")
857
+ .replace(/^-+/g, "")
858
+ .replace(/-+$/g, "");
859
+ return sanitized.length > 0 ? `fork-${sanitized}` : "fork";
860
+ }
861
+
862
+ /** Maximum disambiguation suffixes we try before giving up on a worktree path. */
863
+ const WORKTREE_PATH_MAX_SUFFIX = 100;
864
+
865
+ function toLocalBranchRef(value: string): string {
866
+ return `refs/heads/${value}`;
867
+ }
868
+
869
+ async function requireGitRepoRoot(cwd: string, signal?: AbortSignal): Promise<string> {
870
+ const repoRoot = await git.repo.root(cwd, signal);
871
+ if (!repoRoot) {
872
+ throw new ToolError("Current git repository is unavailable.");
873
+ }
874
+
875
+ return repoRoot;
876
+ }
877
+
878
+ async function requirePrimaryGitRepoRoot(cwd: string, signal?: AbortSignal): Promise<string> {
879
+ const primaryRepoRoot = await git.repo.primaryRoot(cwd, signal);
880
+ if (!primaryRepoRoot) {
881
+ throw new ToolError("Current git repository is unavailable.");
882
+ }
883
+
884
+ return primaryRepoRoot;
885
+ }
886
+
887
+ async function requireCurrentGitBranch(cwd: string, signal?: AbortSignal): Promise<string> {
888
+ const branch = await git.branch.current(cwd, signal);
889
+ if (!branch) {
890
+ throw new ToolError("Current git branch is unavailable. Pass `branch` or `run` explicitly.");
891
+ }
892
+
893
+ return branch;
894
+ }
895
+
896
+ async function requireCurrentGitHead(cwd: string, signal?: AbortSignal): Promise<string> {
897
+ const headSha = await git.head.sha(cwd, signal);
898
+ if (!headSha) {
899
+ throw new ToolError("Current git HEAD is unavailable. Pass `run` explicitly.");
900
+ }
901
+
902
+ return headSha;
903
+ }
904
+
905
+ /**
906
+ * Resolve a worktree path that is free of conflicts.
907
+ *
908
+ * Given a `basePath`, return either `basePath` itself or `${basePath}-2`,
909
+ * `${basePath}-3`, … up to {@link WORKTREE_PATH_MAX_SUFFIX} — whichever is the
910
+ * first variant that is **not** registered with git as another worktree and
911
+ * **not** present on disk. The numeric tail salvages two rare cases that
912
+ * would otherwise abort a checkout: stale leftover dirs from an interrupted
913
+ * `git worktree add`, and the (vanishingly unlikely) `hashPath` collision
914
+ * between two repos that happen to produce the same 7-hex digest.
915
+ */
916
+ async function resolveAvailableWorktreePath(
917
+ basePath: string,
918
+ existingWorktrees: git.GitWorktreeEntry[],
919
+ ): Promise<string> {
920
+ const registered = new Set(existingWorktrees.map(entry => path.resolve(entry.path)));
921
+ for (let attempt = 0; attempt < WORKTREE_PATH_MAX_SUFFIX; attempt += 1) {
922
+ const candidate = attempt === 0 ? basePath : `${basePath}-${attempt + 1}`;
923
+ const normalized = path.resolve(candidate);
924
+ if (registered.has(normalized)) continue;
925
+ try {
926
+ await fs.stat(normalized);
927
+ } catch (error) {
928
+ if (isEnoent(error)) {
929
+ return candidate;
930
+ }
931
+ throw error;
932
+ }
933
+ }
934
+ throw new ToolError(
935
+ `could not find an unused worktree path under ${basePath} (tried ${WORKTREE_PATH_MAX_SUFFIX} suffixes)`,
936
+ );
937
+ }
938
+
939
+ function selectPrCloneUrl(originUrl: string | undefined, repo: Pick<GhRepoViewData, "url" | "sshUrl">): string {
940
+ if (originUrl?.startsWith("http://") || originUrl?.startsWith("https://")) {
941
+ return normalizeOptionalString(repo.url) ?? normalizeOptionalString(repo.sshUrl) ?? "";
942
+ }
943
+
944
+ return normalizeOptionalString(repo.sshUrl) ?? normalizeOptionalString(repo.url) ?? "";
945
+ }
946
+
947
+ async function getRemoteUrls(repoRoot: string, signal?: AbortSignal): Promise<Map<string, string>> {
948
+ const remotes = await git.remote.list(repoRoot, signal);
949
+ const urls = new Map<string, string>();
950
+ for (const remoteName of remotes) {
951
+ const remoteUrl = await git.remote.url(repoRoot, remoteName, signal);
952
+ if (remoteUrl) {
953
+ urls.set(remoteName, remoteUrl);
954
+ }
955
+ }
956
+ return urls;
957
+ }
958
+
959
+ async function ensurePrRemote(
960
+ repoRoot: string,
961
+ data: GhPrViewData,
962
+ signal?: AbortSignal,
963
+ ): Promise<{ name: string; url: string }> {
964
+ if (!data.isCrossRepository) {
965
+ const originUrl = await git.remote.url(repoRoot, "origin", signal);
966
+ if (!originUrl) {
967
+ throw new ToolError("origin remote is unavailable for this repository.");
968
+ }
969
+
970
+ return {
971
+ name: "origin",
972
+ url: originUrl,
973
+ };
974
+ }
975
+
976
+ const headRepository = requireNonEmpty(data.headRepository?.nameWithOwner, "head repository");
977
+ const repoSummary = await git.github.json<GhRepoViewData>(
978
+ repoRoot,
979
+ ["repo", "view", headRepository, "--json", GH_REPO_CLONE_FIELDS.join(",")],
980
+ signal,
981
+ { repoProvided: true },
982
+ );
983
+ const originUrl = await git.remote.url(repoRoot, "origin", signal);
984
+ const remoteUrl = selectPrCloneUrl(originUrl, repoSummary);
985
+ if (!remoteUrl) {
986
+ throw new ToolError(`Could not determine a clone URL for ${headRepository}.`);
987
+ }
988
+
989
+ const remotes = await getRemoteUrls(repoRoot, signal);
990
+ for (const [remoteName, url] of remotes) {
991
+ if (url === remoteUrl) {
992
+ return { name: remoteName, url };
993
+ }
994
+ }
995
+
996
+ const preferredRemoteName = sanitizeRemoteName(
997
+ data.headRepositoryOwner?.login ?? headRepository.split("/")[0] ?? "fork",
998
+ );
999
+ let remoteName = preferredRemoteName;
1000
+ let suffix = 2;
1001
+ while (remotes.has(remoteName)) {
1002
+ remoteName = `${preferredRemoteName}-${suffix}`;
1003
+ suffix += 1;
1004
+ }
1005
+
1006
+ await git.remote.add(repoRoot, remoteName, remoteUrl, signal);
1007
+
1008
+ return {
1009
+ name: remoteName,
1010
+ url: remoteUrl,
1011
+ };
1012
+ }
1013
+
1014
+ async function resolvePrBranchPushTarget(
1015
+ repoRoot: string,
1016
+ localBranch: string,
1017
+ signal?: AbortSignal,
1018
+ ): Promise<{
1019
+ remoteName: string;
1020
+ remoteBranch: string;
1021
+ remoteUrl?: string;
1022
+ prUrl?: string;
1023
+ maintainerCanModify?: boolean;
1024
+ isCrossRepository: boolean;
1025
+ }> {
1026
+ const headRef = await git.config.getBranch(repoRoot, localBranch, "ompPrHeadRef", signal);
1027
+ if (!headRef) {
1028
+ throw new ToolError(`branch ${localBranch} has no PR push metadata; check it out via op: pr_checkout first`);
1029
+ }
1030
+
1031
+ const pushRemote = await git.config.getBranch(repoRoot, localBranch, "pushRemote", signal);
1032
+ const remote = await git.config.getBranch(repoRoot, localBranch, "remote", signal);
1033
+ const prUrl = await git.config.getBranch(repoRoot, localBranch, "ompPrUrl", signal);
1034
+ const maintainerCanModifyValue = await git.config.getBranch(
1035
+ repoRoot,
1036
+ localBranch,
1037
+ "ompPrMaintainerCanModify",
1038
+ signal,
1039
+ );
1040
+ const isCrossRepositoryValue = await git.config.getBranch(repoRoot, localBranch, "ompPrIsCrossRepository", signal);
1041
+
1042
+ const remoteName = pushRemote ?? remote;
1043
+ if (!remoteName) {
1044
+ throw new ToolError(`branch ${localBranch} has no configured push remote`);
1045
+ }
1046
+
1047
+ return {
1048
+ remoteName,
1049
+ remoteBranch: headRef,
1050
+ remoteUrl: await git.remote.url(repoRoot, remoteName, signal),
1051
+ prUrl,
1052
+ maintainerCanModify:
1053
+ maintainerCanModifyValue === undefined
1054
+ ? undefined
1055
+ : ["1", "true", "yes", "on"].includes(maintainerCanModifyValue.toLowerCase()),
1056
+ isCrossRepository: ["1", "true", "yes", "on"].includes((isCrossRepositoryValue ?? "").toLowerCase()),
1057
+ };
1058
+ }
1059
+
1060
+ function formatAuthor(author: GhUser | null | undefined): string | undefined {
1061
+ if (!author) return undefined;
1062
+ if (author.login) return `@${author.login}`;
1063
+ if (author.name) return author.name;
1064
+ return undefined;
1065
+ }
1066
+
1067
+ function formatLabels(labels: GhLabel[] | undefined): string | undefined {
1068
+ const names = labels?.map(label => label.name).filter((value): value is string => Boolean(value)) ?? [];
1069
+ if (names.length === 0) return undefined;
1070
+ return names.join(", ");
1071
+ }
1072
+
1073
+ function pushLine(lines: string[], label: string, value: string | number | boolean | undefined): void {
1074
+ if (value === undefined || value === "") return;
1075
+ lines.push(`${label}: ${value}`);
1076
+ }
1077
+
1078
+ function parseRunReference(value: string | undefined): GhRunReference {
1079
+ const run = normalizeOptionalString(value);
1080
+ if (!run) {
1081
+ return {};
1082
+ }
1083
+
1084
+ if (/^\d+$/.test(run)) {
1085
+ return { runId: Number(run) };
1086
+ }
1087
+
1088
+ const match = run.match(RUN_URL_PATTERN);
1089
+ if (!match) {
1090
+ throw new ToolError("run must be a numeric workflow run ID or a full GitHub Actions run URL");
1091
+ }
1092
+
1093
+ return {
1094
+ repo: match[1],
1095
+ runId: Number(match[2]),
1096
+ };
1097
+ }
1098
+
1099
+ function parsePullRequestUrl(value: string | undefined): { repo?: string; prNumber?: number } {
1100
+ const normalized = normalizeOptionalString(value);
1101
+ if (!normalized) {
1102
+ return {};
1103
+ }
1104
+
1105
+ const match = normalized.match(PR_URL_PATTERN);
1106
+ if (!match) {
1107
+ return {};
1108
+ }
1109
+
1110
+ return {
1111
+ repo: match[1],
1112
+ prNumber: Number(match[2]),
1113
+ };
1114
+ }
1115
+
1116
+ /**
1117
+ * Parse a digit-only decimal positive integer or return undefined. Rejects
1118
+ * `1e2`, `0x10`, `12.0`, leading +/-, or any other shape `Number()` would
1119
+ * accept — those would otherwise key the cache against the wrong row.
1120
+ */
1121
+ export function parsePositiveDecimalInt(value: string | undefined): number | undefined {
1122
+ if (!value || !/^\d+$/.test(value)) return undefined;
1123
+ const num = Number(value);
1124
+ if (!Number.isSafeInteger(num) || num <= 0) return undefined;
1125
+ return num;
1126
+ }
1127
+
1128
+ function parseIssueUrl(value: string | undefined): { repo?: string; issueNumber?: number } {
1129
+ const normalized = normalizeOptionalString(value);
1130
+ if (!normalized) return {};
1131
+ const match = normalized.match(ISSUE_URL_PATTERN);
1132
+ if (!match) return {};
1133
+ return {
1134
+ repo: match[1],
1135
+ issueNumber: Number(match[2]),
1136
+ };
1137
+ }
1138
+
1139
+ function normalizePrReviewComment(comment: GhPrReviewCommentApi): GhPrReviewComment | null {
1140
+ if (typeof comment.id !== "number") {
1141
+ return null;
1142
+ }
1143
+
1144
+ return {
1145
+ author: comment.user ?? null,
1146
+ body: comment.body,
1147
+ createdAt: normalizeOptionalString(comment.created_at),
1148
+ id: comment.id,
1149
+ inReplyToId: typeof comment.in_reply_to_id === "number" ? comment.in_reply_to_id : undefined,
1150
+ line: typeof comment.line === "number" ? comment.line : undefined,
1151
+ originalLine: typeof comment.original_line === "number" ? comment.original_line : undefined,
1152
+ path: normalizeOptionalString(comment.path),
1153
+ side: normalizeOptionalString(comment.side),
1154
+ url: normalizeOptionalString(comment.html_url),
1155
+ };
1156
+ }
1157
+
1158
+ function normalizeRunJob(job: GhActionsJobApi): GhRunJobSnapshot | null {
1159
+ if (typeof job.id !== "number") {
1160
+ return null;
1161
+ }
1162
+
1163
+ return {
1164
+ id: job.id,
1165
+ name: normalizeOptionalString(job.name) ?? `job-${job.id}`,
1166
+ status: normalizeOptionalString(job.status),
1167
+ conclusion: normalizeOptionalString(job.conclusion),
1168
+ startedAt: normalizeOptionalString(job.started_at),
1169
+ completedAt: normalizeOptionalString(job.completed_at),
1170
+ url: normalizeOptionalString(job.html_url),
1171
+ };
1172
+ }
1173
+
1174
+ function normalizeRunSnapshot(run: GhActionsRunApi, jobs: GhRunJobSnapshot[]): GhRunSnapshot {
1175
+ if (typeof run.id !== "number") {
1176
+ throw new ToolError("GitHub Actions run response did not include a run ID.");
1177
+ }
1178
+
1179
+ return {
1180
+ id: run.id,
1181
+ workflowName: normalizeOptionalString(run.name),
1182
+ displayTitle: normalizeOptionalString(run.display_title),
1183
+ status: normalizeOptionalString(run.status),
1184
+ conclusion: normalizeOptionalString(run.conclusion),
1185
+ branch: normalizeOptionalString(run.head_branch),
1186
+ headSha: normalizeOptionalString(run.head_sha),
1187
+ createdAt: normalizeOptionalString(run.created_at),
1188
+ updatedAt: normalizeOptionalString(run.updated_at),
1189
+ url: normalizeOptionalString(run.html_url),
1190
+ jobs,
1191
+ };
1192
+ }
1193
+
1194
+ function getRunOutcome(value: string | undefined): "success" | "failure" | "pending" {
1195
+ if (!value) {
1196
+ return "pending";
1197
+ }
1198
+
1199
+ if (RUN_SUCCESS_CONCLUSIONS.has(value)) {
1200
+ return "success";
1201
+ }
1202
+
1203
+ if (RUN_FAILURE_CONCLUSIONS.has(value)) {
1204
+ return "failure";
1205
+ }
1206
+
1207
+ return "pending";
1208
+ }
1209
+
1210
+ function getRunSnapshotOutcome(run: GhRunSnapshot): "success" | "failure" | "pending" {
1211
+ if (run.status !== "completed") {
1212
+ return "pending";
1213
+ }
1214
+
1215
+ return getRunOutcome(run.conclusion);
1216
+ }
1217
+
1218
+ function getRunCollectionOutcome(runs: GhRunSnapshot[]): "success" | "failure" | "pending" {
1219
+ if (runs.length === 0) {
1220
+ return "pending";
1221
+ }
1222
+
1223
+ let pending = false;
1224
+ for (const run of runs) {
1225
+ if (run.jobs.some(isFailedJob)) {
1226
+ return "failure";
1227
+ }
1228
+
1229
+ const outcome = getRunSnapshotOutcome(run);
1230
+ if (outcome === "failure") {
1231
+ return "failure";
1232
+ }
1233
+ if (outcome === "pending") {
1234
+ pending = true;
1235
+ }
1236
+ }
1237
+
1238
+ return pending ? "pending" : "success";
1239
+ }
1240
+
1241
+ function getRunCollectionSignature(runs: GhRunSnapshot[]): string {
1242
+ return runs
1243
+ .map(run => run.id)
1244
+ .sort((left, right) => left - right)
1245
+ .join(",");
1246
+ }
1247
+
1248
+ function isFailedJob(job: GhRunJobSnapshot): boolean {
1249
+ return job.conclusion !== undefined && JOB_FAILURE_CONCLUSIONS.has(job.conclusion);
1250
+ }
1251
+
1252
+ function formatJobState(job: GhRunJobSnapshot): string {
1253
+ return job.conclusion ?? job.status ?? "unknown";
1254
+ }
1255
+
1256
+ function parseTimestampMs(value: string | undefined): number | undefined {
1257
+ if (!value) {
1258
+ return undefined;
1259
+ }
1260
+
1261
+ const timestamp = Date.parse(value);
1262
+ return Number.isNaN(timestamp) ? undefined : timestamp;
1263
+ }
1264
+
1265
+ function getJobDurationSeconds(job: GhRunJobSnapshot, observedAtMs: number): number | undefined {
1266
+ const startedAtMs = parseTimestampMs(job.startedAt);
1267
+ if (startedAtMs === undefined) {
1268
+ return undefined;
1269
+ }
1270
+
1271
+ const completedAtMs = parseTimestampMs(job.completedAt) ?? observedAtMs;
1272
+ return Math.max(0, Math.floor((completedAtMs - startedAtMs) / 1000));
1273
+ }
1274
+
1275
+ function buildRunWatchJobDetails(job: GhRunJobSnapshot, observedAtMs: number): GhRunWatchJobDetails {
1276
+ return {
1277
+ id: job.id,
1278
+ name: job.name,
1279
+ status: job.status,
1280
+ conclusion: job.conclusion,
1281
+ durationSeconds: getJobDurationSeconds(job, observedAtMs),
1282
+ url: job.url,
1283
+ };
1284
+ }
1285
+
1286
+ function buildRunWatchRunDetails(run: GhRunSnapshot, observedAtMs: number): GhRunWatchRunDetails {
1287
+ return {
1288
+ id: run.id,
1289
+ workflowName: run.workflowName,
1290
+ displayTitle: run.displayTitle,
1291
+ status: run.status,
1292
+ conclusion: run.conclusion,
1293
+ branch: run.branch,
1294
+ headSha: run.headSha,
1295
+ url: run.url,
1296
+ jobs: run.jobs.map(job => buildRunWatchJobDetails(job, observedAtMs)),
1297
+ };
1298
+ }
1299
+
1300
+ function buildFailedLogDetails(failedJobLogs: GhFailedJobLog[]): GhRunWatchFailedLogDetails[] {
1301
+ return failedJobLogs.map(entry => ({
1302
+ runId: entry.run.id,
1303
+ workflowName: entry.run.workflowName,
1304
+ jobName: entry.job.name,
1305
+ conclusion: entry.job.conclusion,
1306
+ tail: entry.tail,
1307
+ available: entry.available,
1308
+ }));
1309
+ }
1310
+
1311
+ function renderJobsSection(jobs: GhRunJobSnapshot[]): string[] {
1312
+ if (jobs.length === 0) {
1313
+ return ["## Jobs", "", "No jobs reported yet."];
1314
+ }
1315
+
1316
+ const lines: string[] = [`## Jobs (${jobs.length})`, ""];
1317
+ for (const job of jobs) {
1318
+ lines.push(`- [${formatJobState(job)}] ${job.name}`);
1319
+ if (job.startedAt) {
1320
+ pushLine(lines, " Started", job.startedAt);
1321
+ }
1322
+ if (job.completedAt) {
1323
+ pushLine(lines, " Completed", job.completedAt);
1324
+ }
1325
+ if (job.url) {
1326
+ pushLine(lines, " URL", job.url);
1327
+ }
1328
+ }
1329
+
1330
+ return lines;
1331
+ }
1332
+
1333
+ function renderFailedJobLogs(
1334
+ failedJobLogs: GhFailedJobLog[],
1335
+ options: { mode: "tail"; tail: number } | { mode: "full" },
1336
+ ): string[] {
1337
+ if (failedJobLogs.length === 0) {
1338
+ return [];
1339
+ }
1340
+
1341
+ const lines: string[] = ["## Failed Jobs", ""];
1342
+ for (const entry of failedJobLogs) {
1343
+ lines.push(`### ${entry.job.name} [${entry.job.conclusion ?? "failed"}]`);
1344
+ pushLine(lines, "Run", `#${entry.run.id}`);
1345
+ pushLine(lines, "Workflow", entry.run.workflowName ?? undefined);
1346
+ if (entry.job.startedAt) {
1347
+ pushLine(lines, "Started", entry.job.startedAt);
1348
+ }
1349
+ if (entry.job.completedAt) {
1350
+ pushLine(lines, "Completed", entry.job.completedAt);
1351
+ }
1352
+ if (entry.job.url) {
1353
+ pushLine(lines, "URL", entry.job.url);
1354
+ }
1355
+ lines.push("");
1356
+ const logText = options.mode === "full" ? entry.full : entry.tail;
1357
+ if (entry.available && logText) {
1358
+ lines.push(options.mode === "full" ? "Full log:" : `Last ${options.tail} log lines:`);
1359
+ lines.push("```text");
1360
+ lines.push(logText);
1361
+ lines.push("```");
1362
+ } else {
1363
+ lines.push(options.mode === "full" ? "Full log unavailable." : "Log tail unavailable.");
1364
+ }
1365
+ lines.push("");
1366
+ }
1367
+
1368
+ return lines;
1369
+ }
1370
+
1371
+ function renderRunSection(run: GhRunSnapshot): string[] {
1372
+ const label = run.workflowName ? `### Run #${run.id} - ${run.workflowName}` : `### Run #${run.id}`;
1373
+ const lines: string[] = [label, ""];
1374
+ pushLine(lines, "Title", run.displayTitle ?? undefined);
1375
+ pushLine(lines, "Branch", run.branch ?? undefined);
1376
+ pushLine(lines, "Commit", formatShortSha(run.headSha));
1377
+ pushLine(lines, "Status", run.status);
1378
+ pushLine(lines, "Conclusion", run.conclusion ?? undefined);
1379
+ pushLine(lines, "Created", run.createdAt);
1380
+ pushLine(lines, "Updated", run.updatedAt);
1381
+ pushLine(lines, "URL", run.url);
1382
+ lines.push("");
1383
+ lines.push(...renderJobsSection(run.jobs));
1384
+ return lines;
1385
+ }
1386
+
1387
+ function formatRunWatchSnapshot(
1388
+ repo: string,
1389
+ run: GhRunSnapshot,
1390
+ pollCount: number,
1391
+ note?: string,
1392
+ includeOutcome: boolean = false,
1393
+ ): string {
1394
+ const failedJobs = run.jobs.filter(isFailedJob);
1395
+ const lines: string[] = [`# Watching GitHub Actions Run #${run.id}`, ""];
1396
+ pushLine(lines, "Repository", repo);
1397
+ pushLine(lines, "Workflow", run.workflowName ?? undefined);
1398
+ pushLine(lines, "Title", run.displayTitle ?? undefined);
1399
+ pushLine(lines, "Branch", run.branch ?? undefined);
1400
+ pushLine(lines, "Status", run.status);
1401
+ pushLine(lines, "Conclusion", run.conclusion ?? undefined);
1402
+ pushLine(lines, "Created", run.createdAt);
1403
+ pushLine(lines, "Updated", run.updatedAt);
1404
+ pushLine(lines, "URL", run.url);
1405
+ pushLine(lines, "Poll", pollCount);
1406
+ pushLine(lines, "Failed jobs", failedJobs.length || undefined);
1407
+
1408
+ if (note) {
1409
+ lines.push("");
1410
+ lines.push(`Note: ${note}`);
1411
+ }
1412
+
1413
+ lines.push("");
1414
+ lines.push(...renderJobsSection(run.jobs));
1415
+
1416
+ if (includeOutcome) {
1417
+ lines.push("");
1418
+ lines.push(failedJobs.length > 0 ? "Failures detected." : "All jobs passed.");
1419
+ }
1420
+
1421
+ return lines.join("\n").trim();
1422
+ }
1423
+
1424
+ function formatRunWatchResult(
1425
+ repo: string,
1426
+ run: GhRunSnapshot,
1427
+ failedJobLogs: GhFailedJobLog[],
1428
+ tail: number,
1429
+ options?: { mode?: "tail" | "full" },
1430
+ ): string {
1431
+ const failedJobs = run.jobs.filter(isFailedJob);
1432
+ const lines: string[] = [`# GitHub Actions Run #${run.id}`, ""];
1433
+ pushLine(lines, "Repository", repo);
1434
+ pushLine(lines, "Workflow", run.workflowName ?? undefined);
1435
+ pushLine(lines, "Title", run.displayTitle ?? undefined);
1436
+ pushLine(lines, "Branch", run.branch ?? undefined);
1437
+ pushLine(lines, "Status", run.status);
1438
+ pushLine(lines, "Conclusion", run.conclusion ?? undefined);
1439
+ pushLine(lines, "Created", run.createdAt);
1440
+ pushLine(lines, "Updated", run.updatedAt);
1441
+ pushLine(lines, "URL", run.url);
1442
+ lines.push("");
1443
+ lines.push(...renderJobsSection(run.jobs));
1444
+
1445
+ if (failedJobs.length > 0) {
1446
+ lines.push("");
1447
+ lines.push(
1448
+ ...renderFailedJobLogs(failedJobLogs, options?.mode === "full" ? { mode: "full" } : { mode: "tail", tail }),
1449
+ );
1450
+ lines.push("Run failed.");
1451
+ } else if (getRunOutcome(run.conclusion) === "success") {
1452
+ lines.push("");
1453
+ lines.push("All jobs passed.");
1454
+ } else {
1455
+ lines.push("");
1456
+ lines.push("Run completed without successful jobs, but no failed job logs were available.");
1457
+ }
1458
+
1459
+ return lines.join("\n").trim();
1460
+ }
1461
+
1462
+ function formatCommitRunWatchSnapshot(
1463
+ repo: string,
1464
+ headSha: string,
1465
+ branch: string | undefined,
1466
+ runs: GhRunSnapshot[],
1467
+ pollCount: number,
1468
+ note?: string,
1469
+ ): string {
1470
+ const failedJobs = runs.flatMap(run => run.jobs.filter(isFailedJob));
1471
+ const completedRuns = runs.filter(run => run.status === "completed").length;
1472
+ const lines: string[] = [`# Watching GitHub Actions for ${formatShortSha(headSha) ?? headSha}`, ""];
1473
+ pushLine(lines, "Repository", repo);
1474
+ pushLine(lines, "Branch", branch);
1475
+ pushLine(lines, "Commit", headSha);
1476
+ pushLine(lines, "Poll", pollCount);
1477
+ pushLine(lines, "Runs", runs.length);
1478
+ pushLine(lines, "Completed runs", `${completedRuns}/${runs.length}`);
1479
+ pushLine(lines, "Failed jobs", failedJobs.length || undefined);
1480
+
1481
+ if (note) {
1482
+ lines.push("");
1483
+ lines.push(`Note: ${note}`);
1484
+ }
1485
+
1486
+ if (runs.length === 0) {
1487
+ lines.push("");
1488
+ lines.push("Waiting for workflow runs for this commit.");
1489
+ return lines.join("\n").trim();
1490
+ }
1491
+
1492
+ for (const run of runs) {
1493
+ lines.push("");
1494
+ lines.push(...renderRunSection(run));
1495
+ }
1496
+
1497
+ return lines.join("\n").trim();
1498
+ }
1499
+
1500
+ function formatCommitRunWatchResult(
1501
+ repo: string,
1502
+ headSha: string,
1503
+ branch: string | undefined,
1504
+ runs: GhRunSnapshot[],
1505
+ failedJobLogs: GhFailedJobLog[],
1506
+ tail: number,
1507
+ options?: { mode?: "tail" | "full" },
1508
+ ): string {
1509
+ const outcome = getRunCollectionOutcome(runs);
1510
+ const lines: string[] = [`# GitHub Actions for ${formatShortSha(headSha) ?? headSha}`, ""];
1511
+ pushLine(lines, "Repository", repo);
1512
+ pushLine(lines, "Branch", branch);
1513
+ pushLine(lines, "Commit", headSha);
1514
+ pushLine(lines, "Runs", runs.length);
1515
+
1516
+ for (const run of runs) {
1517
+ lines.push("");
1518
+ lines.push(...renderRunSection(run));
1519
+ }
1520
+
1521
+ if (failedJobLogs.length > 0) {
1522
+ lines.push("");
1523
+ lines.push(
1524
+ ...renderFailedJobLogs(failedJobLogs, options?.mode === "full" ? { mode: "full" } : { mode: "tail", tail }),
1525
+ );
1526
+ lines.push("Workflow runs for this commit failed.");
1527
+ } else if (outcome === "success") {
1528
+ lines.push("");
1529
+ lines.push("All workflow runs for this commit passed.");
1530
+ } else {
1531
+ lines.push("");
1532
+ lines.push("Workflow runs for this commit did not complete successfully.");
1533
+ }
1534
+
1535
+ return lines.join("\n").trim();
1536
+ }
1537
+
1538
+ function buildGhDetails(repo: string, run: GhRunSnapshot): GhToolDetails {
1539
+ return {
1540
+ repo,
1541
+ branch: run.branch,
1542
+ headSha: run.headSha,
1543
+ runId: run.id,
1544
+ runIds: [run.id],
1545
+ status: run.status,
1546
+ conclusion: run.conclusion,
1547
+ failedJobs: run.jobs.filter(isFailedJob).map(job => job.name),
1548
+ };
1549
+ }
1550
+
1551
+ function buildRunWatchDetails(
1552
+ repo: string,
1553
+ run: GhRunSnapshot,
1554
+ options?: {
1555
+ state?: GhRunWatchViewDetails["state"];
1556
+ pollCount?: number;
1557
+ note?: string;
1558
+ failedJobLogs?: GhFailedJobLog[];
1559
+ },
1560
+ ): GhToolDetails {
1561
+ const observedAtMs = Date.now();
1562
+ return {
1563
+ ...buildGhDetails(repo, run),
1564
+ watch: {
1565
+ mode: "run",
1566
+ state: options?.state ?? "completed",
1567
+ repo,
1568
+ branch: run.branch,
1569
+ headSha: run.headSha,
1570
+ pollCount: options?.pollCount,
1571
+ note: options?.note,
1572
+ run: buildRunWatchRunDetails(run, observedAtMs),
1573
+ failedLogs: buildFailedLogDetails(options?.failedJobLogs ?? []),
1574
+ },
1575
+ };
1576
+ }
1577
+
1578
+ function buildGhRunCollectionDetails(
1579
+ repo: string,
1580
+ headSha: string,
1581
+ branch: string | undefined,
1582
+ runs: GhRunSnapshot[],
1583
+ ): GhToolDetails {
1584
+ const outcome = getRunCollectionOutcome(runs);
1585
+ return {
1586
+ repo,
1587
+ branch,
1588
+ headSha,
1589
+ runIds: runs.map(run => run.id),
1590
+ status: runs.length > 0 && runs.every(run => run.status === "completed") ? "completed" : "in_progress",
1591
+ conclusion: outcome,
1592
+ failedJobs: runs.flatMap(run =>
1593
+ run.jobs.filter(isFailedJob).map(job => `${run.workflowName ?? `run ${run.id}`}: ${job.name}`),
1594
+ ),
1595
+ };
1596
+ }
1597
+
1598
+ function buildCommitRunWatchDetails(
1599
+ repo: string,
1600
+ headSha: string,
1601
+ branch: string | undefined,
1602
+ runs: GhRunSnapshot[],
1603
+ options?: {
1604
+ state?: GhRunWatchViewDetails["state"];
1605
+ pollCount?: number;
1606
+ note?: string;
1607
+ failedJobLogs?: GhFailedJobLog[];
1608
+ },
1609
+ ): GhToolDetails {
1610
+ const observedAtMs = Date.now();
1611
+ return {
1612
+ ...buildGhRunCollectionDetails(repo, headSha, branch, runs),
1613
+ watch: {
1614
+ mode: "commit",
1615
+ state: options?.state ?? "completed",
1616
+ repo,
1617
+ branch,
1618
+ headSha,
1619
+ pollCount: options?.pollCount,
1620
+ note: options?.note,
1621
+ runs: runs.map(run => buildRunWatchRunDetails(run, observedAtMs)),
1622
+ failedLogs: buildFailedLogDetails(options?.failedJobLogs ?? []),
1623
+ },
1624
+ };
1625
+ }
1626
+
1627
+ async function resolveGitHubRepo(
1628
+ cwd: string,
1629
+ repo: string | undefined,
1630
+ runRepo: string | undefined,
1631
+ signal?: AbortSignal,
1632
+ ): Promise<string> {
1633
+ if (repo && runRepo && repo !== runRepo) {
1634
+ throw new ToolError("run URL repository does not match the provided repo");
1635
+ }
1636
+
1637
+ if (repo) {
1638
+ return repo;
1639
+ }
1640
+
1641
+ if (runRepo) {
1642
+ return runRepo;
1643
+ }
1644
+
1645
+ const resolved = await git.github.text(
1646
+ cwd,
1647
+ ["repo", "view", "--json", "nameWithOwner", "-q", ".nameWithOwner"],
1648
+ signal,
1649
+ );
1650
+ return requireNonEmpty(resolved, "repo");
1651
+ }
1652
+
1653
+ /**
1654
+ * Process-lifetime cache of `gh repo view --json nameWithOwner` lookups keyed
1655
+ * by absolute cwd. Avoids repeated `gh` chatter when the same protocol handler
1656
+ * or tool call resolves the default repo many times in a row.
1657
+ *
1658
+ * The shared lookup is intentionally **not** bound to any caller's
1659
+ * AbortSignal. Cancelling one caller would otherwise kill the underlying
1660
+ * `gh repo view` for every concurrent waiter on the same cwd. Each caller's
1661
+ * signal is honored at the wait point via `untilAborted` instead, so an abort
1662
+ * unwinds only that caller.
1663
+ */
1664
+ const DEFAULT_REPO_RESOLVED = new Map<string, string>();
1665
+ const DEFAULT_REPO_INFLIGHT = new Map<string, Promise<string>>();
1666
+
1667
+ export async function resolveDefaultRepoMemoized(cwd: string, signal?: AbortSignal): Promise<string> {
1668
+ const key = path.resolve(cwd);
1669
+ const ready = DEFAULT_REPO_RESOLVED.get(key);
1670
+ if (ready) return ready;
1671
+ let pending = DEFAULT_REPO_INFLIGHT.get(key);
1672
+ if (!pending) {
1673
+ pending = (async () => {
1674
+ // No caller signal: this lookup is shared across every concurrent
1675
+ // waiter on the same cwd.
1676
+ const resolved = await git.github.text(cwd, [
1677
+ "repo",
1678
+ "view",
1679
+ "--json",
1680
+ "nameWithOwner",
1681
+ "-q",
1682
+ ".nameWithOwner",
1683
+ ]);
1684
+ const value = requireNonEmpty(resolved, "repo");
1685
+ DEFAULT_REPO_RESOLVED.set(key, value);
1686
+ return value;
1687
+ })();
1688
+ // Drop the in-flight slot on settle so failures don't poison the cache
1689
+ // and so a successful resolution survives only in `DEFAULT_REPO_RESOLVED`.
1690
+ void pending.then(
1691
+ () => DEFAULT_REPO_INFLIGHT.delete(key),
1692
+ () => DEFAULT_REPO_INFLIGHT.delete(key),
1693
+ );
1694
+ DEFAULT_REPO_INFLIGHT.set(key, pending);
1695
+ }
1696
+ return untilAborted(signal, pending);
1697
+ }
1698
+
1699
+ /**
1700
+ * Matches search-query qualifiers that already scope to a repository, org, or
1701
+ * user. When present, callers should avoid layering a default `repo:<current>`
1702
+ * on top — the user has already expressed an explicit scope.
1703
+ *
1704
+ * Only the leading `repo:`/`org:`/`user:`/`owner:` token is treated as a
1705
+ * scope marker; arbitrary substrings (e.g. inside quoted text) are ignored.
1706
+ */
1707
+ const REPO_SCOPE_QUALIFIER_PATTERN = /(?:^|\s)-?(?:repo|org|user|owner):\S/i;
1708
+
1709
+ /**
1710
+ * Resolve the effective `repo:` scope for a search op. Returns the explicit
1711
+ * `repo` when set, `undefined` when the query already carries a scoping
1712
+ * qualifier, and otherwise the current checkout's `owner/repo` via
1713
+ * `resolveDefaultRepoMemoized`. Resolution failures (no git/gh context, no
1714
+ * configured remote) silently fall back to `undefined` so the search proceeds
1715
+ * across all of GitHub instead of throwing.
1716
+ */
1717
+ async function resolveSearchRepoScope(
1718
+ cwd: string,
1719
+ repo: string | undefined,
1720
+ query: string | undefined,
1721
+ signal: AbortSignal | undefined,
1722
+ ): Promise<string | undefined> {
1723
+ if (repo) return repo;
1724
+ if (query && REPO_SCOPE_QUALIFIER_PATTERN.test(query)) return undefined;
1725
+ try {
1726
+ return await resolveDefaultRepoMemoized(cwd, signal);
1727
+ } catch {
1728
+ return undefined;
1729
+ }
1730
+ }
1731
+
1732
+ async function resolveGitHubBranchHead(
1733
+ cwd: string,
1734
+ repo: string,
1735
+ branch: string,
1736
+ signal?: AbortSignal,
1737
+ ): Promise<string> {
1738
+ const response = await git.github.json<GhBranchApiResponse>(
1739
+ cwd,
1740
+ ["api", "--method", "GET", `/repos/${repo}/branches/${encodeURIComponent(branch)}`],
1741
+ signal,
1742
+ { repoProvided: true },
1743
+ );
1744
+ return requireNonEmpty(response.commit?.sha, `head SHA for branch ${branch}`);
1745
+ }
1746
+
1747
+ async function fetchRunsForCommit(
1748
+ cwd: string,
1749
+ repo: string,
1750
+ headSha: string,
1751
+ branch: string | undefined,
1752
+ signal?: AbortSignal,
1753
+ ): Promise<GhRunSnapshot[]> {
1754
+ const response = await git.github.json<GhActionsRunListResponse>(
1755
+ cwd,
1756
+ [
1757
+ "api",
1758
+ "--method",
1759
+ "GET",
1760
+ `/repos/${repo}/actions/runs`,
1761
+ "-F",
1762
+ `head_sha=${headSha}`,
1763
+ "-F",
1764
+ `per_page=${RUN_JOBS_PAGE_SIZE}`,
1765
+ ...(branch ? ["-F", `branch=${branch}`] : []),
1766
+ ],
1767
+ signal,
1768
+ { repoProvided: true },
1769
+ );
1770
+
1771
+ return Promise.all(
1772
+ (response.workflow_runs ?? [])
1773
+ .filter((run): run is GhActionsRunApi & { id: number } => typeof run.id === "number")
1774
+ .map(async run => {
1775
+ const jobs = await fetchRunJobs(cwd, repo, run.id, signal);
1776
+ return normalizeRunSnapshot(run, jobs);
1777
+ }),
1778
+ );
1779
+ }
1780
+
1781
+ async function fetchRunJobs(
1782
+ cwd: string,
1783
+ repo: string,
1784
+ runId: number,
1785
+ signal?: AbortSignal,
1786
+ ): Promise<GhRunJobSnapshot[]> {
1787
+ const jobs: GhRunJobSnapshot[] = [];
1788
+ let page = 1;
1789
+
1790
+ while (true) {
1791
+ const response = await git.github.json<GhActionsJobsResponse>(
1792
+ cwd,
1793
+ [
1794
+ "api",
1795
+ "--method",
1796
+ "GET",
1797
+ `/repos/${repo}/actions/runs/${runId}/jobs`,
1798
+ "-F",
1799
+ `per_page=${RUN_JOBS_PAGE_SIZE}`,
1800
+ "-F",
1801
+ `page=${page}`,
1802
+ ],
1803
+ signal,
1804
+ { repoProvided: true },
1805
+ );
1806
+ const pageJobs = (response.jobs ?? [])
1807
+ .map(job => normalizeRunJob(job))
1808
+ .filter((job): job is GhRunJobSnapshot => job !== null);
1809
+ jobs.push(...pageJobs);
1810
+
1811
+ if (pageJobs.length < RUN_JOBS_PAGE_SIZE) {
1812
+ break;
1813
+ }
1814
+
1815
+ if ((response.total_count ?? 0) <= jobs.length) {
1816
+ break;
1817
+ }
1818
+
1819
+ page += 1;
1820
+ }
1821
+
1822
+ return jobs;
1823
+ }
1824
+
1825
+ async function fetchPrReviewComments(
1826
+ cwd: string,
1827
+ repo: string,
1828
+ prNumber: number,
1829
+ signal?: AbortSignal,
1830
+ ): Promise<GhPrReviewComment[]> {
1831
+ const reviewComments: GhPrReviewComment[] = [];
1832
+ let page = 1;
1833
+
1834
+ while (true) {
1835
+ const response = await git.github.json<GhPrReviewCommentApi[]>(
1836
+ cwd,
1837
+ [
1838
+ "api",
1839
+ "--method",
1840
+ "GET",
1841
+ `/repos/${repo}/pulls/${prNumber}/comments`,
1842
+ "-F",
1843
+ `per_page=${REVIEW_COMMENTS_PAGE_SIZE}`,
1844
+ "-F",
1845
+ `page=${page}`,
1846
+ ],
1847
+ signal,
1848
+ { repoProvided: true },
1849
+ );
1850
+
1851
+ const pageComments = response
1852
+ .map(comment => normalizePrReviewComment(comment))
1853
+ .filter((comment): comment is GhPrReviewComment => comment !== null);
1854
+ reviewComments.push(...pageComments);
1855
+
1856
+ if (pageComments.length < REVIEW_COMMENTS_PAGE_SIZE) {
1857
+ break;
1858
+ }
1859
+
1860
+ page += 1;
1861
+ }
1862
+
1863
+ return reviewComments;
1864
+ }
1865
+
1866
+ async function fetchRunSnapshot(
1867
+ cwd: string,
1868
+ repo: string,
1869
+ runId: number,
1870
+ signal?: AbortSignal,
1871
+ ): Promise<GhRunSnapshot> {
1872
+ const [run, jobs] = await Promise.all([
1873
+ git.github.json<GhActionsRunApi>(
1874
+ cwd,
1875
+ ["api", "--method", "GET", `/repos/${repo}/actions/runs/${runId}`],
1876
+ signal,
1877
+ {
1878
+ repoProvided: true,
1879
+ },
1880
+ ),
1881
+ fetchRunJobs(cwd, repo, runId, signal),
1882
+ ]);
1883
+
1884
+ return normalizeRunSnapshot(run, jobs);
1885
+ }
1886
+
1887
+ function tailLogLines(log: string, tail: number): string | undefined {
1888
+ const normalized = normalizeBlock(log);
1889
+ if (!normalized) {
1890
+ return undefined;
1891
+ }
1892
+
1893
+ const lines = normalized.split("\n");
1894
+ return lines.slice(-tail).join("\n").trimEnd();
1895
+ }
1896
+
1897
+ async function fetchFailedJobLogs(
1898
+ cwd: string,
1899
+ repo: string,
1900
+ failedJobs: Array<{ run: GhRunSnapshot; job: GhRunJobSnapshot }>,
1901
+ tail: number,
1902
+ signal?: AbortSignal,
1903
+ ): Promise<GhFailedJobLog[]> {
1904
+ return Promise.all(
1905
+ failedJobs.map(async entry => {
1906
+ const result = await git.github.run(cwd, ["api", `/repos/${repo}/actions/jobs/${entry.job.id}/logs`], signal);
1907
+ const fullLog = result.exitCode === 0 ? normalizeBlock(result.stdout) : undefined;
1908
+ const logTail = fullLog ? tailLogLines(fullLog, tail) : undefined;
1909
+ return {
1910
+ run: entry.run,
1911
+ job: entry.job,
1912
+ full: fullLog,
1913
+ tail: logTail,
1914
+ available: Boolean(fullLog),
1915
+ };
1916
+ }),
1917
+ );
1918
+ }
1919
+
1920
+ function formatCommentsSection(comments: GhComment[] | undefined): string[] {
1921
+ if (!comments || comments.length === 0) {
1922
+ return [];
1923
+ }
1924
+
1925
+ const visible = comments.filter(comment => !comment.isMinimized);
1926
+ const hiddenCount = comments.length - visible.length;
1927
+ const lines: string[] = ["## Comments", ""];
1928
+
1929
+ if (visible.length === 0) {
1930
+ lines.push(`No visible comments. Minimized comments omitted: ${hiddenCount}.`);
1931
+ return lines;
1932
+ }
1933
+
1934
+ lines[0] = `## Comments (${visible.length})`;
1935
+
1936
+ for (const comment of visible) {
1937
+ const author = formatAuthor(comment.author) ?? "unknown";
1938
+ const createdAt = comment.createdAt ? ` · ${comment.createdAt}` : "";
1939
+ lines.push(`### ${author}${createdAt}`);
1940
+ lines.push("");
1941
+ lines.push(normalizeText(comment.body) || "No comment body.");
1942
+ if (comment.url) {
1943
+ lines.push("");
1944
+ lines.push(`URL: ${comment.url}`);
1945
+ }
1946
+ lines.push("");
1947
+ }
1948
+
1949
+ if (hiddenCount > 0) {
1950
+ lines.push(`Minimized comments omitted: ${hiddenCount}.`);
1951
+ }
1952
+
1953
+ return lines;
1954
+ }
1955
+
1956
+ function formatReviewsSection(reviews: GhPrReview[] | undefined): string[] {
1957
+ if (!reviews || reviews.length === 0) {
1958
+ return [];
1959
+ }
1960
+
1961
+ const lines: string[] = [`## Reviews (${reviews.length})`, ""];
1962
+ for (const review of reviews) {
1963
+ const author = formatAuthor(review.author) ?? "unknown";
1964
+ const submittedAt = review.submittedAt ? ` - ${review.submittedAt}` : "";
1965
+ const state = review.state ? ` [${review.state}]` : "";
1966
+ lines.push(`### ${author}${submittedAt}${state}`);
1967
+ if (review.commit?.oid) {
1968
+ lines.push("");
1969
+ lines.push(`Commit: ${formatShortSha(review.commit.oid)}`);
1970
+ }
1971
+ lines.push("");
1972
+ lines.push(normalizeText(review.body) || "No review body.");
1973
+ lines.push("");
1974
+ }
1975
+
1976
+ return lines;
1977
+ }
1978
+
1979
+ function formatReviewCommentLocation(comment: GhPrReviewComment): string | undefined {
1980
+ if (!comment.path) {
1981
+ return undefined;
1982
+ }
1983
+
1984
+ const line = comment.line ?? comment.originalLine;
1985
+ return line === undefined ? comment.path : `${comment.path}:${line}`;
1986
+ }
1987
+
1988
+ function formatReviewCommentsSection(comments: GhPrReviewComment[] | undefined): string[] {
1989
+ if (!comments || comments.length === 0) {
1990
+ return [];
1991
+ }
1992
+
1993
+ const lines: string[] = [`## Review Comments (${comments.length})`, ""];
1994
+ for (const comment of comments) {
1995
+ const author = formatAuthor(comment.author) ?? "unknown";
1996
+ const createdAt = comment.createdAt ? ` · ${comment.createdAt}` : "";
1997
+ lines.push(`### ${author}${createdAt}`);
1998
+ lines.push("");
1999
+ pushLine(lines, "Location", formatReviewCommentLocation(comment));
2000
+ pushLine(lines, "Side", comment.side);
2001
+ pushLine(lines, "Reply to", comment.inReplyToId);
2002
+ pushLine(lines, "URL", comment.url);
2003
+ lines.push("");
2004
+ lines.push(normalizeText(comment.body) || "No review comment body.");
2005
+ lines.push("");
2006
+ }
2007
+
2008
+ return lines;
2009
+ }
2010
+
2011
+ function formatRepoView(data: GhRepoViewData, input: { repo?: string; branch?: string }): string {
2012
+ const lines: string[] = [];
2013
+ const name = data.nameWithOwner ?? input.repo ?? "GitHub Repository";
2014
+ lines.push(`# ${name}`);
2015
+ lines.push("");
2016
+ lines.push(normalizeText(data.description) || "No description provided.");
2017
+ lines.push("");
2018
+ pushLine(lines, "URL", data.url);
2019
+ pushLine(lines, "Default branch", data.defaultBranchRef?.name);
2020
+ pushLine(lines, "Branch", normalizeOptionalString(input.branch));
2021
+ pushLine(lines, "Visibility", data.visibility ?? undefined);
2022
+ pushLine(lines, "Viewer permission", data.viewerPermission ?? undefined);
2023
+ pushLine(lines, "Primary language", data.primaryLanguage?.name);
2024
+ pushLine(lines, "Stars", data.stargazerCount);
2025
+ pushLine(lines, "Forks", data.forkCount);
2026
+ pushLine(lines, "Archived", data.isArchived);
2027
+ pushLine(lines, "Fork", data.isFork);
2028
+ pushLine(lines, "Updated", data.updatedAt);
2029
+ pushLine(lines, "Homepage", data.homepageUrl ?? undefined);
2030
+ const topics = data.repositoryTopics
2031
+ ?.map(topic => topic.name ?? topic.topic?.name)
2032
+ .filter((value): value is string => Boolean(value))
2033
+ .join(", ");
2034
+ pushLine(lines, "Topics", topics || undefined);
2035
+ return lines.join("\n").trim();
2036
+ }
2037
+
2038
+ function formatIssueView(data: GhIssueViewData, input: { issue: string; repo?: string; comments?: boolean }): string {
2039
+ const lines: string[] = [];
2040
+ const issueNumber = data.number ?? input.issue;
2041
+ lines.push(`# Issue #${issueNumber}: ${data.title ?? "Untitled"}`);
2042
+ lines.push("");
2043
+ pushLine(lines, "State", data.state);
2044
+ pushLine(lines, "State reason", data.stateReason ?? undefined);
2045
+ pushLine(lines, "Author", formatAuthor(data.author));
2046
+ pushLine(lines, "Created", data.createdAt);
2047
+ pushLine(lines, "Updated", data.updatedAt);
2048
+ pushLine(lines, "Labels", formatLabels(data.labels));
2049
+ pushLine(lines, "URL", data.url);
2050
+ lines.push("");
2051
+ lines.push("## Body");
2052
+ lines.push("");
2053
+ lines.push(normalizeText(data.body) || "No description provided.");
2054
+
2055
+ if ((input.comments ?? true) && data.comments) {
2056
+ const commentSection = formatCommentsSection(data.comments);
2057
+ if (commentSection.length > 0) {
2058
+ lines.push("");
2059
+ lines.push(...commentSection);
2060
+ }
2061
+ }
2062
+
2063
+ return lines.join("\n").trim();
2064
+ }
2065
+
2066
+ function formatPrFiles(files: GhPrFile[] | undefined): string[] {
2067
+ if (!files || files.length === 0) return [];
2068
+
2069
+ const lines: string[] = [`## Files (${files.length})`, ""];
2070
+ for (const file of files.slice(0, FILE_PREVIEW_LIMIT)) {
2071
+ const changeType = file.changeType ?? "CHANGED";
2072
+ const additions = file.additions ?? 0;
2073
+ const deletions = file.deletions ?? 0;
2074
+ lines.push(`- ${file.path ?? "(unknown file)"} [${changeType}] (+${additions} -${deletions})`);
2075
+ }
2076
+
2077
+ if (files.length > FILE_PREVIEW_LIMIT) {
2078
+ lines.push(`- ... ${files.length - FILE_PREVIEW_LIMIT} more files`);
2079
+ }
2080
+
2081
+ return lines;
2082
+ }
2083
+
2084
+ function formatPrView(data: GhPrViewData, input: { pr?: string; repo?: string; comments?: boolean }): string {
2085
+ const lines: string[] = [];
2086
+ const prIdentifier = data.number ?? input.pr ?? "current";
2087
+ lines.push(`# Pull Request #${prIdentifier}: ${data.title ?? "Untitled"}`);
2088
+ lines.push("");
2089
+ pushLine(lines, "State", data.state);
2090
+ pushLine(lines, "Draft", data.isDraft);
2091
+ pushLine(lines, "Author", formatAuthor(data.author));
2092
+ pushLine(lines, "Base", data.baseRefName);
2093
+ pushLine(lines, "Head", data.headRefName);
2094
+ pushLine(lines, "Review decision", data.reviewDecision ?? undefined);
2095
+ pushLine(lines, "Merge state", data.mergeStateStatus);
2096
+ pushLine(lines, "Created", data.createdAt);
2097
+ pushLine(lines, "Updated", data.updatedAt);
2098
+ pushLine(lines, "Labels", formatLabels(data.labels));
2099
+ pushLine(lines, "URL", data.url);
2100
+ lines.push("");
2101
+ lines.push("## Body");
2102
+ lines.push("");
2103
+ lines.push(normalizeText(data.body) || "No description provided.");
2104
+
2105
+ const fileSection = formatPrFiles(data.files);
2106
+ if (fileSection.length > 0) {
2107
+ lines.push("");
2108
+ lines.push(...fileSection);
2109
+ }
2110
+
2111
+ if ((input.comments ?? true) && data.reviews) {
2112
+ const reviewSection = formatReviewsSection(data.reviews);
2113
+ if (reviewSection.length > 0) {
2114
+ lines.push("");
2115
+ lines.push(...reviewSection);
2116
+ }
2117
+ }
2118
+
2119
+ if ((input.comments ?? true) && data.reviewComments) {
2120
+ const reviewCommentsSection = formatReviewCommentsSection(data.reviewComments);
2121
+ if (reviewCommentsSection.length > 0) {
2122
+ lines.push("");
2123
+ lines.push(...reviewCommentsSection);
2124
+ }
2125
+ }
2126
+
2127
+ if ((input.comments ?? true) && data.comments) {
2128
+ const commentSection = formatCommentsSection(data.comments);
2129
+ if (commentSection.length > 0) {
2130
+ lines.push("");
2131
+ lines.push(...commentSection);
2132
+ }
2133
+ }
2134
+
2135
+ return lines.join("\n").trim();
2136
+ }
2137
+
2138
+ function formatPrCheckoutResult(options: {
2139
+ data: GhPrViewData;
2140
+ localBranch: string;
2141
+ worktreePath: string;
2142
+ remoteName: string;
2143
+ remoteUrl: string;
2144
+ reused: boolean;
2145
+ }): string {
2146
+ const { data, localBranch, worktreePath, remoteName, remoteUrl, reused } = options;
2147
+ const lines: string[] = [
2148
+ reused ? `# Pull Request #${data.number ?? "?"} Worktree` : `# Checked Out Pull Request #${data.number ?? "?"}`,
2149
+ "",
2150
+ ];
2151
+ pushLine(lines, "Title", data.title ?? undefined);
2152
+ pushLine(lines, "URL", data.url);
2153
+ pushLine(lines, "Base", data.baseRefName);
2154
+ pushLine(lines, "Head", data.headRefName);
2155
+ pushLine(lines, "Local branch", localBranch);
2156
+ pushLine(lines, "Worktree", worktreePath);
2157
+ pushLine(lines, "Remote", remoteName);
2158
+ pushLine(lines, "Remote URL", remoteUrl);
2159
+ pushLine(lines, "Cross repository", data.isCrossRepository);
2160
+ pushLine(lines, "Maintainer can modify", data.maintainerCanModify);
2161
+ lines.push("");
2162
+ lines.push(
2163
+ reused
2164
+ ? "Reused the existing PR worktree."
2165
+ : "Created a dedicated worktree for this PR and configured the local branch to push back to the PR head branch.",
2166
+ );
2167
+ return lines.join("\n").trim();
2168
+ }
2169
+
2170
+ function formatPrPushResult(options: {
2171
+ localBranch: string;
2172
+ remoteName: string;
2173
+ remoteBranch: string;
2174
+ remoteUrl?: string;
2175
+ prUrl?: string;
2176
+ forceWithLease: boolean;
2177
+ }): string {
2178
+ const lines: string[] = ["# Pushed Pull Request Branch", ""];
2179
+ pushLine(lines, "Local branch", options.localBranch);
2180
+ pushLine(lines, "Remote", options.remoteName);
2181
+ pushLine(lines, "Remote branch", options.remoteBranch);
2182
+ pushLine(lines, "Remote URL", options.remoteUrl);
2183
+ pushLine(lines, "PR", options.prUrl);
2184
+ pushLine(lines, "Force with lease", options.forceWithLease);
2185
+ lines.push("");
2186
+ lines.push(`Pushed ${options.localBranch} to ${options.remoteName}:${options.remoteBranch}.`);
2187
+ return lines.join("\n").trim();
2188
+ }
2189
+
2190
+ function formatSearchResults(
2191
+ kind: "issues" | "pull requests",
2192
+ query: string,
2193
+ repo: string | undefined,
2194
+ items: GhSearchResult[],
2195
+ ): string {
2196
+ const lines: string[] = [`# GitHub ${kind} search`, "", `Query: ${query}`];
2197
+ pushLine(lines, "Repository", repo);
2198
+ pushLine(lines, "Results", items.length);
2199
+
2200
+ if (items.length === 0) {
2201
+ lines.push("");
2202
+ lines.push(`No ${kind} found.`);
2203
+ return lines.join("\n").trim();
2204
+ }
2205
+
2206
+ for (const item of items) {
2207
+ lines.push("");
2208
+ lines.push(`- #${item.number ?? "?"} ${item.title ?? "Untitled"}`);
2209
+ pushLine(lines, " Repo", item.repository?.nameWithOwner);
2210
+ pushLine(lines, " State", item.state);
2211
+ pushLine(lines, " Author", formatAuthor(item.author));
2212
+ pushLine(lines, " Labels", formatLabels(item.labels));
2213
+ pushLine(lines, " Created", item.createdAt);
2214
+ pushLine(lines, " Updated", item.updatedAt);
2215
+ pushLine(lines, " URL", item.url);
2216
+ }
2217
+
2218
+ return lines.join("\n").trim();
2219
+ }
2220
+
2221
+ function formatSearchCodeResults(query: string, repo: string | undefined, items: GhSearchCodeResult[]): string {
2222
+ const lines: string[] = [`# GitHub code search`, "", `Query: ${query}`];
2223
+ pushLine(lines, "Repository", repo);
2224
+ pushLine(lines, "Results", items.length);
2225
+
2226
+ if (items.length === 0) {
2227
+ lines.push("");
2228
+ lines.push("No code matches found.");
2229
+ return lines.join("\n").trim();
2230
+ }
2231
+
2232
+ for (const item of items) {
2233
+ lines.push("");
2234
+ lines.push(`- ${item.path ?? "(unknown path)"}`);
2235
+ pushLine(lines, " Repo", item.repository?.nameWithOwner);
2236
+ pushLine(lines, " Commit", formatShortSha(item.sha));
2237
+ pushLine(lines, " URL", item.url);
2238
+ const fragment = item.textMatches?.find(match => match.fragment)?.fragment;
2239
+ if (fragment) {
2240
+ pushLine(lines, " Match", normalizeText(fragment).split("\n", 1)[0]);
2241
+ }
2242
+ }
2243
+
2244
+ return lines.join("\n").trim();
2245
+ }
2246
+
2247
+ function formatSearchCommitMessage(message: string | undefined): string | undefined {
2248
+ if (!message) return undefined;
2249
+ const firstLine = normalizeText(message).split("\n", 1)[0];
2250
+ return firstLine || undefined;
2251
+ }
2252
+
2253
+ function formatSearchCommitsResults(query: string, repo: string | undefined, items: GhSearchCommitResult[]): string {
2254
+ const lines: string[] = [`# GitHub commits search`, "", `Query: ${query}`];
2255
+ pushLine(lines, "Repository", repo);
2256
+ pushLine(lines, "Results", items.length);
2257
+
2258
+ if (items.length === 0) {
2259
+ lines.push("");
2260
+ lines.push("No commits found.");
2261
+ return lines.join("\n").trim();
2262
+ }
2263
+
2264
+ for (const item of items) {
2265
+ lines.push("");
2266
+ const sha = formatShortSha(item.sha) ?? "(unknown sha)";
2267
+ const subject = formatSearchCommitMessage(item.commit?.message) ?? "(no commit message)";
2268
+ lines.push(`- ${sha} ${subject}`);
2269
+ pushLine(lines, " Repo", item.repository?.nameWithOwner);
2270
+ pushLine(lines, " Author", formatAuthor(item.author) ?? item.commit?.author?.name);
2271
+ pushLine(lines, " Date", item.commit?.author?.date ?? item.commit?.committer?.date);
2272
+ pushLine(lines, " URL", item.url);
2273
+ }
2274
+
2275
+ return lines.join("\n").trim();
2276
+ }
2277
+
2278
+ function formatSearchReposResults(query: string, items: GhSearchRepoResult[]): string {
2279
+ const lines: string[] = [`# GitHub repositories search`, "", `Query: ${query}`];
2280
+ pushLine(lines, "Results", items.length);
2281
+
2282
+ if (items.length === 0) {
2283
+ lines.push("");
2284
+ lines.push("No repositories found.");
2285
+ return lines.join("\n").trim();
2286
+ }
2287
+
2288
+ for (const item of items) {
2289
+ lines.push("");
2290
+ lines.push(`- ${item.fullName ?? "(unknown repository)"}`);
2291
+ const description = normalizeText(item.description).split("\n", 1)[0];
2292
+ if (description) {
2293
+ pushLine(lines, " Description", description);
2294
+ }
2295
+ pushLine(lines, " Language", item.language ?? undefined);
2296
+ pushLine(lines, " Stars", item.stargazersCount);
2297
+ pushLine(lines, " Forks", item.forksCount);
2298
+ pushLine(lines, " Open issues", item.openIssuesCount);
2299
+ pushLine(lines, " Visibility", item.visibility ?? undefined);
2300
+ pushLine(lines, " Archived", item.isArchived);
2301
+ pushLine(lines, " Fork", item.isFork);
2302
+ pushLine(lines, " Updated", item.updatedAt);
2303
+ pushLine(lines, " URL", item.url);
2304
+ }
2305
+
2306
+ return lines.join("\n").trim();
2307
+ }
2308
+
2309
+ async function saveArtifactText(session: ToolSession, toolType: string, text: string): Promise<string | undefined> {
2310
+ const { path: artifactPath, id: artifactId } = (await session.allocateOutputArtifact?.(toolType)) ?? {};
2311
+ if (!artifactPath || !artifactId) {
2312
+ return undefined;
2313
+ }
2314
+
2315
+ await Bun.write(artifactPath, text);
2316
+ return artifactId;
2317
+ }
2318
+
2319
+ function appendArtifactReference(text: string, artifactId: string | undefined, label: string): string {
2320
+ if (!artifactId) {
2321
+ return text;
2322
+ }
2323
+
2324
+ return `${text}\n\n${label}: artifact://${artifactId}`;
2325
+ }
2326
+
2327
+ function buildTextResult(
2328
+ text: string,
2329
+ sourceUrl?: string,
2330
+ details?: GhToolDetails,
2331
+ options?: { artifactId?: string; artifactLabel?: string },
2332
+ ): AgentToolResult<GhToolDetails> {
2333
+ const builder = toolResult<GhToolDetails>(details).text(
2334
+ appendArtifactReference(text, options?.artifactId, options?.artifactLabel ?? "Saved artifact"),
2335
+ );
2336
+ if (sourceUrl) {
2337
+ builder.sourceUrl(sourceUrl);
2338
+ }
2339
+ return builder.done();
2340
+ }
2341
+
2342
+ export class GithubTool implements AgentTool<typeof githubSchema, GhToolDetails> {
2343
+ readonly name = "github";
2344
+ readonly summary = "Interact with GitHub issues, pull requests, and repositories";
2345
+ readonly loadMode = "discoverable";
2346
+ readonly label = "GitHub";
2347
+ readonly description = prompt.render(githubDescription);
2348
+ readonly parameters = githubSchema;
2349
+ readonly strict = true;
2350
+
2351
+ constructor(private readonly session: ToolSession) {}
2352
+
2353
+ static createIf(session: ToolSession): GithubTool | null {
2354
+ if (!git.github.available()) return null;
2355
+ return new GithubTool(session);
2356
+ }
2357
+
2358
+ async execute(
2359
+ _toolCallId: string,
2360
+ params: GithubInput,
2361
+ signal?: AbortSignal,
2362
+ onUpdate?: AgentToolUpdateCallback<GhToolDetails>,
2363
+ _context?: AgentToolContext,
2364
+ ): Promise<AgentToolResult<GhToolDetails>> {
2365
+ return untilAborted(signal, async () => {
2366
+ switch (params.op) {
2367
+ case "repo_view":
2368
+ return executeRepoView(this.session, params, signal);
2369
+ case "pr_create":
2370
+ return executePrCreate(this.session, params, signal);
2371
+ case "pr_checkout":
2372
+ return executePrCheckout(this.session, params, signal);
2373
+ case "pr_push":
2374
+ return executePrPush(this.session, params, signal);
2375
+ case "search_issues":
2376
+ return executeSearchIssues(this.session, params, signal);
2377
+ case "search_prs":
2378
+ return executeSearchPrs(this.session, params, signal);
2379
+ case "search_code":
2380
+ return executeSearchCode(this.session, params, signal);
2381
+ case "search_commits":
2382
+ return executeSearchCommits(this.session, params, signal);
2383
+ case "search_repos":
2384
+ return executeSearchRepos(this.session, params, signal);
2385
+ case "run_watch":
2386
+ return executeRunWatch(this.session, this.name, params, signal, onUpdate);
2387
+ }
2388
+ });
2389
+ }
2390
+ }
2391
+
2392
+ async function executeRepoView(
2393
+ session: ToolSession,
2394
+ params: GithubInput,
2395
+ signal: AbortSignal | undefined,
2396
+ ): Promise<AgentToolResult<GhToolDetails>> {
2397
+ const repo = normalizeOptionalString(params.repo);
2398
+ const branch = normalizeOptionalString(params.branch);
2399
+ const args = ["repo", "view"];
2400
+ if (repo) {
2401
+ args.push(repo);
2402
+ }
2403
+ if (branch) {
2404
+ args.push("--branch", branch);
2405
+ }
2406
+ args.push("--json", GH_REPO_FIELDS.join(","));
2407
+
2408
+ const data = await git.github.json<GhRepoViewData>(session.cwd, args, signal, {
2409
+ repoProvided: Boolean(repo),
2410
+ });
2411
+ return buildTextResult(formatRepoView(data, { repo, branch }), data.url);
2412
+ }
2413
+
2414
+ // ────────────────────────────────────────────────────────────────────────────
2415
+ // Cached issue/PR view fetchers
2416
+ //
2417
+ // Used by `executeIssueView`/`executePrView` and by the `issue://` / `pr://`
2418
+ // internal-URL protocol handlers. The cache wrapper lives in `./github-cache`;
2419
+ // the fresh fetchers stay here to share the existing formatter helpers.
2420
+ // ────────────────────────────────────────────────────────────────────────────
2421
+
2422
+ export interface IssueViewLookupOptions {
2423
+ cwd: string;
2424
+ repo?: string;
2425
+ /** Issue number or GitHub issue URL. */
2426
+ issue: string;
2427
+ includeComments?: boolean;
2428
+ signal?: AbortSignal;
2429
+ settings?: Settings;
2430
+ cacheAuthKey?: string | null;
2431
+ }
2432
+
2433
+ export interface PrViewLookupOptions {
2434
+ cwd: string;
2435
+ repo: string;
2436
+ number: number;
2437
+ includeComments?: boolean;
2438
+ signal?: AbortSignal;
2439
+ settings?: Settings;
2440
+ cacheAuthKey?: string | null;
2441
+ }
2442
+
2443
+ export interface ViewLookupResult<T> {
2444
+ rendered: string;
2445
+ sourceUrl: string | undefined;
2446
+ payload: T;
2447
+ status: CacheStatus;
2448
+ fetchedAt: number;
2449
+ }
2450
+
2451
+ async function fetchIssueViewFresh(
2452
+ cwd: string,
2453
+ repo: string | undefined,
2454
+ identifier: string,
2455
+ includeComments: boolean,
2456
+ signal: AbortSignal | undefined,
2457
+ ): Promise<{ rendered: string; sourceUrl: string | undefined; payload: GhIssueViewData }> {
2458
+ const args = ["issue", "view", identifier];
2459
+ appendRepoFlag(args, repo, identifier);
2460
+ args.push("--json", (includeComments ? GH_ISSUE_FIELDS : GH_ISSUE_FIELDS_NO_COMMENTS).join(","));
2461
+ const data = await git.github.json<GhIssueViewData>(cwd, args, signal, {
2462
+ repoProvided: Boolean(repo),
2463
+ });
2464
+ const rendered = formatIssueView(data, { issue: identifier, repo, comments: includeComments });
2465
+ return { rendered, sourceUrl: data.url, payload: data };
2466
+ }
2467
+
2468
+ async function fetchPrViewFresh(
2469
+ cwd: string,
2470
+ repo: string,
2471
+ number: number,
2472
+ includeComments: boolean,
2473
+ signal: AbortSignal | undefined,
2474
+ ): Promise<{ rendered: string; sourceUrl: string | undefined; payload: GhPrViewData }> {
2475
+ const args = ["pr", "view", String(number)];
2476
+ appendRepoFlag(args, repo, String(number));
2477
+ args.push("--json", (includeComments ? GH_PR_FIELDS : GH_PR_FIELDS_NO_COMMENTS).join(","));
2478
+ const data = await git.github.json<GhPrViewData>(cwd, args, signal, { repoProvided: true });
2479
+ if (includeComments && typeof data.number === "number") {
2480
+ data.reviewComments = await fetchPrReviewComments(cwd, repo, data.number, signal);
2481
+ }
2482
+ const rendered = formatPrView(data, { pr: String(number), repo, comments: includeComments });
2483
+ return { rendered, sourceUrl: data.url, payload: data };
2484
+ }
2485
+
2486
+ /**
2487
+ * Cache-aware issue/view fetcher. Used by both the `github` tool op and the
2488
+ * `issue://` protocol handler so a single shared row services both surfaces.
2489
+ */
2490
+ export async function getOrFetchIssue(options: IssueViewLookupOptions): Promise<ViewLookupResult<GhIssueViewData>> {
2491
+ const identifier = requireNonEmpty(options.issue, "issue");
2492
+ const includeComments = options.includeComments ?? true;
2493
+ const authKey = options.cacheAuthKey === undefined ? (resolveGithubCacheAuthKey() ?? null) : options.cacheAuthKey;
2494
+ const urlParse = parseIssueUrl(identifier);
2495
+ // Prefer the URL's repo when the identifier is a full URL; fall back to the
2496
+ // explicit `repo` option, then to the cwd's default repo.
2497
+ let repo = urlParse.repo ?? normalizeOptionalString(options.repo);
2498
+ let cacheNumber = urlParse.issueNumber;
2499
+ if (cacheNumber === undefined) {
2500
+ cacheNumber = parsePositiveDecimalInt(identifier);
2501
+ }
2502
+ if (cacheNumber !== undefined && !repo) {
2503
+ try {
2504
+ repo = await resolveDefaultRepoMemoized(options.cwd, options.signal);
2505
+ } catch {
2506
+ // Resolution failure leaves `repo` undefined: we'll fall through to a
2507
+ // direct fetch below so gh produces its own error message instead of
2508
+ // us masking it with a friendlier one.
2509
+ repo = undefined;
2510
+ }
2511
+ }
2512
+
2513
+ const doFetch = () => fetchIssueViewFresh(options.cwd, repo, identifier, includeComments, options.signal);
2514
+
2515
+ if (!repo || cacheNumber === undefined) {
2516
+ const fresh = await doFetch();
2517
+ return { ...fresh, status: "miss", fetchedAt: Date.now() };
2518
+ }
2519
+
2520
+ const lookup = await getOrFetchView<GhIssueViewData>({
2521
+ repo,
2522
+ kind: "issue",
2523
+ number: cacheNumber,
2524
+ includeComments,
2525
+ settings: options.settings,
2526
+ authKey,
2527
+ fetchFresh: doFetch,
2528
+ });
2529
+ return {
2530
+ rendered: lookup.rendered,
2531
+ sourceUrl: lookup.sourceUrl,
2532
+ payload: lookup.payload,
2533
+ status: lookup.status,
2534
+ fetchedAt: lookup.fetchedAt,
2535
+ };
2536
+ }
2537
+
2538
+ /**
2539
+ * Cache-aware PR view fetcher. Caller must supply a numeric PR number;
2540
+ * branch-name / current-branch lookups bypass the cache entirely upstream
2541
+ * (see `executePrView`).
2542
+ */
2543
+ export async function getOrFetchPr(options: PrViewLookupOptions): Promise<ViewLookupResult<GhPrViewData>> {
2544
+ const includeComments = options.includeComments ?? true;
2545
+ const authKey = options.cacheAuthKey === undefined ? (resolveGithubCacheAuthKey() ?? null) : options.cacheAuthKey;
2546
+ const doFetch = () => fetchPrViewFresh(options.cwd, options.repo, options.number, includeComments, options.signal);
2547
+ const lookup = await getOrFetchView<GhPrViewData>({
2548
+ repo: options.repo,
2549
+ kind: "pr",
2550
+ number: options.number,
2551
+ includeComments,
2552
+ settings: options.settings,
2553
+ authKey,
2554
+ fetchFresh: doFetch,
2555
+ });
2556
+ return {
2557
+ rendered: lookup.rendered,
2558
+ sourceUrl: lookup.sourceUrl,
2559
+ payload: lookup.payload,
2560
+ status: lookup.status,
2561
+ fetchedAt: lookup.fetchedAt,
2562
+ };
2563
+ }
2564
+
2565
+ // ────────────────────────────────────────────────────────────────────────────
2566
+ // PR diff fetcher
2567
+ //
2568
+ // Used by the `pr://<n>/diff[/…]` internal-URL family. Stores the verbatim
2569
+ // `gh pr diff` text plus a parsed file index so the listing, full-diff, and
2570
+ // per-file slice variants all share one cache row.
2571
+ // ────────────────────────────────────────────────────────────────────────────
2572
+
2573
+ export interface PrDiffFile {
2574
+ /** Display path. Prefers the post-image (`b/<path>`) when present. */
2575
+ path: string;
2576
+ additions: number;
2577
+ deletions: number;
2578
+ changeType: "modified" | "added" | "deleted" | "renamed" | "binary";
2579
+ /** Pre-image path for renames/deletes; same as `path` otherwise. */
2580
+ oldPath?: string;
2581
+ /** Byte offset of the section's `diff --git` line in the unified diff. */
2582
+ startOffset: number;
2583
+ /** Byte offset of the next section (or end-of-text). */
2584
+ endOffset: number;
2585
+ }
2586
+
2587
+ export interface PrDiffPayload {
2588
+ /** Full unified diff text as returned by `gh pr diff --color never`. */
2589
+ unified: string;
2590
+ files: PrDiffFile[];
2591
+ }
2592
+
2593
+ export interface PrDiffLookupOptions {
2594
+ cwd: string;
2595
+ repo: string;
2596
+ number: number;
2597
+ signal?: AbortSignal;
2598
+ settings?: Settings;
2599
+ cacheAuthKey?: string | null;
2600
+ }
2601
+ /**
2602
+ * Split `gh pr diff` output on `^diff --git ` boundaries and parse per-file
2603
+ * metadata. The unified diff is preserved verbatim so callers can slice it by
2604
+ * byte offsets without re-running gh.
2605
+ */
2606
+ export function parsePrUnifiedDiff(text: string): PrDiffPayload {
2607
+ const files: PrDiffFile[] = [];
2608
+ if (text.length === 0) {
2609
+ return { unified: text, files };
2610
+ }
2611
+
2612
+ // Walk match positions manually so we capture each section's byte range.
2613
+ const sectionStarts: number[] = [];
2614
+ const re = /^diff --git /gm;
2615
+ let m: RegExpExecArray | null = re.exec(text);
2616
+ while (m !== null) {
2617
+ sectionStarts.push(m.index);
2618
+ // Avoid zero-length match infinite loop (regex has fixed prefix, but
2619
+ // be explicit).
2620
+ if (re.lastIndex === m.index) re.lastIndex += 1;
2621
+ m = re.exec(text);
2622
+ }
2623
+
2624
+ for (let i = 0; i < sectionStarts.length; i += 1) {
2625
+ const startOffset = sectionStarts[i] ?? 0;
2626
+ const endOffset = sectionStarts[i + 1] ?? text.length;
2627
+ const section = text.slice(startOffset, endOffset);
2628
+ files.push(parsePrDiffSection(section, startOffset, endOffset));
2629
+ }
2630
+ return { unified: text, files };
2631
+ }
2632
+
2633
+ interface ParsedDiffHeaderToken {
2634
+ value: string;
2635
+ nextIndex: number;
2636
+ }
2637
+
2638
+ function skipDiffHeaderSpaces(text: string, index: number): number {
2639
+ let i = index;
2640
+ while (text.charAt(i) === " ") i += 1;
2641
+ return i;
2642
+ }
2643
+
2644
+ function parseDiffQuotedEscape(text: string, slashIndex: number): ParsedDiffHeaderToken {
2645
+ const next = text.charAt(slashIndex + 1);
2646
+ if (next === "") return { value: "\\", nextIndex: slashIndex + 1 };
2647
+
2648
+ if (next >= "0" && next <= "7") {
2649
+ let end = slashIndex + 1;
2650
+ while (end < text.length && end < slashIndex + 4) {
2651
+ const digit = text.charAt(end);
2652
+ if (digit < "0" || digit > "7") break;
2653
+ end += 1;
2654
+ }
2655
+ return {
2656
+ value: String.fromCharCode(Number.parseInt(text.slice(slashIndex + 1, end), 8)),
2657
+ nextIndex: end,
2658
+ };
2659
+ }
2660
+
2661
+ switch (next) {
2662
+ case "a":
2663
+ return { value: "\x07", nextIndex: slashIndex + 2 };
2664
+ case "b":
2665
+ return { value: "\b", nextIndex: slashIndex + 2 };
2666
+ case "f":
2667
+ return { value: "\f", nextIndex: slashIndex + 2 };
2668
+ case "n":
2669
+ return { value: "\n", nextIndex: slashIndex + 2 };
2670
+ case "r":
2671
+ return { value: "\r", nextIndex: slashIndex + 2 };
2672
+ case "t":
2673
+ return { value: "\t", nextIndex: slashIndex + 2 };
2674
+ case "v":
2675
+ return { value: "\v", nextIndex: slashIndex + 2 };
2676
+ case "\\":
2677
+ case '"':
2678
+ return { value: next, nextIndex: slashIndex + 2 };
2679
+ default:
2680
+ return { value: next, nextIndex: slashIndex + 2 };
2681
+ }
2682
+ }
2683
+
2684
+ function parseDiffQuotedToken(text: string, startIndex: number): ParsedDiffHeaderToken | undefined {
2685
+ if (text.charAt(startIndex) !== '"') return undefined;
2686
+ let value = "";
2687
+ for (let i = startIndex + 1; i < text.length; i += 1) {
2688
+ const ch = text.charAt(i);
2689
+ if (ch === '"') return { value, nextIndex: i + 1 };
2690
+ if (ch !== "\\") {
2691
+ value += ch;
2692
+ continue;
2693
+ }
2694
+ const escaped = parseDiffQuotedEscape(text, i);
2695
+ value += escaped.value;
2696
+ i = escaped.nextIndex - 1;
2697
+ }
2698
+ return undefined;
2699
+ }
2700
+
2701
+ function parseDiffHeaderToken(text: string, startIndex: number): ParsedDiffHeaderToken | undefined {
2702
+ const start = skipDiffHeaderSpaces(text, startIndex);
2703
+ if (start >= text.length) return undefined;
2704
+ const quoted = parseDiffQuotedToken(text, start);
2705
+ if (quoted) return quoted;
2706
+ const end = text.indexOf(" ", start);
2707
+ if (end === -1) return { value: text.slice(start), nextIndex: text.length };
2708
+ return { value: text.slice(start, end), nextIndex: end };
2709
+ }
2710
+
2711
+ function stripPrDiffPathPrefix(value: string, prefix: "a/" | "b/"): string | undefined {
2712
+ return value.startsWith(prefix) ? value.slice(prefix.length) : undefined;
2713
+ }
2714
+
2715
+ function parsePrDiffHeaderPaths(header: string): { oldPath?: string; newPath?: string } {
2716
+ const trail = header.slice("diff --git ".length);
2717
+ if (trail.startsWith('"')) {
2718
+ const oldToken = parseDiffQuotedToken(trail, 0);
2719
+ if (!oldToken) return {};
2720
+ const newToken = parseDiffHeaderToken(trail, oldToken.nextIndex);
2721
+ if (!newToken) return {};
2722
+ return {
2723
+ oldPath: stripPrDiffPathPrefix(oldToken.value, "a/"),
2724
+ newPath: stripPrDiffPathPrefix(newToken.value, "b/"),
2725
+ };
2726
+ }
2727
+
2728
+ const bIdx = trail.indexOf(" b/");
2729
+ if (trail.startsWith("a/") && bIdx > 0) {
2730
+ return {
2731
+ oldPath: trail.slice(2, bIdx),
2732
+ newPath: trail.slice(bIdx + 3),
2733
+ };
2734
+ }
2735
+ return {};
2736
+ }
2737
+
2738
+ function isPrDiffFileHeaderLine(line: string): boolean {
2739
+ return (
2740
+ line === "--- /dev/null" ||
2741
+ line === "+++ /dev/null" ||
2742
+ line.startsWith("--- a/") ||
2743
+ line.startsWith("+++ b/") ||
2744
+ line.startsWith('--- "a/') ||
2745
+ line.startsWith('+++ "b/')
2746
+ );
2747
+ }
2748
+
2749
+ function parsePrDiffSection(section: string, startOffset: number, endOffset: number): PrDiffFile {
2750
+ const lines = section.split("\n");
2751
+ const header = lines[0] ?? "";
2752
+ const headerPaths = parsePrDiffHeaderPaths(header);
2753
+ let oldPath = headerPaths.oldPath;
2754
+ let newPath = headerPaths.newPath;
2755
+
2756
+ let changeType: PrDiffFile["changeType"] = "modified";
2757
+ let isBinary = false;
2758
+ let additions = 0;
2759
+ let deletions = 0;
2760
+
2761
+ let inHunk = false;
2762
+ for (let li = 1; li < lines.length; li += 1) {
2763
+ const line = lines[li] ?? "";
2764
+ if (line.startsWith("new file mode")) {
2765
+ changeType = "added";
2766
+ continue;
2767
+ }
2768
+ if (line.startsWith("deleted file mode")) {
2769
+ changeType = "deleted";
2770
+ continue;
2771
+ }
2772
+ if (line.startsWith("rename from ")) {
2773
+ changeType = "renamed";
2774
+ oldPath = line.slice("rename from ".length);
2775
+ continue;
2776
+ }
2777
+ if (line.startsWith("rename to ")) {
2778
+ newPath = line.slice("rename to ".length);
2779
+ continue;
2780
+ }
2781
+ if (line.startsWith("Binary files ") && line.endsWith(" differ")) {
2782
+ isBinary = true;
2783
+ continue;
2784
+ }
2785
+ if (line.startsWith("@@ ")) {
2786
+ inHunk = true;
2787
+ continue;
2788
+ }
2789
+ if (!inHunk && isPrDiffFileHeaderLine(line)) continue;
2790
+ if (line.startsWith("+")) {
2791
+ additions += 1;
2792
+ } else if (line.startsWith("-")) {
2793
+ deletions += 1;
2794
+ }
2795
+ }
2796
+
2797
+ if (isBinary) {
2798
+ if (changeType === "modified") changeType = "binary";
2799
+ additions = 0;
2800
+ deletions = 0;
2801
+ }
2802
+
2803
+ const displayPath =
2804
+ changeType === "deleted" ? (oldPath ?? newPath ?? "(unknown)") : (newPath ?? oldPath ?? "(unknown)");
2805
+ const file: PrDiffFile = {
2806
+ path: displayPath,
2807
+ additions,
2808
+ deletions,
2809
+ changeType,
2810
+ startOffset,
2811
+ endOffset,
2812
+ };
2813
+ if (oldPath && oldPath !== displayPath) {
2814
+ file.oldPath = oldPath;
2815
+ }
2816
+ return file;
2817
+ }
2818
+
2819
+ async function fetchPrDiffFresh(
2820
+ cwd: string,
2821
+ repo: string,
2822
+ number: number,
2823
+ signal: AbortSignal | undefined,
2824
+ ): Promise<{ rendered: string; sourceUrl: string | undefined; payload: PrDiffPayload }> {
2825
+ const args = ["pr", "diff", String(number), "--color", "never"];
2826
+ appendRepoFlag(args, repo, String(number));
2827
+ const text = await git.github.text(cwd, args, signal, { repoProvided: true, trimOutput: false });
2828
+ const payload = parsePrUnifiedDiff(text);
2829
+ return { rendered: text, sourceUrl: undefined, payload };
2830
+ }
2831
+
2832
+ /**
2833
+ * Cache-aware PR diff fetcher. Stores the full unified diff plus a parsed
2834
+ * file index in a single `pr-diff` cache row so the listing, full-diff, and
2835
+ * per-file slice variants of `pr://<n>/diff` share one `gh pr diff`
2836
+ * invocation.
2837
+ */
2838
+ export async function getOrFetchPrDiff(options: PrDiffLookupOptions): Promise<ViewLookupResult<PrDiffPayload>> {
2839
+ const authKey = options.cacheAuthKey === undefined ? (resolveGithubCacheAuthKey() ?? null) : options.cacheAuthKey;
2840
+ const doFetch = () => fetchPrDiffFresh(options.cwd, options.repo, options.number, options.signal);
2841
+ const lookup = await getOrFetchView<PrDiffPayload>({
2842
+ repo: options.repo,
2843
+ kind: "pr-diff",
2844
+ number: options.number,
2845
+ includeComments: false,
2846
+ settings: options.settings,
2847
+ authKey,
2848
+ fetchFresh: doFetch,
2849
+ });
2850
+ return {
2851
+ rendered: lookup.rendered,
2852
+ sourceUrl: lookup.sourceUrl,
2853
+ payload: lookup.payload,
2854
+ status: lookup.status,
2855
+ fetchedAt: lookup.fetchedAt,
2856
+ };
2857
+ }
2858
+
2859
+ function joinSections(sections: string[]): string[] {
2860
+ return sections.flatMap((section, idx) => (idx === 0 ? [section] : ["", "---", "", section]));
2861
+ }
2862
+
2863
+ async function executePrCheckout(
2864
+ session: ToolSession,
2865
+ params: GithubInput,
2866
+ signal: AbortSignal | undefined,
2867
+ ): Promise<AgentToolResult<GhToolDetails>> {
2868
+ const repo = normalizeOptionalString(params.repo);
2869
+ const force = params.force ?? false;
2870
+ const prList = normalizePrIdentifierList(params.pr);
2871
+ const prRefs = prList.length > 0 ? prList : [undefined];
2872
+ const isMulti = prRefs.length > 1;
2873
+
2874
+ const outcomes = await Promise.all(
2875
+ prRefs.map(prRef => checkoutPullRequest(session, signal, { prRef, repo, force })),
2876
+ );
2877
+
2878
+ if (!isMulti) {
2879
+ const [outcome] = outcomes;
2880
+ return buildTextResult(formatPrCheckoutResult(outcome), outcome.data.url, {
2881
+ repo: repo ?? outcome.data.headRepository?.nameWithOwner,
2882
+ branch: outcome.localBranch,
2883
+ worktreePath: outcome.worktreePath,
2884
+ remote: outcome.remoteName,
2885
+ remoteBranch: outcome.headRefName,
2886
+ checkouts: [outcomeToSummary(outcome)],
2887
+ });
2888
+ }
2889
+
2890
+ const sections = outcomes.map(formatPrCheckoutResult);
2891
+ const reusedCount = outcomes.reduce((acc, o) => acc + (o.reused ? 1 : 0), 0);
2892
+ const newCount = outcomes.length - reusedCount;
2893
+ const headerParts: string[] = [];
2894
+ if (newCount > 0) headerParts.push(`${newCount} checked out`);
2895
+ if (reusedCount > 0) headerParts.push(`${reusedCount} reused`);
2896
+ const header = `# ${outcomes.length} Pull Request Worktrees (${headerParts.join(", ")})`;
2897
+ const text = [header, "", ...joinSections(sections)].join("\n").trim();
2898
+
2899
+ return buildTextResult(text, undefined, {
2900
+ repo,
2901
+ checkouts: outcomes.map(outcomeToSummary),
2902
+ });
2903
+ }
2904
+
2905
+ interface PrCheckoutOptions {
2906
+ prRef: string | undefined;
2907
+ repo: string | undefined;
2908
+ force: boolean;
2909
+ }
2910
+
2911
+ interface PrCheckoutOutcome {
2912
+ data: GhPrViewData;
2913
+ localBranch: string;
2914
+ worktreePath: string;
2915
+ remoteName: string;
2916
+ remoteUrl: string;
2917
+ headRefName: string;
2918
+ reused: boolean;
2919
+ }
2920
+
2921
+ async function checkoutPullRequest(
2922
+ session: ToolSession,
2923
+ signal: AbortSignal | undefined,
2924
+ options: PrCheckoutOptions,
2925
+ ): Promise<PrCheckoutOutcome> {
2926
+ const { prRef, repo, force } = options;
2927
+ const args = ["pr", "view"];
2928
+ if (prRef) args.push(prRef);
2929
+ appendRepoFlag(args, repo, prRef);
2930
+ args.push("--json", GH_PR_CHECKOUT_FIELDS.join(","));
2931
+
2932
+ const data = await git.github.json<GhPrViewData>(session.cwd, args, signal, {
2933
+ repoProvided: Boolean(repo),
2934
+ });
2935
+ const prNumber = data.number;
2936
+ if (typeof prNumber !== "number") {
2937
+ throw new ToolError("GitHub CLI did not return a pull request number.");
2938
+ }
2939
+
2940
+ const headRefName = requireNonEmpty(data.headRefName, "head branch");
2941
+ const headRefOid = requireNonEmpty(data.headRefOid, "head commit");
2942
+ const repoRoot = await requireGitRepoRoot(session.cwd, signal);
2943
+ const primaryRepoRoot = await requirePrimaryGitRepoRoot(repoRoot, signal);
2944
+ const localBranch = `pr-${prNumber}`;
2945
+ const worktreePath = getWorktreeDir(`${prNumber}-${hashPath(primaryRepoRoot)}`);
2946
+
2947
+ // Every git mutation against `repoRoot` from here on must run under the
2948
+ // per-repo lock. Worktrees of the same primary repo share `.git/config`,
2949
+ // `commit-graph` chain, `packed-refs`, and worktree metadata files — git
2950
+ // uses O_EXCL lock files for each, with no waiter. Concurrent in-process
2951
+ // callers (e.g. parallel `pr_checkout` calls) would otherwise lose lock
2952
+ // races and surface "could not lock config file" / "Another git process
2953
+ // seems to be running" errors. The gh API call above stays outside the
2954
+ // lock so multiple checkouts can fetch PR metadata in parallel.
2955
+ return git.withRepoLock(
2956
+ repoRoot,
2957
+ async () => {
2958
+ const existingWorktrees = await git.worktree.list(repoRoot, signal);
2959
+ const existingWorktree = existingWorktrees.find(entry => entry.branch === toLocalBranchRef(localBranch));
2960
+
2961
+ const remote = await ensurePrRemote(repoRoot, data, signal);
2962
+ await git.fetch(
2963
+ repoRoot,
2964
+ remote.name,
2965
+ `refs/heads/${headRefName}`,
2966
+ `refs/remotes/${remote.name}/${headRefName}`,
2967
+ signal,
2968
+ );
2969
+
2970
+ if (!existingWorktree) {
2971
+ const localBranchRef = toLocalBranchRef(localBranch);
2972
+ const localBranchExists = await git.ref.exists(repoRoot, localBranchRef, signal);
2973
+ if (localBranchExists) {
2974
+ const existingOid = await git.ref.resolve(repoRoot, localBranchRef, signal);
2975
+ if (existingOid !== headRefOid) {
2976
+ if (!force) {
2977
+ throw new ToolError(
2978
+ `local branch ${localBranch} already exists at ${formatShortSha(existingOid ?? undefined) ?? existingOid ?? "unknown commit"}; pass force=true to reset it`,
2979
+ );
2980
+ }
2981
+
2982
+ await git.branch.force(repoRoot, localBranch, `refs/remotes/${remote.name}/${headRefName}`, signal);
2983
+ }
2984
+ } else {
2985
+ await git.branch.create(repoRoot, localBranch, `refs/remotes/${remote.name}/${headRefName}`, signal);
2986
+ }
2987
+ }
2988
+
2989
+ await git.config.setBranch(repoRoot, localBranch, "remote", remote.name, signal);
2990
+ await git.config.setBranch(repoRoot, localBranch, "merge", `refs/heads/${headRefName}`, signal);
2991
+ await git.config.setBranch(repoRoot, localBranch, "pushRemote", remote.name, signal);
2992
+ await git.config.setBranch(repoRoot, localBranch, "ompPrHeadRef", headRefName, signal);
2993
+ await git.config.setBranch(repoRoot, localBranch, "ompPrUrl", data.url ?? "", signal);
2994
+ await git.config.setBranch(
2995
+ repoRoot,
2996
+ localBranch,
2997
+ "ompPrIsCrossRepository",
2998
+ String(Boolean(data.isCrossRepository)),
2999
+ signal,
3000
+ );
3001
+ await git.config.setBranch(
3002
+ repoRoot,
3003
+ localBranch,
3004
+ "ompPrMaintainerCanModify",
3005
+ String(Boolean(data.maintainerCanModify)),
3006
+ signal,
3007
+ );
3008
+
3009
+ let finalWorktreePath = existingWorktree?.path ?? worktreePath;
3010
+ if (!existingWorktree) {
3011
+ finalWorktreePath = await resolveAvailableWorktreePath(worktreePath, existingWorktrees);
3012
+ await fs.mkdir(path.dirname(finalWorktreePath), { recursive: true });
3013
+ await git.worktree.add(repoRoot, finalWorktreePath, localBranch, { signal });
3014
+ }
3015
+ const resolvedWorktreePath = await fs.realpath(finalWorktreePath);
3016
+
3017
+ return {
3018
+ data,
3019
+ localBranch,
3020
+ worktreePath: resolvedWorktreePath,
3021
+ remoteName: remote.name,
3022
+ remoteUrl: remote.url,
3023
+ headRefName,
3024
+ reused: Boolean(existingWorktree),
3025
+ };
3026
+ },
3027
+ signal,
3028
+ );
3029
+ }
3030
+
3031
+ function outcomeToSummary(outcome: PrCheckoutOutcome): GhPrCheckoutSummary {
3032
+ return {
3033
+ prNumber: typeof outcome.data.number === "number" ? outcome.data.number : undefined,
3034
+ url: outcome.data.url ?? undefined,
3035
+ branch: outcome.localBranch,
3036
+ worktreePath: outcome.worktreePath,
3037
+ remote: outcome.remoteName,
3038
+ remoteBranch: outcome.headRefName,
3039
+ reused: outcome.reused,
3040
+ };
3041
+ }
3042
+
3043
+ async function executePrPush(
3044
+ session: ToolSession,
3045
+ params: GithubInput,
3046
+ signal: AbortSignal | undefined,
3047
+ ): Promise<AgentToolResult<GhToolDetails>> {
3048
+ const repoRoot = await requireGitRepoRoot(session.cwd, signal);
3049
+ const localBranch = normalizeOptionalString(params.branch) ?? (await requireCurrentGitBranch(repoRoot, signal));
3050
+ const refExists = await git.ref.exists(repoRoot, toLocalBranchRef(localBranch), signal);
3051
+ if (!refExists) {
3052
+ throw new ToolError(`local branch ${localBranch} does not exist`);
3053
+ }
3054
+
3055
+ const target = await resolvePrBranchPushTarget(repoRoot, localBranch, signal);
3056
+ const currentBranch = await git.branch.current(repoRoot, signal);
3057
+ const sourceRef = currentBranch === localBranch ? "HEAD" : toLocalBranchRef(localBranch);
3058
+ const refspec = `${sourceRef}:refs/heads/${target.remoteBranch}`;
3059
+ await git.push(repoRoot, {
3060
+ forceWithLease: params.forceWithLease,
3061
+ refspec,
3062
+ remote: target.remoteName,
3063
+ signal,
3064
+ });
3065
+
3066
+ return buildTextResult(
3067
+ formatPrPushResult({
3068
+ localBranch,
3069
+ remoteName: target.remoteName,
3070
+ remoteBranch: target.remoteBranch,
3071
+ remoteUrl: target.remoteUrl,
3072
+ prUrl: target.prUrl,
3073
+ forceWithLease: params.forceWithLease ?? false,
3074
+ }),
3075
+ target.prUrl,
3076
+ {
3077
+ branch: localBranch,
3078
+ remote: target.remoteName,
3079
+ remoteBranch: target.remoteBranch,
3080
+ },
3081
+ );
3082
+ }
3083
+
3084
+ async function executePrCreate(
3085
+ session: ToolSession,
3086
+ params: GithubInput,
3087
+ signal: AbortSignal | undefined,
3088
+ ): Promise<AgentToolResult<GhToolDetails>> {
3089
+ const repo = normalizeOptionalString(params.repo);
3090
+ const title = normalizeOptionalString(params.title);
3091
+ const body = params.body;
3092
+ const base = normalizeOptionalString(params.base);
3093
+ const head = normalizeOptionalString(params.head);
3094
+ const draft = params.draft ?? false;
3095
+ const fill = params.fill ?? false;
3096
+ const reviewers = normalizePrIdentifierList(params.reviewer);
3097
+ const assignees = normalizePrIdentifierList(params.assignee);
3098
+ const labels = normalizePrIdentifierList(params.label);
3099
+
3100
+ if (!fill && !title) {
3101
+ throw new ToolError("title is required unless fill is true");
3102
+ }
3103
+ if (fill && (title || body !== undefined)) {
3104
+ throw new ToolError("fill is mutually exclusive with title and body");
3105
+ }
3106
+
3107
+ const args = ["pr", "create"];
3108
+ appendRepoFlag(args, repo);
3109
+ if (title) args.push("--title", title);
3110
+ if (base) args.push("--base", base);
3111
+ if (head) args.push("--head", head);
3112
+ if (draft) args.push("--draft");
3113
+ if (fill) args.push("--fill");
3114
+ for (const reviewer of reviewers) args.push("--reviewer", reviewer);
3115
+ for (const assignee of assignees) args.push("--assignee", assignee);
3116
+ for (const label of labels) args.push("--label", label);
3117
+
3118
+ let bodyDir: string | undefined;
3119
+ try {
3120
+ if (!fill) {
3121
+ if (body !== undefined && body.length > 0) {
3122
+ // Route through a temp file so multi-KB bodies stay clear of any
3123
+ // argv-length limits and shell-quoting hazards on uncommon platforms.
3124
+ bodyDir = await fs.mkdtemp(path.join(os.tmpdir(), "gh-pr-body-"));
3125
+ const bodyFile = path.join(bodyDir, "body.md");
3126
+ await Bun.write(bodyFile, body);
3127
+ args.push("--body-file", bodyFile);
3128
+ } else {
3129
+ // Avoid gh dropping into an interactive editor when no body is given.
3130
+ args.push("--body", "");
3131
+ }
3132
+ }
3133
+
3134
+ const output = await git.github.text(session.cwd, args, signal, {
3135
+ repoProvided: Boolean(repo),
3136
+ });
3137
+ const url =
3138
+ output
3139
+ .split("\n")
3140
+ .map(line => line.trim())
3141
+ .find(line => line.startsWith("https://github.com/")) ?? output.trim();
3142
+ const parsed = parsePullRequestUrl(url);
3143
+ const resolvedRepo = repo ?? parsed.repo;
3144
+
3145
+ let prView: GhPrViewData | undefined;
3146
+ if (resolvedRepo && parsed.prNumber !== undefined) {
3147
+ try {
3148
+ prView = await git.github.json<GhPrViewData>(
3149
+ session.cwd,
3150
+ [
3151
+ "pr",
3152
+ "view",
3153
+ String(parsed.prNumber),
3154
+ "--repo",
3155
+ resolvedRepo,
3156
+ "--json",
3157
+ GH_PR_FIELDS_NO_COMMENTS.join(","),
3158
+ ],
3159
+ signal,
3160
+ { repoProvided: true },
3161
+ );
3162
+ } catch {
3163
+ // Best-effort summary; PR creation already succeeded.
3164
+ }
3165
+ }
3166
+
3167
+ const text = formatPrCreateResult({
3168
+ url,
3169
+ prNumber: parsed.prNumber,
3170
+ data: prView,
3171
+ title,
3172
+ base,
3173
+ head,
3174
+ draft,
3175
+ });
3176
+ return buildTextResult(text, url || prView?.url);
3177
+ } finally {
3178
+ if (bodyDir) {
3179
+ await fs.rm(bodyDir, { recursive: true, force: true }).catch(() => {});
3180
+ }
3181
+ }
3182
+ }
3183
+
3184
+ function formatPrCreateResult(options: {
3185
+ url: string;
3186
+ prNumber?: number;
3187
+ data?: GhPrViewData;
3188
+ title?: string;
3189
+ base?: string;
3190
+ head?: string;
3191
+ draft?: boolean;
3192
+ }): string {
3193
+ const number = options.prNumber ?? options.data?.number;
3194
+ const headerTitle = options.data?.title ?? options.title ?? "Untitled";
3195
+ const header =
3196
+ number !== undefined
3197
+ ? `# Created Pull Request #${number}: ${headerTitle}`
3198
+ : `# Created Pull Request: ${headerTitle}`;
3199
+ const lines: string[] = [header, ""];
3200
+ pushLine(lines, "URL", options.url || options.data?.url);
3201
+ pushLine(lines, "State", options.data?.state);
3202
+ pushLine(lines, "Draft", options.data?.isDraft ?? options.draft);
3203
+ pushLine(lines, "Base", options.data?.baseRefName ?? options.base);
3204
+ pushLine(lines, "Head", options.data?.headRefName ?? options.head);
3205
+ pushLine(lines, "Author", formatAuthor(options.data?.author));
3206
+ pushLine(lines, "Created", options.data?.createdAt);
3207
+ pushLine(lines, "Labels", formatLabels(options.data?.labels));
3208
+
3209
+ const bodyText = normalizeText(options.data?.body);
3210
+ if (bodyText) {
3211
+ lines.push("");
3212
+ lines.push("## Body");
3213
+ lines.push("");
3214
+ lines.push(bodyText);
3215
+ }
3216
+
3217
+ return lines.join("\n").trim();
3218
+ }
3219
+
3220
+ async function executeSearchIssues(
3221
+ session: ToolSession,
3222
+ params: GithubInput,
3223
+ signal: AbortSignal | undefined,
3224
+ ): Promise<AgentToolResult<GhToolDetails>> {
3225
+ const limit = resolveSearchLimit(params.limit);
3226
+ const dateField = resolveSearchDateField("issues", params.dateField);
3227
+ const dateQualifier = buildSearchDateQualifier(dateField, params.since, params.until);
3228
+ const displayQuery = composeSearchQuery([params.query, dateQualifier]);
3229
+ const repo = await resolveSearchRepoScope(session.cwd, normalizeOptionalString(params.repo), displayQuery, signal);
3230
+ const apiQuery = composeSearchQuery([displayQuery, repo ? `repo:${repo}` : undefined, "is:issue"]);
3231
+ const args = buildGhApiSearchArgs("issues", apiQuery, limit);
3232
+
3233
+ const response = await git.github.json<GhApiSearchResponse<GhApiSearchIssueItem>>(session.cwd, args, signal);
3234
+ const items = (response.items ?? []).map(apiIssueToSearchResult);
3235
+ return buildTextResult(formatSearchResults("issues", displayQuery, repo, items));
3236
+ }
3237
+
3238
+ async function executeSearchPrs(
3239
+ session: ToolSession,
3240
+ params: GithubInput,
3241
+ signal: AbortSignal | undefined,
3242
+ ): Promise<AgentToolResult<GhToolDetails>> {
3243
+ const limit = resolveSearchLimit(params.limit);
3244
+ const dateField = resolveSearchDateField("prs", params.dateField);
3245
+ const dateQualifier = buildSearchDateQualifier(dateField, params.since, params.until);
3246
+ const displayQuery = composeSearchQuery([params.query, dateQualifier]);
3247
+ const repo = await resolveSearchRepoScope(session.cwd, normalizeOptionalString(params.repo), displayQuery, signal);
3248
+ const apiQuery = composeSearchQuery([displayQuery, repo ? `repo:${repo}` : undefined, "is:pr"]);
3249
+ const args = buildGhApiSearchArgs("issues", apiQuery, limit);
3250
+
3251
+ const response = await git.github.json<GhApiSearchResponse<GhApiSearchIssueItem>>(session.cwd, args, signal);
3252
+ const items = (response.items ?? []).map(apiIssueToSearchResult);
3253
+ return buildTextResult(formatSearchResults("pull requests", displayQuery, repo, items));
3254
+ }
3255
+
3256
+ async function executeSearchCode(
3257
+ session: ToolSession,
3258
+ params: GithubInput,
3259
+ signal: AbortSignal | undefined,
3260
+ ): Promise<AgentToolResult<GhToolDetails>> {
3261
+ const query = requireNonEmpty(params.query, "query");
3262
+ if (params.since !== undefined || params.until !== undefined) {
3263
+ throw new ToolError("search_code does not support since/until; GitHub code search has no date qualifier.");
3264
+ }
3265
+ const limit = resolveSearchLimit(params.limit);
3266
+ const repo = await resolveSearchRepoScope(session.cwd, normalizeOptionalString(params.repo), query, signal);
3267
+ const apiQuery = composeSearchQuery([query, repo ? `repo:${repo}` : undefined]);
3268
+ const args = buildGhApiSearchArgs("code", apiQuery, limit, ["Accept: application/vnd.github.text-match+json"]);
3269
+
3270
+ const response = await git.github.json<GhApiSearchResponse<GhApiSearchCodeItem>>(session.cwd, args, signal);
3271
+ const items = (response.items ?? []).map(apiCodeToSearchResult);
3272
+ return buildTextResult(formatSearchCodeResults(query, repo, items));
3273
+ }
3274
+
3275
+ async function executeSearchCommits(
3276
+ session: ToolSession,
3277
+ params: GithubInput,
3278
+ signal: AbortSignal | undefined,
3279
+ ): Promise<AgentToolResult<GhToolDetails>> {
3280
+ const limit = resolveSearchLimit(params.limit);
3281
+ const dateField = resolveSearchDateField("commits", params.dateField);
3282
+ const dateQualifier = buildSearchDateQualifier(dateField, params.since, params.until);
3283
+ const displayQuery = composeSearchQuery([params.query, dateQualifier]);
3284
+ const repo = await resolveSearchRepoScope(session.cwd, normalizeOptionalString(params.repo), displayQuery, signal);
3285
+ const apiQuery = composeSearchQuery([displayQuery, repo ? `repo:${repo}` : undefined]);
3286
+ const args = buildGhApiSearchArgs("commits", apiQuery, limit);
3287
+
3288
+ const response = await git.github.json<GhApiSearchResponse<GhApiSearchCommitItem>>(session.cwd, args, signal);
3289
+ const items = (response.items ?? []).map(apiCommitToSearchResult);
3290
+ return buildTextResult(formatSearchCommitsResults(displayQuery, repo, items));
3291
+ }
3292
+
3293
+ async function executeSearchRepos(
3294
+ session: ToolSession,
3295
+ params: GithubInput,
3296
+ signal: AbortSignal | undefined,
3297
+ ): Promise<AgentToolResult<GhToolDetails>> {
3298
+ const limit = resolveSearchLimit(params.limit);
3299
+ const dateField = resolveSearchDateField("repos", params.dateField);
3300
+ const dateQualifier = buildSearchDateQualifier(dateField, params.since, params.until);
3301
+ const query = composeSearchQuery([params.query, dateQualifier]);
3302
+ const args = buildGhApiSearchArgs("repositories", query, limit);
3303
+
3304
+ const response = await git.github.json<GhApiSearchResponse<GhApiSearchRepoItem>>(session.cwd, args, signal);
3305
+ const items = (response.items ?? []).map(apiRepoToSearchResult);
3306
+ return buildTextResult(formatSearchReposResults(query, items));
3307
+ }
3308
+
3309
+ async function executeRunWatch(
3310
+ session: ToolSession,
3311
+ toolName: string,
3312
+ params: GithubInput,
3313
+ signal: AbortSignal | undefined,
3314
+ onUpdate: AgentToolUpdateCallback<GhToolDetails> | undefined,
3315
+ ): Promise<AgentToolResult<GhToolDetails>> {
3316
+ const branchInput = normalizeOptionalString(params.branch);
3317
+ const runReference = parseRunReference(params.run);
3318
+ const repo = await resolveGitHubRepo(session.cwd, undefined, runReference.repo, signal);
3319
+ const intervalSeconds = RUN_WATCH_INTERVAL_DEFAULT;
3320
+ const graceSeconds = RUN_WATCH_GRACE_DEFAULT;
3321
+ const tail = resolveTailLimit(params.tail);
3322
+ if (runReference.runId !== undefined) {
3323
+ const runId = runReference.runId;
3324
+ let pollCount = 0;
3325
+
3326
+ while (true) {
3327
+ throwIfAborted(signal);
3328
+ pollCount += 1;
3329
+
3330
+ let run = await fetchRunSnapshot(session.cwd, repo, runId, signal);
3331
+ const details = buildRunWatchDetails(repo, run, {
3332
+ state: "watching",
3333
+ pollCount,
3334
+ });
3335
+ onUpdate?.({
3336
+ content: [{ type: "text", text: formatRunWatchSnapshot(repo, run, pollCount) }],
3337
+ details,
3338
+ });
3339
+
3340
+ const failedJobs = run.jobs.filter(isFailedJob);
3341
+ const runCompleted = run.status === "completed";
3342
+
3343
+ if (failedJobs.length > 0) {
3344
+ if (!runCompleted && graceSeconds > 0) {
3345
+ const note = `Failure detected. Waiting ${graceSeconds}s to capture concurrent failures before fetching logs.`;
3346
+ onUpdate?.({
3347
+ content: [
3348
+ {
3349
+ type: "text",
3350
+ text: formatRunWatchSnapshot(repo, run, pollCount, note),
3351
+ },
3352
+ ],
3353
+ details: buildRunWatchDetails(repo, run, {
3354
+ state: "watching",
3355
+ pollCount,
3356
+ note,
3357
+ }),
3358
+ });
3359
+ await scheduler.wait(graceSeconds * 1000, { signal });
3360
+ run = await fetchRunSnapshot(session.cwd, repo, runId, signal);
3361
+ }
3362
+
3363
+ const failedJobLogs = await fetchFailedJobLogs(
3364
+ session.cwd,
3365
+ repo,
3366
+ run.jobs.filter(isFailedJob).map(job => ({ run, job })),
3367
+ tail,
3368
+ signal,
3369
+ );
3370
+ const finalDetails = buildRunWatchDetails(repo, run, {
3371
+ state: "completed",
3372
+ failedJobLogs,
3373
+ });
3374
+ const artifactId = await saveArtifactText(
3375
+ session,
3376
+ toolName,
3377
+ formatRunWatchResult(repo, run, failedJobLogs, tail, { mode: "full" }),
3378
+ );
3379
+ return buildTextResult(
3380
+ formatRunWatchResult(repo, run, failedJobLogs, tail),
3381
+ run.url,
3382
+ { ...finalDetails, artifactId },
3383
+ { artifactId, artifactLabel: "Full failed-job logs" },
3384
+ );
3385
+ }
3386
+
3387
+ if (runCompleted) {
3388
+ const finalDetails = buildRunWatchDetails(repo, run, {
3389
+ state: "completed",
3390
+ });
3391
+ return buildTextResult(formatRunWatchResult(repo, run, [], tail), run.url, finalDetails);
3392
+ }
3393
+
3394
+ await scheduler.wait(intervalSeconds * 1000, { signal });
3395
+ }
3396
+ }
3397
+
3398
+ const branch = branchInput ?? (await requireCurrentGitBranch(session.cwd, signal));
3399
+ const headSha = branchInput
3400
+ ? await resolveGitHubBranchHead(session.cwd, repo, branch, signal)
3401
+ : await requireCurrentGitHead(session.cwd, signal);
3402
+ let pollCount = 0;
3403
+ let settledSuccessSignature: string | undefined;
3404
+
3405
+ while (true) {
3406
+ throwIfAborted(signal);
3407
+ pollCount += 1;
3408
+
3409
+ let runs = await fetchRunsForCommit(session.cwd, repo, headSha, branch, signal);
3410
+ const details = buildCommitRunWatchDetails(repo, headSha, branch, runs, {
3411
+ state: "watching",
3412
+ pollCount,
3413
+ });
3414
+ onUpdate?.({
3415
+ content: [{ type: "text", text: formatCommitRunWatchSnapshot(repo, headSha, branch, runs, pollCount) }],
3416
+ details,
3417
+ });
3418
+
3419
+ const outcome = getRunCollectionOutcome(runs);
3420
+ if (outcome === "failure") {
3421
+ if (graceSeconds > 0) {
3422
+ const note = `Failure detected. Waiting ${graceSeconds}s to capture concurrent failures before fetching logs.`;
3423
+ onUpdate?.({
3424
+ content: [
3425
+ {
3426
+ type: "text",
3427
+ text: formatCommitRunWatchSnapshot(repo, headSha, branch, runs, pollCount, note),
3428
+ },
3429
+ ],
3430
+ details: buildCommitRunWatchDetails(repo, headSha, branch, runs, {
3431
+ state: "watching",
3432
+ pollCount,
3433
+ note,
3434
+ }),
3435
+ });
3436
+ await scheduler.wait(graceSeconds * 1000, { signal });
3437
+ runs = await fetchRunsForCommit(session.cwd, repo, headSha, branch, signal);
3438
+ }
3439
+
3440
+ const failedJobLogs = await fetchFailedJobLogs(
3441
+ session.cwd,
3442
+ repo,
3443
+ runs.flatMap(run => run.jobs.filter(isFailedJob).map(job => ({ run, job }))),
3444
+ tail,
3445
+ signal,
3446
+ );
3447
+ const finalDetails = buildCommitRunWatchDetails(repo, headSha, branch, runs, {
3448
+ state: "completed",
3449
+ failedJobLogs,
3450
+ });
3451
+ const artifactId = await saveArtifactText(
3452
+ session,
3453
+ toolName,
3454
+ formatCommitRunWatchResult(repo, headSha, branch, runs, failedJobLogs, tail, { mode: "full" }),
3455
+ );
3456
+ return buildTextResult(
3457
+ formatCommitRunWatchResult(repo, headSha, branch, runs, failedJobLogs, tail),
3458
+ undefined,
3459
+ { ...finalDetails, artifactId },
3460
+ { artifactId, artifactLabel: "Full failed-job logs" },
3461
+ );
3462
+ }
3463
+
3464
+ if (outcome === "success") {
3465
+ const signature = getRunCollectionSignature(runs);
3466
+ if (signature === settledSuccessSignature) {
3467
+ const finalDetails = buildCommitRunWatchDetails(repo, headSha, branch, runs, {
3468
+ state: "completed",
3469
+ });
3470
+ return buildTextResult(
3471
+ formatCommitRunWatchResult(repo, headSha, branch, runs, [], tail),
3472
+ undefined,
3473
+ finalDetails,
3474
+ );
3475
+ }
3476
+
3477
+ settledSuccessSignature = signature;
3478
+ const note = `All known workflow runs completed successfully. Waiting ${intervalSeconds}s to ensure no additional runs appear for this commit.`;
3479
+ onUpdate?.({
3480
+ content: [
3481
+ {
3482
+ type: "text",
3483
+ text: formatCommitRunWatchSnapshot(repo, headSha, branch, runs, pollCount, note),
3484
+ },
3485
+ ],
3486
+ details: buildCommitRunWatchDetails(repo, headSha, branch, runs, {
3487
+ state: "watching",
3488
+ pollCount,
3489
+ note,
3490
+ }),
3491
+ });
3492
+ await scheduler.wait(intervalSeconds * 1000, { signal });
3493
+ continue;
3494
+ }
3495
+
3496
+ settledSuccessSignature = undefined;
3497
+ await scheduler.wait(intervalSeconds * 1000, { signal });
3498
+ }
3499
+ }