grepmax 0.7.20 → 0.7.22
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/project.js +175 -0
- package/dist/commands/recent.js +131 -0
- package/dist/commands/related.js +170 -0
- package/dist/commands/skeleton.js +43 -0
- package/dist/commands/trace.js +4 -2
- package/dist/index.js +6 -0
- package/dist/lib/output/formatter.js +23 -7
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,175 @@
|
|
|
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.project = void 0;
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const commander_1 = require("commander");
|
|
48
|
+
const vector_db_1 = require("../lib/store/vector-db");
|
|
49
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
50
|
+
const exit_1 = require("../lib/utils/exit");
|
|
51
|
+
const project_registry_1 = require("../lib/utils/project-registry");
|
|
52
|
+
const project_root_1 = require("../lib/utils/project-root");
|
|
53
|
+
function toArr(val) {
|
|
54
|
+
if (val && typeof val.toArray === "function") {
|
|
55
|
+
return val.toArray();
|
|
56
|
+
}
|
|
57
|
+
return Array.isArray(val) ? val : [];
|
|
58
|
+
}
|
|
59
|
+
exports.project = new commander_1.Command("project")
|
|
60
|
+
.description("Show project overview — languages, structure, key symbols")
|
|
61
|
+
.option("--root <dir>", "Project root (defaults to current directory)")
|
|
62
|
+
.action((opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
+
var _a, _b, _c;
|
|
64
|
+
let vectorDb = null;
|
|
65
|
+
try {
|
|
66
|
+
const root = opts.root
|
|
67
|
+
? (_a = (0, project_root_1.findProjectRoot)(path.resolve(opts.root))) !== null && _a !== void 0 ? _a : path.resolve(opts.root)
|
|
68
|
+
: (_b = (0, project_root_1.findProjectRoot)(process.cwd())) !== null && _b !== void 0 ? _b : process.cwd();
|
|
69
|
+
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
70
|
+
const projectName = path.basename(root);
|
|
71
|
+
const paths = (0, project_root_1.ensureProjectPaths)(root);
|
|
72
|
+
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
73
|
+
const table = yield vectorDb.ensureTable();
|
|
74
|
+
const rows = yield table
|
|
75
|
+
.query()
|
|
76
|
+
.select([
|
|
77
|
+
"path",
|
|
78
|
+
"role",
|
|
79
|
+
"is_exported",
|
|
80
|
+
"complexity",
|
|
81
|
+
"defined_symbols",
|
|
82
|
+
"referenced_symbols",
|
|
83
|
+
])
|
|
84
|
+
.where(`path LIKE '${(0, filter_builder_1.escapeSqlString)(prefix)}%'`)
|
|
85
|
+
.limit(200000)
|
|
86
|
+
.toArray();
|
|
87
|
+
if (rows.length === 0) {
|
|
88
|
+
console.log(`No indexed data found for ${root}. Run: gmax index --path ${root}`);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const files = new Set();
|
|
92
|
+
const extCounts = new Map();
|
|
93
|
+
const dirCounts = new Map();
|
|
94
|
+
const roleCounts = new Map();
|
|
95
|
+
const symbolRefs = new Map();
|
|
96
|
+
const entryPoints = [];
|
|
97
|
+
for (const row of rows) {
|
|
98
|
+
const p = String(row.path || "");
|
|
99
|
+
const role = String(row.role || "IMPLEMENTATION");
|
|
100
|
+
const exported = Boolean(row.is_exported);
|
|
101
|
+
const complexity = Number(row.complexity || 0);
|
|
102
|
+
const defs = toArr(row.defined_symbols);
|
|
103
|
+
const refs = toArr(row.referenced_symbols);
|
|
104
|
+
files.add(p);
|
|
105
|
+
const ext = path.extname(p).toLowerCase() || path.basename(p);
|
|
106
|
+
extCounts.set(ext, (extCounts.get(ext) || 0) + 1);
|
|
107
|
+
const rel = p.startsWith(prefix) ? p.slice(prefix.length) : p;
|
|
108
|
+
const parts = rel.split("/");
|
|
109
|
+
const dir = parts.length > 2
|
|
110
|
+
? `${parts.slice(0, 2).join("/")}/`
|
|
111
|
+
: parts.length > 1
|
|
112
|
+
? `${parts[0]}/`
|
|
113
|
+
: "(root)";
|
|
114
|
+
if (!dirCounts.has(dir))
|
|
115
|
+
dirCounts.set(dir, { files: new Set(), chunks: 0 });
|
|
116
|
+
const dc = dirCounts.get(dir);
|
|
117
|
+
dc.files.add(p);
|
|
118
|
+
dc.chunks++;
|
|
119
|
+
roleCounts.set(role, (roleCounts.get(role) || 0) + 1);
|
|
120
|
+
for (const ref of refs)
|
|
121
|
+
symbolRefs.set(ref, (symbolRefs.get(ref) || 0) + 1);
|
|
122
|
+
if (exported && role === "ORCHESTRATION" && complexity >= 5 && defs.length > 0) {
|
|
123
|
+
entryPoints.push({
|
|
124
|
+
symbol: defs[0],
|
|
125
|
+
path: p.startsWith(prefix) ? p.slice(prefix.length) : p,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
const projects = (0, project_registry_1.listProjects)();
|
|
130
|
+
const proj = projects.find((p) => p.root === root);
|
|
131
|
+
console.log(`Project: ${projectName} (${root})`);
|
|
132
|
+
console.log(`Last indexed: ${(_c = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _c !== void 0 ? _c : "unknown"} • ${rows.length} chunks • ${files.size} files\n`);
|
|
133
|
+
const extEntries = Array.from(extCounts.entries())
|
|
134
|
+
.sort((a, b) => b[1] - a[1])
|
|
135
|
+
.slice(0, 8);
|
|
136
|
+
console.log(`Languages: ${extEntries.map(([ext, count]) => `${ext} (${Math.round((count / rows.length) * 100)}%)`).join(", ")}\n`);
|
|
137
|
+
console.log("Directory structure:");
|
|
138
|
+
for (const [dir, data] of Array.from(dirCounts.entries())
|
|
139
|
+
.sort((a, b) => b[1].chunks - a[1].chunks)
|
|
140
|
+
.slice(0, 12)) {
|
|
141
|
+
console.log(` ${dir.padEnd(25)} (${data.files.size} files, ${data.chunks} chunks)`);
|
|
142
|
+
}
|
|
143
|
+
const roleEntries = Array.from(roleCounts.entries()).sort((a, b) => b[1] - a[1]);
|
|
144
|
+
console.log(`\nRoles: ${roleEntries.map(([r, c]) => `${Math.round((c / rows.length) * 100)}% ${r}`).join(", ")}\n`);
|
|
145
|
+
const topSymbols = Array.from(symbolRefs.entries())
|
|
146
|
+
.sort((a, b) => b[1] - a[1])
|
|
147
|
+
.slice(0, 8);
|
|
148
|
+
if (topSymbols.length > 0) {
|
|
149
|
+
console.log("Key symbols (by reference count):");
|
|
150
|
+
for (const [sym, count] of topSymbols) {
|
|
151
|
+
console.log(` ${sym.padEnd(25)} (referenced ${count}x)`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (entryPoints.length > 0) {
|
|
155
|
+
console.log("\nEntry points (exported orchestration):");
|
|
156
|
+
for (const ep of entryPoints.slice(0, 10)) {
|
|
157
|
+
console.log(` ${ep.symbol.padEnd(25)} ${ep.path}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
163
|
+
console.error("Project summary failed:", msg);
|
|
164
|
+
process.exitCode = 1;
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
if (vectorDb) {
|
|
168
|
+
try {
|
|
169
|
+
yield vectorDb.close();
|
|
170
|
+
}
|
|
171
|
+
catch (_d) { }
|
|
172
|
+
}
|
|
173
|
+
yield (0, exit_1.gracefulExit)();
|
|
174
|
+
}
|
|
175
|
+
}));
|
|
@@ -0,0 +1,131 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.recent = void 0;
|
|
53
|
+
const path = __importStar(require("node:path"));
|
|
54
|
+
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 project_root_1 = require("../lib/utils/project-root");
|
|
59
|
+
function formatTimeAgo(ms) {
|
|
60
|
+
const sec = Math.floor(ms / 1000);
|
|
61
|
+
if (sec < 60)
|
|
62
|
+
return `${sec}s ago`;
|
|
63
|
+
const min = Math.floor(sec / 60);
|
|
64
|
+
if (min < 60)
|
|
65
|
+
return `${min}m ago`;
|
|
66
|
+
const hr = Math.floor(min / 60);
|
|
67
|
+
if (hr < 24)
|
|
68
|
+
return `${hr}h ago`;
|
|
69
|
+
const days = Math.floor(hr / 24);
|
|
70
|
+
return `${days}d ago`;
|
|
71
|
+
}
|
|
72
|
+
exports.recent = new commander_1.Command("recent")
|
|
73
|
+
.description("Show recently modified indexed files")
|
|
74
|
+
.option("-l, --limit <n>", "Max files (default 20)", "20")
|
|
75
|
+
.option("--root <dir>", "Project root (defaults to current directory)")
|
|
76
|
+
.action((opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
77
|
+
var _a, e_1, _b, _c;
|
|
78
|
+
var _d, _e;
|
|
79
|
+
const limit = Math.min(Math.max(Number.parseInt(opts.limit || "20", 10), 1), 50);
|
|
80
|
+
try {
|
|
81
|
+
const root = opts.root
|
|
82
|
+
? (_d = (0, project_root_1.findProjectRoot)(path.resolve(opts.root))) !== null && _d !== void 0 ? _d : path.resolve(opts.root)
|
|
83
|
+
: (_e = (0, project_root_1.findProjectRoot)(process.cwd())) !== null && _e !== void 0 ? _e : process.cwd();
|
|
84
|
+
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
85
|
+
const metaCache = new meta_cache_1.MetaCache(config_1.PATHS.lmdbPath);
|
|
86
|
+
try {
|
|
87
|
+
const files = [];
|
|
88
|
+
try {
|
|
89
|
+
for (var _f = true, _g = __asyncValues(metaCache.entries()), _h; _h = yield _g.next(), _a = _h.done, !_a; _f = true) {
|
|
90
|
+
_c = _h.value;
|
|
91
|
+
_f = false;
|
|
92
|
+
const { path: p, entry } = _c;
|
|
93
|
+
if (p.startsWith(prefix)) {
|
|
94
|
+
files.push({ path: p, mtimeMs: entry.mtimeMs });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
99
|
+
finally {
|
|
100
|
+
try {
|
|
101
|
+
if (!_f && !_a && (_b = _g.return)) yield _b.call(_g);
|
|
102
|
+
}
|
|
103
|
+
finally { if (e_1) throw e_1.error; }
|
|
104
|
+
}
|
|
105
|
+
files.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
106
|
+
const top = files.slice(0, limit);
|
|
107
|
+
if (top.length === 0) {
|
|
108
|
+
console.log(`No indexed files found for ${root}`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
console.log(`Recent changes in ${path.basename(root)} (${top.length} most recent):\n`);
|
|
113
|
+
for (const f of top) {
|
|
114
|
+
const rel = f.path.startsWith(prefix)
|
|
115
|
+
? f.path.slice(prefix.length)
|
|
116
|
+
: f.path;
|
|
117
|
+
const ago = formatTimeAgo(now - f.mtimeMs);
|
|
118
|
+
console.log(` ${ago.padEnd(10)} ${rel}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
finally {
|
|
122
|
+
yield metaCache.close();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
127
|
+
console.error("Recent changes failed:", msg);
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
}
|
|
130
|
+
yield (0, exit_1.gracefulExit)();
|
|
131
|
+
}));
|
|
@@ -0,0 +1,170 @@
|
|
|
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.related = void 0;
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const commander_1 = require("commander");
|
|
48
|
+
const vector_db_1 = require("../lib/store/vector-db");
|
|
49
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
50
|
+
const exit_1 = require("../lib/utils/exit");
|
|
51
|
+
const project_root_1 = require("../lib/utils/project-root");
|
|
52
|
+
function toArr(val) {
|
|
53
|
+
if (val && typeof val.toArray === "function") {
|
|
54
|
+
return val.toArray();
|
|
55
|
+
}
|
|
56
|
+
return Array.isArray(val) ? val : [];
|
|
57
|
+
}
|
|
58
|
+
exports.related = new commander_1.Command("related")
|
|
59
|
+
.description("Find files related by shared symbol references")
|
|
60
|
+
.argument("<file>", "File path relative to project root")
|
|
61
|
+
.option("-l, --limit <n>", "Max results per direction (default 10)", "10")
|
|
62
|
+
.action((file, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
63
|
+
var _a;
|
|
64
|
+
const limit = Math.min(Math.max(Number.parseInt(opts.limit || "10", 10), 1), 25);
|
|
65
|
+
let vectorDb = null;
|
|
66
|
+
try {
|
|
67
|
+
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(process.cwd())) !== null && _a !== void 0 ? _a : process.cwd();
|
|
68
|
+
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
69
|
+
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
70
|
+
const absPath = path.resolve(projectRoot, file);
|
|
71
|
+
const table = yield vectorDb.ensureTable();
|
|
72
|
+
const fileChunks = yield table
|
|
73
|
+
.query()
|
|
74
|
+
.select(["defined_symbols", "referenced_symbols"])
|
|
75
|
+
.where(`path = '${(0, filter_builder_1.escapeSqlString)(absPath)}'`)
|
|
76
|
+
.toArray();
|
|
77
|
+
if (fileChunks.length === 0) {
|
|
78
|
+
console.log(`File not found in index: ${file}`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const definedHere = new Set();
|
|
82
|
+
const referencedHere = new Set();
|
|
83
|
+
for (const chunk of fileChunks) {
|
|
84
|
+
for (const s of toArr(chunk.defined_symbols))
|
|
85
|
+
definedHere.add(s);
|
|
86
|
+
for (const s of toArr(chunk.referenced_symbols))
|
|
87
|
+
referencedHere.add(s);
|
|
88
|
+
}
|
|
89
|
+
// Dependencies
|
|
90
|
+
const depCounts = new Map();
|
|
91
|
+
for (const sym of referencedHere) {
|
|
92
|
+
if (definedHere.has(sym))
|
|
93
|
+
continue;
|
|
94
|
+
const rows = yield table
|
|
95
|
+
.query()
|
|
96
|
+
.select(["path"])
|
|
97
|
+
.where(`array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}')`)
|
|
98
|
+
.limit(3)
|
|
99
|
+
.toArray();
|
|
100
|
+
for (const row of rows) {
|
|
101
|
+
const p = String(row.path || "");
|
|
102
|
+
if (p === absPath)
|
|
103
|
+
continue;
|
|
104
|
+
depCounts.set(p, (depCounts.get(p) || 0) + 1);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Dependents
|
|
108
|
+
const revCounts = new Map();
|
|
109
|
+
for (const sym of definedHere) {
|
|
110
|
+
const rows = yield table
|
|
111
|
+
.query()
|
|
112
|
+
.select(["path"])
|
|
113
|
+
.where(`array_contains(referenced_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}')`)
|
|
114
|
+
.limit(20)
|
|
115
|
+
.toArray();
|
|
116
|
+
for (const row of rows) {
|
|
117
|
+
const p = String(row.path || "");
|
|
118
|
+
if (p === absPath)
|
|
119
|
+
continue;
|
|
120
|
+
revCounts.set(p, (revCounts.get(p) || 0) + 1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
console.log(`Related files for ${file}:\n`);
|
|
124
|
+
const topDeps = Array.from(depCounts.entries())
|
|
125
|
+
.sort((a, b) => b[1] - a[1])
|
|
126
|
+
.slice(0, limit);
|
|
127
|
+
if (topDeps.length > 0) {
|
|
128
|
+
console.log("Dependencies (files this imports/calls):");
|
|
129
|
+
for (const [p, count] of topDeps) {
|
|
130
|
+
const rel = p.startsWith(`${projectRoot}/`)
|
|
131
|
+
? p.slice(projectRoot.length + 1)
|
|
132
|
+
: p;
|
|
133
|
+
console.log(` ${rel.padEnd(40)} (${count} shared symbol${count > 1 ? "s" : ""})`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log("Dependencies: none found");
|
|
138
|
+
}
|
|
139
|
+
console.log("");
|
|
140
|
+
const topRevs = Array.from(revCounts.entries())
|
|
141
|
+
.sort((a, b) => b[1] - a[1])
|
|
142
|
+
.slice(0, limit);
|
|
143
|
+
if (topRevs.length > 0) {
|
|
144
|
+
console.log("Dependents (files that call this):");
|
|
145
|
+
for (const [p, count] of topRevs) {
|
|
146
|
+
const rel = p.startsWith(`${projectRoot}/`)
|
|
147
|
+
? p.slice(projectRoot.length + 1)
|
|
148
|
+
: p;
|
|
149
|
+
console.log(` ${rel.padEnd(40)} (${count} shared symbol${count > 1 ? "s" : ""})`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
console.log("Dependents: none found");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
const msg = error instanceof Error ? error.message : "Unknown error";
|
|
158
|
+
console.error("Related files failed:", msg);
|
|
159
|
+
process.exitCode = 1;
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
if (vectorDb) {
|
|
163
|
+
try {
|
|
164
|
+
yield vectorDb.close();
|
|
165
|
+
}
|
|
166
|
+
catch (_b) { }
|
|
167
|
+
}
|
|
168
|
+
yield (0, exit_1.gracefulExit)();
|
|
169
|
+
}
|
|
170
|
+
}));
|
|
@@ -61,6 +61,7 @@ const setup_helpers_1 = require("../lib/setup/setup-helpers");
|
|
|
61
61
|
const retriever_1 = require("../lib/skeleton/retriever");
|
|
62
62
|
const skeletonizer_1 = require("../lib/skeleton/skeletonizer");
|
|
63
63
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
64
|
+
const file_utils_1 = require("../lib/utils/file-utils");
|
|
64
65
|
const exit_1 = require("../lib/utils/exit");
|
|
65
66
|
const project_root_1 = require("../lib/utils/project-root");
|
|
66
67
|
/**
|
|
@@ -140,6 +141,48 @@ Examples:
|
|
|
140
141
|
includeSummary: !options.noSummary,
|
|
141
142
|
};
|
|
142
143
|
// Determine mode based on target
|
|
144
|
+
const resolvedTarget = path.resolve(target);
|
|
145
|
+
// Directory mode
|
|
146
|
+
if (fs.existsSync(resolvedTarget) &&
|
|
147
|
+
fs.statSync(resolvedTarget).isDirectory()) {
|
|
148
|
+
const entries = fs.readdirSync(resolvedTarget, {
|
|
149
|
+
withFileTypes: true,
|
|
150
|
+
});
|
|
151
|
+
const files = entries
|
|
152
|
+
.filter((e) => e.isFile() &&
|
|
153
|
+
(0, file_utils_1.isIndexableFile)(path.join(resolvedTarget, e.name)))
|
|
154
|
+
.map((e) => path.join(resolvedTarget, e.name))
|
|
155
|
+
.slice(0, Number.parseInt(options.limit, 10));
|
|
156
|
+
if (files.length === 0) {
|
|
157
|
+
console.error(`No indexable files in ${target}`);
|
|
158
|
+
process.exitCode = 1;
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
for (const filePath of files) {
|
|
162
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
163
|
+
const result = yield skeletonizer.skeletonizeFile(filePath, content, skeletonOpts);
|
|
164
|
+
outputResult(result, options);
|
|
165
|
+
}
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Batch mode (comma-separated)
|
|
169
|
+
if (target.includes(",")) {
|
|
170
|
+
const targets = target
|
|
171
|
+
.split(",")
|
|
172
|
+
.map((t) => t.trim())
|
|
173
|
+
.filter(Boolean);
|
|
174
|
+
for (const t of targets) {
|
|
175
|
+
const filePath = path.resolve(t);
|
|
176
|
+
if (!fs.existsSync(filePath)) {
|
|
177
|
+
console.error(`Not found: ${t}`);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
181
|
+
const result = yield skeletonizer.skeletonizeFile(filePath, content, skeletonOpts);
|
|
182
|
+
outputResult(result, options);
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
143
186
|
if (isFilePath(target)) {
|
|
144
187
|
// === FILE MODE ===
|
|
145
188
|
const filePath = path.resolve(target);
|
package/dist/commands/trace.js
CHANGED
|
@@ -19,8 +19,10 @@ const project_root_1 = require("../lib/utils/project-root");
|
|
|
19
19
|
exports.trace = new commander_1.Command("trace")
|
|
20
20
|
.description("Trace the call graph for a symbol")
|
|
21
21
|
.argument("<symbol>", "The symbol to trace")
|
|
22
|
-
.
|
|
22
|
+
.option("-d, --depth <n>", "Caller traversal depth (default 1, max 3)", "1")
|
|
23
|
+
.action((symbol, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
24
|
var _a;
|
|
25
|
+
const depth = Math.min(Math.max(Number.parseInt(opts.depth || "1", 10), 1), 3);
|
|
24
26
|
const root = process.cwd();
|
|
25
27
|
let vectorDb = null;
|
|
26
28
|
try {
|
|
@@ -28,7 +30,7 @@ exports.trace = new commander_1.Command("trace")
|
|
|
28
30
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
29
31
|
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
30
32
|
const graphBuilder = new graph_builder_1.GraphBuilder(vectorDb);
|
|
31
|
-
const graph = yield graphBuilder.
|
|
33
|
+
const graph = yield graphBuilder.buildGraphMultiHop(symbol, depth);
|
|
32
34
|
console.log((0, formatter_1.formatTrace)(graph));
|
|
33
35
|
}
|
|
34
36
|
catch (error) {
|
package/dist/index.js
CHANGED
|
@@ -45,6 +45,9 @@ const droid_1 = require("./commands/droid");
|
|
|
45
45
|
const index_1 = require("./commands/index");
|
|
46
46
|
const list_1 = require("./commands/list");
|
|
47
47
|
const mcp_1 = require("./commands/mcp");
|
|
48
|
+
const project_1 = require("./commands/project");
|
|
49
|
+
const recent_1 = require("./commands/recent");
|
|
50
|
+
const related_1 = require("./commands/related");
|
|
48
51
|
const opencode_1 = require("./commands/opencode");
|
|
49
52
|
const search_1 = require("./commands/search");
|
|
50
53
|
const serve_1 = require("./commands/serve");
|
|
@@ -77,6 +80,9 @@ commander_1.program.addCommand(list_1.list);
|
|
|
77
80
|
commander_1.program.addCommand(skeleton_1.skeleton);
|
|
78
81
|
commander_1.program.addCommand(symbols_1.symbols);
|
|
79
82
|
commander_1.program.addCommand(trace_1.trace);
|
|
83
|
+
commander_1.program.addCommand(project_1.project);
|
|
84
|
+
commander_1.program.addCommand(related_1.related);
|
|
85
|
+
commander_1.program.addCommand(recent_1.recent);
|
|
80
86
|
// Services
|
|
81
87
|
commander_1.program.addCommand(serve_1.serve);
|
|
82
88
|
commander_1.program.addCommand(watch_1.watch);
|
|
@@ -130,24 +130,40 @@ function formatTrace(graph) {
|
|
|
130
130
|
return style.dim("Symbol not found.");
|
|
131
131
|
}
|
|
132
132
|
const lines = [];
|
|
133
|
-
// 1.
|
|
134
|
-
if (graph.
|
|
133
|
+
// 1. Importers
|
|
134
|
+
if (graph.importers.length > 0) {
|
|
135
|
+
const filtered = graph.importers.filter((p) => p !== graph.center.file);
|
|
136
|
+
if (filtered.length > 0) {
|
|
137
|
+
lines.push(style.bold("Imported by:"));
|
|
138
|
+
for (const imp of filtered.slice(0, 10)) {
|
|
139
|
+
lines.push(` ${style.dim(imp)}`);
|
|
140
|
+
}
|
|
141
|
+
lines.push("");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// 2. Callers (Upstream, recursive tree)
|
|
145
|
+
function renderCallerTree(trees, depth) {
|
|
146
|
+
for (const t of trees) {
|
|
147
|
+
const pad = " ".repeat(depth);
|
|
148
|
+
lines.push(`${pad}${style.blue("↑")} ${style.green(t.node.symbol)} ${style.dim(`(${t.node.file}:${t.node.line})`)}`);
|
|
149
|
+
renderCallerTree(t.callers, depth + 1);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (graph.callerTree.length > 0) {
|
|
135
153
|
lines.push(style.bold("Callers (Who calls this?):"));
|
|
136
|
-
graph.
|
|
137
|
-
lines.push(` ${style.blue("↑")} ${style.green(caller.symbol)} ${style.dim(`(${caller.file}:${caller.line})`)}`);
|
|
138
|
-
});
|
|
154
|
+
renderCallerTree(graph.callerTree, 1);
|
|
139
155
|
lines.push("");
|
|
140
156
|
}
|
|
141
157
|
else {
|
|
142
158
|
lines.push(style.dim("No known callers."));
|
|
143
159
|
lines.push("");
|
|
144
160
|
}
|
|
145
|
-
//
|
|
161
|
+
// 3. Center (The Symbol)
|
|
146
162
|
lines.push(style.bold(`▶ ${graph.center.symbol}`));
|
|
147
163
|
lines.push(` ${style.dim(`Defined in ${graph.center.file}:${graph.center.line}`)}`);
|
|
148
164
|
lines.push(` ${style.dim(`Role: ${graph.center.role}`)}`);
|
|
149
165
|
lines.push("");
|
|
150
|
-
//
|
|
166
|
+
// 4. Callees (Downstream)
|
|
151
167
|
if (graph.callees.length > 0) {
|
|
152
168
|
lines.push(style.bold("Callees (What does this call?):"));
|
|
153
169
|
graph.callees.forEach((callee) => {
|
package/package.json
CHANGED