@contextstream/mcp-server 0.4.47 → 0.4.49

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.
@@ -105,7 +105,7 @@ function buildHooksConfig(options) {
105
105
  ],
106
106
  UserPromptSubmit: userPromptHooks
107
107
  };
108
- if (options?.includePreCompact) {
108
+ if (options?.includePreCompact !== false) {
109
109
  config.PreCompact = [
110
110
  {
111
111
  // Match both manual (/compact) and automatic compaction
@@ -157,7 +157,7 @@ async function installHookScripts(options) {
157
157
  preToolUse: "npx @contextstream/mcp-server hook pre-tool-use",
158
158
  userPrompt: "npx @contextstream/mcp-server hook user-prompt-submit"
159
159
  };
160
- if (options?.includePreCompact) {
160
+ if (options?.includePreCompact !== false) {
161
161
  result.preCompact = "npx @contextstream/mcp-server hook pre-compact";
162
162
  }
163
163
  if (options?.includeMediaAware !== false) {
@@ -203,7 +203,7 @@ async function installClaudeCodeHooks(options) {
203
203
  "npx @contextstream/mcp-server hook pre-tool-use",
204
204
  "npx @contextstream/mcp-server hook user-prompt-submit"
205
205
  );
206
- if (options.includePreCompact) {
206
+ if (options.includePreCompact !== false) {
207
207
  result.scripts.push("npx @contextstream/mcp-server hook pre-compact");
208
208
  }
209
209
  if (options.includeMediaAware !== false) {
@@ -270,12 +270,11 @@ When Media-Aware hook detects media patterns, it injects context about:
270
270
  - How to get clips for Remotion (with frame-based props)
271
271
  - How to index new media files
272
272
 
273
- ### PreCompact Hook (Optional)
273
+ ### PreCompact Hook
274
274
  - **Command:** \`npx @contextstream/mcp-server hook pre-compact\`
275
275
  - **Purpose:** Saves conversation state before context compaction
276
276
  - **Triggers:** Both manual (/compact) and automatic compaction
277
- - **Disable:** Set \`CONTEXTSTREAM_PRECOMPACT_ENABLED=false\` environment variable
278
- - **Note:** Enable with \`generate_rules(include_pre_compact=true)\` to activate
277
+ - **Installed:** By default (disable with \`CONTEXTSTREAM_HOOK_ENABLED=false\`)
279
278
 
280
279
  When PreCompact runs, it:
281
280
  1. Parses the transcript for active files and tool calls
@@ -2,11 +2,16 @@
2
2
 
3
3
  // src/hooks/user-prompt-submit.ts
4
4
  var ENABLED = process.env.CONTEXTSTREAM_REMINDER_ENABLED !== "false";
5
- var REMINDER = `[CONTEXTSTREAM RULES]
6
- 1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="hybrid") FIRST
7
- 2. Call context_smart at start of EVERY response
8
- 3. Local tools ONLY if ContextStream returns 0 results
9
- [END RULES]`;
5
+ var REMINDER = `[CONTEXTSTREAM - DO THIS FIRST]
6
+ mcp__contextstream__context(user_message="<user's message>") - CALL THIS BEFORE ANY OTHER TOOL
7
+
8
+ Why: Delivers task-specific rules, lessons from past mistakes, and relevant context.
9
+ Skip it = repeat past mistakes, miss relevant decisions, fly blind.
10
+
11
+ BEFORE Glob/Grep/Read/Search/Explore:
12
+ mcp__contextstream__search(mode="hybrid", query="...") FIRST
13
+ Local tools ONLY if search returns 0 results.
14
+ [END]`;
10
15
  function detectEditorFormat(input) {
11
16
  if (input.hookName !== void 0) {
12
17
  return "cline";
package/dist/index.js CHANGED
@@ -591,7 +591,7 @@ function buildHooksConfig(options) {
591
591
  ],
592
592
  UserPromptSubmit: userPromptHooks
593
593
  };
594
- if (options?.includePreCompact) {
594
+ if (options?.includePreCompact !== false) {
595
595
  config.PreCompact = [
596
596
  {
597
597
  // Match both manual (/compact) and automatic compaction
@@ -643,7 +643,7 @@ async function installHookScripts(options) {
643
643
  preToolUse: "npx @contextstream/mcp-server hook pre-tool-use",
644
644
  userPrompt: "npx @contextstream/mcp-server hook user-prompt-submit"
645
645
  };
646
- if (options?.includePreCompact) {
646
+ if (options?.includePreCompact !== false) {
647
647
  result.preCompact = "npx @contextstream/mcp-server hook pre-compact";
648
648
  }
649
649
  if (options?.includeMediaAware !== false) {
@@ -689,7 +689,7 @@ async function installClaudeCodeHooks(options) {
689
689
  "npx @contextstream/mcp-server hook pre-tool-use",
690
690
  "npx @contextstream/mcp-server hook user-prompt-submit"
691
691
  );
692
- if (options.includePreCompact) {
692
+ if (options.includePreCompact !== false) {
693
693
  result.scripts.push("npx @contextstream/mcp-server hook pre-compact");
694
694
  }
695
695
  if (options.includeMediaAware !== false) {
@@ -756,12 +756,11 @@ When Media-Aware hook detects media patterns, it injects context about:
756
756
  - How to get clips for Remotion (with frame-based props)
757
757
  - How to index new media files
758
758
 
759
- ### PreCompact Hook (Optional)
759
+ ### PreCompact Hook
760
760
  - **Command:** \`npx @contextstream/mcp-server hook pre-compact\`
761
761
  - **Purpose:** Saves conversation state before context compaction
762
762
  - **Triggers:** Both manual (/compact) and automatic compaction
763
- - **Disable:** Set \`CONTEXTSTREAM_PRECOMPACT_ENABLED=false\` environment variable
764
- - **Note:** Enable with \`generate_rules(include_pre_compact=true)\` to activate
763
+ - **Installed:** By default (disable with \`CONTEXTSTREAM_HOOK_ENABLED=false\`)
765
764
 
766
765
  When PreCompact runs, it:
767
766
  1. Parses the transcript for active files and tool calls
@@ -2633,11 +2632,16 @@ var init_user_prompt_submit = __esm({
2633
2632
  "src/hooks/user-prompt-submit.ts"() {
2634
2633
  "use strict";
2635
2634
  ENABLED3 = process.env.CONTEXTSTREAM_REMINDER_ENABLED !== "false";
2636
- REMINDER = `[CONTEXTSTREAM RULES]
2637
- 1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="hybrid") FIRST
2638
- 2. Call context_smart at start of EVERY response
2639
- 3. Local tools ONLY if ContextStream returns 0 results
2640
- [END RULES]`;
2635
+ REMINDER = `[CONTEXTSTREAM - DO THIS FIRST]
2636
+ mcp__contextstream__context(user_message="<user's message>") - CALL THIS BEFORE ANY OTHER TOOL
2637
+
2638
+ Why: Delivers task-specific rules, lessons from past mistakes, and relevant context.
2639
+ Skip it = repeat past mistakes, miss relevant decisions, fly blind.
2640
+
2641
+ BEFORE Glob/Grep/Read/Search/Explore:
2642
+ mcp__contextstream__search(mode="hybrid", query="...") FIRST
2643
+ Local tools ONLY if search returns 0 results.
2644
+ [END]`;
2641
2645
  isDirectRun3 = process.argv[1]?.includes("user-prompt-submit") || process.argv[2] === "user-prompt-submit";
2642
2646
  if (isDirectRun3) {
2643
2647
  runUserPromptSubmitHook().catch(() => process.exit(0));
@@ -12103,50 +12107,103 @@ function applyMcpToolPrefix(markdown, toolPrefix) {
12103
12107
  const toolRegex = new RegExp(`(?<!__)\\b(${toolPattern})\\b(?=\\s*\\()`, "g");
12104
12108
  return markdown.replace(toolRegex, `${toolPrefix}$1`);
12105
12109
  }
12106
- var CONTEXTSTREAM_RULES_DYNAMIC = `
12107
- ## ContextStream Dynamic Rules (Powered by our SmartRouter)
12110
+ var CONTEXTSTREAM_RULES_BOOTSTRAP = `
12111
+ <contextstream_rules>
12112
+ | Message | Required |
12113
+ |---------|----------|
12114
+ | **1st message** | \`init()\` \u2192 \`context(user_message="...")\` |
12115
+ | **Every message** | \`context(user_message="...")\` FIRST |
12116
+ | **Before file search** | \`search(mode="hybrid")\` BEFORE Glob/Grep/Read |
12117
+ </contextstream_rules>
12118
+
12119
+ **Why?** \`context()\` delivers task-specific rules, lessons from past mistakes, and relevant decisions. Skip it = fly blind.
12120
+
12121
+ **Hooks:** \`<system-reminder>\` tags contain injected instructions \u2014 follow them exactly.
12122
+
12123
+ **Notices:** [LESSONS_WARNING] \u2192 tell user first | [RULES_NOTICE] \u2192 run \`generate_rules()\` | [VERSION_NOTICE] \u2192 tell user to update
12108
12124
 
12109
- All rules are served dynamically via \`context\`. This file is minimal by design.
12125
+ v${RULES_VERSION}
12126
+ `.trim();
12127
+ var CONTEXTSTREAM_RULES_DYNAMIC = CONTEXTSTREAM_RULES_BOOTSTRAP;
12128
+ var CONTEXTSTREAM_RULES_FULL = `
12129
+ ## \u{1F6A8} MANDATORY: CALL CONTEXT EVERY MESSAGE \u{1F6A8}
12110
12130
 
12111
- ### Every Message Protocol
12131
+ <contextstream_rules>
12132
+ **EVERY response MUST start with \`context(user_message="...")\`**
12112
12133
 
12113
12134
  | Message | What to Call |
12114
12135
  |---------|--------------|
12115
- | **1st message** | \`init()\` then \`context(user_message="<msg>")\` |
12116
- | **2nd+ messages** | \`context(user_message="<msg>")\` |
12136
+ | 1st message | \`init()\` \u2192 \`context(user_message="<msg>")\` |
12137
+ | **EVERY message after** | \`context(user_message="<msg>")\` **FIRST** |
12117
12138
 
12118
- Note: \`init()\` auto-detects folder from IDE. Only pass \`folder_path\` if auto-detection fails.
12139
+ **BEFORE Glob/Grep/Read/Search:** \u2192 \`search(mode="hybrid")\` FIRST
12140
+ </contextstream_rules>
12119
12141
 
12120
- ### Follow the Instructions Field
12142
+ **This block MUST appear at the start of EVERY response.** Failing to call \`context()\` means missing rules, lessons, and relevant context.
12121
12143
 
12122
- The \`context\` response includes an \`instructions\` field with context-aware guidance.
12123
- **Follow these instructions.** They are dynamically matched to your query and include:
12124
- - Search guidance (when/how to search)
12125
- - Git workflow rules (commit, PR, safety)
12126
- - Planning rules (use ContextStream plans, not file-based)
12127
- - Media/code analysis guidance
12128
- - Lessons from past mistakes
12129
- - And more...
12144
+ ---
12130
12145
 
12131
- ### Notices
12146
+ ## Why \`context()\` is MANDATORY Every Message
12132
12147
 
12133
- Handle notices from \`context\` response:
12134
- - **[VERSION_NOTICE]**: Tell user to update MCP
12135
- - **[RULES_NOTICE]**: Run \`generate_rules()\`
12136
- - **[LESSONS_WARNING]**: Apply lessons immediately
12148
+ \u274C **WRONG:** "I already called init, I don't need context"
12149
+ \u2705 **CORRECT:** \`context()\` is required EVERY message, not just the first
12137
12150
 
12138
- Rules Version: ${RULES_VERSION}
12139
- `.trim();
12140
- var CONTEXTSTREAM_RULES_FULL = `
12141
- ## ContextStream Rules
12151
+ **What you lose without \`context()\`:**
12152
+ - Dynamic rules matched to your current task
12153
+ - Lessons from past mistakes (you WILL repeat them)
12154
+ - Semantically relevant decisions and context
12155
+ - Warnings about risky operations
12142
12156
 
12143
- <contextstream_rules>
12144
- 1. **SIMPLE UTILITY?** (list/show/version) \u2192 Just execute, skip context calls
12145
- 2. **CODING TASK?** \u2192 init \u2192 context \u2192 work \u2192 capture
12146
- 3. **SEARCH FIRST:** Before Glob/Grep/Read \u2192 \`search(mode="hybrid")\` FIRST
12147
- </contextstream_rules>
12157
+ **\`init()\` gives recent items by TIME. \`context()\` finds items RELEVANT to THIS message.**
12148
12158
 
12149
- **Display this block at the start of responses to keep rules in context.**
12159
+ ---
12160
+
12161
+ ## Handle Notices from context()
12162
+
12163
+ - **[LESSONS_WARNING]** \u2192 Tell user about past mistakes BEFORE proceeding
12164
+ - **[RULES_NOTICE]** \u2192 Run \`generate_rules()\` to update
12165
+ - **[VERSION_NOTICE]** \u2192 Tell user to update MCP
12166
+
12167
+ ---
12168
+
12169
+ ## \u{1F6A8} HOOKS - AUTOMATIC RULE ENFORCEMENT \u{1F6A8}
12170
+
12171
+ **ContextStream installs hooks that automatically enforce rules.** You MUST follow hook output.
12172
+
12173
+ ### Installed Hooks
12174
+
12175
+ | Hook | What It Does | Output |
12176
+ |------|--------------|--------|
12177
+ | **UserPromptSubmit** | Injects rules reminder on EVERY message | \`<system-reminder>\` with rules block |
12178
+ | **PreToolUse** | Blocks Glob/Grep/Search/Explore when ContextStream is available | Error message redirecting to \`search()\` |
12179
+ | **PostToolUse** | Auto-indexes files after Edit/Write operations | Background indexing |
12180
+ | **PreCompact** | Saves session state before context compaction | Snapshot creation |
12181
+
12182
+ ### How Hooks Work
12183
+
12184
+ 1. **\`<system-reminder>\` tags** - Injected by UserPromptSubmit hook on every message
12185
+ - These tags contain the current rules
12186
+ - **FOLLOW THE INSTRUCTIONS INSIDE** - they ARE the rules
12187
+ - Example: \`[CONTEXTSTREAM RULES] 1. BEFORE Glob/Grep... [END RULES]\`
12188
+
12189
+ 2. **PreToolUse blocking** - If you try to use Glob/Grep/Search/Explore:
12190
+ - Hook returns error: \`STOP: Use mcp__contextstream__search(mode="hybrid") instead\`
12191
+ - **You MUST use the suggested ContextStream tool instead**
12192
+ - Local tools are only allowed if project is not indexed or ContextStream returns 0 results
12193
+
12194
+ 3. **PostToolUse indexing** - After Edit/Write operations:
12195
+ - Changed files are automatically re-indexed
12196
+ - No action required from you
12197
+
12198
+ 4. **PreCompact snapshots** - Before context compaction:
12199
+ - Hook reminds you to save important state
12200
+ - Call \`session(action="capture", event_type="session_snapshot", ...)\` when warned
12201
+
12202
+ ### Disabling Hooks
12203
+
12204
+ Set environment variable: \`CONTEXTSTREAM_HOOK_ENABLED=false\`
12205
+
12206
+ **Note:** Disabling hooks removes rule enforcement. Only disable for debugging.
12150
12207
 
12151
12208
  ---
12152
12209
 
@@ -12232,27 +12289,27 @@ You have access to ContextStream MCP tools for persistent memory and context.
12232
12289
  v0.4.x uses **~11 consolidated domain tools** for ~75% token reduction vs previous versions.
12233
12290
  Rules Version: ${RULES_VERSION}
12234
12291
 
12235
- ## TL;DR - WHEN TO USE CONTEXT
12292
+ ## TL;DR - CONTEXT EVERY MESSAGE
12236
12293
 
12237
- | Request Type | What to Do |
12238
- |--------------|------------|
12239
- | **\u{1F680} Simple utility** (list workspaces, show version) | **Just execute directly** - skip init, context, capture |
12240
- | **\u{1F4BB} Coding task** (edit, create, refactor) | Full context: init \u2192 context \u2192 work \u2192 capture |
12241
- | **\u{1F50D} Code search/discovery** | init \u2192 context \u2192 search() |
12242
- | **\u26A0\uFE0F Risky work** (deploy, migrate, refactor) | Check lessons first: \`session(action="get_lessons")\` |
12243
- | **User frustration/correction** | Capture lesson: \`session(action="capture_lesson", ...)\` |
12294
+ | Message | Required |
12295
+ |---------|----------|
12296
+ | **1st message** | \`init()\` \u2192 \`context(user_message="<msg>")\` |
12297
+ | **EVERY message after** | \`context(user_message="<msg>")\` **FIRST** |
12298
+ | **Before file search** | \`search(mode="hybrid")\` FIRST |
12299
+ | **After significant work** | \`session(action="capture", event_type="decision", ...)\` |
12300
+ | **User correction** | \`session(action="capture_lesson", ...)\` |
12244
12301
 
12245
- ### Simple Utility Operations - FAST PATH
12302
+ ### Why EVERY Message?
12246
12303
 
12247
- **For simple queries, just execute and respond:**
12248
- - "list workspaces" \u2192 \`workspace(action="list")\` \u2192 done
12249
- - "list projects" \u2192 \`project(action="list")\` \u2192 done
12250
- - "show version" \u2192 \`help(action="version")\` \u2192 done
12251
- - "what reminders do I have" \u2192 \`reminder(action="list")\` \u2192 done
12304
+ \`context()\` delivers:
12305
+ - **Dynamic rules** matched to your current task
12306
+ - **Lessons** from past mistakes (prevents repeating errors)
12307
+ - **Relevant decisions** and context (semantic search)
12308
+ - **Warnings** about risky operations
12252
12309
 
12253
- **No init. No context. No capture.** These add noise, not value.
12310
+ **Without \`context()\`, you are blind to relevant context and will repeat past mistakes.**
12254
12311
 
12255
- ### Coding Tasks - FULL CONTEXT
12312
+ ### Protocol
12256
12313
 
12257
12314
  | Step | What to Call |
12258
12315
  |------|--------------|
@@ -12263,12 +12320,7 @@ Rules Version: ${RULES_VERSION}
12263
12320
  | **User correction** | \`session(action="capture_lesson", ...)\` |
12264
12321
  | **\u26A0\uFE0F When warnings received** | **STOP**, acknowledge, explain mitigation, then proceed |
12265
12322
 
12266
- **How to detect simple utility operations:**
12267
- - Single-word commands: "list", "show", "version", "help"
12268
- - Data retrieval with no context dependency: "list my workspaces", "what projects do I have"
12269
- - Status checks: "am I authenticated?", "what's the server version?"
12270
-
12271
- **First message rule (for coding tasks):** After \`init\`:
12323
+ **First message rule:** After \`init\`:
12272
12324
  1. Check for \`lessons\` in response - if present, READ and SUMMARIZE them to user
12273
12325
  2. Then call \`context\` before any other tool or response
12274
12326
 
@@ -12368,8 +12420,8 @@ ContextStream tracks context pressure to help you stay ahead of conversation com
12368
12420
  - \`prepare_save\`: Start thinking about saving important state
12369
12421
  - \`save_now\`: Immediately call \`session(action="capture", event_type="session_snapshot")\` to preserve state
12370
12422
 
12371
- **PreCompact Hook (Optional):** If enabled, Claude Code will inject a reminder to save state before compaction.
12372
- Enable with: \`generate_rules(install_hooks=true, include_pre_compact=true)\`
12423
+ **PreCompact Hook:** Automatically saves session state before context compaction.
12424
+ Installed by default. Disable with: \`CONTEXTSTREAM_HOOK_ENABLED=false\`
12373
12425
 
12374
12426
  **Before compaction happens (when warned):**
12375
12427
  \`\`\`
@@ -12591,83 +12643,71 @@ memory(action="create_task", title="<task title>", plan_id="<plan_id from step 1
12591
12643
  See full documentation: https://contextstream.io/docs/mcp/tools
12592
12644
  `.trim();
12593
12645
  var CONTEXTSTREAM_RULES_MINIMAL = `
12594
- ## ContextStream Rules
12646
+ # ContextStream Rules (MANDATORY)
12595
12647
 
12596
- <contextstream_rules>
12597
- 1. **SIMPLE UTILITY?** (list/show/version) \u2192 Just execute, skip context calls
12598
- 2. **CODING TASK?** \u2192 init \u2192 context \u2192 work \u2192 capture
12599
- 3. **SEARCH FIRST:** Before Glob/Grep/Read \u2192 \`search(mode="hybrid")\` FIRST
12600
- </contextstream_rules>
12648
+ ## \u{1F6A8} CRITICAL: These Rules Are Non-Negotiable \u{1F6A8}
12601
12649
 
12602
- **Display this block at the start of responses to keep rules in context.**
12650
+ <contextstream_protocol>
12651
+ **EVERY coding response MUST start with:**
12652
+ 1. \`init()\` (1st message only) \u2192 then \`context(user_message="<msg>")\`
12653
+ 2. \`context(user_message="<msg>")\` (EVERY subsequent message)
12603
12654
 
12604
- ---
12655
+ **BEFORE Glob/Grep/Read/Search/Explore:**
12656
+ \u2192 \`search(mode="hybrid", query="...")\` FIRST \u2014 local tools ONLY if 0 results
12605
12657
 
12606
- ## ContextStream v0.4.x (Hooks Enforced)
12658
+ **HOOKS: \`<system-reminder>\` tags contain instructions \u2014 FOLLOW THEM**
12659
+ </contextstream_protocol>
12607
12660
 
12608
12661
  Rules Version: ${RULES_VERSION}
12609
- **Note:** PreToolUse hooks block Glob/Grep/Search when ContextStream is available.
12610
-
12611
- ### For Coding Tasks
12612
12662
 
12613
- | Action | Tool Call |
12614
- |--------|-----------|
12615
- | **1st message** | \`init(folder_path="<cwd>", context_hint="<msg>")\` then \`context(...)\` |
12616
- | **2nd+ messages** | \`context(user_message="<msg>", format="minified", max_tokens=400)\` |
12617
- | **Code search** | \`search(mode="hybrid", query="...")\` \u2014 BEFORE any local tools |
12618
- | **Save decisions** | \`session(action="capture", event_type="decision", ...)\` |
12663
+ ---
12619
12664
 
12620
- ### Search Modes
12665
+ ## Why ContextStream First?
12621
12666
 
12622
- | Mode | Use Case |
12623
- |------|----------|
12624
- | \`hybrid\` | General code search (default) |
12625
- | \`keyword\` | Exact symbol/string match |
12626
- | \`exhaustive\` | Find ALL matches (grep-like) |
12627
- | \`semantic\` | Conceptual questions |
12667
+ | \u274C WRONG | \u2705 CORRECT |
12668
+ |----------|-----------|
12669
+ | \`Grep \u2192 Read \u2192 Read \u2192 Read\` (4+ calls) | \`search(mode="hybrid")\` (1 call) |
12670
+ | Missing past decisions & lessons | \`context()\` = rules + lessons + memory |
12671
+ | Ignoring \`<system-reminder>\` hooks | Hooks enforce ContextStream-first |
12628
12672
 
12629
- ### Why ContextStream First?
12673
+ **\`context()\` delivers: rules, lessons from past mistakes, relevant decisions, semantic matches**
12674
+ **\`search()\` is indexed: faster, returns context, one call vs many**
12675
+ **Hooks inject \`<system-reminder>\` tags: these ARE the rules, follow them**
12630
12676
 
12631
- \u274C **WRONG:** \`Grep \u2192 Read \u2192 Read \u2192 Read\` (4+ tool calls, slow)
12632
- \u2705 **CORRECT:** \`search(mode="hybrid")\` (1 call, returns context)
12677
+ ---
12633
12678
 
12634
- ContextStream search is **indexed** and returns semantic matches + context in ONE call.
12679
+ ## Protocol
12635
12680
 
12636
- ### Quick Reference
12681
+ | When | Call |
12682
+ |------|------|
12683
+ | 1st message | \`init()\` \u2192 \`context(user_message="...")\` |
12684
+ | Every message after | \`context(user_message="...")\` |
12685
+ | Before ANY file discovery | \`search(mode="hybrid", query="...")\` |
12686
+ | On \`<system-reminder>\` | **Follow instructions inside** |
12687
+ | Save important decisions | \`session(action="capture", event_type="decision", ...)\` |
12688
+ | Check past mistakes | \`session(action="get_lessons", query="...")\` |
12637
12689
 
12638
- | Tool | Example |
12639
- |------|---------|
12640
- | \`search\` | \`search(mode="hybrid", query="auth", limit=3)\` |
12641
- | \`session\` | \`session(action="capture", event_type="decision", title="...", content="...")\` |
12642
- | \`memory\` | \`memory(action="list_events", limit=10)\` |
12643
- | \`graph\` | \`graph(action="dependencies", file_path="...")\` |
12690
+ ## Search Modes
12644
12691
 
12645
- ### \u{1F680} FAST PATH: Simple Utility Operations
12692
+ | Mode | When |
12693
+ |------|------|
12694
+ | \`hybrid\` | Default \u2014 semantic + keyword |
12695
+ | \`keyword\` | Exact symbol match |
12696
+ | \`exhaustive\` | Find ALL occurrences |
12697
+ | \`semantic\` | Conceptual questions |
12646
12698
 
12647
- **For simple utility commands, SKIP the ceremony and just execute directly:**
12699
+ ## Handle Notices from context()
12648
12700
 
12649
- | Command Type | Just Call | Skip |
12650
- |--------------|-----------|------|
12651
- | List workspaces | \`workspace(action="list")\` | init, context, capture |
12652
- | List projects | \`project(action="list")\` | init, context, capture |
12653
- | Show version | \`help(action="version")\` | init, context, capture |
12654
- | List reminders | \`reminder(action="list")\` | init, context, capture |
12655
- | Check auth | \`help(action="auth")\` | init, context, capture |
12701
+ - **[LESSONS_WARNING]** \u2192 Tell user about past mistakes BEFORE proceeding
12702
+ - **[RULES_NOTICE]** \u2192 Run \`generate_rules()\`
12703
+ - **[VERSION_NOTICE]** \u2192 Tell user to update MCP
12656
12704
 
12657
- **Detect simple operations by these patterns:**
12658
- - "list ...", "show ...", "what are my ...", "get ..."
12659
- - Single-action queries with no context dependency
12660
- - User just wants data, not analysis or coding help
12705
+ ## Fast Path (Simple Utilities Only)
12661
12706
 
12662
- **DO NOT add overhead for utility operations:**
12663
- - \u274C Don't call init just to list workspaces
12664
- - \u274C Don't call context for simple queries
12665
- - \u274C Don't capture "listed workspaces" as an event (that's noise)
12707
+ Skip init/context ONLY for: "list workspaces", "show version", "list reminders"
12708
+ \u2192 Just call: \`workspace(action="list")\`, \`help(action="version")\`, etc.
12666
12709
 
12667
- **Use full context ceremony ONLY for:**
12668
- - Coding tasks (edit, create, refactor, debug)
12669
- - Search/discovery (finding code, understanding architecture)
12670
- - Tasks where past decisions or lessons matter
12710
+ Everything else = full protocol (init \u2192 context \u2192 search \u2192 work)
12671
12711
 
12672
12712
  ### Lessons (Past Mistakes)
12673
12713
 
@@ -12678,7 +12718,7 @@ ContextStream search is **indexed** and returns semantic matches + context in ON
12678
12718
  ### Context Pressure & Compaction
12679
12719
 
12680
12720
  - If \`context\` returns high/critical \`context_pressure\`: call \`session(action="capture", ...)\` to save state
12681
- - PreCompact hooks automatically save snapshots before compaction (if installed)
12721
+ - PreCompact hooks automatically save snapshots before compaction
12682
12722
 
12683
12723
  ### Enhanced Context (Warnings)
12684
12724
 
@@ -12793,8 +12833,8 @@ function getTemplate(editor) {
12793
12833
  function generateRuleContent(editor, options) {
12794
12834
  const template = getTemplate(editor);
12795
12835
  if (!template) return null;
12796
- const mode = options?.mode || "dynamic";
12797
- const rules = mode === "full" ? CONTEXTSTREAM_RULES_FULL : mode === "minimal" ? CONTEXTSTREAM_RULES_MINIMAL : CONTEXTSTREAM_RULES_DYNAMIC;
12836
+ const mode = options?.mode || "bootstrap";
12837
+ const rules = mode === "full" ? CONTEXTSTREAM_RULES_FULL : mode === "minimal" ? CONTEXTSTREAM_RULES_MINIMAL : mode === "bootstrap" ? CONTEXTSTREAM_RULES_BOOTSTRAP : CONTEXTSTREAM_RULES_DYNAMIC;
12798
12838
  let content = template.build(rules);
12799
12839
  if (options?.workspaceName || options?.projectName) {
12800
12840
  const header = `
@@ -13070,6 +13110,112 @@ function trackToolTokenSavings(client, tool, contextText, params, extraMetadata)
13070
13110
  }
13071
13111
  }
13072
13112
 
13113
+ // src/educational-microcopy.ts
13114
+ var SESSION_INIT_TIPS = [
13115
+ "AI work that doesn't disappear.",
13116
+ "Every conversation builds context. Every artifact persists.",
13117
+ "Your AI remembers. Now you can see what it knows.",
13118
+ "Context that survives sessions.",
13119
+ "The bridge between AI conversations and human artifacts."
13120
+ ];
13121
+ function getSessionInitTip(sessionId) {
13122
+ const index = sessionId ? Math.abs(hashString(sessionId)) % SESSION_INIT_TIPS.length : Math.floor(Math.random() * SESSION_INIT_TIPS.length);
13123
+ return SESSION_INIT_TIPS[index];
13124
+ }
13125
+ var CAPTURE_HINTS = {
13126
+ // Core event types
13127
+ decision: "Future you will thank present you.",
13128
+ preference: "Noted. This will inform future suggestions.",
13129
+ insight: "Captured for future reference.",
13130
+ note: "Saved. Won't disappear when the chat does.",
13131
+ implementation: "Implementation recorded.",
13132
+ task: "Task tracked.",
13133
+ bug: "Bug logged for tracking.",
13134
+ feature: "Feature request captured.",
13135
+ plan: "This plan will be here when you come back.",
13136
+ correction: "Correction noted. Learning from this.",
13137
+ lesson: "Learn once, remember forever.",
13138
+ warning: "Warning logged.",
13139
+ frustration: "Feedback captured. We're listening.",
13140
+ conversation: "Conversation preserved.",
13141
+ session_snapshot: "Session state saved. Ready to resume anytime."
13142
+ };
13143
+ function getCaptureHint(eventType) {
13144
+ return CAPTURE_HINTS[eventType] || "Captured. This will survive when the chat disappears.";
13145
+ }
13146
+ var EMPTY_STATE_HINTS = {
13147
+ // Plans
13148
+ list_plans: "No plans yet. Plans live here, not in chat transcripts.",
13149
+ get_plan: "Plan not found. Create one to track implementation across sessions.",
13150
+ // Memory & Search
13151
+ recall: "Nothing found yet. Context builds over time.",
13152
+ search: "No matches. Try a different query or let context accumulate.",
13153
+ list_events: "No events yet. Start capturing decisions and insights.",
13154
+ decisions: "No decisions captured yet. Record the 'why' behind your choices.",
13155
+ timeline: "Timeline empty. Events will appear as you work.",
13156
+ // Lessons
13157
+ get_lessons: "No lessons yet. Capture mistakes to learn from them.",
13158
+ // Tasks
13159
+ list_tasks: "No tasks yet. Break plans into trackable tasks.",
13160
+ // Todos
13161
+ list_todos: "No todos yet. Action items will appear here.",
13162
+ // Diagrams
13163
+ list_diagrams: "No diagrams yet. AI-generated diagrams persist here.",
13164
+ // Docs
13165
+ list_docs: "No docs yet. Turn AI explanations into shareable documentation.",
13166
+ // Reminders
13167
+ list_reminders: "No reminders set. Schedule follow-ups that won't be forgotten.",
13168
+ // Generic
13169
+ default: "Nothing yet. Start a conversation\u2014context builds over time."
13170
+ };
13171
+ function getEmptyStateHint(action) {
13172
+ return EMPTY_STATE_HINTS[action] || EMPTY_STATE_HINTS.default;
13173
+ }
13174
+ var POST_COMPACT_HINTS = {
13175
+ restored: "Picked up where you left off. Session ended, memory didn't.",
13176
+ restored_with_session: (sessionId) => `Restored from session ${sessionId}. Session ended, memory didn't.`,
13177
+ no_snapshot: "No prior session found. Fresh start\u2014context will build as you work.",
13178
+ failed: "Couldn't restore previous session. Use context to retrieve what you need."
13179
+ };
13180
+ var PLAN_HINTS = {
13181
+ created: "Plan saved. It will be here when you come back.",
13182
+ activated: "Plan is now active. Track progress across sessions.",
13183
+ completed: "Plan completed. The journey is preserved for future reference.",
13184
+ abandoned: "Plan archived. Abandoned plans still teach.",
13185
+ updated: "Plan updated. Changes are preserved."
13186
+ };
13187
+ function getPlanStatusHint(status) {
13188
+ const statusMap = {
13189
+ draft: PLAN_HINTS.created,
13190
+ active: PLAN_HINTS.activated,
13191
+ completed: PLAN_HINTS.completed,
13192
+ abandoned: PLAN_HINTS.abandoned,
13193
+ archived: PLAN_HINTS.abandoned
13194
+ };
13195
+ return statusMap[status] || PLAN_HINTS.updated;
13196
+ }
13197
+ var TASK_HINTS = {
13198
+ created: "Task tracked. It won't disappear when the chat does.",
13199
+ completed: "Task done. Progress is preserved.",
13200
+ blocked: "Task blocked. Capture what's blocking for future reference.",
13201
+ cancelled: "Task cancelled. The history remains."
13202
+ };
13203
+ var INTEGRATION_HINTS = {
13204
+ not_connected: "Connect integrations to sync context where your team already works.",
13205
+ slack: "Context from Slack conversations, connected.",
13206
+ github: "Issues and PRs linked to the decisions behind them.",
13207
+ notion: "Decisions synced to where your team documents."
13208
+ };
13209
+ function hashString(str) {
13210
+ let hash = 0;
13211
+ for (let i = 0; i < str.length; i++) {
13212
+ const char = str.charCodeAt(i);
13213
+ hash = (hash << 5) - hash + char;
13214
+ hash = hash & hash;
13215
+ }
13216
+ return hash;
13217
+ }
13218
+
13073
13219
  // src/tools.ts
13074
13220
  var LOG_LEVEL = (process.env.CONTEXTSTREAM_LOG_LEVEL || "normal").toLowerCase();
13075
13221
  var LOG_QUIET = LOG_LEVEL === "quiet";
@@ -13135,6 +13281,7 @@ var lastAutoSavePressureLevel = "";
13135
13281
  var contextCallsSinceLastSave = 0;
13136
13282
  var SEARCH_RULES_REMINDER_ENABLED = process.env.CONTEXTSTREAM_SEARCH_REMINDER?.toLowerCase() !== "false";
13137
13283
  var SEARCH_RULES_REMINDER = `[SEARCH] Use search(mode="hybrid") before Glob/Grep/Read. Local tools only if 0 results.`;
13284
+ var CONTEXT_CALL_REMINDER = `[CONTEXT] Call context(user_message="...") at start of EVERY response. This is MANDATORY.`;
13138
13285
  var LESSONS_REMINDER_PREFIX = `
13139
13286
  \u{1F6A8} [LESSONS_WARNING] Past Mistakes Found - READ BEFORE PROCEEDING!
13140
13287
  \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501
@@ -16821,6 +16968,8 @@ This does semantic search on the first message. You only need context on subsequ
16821
16968
  ideRoots
16822
16969
  );
16823
16970
  result.tools_hint = getCoreToolsHint();
16971
+ const sessionId = typeof result.session_id === "string" ? result.session_id : void 0;
16972
+ result.educational_tip = getSessionInitTip(sessionId);
16824
16973
  const shouldRestoreContext = input.is_post_compact ?? RESTORE_CONTEXT_DEFAULT;
16825
16974
  if (shouldRestoreContext) {
16826
16975
  result.is_post_compact = true;
@@ -16890,15 +17039,15 @@ This does semantic search on the first message. You only need context on subsequ
16890
17039
  ...snapshotData
16891
17040
  };
16892
17041
  result.is_post_compact = true;
16893
- result.post_compact_hint = prevSessionId ? `Session restored from session ${prevSessionId}. Review 'restored_context' to continue where you left off.` : "Session restored from pre-compaction snapshot. Review the 'restored_context' to continue where you left off.";
17042
+ result.post_compact_hint = prevSessionId ? POST_COMPACT_HINTS.restored_with_session(prevSessionId) : POST_COMPACT_HINTS.restored;
16894
17043
  } else {
16895
17044
  result.is_post_compact = true;
16896
- result.post_compact_hint = "Post-compaction session started, but no snapshots found. Use context_smart to retrieve relevant context.";
17045
+ result.post_compact_hint = POST_COMPACT_HINTS.no_snapshot;
16897
17046
  }
16898
17047
  } catch (err) {
16899
17048
  logDebug(`Failed to restore post-compact context: ${err}`);
16900
17049
  result.is_post_compact = true;
16901
- result.post_compact_hint = "Post-compaction session started. Snapshot restoration failed, use context_smart for context.";
17050
+ result.post_compact_hint = POST_COMPACT_HINTS.failed;
16902
17051
  }
16903
17052
  }
16904
17053
  }
@@ -16934,7 +17083,7 @@ This does semantic search on the first message. You only need context on subsequ
16934
17083
  slack_connected: intStatus.slack,
16935
17084
  github_connected: intStatus.github,
16936
17085
  auto_hide_enabled: true,
16937
- hint: intStatus.slack || intStatus.github ? "Integration tools are now available in the tool list." : "Connect integrations at https://contextstream.io/settings/integrations to enable Slack/GitHub tools."
17086
+ hint: intStatus.slack || intStatus.github ? "Integration tools are now available in the tool list." : INTEGRATION_HINTS.not_connected + " https://contextstream.io/settings/integrations"
16938
17087
  };
16939
17088
  } catch (error) {
16940
17089
  logDebug(`Failed to check integration status: ${error}`);
@@ -17946,11 +18095,11 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
17946
18095
  workspace_id: external_exports.string().uuid().optional().describe("Workspace ID to include in rules"),
17947
18096
  project_name: external_exports.string().optional().describe("Project name to include in rules"),
17948
18097
  additional_rules: external_exports.string().optional().describe("Additional project-specific rules to append"),
17949
- mode: external_exports.enum(["minimal", "full"]).optional().describe("Rule verbosity mode (default: minimal)"),
17950
- overwrite_existing: external_exports.boolean().optional().describe("Allow overwriting existing rule files (ContextStream block only)"),
18098
+ mode: external_exports.enum(["minimal", "full", "bootstrap"]).optional().default("bootstrap").describe("Rule verbosity: bootstrap (~15 lines, recommended), minimal (~80 lines), full (~600 lines)"),
18099
+ overwrite_existing: external_exports.boolean().optional().default(true).describe("Overwrite ContextStream block in existing rule files (default: true). User content outside the block is preserved."),
17951
18100
  apply_global: external_exports.boolean().optional().describe("Also write global rule files for supported editors"),
17952
18101
  install_hooks: external_exports.boolean().optional().describe("Install Claude Code hooks to enforce ContextStream-first search. Defaults to true for Claude users. Set to false to skip."),
17953
- include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for automatic state saving before context compaction. Defaults to false."),
18102
+ include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for automatic state saving before context compaction. Defaults to true."),
17954
18103
  dry_run: external_exports.boolean().optional().describe("If true, return content without writing files")
17955
18104
  })
17956
18105
  },
@@ -18041,7 +18190,7 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
18041
18190
  { editor, file: "~/.claude/hooks/contextstream-reminder.py", status: "dry run - would create" },
18042
18191
  { editor, file: "~/.claude/settings.json", status: "dry run - would update" }
18043
18192
  );
18044
- if (input.include_pre_compact) {
18193
+ if (input.include_pre_compact !== false) {
18045
18194
  hooksResults.push({ editor, file: "~/.claude/hooks/contextstream-precompact.py", status: "dry run - would create" });
18046
18195
  }
18047
18196
  } else if (editor === "cline") {
@@ -18072,7 +18221,7 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
18072
18221
  const allHookResults = await installAllEditorHooks({
18073
18222
  scope: "global",
18074
18223
  editors: hookSupportedEditors,
18075
- includePreCompact: input.include_pre_compact
18224
+ includePreCompact: input.include_pre_compact !== false
18076
18225
  });
18077
18226
  for (const result of allHookResults) {
18078
18227
  for (const file of result.installed) {
@@ -18659,6 +18808,9 @@ Action: ${cp.suggested_action === "prepare_save" ? "Consider saving important de
18659
18808
  const instructionsLine = result.instructions ? `
18660
18809
 
18661
18810
  [INSTRUCTIONS] ${result.instructions}` : "";
18811
+ const contextRulesLine = `
18812
+
18813
+ ${CONTEXT_CALL_REMINDER}`;
18662
18814
  const allWarnings = [
18663
18815
  serverWarningsLine || lessonsWarningLine,
18664
18816
  // Server warnings OR client-side lesson detection
@@ -18671,6 +18823,8 @@ ${versionWarningLine}` : "",
18671
18823
  contextPressureWarning,
18672
18824
  semanticHints,
18673
18825
  instructionsLine,
18826
+ contextRulesLine,
18827
+ // Reinforce context() must be called every message
18674
18828
  searchRulesLine
18675
18829
  ].filter(Boolean).join("");
18676
18830
  const finalContext = postCompactContext + result.context;
@@ -19929,8 +20083,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
19929
20083
  code_refs: input.code_refs,
19930
20084
  provenance: input.provenance
19931
20085
  });
20086
+ const captureHint = getCaptureHint(input.event_type);
20087
+ const resultWithHint = { ...result, hint: captureHint };
19932
20088
  return {
19933
- content: [{ type: "text", text: formatContent(result) }]
20089
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
19934
20090
  };
19935
20091
  }
19936
20092
  case "capture_lesson": {
@@ -19986,8 +20142,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
19986
20142
  importance: input.severity === "critical" ? "critical" : input.severity === "high" ? "high" : "medium",
19987
20143
  tags: input.keywords || []
19988
20144
  });
