@kentwynn/kgraph 0.1.0 → 0.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 +98 -124
- package/dist/cli/commands/init.js +20 -1
- package/dist/cli/commands/integrate.d.ts +2 -0
- package/dist/cli/commands/integrate.js +36 -0
- package/dist/cli/index.js +2 -0
- package/dist/config/config.d.ts +1 -0
- package/dist/config/config.js +35 -2
- package/dist/integrations/adapters/claude-code.d.ts +2 -0
- package/dist/integrations/adapters/claude-code.js +13 -0
- package/dist/integrations/adapters/codex.d.ts +2 -0
- package/dist/integrations/adapters/codex.js +13 -0
- package/dist/integrations/adapters/copilot.d.ts +2 -0
- package/dist/integrations/adapters/copilot.js +13 -0
- package/dist/integrations/adapters/cursor.d.ts +2 -0
- package/dist/integrations/adapters/cursor.js +18 -0
- package/dist/integrations/instruction-blocks.d.ts +2 -0
- package/dist/integrations/instruction-blocks.js +27 -0
- package/dist/integrations/integration-registry.d.ts +10 -0
- package/dist/integrations/integration-registry.js +39 -0
- package/dist/integrations/integration-store.d.ts +10 -0
- package/dist/integrations/integration-store.js +68 -0
- package/dist/types/config.d.ts +7 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,200 +1,174 @@
|
|
|
1
1
|
# KGraph
|
|
2
2
|
|
|
3
|
-
Persistent
|
|
3
|
+
Persistent repository intelligence for AI coding tools.
|
|
4
4
|
|
|
5
|
-
KGraph is a local-first CLI
|
|
5
|
+
KGraph is a local-first CLI that builds an inspectable knowledge layer for a codebase. It helps tools like Codex, GitHub Copilot, Cursor, and Claude Code reuse repository structure, workflow knowledge, debugging history, and architecture decisions instead of rediscovering them in every chat.
|
|
6
6
|
|
|
7
|
-
## Why
|
|
7
|
+
## Why It Matters
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
AI coding sessions spend a large part of their budget finding context: reading files, tracing imports, locating the right functions, and re-learning decisions that were already discovered in previous work.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- rediscovering the same architecture
|
|
13
|
-
- re-inferring the same workflows
|
|
14
|
-
- repeating prior debugging conclusions
|
|
15
|
-
- spending tokens just to find the right place to work
|
|
11
|
+
KGraph turns that repeated exploration into durable repository intelligence:
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- persistent repo cognition
|
|
24
|
-
- semantic navigation infrastructure
|
|
25
|
-
- a context engineering layer
|
|
26
|
-
- local filesystem-based project intelligence
|
|
27
|
-
- an inspectable map of structure, relationships, and durable notes
|
|
28
|
-
|
|
29
|
-
KGraph is not:
|
|
13
|
+
```text
|
|
14
|
+
AI chat or developer note
|
|
15
|
+
-> KGraph cognition inbox
|
|
16
|
+
-> structured repo knowledge
|
|
17
|
+
-> compact context for future AI sessions
|
|
18
|
+
```
|
|
30
19
|
|
|
31
|
-
|
|
32
|
-
- a chatbot
|
|
33
|
-
- a vector database
|
|
34
|
-
- a simple RAG wrapper
|
|
35
|
-
- a cloud service
|
|
36
|
-
- an autonomous agent system
|
|
20
|
+
The result is faster navigation, lower token waste, and more consistent understanding across coding sessions.
|
|
37
21
|
|
|
38
|
-
## Install
|
|
22
|
+
## Install
|
|
39
23
|
|
|
40
|
-
|
|
24
|
+
Run the latest published package:
|
|
41
25
|
|
|
42
|
-
|
|
26
|
+
```bash
|
|
27
|
+
npx @kentwynn/kgraph@latest init
|
|
28
|
+
```
|
|
43
29
|
|
|
44
|
-
|
|
30
|
+
Run a specific stable version:
|
|
45
31
|
|
|
46
32
|
```bash
|
|
47
33
|
npx @kentwynn/kgraph@0.1.0 init
|
|
48
34
|
```
|
|
49
35
|
|
|
50
|
-
|
|
36
|
+
Install globally if you use KGraph often:
|
|
51
37
|
|
|
52
38
|
```bash
|
|
53
|
-
|
|
39
|
+
npm install -g @kentwynn/kgraph@latest
|
|
40
|
+
kgraph --version
|
|
54
41
|
```
|
|
55
42
|
|
|
56
|
-
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
Initialize KGraph in a repository and connect your AI tools:
|
|
57
46
|
|
|
58
47
|
```bash
|
|
59
|
-
|
|
60
|
-
npx @kentwynn/kgraph@latest update
|
|
61
|
-
npx @kentwynn/kgraph@latest context "auth token refresh"
|
|
48
|
+
kgraph init --integrations codex,copilot,cursor
|
|
62
49
|
```
|
|
63
50
|
|
|
64
|
-
|
|
51
|
+
Scan the codebase:
|
|
65
52
|
|
|
66
53
|
```bash
|
|
67
|
-
npm install -g @kentwynn/kgraph@latest
|
|
68
|
-
kgraph --version
|
|
69
|
-
kgraph init
|
|
70
54
|
kgraph scan
|
|
71
|
-
kgraph update
|
|
72
|
-
kgraph context "auth token refresh"
|
|
73
55
|
```
|
|
74
56
|
|
|
75
|
-
|
|
57
|
+
Ask for compact context before working on an area:
|
|
76
58
|
|
|
77
59
|
```bash
|
|
78
|
-
|
|
79
|
-
npm run build
|
|
80
|
-
npm run kgraph -- --version
|
|
81
|
-
npm run kgraph -- init
|
|
82
|
-
npm run kgraph -- scan
|
|
83
|
-
npm run kgraph -- update
|
|
84
|
-
npm run kgraph -- context "auth token refresh"
|
|
60
|
+
kgraph context "auth token refresh"
|
|
85
61
|
```
|
|
86
62
|
|
|
87
|
-
|
|
63
|
+
Process saved chat notes and debugging conclusions:
|
|
88
64
|
|
|
89
|
-
|
|
65
|
+
```bash
|
|
66
|
+
kgraph update
|
|
67
|
+
```
|
|
90
68
|
|
|
91
|
-
|
|
69
|
+
## CLI
|
|
92
70
|
|
|
93
71
|
```bash
|
|
94
72
|
kgraph init
|
|
73
|
+
kgraph init --integrations codex,cursor
|
|
74
|
+
kgraph integrate list
|
|
75
|
+
kgraph integrate add codex copilot cursor claude-code
|
|
76
|
+
kgraph integrate remove cursor
|
|
95
77
|
kgraph scan
|
|
96
78
|
kgraph update
|
|
97
79
|
kgraph context "auth token refresh"
|
|
80
|
+
kgraph context "auth token refresh" --json
|
|
98
81
|
```
|
|
99
82
|
|
|
100
|
-
|
|
83
|
+
## AI Tool Integrations
|
|
101
84
|
|
|
102
|
-
|
|
85
|
+
KGraph writes local instruction files so AI tools know how to use the repository knowledge layer during normal coding chats.
|
|
103
86
|
|
|
104
|
-
|
|
87
|
+
| Integration | Instruction file |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| Codex | `AGENTS.md` |
|
|
90
|
+
| GitHub Copilot | `.github/copilot-instructions.md` |
|
|
91
|
+
| Cursor | `.cursor/rules/kgraph.mdc` |
|
|
92
|
+
| Claude Code | `CLAUDE.md` |
|
|
105
93
|
|
|
106
|
-
|
|
94
|
+
Example:
|
|
107
95
|
|
|
108
|
-
|
|
96
|
+
```bash
|
|
97
|
+
kgraph integrate add codex cursor
|
|
98
|
+
kgraph integrate list
|
|
99
|
+
```
|
|
109
100
|
|
|
110
|
-
|
|
111
|
-
- telemetry
|
|
112
|
-
- cloud infrastructure
|
|
113
|
-
- hosted services
|
|
114
|
-
- databases
|
|
115
|
-
- LLM providers
|
|
116
|
-
- embeddings
|
|
117
|
-
- vector search
|
|
118
|
-
- background daemons
|
|
101
|
+
Generated instructions teach AI tools to:
|
|
119
102
|
|
|
120
|
-
|
|
103
|
+
- query `kgraph context "<topic>"` before broad repo exploration
|
|
104
|
+
- save useful architecture, workflow, and debugging discoveries to `.kgraph/inbox/`
|
|
105
|
+
- run `kgraph update` to turn notes into durable cognition
|
|
106
|
+
- run `kgraph scan` after refactors, file moves, or renamed functions
|
|
121
107
|
|
|
122
|
-
|
|
108
|
+
KGraph-managed instruction blocks preserve existing user-authored content.
|
|
123
109
|
|
|
124
|
-
|
|
110
|
+
## Features
|
|
125
111
|
|
|
126
|
-
-
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
-
|
|
112
|
+
- Local `.kgraph/` workspace for repository intelligence
|
|
113
|
+
- JavaScript and TypeScript file, import, export, function, class, and method maps
|
|
114
|
+
- Deterministic relationship maps between files and symbols
|
|
115
|
+
- Markdown cognition inbox for AI chat summaries, decisions, gotchas, and debugging notes
|
|
116
|
+
- Compact context output for AI assistants and scripts
|
|
117
|
+
- JSON output for tool-friendly context retrieval
|
|
118
|
+
- Integration management for Codex, Copilot, Cursor, and Claude Code
|
|
119
|
+
- Stale-reference handling when code changes over time
|
|
120
|
+
- Local-first storage with human-readable JSON, YAML, and Markdown
|
|
133
121
|
|
|
134
|
-
|
|
122
|
+
## How KGraph Grows
|
|
135
123
|
|
|
136
|
-
|
|
137
|
-
- deployment
|
|
138
|
-
- cloud infrastructure
|
|
139
|
-
- hosted dashboards
|
|
140
|
-
- graph databases
|
|
141
|
-
- vector databases
|
|
142
|
-
- embeddings
|
|
143
|
-
- autonomous agents
|
|
144
|
-
- VS Code extension
|
|
124
|
+
KGraph is designed to improve as the project changes:
|
|
145
125
|
|
|
146
|
-
|
|
126
|
+
```text
|
|
127
|
+
kgraph scan
|
|
128
|
+
refreshes current structure
|
|
147
129
|
|
|
148
|
-
|
|
130
|
+
AI chat or developer note
|
|
131
|
+
captures useful reasoning in .kgraph/inbox/
|
|
149
132
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
npm run build
|
|
153
|
-
npm test
|
|
154
|
-
npm pack --dry-run
|
|
155
|
-
npm run check:artifacts
|
|
156
|
-
```
|
|
133
|
+
kgraph update
|
|
134
|
+
converts notes into durable cognition
|
|
157
135
|
|
|
158
|
-
|
|
136
|
+
kgraph context "<topic>"
|
|
137
|
+
returns focused repository context for future work
|
|
138
|
+
```
|
|
159
139
|
|
|
160
|
-
-
|
|
161
|
-
- `.specify/`
|
|
162
|
-
- `.agents/`
|
|
163
|
-
- `AGENTS.md`
|
|
164
|
-
- `REQUIREMENTS.md`
|
|
165
|
-
- `specs/`
|
|
140
|
+
This creates a feedback loop where normal development and AI-assisted debugging gradually improve the repository knowledge map.
|
|
166
141
|
|
|
167
|
-
##
|
|
142
|
+
## Local-First
|
|
168
143
|
|
|
169
|
-
|
|
144
|
+
KGraph stores project intelligence in local files inside `.kgraph/`. The MVP does not require accounts, telemetry, hosted services, databases, model providers, embeddings, or background daemons.
|
|
170
145
|
|
|
171
|
-
|
|
146
|
+
## Development
|
|
172
147
|
|
|
173
148
|
```bash
|
|
174
|
-
npm
|
|
149
|
+
npm install
|
|
175
150
|
npm run build
|
|
176
151
|
npm test
|
|
177
|
-
npm run
|
|
178
|
-
npm pack
|
|
152
|
+
npm run kgraph -- init --integrations codex,cursor
|
|
179
153
|
```
|
|
180
154
|
|
|
181
|
-
|
|
155
|
+
## Release
|
|
182
156
|
|
|
183
|
-
|
|
157
|
+
CI runs build, tests, package checks, and generated-artifact hygiene on pushes and pull requests.
|
|
184
158
|
|
|
185
|
-
|
|
159
|
+
Releases are tag-driven. Bump the package version, push the commit, then push the matching tag:
|
|
186
160
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
- make package publishing safe and intentional
|
|
161
|
+
```bash
|
|
162
|
+
npm version patch
|
|
163
|
+
git push origin main --follow-tags
|
|
164
|
+
```
|
|
192
165
|
|
|
193
|
-
|
|
166
|
+
The release workflow verifies that the tag matches `package.json`, checks that the npm version has not already been published, publishes the package to npm, creates a GitHub Release, and attaches the packed tarball. Manual workflow runs package the project for inspection but do not publish to npm.
|
|
167
|
+
|
|
168
|
+
## Roadmap
|
|
194
169
|
|
|
195
170
|
- richer language scanners
|
|
171
|
+
- better cognition extraction
|
|
172
|
+
- graph visualization
|
|
196
173
|
- Git-aware history and rename detection
|
|
197
|
-
- optional MCP
|
|
198
|
-
- optional editor integrations
|
|
199
|
-
- visual graph exploration
|
|
200
|
-
- optional LLM-assisted cognition extraction
|
|
174
|
+
- optional editor and MCP integrations
|
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
import { writeDefaultConfig } from "../../config/config.js";
|
|
2
|
+
import { normalizeIntegrationNames } from "../../integrations/integration-registry.js";
|
|
3
|
+
import { addIntegrations } from "../../integrations/integration-store.js";
|
|
2
4
|
import { ensureWorkspace } from "../../storage/kgraph-paths.js";
|
|
3
5
|
import { runCommand } from "../errors.js";
|
|
4
6
|
export function registerInitCommand(program) {
|
|
5
|
-
program
|
|
7
|
+
program
|
|
8
|
+
.command("init")
|
|
9
|
+
.description("Initialize a .kgraph workspace")
|
|
10
|
+
.option("--integration <name>", "Configure an AI tool integration", collectOption, [])
|
|
11
|
+
.option("--integrations <names>", "Configure comma-separated AI tool integrations")
|
|
12
|
+
.action((options) => runCommand(async () => {
|
|
6
13
|
const workspace = await ensureWorkspace(process.cwd());
|
|
7
14
|
const wroteConfig = await writeDefaultConfig(workspace);
|
|
8
15
|
console.log(wroteConfig ? "Initialized .kgraph workspace." : ".kgraph workspace already initialized.");
|
|
16
|
+
const names = normalizeIntegrationNames([
|
|
17
|
+
...(options.integration ?? []),
|
|
18
|
+
...(options.integrations ? [options.integrations] : [])
|
|
19
|
+
]);
|
|
20
|
+
if (names.length > 0) {
|
|
21
|
+
const changed = await addIntegrations(workspace, names);
|
|
22
|
+
console.log(`Configured integrations: ${changed.map((item) => item.name).join(", ")}`);
|
|
23
|
+
}
|
|
9
24
|
}));
|
|
10
25
|
}
|
|
26
|
+
function collectOption(value, previous) {
|
|
27
|
+
previous.push(value);
|
|
28
|
+
return previous;
|
|
29
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { addIntegrations, listIntegrations, removeIntegrations } from "../../integrations/integration-store.js";
|
|
2
|
+
import { normalizeIntegrationNames } from "../../integrations/integration-registry.js";
|
|
3
|
+
import { assertWorkspace } from "../../storage/kgraph-paths.js";
|
|
4
|
+
import { KGraphError, runCommand } from "../errors.js";
|
|
5
|
+
export function registerIntegrateCommand(program) {
|
|
6
|
+
const integrate = program.command("integrate").description("Manage AI tool integrations");
|
|
7
|
+
integrate.command("list").description("List configured integrations").action(() => runCommand(async () => {
|
|
8
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
9
|
+
const integrations = await listIntegrations(workspace);
|
|
10
|
+
if (integrations.length === 0) {
|
|
11
|
+
console.log("No integrations configured.");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
for (const integration of integrations) {
|
|
15
|
+
console.log(`${integration.name} ${integration.enabled ? "enabled" : "disabled"} ${integration.targetPath} ${integration.targetExists ? "present" : "missing"}`);
|
|
16
|
+
}
|
|
17
|
+
}));
|
|
18
|
+
integrate.command("add").description("Add AI tool integrations").argument("<names...>").action((names) => runCommand(async () => {
|
|
19
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
20
|
+
const normalized = normalizeIntegrationNames(names);
|
|
21
|
+
if (normalized.length === 0) {
|
|
22
|
+
throw new KGraphError("Provide at least one integration name.");
|
|
23
|
+
}
|
|
24
|
+
const changed = await addIntegrations(workspace, normalized);
|
|
25
|
+
console.log(`Configured integrations: ${changed.map((item) => item.name).join(", ")}`);
|
|
26
|
+
}));
|
|
27
|
+
integrate.command("remove").description("Remove AI tool integrations").argument("<names...>").action((names) => runCommand(async () => {
|
|
28
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
29
|
+
const normalized = normalizeIntegrationNames(names);
|
|
30
|
+
if (normalized.length === 0) {
|
|
31
|
+
throw new KGraphError("Provide at least one integration name.");
|
|
32
|
+
}
|
|
33
|
+
const removed = await removeIntegrations(workspace, normalized);
|
|
34
|
+
console.log(`Removed integrations: ${removed.join(", ")}`);
|
|
35
|
+
}));
|
|
36
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import { registerInitCommand } from "./commands/init.js";
|
|
|
4
4
|
import { registerScanCommand } from "./commands/scan.js";
|
|
5
5
|
import { registerUpdateCommand } from "./commands/update.js";
|
|
6
6
|
import { registerContextCommand } from "./commands/context.js";
|
|
7
|
+
import { registerIntegrateCommand } from "./commands/integrate.js";
|
|
7
8
|
export function createProgram() {
|
|
8
9
|
const program = new Command();
|
|
9
10
|
program
|
|
@@ -14,6 +15,7 @@ export function createProgram() {
|
|
|
14
15
|
registerScanCommand(program);
|
|
15
16
|
registerUpdateCommand(program);
|
|
16
17
|
registerContextCommand(program);
|
|
18
|
+
registerIntegrateCommand(program);
|
|
17
19
|
return program;
|
|
18
20
|
}
|
|
19
21
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
package/dist/config/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { KGraphConfig, KGraphWorkspace } from "../types/config.js";
|
|
2
2
|
export declare const DEFAULT_CONFIG: KGraphConfig;
|
|
3
3
|
export declare function writeDefaultConfig(workspace: KGraphWorkspace): Promise<boolean>;
|
|
4
|
+
export declare function saveConfig(workspace: KGraphWorkspace, config: KGraphConfig): Promise<void>;
|
|
4
5
|
export declare function loadConfig(workspace: KGraphWorkspace): Promise<KGraphConfig>;
|
|
5
6
|
export declare function normalizeConfig(config: Partial<KGraphConfig>): KGraphConfig;
|
package/dist/config/config.js
CHANGED
|
@@ -9,7 +9,8 @@ export const DEFAULT_CONFIG = {
|
|
|
9
9
|
precise: [".js", ".jsx", ".ts", ".tsx"]
|
|
10
10
|
},
|
|
11
11
|
maxContextItems: 8,
|
|
12
|
-
domainHints: {}
|
|
12
|
+
domainHints: {},
|
|
13
|
+
integrations: []
|
|
13
14
|
};
|
|
14
15
|
export async function writeDefaultConfig(workspace) {
|
|
15
16
|
if (await pathExists(workspace.configPath)) {
|
|
@@ -18,6 +19,9 @@ export async function writeDefaultConfig(workspace) {
|
|
|
18
19
|
await writeFile(workspace.configPath, YAML.stringify(DEFAULT_CONFIG), "utf8");
|
|
19
20
|
return true;
|
|
20
21
|
}
|
|
22
|
+
export async function saveConfig(workspace, config) {
|
|
23
|
+
await writeFile(workspace.configPath, YAML.stringify(config), "utf8");
|
|
24
|
+
}
|
|
21
25
|
export async function loadConfig(workspace) {
|
|
22
26
|
if (!(await pathExists(workspace.configPath))) {
|
|
23
27
|
return DEFAULT_CONFIG;
|
|
@@ -44,6 +48,35 @@ export function normalizeConfig(config) {
|
|
|
44
48
|
maxContextItems: typeof config.maxContextItems === "number" && config.maxContextItems > 0
|
|
45
49
|
? config.maxContextItems
|
|
46
50
|
: DEFAULT_CONFIG.maxContextItems,
|
|
47
|
-
domainHints: config.domainHints && typeof config.domainHints === "object" ? config.domainHints : {}
|
|
51
|
+
domainHints: config.domainHints && typeof config.domainHints === "object" ? config.domainHints : {},
|
|
52
|
+
integrations: normalizeIntegrations(config.integrations)
|
|
48
53
|
};
|
|
49
54
|
}
|
|
55
|
+
function normalizeIntegrations(value) {
|
|
56
|
+
if (!Array.isArray(value)) {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
const seen = new Set();
|
|
60
|
+
const integrations = [];
|
|
61
|
+
for (const item of value) {
|
|
62
|
+
if (!item || typeof item !== "object") {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const candidate = item;
|
|
66
|
+
if (typeof candidate.name !== "string" ||
|
|
67
|
+
typeof candidate.targetPath !== "string" ||
|
|
68
|
+
seen.has(candidate.name)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (!["claude-code", "codex", "copilot", "cursor"].includes(candidate.name)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
seen.add(candidate.name);
|
|
75
|
+
integrations.push({
|
|
76
|
+
name: candidate.name,
|
|
77
|
+
enabled: candidate.enabled !== false,
|
|
78
|
+
targetPath: candidate.targetPath
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return integrations;
|
|
82
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const claudeCodeAdapter = {
|
|
2
|
+
name: "claude-code",
|
|
3
|
+
label: "Claude Code",
|
|
4
|
+
targetPath: "CLAUDE.md",
|
|
5
|
+
instructions: `## KGraph Workflow
|
|
6
|
+
|
|
7
|
+
- Start repository work by checking \`kgraph context "<topic>"\` when the user asks about a domain, bug, workflow, or feature.
|
|
8
|
+
- Convert stable discoveries from chat into Markdown notes under \`.kgraph/inbox/\`.
|
|
9
|
+
- Run \`kgraph update\` to preserve those notes as durable cognition.
|
|
10
|
+
- Run \`kgraph scan\` after structural code changes.
|
|
11
|
+
- Run \`kgraph visualize\` when visualization support is available and the user wants to inspect the current knowledge map.
|
|
12
|
+
`
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const codexAdapter = {
|
|
2
|
+
name: "codex",
|
|
3
|
+
label: "Codex",
|
|
4
|
+
targetPath: "AGENTS.md",
|
|
5
|
+
instructions: `## KGraph Workflow
|
|
6
|
+
|
|
7
|
+
- Before broad repository exploration, run \`kgraph context "<topic>"\` to load current repo intelligence.
|
|
8
|
+
- After useful debugging, architecture discovery, workflow learning, or implementation work, write a concise Markdown note into \`.kgraph/inbox/\`.
|
|
9
|
+
- Run \`kgraph update\` after adding inbox notes so KGraph preserves durable cognition.
|
|
10
|
+
- Run \`kgraph scan\` after file moves, function renames, refactors, or other structural changes.
|
|
11
|
+
- When visualization support is available and the developer asks to inspect KGraph, run \`kgraph visualize\` and report the generated local artifact.
|
|
12
|
+
`
|
|
13
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const copilotAdapter = {
|
|
2
|
+
name: "copilot",
|
|
3
|
+
label: "GitHub Copilot",
|
|
4
|
+
targetPath: ".github/copilot-instructions.md",
|
|
5
|
+
instructions: `## KGraph Workflow
|
|
6
|
+
|
|
7
|
+
- Use \`kgraph context "<topic>"\` before scanning many files manually.
|
|
8
|
+
- Preserve stable findings by creating Markdown notes in \`.kgraph/inbox/\`.
|
|
9
|
+
- Use \`kgraph update\` to process chat summaries and debugging conclusions into durable cognition.
|
|
10
|
+
- Use \`kgraph scan\` when code structure changes.
|
|
11
|
+
- Use \`kgraph visualize\` when visualization support is available and the developer asks to inspect the repository knowledge map.
|
|
12
|
+
`
|
|
13
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const cursorAdapter = {
|
|
2
|
+
name: "cursor",
|
|
3
|
+
label: "Cursor",
|
|
4
|
+
targetPath: ".cursor/rules/kgraph.mdc",
|
|
5
|
+
instructions: `---
|
|
6
|
+
description: Use KGraph persistent repo intelligence before broad repository exploration
|
|
7
|
+
alwaysApply: true
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## KGraph Workflow
|
|
11
|
+
|
|
12
|
+
- Query \`kgraph context "<topic>"\` before broad file searches when repo cognition may already exist.
|
|
13
|
+
- Store durable chat, debugging, architecture, and workflow discoveries as Markdown notes in \`.kgraph/inbox/\`.
|
|
14
|
+
- Run \`kgraph update\` after adding useful notes.
|
|
15
|
+
- Run \`kgraph scan\` after refactors, moved folders, renamed functions, or other structure changes.
|
|
16
|
+
- Run \`kgraph visualize\` when visualization support is available and the developer asks to inspect the KGraph map.
|
|
17
|
+
`
|
|
18
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const MARKER_PREFIX = "<!--";
|
|
2
|
+
const MARKER_SUFFIX = "-->";
|
|
3
|
+
export function upsertManagedBlock(content, integrationName, instructions) {
|
|
4
|
+
const normalized = content.trimEnd();
|
|
5
|
+
const block = renderManagedBlock(integrationName, instructions);
|
|
6
|
+
const pattern = managedBlockPattern(integrationName);
|
|
7
|
+
if (pattern.test(content)) {
|
|
8
|
+
return content.replace(pattern, block);
|
|
9
|
+
}
|
|
10
|
+
return `${normalized}${normalized ? "\n\n" : ""}${block}\n`;
|
|
11
|
+
}
|
|
12
|
+
export function removeManagedBlock(content, integrationName) {
|
|
13
|
+
return content.replace(managedBlockPattern(integrationName), "").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
14
|
+
}
|
|
15
|
+
function renderManagedBlock(integrationName, instructions) {
|
|
16
|
+
return [
|
|
17
|
+
`${MARKER_PREFIX} BEGIN KGRAPH ${integrationName} ${MARKER_SUFFIX}`,
|
|
18
|
+
instructions.trim(),
|
|
19
|
+
`${MARKER_PREFIX} END KGRAPH ${integrationName} ${MARKER_SUFFIX}`
|
|
20
|
+
].join("\n");
|
|
21
|
+
}
|
|
22
|
+
function managedBlockPattern(integrationName) {
|
|
23
|
+
return new RegExp(`${escapeRegExp(MARKER_PREFIX)} BEGIN KGRAPH ${escapeRegExp(integrationName)} ${escapeRegExp(MARKER_SUFFIX)}[\\s\\S]*?${escapeRegExp(MARKER_PREFIX)} END KGRAPH ${escapeRegExp(integrationName)} ${escapeRegExp(MARKER_SUFFIX)}\\n?`, "m");
|
|
24
|
+
}
|
|
25
|
+
function escapeRegExp(value) {
|
|
26
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IntegrationName } from "../types/config.js";
|
|
2
|
+
export interface IntegrationAdapter {
|
|
3
|
+
name: IntegrationName;
|
|
4
|
+
label: string;
|
|
5
|
+
targetPath: string;
|
|
6
|
+
instructions: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function listIntegrationAdapters(): IntegrationAdapter[];
|
|
9
|
+
export declare function getIntegrationAdapter(name: string): IntegrationAdapter;
|
|
10
|
+
export declare function normalizeIntegrationNames(values: string[] | undefined): IntegrationName[];
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { claudeCodeAdapter } from "./adapters/claude-code.js";
|
|
2
|
+
import { codexAdapter } from "./adapters/codex.js";
|
|
3
|
+
import { copilotAdapter } from "./adapters/copilot.js";
|
|
4
|
+
import { cursorAdapter } from "./adapters/cursor.js";
|
|
5
|
+
const ADAPTERS = [
|
|
6
|
+
claudeCodeAdapter,
|
|
7
|
+
codexAdapter,
|
|
8
|
+
copilotAdapter,
|
|
9
|
+
cursorAdapter
|
|
10
|
+
].sort((left, right) => left.name.localeCompare(right.name));
|
|
11
|
+
export function listIntegrationAdapters() {
|
|
12
|
+
return ADAPTERS;
|
|
13
|
+
}
|
|
14
|
+
export function getIntegrationAdapter(name) {
|
|
15
|
+
const adapter = ADAPTERS.find((item) => item.name === name);
|
|
16
|
+
if (!adapter) {
|
|
17
|
+
throw new Error(`Unsupported integration "${name}". Supported integrations: ${ADAPTERS.map((item) => item.name).join(", ")}`);
|
|
18
|
+
}
|
|
19
|
+
return adapter;
|
|
20
|
+
}
|
|
21
|
+
export function normalizeIntegrationNames(values) {
|
|
22
|
+
if (!values || values.length === 0) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const names = [];
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
for (const value of values) {
|
|
28
|
+
for (const raw of value.split(",")) {
|
|
29
|
+
const name = raw.trim();
|
|
30
|
+
if (!name || seen.has(name)) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const adapter = getIntegrationAdapter(name);
|
|
34
|
+
seen.add(adapter.name);
|
|
35
|
+
names.push(adapter.name);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return names;
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { IntegrationConfig, IntegrationName, KGraphWorkspace } from "../types/config.js";
|
|
2
|
+
export interface IntegrationStatus {
|
|
3
|
+
name: IntegrationName;
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
targetPath: string;
|
|
6
|
+
targetExists: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function listIntegrations(workspace: KGraphWorkspace): Promise<IntegrationStatus[]>;
|
|
9
|
+
export declare function addIntegrations(workspace: KGraphWorkspace, names: IntegrationName[]): Promise<IntegrationConfig[]>;
|
|
10
|
+
export declare function removeIntegrations(workspace: KGraphWorkspace, names: IntegrationName[]): Promise<IntegrationName[]>;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { loadConfig, saveConfig } from "../config/config.js";
|
|
4
|
+
import { pathExists } from "../storage/kgraph-paths.js";
|
|
5
|
+
import { getIntegrationAdapter } from "./integration-registry.js";
|
|
6
|
+
import { removeManagedBlock, upsertManagedBlock } from "./instruction-blocks.js";
|
|
7
|
+
export async function listIntegrations(workspace) {
|
|
8
|
+
const config = await loadConfig(workspace);
|
|
9
|
+
const statuses = await Promise.all(config.integrations.map(async (integration) => ({
|
|
10
|
+
name: integration.name,
|
|
11
|
+
enabled: integration.enabled,
|
|
12
|
+
targetPath: integration.targetPath,
|
|
13
|
+
targetExists: await pathExists(path.join(workspace.rootPath, integration.targetPath))
|
|
14
|
+
})));
|
|
15
|
+
return statuses.sort((left, right) => left.name.localeCompare(right.name));
|
|
16
|
+
}
|
|
17
|
+
export async function addIntegrations(workspace, names) {
|
|
18
|
+
const config = await loadConfig(workspace);
|
|
19
|
+
const byName = new Map(config.integrations.map((integration) => [integration.name, integration]));
|
|
20
|
+
const changed = [];
|
|
21
|
+
for (const name of names) {
|
|
22
|
+
const adapter = getIntegrationAdapter(name);
|
|
23
|
+
const next = {
|
|
24
|
+
name: adapter.name,
|
|
25
|
+
enabled: true,
|
|
26
|
+
targetPath: adapter.targetPath
|
|
27
|
+
};
|
|
28
|
+
byName.set(adapter.name, next);
|
|
29
|
+
await writeIntegrationInstructions(workspace.rootPath, adapter.targetPath, adapter.name, adapter.instructions);
|
|
30
|
+
changed.push(next);
|
|
31
|
+
}
|
|
32
|
+
config.integrations = [...byName.values()].sort((left, right) => left.name.localeCompare(right.name));
|
|
33
|
+
await saveConfig(workspace, config);
|
|
34
|
+
return changed;
|
|
35
|
+
}
|
|
36
|
+
export async function removeIntegrations(workspace, names) {
|
|
37
|
+
const config = await loadConfig(workspace);
|
|
38
|
+
const removeNames = new Set(names);
|
|
39
|
+
const removed = [];
|
|
40
|
+
for (const name of removeNames) {
|
|
41
|
+
const adapter = getIntegrationAdapter(name);
|
|
42
|
+
await removeIntegrationInstructions(workspace.rootPath, adapter.targetPath, adapter.name);
|
|
43
|
+
removed.push(adapter.name);
|
|
44
|
+
}
|
|
45
|
+
config.integrations = config.integrations.filter((integration) => !removeNames.has(integration.name));
|
|
46
|
+
await saveConfig(workspace, config);
|
|
47
|
+
return removed.sort((left, right) => left.localeCompare(right));
|
|
48
|
+
}
|
|
49
|
+
async function writeIntegrationInstructions(rootPath, targetPath, integrationName, instructions) {
|
|
50
|
+
const fullPath = path.join(rootPath, targetPath);
|
|
51
|
+
const existing = (await pathExists(fullPath)) ? await readFile(fullPath, "utf8") : "";
|
|
52
|
+
const next = upsertManagedBlock(existing, integrationName, instructions);
|
|
53
|
+
await mkdir(path.dirname(fullPath), { recursive: true });
|
|
54
|
+
await writeFile(fullPath, next, "utf8");
|
|
55
|
+
}
|
|
56
|
+
async function removeIntegrationInstructions(rootPath, targetPath, integrationName) {
|
|
57
|
+
const fullPath = path.join(rootPath, targetPath);
|
|
58
|
+
if (!(await pathExists(fullPath))) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const existing = await readFile(fullPath, "utf8");
|
|
62
|
+
const next = removeManagedBlock(existing, integrationName);
|
|
63
|
+
if (next.trim().length === 0) {
|
|
64
|
+
await rm(fullPath, { force: true });
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
await writeFile(fullPath, next, "utf8");
|
|
68
|
+
}
|
package/dist/types/config.d.ts
CHANGED
|
@@ -6,11 +6,18 @@ export interface KGraphConfig {
|
|
|
6
6
|
};
|
|
7
7
|
maxContextItems: number;
|
|
8
8
|
domainHints: Record<string, DomainHint>;
|
|
9
|
+
integrations: IntegrationConfig[];
|
|
9
10
|
}
|
|
10
11
|
export interface DomainHint {
|
|
11
12
|
paths?: string[];
|
|
12
13
|
tags?: string[];
|
|
13
14
|
}
|
|
15
|
+
export type IntegrationName = "claude-code" | "codex" | "copilot" | "cursor";
|
|
16
|
+
export interface IntegrationConfig {
|
|
17
|
+
name: IntegrationName;
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
targetPath: string;
|
|
20
|
+
}
|
|
14
21
|
export interface KGraphWorkspace {
|
|
15
22
|
rootPath: string;
|
|
16
23
|
kgraphPath: string;
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kentwynn/kgraph",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Persistent repo intelligence for AI coding assistants.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"kgraph": "
|
|
7
|
+
"kgraph": "dist/cli/index.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|