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
6 changes: 6 additions & 0 deletions changes/code-diff-cli-dogfood.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"githits": minor
"@githits/mcp": none
---

- **Add silent CodeDiff CLI dogfooding** - Adds `githits code diff` with bounded Git-like views, repository-relative glob filtering, reversible path quoting, apply-safe patch handling, structured completeness diagnostics, and JSON output without exposing an MCP tool or agent guidance yet.
40 changes: 40 additions & 0 deletions docs/implementation/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ The CLI exposes setup/auth commands, `doctor`, `example`, `languages`, `feedback
| `pkg upgrade-review [spec]` | single package spec with current version plus `--to`, OR repeatable `--package` ranges | `--to`, repeatable `--package`, `--no-transitive-security`, `--dependency-issues`, `--min-severity`, `--verbose`, `--json` | Compare current and target versions for upgrade evidence: vulnerabilities, changelog entries, deprecation metadata, peer changes, dependency changes, and transitive security evidence by default. Reports facts only. |
| `docs list <spec>` | package spec (optional `@version`) | `--limit`, `--after`, `--verbose`, `--json` | List hosted/crawled and repository-backed documentation pages for a package. Entries include page IDs for `docs read`; JSON includes exact repo-file follow-up metadata when available. |
| `docs read <page-id>` | page ID from `docs list` or search results | `--lines`, `--verbose`, `--json` | Read a documentation page by page ID. Default output is content-only; `--lines` fetches a bounded range for long pages. |
| `code diff <target> <from>..<to>` | unversioned package/repository target and exact range, or `--repo-url` and range | `--patch`, `--stat`, `--name-only`, `--name-status`, `--max-files`, `--max-patch-bytes`, `--verbose`, `--json`, one glob after `--` | Silently dogfood a bounded exact-tree diff; not exposed through MCP or agent guidance |
| `code files [spec] [path-prefix]` | package spec OR `--repo-url` with optional `--git-ref`; optional `[path-prefix]` | `--path`, repeatable `--glob`, repeatable `--ext`, repeatable `--file-type`, repeatable `--language`, repeatable `--file-intent`, repeatable `--exclude-intent`, `--exclude-docs`, `--exclude-tests`, `--hidden`, `--limit`, `--wait`, `--verbose`, `--json` | List files in an indexed dependency. Selectors (`[path-prefix]`, `--path`, `--glob`) are OR-ed; the other flags filter that scope down further. Plain output is one path per line; `--verbose` adds language / type / size annotations. Indexing errors include elapsed/expected duration when available plus retry via `--wait` or indexed refs/versions from the error detail. |
| `code read <spec?> <path>` | package spec OR `--repo-url` with optional `--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-prefix]` | package spec OR `--repo-url` with optional `--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`, `--symbol-field`, `--wait`, `--verbose`, `--json` | Deterministic text grep over indexed dependency or repository source. Defaults to whole-target, literal, ASCII case-insensitive matching; non-ASCII letters match case-sensitively. Narrow with `[path-prefix]`, `--path`, `--glob`, or `--ext`. Plain output is `file:line:text`; `--verbose` groups matches by file. |
Expand Down Expand Up @@ -502,6 +503,45 @@ Reads a documentation page returned by `docs list` or search results. Default ou

**Troubleshooting.** Same debug areas as the `pkg` family.

### `githits code diff`

```sh
githits code diff npm:express 4.18.1..4.18.2
githits code diff npm:express 4.18.1..4.18.2 --stat
githits code diff npm:express 4.18.1..4.18.2 --name-status -- 'lib/**/*.js'
githits code diff --repo-url https://github.com/expressjs/express v4.18.1..v4.18.2 --name-only
```

Compares two exact source trees left-to-right. Package targets must omit a
version and repository targets must omit a ref because both endpoints belong
in the required two-dot range. Three-dot merge-base syntax and `--git-ref` are
rejected. The optional value after `--` is one repository-relative bounded
glob, not a full Git pathspec. A backslash escapes one following non-slash
character according to the backend grammar.

Patch output is the default. `--stat`, `--name-only`, and `--name-status`
select cheaper views and are mutually exclusive with `--patch` and each other.
`--max-files` applies to every view; `--max-patch-bytes` is patch-only. The CLI
does not send client defaults for either bound.

The selected Git-like view stays on stdout. Completeness, truncation, scope,
content-safety, and display-only path warnings stay on stderr; `--verbose` adds
exact resolutions and scope facts there. JSON keeps the same evidence as a
lean selected-view envelope, including authoritative paths in normalized patch
headers. Text paths use reversible Git-style quoting rather than deleting
control characters. Empty authoritative diffs exit 0. Caller-selected
`--max-files` and `--max-patch-bytes` bounds may intentionally produce partial
patches and still exit 0 with warnings. Unexpectedly incomplete or non-applicable
plain patches are suppressed and exit 1; name, stat, and JSON views preserve
their structured partial evidence. Suppression diagnostics name binary and
metadata-only causes and direct terminal users to stat/name views. Patch output
is applicable unified-diff content but may omit Git metadata such as index and
mode headers. Request, auth, resolution, and backend errors also exit 1.

This is a silent dogfood surface. It is normally registered and documented for
maintainers, but no MCP tool, MCP instruction, Agent Skill, or plugin guidance
promotes it yet.

### `githits code files`

```
Expand Down
64 changes: 57 additions & 7 deletions docs/implementation/code-diff.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
## Purpose

