@kentwynn/kgraph 0.1.18 → 0.1.19

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 CHANGED
@@ -100,6 +100,17 @@ kgraph doctor
100
100
 
101
101
  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`.
102
102
 
103
+ Normal agent flow is intentionally small:
104
+
105
+ ```bash
106
+ kgraph "topic"
107
+ # work normally
108
+ # if repo files changed, write an inbox note when the change has future value
109
+ kgraph
110
+ ```
111
+
112
+ Use `kgraph doctor --quality` and `kgraph repair --dry-run` only when stale or noisy cognition references start making context harder to trust.
113
+
103
114
  ## Main Commands
104
115
 
105
116
  ```bash
@@ -128,9 +139,17 @@ Refreshes maps and cognition without returning topic-specific context.
128
139
 
129
140
  ```bash
130
141
  kgraph doctor
142
+ kgraph doctor --quality
143
+ ```
144
+
145
+ Checks whether the workspace is initialized, maps exist, inbox notes are pending, and configured integrations point to real files. Use `--quality` when context shows stale/noisy cognition references.
146
+
147
+ ```bash
148
+ kgraph repair --dry-run
149
+ kgraph repair
131
150
  ```
132
151
 
133
- Checks whether the workspace is initialized, maps exist, inbox notes are pending, and configured integrations point to real files.
152
+ `repair --dry-run` previews cleanup for noisy cognition references, such as framework names recorded as files or local variables recorded as symbols. `repair` applies that cleanup. Run repair intentionally when stale references make context noisy; it is not part of every normal workflow.
134
153
 
135
154
  ## Optional Step Commands
136
155
 
@@ -255,6 +274,8 @@ Run the local TypeScript CLI without installing globally:
255
274
  npm run kgraph -- init
256
275
  npm run kgraph -- "auth token refresh"
257
276
  npm run kgraph -- doctor
277
+ npm run kgraph -- doctor --quality
278
+ npm run kgraph -- repair --dry-run
258
279
  ```
259
280
 
260
281
  Test the built package as a global local install:
@@ -265,6 +286,7 @@ npm install -g .
265
286
  kgraph --version
266
287
  kgraph doctor
267
288
  kgraph "auth token refresh"
289
+ kgraph repair --dry-run
268
290
  ```
269
291
 
270
292
  Package checks:
@@ -1,2 +1,4 @@
1
1
  import type { Command } from 'commander';
2
+ import { type CognitionQualityReport } from '../../cognition/cognition-quality.js';
2
3
  export declare function registerDoctorCommand(program: Command): void;
4
+ export declare function printQualityReport(report: CognitionQualityReport): void;
@@ -1,5 +1,6 @@
1
1
  import { readdir } from 'node:fs/promises';
2
2
  import path from 'node:path';
3
+ import { analyzeCognitionQuality, } from '../../cognition/cognition-quality.js';
3
4
  import { loadConfig } from '../../config/config.js';
4
5
  import { listIntegrations } from '../../integrations/integration-store.js';
5
6
  import { assertWorkspace, pathExists, resolveWorkspace, } from '../../storage/kgraph-paths.js';
