grepmax 0.26.69 → 0.26.71
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/.claude-plugin/marketplace.json +1 -1
- package/DOCUMENT-SEARCH.md +113 -0
- package/README.md +24 -0
- package/dist/bin.js +11 -2
- package/dist/commands/audit.js +9 -1
- package/dist/commands/mcp.js +16 -3
- package/dist/commands/project.js +7 -1
- package/dist/commands/skeleton.js +13 -10
- package/dist/commands/surprises.js +2 -0
- package/dist/lib/analysis/surprising-connections.js +16 -2
- package/dist/lib/daemon/daemon.js +50 -0
- package/dist/lib/daemon/document-search-handler.js +194 -0
- package/dist/lib/daemon/graph-handler.js +23 -8
- package/dist/lib/daemon/ipc-handler.js +29 -2
- package/dist/lib/daemon/rows-handler.js +48 -4
- package/dist/lib/mcp/document-contract.js +281 -0
- package/dist/lib/mcp/document-search.js +274 -0
- package/dist/lib/output/agent-budget.js +39 -0
- package/dist/lib/output/project-coverage.js +16 -0
- package/dist/lib/store/vector-db.js +13 -0
- package/dist/lib/utils/resource-budget.js +29 -1
- package/dist/lib/workers/embeddings/granite.js +8 -3
- package/dist/lib/workers/embeddings/mlx-client.js +27 -0
- package/dist/lib/workers/orchestrator.js +47 -9
- package/dist/lib/workers/pool.js +85 -3
- package/dist/lib/workers/process-child.js +22 -5
- package/dist/lib/workers/worker.js +4 -1
- package/package.json +5 -3
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "grepmax",
|
|
11
11
|
"source": "./plugins/grepmax",
|
|
12
12
|
"description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
|
|
13
|
-
"version": "0.26.
|
|
13
|
+
"version": "0.26.71",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Robert Owens",
|
|
16
16
|
"email": "robowens@me.com"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Existing-index document search (contract v1)
|
|
2
|
+
|
|
3
|
+
`gmax mcp --existing-index-only` serves two read-only stdio MCP tools. The exact
|
|
4
|
+
entry dispatch precedes the normal CLI. Server identity is
|
|
5
|
+
`gmax-document-search`; the 2025-06-18 initialize exchange is supported by the
|
|
6
|
+
current MCP SDK. Contract version is independent of package version.
|
|
7
|
+
|
|
8
|
+
Every tool returns `structuredContent` with `contractVersion: 1` and capabilities
|
|
9
|
+
`{existingIndexOnly: 1, queryLogging: false, watch: false, runtimeStartup: false}`.
|
|
10
|
+
The text content contains only the result state. No source/snippet bodies are
|
|
11
|
+
returned. Runlist has no gmax, model or SDK runtime dependency.
|
|
12
|
+
|
|
13
|
+
- `document_search_status({paths})` returns `state: ready`, a required positive
|
|
14
|
+
safe-integer `generation`, `project: {root,store,lastIndexed}`,
|
|
15
|
+
actual metadata `covered` paths, `coverage: {requested,indexed,partial}`,
|
|
16
|
+
`embeddingReady`, `queryState` and index state. Readiness does not guarantee
|
|
17
|
+
worker availability when the subsequent query arrives. Coverage is not a
|
|
18
|
+
registry/store-wide chunk count and does not prove current source freshness.
|
|
19
|
+
Covered paths retain a validated `indexedMtimeMs` where available. A missing
|
|
20
|
+
sampled Markdown file reduces coverage instead of discarding other paths;
|
|
21
|
+
malformed or out-of-scope paths still refuse. Counts are recomputed, and
|
|
22
|
+
metadata uses a bounded field allowlist without free-form diagnostics.
|
|
23
|
+
- `semantic_search({query,prefixes})` returns `state: ready`, canonical `root`,
|
|
24
|
+
selected `store`, required `generation`, `matches` and index state. Each pointer is
|
|
25
|
+
`{path,startLine,endLine,score,hash?,hashAlgorithm?}`. Ranges are one-based full
|
|
26
|
+
source ranges, converted from indexed zero-based lines. Score is
|
|
27
|
+
`1/(1+max(0,cosineDistance))`, not a relevance probability.
|
|
28
|
+
- `hashAlgorithm: sha256-bytes` is declared only when the vector row digest agrees
|
|
29
|
+
with current version-1 metadata whose digest hashes the exact indexed bytes.
|
|
30
|
+
Legacy/mismatched provenance retains document-only pointers. Consumers must
|
|
31
|
+
reread and authorize current source, verify the digest and map body lines before
|
|
32
|
+
jumping to a section. This bridge never hashes new bytes to bless old lines.
|
|
33
|
+
|
|
34
|
+
Limits: 500 query characters, 32 explicit prefixes, 2,000 coverage paths and a
|
|
35
|
+
512 KiB serialized path budget, 50 vector candidates, 1 MiB transport frames and
|
|
36
|
+
a 10-second bridge operation deadline. The most specific registered ancestor
|
|
37
|
+
of the canonical checkout selects the primary store; registered spelling is
|
|
38
|
+
preserved for daemon/row lookups. Coverage and prefixes must resolve inside the
|
|
39
|
+
checkout and selected project. Secondary stores are unavailable. No candidate
|
|
40
|
+
refill broadens scope. Symlink targets are rechecked before pointers are returned.
|
|
41
|
+
|
|
42
|
+
Unavailable states: `unsupported_tool`, `unsupported_daemon`, `no_index`,
|
|
43
|
+
`index_unavailable`, `daemon_unavailable`, `store_unavailable`,
|
|
44
|
+
`embedding_unavailable`, `embedding_mismatch`, `host_pressure`, `busy`,
|
|
45
|
+
`cancelled`, `timeout`, `no_coverage`, `search_unavailable`. Envelopes contain
|
|
46
|
+
stable states, never raw query-bearing diagnostics. Schema/unknown-tool errors
|
|
47
|
+
remain standard MCP errors.
|
|
48
|
+
|
|
49
|
+
The supported bridge negotiates daemon `existingIndexOnlySearch: 1` and resource
|
|
50
|
+
generation. Missing, null, non-integer and changed generations refuse; Runlist
|
|
51
|
+
also fences status against subsequent retrieval. Private daemon commands are `documents.status` and `documents.search`;
|
|
52
|
+
Runlist does not call the socket API. The daemon validates roots, stores, bounds
|
|
53
|
+
and generation again under its shared-operation coordinator, including after
|
|
54
|
+
encoding and native retrieval. Paused/contained resources refuse rather than
|
|
55
|
+
return keyword results.
|
|
56
|
+
|
|
57
|
+
Retrieval in this first slice is **dense-only** against an already-open LanceDB
|
|
58
|
+
connection/table. It never invokes normal hybrid search, FTS creation, reranking,
|
|
59
|
+
ColBERT inference, `ensureTable`, schema evolution, index mutation or local-store
|
|
60
|
+
fallback. Query encoding uses a currently idle, already-warm compatible worker:
|
|
61
|
+
CPU requires a loaded Granite tokenizer/session; GPU requires cached positive
|
|
62
|
+
confirmation of the existing configured MLX model. Idle time alone does not revoke
|
|
63
|
+
that identity: each bounded `/embed` response revalidates model and dimensions,
|
|
64
|
+
and successful inference renews the normal health cache. Failure revokes restricted
|
|
65
|
+
eligibility until external work confirms readiness. A worker rechecks before inference;
|
|
66
|
+
no initialization, health polling, retry or backend fallback is allowed. Cold or
|
|
67
|
+
busy workers refuse immediately without queueing, spawning or scaling.
|
|
68
|
+
|
|
69
|
+
Read-only admission samples existing host/ledger state without creating locks,
|
|
70
|
+
reservations, pruning records or changing containment markers. Existing Darwin
|
|
71
|
+
inference requires known-normal aggregate resources even if ordinary expansion
|
|
72
|
+
uses a looser policy. Other platforms retain the existing no-footprint-probe
|
|
73
|
+
policy; this is not a cross-platform native qualification claim.
|
|
74
|
+
An absent ledger in a fresh `critical-only` home is sampled as empty without being
|
|
75
|
+
created; existing corrupt or symlinked ledgers still refuse. Markdown coverage
|
|
76
|
+
and returned pointers require regular files, including after symlink resolution;
|
|
77
|
+
a directory whose name ends in `.md` can be a prefix but never a source pointer.
|
|
78
|
+
|
|
79
|
+
Cancellation closes only the request/owned bridge. It rejects the caller and
|
|
80
|
+
discards late results; an already executing shared worker remains assigned until
|
|
81
|
+
its terminal response or exit. Caller deadlines/heartbeats cannot trigger worker
|
|
82
|
+
replacement or native session initialization. Idle RSS retirement and consecutive
|
|
83
|
+
oversized completions remain enforced, including after restricted work, without
|
|
84
|
+
filling the worker floor on that path. Further restricted calls then report
|
|
85
|
+
unavailable; ordinary work may expand under ordinary admission. Busy inference is
|
|
86
|
+
never interrupted by RSS retirement. The daemon's independent safety/shutdown
|
|
87
|
+
machinery remains authoritative.
|
|
88
|
+
|
|
89
|
+
Native retrieval receives the remaining overall deadline and holds its shared
|
|
90
|
+
operation until the actual native promise settles. A JavaScript timer cannot
|
|
91
|
+
release resources that native code still uses. Caller cancellation/bridge timeout
|
|
92
|
+
remains bounded and late results are discarded. If the SDK fails to settle even
|
|
93
|
+
after its native deadline, exclusive resource teardown stays blocked rather than
|
|
94
|
+
closing underneath the read; no worker/store replacement is induced to hide the
|
|
95
|
+
failure. Cancellation cannot interrupt an already running ONNX native call.
|
|
96
|
+
Global logging settings are unchanged, and this path never logs query text.
|
|
97
|
+
|
|
98
|
+
## Isolated qualification
|
|
99
|
+
|
|
100
|
+
Use `node scripts/build-document-search-candidate.cjs /absolute/new/output` to
|
|
101
|
+
compile/package without overwriting `dist`, installing, publishing, or invoking
|
|
102
|
+
lifecycle scripts. The script copies the pinned native JS runtime with provenance.
|
|
103
|
+
`node scripts/audit-document-search.cjs /absolute/extracted/package` exercises a
|
|
104
|
+
synthetic daemon and checks packaged files/import boundaries. The normal consumer
|
|
105
|
+
audit invokes that check against its freshly installed tarball too.
|
|
106
|
+
|
|
107
|
+
The optional Runlist fixture is
|
|
108
|
+
`RUNLIST_GMAX_QUALIFICATION_ENTRY=/absolute/extracted/package/dist/bin.js node --test desktop/test/semantic-gmax-contract.test.mjs`.
|
|
109
|
+
Fixture homes/IPC are private temporary directories; no real daemon, index,
|
|
110
|
+
watcher, model or grammar download is used. Reusing checkout dependencies for a
|
|
111
|
+
local package probe must be reported separately from fresh dependency resolution.
|
|
112
|
+
Installation, a shared-daemon restart, watcher recovery and live retrieval require
|
|
113
|
+
separate explicit actions. Source/package fixture success proves none of those.
|
package/README.md
CHANGED
|
@@ -223,6 +223,30 @@ gmax surprises --experimental --exclude generated --top 10
|
|
|
223
223
|
|
|
224
224
|
The CLI and MCP output include score, max similarity, pair count, representative symbols, directory buckets, top similarities, applied penalties, and `gmax skeleton` follow-up hints. On large monorepos, prefer `--in`/`--exclude`; the default scan is capped at 50,000 rows and user-provided `--max-rows` is capped at 100,000. If a narrow `--in` scope returns no findings, increase `--dir-depth` so subdirectories are compared inside the scope.
|
|
225
225
|
|
|
226
|
+
Surprises excludes generated code, bindings, fixtures and GraphQL schema/operation output by default. Use CLI `--include-generated` or MCP `include_generated: true` to include these families; `--include-tests` / `include_tests` controls test files separately.
|
|
227
|
+
|
|
228
|
+
### Analysis coverage and compact output
|
|
229
|
+
|
|
230
|
+
Project overviews disclose when their language, directory, role and symbol breakdowns cover the first 200,000 chunks. CLI and MCP output label sampled chunk/file counts and show the full project chunk inventory separately. Inventory counting streams only paths in small batches with an execution deadline.
|
|
231
|
+
|
|
232
|
+
Architecture audits omit unresolved same-name definitions from rankings, cycles and dead-code claims, and report the number omitted. Compact CLI audit and MCP cycle rows retain total file/edge counts and show up to eight complete paths within 1,000 characters, with an explicit omitted-file count.
|
|
233
|
+
|
|
234
|
+
CLI `gmax skeleton --agent` and MCP `code_skeleton` text show at most 120 lines / 6,000 characters per file and report omitted lines and characters. CLI human output and JSON structure remain complete.
|
|
235
|
+
|
|
236
|
+
## Existing-index document search
|
|
237
|
+
|
|
238
|
+
`gmax mcp --existing-index-only` exposes a separate read-only stdio MCP contract
|
|
239
|
+
for Markdown document coverage and semantic pointers. It uses an existing daemon,
|
|
240
|
+
index and already-warm compatible query worker. It cannot start a daemon, watch a
|
|
241
|
+
project, initialize a model, fall back to another backend or mutate the index.
|
|
242
|
+
Cold, busy or unavailable resources return an explicit unavailable state.
|
|
243
|
+
|
|
244
|
+
Results contain canonical paths and one-based source ranges, without cached source
|
|
245
|
+
bodies. The first slice uses dense retrieval with explicit path scope and bounded
|
|
246
|
+
deadlines. Consumers must reread and authorize current source before using a
|
|
247
|
+
pointer. See [the document-search contract](DOCUMENT-SEARCH.md) for tool schemas,
|
|
248
|
+
limits, hash provenance and isolated qualification.
|
|
249
|
+
|
|
226
250
|
## Background Daemon
|
|
227
251
|
|
|
228
252
|
A single daemon watches your projects via native OS file events (FSEvents/inotify). Changes are detected in sub-second and incrementally reindexed. All writes to LanceDB are routed through the daemon via IPC, eliminating lock contention.
|
package/dist/bin.js
CHANGED
|
@@ -152,6 +152,15 @@ function seedConfig(home) {
|
|
|
152
152
|
}
|
|
153
153
|
}
|
|
154
154
|
if (require.main === module) {
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
if (process.argv.slice(2).join(" ") === "mcp --existing-index-only") {
|
|
156
|
+
require("./lib/mcp/document-search").runDocumentSearchBridge();
|
|
157
|
+
}
|
|
158
|
+
else if (process.argv.includes("--existing-index-only")) {
|
|
159
|
+
process.stderr.write("gmax: use exactly mcp --existing-index-only\n");
|
|
160
|
+
process.exitCode = 2;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
selectHome();
|
|
164
|
+
require("./index");
|
|
165
|
+
}
|
|
157
166
|
}
|
package/dist/commands/audit.js
CHANGED
|
@@ -43,8 +43,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.audit = void 0;
|
|
46
|
+
exports.formatHuman = formatHuman;
|
|
47
|
+
exports.formatAgent = formatAgent;
|
|
46
48
|
const commander_1 = require("commander");
|
|
47
49
|
const graph_handler_1 = require("../lib/daemon/graph-handler");
|
|
50
|
+
const agent_budget_1 = require("../lib/output/agent-budget");
|
|
48
51
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
49
52
|
const exit_1 = require("../lib/utils/exit");
|
|
50
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
@@ -67,6 +70,8 @@ function formatCycle(files) {
|
|
|
67
70
|
function formatHuman(r) {
|
|
68
71
|
const out = [];
|
|
69
72
|
out.push(`${style.bold("Audit")} ${style.dim(`— ${r.scannedChunks} chunks across ${r.scannedFiles} files`)}`);
|
|
73
|
+
if (r.ambiguousSymbols)
|
|
74
|
+
out.push(`Unresolved symbol names omitted: ${r.ambiguousSymbols}`);
|
|
70
75
|
out.push("");
|
|
71
76
|
out.push(style.bold("God nodes") + style.dim(" (most depended-upon symbols)"));
|
|
72
77
|
if (r.godNodes.length === 0) {
|
|
@@ -122,8 +127,10 @@ function formatHuman(r) {
|
|
|
122
127
|
return out.join("\n");
|
|
123
128
|
}
|
|
124
129
|
function formatAgent(r) {
|
|
130
|
+
var _a;
|
|
125
131
|
const lines = [];
|
|
126
132
|
lines.push(`scanned\t${r.scannedChunks}\t${r.scannedFiles}`);
|
|
133
|
+
lines.push(`ambiguous_symbols_omitted\t${(_a = r.ambiguousSymbols) !== null && _a !== void 0 ? _a : 0}`);
|
|
127
134
|
for (const g of r.godNodes) {
|
|
128
135
|
const ambiguous = g.defFiles > 1 ? `\tdefs=${g.defFiles}` : "";
|
|
129
136
|
lines.push(`god\t${g.symbol}\t${g.file}:${g.line + 1}\t${g.inboundFiles}\t${g.totalRefs}${ambiguous}`);
|
|
@@ -132,7 +139,8 @@ function formatAgent(r) {
|
|
|
132
139
|
lines.push(`hub\t${h.file}\t${h.dependents}\t${h.defines}\t${h.fanOut}`);
|
|
133
140
|
}
|
|
134
141
|
for (const c of r.fileCycles) {
|
|
135
|
-
|
|
142
|
+
const shown = (0, agent_budget_1.boundedAgentList)(c.files);
|
|
143
|
+
lines.push(`cycle\t${shown.text}\t${c.files.length}\t${c.edgeCount}\tomitted_files=${shown.omitted}`);
|
|
136
144
|
}
|
|
137
145
|
for (const d of r.deadCandidates) {
|
|
138
146
|
lines.push(`dead\t${d.symbol}\t${d.file}:${d.line + 1}`);
|
package/dist/commands/mcp.js
CHANGED
|
@@ -83,9 +83,11 @@ const embedding_generation_1 = require("../lib/index/embedding-generation");
|
|
|
83
83
|
const embedding_status_1 = require("../lib/index/embedding-status");
|
|
84
84
|
const index_config_1 = require("../lib/index/index-config");
|
|
85
85
|
const syncer_1 = require("../lib/index/syncer");
|
|
86
|
+
const agent_budget_1 = require("../lib/output/agent-budget");
|
|
86
87
|
const agent_search_formatter_1 = require("../lib/output/agent-search-formatter");
|
|
87
88
|
const index_state_footer_1 = require("../lib/output/index-state-footer");
|
|
88
89
|
const mcp_results_1 = require("../lib/output/mcp-results");
|
|
90
|
+
const project_coverage_1 = require("../lib/output/project-coverage");
|
|
89
91
|
const searcher_1 = require("../lib/search/searcher");
|
|
90
92
|
const annotator_1 = require("../lib/skeleton/annotator");
|
|
91
93
|
const skeletonizer_1 = require("../lib/skeleton/skeletonizer");
|
|
@@ -1133,7 +1135,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1133
1135
|
const annotated = sourceContent
|
|
1134
1136
|
? (0, annotator_1.annotateSkeletonLines)(skeleton, sourceContent)
|
|
1135
1137
|
: skeleton;
|
|
1136
|
-
parts.push(`// ${t} (~${tokenEstimate} tokens)\n\n${annotated}`);
|
|
1138
|
+
parts.push(`// ${t} (~${tokenEstimate} tokens)\n\n${(0, agent_budget_1.boundedAgentText)(annotated)}`);
|
|
1137
1139
|
}
|
|
1138
1140
|
}
|
|
1139
1141
|
if (fmt === "json") {
|
|
@@ -1518,6 +1520,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1518
1520
|
}
|
|
1519
1521
|
const lines = [];
|
|
1520
1522
|
lines.push(`Audit — ${audit.scannedChunks} chunks across ${audit.scannedFiles} files`);
|
|
1523
|
+
if (audit.ambiguousSymbols)
|
|
1524
|
+
lines.push(`Unresolved symbol names omitted: ${audit.ambiguousSymbols}`);
|
|
1521
1525
|
lines.push("");
|
|
1522
1526
|
lines.push("God nodes (most depended-upon symbols):");
|
|
1523
1527
|
for (const g of audit.godNodes) {
|
|
@@ -1535,7 +1539,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1535
1539
|
lines.push("");
|
|
1536
1540
|
lines.push("File dependency cycles (symbol-derived):");
|
|
1537
1541
|
for (const c of audit.fileCycles) {
|
|
1538
|
-
|
|
1542
|
+
const shown = (0, agent_budget_1.boundedAgentList)(c.files);
|
|
1543
|
+
lines.push(` ${shown.text} - ${c.files.length} files, ${c.edgeCount} internal edges; omitted_files=${shown.omitted}`);
|
|
1539
1544
|
}
|
|
1540
1545
|
if (audit.fileCycles.length === 0)
|
|
1541
1546
|
lines.push(" none");
|
|
@@ -1581,6 +1586,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1581
1586
|
maxRows,
|
|
1582
1587
|
includeTests: Boolean(args.include_tests),
|
|
1583
1588
|
includeEval: Boolean(args.include_eval),
|
|
1589
|
+
includeGenerated: Boolean(args.include_generated),
|
|
1584
1590
|
in: typeof args.in === "string" ? [args.in] : undefined,
|
|
1585
1591
|
exclude: typeof args.exclude === "string" ? [args.exclude] : undefined,
|
|
1586
1592
|
};
|
|
@@ -1990,7 +1996,10 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1990
1996
|
const pct = (count) => Math.round((count / overview.chunks) * 100);
|
|
1991
1997
|
const lines = [];
|
|
1992
1998
|
lines.push(`Project: ${projectName} (${root})`);
|
|
1993
|
-
lines.push(`Last indexed: ${(_a = proj.lastIndexed) !== null && _a !== void 0 ? _a : "unknown"} • ${
|
|
1999
|
+
lines.push(`Last indexed: ${(_a = proj.lastIndexed) !== null && _a !== void 0 ? _a : "unknown"} • ${(0, project_coverage_1.projectCounts)(overview)}`);
|
|
2000
|
+
const coverage = (0, project_coverage_1.projectCoverageNotice)(overview);
|
|
2001
|
+
if (coverage)
|
|
2002
|
+
lines.push(`Coverage: ${coverage}`);
|
|
1994
2003
|
lines.push("");
|
|
1995
2004
|
lines.push(`Languages: ${overview.extEntries
|
|
1996
2005
|
.map(([ext, count]) => `${ext} (${pct(count)}%)`)
|
|
@@ -2976,6 +2985,10 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
2976
2985
|
.boolean()
|
|
2977
2986
|
.describe("Include eval/experiment/script files")
|
|
2978
2987
|
.optional(),
|
|
2988
|
+
include_generated: zod_1.z
|
|
2989
|
+
.boolean()
|
|
2990
|
+
.describe("Include generated code, bindings and fixtures")
|
|
2991
|
+
.optional(),
|
|
2979
2992
|
},
|
|
2980
2993
|
}, handleSurprisingConnections);
|
|
2981
2994
|
tool("get_neighbors", {
|
package/dist/commands/project.js
CHANGED
|
@@ -46,6 +46,7 @@ exports.project = void 0;
|
|
|
46
46
|
const path = __importStar(require("node:path"));
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
48
|
const rows_handler_1 = require("../lib/daemon/rows-handler");
|
|
49
|
+
const project_coverage_1 = require("../lib/output/project-coverage");
|
|
49
50
|
const daemon_client_1 = require("../lib/utils/daemon-client");
|
|
50
51
|
const exit_1 = require("../lib/utils/exit");
|
|
51
52
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
@@ -80,9 +81,12 @@ exports.project = new commander_1.Command("project")
|
|
|
80
81
|
const projects = (0, project_registry_1.listProjects)();
|
|
81
82
|
const proj = projects.find((p) => p.root === root);
|
|
82
83
|
const { chunks, files, extEntries, dirEntries, roleEntries, topSymbols, entryPoints, } = overview;
|
|
84
|
+
const coverage = (0, project_coverage_1.projectCoverageNotice)(overview);
|
|
83
85
|
if (opts.agent) {
|
|
84
86
|
console.log(`name\t${projectName}`);
|
|
85
87
|
console.log(`root\t${root}`);
|
|
88
|
+
if (coverage)
|
|
89
|
+
console.log(`coverage\t${coverage}`);
|
|
86
90
|
console.log(`chunks\t${chunks}`);
|
|
87
91
|
console.log(`files\t${files}`);
|
|
88
92
|
console.log(`last_indexed\t${(_b = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _b !== void 0 ? _b : "unknown"}`);
|
|
@@ -100,7 +104,9 @@ exports.project = new commander_1.Command("project")
|
|
|
100
104
|
}
|
|
101
105
|
else {
|
|
102
106
|
console.log(`Project: ${projectName} (${root})`);
|
|
103
|
-
console.log(`Last indexed: ${(_c = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _c !== void 0 ? _c : "unknown"} • ${
|
|
107
|
+
console.log(`Last indexed: ${(_c = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _c !== void 0 ? _c : "unknown"} • ${(0, project_coverage_1.projectCounts)(overview)}\n`);
|
|
108
|
+
if (coverage)
|
|
109
|
+
console.log(`Coverage: ${coverage}\n`);
|
|
104
110
|
console.log(`Languages: ${extEntries.map(([ext, count]) => `${ext} (${Math.round((count / chunks) * 100)}%)`).join(", ")}\n`);
|
|
105
111
|
console.log("Directory structure:");
|
|
106
112
|
for (const [dir, data] of dirEntries) {
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* gmax skeleton - Show code skeleton (signatures without implementation)
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* gmax skeleton <file> # Skeleton of a file
|
|
7
|
-
* gmax skeleton <symbol> # Find symbol and skeleton its file
|
|
8
|
-
* gmax skeleton "query" # Search and skeleton top results
|
|
9
|
-
*/
|
|
10
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
3
|
if (k2 === undefined) k2 = k;
|
|
12
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -51,6 +43,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
51
43
|
};
|
|
52
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
53
45
|
exports.skeleton = void 0;
|
|
46
|
+
const agent_budget_1 = require("../lib/output/agent-budget");
|
|
47
|
+
/**
|
|
48
|
+
* gmax skeleton - Show code skeleton (signatures without implementation)
|
|
49
|
+
*
|
|
50
|
+
* Usage:
|
|
51
|
+
* gmax skeleton <file> # Skeleton of a file
|
|
52
|
+
* gmax skeleton <symbol> # Find symbol and skeleton its file
|
|
53
|
+
* gmax skeleton "query" # Search and skeleton top results
|
|
54
|
+
*/
|
|
54
55
|
const fs = __importStar(require("node:fs"));
|
|
55
56
|
const commander_1 = require("commander");
|
|
56
57
|
const config_1 = require("../config");
|
|
@@ -392,7 +393,9 @@ Examples:
|
|
|
392
393
|
}
|
|
393
394
|
else {
|
|
394
395
|
for (const result of results) {
|
|
395
|
-
console.log(
|
|
396
|
+
console.log(options.agent
|
|
397
|
+
? (0, agent_budget_1.boundedAgentText)(result.skeleton)
|
|
398
|
+
: result.skeleton);
|
|
396
399
|
console.log(""); // Blank line between files
|
|
397
400
|
}
|
|
398
401
|
}
|
|
@@ -423,6 +426,6 @@ function outputResult(result, options) {
|
|
|
423
426
|
}, null, 2));
|
|
424
427
|
}
|
|
425
428
|
else {
|
|
426
|
-
console.log(result.skeleton);
|
|
429
|
+
console.log(options.agent ? (0, agent_budget_1.boundedAgentText)(result.skeleton) : result.skeleton);
|
|
427
430
|
}
|
|
428
431
|
}
|
|
@@ -132,6 +132,7 @@ exports.surprises = new commander_1.Command("surprises")
|
|
|
132
132
|
.option("--min-sim <n>", "Minimum similarity 0-1", String(surprising_connections_1.DEFAULT_SURPRISE_OPTIONS.minSimilarity))
|
|
133
133
|
.option("--max-rows <n>", `Maximum indexed rows to scan (capped at ${surprising_connections_1.MAX_SURPRISE_ROWS})`, String(surprising_connections_1.DEFAULT_SURPRISE_OPTIONS.maxRows))
|
|
134
134
|
.option("--include-tests", "Include test files", false)
|
|
135
|
+
.option("--include-generated", "Include generated code, bindings and fixtures", false)
|
|
135
136
|
.option("--include-eval", "Include eval/experiment/script files", false)
|
|
136
137
|
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
137
138
|
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
|
|
@@ -180,6 +181,7 @@ exports.surprises = new commander_1.Command("surprises")
|
|
|
180
181
|
maxRows: parseIntOption(opts.maxRows, surprising_connections_1.DEFAULT_SURPRISE_OPTIONS.maxRows, surprising_connections_1.MAX_SURPRISE_ROWS),
|
|
181
182
|
includeTests: Boolean(opts.includeTests),
|
|
182
183
|
includeEval: Boolean(opts.includeEval),
|
|
184
|
+
includeGenerated: Boolean(opts.includeGenerated),
|
|
183
185
|
in: analysisIn,
|
|
184
186
|
exclude: analysisExclude,
|
|
185
187
|
};
|
|
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.SURPRISE_COLUMNS = exports.MAX_SURPRISE_ROWS = exports.DEFAULT_SURPRISE_OPTIONS = void 0;
|
|
46
46
|
exports.normalizeSurpriseOptions = normalizeSurpriseOptions;
|
|
47
47
|
exports.isTestPath = isTestPath;
|
|
48
|
+
exports.isGeneratedPath = isGeneratedPath;
|
|
48
49
|
exports.isEvalPath = isEvalPath;
|
|
49
50
|
exports.relPath = relPath;
|
|
50
51
|
exports.lineLabel = lineLabel;
|
|
@@ -73,6 +74,7 @@ exports.DEFAULT_SURPRISE_OPTIONS = {
|
|
|
73
74
|
maxRows: 50000,
|
|
74
75
|
includeTests: false,
|
|
75
76
|
includeEval: false,
|
|
77
|
+
includeGenerated: false,
|
|
76
78
|
};
|
|
77
79
|
exports.MAX_SURPRISE_ROWS = 100000;
|
|
78
80
|
/**
|
|
@@ -152,8 +154,8 @@ const TEST_FILE_RE = /\.(test|spec)\.[cm]?[jt]sx?$/i;
|
|
|
152
154
|
const NATIVE_TEST_DIR_RE = /(^|\/)\w+Tests?(\/|$)/;
|
|
153
155
|
const NATIVE_TEST_FILE_RE = /Tests?\.(swift|kt|java)$/;
|
|
154
156
|
function normalizeSurpriseOptions(opts = {}) {
|
|
155
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
156
|
-
return Object.assign(Object.assign(Object.assign({}, exports.DEFAULT_SURPRISE_OPTIONS), opts), { sample: Math.max(1, Math.floor((_a = opts.sample) !== null && _a !== void 0 ? _a : exports.DEFAULT_SURPRISE_OPTIONS.sample)), neighbors: Math.max(1, Math.floor((_b = opts.neighbors) !== null && _b !== void 0 ? _b : exports.DEFAULT_SURPRISE_OPTIONS.neighbors)), dirDepth: Math.max(1, Math.floor((_c = opts.dirDepth) !== null && _c !== void 0 ? _c : exports.DEFAULT_SURPRISE_OPTIONS.dirDepth)), minSimilarity: Math.max(0, (_d = opts.minSimilarity) !== null && _d !== void 0 ? _d : exports.DEFAULT_SURPRISE_OPTIONS.minSimilarity), maxRows: Math.max(1, Math.min(exports.MAX_SURPRISE_ROWS, Math.floor((_e = opts.maxRows) !== null && _e !== void 0 ? _e : exports.DEFAULT_SURPRISE_OPTIONS.maxRows))), includeTests: (_f = opts.includeTests) !== null && _f !== void 0 ? _f : exports.DEFAULT_SURPRISE_OPTIONS.includeTests, includeEval: (_g = opts.includeEval) !== null && _g !== void 0 ? _g : exports.DEFAULT_SURPRISE_OPTIONS.includeEval });
|
|
157
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
158
|
+
return Object.assign(Object.assign(Object.assign({}, exports.DEFAULT_SURPRISE_OPTIONS), opts), { sample: Math.max(1, Math.floor((_a = opts.sample) !== null && _a !== void 0 ? _a : exports.DEFAULT_SURPRISE_OPTIONS.sample)), neighbors: Math.max(1, Math.floor((_b = opts.neighbors) !== null && _b !== void 0 ? _b : exports.DEFAULT_SURPRISE_OPTIONS.neighbors)), dirDepth: Math.max(1, Math.floor((_c = opts.dirDepth) !== null && _c !== void 0 ? _c : exports.DEFAULT_SURPRISE_OPTIONS.dirDepth)), minSimilarity: Math.max(0, (_d = opts.minSimilarity) !== null && _d !== void 0 ? _d : exports.DEFAULT_SURPRISE_OPTIONS.minSimilarity), maxRows: Math.max(1, Math.min(exports.MAX_SURPRISE_ROWS, Math.floor((_e = opts.maxRows) !== null && _e !== void 0 ? _e : exports.DEFAULT_SURPRISE_OPTIONS.maxRows))), includeTests: (_f = opts.includeTests) !== null && _f !== void 0 ? _f : exports.DEFAULT_SURPRISE_OPTIONS.includeTests, includeEval: (_g = opts.includeEval) !== null && _g !== void 0 ? _g : exports.DEFAULT_SURPRISE_OPTIONS.includeEval, includeGenerated: (_h = opts.includeGenerated) !== null && _h !== void 0 ? _h : false });
|
|
157
159
|
}
|
|
158
160
|
function isTestPath(filePath) {
|
|
159
161
|
return (TEST_DIR_RE.test(filePath) ||
|
|
@@ -161,6 +163,11 @@ function isTestPath(filePath) {
|
|
|
161
163
|
NATIVE_TEST_DIR_RE.test(filePath) ||
|
|
162
164
|
NATIVE_TEST_FILE_RE.test(filePath));
|
|
163
165
|
}
|
|
166
|
+
function isGeneratedPath(filePath) {
|
|
167
|
+
return (/(^|\/)(?:generated|__generated__|bindings|fixtures|__fixtures__)(\/|$)/i.test(filePath) ||
|
|
168
|
+
/\.generated\.[^.]+$/i.test(filePath) ||
|
|
169
|
+
/\/[^/]*GraphQL\/Sources\/(?:Schema|Operations)\//i.test(filePath));
|
|
170
|
+
}
|
|
164
171
|
function isEvalPath(filePath) {
|
|
165
172
|
return (/(^|\/)src\/eval[^/]*\.ts$/i.test(filePath) ||
|
|
166
173
|
/(^|\/)(benchmarks?|experiments|scripts)(\/|$)/i.test(filePath));
|
|
@@ -477,6 +484,8 @@ function filterableCodeMeta(row, opts) {
|
|
|
477
484
|
return false;
|
|
478
485
|
if (!opts.includeEval && isEvalPath(row.relPath))
|
|
479
486
|
return false;
|
|
487
|
+
if (!opts.includeGenerated && isGeneratedPath(row.relPath))
|
|
488
|
+
return false;
|
|
480
489
|
return row.definedSymbols.length > 0;
|
|
481
490
|
}
|
|
482
491
|
function hasCodeContent(content) {
|
|
@@ -633,6 +642,7 @@ function analyzeSurprisingConnections(table_1, projectRoot_1) {
|
|
|
633
642
|
weakCode: 0,
|
|
634
643
|
tests: 0,
|
|
635
644
|
evalHarness: 0,
|
|
645
|
+
generated: 0,
|
|
636
646
|
sameDirBucket: 0,
|
|
637
647
|
graphEdge: 0,
|
|
638
648
|
belowThreshold: 0,
|
|
@@ -671,6 +681,10 @@ function analyzeSurprisingConnections(table_1, projectRoot_1) {
|
|
|
671
681
|
filters.tests++;
|
|
672
682
|
continue;
|
|
673
683
|
}
|
|
684
|
+
if (!opts.includeGenerated && isGeneratedPath(target.relPath)) {
|
|
685
|
+
filters.generated++;
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
674
688
|
if (!opts.includeEval && isEvalPath(target.relPath)) {
|
|
675
689
|
filters.evalHarness++;
|
|
676
690
|
continue;
|
|
@@ -84,6 +84,7 @@ const root_availability_1 = require("../utils/root-availability");
|
|
|
84
84
|
const safety_latch_1 = require("../utils/safety-latch");
|
|
85
85
|
const watcher_store_1 = require("../utils/watcher-store");
|
|
86
86
|
const pool_1 = require("../workers/pool");
|
|
87
|
+
const document_search_handler_1 = require("./document-search-handler");
|
|
87
88
|
const ipc_handler_1 = require("./ipc-handler");
|
|
88
89
|
const mlx_server_manager_1 = require("./mlx-server-manager");
|
|
89
90
|
const paused_reads_1 = require("./paused-reads");
|
|
@@ -1021,6 +1022,55 @@ class Daemon {
|
|
|
1021
1022
|
? { queue: progress.queue }
|
|
1022
1023
|
: {})), { failedFiles: Math.max((_d = progress === null || progress === void 0 ? void 0 : progress.failedFiles) !== null && _d !== void 0 ? _d : 0, (_e = health.failedFiles) !== null && _e !== void 0 ? _e : 0) });
|
|
1023
1024
|
}
|
|
1025
|
+
/** Separate shared-operation path: never paused keyword fallback or runtime setup. */
|
|
1026
|
+
documentSearch(cmd, signal) {
|
|
1027
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1028
|
+
const state = () => this.pausedReason !== null || (0, autostart_1.daemonStartDeniedReason)()
|
|
1029
|
+
? "host_pressure"
|
|
1030
|
+
: this.shuttingDown || this.recycling
|
|
1031
|
+
? "busy"
|
|
1032
|
+
: !this.vectorDb || !this.metaCache
|
|
1033
|
+
? "store_unavailable"
|
|
1034
|
+
: this.activeConfigurationError()
|
|
1035
|
+
? "embedding_mismatch"
|
|
1036
|
+
: "ready";
|
|
1037
|
+
return this.operations.runShared("documents", signal, (operationSignal) => (0, document_search_handler_1.handleDocumentSearch)({
|
|
1038
|
+
home: config_1.PATHS.globalRoot,
|
|
1039
|
+
state,
|
|
1040
|
+
generation: () => this.resourceGenerationId(),
|
|
1041
|
+
embeddingState: (root) => {
|
|
1042
|
+
const project = (0, project_registry_1.getProject)(root);
|
|
1043
|
+
if ((project === null || project === void 0 ? void 0 : project.status) !== "indexed")
|
|
1044
|
+
return "no_index";
|
|
1045
|
+
if (!this.activeGeneration)
|
|
1046
|
+
return "embedding_unavailable";
|
|
1047
|
+
if (this.workerPool &&
|
|
1048
|
+
this.workerPool.generation.fingerprint !==
|
|
1049
|
+
this.activeGeneration.fingerprint)
|
|
1050
|
+
return "embedding_mismatch";
|
|
1051
|
+
try {
|
|
1052
|
+
return (0, embedding_generation_1.compareEmbeddingGeneration)(project, this.activeGeneration)
|
|
1053
|
+
.state === "stale"
|
|
1054
|
+
? "embedding_mismatch"
|
|
1055
|
+
: "ready";
|
|
1056
|
+
}
|
|
1057
|
+
catch (_a) {
|
|
1058
|
+
return "embedding_mismatch";
|
|
1059
|
+
}
|
|
1060
|
+
},
|
|
1061
|
+
meta: (file) => { var _a; return (_a = this.metaCache) === null || _a === void 0 ? void 0 : _a.get(file); },
|
|
1062
|
+
queryState: () => { var _a; var _b; return (_b = (_a = this.workerPool) === null || _a === void 0 ? void 0 : _a.existingQueryState()) !== null && _b !== void 0 ? _b : "embedding_unavailable"; },
|
|
1063
|
+
encode: (query, requestSignal) => this.workerPool
|
|
1064
|
+
? this.workerPool.encodeQueryExisting(query, requestSignal)
|
|
1065
|
+
: Promise.reject(new Error("embedding_unavailable")),
|
|
1066
|
+
table: () => this.vectorDb
|
|
1067
|
+
? this.vectorDb.existingTableForRead()
|
|
1068
|
+
: Promise.reject(new Error("store_unavailable")),
|
|
1069
|
+
indexState: (root) => this.indexState(root),
|
|
1070
|
+
lastIndexed: (root) => { var _a; return (_a = (0, project_registry_1.getProject)(root)) === null || _a === void 0 ? void 0 : _a.lastIndexed; },
|
|
1071
|
+
}, cmd, operationSignal));
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1024
1074
|
search(payload, signal) {
|
|
1025
1075
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1026
1076
|
// Search handling lives in search-handler.ts (Phase 12 split). The daemon
|