@nghyane/arcane 0.1.12 → 0.1.14

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 (333) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/package.json +21 -70
  3. package/scripts/format-prompts.ts +1 -3
  4. package/src/cli/args.ts +2 -7
  5. package/src/cli/config-cli.ts +1 -1
  6. package/src/cli/plugin-cli.ts +1 -1
  7. package/src/cli/setup-cli.ts +1 -1
  8. package/src/cli/update-cli.ts +1 -1
  9. package/src/cli/web-search-cli.ts +1 -1
  10. package/src/cli.ts +0 -1
  11. package/src/commands/config.ts +1 -1
  12. package/src/commands/grep.ts +1 -1
  13. package/src/commands/jupyter.ts +1 -1
  14. package/src/commands/plugin.ts +1 -1
  15. package/src/commands/setup.ts +1 -1
  16. package/src/commands/shell.ts +1 -1
  17. package/src/commands/ssh.ts +1 -1
  18. package/src/commands/stats.ts +1 -1
  19. package/src/commands/update.ts +1 -1
  20. package/src/config/model-registry.ts +3 -4
  21. package/src/config/model-resolver.ts +36 -9
  22. package/src/config/prompt-templates.ts +1 -9
  23. package/src/config/settings-schema.ts +32 -88
  24. package/src/config/settings.ts +3 -4
  25. package/src/debug/index.ts +1 -1
  26. package/src/debug/log-formatting.ts +1 -1
  27. package/src/debug/log-viewer.ts +2 -2
  28. package/src/discovery/helpers.ts +13 -3
  29. package/src/exa/company.ts +2 -7
  30. package/src/exa/index.ts +1 -35
  31. package/src/exa/linkedin.ts +2 -7
  32. package/src/exa/mcp-client.ts +21 -11
  33. package/src/exa/render.ts +30 -190
  34. package/src/exa/researcher.ts +2 -12
  35. package/src/exa/search.ts +5 -25
  36. package/src/exa/types.ts +3 -3
  37. package/src/exec/bash-executor.ts +2 -1
  38. package/src/exec/non-interactive-env.ts +43 -0
  39. package/src/export/html/index.ts +1 -1
  40. package/src/extensibility/custom-tools/loader.ts +1 -1
  41. package/src/extensibility/custom-tools/types.ts +5 -1
  42. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  43. package/src/extensibility/extensions/runner.ts +1 -1
  44. package/src/extensibility/extensions/types.ts +1 -1
  45. package/src/extensibility/extensions/wrapper.ts +7 -15
  46. package/src/extensibility/hooks/runner.ts +1 -1
  47. package/src/extensibility/hooks/types.ts +1 -1
  48. package/src/extensibility/plugins/doctor.ts +1 -1
  49. package/src/index.ts +13 -13
  50. package/src/lsp/index.ts +77 -24
  51. package/src/lsp/render.ts +34 -583
  52. package/src/lsp/types.ts +3 -3
  53. package/src/lsp/utils.ts +1 -1
  54. package/src/main.ts +1 -1
  55. package/src/mcp/tool-bridge.ts +1 -24
  56. package/src/modes/components/assistant-message.ts +7 -7
  57. package/src/modes/components/bash-execution.ts +48 -113
  58. package/src/modes/components/bordered-loader.ts +1 -1
  59. package/src/modes/components/branch-summary-message.ts +13 -10
  60. package/src/modes/components/compaction-summary-message.ts +14 -13
  61. package/src/modes/components/context-group.ts +106 -0
  62. package/src/modes/components/custom-message.ts +4 -5
  63. package/src/modes/components/diff.ts +2 -2
  64. package/src/modes/components/dynamic-border.ts +1 -1
  65. package/src/modes/components/extensions/extension-dashboard.ts +2 -2
  66. package/src/modes/components/extensions/extension-list.ts +1 -1
  67. package/src/modes/components/extensions/inspector-panel.ts +8 -3
  68. package/src/modes/components/footer.ts +2 -2
  69. package/src/modes/components/history-search.ts +1 -1
  70. package/src/modes/components/hook-editor.ts +1 -1
  71. package/src/modes/components/hook-input.ts +1 -1
  72. package/src/modes/components/hook-message.ts +4 -5
  73. package/src/modes/components/hook-selector.ts +1 -1
  74. package/src/modes/components/index.ts +0 -2
  75. package/src/modes/components/keybinding-hints.ts +1 -1
  76. package/src/modes/components/login-dialog.ts +1 -1
  77. package/src/modes/components/mcp-add-wizard.ts +1 -1
  78. package/src/modes/components/model-selector.ts +1 -1
  79. package/src/modes/components/oauth-selector.ts +1 -1
  80. package/src/modes/components/plugin-settings.ts +1 -1
  81. package/src/modes/components/python-execution.ts +49 -92
  82. package/src/modes/components/queue-mode-selector.ts +1 -1
  83. package/src/modes/components/session-selector.ts +1 -1
  84. package/src/modes/components/settings-defs.ts +5 -10
  85. package/src/modes/components/settings-selector.ts +1 -1
  86. package/src/modes/components/show-images-selector.ts +1 -1
  87. package/src/modes/components/skill-message.ts +4 -4
  88. package/src/modes/components/status-line/segments.ts +2 -2
  89. package/src/modes/components/status-line/separators.ts +1 -1
  90. package/src/modes/components/status-line-segment-editor.ts +1 -1
  91. package/src/modes/components/status-line.ts +1 -1
  92. package/src/modes/components/theme-selector.ts +1 -1
  93. package/src/modes/components/thinking-selector.ts +1 -1
  94. package/src/modes/components/todo-display.ts +2 -4
  95. package/src/modes/components/todo-reminder.ts +4 -4
  96. package/src/modes/components/tool-execution.ts +118 -440
  97. package/src/modes/components/tool-image-display.ts +107 -0
  98. package/src/modes/components/tree-selector.ts +2 -2
  99. package/src/modes/components/ttsr-notification.ts +4 -17
  100. package/src/modes/components/user-message-selector.ts +1 -1
  101. package/src/modes/components/user-message.ts +9 -10
  102. package/src/modes/components/welcome.ts +1 -1
  103. package/src/modes/controllers/command-controller.ts +1 -1
  104. package/src/modes/controllers/event-controller.ts +58 -187
  105. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  106. package/src/modes/controllers/input-controller.ts +3 -1
  107. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  108. package/src/modes/controllers/selector-controller.ts +3 -26
  109. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  110. package/src/modes/interactive-mode.ts +3 -7
  111. package/src/modes/print-mode.ts +5 -5
  112. package/src/modes/rpc/rpc-mode.ts +1 -1
  113. package/src/modes/types.ts +1 -2
  114. package/src/modes/utils/ui-helpers.ts +34 -32
  115. package/src/patch/edit-tool.ts +742 -0
  116. package/src/patch/index.ts +32 -898
  117. package/src/patch/schemas.ts +208 -0
  118. package/src/patch/shared.ts +83 -151
  119. package/src/prompts/agents/explore.md +22 -37
  120. package/src/prompts/agents/frontmatter.md +1 -1
  121. package/src/prompts/agents/init.md +2 -2
  122. package/src/prompts/agents/librarian.md +30 -21
  123. package/src/prompts/agents/oracle.md +9 -2
  124. package/src/prompts/agents/reviewer.md +15 -49
  125. package/src/prompts/agents/task.md +17 -9
  126. package/src/prompts/compaction/branch-summary-context.md +1 -1
  127. package/src/prompts/compaction/branch-summary-preamble.md +1 -1
  128. package/src/prompts/compaction/branch-summary.md +4 -1
  129. package/src/prompts/compaction/compaction-short-summary.md +1 -1
  130. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  131. package/src/prompts/compaction/compaction-summary.md +4 -1
  132. package/src/prompts/compaction/compaction-turn-prefix.md +1 -1
  133. package/src/prompts/compaction/compaction-update-summary.md +1 -1
  134. package/src/prompts/memories/consolidation.md +1 -1
  135. package/src/prompts/memories/read_path.md +1 -1
  136. package/src/prompts/memories/stage_one_input.md +1 -1
  137. package/src/prompts/memories/stage_one_system.md +1 -1
  138. package/src/prompts/review-request.md +1 -1
  139. package/src/prompts/system/agent-creation-architect.md +1 -1
  140. package/src/prompts/system/agent-creation-user.md +1 -1
  141. package/src/prompts/system/custom-system-prompt.md +1 -1
  142. package/src/prompts/system/file-operations.md +1 -1
  143. package/src/prompts/system/subagent-system-prompt.md +2 -2
  144. package/src/prompts/system/summarization-system.md +1 -1
  145. package/src/prompts/system/system-prompt.md +163 -178
  146. package/src/prompts/system/title-system.md +1 -1
  147. package/src/prompts/system/ttsr-interrupt.md +1 -1
  148. package/src/prompts/system/verification-reminder.md +6 -0
  149. package/src/prompts/system/web-search.md +1 -1
  150. package/src/sdk.ts +0 -9
  151. package/src/session/agent-session.ts +244 -1459
  152. package/src/session/auth-storage.ts +5 -0
  153. package/src/session/model-controller.ts +406 -0
  154. package/src/session/retry-utils.ts +71 -0
  155. package/src/session/session-manager.ts +22 -186
  156. package/src/session/session-types.ts +312 -0
  157. package/src/session/stats.ts +387 -0
  158. package/src/session/streaming-edit.ts +258 -0
  159. package/src/session/ttsr.ts +213 -0
  160. package/src/slash-commands/builtin-registry.ts +0 -8
  161. package/src/ssh/connection-manager.ts +1 -0
  162. package/src/stt/recorder.ts +2 -2
  163. package/src/system-prompt.ts +1 -14
  164. package/src/task/agents.ts +7 -33
  165. package/src/task/executor.ts +50 -438
  166. package/src/task/index.ts +104 -71
  167. package/src/task/progress-tracker.ts +390 -0
  168. package/src/task/render.ts +371 -187
  169. package/src/task/subprocess-tool-registry.ts +1 -1
  170. package/src/task/types.ts +14 -47
  171. package/src/tools/ask.ts +31 -42
  172. package/src/tools/bash-interactive.ts +4 -47
  173. package/src/tools/bash-interceptor.ts +2 -2
  174. package/src/tools/bash-normalize.ts +1 -1
  175. package/src/tools/bash-skill-urls.ts +2 -2
  176. package/src/tools/bash.ts +87 -136
  177. package/src/tools/browser.ts +54 -84
  178. package/src/tools/create-tools.ts +186 -0
  179. package/src/tools/default-renderer.ts +104 -0
  180. package/src/tools/explore.ts +11 -10
  181. package/src/tools/fetch.ts +24 -114
  182. package/src/tools/find.ts +48 -132
  183. package/src/tools/gemini-image.ts +5 -15
  184. package/src/tools/github.ts +450 -0
  185. package/src/tools/grep.ts +43 -179
  186. package/src/tools/index.ts +35 -198
  187. package/src/tools/json-tree.ts +3 -3
  188. package/src/tools/librarian.ts +18 -18
  189. package/src/tools/list-limit.ts +2 -2
  190. package/src/tools/notebook.ts +35 -87
  191. package/src/tools/oracle.ts +25 -25
  192. package/src/tools/output-meta.ts +89 -4
  193. package/src/tools/output-utils.ts +2 -2
  194. package/src/tools/python.ts +86 -637
  195. package/src/tools/read.ts +36 -119
  196. package/src/tools/reviewer-tool.ts +19 -21
  197. package/src/tools/search-code.ts +128 -0
  198. package/src/tools/ssh.ts +67 -126
  199. package/src/tools/subagent-tool.ts +197 -123
  200. package/src/tools/todo-write.ts +15 -31
  201. package/src/tools/tool-errors.ts +0 -30
  202. package/src/tools/undo-edit.ts +30 -67
  203. package/src/tools/write.ts +78 -127
  204. package/src/tui/code-cell.ts +4 -4
  205. package/src/tui/file-list.ts +2 -2
  206. package/src/tui/output-block.ts +1 -1
  207. package/src/tui/status-line.ts +1 -1
  208. package/src/tui/tree-list.ts +2 -2
  209. package/src/tui/types.ts +1 -1
  210. package/src/tui/utils.ts +1 -1
  211. package/src/{tools → ui}/render-utils.ts +87 -126
  212. package/src/utils/external-editor.ts +4 -4
  213. package/src/utils/file-mentions.ts +1 -1
  214. package/src/utils/index.ts +30 -0
  215. package/src/utils/tools-manager.ts +9 -19
  216. package/src/web/github-client.ts +290 -0
  217. package/src/web/scrapers/github.ts +11 -62
  218. package/src/web/search/auth.ts +1 -3
  219. package/src/web/search/index.ts +85 -49
  220. package/src/web/search/provider.ts +11 -16
  221. package/src/web/search/providers/grep.ts +160 -0
  222. package/src/web/search/render.ts +48 -235
  223. package/src/web/search/types.ts +1 -1
  224. package/src/commands/commit.ts +0 -36
  225. package/src/commit/agentic/agent.ts +0 -311
  226. package/src/commit/agentic/fallback.ts +0 -96
  227. package/src/commit/agentic/index.ts +0 -359
  228. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  229. package/src/commit/agentic/prompts/session-user.md +0 -25
  230. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  231. package/src/commit/agentic/prompts/system.md +0 -38
  232. package/src/commit/agentic/state.ts +0 -69
  233. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  234. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  235. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  236. package/src/commit/agentic/tools/git-overview.ts +0 -84
  237. package/src/commit/agentic/tools/index.ts +0 -56
  238. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  239. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  240. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  241. package/src/commit/agentic/tools/split-commit.ts +0 -280
  242. package/src/commit/agentic/topo-sort.ts +0 -44
  243. package/src/commit/agentic/trivial.ts +0 -51
  244. package/src/commit/agentic/validation.ts +0 -200
  245. package/src/commit/analysis/conventional.ts +0 -165
  246. package/src/commit/analysis/index.ts +0 -4
  247. package/src/commit/analysis/scope.ts +0 -242
  248. package/src/commit/analysis/summary.ts +0 -112
  249. package/src/commit/analysis/validation.ts +0 -66
  250. package/src/commit/changelog/detect.ts +0 -37
  251. package/src/commit/changelog/generate.ts +0 -110
  252. package/src/commit/changelog/index.ts +0 -234
  253. package/src/commit/changelog/parse.ts +0 -44
  254. package/src/commit/cli.ts +0 -93
  255. package/src/commit/git/diff.ts +0 -148
  256. package/src/commit/git/errors.ts +0 -9
  257. package/src/commit/git/index.ts +0 -211
  258. package/src/commit/git/operations.ts +0 -54
  259. package/src/commit/index.ts +0 -5
  260. package/src/commit/map-reduce/index.ts +0 -64
  261. package/src/commit/map-reduce/map-phase.ts +0 -178
  262. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  263. package/src/commit/map-reduce/utils.ts +0 -9
  264. package/src/commit/message.ts +0 -11
  265. package/src/commit/model-selection.ts +0 -69
  266. package/src/commit/pipeline.ts +0 -243
  267. package/src/commit/prompts/analysis-system.md +0 -148
  268. package/src/commit/prompts/analysis-user.md +0 -38
  269. package/src/commit/prompts/changelog-system.md +0 -50
  270. package/src/commit/prompts/changelog-user.md +0 -18
  271. package/src/commit/prompts/file-observer-system.md +0 -24
  272. package/src/commit/prompts/file-observer-user.md +0 -8
  273. package/src/commit/prompts/reduce-system.md +0 -50
  274. package/src/commit/prompts/reduce-user.md +0 -17
  275. package/src/commit/prompts/summary-retry.md +0 -3
  276. package/src/commit/prompts/summary-system.md +0 -38
  277. package/src/commit/prompts/summary-user.md +0 -13
  278. package/src/commit/prompts/types-description.md +0 -2
  279. package/src/commit/types.ts +0 -109
  280. package/src/commit/utils/exclusions.ts +0 -42
  281. package/src/mcp/render.ts +0 -123
  282. package/src/modes/components/agent-dashboard.ts +0 -1130
  283. package/src/modes/components/codemode-group.ts +0 -369
  284. package/src/modes/components/read-tool-group.ts +0 -119
  285. package/src/modes/components/visual-truncate.ts +0 -63
  286. package/src/prompts/system/subagent-user-prompt.md +0 -8
  287. package/src/prompts/tools/ask.md +0 -44
  288. package/src/prompts/tools/bash.md +0 -24
  289. package/src/prompts/tools/browser.md +0 -33
  290. package/src/prompts/tools/calculator.md +0 -12
  291. package/src/prompts/tools/explore.md +0 -29
  292. package/src/prompts/tools/fetch.md +0 -16
  293. package/src/prompts/tools/find.md +0 -18
  294. package/src/prompts/tools/gemini-image.md +0 -23
  295. package/src/prompts/tools/grep.md +0 -28
  296. package/src/prompts/tools/hashline.md +0 -232
  297. package/src/prompts/tools/librarian.md +0 -24
  298. package/src/prompts/tools/lsp.md +0 -28
  299. package/src/prompts/tools/oracle.md +0 -26
  300. package/src/prompts/tools/patch.md +0 -74
  301. package/src/prompts/tools/python.md +0 -66
  302. package/src/prompts/tools/read.md +0 -36
  303. package/src/prompts/tools/replace.md +0 -38
  304. package/src/prompts/tools/reviewer.md +0 -41
  305. package/src/prompts/tools/ssh.md +0 -51
  306. package/src/prompts/tools/task-summary.md +0 -28
  307. package/src/prompts/tools/task.md +0 -146
  308. package/src/prompts/tools/todo-write.md +0 -65
  309. package/src/prompts/tools/undo-edit.md +0 -7
  310. package/src/prompts/tools/web-search.md +0 -19
  311. package/src/prompts/tools/write.md +0 -18
  312. package/src/task/batch.ts +0 -102
  313. package/src/task/discovery.ts +0 -126
  314. package/src/task/parallel.ts +0 -84
  315. package/src/task/template.ts +0 -32
  316. package/src/tools/calculator.ts +0 -537
  317. package/src/tools/jtd-to-typescript.ts +0 -198
  318. package/src/tools/renderers.ts +0 -60
  319. package/src/tools/tool-result.ts +0 -86
  320. /package/src/{modes/theme → theme}/dark.json +0 -0
  321. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  322. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  323. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  324. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  325. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  326. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  327. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  328. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  329. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  330. /package/src/{modes/theme → theme}/light.json +0 -0
  331. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  332. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  333. /package/src/{modes/theme → theme}/theme.ts +0 -0
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Unified Web Search Tool
3
3
  *