@@ -9,7 +10,8 @@ export function registerDoctorCommand(program) {
9
10
  program
10
11
  .command('doctor')
11
12
  .description('Check KGraph workspace health and next actions')
12
- .action(() => runCommand(async () => {
13
+ .option('--quality', 'Report stale or noisy cognition references')
14
+ .action((options) => runCommand(async () => {
13
15
  const rootPath = process.cwd();
14
16
  const workspace = resolveWorkspace(rootPath);
15
17
  const checks = [];
@@ -37,8 +39,8 @@ export function registerDoctorCommand(program) {
37
39
  ok: mapStatus,
38
40
  detail: mapStatus ? 'structural maps are present' : 'run `kgraph scan` or just `kgraph`',
39
41
  });
40
- if (mapStatus) {
41
- const maps = await readMaps(workspace);
42
+ const maps = mapStatus ? await readMaps(workspace) : undefined;
43
+ if (maps) {
42
44
  checks.push({
43
45
  label: 'scan result',
44
46
  ok: true,
@@ -79,6 +81,12 @@ export function registerDoctorCommand(program) {
79
81
  .join('; '),
80
82
  });
81
83
  printChecks(checks);
84
+ if (options.quality && maps) {
85
+ console.log('');
86
+ console.log('KGraph Cognition Quality');
87
+ console.log('');
88
+ printQualityReport(await analyzeCognitionQuality(workspace, maps));
89
+ }
82
90
  if (checks.some((check) => !check.ok)) {
83
91
  process.exitCode = 1;
84
92
  }
@@ -98,3 +106,23 @@ function printChecks(checks) {
98
106
  console.log(`${check.ok ? 'OK' : 'FAIL'} ${check.label}: ${check.detail}`);
99
107
  }
100
108
  }
109
+ export function printQualityReport(report) {
110
+ console.log(`Notes: ${report.noteCount}`);
111
+ console.log(`Mixed/stale/unresolved notes: ${report.mixedOrStaleCount}`);
112
+ console.log(`Noisy file refs: ${report.noisyFileRefCount}`);
113
+ console.log(`Noisy symbol refs: ${report.noisySymbolRefCount}`);
114
+ if (report.changes.length === 0) {
115
+ return;
116
+ }
117
+ console.log('');
118
+ for (const change of report.changes) {
119
+ console.log(`- ${change.title}`);
120
+ for (const ref of change.removedFileRefs) {
121
+ console.log(` remove file ref: ${ref}`);
122
+ }
123
+ for (const ref of change.removedSymbolRefs) {
124
+ console.log(` remove symbol ref: ${ref}`);
125
+ }
126
+ console.log(` next status: ${change.nextStatus}`);
127
+ }
128
+ }
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerRepairCommand(program: Command): void;
@@ -0,0 +1,31 @@
1
+ import { repairCognition } from '../../cognition/cognition-quality.js';
2
+ import { assertWorkspace } from '../../storage/kgraph-paths.js';
3
+ import { mapsExist, readMaps } from '../../storage/map-store.js';
4
+ import { KGraphError, runCommand } from '../errors.js';
5
+ import { printQualityReport } from './doctor.js';
6
+ export function registerRepairCommand(program) {
7
+ program
8
+ .command('repair')
9
+ .description('Clean noisy stale references from KGraph cognition')
10
+ .option('--dry-run', 'Show proposed cognition cleanup without writing files')
11
+ .action((options) => runCommand(async () => {
12
+ const workspace = await assertWorkspace(process.cwd());
13
+ if (!(await mapsExist(workspace))) {
14
+ throw new KGraphError('KGraph maps are missing. Run `kgraph scan` first.');
15
+ }
16
+ const maps = await readMaps(workspace);
17
+ const report = await repairCognition(workspace, maps, Boolean(options.dryRun));
18
+ console.log(options.dryRun
19
+ ? 'KGraph Repair Dry Run'
20
+ : 'KGraph Repair');
21
+ console.log('');
22
+ printQualityReport(report);
23
+ if (report.changes.length === 0) {
24
+ console.log('No noisy cognition references found.');
25
+ }
26
+ else if (options.dryRun) {
27
+ console.log('');
28
+ console.log('Run `kgraph repair` to apply these changes.');
29
+ }
30
+ }));
31
+ }
@@ -3,13 +3,19 @@ import { refreshCognitionReferenceStatuses } from '../../cognition/cognition-upd
3
3
  import { loadConfig } from '../../config/config.js';
4
4
  import { queryContext } from '../../context/context-query.js';
5
5
  import { scanRepository } from '../../scanner/repo-scanner.js';
6
- import { assertWorkspace } from '../../storage/kgraph-paths.js';
6
+ import { assertWorkspace, pathExists, resolveWorkspace, } from '../../storage/kgraph-paths.js';
7
7
  import { readMaps, writeMaps } from '../../storage/map-store.js';
8
8
  import { runCommand } from '../errors.js';
9
+ import { renderRootHelp, renderWorkflowBanner } from '../help.js';
9
10
  import { renderContextMarkdown } from './context.js';
10
11
  export async function runDefaultWorkflow(query) {
11
12
  await runCommand(async () => {
12
13
  const topic = query?.trim();
14
+ const candidateWorkspace = resolveWorkspace(process.cwd());
15
+ if (!topic && !(await pathExists(candidateWorkspace.kgraphPath))) {
16
+ console.log(renderRootHelp());
17
+ return;
18
+ }
13
19
  const workspace = await assertWorkspace(process.cwd());
14
20
  const config = await loadConfig(workspace);
15
21
  const previousMaps = await readMaps(workspace);
@@ -26,12 +32,16 @@ export async function runDefaultWorkflow(query) {
26
32
  symbols: scan.symbols,
27
33
  });
28
34
  const update = await updateCognition(workspace, { files: scan.files, symbols: scan.symbols }, false);
29
- console.log(`KGraph refreshed ${scan.files.length} files, ${scan.symbols.length} symbols, and ${update.processed.length} cognition notes.`);
35
+ console.log(renderWorkflowBanner({
36
+ files: scan.files.length,
37
+ symbols: scan.symbols.length,
38
+ cognitionNotes: update.processed.length,
39
+ }));
40
+ console.log('');
30
41
  for (const warning of [...scan.warnings, ...update.warnings]) {
31
42
  console.warn(`Warning: ${warning}`);
32
43
  }
33
44
  if (!topic) {
34
- console.log('Add a topic to return compact context, for example: kgraph "auth token refresh"');
35
45
  return;
36
46
  }
37
47
  const maps = await readMaps(workspace);
@@ -1 +1,8 @@
1
1
  export declare function renderRootHelp(useColor?: boolean): string;
2
+ interface WorkflowBannerStats {
3
+ files: number;
4
+ symbols: number;
5
+ cognitionNotes: number;
6
+ }
7
+ export declare function renderWorkflowBanner(stats: WorkflowBannerStats, useColor?: boolean): string;
8
+ export {};
package/dist/cli/help.js CHANGED
@@ -30,6 +30,9 @@ export function renderRootHelp(useColor = supportsColor()) {
30
30
  command('context "auth token refresh"', 'Optional: return context without scanning or updating'),
31
31
  command('update', 'Optional: process only .kgraph/inbox Markdown cognition notes'),
32
32
  command('doctor', 'Check workspace health and next actions'),
33
+ command('doctor --quality', 'Report stale/noisy cognition references'),
34
+ command('repair --dry-run', 'Preview cognition reference cleanup'),
35
+ command('repair', 'Clean noisy stale cognition references'),
33
36
  command('visualize', 'Interactive dependency graph at http://localhost:4242'),
34
37
  command('history', 'Timeline of processed cognition sessions'),
35
38
  '',
@@ -51,6 +54,27 @@ export function renderRootHelp(useColor = supportsColor()) {
51
54
  '',
52
55
  ].join('\n');
53
56
  }
57
+ export function renderWorkflowBanner(stats, useColor = supportsColor()) {
58
+ const theme = new Chalk({ level: useColor ? 3 : 0 });
59
+ const command = (name, description) => ` ${theme.green(name.padEnd(30))} ${description}`;
60
+ return [
61
+ '',
62
+ theme.hex('#7dd3fc').bold(renderLogo()),
63
+ '',
64
+ ` ${theme.bold('KGraph')} ${theme.dim('repo intelligence refreshed')}`,
65
+ '',
66
+ theme.bold('Refresh Complete'),
67
+ command('files', String(stats.files)),
68
+ command('symbols', String(stats.symbols)),
69
+ command('cognition notes processed', String(stats.cognitionNotes)),
70
+ '',
71
+ theme.bold('Next'),
72
+ command('kgraph "auth token refresh"', 'Return compact context for a topic'),
73
+ command('kgraph doctor', 'Check workspace health'),
74
+ command('kgraph doctor --quality', 'Check cognition quality'),
75
+ command('kgraph --help', 'Show all commands'),
76
+ ].join('\n');
77
+ }
54
78
  function renderLogo() {
55
79
  try {
56
80
  return figlet.textSync('KGraph', {
package/dist/cli/index.js CHANGED
@@ -8,6 +8,7 @@ import { registerDoctorCommand } from './commands/doctor.js';
8
8
  import { registerHistoryCommand } from './commands/history.js';
9
9
  import { registerInitCommand } from './commands/init.js';
10
10
  import { registerIntegrateCommand } from './commands/integrate.js';
11
+ import { registerRepairCommand } from './commands/repair.js';
11
12
  import { registerScanCommand } from './commands/scan.js';
12
13
  import { registerUpdateCommand } from './commands/update.js';
13
14
  import { registerVisualizeCommand } from './commands/visualize.js';
@@ -42,6 +43,7 @@ export function createProgram() {
42
43
  registerVisualizeCommand(program);
43
44
  registerHistoryCommand(program);
44
45
  registerDoctorCommand(program);
46
+ registerRepairCommand(program);
45
47
  return program;
46
48
  }
47
49
  if (isCliEntrypoint()) {
@@ -0,0 +1,25 @@
1
+ import type { KGraphWorkspace } from '../types/config.js';
2
+ import type { ReferenceStatus } from '../types/cognition.js';
3
+ import type { FileMap, SymbolMap } from '../types/maps.js';
4
+ export interface CognitionRepairChange {
5
+ noteId: string;
6
+ title: string;
7
+ removedFileRefs: string[];
8
+ removedSymbolRefs: string[];
9
+ nextStatus: ReferenceStatus;
10
+ }
11
+ export interface CognitionQualityReport {
12
+ noteCount: number;
13
+ mixedOrStaleCount: number;
14
+ noisyFileRefCount: number;
15
+ noisySymbolRefCount: number;
16
+ changes: CognitionRepairChange[];
17
+ }
18
+ export declare function analyzeCognitionQuality(workspace: KGraphWorkspace, maps: {
19
+ fileMap: FileMap;
20
+ symbolMap: SymbolMap;
21
+ }): Promise<CognitionQualityReport>;
22
+ export declare function repairCognition(workspace: KGraphWorkspace, maps: {
23
+ fileMap: FileMap;
24
+ symbolMap: SymbolMap;
25
+ }, dryRun?: boolean): Promise<CognitionQualityReport>;
@@ -0,0 +1,111 @@
1
+ import { overwriteDomainRecord, readCognitionNotes, readDomainRecords, writeCognitionNote, } from '../storage/cognition-store.js';
2
+ export async function analyzeCognitionQuality(workspace, maps) {
3
+ const notes = await readCognitionNotes(workspace);
4
+ const changes = notes
5
+ .map((note) => analyzeNote(note, maps))
6
+ .filter((change) => change.removedFileRefs.length > 0 ||
7
+ change.removedSymbolRefs.length > 0);
8
+ return {
9
+ noteCount: notes.length,
10
+ mixedOrStaleCount: notes.filter((note) => ['mixed', 'stale', 'unresolved'].includes(note.referencesStatus)).length,
11
+ noisyFileRefCount: changes.reduce((total, change) => total + change.removedFileRefs.length, 0),
12
+ noisySymbolRefCount: changes.reduce((total, change) => total + change.removedSymbolRefs.length, 0),
13
+ changes,
14
+ };
15
+ }
16
+ export async function repairCognition(workspace, maps, dryRun = false) {
17
+ const notes = await readCognitionNotes(workspace);
18
+ const nextNotes = [];
19
+ const changes = [];
20
+ for (const note of notes) {
21
+ const change = analyzeNote(note, maps);
22
+ const nextNote = applyChange(note, change);
23
+ nextNotes.push(nextNote);
24
+ if (change.removedFileRefs.length > 0 ||
25
+ change.removedSymbolRefs.length > 0) {
26
+ changes.push(change);
27
+ if (!dryRun) {
28
+ await writeCognitionNote(workspace, nextNote);
29
+ }
30
+ }
31
+ }
32
+ if (!dryRun && changes.length > 0) {
33
+ await repairDomainRecords(workspace, nextNotes, maps);
34
+ }
35
+ return {
36
+ noteCount: notes.length,
37
+ mixedOrStaleCount: nextNotes.filter((note) => ['mixed', 'stale', 'unresolved'].includes(note.referencesStatus)).length,
38
+ noisyFileRefCount: changes.reduce((total, change) => total + change.removedFileRefs.length, 0),
39
+ noisySymbolRefCount: changes.reduce((total, change) => total + change.removedSymbolRefs.length, 0),
40
+ changes,
41
+ };
42
+ }
43
+ function analyzeNote(note, maps) {
44
+ const filePaths = new Set(maps.fileMap.files.map((file) => file.path));
45
+ const symbolNames = new Set(maps.symbolMap.symbols.map((symbol) => symbol.name));
46
+ const removedFileRefs = note.relatedFiles.filter((ref) => !filePaths.has(ref) && isNoisyFileRef(ref));
47
+ const removedSymbolRefs = note.relatedSymbols.filter((ref) => !symbolNames.has(ref) && isNoisySymbolRef(ref));
48
+ const nextFiles = note.relatedFiles.filter((ref) => !removedFileRefs.includes(ref));
49
+ const nextSymbols = note.relatedSymbols.filter((ref) => !removedSymbolRefs.includes(ref));
50
+ return {
51
+ noteId: note.id,
52
+ title: note.title,
53
+ removedFileRefs,
54
+ removedSymbolRefs,
55
+ nextStatus: evaluateReferenceStatus(nextFiles, nextSymbols, maps),
56
+ };
57
+ }
58
+ function applyChange(note, change) {
59
+ return {
60
+ ...note,
61
+ relatedFiles: note.relatedFiles.filter((ref) => !change.removedFileRefs.includes(ref)),
62
+ relatedSymbols: note.relatedSymbols.filter((ref) => !change.removedSymbolRefs.includes(ref)),
63
+ referencesStatus: change.nextStatus,
64
+ };
65
+ }
66
+ async function repairDomainRecords(workspace, notes, maps) {
67
+ const domains = await readDomainRecords(workspace);
68
+ const filePaths = new Set(maps.fileMap.files.map((file) => file.path));
69
+ const symbolNames = new Set(maps.symbolMap.symbols.map((symbol) => symbol.name));
70
+ const notesById = new Map(notes.map((note) => [note.id, note]));
71
+ for (const domain of domains) {
72
+ const relatedNotes = domain.cognitionNotes
73
+ .map((id) => notesById.get(id))
74
+ .filter((note) => Boolean(note));
75
+ const next = {
76
+ ...domain,
77
+ pathHints: unique(relatedNotes.flatMap((note) => note.relatedFiles)),
78
+ files: unique(relatedNotes
79
+ .flatMap((note) => note.relatedFiles)
80
+ .filter((file) => filePaths.has(file))),
81
+ symbols: unique(relatedNotes
82
+ .flatMap((note) => note.relatedSymbols)
83
+ .filter((symbol) => symbolNames.has(symbol))),
84
+ };
85
+ await overwriteDomainRecord(workspace, next);
86
+ }
87
+ }
88
+ function evaluateReferenceStatus(relatedFiles, relatedSymbols, maps) {
89
+ const filePaths = new Set(maps.fileMap.files.map((file) => file.path));
90
+ const symbolNames = new Set(maps.symbolMap.symbols.map((symbol) => symbol.name));
91
+ const references = [
92
+ ...relatedFiles.map((file) => filePaths.has(file)),
93
+ ...relatedSymbols.map((symbol) => symbolNames.has(symbol)),
94
+ ];
95
+ if (references.length === 0)
96
+ return 'unresolved';
97
+ if (references.every(Boolean))
98
+ return 'current';
99
+ if (references.every((value) => !value))
100
+ return 'stale';
101
+ return 'mixed';
102
+ }
103
+ function isNoisyFileRef(ref) {
104
+ return !ref.includes('/') && /^[A-Z][A-Za-z0-9_-]*\.[A-Za-z0-9_-]+$/.test(ref);
105
+ }
106
+ function isNoisySymbolRef(ref) {
107
+ return /^[a-z][A-Za-z0-9_$]*$/.test(ref);
108
+ }
109
+ function unique(items) {
110
+ return [...new Set(items)];
111
+ }
@@ -14,13 +14,14 @@ Before exploring the repository, run \`kgraph "<topic>"\` to refresh repo intell
14
14
  1. Infer the topic from the user's request.
15
15
  2. Run \`kgraph "<topic>"\`. This refreshes maps, processes pending inbox notes, and returns focused context in one command.
16
16
  3. Use the returned files, symbols, relationships, and cognition before broad exploration.
17
- 4. Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong.
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
18
  5. At the end of any session that changed repository files, check the KGraph capture workflow before finishing.
19
19
  6. If the file change has future value, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\`; otherwise explicitly skip capture as trivial.
20
20
  7. 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.
21
21
  8. 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.
22
- 9. Run \`kgraph visualize\` when the user wants to inspect the dependency graph opens an interactive graph at http://localhost:4242 with PNG export.
23
- 10. Run \`kgraph history\` to review the timeline of past cognition sessions with git author attribution.
22
+ 9. 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.
23
+ 10. Run \`kgraph visualize\` when the user wants to inspect the dependency graph opens an interactive graph at http://localhost:4242 with PNG export.
24
+ 11. Run \`kgraph history\` to review the timeline of past cognition sessions with git author attribution.
24
25
 
25
26
  The inbox note must use this structure:
26
27
  \`\`\`markdown
@@ -42,7 +43,12 @@ Any implementation or product decision future sessions should know.
42
43
  },
43
44
  {
44
45
  path: '.claude/commands/kgraph-doctor.md',
45
- content: `Run \`kgraph doctor\` to check whether the workspace is initialized, maps exist, inbox notes are pending, and configured integrations point to real files. Summarize any failed checks and the next command to run.
46
+ content: `Run \`kgraph doctor\` to check whether the workspace is initialized, maps exist, inbox notes are pending, and configured integrations point to real files. Use \`kgraph doctor --quality\` when the user asks about stale or noisy cognition references. Summarize any failed checks and the next command to run.
47
+ `,
48
+ },
49
+ {
50
+ path: '.claude/commands/kgraph-repair.md',
51
+ content: `Run \`kgraph repair --dry-run\` first and summarize the proposed cognition cleanup. Run \`kgraph repair\` only when the user asks to apply the cleanup.
46
52
  `,
47
53
  },
48
54
  {
@@ -21,13 +21,14 @@ Workflow:
21
21
  1. Infer the current topic from the user request.
22
22
  2. Run \`kgraph "<topic>"\` before broad repo exploration. This refreshes maps, processes pending inbox notes, and returns focused context in one command.
23
23
  3. Use KGraph's returned files, symbols, relationships, and cognition as navigation hints.
24
- 4. Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong.
24
+ 4. Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong. Run \`kgraph doctor --quality\` when context shows stale/noisy cognition references.
25
25
  5. At the end of any session that changed repository files, check the KGraph capture workflow before finishing.
26
26
  6. If the file change has future value, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\`; otherwise explicitly skip capture as trivial.
27
27
  7. 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.
28
28
  8. 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.
29
- 9. Run \`kgraph visualize\` when the user wants to inspect the dependency graph opens an interactive graph at http://localhost:4242 with PNG export.
30
- 10. Run \`kgraph history\` to review the timeline of past cognition sessions with git author attribution.
29
+ 9. 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.
30
+ 10. Run \`kgraph visualize\` when the user wants to inspect the dependency graph opens an interactive graph at http://localhost:4242 with PNG export.
31
+ 11. Run \`kgraph history\` to review the timeline of past cognition sessions with git author attribution.
31
32
 
32
33
  The inbox note must use this structure:
33
34
  \`\`\`markdown
@@ -5,11 +5,12 @@ export const copilotAdapter = {
5
5
  instructions: `## KGraph Workflow
6
6
 
7
7
  1. **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.
8
- 2. Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong.
8
+ 2. Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong. Run \`kgraph doctor --quality\` when context shows stale/noisy cognition references.
9
9
  3. At the end of any session that changed repository files, check the KGraph capture workflow before finishing.
10
10
  4. If the file change has future value, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\`; otherwise explicitly skip capture as trivial.
11
11
  5. 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.
12
12
  6. 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.
13
+ 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.
13
14
 
14
15
  The inbox note must use this structure:
15
16
  \`\`\`markdown
@@ -36,7 +37,18 @@ description: Check KGraph workspace health and next actions
36
37
  agent: agent
37
38
  ---
38
39
 
39
- Run \`kgraph doctor\` to check whether the workspace is initialized, maps exist, inbox notes are pending, and configured integrations point to real files. Summarize any failed checks and the next command to run.
40
+ Run \`kgraph doctor\` to check whether the workspace is initialized, maps exist, inbox notes are pending, and configured integrations point to real files. Use \`kgraph doctor --quality\` when the user asks about stale or noisy cognition references. Summarize any failed checks and the next command to run.
41
+ `,
42
+ },
43
+ {
44
+ path: '.github/prompts/kgraph-repair.prompt.md',
45
+ content: `---
46
+ description: Preview or clean stale/noisy KGraph cognition references
47
+ agent: agent
48
+ argument-hint: "--dry-run or apply"
49
+ ---
50
+
51
+ Run \`kgraph repair --dry-run\` first and summarize the proposed cognition cleanup. Run \`kgraph repair\` only when the user asks to apply the cleanup.
40
52
  `,
41
53
  },
42
54
  {
@@ -10,11 +10,12 @@ alwaysApply: true
10
10
  ## KGraph Workflow
11
11
 
12
12
  - **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.
13
- - Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong.
13
+ - Run \`kgraph doctor\` when setup, maps, inbox processing, or integrations look wrong. Run \`kgraph doctor --quality\` when context shows stale/noisy cognition references.
14
14
  - At the end of any session that changed repository files, check the KGraph capture workflow before finishing.
15
15
  - If the file change has future value, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\`; otherwise explicitly skip capture as trivial.
16
16
  - 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.
17
17
  - 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.
18
+ - 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.
18
19
  - Run \`kgraph visualize\` to open the interactive dependency graph at http://localhost:4242 with PNG export.
19
20
  - Run \`kgraph history\` to review the timeline of past cognition sessions with git author attribution.
20
21
  `,
@@ -73,6 +73,12 @@ export function extractTsSymbols(sourceText, filePath) {
73
73
  }
74
74
  });
75
75
  }
76
+ if (ts.isInterfaceDeclaration(node)) {
77
+ addSymbol(node.name.text, "interface", node, isExported(node), parentName);
78
+ }
79
+ if (ts.isTypeAliasDeclaration(node)) {
80
+ addSymbol(node.name.text, "type", node, isExported(node), parentName);
81
+ }
76
82
  ts.forEachChild(node, (child) => visit(child, parentName));
77
83
  };
78
84
  try {
@@ -4,6 +4,7 @@ export declare function listInboxNotes(workspace: KGraphWorkspace): Promise<stri
4
4
  export declare function archiveInboxNote(workspace: KGraphWorkspace, inboxPath: string, timestamp: string): Promise<string>;
5
5
  export declare function writeCognitionNote(workspace: KGraphWorkspace, note: CognitionNote): Promise<string>;
6
6
  export declare function writeDomainRecord(workspace: KGraphWorkspace, domain: DomainRecord): Promise<string>;
7
+ export declare function overwriteDomainRecord(workspace: KGraphWorkspace, domain: DomainRecord): Promise<string>;
7
8
  export declare function readCognitionNotes(workspace: KGraphWorkspace): Promise<CognitionNote[]>;
8
9
  export declare function readDomainRecords(workspace: KGraphWorkspace): Promise<DomainRecord[]>;
9
10
  export declare function slugify(value: string): string;
@@ -33,6 +33,12 @@ export async function writeDomainRecord(workspace, domain) {
33
33
  await writeFile(filePath, renderDomainRecord(merged), "utf8");
34
34
  return filePath;
35
35
  }
36
+ export async function overwriteDomainRecord(workspace, domain) {
37
+ await mkdir(workspace.domainsPath, { recursive: true });
38
+ const filePath = path.join(workspace.domainsPath, `${slugify(domain.name)}.md`);
39
+ await writeFile(filePath, renderDomainRecord(domain), "utf8");
40
+ return filePath;
41
+ }
36
42
  export async function readCognitionNotes(workspace) {
37
43
  if (!(await pathExists(workspace.cognitionPath))) {
38
44
  return [];
@@ -1,6 +1,6 @@
1
1
  export type ScanStatus = "mapped" | "generic" | "failed";
2
2
  export type DependencyKind = "local" | "package" | "unknown";
3
- export type SymbolKind = "function" | "class" | "method" | "export" | "import";
3
+ export type SymbolKind = "function" | "class" | "method" | "type" | "interface" | "export" | "import";
4
4
  export type RelationshipType = "import" | "contains" | "mentions" | "belongs-to-domain" | "stale-reference" | "moved-from";
5
5
  export interface RepositoryFile {
6
6
  id: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kentwynn/kgraph",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "Persistent repo intelligence for AI coding assistants.",
5
5
  "type": "module",
6
6
  "bin": {