Implement layered maps and context retrieval
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { tmpdir } from "os";
|
||||
import { execSync } from "child_process";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const projectRoot = fileURLToPath(new URL("..", import.meta.url));
|
||||
|
||||
function runCli(
|
||||
args: string,
|
||||
cwd: string,
|
||||
): { stdout: string; stderr: string; exitCode: number } {
|
||||
try {
|
||||
const stdout = execSync(
|
||||
`npx tsx ${join(projectRoot, "src/cli/cli.ts")} ${args}`,
|
||||
{
|
||||
cwd,
|
||||
encoding: "utf8",
|
||||
stdio: ["pipe", "pipe", "pipe"],
|
||||
},
|
||||
);
|
||||
return { stdout: stdout.trim(), stderr: "", exitCode: 0 };
|
||||
} catch (err: any) {
|
||||
return {
|
||||
stdout: err.stdout?.toString().trim() || "",
|
||||
stderr: err.stderr?.toString().trim() || "",
|
||||
exitCode: err.status || 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
describe("cli context", () => {
|
||||
let dir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
dir = mkdtempSync(join(tmpdir(), "pi-map-cli-"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
rmSync(dir, { recursive: true });
|
||||
});
|
||||
|
||||
it("context command returns a bundle for a matching query", () => {
|
||||
mkdirSync(join(dir, "src"));
|
||||
mkdirSync(join(dir, "src", "auth"));
|
||||
writeFileSync(
|
||||
join(dir, "src", "auth", "tokens.ts"),
|
||||
`export function validateToken() {}\n`,
|
||||
);
|
||||
writeFileSync(
|
||||
join(dir, "src", "auth", ".pi-map.md"),
|
||||
`# src/auth
|
||||
dir: src/auth
|
||||
index: src/auth/.pi-map.index.md
|
||||
## role
|
||||
Authentication and token validation.
|
||||
## files
|
||||
- tokens.ts | Token validation | exp: validateToken | dep: -
|
||||
## arch
|
||||
Guard pattern.
|
||||
## tags
|
||||
auth, token, validate
|
||||
## symbols
|
||||
validateToken
|
||||
## workflows
|
||||
- validate token
|
||||
files: tokens.ts
|
||||
## dirty
|
||||
-
|
||||
`,
|
||||
);
|
||||
writeFileSync(
|
||||
join(dir, "src", "auth", ".pi-map.index.md"),
|
||||
`# src/auth (index)
|
||||
dir: src/auth
|
||||
## role
|
||||
Auth layer.
|
||||
## parent
|
||||
index: ./.pi-map.index.md
|
||||
map: ./.pi-map.md
|
||||
## children
|
||||
-
|
||||
## files
|
||||
- tokens.ts
|
||||
## links
|
||||
index: src/auth/.pi-map.index.md
|
||||
map: src/auth/.pi-map.md
|
||||
## workflows
|
||||
- validate token
|
||||
## dirty
|
||||
-
|
||||
`,
|
||||
);
|
||||
|
||||
const { stdout, exitCode } = runCli('context "token validation"', dir);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("# Context bundle: token validation");
|
||||
expect(stdout).toContain("## relevant indexes");
|
||||
expect(stdout).toContain("src/auth/.pi-map.index.md");
|
||||
expect(stdout).toContain("## relevant maps");
|
||||
expect(stdout).toContain("src/auth/.pi-map.md");
|
||||
expect(stdout).toContain("## likely files");
|
||||
expect(stdout).toContain("src/auth/tokens.ts");
|
||||
expect(stdout).toContain("## instructions");
|
||||
});
|
||||
|
||||
it("context command omits symbols section when no symbols exist", () => {
|
||||
mkdirSync(join(dir, "src"));
|
||||
writeFileSync(
|
||||
join(dir, "src", ".pi-map.md"),
|
||||
`# src
|
||||
dir: src
|
||||
index: src/.pi-map.index.md
|
||||
## role
|
||||
Core source.
|
||||
## files
|
||||
- index.ts | Entry | exp: main | dep: -
|
||||
## arch
|
||||
Entrypoint.
|
||||
## tags
|
||||
-
|
||||
## symbols
|
||||
-
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
`,
|
||||
);
|
||||
writeFileSync(
|
||||
join(dir, "src", ".pi-map.index.md"),
|
||||
`# src (index)
|
||||
dir: src
|
||||
## role
|
||||
Core source.
|
||||
## parent
|
||||
-
|
||||
## children
|
||||
-
|
||||
## files
|
||||
- index.ts
|
||||
## links
|
||||
index: src/.pi-map.index.md
|
||||
map: src/.pi-map.md
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
`,
|
||||
);
|
||||
|
||||
const { stdout, exitCode } = runCli('context "core source"', dir);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("# Context bundle: core source");
|
||||
expect(stdout).not.toContain("## relevant symbols");
|
||||
});
|
||||
|
||||
it("context command returns no-results bundle when nothing matches", () => {
|
||||
mkdirSync(join(dir, "src"));
|
||||
writeFileSync(
|
||||
join(dir, "src", ".pi-map.md"),
|
||||
`# src
|
||||
dir: src
|
||||
index: src/.pi-map.index.md
|
||||
## role
|
||||
Core source.
|
||||
## files
|
||||
- index.ts | Entry | exp: main | dep: -
|
||||
## arch
|
||||
Entrypoint.
|
||||
## tags
|
||||
-
|
||||
## symbols
|
||||
-
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
`,
|
||||
);
|
||||
writeFileSync(
|
||||
join(dir, "src", ".pi-map.index.md"),
|
||||
`# src (index)
|
||||
dir: src
|
||||
## role
|
||||
Core source.
|
||||
## parent
|
||||
-
|
||||
## children
|
||||
-
|
||||
## files
|
||||
- index.ts
|
||||
## links
|
||||
index: src/.pi-map.index.md
|
||||
map: src/.pi-map.md
|
||||
## workflows
|
||||
-
|
||||
## dirty
|
||||
-
|
||||
`,
|
||||
);
|
||||
|
||||
const { stdout, exitCode } = runCli('context "zzzzzzzz"', dir);
|
||||
expect(exitCode).toBe(0);
|
||||
expect(stdout).toContain("# Context bundle: zzzzzzzz");
|
||||
expect(stdout).toContain("No relevant directories found");
|
||||
});
|
||||
|
||||
it("context command errors when query is missing", () => {
|
||||
const { stderr, exitCode } = runCli("context", dir);
|
||||
expect(exitCode).toBe(1);
|
||||
expect(stderr).toContain("Missing query");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user