@kentwynn/kgraph 0.1.23 → 0.1.25

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
@@ -107,14 +107,14 @@ 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
 
@@ -1,2 +1,2 @@
1
- import type { Command } from "commander";
1
+ import type { Command } from 'commander';
2
2
  export declare function registerInitCommand(program: Command): void;
@@ -1,28 +1,43 @@
1
- import { writeDefaultConfig } from "../../config/config.js";
2
- import { normalizeIntegrationNames } from "../../integrations/integration-registry.js";
3
- import { addIntegrations } from "../../integrations/integration-store.js";
4
- import { ensureWorkspace } from "../../storage/kgraph-paths.js";
5
- import { KGraphError, runCommand } from "../errors.js";
1
+ import { loadConfig, writeDefaultConfig } from '../../config/config.js';
2
+ import { normalizeIntegrationNames } from '../../integrations/integration-registry.js';
3
+ import { addIntegrations } from '../../integrations/integration-store.js';
4
+ import { scanRepository } from '../../scanner/repo-scanner.js';
5
+ import { ensureWorkspace } from '../../storage/kgraph-paths.js';
6
+ import { readMaps, writeMaps } from '../../storage/map-store.js';
7
+ import { KGraphError, runCommand } from '../errors.js';
6
8
  export function registerInitCommand(program) {
7
9
  program
8
- .command("init")
9
- .description("Initialize a .kgraph workspace")
10
- .option("--integration <name>", "Configure an AI tool integration", collectOption, [])
11
- .option("--integrations <names>", "Configure comma-separated AI tool integrations")
12
- .option("--mode <mode>", "Integration mode: smart, always, manual, or off", "always")
10
+ .command('init')
11
+ .description('Initialize a .kgraph workspace')
12
+ .option('--integration <name>', 'Configure an AI tool integration', collectOption, [])
13
+ .option('--integrations <names>', 'Configure comma-separated AI tool integrations')
14
+ .option('--mode <mode>', 'Integration mode: always, smart, manual, or off', 'always')
13
15
  .action((options) => runCommand(async () => {
14
16
  const workspace = await ensureWorkspace(process.cwd());
15
17
  const wroteConfig = await writeDefaultConfig(workspace);
16
- console.log(wroteConfig ? "Initialized .kgraph workspace." : ".kgraph workspace already initialized.");
18
+ console.log(wroteConfig
19
+ ? 'Initialized .kgraph workspace.'
20
+ : '.kgraph workspace already initialized.');
17
21
  const names = normalizeIntegrationNames([
18
22
  ...(options.integration ?? []),
19
- ...(options.integrations ? [options.integrations] : [])
23
+ ...(options.integrations ? [options.integrations] : []),
20
24
  ]);
21
25
  if (names.length > 0) {
22
26
  const mode = normalizeIntegrationMode(options.mode);
23
27
  const changed = await addIntegrations(workspace, names, mode);
24
- console.log(`Configured integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(", ")}`);
28
+ console.log(`Configured integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(', ')}`);
25
29
  }
30
+ const config = await loadConfig(workspace);
31
+ const previousMaps = await readMaps(workspace);
32
+ const result = await scanRepository(workspace.rootPath, config, {
33
+ files: previousMaps.fileMap.files,
34
+ symbols: previousMaps.symbolMap.symbols,
35
+ dependencies: previousMaps.dependencyMap.dependencies,
36
+ relationships: previousMaps.relationshipMap.relationships,
37
+ warnings: [],
38
+ });
39
+ await writeMaps(workspace, result);
40
+ console.log(`Scanned ${result.files.length} files and ${result.symbols.length} symbols.`);
26
41
  }));
27
42
  }