4
- * Single tool supporting Anthropic, Perplexity, Exa, Brave, Jina, Kimi, Gemini, Codex, Z.AI, and Synthetic
5
- * providers with provider-specific parameters exposed conditionally.
4
+ * Single tool supporting Anthropic, Perplexity, Exa, Brave, Jina, Kimi, Gemini, Codex, Z.AI, Synthetic,
5
+ * and grep.app providers with provider-specific parameters exposed conditionally.
6
6
  *
7
7
  * When EXA_API_KEY is available, additional specialized tools are exposed:
8
8
  * - web_search_deep: Natural language web search with synthesized results
@@ -14,16 +14,13 @@
14
14
  import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@nghyane/arcane-agent";
15
15
  import { StringEnum } from "@nghyane/arcane-ai";
16
16
  import { Type } from "@sinclair/typebox";
17
- import { renderPromptTemplate } from "../../config/prompt-templates";
18
17
  import { callExaTool, findApiKey as findExaKey, formatSearchResults, isSearchResponse } from "../../exa/mcp-client";
19
18
  import { renderExaCall, renderExaResult } from "../../exa/render";
20
19
  import type { ExaRenderDetails } from "../../exa/types";
21
20
  import type { CustomTool, CustomToolContext, RenderResultOptions } from "../../extensibility/custom-tools/types";