20145
+ const lessonHint = getCaptureHint("lesson");
20146
+ const resultWithHint = { ...result, hint: lessonHint };
19989
20147
  return {
19990
- content: [{ type: "text", text: formatContent(result) }]
20148
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
19991
20149
  };
19992
20150
  }
19993
20151
  case "get_lessons": {
@@ -20000,8 +20158,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
20000
20158
  context_hint: input.query,
20001
20159
  limit: input.limit
20002
20160
  });
20161
+ const lessons = result?.data?.lessons || result?.lessons || [];
20162
+ const resultWithHint = Array.isArray(lessons) && lessons.length === 0 ? { ...result, hint: getEmptyStateHint("get_lessons") } : result;
20003
20163
  return {
20004
- content: [{ type: "text", text: formatContent(result) }]
20164
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20005
20165
  };
20006
20166
  }
20007
20167
  case "recall": {
@@ -20015,7 +20175,9 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
20015
20175
  include_related: input.include_related,
20016
20176
  include_decisions: input.include_decisions
20017
20177
  });
20018
- const outputText = formatContent(result);
20178
+ const recallResults = result?.data?.results || result?.results || [];
20179
+ const recallWithHint = Array.isArray(recallResults) && recallResults.length === 0 ? { ...result, hint: getEmptyStateHint("recall") } : result;
20180
+ const outputText = formatContent(recallWithHint);
20019
20181
  trackToolTokenSavings(client, "session_recall", outputText, {
20020
20182
  workspace_id: workspaceId,
20021
20183
  project_id: projectId
@@ -20035,8 +20197,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
20035
20197
  content: input.content,
20036
20198
  importance
20037
20199
  });