28
43
  function collectOption(value, previous) {
@@ -30,8 +45,11 @@ function collectOption(value, previous) {
30
45
  return previous;
31
46
  }
32
47
  function normalizeIntegrationMode(value) {
33
- if (value === "smart" || value === "always" || value === "manual" || value === "off") {
48
+ if (value === 'smart' ||
49
+ value === 'always' ||
50
+ value === 'manual' ||
51
+ value === 'off') {
34
52
  return value;
35
53
  }
36
- throw new KGraphError("--mode must be smart, always, manual, or off.");
54
+ throw new KGraphError('--mode must be smart, always, manual, or off.');
37
55
  }
@@ -1,2 +1,2 @@
1
- import type { Command } from "commander";
1
+ import type { Command } from 'commander';
2
2
  export declare function registerIntegrateCommand(program: Command): void;
@@ -1,63 +1,75 @@
1
- import { addIntegrations, listIntegrations, removeIntegrations, setIntegrationMode } from "../../integrations/integration-store.js";
2
- import { normalizeIntegrationNames } from "../../integrations/integration-registry.js";
3
- import { assertWorkspace } from "../../storage/kgraph-paths.js";
4
- import { KGraphError, runCommand } from "../errors.js";
1
+ import { normalizeIntegrationNames } from '../../integrations/integration-registry.js';
2
+ import { addIntegrations, listIntegrations, removeIntegrations, setIntegrationMode, } from '../../integrations/integration-store.js';
3
+ import { assertWorkspace } from '../../storage/kgraph-paths.js';
4
+ import { KGraphError, runCommand } from '../errors.js';
5
5
  export function registerIntegrateCommand(program) {
6
- const integrate = program.command("integrate").description("Manage AI tool integrations");
7
- integrate.command("list").description("List configured integrations").action(() => runCommand(async () => {
6
+ const integrate = program
7
+ .command('integrate')
8
+ .description('Manage AI tool integrations');
9
+ integrate
10
+ .command('list')
11
+ .description('List configured integrations')
12
+ .action(() => runCommand(async () => {
8
13
  const workspace = await assertWorkspace(process.cwd());
9
14
  const integrations = await listIntegrations(workspace);
10
15
  if (integrations.length === 0) {
11
- console.log("No integrations configured.");
16
+ console.log('No integrations configured.');
12
17
  return;
13
18
  }
14
19
  for (const integration of integrations) {
15
- console.log(`${integration.name} ${integration.enabled ? "enabled" : "disabled"} ${integration.mode} ${integration.targetPath} ${integration.targetExists ? "present" : "missing"}`);
20
+ console.log(`${integration.name} ${integration.enabled ? 'enabled' : 'disabled'} ${integration.mode} ${integration.targetPath} ${integration.targetExists ? 'present' : 'missing'}`);
16
21
  }
17
22
  }));
18
23
  integrate
19
- .command("add")
20
- .description("Add AI tool integrations")
21
- .argument("<names...>")
22
- .option("--mode <mode>", "smart, always, manual, or off", "always")
24
+ .command('add')
25
+ .description('Add AI tool integrations')
26
+ .argument('<names...>')
27
+ .option('--mode <mode>', 'always, smart, manual, or off', 'always')
23
28
  .action((names, options) => runCommand(async () => {
24
29
  const workspace = await assertWorkspace(process.cwd());
25
30
  const normalized = normalizeIntegrationNames(names);
26
31
  if (normalized.length === 0) {
27
- throw new KGraphError("Provide at least one integration name.");
32
+ throw new KGraphError('Provide at least one integration name.');
28
33
  }
29
34
  const mode = normalizeIntegrationMode(options.mode);
30
35
  const changed = await addIntegrations(workspace, normalized, mode);
31
- console.log(`Configured integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(", ")}`);
36
+ console.log(`Configured integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(', ')}`);
32
37
  }));
33
38
  integrate
34
- .command("set")
35
- .description("Set AI tool integration mode")
36
- .argument("<names...>")
37
- .requiredOption("--mode <mode>", "smart, always, manual, or off")
39
+ .command('set')
40
+ .description('Set AI tool integration mode')
41
+ .argument('<names...>')
42
+ .requiredOption('--mode <mode>', 'smart, always, manual, or off')
38
43
  .action((names, options) => runCommand(async () => {
39
44
  const workspace = await assertWorkspace(process.cwd());
40
45
  const normalized = normalizeIntegrationNames(names);
41
46
  if (normalized.length === 0) {
42
- throw new KGraphError("Provide at least one integration name.");
47
+ throw new KGraphError('Provide at least one integration name.');
43
48
  }
44
49
  const mode = normalizeIntegrationMode(options.mode);
45
50
  const changed = await setIntegrationMode(workspace, normalized, mode);
46
- console.log(`Updated integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(", ")}`);
51
+ console.log(`Updated integrations: ${changed.map((item) => `${item.name}:${item.mode}`).join(', ')}`);
47
52
  }));
48
- integrate.command("remove").description("Remove AI tool integrations").argument("<names...>").action((names) => runCommand(async () => {
53
+ integrate
54
+ .command('remove')
55
+ .description('Remove AI tool integrations')
56
+ .argument('<names...>')
57
+ .action((names) => runCommand(async () => {
49
58
  const workspace = await assertWorkspace(process.cwd());
50
59
  const normalized = normalizeIntegrationNames(names);
51
60
  if (normalized.length === 0) {
52
- throw new KGraphError("Provide at least one integration name.");
61
+ throw new KGraphError('Provide at least one integration name.');
53
62
  }
54
63
  const removed = await removeIntegrations(workspace, normalized);
55
- console.log(`Removed integrations: ${removed.join(", ")}`);
64
+ console.log(`Removed integrations: ${removed.join(', ')}`);
56
65
  }));
57
66
  }
58
67
  function normalizeIntegrationMode(value) {
59
- if (value === "smart" || value === "always" || value === "manual" || value === "off") {
68
+ if (value === 'smart' ||
69
+ value === 'always' ||
70
+ value === 'manual' ||
71
+ value === 'off') {
60
72
  return value;
61
73
  }
62
- throw new KGraphError("--mode must be smart, always, manual, or off.");
74
+ throw new KGraphError('--mode must be smart, always, manual, or off.');
63
75
  }
@@ -1,8 +1,9 @@
1
1
  import YAML from 'yaml';
2
2
  const PATH_REF = /(?:^|\s|`?)([\w./-]+\.(?:ts|tsx|js|jsx|json|md|yaml|yml))(?:\s|$|[),.;`])/g;
3
3
  export function parseMarkdownNote(markdown) {
4
+ const normalized = markdown.replace(/\r\n/g, '\n');
4
5
  const warnings = [];
5
- const { frontmatter, body } = splitFrontmatter(markdown, warnings);
6
+ const { frontmatter, body } = splitFrontmatter(normalized, warnings);
6
7
  const sections = parseSections(body);
7
8
  const frontmatterTitle = typeof frontmatter.title === 'string' ? frontmatter.title : undefined;
8
9
  const title = extractTitle(body) ?? frontmatterTitle ?? 'Untitled Cognition Note';
@@ -17,30 +17,12 @@ export const claudeCodeAdapter = {
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
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
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.
27
20
 
28
- The inbox note must use this structure:
29
- \`\`\`markdown
30
- # <Short Title>
21
+ {{KGRAPH_CAPTURE_POLICY}}
31
22
 
32
- ## Summary
33
- One or two sentences describing the durable change or finding.
34
-
35
- ## Key Files
36
- - \`path/to/file.ts\` — what changed or why it matters
37
-
38
- ## Key Symbols
39
- - \`FunctionName\` — what changed or why it matters
40
-
41
- ## Decisions
42
- Any implementation or product decision future sessions should know.
43
- \`\`\`
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.
44
26
  `,
45
27
  },
46
28
  {
@@ -8,10 +8,7 @@ export const clineAdapter = {
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
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\`.
10
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.
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.
11
+ {{KGRAPH_CAPTURE_POLICY}}
15
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.
16
13
  - Run \`kgraph visualize\` to open the interactive dependency graph at http://localhost:4242 with PNG export.
17
14
  - Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
@@ -24,30 +24,12 @@ Workflow:
24
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. Track meaningful session activity with \`kgraph session start --agent codex\`, \`kgraph session read <path> --agent codex\`, \`kgraph session write <path> --agent codex\`, and \`kgraph session end --agent codex\`.
26
26
  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.
27
- 7. At the end of any session that changed repository files, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\` before finishing.
28
- 8. Do not skip capture for UI text, button, link, route, styling, or small file edits. Skip capture only when no repository files changed.
29
- 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.
30
- 10. After the final \`kgraph\` run, mention whether the inbox note was processed.
31
- 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.
32
- 12. Run \`kgraph visualize\` when the user wants to inspect the dependency graph — opens an interactive graph at http://localhost:4242 with PNG export.
33
- 13. Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
34
27
 
35
- The inbox note must use this structure:
36
- \`\`\`markdown
37
- # <Short Title>
28
+ {{KGRAPH_CAPTURE_POLICY}}
38
29
 
39
- ## Summary
40
- One or two sentences describing the durable change or finding.
41
-
42
- ## Key Files
43
- - \`path/to/file.ts\` — what changed or why it matters
44
-
45
- ## Key Symbols
46
- - \`FunctionName\` — what changed or why it matters
47
-
48
- ## Decisions
49
- Any implementation or product decision future sessions should know.
50
- \`\`\`
30
+ 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.
31
+ 8. Run \`kgraph visualize\` when the user wants to inspect the dependency graph — opens an interactive graph at http://localhost:4242 with PNG export.
32
+ 9. Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
51
33
  `,
52
34
  },
53
35
  ],
@@ -8,28 +8,10 @@ export const copilotAdapter = {
8
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. Track meaningful session activity with \`kgraph session start --agent copilot\`, \`kgraph session read <path> --agent copilot\`, \`kgraph session write <path> --agent copilot\`, and \`kgraph session end --agent copilot\`.
10
10
  4. 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.
11
- 5. At the end of any session that changed repository files, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\` before finishing.
12
- 6. Do not skip capture for UI text, button, link, route, styling, or small file edits. Skip capture only when no repository files changed.
13
- 7. 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
- 8. After the final \`kgraph\` run, mention whether the inbox note was processed.
15
- 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.
16
11
 
17
- The inbox note must use this structure:
18
- \`\`\`markdown
19
- # <Short Title>
12
+ {{KGRAPH_CAPTURE_POLICY}}
20
13
 
21
- ## Summary
22
- One or two sentences describing what was done.
23
-
24
- ## Key Files
25
- - \`path/to/file.ts\` — what it does
26
-
27
- ## Key Symbols
28
- - \`FunctionName\` — what it does
29
-
30
- ## Decisions
31
- Any architectural or implementation decisions made.
32
- \`\`\`
14
+ 5. 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.
33
15
  `,
34
16
  commandFiles: [
35
17
  {
@@ -93,27 +75,7 @@ argument-hint: "Brief description of what was done"
93
75
 
94
76
  Capture this session into KGraph cognition.
95
77
 
96
- 1. For any completed code or repo-file change, write one Markdown note to \`.kgraph/inbox/<slug>.md\` using the structure below.
97
- 2. Do not skip capture for UI text, button, link, route, styling, or small file edits. Skip capture only when no repository files changed.
98
- 3. Use the user's message as context, but keep the note factual and concise.
99
- 4. Run \`kgraph\` once to process the note and refresh maps. Use \`kgraph update\` only when you intentionally want inbox processing without a scan.
100
-
101
- Note structure:
102
- \`\`\`markdown
103
- # <Short Title>
104
-
105
- ## Summary
106
- One or two sentences describing what was done.
107
-
108
- ## Key Files
109
- - \`path/to/file.ts\` — what it does
110
-
111
- ## Key Symbols
112
- - \`FunctionName\` — what it does
113
-
114
- ## Decisions
115
- Any architectural or implementation decisions made.
116
- \`\`\`
78
+ {{KGRAPH_CAPTURE_POLICY}}
117
79
  `,
118
80
  },
119
81
  {
@@ -13,10 +13,7 @@ alwaysApply: true
13
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
  - Track meaningful session activity with \`kgraph session start --agent cursor\`, \`kgraph session read <path> --agent cursor\`, \`kgraph session write <path> --agent cursor\`, and \`kgraph session end --agent cursor\`.
15
15
  - 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.
16
- - At the end of any session that changed repository files, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\` before finishing.
17
- - Do not skip capture for UI text, button, link, route, styling, or small file edits. Skip capture only when no repository files changed.
18
- - 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.
19
- - After the final \`kgraph\` run, mention whether the inbox note was processed.
16
+ {{KGRAPH_CAPTURE_POLICY}}
20
17
  - 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.
21
18
  - Run \`kgraph visualize\` to open the interactive dependency graph at http://localhost:4242 with PNG export.
22
19
  - Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
@@ -8,10 +8,7 @@ export const geminiAdapter = {
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
9
  - Track meaningful session activity with \`kgraph session start --agent gemini\`, \`kgraph session read <path> --agent gemini\`, \`kgraph session write <path> --agent gemini\`, and \`kgraph session end --agent gemini\`.
10
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.
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.
11
+ {{KGRAPH_CAPTURE_POLICY}}
15
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.
16
13
  - Run \`kgraph visualize\` to open the interactive dependency graph at http://localhost:4242 with PNG export.
17
14
  - Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
@@ -8,10 +8,7 @@ export const windsurfAdapter = {
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
9
  - Track meaningful session activity with \`kgraph session start --agent windsurf\`, \`kgraph session read <path> --agent windsurf\`, \`kgraph session write <path> --agent windsurf\`, and \`kgraph session end --agent windsurf\`.
10
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.
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.
11
+ {{KGRAPH_CAPTURE_POLICY}}
15
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.
16
13
  - Run \`kgraph visualize\` to open the interactive dependency graph at http://localhost:4242 with PNG export.
17
14
  - Run \`kgraph history\` or \`kgraph history "<topic>"\` to review past cognition sessions with git author attribution.
@@ -1,6 +1,8 @@
1
- import type { IntegrationMode } from "../types/config.js";
1
+ import type { IntegrationMode } from '../types/config.js';
2
2
  export declare const KGRAPH_CONTEXT_POLICY_PLACEHOLDER = "{{KGRAPH_CONTEXT_POLICY}}";
3
+ export declare const KGRAPH_CAPTURE_POLICY_PLACEHOLDER = "{{KGRAPH_CAPTURE_POLICY}}";
3
4
  export declare function upsertManagedBlock(content: string, integrationName: string, instructions: string): string;
4
5
  export declare function removeManagedBlock(content: string, integrationName: string): string;
5
6
  export declare function applyContextPolicy(content: string, mode: IntegrationMode): string;
6
7
  export declare function renderContextPolicy(mode: IntegrationMode): string;
8
+ export declare function renderCapturePolicy(): string;
@@ -1,6 +1,7 @@
1
- const MARKER_PREFIX = "<!--";
2
- const MARKER_SUFFIX = "-->";
3
- export const KGRAPH_CONTEXT_POLICY_PLACEHOLDER = "{{KGRAPH_CONTEXT_POLICY}}";
1
+ const MARKER_PREFIX = '<!--';
2
+ const MARKER_SUFFIX = '-->';
3
+ export const KGRAPH_CONTEXT_POLICY_PLACEHOLDER = '{{KGRAPH_CONTEXT_POLICY}}';
4
+ export const KGRAPH_CAPTURE_POLICY_PLACEHOLDER = '{{KGRAPH_CAPTURE_POLICY}}';
4
5
  export function upsertManagedBlock(content, integrationName, instructions) {
5
6
  const normalized = content.trimEnd();
6
7
  const block = renderManagedBlock(integrationName, instructions);
@@ -8,37 +9,67 @@ export function upsertManagedBlock(content, integrationName, instructions) {
8
9
  if (pattern.test(content)) {
9
10
  return content.replace(pattern, block);
10
11
  }
11
- return `${normalized}${normalized ? "\n\n" : ""}${block}\n`;
12
+ return normalized ? `${block}\n\n${normalized}\n` : `${block}\n`;
12
13
  }
13
14
  export function removeManagedBlock(content, integrationName) {
14
- return content.replace(managedBlockPattern(integrationName), "").replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
15
+ return (content
16
+ .replace(managedBlockPattern(integrationName), '')
17
+ .replace(/\n{3,}/g, '\n\n')
18
+ .trim() + '\n');
15
19
  }
16
20
  function renderManagedBlock(integrationName, instructions) {
17
21
  return [
18
22
  `${MARKER_PREFIX} BEGIN KGRAPH ${integrationName} ${MARKER_SUFFIX}`,
19
23
  instructions.trim(),
20
- `${MARKER_PREFIX} END KGRAPH ${integrationName} ${MARKER_SUFFIX}`
21
- ].join("\n");
24
+ `${MARKER_PREFIX} END KGRAPH ${integrationName} ${MARKER_SUFFIX}`,
25
+ ].join('\n');
22
26
  }
23
27
  function managedBlockPattern(integrationName) {
24
- return new RegExp(`${escapeRegExp(MARKER_PREFIX)} BEGIN KGRAPH ${escapeRegExp(integrationName)} ${escapeRegExp(MARKER_SUFFIX)}[\\s\\S]*?${escapeRegExp(MARKER_PREFIX)} END KGRAPH ${escapeRegExp(integrationName)} ${escapeRegExp(MARKER_SUFFIX)}\\n?`, "m");
28
+ return new RegExp(`${escapeRegExp(MARKER_PREFIX)} BEGIN KGRAPH ${escapeRegExp(integrationName)} ${escapeRegExp(MARKER_SUFFIX)}[\\s\\S]*?${escapeRegExp(MARKER_PREFIX)} END KGRAPH ${escapeRegExp(integrationName)} ${escapeRegExp(MARKER_SUFFIX)}\\n?`, 'm');
25
29
  }
26
30
  function escapeRegExp(value) {
27
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
31
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
28
32
  }
29
33
  export function applyContextPolicy(content, mode) {
30
- return content.replaceAll(KGRAPH_CONTEXT_POLICY_PLACEHOLDER, renderContextPolicy(mode));
34
+ return content
35
+ .replaceAll(KGRAPH_CONTEXT_POLICY_PLACEHOLDER, renderContextPolicy(mode))
36
+ .replaceAll(KGRAPH_CAPTURE_POLICY_PLACEHOLDER, renderCapturePolicy());
31
37
  }
32
38
  export function renderContextPolicy(mode) {
33
39
  switch (mode) {
34
- case "always":
40
+ case 'always':
35
41
  return 'Every chat in this repository must start by running `kgraph "<topic>"` before answering or exploring files. Infer the topic from the user\'s message; no exceptions, including simple or conversational requests.';
36
- case "manual":
42
+ case 'manual':
37
43
  return 'Do not run KGraph automatically. Run `kgraph "<topic>"` only when the user explicitly asks for KGraph context or invokes the KGraph command.';
38
- case "off":
39
- return "KGraph is disabled for this integration.";
40
- case "smart":
44
+ case 'off':
45
+ return 'KGraph is disabled for this integration.';
46
+ case 'smart':
41
47
  default:
42
48
  return 'For repo-specific coding, debugging, architecture, refactor, review, or file-exploration requests, run `kgraph "<topic>"` before broad repository exploration. Infer the topic from the user\'s message. Skip KGraph for simple conversational requests that do not depend on repo knowledge.';
43
49
  }
44
50
  }
51
+ export function renderCapturePolicy() {
52
+ return `Capture policy:
53
+ - At the end of any session that changed repository files, write one concise Markdown note to \`.kgraph/inbox/<slug>.md\` before finishing.
54
+ - A \`.kgraph/inbox/*.md\` note is KGraph runtime capture, not project documentation. It is allowed and required by this workflow unless the user explicitly says not to capture to KGraph.
55
+ - Do not skip capture for UI text, button, link, route, styling, or small file edits. Skip capture only when no repository files changed.
56
+ - 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.
57
+ - After the final \`kgraph\` run, mention whether the inbox note was processed.
58
+
59
+ The inbox note must use this structure:
60
+ \`\`\`markdown
61
+ # <Short Title>
62
+
63
+ ## Summary
64
+ One or two sentences describing what was done.
65
+
66
+ ## Key Files
67
+ - \`path/to/file.ts\` - what changed or why it matters
68
+
69
+ ## Key Symbols
70
+ - \`FunctionName\` - what changed or why it matters
71
+
72
+ ## Decisions
73
+ Any implementation or product decision future sessions should know.
74
+ \`\`\``;
75
+ }
@@ -1,4 +1,4 @@
1
- import type { IntegrationName } from "../types/config.js";
1
+ import type { IntegrationName } from '../types/config.js';
2
2
  export interface IntegrationAdapter {
3
3
  name: IntegrationName;
4
4
  label: string;
@@ -1,10 +1,10 @@
1
- import { claudeCodeAdapter } from "./adapters/claude-code.js";
2
- import { clineAdapter } from "./adapters/cline.js";
3
- import { codexAdapter } from "./adapters/codex.js";
4
- import { copilotAdapter } from "./adapters/copilot.js";
5
- import { cursorAdapter } from "./adapters/cursor.js";
6
- import { geminiAdapter } from "./adapters/gemini.js";
7
- import { windsurfAdapter } from "./adapters/windsurf.js";
1
+ import { claudeCodeAdapter } from './adapters/claude-code.js';
2
+ import { clineAdapter } from './adapters/cline.js';
3
+ import { codexAdapter } from './adapters/codex.js';
4
+ import { copilotAdapter } from './adapters/copilot.js';
5
+ import { cursorAdapter } from './adapters/cursor.js';
6
+ import { geminiAdapter } from './adapters/gemini.js';
7
+ import { windsurfAdapter } from './adapters/windsurf.js';
8
8
  const ADAPTERS = [
9
9
  claudeCodeAdapter,
10
10
  clineAdapter,
@@ -12,7 +12,7 @@ const ADAPTERS = [
12
12
  copilotAdapter,
13
13
  cursorAdapter,
14
14
  geminiAdapter,
15
- windsurfAdapter
15
+ windsurfAdapter,
16
16
  ].sort((left, right) => left.name.localeCompare(right.name));
17
17
  export function listIntegrationAdapters() {
18
18
  return ADAPTERS;
@@ -20,7 +20,7 @@ export function listIntegrationAdapters() {
20
20
  export function getIntegrationAdapter(name) {
21
21
  const adapter = ADAPTERS.find((item) => item.name === name);
22
22
  if (!adapter) {
23
- throw new Error(`Unsupported integration "${name}". Supported integrations: ${ADAPTERS.map((item) => item.name).join(", ")}`);
23
+ throw new Error(`Unsupported integration "${name}". Supported integrations: ${ADAPTERS.map((item) => item.name).join(', ')}`);
24
24
  }
25
25
  return adapter;
26
26
  }
@@ -31,7 +31,7 @@ export function normalizeIntegrationNames(values) {
31
31
  const names = [];
32
32
  const seen = new Set();
33
33
  for (const value of values) {
34
- for (const raw of value.split(",")) {
34
+ for (const raw of value.split(/[\s,]+/)) {
35
35
  const name = raw.trim();
36
36
  if (!name || seen.has(name)) {
37
37
  continue;
@@ -1,4 +1,4 @@
1
- import type { IntegrationConfig, IntegrationMode, IntegrationName, KGraphWorkspace } from "../types/config.js";
1
+ import type { IntegrationConfig, IntegrationMode, IntegrationName, KGraphWorkspace } from '../types/config.js';
2
2
  export interface IntegrationStatus {
3
3
  name: IntegrationName;
4
4
  enabled: boolean;
@@ -1,9 +1,9 @@
1
- import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { loadConfig, saveConfig } from "../config/config.js";
4
- import { pathExists } from "../storage/kgraph-paths.js";
5
- import { getIntegrationAdapter } from "./integration-registry.js";
6
- import { applyContextPolicy, removeManagedBlock, upsertManagedBlock } from "./instruction-blocks.js";
1
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { loadConfig, saveConfig } from '../config/config.js';
4
+ import { pathExists } from '../storage/kgraph-paths.js';
5
+ import { applyContextPolicy, removeManagedBlock, upsertManagedBlock, } from './instruction-blocks.js';
6
+ import { getIntegrationAdapter } from './integration-registry.js';
7
7
  export async function listIntegrations(workspace) {
8
8
  const config = await loadConfig(workspace);
9
9
  const statuses = await Promise.all(config.integrations.map(async (integration) => ({
@@ -11,11 +11,11 @@ export async function listIntegrations(workspace) {
11
11
  enabled: integration.enabled,
12
12
  mode: integration.mode,
13
13
  targetPath: integration.targetPath,
14
- targetExists: await pathExists(path.join(workspace.rootPath, integration.targetPath))
14
+ targetExists: await pathExists(path.join(workspace.rootPath, integration.targetPath)),
15
15
  })));
16
16
  return statuses.sort((left, right) => left.name.localeCompare(right.name));
17
17
  }
18
- export async function addIntegrations(workspace, names, mode = "always") {
18
+ export async function addIntegrations(workspace, names, mode = 'always') {
19
19
  const config = await loadConfig(workspace);
20
20
  const byName = new Map(config.integrations.map((integration) => [integration.name, integration]));
21
21
  const changed = [];
@@ -23,12 +23,12 @@ export async function addIntegrations(workspace, names, mode = "always") {
23
23
  const adapter = getIntegrationAdapter(name);
24
24
  const next = {
25
25
  name: adapter.name,
26
- enabled: mode !== "off",
26
+ enabled: mode !== 'off',
27
27
  mode,
28
- targetPath: adapter.targetPath
28
+ targetPath: adapter.targetPath,
29
29
  };
30
30
  byName.set(adapter.name, next);
31
- if (mode === "off") {
31
+ if (mode === 'off') {
32
32
  await removeIntegrationInstructions(workspace.rootPath, adapter.targetPath, adapter.name);
33
33
  await removeIntegrationCommandFiles(workspace.rootPath, adapter.commandFiles ?? []);
34
34
  }
@@ -36,7 +36,7 @@ export async function addIntegrations(workspace, names, mode = "always") {
36
36
  await writeIntegrationInstructions(workspace.rootPath, adapter.targetPath, adapter.name, applyContextPolicy(adapter.instructions, mode));
37
37
  await writeIntegrationCommandFiles(workspace.rootPath, (adapter.commandFiles ?? []).map((file) => ({
38
38
  ...file,
39
- content: applyContextPolicy(file.content, mode)
39
+ content: applyContextPolicy(file.content, mode),
40
40
  })));
41
41
  }
42
42
  await removeIntegrationCommandFiles(workspace.rootPath, adapter.obsoleteCommandFiles ?? []);
@@ -66,34 +66,36 @@ export async function removeIntegrations(workspace, names) {
66
66
  }
67
67
  async function writeIntegrationInstructions(rootPath, targetPath, integrationName, instructions) {
68
68
  const fullPath = path.join(rootPath, targetPath);
69
- const existing = (await pathExists(fullPath)) ? await readFile(fullPath, "utf8") : "";
69
+ const existing = (await pathExists(fullPath))
70
+ ? await readFile(fullPath, 'utf8')
71
+ : '';
70
72
  const next = upsertManagedBlock(existing, integrationName, instructions);
71
73
  await mkdir(path.dirname(fullPath), { recursive: true });
72
- await writeFile(fullPath, next, "utf8");
74
+ await writeFile(fullPath, next, 'utf8');
73
75
  }
74
76
  async function removeIntegrationInstructions(rootPath, targetPath, integrationName) {
75
77
  const fullPath = path.join(rootPath, targetPath);
76
78
  if (!(await pathExists(fullPath))) {
77
79
  return;
78
80
  }
79
- const existing = await readFile(fullPath, "utf8");
81
+ const existing = await readFile(fullPath, 'utf8');
80
82
  const next = removeManagedBlock(existing, integrationName);
81
83
  if (next.trim().length === 0) {
82
84
  await rm(fullPath, { force: true });
83
85
  return;
84
86
  }
85
- await writeFile(fullPath, next, "utf8");
87
+ await writeFile(fullPath, next, 'utf8');
86
88
  }
87
89
  async function writeIntegrationCommandFiles(rootPath, files) {
88
90
  for (const file of files) {
89
91
  const fullPath = path.join(rootPath, file.path);
90
92
  await mkdir(path.dirname(fullPath), { recursive: true });
91
- await writeFile(fullPath, file.content.trimEnd() + "\n", "utf8");
93
+ await writeFile(fullPath, file.content.trimEnd() + '\n', 'utf8');
92
94
  }
93
95
  }
94
96
  async function removeIntegrationCommandFiles(rootPath, files) {
95
97
  for (const file of files) {
96
- const filePath = typeof file === "string" ? file : file.path;
98
+ const filePath = typeof file === 'string' ? file : file.path;
97
99
  await rm(path.join(rootPath, filePath), { force: true, recursive: true });
98
100
  }
99
101
  }
@@ -53,6 +53,7 @@ select:hover,button:hover{background:#475569}
53
53
  <span id="t-title">\u29e1 KGraph \u00b7 ${repoName}</span>
54
54
  <span id="t-stats">${meta.fileCount} files &middot; ${meta.symbolCount} symbols &middot; ${meta.cognitionCount} notes &middot; ~${meta.tokenEstimate} tokens</span>
55
55
  <div id="t-controls">
56
+ <label class="clabel"><input type="checkbox" id="tog-lbl" checked> Labels</label>
56
57
  <label class="clabel"><input type="checkbox" id="tog-cog" checked> Cognition</label>
57
58
  <select id="sel-layout" title="Graph layout algorithm">
58
59
  <option value="dagre">Hierarchical</option>
@@ -108,6 +109,27 @@ select:hover,button:hover{background:#475569}
108
109
  cytoscape.use(cytoscapeDagre);
109
110
  }
110
111
 
112
+ // Separate symbol data from graph elements — symbols are shown in sidebar only.
113
+ var SYMBOL_TYPES = { symbol: 1, contains: 1, 'symbol-contains': 1, calls: 1 };
114
+ var coreElements = [];
115
+ var symbolsByFile = {};
116
+ GRAPH_DATA.elements.forEach(function (el) {
117
+ if (el.data.type === 'symbol') {
118
+ var fp = el.data.path;
119
+ if (!symbolsByFile[fp]) symbolsByFile[fp] = [];
120
+ symbolsByFile[fp].push(el.data);
121
+ } else if (!SYMBOL_TYPES[el.data.type]) {
122
+ coreElements.push(el);
123
+ }
124
+ });
125
+
126
+ var LARGE_THRESHOLD = 200;
127
+ var isLarge = coreElements.length > LARGE_THRESHOLD;
128
+
129
+ if (isLarge) {
130
+ document.getElementById('tog-lbl').checked = false;
131
+ }
132
+
111
133
  function esc(v) {
112
134
  return String(v == null ? '' : v)
113
135
  .replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
@@ -122,13 +144,13 @@ select:hover,button:hover{background:#475569}
122
144
 
123
145
  var cy = cytoscape({
124
146
  container: document.getElementById('cy'),
125
- elements: GRAPH_DATA.elements,
147
+ elements: coreElements,
126
148
  style: [
127
149
  {
128
150
  selector: 'node',
129
151
  style: {
130
152
  'background-color': 'data(color)',
131
- label: 'data(label)',
153
+ label: isLarge ? '' : 'data(label)',
132
154
  color: '#94a3b8',
133
155
  'font-size': '10px',
134
156
  'text-valign': 'bottom',
@@ -136,8 +158,8 @@ select:hover,button:hover{background:#475569}
136
158
  'text-margin-y': '5px',
137
159
  'border-width': 1,
138
160
  'border-color': '#1e293b',
139
- width: 30,
140
- height: 30,
161
+ width: isLarge ? 20 : 30,
162
+ height: isLarge ? 20 : 30,
141
163
  'text-wrap': 'ellipsis',
142
164
  'text-max-width': '80px',
143
165
  'overlay-opacity': 0
@@ -204,37 +226,45 @@ select:hover,button:hover{background:#475569}
204
226
  },
205
227
  { selector: '.hidden', style: { display: 'none' } }
206
228
  ],
207
- layout: {
208
- name: 'dagre',
209
- rankDir: 'LR',
210
- nodeSep: 60,
211
- rankSep: 120,
212
- padding: 40,
213
- animate: true,
214
- animationDuration: 400
215
- }
229
+ layout: isLarge
230
+ ? { name: 'cose', animate: false, padding: 40, nodeOverlap: 20, idealEdgeLength: 80, numIter: 100 }
231
+ : { name: 'dagre', rankDir: 'LR', nodeSep: 60, rankSep: 120, padding: 40, animate: true, animationDuration: 400 }
216
232
  });
217
233
 
234
+ var anim = !isLarge;
218
235
  var LAYOUTS = {
219
- dagre: { name: 'dagre', rankDir: 'LR', nodeSep: 60, rankSep: 120, animate: true, animationDuration: 400, padding: 40 },
220
- cose: { name: 'cose', animate: true, animationDuration: 600, padding: 40 },
221
- grid: { name: 'grid', animate: true, animationDuration: 400, padding: 40 },
236
+ dagre: { name: 'dagre', rankDir: 'LR', nodeSep: 60, rankSep: 120, animate: anim, animationDuration: 400, padding: 40 },
237
+ cose: { name: 'cose', animate: anim, animationDuration: 600, padding: 40 },
238
+ grid: { name: 'grid', animate: anim, animationDuration: 400, padding: 40 },
222
239
  concentric: {
223
240
  name: 'concentric',
224
241
  concentric: function (n) { return n.degree(); },
225
242
  levelWidth: function () { return 2; },
226
- animate: true,
243
+ animate: anim,
227
244
  animationDuration: 400,
228
245
  padding: 40
229
246
  }
230
247
  };
231
248
 
249
+ var SYMBOL_KIND_COLORS = { 'function': '#22c55e', 'class': '#a855f7', method: '#14b8a6', 'export': '#f97316', 'import': '#64748b' };
250
+
232
251
  function renderFilePanel(d) {
252
+ var syms = symbolsByFile[d.path] || [];
253
+ var symHtml = '';
254
+ if (syms.length) {
255
+ symHtml = '<div class="sb-sect"><div class="sb-lbl">Symbols (' + syms.length + ')</div><ul class="sb-list">' +
256
+ syms.map(function (s) {
257
+ var c = SYMBOL_KIND_COLORS[s.kind] || '#94a3b8';
258
+ return '<li><span style="color:' + c + ';font-weight:600">' + esc(s.kind) + '</span> <span class="sb-code">' + esc(s.label) + '</span>' +
259
+ (s.parentName ? ' <span style="color:#475569">in ' + esc(s.parentName) + '</span>' : '') + '</li>';
260
+ }).join('') + '</ul></div>';
261
+ }
233
262
  return '<div class="sb-badge" style="background:' + esc(d.color) + '22;color:' + esc(d.color) + ';border:1px solid ' + esc(d.color) + '44">' + esc(d.language) + '</div>' +
234
263
  '<div class="sb-title">' + esc(d.path) + '</div>' +
235
264
  '<div class="sb-sect"><div class="sb-lbl">Scan Status</div><div class="sb-val">' + esc(d.scanStatus) + '</div></div>' +
236
265
  '<div class="sb-sect"><div class="sb-lbl">File Size</div><div class="sb-val">' + bytes(d.size) + '</div></div>' +
237
- '<div class="sb-sect"><div class="sb-lbl">Estimated Tokens</div><div class="sb-val">~' + esc(d.tokenEstimate || 0) + ' tokens</div></div>';
266
+ '<div class="sb-sect"><div class="sb-lbl">Estimated Tokens</div><div class="sb-val">~' + esc(d.tokenEstimate || 0) + ' tokens</div></div>' +
267
+ symHtml;
238
268
  }
239
269
 
240
270
  function renderCognitionPanel(d) {
@@ -269,6 +299,10 @@ select:hover,button:hover{background:#475569}
269
299
  document.getElementById('sidebar').classList.remove('open');
270
300
  });
271
301
 
302
+ document.getElementById('tog-lbl').addEventListener('change', function (e) {
303
+ cy.style().selector('node').style('label', e.target.checked ? 'data(label)' : '').update();
304
+ });
305
+
272
306
  document.getElementById('tog-cog').addEventListener('change', function (e) {
273
307
  if (e.target.checked) {
274
308
  cy.nodes('.cognition').removeClass('hidden');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kentwynn/kgraph",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "Persistent repo intelligence for AI coding assistants.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "scripts": {
15
15
  "clean": "node scripts/clean-dist.mjs",
16
16
  "build": "npm run clean && tsc -p tsconfig.json",
17
- "postbuild": "chmod +x dist/cli/index.js",
17
+ "postbuild": "node -e \"try{require('child_process').execSync('chmod +x dist/cli/index.js')}catch{}\"",
18
18
  "test": "vitest run",
19
19
  "kgraph": "tsx src/cli/index.ts",
20
20
  "check:artifacts": "node scripts/check-clean-artifacts.mjs",