@nghyane/arcane 0.1.13 → 0.1.15

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 (303) 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/index.ts +1 -35
  30. package/src/exa/render.ts +30 -190
  31. package/src/export/html/index.ts +1 -1
  32. package/src/extensibility/custom-tools/loader.ts +1 -1
  33. package/src/extensibility/custom-tools/types.ts +5 -1
  34. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  35. package/src/extensibility/extensions/runner.ts +1 -1
  36. package/src/extensibility/extensions/types.ts +1 -1
  37. package/src/extensibility/extensions/wrapper.ts +7 -15
  38. package/src/extensibility/hooks/runner.ts +1 -1
  39. package/src/extensibility/hooks/types.ts +1 -1
  40. package/src/extensibility/plugins/doctor.ts +1 -1
  41. package/src/index.ts +13 -13
  42. package/src/lsp/index.ts +77 -24
  43. package/src/lsp/render.ts +34 -583
  44. package/src/lsp/types.ts +3 -3
  45. package/src/lsp/utils.ts +1 -1
  46. package/src/main.ts +1 -1
  47. package/src/mcp/tool-bridge.ts +1 -24
  48. package/src/modes/components/assistant-message.ts +7 -7
  49. package/src/modes/components/bash-execution.ts +50 -112
  50. package/src/modes/components/bordered-loader.ts +1 -1
  51. package/src/modes/components/branch-summary-message.ts +16 -10
  52. package/src/modes/components/compaction-summary-message.ts +20 -12
  53. package/src/modes/components/context-group.ts +106 -0
  54. package/src/modes/components/custom-message.ts +4 -5
  55. package/src/modes/components/diff.ts +2 -2
  56. package/src/modes/components/dynamic-border.ts +1 -1
  57. package/src/modes/components/extensions/extension-dashboard.ts +1 -1
  58. package/src/modes/components/extensions/extension-list.ts +1 -1
  59. package/src/modes/components/extensions/inspector-panel.ts +1 -1
  60. package/src/modes/components/footer.ts +2 -2
  61. package/src/modes/components/history-search.ts +1 -1
  62. package/src/modes/components/hook-editor.ts +1 -1
  63. package/src/modes/components/hook-input.ts +1 -1
  64. package/src/modes/components/hook-message.ts +4 -5
  65. package/src/modes/components/hook-selector.ts +1 -1
  66. package/src/modes/components/index.ts +0 -2
  67. package/src/modes/components/keybinding-hints.ts +1 -1
  68. package/src/modes/components/login-dialog.ts +1 -1
  69. package/src/modes/components/mcp-add-wizard.ts +1 -1
  70. package/src/modes/components/model-selector.ts +1 -1
  71. package/src/modes/components/oauth-selector.ts +1 -1
  72. package/src/modes/components/plugin-settings.ts +1 -1
  73. package/src/modes/components/python-execution.ts +51 -91
  74. package/src/modes/components/queue-mode-selector.ts +1 -1
  75. package/src/modes/components/session-selector.ts +1 -1
  76. package/src/modes/components/settings-defs.ts +5 -10
  77. package/src/modes/components/settings-selector.ts +1 -1
  78. package/src/modes/components/show-images-selector.ts +1 -1
  79. package/src/modes/components/skill-message.ts +4 -4
  80. package/src/modes/components/status-line/segments.ts +2 -2
  81. package/src/modes/components/status-line/separators.ts +1 -1
  82. package/src/modes/components/status-line-segment-editor.ts +1 -1
  83. package/src/modes/components/status-line.ts +1 -1
  84. package/src/modes/components/theme-selector.ts +1 -1
  85. package/src/modes/components/thinking-selector.ts +1 -1
  86. package/src/modes/components/todo-display.ts +2 -4
  87. package/src/modes/components/todo-reminder.ts +4 -4
  88. package/src/modes/components/tool-execution.ts +118 -440
  89. package/src/modes/components/tool-image-display.ts +107 -0
  90. package/src/modes/components/tree-selector.ts +2 -2
  91. package/src/modes/components/ttsr-notification.ts +4 -17
  92. package/src/modes/components/user-message-selector.ts +1 -1
  93. package/src/modes/components/user-message.ts +9 -10
  94. package/src/modes/components/welcome.ts +1 -1
  95. package/src/modes/controllers/command-controller.ts +1 -1
  96. package/src/modes/controllers/event-controller.ts +58 -187
  97. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  98. package/src/modes/controllers/input-controller.ts +3 -1
  99. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  100. package/src/modes/controllers/selector-controller.ts +3 -26
  101. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  102. package/src/modes/interactive-mode.ts +3 -7
  103. package/src/modes/print-mode.ts +5 -5
  104. package/src/modes/rpc/rpc-mode.ts +1 -1
  105. package/src/modes/types.ts +1 -2
  106. package/src/modes/utils/ui-helpers.ts +34 -32
  107. package/src/patch/edit-tool.ts +742 -0
  108. package/src/patch/index.ts +32 -898
  109. package/src/patch/schemas.ts +208 -0
  110. package/src/patch/shared.ts +83 -151
  111. package/src/prompts/agents/explore.md +22 -37
  112. package/src/prompts/agents/init.md +1 -1
  113. package/src/prompts/agents/librarian.md +29 -20
  114. package/src/prompts/agents/oracle.md +9 -2
  115. package/src/prompts/agents/reviewer.md +14 -48
  116. package/src/prompts/agents/task.md +16 -8
  117. package/src/prompts/compaction/branch-summary.md +4 -1
  118. package/src/prompts/compaction/compaction-summary.md +4 -1
  119. package/src/prompts/system/subagent-system-prompt.md +1 -1
  120. package/src/prompts/system/system-prompt.md +162 -178
  121. package/src/prompts/system/verification-reminder.md +6 -0
  122. package/src/sdk.ts +0 -9
  123. package/src/session/agent-session.ts +244 -1459
  124. package/src/session/model-controller.ts +406 -0
  125. package/src/session/retry-utils.ts +71 -0
  126. package/src/session/session-manager.ts +22 -186
  127. package/src/session/session-types.ts +312 -0
  128. package/src/session/stats.ts +387 -0
  129. package/src/session/streaming-edit.ts +258 -0
  130. package/src/session/ttsr.ts +213 -0
  131. package/src/slash-commands/builtin-registry.ts +0 -8
  132. package/src/stt/recorder.ts +2 -2
  133. package/src/system-prompt.ts +1 -14
  134. package/src/task/agents.ts +7 -33
  135. package/src/task/executor.ts +50 -438
  136. package/src/task/index.ts +104 -71
  137. package/src/task/progress-tracker.ts +390 -0
  138. package/src/task/render.ts +371 -187
  139. package/src/task/subprocess-tool-registry.ts +1 -1
  140. package/src/task/types.ts +14 -47
  141. package/src/tools/ask.ts +31 -42
  142. package/src/tools/bash-interactive.ts +2 -2
  143. package/src/tools/bash-interceptor.ts +2 -2
  144. package/src/tools/bash-normalize.ts +1 -1
  145. package/src/tools/bash-skill-urls.ts +2 -2
  146. package/src/tools/bash.ts +87 -136
  147. package/src/tools/browser.ts +54 -84
  148. package/src/tools/create-tools.ts +186 -0
  149. package/src/tools/default-renderer.ts +104 -0
  150. package/src/tools/explore.ts +11 -10
  151. package/src/tools/fetch.ts +24 -114
  152. package/src/tools/find.ts +48 -132
  153. package/src/tools/gemini-image.ts +5 -15
  154. package/src/tools/github.ts +450 -0
  155. package/src/tools/grep.ts +43 -179
  156. package/src/tools/index.ts +35 -198
  157. package/src/tools/json-tree.ts +3 -3
  158. package/src/tools/librarian.ts +18 -18
  159. package/src/tools/list-limit.ts +2 -2
  160. package/src/tools/notebook.ts +35 -87
  161. package/src/tools/oracle.ts +25 -25
  162. package/src/tools/output-meta.ts +89 -4
  163. package/src/tools/output-utils.ts +2 -2
  164. package/src/tools/python.ts +86 -637
  165. package/src/tools/read.ts +36 -119
  166. package/src/tools/reviewer-tool.ts +19 -21
  167. package/src/tools/search-code.ts +128 -0
  168. package/src/tools/ssh.ts +67 -126
  169. package/src/tools/subagent-tool.ts +197 -123
  170. package/src/tools/todo-write.ts +15 -31
  171. package/src/tools/tool-errors.ts +0 -30
  172. package/src/tools/undo-edit.ts +30 -67
  173. package/src/tools/write.ts +78 -127
  174. package/src/tui/code-cell.ts +4 -4
  175. package/src/tui/file-list.ts +2 -2
  176. package/src/tui/output-block.ts +1 -1
  177. package/src/tui/status-line.ts +1 -1
  178. package/src/tui/tree-list.ts +2 -2
  179. package/src/tui/types.ts +1 -1
  180. package/src/tui/utils.ts +1 -1
  181. package/src/{tools → ui}/render-utils.ts +87 -126
  182. package/src/utils/external-editor.ts +4 -4
  183. package/src/utils/file-mentions.ts +1 -1
  184. package/src/utils/index.ts +30 -0
  185. package/src/utils/tools-manager.ts +9 -19
  186. package/src/web/github-client.ts +290 -0
  187. package/src/web/scrapers/github.ts +11 -62
  188. package/src/web/search/auth.ts +1 -3
  189. package/src/web/search/index.ts +82 -46
  190. package/src/web/search/provider.ts +11 -16
  191. package/src/web/search/providers/grep.ts +160 -0
  192. package/src/web/search/render.ts +48 -235
  193. package/src/web/search/types.ts +1 -1
  194. package/src/commands/commit.ts +0 -36
  195. package/src/commit/agentic/agent.ts +0 -311
  196. package/src/commit/agentic/fallback.ts +0 -96
  197. package/src/commit/agentic/index.ts +0 -359
  198. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  199. package/src/commit/agentic/prompts/session-user.md +0 -25
  200. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  201. package/src/commit/agentic/prompts/system.md +0 -38
  202. package/src/commit/agentic/state.ts +0 -69
  203. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  204. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  205. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  206. package/src/commit/agentic/tools/git-overview.ts +0 -84
  207. package/src/commit/agentic/tools/index.ts +0 -56
  208. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  209. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  210. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  211. package/src/commit/agentic/tools/split-commit.ts +0 -280
  212. package/src/commit/agentic/topo-sort.ts +0 -44
  213. package/src/commit/agentic/trivial.ts +0 -51
  214. package/src/commit/agentic/validation.ts +0 -200
  215. package/src/commit/analysis/conventional.ts +0 -165
  216. package/src/commit/analysis/index.ts +0 -4
  217. package/src/commit/analysis/scope.ts +0 -242
  218. package/src/commit/analysis/summary.ts +0 -112
  219. package/src/commit/analysis/validation.ts +0 -66
  220. package/src/commit/changelog/detect.ts +0 -37
  221. package/src/commit/changelog/generate.ts +0 -110
  222. package/src/commit/changelog/index.ts +0 -234
  223. package/src/commit/changelog/parse.ts +0 -44
  224. package/src/commit/cli.ts +0 -93
  225. package/src/commit/git/diff.ts +0 -148
  226. package/src/commit/git/errors.ts +0 -9
  227. package/src/commit/git/index.ts +0 -211
  228. package/src/commit/git/operations.ts +0 -54
  229. package/src/commit/index.ts +0 -5
  230. package/src/commit/map-reduce/index.ts +0 -64
  231. package/src/commit/map-reduce/map-phase.ts +0 -178
  232. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  233. package/src/commit/map-reduce/utils.ts +0 -9
  234. package/src/commit/message.ts +0 -11
  235. package/src/commit/model-selection.ts +0 -69
  236. package/src/commit/pipeline.ts +0 -243
  237. package/src/commit/prompts/analysis-system.md +0 -148
  238. package/src/commit/prompts/analysis-user.md +0 -38
  239. package/src/commit/prompts/changelog-system.md +0 -50
  240. package/src/commit/prompts/changelog-user.md +0 -18
  241. package/src/commit/prompts/file-observer-system.md +0 -24
  242. package/src/commit/prompts/file-observer-user.md +0 -8
  243. package/src/commit/prompts/reduce-system.md +0 -50
  244. package/src/commit/prompts/reduce-user.md +0 -17
  245. package/src/commit/prompts/summary-retry.md +0 -3
  246. package/src/commit/prompts/summary-system.md +0 -38
  247. package/src/commit/prompts/summary-user.md +0 -13
  248. package/src/commit/prompts/types-description.md +0 -2
  249. package/src/commit/types.ts +0 -109
  250. package/src/commit/utils/exclusions.ts +0 -42
  251. package/src/mcp/render.ts +0 -123
  252. package/src/modes/components/agent-dashboard.ts +0 -1130
  253. package/src/modes/components/codemode-group.ts +0 -369
  254. package/src/modes/components/read-tool-group.ts +0 -119
  255. package/src/modes/components/visual-truncate.ts +0 -63
  256. package/src/prompts/system/subagent-user-prompt.md +0 -8
  257. package/src/prompts/tools/ask.md +0 -44
  258. package/src/prompts/tools/bash.md +0 -24
  259. package/src/prompts/tools/browser.md +0 -33
  260. package/src/prompts/tools/calculator.md +0 -12
  261. package/src/prompts/tools/explore.md +0 -29
  262. package/src/prompts/tools/fetch.md +0 -16
  263. package/src/prompts/tools/find.md +0 -18
  264. package/src/prompts/tools/gemini-image.md +0 -23
  265. package/src/prompts/tools/grep.md +0 -28
  266. package/src/prompts/tools/hashline.md +0 -232
  267. package/src/prompts/tools/librarian.md +0 -24
  268. package/src/prompts/tools/lsp.md +0 -28
  269. package/src/prompts/tools/oracle.md +0 -26
  270. package/src/prompts/tools/patch.md +0 -74
  271. package/src/prompts/tools/python.md +0 -66
  272. package/src/prompts/tools/read.md +0 -36
  273. package/src/prompts/tools/replace.md +0 -38
  274. package/src/prompts/tools/reviewer.md +0 -41
  275. package/src/prompts/tools/ssh.md +0 -51
  276. package/src/prompts/tools/task-summary.md +0 -28
  277. package/src/prompts/tools/task.md +0 -146
  278. package/src/prompts/tools/todo-write.md +0 -65
  279. package/src/prompts/tools/undo-edit.md +0 -7
  280. package/src/prompts/tools/web-search.md +0 -19
  281. package/src/prompts/tools/write.md +0 -18
  282. package/src/task/batch.ts +0 -102
  283. package/src/task/discovery.ts +0 -126
  284. package/src/task/parallel.ts +0 -84
  285. package/src/task/template.ts +0 -32
  286. package/src/tools/calculator.ts +0 -537
  287. package/src/tools/jtd-to-typescript.ts +0 -198
  288. package/src/tools/renderers.ts +0 -60
  289. package/src/tools/tool-result.ts +0 -86
  290. /package/src/{modes/theme → theme}/dark.json +0 -0
  291. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  292. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  293. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  294. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  295. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  296. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  297. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  298. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  299. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  300. /package/src/{modes/theme → theme}/light.json +0 -0
  301. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  302. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  303. /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) {
@@ -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
+ }