20200
+ const rememberHint = getCaptureHint("preference");
20201
+ const resultWithHint = { ...result, hint: rememberHint };
20038
20202
  return {
20039
- content: [{ type: "text", text: formatContent(result) }]
20203
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20040
20204
  };
20041
20205
  }
20042
20206
  case "user_context": {
@@ -20149,8 +20313,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
20149
20313
  source_tool: input.source_tool || "mcp",
20150
20314
  is_personal: input.is_personal
20151
20315
  });
20316
+ const planHint = getPlanStatusHint(input.status || "draft");
20317
+ const resultWithHint = { ...result, hint: planHint };
20152
20318
  return {
20153
- content: [{ type: "text", text: formatContent(result) }]
20319
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20154
20320
  };
20155
20321
  }
20156
20322
  case "get_plan": {
@@ -20180,8 +20346,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
20180
20346
  tags: input.tags,
20181
20347
  due_at: input.due_at
20182
20348
  });
20349
+ const planUpdateHint = input.status ? getPlanStatusHint(input.status) : "Plan updated. Changes are preserved.";
20350
+ const resultWithHint = { ...result, hint: planUpdateHint };
20183
20351
  return {
20184
- content: [{ type: "text", text: formatContent(result) }]
20352
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20185
20353
  };
20186
20354
  }
