kirograph 0.14.0 → 0.15.0

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 (100) hide show
  1. package/README.md +128 -20
  2. package/dist/assets/logo.png +0 -0
  3. package/dist/bin/commands/help.js +3 -0
  4. package/dist/bin/commands/help.js.map +2 -2
  5. package/dist/bin/commands/memory.js +483 -0
  6. package/dist/bin/commands/memory.js.map +7 -0
  7. package/dist/bin/commands/uninit.js +22 -13
  8. package/dist/bin/commands/uninit.js.map +2 -2
  9. package/dist/bin/installer/config-prompt.js +37 -23
  10. package/dist/bin/installer/config-prompt.js.map +2 -2
  11. package/dist/bin/installer/hooks.js +53 -75
  12. package/dist/bin/installer/hooks.js.map +2 -2
  13. package/dist/bin/installer/index.js +9 -4
  14. package/dist/bin/installer/index.js.map +2 -2
  15. package/dist/bin/installer/prompts.js +37 -6
  16. package/dist/bin/installer/prompts.js.map +2 -2
  17. package/dist/bin/installer/steering.js +19 -0
  18. package/dist/bin/installer/steering.js.map +2 -2
  19. package/dist/bin/installer/targets/aider.js +72 -0
  20. package/dist/bin/installer/targets/aider.js.map +7 -0
  21. package/dist/bin/installer/targets/amp.js +91 -0
  22. package/dist/bin/installer/targets/amp.js.map +7 -0
  23. package/dist/bin/installer/targets/antigravity.js +109 -0
  24. package/dist/bin/installer/targets/antigravity.js.map +7 -0
  25. package/dist/bin/installer/targets/augment.js +81 -0
  26. package/dist/bin/installer/targets/augment.js.map +7 -0
  27. package/dist/bin/installer/targets/claude.js +1 -1
  28. package/dist/bin/installer/targets/claude.js.map +2 -2
  29. package/dist/bin/installer/targets/cline.js +91 -0
  30. package/dist/bin/installer/targets/cline.js.map +7 -0
  31. package/dist/bin/installer/targets/codex.js +1 -1
  32. package/dist/bin/installer/targets/codex.js.map +2 -2
  33. package/dist/bin/installer/targets/continue.js +107 -0
  34. package/dist/bin/installer/targets/continue.js.map +7 -0
  35. package/dist/bin/installer/targets/copilot.js +123 -0
  36. package/dist/bin/installer/targets/copilot.js.map +7 -0
  37. package/dist/bin/installer/targets/cursor.js +143 -0
  38. package/dist/bin/installer/targets/cursor.js.map +7 -0
  39. package/dist/bin/installer/targets/devin.js +148 -0
  40. package/dist/bin/installer/targets/devin.js.map +7 -0
  41. package/dist/bin/installer/targets/gemini-cli.js +126 -0
  42. package/dist/bin/installer/targets/gemini-cli.js.map +7 -0
  43. package/dist/bin/installer/targets/generic.js +120 -0
  44. package/dist/bin/installer/targets/generic.js.map +7 -0
  45. package/dist/bin/installer/targets/goose.js +72 -0
  46. package/dist/bin/installer/targets/goose.js.map +7 -0
  47. package/dist/bin/installer/targets/index.js.map +1 -1
  48. package/dist/bin/installer/targets/junie.js +105 -0
  49. package/dist/bin/installer/targets/junie.js.map +7 -0
  50. package/dist/bin/installer/targets/kilo.js +122 -0
  51. package/dist/bin/installer/targets/kilo.js.map +7 -0
  52. package/dist/bin/installer/targets/kiro.js +3 -3
  53. package/dist/bin/installer/targets/kiro.js.map +2 -2
  54. package/dist/bin/installer/targets/opencode.js +135 -0
  55. package/dist/bin/installer/targets/opencode.js.map +7 -0
  56. package/dist/bin/installer/targets/openhands.js +90 -0
  57. package/dist/bin/installer/targets/openhands.js.map +7 -0
  58. package/dist/bin/installer/targets/replit.js +72 -0
  59. package/dist/bin/installer/targets/replit.js.map +7 -0
  60. package/dist/bin/installer/targets/roo.js +96 -0
  61. package/dist/bin/installer/targets/roo.js.map +7 -0
  62. package/dist/bin/installer/targets/tabnine.js +82 -0
  63. package/dist/bin/installer/targets/tabnine.js.map +7 -0
  64. package/dist/bin/installer/targets/trae.js +84 -0
  65. package/dist/bin/installer/targets/trae.js.map +7 -0
  66. package/dist/bin/installer/targets/warp.js +97 -0
  67. package/dist/bin/installer/targets/warp.js.map +7 -0
  68. package/dist/bin/installer/targets/windsurf.js +141 -0
  69. package/dist/bin/installer/targets/windsurf.js.map +7 -0
  70. package/dist/bin/kirograph.js +3 -1
  71. package/dist/bin/kirograph.js.map +3 -3
  72. package/dist/compression/naive-cost.js +14 -0
  73. package/dist/compression/naive-cost.js.map +2 -2
  74. package/dist/compression/tracker.js +18 -4
  75. package/dist/compression/tracker.js.map +2 -2
  76. package/dist/compression/types.js.map +1 -1
  77. package/dist/config.js +33 -1
  78. package/dist/config.js.map +2 -2
  79. package/dist/db/database.js +17 -0
  80. package/dist/db/database.js.map +2 -2
  81. package/dist/db/memory-schema.sql +51 -0
  82. package/dist/index.js +3 -0
  83. package/dist/index.js.map +2 -2
  84. package/dist/mcp/tool-names.js +5 -1
  85. package/dist/mcp/tool-names.js.map +2 -2
  86. package/dist/mcp/tools.js +232 -3
  87. package/dist/mcp/tools.js.map +2 -2
  88. package/dist/memory/compress.js +142 -0
  89. package/dist/memory/compress.js.map +7 -0
  90. package/dist/memory/database.js +375 -0
  91. package/dist/memory/database.js.map +7 -0
  92. package/dist/memory/index.js +239 -0
  93. package/dist/memory/index.js.map +7 -0
  94. package/dist/memory/symbols.js +54 -0
  95. package/dist/memory/symbols.js.map +7 -0
  96. package/dist/memory/types.js +17 -0
  97. package/dist/memory/types.js.map +7 -0
  98. package/dist/memory/vectors.js +199 -0
  99. package/dist/memory/vectors.js.map +7 -0
  100. package/package.json +1 -1
