@kentwynn/kgraph 0.1.22 → 0.1.24

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.
Files changed (38) hide show
  1. package/README.md +38 -2
  2. package/dist/cli/commands/doctor.js +4 -0
  3. package/dist/cli/commands/init.js +11 -3
  4. package/dist/cli/commands/integrate.js +32 -5
  5. package/dist/cli/commands/session.d.ts +4 -0
  6. package/dist/cli/commands/session.js +112 -0
  7. package/dist/cli/commands/workflow.js +5 -0
  8. package/dist/cli/help.d.ts +6 -0
  9. package/dist/cli/help.js +15 -1
  10. package/dist/cli/index.js +2 -0
  11. package/dist/cognition/cognition-quality.d.ts +4 -0
  12. package/dist/cognition/cognition-quality.js +14 -0
  13. package/dist/config/config.js +6 -0
  14. package/dist/integrations/adapters/claude-code.js +59 -25
  15. package/dist/integrations/adapters/cline.js +3 -5
  16. package/dist/integrations/adapters/codex.js +9 -26
  17. package/dist/integrations/adapters/copilot.js +17 -43
  18. package/dist/integrations/adapters/cursor.js +3 -5
  19. package/dist/integrations/adapters/gemini.js +3 -5
  20. package/dist/integrations/adapters/windsurf.js +3 -5
  21. package/dist/integrations/instruction-blocks.d.ts +6 -0
  22. package/dist/integrations/instruction-blocks.js +45 -0
  23. package/dist/integrations/integration-store.d.ts +4 -2
  24. package/dist/integrations/integration-store.js +19 -5
  25. package/dist/scanner/repo-scanner.js +2 -0
  26. package/dist/session/session-store.d.ts +15 -0
  27. package/dist/session/session-store.js +170 -0
  28. package/dist/session/token-estimator.d.ts +1 -0
  29. package/dist/session/token-estimator.js +17 -0
  30. package/dist/storage/kgraph-paths.js +4 -2
  31. package/dist/types/config.d.ts +3 -0
  32. package/dist/types/maps.d.ts +1 -0
  33. package/dist/types/session.d.ts +51 -0
  34. package/dist/types/session.js +1 -0
  35. package/dist/visualization/graph-builder.d.ts +1 -0
  36. package/dist/visualization/graph-builder.js +14 -1
  37. package/dist/visualization/html-template.js +19 -2
  38. package/package.json +1 -1
package/README.md CHANGED
@@ -107,19 +107,31 @@ kgraph "auth token refresh"
107
107
  kgraph doctor
108
108
  ```
109
109
 
110
- After useful AI work, assistants can save durable notes into `.kgraph/inbox/`. The next `kgraph` run processes those notes automatically. You can also process them directly with `kgraph update`.
110
+ After useful AI work, assistants save durable runtime-capture notes into `.kgraph/inbox/`. These notes are not project documentation; they are KGraph input files that the next `kgraph` run processes automatically. You can also process them directly with `kgraph update`.
111
111
 
112
112
  Normal agent flow is intentionally small:
113
113
 
114
114
  ```bash
115
115
  kgraph "topic"
116
116
  # work normally
117
- # if repo files changed, write an inbox note when the change has future value
117
+ # if repo files changed, write an inbox note before the final refresh
118
118
  kgraph
119
119
  ```
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 changed = await addIntegrations(workspace, names);
22
- console.log(`Configured integrations: ${changed.map((item) => item.name).join(", ")}`);
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.command("add").description("Add AI tool integrations").argument("<names...>").action((names) => runCommand(async () => {
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 changed = await addIntegrations(workspace, normalized);
25
- console.log(`Configured integrations: ${changed.map((item) => item.name).join(", ")}`);
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]) {
@@ -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 for AI tools'),
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));
@@ -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
- Before exploring the repository, run \`kgraph "<topic>"\` to refresh repo intelligence and load focused context. 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.
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,34 +12,17 @@ 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. Run \`kgraph "<topic>"\`. This refreshes maps, processes pending inbox notes, and returns focused context in one command.
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. 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.
19
- 6. At the end of any session that changed repository files, check the KGraph capture workflow before finishing.
20
- 7. If the file change has future value, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\`; otherwise explicitly skip capture as trivial.
21
- 8. Skip capture only for read-only work, trivial formatting, typo-only docs, dependency-only churn, mechanical cleanup with no future value, or sessions where no repo files changed.
22
- 9. Do not run KGraph repeatedly. Run it once at the start with \`kgraph "<topic>"\`. If repo files changed, write any needed inbox note first, then run \`kgraph\` once at the end.
23
- 10. 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.
24
- 11. Run \`kgraph visualize\` when the user wants to inspect the dependency graph — opens an interactive graph at http://localhost:4242 with PNG export.
25
- 12. Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
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.
26
20
 
27
- The inbox note must use this structure:
28
- \`\`\`markdown
29
- # <Short Title>
21
+ {{KGRAPH_CAPTURE_POLICY}}
30
22
 
31
- ## Summary
32
- One or two sentences describing the durable change or finding.
33
-
34
- ## Key Files
35
- - \`path/to/file.ts\` — what changed or why it matters
36
-
37
- ## Key Symbols
38
- - \`FunctionName\` — what changed or why it matters
39
-
40
- ## Decisions
41
- Any implementation or product decision future sessions should know.
42
- \`\`\`
23
+ 7. 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.
24
+ 8. Run \`kgraph visualize\` when the user wants to inspect the dependency graph — opens an interactive graph at http://localhost:4242 with PNG export.
25
+ 9. Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
43
26
  `,