20187
20355
  case "list_plans": {
@@ -20195,8 +20363,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
20195
20363
  limit: input.limit,
20196
20364
  is_personal: input.is_personal
20197
20365
  });
20366
+ const plans = result?.data?.plans || result?.plans || result?.data?.items || result?.items || [];
20367
+ const resultWithHint = plans.length === 0 ? { ...result, hint: getEmptyStateHint("list_plans") } : result;
20198
20368
  return {
20199
- content: [{ type: "text", text: formatContent(result) }]
20369
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20200
20370
  };
20201
20371
  }
20202
20372
  case "restore_context": {
@@ -20690,8 +20860,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
20690
20860
  project_id: projectId,
20691
20861
  limit: input.limit
20692
20862
  });
20863
+ const events = result?.data?.items || result?.items || result?.data || [];
20864
+ const resultWithHint = Array.isArray(events) && events.length === 0 ? { ...result, hint: getEmptyStateHint("list_events") } : result;
20693
20865
  return {
20694
- content: [{ type: "text", text: formatContent(result) }]
20866
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20695
20867
  };
20696
20868
  }
20697
20869
  case "import_batch": {
@@ -20884,8 +21056,10 @@ ${formatContent(result)}`
20884
21056
  tags: input.tags,
20885
21057
  is_personal: input.is_personal
20886
21058
  });
21059
+ const taskCreateHint = TASK_HINTS.created;
21060
+ const resultWithHint = { ...result, hint: taskCreateHint };
20887
21061
  return {
20888
- content: [{ type: "text", text: formatContent(result) }]
21062
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20889
21063
  };
20890
21064
  }
20891
21065
  case "get_task": {
@@ -20917,8 +21091,17 @@ ${formatContent(result)}`
20917
21091
  tags: input.tags,
20918
21092
  blocked_reason: input.blocked_reason
20919
21093
  });
