@contextstream/mcp-server 0.4.51 → 0.4.53

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.
@@ -97,8 +97,17 @@ function extractToolInput(input) {
97
97
  return input.tool_input || input.parameters || input.toolParameters || {};
98
98
  }
99
99
  function blockClaudeCode(message) {
100
- console.error(message);
101
- process.exit(2);
100
+ const response = {
101
+ hookSpecificOutput: {
102
+ hookEventName: "PreToolUse",
103
+ // Use additionalContext instead of deny - tool runs but Claude sees the message
104
+ additionalContext: `[CONTEXTSTREAM] ${message}`
105
+ }
106
+ };
107
+ fs.appendFileSync(DEBUG_FILE, `[PreToolUse] REDIRECT (additionalContext): ${JSON.stringify(response)}
108
+ `);
109
+ console.log(JSON.stringify(response));
110
+ process.exit(0);
102
111
  }
103
112
  function outputClineBlock(errorMessage, contextMod) {
104
113
  const result = {
@@ -127,13 +136,18 @@ function detectEditorFormat(input) {
127
136
  if (input.hookName !== void 0 || input.toolName !== void 0) {
128
137
  return "cline";
129
138
  }
130
- if (input.hook_event_name !== void 0) {
131
- return "cursor";
139
+ if (input.hook_event_name !== void 0 || input.tool_name !== void 0) {
140
+ return "claude";
132
141
  }
133
142
  return "claude";
134
143
  }
135
144
  async function runPreToolUseHook() {
145
+ fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Hook invoked at ${(/* @__PURE__ */ new Date()).toISOString()}
146
+ `);
147
+ console.error("[PreToolUse] Hook invoked at", (/* @__PURE__ */ new Date()).toISOString());
136
148
  if (!ENABLED) {
149
+ fs.appendFileSync(DEBUG_FILE, "[PreToolUse] Hook disabled, exiting\n");
150
+ console.error("[PreToolUse] Hook disabled, exiting");
137
151
  process.exit(0);
138
152
  }
139
153
  let inputData = "";
@@ -153,8 +167,14 @@ async function runPreToolUseHook() {
153
167
  const cwd = extractCwd(input);
154
168
  const tool = extractToolName(input);
155
169
  const toolInput = extractToolInput(input);
170
+ fs.appendFileSync(DEBUG_FILE, `[PreToolUse] tool=${tool}, cwd=${cwd}, editorFormat=${editorFormat}
171
+ `);
156
172
  const { isIndexed } = isProjectIndexed(cwd);
173
+ fs.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}
174
+ `);
157
175
  if (!isIndexed) {
176
+ fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Project not indexed, allowing
177
+ `);
158
178
  if (editorFormat === "cline") {
159
179
  outputClineAllow();
160
180
  } else if (editorFormat === "cursor") {
@@ -164,8 +184,12 @@ async function runPreToolUseHook() {
164
184
  }
165
185
  if (tool === "Glob") {
166
186
  const pattern = toolInput?.pattern || "";
187
+ fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Glob pattern=${pattern}, isDiscovery=${isDiscoveryGlob(pattern)}
188
+ `);
167
189
  if (isDiscoveryGlob(pattern)) {
168
190
  const msg = `STOP: Use mcp__contextstream__search(mode="hybrid", query="${pattern}") instead of Glob.`;
191
+ fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Intercepting discovery glob: ${msg}
192
+ `);
169
193
  if (editorFormat === "cline") {
170
194
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
171
195
  } else if (editorFormat === "cursor") {
@@ -242,12 +266,13 @@ async function runPreToolUseHook() {
242
266
  }
243
267
  process.exit(0);
244
268
  }
245
- var ENABLED, INDEX_STATUS_FILE, STALE_THRESHOLD_DAYS, DISCOVERY_PATTERNS, isDirectRun;
269
+ var ENABLED, INDEX_STATUS_FILE, DEBUG_FILE, STALE_THRESHOLD_DAYS, DISCOVERY_PATTERNS, isDirectRun;
246
270
  var init_pre_tool_use = __esm({
247
271
  "src/hooks/pre-tool-use.ts"() {
248
272
  "use strict";
249
273
  ENABLED = process.env.CONTEXTSTREAM_HOOK_ENABLED !== "false";
250
274
  INDEX_STATUS_FILE = path.join(homedir(), ".contextstream", "indexed-projects.json");
275
+ DEBUG_FILE = "/tmp/pretooluse-hook-debug.log";
251
276
  STALE_THRESHOLD_DAYS = 7;
252
277
  DISCOVERY_PATTERNS = ["**/*", "**/", "src/**", "lib/**", "app/**", "components/**"];
253
278
  isDirectRun = process.argv[1]?.includes("pre-tool-use") || process.argv[2] === "pre-tool-use";
@@ -262,6 +287,184 @@ var user_prompt_submit_exports = {};
262
287
  __export(user_prompt_submit_exports, {
263
288
  runUserPromptSubmitHook: () => runUserPromptSubmitHook
264
289
  });
290
+ import * as fs2 from "node:fs";
291
+ import * as path2 from "node:path";
292
+ import { homedir as homedir2 } from "node:os";
293
+ function loadConfigFromMcpJson(cwd) {
294
+ let searchDir = path2.resolve(cwd);
295
+ for (let i = 0; i < 5; i++) {
296
+ if (!API_KEY) {
297
+ const mcpPath = path2.join(searchDir, ".mcp.json");
298
+ if (fs2.existsSync(mcpPath)) {
299
+ try {
300
+ const content = fs2.readFileSync(mcpPath, "utf-8");
301
+ const config = JSON.parse(content);
302
+ const csEnv = config.mcpServers?.contextstream?.env;
303
+ if (csEnv?.CONTEXTSTREAM_API_KEY) {
304
+ API_KEY = csEnv.CONTEXTSTREAM_API_KEY;
305
+ }
306
+ if (csEnv?.CONTEXTSTREAM_API_URL) {
307
+ API_URL = csEnv.CONTEXTSTREAM_API_URL;
308
+ }
309
+ if (csEnv?.CONTEXTSTREAM_WORKSPACE_ID) {
310
+ WORKSPACE_ID = csEnv.CONTEXTSTREAM_WORKSPACE_ID;
311
+ }
312
+ } catch {
313
+ }
314
+ }
315
+ }
316
+ if (!WORKSPACE_ID || !PROJECT_ID) {
317
+ const csConfigPath = path2.join(searchDir, ".contextstream", "config.json");
318
+ if (fs2.existsSync(csConfigPath)) {
319
+ try {
320
+ const content = fs2.readFileSync(csConfigPath, "utf-8");
321
+ const csConfig = JSON.parse(content);
322
+ if (csConfig.workspace_id && !WORKSPACE_ID) {
323
+ WORKSPACE_ID = csConfig.workspace_id;
324
+ }
325
+ if (csConfig.project_id && !PROJECT_ID) {
326
+ PROJECT_ID = csConfig.project_id;
327
+ }
328
+ } catch {
329
+ }
330
+ }
331
+ }
332
+ const parentDir = path2.dirname(searchDir);
333
+ if (parentDir === searchDir) break;
334
+ searchDir = parentDir;
335
+ }
336
+ if (!API_KEY) {
337
+ const homeMcpPath = path2.join(homedir2(), ".mcp.json");
338
+ if (fs2.existsSync(homeMcpPath)) {
339
+ try {
340
+ const content = fs2.readFileSync(homeMcpPath, "utf-8");
341
+ const config = JSON.parse(content);
342
+ const csEnv = config.mcpServers?.contextstream?.env;
343
+ if (csEnv?.CONTEXTSTREAM_API_KEY) {
344
+ API_KEY = csEnv.CONTEXTSTREAM_API_KEY;
345
+ }
346
+ if (csEnv?.CONTEXTSTREAM_API_URL) {
347
+ API_URL = csEnv.CONTEXTSTREAM_API_URL;
348
+ }
349
+ } catch {
350
+ }
351
+ }
352
+ }
353
+ }
354
+ async function fetchSessionContext() {
355
+ if (!API_KEY) return null;
356
+ try {
357
+ const controller = new AbortController();
358
+ const timeoutId = setTimeout(() => controller.abort(), 3e3);
359
+ const url = new URL(`${API_URL}/api/v1/context`);
360
+ if (WORKSPACE_ID) url.searchParams.set("workspace_id", WORKSPACE_ID);
361
+ if (PROJECT_ID) url.searchParams.set("project_id", PROJECT_ID);
362
+ url.searchParams.set("include_lessons", "true");
363
+ url.searchParams.set("include_decisions", "true");
364
+ url.searchParams.set("include_plans", "true");
365
+ url.searchParams.set("include_reminders", "true");
366
+ url.searchParams.set("limit", "3");
367
+ const response = await fetch(url.toString(), {
368
+ method: "GET",
369
+ headers: {
370
+ "X-API-Key": API_KEY
371
+ },
372
+ signal: controller.signal
373
+ });
374
+ clearTimeout(timeoutId);
375
+ if (response.ok) {
376
+ return await response.json();
377
+ }
378
+ return null;
379
+ } catch {
380
+ return null;
381
+ }
382
+ }
383
+ function buildEnhancedReminder(ctx, isNewSession2) {
384
+ const parts = [ENHANCED_REMINDER_HEADER];
385
+ if (isNewSession2) {
386
+ parts.push(`## \u{1F680} NEW SESSION DETECTED
387
+ 1. Call \`init(folder_path="...")\` - this triggers project indexing
388
+ 2. Wait for indexing: if \`init\` returns \`indexing_status: "started"\`, files are being indexed
389
+ 3. Then call \`context(user_message="...")\` for task-specific context
390
+ 4. Use \`search(mode="hybrid")\` for code discovery (not Glob/Grep/Read)
391
+
392
+ `);
393
+ }
394
+ if (ctx?.lessons && ctx.lessons.length > 0) {
395
+ parts.push(`## \u26A0\uFE0F LESSONS FROM PAST MISTAKES`);
396
+ for (const lesson of ctx.lessons.slice(0, 3)) {
397
+ parts.push(`- **${lesson.title}**: ${lesson.prevention}`);
398
+ }
399
+ parts.push("");
400
+ }
401
+ if (ctx?.active_plans && ctx.active_plans.length > 0) {
402
+ parts.push(`## \u{1F4CB} Active Plans`);
403
+ for (const plan of ctx.active_plans.slice(0, 3)) {
404
+ parts.push(`- ${plan.title} (${plan.status})`);
405
+ }
406
+ parts.push("");
407
+ }
408
+ if (ctx?.pending_tasks && ctx.pending_tasks.length > 0) {
409
+ parts.push(`## \u2705 Pending Tasks`);
410
+ for (const task of ctx.pending_tasks.slice(0, 5)) {
411
+ parts.push(`- ${task.title}`);
412
+ }
413
+ parts.push("");
414
+ }
415
+ if (ctx?.reminders && ctx.reminders.length > 0) {
416
+ parts.push(`## \u{1F514} Reminders`);
417
+ for (const reminder of ctx.reminders.slice(0, 3)) {
418
+ parts.push(`- ${reminder.title}`);
419
+ }
420
+ parts.push("");
421
+ }
422
+ parts.push("---\n");
423
+ parts.push(REMINDER);
424
+ parts.push(`
425
+
426
+ ---
427
+ ## \u{1F6A8} FILE INDEXING & SEARCH - CRITICAL (No PostToolUse Hook) \u{1F6A8}
428
+
429
+ **This editor does NOT have automatic file indexing after Edit/Write.**
430
+
431
+ ### \u26A0\uFE0F BEFORE ANY SEARCH - Check Index Status:
432
+ \`\`\`
433
+ project(action="index_status")
434
+ \`\`\`
435
+ Returns: \`indexed\` (true/false), \`last_indexed_at\`, \`file_count\`
436
+
437
+ ### \u{1F50D} Search Decision Tree:
438
+
439
+ **IF indexed=true AND last_indexed_at is recent:**
440
+ \u2192 Use \`search(mode="hybrid", query="...")\`
441
+
442
+ **IF indexed=false OR last_indexed_at is stale (>7 days):**
443
+ \u2192 Use local tools (Glob/Grep/Read) directly
444
+ \u2192 OR run \`project(action="index")\` first, then search
445
+
446
+ **IF search returns 0 results or errors:**
447
+ \u2192 Fallback to local tools (Glob/Grep/Read)
448
+
449
+ ### \u2705 When Local Tools (Glob/Grep/Read) Are OK:
450
+ - Project is NOT indexed
451
+ - Index is stale/outdated (>7 days)
452
+ - ContextStream search returns 0 results
453
+ - ContextStream returns errors
454
+ - User explicitly requests local tools
455
+
456
+ ### On Session Start:
457
+ 1. Call \`init(folder_path="...")\` - triggers initial indexing
458
+ 2. Check \`project(action="index_status")\` before searching
459
+ 3. If not indexed: use local tools OR wait for indexing
460
+
461
+ ### After File Changes (Edit/Write/Create):
462
+ Files are NOT auto-indexed. You MUST:
463
+ 1. After significant edits: \`project(action="index")\`
464
+ 2. For single file: \`project(action="ingest_local", path="<file>")\`
465
+ 3. Then search will find your changes`);
466
+ return parts.join("\n");
467
+ }
265
468
  function detectEditorFormat2(input) {
266
469
  if (input.hookName !== void 0) {
267
470
  return "cline";
@@ -269,8 +472,23 @@ function detectEditorFormat2(input) {
269
472
  if (input.hook_event_name === "beforeSubmitPrompt") {
270
473
  return "cursor";
271
474
  }
475
+ if (input.hook_event_name === "beforeAgentAction" || input.hook_event_name === "onPromptSubmit") {
476
+ return "antigravity";
477
+ }
272
478
  return "claude";
273
479
  }
480
+ function isNewSession(input, editorFormat) {
481
+ if (editorFormat === "claude" && input.session?.messages) {
482
+ return input.session.messages.length <= 1;
483
+ }
484
+ if (editorFormat === "cursor" && input.history !== void 0) {
485
+ return input.history.length === 0;
486
+ }
487
+ if (editorFormat === "antigravity" && input.history !== void 0) {
488
+ return input.history.length === 0;
489
+ }
490
+ return false;
491
+ }
274
492
  async function runUserPromptSubmitHook() {
275
493
  if (!ENABLED2) {
276
494
  process.exit(0);
@@ -289,6 +507,7 @@ async function runUserPromptSubmitHook() {
289
507
  process.exit(0);
290
508
  }
291
509
  const editorFormat = detectEditorFormat2(input);
510
+ const cwd = input.cwd || process.cwd();
292
511
  if (editorFormat === "claude") {
293
512
  console.log(
294
513
  JSON.stringify({
@@ -299,37 +518,84 @@ async function runUserPromptSubmitHook() {
299
518
  })
300
519
  );
301
520
  } else if (editorFormat === "cline") {
521
+ loadConfigFromMcpJson(cwd);
522
+ const newSession = isNewSession(input, editorFormat);
523
+ const ctx = await fetchSessionContext();
524
+ const enhancedReminder = buildEnhancedReminder(ctx, newSession);
302
525
  console.log(
303
526
  JSON.stringify({
304
527
  cancel: false,
305
- contextModification: REMINDER
528
+ contextModification: enhancedReminder
306
529
  })
307
530
  );
308
531
  } else if (editorFormat === "cursor") {
532
+ loadConfigFromMcpJson(cwd);
533
+ const newSession = isNewSession(input, editorFormat);
534
+ const ctx = await fetchSessionContext();
535
+ const cursorReminder = ctx?.lessons?.length ? `[CONTEXTSTREAM] \u26A0\uFE0F ${ctx.lessons.length} lessons from past mistakes. Use search(mode="hybrid") before Glob/Grep. Call context() first. After file edits: project(action="index") to re-index.` : `[CONTEXTSTREAM] Use search(mode="hybrid") before Glob/Grep/Read. Call context() first. After file edits: project(action="index") to re-index.`;
309
536
  console.log(
310
537
  JSON.stringify({
311
538
  continue: true,
312
- user_message: "[CONTEXTSTREAM] Search with mcp__contextstream__search before using Glob/Grep/Read"
539
+ user_message: cursorReminder
540
+ })
541
+ );
542
+ } else if (editorFormat === "antigravity") {
543
+ loadConfigFromMcpJson(cwd);
544
+ const newSession = isNewSession(input, editorFormat);
545
+ const ctx = await fetchSessionContext();
546
+ const enhancedReminder = buildEnhancedReminder(ctx, newSession);
547
+ console.log(
548
+ JSON.stringify({
549
+ cancel: false,
550
+ contextModification: enhancedReminder
313
551
  })
314
552
  );
315
553
  }
316
554
  process.exit(0);
317
555
  }
318
- var ENABLED2, REMINDER, isDirectRun2;
556
+ var ENABLED2, API_URL, API_KEY, WORKSPACE_ID, PROJECT_ID, REMINDER, ENHANCED_REMINDER_HEADER, isDirectRun2;
319
557
  var init_user_prompt_submit = __esm({
320
558
  "src/hooks/user-prompt-submit.ts"() {
321
559
  "use strict";
322
560
  ENABLED2 = process.env.CONTEXTSTREAM_REMINDER_ENABLED !== "false";
323
- REMINDER = `[CONTEXTSTREAM - DO THIS FIRST]
324
- mcp__contextstream__context(user_message="<user's message>") - CALL THIS BEFORE ANY OTHER TOOL
325
-
326
- Why: Delivers task-specific rules, lessons from past mistakes, and relevant context.
327
- Skip it = repeat past mistakes, miss relevant decisions, fly blind.
328
-
329
- BEFORE Glob/Grep/Read/Search/Explore:
330
- mcp__contextstream__search(mode="hybrid", query="...") FIRST
331
- Local tools ONLY if search returns 0 results.
561
+ API_URL = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
562
+ API_KEY = process.env.CONTEXTSTREAM_API_KEY || "";
563
+ WORKSPACE_ID = null;
564
+ PROJECT_ID = null;
565
+ REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
566
+
567
+ 1. FIRST: Call mcp__contextstream__context(user_message="...") before ANY other tool
568
+ - Returns: dynamic rules, lessons from past mistakes, relevant context
569
+ - Check response for: [LESSONS_WARNING], [RULES_NOTICE], preferences
570
+
571
+ 2. FOR CODE SEARCH: Check index status, then search appropriately
572
+ \u26A0\uFE0F BEFORE searching: mcp__contextstream__project(action="index_status")
573
+ \u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="hybrid", query="...")
574
+ \u2705 IF NOT indexed OR stale: Use local tools (Glob/Grep/Read) directly
575
+ \u2705 IF search returns 0 results: Fallback to local tools (Glob/Grep/Read)
576
+
577
+ 3. WHEN LOCAL TOOLS (Glob/Grep/Read) ARE OK:
578
+ \u2705 Project is NOT indexed (index_status.indexed=false)
579
+ \u2705 Index is stale/outdated (>7 days old)
580
+ \u2705 ContextStream search returns 0 results or errors
581
+ \u2705 User explicitly requests local tools
582
+
583
+ 4. FOR PLANS & TASKS: Use ContextStream, not file-based plans
584
+ \u2705 Plans: mcp__contextstream__session(action="capture_plan", ...)
585
+ \u2705 Tasks: mcp__contextstream__memory(action="create_task", ...)
586
+ \u274C DO NOT use EnterPlanMode or write plans to markdown files
587
+
588
+ 5. CHECK THESE from context() response:
589
+ - Lessons: Past mistakes to avoid (shown as warnings)
590
+ - Reminders: Active reminders for this project
591
+ - Preferences: User's coding style and preferences
592
+ - Rules: Dynamic rules matched to current task
593
+
594
+ 6. SKIP CONTEXTSTREAM: If user preference says "skip contextstream", use local tools instead
332
595
  [END]`;
596
+ ENHANCED_REMINDER_HEADER = `[CONTEXTSTREAM - ENHANCED CONTEXT]
597
+
598
+ `;
333
599
  isDirectRun2 = process.argv[1]?.includes("user-prompt-submit") || process.argv[2] === "user-prompt-submit";
334
600
  if (isDirectRun2) {
335
601
  runUserPromptSubmitHook().catch(() => process.exit(0));
@@ -451,58 +717,58 @@ var pre_compact_exports = {};
451
717
  __export(pre_compact_exports, {
452
718
  runPreCompactHook: () => runPreCompactHook
453
719
  });
454
- import * as fs2 from "node:fs";
455
- import * as path2 from "node:path";
456
- import { homedir as homedir2 } from "node:os";
457
- function loadConfigFromMcpJson(cwd) {
458
- let searchDir = path2.resolve(cwd);
720
+ import * as fs3 from "node:fs";
721
+ import * as path3 from "node:path";
722
+ import { homedir as homedir3 } from "node:os";
723
+ function loadConfigFromMcpJson2(cwd) {
724
+ let searchDir = path3.resolve(cwd);
459
725
  for (let i = 0; i < 5; i++) {
460
- if (!API_KEY) {
461
- const mcpPath = path2.join(searchDir, ".mcp.json");
462
- if (fs2.existsSync(mcpPath)) {
726
+ if (!API_KEY2) {
727
+ const mcpPath = path3.join(searchDir, ".mcp.json");
728
+ if (fs3.existsSync(mcpPath)) {
463
729
  try {
464
- const content = fs2.readFileSync(mcpPath, "utf-8");
730
+ const content = fs3.readFileSync(mcpPath, "utf-8");
465
731
  const config = JSON.parse(content);
466
732
  const csEnv = config.mcpServers?.contextstream?.env;
467
733
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
468
- API_KEY = csEnv.CONTEXTSTREAM_API_KEY;
734
+ API_KEY2 = csEnv.CONTEXTSTREAM_API_KEY;
469
735
  }
470
736
  if (csEnv?.CONTEXTSTREAM_API_URL) {
471
- API_URL = csEnv.CONTEXTSTREAM_API_URL;
737
+ API_URL2 = csEnv.CONTEXTSTREAM_API_URL;
472
738
  }
473
739
  } catch {
474
740
  }
475
741
  }
476
742
  }
477
- if (!WORKSPACE_ID) {
478
- const csConfigPath = path2.join(searchDir, ".contextstream", "config.json");
479
- if (fs2.existsSync(csConfigPath)) {
743
+ if (!WORKSPACE_ID2) {
744
+ const csConfigPath = path3.join(searchDir, ".contextstream", "config.json");
745
+ if (fs3.existsSync(csConfigPath)) {
480
746
  try {
481
- const content = fs2.readFileSync(csConfigPath, "utf-8");
747
+ const content = fs3.readFileSync(csConfigPath, "utf-8");
482
748
  const csConfig = JSON.parse(content);
483
749
  if (csConfig.workspace_id) {
484
- WORKSPACE_ID = csConfig.workspace_id;
750
+ WORKSPACE_ID2 = csConfig.workspace_id;
485
751
  }
486
752
  } catch {
487
753
  }
488
754
  }
489
755
  }
490
- const parentDir = path2.dirname(searchDir);
756
+ const parentDir = path3.dirname(searchDir);
491
757
  if (parentDir === searchDir) break;
492
758
  searchDir = parentDir;
493
759
  }
494
- if (!API_KEY) {
495
- const homeMcpPath = path2.join(homedir2(), ".mcp.json");
496
- if (fs2.existsSync(homeMcpPath)) {
760
+ if (!API_KEY2) {
761
+ const homeMcpPath = path3.join(homedir3(), ".mcp.json");
762
+ if (fs3.existsSync(homeMcpPath)) {
497
763
  try {
498
- const content = fs2.readFileSync(homeMcpPath, "utf-8");
764
+ const content = fs3.readFileSync(homeMcpPath, "utf-8");
499
765
  const config = JSON.parse(content);
500
766
  const csEnv = config.mcpServers?.contextstream?.env;
501
767
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
502
- API_KEY = csEnv.CONTEXTSTREAM_API_KEY;
768
+ API_KEY2 = csEnv.CONTEXTSTREAM_API_KEY;
503
769
  }
504
770
  if (csEnv?.CONTEXTSTREAM_API_URL) {
505
- API_URL = csEnv.CONTEXTSTREAM_API_URL;
771
+ API_URL2 = csEnv.CONTEXTSTREAM_API_URL;
506
772
  }
507
773
  } catch {
508
774
  }
@@ -517,7 +783,7 @@ function parseTranscript(transcriptPath) {
517
783
  let startedAt = (/* @__PURE__ */ new Date()).toISOString();
518
784
  let firstTimestamp = true;
519
785
  try {
520
- const content = fs2.readFileSync(transcriptPath, "utf-8");
786
+ const content = fs3.readFileSync(transcriptPath, "utf-8");
521
787
  const lines = content.split("\n");
522
788
  for (const line of lines) {
523
789
  if (!line.trim()) continue;
@@ -598,7 +864,7 @@ function parseTranscript(transcriptPath) {
598
864
  };
599
865
  }
600
866
  async function saveFullTranscript(sessionId, transcriptData, trigger) {
601
- if (!API_KEY) {
867
+ if (!API_KEY2) {
602
868
  return { success: false, message: "No API key configured" };
603
869
  }
604
870
  if (transcriptData.messages.length === 0) {
@@ -617,17 +883,17 @@ async function saveFullTranscript(sessionId, transcriptData, trigger) {
617
883
  },
618
884
  tags: ["pre_compaction", trigger]
619
885
  };
620
- if (WORKSPACE_ID) {
621
- payload.workspace_id = WORKSPACE_ID;
886
+ if (WORKSPACE_ID2) {
887
+ payload.workspace_id = WORKSPACE_ID2;
622
888
  }
623
889
  try {
624
890
  const controller = new AbortController();
625
891
  const timeoutId = setTimeout(() => controller.abort(), 1e4);
626
- const response = await fetch(`${API_URL}/api/v1/transcripts`, {
892
+ const response = await fetch(`${API_URL2}/api/v1/transcripts`, {
627
893
  method: "POST",
628
894
  headers: {
629
895
  "Content-Type": "application/json",
630
- "X-API-Key": API_KEY
896
+ "X-API-Key": API_KEY2
631
897
  },
632
898
  body: JSON.stringify(payload),
633
899
  signal: controller.signal
@@ -642,7 +908,7 @@ async function saveFullTranscript(sessionId, transcriptData, trigger) {
642
908
  }
643
909
  }
644
910
  async function saveSnapshot(sessionId, transcriptData, trigger) {
645
- if (!API_KEY) {
911
+ if (!API_KEY2) {
646
912
  return { success: false, message: "No API key configured" };
647
913
  }
648
914
  const snapshotContent = {
@@ -663,17 +929,17 @@ async function saveSnapshot(sessionId, transcriptData, trigger) {
663
929
  tags: ["session_snapshot", "pre_compaction", "auto_captured"],
664
930
  source_type: "hook"
665
931
  };
666
- if (WORKSPACE_ID) {
667
- payload.workspace_id = WORKSPACE_ID;
932
+ if (WORKSPACE_ID2) {
933
+ payload.workspace_id = WORKSPACE_ID2;
668
934
  }
669
935
  try {
670
936
  const controller = new AbortController();
671
937
  const timeoutId = setTimeout(() => controller.abort(), 5e3);
672
- const response = await fetch(`${API_URL}/api/v1/memory/events`, {
938
+ const response = await fetch(`${API_URL2}/api/v1/memory/events`, {
673
939
  method: "POST",
674
940
  headers: {
675
941
  "Content-Type": "application/json",
676
- "X-API-Key": API_KEY
942
+ "X-API-Key": API_KEY2
677
943
  },
678
944
  body: JSON.stringify(payload),
679
945
  signal: controller.signal
@@ -705,7 +971,7 @@ async function runPreCompactHook() {
705
971
  process.exit(0);
706
972
  }
707
973
  const cwd = input.cwd || process.cwd();
708
- loadConfigFromMcpJson(cwd);
974
+ loadConfigFromMcpJson2(cwd);
709
975
  const sessionId = input.session_id || "unknown";
710
976
  const transcriptPath = input.transcript_path || "";
711
977
  const trigger = input.trigger || "unknown";
@@ -714,13 +980,15 @@ async function runPreCompactHook() {
714
980
  activeFiles: [],
715
981
  toolCallCount: 0,
716
982
  messageCount: 0,
717
- lastTools: []
983
+ lastTools: [],
984
+ messages: [],
985
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
718
986
  };
719
- if (transcriptPath && fs2.existsSync(transcriptPath)) {
987
+ if (transcriptPath && fs3.existsSync(transcriptPath)) {
720
988
  transcriptData = parseTranscript(transcriptPath);
721
989
  }
722
990
  let autoSaveStatus = "";
723
- if (AUTO_SAVE && API_KEY) {
991
+ if (AUTO_SAVE && API_KEY2) {
724
992
  const transcriptResult = await saveFullTranscript(sessionId, transcriptData, trigger);
725
993
  if (transcriptResult.success) {
726
994
  autoSaveStatus = `
@@ -754,15 +1022,15 @@ User instructions: ${customInstructions}` : ""}`;
754
1022
  );
755
1023
  process.exit(0);
756
1024
  }
757
- var ENABLED4, AUTO_SAVE, API_URL, API_KEY, WORKSPACE_ID, isDirectRun4;
1025
+ var ENABLED4, AUTO_SAVE, API_URL2, API_KEY2, WORKSPACE_ID2, isDirectRun4;
758
1026
  var init_pre_compact = __esm({
759
1027
  "src/hooks/pre-compact.ts"() {
760
1028
  "use strict";
761
1029
  ENABLED4 = process.env.CONTEXTSTREAM_PRECOMPACT_ENABLED !== "false";
762
1030
  AUTO_SAVE = process.env.CONTEXTSTREAM_PRECOMPACT_AUTO_SAVE !== "false";
763
- API_URL = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
764
- API_KEY = process.env.CONTEXTSTREAM_API_KEY || "";
765
- WORKSPACE_ID = null;
1031
+ API_URL2 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
1032
+ API_KEY2 = process.env.CONTEXTSTREAM_API_KEY || "";
1033
+ WORKSPACE_ID2 = null;
766
1034
  isDirectRun4 = process.argv[1]?.includes("pre-compact") || process.argv[2] === "pre-compact";
767
1035
  if (isDirectRun4) {
768
1036
  runPreCompactHook().catch(() => process.exit(0));
@@ -775,9 +1043,9 @@ var post_write_exports = {};
775
1043
  __export(post_write_exports, {
776
1044
  runPostWriteHook: () => runPostWriteHook
777
1045
  });
778
- import * as fs3 from "node:fs";
779
- import * as path3 from "node:path";
780
- import { homedir as homedir3 } from "node:os";
1046
+ import * as fs4 from "node:fs";
1047
+ import * as path4 from "node:path";
1048
+ import { homedir as homedir4 } from "node:os";
781
1049
  function extractFilePath(input) {
782
1050
  if (input.tool_input) {
783
1051
  const filePath = input.tool_input.file_path || input.tool_input.notebook_path || input.tool_input.path;
@@ -802,34 +1070,34 @@ function extractCwd2(input) {
802
1070
  return process.cwd();
803
1071
  }
804
1072
  function findLocalConfig(startDir) {
805
- let currentDir = path3.resolve(startDir);
1073
+ let currentDir = path4.resolve(startDir);
806
1074
  for (let i = 0; i < 10; i++) {
807
- const configPath = path3.join(currentDir, ".contextstream", "config.json");
808
- if (fs3.existsSync(configPath)) {
1075
+ const configPath = path4.join(currentDir, ".contextstream", "config.json");
1076
+ if (fs4.existsSync(configPath)) {
809
1077
  try {
810
- const content = fs3.readFileSync(configPath, "utf-8");
1078
+ const content = fs4.readFileSync(configPath, "utf-8");
811
1079
  return JSON.parse(content);
812
1080
  } catch {
813
1081
  }
814
1082
  }
815
- const parentDir = path3.dirname(currentDir);
1083
+ const parentDir = path4.dirname(currentDir);
816
1084
  if (parentDir === currentDir) break;
817
1085
  currentDir = parentDir;
818
1086
  }
819
1087
  return null;
820
1088
  }
821
1089
  function loadApiConfig(startDir) {
822
- let apiUrl = API_URL2;
823
- let apiKey = API_KEY2;
1090
+ let apiUrl = API_URL3;
1091
+ let apiKey = API_KEY3;
824
1092
  if (apiKey) {
825
1093
  return { apiUrl, apiKey };
826
1094
  }
827
- let currentDir = path3.resolve(startDir);
1095
+ let currentDir = path4.resolve(startDir);
828
1096
  for (let i = 0; i < 10; i++) {
829
- const mcpPath = path3.join(currentDir, ".mcp.json");
830
- if (fs3.existsSync(mcpPath)) {
1097
+ const mcpPath = path4.join(currentDir, ".mcp.json");
1098
+ if (fs4.existsSync(mcpPath)) {
831
1099
  try {
832
- const content = fs3.readFileSync(mcpPath, "utf-8");
1100
+ const content = fs4.readFileSync(mcpPath, "utf-8");
833
1101
  const config = JSON.parse(content);
834
1102
  const csEnv = config.mcpServers?.contextstream?.env;
835
1103
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -842,15 +1110,15 @@ function loadApiConfig(startDir) {
842
1110
  } catch {
843
1111
  }
844
1112
  }
845
- const parentDir = path3.dirname(currentDir);
1113
+ const parentDir = path4.dirname(currentDir);
846
1114
  if (parentDir === currentDir) break;
847
1115
  currentDir = parentDir;
848
1116
  }
849
1117
  if (!apiKey) {
850
- const homeMcpPath = path3.join(homedir3(), ".mcp.json");
851
- if (fs3.existsSync(homeMcpPath)) {
1118
+ const homeMcpPath = path4.join(homedir4(), ".mcp.json");
1119
+ if (fs4.existsSync(homeMcpPath)) {
852
1120
  try {
853
- const content = fs3.readFileSync(homeMcpPath, "utf-8");
1121
+ const content = fs4.readFileSync(homeMcpPath, "utf-8");
854
1122
  const config = JSON.parse(content);
855
1123
  const csEnv = config.mcpServers?.contextstream?.env;
856
1124
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -866,15 +1134,15 @@ function loadApiConfig(startDir) {
866
1134
  return { apiUrl, apiKey };
867
1135
  }
868
1136
  function shouldIndexFile(filePath) {
869
- const ext = path3.extname(filePath).toLowerCase();
1137
+ const ext = path4.extname(filePath).toLowerCase();
870
1138
  if (!INDEXABLE_EXTENSIONS.has(ext)) {
871
- const basename2 = path3.basename(filePath).toLowerCase();
1139
+ const basename2 = path4.basename(filePath).toLowerCase();
872
1140
  if (!["dockerfile", "makefile", "rakefile", "gemfile", "procfile"].includes(basename2)) {
873
1141
  return false;
874
1142
  }
875
1143
  }
876
1144
  try {
877
- const stats = fs3.statSync(filePath);
1145
+ const stats = fs4.statSync(filePath);
878
1146
  if (stats.size > MAX_FILE_SIZE) {
879
1147
  return false;
880
1148
  }
@@ -884,7 +1152,7 @@ function shouldIndexFile(filePath) {
884
1152
  return true;
885
1153
  }
886
1154
  function detectLanguage(filePath) {
887
- const ext = path3.extname(filePath).toLowerCase();
1155
+ const ext = path4.extname(filePath).toLowerCase();
888
1156
  const langMap = {
889
1157
  ".ts": "typescript",
890
1158
  ".tsx": "typescript",
@@ -953,8 +1221,8 @@ function detectLanguage(filePath) {
953
1221
  return langMap[ext] || "text";
954
1222
  }
955
1223
  async function indexFile(filePath, projectId, apiUrl, apiKey, projectRoot) {
956
- const content = fs3.readFileSync(filePath, "utf-8");
957
- const relativePath = path3.relative(projectRoot, filePath);
1224
+ const content = fs4.readFileSync(filePath, "utf-8");
1225
+ const relativePath = path4.relative(projectRoot, filePath);
958
1226
  const payload = {
959
1227
  files: [
960
1228
  {
@@ -979,13 +1247,13 @@ async function indexFile(filePath, projectId, apiUrl, apiKey, projectRoot) {
979
1247
  }
980
1248
  }
981
1249
  function findProjectRoot(filePath) {
982
- let currentDir = path3.dirname(path3.resolve(filePath));
1250
+ let currentDir = path4.dirname(path4.resolve(filePath));
983
1251
  for (let i = 0; i < 10; i++) {
984
- const configPath = path3.join(currentDir, ".contextstream", "config.json");
985
- if (fs3.existsSync(configPath)) {
1252
+ const configPath = path4.join(currentDir, ".contextstream", "config.json");
1253
+ if (fs4.existsSync(configPath)) {
986
1254
  return currentDir;
987
1255
  }
988
- const parentDir = path3.dirname(currentDir);
1256
+ const parentDir = path4.dirname(currentDir);
989
1257
  if (parentDir === currentDir) break;
990
1258
  currentDir = parentDir;
991
1259
  }
@@ -1013,8 +1281,8 @@ async function runPostWriteHook() {
1013
1281
  process.exit(0);
1014
1282
  }
1015
1283
  const cwd = extractCwd2(input);
1016
- const absolutePath = path3.isAbsolute(filePath) ? filePath : path3.resolve(cwd, filePath);
1017
- if (!fs3.existsSync(absolutePath) || !shouldIndexFile(absolutePath)) {
1284
+ const absolutePath = path4.isAbsolute(filePath) ? filePath : path4.resolve(cwd, filePath);
1285
+ if (!fs4.existsSync(absolutePath) || !shouldIndexFile(absolutePath)) {
1018
1286
  process.exit(0);
1019
1287
  }
1020
1288
  const projectRoot = findProjectRoot(absolutePath);
@@ -1035,12 +1303,12 @@ async function runPostWriteHook() {
1035
1303
  }
1036
1304
  process.exit(0);
1037
1305
  }
1038
- var API_URL2, API_KEY2, ENABLED5, INDEXABLE_EXTENSIONS, MAX_FILE_SIZE, isDirectRun5;
1306
+ var API_URL3, API_KEY3, ENABLED5, INDEXABLE_EXTENSIONS, MAX_FILE_SIZE, isDirectRun5;
1039
1307
  var init_post_write = __esm({
1040
1308
  "src/hooks/post-write.ts"() {
1041
1309
  "use strict";
1042
- API_URL2 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
1043
- API_KEY2 = process.env.CONTEXTSTREAM_API_KEY || "";
1310
+ API_URL3 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
1311
+ API_KEY3 = process.env.CONTEXTSTREAM_API_KEY || "";
1044
1312
  ENABLED5 = process.env.CONTEXTSTREAM_POSTWRITE_ENABLED !== "false";
1045
1313
  INDEXABLE_EXTENSIONS = /* @__PURE__ */ new Set([
1046
1314
  ".ts",
@@ -1159,16 +1427,20 @@ __export(hooks_config_exports, {
1159
1427
  writeCursorHooksConfig: () => writeCursorHooksConfig,
1160
1428
  writeIndexStatus: () => writeIndexStatus
1161
1429
  });
1162
- import * as fs4 from "node:fs/promises";
1163
- import * as path4 from "node:path";
1164
- import { homedir as homedir4 } from "node:os";
1430
+ import * as fs5 from "node:fs/promises";
1431
+ import * as path5 from "node:path";
1432
+ import { homedir as homedir5 } from "node:os";
1165
1433
  import { fileURLToPath } from "node:url";
1166
1434
  function getHookCommand(hookName2) {
1435
+ const fs7 = __require("node:fs");
1436
+ const binaryPath = "/usr/local/bin/contextstream-mcp";
1437
+ if (fs7.existsSync(binaryPath)) {
1438
+ return `${binaryPath} hook ${hookName2}`;
1439
+ }
1167
1440
  try {
1168
- const __dirname = path4.dirname(fileURLToPath(import.meta.url));
1169
- const indexPath = path4.join(__dirname, "index.js");
1170
- const fs6 = __require("node:fs");
1171
- if (fs6.existsSync(indexPath)) {
1441
+ const __dirname = path5.dirname(fileURLToPath(import.meta.url));
1442
+ const indexPath = path5.join(__dirname, "index.js");
1443
+ if (fs7.existsSync(indexPath)) {
1172
1444
  return `node ${indexPath} hook ${hookName2}`;
1173
1445
  }
1174
1446
  } catch {
@@ -1177,15 +1449,15 @@ function getHookCommand(hookName2) {
1177
1449
  }
1178
1450
  function getClaudeSettingsPath(scope, projectPath) {
1179
1451
  if (scope === "user") {
1180
- return path4.join(homedir4(), ".claude", "settings.json");
1452
+ return path5.join(homedir5(), ".claude", "settings.json");
1181
1453
  }
1182
1454
  if (!projectPath) {
1183
1455
  throw new Error("projectPath required for project scope");
1184
1456
  }
1185
- return path4.join(projectPath, ".claude", "settings.json");
1457
+ return path5.join(projectPath, ".claude", "settings.json");
1186
1458
  }
1187
1459
  function getHooksDir() {
1188
- return path4.join(homedir4(), ".claude", "hooks");
1460
+ return path5.join(homedir5(), ".claude", "hooks");
1189
1461
  }
1190
1462
  function buildHooksConfig(options) {
1191
1463
  const userPromptHooks = [
@@ -1361,7 +1633,7 @@ function buildHooksConfig(options) {
1361
1633
  }
1362
1634
  async function installHookScripts(options) {
1363
1635
  const hooksDir = getHooksDir();
1364
- await fs4.mkdir(hooksDir, { recursive: true });
1636
+ await fs5.mkdir(hooksDir, { recursive: true });
1365
1637
  const result = {
1366
1638
  preToolUse: getHookCommand("pre-tool-use"),
1367
1639
  userPrompt: getHookCommand("user-prompt-submit")
@@ -1380,7 +1652,7 @@ async function installHookScripts(options) {
1380
1652
  async function readClaudeSettings(scope, projectPath) {
1381
1653
  const settingsPath = getClaudeSettingsPath(scope, projectPath);
1382
1654
  try {
1383
- const content = await fs4.readFile(settingsPath, "utf-8");
1655
+ const content = await fs5.readFile(settingsPath, "utf-8");
1384
1656
  return JSON.parse(content);
1385
1657
  } catch {
1386
1658
  return {};
@@ -1388,9 +1660,9 @@ async function readClaudeSettings(scope, projectPath) {
1388
1660
  }
1389
1661
  async function writeClaudeSettings(settings, scope, projectPath) {
1390
1662
  const settingsPath = getClaudeSettingsPath(scope, projectPath);
1391
- const dir = path4.dirname(settingsPath);
1392
- await fs4.mkdir(dir, { recursive: true });
1393
- await fs4.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1663
+ const dir = path5.dirname(settingsPath);
1664
+ await fs5.mkdir(dir, { recursive: true });
1665
+ await fs5.writeFile(settingsPath, JSON.stringify(settings, null, 2));
1394
1666
  }
1395
1667
  function mergeHooksIntoSettings(existingSettings, newHooks) {
1396
1668
  const settings = { ...existingSettings };
@@ -1540,12 +1812,12 @@ If you prefer to configure manually, add to \`~/.claude/settings.json\`:
1540
1812
  `.trim();
1541
1813
  }
1542
1814
  function getIndexStatusPath() {
1543
- return path4.join(homedir4(), ".contextstream", "indexed-projects.json");
1815
+ return path5.join(homedir5(), ".contextstream", "indexed-projects.json");
1544
1816
  }
1545
1817
  async function readIndexStatus() {
1546
1818
  const statusPath = getIndexStatusPath();
1547
1819
  try {
1548
- const content = await fs4.readFile(statusPath, "utf-8");
1820
+ const content = await fs5.readFile(statusPath, "utf-8");
1549
1821
  return JSON.parse(content);
1550
1822
  } catch {
1551
1823
  return { version: 1, projects: {} };
@@ -1553,13 +1825,13 @@ async function readIndexStatus() {
1553
1825
  }
1554
1826
  async function writeIndexStatus(status) {
1555
1827
  const statusPath = getIndexStatusPath();
1556
- const dir = path4.dirname(statusPath);
1557
- await fs4.mkdir(dir, { recursive: true });
1558
- await fs4.writeFile(statusPath, JSON.stringify(status, null, 2));
1828
+ const dir = path5.dirname(statusPath);
1829
+ await fs5.mkdir(dir, { recursive: true });
1830
+ await fs5.writeFile(statusPath, JSON.stringify(status, null, 2));
1559
1831
  }
1560
1832
  async function markProjectIndexed(projectPath, options) {
1561
1833
  const status = await readIndexStatus();
1562
- const resolvedPath = path4.resolve(projectPath);
1834
+ const resolvedPath = path5.resolve(projectPath);
1563
1835
  status.projects[resolvedPath] = {
1564
1836
  indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
1565
1837
  project_id: options?.project_id,
@@ -1569,113 +1841,113 @@ async function markProjectIndexed(projectPath, options) {
1569
1841
  }
1570
1842
  async function unmarkProjectIndexed(projectPath) {
1571
1843
  const status = await readIndexStatus();
1572
- const resolvedPath = path4.resolve(projectPath);
1844
+ const resolvedPath = path5.resolve(projectPath);
1573
1845
  delete status.projects[resolvedPath];
1574
1846
  await writeIndexStatus(status);
1575
1847
  }
1576
1848
  function getClineHooksDir(scope, projectPath) {
1577
1849
  if (scope === "global") {
1578
- return path4.join(homedir4(), "Documents", "Cline", "Rules", "Hooks");
1850
+ return path5.join(homedir5(), "Documents", "Cline", "Rules", "Hooks");
1579
1851
  }
1580
1852
  if (!projectPath) {
1581
1853
  throw new Error("projectPath required for project scope");
1582
1854
  }
1583
- return path4.join(projectPath, ".clinerules", "hooks");
1855
+ return path5.join(projectPath, ".clinerules", "hooks");
1584
1856
  }
1585
1857
  async function installClineHookScripts(options) {
1586
1858
  const hooksDir = getClineHooksDir(options.scope, options.projectPath);
1587
- await fs4.mkdir(hooksDir, { recursive: true });
1588
- const preToolUsePath = path4.join(hooksDir, "PreToolUse");
1589
- const userPromptPath = path4.join(hooksDir, "UserPromptSubmit");
1590
- const postToolUsePath = path4.join(hooksDir, "PostToolUse");
1591
- await fs4.writeFile(preToolUsePath, CLINE_HOOK_WRAPPER("pre-tool-use"), { mode: 493 });
1592
- await fs4.writeFile(userPromptPath, CLINE_HOOK_WRAPPER("user-prompt-submit"), { mode: 493 });
1859
+ await fs5.mkdir(hooksDir, { recursive: true });
1860
+ const preToolUsePath = path5.join(hooksDir, "PreToolUse");
1861
+ const userPromptPath = path5.join(hooksDir, "UserPromptSubmit");
1862
+ const postToolUsePath = path5.join(hooksDir, "PostToolUse");
1863
+ await fs5.writeFile(preToolUsePath, CLINE_HOOK_WRAPPER("pre-tool-use"), { mode: 493 });
1864
+ await fs5.writeFile(userPromptPath, CLINE_HOOK_WRAPPER("user-prompt-submit"), { mode: 493 });
1593
1865
  const result = {
1594
1866
  preToolUse: preToolUsePath,
1595
1867
  userPromptSubmit: userPromptPath
1596
1868
  };
1597
1869
  if (options.includePostWrite !== false) {
1598
- await fs4.writeFile(postToolUsePath, CLINE_HOOK_WRAPPER("post-write"), { mode: 493 });
1870
+ await fs5.writeFile(postToolUsePath, CLINE_HOOK_WRAPPER("post-write"), { mode: 493 });
1599
1871
  result.postToolUse = postToolUsePath;
1600
1872
  }
1601
1873
  return result;
1602
1874
  }
1603
1875
  function getRooCodeHooksDir(scope, projectPath) {
1604
1876
  if (scope === "global") {
1605
- return path4.join(homedir4(), ".roo", "hooks");
1877
+ return path5.join(homedir5(), ".roo", "hooks");
1606
1878
  }
1607
1879
  if (!projectPath) {
1608
1880
  throw new Error("projectPath required for project scope");
1609
1881
  }
1610
- return path4.join(projectPath, ".roo", "hooks");
1882
+ return path5.join(projectPath, ".roo", "hooks");
1611
1883
  }
1612
1884
  async function installRooCodeHookScripts(options) {
1613
1885
  const hooksDir = getRooCodeHooksDir(options.scope, options.projectPath);
1614
- await fs4.mkdir(hooksDir, { recursive: true });
1615
- const preToolUsePath = path4.join(hooksDir, "PreToolUse");
1616
- const userPromptPath = path4.join(hooksDir, "UserPromptSubmit");
1617
- const postToolUsePath = path4.join(hooksDir, "PostToolUse");
1618
- await fs4.writeFile(preToolUsePath, CLINE_HOOK_WRAPPER("pre-tool-use"), { mode: 493 });
1619
- await fs4.writeFile(userPromptPath, CLINE_HOOK_WRAPPER("user-prompt-submit"), { mode: 493 });
1886
+ await fs5.mkdir(hooksDir, { recursive: true });
1887
+ const preToolUsePath = path5.join(hooksDir, "PreToolUse");
1888
+ const userPromptPath = path5.join(hooksDir, "UserPromptSubmit");
1889
+ const postToolUsePath = path5.join(hooksDir, "PostToolUse");
1890
+ await fs5.writeFile(preToolUsePath, CLINE_HOOK_WRAPPER("pre-tool-use"), { mode: 493 });
1891
+ await fs5.writeFile(userPromptPath, CLINE_HOOK_WRAPPER("user-prompt-submit"), { mode: 493 });
1620
1892
  const result = {
1621
1893
  preToolUse: preToolUsePath,
1622
1894
  userPromptSubmit: userPromptPath
1623
1895
  };
1624
1896
  if (options.includePostWrite !== false) {
1625
- await fs4.writeFile(postToolUsePath, CLINE_HOOK_WRAPPER("post-write"), { mode: 493 });
1897
+ await fs5.writeFile(postToolUsePath, CLINE_HOOK_WRAPPER("post-write"), { mode: 493 });
1626
1898
  result.postToolUse = postToolUsePath;
1627
1899
  }
1628
1900
  return result;
1629
1901
  }
1630
1902
  function getKiloCodeHooksDir(scope, projectPath) {
1631
1903
  if (scope === "global") {
1632
- return path4.join(homedir4(), ".kilocode", "hooks");
1904
+ return path5.join(homedir5(), ".kilocode", "hooks");
1633
1905
  }
1634
1906
  if (!projectPath) {
1635
1907
  throw new Error("projectPath required for project scope");
1636
1908
  }
1637
- return path4.join(projectPath, ".kilocode", "hooks");
1909
+ return path5.join(projectPath, ".kilocode", "hooks");
1638
1910
  }
1639
1911
  async function installKiloCodeHookScripts(options) {
1640
1912
  const hooksDir = getKiloCodeHooksDir(options.scope, options.projectPath);
1641
- await fs4.mkdir(hooksDir, { recursive: true });
1642
- const preToolUsePath = path4.join(hooksDir, "PreToolUse");
1643
- const userPromptPath = path4.join(hooksDir, "UserPromptSubmit");
1644
- const postToolUsePath = path4.join(hooksDir, "PostToolUse");
1645
- await fs4.writeFile(preToolUsePath, CLINE_HOOK_WRAPPER("pre-tool-use"), { mode: 493 });
1646
- await fs4.writeFile(userPromptPath, CLINE_HOOK_WRAPPER("user-prompt-submit"), { mode: 493 });
1913
+ await fs5.mkdir(hooksDir, { recursive: true });
1914
+ const preToolUsePath = path5.join(hooksDir, "PreToolUse");
1915
+ const userPromptPath = path5.join(hooksDir, "UserPromptSubmit");
1916
+ const postToolUsePath = path5.join(hooksDir, "PostToolUse");
1917
+ await fs5.writeFile(preToolUsePath, CLINE_HOOK_WRAPPER("pre-tool-use"), { mode: 493 });
1918
+ await fs5.writeFile(userPromptPath, CLINE_HOOK_WRAPPER("user-prompt-submit"), { mode: 493 });
1647
1919
  const result = {
1648
1920
  preToolUse: preToolUsePath,
1649
1921
  userPromptSubmit: userPromptPath
1650
1922
  };
1651
1923
  if (options.includePostWrite !== false) {
1652
- await fs4.writeFile(postToolUsePath, CLINE_HOOK_WRAPPER("post-write"), { mode: 493 });
1924
+ await fs5.writeFile(postToolUsePath, CLINE_HOOK_WRAPPER("post-write"), { mode: 493 });
1653
1925
  result.postToolUse = postToolUsePath;
1654
1926
  }
1655
1927
  return result;
1656
1928
  }
1657
1929
  function getCursorHooksConfigPath(scope, projectPath) {
1658
1930
  if (scope === "global") {
1659
- return path4.join(homedir4(), ".cursor", "hooks.json");
1931
+ return path5.join(homedir5(), ".cursor", "hooks.json");
1660
1932
  }
1661
1933
  if (!projectPath) {
1662
1934
  throw new Error("projectPath required for project scope");
1663
1935
  }
1664
- return path4.join(projectPath, ".cursor", "hooks.json");
1936
+ return path5.join(projectPath, ".cursor", "hooks.json");
1665
1937
  }
1666
1938
  function getCursorHooksDir(scope, projectPath) {
1667
1939
  if (scope === "global") {
1668
- return path4.join(homedir4(), ".cursor", "hooks");
1940
+ return path5.join(homedir5(), ".cursor", "hooks");
1669
1941
  }
1670
1942
  if (!projectPath) {
1671
1943
  throw new Error("projectPath required for project scope");
1672
1944
  }
1673
- return path4.join(projectPath, ".cursor", "hooks");
1945
+ return path5.join(projectPath, ".cursor", "hooks");
1674
1946
  }
1675
1947
  async function readCursorHooksConfig(scope, projectPath) {
1676
1948
  const configPath = getCursorHooksConfigPath(scope, projectPath);
1677
1949
  try {
1678
- const content = await fs4.readFile(configPath, "utf-8");
1950
+ const content = await fs5.readFile(configPath, "utf-8");
1679
1951
  return JSON.parse(content);
1680
1952
  } catch {
1681
1953
  return { version: 1, hooks: {} };
@@ -1683,13 +1955,13 @@ async function readCursorHooksConfig(scope, projectPath) {
1683
1955
  }
1684
1956
  async function writeCursorHooksConfig(config, scope, projectPath) {
1685
1957
  const configPath = getCursorHooksConfigPath(scope, projectPath);
1686
- const dir = path4.dirname(configPath);
1687
- await fs4.mkdir(dir, { recursive: true });
1688
- await fs4.writeFile(configPath, JSON.stringify(config, null, 2));
1958
+ const dir = path5.dirname(configPath);
1959
+ await fs5.mkdir(dir, { recursive: true });
1960
+ await fs5.writeFile(configPath, JSON.stringify(config, null, 2));
1689
1961
  }
1690
1962
  async function installCursorHookScripts(options) {
1691
1963
  const hooksDir = getCursorHooksDir(options.scope, options.projectPath);
1692
- await fs4.mkdir(hooksDir, { recursive: true });
1964
+ await fs5.mkdir(hooksDir, { recursive: true });
1693
1965
  const existingConfig = await readCursorHooksConfig(options.scope, options.projectPath);
1694
1966
  const filterContextStreamHooks = (hooks2) => {
1695
1967
  if (!hooks2) return [];
@@ -2712,13 +2984,13 @@ var auto_rules_exports = {};
2712
2984
  __export(auto_rules_exports, {
2713
2985
  runAutoRulesHook: () => runAutoRulesHook
2714
2986
  });
2715
- import * as fs5 from "node:fs";
2716
- import * as path5 from "node:path";
2717
- import { homedir as homedir5 } from "node:os";
2987
+ import * as fs6 from "node:fs";
2988
+ import * as path6 from "node:path";
2989
+ import { homedir as homedir6 } from "node:os";
2718
2990
  function hasRunRecently() {
2719
2991
  try {
2720
- if (!fs5.existsSync(MARKER_FILE)) return false;
2721
- const stat = fs5.statSync(MARKER_FILE);
2992
+ if (!fs6.existsSync(MARKER_FILE)) return false;
2993
+ const stat = fs6.statSync(MARKER_FILE);
2722
2994
  const age = Date.now() - stat.mtimeMs;
2723
2995
  return age < COOLDOWN_MS;
2724
2996
  } catch {
@@ -2727,11 +2999,11 @@ function hasRunRecently() {
2727
2999
  }
2728
3000
  function markAsRan() {
2729
3001
  try {
2730
- const dir = path5.dirname(MARKER_FILE);
2731
- if (!fs5.existsSync(dir)) {
2732
- fs5.mkdirSync(dir, { recursive: true });
3002
+ const dir = path6.dirname(MARKER_FILE);
3003
+ if (!fs6.existsSync(dir)) {
3004
+ fs6.mkdirSync(dir, { recursive: true });
2733
3005
  }
2734
- fs5.writeFileSync(MARKER_FILE, (/* @__PURE__ */ new Date()).toISOString());
3006
+ fs6.writeFileSync(MARKER_FILE, (/* @__PURE__ */ new Date()).toISOString());
2735
3007
  } catch {
2736
3008
  }
2737
3009
  }
@@ -2760,8 +3032,8 @@ function extractCwd3(input) {
2760
3032
  }
2761
3033
  function hasPythonHooks(settingsPath) {
2762
3034
  try {
2763
- if (!fs5.existsSync(settingsPath)) return false;
2764
- const content = fs5.readFileSync(settingsPath, "utf-8");
3035
+ if (!fs6.existsSync(settingsPath)) return false;
3036
+ const content = fs6.readFileSync(settingsPath, "utf-8");
2765
3037
  const settings = JSON.parse(content);
2766
3038
  const hooks2 = settings.hooks;
2767
3039
  if (!hooks2) return false;
@@ -2785,8 +3057,8 @@ function hasPythonHooks(settingsPath) {
2785
3057
  }
2786
3058
  }
2787
3059
  function detectPythonHooks(cwd) {
2788
- const globalSettingsPath = path5.join(homedir5(), ".claude", "settings.json");
2789
- const projectSettingsPath = path5.join(cwd, ".claude", "settings.json");
3060
+ const globalSettingsPath = path6.join(homedir6(), ".claude", "settings.json");
3061
+ const projectSettingsPath = path6.join(cwd, ".claude", "settings.json");
2790
3062
  return {
2791
3063
  global: hasPythonHooks(globalSettingsPath),
2792
3064
  project: hasPythonHooks(projectSettingsPath)
@@ -2844,14 +3116,14 @@ async function runAutoRulesHook() {
2844
3116
  }
2845
3117
  process.exit(0);
2846
3118
  }
2847
- var API_URL3, API_KEY3, ENABLED6, MARKER_FILE, COOLDOWN_MS, isDirectRun6;
3119
+ var API_URL4, API_KEY4, ENABLED6, MARKER_FILE, COOLDOWN_MS, isDirectRun6;
2848
3120
  var init_auto_rules = __esm({
2849
3121
  "src/hooks/auto-rules.ts"() {
2850
3122
  "use strict";
2851
- API_URL3 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
2852
- API_KEY3 = process.env.CONTEXTSTREAM_API_KEY || "";
3123
+ API_URL4 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
3124
+ API_KEY4 = process.env.CONTEXTSTREAM_API_KEY || "";
2853
3125
  ENABLED6 = process.env.CONTEXTSTREAM_AUTO_RULES !== "false";
2854
- MARKER_FILE = path5.join(homedir5(), ".contextstream", ".auto-rules-ran");
3126
+ MARKER_FILE = path6.join(homedir6(), ".contextstream", ".auto-rules-ran");
2855
3127
  COOLDOWN_MS = 4 * 60 * 60 * 1e3;
2856
3128
  isDirectRun6 = process.argv[1]?.includes("auto-rules") || process.argv[2] === "auto-rules";
2857
3129
  if (isDirectRun6) {