The transport-neutral adapter exposes PkgSeer's exact-tree `codeDiff` GraphQL
operation to the public `@githits/mcp/client` runtime. It provides the typed
boundary needed by the later CLI and MCP surfaces without choosing their
ergonomics or claiming that a patch proves compatibility.
operation to the public `@githits/mcp/client` runtime. The root package also
registers `githits code diff` as an intentionally unpromoted CLI dogfood
surface. Neither layer claims that a patch proves compatibility.

Phase 1 deliberately adds no CLI command or MCP tool. Those surfaces must first
settle Git-like view names, path-glob behavior, output defaults, and parity
tests.
The CLI is being exercised before any MCP tool or agent instruction is added.
This keeps agent-facing signatures out of the public surface until the Git-like
ergonomics and evidence envelope have been dogfooded.

## Addressing and modes

Expand Down Expand Up @@ -75,12 +75,62 @@ when adopting the package version containing this adapter. The existing test
factories provide deterministic default results so current tool tests remain
focused on their own behavior.

## Silent CLI dogfood contract

The CLI accepts either an unversioned package/repository target followed by an
explicit `from..to` range, or `--repo-url <url>` followed by that range:

```sh
githits code diff npm:express 4.18.1..4.18.2
githits code diff npm:express 4.18.1..4.18.2 --name-status
githits code diff --repo-url https://github.com/expressjs/express v4.18.1..v4.18.2 -- 'lib/**/*.js'
```

The default is bounded patch output. `--patch`, `--stat`, `--name-only`, and
`--name-status` are mutually exclusive; the inventory-backed name views avoid
requesting stats or patches. One optional repository-relative glob follows
`--`. It is the backend's bounded `*`/`?`/exact-`**` grammar, not a Git
pathspec. A backslash escapes exactly one following non-slash character; this
mirrors PkgSeer's `CodeDiff.Raw.PathGlob` compiler rather than shell or Git
escaping. `--max-files` applies to every view and `--max-patch-bytes` applies
only to patch output. Omitted bounds remain absent on the wire so the backend
owns its defaults.

Plain stdout contains only the selected Git-like projection. Resolution,
scope, truncation, unprojectable-file, content-coverage, path-encoding, and
content-safety diagnostics go to stderr. `--verbose` adds exact identity and
scope diagnostics without changing the primary stream. `--json` emits a lean
camel-case data envelope whose file objects include only fields relevant to the
selected view, except that `pathEncoding` is always retained to distinguish
display-only byte escapes. Text views use reversible Git-style quoting for
control characters, quotes, and backslashes instead of changing path identity.
The response projector replaces the raw content service's `a/file` and
`b/file` patch placeholders with the authoritative Git-quoted file path, so
plain and JSON patches agree; added and deleted sides use `/dev/null` like Git.

An empty authoritative diff exits 0. Name, stat, and JSON views retain partial
evidence with explicit completeness fields and diagnostics. Plain patch mode
suppresses stdout and exits 1 when unexpected truncation, failed or unavailable
content, binary/metadata-only changes, display-only paths, unprojectable files,
or content-safety changes would make the stream unsafe to apply. An explicit
`--max-files` authorizes file-count truncation, and an explicit
`--max-patch-bytes` authorizes aggregate patch-budget omissions; neither
authorizes unrelated failure classes. Suppression diagnostics name
binary/metadata-only causes and direct humans to stat/name views while JSON
retains structured partial evidence. The applicable patch stream is unified
diff content; the backend does not provide Git index or mode headers.
Validation, authentication, resolution, and raw-field errors exit 1 through
the shared CLI error envelope. No `code_diff` MCP tool, instruction, skill, or
plugin promotion exists during this phase.

## Key reference files

| File | Responsibility |
| --- | --- |
| `packages/core-internal/src/services/code-navigation-service.ts` | GraphQL query, validation, schemas, normalization, and errors |
| `packages/core-internal/src/services/code-navigation-service.test.ts` | Wire-selection, variables, normalization, and failure fixtures |
| `packages/mcp/src/client.ts` | Public client type/value re-exports |
| `packages/mcp/src/shared/code-diff-{request,response,text}.ts` | CLI-internal normalization, lean projection, and Git-like rendering |
| `src/commands/code/diff.ts` | Commander syntax, service call, stream routing, and CLI errors |
| `scripts/validate-public-packages.ts` | Packed-package runtime and no-network TypeScript consumer checks |
| `docs/plans/code-diff-cli-mcp.md` | Phase 2 CLI/MCP ergonomics and scope decisions |
| `docs/plans/code-diff-cli-mcp.md` | Remaining rollout phases and dogfood acceptance evidence |
Loading