21094
+ let taskUpdateHint = "Task updated.";
21095
+ if (input.task_status === "completed") {
21096
+ taskUpdateHint = TASK_HINTS.completed;
21097
+ } else if (input.task_status === "blocked") {
21098
+ taskUpdateHint = TASK_HINTS.blocked;
21099
+ } else if (input.task_status === "cancelled") {
21100
+ taskUpdateHint = TASK_HINTS.cancelled;
21101
+ }
21102
+ const resultWithHint = { ...result, hint: taskUpdateHint };
20920
21103
  return {
20921
- content: [{ type: "text", text: formatContent(result) }]
21104
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20922
21105
  };
20923
21106
  }
20924
21107
  case "delete_task": {
@@ -20945,8 +21128,10 @@ ${formatContent(result)}`
20945
21128
  limit: input.limit,
20946
21129
  is_personal: input.is_personal
20947
21130
  });
21131
+ const tasks = result?.data?.tasks || result?.tasks || result?.data?.items || result?.items || [];
21132
+ const resultWithHint = Array.isArray(tasks) && tasks.length === 0 ? { ...result, hint: getEmptyStateHint("list_tasks") } : result;
20948
21133
  return {
20949
- content: [{ type: "text", text: formatContent(result) }]
21134
+ content: [{ type: "text", text: formatContent(resultWithHint) }]
20950
21135
  };
20951
21136
  }
20952
21137
  case "reorder_tasks": {
@@ -20998,8 +21183,10 @@ ${formatContent(result)}`
20998
21183
  priority: input.todo_priority,
20999
21184
  is_personal: input.is_personal
21000
21185
  });
