-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcollect-live-evidence.mjs
More file actions
70 lines (63 loc) · 3.21 KB
/
Copy pathcollect-live-evidence.mjs
File metadata and controls
70 lines (63 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/env node
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { buildGraph, serializeGraph } from "../skills/codebase-visualize/lib/scanner.mjs";
import { buildHtml } from "../skills/codebase-visualize/lib/renderer.mjs";
const configPath = process.env.CODEBASE_VISUALIZE_LIVE_CONFIG;
if (!configPath) {
console.error("collect:live failed - set CODEBASE_VISUALIZE_LIVE_CONFIG to a JSON config path");
process.exit(1);
}
const config = JSON.parse(readFileSync(configPath, "utf8").replace(/^\uFEFF/, ""));
if (!Array.isArray(config.targets) || config.targets.length === 0) {
throw new Error("live evidence config requires a non-empty targets array");
}
const outputRoot = resolve(process.env.CODEBASE_VISUALIZE_EVIDENCE_ROOT || join(tmpdir(), "codebase-visualize-live-evidence"));
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const outputRelative = relative(repositoryRoot, outputRoot);
if (outputRelative === "" || (!outputRelative.startsWith("..") && !isAbsolute(outputRelative))) {
throw new Error("live evidence output must remain outside the tracked repository");
}
mkdirSync(outputRoot, { recursive: true });
const reports = [];
const labels = new Set();
for (const target of config.targets) {
if (!/^[a-z0-9][a-z0-9-]*$/.test(target.label)) {
throw new Error(`target label must be generic lowercase kebab-case: ${target.label}`);
}
if (labels.has(target.label)) {
throw new Error(`target label must be unique: ${target.label}`);
}
labels.add(target.label);
const graph = buildGraph(resolve(target.path), { generatedAt: new Date().toISOString() });
const html = buildHtml(graph);
const graphText = serializeGraph(graph);
const targetDir = join(outputRoot, target.label);
mkdirSync(targetDir, { recursive: true });
writeFileSync(join(targetDir, "codebase-graph.json"), graphText, "utf8");
writeFileSync(join(targetDir, "codebase-map.html"), html, "utf8");
const files = graph.nodes.filter((node) => node.type === "file");
const report = {
label: target.label,
files: graph.metadata.counts.files,
folders: graph.metadata.counts.folders,
edges: graph.edges.length,
references: graph.metadata.counts.references_edges,
unknowns: files.filter((node) => node.kind === "unknown").length,
warnings: graph.metadata.scan_warnings.length,
graph_bytes: Buffer.byteLength(graphText),
map_bytes: Buffer.byteLength(html),
orient_docs: files.filter((node) => node.risk_hints?.includes("orient-docs")).length,
};
reports.push(report);
console.log(`LIVE ${target.label} - ${Object.entries(report).filter(([key]) => key !== "label").map(([key, value]) => `${key}=${value}`).join(" ")}`);
}
const summary = {
generated_at: new Date().toISOString(),
target_count: reports.length,
reports,
};
writeFileSync(join(outputRoot, "summary.json"), JSON.stringify(summary, null, 2) + "\n", "utf8");
console.log(`collect:live OK - sanitized summary and raw artifacts written outside tracked source (${statSync(outputRoot).isDirectory() ? "directory ready" : "unexpected output"}).`);