@@ -34,8 +34,10 @@ __export(uninit_exports, {
34
34
  module.exports = __toCommonJS(uninit_exports);
35
35
  var path = __toESM(require("path"));
36
36
  var fs = __toESM(require("fs"));
37
+ var readline = __toESM(require("readline"));
37
38
  var import_banner = require("../banner");
38
39
  var import_ui = require("../ui");
40
+ var import_prompts = require("../installer/prompts");
39
41
  const UNINIT_FAREWELLS = [
40
42
  "Oh. So it's come to this.",
41
43
  "We're sorry to see you go. (Are we? Yes. We are.)",
@@ -49,14 +51,6 @@ const UNINIT_FAREWELLS = [
49
51
  "See you on the other side of `kirograph install`."
50
52
  ];
51
53
  const UNINIT_TARGETS = ["kiro", "claude", "codex", "all"];
52
- async function confirm(question) {
53
- const readline = await import("readline");
54
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
55
- return new Promise((resolve) => rl.question(question, (ans) => {
56
- rl.close();
57
- resolve(ans.toLowerCase() === "y");
58
- }));
59
- }
60
54
  async function runUninit(projectPath, opts) {
61
55
  const target = path.resolve(projectPath ?? process.cwd());
62
56
  const integration = (opts.target ?? "kiro").toLowerCase();
@@ -77,10 +71,11 @@ async function runUninit(projectPath, opts) {
77
71
  console.log(` ${import_ui.violet}${import_ui.bold}${farewell}${import_ui.reset}`);
78
72
  console.log(`
79
73
  ${import_ui.dim}This can remove ${integration} integration files and, separately, the shared .kirograph/ data.${import_ui.reset}`);
80
- console.log(` ${import_ui.dim}Your source code is untouched.${import_ui.reset}
81
- `);
82
- removeIntegration = await confirm(` ${import_ui.violet}Remove ${integration} integration files?${import_ui.reset} ${import_ui.dim}(y/N)${import_ui.reset} `);
83
- removeGraph = await confirm(` ${import_ui.violet}Remove shared .kirograph/ data too?${import_ui.reset} ${import_ui.dim}(y/N)${import_ui.reset} `);
74
+ console.log(` ${import_ui.dim}Your source code is untouched.${import_ui.reset}`);
75
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
76
+ removeIntegration = await (0, import_prompts.askToggle)(rl, `Remove ${integration} integration files?`, "Removes hooks, steering, MCP config, and agent instructions for this target.", false);
77
+ removeGraph = await (0, import_prompts.askToggle)(rl, "Remove shared .kirograph/ data too?", "Deletes the graph database, snapshots, and all indexed data. Cannot be undone.", false);
78
+ rl.close();
84
79
  if (!removeIntegration && !removeGraph) {
85
80
  console.log(`
86
81
  ${import_ui.dim}Cancelled. Nothing removed.${import_ui.reset}
@@ -95,12 +90,21 @@ async function runUninit(projectPath, opts) {
95
90
  }
96
91
  if (removeIntegration && (integration === "kiro" || integration === "all")) {
97
92
  const kiroHooks = [
93
+ "kirograph-mark-dirty-on-save.kiro.hook",
94
+ "kirograph-mark-dirty-on-create.kiro.hook",
95
+ "kirograph-sync-on-delete.kiro.hook",
96
+ "kirograph-sync-if-dirty.kiro.hook",
97
+ "kirograph-compress-hint.kiro.hook",
98
+ "kirograph-mem-capture.kiro.hook",
99
+ // Legacy .json filenames
98
100
  "kirograph-mark-dirty-on-save.json",
99
101
  "kirograph-mark-dirty-on-create.json",
100
102
  "kirograph-sync-on-delete.json",
101
103
  "kirograph-sync-if-dirty.json",
102
104
  "kirograph-sync-on-save.json",
103
- "kirograph-sync-on-create.json"
105
+ "kirograph-sync-on-create.json",
106
+ "kirograph-compress-hint.json",
107
+ "kirograph-mem-capture.json"
104
108
  ];
105
109
  const hooksDir = path.join(target, ".kiro", "hooks");
106
110
  let removedHooks = 0;
@@ -122,6 +126,11 @@ async function runUninit(projectPath, opts) {
122
126
  fs.unlinkSync(agentPath);
123
127
  console.log(` ${import_ui.green}\u2713${import_ui.reset} Removed .kiro/agents/kirograph.json`);
124
128
  }
129
+ const { removeMcpServersConfig } = await Promise.resolve().then(() => require("../installer/common.js"));
130
+ const mcpPath = path.join(target, ".kiro", "settings", "mcp.json");
131
+ if (removeMcpServersConfig(mcpPath)) {
132
+ console.log(` ${import_ui.green}\u2713${import_ui.reset} Removed kirograph from .kiro/settings/mcp.json`);
133
+ }
125
134
  }
126
135
  if (removeIntegration && (integration === "claude" || integration === "all")) {
127
136
  const { uninitClaude } = await Promise.resolve().then(() => require("../installer/targets/claude.js"));
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/bin/commands/uninit.ts"],
4
- "sourcesContent": ["import { Command } from 'commander';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport { printBanner } from '../banner';\nimport { dim, reset, violet, bold, green } from '../ui';\n\nexport const UNINIT_FAREWELLS = [\n \"Oh. So it's come to this.\",\n \"We're sorry to see you go. (Are we? Yes. We are.)\",\n \"Deleting months of carefully indexed knowledge. Bold move.\",\n \"Fine. We'll just sit here in the dark.\",\n \"You can always come back. We won't mention this.\",\n \"The graph remembers everything. Except, soon, anything.\",\n \"Somewhere a tree-sitter is crying.\",\n \"Uninstalling... and pretending it doesn't hurt.\",\n \"574 embeddings. Gone. Just like that.\",\n \"See you on the other side of `kirograph install`.\",\n];\n\ntype UninitTarget = 'kiro' | 'claude' | 'codex' | 'all';\n\nconst UNINIT_TARGETS: UninitTarget[] = ['kiro', 'claude', 'codex', 'all'];\n\nasync function confirm(question: string): Promise<boolean> {\n const readline = await import('readline');\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n return new Promise<boolean>(resolve => rl.question(question, ans => {\n rl.close();\n resolve(ans.toLowerCase() === 'y');\n }));\n}\n\nasync function runUninit(projectPath: string | undefined, opts: { force?: boolean; target?: string }): Promise<void> {\n const target = path.resolve(projectPath ?? process.cwd());\n const integration = (opts.target ?? 'kiro').toLowerCase() as UninitTarget;\n if (!UNINIT_TARGETS.includes(integration)) {\n console.error(`Unknown uninit target: ${opts.target}. Choose from: kiro, claude, codex, all`);\n process.exit(1);\n }\n const dir = path.join(target, '.kirograph');\n if (!fs.existsSync(dir)) { console.log('Not initialized.'); return; }\n\n let removeIntegration = true;\n let removeGraph = opts.force === true;\n\n if (!opts.force) {\n printBanner();\n const farewell = UNINIT_FAREWELLS[Math.floor(Math.random() * UNINIT_FAREWELLS.length)]!;\n console.log(` ${violet}${bold}${farewell}${reset}`);\n console.log(`\\n ${dim}This can remove ${integration} integration files and, separately, the shared .kirograph/ data.${reset}`);\n console.log(` ${dim}Your source code is untouched.${reset}\\n`);\n\n removeIntegration = await confirm(` ${violet}Remove ${integration} integration files?${reset} ${dim}(y/N)${reset} `);\n removeGraph = await confirm(` ${violet}Remove shared .kirograph/ data too?${reset} ${dim}(y/N)${reset} `);\n\n if (!removeIntegration && !removeGraph) {\n console.log(`\\n ${dim}Cancelled. Nothing removed.${reset}\\n`);\n return;\n }\n console.log();\n }\n\n if (removeGraph) {\n fs.rmSync(dir, { recursive: true, force: true });\n console.log(` ${green}\u2713${reset} Removed .kirograph/`);\n }\n\n if (removeIntegration && (integration === 'kiro' || integration === 'all')) {\n // Remove .kiro hooks created by kirograph\n const kiroHooks = [\n 'kirograph-mark-dirty-on-save.json',\n 'kirograph-mark-dirty-on-create.json',\n 'kirograph-sync-on-delete.json',\n 'kirograph-sync-if-dirty.json',\n 'kirograph-sync-on-save.json',\n 'kirograph-sync-on-create.json',\n ];\n const hooksDir = path.join(target, '.kiro', 'hooks');\n let removedHooks = 0;\n for (const hook of kiroHooks) {\n const p = path.join(hooksDir, hook);\n if (fs.existsSync(p)) { fs.unlinkSync(p); removedHooks++; }\n }\n if (removedHooks > 0) console.log(` ${green}\u2713${reset} Removed ${removedHooks} hook(s) from .kiro/hooks/`);\n\n // Remove .kiro/steering/kirograph.md\n const steeringPath = path.join(target, '.kiro', 'steering', 'kirograph.md');\n if (fs.existsSync(steeringPath)) {\n fs.unlinkSync(steeringPath);\n console.log(` ${green}\u2713${reset} Removed .kiro/steering/kirograph.md`);\n }\n\n // Remove .kiro/agents/kirograph.json\n const agentPath = path.join(target, '.kiro', 'agents', 'kirograph.json');\n if (fs.existsSync(agentPath)) {\n fs.unlinkSync(agentPath);\n console.log(` ${green}\u2713${reset} Removed .kiro/agents/kirograph.json`);\n }\n }\n\n if (removeIntegration && (integration === 'claude' || integration === 'all')) {\n const { uninitClaude } = await Promise.resolve().then(() => require('../installer/targets/claude.js'));\n uninitClaude(target);\n }\n\n if (removeIntegration && (integration === 'codex' || integration === 'all')) {\n const { uninitCodex } = await Promise.resolve().then(() => require('../installer/targets/codex.js'));\n uninitCodex(target);\n }\n\n console.log(`\\n ${dim}Done. Run ${violet}kirograph install --target ${integration === 'all' ? 'kiro' : integration}${reset}${dim} to come back anytime.${reset}\\n`);\n}\n\nexport function register(program: Command): void {\n program\n .command('uninit [projectPath]')\n .description('Remove KiroGraph from a project')\n .option('--force', 'Skip confirmation')\n .option('--target <target>', 'Integration target to clean up: kiro, claude, codex, or all', 'kiro')\n .action(runUninit);\n\n program\n .command('uninstall [projectPath]')\n .description('Alias for uninit. Remove KiroGraph from a project')\n .option('--force', 'Skip confirmation')\n .option('--target <target>', 'Integration target to clean up: kiro, claude, codex, or all', 'kiro')\n .action(runUninit);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Command } from 'commander';\nimport * as path from 'path';\nimport * as fs from 'fs';\nimport * as readline from 'readline';\nimport { printBanner } from '../banner';\nimport { dim, reset, violet, bold, green } from '../ui';\nimport { askToggle } from '../installer/prompts';\n\nexport const UNINIT_FAREWELLS = [\n \"Oh. So it's come to this.\",\n \"We're sorry to see you go. (Are we? Yes. We are.)\",\n \"Deleting months of carefully indexed knowledge. Bold move.\",\n \"Fine. We'll just sit here in the dark.\",\n \"You can always come back. We won't mention this.\",\n \"The graph remembers everything. Except, soon, anything.\",\n \"Somewhere a tree-sitter is crying.\",\n \"Uninstalling... and pretending it doesn't hurt.\",\n \"574 embeddings. Gone. Just like that.\",\n \"See you on the other side of `kirograph install`.\",\n];\n\ntype UninitTarget = 'kiro' | 'claude' | 'codex' | 'all';\n\nconst UNINIT_TARGETS: UninitTarget[] = ['kiro', 'claude', 'codex', 'all'];\n\nasync function runUninit(projectPath: string | undefined, opts: { force?: boolean; target?: string }): Promise<void> {\n const target = path.resolve(projectPath ?? process.cwd());\n const integration = (opts.target ?? 'kiro').toLowerCase() as UninitTarget;\n if (!UNINIT_TARGETS.includes(integration)) {\n console.error(`Unknown uninit target: ${opts.target}. Choose from: kiro, claude, codex, all`);\n process.exit(1);\n }\n const dir = path.join(target, '.kirograph');\n if (!fs.existsSync(dir)) { console.log('Not initialized.'); return; }\n\n let removeIntegration = true;\n let removeGraph = opts.force === true;\n\n if (!opts.force) {\n printBanner();\n const farewell = UNINIT_FAREWELLS[Math.floor(Math.random() * UNINIT_FAREWELLS.length)]!;\n console.log(` ${violet}${bold}${farewell}${reset}`);\n console.log(`\\n ${dim}This can remove ${integration} integration files and, separately, the shared .kirograph/ data.${reset}`);\n console.log(` ${dim}Your source code is untouched.${reset}`);\n\n const rl = readline.createInterface({ input: process.stdin, output: process.stdout });\n\n removeIntegration = await askToggle(rl, `Remove ${integration} integration files?`, 'Removes hooks, steering, MCP config, and agent instructions for this target.', false);\n removeGraph = await askToggle(rl, 'Remove shared .kirograph/ data too?', 'Deletes the graph database, snapshots, and all indexed data. Cannot be undone.', false);\n\n rl.close();\n\n if (!removeIntegration && !removeGraph) {\n console.log(`\\n ${dim}Cancelled. Nothing removed.${reset}\\n`);\n return;\n }\n console.log();\n }\n\n if (removeGraph) {\n fs.rmSync(dir, { recursive: true, force: true });\n console.log(` ${green}\u2713${reset} Removed .kirograph/`);\n }\n\n if (removeIntegration && (integration === 'kiro' || integration === 'all')) {\n // Remove .kiro hooks created by kirograph\n const kiroHooks = [\n 'kirograph-mark-dirty-on-save.kiro.hook',\n 'kirograph-mark-dirty-on-create.kiro.hook',\n 'kirograph-sync-on-delete.kiro.hook',\n 'kirograph-sync-if-dirty.kiro.hook',\n 'kirograph-compress-hint.kiro.hook',\n 'kirograph-mem-capture.kiro.hook',\n // Legacy .json filenames\n 'kirograph-mark-dirty-on-save.json',\n 'kirograph-mark-dirty-on-create.json',\n 'kirograph-sync-on-delete.json',\n 'kirograph-sync-if-dirty.json',\n 'kirograph-sync-on-save.json',\n 'kirograph-sync-on-create.json',\n 'kirograph-compress-hint.json',\n 'kirograph-mem-capture.json',\n ];\n const hooksDir = path.join(target, '.kiro', 'hooks');\n let removedHooks = 0;\n for (const hook of kiroHooks) {\n const p = path.join(hooksDir, hook);\n if (fs.existsSync(p)) { fs.unlinkSync(p); removedHooks++; }\n }\n if (removedHooks > 0) console.log(` ${green}\u2713${reset} Removed ${removedHooks} hook(s) from .kiro/hooks/`);\n\n // Remove .kiro/steering/kirograph.md\n const steeringPath = path.join(target, '.kiro', 'steering', 'kirograph.md');\n if (fs.existsSync(steeringPath)) {\n fs.unlinkSync(steeringPath);\n console.log(` ${green}\u2713${reset} Removed .kiro/steering/kirograph.md`);\n }\n\n // Remove .kiro/agents/kirograph.json\n const agentPath = path.join(target, '.kiro', 'agents', 'kirograph.json');\n if (fs.existsSync(agentPath)) {\n fs.unlinkSync(agentPath);\n console.log(` ${green}\u2713${reset} Removed .kiro/agents/kirograph.json`);\n }\n\n // Remove kirograph server from .kiro/settings/mcp.json\n const { removeMcpServersConfig } = await Promise.resolve().then(() => require('../installer/common.js'));\n const mcpPath = path.join(target, '.kiro', 'settings', 'mcp.json');\n if (removeMcpServersConfig(mcpPath)) {\n console.log(` ${green}\u2713${reset} Removed kirograph from .kiro/settings/mcp.json`);\n }\n }\n\n if (removeIntegration && (integration === 'claude' || integration === 'all')) {\n const { uninitClaude } = await Promise.resolve().then(() => require('../installer/targets/claude.js'));\n uninitClaude(target);\n }\n\n if (removeIntegration && (integration === 'codex' || integration === 'all')) {\n const { uninitCodex } = await Promise.resolve().then(() => require('../installer/targets/codex.js'));\n uninitCodex(target);\n }\n\n console.log(`\\n ${dim}Done. Run ${violet}kirograph install --target ${integration === 'all' ? 'kiro' : integration}${reset}${dim} to come back anytime.${reset}\\n`);\n}\n\nexport function register(program: Command): void {\n program\n .command('uninit [projectPath]')\n .description('Remove KiroGraph from a project')\n .option('--force', 'Skip confirmation')\n .option('--target <target>', 'Integration target to clean up: kiro, claude, codex, or all', 'kiro')\n .action(runUninit);\n\n program\n .command('uninstall [projectPath]')\n .description('Alias for uninit. Remove KiroGraph from a project')\n .option('--force', 'Skip confirmation')\n .option('--target <target>', 'Integration target to clean up: kiro, claude, codex, or all', 'kiro')\n .action(runUninit);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -57,16 +57,17 @@ const PRESET_MODELS = [
57
57
  }
58
58
  ];
59
59
  async function promptConfigOptions(rl) {
60
- const enableEmbeddings = await (0, import_prompts.askBool)(
60
+ (0, import_prompts.printSection)("\u{1F50D}", "Semantic Search");
61
+ const enableEmbeddings = await (0, import_prompts.askToggle)(
61
62
  rl,
62
- "Enable semantic embeddings for similarity search? (requires a local embedding model)",
63
- "Enables semantic/similarity-based code search. Increases indexing time; the chosen embedding model is downloaded automatically on first use."
63
+ "Semantic embeddings (similarity search):",
64
+ "Enables natural-language code search via vector embeddings. A local model (~130MB) is downloaded on first use."
64
65
  );
65
- const patch = { enableEmbeddings, useVecIndex: false, semanticEngine: "cosine", typesenseDashboard: false, qdrantDashboard: false, extractDocstrings: true, trackCallSites: true, enableArchitecture: false, cavemanMode: "off", shellCompressionLevel: "normal" };
66
+ const patch = { enableEmbeddings, useVecIndex: false, semanticEngine: "cosine", typesenseDashboard: false, qdrantDashboard: false, extractDocstrings: true, trackCallSites: true, enableArchitecture: false, cavemanMode: "off", shellCompressionLevel: "normal", enableMemory: false };
66
67
  if (enableEmbeddings) {
67
68
  const modelChoice = await (0, import_prompts.arrowSelect)(
68
69
  rl,
69
- "Choose an embedding model:",
70
+ "Embedding model:",
70
71
  PRESET_MODELS.map((m) => ({ value: m.value, label: m.label, description: m.description }))
71
72
  );
72
73
  let embeddingModel;
@@ -100,7 +101,7 @@ async function promptConfigOptions(rl) {
100
101
  }
101
102
  patch.embeddingModel = embeddingModel;
102
103
  patch.embeddingDim = embeddingDim;
103
- const semanticEngine = await (0, import_prompts.arrowSelect)(rl, "Choose the semantic search engine:", [
104
+ const semanticEngine = await (0, import_prompts.arrowSelect)(rl, "Vector search engine:", [
104
105
  { value: "cosine", label: "cosine", description: "In-process cosine similarity. No extra deps. Best for small/medium projects." },
105
106
  { value: "sqlite-vec", label: "sqlite-vec", description: "ANN index. Sub-linear search. Best for large codebases. Needs: better-sqlite3, sqlite-vec (native)." },
106
107
  { value: "orama", label: "orama", description: "Hybrid search (full-text + vector). Pure JS. Needs: @orama/orama, @orama/plugin-data-persistence." },
@@ -112,49 +113,62 @@ async function promptConfigOptions(rl) {
112
113
  patch.semanticEngine = semanticEngine;
113
114
  patch.useVecIndex = semanticEngine === "sqlite-vec";
114
115
  if (semanticEngine === "typesense") {
115
- patch.typesenseDashboard = await (0, import_prompts.askBool)(
116
+ patch.typesenseDashboard = await (0, import_prompts.askToggle)(
116
117
  rl,
117
- "Open Typesense dashboard after indexing?",
118
- "Serves the Typesense Dashboard locally and opens it in your browser after indexing completes."
118
+ "Typesense dashboard:",
119
+ "Serves the Typesense Dashboard locally and opens it in your browser after indexing completes.",
120
+ false
119
121
  );
120
122
  }
121
123
  if (semanticEngine === "qdrant") {
122
- patch.qdrantDashboard = await (0, import_prompts.askBool)(
124
+ patch.qdrantDashboard = await (0, import_prompts.askToggle)(
123
125
  rl,
124
- "Open Qdrant dashboard after indexing?",
125
- "Downloads the Qdrant Web UI (first time only) and opens it in your browser after indexing completes."
126
+ "Qdrant dashboard:",
127
+ "Downloads the Qdrant Web UI (first time only) and opens it in your browser after indexing completes.",
128
+ false
126
129
  );
127
130
  }
128
131
  }
129
- patch.extractDocstrings = await (0, import_prompts.askBool)(
132
+ (0, import_prompts.printSection)("\u{1F4CA}", "Graph Features");
133
+ patch.extractDocstrings = await (0, import_prompts.askToggle)(
130
134
  rl,
131
- "Extract docstrings from source files?",
135
+ "Docstring extraction:",
132
136
  "Enriches symbol metadata and improves context quality. Slightly increases indexing time."
133
137
  );
134
- patch.trackCallSites = await (0, import_prompts.askBool)(
138
+ patch.trackCallSites = await (0, import_prompts.askToggle)(
135
139
  rl,
136
- "Track call sites to enable caller/callee graph traversal?",
137
- "Enables the kirograph_callers and kirograph_callees MCP tools for graph traversal. Increases index size."
140
+ "Call site tracking (caller/callee graph):",
141
+ "Enables kirograph_callers and kirograph_callees MCP tools. Increases index size."
138
142
  );
139
- patch.enableArchitecture = await (0, import_prompts.askBool)(
143
+ patch.enableArchitecture = await (0, import_prompts.askToggle)(
140
144
  rl,
141
- "Enable architecture analysis (package graph + layer detection)?",
142
- "Detects packages from manifests (package.json, go.mod, Cargo.toml, etc.) and architectural layers (api, service, data, ui, shared) from file structure. Enables kirograph_architecture, kirograph_coupling, and kirograph_package MCP tools."
145
+ "Architecture analysis (packages + layers):",
146
+ "Detects packages from manifests and architectural layers. Enables kirograph_architecture, kirograph_coupling, kirograph_package.",
147
+ false
143
148
  );
144
- const cavemanChoice = await (0, import_prompts.arrowSelect)(rl, "Caveman mode: agent communication style:", [
145
- { value: "off", label: "off", description: "Normal responses" },
149
+ (0, import_prompts.printSection)("\u{1F916}", "Agent Behavior");
150
+ const cavemanChoice = await (0, import_prompts.arrowSelect)(rl, "Communication style (caveman mode):", [
151
+ { value: "off", label: "off", description: "Normal responses \u2014 no compression" },
146
152
  { value: "lite", label: "lite", description: "Compact, no filler, full sentences" },
147
153
  { value: "full", label: "full", description: "Fragments, no articles, short synonyms" },
148
154
  { value: "ultra", label: "ultra", description: "Max compression, abbreviations, \u2192 for causality" }
149
155
  ]);
150
156
  patch.cavemanMode = cavemanChoice;
151
- const compressionChoice = await (0, import_prompts.arrowSelect)(rl, "Shell compression: default level for kirograph_exec:", [
157
+ const compressionChoice = await (0, import_prompts.arrowSelect)(rl, "Shell compression (kirograph_exec default level):", [
152
158
  { value: "off", label: "off", description: "No compression hook or steering (tool still available)" },
153
159
  { value: "normal", label: "normal", description: "Balanced: removes noise, keeps structure (recommended)" },
154
160
  { value: "aggressive", label: "aggressive", description: "More compact: groups by category, limits output" },
155
161
  { value: "ultra", label: "ultra", description: "Maximum compression: counts and summaries only" }
156
162
  ]);
157
163
  patch.shellCompressionLevel = compressionChoice;
164
+ (0, import_prompts.printSection)("\u{1F9E0}", "Memory");
165
+ patch.enableMemory = await (0, import_prompts.askToggle)(
166
+ rl,
167
+ "Persistent memory (cross-session observations):",
168
+ "Stores decisions, errors, and patterns across sessions. Compressed (if caveman is on), linked to code symbols, searchable via kirograph_mem_* tools. Zero LLM tokens on write.",
169
+ false
170
+ // Requires explicit enable
171
+ );
158
172
  return patch;
159
173
  }
160
174
  // Annotate the CommonJS export names for ESM import in node:
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/bin/installer/config-prompt.ts"],
4
- "sourcesContent": ["/**\n * KiroGraph Installer \u2014 configuration prompting\n */\n\nimport * as readline from 'readline';\nimport { KiroGraphConfig } from '../../config';\ntype CavemanMode = 'lite' | 'full' | 'ultra';\nimport { ask, askBool, arrowSelect, dim, reset, violet } from './prompts';\nexport type ConfigPatch = Pick<KiroGraphConfig, 'enableEmbeddings' | 'useVecIndex' | 'semanticEngine' | 'typesenseDashboard' | 'qdrantDashboard' | 'extractDocstrings' | 'trackCallSites' | 'enableArchitecture' | 'cavemanMode' | 'shellCompressionLevel'> & { embeddingModel?: string; embeddingDim?: number };\nexport type SemanticEngine = KiroGraphConfig['semanticEngine'];\n\nexport const DEFAULT_EMBEDDING_MODEL = 'nomic-ai/nomic-embed-text-v1.5';\n\n/** Well-known embedding models with their output dimensions. */\nconst PRESET_MODELS = [\n {\n value: 'nomic-ai/nomic-embed-text-v1.5',\n label: 'nomic-embed-text-v1.5',\n dim: 768,\n description: '768-dim \u00B7 ~130MB \u00B7 Best quality for code search (recommended)',\n },\n {\n value: 'onnx-community/embeddinggemma-300m-ONNX',\n label: 'embeddinggemma-300m',\n dim: 768,\n description: '768-dim \u00B7 ~300MB \u00B7 Google Gemma-based, multilingual, 2048-token context',\n },\n {\n value: 'Xenova/all-MiniLM-L6-v2',\n label: 'all-MiniLM-L6-v2',\n dim: 384,\n description: '384-dim \u00B7 ~23MB \u00B7 Fast and lightweight, lower accuracy',\n },\n {\n value: 'BAAI/bge-base-en-v1.5',\n label: 'bge-base-en-v1.5',\n dim: 768,\n description: '768-dim \u00B7 ~110MB \u00B7 Strong general-purpose alternative to nomic',\n },\n {\n value: '__other__',\n label: 'Other',\n dim: 768,\n description: 'Enter a custom HuggingFace model ID and embedding dimension',\n },\n] as const;\n\nexport async function promptConfigOptions(rl: readline.Interface): Promise<ConfigPatch> {\n const enableEmbeddings = await askBool(\n rl,\n 'Enable semantic embeddings for similarity search? (requires a local embedding model)',\n 'Enables semantic/similarity-based code search. Increases indexing time; the chosen embedding model is downloaded automatically on first use.',\n );\n\n const patch: ConfigPatch = { enableEmbeddings, useVecIndex: false, semanticEngine: 'cosine', typesenseDashboard: false, qdrantDashboard: false, extractDocstrings: true, trackCallSites: true, enableArchitecture: false, cavemanMode: 'off', shellCompressionLevel: 'normal' };\n\n if (enableEmbeddings) {\n // \u2500\u2500 Model selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const modelChoice = await arrowSelect<string>(\n rl,\n 'Choose an embedding model:',\n PRESET_MODELS.map(m => ({ value: m.value, label: m.label, description: m.description })),\n );\n\n let embeddingModel: string;\n let embeddingDim: number;\n\n if (modelChoice === '__other__') {\n console.log(`\\n ${dim}Enter a HuggingFace model ID in the format org/model-name.${reset}`);\n while (true) {\n const raw = (await ask(rl, ` ${violet}Model identifier:${reset} `)).trim();\n if (raw.includes('/')) { embeddingModel = raw; break; }\n console.log(` Expected a HuggingFace model ID in the format org/model-name (e.g. nomic-ai/nomic-embed-text-v1.5).`);\n }\n console.log(`\\n ${dim}Enter the embedding output dimension for this model (check the model card on HuggingFace).${reset}`);\n while (true) {\n const raw = (await ask(rl, ` ${violet}Embedding dimension (e.g. 768, 384):${reset} `)).trim();\n const n = parseInt(raw, 10);\n if (!isNaN(n) && n > 0) { embeddingDim = n; break; }\n console.log(` Expected a positive integer (e.g. 768, 384, 1536).`);\n }\n } else {\n const preset = PRESET_MODELS.find(m => m.value === modelChoice)!;\n embeddingModel = preset.value;\n embeddingDim = preset.dim;\n }\n\n patch.embeddingModel = embeddingModel;\n patch.embeddingDim = embeddingDim;\n\n // \u2500\u2500 Engine selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const semanticEngine = await arrowSelect<SemanticEngine>(rl, 'Choose the semantic search engine:', [\n { value: 'cosine', label: 'cosine', description: 'In-process cosine similarity. No extra deps. Best for small/medium projects.' },\n { value: 'sqlite-vec', label: 'sqlite-vec', description: 'ANN index. Sub-linear search. Best for large codebases. Needs: better-sqlite3, sqlite-vec (native).' },\n { value: 'orama', label: 'orama', description: 'Hybrid search (full-text + vector). Pure JS. Needs: @orama/orama, @orama/plugin-data-persistence.' },\n { value: 'pglite', label: 'pglite', description: 'Hybrid search via PostgreSQL + pgvector. Exact results. Pure WASM. Needs: @electric-sql/pglite.' },\n { value: 'lancedb', label: 'lancedb', description: 'ANN search via LanceDB (Apache Lance columnar format). Pure JS. Needs: @lancedb/lancedb.' },\n { value: 'qdrant', label: 'qdrant', description: 'ANN search via Qdrant embedded binary (HNSW index, Cosine). Needs: qdrant-local.' },\n { value: 'typesense', label: 'typesense', description: 'ANN search via Typesense (auto-downloaded binary, HNSW, Cosine). Needs: typesense.' },\n ]);\n patch.semanticEngine = semanticEngine;\n patch.useVecIndex = semanticEngine === 'sqlite-vec';\n\n if (semanticEngine === 'typesense') {\n patch.typesenseDashboard = await askBool(\n rl,\n 'Open Typesense dashboard after indexing?',\n 'Serves the Typesense Dashboard locally and opens it in your browser after indexing completes.',\n );\n }\n\n if (semanticEngine === 'qdrant') {\n patch.qdrantDashboard = await askBool(\n rl,\n 'Open Qdrant dashboard after indexing?',\n 'Downloads the Qdrant Web UI (first time only) and opens it in your browser after indexing completes.',\n );\n }\n }\n\n patch.extractDocstrings = await askBool(\n rl,\n 'Extract docstrings from source files?',\n 'Enriches symbol metadata and improves context quality. Slightly increases indexing time.',\n );\n\n patch.trackCallSites = await askBool(\n rl,\n 'Track call sites to enable caller/callee graph traversal?',\n 'Enables the kirograph_callers and kirograph_callees MCP tools for graph traversal. Increases index size.',\n );\n\n patch.enableArchitecture = await askBool(\n rl,\n 'Enable architecture analysis (package graph + layer detection)?',\n 'Detects packages from manifests (package.json, go.mod, Cargo.toml, etc.) and architectural layers (api, service, data, ui, shared) from file structure. Enables kirograph_architecture, kirograph_coupling, and kirograph_package MCP tools.',\n );\n\n const cavemanChoice = await arrowSelect(rl, 'Caveman mode: agent communication style:', [\n { value: 'off', label: 'off', description: 'Normal responses' },\n { value: 'lite', label: 'lite', description: 'Compact, no filler, full sentences' },\n { value: 'full', label: 'full', description: 'Fragments, no articles, short synonyms' },\n { value: 'ultra', label: 'ultra', description: 'Max compression, abbreviations, \u2192 for causality' },\n ]);\n patch.cavemanMode = cavemanChoice as CavemanMode | 'off';\n\n const compressionChoice = await arrowSelect(rl, 'Shell compression: default level for kirograph_exec:', [\n { value: 'off', label: 'off', description: 'No compression hook or steering (tool still available)' },\n { value: 'normal', label: 'normal', description: 'Balanced: removes noise, keeps structure (recommended)' },\n { value: 'aggressive', label: 'aggressive', description: 'More compact: groups by category, limits output' },\n { value: 'ultra', label: 'ultra', description: 'Maximum compression: counts and summaries only' },\n ]);\n patch.shellCompressionLevel = compressionChoice as KiroGraphConfig['shellCompressionLevel'];\n\n return patch;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * KiroGraph Installer \u2014 configuration prompting\n */\n\nimport * as readline from 'readline';\nimport { KiroGraphConfig } from '../../config';\ntype CavemanMode = 'lite' | 'full' | 'ultra';\nimport { ask, askToggle, arrowSelect, printSection, printSeparator, dim, reset, violet } from './prompts';\nexport type ConfigPatch = Pick<KiroGraphConfig, 'enableEmbeddings' | 'useVecIndex' | 'semanticEngine' | 'typesenseDashboard' | 'qdrantDashboard' | 'extractDocstrings' | 'trackCallSites' | 'enableArchitecture' | 'cavemanMode' | 'shellCompressionLevel' | 'enableMemory'> & { embeddingModel?: string; embeddingDim?: number };\nexport type SemanticEngine = KiroGraphConfig['semanticEngine'];\n\nexport const DEFAULT_EMBEDDING_MODEL = 'nomic-ai/nomic-embed-text-v1.5';\n\n/** Well-known embedding models with their output dimensions. */\nconst PRESET_MODELS = [\n {\n value: 'nomic-ai/nomic-embed-text-v1.5',\n label: 'nomic-embed-text-v1.5',\n dim: 768,\n description: '768-dim \u00B7 ~130MB \u00B7 Best quality for code search (recommended)',\n },\n {\n value: 'onnx-community/embeddinggemma-300m-ONNX',\n label: 'embeddinggemma-300m',\n dim: 768,\n description: '768-dim \u00B7 ~300MB \u00B7 Google Gemma-based, multilingual, 2048-token context',\n },\n {\n value: 'Xenova/all-MiniLM-L6-v2',\n label: 'all-MiniLM-L6-v2',\n dim: 384,\n description: '384-dim \u00B7 ~23MB \u00B7 Fast and lightweight, lower accuracy',\n },\n {\n value: 'BAAI/bge-base-en-v1.5',\n label: 'bge-base-en-v1.5',\n dim: 768,\n description: '768-dim \u00B7 ~110MB \u00B7 Strong general-purpose alternative to nomic',\n },\n {\n value: '__other__',\n label: 'Other',\n dim: 768,\n description: 'Enter a custom HuggingFace model ID and embedding dimension',\n },\n] as const;\n\nexport async function promptConfigOptions(rl: readline.Interface): Promise<ConfigPatch> {\n // \u2500\u2500 Semantic Search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n printSection('\uD83D\uDD0D', 'Semantic Search');\n\n const enableEmbeddings = await askToggle(\n rl,\n 'Semantic embeddings (similarity search):',\n 'Enables natural-language code search via vector embeddings. A local model (~130MB) is downloaded on first use.',\n );\n\n const patch: ConfigPatch = { enableEmbeddings, useVecIndex: false, semanticEngine: 'cosine', typesenseDashboard: false, qdrantDashboard: false, extractDocstrings: true, trackCallSites: true, enableArchitecture: false, cavemanMode: 'off', shellCompressionLevel: 'normal', enableMemory: false };\n\n if (enableEmbeddings) {\n // \u2500\u2500 Model selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const modelChoice = await arrowSelect<string>(\n rl,\n 'Embedding model:',\n PRESET_MODELS.map(m => ({ value: m.value, label: m.label, description: m.description })),\n );\n\n let embeddingModel: string;\n let embeddingDim: number;\n\n if (modelChoice === '__other__') {\n console.log(`\\n ${dim}Enter a HuggingFace model ID in the format org/model-name.${reset}`);\n while (true) {\n const raw = (await ask(rl, ` ${violet}Model identifier:${reset} `)).trim();\n if (raw.includes('/')) { embeddingModel = raw; break; }\n console.log(` Expected a HuggingFace model ID in the format org/model-name (e.g. nomic-ai/nomic-embed-text-v1.5).`);\n }\n console.log(`\\n ${dim}Enter the embedding output dimension for this model (check the model card on HuggingFace).${reset}`);\n while (true) {\n const raw = (await ask(rl, ` ${violet}Embedding dimension (e.g. 768, 384):${reset} `)).trim();\n const n = parseInt(raw, 10);\n if (!isNaN(n) && n > 0) { embeddingDim = n; break; }\n console.log(` Expected a positive integer (e.g. 768, 384, 1536).`);\n }\n } else {\n const preset = PRESET_MODELS.find(m => m.value === modelChoice)!;\n embeddingModel = preset.value;\n embeddingDim = preset.dim;\n }\n\n patch.embeddingModel = embeddingModel;\n patch.embeddingDim = embeddingDim;\n\n // \u2500\u2500 Engine selection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const semanticEngine = await arrowSelect<SemanticEngine>(rl, 'Vector search engine:', [\n { value: 'cosine', label: 'cosine', description: 'In-process cosine similarity. No extra deps. Best for small/medium projects.' },\n { value: 'sqlite-vec', label: 'sqlite-vec', description: 'ANN index. Sub-linear search. Best for large codebases. Needs: better-sqlite3, sqlite-vec (native).' },\n { value: 'orama', label: 'orama', description: 'Hybrid search (full-text + vector). Pure JS. Needs: @orama/orama, @orama/plugin-data-persistence.' },\n { value: 'pglite', label: 'pglite', description: 'Hybrid search via PostgreSQL + pgvector. Exact results. Pure WASM. Needs: @electric-sql/pglite.' },\n { value: 'lancedb', label: 'lancedb', description: 'ANN search via LanceDB (Apache Lance columnar format). Pure JS. Needs: @lancedb/lancedb.' },\n { value: 'qdrant', label: 'qdrant', description: 'ANN search via Qdrant embedded binary (HNSW index, Cosine). Needs: qdrant-local.' },\n { value: 'typesense', label: 'typesense', description: 'ANN search via Typesense (auto-downloaded binary, HNSW, Cosine). Needs: typesense.' },\n ]);\n patch.semanticEngine = semanticEngine;\n patch.useVecIndex = semanticEngine === 'sqlite-vec';\n\n if (semanticEngine === 'typesense') {\n patch.typesenseDashboard = await askToggle(rl,\n 'Typesense dashboard:',\n 'Serves the Typesense Dashboard locally and opens it in your browser after indexing completes.',\n false,\n );\n }\n\n if (semanticEngine === 'qdrant') {\n patch.qdrantDashboard = await askToggle(rl,\n 'Qdrant dashboard:',\n 'Downloads the Qdrant Web UI (first time only) and opens it in your browser after indexing completes.',\n false,\n );\n }\n }\n\n // \u2500\u2500 Graph Features \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n printSection('\uD83D\uDCCA', 'Graph Features');\n\n patch.extractDocstrings = await askToggle(rl,\n 'Docstring extraction:',\n 'Enriches symbol metadata and improves context quality. Slightly increases indexing time.',\n );\n\n patch.trackCallSites = await askToggle(rl,\n 'Call site tracking (caller/callee graph):',\n 'Enables kirograph_callers and kirograph_callees MCP tools. Increases index size.',\n );\n\n patch.enableArchitecture = await askToggle(rl,\n 'Architecture analysis (packages + layers):',\n 'Detects packages from manifests and architectural layers. Enables kirograph_architecture, kirograph_coupling, kirograph_package.',\n false,\n );\n\n // \u2500\u2500 Agent Behavior \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n printSection('\uD83E\uDD16', 'Agent Behavior');\n\n const cavemanChoice = await arrowSelect(rl, 'Communication style (caveman mode):', [\n { value: 'off', label: 'off', description: 'Normal responses \u2014 no compression' },\n { value: 'lite', label: 'lite', description: 'Compact, no filler, full sentences' },\n { value: 'full', label: 'full', description: 'Fragments, no articles, short synonyms' },\n { value: 'ultra', label: 'ultra', description: 'Max compression, abbreviations, \u2192 for causality' },\n ]);\n patch.cavemanMode = cavemanChoice as CavemanMode | 'off';\n\n const compressionChoice = await arrowSelect(rl, 'Shell compression (kirograph_exec default level):', [\n { value: 'off', label: 'off', description: 'No compression hook or steering (tool still available)' },\n { value: 'normal', label: 'normal', description: 'Balanced: removes noise, keeps structure (recommended)' },\n { value: 'aggressive', label: 'aggressive', description: 'More compact: groups by category, limits output' },\n { value: 'ultra', label: 'ultra', description: 'Maximum compression: counts and summaries only' },\n ]);\n patch.shellCompressionLevel = compressionChoice as KiroGraphConfig['shellCompressionLevel'];\n\n // \u2500\u2500 Memory \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n printSection('\uD83E\uDDE0', 'Memory');\n\n (patch as any).enableMemory = await askToggle(rl,\n 'Persistent memory (cross-session observations):',\n 'Stores decisions, errors, and patterns across sessions. Compressed (if caveman is on), linked to code symbols, searchable via kirograph_mem_* tools. Zero LLM tokens on write.',\n false, // Requires explicit enable\n );\n\n return patch;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -34,95 +34,41 @@ module.exports = __toCommonJS(hooks_exports);
34
34
  var fs = __toESM(require("fs"));
35
35
  var path = __toESM(require("path"));
36
36
  var import_errors = require("../../errors");
37
- const FILE_PATTERNS = [
38
- "**/*.ts",
39
- "**/*.tsx",
40
- "**/*.js",
41
- "**/*.jsx",
42
- "**/*.py",
43
- "**/*.go",
44
- "**/*.rs",
45
- "**/*.java",
46
- "**/*.cs",
47
- "**/*.rb",
48
- "**/*.php",
49
- "**/*.swift",
50
- "**/*.kt",
51
- "**/*.dart",
52
- "**/*.ex",
53
- "**/*.exs",
54
- "**/*.scala",
55
- "**/*.sc",
56
- "**/*.lua",
57
- "**/*.zig",
58
- "**/*.sh",
59
- "**/*.bash",
60
- "**/*.ml",
61
- "**/*.mli",
62
- "**/*.elm",
63
- "**/*.sol",
64
- "**/*.vue",
65
- "**/*.m",
66
- "**/*.yaml",
67
- "**/*.yml",
68
- "**/*.tf",
69
- "**/*.tfvars",
70
- "**/*.css",
71
- "**/*.scss",
72
- "**/*.sass",
73
- "**/*.html"
74
- ];
37
+ const HOOK_EXT = ".kiro.hook";
75
38
  const HOOKS = [
76
39
  {
77
- filename: "kirograph-mark-dirty-on-save.json",
78
- hook: {
79
- name: "KiroGraph Mark Dirty on Save",
80
- version: "1.0.0",
81
- description: "Mark the KiroGraph index as dirty when source files are saved. Sync is deferred to agent idle.",
82
- when: { type: "fileEdited", patterns: FILE_PATTERNS },
83
- then: { type: "runCommand", command: "kirograph mark-dirty 2>/dev/null || true" }
84
- }
85
- },
86
- {
87
- filename: "kirograph-mark-dirty-on-create.json",
40
+ filename: `kirograph-sync-if-dirty${HOOK_EXT}`,
88
41
  hook: {
89
- name: "KiroGraph Mark Dirty on Create",
42
+ name: "KiroGraph Sync on Agent Stop",
90
43
  version: "1.0.0",
91
- description: "Mark the KiroGraph index as dirty when source files are created.",
92
- when: { type: "fileCreated", patterns: FILE_PATTERNS },
93
- then: { type: "runCommand", command: "kirograph mark-dirty 2>/dev/null || true" }
44
+ description: "Sync the KiroGraph index when the agent stops, picking up any file edits, creates, or deletes from the session.",
45
+ when: { type: "agentStop" },
46
+ then: { type: "runCommand", command: "kirograph sync --quiet 2>&1 > /dev/null" }
94
47
  }
95
48
  },
96
49
  {
97
- filename: "kirograph-sync-on-delete.json",
50
+ filename: `kirograph-compress-hint${HOOK_EXT}`,
98
51
  hook: {
99
- name: "KiroGraph Sync on Delete",
52
+ name: "KiroGraph Compression Hint",
100
53
  version: "1.0.0",
101
- description: "Remove deleted files from the KiroGraph index immediately.",
102
- when: { type: "fileDeleted", patterns: FILE_PATTERNS },
103
- then: { type: "runCommand", command: "kirograph sync-if-dirty 2>/dev/null || true" }
54
+ description: "Remind the agent to use kirograph_exec for shell commands that benefit from token compression (git, gh, test, lint, build, docker, aws, grep).",
55
+ when: { type: "preToolUse", toolTypes: ["shell"] },
56
+ then: {
57
+ type: "askAgent",
58
+ prompt: "If this shell command is a git operation, GitHub CLI, test runner, linter, build tool, file listing, grep/rg, docker/kubectl, AWS CLI, or package manager command, consider using the kirograph_exec MCP tool instead for 60-90% token savings. The tool compresses output automatically while preserving error details."
59
+ }
104
60
  }
105
61
  },
106
62
  {
107
- filename: "kirograph-sync-if-dirty.json",
63
+ filename: `kirograph-mem-capture${HOOK_EXT}`,
108
64
  hook: {
109
- name: "KiroGraph Deferred Sync",
65
+ name: "KiroGraph Memory Capture",
110
66
  version: "1.0.0",
111
- description: "Sync the KiroGraph index when the agent is idle and a dirty marker is present. Batches multiple rapid saves into one sync.",
67
+ description: "Prompt the agent to store important observations in memory at the end of each session.",
112
68
  when: { type: "agentStop" },
113
- then: { type: "runCommand", command: "kirograph sync-if-dirty --quiet 2>/dev/null || true" }
114
- }
115
- },
116
- {
117
- filename: "kirograph-compress-hint.json",
118
- hook: {
119
- name: "KiroGraph Compression Hint",
120
- version: "1.0.0",
121
- description: "Remind the agent to use kirograph_exec for shell commands that benefit from token compression (git, gh, test, lint, build, docker, aws, grep).",
122
- when: { type: "preToolUse", toolTypes: ["shell"] },
123
69
  then: {
124
70
  type: "askAgent",
125
- prompt: "If this shell command is a git operation, GitHub CLI, test runner, linter, build tool, file listing, grep/rg, docker/kubectl, AWS CLI, or package manager command, consider using the kirograph_exec MCP tool instead for 60-90% token savings. The tool compresses output automatically while preserving error details."
71
+ prompt: "Before ending, review what happened in this session. If there were any important decisions, bug root causes, architecture insights, error patterns, or lessons learned, store them using kirograph_mem_store with the appropriate kind (decision, error, pattern, architecture, note). Keep observations concise \u2014 one fact per observation. Skip if nothing noteworthy happened."
126
72
  }
127
73
  }
128
74
  }
@@ -137,7 +83,7 @@ function migrateOnIdleHooks(hooksDir) {
137
83
  if (!fs.existsSync(hooksDir)) return;
138
84
  let files;
139
85
  try {
140
- files = fs.readdirSync(hooksDir).filter((f) => f.endsWith(".json"));
86
+ files = fs.readdirSync(hooksDir).filter((f) => f.endsWith(".json") || f.endsWith(HOOK_EXT));
141
87
  } catch {
142
88
  return;
143
89
  }
@@ -157,8 +103,21 @@ function migrateOnIdleHooks(hooksDir) {
157
103
  (0, import_errors.logWarn)(`KiroGraph installer: could not parse hook file ${filePath}`);
158
104
  continue;
159
105
  }
106
+ let changed = false;
160
107
  if (obj?.when?.type === "onIdle") {
161
108
  obj.when.type = "agentStop";
109
+ changed = true;
110
+ }
111
+ if (file.endsWith(".json") && file.startsWith("kirograph-")) {
112
+ const newName = file.replace(/\.json$/, HOOK_EXT);
113
+ const newPath = path.join(hooksDir, newName);
114
+ try {
115
+ fs.writeFileSync(newPath, JSON.stringify(obj, null, 2) + "\n");
116
+ fs.unlinkSync(filePath);
117
+ } catch {
118
+ (0, import_errors.logWarn)(`KiroGraph installer: could not migrate hook file ${filePath} \u2192 ${newName}`);
119
+ }
120
+ } else if (changed) {
162
121
  try {
163
122
  fs.writeFileSync(filePath, JSON.stringify(obj, null, 2) + "\n");
164
123
  } catch {
@@ -171,13 +130,32 @@ function writeHooks(kiroDir, opts) {
171
130
  const hooksDir = path.join(kiroDir, "hooks");
172
131
  ensureDir(hooksDir);
173
132
  migrateOnIdleHooks(hooksDir);
174
- const oldHooks = ["kirograph-sync-on-save.json", "kirograph-sync-on-create.json"];
133
+ const oldHooks = [
134
+ "kirograph-sync-on-save.json",
135
+ "kirograph-sync-on-create.json",
136
+ // Legacy .json versions (migrated to .kiro.hook)
137
+ "kirograph-mark-dirty-on-save.json",
138
+ "kirograph-mark-dirty-on-create.json",
139
+ "kirograph-sync-on-delete.json",
140
+ "kirograph-sync-if-dirty.json",
141
+ "kirograph-compress-hint.json",
142
+ "kirograph-mem-capture.json",
143
+ // Removed per-file hooks (consolidated into agentStop sync)
144
+ `kirograph-mark-dirty-on-save${HOOK_EXT}`,
145
+ `kirograph-mark-dirty-on-create${HOOK_EXT}`,
146
+ `kirograph-sync-on-delete${HOOK_EXT}`
147
+ ];
175
148
  for (const old of oldHooks) {
176
149
  const p = path.join(hooksDir, old);
177
150
  if (fs.existsSync(p)) fs.unlinkSync(p);
178
151
  }
179
152
  for (const { filename, hook } of HOOKS) {
180
- if (filename === "kirograph-compress-hint.json" && opts?.enableCompression === false) {
153
+ if (filename === `kirograph-compress-hint${HOOK_EXT}` && opts?.enableCompression === false) {
154
+ const p = path.join(hooksDir, filename);
155
+ if (fs.existsSync(p)) fs.unlinkSync(p);
156
+ continue;
157
+ }
158
+ if (filename === `kirograph-mem-capture${HOOK_EXT}` && !opts?.enableMemory) {
181
159
  const p = path.join(hooksDir, filename);
182
160
  if (fs.existsSync(p)) fs.unlinkSync(p);
183
161
  continue;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/bin/installer/hooks.ts"],
4
- "sourcesContent": ["/**\n * KiroGraph Installer \u2014 Kiro hook file management\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { logWarn } from '../../errors';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst FILE_PATTERNS = [\n '**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx',\n '**/*.py', '**/*.go', '**/*.rs', '**/*.java',\n '**/*.cs', '**/*.rb', '**/*.php', '**/*.swift',\n '**/*.kt', '**/*.dart',\n '**/*.ex', '**/*.exs',\n '**/*.scala', '**/*.sc', '**/*.lua', '**/*.zig',\n '**/*.sh', '**/*.bash', '**/*.ml', '**/*.mli',\n '**/*.elm', '**/*.sol', '**/*.vue', '**/*.m',\n '**/*.yaml', '**/*.yml',\n '**/*.tf', '**/*.tfvars',\n '**/*.css', '**/*.scss', '**/*.sass',\n '**/*.html',\n];\n\nconst HOOKS: Array<{ filename: string; hook: object }> = [\n {\n filename: 'kirograph-mark-dirty-on-save.json',\n hook: {\n name: 'KiroGraph Mark Dirty on Save',\n version: '1.0.0',\n description: 'Mark the KiroGraph index as dirty when source files are saved. Sync is deferred to agent idle.',\n when: { type: 'fileEdited', patterns: FILE_PATTERNS },\n then: { type: 'runCommand', command: 'kirograph mark-dirty 2>/dev/null || true' },\n },\n },\n {\n filename: 'kirograph-mark-dirty-on-create.json',\n hook: {\n name: 'KiroGraph Mark Dirty on Create',\n version: '1.0.0',\n description: 'Mark the KiroGraph index as dirty when source files are created.',\n when: { type: 'fileCreated', patterns: FILE_PATTERNS },\n then: { type: 'runCommand', command: 'kirograph mark-dirty 2>/dev/null || true' },\n },\n },\n {\n filename: 'kirograph-sync-on-delete.json',\n hook: {\n name: 'KiroGraph Sync on Delete',\n version: '1.0.0',\n description: 'Remove deleted files from the KiroGraph index immediately.',\n when: { type: 'fileDeleted', patterns: FILE_PATTERNS },\n then: { type: 'runCommand', command: 'kirograph sync-if-dirty 2>/dev/null || true' },\n },\n },\n {\n filename: 'kirograph-sync-if-dirty.json',\n hook: {\n name: 'KiroGraph Deferred Sync',\n version: '1.0.0',\n description: 'Sync the KiroGraph index when the agent is idle and a dirty marker is present. Batches multiple rapid saves into one sync.',\n when: { type: 'agentStop' },\n then: { type: 'runCommand', command: 'kirograph sync-if-dirty --quiet 2>/dev/null || true' },\n },\n },\n {\n filename: 'kirograph-compress-hint.json',\n hook: {\n name: 'KiroGraph Compression Hint',\n version: '1.0.0',\n description: 'Remind the agent to use kirograph_exec for shell commands that benefit from token compression (git, gh, test, lint, build, docker, aws, grep).',\n when: { type: 'preToolUse', toolTypes: ['shell'] },\n then: {\n type: 'askAgent',\n prompt: 'If this shell command is a git operation, GitHub CLI, test runner, linter, build tool, file listing, grep/rg, docker/kubectl, AWS CLI, or package manager command, consider using the kirograph_exec MCP tool instead for 60-90% token savings. The tool compresses output automatically while preserving error details.',\n },\n },\n },\n];\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction ensureDir(p: string): void {\n fs.mkdirSync(p, { recursive: true });\n}\n\nfunction writeJson(p: string, data: unknown): void {\n fs.writeFileSync(p, JSON.stringify(data, null, 2) + '\\n');\n}\n\nfunction migrateOnIdleHooks(hooksDir: string): void {\n if (!fs.existsSync(hooksDir)) return;\n let files: string[];\n try {\n files = fs.readdirSync(hooksDir).filter(f => f.endsWith('.json'));\n } catch {\n return;\n }\n for (const file of files) {\n const filePath = path.join(hooksDir, file);\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch {\n logWarn(`KiroGraph installer: could not read hook file ${filePath}`);\n continue;\n }\n let obj: any;\n try {\n obj = JSON.parse(raw);\n } catch {\n logWarn(`KiroGraph installer: could not parse hook file ${filePath}`);\n continue;\n }\n if (obj?.when?.type === 'onIdle') {\n obj.when.type = 'agentStop';\n try {\n fs.writeFileSync(filePath, JSON.stringify(obj, null, 2) + '\\n');\n } catch {\n logWarn(`KiroGraph installer: could not write migrated hook file ${filePath}`);\n }\n }\n }\n}\n\n// \u2500\u2500 Public \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function writeHooks(kiroDir: string, opts?: { enableCompression?: boolean }): void {\n const hooksDir = path.join(kiroDir, 'hooks');\n ensureDir(hooksDir);\n\n migrateOnIdleHooks(hooksDir);\n\n const oldHooks = ['kirograph-sync-on-save.json', 'kirograph-sync-on-create.json'];\n for (const old of oldHooks) {\n const p = path.join(hooksDir, old);\n if (fs.existsSync(p)) fs.unlinkSync(p);\n }\n\n for (const { filename, hook } of HOOKS) {\n // Skip compression hook if compression is disabled\n if (filename === 'kirograph-compress-hint.json' && opts?.enableCompression === false) {\n // Remove the hook file if it exists from a previous install\n const p = path.join(hooksDir, filename);\n if (fs.existsSync(p)) fs.unlinkSync(p);\n continue;\n }\n writeJson(path.join(hooksDir, filename), hook);\n }\n\n console.log(` \u2713 Auto-sync hooks written to ${hooksDir}`);\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * KiroGraph Installer \u2014 Kiro hook file management\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { logWarn } from '../../errors';\n\n// \u2500\u2500 Constants \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst HOOK_EXT = '.kiro.hook';\n\nconst HOOKS: Array<{ filename: string; hook: object }> = [\n {\n filename: `kirograph-sync-if-dirty${HOOK_EXT}`,\n hook: {\n name: 'KiroGraph Sync on Agent Stop',\n version: '1.0.0',\n description: 'Sync the KiroGraph index when the agent stops, picking up any file edits, creates, or deletes from the session.',\n when: { type: 'agentStop' },\n then: { type: 'runCommand', command: 'kirograph sync --quiet 2>&1 > /dev/null' },\n },\n },\n {\n filename: `kirograph-compress-hint${HOOK_EXT}`,\n hook: {\n name: 'KiroGraph Compression Hint',\n version: '1.0.0',\n description: 'Remind the agent to use kirograph_exec for shell commands that benefit from token compression (git, gh, test, lint, build, docker, aws, grep).',\n when: { type: 'preToolUse', toolTypes: ['shell'] },\n then: {\n type: 'askAgent',\n prompt: 'If this shell command is a git operation, GitHub CLI, test runner, linter, build tool, file listing, grep/rg, docker/kubectl, AWS CLI, or package manager command, consider using the kirograph_exec MCP tool instead for 60-90% token savings. The tool compresses output automatically while preserving error details.',\n },\n },\n },\n {\n filename: `kirograph-mem-capture${HOOK_EXT}`,\n hook: {\n name: 'KiroGraph Memory Capture',\n version: '1.0.0',\n description: 'Prompt the agent to store important observations in memory at the end of each session.',\n when: { type: 'agentStop' },\n then: {\n type: 'askAgent',\n prompt: 'Before ending, review what happened in this session. If there were any important decisions, bug root causes, architecture insights, error patterns, or lessons learned, store them using kirograph_mem_store with the appropriate kind (decision, error, pattern, architecture, note). Keep observations concise \u2014 one fact per observation. Skip if nothing noteworthy happened.',\n },\n },\n },\n];\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction ensureDir(p: string): void {\n fs.mkdirSync(p, { recursive: true });\n}\n\nfunction writeJson(p: string, data: unknown): void {\n fs.writeFileSync(p, JSON.stringify(data, null, 2) + '\\n');\n}\n\nfunction migrateOnIdleHooks(hooksDir: string): void {\n if (!fs.existsSync(hooksDir)) return;\n let files: string[];\n try {\n files = fs.readdirSync(hooksDir).filter(f => f.endsWith('.json') || f.endsWith(HOOK_EXT));\n } catch {\n return;\n }\n for (const file of files) {\n const filePath = path.join(hooksDir, file);\n let raw: string;\n try {\n raw = fs.readFileSync(filePath, 'utf8');\n } catch {\n logWarn(`KiroGraph installer: could not read hook file ${filePath}`);\n continue;\n }\n let obj: any;\n try {\n obj = JSON.parse(raw);\n } catch {\n logWarn(`KiroGraph installer: could not parse hook file ${filePath}`);\n continue;\n }\n let changed = false;\n if (obj?.when?.type === 'onIdle') {\n obj.when.type = 'agentStop';\n changed = true;\n }\n // Migrate .json \u2192 .kiro.hook extension\n if (file.endsWith('.json') && file.startsWith('kirograph-')) {\n const newName = file.replace(/\\.json$/, HOOK_EXT);\n const newPath = path.join(hooksDir, newName);\n try {\n fs.writeFileSync(newPath, JSON.stringify(obj, null, 2) + '\\n');\n fs.unlinkSync(filePath);\n } catch {\n logWarn(`KiroGraph installer: could not migrate hook file ${filePath} \u2192 ${newName}`);\n }\n } else if (changed) {\n try {\n fs.writeFileSync(filePath, JSON.stringify(obj, null, 2) + '\\n');\n } catch {\n logWarn(`KiroGraph installer: could not write migrated hook file ${filePath}`);\n }\n }\n }\n}\n\n// \u2500\u2500 Public \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function writeHooks(kiroDir: string, opts?: { enableCompression?: boolean; enableMemory?: boolean }): void {\n const hooksDir = path.join(kiroDir, 'hooks');\n ensureDir(hooksDir);\n\n migrateOnIdleHooks(hooksDir);\n\n const oldHooks = [\n 'kirograph-sync-on-save.json', 'kirograph-sync-on-create.json',\n // Legacy .json versions (migrated to .kiro.hook)\n 'kirograph-mark-dirty-on-save.json', 'kirograph-mark-dirty-on-create.json',\n 'kirograph-sync-on-delete.json', 'kirograph-sync-if-dirty.json',\n 'kirograph-compress-hint.json', 'kirograph-mem-capture.json',\n // Removed per-file hooks (consolidated into agentStop sync)\n `kirograph-mark-dirty-on-save${HOOK_EXT}`,\n `kirograph-mark-dirty-on-create${HOOK_EXT}`,\n `kirograph-sync-on-delete${HOOK_EXT}`,\n ];\n for (const old of oldHooks) {\n const p = path.join(hooksDir, old);\n if (fs.existsSync(p)) fs.unlinkSync(p);\n }\n\n for (const { filename, hook } of HOOKS) {\n // Skip compression hook if compression is disabled\n if (filename === `kirograph-compress-hint${HOOK_EXT}` && opts?.enableCompression === false) {\n const p = path.join(hooksDir, filename);\n if (fs.existsSync(p)) fs.unlinkSync(p);\n continue;\n }\n // Skip memory hook if memory is disabled\n if (filename === `kirograph-mem-capture${HOOK_EXT}` && !opts?.enableMemory) {\n const p = path.join(hooksDir, filename);\n if (fs.existsSync(p)) fs.unlinkSync(p);\n continue;\n }\n writeJson(path.join(hooksDir, filename), hook);\n }\n\n console.log(` \u2713 Auto-sync hooks written to ${hooksDir}`);\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }