@contextstream/mcp-server 0.4.61 → 0.4.62

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.
@@ -38,14 +38,181 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
38
38
  mod
39
39
  ));
40
40
 
41
+ // src/hooks/prompt-state.ts
42
+ import * as fs from "node:fs";
43
+ import * as path from "node:path";
44
+ import { homedir } from "node:os";
45
+ function defaultState() {
46
+ return { workspaces: {} };
47
+ }
48
+ function nowIso() {
49
+ return (/* @__PURE__ */ new Date()).toISOString();
50
+ }
51
+ function ensureStateDir() {
52
+ try {
53
+ fs.mkdirSync(path.dirname(STATE_PATH), { recursive: true });
54
+ } catch {
55
+ }
56
+ }
57
+ function normalizePath(input) {
58
+ try {
59
+ return path.resolve(input);
60
+ } catch {
61
+ return input;
62
+ }
63
+ }
64
+ function workspacePathsMatch(a, b) {
65
+ const left = normalizePath(a);
66
+ const right = normalizePath(b);
67
+ return left === right || left.startsWith(`${right}${path.sep}`) || right.startsWith(`${left}${path.sep}`);
68
+ }
69
+ function readState() {
70
+ try {
71
+ const content = fs.readFileSync(STATE_PATH, "utf8");
72
+ const parsed = JSON.parse(content);
73
+ if (!parsed || typeof parsed !== "object" || !parsed.workspaces) {
74
+ return defaultState();
75
+ }
76
+ return parsed;
77
+ } catch {
78
+ return defaultState();
79
+ }
80
+ }
81
+ function writeState(state) {
82
+ try {
83
+ ensureStateDir();
84
+ fs.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2), "utf8");
85
+ } catch {
86
+ }
87
+ }
88
+ function getOrCreateEntry(state, cwd) {
89
+ if (!cwd.trim()) return null;
90
+ const exact = state.workspaces[cwd];
91
+ if (exact) return { key: cwd, entry: exact };
92
+ for (const [trackedCwd, trackedEntry] of Object.entries(state.workspaces)) {
93
+ if (workspacePathsMatch(trackedCwd, cwd)) {
94
+ return { key: trackedCwd, entry: trackedEntry };
95
+ }
96
+ }
97
+ const created = {
98
+ require_context: false,
99
+ require_init: false,
100
+ last_context_at: void 0,
101
+ last_state_change_at: void 0,
102
+ updated_at: nowIso()
103
+ };
104
+ state.workspaces[cwd] = created;
105
+ return { key: cwd, entry: created };
106
+ }
107
+ function cleanupStale(maxAgeSeconds) {
108
+ const state = readState();
109
+ const now = Date.now();
110
+ let changed = false;
111
+ for (const [cwd, entry] of Object.entries(state.workspaces)) {
112
+ const updated = new Date(entry.updated_at);
113
+ if (Number.isNaN(updated.getTime())) continue;
114
+ const ageSeconds = (now - updated.getTime()) / 1e3;
115
+ if (ageSeconds > maxAgeSeconds) {
116
+ delete state.workspaces[cwd];
117
+ changed = true;
118
+ }
119
+ }
120
+ if (changed) {
121
+ writeState(state);
122
+ }
123
+ }
124
+ function markContextRequired(cwd) {
125
+ if (!cwd.trim()) return;
126
+ const state = readState();
127
+ const target = getOrCreateEntry(state, cwd);
128
+ if (!target) return;
129
+ target.entry.require_context = true;
130
+ target.entry.updated_at = nowIso();
131
+ writeState(state);
132
+ }
133
+ function clearContextRequired(cwd) {
134
+ if (!cwd.trim()) return;
135
+ const state = readState();
136
+ const target = getOrCreateEntry(state, cwd);
137
+ if (!target) return;
138
+ target.entry.require_context = false;
139
+ target.entry.last_context_at = nowIso();
140
+ target.entry.updated_at = nowIso();
141
+ writeState(state);
142
+ }
143
+ function isContextRequired(cwd) {
144
+ if (!cwd.trim()) return false;
145
+ const state = readState();
146
+ const target = getOrCreateEntry(state, cwd);
147
+ return Boolean(target?.entry.require_context);
148
+ }
149
+ function markInitRequired(cwd) {
150
+ if (!cwd.trim()) return;
151
+ const state = readState();
152
+ const target = getOrCreateEntry(state, cwd);
153
+ if (!target) return;
154
+ target.entry.require_init = true;
155
+ target.entry.updated_at = nowIso();
156
+ writeState(state);
157
+ }
158
+ function clearInitRequired(cwd) {
159
+ if (!cwd.trim()) return;
160
+ const state = readState();
161
+ const target = getOrCreateEntry(state, cwd);
162
+ if (!target) return;
163
+ target.entry.require_init = false;
164
+ target.entry.updated_at = nowIso();
165
+ writeState(state);
166
+ }
167
+ function isInitRequired(cwd) {
168
+ if (!cwd.trim()) return false;
169
+ const state = readState();
170
+ const target = getOrCreateEntry(state, cwd);
171
+ return Boolean(target?.entry.require_init);
172
+ }
173
+ function markStateChanged(cwd) {
174
+ if (!cwd.trim()) return;
175
+ const state = readState();
176
+ const target = getOrCreateEntry(state, cwd);
177
+ if (!target) return;
178
+ target.entry.last_state_change_at = nowIso();
179
+ target.entry.updated_at = nowIso();
180
+ writeState(state);
181
+ }
182
+ function isContextFreshAndClean(cwd, maxAgeSeconds) {
183
+ if (!cwd.trim()) return false;
184
+ const state = readState();
185
+ const target = getOrCreateEntry(state, cwd);
186
+ const entry = target?.entry;
187
+ if (!entry?.last_context_at) return false;
188
+ const contextAt = new Date(entry.last_context_at);
189
+ if (Number.isNaN(contextAt.getTime())) return false;
190
+ const ageSeconds = (Date.now() - contextAt.getTime()) / 1e3;
191
+ if (ageSeconds < 0 || ageSeconds > maxAgeSeconds) return false;
192
+ if (entry.last_state_change_at) {
193
+ const changedAt = new Date(entry.last_state_change_at);
194
+ if (!Number.isNaN(changedAt.getTime()) && changedAt.getTime() > contextAt.getTime()) {
195
+ return false;
196
+ }
197
+ }
198
+ return true;
199
+ }
200
+ var STATE_PATH;
201
+ var init_prompt_state = __esm({
202
+ "src/hooks/prompt-state.ts"() {
203
+ "use strict";
204
+ STATE_PATH = path.join(homedir(), ".contextstream", "prompt-state.json");
205
+ }
206
+ });
207
+
41
208
  // src/hooks/pre-tool-use.ts
42
209
  var pre_tool_use_exports = {};
43
210
  __export(pre_tool_use_exports, {
44
211
  runPreToolUseHook: () => runPreToolUseHook
45
212
  });