21186
+ const todos = todosResult?.data?.todos || todosResult?.todos || todosResult?.data?.items || todosResult?.items || [];
21187
+ const todosWithHint = Array.isArray(todos) && todos.length === 0 ? { ...todosResult, hint: getEmptyStateHint("list_todos") } : todosResult;
21001
21188
  return {
21002
- content: [{ type: "text", text: formatContent(todosResult) }]
21189
+ content: [{ type: "text", text: formatContent(todosWithHint) }]
21003
21190
  };
21004
21191
  }
21005
21192
  case "get_todo": {
@@ -21075,8 +21262,10 @@ ${formatContent(result)}`
21075
21262
  diagram_type: input.diagram_type,
21076
21263
  is_personal: input.is_personal
21077
21264
  });
21265
+ const diagrams = diagramsResult?.data?.diagrams || diagramsResult?.diagrams || diagramsResult?.data?.items || diagramsResult?.items || [];
21266
+ const diagramsWithHint = Array.isArray(diagrams) && diagrams.length === 0 ? { ...diagramsResult, hint: getEmptyStateHint("list_diagrams") } : diagramsResult;
21078
21267
  return {
21079
- content: [{ type: "text", text: formatContent(diagramsResult) }]
21268
+ content: [{ type: "text", text: formatContent(diagramsWithHint) }]
21080
21269
  };
21081
21270
  }
21082
21271
  case "get_diagram": {
@@ -21120,13 +21309,19 @@ ${formatContent(result)}`
21120
21309
  if (!workspaceId) {
21121
21310
  return errorResult("create_doc requires workspace_id. Call session_init first.");
21122
21311
  }
21312
+ const detectedEditor = getDetectedClientName();
21313
+ const aiMetadata = detectedEditor ? {
21314
+ created_by_ai: true,
21315
+ ai_editor: detectedEditor,
21316
+ ...input.metadata || {}
21317
+ } : input.metadata;
21123
21318
  const docResult = await client.docsCreate({
21124
21319
  workspace_id: workspaceId,
21125
21320
  project_id: projectId,
21126
21321
  title: input.title,
21127
21322
  content: input.content,
21128
21323
  doc_type: input.doc_type,
21129
- metadata: input.metadata,
21324
+ metadata: aiMetadata,
21130
21325
  is_personal: input.is_personal
21131
21326
  });
21132
21327
  return {
@@ -21143,8 +21338,10 @@ ${formatContent(result)}`
21143
21338
  doc_type: input.doc_type,
21144
21339
  is_personal: input.is_personal
21145
21340
  });
21341
+ const docs = docsResult?.data?.docs || docsResult?.docs || docsResult?.data?.items || docsResult?.items || [];
21342
+ const docsWithHint = Array.isArray(docs) && docs.length === 0 ? { ...docsResult, hint: getEmptyStateHint("list_docs") } : docsResult;
21146
21343
  return {
21147
- content: [{ type: "text", text: formatContent(docsResult) }]
21344
+ content: [{ type: "text", text: formatContent(docsWithHint) }]
21148
21345
  };
21149
21346
  }
21150
21347
  case "get_doc": {
@@ -23042,14 +23239,14 @@ Content ID: ${input.content_id}`
23042
23239
  // For editor_rules
23043
23240
  folder_path: external_exports.string().optional(),
23044
23241
  editors: external_exports.array(external_exports.string()).optional(),
23045
- mode: external_exports.enum(["minimal", "full"]).optional(),
23242
+ mode: external_exports.enum(["minimal", "full", "bootstrap"]).optional(),
23046
23243
  dry_run: external_exports.boolean().optional(),
23047
23244
  workspace_id: external_exports.string().uuid().optional(),
23048
23245
  workspace_name: external_exports.string().optional(),
23049
23246
  project_name: external_exports.string().optional(),
23050
23247
  additional_rules: external_exports.string().optional(),
23051
23248
  install_hooks: external_exports.boolean().optional().describe("Install Claude Code hooks (PreToolUse, UserPromptSubmit, PostToolUse). Default: true for Claude users."),
23052
- include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for auto-saving state before compaction. Default: false."),
23249
+ include_pre_compact: external_exports.boolean().optional().describe("Include PreCompact hook for auto-saving state before compaction. Default: true."),
23053
23250
  include_post_write: external_exports.boolean().optional().describe("Include PostToolUse hook for real-time file indexing after Edit/Write operations. Default: true."),
23054
23251
  // For enable_bundle
23055
23252
  bundle: external_exports.enum([
@@ -23106,7 +23303,7 @@ Each domain tool has an 'action' parameter for specific operations.` : "";
23106
23303
  scope: input.folder_path ? "both" : "user",
23107
23304
  projectPath: input.folder_path,
23108
23305
  dryRun: input.dry_run,
23109
- includePreCompact: input.include_pre_compact,
23306
+ includePreCompact: input.include_pre_compact !== false,
23110
23307
  includePostWrite: input.include_post_write
23111
23308
  });
23112
23309
  } catch (err) {
@@ -23207,7 +23404,7 @@ function registerLimitedTools(server) {
23207
23404
  text: `ContextStream: API key not configured.
23208
23405
 
23209
23406
  To set up (creates key + configures your editor):
23210
- npx -y @contextstream/mcp-server setup
23407
+ npx --prefer-online -y @contextstream/mcp-server@latest setup
23211
23408
 
23212
23409
  This will:
23213
23410
  - Start a 5-day Pro trial
@@ -23215,7 +23412,7 @@ This will:
23215
23412
  - Write rules files for better AI assistance
23216
23413
 
23217
23414
  Preview first:
23218
- npx -y @contextstream/mcp-server setup --dry-run
23415
+ npx --prefer-online -y @contextstream/mcp-server@latest setup --dry-run
23219
23416
 
23220
23417
  After setup, restart your editor to enable all ContextStream tools.`
23221
23418
  }
@@ -25354,13 +25551,13 @@ function buildContextStreamMcpServer(params) {
25354
25551
  if (IS_WINDOWS) {
25355
25552
  return {
25356
25553
  command: "cmd",
25357
- args: ["/c", "npx", "-y", "@contextstream/mcp-server"],
25554
+ args: ["/c", "npx", "--prefer-online", "-y", "@contextstream/mcp-server@latest"],
25358
25555
  env
25359
25556
  };
25360
25557
  }
25361
25558
  return {
25362
25559
  command: "npx",
25363
- args: ["-y", "@contextstream/mcp-server"],
25560
+ args: ["--prefer-online", "-y", "@contextstream/mcp-server@latest"],
25364
25561
  env
25365
25562
  };
25366
25563
  }
@@ -25383,14 +25580,14 @@ function buildContextStreamVsCodeServer(params) {
25383
25580
  return {
25384
25581
  type: "stdio",
25385
25582
  command: "cmd",
25386
- args: ["/c", "npx", "-y", "@contextstream/mcp-server"],
25583
+ args: ["/c", "npx", "--prefer-online", "-y", "@contextstream/mcp-server@latest"],
25387
25584
  env
25388
25585
  };
25389
25586
  }
25390
25587
  return {
25391
25588
  type: "stdio",
25392
25589
  command: "npx",
25393
- args: ["-y", "@contextstream/mcp-server"],
25590
+ args: ["--prefer-online", "-y", "@contextstream/mcp-server@latest"],
25394
25591
  env
25395
25592
  };
25396
25593
  }
@@ -25484,9 +25681,9 @@ async function upsertCodexTomlConfig(filePath, params) {
25484
25681
  const showTimingLine = params.showTiming ? `CONTEXTSTREAM_SHOW_TIMING = "true"
25485
25682
  ` : "";
25486
25683
  const commandLine = IS_WINDOWS ? `command = "cmd"
25487
- args = ["/c", "npx", "-y", "@contextstream/mcp-server"]
25684
+ args = ["/c", "npx", "--prefer-online", "-y", "@contextstream/mcp-server@latest"]
25488
25685
  ` : `command = "npx"
25489
- args = ["-y", "@contextstream/mcp-server"]
25686
+ args = ["--prefer-online", "-y", "@contextstream/mcp-server@latest"]
25490
25687
  `;
25491
25688
  const block = `
25492
25689
 
@@ -25634,7 +25831,7 @@ async function runSetupWizard(args) {
25634
25831
  console.log(` Latest version is v${versionNotice.latest}`);
25635
25832
  console.log("");
25636
25833
  console.log(" To use the latest version, exit and run:");
25637
- console.log(" npx -y @contextstream/mcp-server@latest setup");
25834
+ console.log(" npx --prefer-online -y @contextstream/mcp-server@latest setup");
25638
25835
  console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
25639
25836
  console.log("");
25640
25837
  const continueAnyway = normalizeInput(
@@ -25839,7 +26036,7 @@ Code: ${device.user_code}`);
25839
26036
  }
25840
26037
  }
25841
26038
  }
25842
- const mode = "dynamic";
26039
+ const mode = "full";
25843
26040
  const detectedPlanName = await client.getPlanName();
25844
26041
  const detectedGraphTier = await client.getGraphTier();
25845
26042
  const graphTierLabel = detectedGraphTier === "full" ? "full graph" : detectedGraphTier === "lite" ? "graph-lite" : "none";
@@ -25989,10 +26186,10 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
25989
26186
  const envHint = toolset === "router" ? " --env CONTEXTSTREAM_PROGRESSIVE_MODE=true" : "";
25990
26187
  const packHint = contextPackEnabled === false ? " --env CONTEXTSTREAM_CONTEXT_PACK=false" : " --env CONTEXTSTREAM_CONTEXT_PACK=true";
25991
26188
  console.log(
25992
- ` macOS/Linux: claude mcp add --transport stdio contextstream --scope user --env CONTEXTSTREAM_API_URL=... --env CONTEXTSTREAM_API_KEY=...${envHint}${packHint} -- npx -y @contextstream/mcp-server`
26189
+ ` macOS/Linux: claude mcp add --transport stdio contextstream --scope user --env CONTEXTSTREAM_API_URL=... --env CONTEXTSTREAM_API_KEY=...${envHint}${packHint} -- npx --prefer-online -y @contextstream/mcp-server@latest`
25993
26190
  );
25994
26191
  console.log(
25995
- " Windows (native): use `cmd /c npx -y @contextstream/mcp-server` after `--` if `npx` is not found."
26192
+ " Windows (native): use `cmd /c npx --prefer-online -y @contextstream/mcp-server@latest` after `--` if `npx` is not found."
25996
26193
  );
25997
26194
  continue;
25998
26195
  }
@@ -26327,7 +26524,7 @@ function printHelp() {
26327
26524
  console.log(`ContextStream MCP Server (contextstream-mcp) v${VERSION}
26328
26525
 
26329
26526
  Usage:
26330
- npx -y @contextstream/mcp-server
26527
+ npx --prefer-online -y @contextstream/mcp-server@latest
26331
26528
  contextstream-mcp
26332
26529
  contextstream-mcp setup
26333
26530
  contextstream-mcp http
@@ -26374,10 +26571,10 @@ Environment variables:
26374
26571
  Examples:
26375
26572
  CONTEXTSTREAM_API_URL="https://api.contextstream.io" \\
26376
26573
  CONTEXTSTREAM_API_KEY="your_api_key" \\
26377
- npx -y @contextstream/mcp-server
26574
+ npx --prefer-online -y @contextstream/mcp-server@latest
26378
26575
 
26379
26576
  Setup wizard:
26380
- npx -y @contextstream/mcp-server setup
26577
+ npx --prefer-online -y @contextstream/mcp-server@latest setup
26381
26578
 
26382
26579
  Notes:
26383
26580
  - When used from an MCP client (e.g. Codex, Cursor, VS Code),
@@ -26391,7 +26588,7 @@ async function runLimitedModeServer() {
26391
26588
  });
26392
26589
  registerLimitedTools(server);
26393
26590
  console.error(`ContextStream MCP server v${VERSION} (limited mode)`);
26394
- console.error('Run "npx -y @contextstream/mcp-server setup" to enable all tools.');
26591
+ console.error('Run "npx --prefer-online -y @contextstream/mcp-server@latest setup" to enable all tools.');
26395
26592
  const transport = new StdioServerTransport();
26396
26593
  await server.connect(transport);
26397
26594
  console.error("ContextStream MCP server connected (limited mode - setup required)");
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contextstream/mcp-server",
3
3
  "mcpName": "io.github.contextstreamio/mcp-server",
4
- "version": "0.4.47",
4
+ "version": "0.4.49",
5
5
  "description": "ContextStream MCP server - v0.4.x with consolidated domain tools (~11 tools, ~75% token reduction). Code context, memory, search, and AI tools.",
6
6
  "type": "module",
7
7
  "license": "MIT",