22
- import type { Theme } from "../../modes/theme/theme";
23
21
  import webSearchSystemPrompt from "../../prompts/system/web-search.md" with { type: "text" };
24
- import webSearchDescription from "../../prompts/tools/web-search.md" with { type: "text" };
25
- import type { ToolSession } from "../../tools";
26
- import { formatAge } from "../../tools/render-utils";
22
+ import type { Theme } from "../../theme/theme";
23
+ import { formatAge } from "../../ui/render-utils";
27
24
  import { getSearchProvider, resolveProviderChain, type SearchProvider } from "./provider";
28
25
  import { renderSearchCall, renderSearchResult, type SearchRenderDetails } from "./render";
29
26
  import type { SearchResponse } from "./types";
@@ -33,19 +30,22 @@ import { SearchProviderError } from "./types";
33
30
  export const webSearchSchema = Type.Object({
34
31
  query: Type.String({ description: "Search query" }),
35
32
  provider: Type.Optional(
36
- StringEnum(
37
- ["auto", "exa", "brave", "jina", "kimi", "zai", "anthropic", "perplexity", "gemini", "codex", "synthetic"],
38
- {
39
- description: "Search provider (default: auto)",
40
- },
41
- ),
33
+ StringEnum([
34
+ "auto",
35
+ "exa",
36
+ "brave",
37
+ "jina",
38
+ "kimi",
39
+ "zai",
40
+ "anthropic",
41
+ "perplexity",
42
+ "gemini",
43
+ "codex",
44
+ "synthetic",
45
+ ]),
42
46
  ),
43
- recency: Type.Optional(
44
- StringEnum(["day", "week", "month", "year"], {
45
- description: "Recency filter (Brave, Perplexity)",
46
- }),
47
- ),
48
- limit: Type.Optional(Type.Number({ description: "Max results to return" })),
47
+ recency: Type.Optional(StringEnum(["day", "week", "month", "year"], { description: "Filter results by recency" })),
48
+ limit: Type.Optional(Type.Number({ description: "Max number of results" })),
49
49
  });
