@nanonets/graft 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 +228 -0
- package/dist/ai/crux.d.ts +31 -0
- package/dist/ai/crux.d.ts.map +1 -0
- package/dist/ai/crux.js +91 -0
- package/dist/ai/crux.js.map +1 -0
- package/dist/ai/providers.d.ts +37 -0
- package/dist/ai/providers.d.ts.map +1 -0
- package/dist/ai/providers.js +17 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/ai/summarize.d.ts +25 -0
- package/dist/ai/summarize.d.ts.map +1 -0
- package/dist/ai/summarize.js +41 -0
- package/dist/ai/summarize.js.map +1 -0
- package/dist/ai/synthesize.d.ts +32 -0
- package/dist/ai/synthesize.d.ts.map +1 -0
- package/dist/ai/synthesize.js +132 -0
- package/dist/ai/synthesize.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +131 -0
- package/dist/cli.js.map +1 -0
- package/dist/context/build.d.ts +33 -0
- package/dist/context/build.d.ts.map +1 -0
- package/dist/context/build.js +265 -0
- package/dist/context/build.js.map +1 -0
- package/dist/context/check.d.ts +21 -0
- package/dist/context/check.d.ts.map +1 -0
- package/dist/context/check.js +127 -0
- package/dist/context/check.js.map +1 -0
- package/dist/context/node-file.d.ts +80 -0
- package/dist/context/node-file.d.ts.map +1 -0
- package/dist/context/node-file.js +165 -0
- package/dist/context/node-file.js.map +1 -0
- package/dist/engine.d.ts +58 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +87 -0
- package/dist/engine.js.map +1 -0
- package/dist/graph/build.d.ts +33 -0
- package/dist/graph/build.d.ts.map +1 -0
- package/dist/graph/build.js +95 -0
- package/dist/graph/build.js.map +1 -0
- package/dist/graph/check.d.ts +18 -0
- package/dist/graph/check.d.ts.map +1 -0
- package/dist/graph/check.js +126 -0
- package/dist/graph/check.js.map +1 -0
- package/dist/graph/enrich.d.ts +42 -0
- package/dist/graph/enrich.d.ts.map +1 -0
- package/dist/graph/enrich.js +141 -0
- package/dist/graph/enrich.js.map +1 -0
- package/dist/graph/extract.d.ts +23 -0
- package/dist/graph/extract.d.ts.map +1 -0
- package/dist/graph/extract.js +249 -0
- package/dist/graph/extract.js.map +1 -0
- package/dist/graph/resolve.d.ts +4 -0
- package/dist/graph/resolve.d.ts.map +1 -0
- package/dist/graph/resolve.js +0 -0
- package/dist/graph/resolve.js.map +1 -0
- package/dist/graph/types.d.ts +56 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +14 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/graph/write.d.ts +9 -0
- package/dist/graph/write.d.ts.map +1 -0
- package/dist/graph/write.js +39 -0
- package/dist/graph/write.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/ingest/fs.d.ts +10 -0
- package/dist/ingest/fs.d.ts.map +1 -0
- package/dist/ingest/fs.js +48 -0
- package/dist/ingest/fs.js.map +1 -0
- package/dist/util/id.d.ts +7 -0
- package/dist/util/id.d.ts.map +1 -0
- package/dist/util/id.js +14 -0
- package/dist/util/id.js.map +1 -0
- package/dist/viewer/app.js +1 -0
- package/dist/viewer/index.html +48 -0
- package/dist/viewer/style.css +119 -0
- package/dist/viz/assemble.d.ts +33 -0
- package/dist/viz/assemble.d.ts.map +1 -0
- package/dist/viz/assemble.js +101 -0
- package/dist/viz/assemble.js.map +1 -0
- package/dist/viz/serve.d.ts +12 -0
- package/dist/viz/serve.d.ts.map +1 -0
- package/dist/viz/serve.js +128 -0
- package/dist/viz/serve.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The synthesis step: turn per-file prose summaries into a CURATED set of graph
|
|
3
|
+
* nodes. This is where granularity is decided — the model groups related files
|
|
4
|
+
* into subsystem nodes, keeps a notable file as its own node when it deserves
|
|
5
|
+
* one, and adds cross-cutting concept nodes, instead of emitting one entity per
|
|
6
|
+
* incidental identifier. Each node is attributed to the source files it is
|
|
7
|
+
* grounded in, so provenance (and staleness) stays exact.
|
|
8
|
+
*/
|
|
9
|
+
import OpenAI from "openai";
|
|
10
|
+
const SYSTEM_PROMPT = `You build an ARCHITECTURE graph of a codebase from per-file summaries. The reader is an AI agent that will read this graph before working on the code, so it must describe the system at the level a senior engineer would explain it — not file by file.
|
|
11
|
+
|
|
12
|
+
Produce a CURATED set of nodes of mixed granularity:
|
|
13
|
+
- "system" nodes: GROUP files that collaborate as one component (usually a directory or a cohesive set) into a SINGLE node. This should be the most common node type. Prefer one system node over several file nodes.
|
|
14
|
+
- "file" nodes: only for a substantial, standalone module that genuinely deserves its own node apart from its system.
|
|
15
|
+
- "concept" nodes: cross-cutting ideas, design decisions, or invariants that span multiple files (e.g. "local-first provider fallback", "staleness checking", "content-hash provenance"). Include several — they are the most valuable nodes for an agent.
|
|
16
|
+
|
|
17
|
+
Rules:
|
|
18
|
+
- Strongly prefer FEWER, larger, meaningful nodes. For a repo of N files, aim for well under N nodes. Do NOT emit one node per file, and never a node per incidental identifier (a local interface, helper, or third-party symbol).
|
|
19
|
+
- Merge duplicates and surface-form variants into one node.
|
|
20
|
+
- For each node give: a canonical human-readable name; a type ("system" | "file" | "concept"); a 1-3 sentence summary of its ROLE in the system; "sources" = the exact file paths (from the input) it is grounded in (a system lists all its files; a concept lists the files that motivate it); and "links" to other nodes you define, each with a relation and a short description of what concretely happens in the code.
|
|
21
|
+
- The relation MUST be one of exactly these verbs (each answers a question a code reviewer asks): "part_of" (where does this live?), "uses" (what breaks if the target changes?), "depends_on" (same, for non-call dependencies), "produces" (where does this output come from?), "configures" (what changes its behavior without a code change?), "validates" (what checks or judges this? tests, drift checks, scoring), "implements" (what contract must this honor?). Never invent vague relations like "influences", "supports", or "relates_to" — if none of the verbs fit, drop the link.
|
|
22
|
+
- Only link to nodes you actually define in this response.
|
|
23
|
+
Respond only via the record_graph tool / JSON schema.`;
|
|
24
|
+
const NODES_SCHEMA = {
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: {
|
|
27
|
+
nodes: {
|
|
28
|
+
type: "array",
|
|
29
|
+
items: {
|
|
30
|
+
type: "object",
|
|
31
|
+
properties: {
|
|
32
|
+
name: { type: "string" },
|
|
33
|
+
type: { type: "string" },
|
|
34
|
+
summary: { type: "string" },
|
|
35
|
+
sources: { type: "array", items: { type: "string" } },
|
|
36
|
+
links: {
|
|
37
|
+
type: "array",
|
|
38
|
+
items: {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: {
|
|
41
|
+
to: { type: "string" },
|
|
42
|
+
relation: {
|
|
43
|
+
type: "string",
|
|
44
|
+
enum: ["part_of", "uses", "depends_on", "produces", "configures", "validates", "implements"],
|
|
45
|
+
},
|
|
46
|
+
description: { type: "string" },
|
|
47
|
+
},
|
|
48
|
+
required: ["to", "relation"],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
required: ["name", "type", "summary", "sources"],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
required: ["nodes"],
|
|
57
|
+
};
|
|
58
|
+
/** Cap the total summary text sent in one call so it never blows the context. */
|
|
59
|
+
const MAX_INPUT_CHARS = 60_000;
|
|
60
|
+
function userContent(files) {
|
|
61
|
+
const body = files.map((f) => `## ${f.path}\n\n${f.summary}`).join("\n\n");
|
|
62
|
+
return body.length > MAX_INPUT_CHARS
|
|
63
|
+
? `${body.slice(0, MAX_INPUT_CHARS)}\n… (truncated)`
|
|
64
|
+
: body;
|
|
65
|
+
}
|
|
66
|
+
/** Normalize a raw model response into clean {@link SynthNode}s. */
|
|
67
|
+
function clean(nodes) {
|
|
68
|
+
if (!Array.isArray(nodes))
|
|
69
|
+
return [];
|
|
70
|
+
const out = [];
|
|
71
|
+
for (const n of nodes) {
|
|
72
|
+
if (!n || typeof n.name !== "string" || typeof n.type !== "string")
|
|
73
|
+
continue;
|
|
74
|
+
out.push({
|
|
75
|
+
name: n.name,
|
|
76
|
+
type: n.type,
|
|
77
|
+
summary: typeof n.summary === "string" ? n.summary : "",
|
|
78
|
+
sources: Array.isArray(n.sources) ? n.sources.filter((s) => typeof s === "string") : [],
|
|
79
|
+
links: Array.isArray(n.links)
|
|
80
|
+
? n.links
|
|
81
|
+
.filter((l) => l && typeof l.to === "string" && typeof l.relation === "string")
|
|
82
|
+
.map((l) => ({
|
|
83
|
+
to: l.to,
|
|
84
|
+
relation: l.relation,
|
|
85
|
+
description: typeof l.description === "string" ? l.description : undefined,
|
|
86
|
+
}))
|
|
87
|
+
: [],
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
const RECORD_TOOL = {
|
|
93
|
+
type: "function",
|
|
94
|
+
function: {
|
|
95
|
+
name: "record_graph",
|
|
96
|
+
description: "Record the curated architecture-graph nodes and their links.",
|
|
97
|
+
parameters: NODES_SCHEMA,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
/** Synthesizer backed by OpenRouter's OpenAI-compatible chat API (tool calling). */
|
|
101
|
+
export class OpenRouterSynthesizer {
|
|
102
|
+
client;
|
|
103
|
+
model;
|
|
104
|
+
constructor(apiKey, model, baseUrl = "https://openrouter.ai/api/v1") {
|
|
105
|
+
this.client = new OpenAI({ apiKey, baseURL: baseUrl, defaultHeaders: { "X-Title": "Context Graph Engine" } });
|
|
106
|
+
this.model = model;
|
|
107
|
+
}
|
|
108
|
+
async synthesize(files) {
|
|
109
|
+
if (files.length === 0)
|
|
110
|
+
return [];
|
|
111
|
+
const response = await this.client.chat.completions.create({
|
|
112
|
+
model: this.model,
|
|
113
|
+
temperature: 0,
|
|
114
|
+
tools: [RECORD_TOOL],
|
|
115
|
+
tool_choice: { type: "function", function: { name: "record_graph" } },
|
|
116
|
+
messages: [
|
|
117
|
+
{ role: "system", content: SYSTEM_PROMPT },
|
|
118
|
+
{ role: "user", content: userContent(files) },
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
const call = response.choices[0]?.message?.tool_calls?.[0];
|
|
122
|
+
if (!call || call.type !== "function")
|
|
123
|
+
return [];
|
|
124
|
+
try {
|
|
125
|
+
return clean(JSON.parse(call.function.arguments).nodes);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=synthesize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"synthesize.js","sourceRoot":"","sources":["../../src/ai/synthesize.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `graft` CLI. Two commands:
|
|
4
|
+
*
|
|
5
|
+
* init build .context/ from your code (one markdown node per system,
|
|
6
|
+
* API, or concept; linked to each other; committed to the repo).
|
|
7
|
+
* check fail if .context/ has drifted from the code — for CI.
|
|
8
|
+
*
|
|
9
|
+
* Git is the sync: commit .context/ and anyone who clones the repo has the
|
|
10
|
+
* graph, with no setup.
|
|
11
|
+
*/
|
|
12
|
+
import "dotenv/config";
|
|
13
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;GASG;AACH,OAAO,eAAe,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* `graft` CLI. Two commands:
|
|
4
|
+
*
|
|
5
|
+
* init build .context/ from your code (one markdown node per system,
|
|
6
|
+
* API, or concept; linked to each other; committed to the repo).
|
|
7
|
+
* check fail if .context/ has drifted from the code — for CI.
|
|
8
|
+
*
|
|
9
|
+
* Git is the sync: commit .context/ and anyone who clones the repo has the
|
|
10
|
+
* graph, with no setup.
|
|
11
|
+
*/
|
|
12
|
+
import "dotenv/config";
|
|
13
|
+
import { Command } from "commander";
|
|
14
|
+
import { relative } from "node:path";
|
|
15
|
+
import { Graft } from "./engine.js";
|
|
16
|
+
import { formatCheckReport } from "./context/check.js";
|
|
17
|
+
import { formatGraphCheckReport } from "./graph/check.js";
|
|
18
|
+
const program = new Command();
|
|
19
|
+
program
|
|
20
|
+
.name("graft")
|
|
21
|
+
.description("Build a repo's context graph as linked markdown, and keep it in sync with the code.")
|
|
22
|
+
.option("--dir <path>", "context graph directory (default: <repo>/.context)");
|
|
23
|
+
function engineFrom() {
|
|
24
|
+
const opts = program.opts();
|
|
25
|
+
return new Graft({ contextDir: opts.dir });
|
|
26
|
+
}
|
|
27
|
+
program
|
|
28
|
+
.command("init")
|
|
29
|
+
.description("Build .context/ from your code — one markdown node per system, API, or concept")
|
|
30
|
+
.argument("[dir]", "repository root", ".")
|
|
31
|
+
.option("-e, --extensions <exts...>", 'code extensions to include (e.g. ".ts" ".py")')
|
|
32
|
+
.action(async (dir, opts) => {
|
|
33
|
+
const engine = engineFrom();
|
|
34
|
+
const r = await engine.init(dir, {
|
|
35
|
+
extensions: opts.extensions,
|
|
36
|
+
onProgress: ({ phase, index, total, file }) => process.stderr.write(`\r${phase === "summarize" ? "reading" : "writing"} ${index + 1}/${total}: ${file.slice(0, 50).padEnd(50)}`),
|
|
37
|
+
});
|
|
38
|
+
process.stderr.write("\n");
|
|
39
|
+
console.log(`✓ ${r.nodes} nodes, ${r.links} links from ${r.files} files ` +
|
|
40
|
+
`(${r.summarized} read, ${r.cached} cached)`);
|
|
41
|
+
console.log(` → ${r.contextDir}`);
|
|
42
|
+
for (const e of r.errors)
|
|
43
|
+
console.error(`✗ ${e}`);
|
|
44
|
+
const rel = relative(process.cwd(), r.contextDir) || ".context";
|
|
45
|
+
console.log(` commit it: git add ${rel} && git commit -m "update context graph"`);
|
|
46
|
+
});
|
|
47
|
+
program
|
|
48
|
+
.command("graph")
|
|
49
|
+
.description("Build .context/graph.json — a per-symbol code graph (tree-sitter structure + optional LLM meaning)")
|
|
50
|
+
.argument("[dir]", "repository root", ".")
|
|
51
|
+
.option("--llm", "run the Tier-2 LLM pass (summary + crux); unchanged bodies are served from cache")
|
|
52
|
+
.action(async (dir, opts) => {
|
|
53
|
+
const engine = engineFrom();
|
|
54
|
+
const r = await engine.graph(dir, {
|
|
55
|
+
llm: opts.llm,
|
|
56
|
+
onProgress: ({ phase, index, total, file }) => process.stderr.write(`\r${phase === "enrich" ? "summarizing" : "parsing"} ${index + 1}/${total}: ${file.slice(0, 50).padEnd(50)}`),
|
|
57
|
+
});
|
|
58
|
+
process.stderr.write("\n");
|
|
59
|
+
const fmt = (o) => Object.entries(o)
|
|
60
|
+
.sort((a, b) => b[1] - a[1])
|
|
61
|
+
.map(([k, n]) => `${n} ${k}`)
|
|
62
|
+
.join(", ");
|
|
63
|
+
console.log(`✓ ${r.nodes} nodes (${fmt(r.byKind)}) from ${r.files} files [${r.languages.join(", ")}]`);
|
|
64
|
+
console.log(` ${r.edges} edges (${fmt(r.byRelation)})`);
|
|
65
|
+
const m = r.meaning;
|
|
66
|
+
console.log(` meaning: ${m.computed} computed, ${m.cached} cached, ${m.stale} stale, ${m.pending} pending`);
|
|
67
|
+
console.log(` → ${r.graphPath}`);
|
|
68
|
+
for (const e of r.errors)
|
|
69
|
+
console.error(`✗ ${e}`);
|
|
70
|
+
});
|
|
71
|
+
program
|
|
72
|
+
.command("check")
|
|
73
|
+
.description("Fail if .context/ is stale relative to the code (for CI)")
|
|
74
|
+
.argument("[dir]", "repository root", ".")
|
|
75
|
+
.option("-e, --extensions <exts...>", "code extensions to include")
|
|
76
|
+
.option("--json", "output the drift as JSON")
|
|
77
|
+
.action((dir, opts) => {
|
|
78
|
+
const engine = engineFrom();
|
|
79
|
+
const r = engine.check(dir, { extensions: opts.extensions });
|
|
80
|
+
const g = engine.checkGraph(dir); // graph.json is only judged when it exists
|
|
81
|
+
if (opts.json) {
|
|
82
|
+
console.log(JSON.stringify({ context: r, graph: g.missing ? null : g }, null, 2));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log(formatCheckReport(r));
|
|
86
|
+
if (!g.missing)
|
|
87
|
+
console.log("\n" + formatGraphCheckReport(g));
|
|
88
|
+
}
|
|
89
|
+
// A missing graph.json is not a failure — the markdown graph stands alone.
|
|
90
|
+
if (!r.ok || (!g.missing && !g.ok))
|
|
91
|
+
process.exit(1);
|
|
92
|
+
});
|
|
93
|
+
program
|
|
94
|
+
.command("viz")
|
|
95
|
+
.description("Serve an interactive visualization of the context graph (and graph.json when present)")
|
|
96
|
+
.argument("[dir]", "repository root", ".")
|
|
97
|
+
.option("-p, --port <port>", "port to serve on", "4400")
|
|
98
|
+
.option("--no-open", "don't open the browser")
|
|
99
|
+
.action(async (dir, opts) => {
|
|
100
|
+
const { existsSync } = await import("node:fs");
|
|
101
|
+
const { resolve, basename } = await import("node:path");
|
|
102
|
+
const { spawn } = await import("node:child_process");
|
|
103
|
+
const { fileURLToPath } = await import("node:url");
|
|
104
|
+
const { contextDirFor } = await import("./context/node-file.js");
|
|
105
|
+
const { startVizServer } = await import("./viz/serve.js");
|
|
106
|
+
const root = resolve(dir);
|
|
107
|
+
const globalOpts = program.opts();
|
|
108
|
+
const contextDir = contextDirFor(root, globalOpts.dir);
|
|
109
|
+
if (!existsSync(contextDir)) {
|
|
110
|
+
console.error(`✗ no context graph at ${contextDir} — run \`graft init\` first`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
// dist/cli.js → dist/viewer/ (prebuilt at package build time)
|
|
114
|
+
const viewerDir = fileURLToPath(new URL("./viewer/", import.meta.url));
|
|
115
|
+
const srv = await startVizServer({
|
|
116
|
+
contextDir,
|
|
117
|
+
viewerDir,
|
|
118
|
+
port: Number(opts.port),
|
|
119
|
+
repoName: basename(root),
|
|
120
|
+
});
|
|
121
|
+
console.log(`graft viz → ${srv.url} (ctrl-c to stop)`);
|
|
122
|
+
if (opts.open) {
|
|
123
|
+
const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
124
|
+
spawn(opener, [srv.url], { stdio: "ignore", detached: true, shell: process.platform === "win32" }).unref();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
program.parseAsync().catch((err) => {
|
|
128
|
+
console.error(err instanceof Error ? err.message : err);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Summarizer } from "../ai/summarize.js";
|
|
2
|
+
import type { Synthesizer } from "../ai/synthesize.js";
|
|
3
|
+
/** Extensions treated as source code. */
|
|
4
|
+
export declare const CODE_EXTENSIONS: string[];
|
|
5
|
+
export interface BuildProgress {
|
|
6
|
+
phase: "summarize" | "synthesize" | "write";
|
|
7
|
+
index: number;
|
|
8
|
+
total: number;
|
|
9
|
+
file: string;
|
|
10
|
+
}
|
|
11
|
+
export interface BuildOptions {
|
|
12
|
+
/** Override the output dir (default: `<root>/.context`). */
|
|
13
|
+
contextDir?: string;
|
|
14
|
+
/** Extensions to treat as code. Default: {@link CODE_EXTENSIONS}. */
|
|
15
|
+
extensions?: string[];
|
|
16
|
+
/** Human label for the model, recorded in the manifest (e.g. "openrouter:openai/gpt-4o-mini"). */
|
|
17
|
+
model: string;
|
|
18
|
+
summarizer: Summarizer;
|
|
19
|
+
synthesizer: Synthesizer;
|
|
20
|
+
onProgress?: (info: BuildProgress) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface BuildResult {
|
|
23
|
+
contextDir: string;
|
|
24
|
+
files: number;
|
|
25
|
+
summarized: number;
|
|
26
|
+
cached: number;
|
|
27
|
+
batches: number;
|
|
28
|
+
nodes: number;
|
|
29
|
+
links: number;
|
|
30
|
+
errors: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare function buildContext(dir: string, opts: BuildOptions): Promise<BuildResult>;
|
|
33
|
+
//# sourceMappingURL=build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/context/build.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAA0B,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAiB/E,yCAAyC;AACzC,eAAO,MAAM,eAAe,UAK3B,CAAC;AAKF,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CAC5C;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAwBD,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAuKxF"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `init` — build the `.context/` graph from a code repository.
|
|
3
|
+
*
|
|
4
|
+
* Pipeline (no database, no embeddings):
|
|
5
|
+
* 1. Walk the repo for source files.
|
|
6
|
+
* 2. Summarize each file to prose (one LLM call per file, cached by content hash).
|
|
7
|
+
* 3. Synthesize a CURATED node set from the labeled summaries (the synthesizer
|
|
8
|
+
* decides granularity: subsystems, notable files, and concepts). This is
|
|
9
|
+
* one LLM call per batch of summaries; batches are cached by content.
|
|
10
|
+
* 4. Resolve node names → slugs and links → edges; attribute each node to its
|
|
11
|
+
* source files so staleness stays exact.
|
|
12
|
+
* 5. Write one markdown file per node (preserving human notes) + a manifest.
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
15
|
+
import { join, relative, resolve } from "node:path";
|
|
16
|
+
import { walkDir } from "../ingest/fs.js";
|
|
17
|
+
import { contentHash } from "../util/id.js";
|
|
18
|
+
import { CACHE_DIR, MANIFEST_VERSION, contextDirFor, deleteNode, digestSources, existingNodeSlugs, slugify, writeManifest, writeNode, } from "./node-file.js";
|
|
19
|
+
/** Extensions treated as source code. */
|
|
20
|
+
export const CODE_EXTENSIONS = [
|
|
21
|
+
".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
|
|
22
|
+
".py", ".go", ".rs", ".java", ".kt", ".scala",
|
|
23
|
+
".rb", ".php", ".c", ".h", ".cpp", ".hpp", ".cc",
|
|
24
|
+
".cs", ".swift", ".sql", ".sh", ".proto",
|
|
25
|
+
];
|
|
26
|
+
/** Char budget of summary text per synthesis call (keeps each call in-context). */
|
|
27
|
+
const BATCH_CHAR_BUDGET = 48_000;
|
|
28
|
+
export async function buildContext(dir, opts) {
|
|
29
|
+
const root = resolve(dir);
|
|
30
|
+
const outDir = contextDirFor(root, opts.contextDir);
|
|
31
|
+
const exts = opts.extensions ?? CODE_EXTENSIONS;
|
|
32
|
+
const files = walkDir(root)
|
|
33
|
+
.filter((f) => exts.some((e) => f.toLowerCase().endsWith(e)))
|
|
34
|
+
.filter((f) => !f.startsWith(outDir));
|
|
35
|
+
const cache = loadCache(outDir);
|
|
36
|
+
const result = {
|
|
37
|
+
contextDir: outDir,
|
|
38
|
+
files: 0,
|
|
39
|
+
summarized: 0,
|
|
40
|
+
cached: 0,
|
|
41
|
+
batches: 0,
|
|
42
|
+
nodes: 0,
|
|
43
|
+
links: 0,
|
|
44
|
+
errors: [],
|
|
45
|
+
};
|
|
46
|
+
// Phase 1: summarize each file, concurrent, content-hash cached.
|
|
47
|
+
const work = await mapWithConcurrency(files, 8, async (file, i) => {
|
|
48
|
+
const rel = relative(root, file);
|
|
49
|
+
opts.onProgress?.({ phase: "summarize", index: i, total: files.length, file: rel });
|
|
50
|
+
let code;
|
|
51
|
+
try {
|
|
52
|
+
code = readFileSync(file, "utf8");
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
result.errors.push(`${rel}: ${errMsg(err)}`);
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
const hash = contentHash(code);
|
|
59
|
+
const hit = cache.summaries[rel];
|
|
60
|
+
if (hit && hit.hash === hash) {
|
|
61
|
+
result.cached++;
|
|
62
|
+
return { rel, hash, summary: hit.summary };
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
const summary = await opts.summarizer.summarize(code, { path: rel });
|
|
66
|
+
cache.summaries[rel] = { hash, summary };
|
|
67
|
+
result.summarized++;
|
|
68
|
+
return { rel, hash, summary };
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
result.errors.push(`${rel}: ${errMsg(err)}`);
|
|
72
|
+
return { rel, hash }; // covered (counts against staleness) but not summarized
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
const processed = work.filter((w) => w !== undefined);
|
|
76
|
+
result.files = processed.length;
|
|
77
|
+
const hashByPath = new Map(processed.map((w) => [w.rel, w.hash]));
|
|
78
|
+
// Phase 2: synthesize curated nodes from the summaries, batched + cached.
|
|
79
|
+
const summarized = processed
|
|
80
|
+
.filter((w) => Boolean(w.summary))
|
|
81
|
+
.map((w) => ({ path: w.rel, summary: w.summary }))
|
|
82
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
83
|
+
const batches = batchBySize(summarized, BATCH_CHAR_BUDGET);
|
|
84
|
+
result.batches = batches.length;
|
|
85
|
+
const synthNodes = [];
|
|
86
|
+
for (let b = 0; b < batches.length; b++) {
|
|
87
|
+
opts.onProgress?.({ phase: "synthesize", index: b, total: batches.length, file: `batch ${b + 1}` });
|
|
88
|
+
const key = batchKey(batches[b], hashByPath);
|
|
89
|
+
let nodes = cache.synth[key];
|
|
90
|
+
if (!nodes) {
|
|
91
|
+
nodes = await opts.synthesizer.synthesize(batches[b]);
|
|
92
|
+
cache.synth[key] = nodes;
|
|
93
|
+
}
|
|
94
|
+
synthNodes.push(...nodes);
|
|
95
|
+
}
|
|
96
|
+
// Drop cache entries for batches we no longer produce, so it can't grow forever.
|
|
97
|
+
cache.synth = Object.fromEntries(batches.map((batch) => [batchKey(batch, hashByPath), cache.synth[batchKey(batch, hashByPath)] ?? []]));
|
|
98
|
+
saveCache(outDir, cache);
|
|
99
|
+
// Phase 3: merge synth nodes by slug, building a name→slug resolution table.
|
|
100
|
+
const drafts = new Map();
|
|
101
|
+
const nameToSlug = new Map();
|
|
102
|
+
for (const n of synthNodes) {
|
|
103
|
+
const slug = slugify(n.name);
|
|
104
|
+
let draft = drafts.get(slug);
|
|
105
|
+
if (!draft) {
|
|
106
|
+
draft = { name: n.name, slug, type: n.type || "concept", summary: n.summary ?? "", sources: new Map(), links: new Map() };
|
|
107
|
+
drafts.set(slug, draft);
|
|
108
|
+
}
|
|
109
|
+
if ((n.summary?.length ?? 0) > draft.summary.length)
|
|
110
|
+
draft.summary = n.summary;
|
|
111
|
+
if (n.type && draft.type === "concept")
|
|
112
|
+
draft.type = n.type;
|
|
113
|
+
for (const src of n.sources) {
|
|
114
|
+
const hash = hashByPath.get(src);
|
|
115
|
+
if (hash)
|
|
116
|
+
draft.sources.set(src, hash);
|
|
117
|
+
}
|
|
118
|
+
registerName(nameToSlug, n.name, slug);
|
|
119
|
+
}
|
|
120
|
+
// Phase 4: resolve links to slugs (both endpoints must be defined nodes).
|
|
121
|
+
for (const n of synthNodes) {
|
|
122
|
+
const from = drafts.get(slugify(n.name));
|
|
123
|
+
if (!from)
|
|
124
|
+
continue;
|
|
125
|
+
for (const link of n.links) {
|
|
126
|
+
const to = resolveSlug(nameToSlug, link.to);
|
|
127
|
+
if (!to || to === from.slug)
|
|
128
|
+
continue;
|
|
129
|
+
const key = `${to}|${link.relation}`;
|
|
130
|
+
if (!from.links.has(key))
|
|
131
|
+
from.links.set(key, { to, relation: link.relation, description: link.description });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// Concept nodes the model didn't attribute to files inherit the provenance of
|
|
135
|
+
// the nodes they link to, so they still go stale when their subject changes.
|
|
136
|
+
for (const draft of drafts.values()) {
|
|
137
|
+
if (draft.sources.size > 0)
|
|
138
|
+
continue;
|
|
139
|
+
for (const link of draft.links.values()) {
|
|
140
|
+
const target = drafts.get(link.to);
|
|
141
|
+
if (target)
|
|
142
|
+
for (const [p, h] of target.sources)
|
|
143
|
+
draft.sources.set(p, h);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Phase 5: finalize, reconcile with disk, write.
|
|
147
|
+
const nodes = [...drafts.values()].map((d) => {
|
|
148
|
+
const sources = [...d.sources.entries()]
|
|
149
|
+
.map(([path, hash]) => ({ path, hash }))
|
|
150
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
151
|
+
return {
|
|
152
|
+
name: d.name,
|
|
153
|
+
slug: d.slug,
|
|
154
|
+
type: d.type || "concept",
|
|
155
|
+
summary: d.summary,
|
|
156
|
+
sources,
|
|
157
|
+
sourcesDigest: digestSources(sources),
|
|
158
|
+
links: [...d.links.values()].sort((a, b) => a.to.localeCompare(b.to)),
|
|
159
|
+
human: "",
|
|
160
|
+
};
|
|
161
|
+
});
|
|
162
|
+
nodes.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
163
|
+
const liveSlugs = new Set(nodes.map((n) => n.slug));
|
|
164
|
+
for (const slug of existingNodeSlugs(outDir)) {
|
|
165
|
+
if (!liveSlugs.has(slug))
|
|
166
|
+
deleteNode(outDir, slug);
|
|
167
|
+
}
|
|
168
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
169
|
+
opts.onProgress?.({ phase: "write", index: i, total: nodes.length, file: nodes[i].slug });
|
|
170
|
+
writeNode(outDir, nodes[i]);
|
|
171
|
+
}
|
|
172
|
+
result.nodes = nodes.length;
|
|
173
|
+
result.links = nodes.reduce((n, node) => n + node.links.length, 0);
|
|
174
|
+
// Manifest: authoritative file→hash map (every processed file) + node roster.
|
|
175
|
+
const fileRefs = processed
|
|
176
|
+
.map((w) => ({ path: w.rel, hash: w.hash }))
|
|
177
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
178
|
+
const manifest = {
|
|
179
|
+
version: MANIFEST_VERSION,
|
|
180
|
+
model: opts.model,
|
|
181
|
+
repoDigest: digestSources(fileRefs),
|
|
182
|
+
files: fileRefs,
|
|
183
|
+
nodes: nodes.map((n) => ({
|
|
184
|
+
slug: n.slug,
|
|
185
|
+
name: n.name,
|
|
186
|
+
type: n.type,
|
|
187
|
+
sources: n.sources.map((s) => s.path),
|
|
188
|
+
sourcesDigest: n.sourcesDigest,
|
|
189
|
+
})),
|
|
190
|
+
};
|
|
191
|
+
writeManifest(outDir, manifest);
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
/** Greedily pack file summaries into batches under a char budget (≥1 file each). */
|
|
195
|
+
function batchBySize(files, budget) {
|
|
196
|
+
const batches = [];
|
|
197
|
+
let cur = [];
|
|
198
|
+
let size = 0;
|
|
199
|
+
for (const f of files) {
|
|
200
|
+
const len = f.path.length + f.summary.length + 8;
|
|
201
|
+
if (cur.length > 0 && size + len > budget) {
|
|
202
|
+
batches.push(cur);
|
|
203
|
+
cur = [];
|
|
204
|
+
size = 0;
|
|
205
|
+
}
|
|
206
|
+
cur.push(f);
|
|
207
|
+
size += len;
|
|
208
|
+
}
|
|
209
|
+
if (cur.length > 0)
|
|
210
|
+
batches.push(cur);
|
|
211
|
+
return batches;
|
|
212
|
+
}
|
|
213
|
+
/** Stable key for a batch: its files and their content hashes. */
|
|
214
|
+
function batchKey(batch, hashByPath) {
|
|
215
|
+
return contentHash(batch
|
|
216
|
+
.map((f) => `${f.path}:${hashByPath.get(f.path) ?? ""}`)
|
|
217
|
+
.sort()
|
|
218
|
+
.join("\n"));
|
|
219
|
+
}
|
|
220
|
+
function registerName(table, name, slug) {
|
|
221
|
+
const key = name.trim().toLowerCase();
|
|
222
|
+
if (key && !table.has(key))
|
|
223
|
+
table.set(key, slug);
|
|
224
|
+
}
|
|
225
|
+
function resolveSlug(table, name) {
|
|
226
|
+
return table.get(name.trim().toLowerCase());
|
|
227
|
+
}
|
|
228
|
+
function errMsg(err) {
|
|
229
|
+
return err instanceof Error ? err.message : String(err);
|
|
230
|
+
}
|
|
231
|
+
function cachePath(outDir) {
|
|
232
|
+
return join(outDir, CACHE_DIR, "summaries.json");
|
|
233
|
+
}
|
|
234
|
+
function loadCache(outDir) {
|
|
235
|
+
const path = cachePath(outDir);
|
|
236
|
+
if (existsSync(path)) {
|
|
237
|
+
try {
|
|
238
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
239
|
+
return { summaries: parsed.summaries ?? {}, synth: parsed.synth ?? {} };
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
/* fall through to empty */
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return { summaries: {}, synth: {} };
|
|
246
|
+
}
|
|
247
|
+
function saveCache(outDir, cache) {
|
|
248
|
+
const path = cachePath(outDir);
|
|
249
|
+
mkdirSync(join(outDir, CACHE_DIR), { recursive: true });
|
|
250
|
+
writeFileSync(path, JSON.stringify(cache, null, 2));
|
|
251
|
+
}
|
|
252
|
+
/** Run `fn` over `items` with at most `limit` in flight, preserving order. */
|
|
253
|
+
async function mapWithConcurrency(items, limit, fn) {
|
|
254
|
+
const results = new Array(items.length);
|
|
255
|
+
let next = 0;
|
|
256
|
+
const workers = Array.from({ length: Math.min(limit, items.length) }, async () => {
|
|
257
|
+
while (next < items.length) {
|
|
258
|
+
const i = next++;
|
|
259
|
+
results[i] = await fn(items[i], i);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
await Promise.all(workers);
|
|
263
|
+
return results;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/context/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface CheckResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
/** True when there is no graph at all (init has never run). */
|
|
4
|
+
missing: boolean;
|
|
5
|
+
contentDrift: Array<{
|
|
6
|
+
path: string;
|
|
7
|
+
from: string;
|
|
8
|
+
to: string;
|
|
9
|
+
}>;
|
|
10
|
+
removed: string[];
|
|
11
|
+
coverage: string[];
|
|
12
|
+
indexDrift: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface CheckOptions {
|
|
15
|
+
contextDir?: string;
|
|
16
|
+
extensions?: string[];
|
|
17
|
+
}
|
|
18
|
+
export declare function checkContext(dir: string, opts?: CheckOptions): CheckResult;
|
|
19
|
+
/** Render a check result as a human-readable report. */
|
|
20
|
+
export declare function formatCheckReport(r: CheckResult): string;
|
|
21
|
+
//# sourceMappingURL=check.d.ts.map
|