44
27
  },
45
28
  {
@@ -70,6 +53,11 @@ Any implementation or product decision future sessions should know.
70
53
  {
71
54
  path: '.claude/commands/kgraph-impact.md',
72
55
  content: `Run \`kgraph impact "$ARGUMENTS"\` to show matched files/symbols, import users, callers, callees, related cognition, and risk hints.
56
+ `,
57
+ },
58
+ {
59
+ path: '.claude/commands/kgraph-session.md',
60
+ 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
61
  `,
74
62
  },
75
63
  {
@@ -77,6 +65,52 @@ Any implementation or product decision future sessions should know.
77
65
  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
66
  `,
79
67
  },
68
+ {
69
+ path: '.claude/hooks/kgraph-session-start.cjs',
70
+ content: hookScript('start'),
71
+ },
72
+ {
73
+ path: '.claude/hooks/kgraph-session-pre-read.cjs',
74
+ content: hookScript('read'),
75
+ },
76
+ {
77
+ path: '.claude/hooks/kgraph-session-post-write.cjs',
78
+ content: hookScript('write'),
79
+ },
80
+ {
81
+ path: '.claude/hooks/kgraph-session-stop.cjs',
82
+ content: hookScript('end'),
83
+ },
80
84
  ],
81
85
  obsoleteCommandFiles: [],
82
86
  };
87
+ function hookScript(event) {
88
+ const pathArg = event === 'read' || event === 'write'
89
+ ? `const payload = readPayload();
90
+ const filePath = payload?.tool_input?.file_path || payload?.toolInput?.file_path || payload?.file_path;
91
+ if (!filePath) process.exit(0);
92
+ args.push(filePath);`
93
+ : '';
94
+ return `#!/usr/bin/env node
95
+ const { spawnSync } = require('node:child_process');
96
+
97
+ function readPayload() {
98
+ try {
99
+ const chunks = [];
100
+ let chunk;
101
+ while ((chunk = require('node:fs').readFileSync(0, { encoding: 'utf8' }))) {
102
+ chunks.push(chunk);
103
+ break;
104
+ }
105
+ return chunks.join('') ? JSON.parse(chunks.join('')) : {};
106
+ } catch {
107
+ return {};
108
+ }
109
+ }
110
+
111
+ const args = ['session', '${event}', '--agent', 'claude-code', '--source', 'automatic'];
112
+ ${pathArg}
113
+ const result = spawnSync('kgraph', args, { stdio: 'ignore' });
114
+ process.exit(result.status || 0);
115
+ `;
116
+ }
@@ -4,13 +4,11 @@ export const clineAdapter = {
4
4
  targetPath: '.clinerules/kgraph.md',
5
5
  instructions: `# KGraph Workflow
6
6
 
7
- - **Before exploring the repository**, run \`kgraph "<topic>"\` to refresh maps, process pending inbox notes, and load focused repo intelligence. Use the returned files, symbols, relationships, and cognition before any broad exploration.
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, check the KGraph capture workflow before finishing.
11
- - If the file change has future value, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\`; otherwise explicitly skip capture as trivial.
12
- - Skip capture only for read-only work, trivial formatting, typo-only docs, dependency-only churn, mechanical cleanup with no future value, or sessions where no repo files changed.
13
- - Do not run KGraph repeatedly. Run it once at the start with \`kgraph "<topic>"\`. If repo files changed, write any needed inbox note first, then run \`kgraph\` once at the end.
11
+ {{KGRAPH_CAPTURE_POLICY}}
14
12
  - 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
13
  - Run \`kgraph visualize\` to open the interactive dependency graph at http://localhost:4242 with PNG export.
16
14
  - Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.