50
50
 
51
51
  export type SearchParams = {
@@ -183,7 +183,10 @@ function formatForLLM(response: SearchResponse): string {
183
183
  async function executeSearch(
184
184
  _toolCallId: string,
185
185
  params: SearchParams,
186
- ): Promise<{ content: Array<{ type: "text"; text: string }>; details: SearchRenderDetails }> {
186
+ ): Promise<{
187
+ content: Array<{ type: "text"; text: string }>;
188
+ details: SearchRenderDetails;
189
+ }> {
187
190
  const providers =
188
191
  params.provider && params.provider !== "auto" && params.no_fallback
189
192
  ? (await getSearchProvider(params.provider).isAvailable())
@@ -234,16 +237,20 @@ async function executeSearch(
234
237
 
235
238
  return {
236
239
  content: [{ type: "text" as const, text: `Error: ${message}` }],
237
- details: { response: { provider: lastProvider.id, sources: [] }, error: message },
240
+ details: {
241
+ response: { provider: lastProvider.id, sources: [] },
242
+ error: message,
243
+ },
238
244
  };
239
245
  }
240
246
 
241
247
  /**
242
248
  * Execute a web search query for CLI/testing workflows.
243
249
  */
244
- export async function runSearchQuery(
245
- params: SearchParams,
246
- ): Promise<{ content: Array<{ type: "text"; text: string }>; details: SearchRenderDetails }> {
250
+ export async function runSearchQuery(params: SearchParams): Promise<{
251
+ content: Array<{ type: "text"; text: string }>;
252
+ details: SearchRenderDetails;
253
+ }> {
247
254
  return executeSearch("cli-web-search", params);
248
255
  }
249
256
 
@@ -253,15 +260,13 @@ export async function runSearchQuery(
253
260
  * Supports Anthropic, Perplexity, Exa, Brave, Jina, Kimi, Gemini, Codex, Z.AI, and Synthetic providers with automatic fallback.
254
261
  * Session is accepted for interface consistency but not used.
255
262
  */
256
- export class SearchTool implements AgentTool<typeof webSearchSchema, SearchRenderDetails> {
263
+ export class SearchTool implements AgentTool<typeof webSearchSchema, SearchRenderDetails, Theme> {
257
264
  readonly name = "web_search";
258
265
  readonly label = "Web Search";
259
- readonly description: string;
266
+ readonly description = "Search the web";
260
267
  readonly parameters = webSearchSchema;
261
-
262
- constructor(_session: ToolSession) {
263
- this.description = renderPromptTemplate(webSearchDescription);
264
- }
268
+ readonly renderCall = renderSearchCall;
269
+ readonly renderResult = renderSearchResult;
265
270
 
266
271
  async execute(
267
272
  _toolCallId: string,
@@ -278,7 +283,7 @@ export class SearchTool implements AgentTool<typeof webSearchSchema, SearchRende
278
283
  export const webSearchCustomTool: CustomTool<typeof webSearchSchema, SearchRenderDetails> = {
279
284
  name: "web_search",
280
285
  label: "Web Search",
281
- description: renderPromptTemplate(webSearchDescription),
286
+ description: "",
282
287
  parameters: webSearchSchema,
283
288
 
284
289
  async execute(toolCallId: string, params: SearchParams, _onUpdate, _ctx: CustomToolContext, _signal?: AbortSignal) {
@@ -307,36 +312,64 @@ const webSearchDeepSchema = Type.Object({
307
312
  }),
308
313
  ),
309
314
  include_domains: Type.Optional(
310
- Type.Array(Type.String(), { description: "Only include results from these domains" }),
315
+ Type.Array(Type.String(), {
316
+ description: "Only include results from these domains",
317
+ }),
318
+ ),
319
+ exclude_domains: Type.Optional(
320
+ Type.Array(Type.String(), {
321
+ description: "Exclude results from these domains",
322
+ }),
311
323
  ),
312
- exclude_domains: Type.Optional(Type.Array(Type.String(), { description: "Exclude results from these domains" })),
313
324
  start_published_date: Type.Optional(
314
- Type.String({ description: "Filter results published after this date (ISO 8601)" }),
325
+ Type.String({
326
+ description: "Filter results published after this date (ISO 8601)",
327
+ }),
315
328
  ),
316
329
  end_published_date: Type.Optional(
317
- Type.String({ description: "Filter results published before this date (ISO 8601)" }),
330
+ Type.String({
331
+ description: "Filter results published before this date (ISO 8601)",
332
+ }),
318
333
  ),
319
334
  num_results: Type.Optional(
320
- Type.Number({ description: "Maximum results (default: 10, max: 100)", minimum: 1, maximum: 100 }),
335
+ Type.Number({
336
+ description: "Maximum results (default: 10, max: 100)",
337
+ minimum: 1,
338
+ maximum: 100,
339
+ }),
321
340
  ),
322
341
  });
323
342
 
324
343
  /** Schema for code context search */
325
344
  const webSearchCodeContextSchema = Type.Object({
326
345
  query: Type.String({ description: "Code or technical search query" }),
327
- code_context: Type.Optional(Type.String({ description: "Additional context about what you're looking for" })),
346
+ code_context: Type.Optional(
347
+ Type.String({
348
+ description: "Additional context about what you're looking for",
349
+ }),
350
+ ),
328
351
  });
329
352
 
330
353
  /** Schema for URL crawling */
331
354
  const webSearchCrawlSchema = Type.Object({
332
355
  url: Type.String({ description: "URL to crawl and extract content from" }),
333
- text: Type.Optional(Type.Boolean({ description: "Include full page text content (default: false)" })),
334
- highlights: Type.Optional(Type.Boolean({ description: "Include highlighted relevant snippets (default: false)" })),
356
+ text: Type.Optional(
357
+ Type.Boolean({
358
+ description: "Include full page text content (default: false)",
359
+ }),
360
+ ),
361
+ highlights: Type.Optional(
362
+ Type.Boolean({
363
+ description: "Include highlighted relevant snippets (default: false)",
364
+ }),
365
+ ),
335
366
  });
336
367
 
337
368
  /** Schema for LinkedIn search */
338
369
  const webSearchLinkedinSchema = Type.Object({
339
- query: Type.String({ description: 'LinkedIn search query (e.g., "Software Engineer at OpenAI")' }),
370
+ query: Type.String({
371
+ description: 'LinkedIn search query (e.g., "Software Engineer at OpenAI")',
372
+ }),
340
373
  });
341
374
 
342
375
  /** Schema for company research */
@@ -349,7 +382,10 @@ async function executeExaTool(
349
382
  mcpToolName: string,
350
383
  params: Record<string, unknown>,
351
384
  toolName: string,
352
- ): Promise<{ content: Array<{ type: "text"; text: string }>; details: ExaRenderDetails }> {
385
+ ): Promise<{
386
+ content: Array<{ type: "text"; text: string }>;
387
+ details: ExaRenderDetails;
388
+ }> {
353
389
  try {
354
390
  const apiKey = await findExaKey();
355
391
  if (!apiKey) {
@@ -461,7 +497,7 @@ Parameters:
461
497
  parameters: webSearchCrawlSchema,
462
498
 
463
499
  async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
464
- return executeExaTool("crawling", params as Record<string, unknown>, "web_search_crawl");
500
+ return executeExaTool("crawling_exa", params as Record<string, unknown>, "web_search_crawl");
465
501
  },
466
502
 
467
503
  renderCall(args, _options, theme) {
@@ -492,7 +528,7 @@ Parameters:
492
528
  parameters: webSearchLinkedinSchema,
493
529
 
494
530
  async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
495
- return executeExaTool("linkedin_search", params as Record<string, unknown>, "web_search_linkedin");
531
+ return executeExaTool("linkedin_search_exa", params as Record<string, unknown>, "web_search_linkedin");
496
532
  },
497
533
 
498
534
  renderCall(args, _options, theme) {
@@ -522,7 +558,7 @@ Parameters:
522
558
  parameters: webSearchCompanySchema,
523
559
 
524
560
  async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
525
- return executeExaTool("company_research", params as Record<string, unknown>, "web_search_company");
561
+ return executeExaTool("company_research_exa", params as Record<string, unknown>, "web_search_company");
526
562
  },
527
563
 
528
564
  renderCall(args, _options, theme) {
@@ -591,8 +627,8 @@ export async function hasExaSearch(): Promise<boolean> {
591
627
  return exaKey !== null;
592
628
  }
593
629
 
594
- export {
595
- getSearchProvider,
596
- setPreferredSearchProvider,
597
- } from "./provider";
598
- export type { SearchProviderId as SearchProvider, SearchResponse } from "./types";
630
+ export { getSearchProvider, setPreferredSearchProvider } from "./provider";
631
+ export type {
632
+ SearchProviderId as SearchProvider,
633
+ SearchResponse,
634
+ } from "./types";
@@ -56,22 +56,17 @@ export function setPreferredSearchProvider(provider: SearchProviderId | "auto"):
56
56
  export async function resolveProviderChain(
57
57
  preferredProvider: SearchProviderId | "auto" = preferredProvId,
58
58
  ): Promise<SearchProvider[]> {
59
- const providers: SearchProvider[] = [];
59
+ const order: SearchProviderId[] =
60
+ preferredProvider !== "auto"
61
+ ? [preferredProvider, ...SEARCH_PROVIDER_ORDER.filter(id => id !== preferredProvider)]
62
+ : SEARCH_PROVIDER_ORDER;
60
63
 
61
- if (preferredProvider !== "auto") {
62
- if (await getSearchProvider(preferredProvider).isAvailable()) {
63
- providers.push(getSearchProvider(preferredProvider));
64
- }
65
- }
64
+ const checks = await Promise.all(
65
+ order.map(async id => ({
66
+ provider: getSearchProvider(id),
67
+ available: await getSearchProvider(id).isAvailable(),
68
+ })),
69
+ );
66
70
 
67
- for (const id of SEARCH_PROVIDER_ORDER) {
68
- if (id === preferredProvider) continue;
69
-
70
- const provider = getSearchProvider(id);
71
- if (await provider.isAvailable()) {
72
- providers.push(provider);
73
- }
74
- }
75
-
76
- return providers;
71
+ return checks.filter(c => c.available).map(c => c.provider);
77
72
  }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * grep.app Web Search Provider
3
+ *
4
+ * Cross-repo code search across all public GitHub repositories.
5
+ * No API key required. Supports regex and language filtering.
6
+ */
7
+
8
+ import type { SearchSource } from "../types";
9
+
10
+ const GREP_APP_URL = "https://grep.app/api/search";
11
+
12
+ interface GrepAppHit {
13
+ repo: string;
14
+ path: string;
15
+ branch?: string;
16
+ total_matches?: string;
17
+ content?: {
18
+ snippet?: string;
19
+ };
20
+ }
21
+
22
+ interface GrepAppFacetBucket {
23
+ val: string;
24
+ count: number;
25
+ }
26
+
27
+ interface GrepAppResponse {
28
+ time?: number;
29
+ hits?: {
30
+ total?: number;
31
+ hits?: GrepAppHit[];
32
+ };
33
+ facets?: {
34
+ lang?: { buckets?: GrepAppFacetBucket[] };
35
+ repo?: { buckets?: GrepAppFacetBucket[] };
36
+ path?: { buckets?: GrepAppFacetBucket[] };
37
+ };
38
+ }
39
+
40
+ function stripHtml(html: string): string {
41
+ return html
42
+ .replace(/<mark[^>]*>/g, "")
43
+ .replace(/<\/mark>/g, "")
44
+ .replace(/<[^>]+>/g, "")
45
+ .replace(/&lt;/g, "<")
46
+ .replace(/&gt;/g, ">")
47
+ .replace(/&amp;/g, "&")
48
+ .replace(/&quot;/g, '"')
49
+ .replace(/&#39;/g, "'")
50
+ .trim();
51
+ }
52
+
53
+ function extractSnippet(hit: GrepAppHit): { lines: string[]; lineNumbers: number[] } {
54
+ const raw = hit.content?.snippet ?? "";
55
+ if (!raw) return { lines: [], lineNumbers: [] };
56
+
57
+ const lines: string[] = [];
58
+ const lineNumbers: number[] = [];
59
+
60
+ const table = raw.match(/<table[^>]*>(.*?)<\/table>/s);
61
+ if (!table) {
62
+ return { lines: [stripHtml(raw)], lineNumbers: [] };
63
+ }
64
+
65
+ const trBlocks = table[1].split(/<\/tr>/);
66
+ for (const tr of trBlocks) {
67
+ const lineMatch = tr.match(/data-line="(\d+)"/);
68
+ if (lineMatch) lineNumbers.push(Number.parseInt(lineMatch[1], 10));
69
+
70
+ const preMatch = tr.match(/<pre>(.*?)<\/pre>/s);
71
+ if (preMatch) lines.push(stripHtml(preMatch[1]));
72
+ }
73
+ return { lines, lineNumbers };
74
+ }
75
+
76
+ export interface SearchCodeParams {
77
+ query: string;
78
+ regexp?: boolean;
79
+ language?: string;
80
+ repo?: string;
81
+ limit?: number;
82
+ signal?: AbortSignal;
83
+ }
84
+
85
+ export interface SearchCodeSource extends SearchSource {
86
+ branch?: string;
87
+ lineNumbers?: number[];
88
+ matchCount?: number;
89
+ }
90
+
91
+ export interface SearchCodeResponse {
92
+ provider: "grep";
93
+ sources: SearchCodeSource[];
94
+ total?: number;
95
+ timeMs?: number;
96
+ topLanguages?: GrepAppFacetBucket[];
97
+ topRepos?: GrepAppFacetBucket[];
98
+ }
99
+
100
+ export class GrepAppProvider {
101
+ readonly id = "grep";
102
+ readonly label = "grep.app";
103
+
104
+ isAvailable(): boolean {
105
+ return true;
106
+ }
107
+
108
+ async search(params: SearchCodeParams): Promise<SearchCodeResponse> {
109
+ const url = new URL(GREP_APP_URL);
110
+ url.searchParams.set("q", params.query);
111
+ url.searchParams.set("regexp", params.regexp ? "true" : "false");
112
+ url.searchParams.set("case", "false");
113
+ if (params.language) {
114
+ url.searchParams.set("l", params.language);
115
+ }
116
+ if (params.repo) {
117
+ url.searchParams.set("r", params.repo);
118
+ }
119
+
120
+ const response = await fetch(url.toString(), {
121
+ signal: params.signal,
122
+ headers: { Accept: "application/json" },
123
+ });
124
+
125
+ if (!response.ok) {
126
+ const text = await response.text();
127
+ throw new Error(`grep.app error (${response.status}): ${text}`);
128
+ }
129
+
130
+ const data = (await response.json()) as GrepAppResponse;
131
+ const hits = data.hits?.hits ?? [];
132
+ const limit = params.limit ?? 10;
133
+ const sources: SearchCodeSource[] = [];
134
+
135
+ for (const hit of hits.slice(0, limit)) {
136
+ const { lines, lineNumbers } = extractSnippet(hit);
137
+ const branch = hit.branch ?? "HEAD";
138
+ const startLine = lineNumbers[0];
139
+ const lineAnchor = startLine ? `#L${startLine}` : "";
140
+
141
+ sources.push({
142
+ title: `${hit.repo}: ${hit.path}`,
143
+ url: `https://github.com/${hit.repo}/blob/${branch}/${hit.path}${lineAnchor}`,
144
+ snippet: lines.length > 0 ? lines.join("\n") : undefined,
145
+ branch,
146
+ lineNumbers: lineNumbers.length > 0 ? lineNumbers : undefined,
147
+ matchCount: hit.total_matches ? Number.parseInt(hit.total_matches, 10) : undefined,
148
+ });
149
+ }
150
+
151
+ return {
152
+ provider: "grep",
153
+ sources,
154
+ total: data.hits?.total,
155
+ timeMs: data.time,
156
+ topLanguages: data.facets?.lang?.buckets?.slice(0, 5),
157
+ topRepos: data.facets?.repo?.buckets?.slice(0, 5),
158
+ };
159
+ }
160
+ }