46
- import * as fs from "node:fs";
47
- import * as path from "node:path";
48
- import { homedir } from "node:os";
213
+ import * as fs2 from "node:fs";
214
+ import * as path2 from "node:path";
215
+ import { homedir as homedir2 } from "node:os";
49
216
  function isDiscoveryGlob(pattern) {
50
217
  const patternLower = pattern.toLowerCase();
51
218
  for (const p of DISCOVERY_PATTERNS) {
@@ -71,22 +238,22 @@ function isDiscoveryGrep(filePath) {
71
238
  return false;
72
239
  }
73
240
  function isProjectIndexed(cwd) {
74
- if (!fs.existsSync(INDEX_STATUS_FILE)) {
241
+ if (!fs2.existsSync(INDEX_STATUS_FILE)) {
75
242
  return { isIndexed: false, isStale: false };
76
243
  }
77
244
  let data;
78
245
  try {
79
- const content = fs.readFileSync(INDEX_STATUS_FILE, "utf-8");
246
+ const content = fs2.readFileSync(INDEX_STATUS_FILE, "utf-8");
80
247
  data = JSON.parse(content);
81
248
  } catch {
82
249
  return { isIndexed: false, isStale: false };
83
250
  }
84
251
  const projects = data.projects || {};
85
- const cwdPath = path.resolve(cwd);
252
+ const cwdPath = path2.resolve(cwd);
86
253
  for (const [projectPath, info] of Object.entries(projects)) {
87
254
  try {
88
- const indexedPath = path.resolve(projectPath);
89
- if (cwdPath === indexedPath || cwdPath.startsWith(indexedPath + path.sep)) {
255
+ const indexedPath = path2.resolve(projectPath);
256
+ if (cwdPath === indexedPath || cwdPath.startsWith(indexedPath + path2.sep)) {
90
257
  const indexedAt = info.indexed_at;
91
258
  if (indexedAt) {
92
259
  try {
@@ -119,6 +286,97 @@ function extractToolName(input) {
119
286
  function extractToolInput(input) {
120
287
  return input.tool_input || input.parameters || input.toolParameters || {};
121
288
  }
289
+ function normalizeContextstreamToolName(toolName) {
290
+ const trimmed = toolName.trim();
291
+ if (!trimmed) return null;
292
+ const lower = trimmed.toLowerCase();
293
+ const prefixed = "mcp__contextstream__";
294
+ if (lower.startsWith(prefixed)) {
295
+ return lower.slice(prefixed.length);
296
+ }
297
+ if (lower.startsWith("contextstream__")) {
298
+ return lower.slice("contextstream__".length);
299
+ }
300
+ if (lower === "init" || lower === "context") {
301
+ return lower;
302
+ }
303
+ return null;
304
+ }
305
+ function actionFromToolInput(toolInput) {
306
+ const maybeAction = toolInput?.action;
307
+ return typeof maybeAction === "string" ? maybeAction.trim().toLowerCase() : "";
308
+ }
309
+ function isContextstreamReadOnlyOperation(toolName, toolInput) {
310
+ const action = actionFromToolInput(toolInput);
311
+ switch (toolName) {
312
+ case "workspace":
313
+ return action === "list" || action === "get";
314
+ case "memory":
315
+ return action === "list_docs" || action === "list_events" || action === "list_todos" || action === "list_tasks" || action === "list_transcripts" || action === "list_nodes" || action === "decisions" || action === "get_doc" || action === "get_event" || action === "get_task" || action === "get_todo" || action === "get_transcript";
316
+ case "session":
317
+ return action === "get_lessons" || action === "get_plan" || action === "list_plans" || action === "recall";
318
+ case "help":
319
+ return action === "version" || action === "tools" || action === "auth";
320
+ case "project":
321
+ return action === "list" || action === "get" || action === "index_status";
322
+ case "reminder":
323
+ return action === "list" || action === "active";
324
+ case "context":
325
+ case "init":
326
+ return true;
327
+ default:
328
+ return false;
329
+ }
330
+ }
331
+ function isLikelyStateChangingTool(toolLower, toolInput, isContextstreamCall, normalizedContextstreamTool) {
332
+ if (isContextstreamCall && normalizedContextstreamTool) {
333
+ return !isContextstreamReadOnlyOperation(normalizedContextstreamTool, toolInput);
334
+ }
335
+ if ([
336
+ "read",
337
+ "read_file",
338
+ "grep",
339
+ "glob",
340
+ "search",
341
+ "grep_search",
342
+ "code_search",
343
+ "semanticsearch",
344
+ "codebase_search",
345
+ "list_files",
346
+ "search_files",
347
+ "search_files_content",
348
+ "find_files",
349
+ "find_by_name",
350
+ "ls",
351
+ "cat",
352
+ "view"
353
+ ].includes(toolLower)) {
354
+ return false;
355
+ }
356
+ const writeMarkers = [
357
+ "write",
358
+ "edit",
359
+ "create",
360
+ "delete",
361
+ "remove",
362
+ "rename",
363
+ "move",
364
+ "patch",
365
+ "apply",
366
+ "insert",
367
+ "append",
368
+ "replace",
369
+ "update",
370
+ "commit",
371
+ "push",
372
+ "install",
373
+ "exec",
374
+ "run",
375
+ "bash",
376
+ "shell"
377
+ ];
378
+ return writeMarkers.some((marker) => toolLower.includes(marker));
379
+ }
122
380
  function blockClaudeCode(message) {
123
381
  const response = {
124
382
  hookSpecificOutput: {
@@ -127,7 +385,7 @@ function blockClaudeCode(message) {
127
385
  additionalContext: `[CONTEXTSTREAM] ${message}`
128
386
  }
129
387
  };
130
- fs.appendFileSync(DEBUG_FILE, `[PreToolUse] REDIRECT (additionalContext): ${JSON.stringify(response)}
388
+ fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] REDIRECT (additionalContext): ${JSON.stringify(response)}
131
389
  `);
132
390
  console.log(JSON.stringify(response));
133
391
  process.exit(0);
@@ -155,6 +413,25 @@ function outputCursorAllow() {
155
413
  console.log(JSON.stringify({ decision: "allow" }));
156
414
  process.exit(0);
157
415
  }
416
+ function blockWithMessage(editorFormat, message) {
417
+ if (editorFormat === "cline") {
418
+ outputClineBlock(message, "[CONTEXTSTREAM] Follow ContextStream startup requirements.");
419
+ } else if (editorFormat === "cursor") {
420
+ outputCursorBlock(message);
421
+ }
422
+ blockClaudeCode(message);
423
+ }
424
+ function allowTool(editorFormat, cwd, recordStateChange) {
425
+ if (recordStateChange) {
426
+ markStateChanged(cwd);
427
+ }
428
+ if (editorFormat === "cline") {
429
+ outputClineAllow();
430
+ } else if (editorFormat === "cursor") {
431
+ outputCursorAllow();
432
+ }
433
+ process.exit(0);
434
+ }
158
435
  function detectEditorFormat(input) {
159
436
  if (input.hookName !== void 0 || input.toolName !== void 0) {
160
437
  return "cline";
@@ -165,11 +442,11 @@ function detectEditorFormat(input) {
165
442
  return "claude";
166
443
  }
167
444
  async function runPreToolUseHook() {
168
- fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Hook invoked at ${(/* @__PURE__ */ new Date()).toISOString()}
445
+ fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] Hook invoked at ${(/* @__PURE__ */ new Date()).toISOString()}
169
446
  `);
170
447
  console.error("[PreToolUse] Hook invoked at", (/* @__PURE__ */ new Date()).toISOString());
171
448
  if (!ENABLED) {
172
- fs.appendFileSync(DEBUG_FILE, "[PreToolUse] Hook disabled, exiting\n");
449
+ fs2.appendFileSync(DEBUG_FILE, "[PreToolUse] Hook disabled, exiting\n");
173
450
  console.error("[PreToolUse] Hook disabled, exiting");
174
451
  process.exit(0);
175
452
  }
@@ -190,28 +467,52 @@ async function runPreToolUseHook() {
190
467
  const cwd = extractCwd(input);
191
468
  const tool = extractToolName(input);
192
469
  const toolInput = extractToolInput(input);
193
- fs.appendFileSync(DEBUG_FILE, `[PreToolUse] tool=${tool}, cwd=${cwd}, editorFormat=${editorFormat}
470
+ const toolLower = tool.toLowerCase();
471
+ const normalizedContextstreamTool = normalizeContextstreamToolName(tool);
472
+ const isContextstreamCall = normalizedContextstreamTool !== null;
473
+ const recordStateChange = isLikelyStateChangingTool(
474
+ toolLower,
475
+ toolInput,
476
+ isContextstreamCall,
477
+ normalizedContextstreamTool
478
+ );
479
+ fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] tool=${tool}, cwd=${cwd}, editorFormat=${editorFormat}
194
480
  `);
481
+ cleanupStale(180);
482
+ if (isInitRequired(cwd)) {
483
+ if (isContextstreamCall && normalizedContextstreamTool === "init") {
484
+ clearInitRequired(cwd);
485
+ } else {
486
+ const required = "mcp__contextstream__init(...)";
487
+ const msg = `First call required for this session: ${required}. Run it before any other MCP tool. Then call mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>").`;
488
+ blockWithMessage(editorFormat, msg);
489
+ }
490
+ }
491
+ if (isContextRequired(cwd)) {
492
+ if (isContextstreamCall && normalizedContextstreamTool === "context") {
493
+ clearContextRequired(cwd);
494
+ } else if (isContextstreamCall && normalizedContextstreamTool === "init") {
495
+ } else if (isContextstreamCall && normalizedContextstreamTool && isContextstreamReadOnlyOperation(normalizedContextstreamTool, toolInput) && isContextFreshAndClean(cwd, CONTEXT_FRESHNESS_SECONDS)) {
496
+ } else {
497
+ const msg = 'First call required for this prompt: mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>"). Run it before any other MCP tool.';
498
+ blockWithMessage(editorFormat, msg);
499
+ }
500
+ }
195
501
  const { isIndexed } = isProjectIndexed(cwd);
196
- fs.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}
502
+ fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}
197
503
  `);
198
504
  if (!isIndexed) {
199
- fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Project not indexed, allowing
505
+ fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] Project not indexed, allowing
200
506
  `);
201
- if (editorFormat === "cline") {
202
- outputClineAllow();
203
- } else if (editorFormat === "cursor") {
204
- outputCursorAllow();
205
- }
206
- process.exit(0);
507
+ allowTool(editorFormat, cwd, recordStateChange);
207
508
  }
208
509
  if (tool === "Glob") {
209
510
  const pattern = toolInput?.pattern || "";
210
- fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Glob pattern=${pattern}, isDiscovery=${isDiscoveryGlob(pattern)}
511
+ fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] Glob pattern=${pattern}, isDiscovery=${isDiscoveryGlob(pattern)}
211
512
  `);
212
513
  if (isDiscoveryGlob(pattern)) {
213
- const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of Glob.`;
214
- fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Intercepting discovery glob: ${msg}
514
+ const msg = `This project index is current. Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of Glob for faster, richer code results.`;
515
+ fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] Intercepting discovery glob: ${msg}
215
516
  `);
216
517
  if (editorFormat === "cline") {
217
518
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
@@ -233,7 +534,7 @@ async function runPreToolUseHook() {
233
534
  }
234
535
  blockClaudeCode(msg);
235
536
  } else {
236
- const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}.`;
537
+ const msg = `This project index is current. Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool} for faster, richer code results.`;
237
538
  if (editorFormat === "cline") {
238
539
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
239
540
  } else if (editorFormat === "cursor") {
@@ -245,7 +546,7 @@ async function runPreToolUseHook() {
245
546
  } else if (tool === "Task") {
246
547
  const subagentType = toolInput?.subagent_type?.toLowerCase() || "";
247
548
  if (subagentType === "explore") {
248
- const msg = 'STOP: Use mcp__contextstream__search(mode="auto") instead of Task(Explore).';
549
+ const msg = 'Project index is current. Use mcp__contextstream__search(mode="auto") instead of Task(Explore) for broad discovery.';
249
550
  if (editorFormat === "cline") {
250
551
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
251
552
  } else if (editorFormat === "cursor") {
@@ -254,7 +555,7 @@ async function runPreToolUseHook() {
254
555
  blockClaudeCode(msg);
255
556
  }
256
557
  if (subagentType === "plan") {
257
- const msg = 'STOP: Use mcp__contextstream__session(action="capture_plan") for planning. ContextStream plans persist across sessions.';
558
+ const msg = 'After your plan is ready, save it with mcp__contextstream__session(action="capture_plan"). Then create tasks with mcp__contextstream__memory(action="create_task", title="...", plan_id="...").';
258
559
  if (editorFormat === "cline") {
259
560
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream plans for persistence.");
260
561
  } else if (editorFormat === "cursor") {
@@ -263,7 +564,7 @@ async function runPreToolUseHook() {
263
564
  blockClaudeCode(msg);
264
565
  }
265
566
  } else if (tool === "EnterPlanMode") {
266
- const msg = 'STOP: Use mcp__contextstream__session(action="capture_plan", title="...", steps=[...]) instead of EnterPlanMode. ContextStream plans persist across sessions and are searchable.';
567
+ const msg = 'After finalizing your plan, save it to ContextStream (not a local markdown file): mcp__contextstream__session(action="capture_plan", title="...", steps=[...]). Then create tasks with mcp__contextstream__memory(action="create_task", title="...", plan_id="...").';
267
568
  if (editorFormat === "cline") {
268
569
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream plans for persistence.");
269
570
  } else if (editorFormat === "cursor") {
@@ -274,29 +575,27 @@ async function runPreToolUseHook() {
274
575
  if (tool === "list_files" || tool === "search_files") {
275
576
  const pattern = toolInput?.path || toolInput?.regex || "";
276
577
  if (isDiscoveryGlob(pattern) || isDiscoveryGrep(pattern)) {
277
- const msg = `Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}. ContextStream search is indexed and faster.`;
578
+ const msg = `Project index is current. Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool} for faster, richer code results.`;
278
579
  if (editorFormat === "cline") {
279
580
  outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
280
581
  } else if (editorFormat === "cursor") {
281
582
  outputCursorBlock(msg);
282
583
  }
584
+ blockClaudeCode(msg);
283
585
  }
284
586
  }
285
- if (editorFormat === "cline") {
286
- outputClineAllow();
287
- } else if (editorFormat === "cursor") {
288
- outputCursorAllow();
289
- }
290
- process.exit(0);
587
+ allowTool(editorFormat, cwd, recordStateChange);
291
588
  }
292
- var ENABLED, INDEX_STATUS_FILE, DEBUG_FILE, STALE_THRESHOLD_DAYS, DISCOVERY_PATTERNS, isDirectRun;
589
+ var ENABLED, INDEX_STATUS_FILE, DEBUG_FILE, STALE_THRESHOLD_DAYS, CONTEXT_FRESHNESS_SECONDS, DISCOVERY_PATTERNS, isDirectRun;
293
590
  var init_pre_tool_use = __esm({
294
591
  "src/hooks/pre-tool-use.ts"() {
295
592
  "use strict";
593
+ init_prompt_state();
296
594
  ENABLED = process.env.CONTEXTSTREAM_HOOK_ENABLED !== "false";
297
- INDEX_STATUS_FILE = path.join(homedir(), ".contextstream", "indexed-projects.json");
595
+ INDEX_STATUS_FILE = path2.join(homedir2(), ".contextstream", "indexed-projects.json");
298
596
  DEBUG_FILE = "/tmp/pretooluse-hook-debug.log";
299
597
  STALE_THRESHOLD_DAYS = 7;
598
+ CONTEXT_FRESHNESS_SECONDS = 120;
300
599
  DISCOVERY_PATTERNS = ["**/*", "**/", "src/**", "lib/**", "app/**", "components/**"];
301
600
  isDirectRun = process.argv[1]?.includes("pre-tool-use") || process.argv[2] === "pre-tool-use";
302
601
  if (isDirectRun) {
@@ -307,9 +606,9 @@ var init_pre_tool_use = __esm({
307
606
 
308
607
  // src/version.ts
309
608
  import { createRequire } from "module";
310
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync, mkdirSync } from "fs";
311
- import { homedir as homedir2, platform } from "os";
312
- import { join as join2 } from "path";
609
+ import { existsSync as existsSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
610
+ import { homedir as homedir3, platform } from "os";
611
+ import { join as join3 } from "path";
313
612
  import { spawn } from "child_process";
314
613
  function getVersion() {
315
614
  if (typeof __CONTEXTSTREAM_VERSION__ !== "undefined" && __CONTEXTSTREAM_VERSION__) {
@@ -336,13 +635,13 @@ function compareVersions(v1, v2) {
336
635
  return 0;
337
636
  }
338
637
  function getCacheFilePath() {
339
- return join2(homedir2(), ".contextstream", "version-cache.json");
638
+ return join3(homedir3(), ".contextstream", "version-cache.json");
340
639
  }
341
640
  function readCache() {
342
641
  try {
343
642
  const cacheFile = getCacheFilePath();
344
643
  if (!existsSync2(cacheFile)) return null;
345
- const data = JSON.parse(readFileSync2(cacheFile, "utf-8"));
644
+ const data = JSON.parse(readFileSync3(cacheFile, "utf-8"));
346
645
  if (Date.now() - data.checkedAt > CACHE_TTL_MS) return null;
347
646
  return data;
348
647
  } catch {
@@ -351,12 +650,12 @@ function readCache() {
351
650
  }
352
651
  function writeCache(latestVersion) {
353
652
  try {
354
- const configDir = join2(homedir2(), ".contextstream");
653
+ const configDir = join3(homedir3(), ".contextstream");
355
654
  if (!existsSync2(configDir)) {
356
- mkdirSync(configDir, { recursive: true });
655
+ mkdirSync2(configDir, { recursive: true });
357
656
  }
358
657
  const cacheFile = getCacheFilePath();
359
- writeFileSync(
658
+ writeFileSync2(
360
659
  cacheFile,
361
660
  JSON.stringify({
362
661
  latestVersion,
@@ -467,9 +766,9 @@ function isAutoUpdateEnabled() {
467
766
  return false;
468
767
  }
469
768
  try {
470
- const configPath = join2(homedir2(), ".contextstream", "config.json");
769
+ const configPath = join3(homedir3(), ".contextstream", "config.json");
471
770
  if (existsSync2(configPath)) {
472
- const config = JSON.parse(readFileSync2(configPath, "utf-8"));
771
+ const config = JSON.parse(readFileSync3(configPath, "utf-8"));
473
772
  if (config.auto_update === false) {
474
773
  return false;
475
774
  }
@@ -530,7 +829,7 @@ function detectUpdateMethod() {
530
829
  return "curl";
531
830
  }
532
831
  async function runUpdate(method) {
533
- return new Promise((resolve14, reject) => {
832
+ return new Promise((resolve15, reject) => {
534
833
  let command;
535
834
  let args;
536
835
  let shell;
@@ -561,23 +860,23 @@ async function runUpdate(method) {
561
860
  });
562
861
  proc.on("close", (code) => {
563
862
  if (code === 0) {
564
- resolve14();
863
+ resolve15();
565
864
  } else {
566
865
  reject(new Error(`Update process exited with code ${code}`));
567
866
  }
568
867
  });
569
868
  proc.unref();
570
- setTimeout(() => resolve14(), 1e3);
869
+ setTimeout(() => resolve15(), 1e3);
571
870
  });
572
871
  }
573
872
  function writeUpdateMarker(previousVersion, newVersion) {
574
873
  try {
575
- const markerPath = join2(homedir2(), ".contextstream", "update-pending.json");
576
- const configDir = join2(homedir2(), ".contextstream");
874
+ const markerPath = join3(homedir3(), ".contextstream", "update-pending.json");
875
+ const configDir = join3(homedir3(), ".contextstream");
577
876
  if (!existsSync2(configDir)) {
578
- mkdirSync(configDir, { recursive: true });
877
+ mkdirSync2(configDir, { recursive: true });
579
878
  }
580
- writeFileSync(markerPath, JSON.stringify({
879
+ writeFileSync2(markerPath, JSON.stringify({
581
880
  previousVersion,
582
881
  newVersion,
583
882
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -587,9 +886,9 @@ function writeUpdateMarker(previousVersion, newVersion) {
587
886
  }
588
887
  function checkUpdateMarker() {
589
888
  try {
590
- const markerPath = join2(homedir2(), ".contextstream", "update-pending.json");
889
+ const markerPath = join3(homedir3(), ".contextstream", "update-pending.json");
591
890
  if (!existsSync2(markerPath)) return null;
592
- const marker = JSON.parse(readFileSync2(markerPath, "utf-8"));
891
+ const marker = JSON.parse(readFileSync3(markerPath, "utf-8"));
593
892
  const updatedAt = new Date(marker.updatedAt);
594
893
  const hourAgo = new Date(Date.now() - 60 * 60 * 1e3);
595
894
  if (updatedAt < hourAgo) {
@@ -606,7 +905,7 @@ function checkUpdateMarker() {
606
905
  }
607
906
  function clearUpdateMarker() {
608
907
  try {
609
- const markerPath = join2(homedir2(), ".contextstream", "update-pending.json");
908
+ const markerPath = join3(homedir3(), ".contextstream", "update-pending.json");
610
909
  if (existsSync2(markerPath)) {
611
910
  __require("fs").unlinkSync(markerPath);
612
911
  }
@@ -636,17 +935,17 @@ var user_prompt_submit_exports = {};
636
935
  __export(user_prompt_submit_exports, {
637
936
  runUserPromptSubmitHook: () => runUserPromptSubmitHook
638
937
  });
639
- import * as fs2 from "node:fs";
640
- import * as path2 from "node:path";
641
- import { homedir as homedir3 } from "node:os";
938
+ import * as fs3 from "node:fs";
939
+ import * as path3 from "node:path";
940
+ import { homedir as homedir4 } from "node:os";
642
941
  function loadConfigFromMcpJson(cwd) {
643
- let searchDir = path2.resolve(cwd);
942
+ let searchDir = path3.resolve(cwd);
644
943
  for (let i = 0; i < 5; i++) {
645
944
  if (!API_KEY) {
646
- const mcpPath = path2.join(searchDir, ".mcp.json");
647
- if (fs2.existsSync(mcpPath)) {
945
+ const mcpPath = path3.join(searchDir, ".mcp.json");
946
+ if (fs3.existsSync(mcpPath)) {
648
947
  try {
649
- const content = fs2.readFileSync(mcpPath, "utf-8");
948
+ const content = fs3.readFileSync(mcpPath, "utf-8");
650
949
  const config = JSON.parse(content);
651
950
  const csEnv = config.mcpServers?.contextstream?.env;
652
951
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -663,10 +962,10 @@ function loadConfigFromMcpJson(cwd) {
663
962
  }
664
963
  }
665
964
  if (!WORKSPACE_ID || !PROJECT_ID) {
666
- const csConfigPath = path2.join(searchDir, ".contextstream", "config.json");
667
- if (fs2.existsSync(csConfigPath)) {
965
+ const csConfigPath = path3.join(searchDir, ".contextstream", "config.json");
966
+ if (fs3.existsSync(csConfigPath)) {
668
967
  try {
669
- const content = fs2.readFileSync(csConfigPath, "utf-8");
968
+ const content = fs3.readFileSync(csConfigPath, "utf-8");
670
969
  const csConfig = JSON.parse(content);
671
970
  if (csConfig.workspace_id && !WORKSPACE_ID) {
672
971
  WORKSPACE_ID = csConfig.workspace_id;
@@ -678,15 +977,15 @@ function loadConfigFromMcpJson(cwd) {
678
977
  }
679
978
  }
680
979
  }
681
- const parentDir = path2.dirname(searchDir);
980
+ const parentDir = path3.dirname(searchDir);
682
981
  if (parentDir === searchDir) break;
683
982
  searchDir = parentDir;
684
983
  }
685
984
  if (!API_KEY) {
686
- const homeMcpPath = path2.join(homedir3(), ".mcp.json");
687
- if (fs2.existsSync(homeMcpPath)) {
985
+ const homeMcpPath = path3.join(homedir4(), ".mcp.json");
986
+ if (fs3.existsSync(homeMcpPath)) {
688
987
  try {
689
- const content = fs2.readFileSync(homeMcpPath, "utf-8");
988
+ const content = fs3.readFileSync(homeMcpPath, "utf-8");
690
989
  const config = JSON.parse(content);
691
990
  const csEnv = config.mcpServers?.contextstream?.env;
692
991
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -702,7 +1001,7 @@ function loadConfigFromMcpJson(cwd) {
702
1001
  }
703
1002
  function readTranscriptFile(transcriptPath) {
704
1003
  try {
705
- const content = fs2.readFileSync(transcriptPath, "utf-8");
1004
+ const content = fs3.readFileSync(transcriptPath, "utf-8");
706
1005
  const lines = content.trim().split("\n");
707
1006
  const messages = [];
708
1007
  for (const line of lines) {
@@ -1110,6 +1409,11 @@ async function runUserPromptSubmitHook() {
1110
1409
  }
1111
1410
  const editorFormat = detectEditorFormat2(input);
1112
1411
  const cwd = input.cwd || process.cwd();
1412
+ cleanupStale(180);
1413
+ markContextRequired(cwd);
1414
+ if (isNewSession(input, editorFormat)) {
1415
+ markInitRequired(cwd);
1416
+ }
1113
1417
  if (editorFormat === "claude") {
1114
1418
  loadConfigFromMcpJson(cwd);
1115
1419
  let context = REMINDER;
@@ -1166,20 +1470,23 @@ var init_user_prompt_submit = __esm({
1166
1470
  "src/hooks/user-prompt-submit.ts"() {
1167
1471
  "use strict";
1168
1472
  init_version();
1473
+ init_prompt_state();
1169
1474
  ENABLED2 = process.env.CONTEXTSTREAM_REMINDER_ENABLED !== "false";
1170
1475
  API_URL = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
1171
1476
  API_KEY = process.env.CONTEXTSTREAM_API_KEY || "";
1172
1477
  WORKSPACE_ID = null;
1173
1478
  PROJECT_ID = null;
1174
- REMINDER = `[CONTEXTSTREAM] Call mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>") FIRST before any other tool. Response contains dynamic rules, lessons, preferences. For search: use search(mode="auto") if indexed, else local tools.
1479
+ REMINDER = `[CONTEXTSTREAM] On the first message in every session call mcp__contextstream__init(...), then call mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>") FIRST before any other tool. On subsequent messages, default to context first. Narrow bypass is allowed only for immediate read-only ContextStream calls when prior context is fresh and no state-changing tool has run. Response contains dynamic rules, lessons, preferences.
1480
+ COMMON MEMORY CALLS: list docs via memory(action="list_docs"), list lessons via session(action="get_lessons"), list plans via session(action="list_plans"), list tasks/todos via memory(action="list_tasks"|"list_todos").
1175
1481
  [END]`;
1176
1482
  FULL_REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
1177
1483
 
1178
- 1. FIRST: Call mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>") before ANY other tool
1484
+ 1. FIRST MESSAGE IN SESSION: Call mcp__contextstream__init(...) then mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>")
1179
1485
  - Returns: dynamic rules, lessons from past mistakes, relevant context
1180
1486
  - Check response for: [LESSONS_WARNING], [RULES_NOTICE], preferences
1181
1487
  - save_exchange=true saves each conversation turn for later retrieval
1182
1488
  - Use a consistent session_id for the entire conversation (generate once on first message)
1489
+ - On subsequent messages, default to context() first. Narrow bypass: immediate read-only ContextStream calls when context is fresh and no state-changing tool has run.
1183
1490
 
1184
1491
  2. FOR CODE SEARCH: Check index status, then search appropriately
1185
1492
  \u26A0\uFE0F BEFORE searching: mcp__contextstream__project(action="index_status")
@@ -1330,17 +1637,17 @@ var pre_compact_exports = {};
1330
1637
  __export(pre_compact_exports, {
1331
1638
  runPreCompactHook: () => runPreCompactHook
1332
1639
  });
1333
- import * as fs3 from "node:fs";
1334
- import * as path3 from "node:path";
1335
- import { homedir as homedir4 } from "node:os";
1640
+ import * as fs4 from "node:fs";
1641
+ import * as path4 from "node:path";
1642
+ import { homedir as homedir5 } from "node:os";
1336
1643
  function loadConfigFromMcpJson2(cwd) {
1337
- let searchDir = path3.resolve(cwd);
1644
+ let searchDir = path4.resolve(cwd);
1338
1645
  for (let i = 0; i < 5; i++) {
1339
1646
  if (!API_KEY2) {
1340
- const mcpPath = path3.join(searchDir, ".mcp.json");
1341
- if (fs3.existsSync(mcpPath)) {
1647
+ const mcpPath = path4.join(searchDir, ".mcp.json");
1648
+ if (fs4.existsSync(mcpPath)) {
1342
1649
  try {
1343
- const content = fs3.readFileSync(mcpPath, "utf-8");
1650
+ const content = fs4.readFileSync(mcpPath, "utf-8");
1344
1651
  const config = JSON.parse(content);
1345
1652
  const csEnv = config.mcpServers?.contextstream?.env;
1346
1653
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -1354,10 +1661,10 @@ function loadConfigFromMcpJson2(cwd) {
1354
1661
  }
1355
1662
  }
1356
1663
  if (!WORKSPACE_ID2) {
1357
- const csConfigPath = path3.join(searchDir, ".contextstream", "config.json");
1358
- if (fs3.existsSync(csConfigPath)) {
1664
+ const csConfigPath = path4.join(searchDir, ".contextstream", "config.json");
1665
+ if (fs4.existsSync(csConfigPath)) {
1359
1666
  try {
1360
- const content = fs3.readFileSync(csConfigPath, "utf-8");
1667
+ const content = fs4.readFileSync(csConfigPath, "utf-8");
1361
1668
  const csConfig = JSON.parse(content);
1362
1669
  if (csConfig.workspace_id) {
1363
1670
  WORKSPACE_ID2 = csConfig.workspace_id;
@@ -1366,15 +1673,15 @@ function loadConfigFromMcpJson2(cwd) {
1366
1673
  }
1367
1674
  }
1368
1675
  }
1369
- const parentDir = path3.dirname(searchDir);
1676
+ const parentDir = path4.dirname(searchDir);
1370
1677
  if (parentDir === searchDir) break;
1371
1678
  searchDir = parentDir;
1372
1679
  }
1373
1680
  if (!API_KEY2) {
1374
- const homeMcpPath = path3.join(homedir4(), ".mcp.json");
1375
- if (fs3.existsSync(homeMcpPath)) {
1681
+ const homeMcpPath = path4.join(homedir5(), ".mcp.json");
1682
+ if (fs4.existsSync(homeMcpPath)) {
1376
1683
  try {
1377
- const content = fs3.readFileSync(homeMcpPath, "utf-8");
1684
+ const content = fs4.readFileSync(homeMcpPath, "utf-8");
1378
1685
  const config = JSON.parse(content);
1379
1686
  const csEnv = config.mcpServers?.contextstream?.env;
1380
1687
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -1396,7 +1703,7 @@ function parseTranscript(transcriptPath) {
1396
1703
  let startedAt = (/* @__PURE__ */ new Date()).toISOString();
1397
1704
  let firstTimestamp = true;
1398
1705
  try {
1399
- const content = fs3.readFileSync(transcriptPath, "utf-8");
1706
+ const content = fs4.readFileSync(transcriptPath, "utf-8");
1400
1707
  const lines = content.split("\n");
1401
1708
  for (const line of lines) {
1402
1709
  if (!line.trim()) continue;
@@ -1597,7 +1904,7 @@ async function runPreCompactHook() {
1597
1904
  messages: [],
1598
1905
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
1599
1906
  };
1600
- if (transcriptPath && fs3.existsSync(transcriptPath)) {
1907
+ if (transcriptPath && fs4.existsSync(transcriptPath)) {
1601
1908
  transcriptData = parseTranscript(transcriptPath);
1602
1909
  }
1603
1910
  let autoSaveStatus = "";
@@ -1656,17 +1963,17 @@ var post_compact_exports = {};
1656
1963
  __export(post_compact_exports, {
1657
1964
  runPostCompactHook: () => runPostCompactHook
1658
1965
  });
1659
- import * as fs4 from "node:fs";
1660
- import * as path4 from "node:path";
1661
- import { homedir as homedir5 } from "node:os";
1966
+ import * as fs5 from "node:fs";
1967
+ import * as path5 from "node:path";
1968
+ import { homedir as homedir6 } from "node:os";
1662
1969
  function loadConfigFromMcpJson3(cwd) {
1663
- let searchDir = path4.resolve(cwd);
1970
+ let searchDir = path5.resolve(cwd);
1664
1971
  for (let i = 0; i < 5; i++) {
1665
1972
  if (!API_KEY3) {
1666
- const mcpPath = path4.join(searchDir, ".mcp.json");
1667
- if (fs4.existsSync(mcpPath)) {
1973
+ const mcpPath = path5.join(searchDir, ".mcp.json");
1974
+ if (fs5.existsSync(mcpPath)) {
1668
1975
  try {
1669
- const content = fs4.readFileSync(mcpPath, "utf-8");
1976
+ const content = fs5.readFileSync(mcpPath, "utf-8");
1670
1977
  const config = JSON.parse(content);
1671
1978
  const csEnv = config.mcpServers?.contextstream?.env;
1672
1979
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -1680,10 +1987,10 @@ function loadConfigFromMcpJson3(cwd) {
1680
1987
  }
1681
1988
  }
1682
1989
  if (!WORKSPACE_ID3) {
1683
- const csConfigPath = path4.join(searchDir, ".contextstream", "config.json");
1684
- if (fs4.existsSync(csConfigPath)) {
1990
+ const csConfigPath = path5.join(searchDir, ".contextstream", "config.json");
1991
+ if (fs5.existsSync(csConfigPath)) {
1685
1992
  try {
1686
- const content = fs4.readFileSync(csConfigPath, "utf-8");
1993
+ const content = fs5.readFileSync(csConfigPath, "utf-8");
1687
1994
  const csConfig = JSON.parse(content);
1688
1995
  if (csConfig.workspace_id) {
1689
1996
  WORKSPACE_ID3 = csConfig.workspace_id;
@@ -1692,15 +1999,15 @@ function loadConfigFromMcpJson3(cwd) {
1692
1999
  }
1693
2000
  }
1694
2001
  }
1695
- const parentDir = path4.dirname(searchDir);
2002
+ const parentDir = path5.dirname(searchDir);
1696
2003
  if (parentDir === searchDir) break;
1697
2004
  searchDir = parentDir;
1698
2005
  }
1699
2006
  if (!API_KEY3) {
1700
- const homeMcpPath = path4.join(homedir5(), ".mcp.json");
1701
- if (fs4.existsSync(homeMcpPath)) {
2007
+ const homeMcpPath = path5.join(homedir6(), ".mcp.json");
2008
+ if (fs5.existsSync(homeMcpPath)) {
1702
2009
  try {
1703
- const content = fs4.readFileSync(homeMcpPath, "utf-8");
2010
+ const content = fs5.readFileSync(homeMcpPath, "utf-8");
1704
2011
  const config = JSON.parse(content);
1705
2012
  const csEnv = config.mcpServers?.contextstream?.env;
1706
2013
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -1834,9 +2141,9 @@ var post_write_exports = {};
1834
2141
  __export(post_write_exports, {
1835
2142
  runPostWriteHook: () => runPostWriteHook
1836
2143
  });
1837
- import * as fs5 from "node:fs";
1838
- import * as path5 from "node:path";
1839
- import { homedir as homedir6 } from "node:os";
2144
+ import * as fs6 from "node:fs";
2145
+ import * as path6 from "node:path";
2146
+ import { homedir as homedir7 } from "node:os";
1840
2147
  function extractFilePath(input) {
1841
2148
  if (input.tool_input) {
1842
2149
  const filePath = input.tool_input.file_path || input.tool_input.notebook_path || input.tool_input.path;
@@ -1861,17 +2168,17 @@ function extractCwd2(input) {
1861
2168
  return process.cwd();
1862
2169
  }
1863
2170
  function findLocalConfig(startDir) {
1864
- let currentDir = path5.resolve(startDir);
2171
+ let currentDir = path6.resolve(startDir);
1865
2172
  for (let i = 0; i < 10; i++) {
1866
- const configPath = path5.join(currentDir, ".contextstream", "config.json");
1867
- if (fs5.existsSync(configPath)) {
2173
+ const configPath = path6.join(currentDir, ".contextstream", "config.json");
2174
+ if (fs6.existsSync(configPath)) {
1868
2175
  try {
1869
- const content = fs5.readFileSync(configPath, "utf-8");
2176
+ const content = fs6.readFileSync(configPath, "utf-8");
1870
2177
  return JSON.parse(content);
1871
2178
  } catch {
1872
2179
  }
1873
2180
  }
1874
- const parentDir = path5.dirname(currentDir);
2181
+ const parentDir = path6.dirname(currentDir);
1875
2182
  if (parentDir === currentDir) break;
1876
2183
  currentDir = parentDir;
1877
2184
  }
@@ -1883,12 +2190,12 @@ function loadApiConfig(startDir) {
1883
2190
  if (apiKey) {
1884
2191
  return { apiUrl, apiKey };
1885
2192
  }
1886
- let currentDir = path5.resolve(startDir);
2193
+ let currentDir = path6.resolve(startDir);
1887
2194
  for (let i = 0; i < 10; i++) {
1888
- const mcpPath = path5.join(currentDir, ".mcp.json");
1889
- if (fs5.existsSync(mcpPath)) {
2195
+ const mcpPath = path6.join(currentDir, ".mcp.json");
2196
+ if (fs6.existsSync(mcpPath)) {
1890
2197
  try {
1891
- const content = fs5.readFileSync(mcpPath, "utf-8");
2198
+ const content = fs6.readFileSync(mcpPath, "utf-8");
1892
2199
  const config = JSON.parse(content);
1893
2200
  const csEnv = config.mcpServers?.contextstream?.env;
1894
2201
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -1901,15 +2208,15 @@ function loadApiConfig(startDir) {
1901
2208
  } catch {
1902
2209
  }
1903
2210
  }
1904
- const parentDir = path5.dirname(currentDir);
2211
+ const parentDir = path6.dirname(currentDir);
1905
2212
  if (parentDir === currentDir) break;
1906
2213
  currentDir = parentDir;
1907
2214
  }
1908
2215
  if (!apiKey) {
1909
- const homeMcpPath = path5.join(homedir6(), ".mcp.json");
1910
- if (fs5.existsSync(homeMcpPath)) {
2216
+ const homeMcpPath = path6.join(homedir7(), ".mcp.json");
2217
+ if (fs6.existsSync(homeMcpPath)) {
1911
2218
  try {
1912
- const content = fs5.readFileSync(homeMcpPath, "utf-8");
2219
+ const content = fs6.readFileSync(homeMcpPath, "utf-8");
1913
2220
  const config = JSON.parse(content);
1914
2221
  const csEnv = config.mcpServers?.contextstream?.env;
1915
2222
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -1925,15 +2232,15 @@ function loadApiConfig(startDir) {
1925
2232
  return { apiUrl, apiKey };
1926
2233
  }
1927
2234
  function shouldIndexFile(filePath) {
1928
- const ext = path5.extname(filePath).toLowerCase();
2235
+ const ext = path6.extname(filePath).toLowerCase();
1929
2236
  if (!INDEXABLE_EXTENSIONS.has(ext)) {
1930
- const basename2 = path5.basename(filePath).toLowerCase();
2237
+ const basename2 = path6.basename(filePath).toLowerCase();
1931
2238
  if (!["dockerfile", "makefile", "rakefile", "gemfile", "procfile"].includes(basename2)) {
1932
2239
  return false;
1933
2240
  }
1934
2241
  }
1935
2242
  try {
1936
- const stats = fs5.statSync(filePath);
2243
+ const stats = fs6.statSync(filePath);
1937
2244
  if (stats.size > MAX_FILE_SIZE) {
1938
2245
  return false;
1939
2246
  }
@@ -1943,7 +2250,7 @@ function shouldIndexFile(filePath) {
1943
2250
  return true;
1944
2251
  }
1945
2252
  function detectLanguage(filePath) {
1946
- const ext = path5.extname(filePath).toLowerCase();
2253
+ const ext = path6.extname(filePath).toLowerCase();
1947
2254
  const langMap = {
1948
2255
  ".ts": "typescript",
1949
2256
  ".tsx": "typescript",
@@ -2012,8 +2319,8 @@ function detectLanguage(filePath) {
2012
2319
  return langMap[ext] || "text";
2013
2320
  }
2014
2321
  async function indexFile(filePath, projectId, apiUrl, apiKey, projectRoot) {
2015
- const content = fs5.readFileSync(filePath, "utf-8");
2016
- const relativePath = path5.relative(projectRoot, filePath);
2322
+ const content = fs6.readFileSync(filePath, "utf-8");
2323
+ const relativePath = path6.relative(projectRoot, filePath);
2017
2324
  const payload = {
2018
2325
  files: [
2019
2326
  {
@@ -2045,13 +2352,13 @@ async function indexFile(filePath, projectId, apiUrl, apiKey, projectRoot) {
2045
2352
  }
2046
2353
  }
2047
2354
  function findProjectRoot(filePath) {
2048
- let currentDir = path5.dirname(path5.resolve(filePath));
2355
+ let currentDir = path6.dirname(path6.resolve(filePath));
2049
2356
  for (let i = 0; i < 10; i++) {
2050
- const configPath = path5.join(currentDir, ".contextstream", "config.json");
2051
- if (fs5.existsSync(configPath)) {
2357
+ const configPath = path6.join(currentDir, ".contextstream", "config.json");
2358
+ if (fs6.existsSync(configPath)) {
2052
2359
  return currentDir;
2053
2360
  }
2054
- const parentDir = path5.dirname(currentDir);
2361
+ const parentDir = path6.dirname(currentDir);
2055
2362
  if (parentDir === currentDir) break;
2056
2363
  currentDir = parentDir;
2057
2364
  }
@@ -2079,8 +2386,8 @@ async function runPostWriteHook() {
2079
2386
  process.exit(0);
2080
2387
  }
2081
2388
  const cwd = extractCwd2(input);
2082
- const absolutePath = path5.isAbsolute(filePath) ? filePath : path5.resolve(cwd, filePath);
2083
- if (!fs5.existsSync(absolutePath) || !shouldIndexFile(absolutePath)) {
2389
+ const absolutePath = path6.isAbsolute(filePath) ? filePath : path6.resolve(cwd, filePath);
2390
+ if (!fs6.existsSync(absolutePath) || !shouldIndexFile(absolutePath)) {
2084
2391
  process.exit(0);
2085
2392
  }
2086
2393
  const projectRoot = findProjectRoot(absolutePath);
@@ -2175,7 +2482,7 @@ var init_post_write = __esm({
2175
2482
  ".prisma",
2176
2483
  ".proto"
2177
2484
  ]);
2178
- MAX_FILE_SIZE = 1024 * 1024;
2485
+ MAX_FILE_SIZE = 5 * 1024 * 1024;
2179
2486
  isDirectRun6 = process.argv[1]?.includes("post-write") || process.argv[2] === "post-write";
2180
2487
  if (isDirectRun6) {
2181
2488
  runPostWriteHook().catch(() => process.exit(0));
@@ -2480,7 +2787,7 @@ var require_ignore = __commonJS({
2480
2787
  // path matching.
2481
2788
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
2482
2789
  // @returns {TestResult} true if a file is ignored
2483
- test(path16, checkUnignored, mode) {
2790
+ test(path17, checkUnignored, mode) {
2484
2791
  let ignored = false;
2485
2792
  let unignored = false;
2486
2793
  let matchedRule;
@@ -2489,7 +2796,7 @@ var require_ignore = __commonJS({
2489
2796
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
2490
2797
  return;
2491
2798
  }
2492
- const matched = rule[mode].test(path16);
2799
+ const matched = rule[mode].test(path17);
2493
2800
  if (!matched) {
2494
2801
  return;
2495
2802
  }
@@ -2510,17 +2817,17 @@ var require_ignore = __commonJS({
2510
2817
  var throwError = (message, Ctor) => {
2511
2818
  throw new Ctor(message);
2512
2819
  };
2513
- var checkPath = (path16, originalPath, doThrow) => {
2514
- if (!isString(path16)) {
2820
+ var checkPath = (path17, originalPath, doThrow) => {
2821
+ if (!isString(path17)) {
2515
2822
  return doThrow(
2516
2823
  `path must be a string, but got \`${originalPath}\``,
2517
2824
  TypeError
2518
2825
  );
2519
2826
  }
2520
- if (!path16) {
2827
+ if (!path17) {
2521
2828
  return doThrow(`path must not be empty`, TypeError);
2522
2829
  }
2523
- if (checkPath.isNotRelative(path16)) {
2830
+ if (checkPath.isNotRelative(path17)) {
2524
2831
  const r = "`path.relative()`d";
2525
2832
  return doThrow(
2526
2833
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -2529,7 +2836,7 @@ var require_ignore = __commonJS({
2529
2836
  }
2530
2837
  return true;
2531
2838
  };
2532
- var isNotRelative = (path16) => REGEX_TEST_INVALID_PATH.test(path16);
2839
+ var isNotRelative = (path17) => REGEX_TEST_INVALID_PATH.test(path17);
2533
2840
  checkPath.isNotRelative = isNotRelative;
2534
2841
  checkPath.convert = (p) => p;
2535
2842
  var Ignore2 = class {
@@ -2559,19 +2866,19 @@ var require_ignore = __commonJS({
2559
2866
  }
2560
2867
  // @returns {TestResult}
2561
2868
  _test(originalPath, cache, checkUnignored, slices) {
2562
- const path16 = originalPath && checkPath.convert(originalPath);
2869
+ const path17 = originalPath && checkPath.convert(originalPath);
2563
2870
  checkPath(
2564
- path16,
2871
+ path17,
2565
2872
  originalPath,
2566
2873
  this._strictPathCheck ? throwError : RETURN_FALSE
2567
2874
  );
2568
- return this._t(path16, cache, checkUnignored, slices);
2875
+ return this._t(path17, cache, checkUnignored, slices);
2569
2876
  }
2570
- checkIgnore(path16) {
2571
- if (!REGEX_TEST_TRAILING_SLASH.test(path16)) {
2572
- return this.test(path16);
2877
+ checkIgnore(path17) {
2878
+ if (!REGEX_TEST_TRAILING_SLASH.test(path17)) {
2879
+ return this.test(path17);
2573
2880
  }
2574
- const slices = path16.split(SLASH).filter(Boolean);
2881
+ const slices = path17.split(SLASH).filter(Boolean);
2575
2882
  slices.pop();
2576
2883
  if (slices.length) {
2577
2884
  const parent = this._t(
@@ -2584,18 +2891,18 @@ var require_ignore = __commonJS({
2584
2891
  return parent;
2585
2892
  }
2586
2893
  }
2587
- return this._rules.test(path16, false, MODE_CHECK_IGNORE);
2894
+ return this._rules.test(path17, false, MODE_CHECK_IGNORE);
2588
2895
  }
2589
- _t(path16, cache, checkUnignored, slices) {
2590
- if (path16 in cache) {
2591
- return cache[path16];
2896
+ _t(path17, cache, checkUnignored, slices) {
2897
+ if (path17 in cache) {
2898
+ return cache[path17];
2592
2899
  }
2593
2900
  if (!slices) {
2594
- slices = path16.split(SLASH).filter(Boolean);
2901
+ slices = path17.split(SLASH).filter(Boolean);
2595
2902
  }
2596
2903
  slices.pop();
2597
2904
  if (!slices.length) {
2598
- return cache[path16] = this._rules.test(path16, checkUnignored, MODE_IGNORE);
2905
+ return cache[path17] = this._rules.test(path17, checkUnignored, MODE_IGNORE);
2599
2906
  }
2600
2907
  const parent = this._t(
2601
2908
  slices.join(SLASH) + SLASH,
@@ -2603,29 +2910,29 @@ var require_ignore = __commonJS({
2603
2910
  checkUnignored,
2604
2911
  slices
2605
2912
  );
2606
- return cache[path16] = parent.ignored ? parent : this._rules.test(path16, checkUnignored, MODE_IGNORE);
2913
+ return cache[path17] = parent.ignored ? parent : this._rules.test(path17, checkUnignored, MODE_IGNORE);
2607
2914
  }
2608
- ignores(path16) {
2609
- return this._test(path16, this._ignoreCache, false).ignored;
2915
+ ignores(path17) {
2916
+ return this._test(path17, this._ignoreCache, false).ignored;
2610
2917
  }
2611
2918
  createFilter() {
2612
- return (path16) => !this.ignores(path16);
2919
+ return (path17) => !this.ignores(path17);
2613
2920
  }
2614
2921
  filter(paths) {
2615
2922
  return makeArray(paths).filter(this.createFilter());
2616
2923
  }
2617
2924
  // @returns {TestResult}
2618
- test(path16) {
2619
- return this._test(path16, this._testCache, true);
2925
+ test(path17) {
2926
+ return this._test(path17, this._testCache, true);
2620
2927
  }
2621
2928
  };
2622
2929
  var factory = (options) => new Ignore2(options);
2623
- var isPathValid = (path16) => checkPath(path16 && checkPath.convert(path16), path16, RETURN_FALSE);
2930
+ var isPathValid = (path17) => checkPath(path17 && checkPath.convert(path17), path17, RETURN_FALSE);
2624
2931
  var setupWindows = () => {
2625
2932
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
2626
2933
  checkPath.convert = makePosix;
2627
2934
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
2628
- checkPath.isNotRelative = (path16) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path16) || isNotRelative(path16);
2935
+ checkPath.isNotRelative = (path17) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path17) || isNotRelative(path17);
2629
2936
  };
2630
2937
  if (
2631
2938
  // Detect `process` so that it can run in browsers.
@@ -2641,16 +2948,16 @@ var require_ignore = __commonJS({
2641
2948
  });
2642
2949
 
2643
2950
  // src/ignore.ts
2644
- import * as fs6 from "fs";
2645
- import * as path6 from "path";
2951
+ import * as fs7 from "fs";
2952
+ import * as path7 from "path";
2646
2953
  async function loadIgnorePatterns(projectRoot) {
2647
2954
  const ig = (0, import_ignore.default)();
2648
2955
  const patterns = [...DEFAULT_IGNORE_PATTERNS];
2649
2956
  ig.add(DEFAULT_IGNORE_PATTERNS);
2650
- const ignoreFilePath = path6.join(projectRoot, IGNORE_FILENAME);
2957
+ const ignoreFilePath = path7.join(projectRoot, IGNORE_FILENAME);
2651
2958
  let hasUserPatterns = false;
2652
2959
  try {
2653
- const content = await fs6.promises.readFile(ignoreFilePath, "utf-8");
2960
+ const content = await fs7.promises.readFile(ignoreFilePath, "utf-8");
2654
2961
  const userPatterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
2655
2962
  if (userPatterns.length > 0) {
2656
2963
  ig.add(userPatterns);
@@ -2731,8 +3038,8 @@ __export(files_exports, {
2731
3038
  sha256Hex: () => sha256Hex,
2732
3039
  writeHashManifest: () => writeHashManifest
2733
3040
  });
2734
- import * as fs7 from "fs";
2735
- import * as path7 from "path";
3041
+ import * as fs8 from "fs";
3042
+ import * as path8 from "path";
2736
3043
  import { exec } from "child_process";
2737
3044
  import { promisify } from "util";
2738
3045
  import * as os from "os";
@@ -2852,14 +3159,14 @@ async function readFilesFromDirectory(rootPath, options = {}) {
2852
3159
  if (files.length >= maxFiles) return;
2853
3160
  let entries;
2854
3161
  try {
2855
- entries = await fs7.promises.readdir(dir, { withFileTypes: true });
3162
+ entries = await fs8.promises.readdir(dir, { withFileTypes: true });
2856
3163
  } catch {
2857
3164
  return;
2858
3165
  }
2859
3166
  for (const entry of entries) {
2860
3167
  if (files.length >= maxFiles) break;
2861
- const fullPath = path7.join(dir, entry.name);
2862
- const relPath = path7.join(relativePath, entry.name);
3168
+ const fullPath = path8.join(dir, entry.name);
3169
+ const relPath = path8.join(relativePath, entry.name);
2863
3170
  if (entry.isDirectory()) {
2864
3171
  if (IGNORE_DIRS.has(entry.name)) continue;
2865
3172
  if (ig.ignores(relPath + "/")) continue;
@@ -2870,9 +3177,9 @@ async function readFilesFromDirectory(rootPath, options = {}) {
2870
3177
  const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
2871
3178
  if (!CODE_EXTENSIONS.has(ext)) continue;
2872
3179
  try {
2873
- const stat = await fs7.promises.stat(fullPath);
3180
+ const stat = await fs8.promises.stat(fullPath);
2874
3181
  if (stat.size > maxFileSize) continue;
2875
- const content = await fs7.promises.readFile(fullPath, "utf-8");
3182
+ const content = await fs8.promises.readFile(fullPath, "utf-8");
2876
3183
  const file = {
2877
3184
  path: relPath,
2878
3185
  content,
@@ -2911,13 +3218,13 @@ async function* readAllFilesInBatches(rootPath, options = {}) {
2911
3218
  async function* walkDir(dir, relativePath = "") {
2912
3219
  let entries;
2913
3220
  try {
2914
- entries = await fs7.promises.readdir(dir, { withFileTypes: true });
3221
+ entries = await fs8.promises.readdir(dir, { withFileTypes: true });
2915
3222
  } catch {
2916
3223
  return;
2917
3224
  }
2918
3225
  for (const entry of entries) {
2919
- const fullPath = path7.join(dir, entry.name);
2920
- const relPath = path7.join(relativePath, entry.name);
3226
+ const fullPath = path8.join(dir, entry.name);
3227
+ const relPath = path8.join(relativePath, entry.name);
2921
3228
  if (entry.isDirectory()) {
2922
3229
  if (IGNORE_DIRS.has(entry.name)) continue;
2923
3230
  if (ig.ignores(relPath + "/")) continue;
@@ -2928,9 +3235,9 @@ async function* readAllFilesInBatches(rootPath, options = {}) {
2928
3235
  const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
2929
3236
  if (!CODE_EXTENSIONS.has(ext)) continue;
2930
3237
  try {
2931
- const stat = await fs7.promises.stat(fullPath);
3238
+ const stat = await fs8.promises.stat(fullPath);
2932
3239
  if (stat.size > maxFileSize) continue;
2933
- const content = await fs7.promises.readFile(fullPath, "utf-8");
3240
+ const content = await fs8.promises.readFile(fullPath, "utf-8");
2934
3241
  const file = {
2935
3242
  path: relPath,
2936
3243
  content,
@@ -2997,13 +3304,13 @@ async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}
2997
3304
  async function* walkDir(dir, relativePath = "") {
2998
3305
  let entries;
2999
3306
  try {
3000
- entries = await fs7.promises.readdir(dir, { withFileTypes: true });
3307
+ entries = await fs8.promises.readdir(dir, { withFileTypes: true });
3001
3308
  } catch {
3002
3309
  return;
3003
3310
  }
3004
3311
  for (const entry of entries) {
3005
- const fullPath = path7.join(dir, entry.name);
3006
- const relPath = path7.join(relativePath, entry.name);
3312
+ const fullPath = path8.join(dir, entry.name);
3313
+ const relPath = path8.join(relativePath, entry.name);
3007
3314
  if (entry.isDirectory()) {
3008
3315
  if (IGNORE_DIRS.has(entry.name)) continue;
3009
3316
  if (ig.ignores(relPath + "/")) continue;
@@ -3014,11 +3321,11 @@ async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}
3014
3321
  const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
3015
3322
  if (!CODE_EXTENSIONS.has(ext)) continue;
3016
3323
  try {
3017
- const stat = await fs7.promises.stat(fullPath);
3324
+ const stat = await fs8.promises.stat(fullPath);
3018
3325
  filesScanned++;
3019
3326
  if (stat.mtimeMs <= sinceMs) continue;
3020
3327
  if (stat.size > maxFileSize) continue;
3021
- const content = await fs7.promises.readFile(fullPath, "utf-8");
3328
+ const content = await fs8.promises.readFile(fullPath, "utf-8");
3022
3329
  filesChanged++;
3023
3330
  const file = {
3024
3331
  path: relPath,
@@ -3087,7 +3394,7 @@ async function countIndexableFiles(rootPath, options = {}) {
3087
3394
  }
3088
3395
  let entries;
3089
3396
  try {
3090
- entries = await fs7.promises.readdir(dir, { withFileTypes: true });
3397
+ entries = await fs8.promises.readdir(dir, { withFileTypes: true });
3091
3398
  } catch {
3092
3399
  return;
3093
3400
  }
@@ -3096,8 +3403,8 @@ async function countIndexableFiles(rootPath, options = {}) {
3096
3403
  stopped = true;
3097
3404
  return;
3098
3405
  }
3099
- const fullPath = path7.join(dir, entry.name);
3100
- const relPath = path7.join(relativePath, entry.name);
3406
+ const fullPath = path8.join(dir, entry.name);
3407
+ const relPath = path8.join(relativePath, entry.name);
3101
3408
  if (entry.isDirectory()) {
3102
3409
  if (IGNORE_DIRS.has(entry.name)) continue;
3103
3410
  if (ig.ignores(relPath + "/")) continue;
@@ -3108,7 +3415,7 @@ async function countIndexableFiles(rootPath, options = {}) {
3108
3415
  const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
3109
3416
  if (!CODE_EXTENSIONS.has(ext)) continue;
3110
3417
  try {
3111
- const stat = await fs7.promises.stat(fullPath);
3418
+ const stat = await fs8.promises.stat(fullPath);
3112
3419
  if (stat.size > maxFileSize) continue;
3113
3420
  count++;
3114
3421
  if (count >= maxFiles) {
@@ -3160,11 +3467,11 @@ function sha256Hex(content) {
3160
3467
  return crypto.createHash("sha256").update(content).digest("hex");
3161
3468
  }
3162
3469
  function hashManifestPath(projectId) {
3163
- return path7.join(os.homedir(), ".contextstream", "file-hashes", `${projectId}.json`);
3470
+ return path8.join(os.homedir(), ".contextstream", "file-hashes", `${projectId}.json`);
3164
3471
  }
3165
3472
  function readHashManifest(projectId) {
3166
3473
  try {
3167
- const content = fs7.readFileSync(hashManifestPath(projectId), "utf-8");
3474
+ const content = fs8.readFileSync(hashManifestPath(projectId), "utf-8");
3168
3475
  const parsed = JSON.parse(content);
3169
3476
  return new Map(Object.entries(parsed));
3170
3477
  } catch {
@@ -3174,16 +3481,16 @@ function readHashManifest(projectId) {
3174
3481
  function writeHashManifest(projectId, hashes) {
3175
3482
  const filePath = hashManifestPath(projectId);
3176
3483
  try {
3177
- const dir = path7.dirname(filePath);
3178
- fs7.mkdirSync(dir, { recursive: true });
3484
+ const dir = path8.dirname(filePath);
3485
+ fs8.mkdirSync(dir, { recursive: true });
3179
3486
  const obj = Object.fromEntries(hashes);
3180
- fs7.writeFileSync(filePath, JSON.stringify(obj, null, 2));
3487
+ fs8.writeFileSync(filePath, JSON.stringify(obj, null, 2));
3181
3488
  } catch {
3182
3489
  }
3183
3490
  }
3184
3491
  function deleteHashManifest(projectId) {
3185
3492
  try {
3186
- fs7.unlinkSync(hashManifestPath(projectId));
3493
+ fs8.unlinkSync(hashManifestPath(projectId));
3187
3494
  } catch {
3188
3495
  }
3189
3496
  }
@@ -3296,7 +3603,7 @@ var init_files = __esm({
3296
3603
  "Gemfile.lock",
3297
3604
  "composer.lock"
3298
3605
  ]);
3299
- MAX_FILE_SIZE2 = 1024 * 1024;
3606
+ MAX_FILE_SIZE2 = 5 * 1024 * 1024;
3300
3607
  MAX_BATCH_BYTES = 10 * 1024 * 1024;
3301
3608
  LARGE_FILE_THRESHOLD = 2 * 1024 * 1024;
3302
3609
  MAX_FILES_PER_BATCH = 200;
@@ -3347,17 +3654,17 @@ __export(hooks_config_exports, {
3347
3654
  writeCursorHooksConfig: () => writeCursorHooksConfig,
3348
3655
  writeIndexStatus: () => writeIndexStatus
3349
3656
  });
3350
- import * as fs8 from "node:fs/promises";
3657
+ import * as fs9 from "node:fs/promises";
3351
3658
  import * as fsSync from "node:fs";
3352
- import * as path8 from "node:path";
3353
- import { homedir as homedir8 } from "node:os";
3659
+ import * as path9 from "node:path";
3660
+ import { homedir as homedir9 } from "node:os";
3354
3661
  import { fileURLToPath } from "node:url";
3355
3662
  function getHookCommand(hookName2) {
3356
3663
  const isWindows = process.platform === "win32";
3357
3664
  if (isWindows) {
3358
3665
  const localAppData = process.env.LOCALAPPDATA;
3359
3666
  if (localAppData) {
3360
- const windowsBinaryPath = path8.join(localAppData, "ContextStream", "contextstream-mcp.exe");
3667
+ const windowsBinaryPath = path9.join(localAppData, "ContextStream", "contextstream-mcp.exe");
3361
3668
  if (fsSync.existsSync(windowsBinaryPath)) {
3362
3669
  return `"${windowsBinaryPath}" hook ${hookName2}`;
3363
3670
  }
@@ -3369,8 +3676,8 @@ function getHookCommand(hookName2) {
3369
3676
  }
3370
3677
  }
3371
3678
  try {
3372
- const __dirname = path8.dirname(fileURLToPath(import.meta.url));
3373
- const indexPath = path8.join(__dirname, "index.js");
3679
+ const __dirname = path9.dirname(fileURLToPath(import.meta.url));
3680
+ const indexPath = path9.join(__dirname, "index.js");
3374
3681
  if (fsSync.existsSync(indexPath)) {
3375
3682
  return `node "${indexPath}" hook ${hookName2}`;
3376
3683
  }
@@ -3380,15 +3687,15 @@ function getHookCommand(hookName2) {
3380
3687
  }
3381
3688
  function getClaudeSettingsPath(scope, projectPath) {
3382
3689
  if (scope === "user") {
3383
- return path8.join(homedir8(), ".claude", "settings.json");
3690
+ return path9.join(homedir9(), ".claude", "settings.json");
3384
3691
  }
3385
3692
  if (!projectPath) {
3386
3693
  throw new Error("projectPath required for project scope");
3387
3694
  }
3388
- return path8.join(projectPath, ".claude", "settings.json");
3695
+ return path9.join(projectPath, ".claude", "settings.json");
3389
3696
  }
3390
3697
  function getHooksDir() {
3391
- return path8.join(homedir8(), ".claude", "hooks");
3698
+ return path9.join(homedir9(), ".claude", "hooks");
3392
3699
  }
3393
3700
  function buildHooksConfig(options) {
3394
3701
  const userPromptHooks = [
@@ -3564,7 +3871,7 @@ function buildHooksConfig(options) {
3564
3871
  }
3565
3872
  async function installHookScripts(options) {
3566
3873
  const hooksDir = getHooksDir();
3567
- await fs8.mkdir(hooksDir, { recursive: true });
3874
+ await fs9.mkdir(hooksDir, { recursive: true });
3568
3875
  const result = {
3569
3876
  preToolUse: getHookCommand("pre-tool-use"),
3570
3877
  userPrompt: getHookCommand("user-prompt-submit")
@@ -3583,7 +3890,7 @@ async function installHookScripts(options) {
3583
3890
  async function readClaudeSettings(scope, projectPath) {
3584
3891
  const settingsPath = getClaudeSettingsPath(scope, projectPath);
3585
3892
  try {
3586
- const content = await fs8.readFile(settingsPath, "utf-8");
3893
+ const content = await fs9.readFile(settingsPath, "utf-8");
3587
3894
  return JSON.parse(content);
3588
3895
  } catch {
3589
3896
  return {};
@@ -3591,9 +3898,9 @@ async function readClaudeSettings(scope, projectPath) {
3591
3898
  }
3592
3899
  async function writeClaudeSettings(settings, scope, projectPath) {
3593
3900
  const settingsPath = getClaudeSettingsPath(scope, projectPath);
3594
- const dir = path8.dirname(settingsPath);
3595
- await fs8.mkdir(dir, { recursive: true });
3596
- await fs8.writeFile(settingsPath, JSON.stringify(settings, null, 2));
3901
+ const dir = path9.dirname(settingsPath);
3902
+ await fs9.mkdir(dir, { recursive: true });
3903
+ await fs9.writeFile(settingsPath, JSON.stringify(settings, null, 2));
3597
3904
  }
3598
3905
  function mergeHooksIntoSettings(existingSettings, newHooks) {
3599
3906
  const settings = { ...existingSettings };
@@ -3743,12 +4050,12 @@ If you prefer to configure manually, add to \`~/.claude/settings.json\`:
3743
4050
  `.trim();
3744
4051
  }
3745
4052
  function getIndexStatusPath() {
3746
- return path8.join(homedir8(), ".contextstream", "indexed-projects.json");
4053
+ return path9.join(homedir9(), ".contextstream", "indexed-projects.json");
3747
4054
  }
3748
4055
  async function readIndexStatus() {
3749
4056
  const statusPath = getIndexStatusPath();
3750
4057
  try {
3751
- const content = await fs8.readFile(statusPath, "utf-8");
4058
+ const content = await fs9.readFile(statusPath, "utf-8");
3752
4059
  return JSON.parse(content);
3753
4060
  } catch {
3754
4061
  return { version: 1, projects: {} };
@@ -3756,13 +4063,13 @@ async function readIndexStatus() {
3756
4063
  }
3757
4064
  async function writeIndexStatus(status) {
3758
4065
  const statusPath = getIndexStatusPath();
3759
- const dir = path8.dirname(statusPath);
3760
- await fs8.mkdir(dir, { recursive: true });
3761
- await fs8.writeFile(statusPath, JSON.stringify(status, null, 2));
4066
+ const dir = path9.dirname(statusPath);
4067
+ await fs9.mkdir(dir, { recursive: true });
4068
+ await fs9.writeFile(statusPath, JSON.stringify(status, null, 2));
3762
4069
  }
3763
4070
  async function markProjectIndexed(projectPath, options) {
3764
4071
  const status = await readIndexStatus();
3765
- const resolvedPath = path8.resolve(projectPath);
4072
+ const resolvedPath = path9.resolve(projectPath);
3766
4073
  status.projects[resolvedPath] = {
3767
4074
  indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
3768
4075
  project_id: options?.project_id,
@@ -3772,7 +4079,7 @@ async function markProjectIndexed(projectPath, options) {
3772
4079
  }
3773
4080
  async function unmarkProjectIndexed(projectPath) {
3774
4081
  const status = await readIndexStatus();
3775
- const resolvedPath = path8.resolve(projectPath);
4082
+ const resolvedPath = path9.resolve(projectPath);
3776
4083
  delete status.projects[resolvedPath];
3777
4084
  await writeIndexStatus(status);
3778
4085
  }
@@ -3785,12 +4092,12 @@ async function clearProjectIndex(projectPath, projectId) {
3785
4092
  }
3786
4093
  function getClineHooksDir(scope, projectPath) {
3787
4094
  if (scope === "global") {
3788
- return path8.join(homedir8(), "Documents", "Cline", "Rules", "Hooks");
4095
+ return path9.join(homedir9(), "Documents", "Cline", "Rules", "Hooks");
3789
4096
  }
3790
4097
  if (!projectPath) {
3791
4098
  throw new Error("projectPath required for project scope");
3792
4099
  }
3793
- return path8.join(projectPath, ".clinerules", "hooks");
4100
+ return path9.join(projectPath, ".clinerules", "hooks");
3794
4101
  }
3795
4102
  function getHookWrapperScript(hookName2) {
3796
4103
  const isWindows = process.platform === "win32";
@@ -3814,107 +4121,107 @@ exec ${command}
3814
4121
  }
3815
4122
  async function installClineHookScripts(options) {
3816
4123
  const hooksDir = getClineHooksDir(options.scope, options.projectPath);
3817
- await fs8.mkdir(hooksDir, { recursive: true });
4124
+ await fs9.mkdir(hooksDir, { recursive: true });
3818
4125
  const preToolUseWrapper = getHookWrapperScript("pre-tool-use");
3819
4126
  const userPromptWrapper = getHookWrapperScript("user-prompt-submit");
3820
4127
  const postWriteWrapper = getHookWrapperScript("post-write");
3821
- const preToolUsePath = path8.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
3822
- const userPromptPath = path8.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
3823
- const postToolUsePath = path8.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
3824
- await fs8.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
3825
- await fs8.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
4128
+ const preToolUsePath = path9.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
4129
+ const userPromptPath = path9.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
4130
+ const postToolUsePath = path9.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
4131
+ await fs9.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
4132
+ await fs9.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
3826
4133
  const result = {
3827
4134
  preToolUse: preToolUsePath,
3828
4135
  userPromptSubmit: userPromptPath
3829
4136
  };
3830
4137
  if (options.includePostWrite !== false) {
3831
- await fs8.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
4138
+ await fs9.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
3832
4139
  result.postToolUse = postToolUsePath;
3833
4140
  }
3834
4141
  return result;
3835
4142
  }
3836
4143
  function getRooCodeHooksDir(scope, projectPath) {
3837
4144
  if (scope === "global") {
3838
- return path8.join(homedir8(), ".roo", "hooks");
4145
+ return path9.join(homedir9(), ".roo", "hooks");
3839
4146
  }
3840
4147
  if (!projectPath) {
3841
4148
  throw new Error("projectPath required for project scope");
3842
4149
  }
3843
- return path8.join(projectPath, ".roo", "hooks");
4150
+ return path9.join(projectPath, ".roo", "hooks");
3844
4151
  }
3845
4152
  async function installRooCodeHookScripts(options) {
3846
4153
  const hooksDir = getRooCodeHooksDir(options.scope, options.projectPath);
3847
- await fs8.mkdir(hooksDir, { recursive: true });
4154
+ await fs9.mkdir(hooksDir, { recursive: true });
3848
4155
  const preToolUseWrapper = getHookWrapperScript("pre-tool-use");
3849
4156
  const userPromptWrapper = getHookWrapperScript("user-prompt-submit");
3850
4157
  const postWriteWrapper = getHookWrapperScript("post-write");
3851
- const preToolUsePath = path8.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
3852
- const userPromptPath = path8.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
3853
- const postToolUsePath = path8.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
3854
- await fs8.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
3855
- await fs8.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
4158
+ const preToolUsePath = path9.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
4159
+ const userPromptPath = path9.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
4160
+ const postToolUsePath = path9.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
4161
+ await fs9.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
4162
+ await fs9.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
3856
4163
  const result = {
3857
4164
  preToolUse: preToolUsePath,
3858
4165
  userPromptSubmit: userPromptPath
3859
4166
  };
3860
4167
  if (options.includePostWrite !== false) {
3861
- await fs8.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
4168
+ await fs9.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
3862
4169
  result.postToolUse = postToolUsePath;
3863
4170
  }
3864
4171
  return result;
3865
4172
  }
3866
4173
  function getKiloCodeHooksDir(scope, projectPath) {
3867
4174
  if (scope === "global") {
3868
- return path8.join(homedir8(), ".kilocode", "hooks");
4175
+ return path9.join(homedir9(), ".kilocode", "hooks");
3869
4176
  }
3870
4177
  if (!projectPath) {
3871
4178
  throw new Error("projectPath required for project scope");
3872
4179
  }
3873
- return path8.join(projectPath, ".kilocode", "hooks");
4180
+ return path9.join(projectPath, ".kilocode", "hooks");
3874
4181
  }
3875
4182
  async function installKiloCodeHookScripts(options) {
3876
4183
  const hooksDir = getKiloCodeHooksDir(options.scope, options.projectPath);
3877
- await fs8.mkdir(hooksDir, { recursive: true });
4184
+ await fs9.mkdir(hooksDir, { recursive: true });
3878
4185
  const preToolUseWrapper = getHookWrapperScript("pre-tool-use");
3879
4186
  const userPromptWrapper = getHookWrapperScript("user-prompt-submit");
3880
4187
  const postWriteWrapper = getHookWrapperScript("post-write");
3881
- const preToolUsePath = path8.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
3882
- const userPromptPath = path8.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
3883
- const postToolUsePath = path8.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
3884
- await fs8.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
3885
- await fs8.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
4188
+ const preToolUsePath = path9.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
4189
+ const userPromptPath = path9.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
4190
+ const postToolUsePath = path9.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
4191
+ await fs9.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
4192
+ await fs9.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
3886
4193
  const result = {
3887
4194
  preToolUse: preToolUsePath,
3888
4195
  userPromptSubmit: userPromptPath
3889
4196
  };
3890
4197
  if (options.includePostWrite !== false) {
3891
- await fs8.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
4198
+ await fs9.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
3892
4199
  result.postToolUse = postToolUsePath;
3893
4200
  }
3894
4201
  return result;
3895
4202
  }
3896
4203
  function getCursorHooksConfigPath(scope, projectPath) {
3897
4204
  if (scope === "global") {
3898
- return path8.join(homedir8(), ".cursor", "hooks.json");
4205
+ return path9.join(homedir9(), ".cursor", "hooks.json");
3899
4206
  }
3900
4207
  if (!projectPath) {
3901
4208
  throw new Error("projectPath required for project scope");
3902
4209
  }
3903
- return path8.join(projectPath, ".cursor", "hooks.json");
4210
+ return path9.join(projectPath, ".cursor", "hooks.json");
3904
4211
  }
3905
4212
  function getCursorHooksDir(scope, projectPath) {
3906
4213
  if (scope === "global") {
3907
- return path8.join(homedir8(), ".cursor", "hooks");
4214
+ return path9.join(homedir9(), ".cursor", "hooks");
3908
4215
  }
3909
4216
  if (!projectPath) {
3910
4217
  throw new Error("projectPath required for project scope");
3911
4218
  }
3912
- return path8.join(projectPath, ".cursor", "hooks");
4219
+ return path9.join(projectPath, ".cursor", "hooks");
3913
4220
  }
3914
4221
  async function readCursorHooksConfig(scope, projectPath) {
3915
4222
  const configPath = getCursorHooksConfigPath(scope, projectPath);
3916
4223
  try {
3917
- const content = await fs8.readFile(configPath, "utf-8");
4224
+ const content = await fs9.readFile(configPath, "utf-8");
3918
4225
  return JSON.parse(content);
3919
4226
  } catch {
3920
4227
  return { version: 1, hooks: {} };
@@ -3922,13 +4229,13 @@ async function readCursorHooksConfig(scope, projectPath) {
3922
4229
  }
3923
4230
  async function writeCursorHooksConfig(config, scope, projectPath) {
3924
4231
  const configPath = getCursorHooksConfigPath(scope, projectPath);
3925
- const dir = path8.dirname(configPath);
3926
- await fs8.mkdir(dir, { recursive: true });
3927
- await fs8.writeFile(configPath, JSON.stringify(config, null, 2));
4232
+ const dir = path9.dirname(configPath);
4233
+ await fs9.mkdir(dir, { recursive: true });
4234
+ await fs9.writeFile(configPath, JSON.stringify(config, null, 2));
3928
4235
  }
3929
4236
  async function installCursorHookScripts(options) {
3930
4237
  const hooksDir = getCursorHooksDir(options.scope, options.projectPath);
3931
- await fs8.mkdir(hooksDir, { recursive: true });
4238
+ await fs9.mkdir(hooksDir, { recursive: true });
3932
4239
  const existingConfig = await readCursorHooksConfig(options.scope, options.projectPath);
3933
4240
  const filterContextStreamHooks = (hooks2) => {
3934
4241
  if (!hooks2) return [];
@@ -4944,13 +5251,13 @@ var auto_rules_exports = {};
4944
5251
  __export(auto_rules_exports, {
4945
5252
  runAutoRulesHook: () => runAutoRulesHook
4946
5253
  });
4947
- import * as fs9 from "node:fs";
4948
- import * as path9 from "node:path";
4949
- import { homedir as homedir9 } from "node:os";
5254
+ import * as fs10 from "node:fs";
5255
+ import * as path10 from "node:path";
5256
+ import { homedir as homedir10 } from "node:os";
4950
5257
  function hasRunRecently() {
4951
5258
  try {
4952
- if (!fs9.existsSync(MARKER_FILE)) return false;
4953
- const stat = fs9.statSync(MARKER_FILE);
5259
+ if (!fs10.existsSync(MARKER_FILE)) return false;
5260
+ const stat = fs10.statSync(MARKER_FILE);
4954
5261
  const age = Date.now() - stat.mtimeMs;
4955
5262
  return age < COOLDOWN_MS;
4956
5263
  } catch {
@@ -4959,11 +5266,11 @@ function hasRunRecently() {
4959
5266
  }
4960
5267
  function markAsRan() {
4961
5268
  try {
4962
- const dir = path9.dirname(MARKER_FILE);
4963
- if (!fs9.existsSync(dir)) {
4964
- fs9.mkdirSync(dir, { recursive: true });
5269
+ const dir = path10.dirname(MARKER_FILE);
5270
+ if (!fs10.existsSync(dir)) {
5271
+ fs10.mkdirSync(dir, { recursive: true });
4965
5272
  }
4966
- fs9.writeFileSync(MARKER_FILE, (/* @__PURE__ */ new Date()).toISOString());
5273
+ fs10.writeFileSync(MARKER_FILE, (/* @__PURE__ */ new Date()).toISOString());
4967
5274
  } catch {
4968
5275
  }
4969
5276
  }
@@ -4992,8 +5299,8 @@ function extractCwd3(input) {
4992
5299
  }
4993
5300
  function hasPythonHooks(settingsPath) {
4994
5301
  try {
4995
- if (!fs9.existsSync(settingsPath)) return false;
4996
- const content = fs9.readFileSync(settingsPath, "utf-8");
5302
+ if (!fs10.existsSync(settingsPath)) return false;
5303
+ const content = fs10.readFileSync(settingsPath, "utf-8");
4997
5304
  const settings = JSON.parse(content);
4998
5305
  const hooks2 = settings.hooks;
4999
5306
  if (!hooks2) return false;
@@ -5017,8 +5324,8 @@ function hasPythonHooks(settingsPath) {
5017
5324
  }
5018
5325
  }
5019
5326
  function detectPythonHooks(cwd) {
5020
- const globalSettingsPath = path9.join(homedir9(), ".claude", "settings.json");
5021
- const projectSettingsPath = path9.join(cwd, ".claude", "settings.json");
5327
+ const globalSettingsPath = path10.join(homedir10(), ".claude", "settings.json");
5328
+ const projectSettingsPath = path10.join(cwd, ".claude", "settings.json");
5022
5329
  return {
5023
5330
  global: hasPythonHooks(globalSettingsPath),
5024
5331
  project: hasPythonHooks(projectSettingsPath)
@@ -5083,7 +5390,7 @@ var init_auto_rules = __esm({
5083
5390
  API_URL5 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
5084
5391
  API_KEY5 = process.env.CONTEXTSTREAM_API_KEY || "";
5085
5392
  ENABLED7 = process.env.CONTEXTSTREAM_AUTO_RULES !== "false";
5086
- MARKER_FILE = path9.join(homedir9(), ".contextstream", ".auto-rules-ran");
5393
+ MARKER_FILE = path10.join(homedir10(), ".contextstream", ".auto-rules-ran");
5087
5394
  COOLDOWN_MS = 4 * 60 * 60 * 1e3;
5088
5395
  isDirectRun7 = process.argv[1]?.includes("auto-rules") || process.argv[2] === "auto-rules";
5089
5396
  if (isDirectRun7) {
@@ -5097,17 +5404,17 @@ var on_bash_exports = {};
5097
5404
  __export(on_bash_exports, {
5098
5405
  runOnBashHook: () => runOnBashHook
5099
5406
  });
5100
- import * as fs10 from "node:fs";
5101
- import * as path10 from "node:path";
5102
- import { homedir as homedir10 } from "node:os";
5407
+ import * as fs11 from "node:fs";
5408
+ import * as path11 from "node:path";
5409
+ import { homedir as homedir11 } from "node:os";
5103
5410
  function loadConfigFromMcpJson4(cwd) {
5104
- let searchDir = path10.resolve(cwd);
5411
+ let searchDir = path11.resolve(cwd);
5105
5412
  for (let i = 0; i < 5; i++) {
5106
5413
  if (!API_KEY6) {
5107
- const mcpPath = path10.join(searchDir, ".mcp.json");
5108
- if (fs10.existsSync(mcpPath)) {
5414
+ const mcpPath = path11.join(searchDir, ".mcp.json");
5415
+ if (fs11.existsSync(mcpPath)) {
5109
5416
  try {
5110
- const content = fs10.readFileSync(mcpPath, "utf-8");
5417
+ const content = fs11.readFileSync(mcpPath, "utf-8");
5111
5418
  const config = JSON.parse(content);
5112
5419
  const csEnv = config.mcpServers?.contextstream?.env;
5113
5420
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5121,10 +5428,10 @@ function loadConfigFromMcpJson4(cwd) {
5121
5428
  }
5122
5429
  }
5123
5430
  if (!WORKSPACE_ID4) {
5124
- const csConfigPath = path10.join(searchDir, ".contextstream", "config.json");
5125
- if (fs10.existsSync(csConfigPath)) {
5431
+ const csConfigPath = path11.join(searchDir, ".contextstream", "config.json");
5432
+ if (fs11.existsSync(csConfigPath)) {
5126
5433
  try {
5127
- const content = fs10.readFileSync(csConfigPath, "utf-8");
5434
+ const content = fs11.readFileSync(csConfigPath, "utf-8");
5128
5435
  const csConfig = JSON.parse(content);
5129
5436
  if (csConfig.workspace_id) {
5130
5437
  WORKSPACE_ID4 = csConfig.workspace_id;
@@ -5133,15 +5440,15 @@ function loadConfigFromMcpJson4(cwd) {
5133
5440
  }
5134
5441
  }
5135
5442
  }
5136
- const parentDir = path10.dirname(searchDir);
5443
+ const parentDir = path11.dirname(searchDir);
5137
5444
  if (parentDir === searchDir) break;
5138
5445
  searchDir = parentDir;
5139
5446
  }
5140
5447
  if (!API_KEY6) {
5141
- const homeMcpPath = path10.join(homedir10(), ".mcp.json");
5142
- if (fs10.existsSync(homeMcpPath)) {
5448
+ const homeMcpPath = path11.join(homedir11(), ".mcp.json");
5449
+ if (fs11.existsSync(homeMcpPath)) {
5143
5450
  try {
5144
- const content = fs10.readFileSync(homeMcpPath, "utf-8");
5451
+ const content = fs11.readFileSync(homeMcpPath, "utf-8");
5145
5452
  const config = JSON.parse(content);
5146
5453
  const csEnv = config.mcpServers?.contextstream?.env;
5147
5454
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5293,17 +5600,17 @@ var on_task_exports = {};
5293
5600
  __export(on_task_exports, {
5294
5601
  runOnTaskHook: () => runOnTaskHook
5295
5602
  });
5296
- import * as fs11 from "node:fs";
5297
- import * as path11 from "node:path";
5298
- import { homedir as homedir11 } from "node:os";
5603
+ import * as fs12 from "node:fs";
5604
+ import * as path12 from "node:path";
5605
+ import { homedir as homedir12 } from "node:os";
5299
5606
  function loadConfigFromMcpJson5(cwd) {
5300
- let searchDir = path11.resolve(cwd);
5607
+ let searchDir = path12.resolve(cwd);
5301
5608
  for (let i = 0; i < 5; i++) {
5302
5609
  if (!API_KEY7) {
5303
- const mcpPath = path11.join(searchDir, ".mcp.json");
5304
- if (fs11.existsSync(mcpPath)) {
5610
+ const mcpPath = path12.join(searchDir, ".mcp.json");
5611
+ if (fs12.existsSync(mcpPath)) {
5305
5612
  try {
5306
- const content = fs11.readFileSync(mcpPath, "utf-8");
5613
+ const content = fs12.readFileSync(mcpPath, "utf-8");
5307
5614
  const config = JSON.parse(content);
5308
5615
  const csEnv = config.mcpServers?.contextstream?.env;
5309
5616
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5317,10 +5624,10 @@ function loadConfigFromMcpJson5(cwd) {
5317
5624
  }
5318
5625
  }
5319
5626
  if (!WORKSPACE_ID5) {
5320
- const csConfigPath = path11.join(searchDir, ".contextstream", "config.json");
5321
- if (fs11.existsSync(csConfigPath)) {
5627
+ const csConfigPath = path12.join(searchDir, ".contextstream", "config.json");
5628
+ if (fs12.existsSync(csConfigPath)) {
5322
5629
  try {
5323
- const content = fs11.readFileSync(csConfigPath, "utf-8");
5630
+ const content = fs12.readFileSync(csConfigPath, "utf-8");
5324
5631
  const csConfig = JSON.parse(content);
5325
5632
  if (csConfig.workspace_id) {
5326
5633
  WORKSPACE_ID5 = csConfig.workspace_id;
@@ -5329,15 +5636,15 @@ function loadConfigFromMcpJson5(cwd) {
5329
5636
  }
5330
5637
  }
5331
5638
  }
5332
- const parentDir = path11.dirname(searchDir);
5639
+ const parentDir = path12.dirname(searchDir);
5333
5640
  if (parentDir === searchDir) break;
5334
5641
  searchDir = parentDir;
5335
5642
  }
5336
5643
  if (!API_KEY7) {
5337
- const homeMcpPath = path11.join(homedir11(), ".mcp.json");
5338
- if (fs11.existsSync(homeMcpPath)) {
5644
+ const homeMcpPath = path12.join(homedir12(), ".mcp.json");
5645
+ if (fs12.existsSync(homeMcpPath)) {
5339
5646
  try {
5340
- const content = fs11.readFileSync(homeMcpPath, "utf-8");
5647
+ const content = fs12.readFileSync(homeMcpPath, "utf-8");
5341
5648
  const config = JSON.parse(content);
5342
5649
  const csEnv = config.mcpServers?.contextstream?.env;
5343
5650
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5438,17 +5745,17 @@ var on_read_exports = {};
5438
5745
  __export(on_read_exports, {
5439
5746
  runOnReadHook: () => runOnReadHook
5440
5747
  });
5441
- import * as fs12 from "node:fs";
5442
- import * as path12 from "node:path";
5443
- import { homedir as homedir12 } from "node:os";
5748
+ import * as fs13 from "node:fs";
5749
+ import * as path13 from "node:path";
5750
+ import { homedir as homedir13 } from "node:os";
5444
5751
  function loadConfigFromMcpJson6(cwd) {
5445
- let searchDir = path12.resolve(cwd);
5752
+ let searchDir = path13.resolve(cwd);
5446
5753
  for (let i = 0; i < 5; i++) {
5447
5754
  if (!API_KEY8) {
5448
- const mcpPath = path12.join(searchDir, ".mcp.json");
5449
- if (fs12.existsSync(mcpPath)) {
5755
+ const mcpPath = path13.join(searchDir, ".mcp.json");
5756
+ if (fs13.existsSync(mcpPath)) {
5450
5757
  try {
5451
- const content = fs12.readFileSync(mcpPath, "utf-8");
5758
+ const content = fs13.readFileSync(mcpPath, "utf-8");
5452
5759
  const config = JSON.parse(content);
5453
5760
  const csEnv = config.mcpServers?.contextstream?.env;
5454
5761
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5462,10 +5769,10 @@ function loadConfigFromMcpJson6(cwd) {
5462
5769
  }
5463
5770
  }
5464
5771
  if (!WORKSPACE_ID6) {
5465
- const csConfigPath = path12.join(searchDir, ".contextstream", "config.json");
5466
- if (fs12.existsSync(csConfigPath)) {
5772
+ const csConfigPath = path13.join(searchDir, ".contextstream", "config.json");
5773
+ if (fs13.existsSync(csConfigPath)) {
5467
5774
  try {
5468
- const content = fs12.readFileSync(csConfigPath, "utf-8");
5775
+ const content = fs13.readFileSync(csConfigPath, "utf-8");
5469
5776
  const csConfig = JSON.parse(content);
5470
5777
  if (csConfig.workspace_id) {
5471
5778
  WORKSPACE_ID6 = csConfig.workspace_id;
@@ -5474,15 +5781,15 @@ function loadConfigFromMcpJson6(cwd) {
5474
5781
  }
5475
5782
  }
5476
5783
  }
5477
- const parentDir = path12.dirname(searchDir);
5784
+ const parentDir = path13.dirname(searchDir);
5478
5785
  if (parentDir === searchDir) break;
5479
5786
  searchDir = parentDir;
5480
5787
  }
5481
5788
  if (!API_KEY8) {
5482
- const homeMcpPath = path12.join(homedir12(), ".mcp.json");
5483
- if (fs12.existsSync(homeMcpPath)) {
5789
+ const homeMcpPath = path13.join(homedir13(), ".mcp.json");
5790
+ if (fs13.existsSync(homeMcpPath)) {
5484
5791
  try {
5485
- const content = fs12.readFileSync(homeMcpPath, "utf-8");
5792
+ const content = fs13.readFileSync(homeMcpPath, "utf-8");
5486
5793
  const config = JSON.parse(content);
5487
5794
  const csEnv = config.mcpServers?.contextstream?.env;
5488
5795
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5607,17 +5914,17 @@ var on_web_exports = {};
5607
5914
  __export(on_web_exports, {
5608
5915
  runOnWebHook: () => runOnWebHook
5609
5916
  });
5610
- import * as fs13 from "node:fs";
5611
- import * as path13 from "node:path";
5612
- import { homedir as homedir13 } from "node:os";
5917
+ import * as fs14 from "node:fs";
5918
+ import * as path14 from "node:path";
5919
+ import { homedir as homedir14 } from "node:os";
5613
5920
  function loadConfigFromMcpJson7(cwd) {
5614
- let searchDir = path13.resolve(cwd);
5921
+ let searchDir = path14.resolve(cwd);
5615
5922
  for (let i = 0; i < 5; i++) {
5616
5923
  if (!API_KEY9) {
5617
- const mcpPath = path13.join(searchDir, ".mcp.json");
5618
- if (fs13.existsSync(mcpPath)) {
5924
+ const mcpPath = path14.join(searchDir, ".mcp.json");
5925
+ if (fs14.existsSync(mcpPath)) {
5619
5926
  try {
5620
- const content = fs13.readFileSync(mcpPath, "utf-8");
5927
+ const content = fs14.readFileSync(mcpPath, "utf-8");
5621
5928
  const config = JSON.parse(content);
5622
5929
  const csEnv = config.mcpServers?.contextstream?.env;
5623
5930
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5631,10 +5938,10 @@ function loadConfigFromMcpJson7(cwd) {
5631
5938
  }
5632
5939
  }
5633
5940
  if (!WORKSPACE_ID7) {
5634
- const csConfigPath = path13.join(searchDir, ".contextstream", "config.json");
5635
- if (fs13.existsSync(csConfigPath)) {
5941
+ const csConfigPath = path14.join(searchDir, ".contextstream", "config.json");
5942
+ if (fs14.existsSync(csConfigPath)) {
5636
5943
  try {
5637
- const content = fs13.readFileSync(csConfigPath, "utf-8");
5944
+ const content = fs14.readFileSync(csConfigPath, "utf-8");
5638
5945
  const csConfig = JSON.parse(content);
5639
5946
  if (csConfig.workspace_id) {
5640
5947
  WORKSPACE_ID7 = csConfig.workspace_id;
@@ -5643,15 +5950,15 @@ function loadConfigFromMcpJson7(cwd) {
5643
5950
  }
5644
5951
  }
5645
5952
  }
5646
- const parentDir = path13.dirname(searchDir);
5953
+ const parentDir = path14.dirname(searchDir);
5647
5954
  if (parentDir === searchDir) break;
5648
5955
  searchDir = parentDir;
5649
5956
  }
5650
5957
  if (!API_KEY9) {
5651
- const homeMcpPath = path13.join(homedir13(), ".mcp.json");
5652
- if (fs13.existsSync(homeMcpPath)) {
5958
+ const homeMcpPath = path14.join(homedir14(), ".mcp.json");
5959
+ if (fs14.existsSync(homeMcpPath)) {
5653
5960
  try {
5654
- const content = fs13.readFileSync(homeMcpPath, "utf-8");
5961
+ const content = fs14.readFileSync(homeMcpPath, "utf-8");
5655
5962
  const config = JSON.parse(content);
5656
5963
  const csEnv = config.mcpServers?.contextstream?.env;
5657
5964
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -5844,7 +6151,7 @@ var init_rules_templates = __esm({
5844
6151
  | Message | Required |
5845
6152
  |---------|----------|
5846
6153
  | **1st message** | \`init()\` \u2192 \`context(user_message="...")\` |
5847
- | **Every message** | \`context(user_message="...")\` FIRST |
6154
+ | **Subsequent messages (default)** | \`context(user_message="...")\` FIRST (narrow read-only bypass when context is fresh and no state-changing tool has run) |
5848
6155
  | **Before file search** | \`search(mode="auto")\` BEFORE Glob/Grep/Read |
5849
6156
  </contextstream_rules>
5850
6157
 
@@ -5858,27 +6165,25 @@ v${RULES_VERSION}
5858
6165
  `.trim();
5859
6166
  CONTEXTSTREAM_RULES_DYNAMIC = CONTEXTSTREAM_RULES_BOOTSTRAP;
5860
6167
  CONTEXTSTREAM_RULES_FULL = `
5861
- ## \u{1F6A8} MANDATORY: CALL CONTEXT EVERY MESSAGE \u{1F6A8}
6168
+ ## \u{1F6A8} MANDATORY STARTUP: CONTEXT-FIRST FLOW \u{1F6A8}
5862
6169
 
5863
6170
  <contextstream_rules>
5864
- **EVERY response MUST start with \`context(user_message="...")\`**
5865
-
5866
6171
  | Message | What to Call |
5867
6172
  |---------|--------------|
5868
- | 1st message | \`init()\` \u2192 \`context(user_message="<msg>")\` |
5869
- | **EVERY message after** | \`context(user_message="<msg>")\` **FIRST** |
5870
-
5871
- **BEFORE Glob/Grep/Read/Search:** \u2192 \`search(mode="auto")\` FIRST
6173
+ | **First message in session** | \`init()\` \u2192 \`context(user_message="<msg>")\` BEFORE any other tool |
6174
+ | **Subsequent messages (default)** | \`context(user_message="<msg>")\` FIRST, then other tools |
6175
+ | **Narrow bypass** | Immediate read-only ContextStream calls are allowed only when prior context is fresh and no state-changing tool has run |
6176
+ | **Before Glob/Grep/Read/Search** | \`search(mode="auto", query="...")\` FIRST |
5872
6177
  </contextstream_rules>
5873
6178
 
5874
- **This block MUST appear at the start of EVERY response.** Failing to call \`context()\` means missing rules, lessons, and relevant context.
6179
+ Use \`context()\` by default to get task-specific rules, lessons from past mistakes, and relevant decisions.
5875
6180
 
5876
6181
  ---
5877
6182
 
5878
- ## Why \`context()\` is MANDATORY Every Message
6183
+ ## Why Default Context-First
5879
6184
 
5880
- \u274C **WRONG:** "I already called init, I don't need context"
5881
- \u2705 **CORRECT:** \`context()\` is required EVERY message, not just the first
6185
+ \u274C **Wrong:** "I already called init, so I can skip context for everything"
6186
+ \u2705 **Correct:** \`context()\` is the default first call for subsequent messages, with a narrow read-only bypass when context is still fresh and state is unchanged
5882
6187
 
5883
6188
  **What you lose without \`context()\`:**
5884
6189
  - Dynamic rules matched to your current task
@@ -5886,7 +6191,7 @@ v${RULES_VERSION}
5886
6191
  - Semantically relevant decisions and context
5887
6192
  - Warnings about risky operations
5888
6193
 
5889
- **\`init()\` gives recent items by TIME. \`context()\` finds items RELEVANT to THIS message.**
6194
+ **\`init()\` returns recent items by time. \`context()\` finds items semantically relevant to this message.**
5890
6195
 
5891
6196
  ---
5892
6197
 
@@ -6392,9 +6697,10 @@ See full documentation: https://contextstream.io/docs/mcp/tools
6392
6697
  ## \u{1F6A8} CRITICAL: These Rules Are Non-Negotiable \u{1F6A8}
6393
6698
 
6394
6699
  <contextstream_protocol>
6395
- **EVERY coding response MUST start with:**
6396
- 1. \`init()\` (1st message only) \u2192 then \`context(user_message="<msg>")\`
6397
- 2. \`context(user_message="<msg>")\` (EVERY subsequent message)
6700
+ **MANDATORY STARTUP:**
6701
+ 1. First message in session: \`init()\` \u2192 then \`context(user_message="<msg>")\`
6702
+ 2. Subsequent messages (default): \`context(user_message="<msg>")\` FIRST
6703
+ 3. Narrow bypass: immediate read-only ContextStream calls are allowed only when prior context is fresh and no state-changing tool has run
6398
6704
 
6399
6705
  **BEFORE Glob/Grep/Read/Search/Explore:**
6400
6706
  \u2192 \`search(mode="auto", query="...")\` FIRST \u2014 local tools ONLY if 0 results
@@ -6424,8 +6730,9 @@ Rules Version: ${RULES_VERSION}
6424
6730
 
6425
6731
  | When | Call |
6426
6732
  |------|------|
6427
- | 1st message | \`init()\` \u2192 \`context(user_message="...")\` |
6428
- | Every message after | \`context(user_message="...")\` |
6733
+ | 1st message in session | \`init()\` \u2192 \`context(user_message="...")\` |
6734
+ | Subsequent messages (default) | \`context(user_message="...")\` first |
6735
+ | Narrow bypass | Immediate read-only ContextStream calls when context is fresh and no state-changing tool has run |
6429
6736
  | Before ANY file discovery | \`search(mode="auto", query="...")\` |
6430
6737
  | On \`<system-reminder>\` | **Follow instructions inside** |
6431
6738
  | Save important decisions | \`session(action="capture", event_type="decision", ...)\` |
@@ -6448,12 +6755,10 @@ Rules Version: ${RULES_VERSION}
6448
6755
  - **[RULES_NOTICE]** \u2192 Run \`generate_rules()\`
6449
6756
  - **[VERSION_NOTICE]** \u2192 Tell user to update MCP
6450
6757
 
6451
- ## Fast Path (Simple Utilities Only)
6452
-
6453
- Skip init/context ONLY for: "list workspaces", "show version", "list reminders"
6454
- \u2192 Just call: \`workspace(action="list")\`, \`help(action="version")\`, etc.
6758
+ ## Read-Only Examples
6455
6759
 
6456
- Everything else = full protocol (init \u2192 context \u2192 search \u2192 work)
6760
+ Default behavior is context-first. Narrow bypass applies only for immediate read-only ContextStream calls when context is fresh and state is unchanged.
6761
+ Examples: \`workspace(action="list"|"get")\`, \`help(action="version"|"tools"|"auth")\`, \`project(action="index_status")\`.
6457
6762
 
6458
6763
  ### Lessons (Past Mistakes)
6459
6764
 
@@ -6542,7 +6847,7 @@ You MUST follow these rules manually - there is no automatic enforcement.
6542
6847
  - Check for [RULES_NOTICE] - update rules if needed
6543
6848
  - **save_exchange=true** saves each conversation turn for later retrieval
6544
6849
 
6545
- 4. **NEVER skip init/context** - you will miss critical context
6850
+ 4. **Default behavior:** call \`context(...)\` first on each message. Narrow bypass is allowed only for immediate read-only ContextStream calls when previous context is still fresh and no state-changing tool has run.
6546
6851
 
6547
6852
  ---
6548
6853
 
@@ -6551,7 +6856,7 @@ You MUST follow these rules manually - there is no automatic enforcement.
6551
6856
  **This editor does NOT have hooks to auto-save transcripts.**
6552
6857
  You MUST save each conversation turn manually:
6553
6858
 
6554
- ### On EVERY message (including the first):
6859
+ ### On MOST messages (including the first):
6555
6860
  \`\`\`
6556
6861
  context(user_message="<user's message>", save_exchange=true, session_id="<session-id>")
6557
6862
  \`\`\`
@@ -6626,6 +6931,28 @@ search(mode="auto", query="what you're looking for")
6626
6931
  **IF ContextStream search returns 0 results or errors:**
6627
6932
  \u2192 Use local tools (Glob/Grep/Read) as fallback
6628
6933
 
6934
+ ### Choose Search Mode Intelligently:
6935
+ - \`auto\` (recommended): query-aware mode selection
6936
+ - \`hybrid\`: mixed semantic + keyword retrieval for broad discovery
6937
+ - \`semantic\`: conceptual questions ("how does X work?")
6938
+ - \`keyword\`: exact text / quoted string
6939
+ - \`pattern\`: glob or regex (\`*.ts\`, \`foo\\s+bar\`)
6940
+ - \`refactor\`: symbol usage / rename-safe lookup
6941
+ - \`exhaustive\`: all occurrences / complete match coverage
6942
+ - \`team\`: cross-project team search
6943
+
6944
+ ### Output Format Hints:
6945
+ - Use \`output_format="paths"\` for file listings and rename targets
6946
+ - Use \`output_format="count"\` for "how many" queries
6947
+
6948
+ ### Two-Phase Search Pattern (for precision):
6949
+ - Pass 1 (discovery): \`search(mode="auto", query="<concept + module>", output_format="paths", limit=10)\`
6950
+ - Pass 2 (precision): use one of:
6951
+ - exact text/symbol: \`search(mode="keyword", query="\\"exact_text\\"", include_content=true)\`
6952
+ - symbol usage: \`search(mode="refactor", query="SymbolName", output_format="paths")\`
6953
+ - all occurrences: \`search(mode="exhaustive", query="symbol_or_text")\`
6954
+ - Then use local Read/Grep only on paths returned by ContextStream.
6955
+
6629
6956
  ### When Local Tools Are OK:
6630
6957
  \u2705 Project is not indexed
6631
6958
  \u2705 Index is stale/outdated (>7 days old)
@@ -6782,17 +7109,17 @@ var session_init_exports = {};
6782
7109
  __export(session_init_exports, {
6783
7110
  runSessionInitHook: () => runSessionInitHook
6784
7111
  });
6785
- import * as fs14 from "node:fs";
6786
- import * as path14 from "node:path";
6787
- import { homedir as homedir14 } from "node:os";
7112
+ import * as fs15 from "node:fs";
7113
+ import * as path15 from "node:path";
7114
+ import { homedir as homedir15 } from "node:os";
6788
7115
  function loadConfigFromMcpJson8(cwd) {
6789
- let searchDir = path14.resolve(cwd);
7116
+ let searchDir = path15.resolve(cwd);
6790
7117
  for (let i = 0; i < 5; i++) {
6791
7118
  if (!API_KEY10) {
6792
- const mcpPath = path14.join(searchDir, ".mcp.json");
6793
- if (fs14.existsSync(mcpPath)) {
7119
+ const mcpPath = path15.join(searchDir, ".mcp.json");
7120
+ if (fs15.existsSync(mcpPath)) {
6794
7121
  try {
6795
- const content = fs14.readFileSync(mcpPath, "utf-8");
7122
+ const content = fs15.readFileSync(mcpPath, "utf-8");
6796
7123
  const config = JSON.parse(content);
6797
7124
  const csEnv = config.mcpServers?.contextstream?.env;
6798
7125
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -6809,10 +7136,10 @@ function loadConfigFromMcpJson8(cwd) {
6809
7136
  }
6810
7137
  }
6811
7138
  if (!WORKSPACE_ID8 || !PROJECT_ID2) {
6812
- const csConfigPath = path14.join(searchDir, ".contextstream", "config.json");
6813
- if (fs14.existsSync(csConfigPath)) {
7139
+ const csConfigPath = path15.join(searchDir, ".contextstream", "config.json");
7140
+ if (fs15.existsSync(csConfigPath)) {
6814
7141
  try {
6815
- const content = fs14.readFileSync(csConfigPath, "utf-8");
7142
+ const content = fs15.readFileSync(csConfigPath, "utf-8");
6816
7143
  const csConfig = JSON.parse(content);
6817
7144
  if (csConfig.workspace_id && !WORKSPACE_ID8) {
6818
7145
  WORKSPACE_ID8 = csConfig.workspace_id;
@@ -6824,15 +7151,15 @@ function loadConfigFromMcpJson8(cwd) {
6824
7151
  }
6825
7152
  }
6826
7153
  }
6827
- const parentDir = path14.dirname(searchDir);
7154
+ const parentDir = path15.dirname(searchDir);
6828
7155
  if (parentDir === searchDir) break;
6829
7156
  searchDir = parentDir;
6830
7157
  }
6831
7158
  if (!API_KEY10) {
6832
- const homeMcpPath = path14.join(homedir14(), ".mcp.json");
6833
- if (fs14.existsSync(homeMcpPath)) {
7159
+ const homeMcpPath = path15.join(homedir15(), ".mcp.json");
7160
+ if (fs15.existsSync(homeMcpPath)) {
6834
7161
  try {
6835
- const content = fs14.readFileSync(homeMcpPath, "utf-8");
7162
+ const content = fs15.readFileSync(homeMcpPath, "utf-8");
6836
7163
  const config = JSON.parse(content);
6837
7164
  const csEnv = config.mcpServers?.contextstream?.env;
6838
7165
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -6910,7 +7237,9 @@ function formatContext(ctx, options = {}) {
6910
7237
  }
6911
7238
  }
6912
7239
  if (!ctx) {
6913
- parts.push('\nNo stored context found. Call `mcp__contextstream__context(user_message="starting new session")` to initialize.');
7240
+ parts.push(
7241
+ '\nNo saved context found yet. On the first message in this session call `mcp__contextstream__init(...)` then `mcp__contextstream__context(user_message="starting new session")`.'
7242
+ );
6914
7243
  return parts.join("\n");
6915
7244
  }
6916
7245
  if (ctx.lessons && ctx.lessons.length > 0) {
@@ -6938,7 +7267,9 @@ function formatContext(ctx, options = {}) {
6938
7267
  }
6939
7268
  }
6940
7269
  parts.push("\n---");
6941
- parts.push('Call `mcp__contextstream__context(user_message="...")` for task-specific context.');
7270
+ parts.push(
7271
+ 'On the first message in a new session call `mcp__contextstream__init(...)` then `mcp__contextstream__context(user_message="...")`. After that, call `mcp__contextstream__context(user_message="...")` on every message.'
7272
+ );
6942
7273
  return parts.join("\n");
6943
7274
  }
6944
7275
  function regenerateRuleFiles(folderPath) {
@@ -6947,10 +7278,10 @@ function regenerateRuleFiles(folderPath) {
6947
7278
  for (const editor of editors) {
6948
7279
  const rule = generateRuleContent(editor, { mode: "bootstrap" });
6949
7280
  if (!rule) continue;
6950
- const filePath = path14.join(folderPath, rule.filename);
6951
- if (!fs14.existsSync(filePath)) continue;
7281
+ const filePath = path15.join(folderPath, rule.filename);
7282
+ if (!fs15.existsSync(filePath)) continue;
6952
7283
  try {
6953
- const existing = fs14.readFileSync(filePath, "utf8");
7284
+ const existing = fs15.readFileSync(filePath, "utf8");
6954
7285
  const startIdx = existing.indexOf(CONTEXTSTREAM_START_MARKER);
6955
7286
  const endIdx = existing.indexOf(CONTEXTSTREAM_END_MARKER);
6956
7287
  if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) continue;
@@ -6960,7 +7291,7 @@ function regenerateRuleFiles(folderPath) {
6960
7291
  ${rule.content.trim()}
6961
7292
  ${CONTEXTSTREAM_END_MARKER}`;
6962
7293
  const merged = [before, newBlock, after].filter((p) => p.length > 0).join("\n\n");
6963
- fs14.writeFileSync(filePath, merged.trim() + "\n", "utf8");
7294
+ fs15.writeFileSync(filePath, merged.trim() + "\n", "utf8");
6964
7295
  updated++;
6965
7296
  } catch {
6966
7297
  }
@@ -6985,6 +7316,8 @@ async function runSessionInitHook() {
6985
7316
  process.exit(0);
6986
7317
  }
6987
7318
  const cwd = input.cwd || process.cwd();
7319
+ cleanupStale(360);
7320
+ markInitRequired(cwd);
6988
7321
  loadConfigFromMcpJson8(cwd);
6989
7322
  const updateMarker = checkUpdateMarker();
6990
7323
  if (updateMarker) {
@@ -7018,6 +7351,7 @@ var init_session_init = __esm({
7018
7351
  "use strict";
7019
7352
  init_version();
7020
7353
  init_rules_templates();
7354
+ init_prompt_state();
7021
7355
  ENABLED12 = process.env.CONTEXTSTREAM_SESSION_INIT_ENABLED !== "false";
7022
7356
  API_URL10 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
7023
7357
  API_KEY10 = process.env.CONTEXTSTREAM_API_KEY || "";
@@ -7037,17 +7371,17 @@ var session_end_exports = {};
7037
7371
  __export(session_end_exports, {
7038
7372
  runSessionEndHook: () => runSessionEndHook
7039
7373
  });
7040
- import * as fs15 from "node:fs";
7041
- import * as path15 from "node:path";
7042
- import { homedir as homedir15 } from "node:os";
7374
+ import * as fs16 from "node:fs";
7375
+ import * as path16 from "node:path";
7376
+ import { homedir as homedir16 } from "node:os";
7043
7377
  function loadConfigFromMcpJson9(cwd) {
7044
- let searchDir = path15.resolve(cwd);
7378
+ let searchDir = path16.resolve(cwd);
7045
7379
  for (let i = 0; i < 5; i++) {
7046
7380
  if (!API_KEY11) {
7047
- const mcpPath = path15.join(searchDir, ".mcp.json");
7048
- if (fs15.existsSync(mcpPath)) {
7381
+ const mcpPath = path16.join(searchDir, ".mcp.json");
7382
+ if (fs16.existsSync(mcpPath)) {
7049
7383
  try {
7050
- const content = fs15.readFileSync(mcpPath, "utf-8");
7384
+ const content = fs16.readFileSync(mcpPath, "utf-8");
7051
7385
  const config = JSON.parse(content);
7052
7386
  const csEnv = config.mcpServers?.contextstream?.env;
7053
7387
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -7061,10 +7395,10 @@ function loadConfigFromMcpJson9(cwd) {
7061
7395
  }
7062
7396
  }
7063
7397
  if (!WORKSPACE_ID9 || !PROJECT_ID3) {
7064
- const csConfigPath = path15.join(searchDir, ".contextstream", "config.json");
7065
- if (fs15.existsSync(csConfigPath)) {
7398
+ const csConfigPath = path16.join(searchDir, ".contextstream", "config.json");
7399
+ if (fs16.existsSync(csConfigPath)) {
7066
7400
  try {
7067
- const content = fs15.readFileSync(csConfigPath, "utf-8");
7401
+ const content = fs16.readFileSync(csConfigPath, "utf-8");
7068
7402
  const csConfig = JSON.parse(content);
7069
7403
  if (csConfig.workspace_id && !WORKSPACE_ID9) {
7070
7404
  WORKSPACE_ID9 = csConfig.workspace_id;
@@ -7076,15 +7410,15 @@ function loadConfigFromMcpJson9(cwd) {
7076
7410
  }
7077
7411
  }
7078
7412
  }
7079
- const parentDir = path15.dirname(searchDir);
7413
+ const parentDir = path16.dirname(searchDir);
7080
7414
  if (parentDir === searchDir) break;
7081
7415
  searchDir = parentDir;
7082
7416
  }
7083
7417
  if (!API_KEY11) {
7084
- const homeMcpPath = path15.join(homedir15(), ".mcp.json");
7085
- if (fs15.existsSync(homeMcpPath)) {
7418
+ const homeMcpPath = path16.join(homedir16(), ".mcp.json");
7419
+ if (fs16.existsSync(homeMcpPath)) {
7086
7420
  try {
7087
- const content = fs15.readFileSync(homeMcpPath, "utf-8");
7421
+ const content = fs16.readFileSync(homeMcpPath, "utf-8");
7088
7422
  const config = JSON.parse(content);
7089
7423
  const csEnv = config.mcpServers?.contextstream?.env;
7090
7424
  if (csEnv?.CONTEXTSTREAM_API_KEY) {
@@ -7107,11 +7441,11 @@ function parseTranscriptStats(transcriptPath) {
7107
7441
  messages: [],
7108
7442
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
7109
7443
  };
7110
- if (!transcriptPath || !fs15.existsSync(transcriptPath)) {
7444
+ if (!transcriptPath || !fs16.existsSync(transcriptPath)) {
7111
7445
  return stats;
7112
7446
  }
7113
7447
  try {
7114
- const content = fs15.readFileSync(transcriptPath, "utf-8");
7448
+ const content = fs16.readFileSync(transcriptPath, "utf-8");
7115
7449
  const lines = content.split("\n");
7116
7450
  let firstTimestamp = null;
7117
7451
  let lastTimestamp = null;