Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ When package/source access is enabled for the current token, GitHits also expose
| `search_symbols` | Exact-token search inside indexed dependency source |
| `list_files` | Discover what files a dependency or repo contains |
| `read_file` | Read a dependency file by path |
| `grep_file` | Search for a case-insensitive substring within one file |
| `grep_repo` | Deterministic text grep across indexed dependency or repo files |

These advanced tools remain feature-gated. The MCP server advertises them only when the authenticated token is entitled to package/source access.

Expand Down
24 changes: 12 additions & 12 deletions docs/implementation/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ The CLI exposes four primary top-level commands: `example`, `languages`, and `fe
| `pkg changelog [spec]` | package spec OR `--repo-url` | `--from`, `--to`, `--limit`, `--git-ref`, `--no-body`, `--verbose`, `--json` | Release notes / changelog entries for a package or GitHub repo (GitHub Releases, CHANGELOG.md, or HexDocs). Default shows each entry with a 10-line body preview; `--verbose` uncaps, `--no-body` drops. |
| `code files [spec] [path-prefix]` | package spec OR `--repo-url` + `--git-ref`; optional `[path-prefix]` | `--limit`, `--wait`, `--verbose`, `--json` | List files in an indexed dependency. `[path-prefix]` is a literal directory prefix (not a glob). Plain output is one path per line; `--verbose` adds language / type / size annotations. Indexing-retry via `--wait` or the `availableVersions` hint in the error envelope. |
| `code read <spec?> <path>` | package spec OR `--repo-url` + `--git-ref`; plus `<path>` | `--lines`, `--start`, `--end`, `--wait`, `--verbose`, `--json` | Read a file's contents. Plain output is the raw file bytes (pipe-friendly); `--verbose` adds a header and a line-number gutter. `--lines 10-40` concise form; `--start`/`--end` equivalent. Binary files show a sentinel line. |
| `code grep <spec?> <pattern> <path>` | package spec OR `--repo-url` + `--git-ref`; plus `<pattern>` and `<path>` | `--context`, `--limit`, `--wait`, `--verbose`, `--json` | Search within a single file for a case-insensitive substring (not regex). Plain output is matching lines only (pipe-friendly, `grep`-style); `--verbose` adds a header and a line-number gutter with `>` markers on match lines. `--context <n>` adds surrounding lines (default 0, up to 10); overlapping blocks merge without duplicates. Max 200-char pattern; up to 200 matches. |
| `code grep [spec] <pattern> [path-prefix]` | package spec OR `--repo-url` + `--git-ref`; plus `<pattern>` and optional `[path-prefix]` | `--path`, repeatable `--glob`, repeatable `--ext`, `--regex`, `--case-sensitive`, `-C/-A/-B`, `--exclude-docs`, `--exclude-tests`, `--limit`, `--per-file-limit`, `--cursor`, `--wait`, `--verbose`, `--json` | Deterministic text grep over indexed dependency or repository source. Defaults to whole-target, literal, case-insensitive matching; narrow with `[path-prefix]`, `--path`, `--glob`, or `--ext`. Plain output is `file:line:text`; `--verbose` groups matches by file. |

### `githits init`

Expand Down Expand Up @@ -315,30 +315,30 @@ Reads a file from an indexed dependency. `<path>` is package-relative in spec mo
### `githits code grep`

```
githits code grep npm:express express lib/express.js
githits code grep npm:express express lib/express.js --context 2 # merged blocks
githits code grep npm:express express lib/express.js --verbose # + header + gutter + `>` marker
githits code grep --repo-url https://github.com/expressjs/express --git-ref main export lib/express.js
githits code grep npm:express express lib/express.js --json
githits code grep npm:express middleware
githits code grep npm:express middleware src/ -C 2
githits code grep npm:express "router\\.(use|get)" --regex --glob 'lib/**/*.js'
githits code grep --repo-url https://github.com/expressjs/express --git-ref main export lib/
githits code grep npm:express middleware --path lib/express.js --json
```

Case-insensitive **substring** search inside a single file — not regex. Max pattern 200 chars; up to 200 matches with up to 10 context lines each. For symbol-shaped searches use `githits code search` (backed by `search_symbols`).
Deterministic text grep over indexed dependency or repository source. Defaults to case-insensitive literal matching across the whole target. Pass `[path-prefix]`, `--path`, `--glob`, or `--ext` to narrow scope. `--regex` switches to RE2 regex mode. Max pattern 200 chars. For discovery and ranking, use top-level `githits search` instead.

**Plain output (default).** Matching lines only, one per line on stdout — mirrors `grep`'s default. `--context <n>` (0–10, default **0**) adds surrounding lines; nearby matches whose contexts touch or overlap merge into a single block with no duplicated lines. Distinct blocks are separated by `--` on its own line, matching `grep -C` / `rg -C` convention.
**Plain output (default).** One `file:line:text` record per match on stdout, pipe-friendly and deterministic. `-C/--context`, `-A/--after-context`, and `-B/--before-context` add surrounding lines. Distinct match groups are separated by `--`.

**`--verbose`.** Adds header, right-aligned line-number gutter, and a `>` marker on match lines so they're distinguishable from context at a glance.
**`--verbose`.** Adds a summary header and grouped file sections with a `>` marker on match lines.

**`stdout` vs `stderr` routing (plain mode).** "More matches available" truncation warning goes to **stderr**. When a zero-match pattern looks like a regex attempt (`\bfoo\b`, `^start`, character classes, etc.) a one-line nudge — "Note: pattern matched literally — this tool does case-insensitive substring search, not regex." — also goes to stderr. Pipes stay clean; humans still see the hints.
**`stdout` vs `stderr` routing (plain mode).** The pagination hint for `nextCursor` goes to **stderr** so stdout stays machine-friendly.

**Exit codes (grep-compatible).**

- `0` — at least one match.
- `1` — zero matches. Fires in both plain and `--json` modes so scripting (`if code grep X file; then …`) behaves consistently across surfaces.
- `2` — error (missing file, indexing, invalid arguments, backend failure). Distinguished from "no match" so scripts can branch correctly.

This is the standard `grep(1)` contract; the tool adopts it deliberately because its output shape mirrors grep's.
This is still the standard `grep(1)` contract even though the output includes file paths by default.

**Regex pattern note.** The `GREP_PATTERN_SEMANTICS_NOTE` string ("Case-insensitive substring matching. NOT regex — …") is shared verbatim across the CLI help text, the MCP tool description, and the MCP `pattern` argument's `describe` so the three surfaces never disagree about pattern semantics.
**Pattern note.** The `GREP_REPO_PATTERN_NOTE` string is shared verbatim across the CLI help text, the MCP tool description, and the MCP `pattern` argument's `describe` so the three surfaces never disagree about literal-vs-regex semantics.

## Architecture

Expand Down
30 changes: 14 additions & 16 deletions docs/implementation/mcp-cli-parity.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,11 @@ When a new tool lands with both MCP and CLI surfaces:
| `src/shared/list-files-response.ts` | JSON envelope builder for `list_files` (shared); terminal formatter (CLI-only). Resolves the `hasMore` → `N+` header behaviour. |
| `src/shared/read-file-request.ts` | Shared request builder for `read_file`; trims filePath, validates start/end line positive-integer rules, rejects reversed ranges. |
| `src/shared/read-file-response.ts` | JSON envelope builder for `read_file` (shared); terminal formatter (CLI-only). Normalises the envelope key to `path` (not `filePath`) so `list_files` → `read_file` chains without renames. |
| `src/shared/grep-file-request.ts` | Shared request builder for `grep_file`; exports `GREP_PATTERN_SEMANTICS_NOTE` referenced by MCP description, MCP `pattern` describe, and CLI help. Also exports `looksLikeRegexAttempt` heuristic. |
| `src/shared/grep-file-response.ts` | JSON envelope builder for `grep_file` (shared); terminal formatter (CLI-only) owns the regex-char empty-result nudge. |
| `src/shared/grep-repo-request.ts` | Shared request builder for `grep_repo`; exports `GREP_REPO_PATTERN_NOTE` referenced by MCP description, MCP `pattern` describe, and CLI help. Compiles public scope inputs into backend `pathSelectors` and applies internal `allowUnscoped` when no scope filters are given. |
| `src/shared/grep-repo-response.ts` | JSON envelope builder for `grep_repo` (shared); terminal formatter (CLI-only) renders plain `file:line:text` or verbose grouped output and surfaces pagination via stderr. |
| `src/shared/code-navigation-error-map.ts` | `mapCodeNavigationError` classifier. Owns the `INDEXING` / `FILE_NOT_FOUND` / `NOT_FOUND` codes shared across all four code-nav tools. |
| `src/shared/code-navigation-defaults.ts` | `DEFAULT_WAIT_TIMEOUT_MS = 20_000` + `MAX_WAIT_TIMEOUT_MS = 60_000`. Both CLI and MCP request builders import these so defaults never diverge. |
| `src/tools/code-navigation-shared.ts` | `codeTargetSchema` + `resolveCodeTarget` — the single addressing primitive used by `search_symbols`, `list_files`, `read_file`, `grep_file`. |
| `src/tools/code-navigation-shared.ts` | `codeTargetSchema` + `resolveCodeTarget` — the single addressing primitive used by `search_symbols`, `list_files`, `read_file`, `grep_repo`. |
| `src/shared/package-intelligence-error-map.ts` | `mapPackageIntelligenceError` classifier (reuses `MappedError` from the code-nav map). |
| `src/services/promote-version-not-found.ts` | Shared helper that promotes generic backend errors with "no matching version" messages into typed `VERSION_NOT_FOUND`. Used by the `packageVulnerabilities`, `packageDependencies`, and `packageChangelog` executors. Handles both `version` (single-version queries) and `fromVersion` / `toVersion` (range queries), and skips `details.package` synthesis when registry/name aren't available (repo-URL mode). |
| `src/tools/search-symbols.ts` | MCP tool definition for `search_symbols`. |
Expand All @@ -190,7 +190,7 @@ When a new tool lands with both MCP and CLI surfaces:
| `src/tools/package-changelog.ts` | MCP tool definition for `package_changelog`. |
| `src/tools/list-files.ts` | MCP tool definition for `list_files`. |
| `src/tools/read-file.ts` | MCP tool definition for `read_file`. |
| `src/tools/grep-file.ts` | MCP tool definition for `grep_file`. |
| `src/tools/grep-repo.ts` | MCP tool definition for `grep_repo`. |
| `src/commands/code/search-symbols.ts` | CLI command. |
| `src/commands/search.ts` | Top-level CLI commands for unified `search` and `search-status`. |
| `src/commands/pkg/info.ts` | CLI command for `pkg info`. |
Expand All @@ -207,7 +207,7 @@ When a new tool lands with both MCP and CLI surfaces:
| `src/tools/package-changelog-parity.test.ts` | Parity tests for `package_changelog` (cite rule IDs). |
| `src/tools/list-files-parity.test.ts` | Parity tests for `list_files` (cite rule IDs). |
| `src/tools/read-file-parity.test.ts` | Parity tests for `read_file` (cite rule IDs). |
| `src/tools/grep-file-parity.test.ts` | Parity tests for `grep_file` (cite rule IDs). |
| `src/tools/grep-repo-parity.test.ts` | Parity tests for `grep_repo` (cite rule IDs). |

## Per-tool notes

Expand Down Expand Up @@ -408,7 +408,7 @@ When a new tool lands with both MCP and CLI surfaces:
- `toMatchObject` for builder-sourced `INVALID_ARGUMENT` cases:
`<spec>@<version>` rejection, `--from` + `--limit` mutex.

### `list_files` / `read_file` / `grep_file` (file-exploration bundle)
### `list_files` / `read_file` / `grep_repo` (file-exploration bundle)

All three reuse `codeTargetSchema` + `resolveCodeTarget` from
`src/tools/code-navigation-shared.ts`. The indexing lifecycle is
Expand All @@ -431,17 +431,15 @@ so envelope-drift surfaces in the test rather than at an agent.
on the backend doesn't return `availableVersions` on
INDEXING responses, so its `details` block carries only
`indexingRef` — MCP description calls this out explicitly.
- **`grep_file`**: `GREP_PATTERN_SEMANTICS_NOTE` constant
(exported from `grep-file-request.ts`) ensures the
substring-only disclosure is identical in the MCP
- **`grep_repo`**: `GREP_REPO_PATTERN_NOTE` constant
(exported from `grep-repo-request.ts`) ensures the
literal-vs-regex disclosure is identical in the MCP
description, MCP `pattern` field describe, and CLI help text.
Regex-char heuristic in the terminal formatter nudges users
who typed clearly-regex patterns; the JSON envelope never
carries this hint. Triggered signals cover `\b\B\w\W\d\D\s\S`,
escaped metacharacters, character classes, non-capturing /
lookaround / named groups / inline flags, and brace
quantifiers. Deliberately excludes bare `.`, `*`, `+`, `?`,
`^`, `$`, `|`, `(`, `)` — too common in ordinary code.
The shared request builder compiles `path`, `path_prefix`, and
`globs` into backend `pathSelectors`, keeps `allowUnscoped`
internal-only, and defaults grep to whole-target, literal,
case-insensitive matching. The shared response builder keeps CLI
`--json` and MCP payloads byte-identical for equivalent inputs.

- **Parity assertion policy** (coded in the three parity
tests):
Expand Down
Loading
Loading