@kentwynn/kgraph 0.1.22 → 0.1.23
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 +36 -0
- package/dist/cli/commands/doctor.js +4 -0
- package/dist/cli/commands/init.js +11 -3
- package/dist/cli/commands/integrate.js +32 -5
- package/dist/cli/commands/session.d.ts +4 -0
- package/dist/cli/commands/session.js +112 -0
- package/dist/cli/commands/workflow.js +5 -0
- package/dist/cli/help.d.ts +6 -0
- package/dist/cli/help.js +15 -1
- package/dist/cli/index.js +2 -0
- package/dist/cognition/cognition-quality.d.ts +4 -0
- package/dist/cognition/cognition-quality.js +14 -0
- package/dist/config/config.js +6 -0
- package/dist/integrations/adapters/claude-code.js +62 -10
- package/dist/integrations/adapters/cline.js +6 -5
- package/dist/integrations/adapters/codex.js +12 -11
- package/dist/integrations/adapters/copilot.js +22 -10
- package/dist/integrations/adapters/cursor.js +6 -5
- package/dist/integrations/adapters/gemini.js +6 -5
- package/dist/integrations/adapters/windsurf.js +6 -5
- package/dist/integrations/instruction-blocks.d.ts +4 -0
- package/dist/integrations/instruction-blocks.js +17 -0
- package/dist/integrations/integration-store.d.ts +4 -2
- package/dist/integrations/integration-store.js +19 -5
- package/dist/scanner/repo-scanner.js +2 -0
- package/dist/session/session-store.d.ts +15 -0
- package/dist/session/session-store.js +170 -0
- package/dist/session/token-estimator.d.ts +1 -0
- package/dist/session/token-estimator.js +17 -0
- package/dist/storage/kgraph-paths.js +4 -2
- package/dist/types/config.d.ts +3 -0
- package/dist/types/maps.d.ts +1 -0
- package/dist/types/session.d.ts +51 -0
- package/dist/types/session.js +1 -0
- package/dist/visualization/graph-builder.d.ts +1 -0
- package/dist/visualization/graph-builder.js +14 -1
- package/dist/visualization/html-template.js +19 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -120,6 +120,18 @@ kgraph
|
|
|
120
120
|
|
|
121
121
|
Use `kgraph doctor --quality` and `kgraph repair --dry-run` only when stale or noisy cognition references start making context harder to trust.
|
|
122
122
|
|
|
123
|
+
Agents can also report session activity so KGraph can estimate token waste:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
kgraph session start --agent codex
|
|
127
|
+
kgraph session read src/auth.ts --agent codex
|
|
128
|
+
kgraph session write src/auth.ts --agent codex
|
|
129
|
+
kgraph session end --agent codex
|
|
130
|
+
kgraph session
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
This is optional. Claude Code can use generated hook scripts for automatic capture; other agents use the same commands through their managed instructions, rules, or prompts.
|
|
134
|
+
|
|
123
135
|
## Main Commands
|
|
124
136
|
|
|
125
137
|
```bash
|
|
@@ -167,6 +179,18 @@ kgraph impact "createSession" --json
|
|
|
167
179
|
|
|
168
180
|
Show practical impact for a file, symbol, or topic: matched files/symbols, import users, callers, callees, ownership edges, related cognition, and risk hints.
|
|
169
181
|
|
|
182
|
+
```bash
|
|
183
|
+
kgraph session
|
|
184
|
+
kgraph session --json
|
|
185
|
+
kgraph session reset
|
|
186
|
+
kgraph session start --agent codex
|
|
187
|
+
kgraph session read src/auth.ts --agent codex
|
|
188
|
+
kgraph session write src/auth.ts --agent codex
|
|
189
|
+
kgraph session end --agent codex
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Track agent-reported read/write activity, repeated reads, and estimated token cost. Supported agents are `codex`, `claude-code`, `copilot`, `cursor`, `gemini`, `windsurf`, and `cline`.
|
|
193
|
+
|
|
170
194
|
## Optional Step Commands
|
|
171
195
|
|
|
172
196
|
These are useful for scripting, debugging, or when you want a single operation.
|
|
@@ -214,10 +238,21 @@ KGraph integrations are local files. They do not start background agents, call A
|
|
|
214
238
|
|
|
215
239
|
```bash
|
|
216
240
|
kgraph integrate add codex copilot cursor claude-code gemini windsurf cline
|
|
241
|
+
kgraph integrate add copilot --mode always
|
|
242
|
+
kgraph integrate set copilot --mode manual
|
|
217
243
|
kgraph integrate list
|
|
218
244
|
kgraph integrate remove cursor
|
|
219
245
|
```
|
|
220
246
|
|
|
247
|
+
New integrations default to `always` mode because coding agents often under-classify small UI, route, button, and link changes as not needing repo context.
|
|
248
|
+
|
|
249
|
+
| Mode | Behavior |
|
|
250
|
+
| --- | --- |
|
|
251
|
+
| `always` | Every chat in the repository starts with `kgraph "<topic>"`, even simple or conversational requests. |
|
|
252
|
+
| `smart` | Runs KGraph automatically for repo-specific coding, debugging, architecture, refactor, review, or file-exploration requests. Skips simple conversational requests that do not depend on repo knowledge. |
|
|
253
|
+
| `manual` | Exposes KGraph commands and instructions, but the agent runs KGraph only when the user explicitly asks. |
|
|
254
|
+
| `off` | Disables that integration and removes generated KGraph instruction blocks/command files. |
|
|
255
|
+
|
|
221
256
|
| Tool | Files KGraph manages |
|
|
222
257
|
| --- | --- |
|
|
223
258
|
| Codex | `AGENTS.md`, `.agents/skills/kgraph/SKILL.md` |
|
|
@@ -248,6 +283,7 @@ All runtime data lives under `.kgraph/`:
|
|
|
248
283
|
├── cognition/
|
|
249
284
|
├── domains/
|
|
250
285
|
├── interactions/processed/
|
|
286
|
+
├── sessions/
|
|
251
287
|
└── context/
|
|
252
288
|
```
|
|
253
289
|
|
|
@@ -115,6 +115,10 @@ export function printQualityReport(report) {
|
|
|
115
115
|
console.log(`Unresolved call edges: ${report.unresolvedCallCount}`);
|
|
116
116
|
console.log(`Duplicate cognition titles: ${report.duplicateTitleCount}`);
|
|
117
117
|
console.log(`Generated files scanned: ${report.generatedFileScanCount}`);
|
|
118
|
+
console.log(`Expensive files: ${report.expensiveFileCount}`);
|
|
119
|
+
console.log(`Session repeated reads: ${report.sessionRepeatedReadCount}`);
|
|
120
|
+
console.log(`Session estimated read tokens: ${report.sessionEstimatedReadTokens}`);
|
|
121
|
+
console.log(`Session repeated-read tokens: ${report.sessionEstimatedRepeatedReadTokens}`);
|
|
118
122
|
if (report.changes.length === 0) {
|
|
119
123
|
return;
|
|
120
124
|
}
|
|
@@ -2,13 +2,14 @@ import { writeDefaultConfig } from "../../config/config.js";
|
|
|
2
2
|
import { normalizeIntegrationNames } from "../../integrations/integration-registry.js";
|
|
3
3
|
import { addIntegrations } from "../../integrations/integration-store.js";
|
|
4
4
|
import { ensureWorkspace } from "../../storage/kgraph-paths.js";
|
|
5
|
-
import { runCommand } from "../errors.js";
|
|
5
|
+
import { KGraphError, runCommand } from "../errors.js";
|
|
6
6
|
export function registerInitCommand(program) {
|
|
7
7
|
program
|
|
8
8
|
.command("init")
|
|
9
9
|
.description("Initialize a .kgraph workspace")
|
|
10
10
|
.option("--integration <name>", "Configure an AI tool integration", collectOption, [])
|
|
11
11
|
.option("--integrations <names>", "Configure comma-separated AI tool integrations")
|
|
12
|
+
.option("--mode <mode>", "Integration mode: smart, always, manual, or off", "always")
|
|
12
13
|
.action((options) => runCommand(async () => {
|
|
13
14
|
const workspace = await ensureWorkspace(process.cwd());
|
|
14
15
|
const wroteConfig = await writeDefaultConfig(workspace);
|
|
@@ -18,8 +19,9 @@ export function registerInitCommand(program) {
|
|
|
18
19
|
...(options.integrations ? [options.integrations] : [])
|
|
19
20
|
]);
|
|
20
21
|
if (names.length > 0) {
|
|
21
|
-
const
|
|
22
|
-
|
|
22
|
+
const mode = normalizeIntegrationMode(options.mode);
|
|
23
|
+
const changed = await addIntegrations(workspace, names, mode);
|
|
24
|
+
console.log(`Configured integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(", ")}`);
|
|
23
25
|
}
|
|
24
26
|
}));
|
|
25
27
|
}
|
|
@@ -27,3 +29,9 @@ function collectOption(value, previous) {
|
|
|
27
29
|
previous.push(value);
|
|
28
30
|
return previous;
|
|
29
31
|
}
|
|
32
|
+
function normalizeIntegrationMode(value) {
|
|
33
|
+
if (value === "smart" || value === "always" || value === "manual" || value === "off") {
|
|
34
|
+
return value;
|
|
35
|
+
}
|
|
36
|
+
throw new KGraphError("--mode must be smart, always, manual, or off.");
|
|
37
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { addIntegrations, listIntegrations, removeIntegrations } from "../../integrations/integration-store.js";
|
|
1
|
+
import { addIntegrations, listIntegrations, removeIntegrations, setIntegrationMode } from "../../integrations/integration-store.js";
|
|
2
2
|
import { normalizeIntegrationNames } from "../../integrations/integration-registry.js";
|
|
3
3
|
import { assertWorkspace } from "../../storage/kgraph-paths.js";
|
|
4
4
|
import { KGraphError, runCommand } from "../errors.js";
|
|
@@ -12,17 +12,38 @@ export function registerIntegrateCommand(program) {
|
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
for (const integration of integrations) {
|
|
15
|
-
console.log(`${integration.name} ${integration.enabled ? "enabled" : "disabled"} ${integration.targetPath} ${integration.targetExists ? "present" : "missing"}`);
|
|
15
|
+
console.log(`${integration.name} ${integration.enabled ? "enabled" : "disabled"} ${integration.mode} ${integration.targetPath} ${integration.targetExists ? "present" : "missing"}`);
|
|
16
16
|
}
|
|
17
17
|
}));
|
|
18
|
-
integrate
|
|
18
|
+
integrate
|
|
19
|
+
.command("add")
|
|
20
|
+
.description("Add AI tool integrations")
|
|
21
|
+
.argument("<names...>")
|
|
22
|
+
.option("--mode <mode>", "smart, always, manual, or off", "always")
|
|
23
|
+
.action((names, options) => runCommand(async () => {
|
|
19
24
|
const workspace = await assertWorkspace(process.cwd());
|
|
20
25
|
const normalized = normalizeIntegrationNames(names);
|
|
21
26
|
if (normalized.length === 0) {
|
|
22
27
|
throw new KGraphError("Provide at least one integration name.");
|
|
23
28
|
}
|
|
24
|
-
const
|
|
25
|
-
|
|
29
|
+
const mode = normalizeIntegrationMode(options.mode);
|
|
30
|
+
const changed = await addIntegrations(workspace, normalized, mode);
|
|
31
|
+
console.log(`Configured integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(", ")}`);
|
|
32
|
+
}));
|
|
33
|
+
integrate
|
|
34
|
+
.command("set")
|
|
35
|
+
.description("Set AI tool integration mode")
|
|
36
|
+
.argument("<names...>")
|
|
37
|
+
.requiredOption("--mode <mode>", "smart, always, manual, or off")
|
|
38
|
+
.action((names, options) => runCommand(async () => {
|
|
39
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
40
|
+
const normalized = normalizeIntegrationNames(names);
|
|
41
|
+
if (normalized.length === 0) {
|
|
42
|
+
throw new KGraphError("Provide at least one integration name.");
|
|
43
|
+
}
|
|
44
|
+
const mode = normalizeIntegrationMode(options.mode);
|
|
45
|
+
const changed = await setIntegrationMode(workspace, normalized, mode);
|
|
46
|
+
console.log(`Updated integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(", ")}`);
|
|
26
47
|
}));
|
|
27
48
|
integrate.command("remove").description("Remove AI tool integrations").argument("<names...>").action((names) => runCommand(async () => {
|
|
28
49
|
const workspace = await assertWorkspace(process.cwd());
|
|
@@ -34,3 +55,9 @@ export function registerIntegrateCommand(program) {
|
|
|
34
55
|
console.log(`Removed integrations: ${removed.join(", ")}`);
|
|
35
56
|
}));
|
|
36
57
|
}
|
|
58
|
+
function normalizeIntegrationMode(value) {
|
|
59
|
+
if (value === "smart" || value === "always" || value === "manual" || value === "off") {
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
throw new KGraphError("--mode must be smart, always, manual, or off.");
|
|
63
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { buildSessionReport } from '../../session/session-store.js';
|
|
3
|
+
export declare function registerSessionCommand(program: Command): void;
|
|
4
|
+
export declare function renderSessionReport(report: Awaited<ReturnType<typeof buildSessionReport>>): string;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { assertSessionAgent, buildSessionReport, recordSessionEvent, resetSession, } from '../../session/session-store.js';
|
|
2
|
+
import { assertWorkspace } from '../../storage/kgraph-paths.js';
|
|
3
|
+
import { readMaps } from '../../storage/map-store.js';
|
|
4
|
+
import { KGraphError, runCommand } from '../errors.js';
|
|
5
|
+
export function registerSessionCommand(program) {
|
|
6
|
+
const session = program
|
|
7
|
+
.command('session')
|
|
8
|
+
.description('Track agent read/write session activity and token estimates')
|
|
9
|
+
.option('--json', 'Print JSON output')
|
|
10
|
+
.action((options) => runCommand(async () => {
|
|
11
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
12
|
+
const report = await buildSessionReport(workspace);
|
|
13
|
+
console.log(options.json ? JSON.stringify(report, null, 2) : renderSessionReport(report));
|
|
14
|
+
}));
|
|
15
|
+
session
|
|
16
|
+
.command('start')
|
|
17
|
+
.requiredOption('--agent <name>', 'KGraph integration agent name')
|
|
18
|
+
.option('--source <source>', 'automatic, agent-reported, or manual', 'manual')
|
|
19
|
+
.action((options) => runCommand(async () => {
|
|
20
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
21
|
+
const event = await recordSessionEvent(workspace, {
|
|
22
|
+
agent: requireAgent(options.agent),
|
|
23
|
+
type: 'start',
|
|
24
|
+
captureSource: normalizeSource(options.source),
|
|
25
|
+
});
|
|
26
|
+
console.log(`KGraph session started for ${event.agent}.`);
|
|
27
|
+
}));
|
|
28
|
+
session
|
|
29
|
+
.command('read <path>')
|
|
30
|
+
.requiredOption('--agent <name>', 'KGraph integration agent name')
|
|
31
|
+
.option('--source <source>', 'automatic, agent-reported, or manual', 'manual')
|
|
32
|
+
.action((filePath, options) => runCommand(async () => {
|
|
33
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
34
|
+
const maps = await readMaps(workspace);
|
|
35
|
+
const event = await recordSessionEvent(workspace, {
|
|
36
|
+
agent: requireAgent(options.agent),
|
|
37
|
+
type: 'read',
|
|
38
|
+
path: filePath,
|
|
39
|
+
captureSource: normalizeSource(options.source),
|
|
40
|
+
fileMap: maps.fileMap,
|
|
41
|
+
});
|
|
42
|
+
console.log(`KGraph recorded read: ${event.path}${event.repeated ? ' (repeated)' : ''}${event.tokenEstimate !== undefined ? ` ~${event.tokenEstimate} tokens` : ''}.`);
|
|
43
|
+
}));
|
|
44
|
+
session
|
|
45
|
+
.command('write <path>')
|
|
46
|
+
.requiredOption('--agent <name>', 'KGraph integration agent name')
|
|
47
|
+
.option('--source <source>', 'automatic, agent-reported, or manual', 'manual')
|
|
48
|
+
.action((filePath, options) => runCommand(async () => {
|
|
49
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
50
|
+
const maps = await readMaps(workspace);
|
|
51
|
+
const event = await recordSessionEvent(workspace, {
|
|
52
|
+
agent: requireAgent(options.agent),
|
|
53
|
+
type: 'write',
|
|
54
|
+
path: filePath,
|
|
55
|
+
captureSource: normalizeSource(options.source),
|
|
56
|
+
fileMap: maps.fileMap,
|
|
57
|
+
});
|
|
58
|
+
console.log(`KGraph recorded write: ${event.path}${event.tokenEstimate !== undefined ? ` ~${event.tokenEstimate} tokens` : ''}.`);
|
|
59
|
+
}));
|
|
60
|
+
session
|
|
61
|
+
.command('end')
|
|
62
|
+
.requiredOption('--agent <name>', 'KGraph integration agent name')
|
|
63
|
+
.option('--source <source>', 'automatic, agent-reported, or manual', 'manual')
|
|
64
|
+
.action((options) => runCommand(async () => {
|
|
65
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
66
|
+
const event = await recordSessionEvent(workspace, {
|
|
67
|
+
agent: requireAgent(options.agent),
|
|
68
|
+
type: 'end',
|
|
69
|
+
captureSource: normalizeSource(options.source),
|
|
70
|
+
});
|
|
71
|
+
console.log(`KGraph session ended for ${event.agent}.`);
|
|
72
|
+
}));
|
|
73
|
+
session
|
|
74
|
+
.command('reset')
|
|
75
|
+
.description('Clear the current session tracker')
|
|
76
|
+
.action(() => runCommand(async () => {
|
|
77
|
+
const workspace = await assertWorkspace(process.cwd());
|
|
78
|
+
await resetSession(workspace);
|
|
79
|
+
console.log('KGraph current session reset.');
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
export function renderSessionReport(report) {
|
|
83
|
+
const lines = ['', 'KGraph Session', ''];
|
|
84
|
+
lines.push(`Active agents: ${report.activeAgents.length === 0 ? 'none' : report.activeAgents.map((agent) => agent.agent).join(', ')}`);
|
|
85
|
+
lines.push(`Reads: ${report.readCount}`);
|
|
86
|
+
lines.push(`Writes: ${report.writeCount}`);
|
|
87
|
+
lines.push(`Repeated reads: ${report.repeatedReadCount}`);
|
|
88
|
+
lines.push(`Estimated read tokens: ${report.estimatedReadTokens}`);
|
|
89
|
+
lines.push(`Estimated repeated-read tokens: ${report.estimatedRepeatedReadTokens}`);
|
|
90
|
+
lines.push('', 'Top Repeated Reads');
|
|
91
|
+
lines.push(...formatList(report.topRepeatedReads.map((item) => `- ${item.path} read ${item.count} times (~${item.estimatedTokens} tokens)`)));
|
|
92
|
+
lines.push('', 'Recent Events');
|
|
93
|
+
lines.push(...formatList(report.recentEvents.map((event) => `- ${event.agent} ${event.type}${event.path ? ` ${event.path}` : ''} [${event.captureSource}]`)));
|
|
94
|
+
lines.push('', 'Recent Ledger');
|
|
95
|
+
lines.push(...formatList(report.ledger.map((entry) => `- ${entry.agent} ${entry.readCount} reads, ${entry.writeCount} writes, ${entry.repeatedReadCount} repeated`)));
|
|
96
|
+
return lines.join('\n');
|
|
97
|
+
}
|
|
98
|
+
function requireAgent(value) {
|
|
99
|
+
if (!value) {
|
|
100
|
+
throw new KGraphError('--agent is required.');
|
|
101
|
+
}
|
|
102
|
+
return assertSessionAgent(value);
|
|
103
|
+
}
|
|
104
|
+
function normalizeSource(value) {
|
|
105
|
+
if (value === 'automatic' || value === 'agent-reported' || value === 'manual') {
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
throw new KGraphError('--source must be automatic, agent-reported, or manual.');
|
|
109
|
+
}
|
|
110
|
+
function formatList(items) {
|
|
111
|
+
return items.length > 0 ? items : ['- None'];
|
|
112
|
+
}
|
|
@@ -36,6 +36,11 @@ export async function runDefaultWorkflow(query) {
|
|
|
36
36
|
files: scan.files.length,
|
|
37
37
|
symbols: scan.symbols.length,
|
|
38
38
|
cognitionNotes: update.processed.length,
|
|
39
|
+
integrations: config.integrations.map((integration) => ({
|
|
40
|
+
name: integration.name,
|
|
41
|
+
mode: integration.mode,
|
|
42
|
+
enabled: integration.enabled,
|
|
43
|
+
})),
|
|
39
44
|
}));
|
|
40
45
|
console.log('');
|
|
41
46
|
for (const warning of [...scan.warnings, ...update.warnings]) {
|
package/dist/cli/help.d.ts
CHANGED
|
@@ -3,6 +3,12 @@ interface WorkflowBannerStats {
|
|
|
3
3
|
files: number;
|
|
4
4
|
symbols: number;
|
|
5
5
|
cognitionNotes: number;
|
|
6
|
+
integrations?: WorkflowBannerIntegration[];
|
|
7
|
+
}
|
|
8
|
+
interface WorkflowBannerIntegration {
|
|
9
|
+
name: string;
|
|
10
|
+
mode: string;
|
|
11
|
+
enabled: boolean;
|
|
6
12
|
}
|
|
7
13
|
export declare function renderWorkflowBanner(stats: WorkflowBannerStats, useColor?: boolean): string;
|
|
8
14
|
export {};
|
package/dist/cli/help.js
CHANGED
|
@@ -27,6 +27,8 @@ export function renderRootHelp(useColor = supportsColor()) {
|
|
|
27
27
|
'',
|
|
28
28
|
theme.bold('Workflows'),
|
|
29
29
|
command('scan', 'Optional: refresh only file, symbol, import, and relationship maps'),
|
|
30
|
+
command('session', 'Show agent read/write activity and token estimates'),
|
|
31
|
+
command('session read src/auth.ts --agent codex', 'Record an agent file read'),
|
|
30
32
|
command('context "auth token refresh"', 'Optional: return context without scanning or updating'),
|
|
31
33
|
command('impact "Button"', 'Show imports, callers, calls, cognition, and risk'),
|
|
32
34
|
command('update', 'Optional: process only .kgraph/inbox Markdown cognition notes'),
|
|
@@ -39,8 +41,11 @@ export function renderRootHelp(useColor = supportsColor()) {
|
|
|
39
41
|
'',
|
|
40
42
|
theme.bold('Integrations'),
|
|
41
43
|
command('integrate list', 'Show configured AI tool integrations'),
|
|
42
|
-
command('integrate add gemini windsurf cline', 'Write KGraph instructions
|
|
44
|
+
command('integrate add gemini windsurf cline', 'Write KGraph instructions using always mode by default'),
|
|
45
|
+
command('integrate add copilot --mode always', 'Every Copilot chat starts with kgraph "<topic>"'),
|
|
46
|
+
command('integrate set copilot --mode manual', 'Only run KGraph when explicitly requested'),
|
|
43
47
|
command('integrate remove cursor', 'Remove KGraph-managed instruction blocks'),
|
|
48
|
+
command('--mode smart|always|manual|off', 'Control automatic KGraph involvement per integration'),
|
|
44
49
|
'',
|
|
45
50
|
theme.bold('Options'),
|
|
46
51
|
command('-V, --version', 'Show version'),
|
|
@@ -58,6 +63,13 @@ export function renderRootHelp(useColor = supportsColor()) {
|
|
|
58
63
|
export function renderWorkflowBanner(stats, useColor = supportsColor()) {
|
|
59
64
|
const theme = new Chalk({ level: useColor ? 3 : 0 });
|
|
60
65
|
const command = (name, description) => ` ${theme.green(name.padEnd(42))} ${description}`;
|
|
66
|
+
const integrationLine = stats.integrations && stats.integrations.length > 0
|
|
67
|
+
? stats.integrations
|
|
68
|
+
.map((integration) => integration.enabled
|
|
69
|
+
? `${integration.name}:${integration.mode}`
|
|
70
|
+
: `${integration.name}:off`)
|
|
71
|
+
.join(', ')
|
|
72
|
+
: 'none configured';
|
|
61
73
|
return [
|
|
62
74
|
'',
|
|
63
75
|
theme.hex('#7dd3fc').bold(renderLogo()),
|
|
@@ -68,11 +80,13 @@ export function renderWorkflowBanner(stats, useColor = supportsColor()) {
|
|
|
68
80
|
command('files', String(stats.files)),
|
|
69
81
|
command('symbols', String(stats.symbols)),
|
|
70
82
|
command('cognition notes processed', String(stats.cognitionNotes)),
|
|
83
|
+
command('integration modes', integrationLine),
|
|
71
84
|
'',
|
|
72
85
|
theme.bold('Next'),
|
|
73
86
|
command('kgraph "auth token refresh"', 'Return compact context for a topic'),
|
|
74
87
|
command('kgraph doctor', 'Check workspace health'),
|
|
75
88
|
command('kgraph doctor --quality', 'Check cognition quality'),
|
|
89
|
+
command('kgraph session', 'Check session token waste'),
|
|
76
90
|
command('kgraph --help', 'Show all commands'),
|
|
77
91
|
].join('\n');
|
|
78
92
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -11,6 +11,7 @@ import { registerInitCommand } from './commands/init.js';
|
|
|
11
11
|
import { registerIntegrateCommand } from './commands/integrate.js';
|
|
12
12
|
import { registerRepairCommand } from './commands/repair.js';
|
|
13
13
|
import { registerScanCommand } from './commands/scan.js';
|
|
14
|
+
import { registerSessionCommand } from './commands/session.js';
|
|
14
15
|
import { registerUpdateCommand } from './commands/update.js';
|
|
15
16
|
import { registerVisualizeCommand } from './commands/visualize.js';
|
|
16
17
|
import { runDefaultWorkflow } from './commands/workflow.js';
|
|
@@ -38,6 +39,7 @@ export function createProgram() {
|
|
|
38
39
|
});
|
|
39
40
|
registerInitCommand(program);
|
|
40
41
|
registerScanCommand(program);
|
|
42
|
+
registerSessionCommand(program);
|
|
41
43
|
registerUpdateCommand(program);
|
|
42
44
|
registerContextCommand(program);
|
|
43
45
|
registerImpactCommand(program);
|
|
@@ -17,6 +17,10 @@ export interface CognitionQualityReport {
|
|
|
17
17
|
unresolvedCallCount: number;
|
|
18
18
|
duplicateTitleCount: number;
|
|
19
19
|
generatedFileScanCount: number;
|
|
20
|
+
expensiveFileCount: number;
|
|
21
|
+
sessionRepeatedReadCount: number;
|
|
22
|
+
sessionEstimatedReadTokens: number;
|
|
23
|
+
sessionEstimatedRepeatedReadTokens: number;
|
|
20
24
|
changes: CognitionRepairChange[];
|
|
21
25
|
}
|
|
22
26
|
export declare function analyzeCognitionQuality(workspace: KGraphWorkspace, maps: {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { overwriteDomainRecord, readCognitionNotes, readDomainRecords, writeCognitionNote, } from '../storage/cognition-store.js';
|
|
2
|
+
import { buildSessionReport } from '../session/session-store.js';
|
|
2
3
|
export async function analyzeCognitionQuality(workspace, maps) {
|
|
3
4
|
const notes = await readCognitionNotes(workspace);
|
|
5
|
+
const session = await buildSessionReport(workspace);
|
|
4
6
|
const changes = notes
|
|
5
7
|
.map((note) => analyzeNote(note, maps))
|
|
6
8
|
.filter((change) => change.removedFileRefs.length > 0 ||
|
|
@@ -14,11 +16,16 @@ export async function analyzeCognitionQuality(workspace, maps) {
|
|
|
14
16
|
unresolvedCallCount: countUnresolvedCalls(maps.symbolMap, maps.relationshipMap),
|
|
15
17
|
duplicateTitleCount: countDuplicateTitles(notes),
|
|
16
18
|
generatedFileScanCount: countGeneratedScannedFiles(maps.fileMap),
|
|
19
|
+
expensiveFileCount: countExpensiveFiles(maps.fileMap),
|
|
20
|
+
sessionRepeatedReadCount: session.repeatedReadCount,
|
|
21
|
+
sessionEstimatedReadTokens: session.estimatedReadTokens,
|
|
22
|
+
sessionEstimatedRepeatedReadTokens: session.estimatedRepeatedReadTokens,
|
|
17
23
|
changes,
|
|
18
24
|
};
|
|
19
25
|
}
|
|
20
26
|
export async function repairCognition(workspace, maps, dryRun = false) {
|
|
21
27
|
const notes = await readCognitionNotes(workspace);
|
|
28
|
+
const session = await buildSessionReport(workspace);
|
|
22
29
|
const nextNotes = [];
|
|
23
30
|
const changes = [];
|
|
24
31
|
for (const note of notes) {
|
|
@@ -45,6 +52,10 @@ export async function repairCognition(workspace, maps, dryRun = false) {
|
|
|
45
52
|
unresolvedCallCount: countUnresolvedCalls(maps.symbolMap, maps.relationshipMap),
|
|
46
53
|
duplicateTitleCount: countDuplicateTitles(nextNotes),
|
|
47
54
|
generatedFileScanCount: countGeneratedScannedFiles(maps.fileMap),
|
|
55
|
+
expensiveFileCount: countExpensiveFiles(maps.fileMap),
|
|
56
|
+
sessionRepeatedReadCount: session.repeatedReadCount,
|
|
57
|
+
sessionEstimatedReadTokens: session.estimatedReadTokens,
|
|
58
|
+
sessionEstimatedRepeatedReadTokens: session.estimatedRepeatedReadTokens,
|
|
48
59
|
changes,
|
|
49
60
|
};
|
|
50
61
|
}
|
|
@@ -86,6 +97,9 @@ function countGeneratedScannedFiles(fileMap) {
|
|
|
86
97
|
'GEMINI.md',
|
|
87
98
|
].some((prefix) => file.path === prefix || file.path.startsWith(prefix))).length;
|
|
88
99
|
}
|
|
100
|
+
function countExpensiveFiles(fileMap) {
|
|
101
|
+
return fileMap.files.filter((file) => (file.tokenEstimate ?? 0) >= 1000).length;
|
|
102
|
+
}
|
|
89
103
|
function analyzeNote(note, maps) {
|
|
90
104
|
const filePaths = new Set(maps.fileMap.files.map((file) => file.path));
|
|
91
105
|
const symbolNames = new Set(maps.symbolMap.symbols.map((symbol) => symbol.name));
|
package/dist/config/config.js
CHANGED
|
@@ -150,8 +150,14 @@ function normalizeIntegrations(value) {
|
|
|
150
150
|
integrations.push({
|
|
151
151
|
name: candidate.name,
|
|
152
152
|
enabled: candidate.enabled !== false,
|
|
153
|
+
mode: normalizeIntegrationMode(candidate.mode),
|
|
153
154
|
targetPath: candidate.targetPath,
|
|
154
155
|
});
|
|
155
156
|
}
|
|
156
157
|
return integrations;
|
|
157
158
|
}
|
|
159
|
+
function normalizeIntegrationMode(value) {
|
|
160
|
+
return value === 'always' || value === 'manual' || value === 'off'
|
|
161
|
+
? value
|
|
162
|
+
: 'smart';
|
|
163
|
+
}
|
|
@@ -4,7 +4,7 @@ export const claudeCodeAdapter = {
|
|
|
4
4
|
targetPath: 'CLAUDE.md',
|
|
5
5
|
instructions: `## KGraph Workflow
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
{{KGRAPH_CONTEXT_POLICY}} Use /kgraph for the full automated workflow. Run \`kgraph doctor\` when setup or generated maps look wrong. Run \`kgraph scan\`, \`kgraph update\`, and \`kgraph context\` manually only when you need one specific step.
|
|
8
8
|
`,
|
|
9
9
|
commandFiles: [
|
|
10
10
|
{
|
|
@@ -12,17 +12,18 @@ Before exploring the repository, run \`kgraph "<topic>"\` to refresh repo intell
|
|
|
12
12
|
content: `Use KGraph persistent repo intelligence for the current request.
|
|
13
13
|
|
|
14
14
|
1. Infer the topic from the user's request.
|
|
15
|
-
2.
|
|
15
|
+
2. {{KGRAPH_CONTEXT_POLICY}}
|
|
16
16
|
3. Use the returned files, symbols, relationships, and cognition before broad exploration.
|
|
17
17
|
4. Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong. Run \`kgraph doctor --quality\` when context shows stale/noisy cognition references.
|
|
18
|
-
5.
|
|
19
|
-
6.
|
|
20
|
-
7.
|
|
21
|
-
8.
|
|
22
|
-
9. Do not run KGraph repeatedly. Run it once at the start with \`kgraph "<topic>"\`. If repo files changed, write
|
|
23
|
-
10.
|
|
24
|
-
11. Run \`kgraph
|
|
25
|
-
12. Run \`kgraph
|
|
18
|
+
5. Track meaningful session activity with \`kgraph session start --agent claude-code\`, \`kgraph session read <path> --agent claude-code\`, \`kgraph session write <path> --agent claude-code\`, and \`kgraph session end --agent claude-code\` when native hooks are unavailable.
|
|
19
|
+
6. Run \`kgraph impact "<file-or-symbol>"\` when the user asks what a change may affect. Run \`kgraph history "<topic>"\` when prior work or decisions matter.
|
|
20
|
+
7. At the end of any session that changed repository files, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\` before finishing.
|
|
21
|
+
8. Do not skip capture for UI text, button, link, route, styling, or small file edits. Skip capture only when no repository files changed.
|
|
22
|
+
9. Do not run KGraph repeatedly. Run it once at the start with \`kgraph "<topic>"\`. If repo files changed, write the inbox note first, then run \`kgraph\` once at the end.
|
|
23
|
+
10. After the final \`kgraph\` run, mention whether the inbox note was processed.
|
|
24
|
+
11. Run \`kgraph repair --dry-run\` before cleanup when stale/noisy cognition needs fixing. Run \`kgraph repair\` only when the user asks to apply that cleanup.
|
|
25
|
+
12. Run \`kgraph visualize\` when the user wants to inspect the dependency graph — opens an interactive graph at http://localhost:4242 with PNG export.
|
|
26
|
+
13. Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
|
|
26
27
|
|
|
27
28
|
The inbox note must use this structure:
|
|
28
29
|
\`\`\`markdown
|
|
@@ -70,6 +71,11 @@ Any implementation or product decision future sessions should know.
|
|
|
70
71
|
{
|
|
71
72
|
path: '.claude/commands/kgraph-impact.md',
|
|
72
73
|
content: `Run \`kgraph impact "$ARGUMENTS"\` to show matched files/symbols, import users, callers, callees, related cognition, and risk hints.
|
|
74
|
+
`,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
path: '.claude/commands/kgraph-session.md',
|
|
78
|
+
content: `Use \`kgraph session\` to inspect session read/write/token estimates. Record meaningful events with \`kgraph session start --agent claude-code\`, \`kgraph session read <path> --agent claude-code\`, \`kgraph session write <path> --agent claude-code\`, and \`kgraph session end --agent claude-code\`.
|
|
73
79
|
`,
|
|
74
80
|
},
|
|
75
81
|
{
|
|
@@ -77,6 +83,52 @@ Any implementation or product decision future sessions should know.
|
|
|
77
83
|
content: `Run \`kgraph history\` or \`kgraph history "$ARGUMENTS"\` to show processed cognition sessions. Includes git author attribution when available. Use \`--last <n>\` to limit entries, \`--json\` for machine-readable output.
|
|
78
84
|
`,
|
|
79
85
|
},
|
|
86
|
+
{
|
|
87
|
+
path: '.claude/hooks/kgraph-session-start.cjs',
|
|
88
|
+
content: hookScript('start'),
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
path: '.claude/hooks/kgraph-session-pre-read.cjs',
|
|
92
|
+
content: hookScript('read'),
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
path: '.claude/hooks/kgraph-session-post-write.cjs',
|
|
96
|
+
content: hookScript('write'),
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
path: '.claude/hooks/kgraph-session-stop.cjs',
|
|
100
|
+
content: hookScript('end'),
|
|
101
|
+
},
|
|
80
102
|
],
|
|
81
103
|
obsoleteCommandFiles: [],
|
|
82
104
|
};
|
|
105
|
+
function hookScript(event) {
|
|
106
|
+
const pathArg = event === 'read' || event === 'write'
|
|
107
|
+
? `const payload = readPayload();
|
|
108
|
+
const filePath = payload?.tool_input?.file_path || payload?.toolInput?.file_path || payload?.file_path;
|
|
109
|
+
if (!filePath) process.exit(0);
|
|
110
|
+
args.push(filePath);`
|
|
111
|
+
: '';
|
|
112
|
+
return `#!/usr/bin/env node
|
|
113
|
+
const { spawnSync } = require('node:child_process');
|
|
114
|
+
|
|
115
|
+
function readPayload() {
|
|
116
|
+
try {
|
|
117
|
+
const chunks = [];
|
|
118
|
+
let chunk;
|
|
119
|
+
while ((chunk = require('node:fs').readFileSync(0, { encoding: 'utf8' }))) {
|
|
120
|
+
chunks.push(chunk);
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
return chunks.join('') ? JSON.parse(chunks.join('')) : {};
|
|
124
|
+
} catch {
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const args = ['session', '${event}', '--agent', 'claude-code', '--source', 'automatic'];
|
|
130
|
+
${pathArg}
|
|
131
|
+
const result = spawnSync('kgraph', args, { stdio: 'ignore' });
|
|
132
|
+
process.exit(result.status || 0);
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
@@ -4,13 +4,14 @@ export const clineAdapter = {
|
|
|
4
4
|
targetPath: '.clinerules/kgraph.md',
|
|
5
5
|
instructions: `# KGraph Workflow
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- {{KGRAPH_CONTEXT_POLICY}}
|
|
8
8
|
- Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong. Run \`kgraph doctor --quality\` when context shows stale/noisy cognition references.
|
|
9
|
+
- Track meaningful session activity with \`kgraph session start --agent cline\`, \`kgraph session read <path> --agent cline\`, \`kgraph session write <path> --agent cline\`, and \`kgraph session end --agent cline\`.
|
|
9
10
|
- Run \`kgraph impact "<file-or-symbol>"\` when the user asks what a change may affect. Run \`kgraph history "<topic>"\` when prior work or decisions matter.
|
|
10
|
-
- At the end of any session that changed repository files,
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
11
|
+
- At the end of any session that changed repository files, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\` before finishing.
|
|
12
|
+
- Do not skip capture for UI text, button, link, route, styling, or small file edits. Skip capture only when no repository files changed.
|
|
13
|
+
- Do not run KGraph repeatedly. Run it once at the start with \`kgraph "<topic>"\`. If repo files changed, write the inbox note first, then run \`kgraph\` once at the end.
|
|
14
|
+
- After the final \`kgraph\` run, mention whether the inbox note was processed.
|
|
14
15
|
- Run \`kgraph repair --dry-run\` before cleanup when stale/noisy cognition needs fixing. Run \`kgraph repair\` only when the user asks to apply that cleanup.
|
|
15
16
|
- Run \`kgraph visualize\` to open the interactive dependency graph at http://localhost:4242 with PNG export.
|
|
16
17
|
- Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
|