@contextstream/mcp-server 0.4.57 → 0.4.59

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.
@@ -43,7 +43,7 @@ function compareVersions(v1, v2) {
43
43
  }
44
44
  return 0;
45
45
  }
46
- var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
46
+ var CACHE_TTL_MS = 12 * 60 * 60 * 1e3;
47
47
  var latestVersionPromise = null;
48
48
  function getCacheFilePath() {
49
49
  return join(homedir(), ".contextstream", "version-cache.json");
@@ -179,7 +179,9 @@ var API_URL = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io
179
179
  var API_KEY = process.env.CONTEXTSTREAM_API_KEY || "";
180
180
  var WORKSPACE_ID = null;
181
181
  var PROJECT_ID = null;
182
- var REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
182
+ var 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.
183
+ [END]`;
184
+ var FULL_REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
183
185
 
184
186
  1. FIRST: Call mcp__contextstream__context(user_message="...", save_exchange=true, session_id="<session-id>") before ANY other tool
185
187
  - Returns: dynamic rules, lessons from past mistakes, relevant context
@@ -189,7 +191,7 @@ var REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
189
191
 
190
192
  2. FOR CODE SEARCH: Check index status, then search appropriately
191
193
  \u26A0\uFE0F BEFORE searching: mcp__contextstream__project(action="index_status")
192
- \u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="hybrid", query="...")
194
+ \u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="auto", query="...")
193
195
  \u2705 IF NOT indexed OR stale: Use local tools (Glob/Grep/Read) directly
194
196
  \u2705 IF search returns 0 results: Fallback to local tools (Glob/Grep/Read)
195
197
 
@@ -434,6 +436,34 @@ async function saveLastExchange(exchange, cwd, clientName) {
434
436
  } catch {
435
437
  }
436
438
  }
439
+ async function fetchHookContext() {
440
+ if (!API_KEY) return null;
441
+ try {
442
+ const controller = new AbortController();
443
+ const timeoutId = setTimeout(() => controller.abort(), 2e3);
444
+ const url = `${API_URL}/api/v1/context/hook`;
445
+ const body = {};
446
+ if (WORKSPACE_ID) body.workspace_id = WORKSPACE_ID;
447
+ if (PROJECT_ID) body.project_id = PROJECT_ID;
448
+ const response = await fetch(url, {
449
+ method: "POST",
450
+ headers: {
451
+ "X-API-Key": API_KEY,
452
+ "Content-Type": "application/json"
453
+ },
454
+ body: JSON.stringify(body),
455
+ signal: controller.signal
456
+ });
457
+ clearTimeout(timeoutId);
458
+ if (response.ok) {
459
+ const data = await response.json();
460
+ return data?.data?.context || null;
461
+ }
462
+ return null;
463
+ } catch {
464
+ return null;
465
+ }
466
+ }
437
467
  async function fetchSessionContext() {
438
468
  if (!API_KEY) return null;
439
469
  try {
@@ -512,26 +542,6 @@ function transformSmartContextResponse(data) {
512
542
  return null;
513
543
  }
514
544
  }
515
- function buildClaudeReminder(ctx, versionNotice) {
516
- const parts = [];
517
- if (versionNotice?.behind) {
518
- const versionInfo = getVersionNoticeForHook(versionNotice);
519
- if (versionInfo) {
520
- parts.push(versionInfo);
521
- parts.push("");
522
- }
523
- }
524
- const highImportancePrefs = ctx?.preferences?.filter((p) => p.importance === "high") || [];
525
- if (highImportancePrefs.length > 0) {
526
- parts.push(`[USER PREFERENCES - Always respect these]`);
527
- for (const pref of highImportancePrefs.slice(0, 5)) {
528
- parts.push(`\u2022 ${pref.title}: ${pref.content}`);
529
- }
530
- parts.push("");
531
- }
532
- parts.push(REMINDER);
533
- return parts.join("\n");
534
- }
535
545
  function buildEnhancedReminder(ctx, isNewSession2, versionNotice) {
536
546
  const parts = [ENHANCED_REMINDER_HEADER];
537
547
  if (versionNotice?.behind) {
@@ -549,7 +559,7 @@ function buildEnhancedReminder(ctx, isNewSession2, versionNotice) {
549
559
  2. Wait for indexing: if \`init\` returns \`indexing_status: "started"\`, files are being indexed
550
560
  3. Generate a unique session_id (e.g., "session-" + timestamp or UUID) - use this for ALL context() calls
551
561
  4. Call \`context(user_message="...", save_exchange=true, session_id="<your-session-id>")\` for task-specific context
552
- 5. Use \`search(mode="hybrid")\` for code discovery (not Glob/Grep/Read)
562
+ 5. Use \`search(mode="auto")\` for code discovery (not Glob/Grep/Read)
553
563
 
554
564
  `);
555
565
  }
@@ -590,7 +600,7 @@ function buildEnhancedReminder(ctx, isNewSession2, versionNotice) {
590
600
  parts.push("");
591
601
  }
592
602
  parts.push("---\n");
