code-graph-llm 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -77
- package/index.js +91 -15
- package/llm-code-graph.md +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,97 +1,56 @@
|
|
|
1
1
|
# CODE-GRAPH
|
|
2
2
|
|
|
3
|
-
A language-agnostic, ultra-compact codebase mapper designed specifically for LLM agents to optimize context and token usage.
|
|
3
|
+
A language-agnostic, ultra-compact codebase mapper designed specifically for LLM agents to optimize context and token usage. It doesn't just list files; it provides a high-signal "map" of your project's architecture, including descriptions and signatures.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Features
|
|
6
|
+
- **Smart Context Extraction:** Captures JSDoc, Python docstrings, and preceding comments for files and symbols.
|
|
7
|
+
- **Signature Fallback:** Automatically extracts function signatures (parameters/types) if documentation is missing.
|
|
8
|
+
- **Compact & Dense:** Optimized for LLM token efficiency, replacing expensive recursive file scans.
|
|
9
|
+
- **Language-Agnostic:** Optimized regex support for JS/TS, Python, Go, Rust, Java, C#, C/C++, Swift, PHP, Ruby, Dart, and more.
|
|
10
|
+
- **Recursive Ignore Logic:** Deeply respects `.gitignore` and standard excludes (`node_modules`, `.git`).
|
|
11
|
+
- **Live Sync:** Continuous background updates or Git pre-commit hooks.
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
You can install **Code-Graph** globally or as a project-specific dependency without cloning the repository.
|
|
13
|
+
## Installation
|
|
9
14
|
|
|
10
|
-
|
|
15
|
+
### 1. Install via NPM
|
|
11
16
|
```bash
|
|
17
|
+
# Global installation for CLI use
|
|
12
18
|
npm install -g code-graph-llm
|
|
13
|
-
```
|
|
14
19
|
|
|
15
|
-
|
|
16
|
-
```bash
|
|
20
|
+
# Local project dependency
|
|
17
21
|
npm install --save-dev code-graph-llm
|
|
18
22
|
```
|
|
19
23
|
|
|
20
|
-
### 2.
|
|
21
|
-
Once installed, you can run it from any project directory:
|
|
24
|
+
### 2. Basic Usage
|
|
22
25
|
```bash
|
|
23
|
-
# Generate the map
|
|
26
|
+
# Generate the llm-code-graph.md map
|
|
24
27
|
code-graph generate
|
|
25
28
|
|
|
26
|
-
# Start the live watcher
|
|
29
|
+
# Start the live watcher for real-time updates
|
|
27
30
|
code-graph watch
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Usage in Different Workflows
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
If installed as a dependency, add it to your scripts:
|
|
34
|
-
```json
|
|
35
|
-
"scripts": {
|
|
36
|
-
"postinstall": "code-graph generate",
|
|
37
|
-
"pretest": "code-graph generate"
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
### 2. Git Integration
|
|
42
|
-
Automatically update and stage `llm-code-graph.md` on every commit:
|
|
43
|
-
```bash
|
|
32
|
+
# Install the Git pre-commit hook
|
|
44
33
|
code-graph install-hook
|
|
45
34
|
```
|
|
46
35
|
|
|
47
|
-
---
|
|
48
|
-
|
|
49
36
|
## LLM Usage & Token Efficiency
|
|
50
37
|
|
|
51
|
-
|
|
38
|
+
### The "Read First" Strategy
|
|
39
|
+
Instruct your LLM agent to read `llm-code-graph.md` as its first step. The file uses a dense format that provides immediate architectural context:
|
|
52
40
|
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
**Example Map Entry:**
|
|
42
|
+
```markdown
|
|
43
|
+
- src/auth.js | desc: Handles user authentication and JWT validation.
|
|
44
|
+
- syms: [login [ (username, password) ], validateToken [ (token: string) ]]
|
|
45
|
+
```
|
|
55
46
|
|
|
56
47
|
**Example System Prompt:**
|
|
57
|
-
> "Before
|
|
58
|
-
|
|
59
|
-
### 2. Targeted File Reads
|
|
60
|
-
The `|syms:[...]` metadata allows the LLM to identify exactly which file contains a specific function or class. It can jump directly to the relevant file.
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## Language Examples & Build Phase Integration
|
|
48
|
+
> "Before acting, read `llm-code-graph.md`. It contains the project map, file descriptions, and function signatures. Use this to locate relevant logic instead of scanning the full codebase."
|
|
65
49
|
|
|
66
|
-
|
|
67
|
-
```rust
|
|
68
|
-
use std::process::Command;
|
|
69
|
-
fn main() {
|
|
70
|
-
Command::new("code-graph").arg("generate").status().unwrap();
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### 2. Java/Kotlin (Maven/Gradle)
|
|
75
|
-
|
|
76
|
-
#### Maven (pom.xml)
|
|
77
|
-
```xml
|
|
78
|
-
<plugin>
|
|
79
|
-
<groupId>org.codehaus.mojo</groupId>
|
|
80
|
-
<artifactId>exec-maven-plugin</artifactId>
|
|
81
|
-
<executions>
|
|
82
|
-
<execution>
|
|
83
|
-
<phase>compile</phase>
|
|
84
|
-
<goals><goal>exec</goal></goals>
|
|
85
|
-
<configuration>
|
|
86
|
-
<executable>code-graph</executable>
|
|
87
|
-
<arguments><argument>generate</argument></arguments>
|
|
88
|
-
</configuration>
|
|
89
|
-
</execution>
|
|
90
|
-
</executions>
|
|
91
|
-
</plugin>
|
|
92
|
-
```
|
|
50
|
+
## Build Phase Integration
|
|
93
51
|
|
|
94
|
-
|
|
52
|
+
### 1. Java/Kotlin (Maven/Gradle)
|
|
53
|
+
**Gradle (Groovy):**
|
|
95
54
|
```groovy
|
|
96
55
|
task generateCodeGraph(type: Exec) {
|
|
97
56
|
commandLine 'code-graph', 'generate'
|
|
@@ -99,19 +58,31 @@ task generateCodeGraph(type: Exec) {
|
|
|
99
58
|
compileJava.dependsOn generateCodeGraph
|
|
100
59
|
```
|
|
101
60
|
|
|
102
|
-
###
|
|
103
|
-
|
|
61
|
+
### 2. Python
|
|
62
|
+
**Makefile:**
|
|
104
63
|
```makefile
|
|
105
64
|
map:
|
|
106
65
|
code-graph generate
|
|
66
|
+
test: map
|
|
67
|
+
pytest
|
|
107
68
|
```
|
|
108
69
|
|
|
109
|
-
|
|
70
|
+
### 3. Rust (build.rs)
|
|
71
|
+
```rust
|
|
72
|
+
use std::process::Command;
|
|
73
|
+
fn main() {
|
|
74
|
+
Command::new("code-graph").arg("generate").status().unwrap();
|
|
75
|
+
}
|
|
76
|
+
```
|
|
110
77
|
|
|
111
78
|
## How it works
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
79
|
+
1. **File Scanning:** Recursively walks the directory, ignoring patterns in `.gitignore`.
|
|
80
|
+
2. **Context Extraction:** Scans for classes, functions, and variables.
|
|
81
|
+
3. **Docstring Capture:** If a symbol has a preceding comment (`//`, `/**`, `#`, `"""`), it's captured as a description.
|
|
82
|
+
4. **Signature Capture:** If no comment is found, it captures the declaration signature (parameters) as a fallback.
|
|
83
|
+
5. **Compilation:** Writes a single, minified `llm-code-graph.md` file designed for machine consumption.
|
|
84
|
+
|
|
85
|
+
## Publishing as a Package
|
|
86
|
+
To share your own version:
|
|
87
|
+
1. `npm login`
|
|
88
|
+
2. `npm publish --access public`
|
package/index.js
CHANGED
|
@@ -13,14 +13,38 @@ const IGNORE_FILE = '.gitignore';
|
|
|
13
13
|
const DEFAULT_MAP_FILE = 'llm-code-graph.md';
|
|
14
14
|
|
|
15
15
|
const SYMBOL_REGEXES = [
|
|
16
|
-
|
|
17
|
-
/\b(?:
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
// Types, Classes, Interfaces, and Containers (Universal)
|
|
17
|
+
/\b(?:class|interface|type|struct|enum|protocol|extension|trait|module|namespace|object)\s+([a-zA-Z_]\w*)/g,
|
|
18
|
+
|
|
19
|
+
// Explicit Function Keywords (JS, Python, Go, Rust, Ruby, PHP, Swift, Kotlin, Dart)
|
|
20
|
+
/\b(?:function|def|fn|func|fun|method|procedure|sub|routine)\s+([a-zA-Z_]\w*)/g,
|
|
21
|
+
|
|
22
|
+
// C-style / Java / C# / TypeScript Method Patterns
|
|
23
|
+
// Matches: ReturnType Name(...) or AccessModifier Name(...)
|
|
24
|
+
/\b(?:void|async|public|private|protected|static|virtual|override|readonly|int|float|double|char|bool|string|val|var|let|const|final)\s+([a-zA-Z_]\w*)(?=\s*\(|(?:\s*:\s*\w+)?\s*=>)/g,
|
|
25
|
+
|
|
26
|
+
// Exported symbols (JS/TS specific but captures named exports)
|
|
27
|
+
/\bexport\s+(?:default\s+)?(?:const|let|var|function|class|type|interface|enum|async|val)\s+([a-zA-Z_]\w*)/g,
|
|
28
|
+
|
|
29
|
+
// Ruby: def name, class Name, module Name (defs covered by Explicit Function Keywords)
|
|
30
|
+
|
|
31
|
+
// PHP: class Name, interface Name, trait Name, function Name
|
|
32
|
+
|
|
33
|
+
// Swift: func name, class Name, struct Name, protocol Name, extension Name
|
|
34
|
+
|
|
35
|
+
// Dart: class Name, void name, var name (void/var covered by C-style pattern)
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const SUPPORTED_EXTENSIONS = [
|
|
39
|
+
'.js', '.ts', '.jsx', '.tsx',
|
|
40
|
+
'.py', '.go', '.rs', '.java',
|
|
41
|
+
'.cpp', '.c', '.h', '.hpp', '.cc',
|
|
42
|
+
'.rb', '.php', '.swift', '.kt',
|
|
43
|
+
'.cs', '.dart', '.scala', '.m', '.mm'
|
|
20
44
|
];
|
|
21
45
|
|
|
22
46
|
function getIgnores(cwd) {
|
|
23
|
-
const ig = ignore().add(['.git', 'node_modules', DEFAULT_MAP_FILE]);
|
|
47
|
+
const ig = ignore().add(['.git', 'node_modules', DEFAULT_MAP_FILE, 'package-lock.json']);
|
|
24
48
|
const ignorePath = path.join(cwd, IGNORE_FILE);
|
|
25
49
|
if (fs.existsSync(ignorePath)) {
|
|
26
50
|
ig.add(fs.readFileSync(ignorePath, 'utf8'));
|
|
@@ -29,14 +53,46 @@ function getIgnores(cwd) {
|
|
|
29
53
|
}
|
|
30
54
|
|
|
31
55
|
function extractSymbols(content) {
|
|
32
|
-
const symbols =
|
|
56
|
+
const symbols = [];
|
|
33
57
|
for (const regex of SYMBOL_REGEXES) {
|
|
34
58
|
let match;
|
|
59
|
+
regex.lastIndex = 0;
|
|
35
60
|
while ((match = regex.exec(content)) !== null) {
|
|
36
|
-
if (match[1])
|
|
61
|
+
if (match[1]) {
|
|
62
|
+
const symbolName = match[1];
|
|
63
|
+
if (['if', 'for', 'while', 'switch', 'return', 'await', 'yield'].includes(symbolName)) continue;
|
|
64
|
+
|
|
65
|
+
// 1. Extract preceding comment/docstring
|
|
66
|
+
const linesBefore = content.substring(0, match.index).split('\n');
|
|
67
|
+
let comment = '';
|
|
68
|
+
for (let i = linesBefore.length - 1; i >= 0; i--) {
|
|
69
|
+
const line = linesBefore[i].trim();
|
|
70
|
+
if (line.startsWith('//') || line.startsWith('*') || line.startsWith('"""') || line.startsWith('#')) {
|
|
71
|
+
const clean = line.replace(/[\/*#"]/g, '').trim();
|
|
72
|
+
if (clean) comment = clean + (comment ? ' ' + comment : '');
|
|
73
|
+
if (comment.length > 80) break;
|
|
74
|
+
} else if (line === '' && comment === '') {
|
|
75
|
+
continue;
|
|
76
|
+
} else {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 2. Backup: Extract Signature (Parameters/Type) if no comment
|
|
82
|
+
let context = comment;
|
|
83
|
+
if (!context) {
|
|
84
|
+
const remainingLine = content.substring(match.index + match[0].length).split('\n')[0];
|
|
85
|
+
const sigMatch = remainingLine.match(/^[^:{;]*/);
|
|
86
|
+
if (sigMatch && sigMatch[0].trim()) {
|
|
87
|
+
context = sigMatch[0].trim();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
symbols.push(context ? `${symbolName} [${context}]` : symbolName);
|
|
92
|
+
}
|
|
37
93
|
}
|
|
38
94
|
}
|
|
39
|
-
return Array.from(symbols).sort();
|
|
95
|
+
return Array.from(new Set(symbols)).sort();
|
|
40
96
|
}
|
|
41
97
|
|
|
42
98
|
async function generate(cwd = process.cwd()) {
|
|
@@ -47,20 +103,39 @@ async function generate(cwd = process.cwd()) {
|
|
|
47
103
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
48
104
|
for (const entry of entries) {
|
|
49
105
|
const fullPath = path.join(dir, entry.name);
|
|
50
|
-
|
|
106
|
+
let relativePath = path.relative(cwd, fullPath);
|
|
107
|
+
const normalizedPath = relativePath.replace(/\\/g, '/');
|
|
108
|
+
const checkPath = entry.isDirectory() ? `${normalizedPath}/` : normalizedPath;
|
|
51
109
|
|
|
52
|
-
if (ig.ignores(
|
|
110
|
+
if (ig.ignores(checkPath)) continue;
|
|
53
111
|
|
|
54
112
|
if (entry.isDirectory()) {
|
|
55
113
|
walk(fullPath);
|
|
56
114
|
} else if (entry.isFile()) {
|
|
57
115
|
const ext = path.extname(entry.name);
|
|
58
|
-
if (
|
|
116
|
+
if (SUPPORTED_EXTENSIONS.includes(ext)) {
|
|
59
117
|
const content = fs.readFileSync(fullPath, 'utf8');
|
|
118
|
+
|
|
119
|
+
// Extract file-level description
|
|
120
|
+
const firstLines = content.split('\n').slice(0, 5);
|
|
121
|
+
let fileDesc = '';
|
|
122
|
+
for (const line of firstLines) {
|
|
123
|
+
const trimmed = line.trim();
|
|
124
|
+
if (trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*')) {
|
|
125
|
+
fileDesc += trimmed.replace(/[\/*#]/g, '').trim() + ' ';
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
60
129
|
const symbols = extractSymbols(content);
|
|
61
|
-
|
|
130
|
+
|
|
131
|
+
// Backup: If no file description, provide a summary
|
|
132
|
+
if (!fileDesc.trim() && symbols.length > 0) {
|
|
133
|
+
fileDesc = `Contains ${symbols.length} symbols.`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
files.push({ path: normalizedPath, desc: fileDesc.trim(), symbols });
|
|
62
137
|
} else {
|
|
63
|
-
files.push({ path:
|
|
138
|
+
files.push({ path: normalizedPath, desc: '', symbols: [] });
|
|
64
139
|
}
|
|
65
140
|
}
|
|
66
141
|
}
|
|
@@ -69,8 +144,9 @@ async function generate(cwd = process.cwd()) {
|
|
|
69
144
|
walk(cwd);
|
|
70
145
|
|
|
71
146
|
const output = files.map(f => {
|
|
72
|
-
const
|
|
73
|
-
|
|
147
|
+
const descStr = f.desc ? ` | desc: ${f.desc.substring(0, 100)}` : '';
|
|
148
|
+
const symStr = f.symbols.length > 0 ? `\n - syms: [${f.symbols.join(', ')}]` : '';
|
|
149
|
+
return `- ${f.path}${descStr}${symStr}`;
|
|
74
150
|
}).join('\n');
|
|
75
151
|
|
|
76
152
|
const header = `# CODE_GRAPH_MAP\n> LLM_ONLY: DO NOT EDIT. COMPACT PROJECT MAP.\n\n`;
|
package/llm-code-graph.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
> LLM_ONLY: DO NOT EDIT. COMPACT PROJECT MAP.
|
|
3
3
|
|
|
4
4
|
- .gitignore
|
|
5
|
-
- index.js|
|
|
6
|
-
-
|
|
5
|
+
- index.js | desc: !usrbinenv node
|
|
6
|
+
- syms: [Name [Dart:], Name [PHP: class Name, interface Name, trait Name,], Name [PHP: class Name, interface Name,], Name [PHP: class Name,], Name [PHP:], Name [Ruby: def name, class Name,], Name [Ruby: def name,], Name [Swift: func name, class Name, struct Name, protocol Name,], Name [Swift: func name, class Name, struct Name,], Name [Swift: func name, class Name,], Name [Swift: func name,], extractSymbols [(content)], generate [(cwd = process.cwd())], getIgnores [(cwd)], installHook [(cwd = process.cwd())], name [Dart: class Name, void name,], name [Ruby:], name [Swift:], walk [(dir)], watch [(cwd = process.cwd())]]
|
|
7
7
|
- package.json
|
|
8
8
|
- README.md
|