diffctx 1.12.1 → 1.12.3
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.
- package/README.md +117 -56
- package/bin/diffctx.js +3 -3
- package/checksums.json +4 -4
- package/install.js +31 -12
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -3,15 +3,16 @@
|
|
|
3
3
|
[](https://github.com/nikolay-e/diffctx/actions/workflows/ci.yml)
|
|
4
4
|
[](https://pypi.org/project/diffctx/)
|
|
5
5
|
[](https://crates.io/crates/diffctx)
|
|
6
|
+
[](https://www.npmjs.com/package/diffctx)
|
|
6
7
|
[](https://pypi.org/project/diffctx/)
|
|
7
8
|
|
|
8
9
|
**diffctx selects the minimum code an LLM needs to review a git diff.**
|
|
9
|
-
Instead of pasting whole files, it walks the dependency graph from the
|
|
10
|
-
lines
|
|
10
|
+
Instead of pasting whole files, it walks the dependency graph outward from the
|
|
11
|
+
changed lines and stops once more context stops paying for itself.
|
|
11
12
|
|
|
12
13
|
> Coming from [`treemapper`](https://pypi.org/project/treemapper/)? That name is
|
|
13
|
-
> deprecated
|
|
14
|
-
>
|
|
14
|
+
> deprecated. Every command, flag, and API call works unchanged:
|
|
15
|
+
> `treemapper` → `diffctx`, `treemapper-mcp` → `diffctx-mcp`.
|
|
15
16
|
|
|
16
17
|
## Why not just use `tree` or repomix?
|
|
17
18
|
|
|
@@ -26,6 +27,9 @@ lines outward and stops as soon as additional context stops paying for itself.
|
|
|
26
27
|
| Python API | ✗ | ✗ | ✗ | ✓ |
|
|
27
28
|
| MCP server | ✗ | ✗ | ✗ | ✓ |
|
|
28
29
|
|
|
30
|
+
Fuller positioning — measured results, and when a whole-repo packer or a
|
|
31
|
+
persistent code-graph server fits better: [COMPARISON.md](COMPARISON.md).
|
|
32
|
+
|
|
29
33
|
## Install
|
|
30
34
|
|
|
31
35
|
```bash
|
|
@@ -35,21 +39,32 @@ pip install diffctx # or: into an active environment
|
|
|
35
39
|
pipx install 'diffctx[mcp]' # + MCP server for AI assistants
|
|
36
40
|
```
|
|
37
41
|
|
|
38
|
-
The `[tree-sitter]` extra adds AST-level parsing for more accurate context
|
|
39
|
-
selection across 30+ languages.
|
|
40
|
-
|
|
41
42
|
Without Python:
|
|
42
43
|
|
|
43
44
|
```bash
|
|
44
45
|
cargo install diffctx # native CLI from crates.io
|
|
46
|
+
npx diffctx . --diff HEAD~1 # npm wrapper over the native binary
|
|
45
47
|
docker run --rm -v "$PWD:/repo" ghcr.io/nikolay-e/diffctx . --diff HEAD~1
|
|
46
48
|
```
|
|
47
49
|
|
|
50
|
+
On Windows, via Scoop (this repository is the bucket):
|
|
51
|
+
|
|
52
|
+
```powershell
|
|
53
|
+
scoop bucket add diffctx https://github.com/nikolay-e/diffctx
|
|
54
|
+
scoop install diffctx/diffctx
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The image runs as a non-root user (uid 10001) and writes to stdout — the
|
|
58
|
+
native binary has no `-o` flag, so redirect to capture: `... --diff HEAD~1 >
|
|
59
|
+
context.yaml`.
|
|
60
|
+
|
|
48
61
|
Prebuilt binaries for linux (x86_64/aarch64), macOS (arm64) and Windows (x64)
|
|
49
62
|
are attached to every [release](https://github.com/nikolay-e/diffctx/releases/latest).
|
|
50
63
|
The native binary covers diff mode with YAML/JSON output; tree mode, Markdown
|
|
51
64
|
output, the `graph` subcommand and the MCP server live in the Python package.
|
|
52
|
-
`cargo add diffctx` embeds the
|
|
65
|
+
`cargo add diffctx` embeds the pipeline in a Rust project — the library is
|
|
66
|
+
imported as `_diffctx` (`use _diffctx::pipeline::build_diff_context`), since
|
|
67
|
+
the crate doubles as the Python extension module
|
|
53
68
|
([docs.rs](https://docs.rs/diffctx)).
|
|
54
69
|
|
|
55
70
|
## Quick start
|
|
@@ -59,32 +74,34 @@ diffctx . --diff HEAD~1 # smart context for last commit → paste into Cla
|
|
|
59
74
|
diffctx . -f md -c # full codebase export → clipboard in Markdown
|
|
60
75
|
```
|
|
61
76
|
|
|
62
|
-

|
|
77
|
+

|
|
63
78
|
|
|
64
|
-
*`diffctx . --diff HEAD~1` selects only the fragments
|
|
65
|
-
|
|
66
|
-
instead of dumping every changed file in full.*
|
|
79
|
+
*`diffctx . --diff HEAD~1` selects only the fragments an LLM needs to review the
|
|
80
|
+
last commit, instead of dumping every changed file in full.*
|
|
67
81
|
|
|
68
82
|
## Diff context mode
|
|
69
83
|
|
|
70
|
-
Finds the minimal set of
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
Finds the minimal set of fragments needed to understand a change — imports,
|
|
85
|
+
callers, type definitions, config dependencies — across 50+ file types. It
|
|
86
|
+
builds a code graph (imports, co-changes, type refs), propagates relevance
|
|
87
|
+
outward from the changed lines, and stops when relevance drops below `--tau` or
|
|
88
|
+
the `--budget` token cap is hit.
|
|
75
89
|
|
|
76
90
|
| Flag | Default | Description |
|
|
77
91
|
|-------------|---------|--------------------------------------------------------------------------|
|
|
78
92
|
| `--scoring` | `ego` | `ego` = bounded expansion around changed nodes (fast, predictable radius); `ppr` = Personalized PageRank (global, smoother decay, slower); `bm25` = lexical retrieval against the diff hunks (baseline for sparse graphs) |
|
|
79
|
-
| `--budget` | auto | Hard token
|
|
93
|
+
| `--budget` | auto | Hard cap in o200k_base tokens (see [Token counting](docs/product/token-budget.md)): `N` enforces a fixed cap, `-1` disables it, `0` is a strict-zero floor (empty selection; use `--full` for changed files only) |
|
|
80
94
|
| `--alpha` | 0.60 | PPR damping; higher = context clusters tighter around changes (`--scoring ppr` only) |
|
|
81
95
|
| `--tau` | 0.12 | Relevance threshold for full fragment content; lower-scoring fragments are stubbed or dropped (lower = more context) |
|
|
82
96
|
| `--full` | false | Only the changed files, every fragment, no related-code context |
|
|
83
97
|
| `--timeout` | 300 | Wall-clock deadline in seconds; on expiry diffctx exits 124 instead of hanging |
|
|
98
|
+
| `--with-raw-diff` | false | Also embed git's raw unified diff ahead of the selected fragments — additive (selection unchanged), not charged to `--budget`, lock/ignored/secret-like sections omitted. Python CLI only |
|
|
84
99
|
|
|
85
100
|
Calibration of `--alpha`, `--tau`, and the edge-weight priors:
|
|
86
|
-
[`docs/parameter-strategy.md`](docs/parameter-strategy.md).
|
|
87
|
-
|
|
101
|
+
[`docs/engineering/parameter-strategy.md`](docs/engineering/parameter-strategy.md).
|
|
102
|
+
Theory:
|
|
103
|
+
[diffctx: Budgeted Typed-Graph Retrieval for Diff-Aware Code Context
|
|
104
|
+
Selection (Zenodo, 2026)](https://doi.org/10.5281/zenodo.18824579).
|
|
88
105
|
|
|
89
106
|
### `graph` subcommand
|
|
90
107
|
|
|
@@ -102,28 +119,34 @@ diffctx graph . --level file -f graphml -o g.xml # file-level graph as GraphML
|
|
|
102
119
|
<!-- BEGIN USAGE -->
|
|
103
120
|
```bash
|
|
104
121
|
# full codebase export:
|
|
105
|
-
diffctx .
|
|
106
|
-
diffctx . -f md -c
|
|
107
|
-
diffctx . -f json -o tree.json
|
|
108
|
-
diffctx . --no-content
|
|
109
|
-
diffctx . --max-depth 3
|
|
110
|
-
diffctx . -i custom.ignore
|
|
122
|
+
diffctx . # Markdown to stdout + token count
|
|
123
|
+
diffctx . -f md -c # Markdown → clipboard
|
|
124
|
+
diffctx . -f json -o tree.json # JSON → file
|
|
125
|
+
diffctx . --no-content # structure only, no file contents
|
|
126
|
+
diffctx . --max-depth 3 # limit depth
|
|
127
|
+
diffctx . -i custom.ignore # custom ignore patterns
|
|
111
128
|
|
|
112
129
|
# diff context mode (requires git repo):
|
|
113
|
-
diffctx . --diff
|
|
114
|
-
diffctx . --diff HEAD~1
|
|
115
|
-
diffctx . --diff main..feature
|
|
116
|
-
diffctx . --diff HEAD~1 --budget 30000
|
|
117
|
-
diffctx . --diff HEAD~1 -c
|
|
130
|
+
diffctx . --diff # uncommitted changes (working tree vs HEAD)
|
|
131
|
+
diffctx . --diff HEAD~1 # context for last commit
|
|
132
|
+
diffctx . --diff main..feature # context for feature branch
|
|
133
|
+
diffctx . --diff HEAD~1 --budget 30000 # limit to ~30k tokens
|
|
134
|
+
diffctx . --diff HEAD~1 -c # diff context to clipboard
|
|
135
|
+
diffctx . --diff HEAD~1 --with-raw-diff # raw patch + selected context
|
|
118
136
|
```
|
|
119
137
|
<!-- END USAGE -->
|
|
120
138
|
|
|
121
139
|
Every run reports token count and size on stderr — `12,847 tokens
|
|
122
|
-
(o200k_base), 52.3 KB` (tiktoken, the GPT-4o tokenizer; `~`-prefixed
|
|
123
|
-
|
|
124
|
-
`
|
|
125
|
-
|
|
126
|
-
`<
|
|
140
|
+
(o200k_base), 52.3 KB` (tiktoken, the GPT-4o tokenizer; `~`-prefixed above
|
|
141
|
+
1 MB). `-c/--copy` copies output via `pbcopy` (macOS), `clip` (Windows), or
|
|
142
|
+
`wl-copy`/`xclip`/`xsel` (Linux). Unreadable files become placeholders like
|
|
143
|
+
`<binary file: N bytes>`, `<file too large: N bytes>`, or
|
|
144
|
+
`<unreadable content: not utf-8>`.
|
|
145
|
+
|
|
146
|
+
Counts come from tiktoken's `o200k_base` encoder and are exact only for the
|
|
147
|
+
GPT-4o family; Claude, Gemini and others tokenize differently, so treat
|
|
148
|
+
`--budget` as an upper bound in o200k tokens and leave headroom. Details:
|
|
149
|
+
[`docs/product/token-budget.md`](docs/product/token-budget.md).
|
|
127
150
|
|
|
128
151
|
## Python API
|
|
129
152
|
|
|
@@ -140,6 +163,7 @@ ctx = build_diff_context(
|
|
|
140
163
|
full=False,
|
|
141
164
|
scoring_mode="ego",
|
|
142
165
|
timeout=300,
|
|
166
|
+
with_raw_diff=False, # True also embeds the raw unified diff (not charged to budget)
|
|
143
167
|
)
|
|
144
168
|
print(to_markdown(ctx))
|
|
145
169
|
|
|
@@ -159,32 +183,48 @@ print(to_yaml(tree))
|
|
|
159
183
|
|
|
160
184
|
diffctx includes an [MCP](https://modelcontextprotocol.io) server that lets AI
|
|
161
185
|
assistants (Claude Code, Cursor, Windsurf, etc.) call diff context analysis
|
|
162
|
-
automatically during code review. Install with `pip install 'diffctx[mcp]'
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
"mcpServers": {
|
|
168
|
-
"diffctx": {
|
|
169
|
-
"command": "diffctx-mcp"
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
186
|
+
automatically during code review. Install with `pip install 'diffctx[mcp]'`,
|
|
187
|
+
then register it — for Claude Code:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
claude mcp add diffctx -- diffctx-mcp
|
|
173
191
|
```
|
|
174
192
|
|
|
175
|
-
The server exposes
|
|
176
|
-
|
|
193
|
+
The server exposes three tools — `get_diff_context`, `get_tree_map`, and
|
|
194
|
+
`get_file_context` — that assistants call when reviewing PRs, explaining
|
|
195
|
+
changes, or investigating broken tests. Tool reference and configs for
|
|
177
196
|
Cursor, Continue, Windsurf, and Zed:
|
|
178
197
|
[`src/diffctx/mcp/README.md`](src/diffctx/mcp/README.md).
|
|
179
198
|
|
|
180
199
|
## Ignore patterns
|
|
181
200
|
|
|
182
201
|
Respects `.gitignore` and `.diffctx/ignore` automatically — hierarchically at
|
|
183
|
-
every directory level, with gitignore semantics (negation `!important.log`,
|
|
184
|
-
anchored `/root_only.txt`). `.diffctx/whitelist` acts as an include-only
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
202
|
+
every directory level, with full gitignore semantics (negation `!important.log`,
|
|
203
|
+
anchored `/root_only.txt`). `.diffctx/whitelist` acts as an include-only filter,
|
|
204
|
+
and the output file is always auto-ignored. `--no-default-ignores` disables the
|
|
205
|
+
built-in patterns; `--no-ignores` disables all ignore rules (tree mode only).
|
|
206
|
+
|
|
207
|
+
An excluded path never appears in the output in any role: in diff mode it is
|
|
208
|
+
dropped both from `changed_files` and from the candidate universe, so it cannot
|
|
209
|
+
come back as a related-context fragment either (including under `--full`). The
|
|
210
|
+
same guarantee covers secret-like paths (`id_rsa`, `*.pem`, `*.key`, ...),
|
|
211
|
+
which are filtered even without an ignore entry.
|
|
212
|
+
|
|
213
|
+
## Token cache
|
|
214
|
+
|
|
215
|
+
Diff mode caches per-blob tokenization under
|
|
216
|
+
`~/Library/Caches/diffctx/token-cache` (macOS),
|
|
217
|
+
`$XDG_CACHE_HOME/diffctx/token-cache` (Linux) or
|
|
218
|
+
`%LOCALAPPDATA%\diffctx\token-cache` (Windows). It is a pure speedup: deleting
|
|
219
|
+
it only costs one cold run.
|
|
220
|
+
|
|
221
|
+
| Variable | Effect |
|
|
222
|
+
|----------|--------|
|
|
223
|
+
| `DIFFCTX_TOKEN_CACHE_DIR` | Relocate the cache |
|
|
224
|
+
| `DIFFCTX_TOKEN_CACHE_MAX_BYTES` | Size cap, default `536870912` (512 MB); `0` disables eviction |
|
|
225
|
+
|
|
226
|
+
Eviction is amortized: each run trims one of the cache's 256 shards back under
|
|
227
|
+
its share of the cap, oldest entries first.
|
|
188
228
|
|
|
189
229
|
## Exit codes
|
|
190
230
|
|
|
@@ -194,17 +234,38 @@ disables the built-in patterns; `--no-ignores` disables all ignore rules
|
|
|
194
234
|
| `1` | Runtime error (bad path, permission denied, etc.) |
|
|
195
235
|
| `2` | Usage error (invalid flags/arguments) |
|
|
196
236
|
| `3` | Environment error (`--diff` outside a git repo, git not installed, no commits yet) |
|
|
197
|
-
| `4` | `--diff` produced no semantic context (clean tree, binary-only, everything filtered); output is still emitted. Deletion/rename-only diffs list `deleted_files`/`renamed_files` and exit `0` |
|
|
237
|
+
| `4` | `--diff` produced no semantic context (clean tree, binary-only, everything filtered); output is still emitted. Deletion/rename/lockfile-only diffs list `deleted_files`/`renamed_files`/`lockfile_changes` and exit `0` |
|
|
238
|
+
| `124`| `--diff` exceeded the `--timeout` wall-clock deadline |
|
|
198
239
|
| `130`| Interrupted (Ctrl-C) |
|
|
199
240
|
| `141`| Broken pipe (e.g. piping into `head`) |
|
|
200
241
|
|
|
242
|
+
## Repository layout
|
|
243
|
+
|
|
244
|
+
Rust product code lives in `crates/diffctx-native/`; the Python CLI and MCP
|
|
245
|
+
package live in `src/diffctx/`. Evaluation code, immutable datasets, and paper
|
|
246
|
+
artifacts are intentionally separated under `eval/`, `datasets/`, and `paper/`.
|
|
247
|
+
See [repository ownership boundaries](docs/architecture/repository-layout.md)
|
|
248
|
+
for the lifecycle and entry point of each area.
|
|
249
|
+
|
|
201
250
|
## License
|
|
202
251
|
|
|
203
252
|
Apache 2.0
|
|
204
253
|
|
|
254
|
+
<!-- mcp-name: io.github.nikolay-e/diffctx -->
|
|
255
|
+
<!-- Ownership marker read from the PyPI description by the MCP registry. -->
|
|
256
|
+
<!-- Must survive edits verbatim: one space after the colon, case-sensitive. -->
|
|
257
|
+
|
|
205
258
|
---
|
|
206
259
|
|
|
260
|
+
- [Documentation site](https://nikolay-e.github.io/diffctx/) — the pipeline
|
|
261
|
+
end to end: diff → fragments → graph → relevance → selection
|
|
262
|
+
- [GitHub Action](docs/product/github-action.md) — diff context as a CI step
|
|
263
|
+
for LLM review
|
|
264
|
+
- [Token counting](docs/product/token-budget.md) — which encoder, and what
|
|
265
|
+
`--budget` means for non-GPT models
|
|
266
|
+
- [Comparison](COMPARISON.md) — measured results, and when a whole-repo packer
|
|
267
|
+
or a persistent code-graph server fits better
|
|
207
268
|
- [Changelog](CHANGELOG.md)
|
|
208
269
|
- [Security policy](SECURITY.md) — threat model and vulnerability reporting
|
|
209
|
-
- [Parameter strategy](docs/parameter-strategy.md) — how `--alpha`,
|
|
270
|
+
- [Parameter strategy](docs/engineering/parameter-strategy.md) — how `--alpha`,
|
|
210
271
|
`--tau`, and edge weights are calibrated
|
package/bin/diffctx.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const path = require('path');
|
|
6
|
-
const { spawnSync } = require('child_process');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const path = require('node:path');
|
|
6
|
+
const { spawnSync } = require('node:child_process');
|
|
7
7
|
|
|
8
8
|
const binaryName = process.platform === 'win32' ? 'diffctx.exe' : 'diffctx';
|
|
9
9
|
const binaryPath = path.join(__dirname, binaryName);
|
package/checksums.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"diffctx-1.12.
|
|
3
|
-
"diffctx-1.12.
|
|
4
|
-
"diffctx-1.12.
|
|
5
|
-
"diffctx-1.12.
|
|
2
|
+
"diffctx-1.12.3-aarch64-apple-darwin.tar.gz": "d62da2cd29e08130dc82936080d0b5734dc91bf392b9d7beb7696d7869bbd56c",
|
|
3
|
+
"diffctx-1.12.3-aarch64-unknown-linux-gnu.tar.gz": "a064e1edf242ddd448d8ed12445dacdcc32c5084ee82c62d54854e3b6b15abca",
|
|
4
|
+
"diffctx-1.12.3-x86_64-pc-windows-msvc.zip": "daf1064d4a4983305812443f79cb9a3d350c53468a513a127a4d5f079a19489c",
|
|
5
|
+
"diffctx-1.12.3-x86_64-unknown-linux-gnu.tar.gz": "83019a9eb2fa8a49eaa7999f5f6f9d88c72a88719c6ab456135ef0ed38f6f7fa"
|
|
6
6
|
}
|
package/install.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const crypto = require('crypto');
|
|
8
|
-
const https = require('https');
|
|
9
|
-
const { execFileSync } = require('child_process');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const crypto = require('node:crypto');
|
|
8
|
+
const https = require('node:https');
|
|
9
|
+
const { execFileSync } = require('node:child_process');
|
|
10
10
|
|
|
11
11
|
const { version } = require('./package.json');
|
|
12
12
|
const checksums = require('./checksums.json');
|
|
@@ -65,16 +65,33 @@ function verify(archivePath, expectedSha256) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
function systemBinary(candidates, name) {
|
|
69
|
+
const found = candidates.find((candidate) => fs.existsSync(candidate));
|
|
70
|
+
if (!found) {
|
|
71
|
+
throw new Error(`cannot locate ${name}; expected one of ${candidates.join(', ')}`);
|
|
72
|
+
}
|
|
73
|
+
return found;
|
|
74
|
+
}
|
|
75
|
+
|
|
68
76
|
function extract(archivePath, archiveKind, destinationDir) {
|
|
69
77
|
if (archiveKind === 'zip') {
|
|
78
|
+
const systemRoot = process.env.SystemRoot || String.raw`C:\Windows`;
|
|
79
|
+
const powershell = systemBinary(
|
|
80
|
+
[
|
|
81
|
+
path.join(systemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe'),
|
|
82
|
+
path.join(systemRoot, 'SysWOW64', 'WindowsPowerShell', 'v1.0', 'powershell.exe'),
|
|
83
|
+
],
|
|
84
|
+
'powershell.exe'
|
|
85
|
+
);
|
|
70
86
|
execFileSync(
|
|
71
|
-
|
|
87
|
+
powershell,
|
|
72
88
|
['-NoProfile', '-Command', `Expand-Archive -LiteralPath '${archivePath}' -DestinationPath '${destinationDir}' -Force`],
|
|
73
89
|
{ stdio: 'inherit' }
|
|
74
90
|
);
|
|
75
91
|
return;
|
|
76
92
|
}
|
|
77
|
-
|
|
93
|
+
const tar = systemBinary(['/usr/bin/tar', '/bin/tar'], 'tar');
|
|
94
|
+
execFileSync(tar, ['-xzf', archivePath, '-C', destinationDir], { stdio: 'inherit' });
|
|
78
95
|
}
|
|
79
96
|
|
|
80
97
|
async function main() {
|
|
@@ -96,10 +113,12 @@ async function main() {
|
|
|
96
113
|
extract(archivePath, archive, workDir);
|
|
97
114
|
|
|
98
115
|
const binaryName = process.platform === 'win32' ? 'diffctx.exe' : 'diffctx';
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
116
|
+
const extracted = path.join(workDir, binaryName);
|
|
117
|
+
const installed = path.join(binDir, binaryName);
|
|
118
|
+
fs.copyFileSync(extracted, installed);
|
|
119
|
+
// Carry over the archive's mode instead of a hardcoded literal, so the
|
|
120
|
+
// binary stays executable without widening permissions beyond the release.
|
|
121
|
+
fs.chmodSync(installed, fs.statSync(extracted).mode & 0o777);
|
|
103
122
|
fs.rmSync(workDir, { recursive: true, force: true });
|
|
104
123
|
}
|
|
105
124
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "diffctx",
|
|
3
|
-
"
|
|
3
|
+
"mcpName": "io.github.nikolay-e/diffctx",
|
|
4
|
+
"version": "1.12.3",
|
|
4
5
|
"description": "Selects the minimum code an LLM needs to review a git diff",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"git",
|
|
7
8
|
"diff",
|
|
8
9
|
"llm",
|
|
9
10
|
"code-review",
|
|
10
|
-
"context"
|
|
11
|
+
"context",
|
|
12
|
+
"mcp",
|
|
13
|
+
"code-context",
|
|
14
|
+
"context-engineering",
|
|
15
|
+
"ai-agents",
|
|
16
|
+
"diff-context",
|
|
17
|
+
"llm-context",
|
|
18
|
+
"codebase"
|
|
11
19
|
],
|
|
12
20
|
"homepage": "https://github.com/nikolay-e/diffctx",
|
|
13
21
|
"bugs": "https://github.com/nikolay-e/diffctx/issues",
|