593
- parts.push(REMINDER);
603
+ parts.push(FULL_REMINDER);
594
604
  parts.push(`
595
605
 
596
606
  ---
@@ -607,7 +617,7 @@ Returns: \`indexed\` (true/false), \`last_indexed_at\`, \`file_count\`
607
617
  ### \u{1F50D} Search Decision Tree:
608
618
 
609
619
  **IF indexed=true AND last_indexed_at is recent:**
610
- \u2192 Use \`search(mode="hybrid", query="...")\`
620
+ \u2192 Use \`search(mode="auto", query="...")\`
611
621
 
612
622
  **IF indexed=false OR last_indexed_at is stale (>7 days):**
613
623
  \u2192 Use local tools (Glob/Grep/Read) directly
@@ -678,55 +688,54 @@ async function runUserPromptSubmitHook() {
678
688
  }
679
689
  const editorFormat = detectEditorFormat(input);
680
690
  const cwd = input.cwd || process.cwd();
681
- loadConfigFromMcpJson(cwd);
682
- const versionNoticePromise = getUpdateNotice();
683
- const lastExchange = extractLastExchange(input, editorFormat);
684
- const clientName = editorFormat === "claude" ? "claude-code" : editorFormat;
685
- const saveExchangePromise = lastExchange ? saveLastExchange(lastExchange, cwd, clientName) : Promise.resolve();
686
691
  if (editorFormat === "claude") {
687
- const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise, saveExchangePromise]);
688
- const claudeReminder = buildClaudeReminder(ctx, versionNotice);
692
+ loadConfigFromMcpJson(cwd);
693
+ let context = REMINDER;
694
+ if (API_KEY) {
695
+ try {
696
+ const hookContext = await fetchHookContext();
697
+ if (hookContext) {
698
+ context = hookContext;
699
+ }
700
+ } catch {
701
+ }
702
+ }
689
703
  console.log(
690
704
  JSON.stringify({
691
705
  hookSpecificOutput: {
692
706
  hookEventName: "UserPromptSubmit",
693
- additionalContext: claudeReminder
707
+ additionalContext: context
694
708
  }
695
709
  })
696
710
  );
697
- } else if (editorFormat === "cline") {
698
- const newSession = isNewSession(input, editorFormat);
699
- const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise, saveExchangePromise]);
700
- const enhancedReminder = buildEnhancedReminder(ctx, newSession, versionNotice);
701
- console.log(
702
- JSON.stringify({
703
- cancel: false,
704
- contextModification: enhancedReminder
705
- })
706
- );
707
- } else if (editorFormat === "cursor") {
711
+ } else {
712
+ loadConfigFromMcpJson(cwd);
713
+ const versionNoticePromise = getUpdateNotice();
714
+ const lastExchange = extractLastExchange(input, editorFormat);
715
+ const clientName = editorFormat;
716
+ const saveExchangePromise = lastExchange ? saveLastExchange(lastExchange, cwd, clientName) : Promise.resolve();
708
717
  const newSession = isNewSession(input, editorFormat);
709
718
  const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise, saveExchangePromise]);
710
- let cursorReminder = ctx?.lessons?.length ? `[CONTEXTSTREAM] \u26A0\uFE0F ${ctx.lessons.length} lessons from past mistakes. Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="hybrid") before Glob/Grep. After file edits: project(action="index").` : `[CONTEXTSTREAM] Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="hybrid") before Glob/Grep/Read. After file edits: project(action="index").`;
711
- if (versionNotice?.behind) {
712
- cursorReminder += ` [UPDATE v${versionNotice.current}\u2192${versionNotice.latest}]`;
719
+ if (editorFormat === "cursor") {
720
+ let cursorReminder = ctx?.lessons?.length ? `[CONTEXTSTREAM] \u26A0\uFE0F ${ctx.lessons.length} lessons from past mistakes. Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="auto") before Glob/Grep. After file edits: project(action="index").` : `[CONTEXTSTREAM] Call context(save_exchange=true, session_id="...") FIRST. Use search(mode="auto") before Glob/Grep/Read. After file edits: project(action="index").`;
721
+ if (versionNotice?.behind) {
722
+ cursorReminder += ` [UPDATE v${versionNotice.current}\u2192${versionNotice.latest}]`;
723
+ }
724
+ console.log(
725
+ JSON.stringify({
726
+ continue: true,
727
+ user_message: cursorReminder
728
+ })
729
+ );
730
+ } else {
731
+ const enhancedReminder = buildEnhancedReminder(ctx, newSession, versionNotice);
732
+ console.log(
733
+ JSON.stringify({
734
+ cancel: false,
735
+ contextModification: enhancedReminder
736
+ })
737
+ );
713
738
  }
714
- console.log(
715
- JSON.stringify({
716
- continue: true,
717
- user_message: cursorReminder
718
- })
719
- );
720
- } else if (editorFormat === "antigravity") {
721
- const newSession = isNewSession(input, editorFormat);
722
- const [ctx, versionNotice] = await Promise.all([fetchSessionContext(), versionNoticePromise, saveExchangePromise]);
723
- const enhancedReminder = buildEnhancedReminder(ctx, newSession, versionNotice);
724
- console.log(
725
- JSON.stringify({
726
- cancel: false,
727
- contextModification: enhancedReminder
728
- })
729
- );
730
739
  }
731
740
  process.exit(0);
732
741
  }