@dreamtree-org/graphify 1.1.3 → 1.3.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/README.md +18 -2
- package/dist/{chunk-ZK3TA6FW.js → chunk-K322XB4U.js} +45 -7
- package/dist/{chunk-ZK3TA6FW.js.map → chunk-K322XB4U.js.map} +1 -1
- package/dist/{chunk-NS5HB65S.js → chunk-UBXYMMXJ.js} +9 -4
- package/dist/{chunk-NS5HB65S.js.map → chunk-UBXYMMXJ.js.map} +1 -1
- package/dist/cli/index.cjs +135 -23
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +65 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +67 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +58 -4
- package/dist/index.d.ts +58 -4
- package/dist/index.js +8 -2
- package/dist/mcp/server.cjs +43 -6
- package/dist/mcp/server.cjs.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/package.json +1 -1
- package/src/skill/SKILL.md +9 -4
package/dist/cli/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
runPipeline,
|
|
14
14
|
saveResult,
|
|
15
15
|
validateRules
|
|
16
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-UBXYMMXJ.js";
|
|
17
17
|
import {
|
|
18
18
|
affectedBy,
|
|
19
19
|
buildContextPack,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
shortestPath,
|
|
26
26
|
testsForChangedFiles,
|
|
27
27
|
testsForNode
|
|
28
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-K322XB4U.js";
|
|
29
29
|
import {
|
|
30
30
|
validateDsn,
|
|
31
31
|
validateUrl
|
|
@@ -503,6 +503,29 @@ function packageRoot() {
|
|
|
503
503
|
const packageJsonPath = require2.resolve("@dreamtree-org/graphify/package.json");
|
|
504
504
|
return path4.dirname(packageJsonPath);
|
|
505
505
|
}
|
|
506
|
+
var MCP_SERVER_ENTRY = {
|
|
507
|
+
command: "npx",
|
|
508
|
+
args: ["-y", "@dreamtree-org/graphify", "--mcp"]
|
|
509
|
+
};
|
|
510
|
+
async function upsertMcpServer(filePath, serversKey = "mcpServers") {
|
|
511
|
+
let config = {};
|
|
512
|
+
try {
|
|
513
|
+
config = JSON.parse(await fs6.readFile(filePath, "utf-8"));
|
|
514
|
+
} catch (error) {
|
|
515
|
+
if (error.code !== "ENOENT") {
|
|
516
|
+
throw new Error(`cannot update ${filePath} \u2014 it exists but is not valid JSON; fix or remove it and re-run.`, {
|
|
517
|
+
cause: error
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const servers = config[serversKey] ?? {};
|
|
522
|
+
servers["graphify"] = MCP_SERVER_ENTRY;
|
|
523
|
+
config[serversKey] = servers;
|
|
524
|
+
await fs6.mkdir(path4.dirname(filePath), { recursive: true });
|
|
525
|
+
await fs6.writeFile(filePath, `${JSON.stringify(config, null, 2)}
|
|
526
|
+
`, "utf-8");
|
|
527
|
+
return filePath;
|
|
528
|
+
}
|
|
506
529
|
var MD_MARKER_BEGIN = "<!-- >>> graphify >>> -->";
|
|
507
530
|
var MD_MARKER_END = "<!-- <<< graphify <<< -->";
|
|
508
531
|
async function writeOwnedFile(filePath, content) {
|
|
@@ -537,7 +560,8 @@ var PLATFORMS = {
|
|
|
537
560
|
claude: async (cwd, content) => {
|
|
538
561
|
const target = path4.join(cwd, ".claude", "skills", "graphify", "SKILL.md");
|
|
539
562
|
await writeOwnedFile(target, content);
|
|
540
|
-
|
|
563
|
+
const mcpPath = await upsertMcpServer(path4.join(cwd, ".mcp.json"));
|
|
564
|
+
return { host: "Claude Code", path: target, mcpPath };
|
|
541
565
|
},
|
|
542
566
|
cursor: async (cwd, content) => {
|
|
543
567
|
const target = path4.join(cwd, ".cursor", "rules", "graphify.mdc");
|
|
@@ -550,7 +574,8 @@ alwaysApply: false
|
|
|
550
574
|
---
|
|
551
575
|
${body}`
|
|
552
576
|
);
|
|
553
|
-
|
|
577
|
+
const mcpPath = await upsertMcpServer(path4.join(cwd, ".cursor", "mcp.json"));
|
|
578
|
+
return { host: "Cursor", path: target, mcpPath };
|
|
554
579
|
},
|
|
555
580
|
windsurf: async (cwd, content) => {
|
|
556
581
|
const target = path4.join(cwd, ".windsurf", "rules", "graphify.md");
|
|
@@ -570,10 +595,32 @@ ${body}`
|
|
|
570
595
|
gemini: async (cwd, content) => {
|
|
571
596
|
const target = path4.join(cwd, "GEMINI.md");
|
|
572
597
|
await upsertMarkedBlock(target, content.replace(/^---[\s\S]*?---\n/, ""));
|
|
573
|
-
|
|
598
|
+
const mcpPath = await upsertMcpServer(path4.join(cwd, ".gemini", "settings.json"));
|
|
599
|
+
return { host: "Gemini CLI", path: target, mcpPath };
|
|
574
600
|
}
|
|
575
601
|
};
|
|
576
602
|
var SUPPORTED_PLATFORMS = Object.keys(PLATFORMS).sort((a, b) => a.localeCompare(b));
|
|
603
|
+
var PLATFORM_MARKERS = {
|
|
604
|
+
cursor: [".cursor"],
|
|
605
|
+
windsurf: [".windsurf"],
|
|
606
|
+
cline: [".clinerules"],
|
|
607
|
+
agents: ["AGENTS.md"],
|
|
608
|
+
gemini: ["GEMINI.md", ".gemini"]
|
|
609
|
+
};
|
|
610
|
+
async function detectPlatforms(cwd = process.cwd()) {
|
|
611
|
+
const platforms = ["claude"];
|
|
612
|
+
for (const [platform, markers] of Object.entries(PLATFORM_MARKERS)) {
|
|
613
|
+
for (const marker of markers) {
|
|
614
|
+
try {
|
|
615
|
+
await fs6.access(path4.join(cwd, marker));
|
|
616
|
+
platforms.push(platform);
|
|
617
|
+
break;
|
|
618
|
+
} catch {
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
return platforms;
|
|
623
|
+
}
|
|
577
624
|
async function runInstall(platforms = ["claude"], cwd = process.cwd()) {
|
|
578
625
|
const sourcePath = path4.join(packageRoot(), "src", "skill", "SKILL.md");
|
|
579
626
|
const content = await fs6.readFile(sourcePath, "utf-8");
|
|
@@ -589,7 +636,8 @@ async function runInstall(platforms = ["claude"], cwd = process.cwd()) {
|
|
|
589
636
|
results.push(await installer(cwd, content));
|
|
590
637
|
}
|
|
591
638
|
for (const result of results) {
|
|
592
|
-
|
|
639
|
+
const mcpNote = result.mcpPath ? ` (MCP server registered in ${result.mcpPath})` : "";
|
|
640
|
+
console.log(`Installed graphify for ${result.host} -> ${result.path}${mcpNote}`);
|
|
593
641
|
}
|
|
594
642
|
return results;
|
|
595
643
|
}
|
|
@@ -699,7 +747,7 @@ async function watchAndRebuild(root, runOnce) {
|
|
|
699
747
|
});
|
|
700
748
|
}
|
|
701
749
|
var program = new Command();
|
|
702
|
-
program.name("graphify").description("Turn a folder of code/docs/papers into a queryable knowledge graph.").argument("[path]", "path to scan, or a GitHub URL", ".").option("--mode <mode>", "extraction mode (deep for richer INFERRED edges \u2014 reserved, no-op in v1)").option("--update", "incremental rebuild \u2014 reuse cached extractions for unchanged files").option("--watch", "rebuild on file change").option("--cluster-only", "rerun clustering on an existing graph").option("--leiden", "use Leiden instead of Louvain for community detection (v2 \u2014 better community quality)").option("--max-iterations <n>", "Leiden only: cap on outer iterations for very large graphs", Number).option("--no-viz", "skip graph.html").option("--svg", "also export graph.svg (not implemented in v1)").option("--graphml", "also export graph.graphml (not implemented in v1)").option("--neo4j", "generate graphify-out/cypher.txt for Neo4j (not implemented in v1)").option("--mcp", "start MCP stdio server instead of running the pipeline").option("--mysql <dsn>", "also extract a MySQL schema (mysql://user:pass@host:port/db) into the graph").action(async (targetArg, options) => {
|
|
750
|
+
program.name("graphify").description("Turn a folder of code/docs/papers into a queryable knowledge graph.").argument("[path]", "path to scan, or a GitHub URL", ".").option("--mode <mode>", "extraction mode (deep for richer INFERRED edges \u2014 reserved, no-op in v1)").option("--update", "incremental rebuild \u2014 reuse cached extractions for unchanged files").option("--watch", "rebuild on file change").option("--cluster-only", "rerun clustering on an existing graph").option("--leiden", "use Leiden instead of Louvain for community detection (v2 \u2014 better community quality)").option("--max-iterations <n>", "Leiden only: cap on outer iterations for very large graphs", Number).option("--no-viz", "skip graph.html").option("--svg", "also export graph.svg (not implemented in v1)").option("--graphml", "also export graph.graphml (not implemented in v1)").option("--neo4j", "generate graphify-out/cypher.txt for Neo4j (not implemented in v1)").option("--mcp", "start MCP stdio server instead of running the pipeline").option("--no-install", "skip auto-installing the agent skill + MCP config after the build").option("--mysql <dsn>", "also extract a MySQL schema (mysql://user:pass@host:port/db) into the graph").action(async (targetArg, options) => {
|
|
703
751
|
try {
|
|
704
752
|
if (options.mcp) {
|
|
705
753
|
const outDir = path5.resolve(targetArg === "." ? process.cwd() : targetArg, "graphify-out");
|
|
@@ -708,7 +756,8 @@ program.name("graphify").description("Turn a folder of code/docs/papers into a q
|
|
|
708
756
|
return;
|
|
709
757
|
}
|
|
710
758
|
let root = targetArg;
|
|
711
|
-
|
|
759
|
+
const cloned = looksLikeGitUrl(targetArg);
|
|
760
|
+
if (cloned) {
|
|
712
761
|
console.error(`Cloning ${targetArg} ...`);
|
|
713
762
|
root = await cloneRepo(targetArg);
|
|
714
763
|
}
|
|
@@ -734,6 +783,13 @@ program.name("graphify").description("Turn a folder of code/docs/papers into a q
|
|
|
734
783
|
onProgress: (m) => console.error(m)
|
|
735
784
|
});
|
|
736
785
|
await runOnce();
|
|
786
|
+
if (options.install && !cloned) {
|
|
787
|
+
try {
|
|
788
|
+
await runInstall(await detectPlatforms(root), root);
|
|
789
|
+
} catch (error) {
|
|
790
|
+
console.error(`graphify: agent skill/MCP install skipped: ${error.message}`);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
737
793
|
if (options.watch) {
|
|
738
794
|
console.error(`Watching ${root} for changes (Ctrl+C to stop) ...`);
|
|
739
795
|
await watchAndRebuild(root, runOnce);
|
|
@@ -815,7 +871,7 @@ program.command("benchmark [questions...]").description("measure token savings o
|
|
|
815
871
|
process.exitCode = 1;
|
|
816
872
|
}
|
|
817
873
|
});
|
|
818
|
-
program.command("install").description("install the skill/rules files into local agents (claude, cursor, windsurf, cline, agents, gemini, all)").option("--platform <names...>", "platform(s) to install for", ["claude"]).action(async (options) => {
|
|
874
|
+
program.command("install").description("install the skill/rules files + project MCP config into local agents (claude, cursor, windsurf, cline, agents, gemini, all)").option("--platform <names...>", "platform(s) to install for", ["claude"]).action(async (options) => {
|
|
819
875
|
try {
|
|
820
876
|
await runInstall(options.platform);
|
|
821
877
|
} catch (error) {
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/commands/affected.ts","../../src/cli/commands/benchmark.ts","../../src/cli/commands/check.ts","../../src/cli/commands/context.ts","../../src/cli/commands/explain.ts","../../src/cli/commands/review.ts","../../src/cli/commands/tests.ts","../../src/cli/commands/global.ts","../../src/cli/commands/hook.ts","../../src/cli/commands/install.ts","../../src/cli/commands/path.ts","../../src/cli/commands/query.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { execFile } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport { watch as watchFiles } from 'chokidar';\nimport { Command } from 'commander';\nimport { analyze } from '../analyze.js';\nimport { cluster } from '../cluster.js';\nimport { exportGraph } from '../export.js';\nimport { loadGraph } from '../graphStore.js';\nimport { runPipeline } from '../pipeline.js';\nimport { renderReport } from '../report.js';\nimport { validateDsn, validateUrl } from '../security.js';\nimport type { ExtractionResult } from '../types.js';\nimport { runAffected } from './commands/affected.js';\nimport { runBenchmark } from './commands/benchmark.js';\nimport { runCheck } from './commands/check.js';\nimport { runContext } from './commands/context.js';\nimport { runExplain } from './commands/explain.js';\nimport { runReview } from './commands/review.js';\nimport { runTests } from './commands/tests.js';\nimport { runGlobalAdd, runGlobalBuild, runGlobalList, runGlobalRemove, runMerge } from './commands/global.js';\nimport { runHookInstall, runHookUninstall } from './commands/hook.js';\nimport { loadResults, renderLessons, saveResult, type ResultOutcome, type ResultType } from '../memory.js';\nimport { runInstall } from './commands/install.js';\nimport { runPath } from './commands/path.js';\nimport { runQuery } from './commands/query.js';\n\nconst execFileAsync = promisify(execFile);\n\ninterface DefaultCommandOptions {\n mode?: string;\n update?: boolean;\n watch?: boolean;\n clusterOnly?: boolean;\n viz: boolean; // commander negatable --no-viz -> options.viz\n svg?: boolean;\n graphml?: boolean;\n neo4j?: boolean;\n mcp?: boolean;\n leiden?: boolean;\n maxIterations?: number;\n mysql?: string;\n}\n\nfunction looksLikeGitUrl(value: string): boolean {\n if (!/^https?:\\/\\//i.test(value)) return false;\n return /github\\.com|gitlab\\.com|bitbucket\\.org/i.test(value) || value.endsWith('.git');\n}\n\n/** Clone `url` into a fresh temp directory using an argv-array child_process call (never shell: true, never a shell string built from input). */\nasync function cloneRepo(url: string): Promise<string> {\n const validated = validateUrl(url);\n const dest = await fs.mkdtemp(path.join(os.tmpdir(), 'graphify-clone-'));\n await execFileAsync('git', ['clone', '--depth', '1', validated, dest]);\n return dest;\n}\n\nfunction exportOptionsFrom(options: DefaultCommandOptions) {\n return { html: options.viz, svg: options.svg, graphml: options.graphml, neo4j: options.neo4j };\n}\n\nfunction clusterOptionsFrom(options: DefaultCommandOptions) {\n return {\n algorithm: options.leiden ? ('leiden' as const) : ('louvain' as const),\n maxIterations: options.maxIterations,\n };\n}\n\nasync function runClusterOnly(root: string, options: DefaultCommandOptions): Promise<void> {\n const outDir = path.join(root, 'graphify-out');\n const graph = await loadGraph(outDir);\n cluster(graph, clusterOptionsFrom(options));\n const analysis = analyze(graph);\n const report = renderReport(graph, analysis);\n await exportGraph(graph, { outDir, ...exportOptionsFrom(options) }, report);\n console.error(`Re-clustered the existing graph (${clusterOptionsFrom(options).algorithm}).`);\n}\n\n/** Watch `root` (ignoring graphify-out/, node_modules/, .git/) and re-run `runOnce` on any change, debounced. Never resolves — the process stays alive until interrupted, matching normal watch-mode CLI behavior. */\nasync function watchAndRebuild(root: string, runOnce: () => Promise<unknown>): Promise<void> {\n const watcher = watchFiles(root, {\n ignored: (filePath: string) => /(^|[/\\\\])(node_modules|\\.git|graphify-out)([/\\\\]|$)/.test(filePath),\n ignoreInitial: true,\n });\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n let running = false;\n const schedule = (): void => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n if (running) return;\n running = true;\n console.error('Change detected, rebuilding...');\n runOnce()\n .catch((error: unknown) => console.error(`graphify --watch: rebuild failed: ${(error as Error).message}`))\n .finally(() => {\n running = false;\n });\n }, 300);\n };\n\n watcher.on('add', schedule).on('change', schedule).on('unlink', schedule);\n\n await new Promise<never>(() => {\n /* keep the process alive until the user interrupts it (Ctrl+C) */\n });\n}\n\nconst program = new Command();\n\nprogram\n .name('graphify')\n .description('Turn a folder of code/docs/papers into a queryable knowledge graph.')\n .argument('[path]', 'path to scan, or a GitHub URL', '.')\n .option('--mode <mode>', 'extraction mode (deep for richer INFERRED edges — reserved, no-op in v1)')\n .option('--update', 'incremental rebuild — reuse cached extractions for unchanged files')\n .option('--watch', 'rebuild on file change')\n .option('--cluster-only', 'rerun clustering on an existing graph')\n .option('--leiden', 'use Leiden instead of Louvain for community detection (v2 — better community quality)')\n .option('--max-iterations <n>', 'Leiden only: cap on outer iterations for very large graphs', Number)\n .option('--no-viz', 'skip graph.html')\n .option('--svg', 'also export graph.svg (not implemented in v1)')\n .option('--graphml', 'also export graph.graphml (not implemented in v1)')\n .option('--neo4j', 'generate graphify-out/cypher.txt for Neo4j (not implemented in v1)')\n .option('--mcp', 'start MCP stdio server instead of running the pipeline')\n .option('--mysql <dsn>', 'also extract a MySQL schema (mysql://user:pass@host:port/db) into the graph')\n .action(async (targetArg: string, options: DefaultCommandOptions) => {\n try {\n if (options.mcp) {\n const outDir = path.resolve(targetArg === '.' ? process.cwd() : targetArg, 'graphify-out');\n const { startServer } = await import('../mcp/server.js');\n await startServer(path.join(outDir, 'graph.json'));\n return;\n }\n\n let root = targetArg;\n if (looksLikeGitUrl(targetArg)) {\n console.error(`Cloning ${targetArg} ...`);\n root = await cloneRepo(targetArg);\n }\n root = path.resolve(root);\n\n if (options.mode) {\n console.error(`--mode ${options.mode} is reserved for a future richer-INFERRED-edges pass — currently a no-op.`);\n }\n\n if (options.clusterOnly) {\n await runClusterOnly(root, options);\n return;\n }\n\n let extraExtractions: ExtractionResult[] | undefined;\n if (options.mysql) {\n const { extractMysql } = await import('../extractors/mysql.js');\n console.error(`Extracting MySQL schema from ${validateDsn(options.mysql).safeDisplay} ...`);\n extraExtractions = [await extractMysql(options.mysql)];\n }\n\n const runOnce = () =>\n runPipeline(root, {\n ...exportOptionsFrom(options),\n ...clusterOptionsFrom(options),\n extraExtractions,\n update: options.update,\n onProgress: (m) => console.error(m),\n });\n await runOnce();\n\n if (options.watch) {\n console.error(`Watching ${root} for changes (Ctrl+C to stop) ...`);\n await watchAndRebuild(root, runOnce);\n }\n } catch (error) {\n console.error(`graphify: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('query <question>')\n .description('BFS (default) or DFS traversal answering a question against the existing graph')\n .option('--dfs', 'depth-first traversal (trace a specific path)')\n .option('--budget <tokens>', 'cap answer at N tokens', Number)\n .action(async (question: string, options: { dfs?: boolean; budget?: number }) => {\n try {\n await runQuery(question, options);\n } catch (error) {\n console.error(`graphify query: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('path <from> <to>')\n .description('shortest path between two named nodes')\n .action(async (from: string, to: string) => {\n try {\n await runPath(from, to);\n } catch (error) {\n console.error(`graphify path: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('explain <node>')\n .description('plain-language explanation of a node')\n .action(async (node: string) => {\n try {\n await runExplain(node);\n } catch (error) {\n console.error(`graphify explain: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('affected <node>')\n .description('reverse impact analysis — everything that (transitively) depends on a node')\n .option('--depth <n>', 'how many reverse hops to follow (default 3)', Number)\n .option('--limit <n>', 'cap on affected nodes reported (default 200)', Number)\n .action(async (node: string, options: { depth?: number; limit?: number }) => {\n try {\n await runAffected(node, options);\n } catch (error) {\n console.error(`graphify affected: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('context <task>')\n .description('token-budgeted working-set pack — the actual code for a task, in one call')\n .option('--budget <tokens>', 'approximate token cap for the pack (default 4000)', Number)\n .action(async (task: string, options: { budget?: number }) => {\n try {\n await runContext(task, options);\n } catch (error) {\n console.error(`graphify context: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('tests [node]')\n .description('structural test selection — the minimal test files worth running for a change')\n .option('--changed [rev]', 'select for the working-tree diff (optionally vs a revision) instead of a node')\n .action(async (node: string | undefined, options: { changed?: string | boolean }) => {\n try {\n await runTests(node, options);\n } catch (error) {\n console.error(`graphify tests: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('review <base> [head]')\n .description('structural review between two git revisions: added/removed/rewired symbols with blast radius + tests')\n .action(async (base: string, head?: string) => {\n try {\n await runReview(base, head);\n } catch (error) {\n console.error(`graphify review: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('check')\n .description('check the graph against dependency rules (graphify.rules.json) — exits 1 on violations')\n .option('--rules <file>', 'rules file (default ./graphify.rules.json)')\n .action(async (options: { rules?: string }) => {\n try {\n await runCheck(options);\n } catch (error) {\n console.error(`graphify check: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('benchmark [questions...]')\n .description('measure token savings of graph answers vs reading the files they touch')\n .action(async (questions: string[]) => {\n try {\n await runBenchmark(questions);\n } catch (error) {\n console.error(`graphify benchmark: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('install')\n .description('install the skill/rules files into local agents (claude, cursor, windsurf, cline, agents, gemini, all)')\n .option('--platform <names...>', 'platform(s) to install for', ['claude'])\n .action(async (options: { platform: string[] }) => {\n try {\n await runInstall(options.platform);\n } catch (error) {\n console.error(`graphify install: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nconst globalCommand = program\n .command('global')\n .description('manage the cross-project global graph (registry at ~/.graphify/global.json)');\n\nglobalCommand\n .command('add [path]')\n .description('register a project (must already have graphify-out/graph.json)')\n .action(async (target?: string) => {\n try {\n await runGlobalAdd(target);\n } catch (error) {\n console.error(`graphify global add: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nglobalCommand\n .command('remove <name>')\n .description('unregister a project by name')\n .action(async (name: string) => {\n try {\n await runGlobalRemove(name);\n } catch (error) {\n console.error(`graphify global remove: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nglobalCommand\n .command('list')\n .description('list registered projects')\n .action(async () => {\n try {\n await runGlobalList();\n } catch (error) {\n console.error(`graphify global list: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nglobalCommand\n .command('build')\n .description('merge every registered project into one global graph')\n .option('--out <dir>', 'output directory (default ~/.graphify/global-out)')\n .action(async (options: { out?: string }) => {\n try {\n await runGlobalBuild(options);\n } catch (error) {\n console.error(`graphify global build: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('merge <dirs...>')\n .description('one-shot merge of two or more built project graphs into one')\n .option('--out <dir>', 'output directory (default ./graphify-merged)')\n .action(async (dirs: string[], options: { out?: string }) => {\n try {\n await runMerge(dirs, options);\n } catch (error) {\n console.error(`graphify merge: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('save-result')\n .description('save a Q&A result to graphify-out/memory/ for the graph feedback loop')\n .requiredOption('--question <q>', 'the question that was asked')\n .requiredOption('--answer <a>', 'the answer that was given')\n .option('--nodes <ids...>', 'node ids/labels cited in the answer', [])\n .option('--type <t>', 'query|path|explain|affected', 'query')\n .option('--outcome <o>', 'useful|dead_end|corrected', 'useful')\n .option('--correction <text>', 'what the right answer was (pairs with --outcome corrected)')\n .action(async (options: {\n question: string;\n answer: string;\n nodes: string[];\n type: string;\n outcome: string;\n correction?: string;\n }) => {\n try {\n const memoryDir = path.join(process.cwd(), 'graphify-out', 'memory');\n const file = await saveResult(\n {\n question: options.question,\n answer: options.answer,\n nodes: options.nodes,\n type: options.type as ResultType,\n outcome: options.outcome as ResultOutcome,\n correction: options.correction,\n },\n memoryDir,\n );\n console.log(`Saved -> ${file}`);\n } catch (error) {\n console.error(`graphify save-result: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('reflect')\n .description('aggregate graphify-out/memory/ into a recency-weighted lessons doc')\n .option('--half-life-days <n>', 'a result loses half its weight every N days (default 30)', Number)\n .option('--out <file>', 'output path (default graphify-out/reflections/LESSONS.md)')\n .action(async (options: { halfLifeDays?: number; out?: string }) => {\n try {\n const memoryDir = path.join(process.cwd(), 'graphify-out', 'memory');\n const results = await loadResults(memoryDir);\n const lessons = renderLessons(results, { halfLifeDays: options.halfLifeDays });\n const outPath = path.resolve(options.out ?? path.join(process.cwd(), 'graphify-out', 'reflections', 'LESSONS.md'));\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, lessons, 'utf-8');\n console.log(`Reflected ${results.length} result(s) -> ${outPath}`);\n } catch (error) {\n console.error(`graphify reflect: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nconst hookCommand = program\n .command('hook')\n .description('manage the git hooks that auto-rebuild the graph on commit/pull');\n\nhookCommand\n .command('install')\n .description('install post-commit and post-merge hooks (preserves existing hook content)')\n .action(async () => {\n try {\n await runHookInstall();\n } catch (error) {\n console.error(`graphify hook install: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nhookCommand\n .command('uninstall')\n .description('remove the graphify block from the git hooks')\n .action(async () => {\n try {\n await runHookUninstall();\n } catch (error) {\n console.error(`graphify hook uninstall: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram.parseAsync(process.argv);\n","import { loadGraph } from '../../graphStore.js';\nimport { affectedBy } from '../../impact.js';\n\nexport interface AffectedOptions {\n depth?: number;\n limit?: number;\n}\n\n/** Reverse impact analysis: everything that (transitively) depends on the named node. */\nexport async function runAffected(nodeName: string, options: AffectedOptions = {}): Promise<void> {\n const graph = await loadGraph();\n const result = affectedBy(graph, nodeName, { maxDepth: options.depth, limit: options.limit });\n\n if (!result) {\n console.log(`No node matched \"${nodeName}\".`);\n return;\n }\n\n console.log(`Impact of changing ${result.target.label} (${result.target.id}):`);\n\n if (result.affected.length === 0) {\n console.log(' Nothing in the graph depends on it — no incoming dependency edges.');\n return;\n }\n\n let currentDepth = 0;\n for (const node of result.affected) {\n if (node.depth !== currentDepth) {\n currentDepth = node.depth;\n console.log('');\n console.log(currentDepth === 1 ? 'Directly affected:' : `Affected at depth ${currentDepth}:`);\n }\n const isPlaceholder =\n node.sourceFile === '<unknown>' || node.sourceFile === '<external>' || node.sourceFile === '';\n const where = isPlaceholder\n ? '(reference only)'\n : `${node.sourceFile}${node.sourceLocation ? `:${node.sourceLocation}` : ''}`;\n console.log(\n ` ${node.label} — ${where} ` +\n `(--${node.via.relation}--> ${node.via.dependsOn}, ${node.via.confidence})`,\n );\n }\n\n console.log('');\n const { EXTRACTED, INFERRED, AMBIGUOUS } = result.byConfidence;\n console.log(\n `Blast radius: ${result.affected.length} node(s) within ${result.maxDepth} hop(s) — ` +\n `${EXTRACTED} certain (EXTRACTED), ${INFERRED} likely (INFERRED), ${AMBIGUOUS} uncertain (AMBIGUOUS).`,\n );\n if (result.truncated) {\n console.log('(List truncated — raise --limit to see more.)');\n }\n}\n","import * as fs from 'node:fs/promises';\nimport type Graph from 'graphology';\nimport { loadGraph } from '../../graphStore.js';\nimport { queryGraph } from '../../query.js';\nimport { isTestFile } from '../../testmap.js';\n\n/**\n * `graphify benchmark` — measure the token savings of answering through the\n * graph instead of reading source files. For each question it compares the\n * serialized size of the graph answer against the size of every source file\n * that answer's nodes live in (the \"just read the relevant files\" baseline\n * an agent without the graph would pay). Chars/4 is the usual token\n * approximation, applied to both sides so the ratio is fair.\n */\n\nexport interface BenchmarkRow {\n question: string;\n graphTokens: number;\n naiveTokens: number;\n /** naive / graph — how many times cheaper the graph answer is. */\n reduction: number;\n filesRead: number;\n filesMissing: number;\n}\n\nexport type FileReader = (path: string) => Promise<string>;\n\nconst tokensOf = (text: string): number => Math.ceil(text.length / 4);\n\nexport async function benchmarkQuestion(\n graph: Graph,\n question: string,\n readFile: FileReader,\n): Promise<BenchmarkRow> {\n const result = queryGraph(graph, question);\n // Compact JSON, matching how queryGraph's own token budget measures itself.\n const graphTokens = tokensOf(JSON.stringify(result));\n\n const sourceFiles = new Set<string>();\n for (const node of result.visited) {\n if (node.sourceFile && !node.sourceFile.startsWith('<') && !node.sourceFile.includes('://')) {\n sourceFiles.add(node.sourceFile);\n }\n }\n\n let naiveTokens = 0;\n let filesRead = 0;\n let filesMissing = 0;\n for (const file of [...sourceFiles].sort((a, b) => a.localeCompare(b))) {\n try {\n naiveTokens += tokensOf(await readFile(file));\n filesRead++;\n } catch {\n filesMissing++;\n }\n }\n\n return {\n question,\n graphTokens,\n naiveTokens,\n reduction: graphTokens > 0 && naiveTokens > 0 ? naiveTokens / graphTokens : 0,\n filesRead,\n filesMissing,\n };\n}\n\n/** Files no agent would ask a \"how does X work\" question about — build config, examples, scripts, docs. */\nconst NON_QUESTION_FILE =\n /(^|\\/)(examples?|scripts?|bench(?:mark)?s?|fixtures?|docs?|\\.github)\\/|\\.(config|conf)\\.[^/]+$|(^|\\/)(rollup|webpack|vite|vitest|jest|babel|tsup|eslint|prettier)\\.[^/]*$/i;\n\n/**\n * Default questions when none are given: the labels of the highest-degree\n * (most load-bearing) SOURCE entities. Tests, build config, and examples\n * are excluded — they score high on degree but are questions no agent\n * would ask, and they drag the measured reduction down unfairly.\n */\nexport function defaultQuestions(graph: Graph, count = 5): string[] {\n const entries = [...graph.nodes()]\n .map((id) => ({\n id,\n degree: graph.degree(id),\n label: (graph.getNodeAttribute(id, 'label') as string | undefined) ?? id,\n file: (graph.getNodeAttribute(id, 'sourceFile') as string | undefined) ?? '',\n }))\n // File nodes score high on degree but make poor questions — prefer entities.\n .filter((e) => e.id.includes('::'))\n .filter((e) => !isTestFile(e.file) && !NON_QUESTION_FILE.test(e.file))\n .sort((a, b) => b.degree - a.degree || a.id.localeCompare(b.id));\n return entries.slice(0, count).map((e) => `how does ${e.label} work`);\n}\n\nexport async function runBenchmark(questions: string[]): Promise<BenchmarkRow[]> {\n const graph = await loadGraph();\n const effective = questions.length > 0 ? questions : defaultQuestions(graph);\n if (effective.length === 0) {\n console.log('The graph has no entity nodes to benchmark against — build it first.');\n return [];\n }\n\n const rows: BenchmarkRow[] = [];\n for (const question of effective) {\n rows.push(await benchmarkQuestion(graph, question, (p) => fs.readFile(p, 'utf-8')));\n }\n\n console.log('Token cost per question — graph answer vs reading the files it touches:\\n');\n for (const row of rows) {\n const reduction = row.reduction > 0 ? `${row.reduction.toFixed(1)}x` : 'n/a';\n console.log(` \"${row.question}\"`);\n console.log(\n ` graph: ~${row.graphTokens} tokens | files: ~${row.naiveTokens} tokens ` +\n `(${row.filesRead} file(s)${row.filesMissing ? `, ${row.filesMissing} unreadable` : ''}) | reduction: ${reduction}`,\n );\n }\n\n const scored = rows.filter((r) => r.reduction > 0);\n if (scored.length > 0) {\n const avg = scored.reduce((s, r) => s + r.reduction, 0) / scored.length;\n console.log(`\\nAverage reduction: ${avg.toFixed(1)}x across ${scored.length} question(s).`);\n } else {\n console.log('\\nNo reduction could be measured — run from the project root so source files are readable.');\n }\n return rows;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { checkRules, validateRules } from '../../check.js';\nimport { loadGraph } from '../../graphStore.js';\n\nexport interface CheckCommandOptions {\n rules?: string;\n}\n\n/**\n * Check the graph against declared dependency rules. Exits non-zero on\n * violations so CI (and agents verifying their own edits) can gate on it.\n */\nexport async function runCheck(options: CheckCommandOptions = {}): Promise<void> {\n const rulesPath = path.resolve(options.rules ?? 'graphify.rules.json');\n let raw: string;\n try {\n raw = await fs.readFile(rulesPath, 'utf-8');\n } catch {\n throw new Error(\n `No rules file at ${rulesPath} — create graphify.rules.json with ` +\n '{ \"rules\": [{ \"name\": \"...\", \"from\": \"src/a/**\", \"disallow\": [\"src/b/**\"] }] }.',\n );\n }\n const config = validateRules(JSON.parse(raw));\n\n const graph = await loadGraph();\n const violations = checkRules(graph, config);\n\n if (violations.length === 0) {\n console.log(`OK — ${config.rules.length} rule(s), no violations.`);\n return;\n }\n\n console.log(`${violations.length} violation(s):`);\n for (const v of violations) {\n console.log(` [${v.rule}] ${v.fromNode} --${v.relation}--> ${v.toNode}`);\n console.log(` ${v.fromFile} must not depend on ${v.toFile}${v.reason ? ` — ${v.reason}` : ''}`);\n }\n process.exitCode = 1;\n}\n","import * as fs from 'node:fs/promises';\nimport { buildContextPack, renderContextPack } from '../../context.js';\nimport { loadGraph } from '../../graphStore.js';\n\nexport interface ContextCommandOptions {\n budget?: number;\n}\n\n/** Token-budgeted working-set pack: the actual code an agent needs for a task, in one call. */\nexport async function runContext(task: string, options: ContextCommandOptions = {}): Promise<void> {\n const graph = await loadGraph();\n const pack = await buildContextPack(graph, task, (p) => fs.readFile(p, 'utf-8'), {\n tokenBudget: options.budget,\n });\n console.log(renderContextPack(pack));\n}\n","import { loadGraph } from '../../graphStore.js';\nimport { explainNode } from '../../query.js';\n\n/** Plain-language explanation of a single node. */\nexport async function runExplain(nodeName: string): Promise<void> {\n const graph = await loadGraph();\n const result = explainNode(graph, nodeName);\n\n if (!result) {\n console.log(`No node matched \"${nodeName}\".`);\n return;\n }\n\n console.log(result.label);\n if (result.sourceFile === '<unknown>' || result.sourceFile === '<external>' || result.sourceFile === '') {\n // Auto-vivified endpoint (re-export alias / unresolved reference) — it\n // has no source of its own, so \"<unknown>:L0\" would read like a bug.\n console.log(' location: (reference only — no declaration seen; check its outgoing edges for the real definition)');\n } else {\n const location = result.sourceLocation ? `:${result.sourceLocation}` : '';\n console.log(` location: ${result.sourceFile}${location}`);\n }\n if (result.communityLabel) {\n console.log(` community: ${result.communityLabel}`);\n }\n\n console.log('');\n console.log(`Calls / references out (${result.outgoing.length}):`);\n if (result.outgoing.length === 0) {\n console.log(' (none)');\n } else {\n for (const edge of result.outgoing) {\n console.log(` --${edge.relation}--> ${edge.target} (${edge.confidence})`);\n }\n }\n\n console.log('');\n console.log(`Referenced by (${result.incoming.length}):`);\n if (result.incoming.length === 0) {\n console.log(' (none)');\n } else {\n for (const edge of result.incoming) {\n console.log(` ${edge.source} --${edge.relation}--> (${edge.confidence})`);\n }\n }\n}\n","import { renderReview, reviewRevisions } from '../../diff.js';\n\n/** Structural review between two git revisions (head defaults to HEAD). */\nexport async function runReview(base: string, head?: string): Promise<void> {\n const diff = await reviewRevisions(process.cwd(), base, head ?? 'HEAD');\n console.log(renderReview(diff));\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { loadGraph } from '../../graphStore.js';\nimport { testsForChangedFiles, testsForNode } from '../../testmap.js';\n\nconst execFileAsync = promisify(execFile);\n\nexport interface TestsCommandOptions {\n /** Select tests for the working-tree diff (optionally against a rev) instead of a named node. */\n changed?: string | boolean;\n}\n\n/** Structural test selection: the minimal test files worth running for a change. */\nexport async function runTests(nodeQuery: string | undefined, options: TestsCommandOptions = {}): Promise<void> {\n const graph = await loadGraph();\n\n let selection;\n if (options.changed !== undefined && options.changed !== false) {\n const args = ['diff', '--name-only'];\n if (typeof options.changed === 'string') args.push(options.changed);\n const { stdout } = await execFileAsync('git', args);\n const changedFiles = stdout.split('\\n').map((l) => l.trim()).filter(Boolean);\n if (changedFiles.length === 0) {\n console.log('No changed files in the diff.');\n return;\n }\n selection = testsForChangedFiles(graph, changedFiles);\n } else if (nodeQuery) {\n selection = testsForNode(graph, nodeQuery);\n if (!selection) {\n console.log(`No node matched \"${nodeQuery}\".`);\n return;\n }\n } else {\n console.log('Provide a node to select tests for, or --changed for the working-tree diff.');\n return;\n }\n\n if (selection.testFiles.length === 0) {\n console.log(\n `No test files found in the blast radius of ${selection.target} ` +\n `(${selection.affectedNodeCount} affected node(s) checked) — either it's untested or the tests ` +\n 'reach it through a path the graph does not capture.',\n );\n return;\n }\n\n const how =\n selection.precision === 'usage'\n ? 'selected by actual usage (calls/inheritance)'\n : 'selected by import reachability — may over-include files sharing an entry point';\n console.log(`Test files for ${selection.target} (${how}; most direct first):`);\n for (const test of selection.testFiles) {\n const via = test.depth === 0 ? test.via : `depth ${test.depth}, via ${test.via}`;\n console.log(` ${test.file} (${via})`);\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { analyze } from '../../analyze.js';\nimport { cluster } from '../../cluster.js';\nimport { exportGraph } from '../../export.js';\nimport { loadGraph } from '../../graphStore.js';\nimport { mergeGraphs, type MergeEntry } from '../../merge.js';\nimport { renderReport } from '../../report.js';\n\n/**\n * `graphify global add|remove|list|build` — a registry of projects whose\n * built graphs get merged into one global cross-project graph, plus the\n * one-shot `graphify merge <dir...>` for merging without a registry.\n * The registry lives at ~/.graphify/global.json; the merged output defaults\n * to ~/.graphify/global-out/.\n */\n\nexport interface GlobalRegistry {\n projects: Array<{ name: string; root: string }>;\n}\n\nfunction registryDir(): string {\n return path.join(os.homedir(), '.graphify');\n}\n\nfunction registryPath(): string {\n return path.join(registryDir(), 'global.json');\n}\n\nasync function readRegistry(): Promise<GlobalRegistry> {\n try {\n const raw = await fs.readFile(registryPath(), 'utf-8');\n const parsed: unknown = JSON.parse(raw);\n const projects = (parsed as GlobalRegistry).projects;\n if (!Array.isArray(projects)) return { projects: [] };\n return { projects: projects.filter((p) => typeof p?.name === 'string' && typeof p?.root === 'string') };\n } catch {\n return { projects: [] };\n }\n}\n\nasync function writeRegistry(registry: GlobalRegistry): Promise<void> {\n await fs.mkdir(registryDir(), { recursive: true });\n await fs.writeFile(registryPath(), JSON.stringify(registry, null, 2), 'utf-8');\n}\n\n/** Project name for a root: its package.json \"name\" if present, else the directory basename. */\nasync function projectNameFor(root: string): Promise<string> {\n try {\n const raw = await fs.readFile(path.join(root, 'package.json'), 'utf-8');\n const name = (JSON.parse(raw) as { name?: unknown }).name;\n if (typeof name === 'string' && name.length > 0) return name;\n } catch {\n // no package.json — fall through to the basename\n }\n return path.basename(root);\n}\n\nexport async function runGlobalAdd(target: string = '.'): Promise<void> {\n const root = path.resolve(target);\n const graphJson = path.join(root, 'graphify-out', 'graph.json');\n try {\n await fs.access(graphJson);\n } catch {\n throw new Error(`${root} has no graphify-out/graph.json — run \\`graphify ${target}\\` first, then add it.`);\n }\n\n const name = await projectNameFor(root);\n const registry = await readRegistry();\n\n const existing = registry.projects.find((p) => p.name === name);\n if (existing) {\n if (existing.root === root) {\n console.log(`${name} is already registered (${root}).`);\n return;\n }\n throw new Error(\n `A different project is already registered as \"${name}\" (${existing.root}). ` +\n 'Remove it first with `graphify global remove`.',\n );\n }\n\n registry.projects.push({ name, root });\n registry.projects.sort((a, b) => a.name.localeCompare(b.name));\n await writeRegistry(registry);\n console.log(`Registered ${name} (${root}). ${registry.projects.length} project(s) in the global graph.`);\n}\n\nexport async function runGlobalRemove(name: string): Promise<void> {\n const registry = await readRegistry();\n const before = registry.projects.length;\n registry.projects = registry.projects.filter((p) => p.name !== name);\n if (registry.projects.length === before) {\n throw new Error(`No project named \"${name}\" is registered. See \\`graphify global list\\`.`);\n }\n await writeRegistry(registry);\n console.log(`Removed ${name}. ${registry.projects.length} project(s) remain.`);\n}\n\nexport async function runGlobalList(): Promise<void> {\n const registry = await readRegistry();\n if (registry.projects.length === 0) {\n console.log('No projects registered. Add one with `graphify global add <path>`.');\n return;\n }\n for (const project of registry.projects) {\n console.log(`${project.name} ${project.root}`);\n }\n}\n\n/** Load every entry's graph, skipping (with a warning) the ones that fail — one broken project must not sink the merge. */\nasync function loadEntries(sources: Array<{ name: string; outDir: string }>): Promise<MergeEntry[]> {\n const entries: MergeEntry[] = [];\n for (const source of sources) {\n try {\n entries.push({ name: source.name, graph: await loadGraph(source.outDir) });\n } catch (error) {\n console.warn(`Skipping ${source.name}: ${(error as Error).message}`);\n }\n }\n return entries;\n}\n\nasync function mergeAndExport(entries: MergeEntry[], outDir: string): Promise<void> {\n if (entries.length === 0) {\n throw new Error('Nothing to merge — no project graphs could be loaded.');\n }\n\n const merged = mergeGraphs(entries);\n cluster(merged);\n const analysis = analyze(merged);\n const report = renderReport(merged, analysis);\n await exportGraph(merged, { outDir }, report);\n\n console.log(\n `Merged ${entries.length} project(s) into ${outDir} — ` +\n `${merged.order} node(s), ${merged.size} edge(s).`,\n );\n}\n\nexport async function runGlobalBuild(options: { out?: string } = {}): Promise<void> {\n const registry = await readRegistry();\n if (registry.projects.length === 0) {\n throw new Error('No projects registered. Add some with `graphify global add <path>` first.');\n }\n\n const entries = await loadEntries(\n registry.projects.map((p) => ({ name: p.name, outDir: path.join(p.root, 'graphify-out') })),\n );\n await mergeAndExport(entries, path.resolve(options.out ?? path.join(registryDir(), 'global-out')));\n}\n\n/** One-shot merge of two or more project directories, no registry involved. */\nexport async function runMerge(targets: string[], options: { out?: string } = {}): Promise<void> {\n if (targets.length < 2) {\n throw new Error('Provide at least two project directories to merge.');\n }\n\n const sources: Array<{ name: string; outDir: string }> = [];\n for (const target of targets) {\n const root = path.resolve(target);\n sources.push({ name: await projectNameFor(root), outDir: path.join(root, 'graphify-out') });\n }\n\n const names = sources.map((s) => s.name);\n const duplicate = names.find((name, i) => names.indexOf(name) !== i);\n if (duplicate !== undefined) {\n throw new Error(`Two of the given projects resolve to the same name (\"${duplicate}\") — rename one.`);\n }\n\n const entries = await loadEntries(sources);\n await mergeAndExport(entries, path.resolve(options.out ?? 'graphify-merged'));\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * `graphify hook install` / `graphify hook uninstall` — auto-rebuild the\n * graph after commits and pulls, mirroring the Python original's\n * `hook install`. The hook body lives inside a marked block so we can\n * coexist with (and later cleanly remove ourselves from) hooks the user\n * already has; we never overwrite or delete anything outside our markers.\n */\n\nconst MARKER_BEGIN = '# >>> graphify >>>';\nconst MARKER_END = '# <<< graphify <<<';\n\n/** post-commit: rebuild after each commit. post-merge: rebuild after pull/merge. */\nconst HOOK_NAMES = ['post-commit', 'post-merge'] as const;\n\nconst HOOK_BLOCK = `${MARKER_BEGIN}\n# Rebuild the graphify knowledge graph in the background so the hook never\n# slows down the commit. Errors are silenced — a failed rebuild should never\n# break a git operation. Installed by \\`graphify hook install\\`.\n(graphify . --update --no-viz >/dev/null 2>&1 &)\n${MARKER_END}`;\n\nexport interface HookResult {\n hook: string;\n path: string;\n action: 'created' | 'appended' | 'already-installed' | 'removed' | 'not-installed';\n}\n\nasync function hooksDir(cwd: string): Promise<string> {\n const gitDir = path.join(cwd, '.git');\n let stats;\n try {\n stats = await fs.stat(gitDir);\n } catch {\n throw new Error(`${cwd} is not a git repository (no .git directory) — run this from the repo root.`);\n }\n if (!stats.isDirectory()) {\n // .git can be a file in worktrees/submodules (\"gitdir: <path>\") — follow it.\n const content = (await fs.readFile(gitDir, 'utf-8')).trim();\n const match = /^gitdir:\\s*(.+)$/.exec(content);\n if (!match) throw new Error(`${gitDir} exists but is neither a directory nor a gitdir pointer.`);\n return path.resolve(cwd, match[1] as string, 'hooks');\n }\n return path.join(gitDir, 'hooks');\n}\n\n/** Install the marked graphify block into post-commit and post-merge, preserving any existing hook content. */\nexport async function runHookInstall(cwd: string = process.cwd()): Promise<HookResult[]> {\n const dir = await hooksDir(cwd);\n await fs.mkdir(dir, { recursive: true });\n\n const results: HookResult[] = [];\n for (const hook of HOOK_NAMES) {\n const hookPath = path.join(dir, hook);\n let existing: string | null = null;\n try {\n existing = await fs.readFile(hookPath, 'utf-8');\n } catch {\n // no existing hook — we'll create it\n }\n\n if (existing === null) {\n await fs.writeFile(hookPath, `#!/bin/sh\\n${HOOK_BLOCK}\\n`, { mode: 0o755 });\n results.push({ hook, path: hookPath, action: 'created' });\n } else if (existing.includes(MARKER_BEGIN)) {\n results.push({ hook, path: hookPath, action: 'already-installed' });\n } else {\n const separator = existing.endsWith('\\n') ? '' : '\\n';\n await fs.writeFile(hookPath, `${existing}${separator}${HOOK_BLOCK}\\n`, 'utf-8');\n await fs.chmod(hookPath, 0o755);\n results.push({ hook, path: hookPath, action: 'appended' });\n }\n }\n\n for (const result of results) {\n console.log(`${result.hook}: ${result.action} (${result.path})`);\n }\n console.log('');\n console.log('The graph will rebuild in the background after each commit and pull.');\n console.log('Remove with `graphify hook uninstall`.');\n return results;\n}\n\n/** Remove only the marked graphify block; delete the hook file if nothing else is left in it. */\nexport async function runHookUninstall(cwd: string = process.cwd()): Promise<HookResult[]> {\n const dir = await hooksDir(cwd);\n\n const results: HookResult[] = [];\n for (const hook of HOOK_NAMES) {\n const hookPath = path.join(dir, hook);\n let existing: string | null = null;\n try {\n existing = await fs.readFile(hookPath, 'utf-8');\n } catch {\n // nothing installed\n }\n\n if (existing === null || !existing.includes(MARKER_BEGIN)) {\n results.push({ hook, path: hookPath, action: 'not-installed' });\n continue;\n }\n\n const blockPattern = new RegExp(`\\\\n?${MARKER_BEGIN}[\\\\s\\\\S]*?${MARKER_END}\\\\n?`);\n const remaining = existing.replace(blockPattern, '\\n').trim();\n\n if (remaining === '' || remaining === '#!/bin/sh') {\n await fs.unlink(hookPath);\n } else {\n await fs.writeFile(hookPath, `${remaining}\\n`, 'utf-8');\n }\n results.push({ hook, path: hookPath, action: 'removed' });\n }\n\n for (const result of results) {\n console.log(`${result.hook}: ${result.action}`);\n }\n return results;\n}\n","import { createRequire } from 'node:module';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Resolve this package's own root directory, whether we're running from\n * source (tests/dev), the built dist/ bundle, or installed as a real\n * dependency elsewhere. Uses Node's self-reference resolution (walking up\n * from this module's location to the nearest package.json named\n * \"@dreamtree-org/graphify\") rather than a hardcoded relative path, since\n * the number of directories between this file and the package root\n * differs between src/ and the bundled dist/ output.\n */\nfunction packageRoot(): string {\n const packageJsonPath = require.resolve('@dreamtree-org/graphify/package.json');\n return path.dirname(packageJsonPath);\n}\n\nexport interface InstallResult {\n host: string;\n path: string;\n}\n\n/** Markers for hosts where we append into a shared file (AGENTS.md / GEMINI.md) instead of owning one. */\nconst MD_MARKER_BEGIN = '<!-- >>> graphify >>> -->';\nconst MD_MARKER_END = '<!-- <<< graphify <<< -->';\n\nasync function writeOwnedFile(filePath: string, content: string): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\n/** Create `filePath` with the marked block, or replace/append the block in an existing file — user content is never touched. */\nasync function upsertMarkedBlock(filePath: string, content: string): Promise<void> {\n const block = `${MD_MARKER_BEGIN}\\n${content.trim()}\\n${MD_MARKER_END}`;\n let existing: string | null = null;\n try {\n existing = await fs.readFile(filePath, 'utf-8');\n } catch {\n // file doesn't exist yet\n }\n\n if (existing === null) {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, `${block}\\n`, 'utf-8');\n return;\n }\n if (existing.includes(MD_MARKER_BEGIN)) {\n const pattern = new RegExp(`${MD_MARKER_BEGIN}[\\\\s\\\\S]*?${MD_MARKER_END}`);\n await fs.writeFile(filePath, existing.replace(pattern, block), 'utf-8');\n return;\n }\n const separator = existing.endsWith('\\n') ? '\\n' : '\\n\\n';\n await fs.writeFile(filePath, `${existing}${separator}${block}\\n`, 'utf-8');\n}\n\ntype PlatformInstaller = (cwd: string, skillContent: string) => Promise<InstallResult>;\n\n/**\n * Curated per-host installers. `claude` gets the native skill layout; hosts\n * with a project rules directory (cursor/windsurf/cline) get their own\n * rules file; hosts that read a single shared instructions file\n * (AGENTS.md-based agents like Codex/opencode/Amp, and Gemini CLI's\n * GEMINI.md) get an idempotent marked block appended.\n */\nconst PLATFORMS: Record<string, PlatformInstaller> = {\n claude: async (cwd, content) => {\n const target = path.join(cwd, '.claude', 'skills', 'graphify', 'SKILL.md');\n await writeOwnedFile(target, content);\n return { host: 'Claude Code', path: target };\n },\n cursor: async (cwd, content) => {\n const target = path.join(cwd, '.cursor', 'rules', 'graphify.mdc');\n const body = content.replace(/^---[\\s\\S]*?---\\n/, ''); // strip the skill frontmatter\n await writeOwnedFile(\n target,\n `---\\ndescription: Query the graphify knowledge graph for codebase structure questions\\nalwaysApply: false\\n---\\n${body}`,\n );\n return { host: 'Cursor', path: target };\n },\n windsurf: async (cwd, content) => {\n const target = path.join(cwd, '.windsurf', 'rules', 'graphify.md');\n await writeOwnedFile(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n return { host: 'Windsurf', path: target };\n },\n cline: async (cwd, content) => {\n const target = path.join(cwd, '.clinerules', 'graphify.md');\n await writeOwnedFile(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n return { host: 'Cline', path: target };\n },\n agents: async (cwd, content) => {\n const target = path.join(cwd, 'AGENTS.md');\n await upsertMarkedBlock(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n return { host: 'AGENTS.md agents (Codex, opencode, Amp, ...)', path: target };\n },\n gemini: async (cwd, content) => {\n const target = path.join(cwd, 'GEMINI.md');\n await upsertMarkedBlock(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n return { host: 'Gemini CLI', path: target };\n },\n};\n\nexport const SUPPORTED_PLATFORMS = Object.keys(PLATFORMS).sort((a, b) => a.localeCompare(b));\n\n/**\n * Install the graphify skill/rules for the requested platforms (default:\n * claude). `all` installs every supported platform.\n */\nexport async function runInstall(\n platforms: string[] = ['claude'],\n cwd: string = process.cwd(),\n): Promise<InstallResult[]> {\n const sourcePath = path.join(packageRoot(), 'src', 'skill', 'SKILL.md');\n const content = await fs.readFile(sourcePath, 'utf-8');\n\n const requested = platforms.includes('all') ? SUPPORTED_PLATFORMS : platforms;\n const results: InstallResult[] = [];\n for (const platform of requested) {\n const installer = PLATFORMS[platform];\n if (!installer) {\n throw new Error(\n `Unknown platform \"${platform}\" — supported: ${SUPPORTED_PLATFORMS.join(', ')}, or \"all\".`,\n );\n }\n results.push(await installer(cwd, content));\n }\n\n for (const result of results) {\n console.log(`Installed graphify for ${result.host} -> ${result.path}`);\n }\n return results;\n}\n","import { loadGraph } from '../../graphStore.js';\nimport { shortestPath } from '../../query.js';\n\n/** Shortest path between two named nodes. */\nexport async function runPath(fromNode: string, toNode: string): Promise<void> {\n const graph = await loadGraph();\n const result = shortestPath(graph, fromNode, toNode);\n\n if (!result) {\n console.log(`Could not resolve \"${fromNode}\" and/or \"${toNode}\" to a node in the graph.`);\n return;\n }\n\n if (!result.found) {\n console.log(\n `No path found between \"${result.from.label}\" and \"${result.to.label}\" — they may be in ` +\n 'disconnected parts of the graph (see GRAPH_REPORT.md § Open Questions).',\n );\n return;\n }\n\n console.log(`${result.from.label} -> ${result.to.label} (${result.path.length} node(s)):`);\n console.log(` ${result.path.join(' -> ')}`);\n if (result.edges.length > 0) {\n console.log('');\n console.log('Edges along the path:');\n for (const edge of result.edges) {\n console.log(` ${edge.source} --${edge.relation}--> ${edge.target} (${edge.confidence})`);\n }\n }\n}\n","import { loadGraph } from '../../graphStore.js';\nimport { queryGraph } from '../../query.js';\n\nexport interface QueryOptions {\n dfs?: boolean;\n /** Approximate token cap for the printed context (default 2000). */\n budget?: number;\n}\n\n/** BFS (default) or DFS traversal answering a natural-language question against the graph. */\nexport async function runQuery(question: string, options: QueryOptions = {}): Promise<void> {\n const graph = await loadGraph();\n const result = queryGraph(graph, question, { dfs: options.dfs, tokenBudget: options.budget });\n\n if (result.seeds.length === 0) {\n console.log(\n `No nodes matched \"${question}\". Try different keywords, or run \\`graphify explain <node>\\` ` +\n 'if you already know the name.',\n );\n return;\n }\n\n console.log(`Matched ${result.seeds.length} seed node(s):`);\n for (const seed of result.seeds) {\n console.log(` - ${seed.label} (${seed.id})`);\n }\n\n console.log('');\n console.log(`Context — ${result.visited.length} node(s), ${options.dfs ? 'DFS' : 'BFS'} traversal:`);\n for (const node of result.visited) {\n const location = node.sourceLocation ? `:${node.sourceLocation}` : '';\n console.log(` [depth ${node.depth}] ${node.label} — ${node.sourceFile}${location}`);\n }\n\n console.log('');\n console.log(`Edges within this context (${result.edges.length}):`);\n for (const edge of result.edges) {\n console.log(` ${edge.source} --${edge.relation}--> ${edge.target} (${edge.confidence})`);\n }\n}\n"],"mappings":"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","names":["execFile","fs","os","path","promisify","readFile","fs","fs","fs","path","fs","path","fs","path","require","execFileAsync","promisify","execFile"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/commands/affected.ts","../../src/cli/commands/benchmark.ts","../../src/cli/commands/check.ts","../../src/cli/commands/context.ts","../../src/cli/commands/explain.ts","../../src/cli/commands/review.ts","../../src/cli/commands/tests.ts","../../src/cli/commands/global.ts","../../src/cli/commands/hook.ts","../../src/cli/commands/install.ts","../../src/cli/commands/path.ts","../../src/cli/commands/query.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { execFile } from 'node:child_process';\nimport * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport { watch as watchFiles } from 'chokidar';\nimport { Command } from 'commander';\nimport { analyze } from '../analyze.js';\nimport { cluster } from '../cluster.js';\nimport { exportGraph } from '../export.js';\nimport { loadGraph } from '../graphStore.js';\nimport { runPipeline } from '../pipeline.js';\nimport { renderReport } from '../report.js';\nimport { validateDsn, validateUrl } from '../security.js';\nimport type { ExtractionResult } from '../types.js';\nimport { runAffected } from './commands/affected.js';\nimport { runBenchmark } from './commands/benchmark.js';\nimport { runCheck } from './commands/check.js';\nimport { runContext } from './commands/context.js';\nimport { runExplain } from './commands/explain.js';\nimport { runReview } from './commands/review.js';\nimport { runTests } from './commands/tests.js';\nimport { runGlobalAdd, runGlobalBuild, runGlobalList, runGlobalRemove, runMerge } from './commands/global.js';\nimport { runHookInstall, runHookUninstall } from './commands/hook.js';\nimport { loadResults, renderLessons, saveResult, type ResultOutcome, type ResultType } from '../memory.js';\nimport { detectPlatforms, runInstall } from './commands/install.js';\nimport { runPath } from './commands/path.js';\nimport { runQuery } from './commands/query.js';\n\nconst execFileAsync = promisify(execFile);\n\ninterface DefaultCommandOptions {\n mode?: string;\n update?: boolean;\n watch?: boolean;\n clusterOnly?: boolean;\n viz: boolean; // commander negatable --no-viz -> options.viz\n svg?: boolean;\n graphml?: boolean;\n neo4j?: boolean;\n mcp?: boolean;\n install: boolean; // commander negatable --no-install -> options.install\n leiden?: boolean;\n maxIterations?: number;\n mysql?: string;\n}\n\nfunction looksLikeGitUrl(value: string): boolean {\n if (!/^https?:\\/\\//i.test(value)) return false;\n return /github\\.com|gitlab\\.com|bitbucket\\.org/i.test(value) || value.endsWith('.git');\n}\n\n/** Clone `url` into a fresh temp directory using an argv-array child_process call (never shell: true, never a shell string built from input). */\nasync function cloneRepo(url: string): Promise<string> {\n const validated = validateUrl(url);\n const dest = await fs.mkdtemp(path.join(os.tmpdir(), 'graphify-clone-'));\n await execFileAsync('git', ['clone', '--depth', '1', validated, dest]);\n return dest;\n}\n\nfunction exportOptionsFrom(options: DefaultCommandOptions) {\n return { html: options.viz, svg: options.svg, graphml: options.graphml, neo4j: options.neo4j };\n}\n\nfunction clusterOptionsFrom(options: DefaultCommandOptions) {\n return {\n algorithm: options.leiden ? ('leiden' as const) : ('louvain' as const),\n maxIterations: options.maxIterations,\n };\n}\n\nasync function runClusterOnly(root: string, options: DefaultCommandOptions): Promise<void> {\n const outDir = path.join(root, 'graphify-out');\n const graph = await loadGraph(outDir);\n cluster(graph, clusterOptionsFrom(options));\n const analysis = analyze(graph);\n const report = renderReport(graph, analysis);\n await exportGraph(graph, { outDir, ...exportOptionsFrom(options) }, report);\n console.error(`Re-clustered the existing graph (${clusterOptionsFrom(options).algorithm}).`);\n}\n\n/** Watch `root` (ignoring graphify-out/, node_modules/, .git/) and re-run `runOnce` on any change, debounced. Never resolves — the process stays alive until interrupted, matching normal watch-mode CLI behavior. */\nasync function watchAndRebuild(root: string, runOnce: () => Promise<unknown>): Promise<void> {\n const watcher = watchFiles(root, {\n ignored: (filePath: string) => /(^|[/\\\\])(node_modules|\\.git|graphify-out)([/\\\\]|$)/.test(filePath),\n ignoreInitial: true,\n });\n\n let timer: ReturnType<typeof setTimeout> | null = null;\n let running = false;\n const schedule = (): void => {\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n if (running) return;\n running = true;\n console.error('Change detected, rebuilding...');\n runOnce()\n .catch((error: unknown) => console.error(`graphify --watch: rebuild failed: ${(error as Error).message}`))\n .finally(() => {\n running = false;\n });\n }, 300);\n };\n\n watcher.on('add', schedule).on('change', schedule).on('unlink', schedule);\n\n await new Promise<never>(() => {\n /* keep the process alive until the user interrupts it (Ctrl+C) */\n });\n}\n\nconst program = new Command();\n\nprogram\n .name('graphify')\n .description('Turn a folder of code/docs/papers into a queryable knowledge graph.')\n .argument('[path]', 'path to scan, or a GitHub URL', '.')\n .option('--mode <mode>', 'extraction mode (deep for richer INFERRED edges — reserved, no-op in v1)')\n .option('--update', 'incremental rebuild — reuse cached extractions for unchanged files')\n .option('--watch', 'rebuild on file change')\n .option('--cluster-only', 'rerun clustering on an existing graph')\n .option('--leiden', 'use Leiden instead of Louvain for community detection (v2 — better community quality)')\n .option('--max-iterations <n>', 'Leiden only: cap on outer iterations for very large graphs', Number)\n .option('--no-viz', 'skip graph.html')\n .option('--svg', 'also export graph.svg (not implemented in v1)')\n .option('--graphml', 'also export graph.graphml (not implemented in v1)')\n .option('--neo4j', 'generate graphify-out/cypher.txt for Neo4j (not implemented in v1)')\n .option('--mcp', 'start MCP stdio server instead of running the pipeline')\n .option('--no-install', 'skip auto-installing the agent skill + MCP config after the build')\n .option('--mysql <dsn>', 'also extract a MySQL schema (mysql://user:pass@host:port/db) into the graph')\n .action(async (targetArg: string, options: DefaultCommandOptions) => {\n try {\n if (options.mcp) {\n const outDir = path.resolve(targetArg === '.' ? process.cwd() : targetArg, 'graphify-out');\n const { startServer } = await import('../mcp/server.js');\n await startServer(path.join(outDir, 'graph.json'));\n return;\n }\n\n let root = targetArg;\n const cloned = looksLikeGitUrl(targetArg);\n if (cloned) {\n console.error(`Cloning ${targetArg} ...`);\n root = await cloneRepo(targetArg);\n }\n root = path.resolve(root);\n\n if (options.mode) {\n console.error(`--mode ${options.mode} is reserved for a future richer-INFERRED-edges pass — currently a no-op.`);\n }\n\n if (options.clusterOnly) {\n await runClusterOnly(root, options);\n return;\n }\n\n let extraExtractions: ExtractionResult[] | undefined;\n if (options.mysql) {\n const { extractMysql } = await import('../extractors/mysql.js');\n console.error(`Extracting MySQL schema from ${validateDsn(options.mysql).safeDisplay} ...`);\n extraExtractions = [await extractMysql(options.mysql)];\n }\n\n const runOnce = () =>\n runPipeline(root, {\n ...exportOptionsFrom(options),\n ...clusterOptionsFrom(options),\n extraExtractions,\n update: options.update,\n onProgress: (m) => console.error(m),\n });\n await runOnce();\n\n // Make the graph instantly usable by AI agents: install the skill and\n // register the project-scoped MCP server for whichever hosts this\n // project uses. Skipped for cloned URLs (the clone lives in a temp\n // dir) and with --no-install; a failure here never fails the build.\n if (options.install && !cloned) {\n try {\n await runInstall(await detectPlatforms(root), root);\n } catch (error) {\n console.error(`graphify: agent skill/MCP install skipped: ${(error as Error).message}`);\n }\n }\n\n if (options.watch) {\n console.error(`Watching ${root} for changes (Ctrl+C to stop) ...`);\n await watchAndRebuild(root, runOnce);\n }\n } catch (error) {\n console.error(`graphify: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('query <question>')\n .description('BFS (default) or DFS traversal answering a question against the existing graph')\n .option('--dfs', 'depth-first traversal (trace a specific path)')\n .option('--budget <tokens>', 'cap answer at N tokens', Number)\n .action(async (question: string, options: { dfs?: boolean; budget?: number }) => {\n try {\n await runQuery(question, options);\n } catch (error) {\n console.error(`graphify query: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('path <from> <to>')\n .description('shortest path between two named nodes')\n .action(async (from: string, to: string) => {\n try {\n await runPath(from, to);\n } catch (error) {\n console.error(`graphify path: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('explain <node>')\n .description('plain-language explanation of a node')\n .action(async (node: string) => {\n try {\n await runExplain(node);\n } catch (error) {\n console.error(`graphify explain: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('affected <node>')\n .description('reverse impact analysis — everything that (transitively) depends on a node')\n .option('--depth <n>', 'how many reverse hops to follow (default 3)', Number)\n .option('--limit <n>', 'cap on affected nodes reported (default 200)', Number)\n .action(async (node: string, options: { depth?: number; limit?: number }) => {\n try {\n await runAffected(node, options);\n } catch (error) {\n console.error(`graphify affected: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('context <task>')\n .description('token-budgeted working-set pack — the actual code for a task, in one call')\n .option('--budget <tokens>', 'approximate token cap for the pack (default 4000)', Number)\n .action(async (task: string, options: { budget?: number }) => {\n try {\n await runContext(task, options);\n } catch (error) {\n console.error(`graphify context: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('tests [node]')\n .description('structural test selection — the minimal test files worth running for a change')\n .option('--changed [rev]', 'select for the working-tree diff (optionally vs a revision) instead of a node')\n .action(async (node: string | undefined, options: { changed?: string | boolean }) => {\n try {\n await runTests(node, options);\n } catch (error) {\n console.error(`graphify tests: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('review <base> [head]')\n .description('structural review between two git revisions: added/removed/rewired symbols with blast radius + tests')\n .action(async (base: string, head?: string) => {\n try {\n await runReview(base, head);\n } catch (error) {\n console.error(`graphify review: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('check')\n .description('check the graph against dependency rules (graphify.rules.json) — exits 1 on violations')\n .option('--rules <file>', 'rules file (default ./graphify.rules.json)')\n .action(async (options: { rules?: string }) => {\n try {\n await runCheck(options);\n } catch (error) {\n console.error(`graphify check: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('benchmark [questions...]')\n .description('measure token savings of graph answers vs reading the files they touch')\n .action(async (questions: string[]) => {\n try {\n await runBenchmark(questions);\n } catch (error) {\n console.error(`graphify benchmark: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('install')\n .description('install the skill/rules files + project MCP config into local agents (claude, cursor, windsurf, cline, agents, gemini, all)')\n .option('--platform <names...>', 'platform(s) to install for', ['claude'])\n .action(async (options: { platform: string[] }) => {\n try {\n await runInstall(options.platform);\n } catch (error) {\n console.error(`graphify install: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nconst globalCommand = program\n .command('global')\n .description('manage the cross-project global graph (registry at ~/.graphify/global.json)');\n\nglobalCommand\n .command('add [path]')\n .description('register a project (must already have graphify-out/graph.json)')\n .action(async (target?: string) => {\n try {\n await runGlobalAdd(target);\n } catch (error) {\n console.error(`graphify global add: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nglobalCommand\n .command('remove <name>')\n .description('unregister a project by name')\n .action(async (name: string) => {\n try {\n await runGlobalRemove(name);\n } catch (error) {\n console.error(`graphify global remove: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nglobalCommand\n .command('list')\n .description('list registered projects')\n .action(async () => {\n try {\n await runGlobalList();\n } catch (error) {\n console.error(`graphify global list: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nglobalCommand\n .command('build')\n .description('merge every registered project into one global graph')\n .option('--out <dir>', 'output directory (default ~/.graphify/global-out)')\n .action(async (options: { out?: string }) => {\n try {\n await runGlobalBuild(options);\n } catch (error) {\n console.error(`graphify global build: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('merge <dirs...>')\n .description('one-shot merge of two or more built project graphs into one')\n .option('--out <dir>', 'output directory (default ./graphify-merged)')\n .action(async (dirs: string[], options: { out?: string }) => {\n try {\n await runMerge(dirs, options);\n } catch (error) {\n console.error(`graphify merge: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('save-result')\n .description('save a Q&A result to graphify-out/memory/ for the graph feedback loop')\n .requiredOption('--question <q>', 'the question that was asked')\n .requiredOption('--answer <a>', 'the answer that was given')\n .option('--nodes <ids...>', 'node ids/labels cited in the answer', [])\n .option('--type <t>', 'query|path|explain|affected', 'query')\n .option('--outcome <o>', 'useful|dead_end|corrected', 'useful')\n .option('--correction <text>', 'what the right answer was (pairs with --outcome corrected)')\n .action(async (options: {\n question: string;\n answer: string;\n nodes: string[];\n type: string;\n outcome: string;\n correction?: string;\n }) => {\n try {\n const memoryDir = path.join(process.cwd(), 'graphify-out', 'memory');\n const file = await saveResult(\n {\n question: options.question,\n answer: options.answer,\n nodes: options.nodes,\n type: options.type as ResultType,\n outcome: options.outcome as ResultOutcome,\n correction: options.correction,\n },\n memoryDir,\n );\n console.log(`Saved -> ${file}`);\n } catch (error) {\n console.error(`graphify save-result: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command('reflect')\n .description('aggregate graphify-out/memory/ into a recency-weighted lessons doc')\n .option('--half-life-days <n>', 'a result loses half its weight every N days (default 30)', Number)\n .option('--out <file>', 'output path (default graphify-out/reflections/LESSONS.md)')\n .action(async (options: { halfLifeDays?: number; out?: string }) => {\n try {\n const memoryDir = path.join(process.cwd(), 'graphify-out', 'memory');\n const results = await loadResults(memoryDir);\n const lessons = renderLessons(results, { halfLifeDays: options.halfLifeDays });\n const outPath = path.resolve(options.out ?? path.join(process.cwd(), 'graphify-out', 'reflections', 'LESSONS.md'));\n await fs.mkdir(path.dirname(outPath), { recursive: true });\n await fs.writeFile(outPath, lessons, 'utf-8');\n console.log(`Reflected ${results.length} result(s) -> ${outPath}`);\n } catch (error) {\n console.error(`graphify reflect: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nconst hookCommand = program\n .command('hook')\n .description('manage the git hooks that auto-rebuild the graph on commit/pull');\n\nhookCommand\n .command('install')\n .description('install post-commit and post-merge hooks (preserves existing hook content)')\n .action(async () => {\n try {\n await runHookInstall();\n } catch (error) {\n console.error(`graphify hook install: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nhookCommand\n .command('uninstall')\n .description('remove the graphify block from the git hooks')\n .action(async () => {\n try {\n await runHookUninstall();\n } catch (error) {\n console.error(`graphify hook uninstall: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram.parseAsync(process.argv);\n","import { loadGraph } from '../../graphStore.js';\nimport { affectedBy } from '../../impact.js';\n\nexport interface AffectedOptions {\n depth?: number;\n limit?: number;\n}\n\n/** Reverse impact analysis: everything that (transitively) depends on the named node. */\nexport async function runAffected(nodeName: string, options: AffectedOptions = {}): Promise<void> {\n const graph = await loadGraph();\n const result = affectedBy(graph, nodeName, { maxDepth: options.depth, limit: options.limit });\n\n if (!result) {\n console.log(`No node matched \"${nodeName}\".`);\n return;\n }\n\n console.log(`Impact of changing ${result.target.label} (${result.target.id}):`);\n\n if (result.affected.length === 0) {\n console.log(' Nothing in the graph depends on it — no incoming dependency edges.');\n return;\n }\n\n let currentDepth = 0;\n for (const node of result.affected) {\n if (node.depth !== currentDepth) {\n currentDepth = node.depth;\n console.log('');\n console.log(currentDepth === 1 ? 'Directly affected:' : `Affected at depth ${currentDepth}:`);\n }\n const isPlaceholder =\n node.sourceFile === '<unknown>' || node.sourceFile === '<external>' || node.sourceFile === '';\n const where = isPlaceholder\n ? '(reference only)'\n : `${node.sourceFile}${node.sourceLocation ? `:${node.sourceLocation}` : ''}`;\n console.log(\n ` ${node.label} — ${where} ` +\n `(--${node.via.relation}--> ${node.via.dependsOn}, ${node.via.confidence})`,\n );\n }\n\n console.log('');\n const { EXTRACTED, INFERRED, AMBIGUOUS } = result.byConfidence;\n console.log(\n `Blast radius: ${result.affected.length} node(s) within ${result.maxDepth} hop(s) — ` +\n `${EXTRACTED} certain (EXTRACTED), ${INFERRED} likely (INFERRED), ${AMBIGUOUS} uncertain (AMBIGUOUS).`,\n );\n if (result.truncated) {\n console.log('(List truncated — raise --limit to see more.)');\n }\n}\n","import * as fs from 'node:fs/promises';\nimport type Graph from 'graphology';\nimport { loadGraph } from '../../graphStore.js';\nimport { queryGraph } from '../../query.js';\nimport { isTestFile } from '../../testmap.js';\n\n/**\n * `graphify benchmark` — measure the token savings of answering through the\n * graph instead of reading source files. For each question it compares the\n * serialized size of the graph answer against the size of every source file\n * that answer's nodes live in (the \"just read the relevant files\" baseline\n * an agent without the graph would pay). Chars/4 is the usual token\n * approximation, applied to both sides so the ratio is fair.\n */\n\nexport interface BenchmarkRow {\n question: string;\n graphTokens: number;\n naiveTokens: number;\n /** naive / graph — how many times cheaper the graph answer is. */\n reduction: number;\n filesRead: number;\n filesMissing: number;\n}\n\nexport type FileReader = (path: string) => Promise<string>;\n\nconst tokensOf = (text: string): number => Math.ceil(text.length / 4);\n\nexport async function benchmarkQuestion(\n graph: Graph,\n question: string,\n readFile: FileReader,\n): Promise<BenchmarkRow> {\n const result = queryGraph(graph, question);\n // Compact JSON, matching how queryGraph's own token budget measures itself.\n const graphTokens = tokensOf(JSON.stringify(result));\n\n const sourceFiles = new Set<string>();\n for (const node of result.visited) {\n if (node.sourceFile && !node.sourceFile.startsWith('<') && !node.sourceFile.includes('://')) {\n sourceFiles.add(node.sourceFile);\n }\n }\n\n let naiveTokens = 0;\n let filesRead = 0;\n let filesMissing = 0;\n for (const file of [...sourceFiles].sort((a, b) => a.localeCompare(b))) {\n try {\n naiveTokens += tokensOf(await readFile(file));\n filesRead++;\n } catch {\n filesMissing++;\n }\n }\n\n return {\n question,\n graphTokens,\n naiveTokens,\n reduction: graphTokens > 0 && naiveTokens > 0 ? naiveTokens / graphTokens : 0,\n filesRead,\n filesMissing,\n };\n}\n\n/** Files no agent would ask a \"how does X work\" question about — build config, examples, scripts, docs. */\nconst NON_QUESTION_FILE =\n /(^|\\/)(examples?|scripts?|bench(?:mark)?s?|fixtures?|docs?|\\.github)\\/|\\.(config|conf)\\.[^/]+$|(^|\\/)(rollup|webpack|vite|vitest|jest|babel|tsup|eslint|prettier)\\.[^/]*$/i;\n\n/**\n * Default questions when none are given: the labels of the highest-degree\n * (most load-bearing) SOURCE entities. Tests, build config, and examples\n * are excluded — they score high on degree but are questions no agent\n * would ask, and they drag the measured reduction down unfairly.\n */\nexport function defaultQuestions(graph: Graph, count = 5): string[] {\n const entries = [...graph.nodes()]\n .map((id) => ({\n id,\n degree: graph.degree(id),\n label: (graph.getNodeAttribute(id, 'label') as string | undefined) ?? id,\n file: (graph.getNodeAttribute(id, 'sourceFile') as string | undefined) ?? '',\n }))\n // File nodes score high on degree but make poor questions — prefer entities.\n .filter((e) => e.id.includes('::'))\n .filter((e) => !isTestFile(e.file) && !NON_QUESTION_FILE.test(e.file))\n .sort((a, b) => b.degree - a.degree || a.id.localeCompare(b.id));\n return entries.slice(0, count).map((e) => `how does ${e.label} work`);\n}\n\nexport async function runBenchmark(questions: string[]): Promise<BenchmarkRow[]> {\n const graph = await loadGraph();\n const effective = questions.length > 0 ? questions : defaultQuestions(graph);\n if (effective.length === 0) {\n console.log('The graph has no entity nodes to benchmark against — build it first.');\n return [];\n }\n\n const rows: BenchmarkRow[] = [];\n for (const question of effective) {\n rows.push(await benchmarkQuestion(graph, question, (p) => fs.readFile(p, 'utf-8')));\n }\n\n console.log('Token cost per question — graph answer vs reading the files it touches:\\n');\n for (const row of rows) {\n const reduction = row.reduction > 0 ? `${row.reduction.toFixed(1)}x` : 'n/a';\n console.log(` \"${row.question}\"`);\n console.log(\n ` graph: ~${row.graphTokens} tokens | files: ~${row.naiveTokens} tokens ` +\n `(${row.filesRead} file(s)${row.filesMissing ? `, ${row.filesMissing} unreadable` : ''}) | reduction: ${reduction}`,\n );\n }\n\n const scored = rows.filter((r) => r.reduction > 0);\n if (scored.length > 0) {\n const avg = scored.reduce((s, r) => s + r.reduction, 0) / scored.length;\n console.log(`\\nAverage reduction: ${avg.toFixed(1)}x across ${scored.length} question(s).`);\n } else {\n console.log('\\nNo reduction could be measured — run from the project root so source files are readable.');\n }\n return rows;\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { checkRules, validateRules } from '../../check.js';\nimport { loadGraph } from '../../graphStore.js';\n\nexport interface CheckCommandOptions {\n rules?: string;\n}\n\n/**\n * Check the graph against declared dependency rules. Exits non-zero on\n * violations so CI (and agents verifying their own edits) can gate on it.\n */\nexport async function runCheck(options: CheckCommandOptions = {}): Promise<void> {\n const rulesPath = path.resolve(options.rules ?? 'graphify.rules.json');\n let raw: string;\n try {\n raw = await fs.readFile(rulesPath, 'utf-8');\n } catch {\n throw new Error(\n `No rules file at ${rulesPath} — create graphify.rules.json with ` +\n '{ \"rules\": [{ \"name\": \"...\", \"from\": \"src/a/**\", \"disallow\": [\"src/b/**\"] }] }.',\n );\n }\n const config = validateRules(JSON.parse(raw));\n\n const graph = await loadGraph();\n const violations = checkRules(graph, config);\n\n if (violations.length === 0) {\n console.log(`OK — ${config.rules.length} rule(s), no violations.`);\n return;\n }\n\n console.log(`${violations.length} violation(s):`);\n for (const v of violations) {\n console.log(` [${v.rule}] ${v.fromNode} --${v.relation}--> ${v.toNode}`);\n console.log(` ${v.fromFile} must not depend on ${v.toFile}${v.reason ? ` — ${v.reason}` : ''}`);\n }\n process.exitCode = 1;\n}\n","import * as fs from 'node:fs/promises';\nimport { buildContextPack, renderContextPack } from '../../context.js';\nimport { loadGraph } from '../../graphStore.js';\n\nexport interface ContextCommandOptions {\n budget?: number;\n}\n\n/** Token-budgeted working-set pack: the actual code an agent needs for a task, in one call. */\nexport async function runContext(task: string, options: ContextCommandOptions = {}): Promise<void> {\n const graph = await loadGraph();\n const pack = await buildContextPack(graph, task, (p) => fs.readFile(p, 'utf-8'), {\n tokenBudget: options.budget,\n });\n console.log(renderContextPack(pack));\n}\n","import { loadGraph } from '../../graphStore.js';\nimport { explainNode } from '../../query.js';\n\n/** Plain-language explanation of a single node. */\nexport async function runExplain(nodeName: string): Promise<void> {\n const graph = await loadGraph();\n const result = explainNode(graph, nodeName);\n\n if (!result) {\n console.log(`No node matched \"${nodeName}\".`);\n return;\n }\n\n console.log(result.label);\n if (result.sourceFile === '<unknown>' || result.sourceFile === '<external>' || result.sourceFile === '') {\n // Auto-vivified endpoint (re-export alias / unresolved reference) — it\n // has no source of its own, so \"<unknown>:L0\" would read like a bug.\n console.log(' location: (reference only — no declaration seen; check its outgoing edges for the real definition)');\n } else {\n const location = result.sourceLocation ? `:${result.sourceLocation}` : '';\n console.log(` location: ${result.sourceFile}${location}`);\n }\n if (result.communityLabel) {\n console.log(` community: ${result.communityLabel}`);\n }\n\n console.log('');\n console.log(`Calls / references out (${result.outgoing.length}):`);\n if (result.outgoing.length === 0) {\n console.log(' (none)');\n } else {\n for (const edge of result.outgoing) {\n console.log(` --${edge.relation}--> ${edge.target} (${edge.confidence})`);\n }\n }\n\n console.log('');\n console.log(`Referenced by (${result.incoming.length}):`);\n if (result.incoming.length === 0) {\n console.log(' (none)');\n } else {\n for (const edge of result.incoming) {\n console.log(` ${edge.source} --${edge.relation}--> (${edge.confidence})`);\n }\n }\n}\n","import { renderReview, reviewRevisions } from '../../diff.js';\n\n/** Structural review between two git revisions (head defaults to HEAD). */\nexport async function runReview(base: string, head?: string): Promise<void> {\n const diff = await reviewRevisions(process.cwd(), base, head ?? 'HEAD');\n console.log(renderReview(diff));\n}\n","import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { loadGraph } from '../../graphStore.js';\nimport { testsForChangedFiles, testsForNode } from '../../testmap.js';\n\nconst execFileAsync = promisify(execFile);\n\nexport interface TestsCommandOptions {\n /** Select tests for the working-tree diff (optionally against a rev) instead of a named node. */\n changed?: string | boolean;\n}\n\n/** Structural test selection: the minimal test files worth running for a change. */\nexport async function runTests(nodeQuery: string | undefined, options: TestsCommandOptions = {}): Promise<void> {\n const graph = await loadGraph();\n\n let selection;\n if (options.changed !== undefined && options.changed !== false) {\n const args = ['diff', '--name-only'];\n if (typeof options.changed === 'string') args.push(options.changed);\n const { stdout } = await execFileAsync('git', args);\n const changedFiles = stdout.split('\\n').map((l) => l.trim()).filter(Boolean);\n if (changedFiles.length === 0) {\n console.log('No changed files in the diff.');\n return;\n }\n selection = testsForChangedFiles(graph, changedFiles);\n } else if (nodeQuery) {\n selection = testsForNode(graph, nodeQuery);\n if (!selection) {\n console.log(`No node matched \"${nodeQuery}\".`);\n return;\n }\n } else {\n console.log('Provide a node to select tests for, or --changed for the working-tree diff.');\n return;\n }\n\n if (selection.testFiles.length === 0) {\n console.log(\n `No test files found in the blast radius of ${selection.target} ` +\n `(${selection.affectedNodeCount} affected node(s) checked) — either it's untested or the tests ` +\n 'reach it through a path the graph does not capture.',\n );\n return;\n }\n\n const how =\n selection.precision === 'usage'\n ? 'selected by actual usage (calls/inheritance)'\n : 'selected by import reachability — may over-include files sharing an entry point';\n console.log(`Test files for ${selection.target} (${how}; most direct first):`);\n for (const test of selection.testFiles) {\n const via = test.depth === 0 ? test.via : `depth ${test.depth}, via ${test.via}`;\n console.log(` ${test.file} (${via})`);\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\nimport { analyze } from '../../analyze.js';\nimport { cluster } from '../../cluster.js';\nimport { exportGraph } from '../../export.js';\nimport { loadGraph } from '../../graphStore.js';\nimport { mergeGraphs, type MergeEntry } from '../../merge.js';\nimport { renderReport } from '../../report.js';\n\n/**\n * `graphify global add|remove|list|build` — a registry of projects whose\n * built graphs get merged into one global cross-project graph, plus the\n * one-shot `graphify merge <dir...>` for merging without a registry.\n * The registry lives at ~/.graphify/global.json; the merged output defaults\n * to ~/.graphify/global-out/.\n */\n\nexport interface GlobalRegistry {\n projects: Array<{ name: string; root: string }>;\n}\n\nfunction registryDir(): string {\n return path.join(os.homedir(), '.graphify');\n}\n\nfunction registryPath(): string {\n return path.join(registryDir(), 'global.json');\n}\n\nasync function readRegistry(): Promise<GlobalRegistry> {\n try {\n const raw = await fs.readFile(registryPath(), 'utf-8');\n const parsed: unknown = JSON.parse(raw);\n const projects = (parsed as GlobalRegistry).projects;\n if (!Array.isArray(projects)) return { projects: [] };\n return { projects: projects.filter((p) => typeof p?.name === 'string' && typeof p?.root === 'string') };\n } catch {\n return { projects: [] };\n }\n}\n\nasync function writeRegistry(registry: GlobalRegistry): Promise<void> {\n await fs.mkdir(registryDir(), { recursive: true });\n await fs.writeFile(registryPath(), JSON.stringify(registry, null, 2), 'utf-8');\n}\n\n/** Project name for a root: its package.json \"name\" if present, else the directory basename. */\nasync function projectNameFor(root: string): Promise<string> {\n try {\n const raw = await fs.readFile(path.join(root, 'package.json'), 'utf-8');\n const name = (JSON.parse(raw) as { name?: unknown }).name;\n if (typeof name === 'string' && name.length > 0) return name;\n } catch {\n // no package.json — fall through to the basename\n }\n return path.basename(root);\n}\n\nexport async function runGlobalAdd(target: string = '.'): Promise<void> {\n const root = path.resolve(target);\n const graphJson = path.join(root, 'graphify-out', 'graph.json');\n try {\n await fs.access(graphJson);\n } catch {\n throw new Error(`${root} has no graphify-out/graph.json — run \\`graphify ${target}\\` first, then add it.`);\n }\n\n const name = await projectNameFor(root);\n const registry = await readRegistry();\n\n const existing = registry.projects.find((p) => p.name === name);\n if (existing) {\n if (existing.root === root) {\n console.log(`${name} is already registered (${root}).`);\n return;\n }\n throw new Error(\n `A different project is already registered as \"${name}\" (${existing.root}). ` +\n 'Remove it first with `graphify global remove`.',\n );\n }\n\n registry.projects.push({ name, root });\n registry.projects.sort((a, b) => a.name.localeCompare(b.name));\n await writeRegistry(registry);\n console.log(`Registered ${name} (${root}). ${registry.projects.length} project(s) in the global graph.`);\n}\n\nexport async function runGlobalRemove(name: string): Promise<void> {\n const registry = await readRegistry();\n const before = registry.projects.length;\n registry.projects = registry.projects.filter((p) => p.name !== name);\n if (registry.projects.length === before) {\n throw new Error(`No project named \"${name}\" is registered. See \\`graphify global list\\`.`);\n }\n await writeRegistry(registry);\n console.log(`Removed ${name}. ${registry.projects.length} project(s) remain.`);\n}\n\nexport async function runGlobalList(): Promise<void> {\n const registry = await readRegistry();\n if (registry.projects.length === 0) {\n console.log('No projects registered. Add one with `graphify global add <path>`.');\n return;\n }\n for (const project of registry.projects) {\n console.log(`${project.name} ${project.root}`);\n }\n}\n\n/** Load every entry's graph, skipping (with a warning) the ones that fail — one broken project must not sink the merge. */\nasync function loadEntries(sources: Array<{ name: string; outDir: string }>): Promise<MergeEntry[]> {\n const entries: MergeEntry[] = [];\n for (const source of sources) {\n try {\n entries.push({ name: source.name, graph: await loadGraph(source.outDir) });\n } catch (error) {\n console.warn(`Skipping ${source.name}: ${(error as Error).message}`);\n }\n }\n return entries;\n}\n\nasync function mergeAndExport(entries: MergeEntry[], outDir: string): Promise<void> {\n if (entries.length === 0) {\n throw new Error('Nothing to merge — no project graphs could be loaded.');\n }\n\n const merged = mergeGraphs(entries);\n cluster(merged);\n const analysis = analyze(merged);\n const report = renderReport(merged, analysis);\n await exportGraph(merged, { outDir }, report);\n\n console.log(\n `Merged ${entries.length} project(s) into ${outDir} — ` +\n `${merged.order} node(s), ${merged.size} edge(s).`,\n );\n}\n\nexport async function runGlobalBuild(options: { out?: string } = {}): Promise<void> {\n const registry = await readRegistry();\n if (registry.projects.length === 0) {\n throw new Error('No projects registered. Add some with `graphify global add <path>` first.');\n }\n\n const entries = await loadEntries(\n registry.projects.map((p) => ({ name: p.name, outDir: path.join(p.root, 'graphify-out') })),\n );\n await mergeAndExport(entries, path.resolve(options.out ?? path.join(registryDir(), 'global-out')));\n}\n\n/** One-shot merge of two or more project directories, no registry involved. */\nexport async function runMerge(targets: string[], options: { out?: string } = {}): Promise<void> {\n if (targets.length < 2) {\n throw new Error('Provide at least two project directories to merge.');\n }\n\n const sources: Array<{ name: string; outDir: string }> = [];\n for (const target of targets) {\n const root = path.resolve(target);\n sources.push({ name: await projectNameFor(root), outDir: path.join(root, 'graphify-out') });\n }\n\n const names = sources.map((s) => s.name);\n const duplicate = names.find((name, i) => names.indexOf(name) !== i);\n if (duplicate !== undefined) {\n throw new Error(`Two of the given projects resolve to the same name (\"${duplicate}\") — rename one.`);\n }\n\n const entries = await loadEntries(sources);\n await mergeAndExport(entries, path.resolve(options.out ?? 'graphify-merged'));\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\n/**\n * `graphify hook install` / `graphify hook uninstall` — auto-rebuild the\n * graph after commits and pulls, mirroring the Python original's\n * `hook install`. The hook body lives inside a marked block so we can\n * coexist with (and later cleanly remove ourselves from) hooks the user\n * already has; we never overwrite or delete anything outside our markers.\n */\n\nconst MARKER_BEGIN = '# >>> graphify >>>';\nconst MARKER_END = '# <<< graphify <<<';\n\n/** post-commit: rebuild after each commit. post-merge: rebuild after pull/merge. */\nconst HOOK_NAMES = ['post-commit', 'post-merge'] as const;\n\nconst HOOK_BLOCK = `${MARKER_BEGIN}\n# Rebuild the graphify knowledge graph in the background so the hook never\n# slows down the commit. Errors are silenced — a failed rebuild should never\n# break a git operation. Installed by \\`graphify hook install\\`.\n(graphify . --update --no-viz >/dev/null 2>&1 &)\n${MARKER_END}`;\n\nexport interface HookResult {\n hook: string;\n path: string;\n action: 'created' | 'appended' | 'already-installed' | 'removed' | 'not-installed';\n}\n\nasync function hooksDir(cwd: string): Promise<string> {\n const gitDir = path.join(cwd, '.git');\n let stats;\n try {\n stats = await fs.stat(gitDir);\n } catch {\n throw new Error(`${cwd} is not a git repository (no .git directory) — run this from the repo root.`);\n }\n if (!stats.isDirectory()) {\n // .git can be a file in worktrees/submodules (\"gitdir: <path>\") — follow it.\n const content = (await fs.readFile(gitDir, 'utf-8')).trim();\n const match = /^gitdir:\\s*(.+)$/.exec(content);\n if (!match) throw new Error(`${gitDir} exists but is neither a directory nor a gitdir pointer.`);\n return path.resolve(cwd, match[1] as string, 'hooks');\n }\n return path.join(gitDir, 'hooks');\n}\n\n/** Install the marked graphify block into post-commit and post-merge, preserving any existing hook content. */\nexport async function runHookInstall(cwd: string = process.cwd()): Promise<HookResult[]> {\n const dir = await hooksDir(cwd);\n await fs.mkdir(dir, { recursive: true });\n\n const results: HookResult[] = [];\n for (const hook of HOOK_NAMES) {\n const hookPath = path.join(dir, hook);\n let existing: string | null = null;\n try {\n existing = await fs.readFile(hookPath, 'utf-8');\n } catch {\n // no existing hook — we'll create it\n }\n\n if (existing === null) {\n await fs.writeFile(hookPath, `#!/bin/sh\\n${HOOK_BLOCK}\\n`, { mode: 0o755 });\n results.push({ hook, path: hookPath, action: 'created' });\n } else if (existing.includes(MARKER_BEGIN)) {\n results.push({ hook, path: hookPath, action: 'already-installed' });\n } else {\n const separator = existing.endsWith('\\n') ? '' : '\\n';\n await fs.writeFile(hookPath, `${existing}${separator}${HOOK_BLOCK}\\n`, 'utf-8');\n await fs.chmod(hookPath, 0o755);\n results.push({ hook, path: hookPath, action: 'appended' });\n }\n }\n\n for (const result of results) {\n console.log(`${result.hook}: ${result.action} (${result.path})`);\n }\n console.log('');\n console.log('The graph will rebuild in the background after each commit and pull.');\n console.log('Remove with `graphify hook uninstall`.');\n return results;\n}\n\n/** Remove only the marked graphify block; delete the hook file if nothing else is left in it. */\nexport async function runHookUninstall(cwd: string = process.cwd()): Promise<HookResult[]> {\n const dir = await hooksDir(cwd);\n\n const results: HookResult[] = [];\n for (const hook of HOOK_NAMES) {\n const hookPath = path.join(dir, hook);\n let existing: string | null = null;\n try {\n existing = await fs.readFile(hookPath, 'utf-8');\n } catch {\n // nothing installed\n }\n\n if (existing === null || !existing.includes(MARKER_BEGIN)) {\n results.push({ hook, path: hookPath, action: 'not-installed' });\n continue;\n }\n\n const blockPattern = new RegExp(`\\\\n?${MARKER_BEGIN}[\\\\s\\\\S]*?${MARKER_END}\\\\n?`);\n const remaining = existing.replace(blockPattern, '\\n').trim();\n\n if (remaining === '' || remaining === '#!/bin/sh') {\n await fs.unlink(hookPath);\n } else {\n await fs.writeFile(hookPath, `${remaining}\\n`, 'utf-8');\n }\n results.push({ hook, path: hookPath, action: 'removed' });\n }\n\n for (const result of results) {\n console.log(`${result.hook}: ${result.action}`);\n }\n return results;\n}\n","import { createRequire } from 'node:module';\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Resolve this package's own root directory, whether we're running from\n * source (tests/dev), the built dist/ bundle, or installed as a real\n * dependency elsewhere. Uses Node's self-reference resolution (walking up\n * from this module's location to the nearest package.json named\n * \"@dreamtree-org/graphify\") rather than a hardcoded relative path, since\n * the number of directories between this file and the package root\n * differs between src/ and the bundled dist/ output.\n */\nfunction packageRoot(): string {\n const packageJsonPath = require.resolve('@dreamtree-org/graphify/package.json');\n return path.dirname(packageJsonPath);\n}\n\nexport interface InstallResult {\n host: string;\n path: string;\n /** Project-scoped MCP config file this install registered the graphify server in, if the host supports one. */\n mcpPath?: string;\n}\n\n/**\n * The MCP server entry written into project-scoped MCP configs. `npx -y`\n * resolves a locally installed @dreamtree-org/graphify first and falls back\n * to fetching it, so the config works both for the person who ran the\n * install and for teammates who check the file in without installing\n * anything. MCP hosts launch project servers with cwd = project root, so\n * the default graph path (./graphify-out/graph.json) resolves correctly.\n */\nconst MCP_SERVER_ENTRY = {\n command: 'npx',\n args: ['-y', '@dreamtree-org/graphify', '--mcp'],\n};\n\n/**\n * Register the graphify MCP server under `serversKey` in a JSON config\n * file, creating the file if needed and preserving every existing key\n * (other servers, unrelated settings). Idempotent: re-running replaces the\n * graphify entry only. Refuses to touch a file it cannot parse rather than\n * clobbering user config.\n */\nasync function upsertMcpServer(filePath: string, serversKey = 'mcpServers'): Promise<string> {\n let config: Record<string, unknown> = {};\n try {\n config = JSON.parse(await fs.readFile(filePath, 'utf-8')) as Record<string, unknown>;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n throw new Error(`cannot update ${filePath} — it exists but is not valid JSON; fix or remove it and re-run.`, {\n cause: error,\n });\n }\n }\n\n const servers = (config[serversKey] ?? {}) as Record<string, unknown>;\n servers['graphify'] = MCP_SERVER_ENTRY;\n config[serversKey] = servers;\n\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, `${JSON.stringify(config, null, 2)}\\n`, 'utf-8');\n return filePath;\n}\n\n/** Markers for hosts where we append into a shared file (AGENTS.md / GEMINI.md) instead of owning one. */\nconst MD_MARKER_BEGIN = '<!-- >>> graphify >>> -->';\nconst MD_MARKER_END = '<!-- <<< graphify <<< -->';\n\nasync function writeOwnedFile(filePath: string, content: string): Promise<void> {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, content, 'utf-8');\n}\n\n/** Create `filePath` with the marked block, or replace/append the block in an existing file — user content is never touched. */\nasync function upsertMarkedBlock(filePath: string, content: string): Promise<void> {\n const block = `${MD_MARKER_BEGIN}\\n${content.trim()}\\n${MD_MARKER_END}`;\n let existing: string | null = null;\n try {\n existing = await fs.readFile(filePath, 'utf-8');\n } catch {\n // file doesn't exist yet\n }\n\n if (existing === null) {\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, `${block}\\n`, 'utf-8');\n return;\n }\n if (existing.includes(MD_MARKER_BEGIN)) {\n const pattern = new RegExp(`${MD_MARKER_BEGIN}[\\\\s\\\\S]*?${MD_MARKER_END}`);\n await fs.writeFile(filePath, existing.replace(pattern, block), 'utf-8');\n return;\n }\n const separator = existing.endsWith('\\n') ? '\\n' : '\\n\\n';\n await fs.writeFile(filePath, `${existing}${separator}${block}\\n`, 'utf-8');\n}\n\ntype PlatformInstaller = (cwd: string, skillContent: string) => Promise<InstallResult>;\n\n/**\n * Curated per-host installers. `claude` gets the native skill layout; hosts\n * with a project rules directory (cursor/windsurf/cline) get their own\n * rules file; hosts that read a single shared instructions file\n * (AGENTS.md-based agents like Codex/opencode/Amp, and Gemini CLI's\n * GEMINI.md) get an idempotent marked block appended.\n */\nconst PLATFORMS: Record<string, PlatformInstaller> = {\n claude: async (cwd, content) => {\n const target = path.join(cwd, '.claude', 'skills', 'graphify', 'SKILL.md');\n await writeOwnedFile(target, content);\n const mcpPath = await upsertMcpServer(path.join(cwd, '.mcp.json'));\n return { host: 'Claude Code', path: target, mcpPath };\n },\n cursor: async (cwd, content) => {\n const target = path.join(cwd, '.cursor', 'rules', 'graphify.mdc');\n const body = content.replace(/^---[\\s\\S]*?---\\n/, ''); // strip the skill frontmatter\n await writeOwnedFile(\n target,\n `---\\ndescription: Query the graphify knowledge graph for codebase structure questions\\nalwaysApply: false\\n---\\n${body}`,\n );\n const mcpPath = await upsertMcpServer(path.join(cwd, '.cursor', 'mcp.json'));\n return { host: 'Cursor', path: target, mcpPath };\n },\n windsurf: async (cwd, content) => {\n const target = path.join(cwd, '.windsurf', 'rules', 'graphify.md');\n await writeOwnedFile(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n return { host: 'Windsurf', path: target };\n },\n cline: async (cwd, content) => {\n const target = path.join(cwd, '.clinerules', 'graphify.md');\n await writeOwnedFile(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n return { host: 'Cline', path: target };\n },\n agents: async (cwd, content) => {\n const target = path.join(cwd, 'AGENTS.md');\n await upsertMarkedBlock(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n return { host: 'AGENTS.md agents (Codex, opencode, Amp, ...)', path: target };\n },\n gemini: async (cwd, content) => {\n const target = path.join(cwd, 'GEMINI.md');\n await upsertMarkedBlock(target, content.replace(/^---[\\s\\S]*?---\\n/, ''));\n const mcpPath = await upsertMcpServer(path.join(cwd, '.gemini', 'settings.json'));\n return { host: 'Gemini CLI', path: target, mcpPath };\n },\n};\n\nexport const SUPPORTED_PLATFORMS = Object.keys(PLATFORMS).sort((a, b) => a.localeCompare(b));\n\n/** Filesystem markers that indicate a given agent host is in use in a project. */\nconst PLATFORM_MARKERS: Record<string, string[]> = {\n cursor: ['.cursor'],\n windsurf: ['.windsurf'],\n cline: ['.clinerules'],\n agents: ['AGENTS.md'],\n gemini: ['GEMINI.md', '.gemini'],\n};\n\n/**\n * Detect which agent hosts a project uses so the default pipeline run can\n * install for them automatically. Claude Code is always included — it picks\n * up `.claude/skills/` and `.mcp.json` from any project with zero prior\n * setup, so installing it is what makes `npx @dreamtree-org/graphify .`\n * work \"instantly\"; the other hosts are added only when their config\n * dir/file already exists.\n */\nexport async function detectPlatforms(cwd: string = process.cwd()): Promise<string[]> {\n const platforms = ['claude'];\n for (const [platform, markers] of Object.entries(PLATFORM_MARKERS)) {\n for (const marker of markers) {\n try {\n await fs.access(path.join(cwd, marker));\n platforms.push(platform);\n break;\n } catch {\n // marker absent — not this host\n }\n }\n }\n return platforms;\n}\n\n/**\n * Install the graphify skill/rules for the requested platforms (default:\n * claude). `all` installs every supported platform.\n */\nexport async function runInstall(\n platforms: string[] = ['claude'],\n cwd: string = process.cwd(),\n): Promise<InstallResult[]> {\n const sourcePath = path.join(packageRoot(), 'src', 'skill', 'SKILL.md');\n const content = await fs.readFile(sourcePath, 'utf-8');\n\n const requested = platforms.includes('all') ? SUPPORTED_PLATFORMS : platforms;\n const results: InstallResult[] = [];\n for (const platform of requested) {\n const installer = PLATFORMS[platform];\n if (!installer) {\n throw new Error(\n `Unknown platform \"${platform}\" — supported: ${SUPPORTED_PLATFORMS.join(', ')}, or \"all\".`,\n );\n }\n results.push(await installer(cwd, content));\n }\n\n for (const result of results) {\n const mcpNote = result.mcpPath ? ` (MCP server registered in ${result.mcpPath})` : '';\n console.log(`Installed graphify for ${result.host} -> ${result.path}${mcpNote}`);\n }\n return results;\n}\n","import { loadGraph } from '../../graphStore.js';\nimport { shortestPath } from '../../query.js';\n\n/** Shortest path between two named nodes. */\nexport async function runPath(fromNode: string, toNode: string): Promise<void> {\n const graph = await loadGraph();\n const result = shortestPath(graph, fromNode, toNode);\n\n if (!result) {\n console.log(`Could not resolve \"${fromNode}\" and/or \"${toNode}\" to a node in the graph.`);\n return;\n }\n\n if (!result.found) {\n console.log(\n `No path found between \"${result.from.label}\" and \"${result.to.label}\" — they may be in ` +\n 'disconnected parts of the graph (see GRAPH_REPORT.md § Open Questions).',\n );\n return;\n }\n\n console.log(`${result.from.label} -> ${result.to.label} (${result.path.length} node(s)):`);\n console.log(` ${result.path.join(' -> ')}`);\n if (result.edges.length > 0) {\n console.log('');\n console.log('Edges along the path:');\n for (const edge of result.edges) {\n console.log(` ${edge.source} --${edge.relation}--> ${edge.target} (${edge.confidence})`);\n }\n }\n}\n","import { loadGraph } from '../../graphStore.js';\nimport { queryGraph } from '../../query.js';\n\nexport interface QueryOptions {\n dfs?: boolean;\n /** Approximate token cap for the printed context (default 2000). */\n budget?: number;\n}\n\n/** BFS (default) or DFS traversal answering a natural-language question against the graph. */\nexport async function runQuery(question: string, options: QueryOptions = {}): Promise<void> {\n const graph = await loadGraph();\n const result = queryGraph(graph, question, { dfs: options.dfs, tokenBudget: options.budget });\n\n if (result.seeds.length === 0) {\n console.log(\n `No nodes matched \"${question}\". Try different keywords, or run \\`graphify explain <node>\\` ` +\n 'if you already know the name.',\n );\n return;\n }\n\n console.log(`Matched ${result.seeds.length} seed node(s):`);\n for (const seed of result.seeds) {\n console.log(` - ${seed.label} (${seed.id})`);\n }\n\n console.log('');\n console.log(`Context — ${result.visited.length} node(s), ${options.dfs ? 'DFS' : 'BFS'} traversal:`);\n for (const node of result.visited) {\n const location = node.sourceLocation ? `:${node.sourceLocation}` : '';\n console.log(` [depth ${node.depth}] ${node.label} — ${node.sourceFile}${location}`);\n }\n\n console.log('');\n console.log(`Edges within this context (${result.edges.length}):`);\n for (const edge of result.edges) {\n console.log(` ${edge.source} --${edge.relation}--> ${edge.target} (${edge.confidence})`);\n }\n}\n"],"mappings":"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","names":["execFile","fs","os","path","promisify","readFile","fs","fs","fs","path","fs","path","fs","path","require","execFileAsync","promisify","execFile"]}
|