@dreamtree-org/graphify 1.0.0 → 1.1.1
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 +106 -35
- package/dist/chunk-6JLEILYF.js +207 -0
- package/dist/chunk-6JLEILYF.js.map +1 -0
- package/dist/{chunk-DG5FECXV.js → chunk-EW23BLJC.js} +557 -27
- package/dist/chunk-EW23BLJC.js.map +1 -0
- package/dist/chunk-YT7B6DOD.js +554 -0
- package/dist/chunk-YT7B6DOD.js.map +1 -0
- package/dist/chunk-ZPB37LLQ.js +155 -0
- package/dist/chunk-ZPB37LLQ.js.map +1 -0
- package/dist/cli/index.cjs +1939 -143
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +683 -40
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1131 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +333 -5
- package/dist/index.d.ts +333 -5
- package/dist/index.js +50 -5
- package/dist/mcp/server.cjs +444 -56
- package/dist/mcp/server.cjs.map +1 -1
- package/dist/mcp/server.js +65 -4
- package/dist/mcp/server.js.map +1 -1
- package/dist/mysql-EJ6XOWR4.js +8 -0
- package/dist/mysql-EJ6XOWR4.js.map +1 -0
- package/package.json +2 -1
- package/src/skill/SKILL.md +45 -10
- package/dist/chunk-5ANIDX3G.js +0 -364
- package/dist/chunk-5ANIDX3G.js.map +0 -1
- package/dist/chunk-DG5FECXV.js.map +0 -1
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/commands/explain.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 { validateUrl } from '../security.js';\nimport { runExplain } from './commands/explain.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}\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 re-extract of changed files only (not implemented in v1 — runs full pipeline)')\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 .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.update) {\n console.error(\n '--update (incremental re-extract) is not implemented yet in v1 — running the full pipeline instead.',\n );\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 const runOnce = () =>\n runPipeline(root, {\n ...exportOptionsFrom(options),\n ...clusterOptionsFrom(options),\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('install')\n .description('install the skill files into the local agent(s)')\n .action(async () => {\n try {\n await runInstall();\n } catch (error) {\n console.error(`graphify install: ${(error as Error).message}`);\n process.exitCode = 1;\n }\n });\n\nprogram.parseAsync(process.argv);\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 const location = result.sourceLocation ? `:${result.sourceLocation}` : '';\n console.log(result.label);\n console.log(` location: ${result.sourceFile}${location}`);\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 { 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/**\n * Copy SKILL.md into the local agent's skill directory. Claude Code only\n * for v1 (project-local `.claude/skills/graphify/SKILL.md`) — other hosts\n * (Cursor, etc.) are a clearly-flagged follow-up, not faked with an empty\n * or copy-pasted file.\n */\nexport async function runInstall(cwd: string = process.cwd()): Promise<InstallResult[]> {\n const sourcePath = path.join(packageRoot(), 'src', 'skill', 'SKILL.md');\n const content = await fs.readFile(sourcePath, 'utf-8');\n\n const results: InstallResult[] = [];\n\n const claudeCodeDir = path.join(cwd, '.claude', 'skills', 'graphify');\n await fs.mkdir(claudeCodeDir, { recursive: true });\n const claudeCodePath = path.join(claudeCodeDir, 'SKILL.md');\n await fs.writeFile(claudeCodePath, content, 'utf-8');\n results.push({ host: 'Claude Code', path: claudeCodePath });\n\n for (const result of results) {\n console.log(`Installed graphify skill for ${result.host} -> ${result.path}`);\n }\n console.log('');\n console.log(\n 'Other hosts (Cursor, etc.) are not implemented yet by `graphify install` — see ARCHITECTURE.md.',\n );\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 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, budget: 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":["fs","path","require"]}
|
|
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 location = node.sourceLocation ? `:${node.sourceLocation}` : '';\n console.log(\n ` ${node.label} — ${node.sourceFile}${location} ` +\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';\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/** Default questions when none are given: the labels of the highest-degree (most load-bearing) nodes. */\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 }))\n // File nodes score high on degree but make poor questions — prefer entities.\n .filter((e) => e.id.includes('::'))\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 const location = result.sourceLocation ? `:${result.sourceLocation}` : '';\n console.log(result.label);\n console.log(` location: ${result.sourceFile}${location}`);\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 console.log(`Test files for ${selection.target} (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"]}
|