mincut-context 1.0.0

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 (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +268 -0
  3. package/dist/adapters/cli/bin.d.ts +3 -0
  4. package/dist/adapters/cli/bin.d.ts.map +1 -0
  5. package/dist/adapters/cli/bin.js +119 -0
  6. package/dist/adapters/cli/bin.js.map +1 -0
  7. package/dist/adapters/cli/render.d.ts +10 -0
  8. package/dist/adapters/cli/render.d.ts.map +1 -0
  9. package/dist/adapters/cli/render.js +65 -0
  10. package/dist/adapters/cli/render.js.map +1 -0
  11. package/dist/adapters/cli/tui.d.ts +9 -0
  12. package/dist/adapters/cli/tui.d.ts.map +1 -0
  13. package/dist/adapters/cli/tui.js +57 -0
  14. package/dist/adapters/cli/tui.js.map +1 -0
  15. package/dist/adapters/lib/index.d.ts +6 -0
  16. package/dist/adapters/lib/index.d.ts.map +1 -0
  17. package/dist/adapters/lib/index.js +4 -0
  18. package/dist/adapters/lib/index.js.map +1 -0
  19. package/dist/adapters/mcp/handler.d.ts +112 -0
  20. package/dist/adapters/mcp/handler.d.ts.map +1 -0
  21. package/dist/adapters/mcp/handler.js +128 -0
  22. package/dist/adapters/mcp/handler.js.map +1 -0
  23. package/dist/adapters/mcp/index.d.ts +6 -0
  24. package/dist/adapters/mcp/index.d.ts.map +1 -0
  25. package/dist/adapters/mcp/index.js +32 -0
  26. package/dist/adapters/mcp/index.js.map +1 -0
  27. package/dist/core/graph.d.ts +50 -0
  28. package/dist/core/graph.d.ts.map +1 -0
  29. package/dist/core/graph.js +110 -0
  30. package/dist/core/graph.js.map +1 -0
  31. package/dist/core/index.d.ts +7 -0
  32. package/dist/core/index.d.ts.map +1 -0
  33. package/dist/core/index.js +4 -0
  34. package/dist/core/index.js.map +1 -0
  35. package/dist/core/pagerank.d.ts +30 -0
  36. package/dist/core/pagerank.d.ts.map +1 -0
  37. package/dist/core/pagerank.js +88 -0
  38. package/dist/core/pagerank.js.map +1 -0
  39. package/dist/core/select.d.ts +60 -0
  40. package/dist/core/select.d.ts.map +1 -0
  41. package/dist/core/select.js +121 -0
  42. package/dist/core/select.js.map +1 -0
  43. package/dist/index/builder.d.ts +13 -0
  44. package/dist/index/builder.d.ts.map +1 -0
  45. package/dist/index/builder.js +186 -0
  46. package/dist/index/builder.js.map +1 -0
  47. package/dist/index/walker.d.ts +15 -0
  48. package/dist/index/walker.d.ts.map +1 -0
  49. package/dist/index/walker.js +103 -0
  50. package/dist/index/walker.js.map +1 -0
  51. package/dist/parsers/parser.d.ts +35 -0
  52. package/dist/parsers/parser.d.ts.map +1 -0
  53. package/dist/parsers/parser.js +8 -0
  54. package/dist/parsers/parser.js.map +1 -0
  55. package/dist/parsers/py.d.ts +3 -0
  56. package/dist/parsers/py.d.ts.map +1 -0
  57. package/dist/parsers/py.js +169 -0
  58. package/dist/parsers/py.js.map +1 -0
  59. package/dist/parsers/ts.d.ts +3 -0
  60. package/dist/parsers/ts.d.ts.map +1 -0
  61. package/dist/parsers/ts.js +240 -0
  62. package/dist/parsers/ts.js.map +1 -0
  63. package/dist/seeds/embedding.d.ts +27 -0
  64. package/dist/seeds/embedding.d.ts.map +1 -0
  65. package/dist/seeds/embedding.js +90 -0
  66. package/dist/seeds/embedding.js.map +1 -0
  67. package/dist/seeds/keyword.d.ts +22 -0
  68. package/dist/seeds/keyword.d.ts.map +1 -0
  69. package/dist/seeds/keyword.js +106 -0
  70. package/dist/seeds/keyword.js.map +1 -0
  71. package/dist/seeds/transformers-embedder.d.ts +21 -0
  72. package/dist/seeds/transformers-embedder.d.ts.map +1 -0
  73. package/dist/seeds/transformers-embedder.js +26 -0
  74. package/dist/seeds/transformers-embedder.js.map +1 -0
  75. package/dist/select/pack.d.ts +48 -0
  76. package/dist/select/pack.d.ts.map +1 -0
  77. package/dist/select/pack.js +135 -0
  78. package/dist/select/pack.js.map +1 -0
  79. package/package.json +94 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dhrupo Nil
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,268 @@
1
+ <div align="center">
2
+
3
+ # `mincut-context`
4
+
5
+ **Token-minimal context selection for AI coding agents.**
6
+ A symbol graph of your repo + personalized PageRank + budget-constrained min-cut — picks the smallest provably-relevant context for any task.
7
+
8
+ [![npm](https://img.shields.io/npm/v/mincut-context?logo=npm)](https://www.npmjs.com/package/mincut-context)
9
+ [![license](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
10
+ [![tests](https://img.shields.io/badge/tests-116%20passing-brightgreen)](./tests)
11
+ [![types](https://img.shields.io/badge/types-TypeScript-blue)](./src)
12
+ [![node](https://img.shields.io/badge/node-%3E%3D18.17-success)](./package.json)
13
+
14
+ </div>
15
+
16
+ <p align="center"><img src="docs/demo.gif" alt="mcx pack demo — keyword + semantic search on a real repo" width="900" /></p>
17
+
18
+ > One sentence: an agent that opens `mincut-context` first gets the minimum cohesive *region* of code its task depends on — not a grep hit, not a whole file, not the whole repo.
19
+
20
+ ---
21
+
22
+ ## The problem
23
+
24
+ AI coding agents waste your context window. Two failure modes:
25
+
26
+ | | What it does | Cost |
27
+ |---|---|---|
28
+ | **Over-stuff** | Dumps whole files / all of `src/` | Burns tokens, drowns the model, hurts answer quality |
29
+ | **Under-stuff** | Grep a string, return 3 lines | Misses callers, dependents, tests — model hallucinates |
30
+
31
+ Neither uses what the code actually *is*: a graph.
32
+
33
+ ## The idea
34
+
35
+ Treat context selection as a graph problem.
36
+
37
+ > Given a symbol graph `G = (V, E, w)` where `V` are code units (functions, classes), `E` are dependency edges (imports, calls, references), `w(v)` is the token cost of `v`, a token budget `B`, and seeds `S ⊆ V` derived from the task:
38
+ >
39
+ > Find `T ⊇ S` with `Σ tokens(T) ≤ B` minimizing the **boundary cut cost** `cut(T, V\T) = Σ w(e)` for edges crossing the boundary.
40
+
41
+ In plain English: pick a connected, low-token region that has few "loose ends" pointing outside it. The inside of the cut is what the agent needs to see; the outside is safely ignorable.
42
+
43
+ The objective is **submodular**, so a greedy algorithm gives a `(1 - 1/e) ≈ 0.63` approximation guarantee. Full math in [`SPEC.md`](./SPEC.md).
44
+
45
+ ---
46
+
47
+ ## Install
48
+
49
+ ```bash
50
+ npm install -g mincut-context # global CLI
51
+ # or
52
+ npm install --save-dev mincut-context # per-project
53
+ ```
54
+
55
+ Requires Node 18.17+.
56
+
57
+ ## Use it three ways
58
+
59
+ ### 1. As an MCP server — the recommended path for agents
60
+
61
+ Drop into Claude Code, Codex, Cursor, or any MCP-aware client:
62
+
63
+ ```json
64
+ {
65
+ "mcpServers": {
66
+ "mincut-context": {
67
+ "command": "npx",
68
+ "args": ["-y", "mincut-context", "mcp"]
69
+ }
70
+ }
71
+ }
72
+ ```
73
+
74
+ Your agent now has three tools:
75
+
76
+ | Tool | Description |
77
+ |---|---|
78
+ | `pack_context(task, repo, budget?)` | Get a token-minimal, structurally-relevant context window |
79
+ | `expand_node(node, depth?)` | Pull more around a specific symbol |
80
+ | `explain_selection()` | The rationale for the last selection |
81
+
82
+ ### 2. As a CLI
83
+
84
+ ```bash
85
+ mcx pack "your task description" --budget 4000 # plain output
86
+ mcx pack "..." --format json | jq # pipe-friendly
87
+ mcx pack "..." --format markdown > context.md # ready-to-paste
88
+ mcx pack "..." --interactive # Ink TUI to pin / exclude
89
+ mcx pack "..." --embed # semantic seeding
90
+ mcx index . # warm the parse
91
+ mcx mcp # run as MCP server
92
+ ```
93
+
94
+ ### 3. As a library
95
+
96
+ ```ts
97
+ import { pack } from 'mincut-context';
98
+
99
+ const result = await pack({
100
+ task: 'fix the login validation bug',
101
+ repo: process.cwd(),
102
+ budget: 4000,
103
+ });
104
+
105
+ for (const f of result.files) {
106
+ console.log(f.path, f.score.toFixed(3), f.tokens, '·', f.reasons[0]);
107
+ }
108
+ // → src/auth/login.ts 0.541 612 · seed — matched directly by task
109
+ // → src/auth/session.ts 0.408 483 · attached (60%)
110
+ ```
111
+
112
+ ---
113
+
114
+ ## How it works
115
+
116
+ ```text
117
+ pack(task, repo, budget):
118
+ 1. graph = index(repo) # tree-sitter → symbol+edge graph
119
+ 2. seeds = scoreSeeds(task, graph) # keyword IDF (+ embeddings if --embed)
120
+ 3. ranks = personalizedPageRank(graph, seeds, α=0.85)
121
+ 4. T = greedyMinCut(graph, ranks, seeds, budget):
122
+ T ← seeds
123
+ while Σ tokens(T) < B:
124
+ v* ← argmax_{v ∉ T, attach(v,T) > 0}
125
+ rank(v) · attach(v,T) / tokens(v)
126
+ T ← T ∪ {v*}
127
+ 5. ranges = collapseToFileRanges(T)
128
+ 6. return { files: ranges, tokens, graph: {...}, explain }
129
+ ```
130
+
131
+ The "no isolated nodes" rule (`attach(v, T) > 0`) is what gives you the *cohesion guarantee* — adding a fully-detached node would strictly increase the cut without benefit, so the greedy refuses. That's why an "auth" task never drags in unrelated UI files even when budget permits.
132
+
133
+ ### Why semantic embeddings? (optional)
134
+
135
+ Pure keyword matching misses semantic neighbors:
136
+
137
+ ```bash
138
+ $ mcx pack "ranking and centrality algorithm" --repo .
139
+ no context selected — no symbols matched
140
+
141
+ $ mcx pack "ranking and centrality algorithm" --repo . --embed --embed-weight 0.8
142
+ → src/core/graph.ts 0.638 205 tok
143
+ → src/core/pagerank.ts 0.282 725 tok ← the actual algorithm!
144
+ → src/seeds/keyword.ts 0.080 18 tok
145
+ ```
146
+
147
+ "Centrality" never appears in any symbol name — only embeddings could find this. Uses `@xenova/transformers` (Transformers.js + ONNX), runs fully local, ~22 MB model download on first use.
148
+
149
+ ---
150
+
151
+ ## Real-world examples
152
+
153
+ **On the [Fluent Player](https://fluentplayer.com) free repo** (225 files, 845 symbols, 2,726 edges):
154
+
155
+ ```bash
156
+ $ mcx pack "analytics visit tracking" --budget 3000 --exclude tests/**
157
+ → resources/js/utils/googleAnalytics.js 0.553 556 tok ← seed
158
+ → resources/js/utils/ajax.js 0.174 254 tok
159
+ → resources/js/AnalyticsTracker.js 0.162 1477 tok
160
+ → resources/admin/utils/Notify.js 0.077 104 tok
161
+ → [5 tail files pulled in by graph attachment]
162
+ selected 20 / 845 symbols (2.4% of codebase)
163
+ ```
164
+
165
+ That's exactly the analytics slice — no UI noise, no test fixtures, no unrelated modules. An agent given this context can reason about analytics changes without the rest of the repo.
166
+
167
+ ---
168
+
169
+ ## Languages
170
+
171
+ | Language | Status | Notes |
172
+ |---|---|---|
173
+ | TypeScript / JavaScript | ✅ v1.0 | `.ts .tsx .js .jsx .mjs .cjs` |
174
+ | Python | ✅ v1.0 | `.py .pyi`, relative imports, decorators, methods |
175
+ | Rust, Go, PHP, Vue SFC, … | community welcome | tree-sitter grammar + symbol queries |
176
+
177
+ Adding a language is one parser file implementing `LanguageParser` + one line in `parseForExt`. See [`src/parsers/py.ts`](./src/parsers/py.ts) as a template.
178
+
179
+ ---
180
+
181
+ ## CLI reference
182
+
183
+ ```text
184
+ Usage: mcx pack [options] <task...>
185
+
186
+ Pack a token-minimal context window for the given task.
187
+
188
+ Options:
189
+ -r, --repo <path> Repository root (default: cwd)
190
+ -b, --budget <tokens> Token budget (default: 4000)
191
+ -k, --seeds <count> Top-k seeds (default: 8)
192
+ --alpha <number> PageRank damping (default: 0.85)
193
+ --include <pattern...> Restrict to glob patterns (e.g. src/auth/**)
194
+ --exclude <pattern...> Extra ignore patterns appended to .gitignore
195
+ -f, --format <fmt> plain | json | markdown
196
+ --no-color Disable colored output
197
+ --embed Use semantic embeddings (~22 MB model first run)
198
+ --embed-weight <number> Blend 0..1 (0=keyword, 1=embedding only)
199
+ --embed-model <id> HF model id (default Xenova/all-MiniLM-L6-v2)
200
+ -i, --interactive Ink TUI for pin/exclude before output
201
+ ```
202
+
203
+ ---
204
+
205
+ ## How it compares
206
+
207
+ | Approach | Token-aware | Structural | Semantic | Explainable |
208
+ |---|---|---|---|---|
209
+ | **Whole file dump** (`cat`, `Read`) | ❌ | ❌ | ❌ | trivially |
210
+ | **Grep / ripgrep** | ❌ | ❌ | ❌ | yes |
211
+ | **Cursor/Continue RAG** | partial | ❌ | ✅ | hard |
212
+ | **AST/symbol graph alone** | ❌ | ✅ | ❌ | yes |
213
+ | **`mincut-context`** | ✅ (budget) | ✅ (graph) | ✅ (--embed) | per-node `reason` |
214
+
215
+ ---
216
+
217
+ ## Roadmap
218
+
219
+ - [x] Core: graph + personalized PageRank + greedy min-cut
220
+ - [x] TS/JS parser
221
+ - [x] Python parser
222
+ - [x] CLI (plain / JSON / markdown)
223
+ - [x] MCP server
224
+ - [x] Local embeddings (`@xenova/transformers`)
225
+ - [x] Ink TUI
226
+ - [ ] Persistent on-disk parse cache (incremental reindex)
227
+ - [ ] Louvain community boost for explanation quality
228
+ - [ ] Vue SFC / Svelte parsers
229
+ - [ ] Rust / Go parsers
230
+ - [ ] LSP-backed type-aware call resolution (post-1.0)
231
+
232
+ ---
233
+
234
+ ## Tradeoffs (honest)
235
+
236
+ | What's not optimal | What we do |
237
+ |---|---|
238
+ | True optimal min-cut is NP-hard | Greedy submodular — `(1−1/e)` bound |
239
+ | Tree-sitter symbols are syntactic, not type-aware | Don't follow generics or dynamic dispatch — good for context, not refactoring |
240
+ | Embedding model adds ~22 MB on first run | Opt-in behind `--embed` flag |
241
+ | Cold start parses whole repo | `.mincut-cache/` per-file cache planned for v1.1 |
242
+ | Python class-level constants aren't symbols yet | Only `def` and `class` for now |
243
+
244
+ ---
245
+
246
+ ## Contributing
247
+
248
+ ```bash
249
+ git clone https://github.com/dhrupo/mincut-context.git
250
+ cd mincut-context
251
+ npm install
252
+ npm test # 116 tests across unit + integration + MCP + CLI + TUI
253
+ npm run build
254
+ node dist/adapters/cli/bin.js pack "..." --repo /path/to/some-repo
255
+ ```
256
+
257
+ PRs especially welcome for:
258
+ - **New language parsers** — tree-sitter grammar + symbol queries
259
+ - **LSP integration** — type-aware call resolution
260
+ - **Cache layer** — persistent `.mincut-cache/`
261
+
262
+ Each PR must keep the test suite green (`npm test`). New behavior requires tests first (TDD).
263
+
264
+ ---
265
+
266
+ ## License
267
+
268
+ [MIT](./LICENSE)
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../../src/adapters/cli/bin.ts"],"names":[],"mappings":""}
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import path from 'node:path';
4
+ import { pack } from '../../select/pack.js';
5
+ import { indexRepo } from '../../index/builder.js';
6
+ import { renderJson, renderMarkdown, renderPlain } from './render.js';
7
+ async function runInteractive(result, budget) {
8
+ const React = (await import('react')).default;
9
+ const { render } = await import('ink');
10
+ const { ReviewApp } = await import('./tui.js');
11
+ return new Promise((resolve) => {
12
+ const app = render(React.createElement(ReviewApp, {
13
+ initial: result,
14
+ budget,
15
+ onSubmit: (paths) => {
16
+ const keep = new Set(paths);
17
+ resolve({
18
+ ...result,
19
+ files: result.files.filter((f) => keep.has(f.path)),
20
+ tokens: result.files
21
+ .filter((f) => keep.has(f.path))
22
+ .reduce((s, f) => s + f.tokens, 0),
23
+ });
24
+ app.unmount();
25
+ },
26
+ }));
27
+ });
28
+ }
29
+ const program = new Command();
30
+ program
31
+ .name('mcx')
32
+ .description('mincut-context — token-minimal context selection for AI coding agents')
33
+ .version('1.0.0');
34
+ program
35
+ .command('pack <task...>')
36
+ .description('Pack a token-minimal context window for the given task')
37
+ .option('-r, --repo <path>', 'Repository root', process.cwd())
38
+ .option('-b, --budget <tokens>', 'Token budget', (v) => Number(v), 4000)
39
+ .option('-k, --seeds <count>', 'Top-k seeds', (v) => Number(v), 8)
40
+ .option('--alpha <number>', 'PageRank damping factor', (v) => Number(v), 0.85)
41
+ .option('--include <pattern...>', 'Restrict to glob patterns (e.g. src/auth/**)')
42
+ .option('--exclude <pattern...>', 'Extra ignore patterns appended to .gitignore')
43
+ .option('-f, --format <fmt>', 'Output format: plain | json | markdown', 'plain')
44
+ .option('--no-color', 'Disable colored output')
45
+ .option('--embed', 'Use semantic embeddings (downloads ~22 MB model on first run)', false)
46
+ .option('--embed-weight <number>', 'Blend factor 0..1 (0=keyword, 1=embedding only)', (v) => Number(v), 0.5)
47
+ .option('--embed-model <id>', 'Hugging Face model id', 'Xenova/all-MiniLM-L6-v2')
48
+ .option('-i, --interactive', 'Interactive review — pin/exclude in a TUI before output', false)
49
+ .action(async (taskWords, opts) => {
50
+ const task = taskWords.join(' ').trim();
51
+ if (!task) {
52
+ process.stderr.write('error: task is required\n');
53
+ process.exit(1);
54
+ }
55
+ try {
56
+ let embedder;
57
+ if (opts.embed) {
58
+ const { createTransformersEmbedder } = await import('../../seeds/transformers-embedder.js');
59
+ embedder = createTransformersEmbedder({ model: opts.embedModel });
60
+ }
61
+ const result = await pack({
62
+ task,
63
+ repo: path.resolve(opts.repo),
64
+ budget: opts.budget,
65
+ seeds: opts.seeds,
66
+ alpha: opts.alpha,
67
+ include: opts.include,
68
+ exclude: opts.exclude,
69
+ embedder,
70
+ embedWeight: opts.embedWeight,
71
+ });
72
+ const color = Boolean(opts.color) && process.stdout.isTTY;
73
+ const fmt = (opts.format ?? 'plain').toLowerCase();
74
+ let finalResult = result;
75
+ if (opts.interactive && process.stdout.isTTY) {
76
+ finalResult = await runInteractive(result, opts.budget);
77
+ }
78
+ if (fmt === 'json') {
79
+ process.stdout.write(renderJson(finalResult));
80
+ process.stdout.write('\n');
81
+ }
82
+ else if (fmt === 'markdown' || fmt === 'md') {
83
+ process.stdout.write(renderMarkdown(finalResult, { color, budget: opts.budget, task }));
84
+ }
85
+ else {
86
+ process.stdout.write(renderPlain(finalResult, { color, budget: opts.budget }));
87
+ }
88
+ }
89
+ catch (err) {
90
+ process.stderr.write(`error: ${err.message}\n`);
91
+ process.exit(1);
92
+ }
93
+ });
94
+ program
95
+ .command('index')
96
+ .description('Index the repo and print stats (warms the parse cache, if any)')
97
+ .option('-r, --repo <path>', 'Repository root', process.cwd())
98
+ .option('--include <pattern...>', 'Restrict to glob patterns')
99
+ .action((opts) => {
100
+ const t0 = Date.now();
101
+ const { stats } = indexRepo(path.resolve(opts.repo), {
102
+ include: opts.include,
103
+ });
104
+ const elapsed = Date.now() - t0;
105
+ process.stdout.write(`indexed ${stats.files} files · ${stats.symbols} symbols · ${stats.edges} edges ` +
106
+ `(${stats.unresolvedCalls} unresolved calls) in ${elapsed} ms\n`);
107
+ });
108
+ program
109
+ .command('mcp')
110
+ .description('Run as an MCP server over stdio (slice 8 — placeholder)')
111
+ .action(async () => {
112
+ const { runMcpServer } = await import('../mcp/index.js');
113
+ await runMcpServer();
114
+ });
115
+ program.parseAsync().catch((err) => {
116
+ process.stderr.write(`error: ${err.message}\n`);
117
+ process.exit(1);
118
+ });
119
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../../../src/adapters/cli/bin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { PackResult } from '../../select/pack.js';
2
+ export interface RenderOptions {
3
+ color: boolean;
4
+ budget: number;
5
+ task?: string;
6
+ }
7
+ export declare function renderPlain(result: PackResult, options: RenderOptions): string;
8
+ export declare function renderJson(result: PackResult): string;
9
+ export declare function renderMarkdown(result: PackResult, options: RenderOptions): string;
10
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/adapters/cli/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAgBvD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CA6B9E;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAErD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,aAAa,GAAG,MAAM,CAgBjF"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * ANSI dim/reset. We hand-code these instead of pulling a colors lib so the
3
+ * package stays tiny and works in non-TTY pipes (we detect and strip).
4
+ */
5
+ const COLOR = {
6
+ reset: '\x1b[0m',
7
+ dim: '\x1b[2m',
8
+ bold: '\x1b[1m',
9
+ green: '\x1b[32m',
10
+ cyan: '\x1b[36m',
11
+ yellow: '\x1b[33m',
12
+ red: '\x1b[31m',
13
+ };
14
+ export function renderPlain(result, options) {
15
+ const c = options.color ? COLOR : Object.fromEntries(Object.keys(COLOR).map((k) => [k, '']));
16
+ if (result.files.length === 0) {
17
+ return `${c.yellow}no context selected${c.reset}\n${c.dim}${result.explain}${c.reset}\n`;
18
+ }
19
+ const lines = [];
20
+ const pad = Math.max(...result.files.map((f) => f.path.length)) + 2;
21
+ const maxScore = result.files[0]?.score ?? 1;
22
+ for (const file of result.files) {
23
+ const ranges = file.ranges.map((r) => `${r.start}-${r.end}`).join(',');
24
+ const score = file.score / Math.max(maxScore, 1e-9);
25
+ const bar = bar20(score);
26
+ lines.push(`${c.green}→${c.reset} ${file.path.padEnd(pad)}` +
27
+ `${c.dim}lines ${ranges.padEnd(14)} ${c.reset}` +
28
+ `${c.cyan}${bar}${c.reset} ` +
29
+ `${c.bold}${file.score.toFixed(3)}${c.reset} ` +
30
+ `${c.dim}${file.tokens} tok${c.reset}`);
31
+ }
32
+ lines.push('');
33
+ const pct = options.budget > 0 ? Math.round((result.tokens / options.budget) * 100) : 0;
34
+ lines.push(`${c.bold}selected${c.reset} ${result.graph.selected} symbols · ` +
35
+ `${c.bold}cut${c.reset} ${result.graph.cutCost.toFixed(1)} · ` +
36
+ `${c.bold}frontier${c.reset} ${result.graph.frontier} · ` +
37
+ `${c.bold}${result.tokens}${c.reset} / ${options.budget} tokens (${pct}%)`);
38
+ return lines.join('\n') + '\n';
39
+ }
40
+ export function renderJson(result) {
41
+ return JSON.stringify(result, null, 2);
42
+ }
43
+ export function renderMarkdown(result, options) {
44
+ const lines = [];
45
+ lines.push(`# Context for: ${escape(options.task ?? '')}`);
46
+ lines.push('');
47
+ lines.push(`Selected ${result.graph.selected} symbols from ${result.files.length} files · ` +
48
+ `${result.tokens} / ${options.budget} tokens · cut cost ${result.graph.cutCost.toFixed(1)}`);
49
+ lines.push('');
50
+ for (const file of result.files) {
51
+ const ranges = file.ranges.map((r) => `${r.start}-${r.end}`).join(', ');
52
+ lines.push(`## \`${file.path}\` (lines ${ranges})`);
53
+ lines.push(`<sub>score ${file.score.toFixed(3)} · ${file.tokens} tokens</sub>`);
54
+ lines.push('');
55
+ }
56
+ return lines.join('\n');
57
+ }
58
+ function bar20(fraction) {
59
+ const n = Math.max(0, Math.min(20, Math.round(fraction * 20)));
60
+ return '█'.repeat(n).padEnd(20, '·');
61
+ }
62
+ function escape(s) {
63
+ return s.replace(/[`*_]/g, '\\$&');
64
+ }
65
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/adapters/cli/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { PackResult } from '../../select/pack.js';
3
+ export interface ReviewAppProps {
4
+ initial: PackResult;
5
+ budget: number;
6
+ onSubmit: (paths: string[]) => void;
7
+ }
8
+ export declare function ReviewApp({ initial, budget, onSubmit }: ReviewAppProps): React.ReactElement;
9
+ //# sourceMappingURL=tui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.d.ts","sourceRoot":"","sources":["../../../src/adapters/cli/tui.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CACrC;AAOD,wBAAgB,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,cAAc,GAAG,KAAK,CAAC,YAAY,CAiG3F"}
@@ -0,0 +1,57 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box, Text, useApp, useInput } from 'ink';
4
+ export function ReviewApp({ initial, budget, onSubmit }) {
5
+ const { exit } = useApp();
6
+ const [cursor, setCursor] = useState(0);
7
+ const [state, setState] = useState(() => initial.files.map(() => ({ pinned: false, excluded: false })));
8
+ const submit = () => {
9
+ const paths = initial.files
10
+ .map((f, i) => (state[i].excluded ? null : f.path))
11
+ .filter((p) => p !== null);
12
+ onSubmit(paths);
13
+ exit();
14
+ };
15
+ useInput((input, key) => {
16
+ if (key.downArrow || input === 'j') {
17
+ setCursor((c) => Math.min(initial.files.length - 1, c + 1));
18
+ return;
19
+ }
20
+ if (key.upArrow || input === 'k') {
21
+ setCursor((c) => Math.max(0, c - 1));
22
+ return;
23
+ }
24
+ if (input === 'x') {
25
+ setState((s) => s.map((r, i) => (i === cursor ? { ...r, excluded: !r.excluded } : r)));
26
+ return;
27
+ }
28
+ if (input === 'p') {
29
+ setState((s) => s.map((r, i) => (i === cursor ? { ...r, pinned: !r.pinned } : r)));
30
+ return;
31
+ }
32
+ if (key.return) {
33
+ submit();
34
+ return;
35
+ }
36
+ if (input === 'q' || (key.ctrl && input === 'c')) {
37
+ onSubmit([]);
38
+ exit();
39
+ }
40
+ });
41
+ const includedTokens = initial.files.reduce((sum, f, i) => sum + (state[i]?.excluded ? 0 : f.tokens), 0);
42
+ const includedCount = state.filter((s) => !s.excluded).length;
43
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "mincut-context" }), _jsx(Text, { children: " \u00B7 " }), _jsxs(Text, { dimColor: true, children: [initial.graph.selected, " symbols \u00B7 cut ", initial.graph.cutCost.toFixed(1), " \u00B7 frontier", ' ', initial.graph.frontier] })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: initial.files.map((f, i) => {
44
+ const row = state[i];
45
+ const cursorMark = i === cursor ? '▶' : ' ';
46
+ const pinMark = row.pinned ? '★' : ' ';
47
+ const excludeMark = row.excluded ? '✗' : ' ';
48
+ const ranges = f.ranges.map((r) => `${r.start}-${r.end}`).join(',');
49
+ const dim = row.excluded;
50
+ return (_jsxs(Box, { children: [_jsxs(Text, { color: i === cursor ? 'cyan' : undefined, children: [cursorMark, " "] }), _jsx(Text, { color: "yellow", children: pinMark }), _jsx(Text, { color: "red", children: excludeMark }), _jsx(Text, { dimColor: dim, children: " " }), _jsx(Text, { dimColor: dim, children: f.path.padEnd(36) }), _jsx(Text, { dimColor: true, children: ` lines ${ranges.padEnd(12)} ` }), _jsx(Text, { color: "cyan", children: bar20(f.score / Math.max(initial.files[0]?.score ?? 1, 1e-9)) }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: f.score.toFixed(3) }), _jsx(Text, { dimColor: true, children: ` ${f.tokens} tok` })] }, f.path));
51
+ }) }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: [includedCount, " / ", initial.files.length, " files \u00B7 ", includedTokens, " / ", budget, " tokens"] }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "\u2191/\u2193 or j/k navigate \u00B7 p pin \u00B7 x exclude \u00B7 Enter copy \u00B7 q quit" }) })] }));
52
+ }
53
+ function bar20(fraction) {
54
+ const n = Math.max(0, Math.min(20, Math.round(fraction * 20)));
55
+ return '█'.repeat(n).padEnd(20, '·');
56
+ }
57
+ //# sourceMappingURL=tui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tui.js","sourceRoot":"","sources":["../../../src/adapters/cli/tui.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { pack } from '../../select/pack.js';
2
+ export type { PackOptions, PackResult, PackedFile, FileRange, } from '../../select/pack.js';
3
+ export { indexRepo } from '../../index/builder.js';
4
+ export type { IndexResult } from '../../index/builder.js';
5
+ export { SymbolGraph, personalizedPageRank, greedySelect, } from '../../core/index.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAC5C,YAAY,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,SAAS,GACV,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { pack } from '../../select/pack.js';
2
+ export { indexRepo } from '../../index/builder.js';
3
+ export { SymbolGraph, personalizedPageRank, greedySelect, } from '../../core/index.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAO5C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EACL,WAAW,EACX,oBAAoB,EACpB,YAAY,GACb,MAAM,qBAAqB,CAAC"}