kirograph 0.14.0 → 0.14.1

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.
@@ -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 { 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.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 // 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 ];\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
  }
@@ -34,87 +34,20 @@ 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",
88
- hook: {
89
- name: "KiroGraph Mark Dirty on Create",
90
- 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" }
94
- }
95
- },
96
- {
97
- filename: "kirograph-sync-on-delete.json",
98
- hook: {
99
- name: "KiroGraph Sync on Delete",
100
- 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" }
104
- }
105
- },
106
- {
107
- filename: "kirograph-sync-if-dirty.json",
40
+ filename: `kirograph-sync-if-dirty${HOOK_EXT}`,
108
41
  hook: {
109
- name: "KiroGraph Deferred Sync",
42
+ name: "KiroGraph Sync on Agent Stop",
110
43
  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.",
44
+ description: "Sync the KiroGraph index when the agent stops, picking up any file edits, creates, or deletes from the session.",
112
45
  when: { type: "agentStop" },
113
- then: { type: "runCommand", command: "kirograph sync-if-dirty --quiet 2>/dev/null || true" }
46
+ then: { type: "askAgent", prompt: "If any source file was created, edited, or deleted during this session, run kirograph_exec with command 'kirograph sync --quiet' to sync the index. If no files were changed, do nothing. Do not explain, just run the tool silently." }
114
47
  }
115
48
  },
