grepmax 0.16.2 → 0.16.4
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/dist/commands/diff.js +8 -140
- package/dist/commands/extract.js +20 -0
- package/dist/commands/log.js +231 -0
- package/dist/commands/peek.js +19 -0
- package/dist/commands/recent.js +7 -129
- package/dist/commands/related.js +73 -1
- package/dist/commands/search.js +71 -50
- package/dist/commands/test-find.js +10 -2
- package/dist/commands/trace.js +141 -4
- package/dist/index.js +2 -0
- package/dist/lib/graph/impact.js +51 -0
- package/dist/lib/utils/git.js +90 -0
- package/dist/lib/utils/tests-footer.js +78 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/skills/grepmax/SKILL.md +22 -13
package/dist/commands/diff.js
CHANGED
|
@@ -1,145 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.diff = void 0;
|
|
13
4
|
const commander_1 = require("commander");
|
|
14
|
-
const searcher_1 = require("../lib/search/searcher");
|
|
15
|
-
const vector_db_1 = require("../lib/store/vector-db");
|
|
16
|
-
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
17
|
-
const exit_1 = require("../lib/utils/exit");
|
|
18
|
-
const git_1 = require("../lib/utils/git");
|
|
19
|
-
const project_registry_1 = require("../lib/utils/project-registry");
|
|
20
|
-
const project_root_1 = require("../lib/utils/project-root");
|
|
21
|
-
const arrow_1 = require("../lib/utils/arrow");
|
|
22
5
|
exports.diff = new commander_1.Command("diff")
|
|
23
|
-
.description("
|
|
24
|
-
.argument("[ref]", "
|
|
25
|
-
.
|
|
26
|
-
.
|
|
27
|
-
.
|
|
28
|
-
.
|
|
29
|
-
.
|
|
30
|
-
|
|
31
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
32
|
-
const limit = Math.min(Math.max(Number.parseInt(opts.maxCount || "10", 10), 1), 50);
|
|
33
|
-
let vectorDb = null;
|
|
34
|
-
try {
|
|
35
|
-
const root = (0, project_registry_1.resolveRootOrExit)(opts.root);
|
|
36
|
-
if (root === null)
|
|
37
|
-
return;
|
|
38
|
-
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
|
|
39
|
-
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
40
|
-
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
41
|
-
const changedFiles = (0, git_1.getChangedFiles)(ref, projectRoot);
|
|
42
|
-
if (changedFiles.length === 0) {
|
|
43
|
-
console.log(ref ? `No changes found relative to ${ref}.` : "No uncommitted changes found.");
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const rel = (p) => p.startsWith(`${projectRoot}/`) ? p.slice(projectRoot.length + 1) : p;
|
|
47
|
-
if (opts.query) {
|
|
48
|
-
// Semantic search scoped to changed files
|
|
49
|
-
const searcher = new searcher_1.Searcher(vectorDb);
|
|
50
|
-
const response = yield searcher.search(opts.query, limit, { rerank: true }, Object.assign({}, (opts.role ? { role: opts.role } : {})), projectRoot);
|
|
51
|
-
// Filter results to only changed files
|
|
52
|
-
const changedSet = new Set(changedFiles);
|
|
53
|
-
const filtered = response.data.filter((r) => {
|
|
54
|
-
var _a;
|
|
55
|
-
const p = ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.path) || r.path || "";
|
|
56
|
-
return changedSet.has(p);
|
|
57
|
-
});
|
|
58
|
-
if (filtered.length === 0) {
|
|
59
|
-
console.log("No indexed results found in changed files for that query.");
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (opts.agent) {
|
|
63
|
-
for (const r of filtered.slice(0, limit)) {
|
|
64
|
-
const p = String(r.path || ((_b = r.metadata) === null || _b === void 0 ? void 0 : _b.path) || "");
|
|
65
|
-
const line = Number((_c = r.start_line) !== null && _c !== void 0 ? _c : 0);
|
|
66
|
-
const sym = (_e = (_d = (0, arrow_1.toArr)(r.defined_symbols)) === null || _d === void 0 ? void 0 : _d[0]) !== null && _e !== void 0 ? _e : "";
|
|
67
|
-
const role = String(r.role || "IMPL");
|
|
68
|
-
console.log(`${rel(p)}:${line + 1} ${sym} [${role}]`);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
else {
|
|
72
|
-
console.log(`Changed files matching "${opts.query}":\n`);
|
|
73
|
-
for (const r of filtered.slice(0, limit)) {
|
|
74
|
-
const p = String(r.path || ((_f = r.metadata) === null || _f === void 0 ? void 0 : _f.path) || "");
|
|
75
|
-
const line = Number((_g = r.start_line) !== null && _g !== void 0 ? _g : 0);
|
|
76
|
-
const sym = (_j = (_h = (0, arrow_1.toArr)(r.defined_symbols)) === null || _h === void 0 ? void 0 : _h[0]) !== null && _j !== void 0 ? _j : "";
|
|
77
|
-
const role = String(r.role || "IMPLEMENTATION");
|
|
78
|
-
const score = (_l = (_k = r.score) === null || _k === void 0 ? void 0 : _k.toFixed(3)) !== null && _l !== void 0 ? _l : "?";
|
|
79
|
-
console.log(` ${rel(p)}:${line + 1} ${sym} [${role}] (${score})`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
else {
|
|
84
|
-
// No query — list changed files with their indexed symbols
|
|
85
|
-
const table = yield vectorDb.ensureTable();
|
|
86
|
-
if (opts.agent) {
|
|
87
|
-
for (const file of changedFiles) {
|
|
88
|
-
const chunks = yield table
|
|
89
|
-
.query()
|
|
90
|
-
.select(["path", "start_line", "defined_symbols", "role"])
|
|
91
|
-
.where(`path = '${(0, filter_builder_1.escapeSqlString)(file)}'`)
|
|
92
|
-
.limit(50)
|
|
93
|
-
.toArray();
|
|
94
|
-
if (chunks.length === 0) {
|
|
95
|
-
console.log(`${rel(file)}\t(not indexed)`);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
for (const chunk of chunks) {
|
|
99
|
-
const sym = (_o = (_m = (0, arrow_1.toArr)(chunk.defined_symbols)) === null || _m === void 0 ? void 0 : _m[0]) !== null && _o !== void 0 ? _o : "";
|
|
100
|
-
const line = (_p = chunk.start_line) !== null && _p !== void 0 ? _p : 0;
|
|
101
|
-
const role = (chunk.role || "IMPL").slice(0, 4);
|
|
102
|
-
if (sym) {
|
|
103
|
-
console.log(`${rel(file)}:${line + 1}\t${sym}\t[${role}]`);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
console.log(`${changedFiles.length} changed file${changedFiles.length === 1 ? "" : "s"}${ref ? ` (vs ${ref})` : ""}:\n`);
|
|
111
|
-
for (const file of changedFiles) {
|
|
112
|
-
const chunks = yield table
|
|
113
|
-
.query()
|
|
114
|
-
.select(["defined_symbols", "role"])
|
|
115
|
-
.where(`path = '${(0, filter_builder_1.escapeSqlString)(file)}'`)
|
|
116
|
-
.limit(50)
|
|
117
|
-
.toArray();
|
|
118
|
-
const symbols = chunks
|
|
119
|
-
.flatMap((c) => (0, arrow_1.toArr)(c.defined_symbols))
|
|
120
|
-
.filter(Boolean);
|
|
121
|
-
if (symbols.length > 0) {
|
|
122
|
-
console.log(` ${rel(file)} (${symbols.length} symbol${symbols.length === 1 ? "" : "s"}: ${symbols.slice(0, 5).join(", ")}${symbols.length > 5 ? "..." : ""})`);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
console.log(` ${rel(file)}`);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
133
|
-
console.error("Diff failed:", msg);
|
|
134
|
-
process.exitCode = 1;
|
|
135
|
-
}
|
|
136
|
-
finally {
|
|
137
|
-
if (vectorDb) {
|
|
138
|
-
try {
|
|
139
|
-
yield vectorDb.close();
|
|
140
|
-
}
|
|
141
|
-
catch (_q) { }
|
|
142
|
-
}
|
|
143
|
-
yield (0, exit_1.gracefulExit)();
|
|
144
|
-
}
|
|
145
|
-
}));
|
|
6
|
+
.description("[deprecated] Use 'gmax log' instead")
|
|
7
|
+
.argument("[ref]", "(ignored — diff is deprecated)")
|
|
8
|
+
.allowUnknownOption(true)
|
|
9
|
+
.allowExcessArguments(true)
|
|
10
|
+
.action(() => {
|
|
11
|
+
console.error("gmax diff is deprecated; use 'gmax log <path-or-symbol>' instead");
|
|
12
|
+
process.exitCode = 1;
|
|
13
|
+
});
|
package/dist/commands/extract.js
CHANGED
|
@@ -110,6 +110,7 @@ exports.extract = new commander_1.Command("extract")
|
|
|
110
110
|
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => (prev ? [...prev, value] : [value]))
|
|
111
111
|
.option("--agent", "Compact output for AI agents", false)
|
|
112
112
|
.option("--imports", "Prepend file imports", false)
|
|
113
|
+
.option("--no-tests", "Suppress the tests footer")
|
|
113
114
|
.action((symbol, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
114
115
|
var _a;
|
|
115
116
|
let vectorDb = null;
|
|
@@ -176,6 +177,16 @@ exports.extract = new commander_1.Command("extract")
|
|
|
176
177
|
}
|
|
177
178
|
console.log(`${relPath}:${startLine + 1}-${endLine + 1}`);
|
|
178
179
|
console.log(body.join("\n"));
|
|
180
|
+
if (opts.tests !== false) {
|
|
181
|
+
const { fetchTestsForFooter, renderTestsFooterAgent } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
|
|
182
|
+
const tests = yield fetchTestsForFooter(symbol, vectorDb, scope.pathPrefix, scope.excludePrefixes);
|
|
183
|
+
if (tests && tests.length > 0) {
|
|
184
|
+
console.log("--- tests:");
|
|
185
|
+
for (const line of renderTestsFooterAgent(tests, projectRoot)) {
|
|
186
|
+
console.log(line);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
179
190
|
}
|
|
180
191
|
else {
|
|
181
192
|
// Rich output with line numbers
|
|
@@ -207,6 +218,15 @@ exports.extract = new commander_1.Command("extract")
|
|
|
207
218
|
.join(", ");
|
|
208
219
|
console.log(`\n${style.dim(`Also defined in: ${otherLocs}`)}`);
|
|
209
220
|
}
|
|
221
|
+
if (!opts.agent && opts.tests !== false) {
|
|
222
|
+
const { fetchTestsForFooter, renderTestsFooterHuman } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
|
|
223
|
+
const tests = yield fetchTestsForFooter(symbol, vectorDb, scope.pathPrefix, scope.excludePrefixes);
|
|
224
|
+
if (tests && tests.length > 0) {
|
|
225
|
+
for (const line of renderTestsFooterHuman(tests, projectRoot)) {
|
|
226
|
+
console.log(line);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
210
230
|
}
|
|
211
231
|
catch (error) {
|
|
212
232
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.log = void 0;
|
|
46
|
+
const fs = __importStar(require("node:fs"));
|
|
47
|
+
const path = __importStar(require("node:path"));
|
|
48
|
+
const commander_1 = require("commander");
|
|
49
|
+
const vector_db_1 = require("../lib/store/vector-db");
|
|
50
|
+
const exit_1 = require("../lib/utils/exit");
|
|
51
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
52
|
+
const git_1 = require("../lib/utils/git");
|
|
53
|
+
const project_registry_1 = require("../lib/utils/project-registry");
|
|
54
|
+
const project_root_1 = require("../lib/utils/project-root");
|
|
55
|
+
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
56
|
+
const style = {
|
|
57
|
+
bold: (s) => (useColors ? `\x1b[1m${s}\x1b[22m` : s),
|
|
58
|
+
dim: (s) => (useColors ? `\x1b[2m${s}\x1b[22m` : s),
|
|
59
|
+
cyan: (s) => (useColors ? `\x1b[36m${s}\x1b[39m` : s),
|
|
60
|
+
yellow: (s) => (useColors ? `\x1b[33m${s}\x1b[39m` : s),
|
|
61
|
+
};
|
|
62
|
+
function relativize(p, projectRoot) {
|
|
63
|
+
const prefix = projectRoot.endsWith("/") ? projectRoot : `${projectRoot}/`;
|
|
64
|
+
return p.startsWith(prefix) ? p.slice(prefix.length) : p;
|
|
65
|
+
}
|
|
66
|
+
function resolveSymbolPaths(vectorDb, symbol, projectRoot, inOpt, excludeOpt) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
const { resolveScope, buildScopeWhere } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/scope-filter")));
|
|
69
|
+
const scope = resolveScope({
|
|
70
|
+
projectRoot,
|
|
71
|
+
in: inOpt,
|
|
72
|
+
exclude: excludeOpt,
|
|
73
|
+
});
|
|
74
|
+
const where = buildScopeWhere(scope, `array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(symbol)}')`);
|
|
75
|
+
const table = yield vectorDb.ensureTable();
|
|
76
|
+
const rows = yield table
|
|
77
|
+
.query()
|
|
78
|
+
.select(["path"])
|
|
79
|
+
.where(where)
|
|
80
|
+
.limit(50)
|
|
81
|
+
.toArray();
|
|
82
|
+
const paths = new Set();
|
|
83
|
+
for (const row of rows) {
|
|
84
|
+
const p = String(row.path || "");
|
|
85
|
+
if (p)
|
|
86
|
+
paths.add(p);
|
|
87
|
+
}
|
|
88
|
+
return [...paths];
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
function printHuman(commits, projectRoot, targetPaths) {
|
|
92
|
+
for (const c of commits) {
|
|
93
|
+
const header = `${style.yellow(c.shortHash)} ${c.author} ${style.dim(c.relDate)} ${style.bold(c.subject)}`;
|
|
94
|
+
console.log(header);
|
|
95
|
+
const stat = `${c.filesChanged} file${c.filesChanged === 1 ? "" : "s"} changed, +${c.insertions} / -${c.deletions}`;
|
|
96
|
+
console.log(` ${style.dim(stat)}`);
|
|
97
|
+
if (targetPaths && targetPaths.length > 1) {
|
|
98
|
+
const targetSet = new Set(targetPaths);
|
|
99
|
+
const touched = c.numstatLines
|
|
100
|
+
.filter((n) => targetSet.has(n.path) || targetSet.has(path.resolve(projectRoot, n.path)))
|
|
101
|
+
.map((n) => relativize(n.path, projectRoot));
|
|
102
|
+
if (touched.length > 0) {
|
|
103
|
+
console.log(` ${style.dim(`via: ${touched.join(", ")}`)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
console.log();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function printAgent(commits, projectRoot, targetPaths) {
|
|
110
|
+
const targetSet = targetPaths && targetPaths.length > 0 ? new Set(targetPaths) : null;
|
|
111
|
+
for (const c of commits) {
|
|
112
|
+
let touched = "";
|
|
113
|
+
if (targetSet) {
|
|
114
|
+
const touchedPaths = c.numstatLines
|
|
115
|
+
.filter((n) => targetSet.has(n.path) || targetSet.has(path.resolve(projectRoot, n.path)))
|
|
116
|
+
.map((n) => relativize(n.path, projectRoot));
|
|
117
|
+
touched = touchedPaths.join(",");
|
|
118
|
+
}
|
|
119
|
+
const subject = c.subject.replace(/\t/g, " ");
|
|
120
|
+
console.log(`${c.shortHash}\t${c.isoDate}\t${c.author}\t${subject}\t${c.filesChanged}\t${c.insertions}\t${c.deletions}\t${touched}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.log = new commander_1.Command("log")
|
|
124
|
+
.description("Show git commit history for a path or symbol")
|
|
125
|
+
.argument("<path-or-symbol>", "File/dir path or symbol name")
|
|
126
|
+
.option("-l, --limit <n>", "Max commits (default 20)", "20")
|
|
127
|
+
.option("--since <date>", "Filter by date (e.g. '2 weeks ago', '2025-01-01')")
|
|
128
|
+
.option("--from <ref>", "Show commits since git ref (translates to <ref>..HEAD)")
|
|
129
|
+
.option("--author <name>", "Filter by author")
|
|
130
|
+
.option("--root <dir>", "Project root directory")
|
|
131
|
+
.option("--in <subpath>", "Restrict symbol resolution to a sub-path (repeatable; symbol mode only)", (value, prev) => prev ? [...prev, value] : [value])
|
|
132
|
+
.option("--exclude <subpath>", "Exclude a sub-path from symbol resolution (repeatable; symbol mode only)", (value, prev) => prev ? [...prev, value] : [value])
|
|
133
|
+
.option("--no-follow", "Disable rename tracking (default: enabled for single files in path mode)")
|
|
134
|
+
.option("--agent", "Compact TSV output for AI agents", false)
|
|
135
|
+
.action((arg, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
136
|
+
var _a;
|
|
137
|
+
const limit = Math.min(Math.max(Number.parseInt(opts.limit || "20", 10), 1), 200);
|
|
138
|
+
const root = (0, project_registry_1.resolveRootOrExit)(opts.root);
|
|
139
|
+
if (root === null)
|
|
140
|
+
return;
|
|
141
|
+
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
|
|
142
|
+
let vectorDb = null;
|
|
143
|
+
try {
|
|
144
|
+
// 1. Try arg as path (relative to projectRoot, then cwd).
|
|
145
|
+
const candidates = [
|
|
146
|
+
path.resolve(projectRoot, arg),
|
|
147
|
+
path.resolve(process.cwd(), arg),
|
|
148
|
+
];
|
|
149
|
+
let resolvedPath = null;
|
|
150
|
+
for (const c of candidates) {
|
|
151
|
+
if (fs.existsSync(c)) {
|
|
152
|
+
resolvedPath = c;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (resolvedPath) {
|
|
157
|
+
const isDir = fs.statSync(resolvedPath).isDirectory();
|
|
158
|
+
const commits = (0, git_1.getCommitHistory)({
|
|
159
|
+
paths: [resolvedPath],
|
|
160
|
+
limit,
|
|
161
|
+
since: opts.since,
|
|
162
|
+
from: opts.from,
|
|
163
|
+
author: opts.author,
|
|
164
|
+
follow: !isDir && opts.follow !== false,
|
|
165
|
+
cwd: projectRoot,
|
|
166
|
+
});
|
|
167
|
+
if (commits.length === 0) {
|
|
168
|
+
console.log(opts.agent
|
|
169
|
+
? ""
|
|
170
|
+
: `No commits found for ${relativize(resolvedPath, projectRoot)}.`);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (opts.agent)
|
|
174
|
+
printAgent(commits, projectRoot, null);
|
|
175
|
+
else
|
|
176
|
+
printHuman(commits, projectRoot, null);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
// 2. Try arg as symbol via index lookup.
|
|
180
|
+
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
181
|
+
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
182
|
+
const symbolPaths = yield resolveSymbolPaths(vectorDb, arg, projectRoot, opts.in, opts.exclude);
|
|
183
|
+
if (symbolPaths.length === 0) {
|
|
184
|
+
console.error(`gmax log: no file or symbol matched '${arg}'`);
|
|
185
|
+
if (!opts.agent) {
|
|
186
|
+
console.error("");
|
|
187
|
+
console.error("Try `gmax search <term>` to find a symbol, or pass a file path.");
|
|
188
|
+
}
|
|
189
|
+
process.exitCode = 1;
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const commits = (0, git_1.getCommitHistory)({
|
|
193
|
+
paths: symbolPaths,
|
|
194
|
+
limit,
|
|
195
|
+
since: opts.since,
|
|
196
|
+
from: opts.from,
|
|
197
|
+
author: opts.author,
|
|
198
|
+
follow: false,
|
|
199
|
+
cwd: projectRoot,
|
|
200
|
+
});
|
|
201
|
+
if (commits.length === 0) {
|
|
202
|
+
console.log(opts.agent
|
|
203
|
+
? ""
|
|
204
|
+
: `No commits found touching defining files for symbol '${arg}'.`);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (opts.agent)
|
|
208
|
+
printAgent(commits, projectRoot, symbolPaths);
|
|
209
|
+
else {
|
|
210
|
+
if (symbolPaths.length > 1) {
|
|
211
|
+
console.log(style.dim(`// '${arg}' defined in ${symbolPaths.length} files; commits merged by hash.`));
|
|
212
|
+
console.log();
|
|
213
|
+
}
|
|
214
|
+
printHuman(commits, projectRoot, symbolPaths);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
219
|
+
console.error("Log failed:", msg);
|
|
220
|
+
process.exitCode = 1;
|
|
221
|
+
}
|
|
222
|
+
finally {
|
|
223
|
+
if (vectorDb) {
|
|
224
|
+
try {
|
|
225
|
+
yield vectorDb.close();
|
|
226
|
+
}
|
|
227
|
+
catch (_b) { }
|
|
228
|
+
}
|
|
229
|
+
yield (0, exit_1.gracefulExit)();
|
|
230
|
+
}
|
|
231
|
+
}));
|
package/dist/commands/peek.js
CHANGED
|
@@ -98,6 +98,7 @@ exports.peek = new commander_1.Command("peek")
|
|
|
98
98
|
.option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => (prev ? [...prev, value] : [value]))
|
|
99
99
|
.option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => (prev ? [...prev, value] : [value]))
|
|
100
100
|
.option("--agent", "Compact output for AI agents", false)
|
|
101
|
+
.option("--no-tests", "Suppress the tests footer")
|
|
101
102
|
.action((symbol, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
102
103
|
var _a;
|
|
103
104
|
let vectorDb = null;
|
|
@@ -225,6 +226,15 @@ exports.peek = new commander_1.Command("peek")
|
|
|
225
226
|
if (calleeList.length > MAX_CALLEES) {
|
|
226
227
|
console.log(`-> ... ${calleeList.length - MAX_CALLEES} more`);
|
|
227
228
|
}
|
|
229
|
+
if (opts.tests !== false) {
|
|
230
|
+
const { fetchTestsForFooter, renderTestsFooterAgent } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
|
|
231
|
+
const tests = yield fetchTestsForFooter(symbol, vectorDb, scope.pathPrefix, scope.excludePrefixes);
|
|
232
|
+
if (tests && tests.length > 0) {
|
|
233
|
+
for (const line of renderTestsFooterAgent(tests, projectRoot)) {
|
|
234
|
+
console.log(line);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
228
238
|
}
|
|
229
239
|
else {
|
|
230
240
|
// Rich output
|
|
@@ -276,6 +286,15 @@ exports.peek = new commander_1.Command("peek")
|
|
|
276
286
|
else {
|
|
277
287
|
console.log(style.dim("No known callees."));
|
|
278
288
|
}
|
|
289
|
+
if (opts.tests !== false) {
|
|
290
|
+
const { fetchTestsForFooter, renderTestsFooterHuman } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/tests-footer")));
|
|
291
|
+
const tests = yield fetchTestsForFooter(symbol, vectorDb, scope.pathPrefix, scope.excludePrefixes);
|
|
292
|
+
if (tests && tests.length > 0) {
|
|
293
|
+
for (const line of renderTestsFooterHuman(tests, projectRoot)) {
|
|
294
|
+
console.log(line);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
279
298
|
}
|
|
280
299
|
}
|
|
281
300
|
catch (error) {
|
package/dist/commands/recent.js
CHANGED
|
@@ -1,134 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
45
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
46
|
-
var m = o[Symbol.asyncIterator], i;
|
|
47
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
48
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
49
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
50
|
-
};
|
|
51
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
3
|
exports.recent = void 0;
|
|
53
|
-
const path = __importStar(require("node:path"));
|
|
54
4
|
const commander_1 = require("commander");
|
|
55
|
-
const config_1 = require("../config");
|
|
56
|
-
const meta_cache_1 = require("../lib/store/meta-cache");
|
|
57
|
-
const exit_1 = require("../lib/utils/exit");
|
|
58
|
-
const format_helpers_1 = require("../lib/utils/format-helpers");
|
|
59
|
-
const project_registry_1 = require("../lib/utils/project-registry");
|
|
60
|
-
const project_root_1 = require("../lib/utils/project-root");
|
|
61
5
|
exports.recent = new commander_1.Command("recent")
|
|
62
|
-
.description("
|
|
63
|
-
.
|
|
64
|
-
.
|
|
65
|
-
.
|
|
66
|
-
.
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const limit = Math.min(Math.max(Number.parseInt(opts.limit || "20", 10), 1), 50);
|
|
70
|
-
try {
|
|
71
|
-
const resolvedRoot = (0, project_registry_1.resolveRootOrExit)(opts.root);
|
|
72
|
-
if (resolvedRoot === null)
|
|
73
|
-
return;
|
|
74
|
-
const root = (_d = (0, project_root_1.findProjectRoot)(resolvedRoot)) !== null && _d !== void 0 ? _d : resolvedRoot;
|
|
75
|
-
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
76
|
-
const metaCache = new meta_cache_1.MetaCache(config_1.PATHS.lmdbPath);
|
|
77
|
-
try {
|
|
78
|
-
const files = [];
|
|
79
|
-
try {
|
|
80
|
-
for (var _e = true, _f = __asyncValues(metaCache.entries()), _g; _g = yield _f.next(), _a = _g.done, !_a; _e = true) {
|
|
81
|
-
_c = _g.value;
|
|
82
|
-
_e = false;
|
|
83
|
-
const { path: p, entry } = _c;
|
|
84
|
-
if (p.startsWith(prefix)) {
|
|
85
|
-
files.push({ path: p, mtimeMs: entry.mtimeMs });
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
90
|
-
finally {
|
|
91
|
-
try {
|
|
92
|
-
if (!_e && !_a && (_b = _f.return)) yield _b.call(_f);
|
|
93
|
-
}
|
|
94
|
-
finally { if (e_1) throw e_1.error; }
|
|
95
|
-
}
|
|
96
|
-
files.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
97
|
-
const top = files.slice(0, limit);
|
|
98
|
-
if (top.length === 0) {
|
|
99
|
-
console.log(`No indexed files found for ${root}`);
|
|
100
|
-
console.log("\nTry: `gmax add` to register and index this project, or `gmax status` to see what's indexed.");
|
|
101
|
-
process.exitCode = 1;
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
const now = Date.now();
|
|
105
|
-
if (opts.agent) {
|
|
106
|
-
for (const f of top) {
|
|
107
|
-
const rel = f.path.startsWith(prefix)
|
|
108
|
-
? f.path.slice(prefix.length)
|
|
109
|
-
: f.path;
|
|
110
|
-
console.log(`${rel}\t${(0, format_helpers_1.formatTimeAgo)(now - f.mtimeMs)}`);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
console.log(`Recent changes in ${path.basename(root)} (${top.length} most recent):\n`);
|
|
115
|
-
for (const f of top) {
|
|
116
|
-
const rel = f.path.startsWith(prefix)
|
|
117
|
-
? f.path.slice(prefix.length)
|
|
118
|
-
: f.path;
|
|
119
|
-
const ago = (0, format_helpers_1.formatTimeAgo)(now - f.mtimeMs);
|
|
120
|
-
console.log(` ${ago.padEnd(10)} ${rel}`);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
finally {
|
|
125
|
-
yield metaCache.close();
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
130
|
-
console.error("Recent changes failed:", msg);
|
|
131
|
-
process.exitCode = 1;
|
|
132
|
-
}
|
|
133
|
-
yield (0, exit_1.gracefulExit)();
|
|
134
|
-
}));
|
|
6
|
+
.description("[deprecated] Use 'gmax log' instead")
|
|
7
|
+
.allowUnknownOption(true)
|
|
8
|
+
.allowExcessArguments(true)
|
|
9
|
+
.action(() => {
|
|
10
|
+
console.error("gmax recent is deprecated; use 'gmax log <path-or-symbol>' instead");
|
|
11
|
+
process.exitCode = 1;
|
|
12
|
+
});
|