@ulpi/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/auth-PN7TMQHV-2W4ICG64.js +15 -0
- package/dist/chunk-247GVVKK.js +2259 -0
- package/dist/chunk-2CLNOKPA.js +793 -0
- package/dist/chunk-2HEE5OKX.js +79 -0
- package/dist/chunk-2MZER6ND.js +415 -0
- package/dist/chunk-3SBPZRB5.js +772 -0
- package/dist/chunk-4VNS5WPM.js +42 -0
- package/dist/chunk-6JCMYYBT.js +1546 -0
- package/dist/chunk-6OCEY7JY.js +422 -0
- package/dist/chunk-74WVVWJ4.js +375 -0
- package/dist/chunk-7AL4DOEJ.js +131 -0
- package/dist/chunk-7LXY5UVC.js +330 -0
- package/dist/chunk-DBMUNBNB.js +3048 -0
- package/dist/chunk-JWUUVXIV.js +13694 -0
- package/dist/chunk-KIKPIH6N.js +4048 -0
- package/dist/chunk-KLEASXUR.js +70 -0
- package/dist/chunk-MIAQVCFW.js +39 -0
- package/dist/chunk-NNUWU6CV.js +1610 -0
- package/dist/chunk-PKD4ASEM.js +115 -0
- package/dist/chunk-Q4HIY43N.js +4230 -0
- package/dist/chunk-QJ5GSMEC.js +146 -0
- package/dist/chunk-SIAQVRKG.js +2163 -0
- package/dist/chunk-SPOI23SB.js +197 -0
- package/dist/chunk-YM2HV4IA.js +505 -0
- package/dist/codemap-RRJIDBQ5.js +636 -0
- package/dist/config-EGAXXCGL.js +127 -0
- package/dist/dist-6G7JC2RA.js +90 -0
- package/dist/dist-7LHZ65GC.js +418 -0
- package/dist/dist-LZKZFPVX.js +140 -0
- package/dist/dist-R5F4MX3I.js +107 -0
- package/dist/dist-R5ZJ4LX5.js +56 -0
- package/dist/dist-RJGCUS3L.js +87 -0
- package/dist/dist-RKOGLK7R.js +151 -0
- package/dist/dist-W7K4WPAF.js +597 -0
- package/dist/export-import-4A5MWLIA.js +53 -0
- package/dist/history-ATTUKOHO.js +934 -0
- package/dist/index.js +2120 -0
- package/dist/init-AY5C2ZAS.js +393 -0
- package/dist/launchd-LF2QMSKZ.js +148 -0
- package/dist/log-TVTUXAYD.js +75 -0
- package/dist/mcp-installer-NQCGKQ23.js +124 -0
- package/dist/memory-J3G24QHS.js +406 -0
- package/dist/ollama-3XCUZMZT-FYKHW4TZ.js +7 -0
- package/dist/openai-E7G2YAHU-UYY4ZWON.js +8 -0
- package/dist/projects-ATHDD3D6.js +271 -0
- package/dist/review-ADUPV3PN.js +152 -0
- package/dist/rules-E427DKYJ.js +134 -0
- package/dist/server-MOYPE4SM-N7SE2AN7.js +18 -0
- package/dist/server-X5P6WH2M-7K2RY34N.js +11 -0
- package/dist/skills/ulpi-generate-guardian/SKILL.md +511 -0
- package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +692 -0
- package/dist/skills/ulpi-generate-guardian/references/language-rules.md +596 -0
- package/dist/skills-CX73O3IV.js +76 -0
- package/dist/status-4DFHDJMN.js +66 -0
- package/dist/templates/biome.yml +24 -0
- package/dist/templates/conventional-commits.yml +18 -0
- package/dist/templates/django.yml +30 -0
- package/dist/templates/docker.yml +30 -0
- package/dist/templates/eslint.yml +13 -0
- package/dist/templates/express.yml +20 -0
- package/dist/templates/fastapi.yml +23 -0
- package/dist/templates/git-flow.yml +26 -0
- package/dist/templates/github-flow.yml +27 -0
- package/dist/templates/go.yml +33 -0
- package/dist/templates/jest.yml +24 -0
- package/dist/templates/laravel.yml +30 -0
- package/dist/templates/monorepo.yml +26 -0
- package/dist/templates/nestjs.yml +21 -0
- package/dist/templates/nextjs.yml +31 -0
- package/dist/templates/nodejs.yml +33 -0
- package/dist/templates/npm.yml +15 -0
- package/dist/templates/php.yml +25 -0
- package/dist/templates/pnpm.yml +15 -0
- package/dist/templates/prettier.yml +23 -0
- package/dist/templates/prisma.yml +21 -0
- package/dist/templates/python.yml +33 -0
- package/dist/templates/quality-of-life.yml +111 -0
- package/dist/templates/ruby.yml +25 -0
- package/dist/templates/rust.yml +34 -0
- package/dist/templates/typescript.yml +14 -0
- package/dist/templates/vitest.yml +24 -0
- package/dist/templates/yarn.yml +15 -0
- package/dist/templates-U7T6MARD.js +156 -0
- package/dist/ui-L7UAWXDY.js +167 -0
- package/dist/ui.html +698 -0
- package/dist/ulpi-RMMCUAGP-JCJ273T6.js +161 -0
- package/dist/uninstall-6SW35IK4.js +25 -0
- package/dist/update-M2B4RLGH.js +61 -0
- package/dist/version-checker-ANCS3IHR.js +10 -0
- package/package.json +92 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
import "./chunk-4VNS5WPM.js";
|
|
2
|
+
|
|
3
|
+
// src/commands/codemap.ts
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
async function runCodemap(args, projectDir) {
|
|
6
|
+
const subcommand = args[0];
|
|
7
|
+
switch (subcommand) {
|
|
8
|
+
case "init":
|
|
9
|
+
return await initSubcommand(projectDir);
|
|
10
|
+
case "search":
|
|
11
|
+
return await searchSubcommand(args.slice(1), projectDir);
|
|
12
|
+
case "status":
|
|
13
|
+
return await statusSubcommand(projectDir);
|
|
14
|
+
case "reindex":
|
|
15
|
+
return await reindexSubcommand(projectDir);
|
|
16
|
+
case "config":
|
|
17
|
+
return await configSubcommand(args.slice(1), projectDir);
|
|
18
|
+
case "watch":
|
|
19
|
+
return await watchSubcommand(projectDir);
|
|
20
|
+
case "export":
|
|
21
|
+
return await exportSubcommand(projectDir);
|
|
22
|
+
case "import":
|
|
23
|
+
return await importSubcommand(projectDir);
|
|
24
|
+
case "serve":
|
|
25
|
+
return await serveSubcommand(projectDir);
|
|
26
|
+
case "eval":
|
|
27
|
+
return await evalSubcommand(args.slice(1), projectDir);
|
|
28
|
+
case "migrate-index":
|
|
29
|
+
return await migrateIndexSubcommand(projectDir);
|
|
30
|
+
case "deps":
|
|
31
|
+
return await depsSubcommand(args.slice(1), projectDir);
|
|
32
|
+
case "rdeps":
|
|
33
|
+
case "dependents":
|
|
34
|
+
return await dependentsSubcommand(args.slice(1), projectDir);
|
|
35
|
+
case "rank":
|
|
36
|
+
return await rankSubcommand(args.slice(1), projectDir);
|
|
37
|
+
case "cycles":
|
|
38
|
+
return await cyclesSubcommand(projectDir);
|
|
39
|
+
case "coupling":
|
|
40
|
+
return await couplingSubcommand(args.slice(1), projectDir);
|
|
41
|
+
default:
|
|
42
|
+
console.log(`
|
|
43
|
+
Usage: ulpi codemap <subcommand>
|
|
44
|
+
|
|
45
|
+
Subcommands:
|
|
46
|
+
init Index the current project
|
|
47
|
+
search <query> Search code by intent
|
|
48
|
+
status Show index status and stats
|
|
49
|
+
reindex Force full re-index
|
|
50
|
+
watch Start file watcher for incremental updates
|
|
51
|
+
export Export index to shadow branch
|
|
52
|
+
import Import index from shadow branch
|
|
53
|
+
serve Start MCP server
|
|
54
|
+
config [key] [value] View or update CodeMap configuration
|
|
55
|
+
eval Run quality evaluation harness
|
|
56
|
+
migrate-index Migrate index to new format
|
|
57
|
+
deps <file> Show files this file depends on
|
|
58
|
+
dependents <file> Show files that depend on this file (alias: rdeps)
|
|
59
|
+
rank [--limit N] Show top-ranked files by PageRank
|
|
60
|
+
cycles Detect circular dependencies
|
|
61
|
+
coupling [path] Show coupling metrics for files
|
|
62
|
+
`.trim());
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function initSubcommand(projectDir) {
|
|
66
|
+
console.log(chalk.bold("\nCodeMap \u2014 Index Project\n"));
|
|
67
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
68
|
+
const branch = getCurrentBranch(projectDir);
|
|
69
|
+
const { runInitPipeline, loadCodemapConfig } = await import("./dist-LZKZFPVX.js");
|
|
70
|
+
const config = loadCodemapConfig(projectDir);
|
|
71
|
+
if (config.embedding.provider === "openai") {
|
|
72
|
+
const { resolveApiKey } = await import("./dist-RKOGLK7R.js");
|
|
73
|
+
if (!resolveApiKey("openai")) {
|
|
74
|
+
console.error(chalk.red("Error: OpenAI API key not found.\n"));
|
|
75
|
+
console.error(chalk.dim(" Set it: ulpi config set openai-key <your-key>"));
|
|
76
|
+
console.error(chalk.dim(" Or switch: ulpi codemap config embedding.provider ulpi"));
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
} else if (config.embedding.provider === "ulpi") {
|
|
80
|
+
const { resolveApiKey } = await import("./dist-RKOGLK7R.js");
|
|
81
|
+
if (!resolveApiKey("ulpi")) {
|
|
82
|
+
console.error(chalk.red("Error: ULPI API key not found.\n"));
|
|
83
|
+
console.error(chalk.dim(" Set it: ulpi config set ulpi-key <your-key>"));
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const result = await runInitPipeline(projectDir, (progress) => {
|
|
89
|
+
const pct = progress.total > 0 ? ` (${Math.round(progress.current / progress.total * 100)}%)` : "";
|
|
90
|
+
process.stdout.write(`\r ${chalk.dim(progress.phase)}${pct} ${progress.message} `);
|
|
91
|
+
}, branch);
|
|
92
|
+
process.stdout.write("\r" + " ".repeat(80) + "\r");
|
|
93
|
+
console.log(chalk.green("\u2713 Indexing complete"));
|
|
94
|
+
console.log(chalk.dim(` Files: ${result.totalFiles}`));
|
|
95
|
+
console.log(chalk.dim(` Chunks: ${result.totalChunks}`));
|
|
96
|
+
console.log(chalk.dim(` Provider: ${result.embeddingProvider} (${result.embeddingModel})`));
|
|
97
|
+
console.log(chalk.dim(` Duration: ${(result.durationMs / 1e3).toFixed(1)}s`));
|
|
98
|
+
console.log(chalk.dim(` Branch: ${branch}`));
|
|
99
|
+
const { installMcpServer } = await import("./mcp-installer-NQCGKQ23.js");
|
|
100
|
+
const mcp = installMcpServer(projectDir);
|
|
101
|
+
if (mcp.installed) {
|
|
102
|
+
console.log(chalk.green("\u2713 MCP server registered"));
|
|
103
|
+
console.log(chalk.dim(" Claude Code will auto-start the codemap MCP server"));
|
|
104
|
+
} else {
|
|
105
|
+
console.log(chalk.dim(` MCP: ${mcp.message}`));
|
|
106
|
+
}
|
|
107
|
+
} catch (err) {
|
|
108
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
109
|
+
console.error(chalk.red(`
|
|
110
|
+
Error: ${message}`));
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function searchSubcommand(args, projectDir) {
|
|
115
|
+
const query = args.filter((a) => !a.startsWith("--")).join(" ");
|
|
116
|
+
if (!query) {
|
|
117
|
+
console.log(chalk.red("Usage: ulpi codemap search <query>"));
|
|
118
|
+
console.log(chalk.dim(' Example: ulpi codemap search "review decision handling"'));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const limitFlag = args.find((a) => a.startsWith("--limit"));
|
|
122
|
+
let limit = 10;
|
|
123
|
+
if (limitFlag) {
|
|
124
|
+
const val = limitFlag.includes("=") ? limitFlag.split("=")[1] : args[args.indexOf(limitFlag) + 1];
|
|
125
|
+
if (val) limit = parseInt(val, 10) || 10;
|
|
126
|
+
}
|
|
127
|
+
const noTests = args.includes("--no-tests");
|
|
128
|
+
const noDocs = args.includes("--no-docs");
|
|
129
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
130
|
+
const branch = getCurrentBranch(projectDir);
|
|
131
|
+
const { searchCode, getCodemapStatus } = await import("./dist-LZKZFPVX.js");
|
|
132
|
+
const status = getCodemapStatus(projectDir, branch);
|
|
133
|
+
if (!status.initialized) {
|
|
134
|
+
console.log(chalk.red("Error: CodeMap index not initialized."));
|
|
135
|
+
console.log(chalk.dim("Run 'ulpi codemap init' first."));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const result = await searchCode(projectDir, query, {
|
|
140
|
+
limit,
|
|
141
|
+
includeTests: !noTests,
|
|
142
|
+
includeDocs: !noDocs,
|
|
143
|
+
branch
|
|
144
|
+
});
|
|
145
|
+
if (result.results.length === 0) {
|
|
146
|
+
console.log(chalk.yellow("No results found."));
|
|
147
|
+
console.log(chalk.dim(` Query: "${query}"`));
|
|
148
|
+
console.log(chalk.dim(` Duration: ${result.durationMs}ms`));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
console.log(chalk.bold(`
|
|
152
|
+
CodeMap Search \u2014 "${query}"
|
|
153
|
+
`));
|
|
154
|
+
console.log(chalk.dim(` ${result.results.length} results in ${result.durationMs}ms
|
|
155
|
+
`));
|
|
156
|
+
for (let i = 0; i < result.results.length; i++) {
|
|
157
|
+
const r = result.results[i];
|
|
158
|
+
const score = (r.score * 100).toFixed(1);
|
|
159
|
+
console.log(
|
|
160
|
+
chalk.cyan(` ${i + 1}. `) + chalk.white(r.filePath) + chalk.dim(`:${r.startLine}-${r.endLine}`) + chalk.dim(` (${score}%)`)
|
|
161
|
+
);
|
|
162
|
+
const firstLine = r.snippet.split("\n")[0]?.trim();
|
|
163
|
+
if (firstLine) {
|
|
164
|
+
console.log(chalk.dim(` ${truncate(firstLine, 80)}`));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
console.log("");
|
|
168
|
+
} catch (err) {
|
|
169
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
170
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
171
|
+
process.exit(1);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function statusSubcommand(projectDir) {
|
|
175
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
176
|
+
const branch = getCurrentBranch(projectDir);
|
|
177
|
+
const { getCodemapStatus } = await import("./dist-LZKZFPVX.js");
|
|
178
|
+
const status = getCodemapStatus(projectDir, branch);
|
|
179
|
+
console.log(chalk.bold("\nCodeMap Status\n"));
|
|
180
|
+
if (!status.initialized) {
|
|
181
|
+
console.log(chalk.yellow(" Not initialized"));
|
|
182
|
+
console.log(chalk.dim(" Run 'ulpi codemap init' to index this project.\n"));
|
|
183
|
+
console.log(chalk.dim(` Provider: ${status.embeddingProvider} (${status.embeddingModel})`));
|
|
184
|
+
console.log(chalk.dim(` Dimensions: ${status.dimensions}`));
|
|
185
|
+
console.log("");
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const modeColor = status.mode === "watching" ? chalk.green : status.mode === "error" ? chalk.red : chalk.dim;
|
|
189
|
+
console.log(` ${chalk.dim("Mode:")} ${modeColor(status.mode)}`);
|
|
190
|
+
console.log(` ${chalk.dim("Branch:")} ${status.branch ?? "unknown"}`);
|
|
191
|
+
console.log(` ${chalk.dim("Provider:")} ${status.embeddingProvider} (${status.embeddingModel})`);
|
|
192
|
+
console.log(` ${chalk.dim("Dimensions:")} ${status.dimensions}`);
|
|
193
|
+
console.log(` ${chalk.dim("Files:")} ${status.totalFiles}`);
|
|
194
|
+
console.log(` ${chalk.dim("Chunks:")} ${status.totalChunks}`);
|
|
195
|
+
if (status.staleFiles > 0) {
|
|
196
|
+
console.log(` ${chalk.dim("Stale files:")} ${chalk.yellow(String(status.staleFiles))}`);
|
|
197
|
+
}
|
|
198
|
+
console.log(` ${chalk.dim("Index size:")} ${formatBytes(status.indexSizeBytes)}`);
|
|
199
|
+
if (status.lastUpdated) {
|
|
200
|
+
console.log(` ${chalk.dim("Last updated:")} ${status.lastUpdated}`);
|
|
201
|
+
}
|
|
202
|
+
console.log("");
|
|
203
|
+
}
|
|
204
|
+
async function reindexSubcommand(projectDir) {
|
|
205
|
+
console.log(chalk.bold("\nCodeMap \u2014 Re-index Project\n"));
|
|
206
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
207
|
+
const branch = getCurrentBranch(projectDir);
|
|
208
|
+
const { getCodemapStatus } = await import("./dist-LZKZFPVX.js");
|
|
209
|
+
const status = getCodemapStatus(projectDir, branch);
|
|
210
|
+
if (!status.initialized) {
|
|
211
|
+
console.log(chalk.yellow("Index not initialized. Running init instead..."));
|
|
212
|
+
}
|
|
213
|
+
return initSubcommand(projectDir);
|
|
214
|
+
}
|
|
215
|
+
async function configSubcommand(args, projectDir) {
|
|
216
|
+
const { loadCodemapConfig, saveCodemapConfig } = await import("./dist-LZKZFPVX.js");
|
|
217
|
+
const config = loadCodemapConfig(projectDir);
|
|
218
|
+
if (args.length === 0) {
|
|
219
|
+
console.log(chalk.bold("\nCodeMap Configuration\n"));
|
|
220
|
+
console.log(JSON.stringify(config, null, 2));
|
|
221
|
+
console.log("");
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const key = args[0];
|
|
225
|
+
const value = args[1];
|
|
226
|
+
if (!value) {
|
|
227
|
+
const val = getNestedValue(config, key);
|
|
228
|
+
if (val === void 0) {
|
|
229
|
+
console.log(chalk.red(`Unknown config key: ${key}`));
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
console.log(String(val));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const { CodemapConfigSchema } = await import("./dist-6G7JC2RA.js");
|
|
237
|
+
const updated = setNestedValue(config, key, value);
|
|
238
|
+
const validated = CodemapConfigSchema.parse(updated);
|
|
239
|
+
saveCodemapConfig(projectDir, validated);
|
|
240
|
+
console.log(chalk.green(`\u2713 Set ${key} = ${value}`));
|
|
241
|
+
} catch (err) {
|
|
242
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
243
|
+
console.log(chalk.red(`Error: ${message}`));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function truncate(str, maxLen) {
|
|
247
|
+
if (str.length <= maxLen) return str;
|
|
248
|
+
return str.slice(0, maxLen - 3) + "...";
|
|
249
|
+
}
|
|
250
|
+
function formatBytes(bytes) {
|
|
251
|
+
if (bytes === 0) return "0 B";
|
|
252
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
253
|
+
const i = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
|
|
254
|
+
const val = bytes / Math.pow(1024, i);
|
|
255
|
+
return `${val.toFixed(i === 0 ? 0 : 1)} ${units[i]}`;
|
|
256
|
+
}
|
|
257
|
+
function getNestedValue(obj, path) {
|
|
258
|
+
const parts = path.split(".");
|
|
259
|
+
let current = obj;
|
|
260
|
+
for (const part of parts) {
|
|
261
|
+
if (current === null || current === void 0 || typeof current !== "object") return void 0;
|
|
262
|
+
current = current[part];
|
|
263
|
+
}
|
|
264
|
+
return current;
|
|
265
|
+
}
|
|
266
|
+
function setNestedValue(obj, path, value) {
|
|
267
|
+
const clone = JSON.parse(JSON.stringify(obj));
|
|
268
|
+
const parts = path.split(".");
|
|
269
|
+
let current = clone;
|
|
270
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
271
|
+
const part = parts[i];
|
|
272
|
+
if (typeof current[part] !== "object" || current[part] === null) {
|
|
273
|
+
current[part] = {};
|
|
274
|
+
}
|
|
275
|
+
current = current[part];
|
|
276
|
+
}
|
|
277
|
+
const lastKey = parts[parts.length - 1];
|
|
278
|
+
if (value === "true") current[lastKey] = true;
|
|
279
|
+
else if (value === "false") current[lastKey] = false;
|
|
280
|
+
else if (/^\d+$/.test(value)) current[lastKey] = parseInt(value, 10);
|
|
281
|
+
else if (/^\d+\.\d+$/.test(value)) current[lastKey] = parseFloat(value);
|
|
282
|
+
else current[lastKey] = value;
|
|
283
|
+
return clone;
|
|
284
|
+
}
|
|
285
|
+
async function watchSubcommand(projectDir) {
|
|
286
|
+
console.log(chalk.bold("\nCodeMap \u2014 Watch Mode\n"));
|
|
287
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
288
|
+
const branch = getCurrentBranch(projectDir);
|
|
289
|
+
const { getCodemapStatus, CodemapWatcher } = await import("./dist-LZKZFPVX.js");
|
|
290
|
+
const status = getCodemapStatus(projectDir, branch);
|
|
291
|
+
if (!status.initialized) {
|
|
292
|
+
console.log(chalk.yellow("Index not initialized. Running init first..."));
|
|
293
|
+
await initSubcommand(projectDir);
|
|
294
|
+
console.log("");
|
|
295
|
+
}
|
|
296
|
+
const watcher = new CodemapWatcher({ projectDir, branch });
|
|
297
|
+
console.log(chalk.green("\u2713 Watcher started"));
|
|
298
|
+
console.log(chalk.dim(" Watching for file changes..."));
|
|
299
|
+
console.log(chalk.dim(" Press Ctrl+C to stop.\n"));
|
|
300
|
+
await watcher.start();
|
|
301
|
+
await new Promise((resolve) => {
|
|
302
|
+
const shutdown = async () => {
|
|
303
|
+
console.log(chalk.dim("\n Stopping watcher..."));
|
|
304
|
+
await watcher.stop();
|
|
305
|
+
console.log(chalk.green("\u2713 Watcher stopped"));
|
|
306
|
+
resolve();
|
|
307
|
+
};
|
|
308
|
+
process.on("SIGINT", () => {
|
|
309
|
+
shutdown().catch(() => process.exit(0));
|
|
310
|
+
});
|
|
311
|
+
process.on("SIGTERM", () => {
|
|
312
|
+
shutdown().catch(() => process.exit(0));
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
async function exportSubcommand(projectDir) {
|
|
317
|
+
console.log(chalk.bold("\nCodeMap \u2014 Export Index\n"));
|
|
318
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
319
|
+
const branch = getCurrentBranch(projectDir);
|
|
320
|
+
const { exportIndex } = await import("./dist-LZKZFPVX.js");
|
|
321
|
+
try {
|
|
322
|
+
const result = await exportIndex(projectDir, branch);
|
|
323
|
+
console.log(chalk.green("\u2713 Export complete"));
|
|
324
|
+
console.log(chalk.dim(` Branch: ${result.branchName}`));
|
|
325
|
+
console.log(chalk.dim(` Commit: ${result.commitSha.slice(0, 8)}`));
|
|
326
|
+
console.log(chalk.dim(` Files: ${result.filesExported}`));
|
|
327
|
+
console.log(chalk.dim(` Size: ${formatBytes(result.totalSizeBytes)}`));
|
|
328
|
+
console.log("");
|
|
329
|
+
} catch (err) {
|
|
330
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
331
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
332
|
+
process.exit(1);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
async function importSubcommand(projectDir) {
|
|
336
|
+
console.log(chalk.bold("\nCodeMap \u2014 Import Index\n"));
|
|
337
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
338
|
+
const branch = getCurrentBranch(projectDir);
|
|
339
|
+
const { importIndex } = await import("./dist-LZKZFPVX.js");
|
|
340
|
+
try {
|
|
341
|
+
const result = await importIndex(projectDir, branch);
|
|
342
|
+
if (!result.success) {
|
|
343
|
+
console.log(chalk.yellow(`Import skipped: ${result.message}`));
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
console.log(chalk.green("\u2713 Import complete"));
|
|
347
|
+
console.log(chalk.dim(` Files: ${result.filesImported}`));
|
|
348
|
+
console.log(chalk.dim(` Size: ${formatBytes(result.totalSizeBytes)}`));
|
|
349
|
+
if (result.rebuildRecommended) {
|
|
350
|
+
console.log(chalk.yellow("\n Warning: Embedding provider/model mismatch detected."));
|
|
351
|
+
console.log(chalk.yellow(" Run 'ulpi codemap reindex' to rebuild with current settings."));
|
|
352
|
+
}
|
|
353
|
+
console.log("");
|
|
354
|
+
} catch (err) {
|
|
355
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
356
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async function serveSubcommand(projectDir) {
|
|
361
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
362
|
+
const branch = getCurrentBranch(projectDir);
|
|
363
|
+
const { getCodemapStatus } = await import("./dist-LZKZFPVX.js");
|
|
364
|
+
const status = getCodemapStatus(projectDir, branch);
|
|
365
|
+
if (!status.initialized) {
|
|
366
|
+
console.error(chalk.red("Error: CodeMap index not initialized. Run 'ulpi codemap init' first."));
|
|
367
|
+
process.exit(1);
|
|
368
|
+
}
|
|
369
|
+
console.error(chalk.dim("[codemap-mcp] Starting MCP server..."));
|
|
370
|
+
console.error(chalk.dim(`[codemap-mcp] Project: ${projectDir}`));
|
|
371
|
+
console.error(chalk.dim(`[codemap-mcp] Index: ${status.totalFiles} files, ${status.totalChunks} chunks`));
|
|
372
|
+
const { startMcpServer } = await import("./dist-W7K4WPAF.js");
|
|
373
|
+
await startMcpServer({ projectDir, branch });
|
|
374
|
+
}
|
|
375
|
+
async function evalSubcommand(args, projectDir) {
|
|
376
|
+
const { runEvalHarness } = await import("./dist-LZKZFPVX.js");
|
|
377
|
+
const path = await import("path");
|
|
378
|
+
const datasetIdx = args.indexOf("--dataset");
|
|
379
|
+
let datasetPath;
|
|
380
|
+
if (datasetIdx !== -1 && args[datasetIdx + 1]) {
|
|
381
|
+
datasetPath = path.resolve(args[datasetIdx + 1]);
|
|
382
|
+
} else {
|
|
383
|
+
const { projectCodemapDir } = await import("./dist-RKOGLK7R.js");
|
|
384
|
+
datasetPath = path.join(projectCodemapDir(projectDir), "eval", "queries.json");
|
|
385
|
+
}
|
|
386
|
+
const jsonOutput = args.includes("--json");
|
|
387
|
+
console.log(chalk.bold("\nCodeMap \u2014 Eval Harness\n"));
|
|
388
|
+
console.log(chalk.dim(` Dataset: ${datasetPath}`));
|
|
389
|
+
try {
|
|
390
|
+
const report = await runEvalHarness(projectDir, datasetPath);
|
|
391
|
+
if (jsonOutput) {
|
|
392
|
+
console.log(JSON.stringify(report, null, 2));
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
console.log(chalk.bold("\n Aggregate Metrics:"));
|
|
396
|
+
console.log(` Recall@5: ${(report.aggregate.recallAt5 * 100).toFixed(1)}%`);
|
|
397
|
+
console.log(` MRR@10: ${(report.aggregate.mrrAt10 * 100).toFixed(1)}%`);
|
|
398
|
+
console.log(` nDCG@10: ${(report.aggregate.ndcgAt10 * 100).toFixed(1)}%`);
|
|
399
|
+
console.log(chalk.dim(`
|
|
400
|
+
Queries: ${report.queriesCount}`));
|
|
401
|
+
console.log(chalk.dim(` Total: ${(report.timing.totalMs / 1e3).toFixed(1)}s`));
|
|
402
|
+
console.log(chalk.dim(` Avg: ${report.timing.avgPerQueryMs.toFixed(0)}ms/query`));
|
|
403
|
+
if (report.aggregate.recallAt5 < 0.8) {
|
|
404
|
+
console.log(chalk.yellow(`
|
|
405
|
+
Warning: Recall@5 (${(report.aggregate.recallAt5 * 100).toFixed(1)}%) below target (80%)`));
|
|
406
|
+
}
|
|
407
|
+
if (report.aggregate.mrrAt10 < 0.65) {
|
|
408
|
+
console.log(chalk.yellow(` Warning: MRR@10 (${(report.aggregate.mrrAt10 * 100).toFixed(1)}%) below target (65%)`));
|
|
409
|
+
}
|
|
410
|
+
console.log("");
|
|
411
|
+
} catch (err) {
|
|
412
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
413
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
414
|
+
process.exit(1);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
async function migrateIndexSubcommand(projectDir) {
|
|
418
|
+
console.log(chalk.bold("\nCodeMap \u2014 Migrate Legacy Index\n"));
|
|
419
|
+
const { migrateFromLegacy } = await import("./dist-LZKZFPVX.js");
|
|
420
|
+
try {
|
|
421
|
+
const result = await migrateFromLegacy(projectDir);
|
|
422
|
+
if (!result.migrated) {
|
|
423
|
+
console.log(chalk.yellow(` ${result.message}`));
|
|
424
|
+
} else {
|
|
425
|
+
console.log(chalk.green("\u2713 Migration complete"));
|
|
426
|
+
console.log(chalk.dim(` Files: ${result.filesCount}`));
|
|
427
|
+
console.log(chalk.dim(` Size: ${formatBytes(result.totalSizeBytes)}`));
|
|
428
|
+
}
|
|
429
|
+
console.log("");
|
|
430
|
+
} catch (err) {
|
|
431
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
432
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
async function depsSubcommand(args, projectDir) {
|
|
437
|
+
const filePath = args.filter((a) => !a.startsWith("-"))[0];
|
|
438
|
+
if (!filePath) {
|
|
439
|
+
console.log(chalk.red("Usage: ulpi codemap deps <file> [--transitive|-t] [--depth N]"));
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const transitive = args.includes("--transitive") || args.includes("-t");
|
|
443
|
+
const depthIdx = args.indexOf("--depth");
|
|
444
|
+
const maxDepth = depthIdx >= 0 ? parseInt(args[depthIdx + 1], 10) || 5 : 5;
|
|
445
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
446
|
+
const branch = getCurrentBranch(projectDir);
|
|
447
|
+
const { loadGraph, getOutgoingEdges, getTransitiveDeps } = await import("./dist-R5ZJ4LX5.js");
|
|
448
|
+
const graph = loadGraph(projectDir, branch);
|
|
449
|
+
if (!graph) {
|
|
450
|
+
console.log(chalk.yellow("No dependency graph found. Run 'ulpi codemap init' first."));
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (transitive) {
|
|
454
|
+
const deps = getTransitiveDeps(graph, filePath, maxDepth);
|
|
455
|
+
console.log(chalk.bold(`
|
|
456
|
+
Transitive dependencies of ${filePath} (depth ${maxDepth}):
|
|
457
|
+
`));
|
|
458
|
+
if (deps.length === 0) {
|
|
459
|
+
console.log(chalk.dim(" No dependencies found."));
|
|
460
|
+
} else {
|
|
461
|
+
for (const dep of deps) {
|
|
462
|
+
console.log(chalk.dim(" - ") + dep);
|
|
463
|
+
}
|
|
464
|
+
console.log(chalk.dim(`
|
|
465
|
+
${deps.length} files total`));
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
const edges = getOutgoingEdges(graph, filePath);
|
|
469
|
+
console.log(chalk.bold(`
|
|
470
|
+
Direct dependencies of ${filePath}:
|
|
471
|
+
`));
|
|
472
|
+
if (edges.length === 0) {
|
|
473
|
+
console.log(chalk.dim(" No dependencies found."));
|
|
474
|
+
} else {
|
|
475
|
+
for (const edge of edges) {
|
|
476
|
+
const count = edge.symbols.length;
|
|
477
|
+
const countColor = count >= 5 ? chalk.green : count >= 2 ? chalk.yellow : chalk.dim;
|
|
478
|
+
const symbols = edge.symbols.slice(0, 5).join(", ");
|
|
479
|
+
const more = count > 5 ? ` (+${count - 5} more)` : "";
|
|
480
|
+
console.log(chalk.dim(" - ") + edge.target + " " + countColor(`[${count}]`) + chalk.dim(` ${symbols}${more}`));
|
|
481
|
+
}
|
|
482
|
+
console.log(chalk.dim(`
|
|
483
|
+
${edges.length} direct dependencies`));
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
async function dependentsSubcommand(args, projectDir) {
|
|
488
|
+
const filePath = args.filter((a) => !a.startsWith("-"))[0];
|
|
489
|
+
if (!filePath) {
|
|
490
|
+
console.log(chalk.red("Usage: ulpi codemap dependents <file> [--transitive|-t] [--depth N]"));
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const transitive = args.includes("--transitive") || args.includes("-t");
|
|
494
|
+
const depthIdx = args.indexOf("--depth");
|
|
495
|
+
const maxDepth = depthIdx >= 0 ? parseInt(args[depthIdx + 1], 10) || 5 : 5;
|
|
496
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
497
|
+
const branch = getCurrentBranch(projectDir);
|
|
498
|
+
const { loadGraph, getIncomingEdges, getTransitiveRdeps } = await import("./dist-R5ZJ4LX5.js");
|
|
499
|
+
const graph = loadGraph(projectDir, branch);
|
|
500
|
+
if (!graph) {
|
|
501
|
+
console.log(chalk.yellow("No dependency graph found. Run 'ulpi codemap init' first."));
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
if (transitive) {
|
|
505
|
+
const rdeps = getTransitiveRdeps(graph, filePath, maxDepth);
|
|
506
|
+
console.log(chalk.bold(`
|
|
507
|
+
Transitive dependents of ${filePath} (depth ${maxDepth}):
|
|
508
|
+
`));
|
|
509
|
+
if (rdeps.length === 0) {
|
|
510
|
+
console.log(chalk.dim(" No dependents found."));
|
|
511
|
+
} else {
|
|
512
|
+
for (const dep of rdeps) {
|
|
513
|
+
console.log(chalk.dim(" - ") + dep);
|
|
514
|
+
}
|
|
515
|
+
console.log(chalk.dim(`
|
|
516
|
+
${rdeps.length} files total`));
|
|
517
|
+
}
|
|
518
|
+
} else {
|
|
519
|
+
const edges = getIncomingEdges(graph, filePath);
|
|
520
|
+
console.log(chalk.bold(`
|
|
521
|
+
Direct dependents of ${filePath}:
|
|
522
|
+
`));
|
|
523
|
+
if (edges.length === 0) {
|
|
524
|
+
console.log(chalk.dim(" No dependents found."));
|
|
525
|
+
} else {
|
|
526
|
+
for (const edge of edges) {
|
|
527
|
+
const count = edge.symbols.length;
|
|
528
|
+
const countColor = count >= 5 ? chalk.green : count >= 2 ? chalk.yellow : chalk.dim;
|
|
529
|
+
const symbols = edge.symbols.slice(0, 5).join(", ");
|
|
530
|
+
const more = count > 5 ? ` (+${count - 5} more)` : "";
|
|
531
|
+
console.log(chalk.dim(" - ") + edge.source + " " + countColor(`[${count}]`) + chalk.dim(` ${symbols}${more}`));
|
|
532
|
+
}
|
|
533
|
+
console.log(chalk.dim(`
|
|
534
|
+
${edges.length} direct dependents`));
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
async function rankSubcommand(args, projectDir) {
|
|
539
|
+
const limitIdx = args.indexOf("--limit");
|
|
540
|
+
const limit = limitIdx >= 0 ? parseInt(args[limitIdx + 1], 10) || 20 : 20;
|
|
541
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
542
|
+
const branch = getCurrentBranch(projectDir);
|
|
543
|
+
const { loadPageRank, loadGraph } = await import("./dist-R5ZJ4LX5.js");
|
|
544
|
+
const result = loadPageRank(projectDir, branch);
|
|
545
|
+
if (!result) {
|
|
546
|
+
console.log(chalk.yellow("No PageRank data found. Run 'ulpi codemap init' first."));
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const graph = loadGraph(projectDir, branch);
|
|
550
|
+
const sorted = Object.entries(result.ranks).sort((a, b) => b[1] - a[1]).slice(0, limit);
|
|
551
|
+
const topRank = sorted[0]?.[1] ?? 0;
|
|
552
|
+
console.log(chalk.bold(`
|
|
553
|
+
Top ${sorted.length} files by PageRank
|
|
554
|
+
`));
|
|
555
|
+
console.log(chalk.dim(` d=${result.dampingFactor}, ${result.converged ? "converged" : "not converged"} in ${result.iterations} iterations
|
|
556
|
+
`));
|
|
557
|
+
console.log(chalk.dim(" # Score Defs Refs File"));
|
|
558
|
+
console.log(chalk.dim(" " + "\u2014".repeat(70)));
|
|
559
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
560
|
+
const [file, rank] = sorted[i];
|
|
561
|
+
const rankStr = (rank * 1e3).toFixed(3).padStart(7);
|
|
562
|
+
const node = graph?.nodes[file];
|
|
563
|
+
const defs = String(node?.definitionCount ?? 0).padStart(4);
|
|
564
|
+
const refs = String(node?.referenceCount ?? 0).padStart(5);
|
|
565
|
+
const ratio = topRank > 0 ? rank / topRank : 0;
|
|
566
|
+
const rankColor = ratio > 0.5 ? chalk.green : ratio > 0.2 ? chalk.yellow : chalk.dim;
|
|
567
|
+
console.log(` ${chalk.dim((i + 1).toString().padStart(3) + ".")} ${rankColor(rankStr)} ${chalk.dim(defs)} ${chalk.dim(refs)} ${file}`);
|
|
568
|
+
}
|
|
569
|
+
console.log(chalk.dim(`
|
|
570
|
+
${Object.keys(result.ranks).length} total files`));
|
|
571
|
+
}
|
|
572
|
+
async function cyclesSubcommand(projectDir) {
|
|
573
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
574
|
+
const branch = getCurrentBranch(projectDir);
|
|
575
|
+
const { loadMetrics, loadGraph, detectCycles } = await import("./dist-R5ZJ4LX5.js");
|
|
576
|
+
let cycles;
|
|
577
|
+
const metrics = loadMetrics(projectDir, branch);
|
|
578
|
+
if (metrics) {
|
|
579
|
+
cycles = metrics.cycles;
|
|
580
|
+
} else {
|
|
581
|
+
const graph = loadGraph(projectDir, branch);
|
|
582
|
+
if (!graph) {
|
|
583
|
+
console.log(chalk.yellow("No dependency graph found. Run 'ulpi codemap init' first."));
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
cycles = detectCycles(graph);
|
|
587
|
+
}
|
|
588
|
+
if (cycles.length === 0) {
|
|
589
|
+
console.log(chalk.green("\nNo circular dependencies detected.\n"));
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
console.log(chalk.bold(`
|
|
593
|
+
Circular Dependencies
|
|
594
|
+
`));
|
|
595
|
+
for (let i = 0; i < cycles.length; i++) {
|
|
596
|
+
const cycle = cycles[i];
|
|
597
|
+
const color = cycle.files.length <= 2 ? chalk.red : chalk.yellow;
|
|
598
|
+
const chain = cycle.files.join(chalk.dim(" -> "));
|
|
599
|
+
console.log(` ${color(`${i + 1}.`)} ${chain} ${chalk.dim("->")} ${color(cycle.files[0])}`);
|
|
600
|
+
}
|
|
601
|
+
console.log(chalk.dim(`
|
|
602
|
+
Found ${cycles.length} circular dependency cycle${cycles.length === 1 ? "" : "s"}`));
|
|
603
|
+
}
|
|
604
|
+
async function couplingSubcommand(args, projectDir) {
|
|
605
|
+
const modulePath = args.filter((a) => !a.startsWith("--"))[0] || "";
|
|
606
|
+
const { getCurrentBranch } = await import("./dist-RKOGLK7R.js");
|
|
607
|
+
const branch = getCurrentBranch(projectDir);
|
|
608
|
+
const { loadGraph, computeCoupling } = await import("./dist-R5ZJ4LX5.js");
|
|
609
|
+
const graph = loadGraph(projectDir, branch);
|
|
610
|
+
if (!graph) {
|
|
611
|
+
console.log(chalk.yellow("No dependency graph found. Run 'ulpi codemap init' first."));
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
const allCoupling = computeCoupling(graph);
|
|
615
|
+
const filtered = modulePath ? allCoupling.filter((c) => c.filePath.startsWith(modulePath)) : allCoupling;
|
|
616
|
+
const sorted = filtered.sort((a, b) => b.instability - a.instability);
|
|
617
|
+
console.log(chalk.bold(`
|
|
618
|
+
Coupling Metrics${modulePath ? ` for ${modulePath}` : ""}:
|
|
619
|
+
`));
|
|
620
|
+
console.log(chalk.dim(" File Ca Ce Instability"));
|
|
621
|
+
console.log(chalk.dim(" " + "\u2014".repeat(70)));
|
|
622
|
+
for (const m of sorted.slice(0, 30)) {
|
|
623
|
+
const instColor = m.instability > 0.8 ? chalk.red : m.instability > 0.5 ? chalk.yellow : chalk.green;
|
|
624
|
+
const name = m.filePath.length > 45 ? "..." + m.filePath.slice(-42) : m.filePath.padEnd(45);
|
|
625
|
+
console.log(` ${name} ${String(m.afferentCoupling).padStart(4)} ${String(m.efferentCoupling).padStart(4)} ${instColor(m.instability.toFixed(3))}`);
|
|
626
|
+
}
|
|
627
|
+
if (sorted.length > 30) {
|
|
628
|
+
console.log(chalk.dim(`
|
|
629
|
+
... and ${sorted.length - 30} more files`));
|
|
630
|
+
}
|
|
631
|
+
console.log(chalk.dim(`
|
|
632
|
+
${sorted.length} files analyzed`));
|
|
633
|
+
}
|
|
634
|
+
export {
|
|
635
|
+
runCodemap
|
|
636
|
+
};
|