116
49
  {
117
- filename: "kirograph-compress-hint.json",
50
+ filename: `kirograph-compress-hint${HOOK_EXT}`,
118
51
  hook: {
119
52
  name: "KiroGraph Compression Hint",
120
53
  version: "1.0.0",
@@ -137,7 +70,7 @@ function migrateOnIdleHooks(hooksDir) {
137
70
  if (!fs.existsSync(hooksDir)) return;
138
71
  let files;
139
72
  try {
140
- files = fs.readdirSync(hooksDir).filter((f) => f.endsWith(".json"));
73
+ files = fs.readdirSync(hooksDir).filter((f) => f.endsWith(".json") || f.endsWith(HOOK_EXT));
141
74
  } catch {
142
75
  return;
143
76
  }
@@ -157,8 +90,21 @@ function migrateOnIdleHooks(hooksDir) {
157
90
  (0, import_errors.logWarn)(`KiroGraph installer: could not parse hook file ${filePath}`);
158
91
  continue;
159
92
  }
93
+ let changed = false;
160
94
  if (obj?.when?.type === "onIdle") {
161
95
  obj.when.type = "agentStop";
96
+ changed = true;
97
+ }
98
+ if (file.endsWith(".json") && file.startsWith("kirograph-")) {
99
+ const newName = file.replace(/\.json$/, HOOK_EXT);
100
+ const newPath = path.join(hooksDir, newName);
101
+ try {
102
+ fs.writeFileSync(newPath, JSON.stringify(obj, null, 2) + "\n");
103
+ fs.unlinkSync(filePath);
104
+ } catch {
105
+ (0, import_errors.logWarn)(`KiroGraph installer: could not migrate hook file ${filePath} \u2192 ${newName}`);
106
+ }
107
+ } else if (changed) {
162
108
  try {
163
109
  fs.writeFileSync(filePath, JSON.stringify(obj, null, 2) + "\n");
164
110
  } catch {
@@ -171,13 +117,26 @@ function writeHooks(kiroDir, opts) {
171
117
  const hooksDir = path.join(kiroDir, "hooks");
172
118
  ensureDir(hooksDir);
173
119
  migrateOnIdleHooks(hooksDir);
174
- const oldHooks = ["kirograph-sync-on-save.json", "kirograph-sync-on-create.json"];
120
+ const oldHooks = [
121
+ "kirograph-sync-on-save.json",
122
+ "kirograph-sync-on-create.json",
123
+ // Legacy .json versions (migrated to .kiro.hook)
124
+ "kirograph-mark-dirty-on-save.json",
125
+ "kirograph-mark-dirty-on-create.json",
126
+ "kirograph-sync-on-delete.json",
127
+ "kirograph-sync-if-dirty.json",
128
+ "kirograph-compress-hint.json",
129
+ // Removed per-file hooks (consolidated into agentStop sync)
130
+ `kirograph-mark-dirty-on-save${HOOK_EXT}`,
131
+ `kirograph-mark-dirty-on-create${HOOK_EXT}`,
132
+ `kirograph-sync-on-delete${HOOK_EXT}`
133
+ ];
175
134
  for (const old of oldHooks) {
176
135
  const p = path.join(hooksDir, old);
177
136
  if (fs.existsSync(p)) fs.unlinkSync(p);
178
137
  }
179
138
  for (const { filename, hook } of HOOKS) {
180
- if (filename === "kirograph-compress-hint.json" && opts?.enableCompression === false) {
139
+ if (filename === `kirograph-compress-hint${HOOK_EXT}` && opts?.enableCompression === false) {
181
140
  const p = path.join(hooksDir, filename);
182
141
  if (fs.existsSync(p)) fs.unlinkSync(p);
183
142
  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: 'askAgent', prompt: \"If any source file was created, edited, or deleted during this session, run kirograph_exec with command 'kirograph sync --quiet' to sync the index. If no files were changed, do nothing. Do not explain, just run the tool silently.\" },\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\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 }): 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',\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 // 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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",
6
6
  "names": []
7
7
  }
@@ -59,7 +59,7 @@ process.on("uncaughtException", (err) => {
59
59
  process.exit(1);
60
60
  });
61
61
  const program = new import_commander.Command();
62
- program.name("kirograph").description("Semantic code knowledge graph for Kiro").version("0.14.0").addHelpCommand(true).hook("preAction", (thisCommand) => {
62
+ program.name("kirograph").description("Semantic code knowledge graph for Kiro").version("0.14.1").addHelpCommand(true).hook("preAction", (thisCommand) => {
63
63
  const name = thisCommand.name();
64
64
  if (name === "init") (0, import_banner.printBanner)();
65
65
  });
@@ -0,0 +1,51 @@
1
+ -- KiroGraph Memory Schema (opt-in, enableMemory=true)
2
+ -- Isolated from core graph tables. No FK to nodes(id) to avoid cascade on reindex.
3
+
4
+ CREATE TABLE IF NOT EXISTS mem_sessions (
5
+ id TEXT PRIMARY KEY,
6
+ ide TEXT,
7
+ cwd TEXT,
8
+ started_at INTEGER NOT NULL,
9
+ ended_at INTEGER
10
+ );
11
+
12
+ CREATE INDEX IF NOT EXISTS idx_mem_sessions_started ON mem_sessions(started_at);
13
+
14
+ CREATE TABLE IF NOT EXISTS mem_observations (
15
+ id TEXT PRIMARY KEY,
16
+ session_id TEXT REFERENCES mem_sessions(id) ON DELETE SET NULL,
17
+ content TEXT NOT NULL,
18
+ content_raw TEXT,
19
+ content_hash TEXT,
20
+ kind TEXT NOT NULL,
21
+ source TEXT NOT NULL DEFAULT 'hook',
22
+ tags TEXT,
23
+ created_at INTEGER NOT NULL
24
+ );
25
+
26
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_mem_obs_hash ON mem_observations(content_hash);
27
+ CREATE INDEX IF NOT EXISTS idx_mem_obs_session ON mem_observations(session_id);
28
+ CREATE INDEX IF NOT EXISTS idx_mem_obs_kind ON mem_observations(kind);
29
+ CREATE INDEX IF NOT EXISTS idx_mem_obs_created ON mem_observations(created_at);
30
+
31
+ CREATE VIRTUAL TABLE IF NOT EXISTS mem_fts USING fts5(
32
+ id UNINDEXED,
33
+ content,
34
+ kind UNINDEXED
35
+ );
36
+
37
+ CREATE TABLE IF NOT EXISTS mem_links (
38
+ observation_id TEXT NOT NULL REFERENCES mem_observations(id) ON DELETE CASCADE,
39
+ qualified_name TEXT NOT NULL,
40
+ relevance REAL NOT NULL DEFAULT 1.0,
41
+ PRIMARY KEY (observation_id, qualified_name)
42
+ );
43
+
44
+ CREATE INDEX IF NOT EXISTS idx_mem_links_qname ON mem_links(qualified_name);
45
+
46
+ CREATE TABLE IF NOT EXISTS mem_vectors (
47
+ observation_id TEXT PRIMARY KEY REFERENCES mem_observations(id) ON DELETE CASCADE,
48
+ embedding BLOB NOT NULL,
49
+ model TEXT NOT NULL,
50
+ created_at INTEGER NOT NULL
51
+ );
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var compress_exports = {};
20
+ __export(compress_exports, {
21
+ compressObservation: () => compressObservation,
22
+ extractIdentifiers: () => extractIdentifiers
23
+ });
24
+ module.exports = __toCommonJS(compress_exports);
25
+ const CODE_BLOCK_RE = /```[\s\S]*?```/g;
26
+ const INLINE_CODE_RE = /`[^`]+`/g;
27
+ const FILE_PATH_RE = /(?:\.?\.?\/)?[\w\-./\\]+\.\w{1,10}/g;
28
+ const URL_RE = /https?:\/\/[^\s)]+/g;
29
+ const VERSION_RE = /\bv?\d+\.\d+(?:\.\d+)?(?:-[\w.]+)?\b/g;
30
+ const IDENTIFIER_RE = /\b(?:[A-Z][a-z]+(?:[A-Z][a-z]+)+|[a-z]+(?:[A-Z][a-z]+)+|[a-z]+(?:_[a-z]+)+|[A-Z]+(?:_[A-Z]+)+)\b/g;
31
+ const FILLER_WORDS = /\b(just|really|basically|simply|actually|very|quite|rather|somewhat|perhaps|maybe)\b/gi;
32
+ const ARTICLES = /\b(a|an|the)\b/gi;
33
+ const HEDGING_PHRASES = [
34
+ /\bI think\b/gi,
35
+ /\bit seems (like |that )?/gi,
36
+ /\byou might want to\b/gi,
37
+ /\byou may want to\b/gi,
38
+ /\bit looks like\b/gi,
39
+ /\bprobably\b/gi,
40
+ /\bI believe\b/gi,
41
+ /\bin my opinion\b/gi
42
+ ];
43
+ const PLEASANTRIES = [
44
+ /\b(please|thanks|thank you|sorry|excuse me)\b/gi,
45
+ /^(hi|hello|hey|sure|okay|ok|great|nice|cool|awesome|perfect),?\s*/gim
46
+ ];
47
+ const ABBREVIATIONS = [
48
+ [/\bdatabase\b/gi, "DB"],
49
+ [/\bauthentication\b/gi, "auth"],
50
+ [/\bauthenticate\b/gi, "auth"],
51
+ [/\brequest\b/gi, "req"],
52
+ [/\bresponse\b/gi, "res"],
53
+ [/\bfunction\b/gi, "fn"],
54
+ [/\bconfiguration\b/gi, "cfg"],
55
+ [/\bconfigure\b/gi, "cfg"],
56
+ [/\bmessage\b/gi, "msg"],
57
+ [/\berror\b/gi, "err"],
58
+ [/\bimplementation\b/gi, "impl"],
59
+ [/\bimplement\b/gi, "impl"],
60
+ [/\bdependency\b/gi, "dep"],
61
+ [/\bdependencies\b/gi, "deps"],
62
+ [/\brepository\b/gi, "repo"],
63
+ [/\benvironment\b/gi, "env"],
64
+ [/\bapplication\b/gi, "app"],
65
+ [/\bmiddleware\b/gi, "mw"],
66
+ [/\bparameter\b/gi, "param"],
67
+ [/\bparameters\b/gi, "params"]
68
+ ];
69
+ function compressObservation(text, mode) {
70
+ const originalLength = text.length;
71
+ if (mode === "off") {
72
+ return {
73
+ compressed: text,
74
+ originalLength,
75
+ compressedLength: text.length,
76
+ detectedSymbols: extractIdentifiers(text)
77
+ };
78
+ }
79
+ const preserved = /* @__PURE__ */ new Map();
80
+ let processed = text;
81
+ let placeholderIdx = 0;
82
+ function preserve(re) {
83
+ processed = processed.replace(re, (match) => {
84
+ const key = `\0P${placeholderIdx++}\0`;
85
+ preserved.set(key, match);
86
+ return key;
87
+ });
88
+ }
89
+ preserve(CODE_BLOCK_RE);
90
+ preserve(INLINE_CODE_RE);
91
+ preserve(URL_RE);
92
+ preserve(FILE_PATH_RE);
93
+ preserve(VERSION_RE);
94
+ preserve(IDENTIFIER_RE);
95
+ if (mode === "lite" || mode === "full" || mode === "ultra") {
96
+ processed = processed.replace(FILLER_WORDS, "");
97
+ for (const re of PLEASANTRIES) {
98
+ processed = processed.replace(re, "");
99
+ }
100
+ }
101
+ if (mode === "full" || mode === "ultra") {
102
+ processed = processed.replace(ARTICLES, "");
103
+ for (const re of HEDGING_PHRASES) {
104
+ processed = processed.replace(re, "");
105
+ }
106
+ }
107
+ if (mode === "ultra") {
108
+ for (const [re, replacement] of ABBREVIATIONS) {
109
+ processed = processed.replace(re, replacement);
110
+ }
111
+ processed = processed.replace(/\b(because|so|therefore|thus|hence)\b/gi, "\u2192");
112
+ processed = processed.replace(/\band\b/gi, "+");
113
+ }
114
+ processed = processed.split("\n").map((line) => line.replace(/\s{2,}/g, " ").trim()).filter((line) => line.length > 0).join("\n");
115
+ for (const [key, value] of preserved) {
116
+ processed = processed.replace(key, value);
117
+ }
118
+ return {
119
+ compressed: processed,
120
+ originalLength,
121
+ compressedLength: processed.length,
122
+ detectedSymbols: extractIdentifiers(text)
123
+ };
124
+ }
125
+ function extractIdentifiers(text) {
126
+ const matches = /* @__PURE__ */ new Set();
127
+ const camelPascal = text.match(/\b[A-Z]?[a-z]+(?:[A-Z][a-z]+)+\b/g);
128
+ if (camelPascal) camelPascal.forEach((m) => matches.add(m));
129
+ const pascal = text.match(/\b[A-Z][a-z]+(?:[A-Z][a-z]+)+\b/g);
130
+ if (pascal) pascal.forEach((m) => matches.add(m));
131
+ const snake = text.match(/\b[a-z]+(?:_[a-z]+)+\b/g);
132
+ if (snake) snake.forEach((m) => matches.add(m));
133
+ const screaming = text.match(/\b[A-Z]+(?:_[A-Z]+)+\b/g);
134
+ if (screaming) screaming.forEach((m) => matches.add(m));
135
+ return [...matches];
136
+ }
137
+ // Annotate the CommonJS export names for ESM import in node:
138
+ 0 && (module.exports = {
139
+ compressObservation,
140
+ extractIdentifiers
141
+ });
142
+ //# sourceMappingURL=compress.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/memory/compress.ts"],
4
+ "sourcesContent": ["/**\n * KiroGraph Memory \u2014 Deterministic observation compressor\n *\n * Applies caveman grammar rules programmatically. No LLM involved.\n * Only runs when cavemanMode is not 'off'. Uses the same level the user chose.\n */\n\nimport type { CompressResult } from './types';\n\nexport type CavemanMode = 'off' | 'lite' | 'full' | 'ultra';\n\n// \u2500\u2500 Patterns to preserve (never compress) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\n/** Matches code blocks (``` ... ```) */\nconst CODE_BLOCK_RE = /```[\\s\\S]*?```/g;\n\n/** Matches inline code (`...`) */\nconst INLINE_CODE_RE = /`[^`]+`/g;\n\n/** Matches file paths (containing / or \\ with extensions) */\nconst FILE_PATH_RE = /(?:\\.?\\.?\\/)?[\\w\\-./\\\\]+\\.\\w{1,10}/g;\n\n/** Matches URLs */\nconst URL_RE = /https?:\\/\\/[^\\s)]+/g;\n\n/** Matches version numbers (v1.2.3, 1.2.3) */\nconst VERSION_RE = /\\bv?\\d+\\.\\d+(?:\\.\\d+)?(?:-[\\w.]+)?\\b/g;\n\n/** Matches identifiers: camelCase, PascalCase, snake_case, SCREAMING_SNAKE */\nconst IDENTIFIER_RE = /\\b(?:[A-Z][a-z]+(?:[A-Z][a-z]+)+|[a-z]+(?:[A-Z][a-z]+)+|[a-z]+(?:_[a-z]+)+|[A-Z]+(?:_[A-Z]+)+)\\b/g;\n\n// \u2500\u2500 Filler / article / hedging patterns \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 FILLER_WORDS = /\\b(just|really|basically|simply|actually|very|quite|rather|somewhat|perhaps|maybe)\\b/gi;\n\nconst ARTICLES = /\\b(a|an|the)\\b/gi;\n\nconst HEDGING_PHRASES = [\n /\\bI think\\b/gi,\n /\\bit seems (like |that )?/gi,\n /\\byou might want to\\b/gi,\n /\\byou may want to\\b/gi,\n /\\bit looks like\\b/gi,\n /\\bprobably\\b/gi,\n /\\bI believe\\b/gi,\n /\\bin my opinion\\b/gi,\n];\n\nconst PLEASANTRIES = [\n /\\b(please|thanks|thank you|sorry|excuse me)\\b/gi,\n /^(hi|hello|hey|sure|okay|ok|great|nice|cool|awesome|perfect),?\\s*/gim,\n];\n\n// \u2500\u2500 Abbreviations (ultra only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 ABBREVIATIONS: [RegExp, string][] = [\n [/\\bdatabase\\b/gi, 'DB'],\n [/\\bauthentication\\b/gi, 'auth'],\n [/\\bauthenticate\\b/gi, 'auth'],\n [/\\brequest\\b/gi, 'req'],\n [/\\bresponse\\b/gi, 'res'],\n [/\\bfunction\\b/gi, 'fn'],\n [/\\bconfiguration\\b/gi, 'cfg'],\n [/\\bconfigure\\b/gi, 'cfg'],\n [/\\bmessage\\b/gi, 'msg'],\n [/\\berror\\b/gi, 'err'],\n [/\\bimplementation\\b/gi, 'impl'],\n [/\\bimplement\\b/gi, 'impl'],\n [/\\bdependency\\b/gi, 'dep'],\n [/\\bdependencies\\b/gi, 'deps'],\n [/\\brepository\\b/gi, 'repo'],\n [/\\benvironment\\b/gi, 'env'],\n [/\\bapplication\\b/gi, 'app'],\n [/\\bmiddleware\\b/gi, 'mw'],\n [/\\bparameter\\b/gi, 'param'],\n [/\\bparameters\\b/gi, 'params'],\n];\n\n// \u2500\u2500 Core compressor \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\n/**\n * Compress observation text using caveman grammar rules.\n * Returns the text unchanged if mode is 'off'.\n */\nexport function compressObservation(text: string, mode: CavemanMode): CompressResult {\n const originalLength = text.length;\n\n if (mode === 'off') {\n return {\n compressed: text,\n originalLength,\n compressedLength: text.length,\n detectedSymbols: extractIdentifiers(text),\n };\n }\n\n // Extract preserved tokens (code blocks, paths, URLs, versions, identifiers)\n const preserved = new Map<string, string>();\n let processed = text;\n let placeholderIdx = 0;\n\n function preserve(re: RegExp): void {\n processed = processed.replace(re, (match) => {\n const key = `\\x00P${placeholderIdx++}\\x00`;\n preserved.set(key, match);\n return key;\n });\n }\n\n // Order matters: code blocks first (they may contain other patterns)\n preserve(CODE_BLOCK_RE);\n preserve(INLINE_CODE_RE);\n preserve(URL_RE);\n preserve(FILE_PATH_RE);\n preserve(VERSION_RE);\n preserve(IDENTIFIER_RE);\n\n // Apply compression rules based on mode\n if (mode === 'lite' || mode === 'full' || mode === 'ultra') {\n // All modes: drop filler words\n processed = processed.replace(FILLER_WORDS, '');\n\n // All modes: drop pleasantries\n for (const re of PLEASANTRIES) {\n processed = processed.replace(re, '');\n }\n }\n\n if (mode === 'full' || mode === 'ultra') {\n // Drop articles\n processed = processed.replace(ARTICLES, '');\n\n // Drop hedging phrases\n for (const re of HEDGING_PHRASES) {\n processed = processed.replace(re, '');\n }\n }\n\n if (mode === 'ultra') {\n // Apply abbreviations\n for (const [re, replacement] of ABBREVIATIONS) {\n processed = processed.replace(re, replacement);\n }\n\n // Replace \"because\" / \"so\" / \"therefore\" with \u2192\n processed = processed.replace(/\\b(because|so|therefore|thus|hence)\\b/gi, '\u2192');\n\n // Replace \"and\" with +\n processed = processed.replace(/\\band\\b/gi, '+');\n }\n\n // Clean up multiple spaces and leading/trailing whitespace per line\n processed = processed\n .split('\\n')\n .map(line => line.replace(/\\s{2,}/g, ' ').trim())\n .filter(line => line.length > 0)\n .join('\\n');\n\n // Restore preserved tokens\n for (const [key, value] of preserved) {\n processed = processed.replace(key, value);\n }\n\n return {\n compressed: processed,\n originalLength,\n compressedLength: processed.length,\n detectedSymbols: extractIdentifiers(text),\n };\n}\n\n/**\n * Extract candidate identifiers from text (camelCase, PascalCase, snake_case).\n * Used for symbol detection.\n */\nexport function extractIdentifiers(text: string): string[] {\n const matches = new Set<string>();\n\n // camelCase and PascalCase\n const camelPascal = text.match(/\\b[A-Z]?[a-z]+(?:[A-Z][a-z]+)+\\b/g);\n if (camelPascal) camelPascal.forEach(m => matches.add(m));\n\n // PascalCase (starting with uppercase)\n const pascal = text.match(/\\b[A-Z][a-z]+(?:[A-Z][a-z]+)+\\b/g);\n if (pascal) pascal.forEach(m => matches.add(m));\n\n // snake_case (at least one underscore, all lowercase)\n const snake = text.match(/\\b[a-z]+(?:_[a-z]+)+\\b/g);\n if (snake) snake.forEach(m => matches.add(m));\n\n // SCREAMING_SNAKE_CASE\n const screaming = text.match(/\\b[A-Z]+(?:_[A-Z]+)+\\b/g);\n if (screaming) screaming.forEach(m => matches.add(m));\n\n return [...matches];\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }