Implement layered maps and context retrieval
This commit is contained in:
+67
-13
@@ -4,6 +4,7 @@ import { patchFile } from "../patch.js";
|
||||
import { validateMaps } from "../validate.js";
|
||||
import { reinitPath } from "../init.js";
|
||||
import { discoverProject } from "../discover.js";
|
||||
import { retrieveContext } from "../retrieve.js";
|
||||
import { createLLMClient, LLMError } from "../llm/llm-client.js";
|
||||
import { loadConfig } from "../config.js";
|
||||
import pc from "picocolors";
|
||||
@@ -11,6 +12,8 @@ import pc from "picocolors";
|
||||
const args = process.argv.slice(2);
|
||||
const command = args[0];
|
||||
|
||||
type PatchMode = "auto" | "small" | "structural";
|
||||
|
||||
function printUsage() {
|
||||
console.log(`${pc.bold("project-map")} — hierarchical project analysis for Pi agents
|
||||
`);
|
||||
@@ -30,6 +33,9 @@ function printUsage() {
|
||||
console.log(
|
||||
` project-map ${pc.cyan("--help")} Show this help message`,
|
||||
);
|
||||
console.log(
|
||||
` project-map ${pc.cyan("context")} <query> Retrieve relevant project context for a query`,
|
||||
);
|
||||
console.log(
|
||||
` project-map ${pc.cyan("--version")} Show version\n`,
|
||||
);
|
||||
@@ -40,19 +46,21 @@ function printUsage() {
|
||||
console.log(
|
||||
` --llm-model=<model> LLM model name (or set LLM_MODEL env var)`,
|
||||
);
|
||||
console.log(` --llm-base-url=<url> Custom base URL for LLM API\n`);
|
||||
console.log(` --llm-base-url=<url> Custom base URL for LLM API`);
|
||||
console.log(
|
||||
` --patch-mode=<mode> Patch/repair mode: auto|small|structural\n`,
|
||||
);
|
||||
console.log(`${pc.bold("Examples:")}`);
|
||||
console.log(` project-map init`);
|
||||
console.log(` project-map patch src/components/Button.tsx`);
|
||||
console.log(` project-map validate --fix`);
|
||||
console.log(` project-map reinit`);
|
||||
console.log(
|
||||
` project-map init --llm-provider=kimi --llm-model=kimi-k2-6`,
|
||||
);
|
||||
console.log(` project-map context "authentication logic"`);
|
||||
console.log(` project-map init --llm-provider=kimi --llm-model=kimi-k2-6`);
|
||||
}
|
||||
|
||||
function printVersion() {
|
||||
const pkg = require("../package.json");
|
||||
const pkg = require("../../package.json");
|
||||
console.log(pkg.version);
|
||||
}
|
||||
|
||||
@@ -63,7 +71,12 @@ function formatCount(count: number, label: string): string {
|
||||
return `${pc.bold(String(count))} ${count === 1 ? label : plural}`;
|
||||
}
|
||||
|
||||
function renderProgressBar(completed: number, total: number, currentFile?: string, width = 30): string {
|
||||
function renderProgressBar(
|
||||
completed: number,
|
||||
total: number,
|
||||
currentFile?: string,
|
||||
width = 30,
|
||||
): string {
|
||||
const pct = total > 0 ? completed / total : 0;
|
||||
const filled = Math.round(width * pct);
|
||||
const bar = "█".repeat(filled) + "░".repeat(width - filled);
|
||||
@@ -77,6 +90,7 @@ function parseArgs(args: string[]): {
|
||||
llmProvider?: string;
|
||||
llmModel?: string;
|
||||
llmBaseUrl?: string;
|
||||
patchMode?: PatchMode;
|
||||
positional: string[];
|
||||
} {
|
||||
let path = ".";
|
||||
@@ -84,6 +98,7 @@ function parseArgs(args: string[]): {
|
||||
let llmProvider: string | undefined;
|
||||
let llmModel: string | undefined;
|
||||
let llmBaseUrl: string | undefined;
|
||||
let patchMode: PatchMode | undefined;
|
||||
const positional: string[] = [];
|
||||
|
||||
for (const arg of args.slice(1)) {
|
||||
@@ -95,13 +110,23 @@ function parseArgs(args: string[]): {
|
||||
llmModel = arg.slice("--llm-model=".length);
|
||||
} else if (arg.startsWith("--llm-base-url=")) {
|
||||
llmBaseUrl = arg.slice("--llm-base-url=".length);
|
||||
} else if (arg.startsWith("--patch-mode=")) {
|
||||
patchMode = arg.slice("--patch-mode=".length) as PatchMode;
|
||||
} else if (!arg.startsWith("-")) {
|
||||
positional.push(arg);
|
||||
path = arg;
|
||||
}
|
||||
}
|
||||
|
||||
return { path, fix, llmProvider, llmModel, llmBaseUrl, positional };
|
||||
return {
|
||||
path,
|
||||
fix,
|
||||
llmProvider,
|
||||
llmModel,
|
||||
llmBaseUrl,
|
||||
patchMode,
|
||||
positional,
|
||||
};
|
||||
}
|
||||
|
||||
function createClientFromArgs(args: ReturnType<typeof parseArgs>) {
|
||||
@@ -142,8 +167,12 @@ async function main() {
|
||||
llmClient: client,
|
||||
cacheDir: targetPath,
|
||||
onProgress: (info) => {
|
||||
const line = renderProgressBar(info.completed, info.total, info.currentFile);
|
||||
process.stdout.write("\r" + line.padEnd(lastLine.length));
|
||||
const line = renderProgressBar(
|
||||
info.completed,
|
||||
info.total,
|
||||
info.currentFile,
|
||||
);
|
||||
process.stdout.write(`\r${line.padEnd(lastLine.length)}`);
|
||||
lastLine = line;
|
||||
},
|
||||
});
|
||||
@@ -162,13 +191,22 @@ async function main() {
|
||||
process.exit(1);
|
||||
}
|
||||
const client = createClientFromArgs(parsed);
|
||||
await patchFile(parsed.positional[0], client, process.cwd());
|
||||
await patchFile(parsed.positional[0], client, process.cwd(), {
|
||||
patchMode: parsed.patchMode,
|
||||
rootPath: process.cwd(),
|
||||
});
|
||||
console.log(`${pc.green("✓")} Patched`);
|
||||
break;
|
||||
}
|
||||
case "validate": {
|
||||
const { path, fix } = parsed;
|
||||
const result = await validateMaps(path, { fix, verbose: true });
|
||||
const result = await validateMaps(path, {
|
||||
fix,
|
||||
verbose: true,
|
||||
llmClient: fix ? createClientFromArgs(parsed) : undefined,
|
||||
cacheDir: process.cwd(),
|
||||
patchMode: parsed.patchMode,
|
||||
});
|
||||
if (result.clean) {
|
||||
console.log(`${pc.green("✓")} All .pi-map.md files are clean.`);
|
||||
} else {
|
||||
@@ -190,6 +228,18 @@ async function main() {
|
||||
process.exit(result.clean ? 0 : 1);
|
||||
break;
|
||||
}
|
||||
case "context": {
|
||||
if (!parsed.positional[0]) {
|
||||
console.error(
|
||||
`${pc.red("Error:")} Missing query. Usage: project-map context <query>`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const query = parsed.positional[0];
|
||||
const bundle = retrieveContext(query, process.cwd());
|
||||
console.log(bundle);
|
||||
break;
|
||||
}
|
||||
case "reinit": {
|
||||
const targetPath = parsed.positional[0] || ".";
|
||||
const start = Date.now();
|
||||
@@ -204,8 +254,12 @@ async function main() {
|
||||
llmClient: client,
|
||||
cacheDir: targetPath,
|
||||
onProgress: (info) => {
|
||||
const line = renderProgressBar(info.completed, info.total, info.currentFile);
|
||||
process.stdout.write("\r" + line.padEnd(lastLine.length));
|
||||
const line = renderProgressBar(
|
||||
info.completed,
|
||||
info.total,
|
||||
info.currentFile,
|
||||
);
|
||||
process.stdout.write(`\r${line.padEnd(lastLine.length)}`);
|
||||
lastLine = line;
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user