@nghyane/arcane 0.1.13 → 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 (323) 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 +48 -113
  50. package/src/modes/components/bordered-loader.ts +1 -1
  51. package/src/modes/components/branch-summary-message.ts +13 -10
  52. package/src/modes/components/compaction-summary-message.ts +14 -13
  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 +49 -92
  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/frontmatter.md +1 -1
  113. package/src/prompts/agents/init.md +2 -2
  114. package/src/prompts/agents/librarian.md +30 -21
  115. package/src/prompts/agents/oracle.md +9 -2
  116. package/src/prompts/agents/reviewer.md +15 -49
  117. package/src/prompts/agents/task.md +17 -9
  118. package/src/prompts/compaction/branch-summary-context.md +1 -1
  119. package/src/prompts/compaction/branch-summary-preamble.md +1 -1
  120. package/src/prompts/compaction/branch-summary.md +4 -1
  121. package/src/prompts/compaction/compaction-short-summary.md +1 -1
  122. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  123. package/src/prompts/compaction/compaction-summary.md +4 -1
  124. package/src/prompts/compaction/compaction-turn-prefix.md +1 -1
  125. package/src/prompts/compaction/compaction-update-summary.md +1 -1
  126. package/src/prompts/memories/consolidation.md +1 -1
  127. package/src/prompts/memories/read_path.md +1 -1
  128. package/src/prompts/memories/stage_one_input.md +1 -1
  129. package/src/prompts/memories/stage_one_system.md +1 -1
  130. package/src/prompts/review-request.md +1 -1
  131. package/src/prompts/system/agent-creation-architect.md +1 -1
  132. package/src/prompts/system/agent-creation-user.md +1 -1
  133. package/src/prompts/system/custom-system-prompt.md +1 -1
  134. package/src/prompts/system/file-operations.md +1 -1
  135. package/src/prompts/system/subagent-system-prompt.md +2 -2
  136. package/src/prompts/system/summarization-system.md +1 -1
  137. package/src/prompts/system/system-prompt.md +163 -178
  138. package/src/prompts/system/title-system.md +1 -1
  139. package/src/prompts/system/ttsr-interrupt.md +1 -1
  140. package/src/prompts/system/verification-reminder.md +6 -0
  141. package/src/prompts/system/web-search.md +1 -1
  142. package/src/sdk.ts +0 -9
  143. package/src/session/agent-session.ts +244 -1459
  144. package/src/session/model-controller.ts +406 -0
  145. package/src/session/retry-utils.ts +71 -0
  146. package/src/session/session-manager.ts +22 -186
  147. package/src/session/session-types.ts +312 -0
  148. package/src/session/stats.ts +387 -0
  149. package/src/session/streaming-edit.ts +258 -0
  150. package/src/session/ttsr.ts +213 -0
  151. package/src/slash-commands/builtin-registry.ts +0 -8
  152. package/src/stt/recorder.ts +2 -2
  153. package/src/system-prompt.ts +1 -14
  154. package/src/task/agents.ts +7 -33
  155. package/src/task/executor.ts +50 -438
  156. package/src/task/index.ts +104 -71
  157. package/src/task/progress-tracker.ts +390 -0
  158. package/src/task/render.ts +371 -187
  159. package/src/task/subprocess-tool-registry.ts +1 -1
  160. package/src/task/types.ts +14 -47
  161. package/src/tools/ask.ts +31 -42
  162. package/src/tools/bash-interactive.ts +2 -2
  163. package/src/tools/bash-interceptor.ts +2 -2
  164. package/src/tools/bash-normalize.ts +1 -1
  165. package/src/tools/bash-skill-urls.ts +2 -2
  166. package/src/tools/bash.ts +87 -136
  167. package/src/tools/browser.ts +54 -84
  168. package/src/tools/create-tools.ts +186 -0
  169. package/src/tools/default-renderer.ts +104 -0
  170. package/src/tools/explore.ts +11 -10
  171. package/src/tools/fetch.ts +24 -114
  172. package/src/tools/find.ts +48 -132
  173. package/src/tools/gemini-image.ts +5 -15
  174. package/src/tools/github.ts +450 -0
  175. package/src/tools/grep.ts +43 -179
  176. package/src/tools/index.ts +35 -198
  177. package/src/tools/json-tree.ts +3 -3
  178. package/src/tools/librarian.ts +18 -18
  179. package/src/tools/list-limit.ts +2 -2
  180. package/src/tools/notebook.ts +35 -87
  181. package/src/tools/oracle.ts +25 -25
  182. package/src/tools/output-meta.ts +89 -4
  183. package/src/tools/output-utils.ts +2 -2
  184. package/src/tools/python.ts +86 -637
  185. package/src/tools/read.ts +36 -119
  186. package/src/tools/reviewer-tool.ts +19 -21
  187. package/src/tools/search-code.ts +128 -0
  188. package/src/tools/ssh.ts +67 -126
  189. package/src/tools/subagent-tool.ts +197 -123
  190. package/src/tools/todo-write.ts +15 -31
  191. package/src/tools/tool-errors.ts +0 -30
  192. package/src/tools/undo-edit.ts +30 -67
  193. package/src/tools/write.ts +78 -127
  194. package/src/tui/code-cell.ts +4 -4
  195. package/src/tui/file-list.ts +2 -2
  196. package/src/tui/output-block.ts +1 -1
  197. package/src/tui/status-line.ts +1 -1
  198. package/src/tui/tree-list.ts +2 -2
  199. package/src/tui/types.ts +1 -1
  200. package/src/tui/utils.ts +1 -1
  201. package/src/{tools → ui}/render-utils.ts +87 -126
  202. package/src/utils/external-editor.ts +4 -4
  203. package/src/utils/file-mentions.ts +1 -1
  204. package/src/utils/index.ts +30 -0
  205. package/src/utils/tools-manager.ts +9 -19
  206. package/src/web/github-client.ts +290 -0
  207. package/src/web/scrapers/github.ts +11 -62
  208. package/src/web/search/auth.ts +1 -3
  209. package/src/web/search/index.ts +82 -46
  210. package/src/web/search/provider.ts +11 -16
  211. package/src/web/search/providers/grep.ts +160 -0
  212. package/src/web/search/render.ts +48 -235
  213. package/src/web/search/types.ts +1 -1
  214. package/src/commands/commit.ts +0 -36
  215. package/src/commit/agentic/agent.ts +0 -311
  216. package/src/commit/agentic/fallback.ts +0 -96
  217. package/src/commit/agentic/index.ts +0 -359
  218. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  219. package/src/commit/agentic/prompts/session-user.md +0 -25
  220. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  221. package/src/commit/agentic/prompts/system.md +0 -38
  222. package/src/commit/agentic/state.ts +0 -69
  223. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  224. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  225. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  226. package/src/commit/agentic/tools/git-overview.ts +0 -84
  227. package/src/commit/agentic/tools/index.ts +0 -56
  228. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  229. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  230. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  231. package/src/commit/agentic/tools/split-commit.ts +0 -280
  232. package/src/commit/agentic/topo-sort.ts +0 -44
  233. package/src/commit/agentic/trivial.ts +0 -51
  234. package/src/commit/agentic/validation.ts +0 -200
  235. package/src/commit/analysis/conventional.ts +0 -165
  236. package/src/commit/analysis/index.ts +0 -4
  237. package/src/commit/analysis/scope.ts +0 -242
  238. package/src/commit/analysis/summary.ts +0 -112
  239. package/src/commit/analysis/validation.ts +0 -66
  240. package/src/commit/changelog/detect.ts +0 -37
  241. package/src/commit/changelog/generate.ts +0 -110
  242. package/src/commit/changelog/index.ts +0 -234
  243. package/src/commit/changelog/parse.ts +0 -44
  244. package/src/commit/cli.ts +0 -93
  245. package/src/commit/git/diff.ts +0 -148
  246. package/src/commit/git/errors.ts +0 -9
  247. package/src/commit/git/index.ts +0 -211
  248. package/src/commit/git/operations.ts +0 -54
  249. package/src/commit/index.ts +0 -5
  250. package/src/commit/map-reduce/index.ts +0 -64
  251. package/src/commit/map-reduce/map-phase.ts +0 -178
  252. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  253. package/src/commit/map-reduce/utils.ts +0 -9
  254. package/src/commit/message.ts +0 -11
  255. package/src/commit/model-selection.ts +0 -69
  256. package/src/commit/pipeline.ts +0 -243
  257. package/src/commit/prompts/analysis-system.md +0 -148
  258. package/src/commit/prompts/analysis-user.md +0 -38
  259. package/src/commit/prompts/changelog-system.md +0 -50
  260. package/src/commit/prompts/changelog-user.md +0 -18
  261. package/src/commit/prompts/file-observer-system.md +0 -24
  262. package/src/commit/prompts/file-observer-user.md +0 -8
  263. package/src/commit/prompts/reduce-system.md +0 -50
  264. package/src/commit/prompts/reduce-user.md +0 -17
  265. package/src/commit/prompts/summary-retry.md +0 -3
  266. package/src/commit/prompts/summary-system.md +0 -38
  267. package/src/commit/prompts/summary-user.md +0 -13
  268. package/src/commit/prompts/types-description.md +0 -2
  269. package/src/commit/types.ts +0 -109
  270. package/src/commit/utils/exclusions.ts +0 -42
  271. package/src/mcp/render.ts +0 -123
  272. package/src/modes/components/agent-dashboard.ts +0 -1130
  273. package/src/modes/components/codemode-group.ts +0 -369
  274. package/src/modes/components/read-tool-group.ts +0 -119
  275. package/src/modes/components/visual-truncate.ts +0 -63
  276. package/src/prompts/system/subagent-user-prompt.md +0 -8
  277. package/src/prompts/tools/ask.md +0 -44
  278. package/src/prompts/tools/bash.md +0 -24
  279. package/src/prompts/tools/browser.md +0 -33
  280. package/src/prompts/tools/calculator.md +0 -12
  281. package/src/prompts/tools/explore.md +0 -29
  282. package/src/prompts/tools/fetch.md +0 -16
  283. package/src/prompts/tools/find.md +0 -18
  284. package/src/prompts/tools/gemini-image.md +0 -23
  285. package/src/prompts/tools/grep.md +0 -28
  286. package/src/prompts/tools/hashline.md +0 -232
  287. package/src/prompts/tools/librarian.md +0 -24
  288. package/src/prompts/tools/lsp.md +0 -28
  289. package/src/prompts/tools/oracle.md +0 -26
  290. package/src/prompts/tools/patch.md +0 -74
  291. package/src/prompts/tools/python.md +0 -66
  292. package/src/prompts/tools/read.md +0 -36
  293. package/src/prompts/tools/replace.md +0 -38
  294. package/src/prompts/tools/reviewer.md +0 -41
  295. package/src/prompts/tools/ssh.md +0 -51
  296. package/src/prompts/tools/task-summary.md +0 -28
  297. package/src/prompts/tools/task.md +0 -146
  298. package/src/prompts/tools/todo-write.md +0 -65
  299. package/src/prompts/tools/undo-edit.md +0 -7
  300. package/src/prompts/tools/web-search.md +0 -19
  301. package/src/prompts/tools/write.md +0 -18
  302. package/src/task/batch.ts +0 -102
  303. package/src/task/discovery.ts +0 -126
  304. package/src/task/parallel.ts +0 -84
  305. package/src/task/template.ts +0 -32
  306. package/src/tools/calculator.ts +0 -537
  307. package/src/tools/jtd-to-typescript.ts +0 -198
  308. package/src/tools/renderers.ts +0 -60
  309. package/src/tools/tool-result.ts +0 -86
  310. /package/src/{modes/theme → theme}/dark.json +0 -0
  311. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  312. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  313. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  314. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  315. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  316. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  317. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  318. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  319. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  320. /package/src/{modes/theme → theme}/light.json +0 -0
  321. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  322. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  323. /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
+ }