From da64c7d69958302a1bad495e58cb3c81b958386b Mon Sep 17 00:00:00 2001 From: Juha Litola Date: Mon, 27 Apr 2026 16:10:57 +0300 Subject: [PATCH] feat: make example language optional Allow CLI and MCP example search requests to omit language so production can infer it from the query. Update packaged agent guidance and tests to keep clients from forcing language selection. --- GEMINI.md | 6 +-- commands/example.md | 13 ++--- commands/help.md | 6 +-- commands/search.md | 13 ++--- docs/implementation/cli-commands.md | 5 +- docs/implementation/tools.md | 2 +- plugins/claude/commands/example.md | 13 ++--- plugins/claude/commands/help.md | 6 +-- plugins/claude/commands/search.md | 13 ++--- plugins/claude/skills/search/SKILL.md | 3 +- skills/search/SKILL.md | 3 +- src/cli.ts | 3 +- src/commands/example.test.ts | 18 +++++++ src/commands/example.ts | 8 ++- src/commands/mcp-instructions.ts | 2 +- src/commands/mcp.ts | 54 +++++++++++++------ src/services/code-navigation-service.test.ts | 7 --- src/services/githits-service.test.ts | 10 ++++ src/services/githits-service.ts | 2 +- .../package-intelligence-error-map.test.ts | 3 +- src/shared/pkgseer-graphql.test.ts | 3 +- src/shared/unified-search-response.ts | 1 - src/tools/get-example.test.ts | 15 ++++++ src/tools/get-example.ts | 5 +- src/tools/grep-repo.ts | 5 -- src/tools/package-summary-parity.test.ts | 5 +- 26 files changed, 141 insertions(+), 83 deletions(-) diff --git a/GEMINI.md b/GEMINI.md index 30e6c02c..d3e8474b 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -11,12 +11,12 @@ Find code examples from open source repositories. **Parameters:** - `query` (string, required) - natural language description of what you need -- `language` (string, required) - programming language name (use `search_language` to verify) +- `language` (string, optional) - programming language name; omit it to let GitHits infer the language from the query - `license_mode` (string, optional) - one of `strict` (default), `yolo`, or `custom` ### search_language -Look up supported programming language names. Use this before calling `get_example` to get the correct language identifier. +Look up supported programming language names. Use this before calling `get_example` only when you need to force a specific language and the exact name is uncertain. **Parameters:** @@ -60,7 +60,7 @@ Do not use `get_example` for: ## How to Search Well -- Call `search_language` first to confirm the correct language name before calling `get_example` +- Pass `language` only when you need to force a specific language; call `search_language` first if the exact language name is uncertain - Formulate queries as natural language questions (e.g., "How to stream responses with the Vercel AI SDK in Next.js") - Include specific error messages, library names, or API names when relevant - Keep queries focused: 3-4 technical terms maximum diff --git a/commands/example.md b/commands/example.md index 50ef562d..cfc7a72d 100644 --- a/commands/example.md +++ b/commands/example.md @@ -6,16 +6,17 @@ description: Search for canonical code examples from open source via GitHits Search for code examples using GitHits for the query: "$ARGUMENTS" -Use the GitHits MCP `get_example` tool with the user's query. The tool requires two -parameters: +Use the GitHits MCP `get_example` tool with the user's query. + +Required parameter: - **query**: The user's search query, formulated in natural language. -- **language**: The programming language. If the language is unclear from - context, use the `search_language` tool first to find the correct language - name. -Optional parameter: +Optional parameters: +- **language**: The programming language. Omit it to let GitHits infer the + language from the query. If you need to force a specific language and the + exact name is uncertain, use the `search_language` tool first. - **license_mode**: `"strict"` (default, excludes copyleft), `"yolo"` (all licenses), or `"custom"` (user's blocklist). diff --git a/commands/help.md b/commands/help.md index 0c1fd1ee..0e7d8235 100644 --- a/commands/help.md +++ b/commands/help.md @@ -28,9 +28,9 @@ context summary: This plugin connects to the GitHits MCP server and always exposes three core tools: - **get_example** — Find code examples by describing what you need in natural - language. Requires `query` and `language` parameters. -- **search_language** — Look up supported programming language names before - searching. + language. Requires `query`; `language` is optional and inferred when omitted. +- **search_language** — Look up supported programming language names when you + need to force a specific language. - **feedback** — Rate a search result to improve future quality. Additional indexed dependency/package tools such as `search`, `package_summary`, diff --git a/commands/search.md b/commands/search.md index 0e16f7b7..948e363b 100644 --- a/commands/search.md +++ b/commands/search.md @@ -8,16 +8,17 @@ Use GitHits example search for the query: "$ARGUMENTS" This slash command is the older alias for `/githits:example`. -Use the GitHits MCP `get_example` tool with the user's query. The tool requires two -parameters: +Use the GitHits MCP `get_example` tool with the user's query. + +Required parameter: - **query**: The user's search query, formulated in natural language. -- **language**: The programming language. If the language is unclear from - context, use the `search_language` tool first to find the correct language - name. -Optional parameter: +Optional parameters: +- **language**: The programming language. Omit it to let GitHits infer the + language from the query. If you need to force a specific language and the + exact name is uncertain, use the `search_language` tool first. - **license_mode**: `"strict"` (default, excludes copyleft), `"yolo"` (all licenses), or `"custom"` (user's blocklist). diff --git a/docs/implementation/cli-commands.md b/docs/implementation/cli-commands.md index 91b0e9d6..4a29f4b3 100644 --- a/docs/implementation/cli-commands.md +++ b/docs/implementation/cli-commands.md @@ -9,7 +9,7 @@ The CLI exposes three always-on top-level commands: `example`, `languages`, and | Command | Required Args | Options | Description | |---|---|---|---| | `init` | — | `-y, --yes`, `--skip-login` | Authenticate and set up MCP server for coding agents | -| `example ` | `-l, --lang ` | `--license `, `--explain`, `--json` | Search for code examples | +| `example ` | `` | `-l, --lang `, `--license `, `--explain`, `--json` | Search for code examples | | `search ` | `--in ` | `--source `, `--kind `, `--category `, `--path-prefix `, `--intent `, `--public`, `--name `, `--lang `, `--allow-partial`, `--limit `, `--offset `, `--wait `, `--json` | Unified indexed search across dependency/repository code, docs, and symbols | | `search-status ` | `` | `--json` | Check progress, fetch partial hits, or fetch final results for a prior unified search | | `languages [query]` | — | `--json` | List or filter supported languages | @@ -41,13 +41,14 @@ The command uses `createContainer()` lazily for the login step. Tool detection a ### `githits example` ``` +githits example "how to use express middleware" githits example "how to use express middleware" --lang javascript githits example "async file reading" -l python --license yolo githits example "react hooks patterns" -l typescript --explain githits example "react hooks patterns" -l typescript --json ``` -Default output is markdown (the API response). With `--explain`, an AI-generated explanation is included alongside the code example. With `--json`, output is `{ "result": "", "solution_id": "" }` (`solution_id` is omitted only if the markdown lacks a solution URL — pass it back to `feedback`). The MCP `get_example` tool always sends `include_explanation: false` since LLMs don't need the extra context. +Default output is markdown (the API response). `--lang` is optional; when omitted, the backend infers the language from the query. With `--explain`, an AI-generated explanation is included alongside the code example. With `--json`, output is `{ "result": "", "solution_id": "" }` (`solution_id` is omitted only if the markdown lacks a solution URL — pass it back to `feedback`). The MCP `get_example` tool always sends `include_explanation: false` since LLMs don't need the extra context. ### `githits search` diff --git a/docs/implementation/tools.md b/docs/implementation/tools.md index f9c59385..3be1a2b6 100644 --- a/docs/implementation/tools.md +++ b/docs/implementation/tools.md @@ -19,7 +19,7 @@ Both expose the same tools with identical names, parameters, and descriptions. T | Tool | Parameters | Description | |---|---|---| -| `get_example` | `query`, `language`, `license_mode?` | Search for canonical code examples. Returns markdown-formatted results. | +| `get_example` | `query`, `language?`, `license_mode?` | Search for canonical code examples. Returns markdown-formatted results. If `language` is omitted, the backend infers it from the query. | | `search_language` | `query` | Find supported programming language names before searching. | | `feedback` | `solution_id`, `accepted`, `feedback_text?` | Submit feedback on a search result to improve quality. | | `search` | `query`, `target?`, `targets?`, `sources?`, `category?`, `kind?`, `path_prefix?`, `file_intent?`, `public_only?`, `name?`, `language?`, `allow_partial_results?`, `limit?`, `offset?`, `wait_timeout_ms?` | Unified indexed dependency/repository discovery search across code, docs, and symbols. Omit `file_intent` to search across all intents; set it only when you want to narrow results, and note that some sources may ignore it and report that in `sourceStatus`. Prefer `sources:["symbol"]` for symbol-shaped unified search. Complete-by-default; set `allow_partial_results: true` to receive available partial hits while indexing continues. | diff --git a/plugins/claude/commands/example.md b/plugins/claude/commands/example.md index 50ef562d..cfc7a72d 100644 --- a/plugins/claude/commands/example.md +++ b/plugins/claude/commands/example.md @@ -6,16 +6,17 @@ description: Search for canonical code examples from open source via GitHits Search for code examples using GitHits for the query: "$ARGUMENTS" -Use the GitHits MCP `get_example` tool with the user's query. The tool requires two -parameters: +Use the GitHits MCP `get_example` tool with the user's query. + +Required parameter: - **query**: The user's search query, formulated in natural language. -- **language**: The programming language. If the language is unclear from - context, use the `search_language` tool first to find the correct language - name. -Optional parameter: +Optional parameters: +- **language**: The programming language. Omit it to let GitHits infer the + language from the query. If you need to force a specific language and the + exact name is uncertain, use the `search_language` tool first. - **license_mode**: `"strict"` (default, excludes copyleft), `"yolo"` (all licenses), or `"custom"` (user's blocklist). diff --git a/plugins/claude/commands/help.md b/plugins/claude/commands/help.md index 0c1fd1ee..0e7d8235 100644 --- a/plugins/claude/commands/help.md +++ b/plugins/claude/commands/help.md @@ -28,9 +28,9 @@ context summary: This plugin connects to the GitHits MCP server and always exposes three core tools: - **get_example** — Find code examples by describing what you need in natural - language. Requires `query` and `language` parameters. -- **search_language** — Look up supported programming language names before - searching. + language. Requires `query`; `language` is optional and inferred when omitted. +- **search_language** — Look up supported programming language names when you + need to force a specific language. - **feedback** — Rate a search result to improve future quality. Additional indexed dependency/package tools such as `search`, `package_summary`, diff --git a/plugins/claude/commands/search.md b/plugins/claude/commands/search.md index 0e16f7b7..948e363b 100644 --- a/plugins/claude/commands/search.md +++ b/plugins/claude/commands/search.md @@ -8,16 +8,17 @@ Use GitHits example search for the query: "$ARGUMENTS" This slash command is the older alias for `/githits:example`. -Use the GitHits MCP `get_example` tool with the user's query. The tool requires two -parameters: +Use the GitHits MCP `get_example` tool with the user's query. + +Required parameter: - **query**: The user's search query, formulated in natural language. -- **language**: The programming language. If the language is unclear from - context, use the `search_language` tool first to find the correct language - name. -Optional parameter: +Optional parameters: +- **language**: The programming language. Omit it to let GitHits infer the + language from the query. If you need to force a specific language and the + exact name is uncertain, use the `search_language` tool first. - **license_mode**: `"strict"` (default, excludes copyleft), `"yolo"` (all licenses), or `"custom"` (user's blocklist). diff --git a/plugins/claude/skills/search/SKILL.md b/plugins/claude/skills/search/SKILL.md index b4e1c3ee..1317b7e6 100644 --- a/plugins/claude/skills/search/SKILL.md +++ b/plugins/claude/skills/search/SKILL.md @@ -28,7 +28,8 @@ Authentication: Guidelines: - Prefer existing search context if it already answers the problem. -- Use `search_language` first when language naming is uncertain. +- Pass `language` only when you need to force a specific language; use + `search_language` first if the exact language name is uncertain. - Use `get_example` for one focused example-search question at a time. - When the task is about indexed dependency or repository internals and the capability-gated tools are available, prefer unified `search` instead of diff --git a/skills/search/SKILL.md b/skills/search/SKILL.md index b4e1c3ee..1317b7e6 100644 --- a/skills/search/SKILL.md +++ b/skills/search/SKILL.md @@ -28,7 +28,8 @@ Authentication: Guidelines: - Prefer existing search context if it already answers the problem. -- Use `search_language` first when language naming is uncertain. +- Pass `language` only when you need to force a specific language; use + `search_language` first if the exact language name is uncertain. - Use `get_example` for one focused example-search question at a time. - When the task is about indexed dependency or repository internals and the capability-gated tools are available, prefer unified `search` instead of diff --git a/src/cli.ts b/src/cli.ts index c8cd5c42..13dd0eb0 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -61,7 +61,7 @@ Getting started: githits init Set up MCP for your coding agents githits login Authenticate with your GitHits account githits mcp Show MCP setup instructions - githits example "query" -l python Get code examples + githits example "query" Get code examples Learn more at https://githits.com Docs: https://app.githits.com/docs/ @@ -84,7 +84,6 @@ registerLanguagesCommand(program); registerFeedbackCommand(program); const argv = process.argv.slice(2); const registrationArgv = stripRootRegistrationOptions(argv); -const helpInvocation = isHelpInvocation(registrationArgv); const shouldLoadGatedHelpRegistration = needsGatedHelpRegistration(registrationArgv); const helpRegistrationOptions = shouldLoadGatedHelpRegistration diff --git a/src/commands/example.test.ts b/src/commands/example.test.ts index 69b4d8ec..1b2c066c 100644 --- a/src/commands/example.test.ts +++ b/src/commands/example.test.ts @@ -39,6 +39,24 @@ describe("exampleAction", () => { consoleSpy.mockRestore(); }); + it("calls service without language when --lang is omitted", async () => { + const searchFn = mock(() => Promise.resolve("result")); + const deps = createDeps({ + githitsService: createMockGitHitsService({ search: searchFn }), + }); + const consoleSpy = spyOn(console, "log").mockImplementation(() => {}); + + await exampleAction("hello world", {}, deps); + + expect(searchFn).toHaveBeenCalledWith({ + query: "hello world", + language: undefined, + licenseMode: undefined, + includeExplanation: undefined, + }); + consoleSpy.mockRestore(); + }); + it("outputs JSON when --json flag provided", async () => { const consoleSpy = spyOn(console, "log").mockImplementation(() => {}); diff --git a/src/commands/example.ts b/src/commands/example.ts index 03e43c87..45a701c9 100644 --- a/src/commands/example.ts +++ b/src/commands/example.ts @@ -4,7 +4,7 @@ import { extractSolutionId } from "../shared/extract-solution-id.js"; import { AuthRequiredError, requireAuth } from "../shared/require-auth.js"; export interface ExampleOptions { - lang: string; + lang?: string; license?: "strict" | "yolo" | "custom"; explain?: boolean; json?: boolean; @@ -53,6 +53,7 @@ const EXAMPLE_DESCRIPTION = `Get verified, canonical code examples from global o For dependency, package, or repository source search, use \`githits search\` instead. Examples: + githits example "how to use express middleware" githits example "how to use express middleware" --lang javascript githits example "async file reading" -l python --license yolo githits example "react hooks patterns" -l typescript --explain @@ -64,7 +65,10 @@ export function registerExampleCommand(program: Command) { .summary("Get code examples from global open source") .description(EXAMPLE_DESCRIPTION) .argument("", "Natural language example-search query") - .requiredOption("-l, --lang ", "Programming language") + .option( + "-l, --lang ", + "Optional programming language; omitted values are inferred by GitHits", + ) .addOption( new Option("--license ", "License filter mode") .choices(["strict", "yolo", "custom"]) diff --git a/src/commands/mcp-instructions.ts b/src/commands/mcp-instructions.ts index 910d2e79..5377034f 100644 --- a/src/commands/mcp-instructions.ts +++ b/src/commands/mcp-instructions.ts @@ -17,7 +17,7 @@ import type { Dependencies } from "../container.js"; const CORE_BLOCK = `GitHits surfaces verified, canonical code examples from global open source. Use it when you're stuck, the user is frustrated by repeated failed attempts, you need up-to-date API usage, or the user mentions GitHits. -Workflow: call \`search_language\` first if the language name is uncertain → call \`get_example\` with one focused question → send \`feedback\` on the returned solution_id so quality improves. Each search addresses a single issue; reuse context from prior results before re-searching.`; +Workflow: call \`get_example\` with one focused question, optionally passing \`language\` when the desired language is known; call \`search_language\` first only if you need to force a language and the exact name is uncertain. Send \`feedback\` on the returned solution_id so quality improves. Each search addresses a single issue; reuse context from prior results before re-searching.`; const PACKAGE_TOOLS_PREAMBLE = `Package tools work with third-party dependency source plus registry metadata. Use them when a stack trace points into a dependency, you need to verify how a library actually works, or you're evaluating whether to add or upgrade a package. diff --git a/src/commands/mcp.ts b/src/commands/mcp.ts index 28bc67a6..641b3f62 100644 --- a/src/commands/mcp.ts +++ b/src/commands/mcp.ts @@ -24,6 +24,7 @@ import { createSearchStatusTool, createSearchTool, type ToolDefinition, + type ZodRawShape, } from "../tools/index.js"; import { buildMcpInstructions, @@ -35,37 +36,58 @@ import { */ export function getMcpToolDefinitions( deps: Dependencies, -): ToolDefinition[] { - const tools: ToolDefinition[] = [ - createGetExampleTool(deps.githitsService), - createSearchLanguageTool(deps.githitsService), - createFeedbackTool(deps.githitsService), +): ToolDefinition[] { + const tools: ToolDefinition[] = [ + eraseTool(createGetExampleTool(deps.githitsService)), + eraseTool(createSearchLanguageTool(deps.githitsService)), + eraseTool(createFeedbackTool(deps.githitsService)), ]; const gateOpen = isPackageToolsCapabilityOpen(deps); if (gateOpen && deps.codeNavigationService) { - tools.push(createSearchTool(deps.codeNavigationService)); - tools.push(createSearchStatusTool(deps.codeNavigationService)); - tools.push(createListFilesTool(deps.codeNavigationService)); - tools.push(createReadFileTool(deps.codeNavigationService)); - tools.push(createGrepRepoTool(deps.codeNavigationService)); + tools.push(eraseTool(createSearchTool(deps.codeNavigationService))); + tools.push(eraseTool(createSearchStatusTool(deps.codeNavigationService))); + tools.push(eraseTool(createListFilesTool(deps.codeNavigationService))); + tools.push(eraseTool(createReadFileTool(deps.codeNavigationService))); + tools.push(eraseTool(createGrepRepoTool(deps.codeNavigationService))); } if (gateOpen && deps.packageIntelligenceService) { - tools.push(createListPackageDocsTool(deps.packageIntelligenceService)); - tools.push(createReadPackageDocTool(deps.packageIntelligenceService)); - tools.push(createPackageSummaryTool(deps.packageIntelligenceService)); tools.push( - createPackageVulnerabilitiesTool(deps.packageIntelligenceService), + eraseTool(createListPackageDocsTool(deps.packageIntelligenceService)), + ); + tools.push( + eraseTool(createReadPackageDocTool(deps.packageIntelligenceService)), + ); + tools.push( + eraseTool(createPackageSummaryTool(deps.packageIntelligenceService)), + ); + tools.push( + eraseTool( + createPackageVulnerabilitiesTool(deps.packageIntelligenceService), + ), + ); + tools.push( + eraseTool(createPackageDependenciesTool(deps.packageIntelligenceService)), + ); + tools.push( + eraseTool(createPackageChangelogTool(deps.packageIntelligenceService)), ); - tools.push(createPackageDependenciesTool(deps.packageIntelligenceService)); - tools.push(createPackageChangelogTool(deps.packageIntelligenceService)); } return tools; } +function eraseTool( + tool: ToolDefinition, +): ToolDefinition { + return { + ...tool, + handler: (args, extra) => tool.handler(args as TArgs, extra), + }; +} + /** * Creates the MCP server with injected dependencies. */ diff --git a/src/services/code-navigation-service.test.ts b/src/services/code-navigation-service.test.ts index 7e3be1b4..2f28dc1b 100644 --- a/src/services/code-navigation-service.test.ts +++ b/src/services/code-navigation-service.test.ts @@ -11,15 +11,8 @@ import { CodeNavigationBackendError, CodeNavigationFileNotFoundError, CodeNavigationIndexingError, - CodeNavigationNetworkError, CodeNavigationServiceImpl, - CodeNavigationTargetNotFoundError, - CodeNavigationUnresolvableError, - CodeNavigationValidationError, - CodeNavigationVersionNotFoundError, - MalformedCodeNavigationResponseError, } from "./code-navigation-service.js"; -import { AuthenticationError } from "./githits-service.js"; import { createMockTokenProvider } from "./test-helpers.js"; function mockFetch(impl: () => Promise) { diff --git a/src/services/githits-service.test.ts b/src/services/githits-service.test.ts index 748e6b33..578ddfaf 100644 --- a/src/services/githits-service.test.ts +++ b/src/services/githits-service.test.ts @@ -79,6 +79,16 @@ describe("GitHitsServiceImpl", () => { expect(body.license_mode).toBe("yolo"); }); + it("omits language from JSON when not provided", async () => { + const fn = mockFetch(() => Promise.resolve(new Response("result"))); + + await service.search({ query: "test" }); + + const call = fn.mock.calls[0] as unknown as [string, RequestInit]; + const body = JSON.parse(call[1].body as string); + expect(body).not.toHaveProperty("language"); + }); + it("passes include_explanation when set", async () => { const fn = mockFetch(() => Promise.resolve(new Response("result"))); diff --git a/src/services/githits-service.ts b/src/services/githits-service.ts index 348d769e..0f373038 100644 --- a/src/services/githits-service.ts +++ b/src/services/githits-service.ts @@ -44,7 +44,7 @@ export interface Language { */ export interface SearchParams { query: string; - language: string; + language?: string; licenseMode?: "strict" | "yolo" | "custom"; includeExplanation?: boolean; } diff --git a/src/shared/package-intelligence-error-map.test.ts b/src/shared/package-intelligence-error-map.test.ts index cda8d865..ccced1e4 100644 --- a/src/shared/package-intelligence-error-map.test.ts +++ b/src/shared/package-intelligence-error-map.test.ts @@ -189,13 +189,12 @@ describe("mapPackageIntelligenceError — debug emissions", () => { process.env.GITHITS_DEBUG = "pkg-intel"; stderrLines = []; originalWrite = process.stderr.write.bind(process.stderr); - // biome-ignore lint/suspicious/noExplicitAny: test-only monkeypatch process.stderr.write = ((chunk: string | Uint8Array) => { stderrLines.push( typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk), ); return true; - }) as any; + }) as typeof process.stderr.write; }); afterEach(() => { diff --git a/src/shared/pkgseer-graphql.test.ts b/src/shared/pkgseer-graphql.test.ts index 65c49d6b..f1e78ad8 100644 --- a/src/shared/pkgseer-graphql.test.ts +++ b/src/shared/pkgseer-graphql.test.ts @@ -250,13 +250,12 @@ describe("postPkgseerGraphql", () => { const stderrLines: string[] = []; const originalWrite = process.stderr.write.bind(process.stderr); // Capture stderr for the duration of the call. - // biome-ignore lint/suspicious/noExplicitAny: test-only monkeypatch process.stderr.write = ((chunk: string | Uint8Array) => { stderrLines.push( typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk), ); return true; - }) as any; + }) as typeof process.stderr.write; try { const fetchFn = mock(() => Promise.reject(new Error("ENOTFOUND"))); diff --git a/src/shared/unified-search-response.ts b/src/shared/unified-search-response.ts index fd76fdda..be0fe4b4 100644 --- a/src/shared/unified-search-response.ts +++ b/src/shared/unified-search-response.ts @@ -1,7 +1,6 @@ import type { UnifiedSearchCompleted, UnifiedSearchHit, - UnifiedSearchIncomplete, UnifiedSearchOutcome, UnifiedSearchParams, UnifiedSearchProgress, diff --git a/src/tools/get-example.test.ts b/src/tools/get-example.test.ts index aebd16da..08ab94d8 100644 --- a/src/tools/get-example.test.ts +++ b/src/tools/get-example.test.ts @@ -34,6 +34,21 @@ describe("getExampleTool", () => { }); }); + it("allows language to be omitted", async () => { + const searchFn = mock(() => Promise.resolve("result")); + const service = createMockGitHitsService({ search: searchFn }); + const tool = createGetExampleTool(service); + + await tool.handler({ query: "test" }, {}); + + expect(searchFn).toHaveBeenCalledWith({ + query: "test", + language: undefined, + licenseMode: undefined, + includeExplanation: false, + }); + }); + it("returns error result on service failure", async () => { const service = createMockGitHitsService({ search: mock(() => Promise.reject(new Error("Network error"))), diff --git a/src/tools/get-example.ts b/src/tools/get-example.ts index 83fc20b0..6838e7bc 100644 --- a/src/tools/get-example.ts +++ b/src/tools/get-example.ts @@ -6,7 +6,7 @@ import { type ToolDefinition, textResult } from "./types.js"; interface GetExampleArgs { query: string; - language: string; + language?: string; license_mode?: "strict" | "yolo" | "custom"; } @@ -20,8 +20,9 @@ const schema = { language: z .string() .min(1) + .optional() .describe( - "Programming language. Use search_language first if the exact name is uncertain.", + "Optional programming language. If omitted, GitHits tries to infer it automatically. Use search_language first only when you need to force a specific language and the exact name is uncertain.", ), license_mode: z .enum(["strict", "yolo", "custom"]) diff --git a/src/tools/grep-repo.ts b/src/tools/grep-repo.ts index 76cf19d9..950f3b0c 100644 --- a/src/tools/grep-repo.ts +++ b/src/tools/grep-repo.ts @@ -38,11 +38,6 @@ export interface GrepRepoArgs { wait_timeout_ms?: number; } -const pathSelectorSchema = z.object({ - kind: z.enum(["exact", "prefix", "glob"]), - value: z.string(), -}); - const schema = { target: codeTargetSchema, pattern: z.string().describe(GREP_REPO_PATTERN_NOTE), diff --git a/src/tools/package-summary-parity.test.ts b/src/tools/package-summary-parity.test.ts index 65bc6691..54c796df 100644 --- a/src/tools/package-summary-parity.test.ts +++ b/src/tools/package-summary-parity.test.ts @@ -28,10 +28,7 @@ import { PackageIntelligenceBackendError, PackageIntelligenceTargetNotFoundError, } from "../services/index.js"; -import { - createMockPackageIntelligenceService, - defaultPackageSummary, -} from "../services/test-helpers.js"; +import { createMockPackageIntelligenceService } from "../services/test-helpers.js"; import { createPackageSummaryTool } from "./package-summary.js"; function cliDeps(