@contextstream/mcp-server 0.4.44 → 0.4.45
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.
- package/README.md +92 -211
- package/dist/hooks/auto-rules.js +912 -0
- package/dist/hooks/media-aware.js +103 -0
- package/dist/hooks/post-write.js +341 -0
- package/dist/hooks/pre-compact.js +229 -0
- package/dist/hooks/pre-tool-use.js +236 -0
- package/dist/hooks/user-prompt-submit.js +69 -0
- package/dist/index.js +11659 -10452
- package/package.json +3 -2
|
@@ -0,0 +1,912 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/version.ts
|
|
13
|
+
import { createRequire } from "module";
|
|
14
|
+
function getVersion() {
|
|
15
|
+
try {
|
|
16
|
+
const require2 = createRequire(import.meta.url);
|
|
17
|
+
const pkg = require2("../package.json");
|
|
18
|
+
const version = pkg?.version;
|
|
19
|
+
if (typeof version === "string" && version.trim()) return version.trim();
|
|
20
|
+
} catch {
|
|
21
|
+
}
|
|
22
|
+
return "unknown";
|
|
23
|
+
}
|
|
24
|
+
var VERSION, CACHE_TTL_MS;
|
|
25
|
+
var init_version = __esm({
|
|
26
|
+
"src/version.ts"() {
|
|
27
|
+
"use strict";
|
|
28
|
+
VERSION = getVersion();
|
|
29
|
+
CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// src/rules-templates.ts
|
|
34
|
+
var rules_templates_exports = {};
|
|
35
|
+
__export(rules_templates_exports, {
|
|
36
|
+
RULES_VERSION: () => RULES_VERSION,
|
|
37
|
+
TEMPLATES: () => TEMPLATES,
|
|
38
|
+
generateAllRuleFiles: () => generateAllRuleFiles,
|
|
39
|
+
generateRuleContent: () => generateRuleContent,
|
|
40
|
+
getAvailableEditors: () => getAvailableEditors,
|
|
41
|
+
getTemplate: () => getTemplate
|
|
42
|
+
});
|
|
43
|
+
function applyMcpToolPrefix(markdown, toolPrefix) {
|
|
44
|
+
const toolPattern = CONTEXTSTREAM_TOOL_NAMES.join("|");
|
|
45
|
+
const toolRegex = new RegExp(`(?<!__)\\b(${toolPattern})\\b(?=\\s*\\()`, "g");
|
|
46
|
+
return markdown.replace(toolRegex, `${toolPrefix}$1`);
|
|
47
|
+
}
|
|
48
|
+
function getAvailableEditors() {
|
|
49
|
+
return Object.keys(TEMPLATES);
|
|
50
|
+
}
|
|
51
|
+
function getTemplate(editor) {
|
|
52
|
+
return TEMPLATES[editor.toLowerCase()] || null;
|
|
53
|
+
}
|
|
54
|
+
function generateRuleContent(editor, options) {
|
|
55
|
+
const template = getTemplate(editor);
|
|
56
|
+
if (!template) return null;
|
|
57
|
+
const mode = options?.mode || "dynamic";
|
|
58
|
+
const rules = mode === "full" ? CONTEXTSTREAM_RULES_FULL : mode === "minimal" ? CONTEXTSTREAM_RULES_MINIMAL : CONTEXTSTREAM_RULES_DYNAMIC;
|
|
59
|
+
let content = template.build(rules);
|
|
60
|
+
if (options?.workspaceName || options?.projectName) {
|
|
61
|
+
const header = `
|
|
62
|
+
# Workspace: ${options.workspaceName || "Unknown"}
|
|
63
|
+
${options.projectName ? `# Project: ${options.projectName}` : ""}
|
|
64
|
+
${options.workspaceId ? `# Workspace ID: ${options.workspaceId}` : ""}
|
|
65
|
+
|
|
66
|
+
`;
|
|
67
|
+
content = header + content;
|
|
68
|
+
}
|
|
69
|
+
if (options?.additionalRules) {
|
|
70
|
+
content += "\n\n## Project-Specific Rules\n\n" + options.additionalRules;
|
|
71
|
+
}
|
|
72
|
+
if (editor.toLowerCase() === "claude") {
|
|
73
|
+
content = applyMcpToolPrefix(content, `mcp__${DEFAULT_CLAUDE_MCP_SERVER_NAME}__`);
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
filename: template.filename,
|
|
77
|
+
content: content.trim() + "\n"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function generateAllRuleFiles(options) {
|
|
81
|
+
return getAvailableEditors().map((editor) => {
|
|
82
|
+
const result = generateRuleContent(editor, options);
|
|
83
|
+
if (!result) return null;
|
|
84
|
+
return { editor, ...result };
|
|
85
|
+
}).filter((r) => r !== null);
|
|
86
|
+
}
|
|
87
|
+
var DEFAULT_CLAUDE_MCP_SERVER_NAME, RULES_VERSION, CONTEXTSTREAM_TOOL_NAMES, CONTEXTSTREAM_RULES_DYNAMIC, CONTEXTSTREAM_RULES_FULL, CONTEXTSTREAM_RULES_MINIMAL, TEMPLATES;
|
|
88
|
+
var init_rules_templates = __esm({
|
|
89
|
+
"src/rules-templates.ts"() {
|
|
90
|
+
"use strict";
|
|
91
|
+
init_version();
|
|
92
|
+
DEFAULT_CLAUDE_MCP_SERVER_NAME = "contextstream";
|
|
93
|
+
RULES_VERSION = VERSION === "unknown" ? "0.0.0" : VERSION;
|
|
94
|
+
CONTEXTSTREAM_TOOL_NAMES = [
|
|
95
|
+
// Standalone tools (always present)
|
|
96
|
+
"init",
|
|
97
|
+
// Renamed from session_init - initialize conversation session
|
|
98
|
+
"context",
|
|
99
|
+
// Renamed from context_smart - get relevant context every message
|
|
100
|
+
"context_feedback",
|
|
101
|
+
"generate_rules",
|
|
102
|
+
// Consolidated domain tools (v0.4.x default)
|
|
103
|
+
"search",
|
|
104
|
+
// Modes: semantic, hybrid, keyword, pattern
|
|
105
|
+
"session",
|
|
106
|
+
// Actions: capture, capture_lesson, get_lessons, recall, remember, user_context, summary, compress, delta, smart_search, decision_trace
|
|
107
|
+
"memory",
|
|
108
|
+
// Actions: create_event, get_event, update_event, delete_event, list_events, distill_event, create_node, get_node, update_node, delete_node, list_nodes, supersede_node, search, decisions, timeline, summary
|
|
109
|
+
"graph",
|
|
110
|
+
// Actions: dependencies, impact, call_path, related, path, decisions, ingest, circular_dependencies, unused_code, contradictions
|
|
111
|
+
"project",
|
|
112
|
+
// Actions: list, get, create, update, index, overview, statistics, files, index_status, ingest_local
|
|
113
|
+
"workspace",
|
|
114
|
+
// Actions: list, get, associate, bootstrap
|
|
115
|
+
"reminder",
|
|
116
|
+
// Actions: list, active, create, snooze, complete, dismiss
|
|
117
|
+
"integration",
|
|
118
|
+
// Provider: slack, github, all; Actions: status, search, stats, activity, contributors, knowledge, summary, channels, discussions, sync_users, repos, issues
|
|
119
|
+
"help"
|
|
120
|
+
// Actions: tools, auth, version, editor_rules, enable_bundle
|
|
121
|
+
];
|
|
122
|
+
CONTEXTSTREAM_RULES_DYNAMIC = `
|
|
123
|
+
## ContextStream Dynamic Rules (Powered by our SmartRouter)
|
|
124
|
+
|
|
125
|
+
All rules are served dynamically via \`context\`. This file is minimal by design.
|
|
126
|
+
|
|
127
|
+
### Every Message Protocol
|
|
128
|
+
|
|
129
|
+
| Message | What to Call |
|
|
130
|
+
|---------|--------------|
|
|
131
|
+
| **1st message** | \`init()\` then \`context(user_message="<msg>")\` |
|
|
132
|
+
| **2nd+ messages** | \`context(user_message="<msg>")\` |
|
|
133
|
+
|
|
134
|
+
Note: \`init()\` auto-detects folder from IDE. Only pass \`folder_path\` if auto-detection fails.
|
|
135
|
+
|
|
136
|
+
### Follow the Instructions Field
|
|
137
|
+
|
|
138
|
+
The \`context\` response includes an \`instructions\` field with context-aware guidance.
|
|
139
|
+
**Follow these instructions.** They are dynamically matched to your query and include:
|
|
140
|
+
- Search guidance (when/how to search)
|
|
141
|
+
- Git workflow rules (commit, PR, safety)
|
|
142
|
+
- Planning rules (use ContextStream plans, not file-based)
|
|
143
|
+
- Media/code analysis guidance
|
|
144
|
+
- Lessons from past mistakes
|
|
145
|
+
- And more...
|
|
146
|
+
|
|
147
|
+
### Notices
|
|
148
|
+
|
|
149
|
+
Handle notices from \`context\` response:
|
|
150
|
+
- **[VERSION_NOTICE]**: Tell user to update MCP
|
|
151
|
+
- **[RULES_NOTICE]**: Run \`generate_rules()\`
|
|
152
|
+
- **[LESSONS_WARNING]**: Apply lessons immediately
|
|
153
|
+
|
|
154
|
+
Rules Version: ${RULES_VERSION}
|
|
155
|
+
`.trim();
|
|
156
|
+
CONTEXTSTREAM_RULES_FULL = `
|
|
157
|
+
## ContextStream Rules
|
|
158
|
+
|
|
159
|
+
<contextstream_rules>
|
|
160
|
+
1. **SIMPLE UTILITY?** (list/show/version) \u2192 Just execute, skip context calls
|
|
161
|
+
2. **CODING TASK?** \u2192 init \u2192 context \u2192 work \u2192 capture
|
|
162
|
+
3. **SEARCH FIRST:** Before Glob/Grep/Read \u2192 \`search(mode="hybrid")\` FIRST
|
|
163
|
+
</contextstream_rules>
|
|
164
|
+
|
|
165
|
+
**Display this block at the start of responses to keep rules in context.**
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## \u{1F6A8} CRITICAL RULE #1 - CONTEXTSTREAM SEARCH FIRST \u{1F6A8}
|
|
170
|
+
|
|
171
|
+
**BEFORE using Glob, Grep, Search, Read (for discovery), Explore, or ANY local file scanning:**
|
|
172
|
+
\`\`\`
|
|
173
|
+
STOP \u2192 Call search(mode="hybrid", query="...") FIRST
|
|
174
|
+
\`\`\`
|
|
175
|
+
|
|
176
|
+
**Note:** PreToolUse hooks block these tools when ContextStream is available.
|
|
177
|
+
**Claude Code users:** Your tool names are \`mcp__contextstream__search\`, \`mcp__contextstream__init\`, etc.
|
|
178
|
+
|
|
179
|
+
\u274C **NEVER DO THIS:**
|
|
180
|
+
- \`Glob("**/*.ts")\` \u2192 Use \`search(mode="pattern", query="*.ts")\` instead
|
|
181
|
+
- \`Grep("functionName")\` \u2192 Use \`search(mode="keyword", query="functionName")\` instead
|
|
182
|
+
- \`Read(file)\` for discovery \u2192 Use \`search(mode="hybrid", query="...")\` instead
|
|
183
|
+
- \`Task(subagent_type="Explore")\` \u2192 Use \`search(mode="hybrid")\` instead
|
|
184
|
+
|
|
185
|
+
\u2705 **ALWAYS DO THIS:**
|
|
186
|
+
1. \`search(mode="hybrid", query="what you're looking for")\`
|
|
187
|
+
2. Only use local tools (Glob/Grep/Read) if ContextStream returns **0 results**
|
|
188
|
+
3. Use Read ONLY for exact file edits after you know the file path
|
|
189
|
+
|
|
190
|
+
This applies to **EVERY search** throughout the **ENTIRE conversation**, not just the first message.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## \u{1F6A8} CRITICAL RULE #2 - AUTO-INDEXING \u{1F6A8}
|
|
195
|
+
|
|
196
|
+
**ContextStream auto-indexes your project on \`init\`.** You do NOT need to:
|
|
197
|
+
- Ask the user to index
|
|
198
|
+
- Manually trigger ingestion
|
|
199
|
+
- Check index_status before every search
|
|
200
|
+
|
|
201
|
+
**When \`init\` returns \`indexing_status: "started"\` or \`"refreshing"\`:**
|
|
202
|
+
- Background indexing is running automatically
|
|
203
|
+
- Search results will be available within seconds to minutes
|
|
204
|
+
- **DO NOT fall back to local tools** - wait for ContextStream search to work
|
|
205
|
+
- If search returns 0 results initially, try again after a moment
|
|
206
|
+
|
|
207
|
+
**Only manually trigger indexing if:**
|
|
208
|
+
- \`init\` returned \`ingest_recommendation.recommended: true\` (rare edge case)
|
|
209
|
+
- User explicitly asks to re-index
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## \u{1F6A8} CRITICAL RULE #3 - LESSONS (PAST MISTAKES) \u{1F6A8}
|
|
214
|
+
|
|
215
|
+
**Lessons are past mistakes that MUST inform your work.** Ignoring lessons leads to repeated failures.
|
|
216
|
+
|
|
217
|
+
### On \`init\`:
|
|
218
|
+
- Check for \`lessons\` and \`lessons_warning\` in the response
|
|
219
|
+
- If present, **READ THEM IMMEDIATELY** before doing any work
|
|
220
|
+
- These are high-priority lessons (critical/high severity) relevant to your context
|
|
221
|
+
- **Apply the prevention steps** from each lesson to avoid repeating mistakes
|
|
222
|
+
|
|
223
|
+
### On \`context\`:
|
|
224
|
+
- Check for \`[LESSONS_WARNING]\` tag in the response
|
|
225
|
+
- If present, you **MUST** tell the user about the lessons before proceeding
|
|
226
|
+
- Lessons are proactively fetched when risky actions are detected (refactor, migrate, deploy, etc.)
|
|
227
|
+
- **Do not skip or bury this warning** - lessons represent real past mistakes
|
|
228
|
+
|
|
229
|
+
### Before ANY Non-Trivial Work:
|
|
230
|
+
**ALWAYS call \`session(action="get_lessons", query="<topic>")\`** where \`<topic>\` matches what you're about to do:
|
|
231
|
+
- Before refactoring \u2192 \`session(action="get_lessons", query="refactoring")\`
|
|
232
|
+
- Before API changes \u2192 \`session(action="get_lessons", query="API changes")\`
|
|
233
|
+
- Before database work \u2192 \`session(action="get_lessons", query="database migrations")\`
|
|
234
|
+
- Before deployments \u2192 \`session(action="get_lessons", query="deployment")\`
|
|
235
|
+
|
|
236
|
+
### When Lessons Are Found:
|
|
237
|
+
1. **Summarize the lessons** to the user before proceeding
|
|
238
|
+
2. **Explicitly state how you will avoid the past mistakes**
|
|
239
|
+
3. If a lesson conflicts with the current approach, **warn the user**
|
|
240
|
+
|
|
241
|
+
**Failing to check lessons before risky work is a critical error.**
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## ContextStream v0.4.x Integration (Enhanced)
|
|
246
|
+
|
|
247
|
+
You have access to ContextStream MCP tools for persistent memory and context.
|
|
248
|
+
v0.4.x uses **~11 consolidated domain tools** for ~75% token reduction vs previous versions.
|
|
249
|
+
Rules Version: ${RULES_VERSION}
|
|
250
|
+
|
|
251
|
+
## TL;DR - WHEN TO USE CONTEXT
|
|
252
|
+
|
|
253
|
+
| Request Type | What to Do |
|
|
254
|
+
|--------------|------------|
|
|
255
|
+
| **\u{1F680} Simple utility** (list workspaces, show version) | **Just execute directly** - skip init, context, capture |
|
|
256
|
+
| **\u{1F4BB} Coding task** (edit, create, refactor) | Full context: init \u2192 context \u2192 work \u2192 capture |
|
|
257
|
+
| **\u{1F50D} Code search/discovery** | init \u2192 context \u2192 search() |
|
|
258
|
+
| **\u26A0\uFE0F Risky work** (deploy, migrate, refactor) | Check lessons first: \`session(action="get_lessons")\` |
|
|
259
|
+
| **User frustration/correction** | Capture lesson: \`session(action="capture_lesson", ...)\` |
|
|
260
|
+
|
|
261
|
+
### Simple Utility Operations - FAST PATH
|
|
262
|
+
|
|
263
|
+
**For simple queries, just execute and respond:**
|
|
264
|
+
- "list workspaces" \u2192 \`workspace(action="list")\` \u2192 done
|
|
265
|
+
- "list projects" \u2192 \`project(action="list")\` \u2192 done
|
|
266
|
+
- "show version" \u2192 \`help(action="version")\` \u2192 done
|
|
267
|
+
- "what reminders do I have" \u2192 \`reminder(action="list")\` \u2192 done
|
|
268
|
+
|
|
269
|
+
**No init. No context. No capture.** These add noise, not value.
|
|
270
|
+
|
|
271
|
+
### Coding Tasks - FULL CONTEXT
|
|
272
|
+
|
|
273
|
+
| Step | What to Call |
|
|
274
|
+
|------|--------------|
|
|
275
|
+
| **1st message** | \`init(folder_path="...", context_hint="<msg>")\`, then \`context(...)\` |
|
|
276
|
+
| **2nd+ messages** | \`context(user_message="<msg>", format="minified", max_tokens=400)\` |
|
|
277
|
+
| **Code search** | \`search(mode="hybrid", query="...")\` \u2014 BEFORE Glob/Grep/Read |
|
|
278
|
+
| **After significant work** | \`session(action="capture", event_type="decision", ...)\` |
|
|
279
|
+
| **User correction** | \`session(action="capture_lesson", ...)\` |
|
|
280
|
+
| **\u26A0\uFE0F When warnings received** | **STOP**, acknowledge, explain mitigation, then proceed |
|
|
281
|
+
|
|
282
|
+
**How to detect simple utility operations:**
|
|
283
|
+
- Single-word commands: "list", "show", "version", "help"
|
|
284
|
+
- Data retrieval with no context dependency: "list my workspaces", "what projects do I have"
|
|
285
|
+
- Status checks: "am I authenticated?", "what's the server version?"
|
|
286
|
+
|
|
287
|
+
**First message rule (for coding tasks):** After \`init\`:
|
|
288
|
+
1. Check for \`lessons\` in response - if present, READ and SUMMARIZE them to user
|
|
289
|
+
2. Then call \`context\` before any other tool or response
|
|
290
|
+
|
|
291
|
+
**Context Pack (Pro+):** If enabled, use \`context(..., mode="pack", distill=true)\` for code/file queries. If unavailable or disabled, omit \`mode\` and proceed with standard \`context\` (the API will fall back).
|
|
292
|
+
|
|
293
|
+
**Tool naming:** Use the exact tool names exposed by your MCP client. Claude Code typically uses \`mcp__<server>__<tool>\` where \`<server>\` matches your MCP config (often \`contextstream\`). If a tool call fails with "No such tool available", refresh rules and match the tool list.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Consolidated Domain Tools Architecture
|
|
298
|
+
|
|
299
|
+
v0.4.x consolidates ~58 individual tools into ~11 domain tools with action/mode dispatch:
|
|
300
|
+
|
|
301
|
+
### Standalone Tools
|
|
302
|
+
- **\`init\`** - Initialize session with workspace detection + context (skip for simple utility operations)
|
|
303
|
+
- **\`context\`** - Semantic search for relevant context (skip for simple utility operations)
|
|
304
|
+
|
|
305
|
+
### Domain Tools (Use action/mode parameter)
|
|
306
|
+
|
|
307
|
+
| Domain | Actions/Modes | Example |
|
|
308
|
+
|--------|---------------|---------|
|
|
309
|
+
| **\`search\`** | mode: semantic, hybrid, keyword, pattern | \`search(mode="hybrid", query="auth implementation", limit=3)\` |
|
|
310
|
+
| **\`session\`** | action: capture, capture_lesson, get_lessons, recall, remember, user_context, summary, compress, delta, smart_search, decision_trace | \`session(action="capture", event_type="decision", title="Use JWT", content="...")\` |
|
|
311
|
+
| **\`memory\`** | action: create_event, get_event, update_event, delete_event, list_events, distill_event, create_node, get_node, update_node, delete_node, list_nodes, supersede_node, search, decisions, timeline, summary | \`memory(action="list_events", limit=10)\` |
|
|
312
|
+
| **\`graph\`** | action: dependencies, impact, call_path, related, path, decisions, ingest, circular_dependencies, unused_code, contradictions | \`graph(action="impact", symbol_name="AuthService")\` |
|
|
313
|
+
| **\`project\`** | action: list, get, create, update, index, overview, statistics, files, index_status, ingest_local | \`project(action="statistics")\` |
|
|
314
|
+
| **\`workspace\`** | action: list, get, associate, bootstrap | \`workspace(action="list")\` |
|
|
315
|
+
| **\`reminder\`** | action: list, active, create, snooze, complete, dismiss | \`reminder(action="active")\` |
|
|
316
|
+
| **\`integration\`** | provider: slack/github/all; action: status, search, stats, activity, contributors, knowledge, summary, channels, discussions, sync_users, repos, issues | \`integration(provider="github", action="search", query="...")\` |
|
|
317
|
+
| **\`help\`** | action: tools, auth, version, editor_rules, enable_bundle | \`help(action="tools")\` |
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
### Why context is Required (Even After init)
|
|
322
|
+
|
|
323
|
+
**Common mistake:** "init already gave me context, I don't need context"
|
|
324
|
+
|
|
325
|
+
**This is WRONG. Here's why:**
|
|
326
|
+
- \`init\` returns the last ~10 items **BY TIME** (chronological)
|
|
327
|
+
- \`context\` **SEARCHES** for items **RELEVANT to THIS message** (semantic)
|
|
328
|
+
|
|
329
|
+
**Example failure:**
|
|
330
|
+
- User asks: "how should I implement authentication?"
|
|
331
|
+
- Auth decisions were made 20 conversations ago
|
|
332
|
+
- \`init\` won't have it (too old, not in recent 10)
|
|
333
|
+
- \`context\` FINDS it via semantic search
|
|
334
|
+
|
|
335
|
+
**Without context, you WILL miss relevant older context.**
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
### Recommended Token Budgets
|
|
340
|
+
|
|
341
|
+
- For trivial/local edits: \`context(..., max_tokens=200)\`
|
|
342
|
+
- Default: \`context(..., max_tokens=400)\`
|
|
343
|
+
- Deep debugging/architecture: \`context(..., max_tokens=800)\`
|
|
344
|
+
- Keep \`format="minified"\` (default) unless debugging
|
|
345
|
+
|
|
346
|
+
If context still feels missing, use \`session(action="recall", query="...")\` for focused deep lookup.
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
### Rules, Version & Lessons Notices
|
|
351
|
+
|
|
352
|
+
**[RULES_NOTICE]** - Update rules via \`generate_rules()\` (or rerun setup).
|
|
353
|
+
|
|
354
|
+
**[VERSION_NOTICE]** - You **MUST IMMEDIATELY** tell the user:
|
|
355
|
+
1. A new MCP server version is available
|
|
356
|
+
2. The exact update command to run
|
|
357
|
+
3. That they need to restart their AI tool after updating
|
|
358
|
+
**Do not skip this** - users often miss stderr warnings.
|
|
359
|
+
|
|
360
|
+
**[LESSONS_WARNING]** - You **MUST** before proceeding:
|
|
361
|
+
1. Read all lessons listed
|
|
362
|
+
2. Tell the user about relevant lessons
|
|
363
|
+
3. Explain how you will avoid each past mistake
|
|
364
|
+
**This is critical** - ignoring lessons leads to repeated failures.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
### Preferences & Lessons (Use Early)
|
|
369
|
+
|
|
370
|
+
- If preferences/style matter: \`session(action="user_context")\`
|
|
371
|
+
- Before risky changes: \`session(action="get_lessons", query="<topic>")\`
|
|
372
|
+
- On frustration/corrections: \`session(action="capture_lesson", title="...", trigger="...", impact="...", prevention="...")\`
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### Context Pressure & Compaction Awareness
|
|
377
|
+
|
|
378
|
+
ContextStream tracks context pressure to help you stay ahead of conversation compaction:
|
|
379
|
+
|
|
380
|
+
**Automatic tracking:** Token usage is tracked automatically. \`context\` returns \`context_pressure\` when usage is high.
|
|
381
|
+
|
|
382
|
+
**When \`context\` returns \`context_pressure\` with high/critical level:**
|
|
383
|
+
1. Review the \`suggested_action\` field:
|
|
384
|
+
- \`prepare_save\`: Start thinking about saving important state
|
|
385
|
+
- \`save_now\`: Immediately call \`session(action="capture", event_type="session_snapshot")\` to preserve state
|
|
386
|
+
|
|
387
|
+
**PreCompact Hook (Optional):** If enabled, Claude Code will inject a reminder to save state before compaction.
|
|
388
|
+
Enable with: \`generate_rules(install_hooks=true, include_pre_compact=true)\`
|
|
389
|
+
|
|
390
|
+
**Before compaction happens (when warned):**
|
|
391
|
+
\`\`\`
|
|
392
|
+
session(action="capture", event_type="session_snapshot", title="Pre-compaction snapshot", content="{
|
|
393
|
+
\\"conversation_summary\\": \\"<summarize what we've been doing>\\",
|
|
394
|
+
\\"current_goal\\": \\"<the main task>\\",
|
|
395
|
+
\\"active_files\\": [\\"file1.ts\\", \\"file2.ts\\"],
|
|
396
|
+
\\"recent_decisions\\": [{title: \\"...\\", rationale: \\"...\\"}],
|
|
397
|
+
\\"unfinished_work\\": [{task: \\"...\\", status: \\"...\\", next_steps: \\"...\\"}]
|
|
398
|
+
}")
|
|
399
|
+
\`\`\`
|
|
400
|
+
|
|
401
|
+
**After compaction (when context seems lost):**
|
|
402
|
+
1. Call \`init(folder_path="...", is_post_compact=true)\` - this auto-restores the most recent snapshot
|
|
403
|
+
2. Or call \`session_restore_context()\` directly to get the saved state
|
|
404
|
+
3. Review the \`restored_context\` to understand prior work
|
|
405
|
+
4. Acknowledge to the user what was restored and continue
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
### Index Status (Auto-Managed)
|
|
410
|
+
|
|
411
|
+
**Indexing is automatic.** After \`init\`, the project is auto-indexed in the background.
|
|
412
|
+
|
|
413
|
+
**You do NOT need to manually check index_status before every search.** Just use \`search()\`.
|
|
414
|
+
|
|
415
|
+
**If search returns 0 results and you expected matches:**
|
|
416
|
+
1. Check if \`init\` returned \`indexing_status: "started"\` - indexing may still be in progress
|
|
417
|
+
2. Wait a moment and retry \`search()\`
|
|
418
|
+
3. Only as a last resort: \`project(action="index_status")\` to check
|
|
419
|
+
|
|
420
|
+
**Graph data:** If graph queries (\`dependencies\`, \`impact\`) return empty, run \`graph(action="ingest")\` once.
|
|
421
|
+
|
|
422
|
+
**NEVER fall back to local tools (Glob/Grep/Read) just because search returned 0 results on first try.** Retry first.
|
|
423
|
+
|
|
424
|
+
### Enhanced Context (Server-Side Warnings)
|
|
425
|
+
|
|
426
|
+
\`context\` now includes **intelligent server-side filtering** that proactively surfaces relevant warnings:
|
|
427
|
+
|
|
428
|
+
**Response fields:**
|
|
429
|
+
- \`warnings\`: Array of warning strings (displayed with \u26A0\uFE0F prefix)
|
|
430
|
+
|
|
431
|
+
**What triggers warnings:**
|
|
432
|
+
- **Lessons**: Past mistakes relevant to the current query (via semantic matching)
|
|
433
|
+
- **Risky actions**: Detected high-risk operations (deployments, migrations, destructive commands)
|
|
434
|
+
- **Breaking changes**: When modifications may impact other parts of the codebase
|
|
435
|
+
|
|
436
|
+
**When you receive warnings:**
|
|
437
|
+
1. **STOP** and read each warning carefully
|
|
438
|
+
2. **Acknowledge** the warning to the user
|
|
439
|
+
3. **Explain** how you will avoid the issue
|
|
440
|
+
4. Only proceed after addressing the warnings
|
|
441
|
+
|
|
442
|
+
### Search & Code Intelligence (ContextStream-first)
|
|
443
|
+
|
|
444
|
+
\u26A0\uFE0F **STOP: Before using Search/Glob/Grep/Read/Explore** \u2192 Call \`search(mode="hybrid")\` FIRST. Use local tools ONLY if ContextStream returns 0 results.
|
|
445
|
+
|
|
446
|
+
**\u274C WRONG workflow (wastes tokens, slow):**
|
|
447
|
+
\`\`\`
|
|
448
|
+
Grep "function" \u2192 Read file1.ts \u2192 Read file2.ts \u2192 Read file3.ts \u2192 finally understand
|
|
449
|
+
\`\`\`
|
|
450
|
+
|
|
451
|
+
**\u2705 CORRECT workflow (fast, complete):**
|
|
452
|
+
\`\`\`
|
|
453
|
+
search(mode="hybrid", query="function implementation") \u2192 done (results include context)
|
|
454
|
+
\`\`\`
|
|
455
|
+
|
|
456
|
+
**Why?** ContextStream search returns semantic matches + context + file locations in ONE call. Local tools require multiple round-trips.
|
|
457
|
+
|
|
458
|
+
**Search order:**
|
|
459
|
+
1. \`session(action="smart_search", query="...")\` - context-enriched
|
|
460
|
+
2. \`search(mode="hybrid", query="...", limit=3)\` or \`search(mode="keyword", query="<filename>", limit=3)\`
|
|
461
|
+
3. \`project(action="files")\` - file tree/list (only when needed)
|
|
462
|
+
4. \`graph(action="dependencies", ...)\` - code structure
|
|
463
|
+
5. Local repo scans (rg/ls/find) - ONLY if ContextStream returns no results, errors, or the user explicitly asks
|
|
464
|
+
|
|
465
|
+
**Search Mode Selection:**
|
|
466
|
+
|
|
467
|
+
| Need | Mode | Example |
|
|
468
|
+
|------|------|---------|
|
|
469
|
+
| Find code by meaning | \`hybrid\` | "authentication logic", "error handling" |
|
|
470
|
+
| Exact string/symbol | \`keyword\` | "UserAuthService", "API_KEY" |
|
|
471
|
+
| File patterns | \`pattern\` | "*.sql", "test_*.py" |
|
|
472
|
+
| ALL matches (grep-like) | \`exhaustive\` | "TODO", "FIXME" (find all occurrences) |
|
|
473
|
+
| Symbol renaming | \`refactor\` | "oldFunctionName" (word-boundary matching) |
|
|
474
|
+
| Conceptual search | \`semantic\` | "how does caching work" |
|
|
475
|
+
|
|
476
|
+
**Token Efficiency:** Use \`output_format\` to reduce response size:
|
|
477
|
+
- \`full\` (default): Full content for understanding code
|
|
478
|
+
- \`paths\`: File paths only (80% token savings) - use for file listings
|
|
479
|
+
- \`minimal\`: Compact format (60% savings) - use for refactoring
|
|
480
|
+
- \`count\`: Match counts only (90% savings) - use for quick checks
|
|
481
|
+
|
|
482
|
+
**When to use \`output_format=count\`:**
|
|
483
|
+
- User asks "how many X" or "count of X" \u2192 \`search(..., output_format="count")\`
|
|
484
|
+
- Checking if something exists \u2192 count > 0 is sufficient
|
|
485
|
+
- Large exhaustive searches \u2192 get count first, then fetch if needed
|
|
486
|
+
|
|
487
|
+
**Auto-suggested formats:** Search responses include \`query_interpretation.suggested_output_format\` when the API detects an optimal format:
|
|
488
|
+
- Symbol queries (e.g., "authOptions") \u2192 suggests \`minimal\` (path + line + snippet)
|
|
489
|
+
- Count queries (e.g., "how many") \u2192 suggests \`count\`
|
|
490
|
+
**USE the suggested format** on subsequent searches for best token efficiency.
|
|
491
|
+
|
|
492
|
+
**Search defaults:** \`search\` returns the top 3 results with compact snippets. Use \`limit\` + \`offset\` for pagination, and \`content_max_chars\` to expand snippets when needed.
|
|
493
|
+
|
|
494
|
+
If ContextStream returns results, stop and use them. NEVER use local Search/Explore/Read unless you need exact code edits or ContextStream returned 0 results.
|
|
495
|
+
|
|
496
|
+
**Code Analysis:**
|
|
497
|
+
- Dependencies: \`graph(action="dependencies", file_path="...")\`
|
|
498
|
+
- Change impact: \`graph(action="impact", symbol_name="...")\`
|
|
499
|
+
- Call path: \`graph(action="call_path", from_symbol="...", to_symbol="...")\`
|
|
500
|
+
- Build graph: \`graph(action="ingest")\` - async, can take a few minutes
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
### Distillation & Memory Hygiene
|
|
505
|
+
|
|
506
|
+
- Quick context: \`session(action="summary")\`
|
|
507
|
+
- Long chat: \`session(action="compress", content="...")\`
|
|
508
|
+
- Memory summary: \`memory(action="summary")\`
|
|
509
|
+
- Condense noisy entries: \`memory(action="distill_event", event_id="...")\`
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
### When to Capture
|
|
514
|
+
|
|
515
|
+
| When | Call | Example |
|
|
516
|
+
|------|------|---------|
|
|
517
|
+
| User makes decision | \`session(action="capture", event_type="decision", ...)\` | "Let's use PostgreSQL" |
|
|
518
|
+
| User states preference | \`session(action="capture", event_type="preference", ...)\` | "I prefer TypeScript" |
|
|
519
|
+
| Complete significant task | \`session(action="capture", event_type="task", ...)\` | Capture what was done |
|
|
520
|
+
| Need past context | \`session(action="recall", query="...")\` | "What did we decide about X?" |
|
|
521
|
+
|
|
522
|
+
**DO NOT capture utility operations:**
|
|
523
|
+
- \u274C "Listed workspaces" - not meaningful context
|
|
524
|
+
- \u274C "Showed version" - not a decision
|
|
525
|
+
- \u274C "Listed projects" - just data retrieval
|
|
526
|
+
|
|
527
|
+
**DO capture meaningful work:**
|
|
528
|
+
- \u2705 Decisions, preferences, completed features
|
|
529
|
+
- \u2705 Lessons from mistakes
|
|
530
|
+
- \u2705 Insights about architecture or patterns
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
### \u{1F6A8} Plans & Tasks - USE CONTEXTSTREAM, NOT FILE-BASED PLANS \u{1F6A8}
|
|
535
|
+
|
|
536
|
+
**CRITICAL: When the user requests planning, implementation plans, roadmaps, task breakdowns, or step-by-step approaches:**
|
|
537
|
+
|
|
538
|
+
\u274C **DO NOT** use built-in plan mode (EnterPlanMode tool)
|
|
539
|
+
\u274C **DO NOT** write plans to markdown files or plan documents
|
|
540
|
+
\u274C **DO NOT** ask "should I create a plan file?"
|
|
541
|
+
|
|
542
|
+
\u2705 **ALWAYS** use ContextStream's plan/task system instead
|
|
543
|
+
|
|
544
|
+
**Trigger phrases to detect (use ContextStream immediately):**
|
|
545
|
+
- "create a plan", "make a plan", "plan this", "plan for"
|
|
546
|
+
- "implementation plan", "roadmap", "milestones"
|
|
547
|
+
- "break down", "breakdown", "break this into steps"
|
|
548
|
+
- "what are the steps", "step by step", "outline the approach"
|
|
549
|
+
- "task list", "todo list", "action items"
|
|
550
|
+
- "how should we approach", "implementation strategy"
|
|
551
|
+
|
|
552
|
+
**When detected, immediately:**
|
|
553
|
+
|
|
554
|
+
1. **Create the plan in ContextStream:**
|
|
555
|
+
\`\`\`
|
|
556
|
+
session(action="capture_plan", title="<descriptive title>", description="<what this plan accomplishes>", goals=["goal1", "goal2"], steps=[{id: "1", title: "Step 1", order: 1, description: "..."}, ...])
|
|
557
|
+
\`\`\`
|
|
558
|
+
|
|
559
|
+
2. **Create tasks for each step:**
|
|
560
|
+
\`\`\`
|
|
561
|
+
memory(action="create_task", title="<task title>", plan_id="<plan_id from step 1>", priority="high|medium|low", description="<detailed task description>")
|
|
562
|
+
\`\`\`
|
|
563
|
+
|
|
564
|
+
**Why ContextStream plans are better:**
|
|
565
|
+
- Plans persist across sessions and are searchable
|
|
566
|
+
- Tasks track status (pending/in_progress/completed/blocked)
|
|
567
|
+
- Context is preserved with workspace/project association
|
|
568
|
+
- Can be retrieved with \`session(action="get_plan", plan_id="...", include_tasks=true)\`
|
|
569
|
+
- Future sessions can continue from where you left off
|
|
570
|
+
|
|
571
|
+
**Managing plans/tasks:**
|
|
572
|
+
- List plans: \`session(action="list_plans")\`
|
|
573
|
+
- Get plan with tasks: \`session(action="get_plan", plan_id="<uuid>", include_tasks=true)\`
|
|
574
|
+
- List tasks: \`memory(action="list_tasks", plan_id="<uuid>")\` or \`memory(action="list_tasks")\` for all
|
|
575
|
+
- Update task status: \`memory(action="update_task", task_id="<uuid>", task_status="pending|in_progress|completed|blocked")\`
|
|
576
|
+
- Link task to plan: \`memory(action="update_task", task_id="<uuid>", plan_id="<plan_uuid>")\`
|
|
577
|
+
- Unlink task from plan: \`memory(action="update_task", task_id="<uuid>", plan_id=null)\`
|
|
578
|
+
- Delete: \`memory(action="delete_task", task_id="<uuid>")\` or \`memory(action="delete_event", event_id="<plan_uuid>")\`
|
|
579
|
+
|
|
580
|
+
---
|
|
581
|
+
|
|
582
|
+
### Complete Action Reference
|
|
583
|
+
|
|
584
|
+
**session actions:**
|
|
585
|
+
- \`capture\` - Save decision/insight/task (requires: event_type, title, content)
|
|
586
|
+
- \`capture_lesson\` - Save lesson from mistake (requires: title, category, trigger, impact, prevention)
|
|
587
|
+
- \`get_lessons\` - Retrieve relevant lessons (optional: query, category, severity)
|
|
588
|
+
- \`recall\` - Natural language memory recall (requires: query)
|
|
589
|
+
- \`remember\` - Quick save to memory (requires: content)
|
|
590
|
+
- \`user_context\` - Get user preferences/style
|
|
591
|
+
- \`summary\` - Workspace summary
|
|
592
|
+
- \`compress\` - Compress long conversation
|
|
593
|
+
- \`delta\` - Changes since timestamp
|
|
594
|
+
- \`smart_search\` - Context-enriched search
|
|
595
|
+
- \`decision_trace\` - Trace decision provenance
|
|
596
|
+
|
|
597
|
+
**memory actions:**
|
|
598
|
+
- Event CRUD: \`create_event\`, \`get_event\`, \`update_event\`, \`delete_event\`, \`list_events\`, \`distill_event\`
|
|
599
|
+
- Node CRUD: \`create_node\`, \`get_node\`, \`update_node\`, \`delete_node\`, \`list_nodes\`, \`supersede_node\`
|
|
600
|
+
- Query: \`search\`, \`decisions\`, \`timeline\`, \`summary\`
|
|
601
|
+
|
|
602
|
+
**graph actions:**
|
|
603
|
+
- Analysis: \`dependencies\`, \`impact\`, \`call_path\`, \`related\`, \`path\`
|
|
604
|
+
- Quality: \`circular_dependencies\`, \`unused_code\`, \`contradictions\`
|
|
605
|
+
- Management: \`ingest\`, \`decisions\`
|
|
606
|
+
|
|
607
|
+
See full documentation: https://contextstream.io/docs/mcp/tools
|
|
608
|
+
`.trim();
|
|
609
|
+
CONTEXTSTREAM_RULES_MINIMAL = `
|
|
610
|
+
## ContextStream Rules
|
|
611
|
+
|
|
612
|
+
<contextstream_rules>
|
|
613
|
+
1. **SIMPLE UTILITY?** (list/show/version) \u2192 Just execute, skip context calls
|
|
614
|
+
2. **CODING TASK?** \u2192 init \u2192 context \u2192 work \u2192 capture
|
|
615
|
+
3. **SEARCH FIRST:** Before Glob/Grep/Read \u2192 \`search(mode="hybrid")\` FIRST
|
|
616
|
+
</contextstream_rules>
|
|
617
|
+
|
|
618
|
+
**Display this block at the start of responses to keep rules in context.**
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
## ContextStream v0.4.x (Hooks Enforced)
|
|
623
|
+
|
|
624
|
+
Rules Version: ${RULES_VERSION}
|
|
625
|
+
**Note:** PreToolUse hooks block Glob/Grep/Search when ContextStream is available.
|
|
626
|
+
|
|
627
|
+
### For Coding Tasks
|
|
628
|
+
|
|
629
|
+
| Action | Tool Call |
|
|
630
|
+
|--------|-----------|
|
|
631
|
+
| **1st message** | \`init(folder_path="<cwd>", context_hint="<msg>")\` then \`context(...)\` |
|
|
632
|
+
| **2nd+ messages** | \`context(user_message="<msg>", format="minified", max_tokens=400)\` |
|
|
633
|
+
| **Code search** | \`search(mode="hybrid", query="...")\` \u2014 BEFORE any local tools |
|
|
634
|
+
| **Save decisions** | \`session(action="capture", event_type="decision", ...)\` |
|
|
635
|
+
|
|
636
|
+
### Search Modes
|
|
637
|
+
|
|
638
|
+
| Mode | Use Case |
|
|
639
|
+
|------|----------|
|
|
640
|
+
| \`hybrid\` | General code search (default) |
|
|
641
|
+
| \`keyword\` | Exact symbol/string match |
|
|
642
|
+
| \`exhaustive\` | Find ALL matches (grep-like) |
|
|
643
|
+
| \`semantic\` | Conceptual questions |
|
|
644
|
+
|
|
645
|
+
### Why ContextStream First?
|
|
646
|
+
|
|
647
|
+
\u274C **WRONG:** \`Grep \u2192 Read \u2192 Read \u2192 Read\` (4+ tool calls, slow)
|
|
648
|
+
\u2705 **CORRECT:** \`search(mode="hybrid")\` (1 call, returns context)
|
|
649
|
+
|
|
650
|
+
ContextStream search is **indexed** and returns semantic matches + context in ONE call.
|
|
651
|
+
|
|
652
|
+
### Quick Reference
|
|
653
|
+
|
|
654
|
+
| Tool | Example |
|
|
655
|
+
|------|---------|
|
|
656
|
+
| \`search\` | \`search(mode="hybrid", query="auth", limit=3)\` |
|
|
657
|
+
| \`session\` | \`session(action="capture", event_type="decision", title="...", content="...")\` |
|
|
658
|
+
| \`memory\` | \`memory(action="list_events", limit=10)\` |
|
|
659
|
+
| \`graph\` | \`graph(action="dependencies", file_path="...")\` |
|
|
660
|
+
|
|
661
|
+
### \u{1F680} FAST PATH: Simple Utility Operations
|
|
662
|
+
|
|
663
|
+
**For simple utility commands, SKIP the ceremony and just execute directly:**
|
|
664
|
+
|
|
665
|
+
| Command Type | Just Call | Skip |
|
|
666
|
+
|--------------|-----------|------|
|
|
667
|
+
| List workspaces | \`workspace(action="list")\` | init, context, capture |
|
|
668
|
+
| List projects | \`project(action="list")\` | init, context, capture |
|
|
669
|
+
| Show version | \`help(action="version")\` | init, context, capture |
|
|
670
|
+
| List reminders | \`reminder(action="list")\` | init, context, capture |
|
|
671
|
+
| Check auth | \`help(action="auth")\` | init, context, capture |
|
|
672
|
+
|
|
673
|
+
**Detect simple operations by these patterns:**
|
|
674
|
+
- "list ...", "show ...", "what are my ...", "get ..."
|
|
675
|
+
- Single-action queries with no context dependency
|
|
676
|
+
- User just wants data, not analysis or coding help
|
|
677
|
+
|
|
678
|
+
**DO NOT add overhead for utility operations:**
|
|
679
|
+
- \u274C Don't call init just to list workspaces
|
|
680
|
+
- \u274C Don't call context for simple queries
|
|
681
|
+
- \u274C Don't capture "listed workspaces" as an event (that's noise)
|
|
682
|
+
|
|
683
|
+
**Use full context ceremony ONLY for:**
|
|
684
|
+
- Coding tasks (edit, create, refactor, debug)
|
|
685
|
+
- Search/discovery (finding code, understanding architecture)
|
|
686
|
+
- Tasks where past decisions or lessons matter
|
|
687
|
+
|
|
688
|
+
### Lessons (Past Mistakes)
|
|
689
|
+
|
|
690
|
+
- After \`init\`: Check for \`lessons\` field and apply before work
|
|
691
|
+
- Before risky work: \`session(action="get_lessons", query="<topic>")\`
|
|
692
|
+
- On mistakes: \`session(action="capture_lesson", title="...", trigger="...", impact="...", prevention="...")\`
|
|
693
|
+
|
|
694
|
+
### Context Pressure & Compaction
|
|
695
|
+
|
|
696
|
+
- If \`context\` returns high/critical \`context_pressure\`: call \`session(action="capture", ...)\` to save state
|
|
697
|
+
- PreCompact hooks automatically save snapshots before compaction (if installed)
|
|
698
|
+
|
|
699
|
+
### Enhanced Context (Warnings)
|
|
700
|
+
|
|
701
|
+
\`context\` returns server-side \`warnings\` for lessons, risky actions, and breaking changes.
|
|
702
|
+
When warnings are present: **STOP**, acknowledge them, explain mitigation, then proceed.
|
|
703
|
+
|
|
704
|
+
### Automatic Context Restoration
|
|
705
|
+
|
|
706
|
+
**Context restoration is now enabled by default.** Every \`init\` call automatically:
|
|
707
|
+
- Restores context from recent snapshots (if available)
|
|
708
|
+
- Returns \`restored_context\` field with snapshot data
|
|
709
|
+
- Sets \`is_post_compact=true\` in response when restoration occurs
|
|
710
|
+
|
|
711
|
+
**No special handling needed after compaction** - just call \`init\` normally.
|
|
712
|
+
|
|
713
|
+
To disable automatic restoration:
|
|
714
|
+
- Pass \`is_post_compact=false\` in the API call
|
|
715
|
+
- Or set \`CONTEXTSTREAM_RESTORE_CONTEXT=false\` environment variable
|
|
716
|
+
|
|
717
|
+
### Notices - MUST HANDLE IMMEDIATELY
|
|
718
|
+
|
|
719
|
+
- **[VERSION_NOTICE]**: Tell the user about the update and command to run
|
|
720
|
+
- **[RULES_NOTICE]**: Run \`generate_rules(overwrite_existing=true)\` to update
|
|
721
|
+
- **[LESSONS_WARNING]**: Read lessons, tell user about them, explain how you'll avoid past mistakes
|
|
722
|
+
|
|
723
|
+
### Plans & Tasks
|
|
724
|
+
|
|
725
|
+
When user asks for a plan, use ContextStream (not EnterPlanMode):
|
|
726
|
+
1. \`session(action="capture_plan", title="...", steps=[...])\`
|
|
727
|
+
2. \`memory(action="create_task", title="...", plan_id="<id>")\`
|
|
728
|
+
|
|
729
|
+
### Workspace-Only Mode (Multi-Project Folders)
|
|
730
|
+
|
|
731
|
+
If working in a parent folder containing multiple projects:
|
|
732
|
+
\`\`\`
|
|
733
|
+
init(folder_path="...", skip_project_creation=true)
|
|
734
|
+
\`\`\`
|
|
735
|
+
|
|
736
|
+
This enables workspace-level memory and context without project-specific indexing.
|
|
737
|
+
Use for monorepos or folders with multiple independent projects.
|
|
738
|
+
|
|
739
|
+
Full docs: https://contextstream.io/docs/mcp/tools
|
|
740
|
+
`.trim();
|
|
741
|
+
TEMPLATES = {
|
|
742
|
+
codex: {
|
|
743
|
+
filename: "AGENTS.md",
|
|
744
|
+
description: "Codex CLI agent instructions",
|
|
745
|
+
build: (rules) => `# Codex CLI Instructions
|
|
746
|
+
${rules}
|
|
747
|
+
`
|
|
748
|
+
},
|
|
749
|
+
cursor: {
|
|
750
|
+
filename: ".cursorrules",
|
|
751
|
+
description: "Cursor AI rules",
|
|
752
|
+
build: (rules) => `# Cursor Rules
|
|
753
|
+
${rules}
|
|
754
|
+
`
|
|
755
|
+
},
|
|
756
|
+
cline: {
|
|
757
|
+
filename: ".clinerules",
|
|
758
|
+
description: "Cline AI rules",
|
|
759
|
+
build: (rules) => `# Cline Rules
|
|
760
|
+
${rules}
|
|
761
|
+
`
|
|
762
|
+
},
|
|
763
|
+
kilo: {
|
|
764
|
+
filename: ".kilocode/rules/contextstream.md",
|
|
765
|
+
description: "Kilo Code AI rules",
|
|
766
|
+
build: (rules) => `# Kilo Code Rules
|
|
767
|
+
${rules}
|
|
768
|
+
`
|
|
769
|
+
},
|
|
770
|
+
roo: {
|
|
771
|
+
filename: ".roo/rules/contextstream.md",
|
|
772
|
+
description: "Roo Code AI rules",
|
|
773
|
+
build: (rules) => `# Roo Code Rules
|
|
774
|
+
${rules}
|
|
775
|
+
`
|
|
776
|
+
},
|
|
777
|
+
claude: {
|
|
778
|
+
filename: "CLAUDE.md",
|
|
779
|
+
description: "Claude Code instructions",
|
|
780
|
+
build: (rules) => `# Claude Code Instructions
|
|
781
|
+
${rules}
|
|
782
|
+
`
|
|
783
|
+
},
|
|
784
|
+
aider: {
|
|
785
|
+
filename: ".aider.conf.yml",
|
|
786
|
+
description: "Aider configuration with system prompt",
|
|
787
|
+
build: (rules) => `# Aider Configuration
|
|
788
|
+
# Note: Aider uses different config format - this adds to the system prompt
|
|
789
|
+
|
|
790
|
+
# Add ContextStream guidance to conventions
|
|
791
|
+
conventions: |
|
|
792
|
+
${rules.split("\n").map((line) => " " + line).join("\n")}
|
|
793
|
+
`
|
|
794
|
+
},
|
|
795
|
+
antigravity: {
|
|
796
|
+
filename: "GEMINI.md",
|
|
797
|
+
description: "Google Antigravity AI rules",
|
|
798
|
+
build: (rules) => `# Antigravity Agent Rules
|
|
799
|
+
${rules}
|
|
800
|
+
`
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
// src/hooks/auto-rules.ts
|
|
807
|
+
import * as fs from "node:fs";
|
|
808
|
+
import * as path from "node:path";
|
|
809
|
+
import { homedir } from "node:os";
|
|
810
|
+
var API_URL = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
811
|
+
var API_KEY = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
812
|
+
var ENABLED = process.env.CONTEXTSTREAM_AUTO_RULES !== "false";
|
|
813
|
+
var MARKER_FILE = path.join(homedir(), ".contextstream", ".auto-rules-ran");
|
|
814
|
+
var COOLDOWN_MS = 4 * 60 * 60 * 1e3;
|
|
815
|
+
function hasRunRecently() {
|
|
816
|
+
try {
|
|
817
|
+
if (!fs.existsSync(MARKER_FILE)) return false;
|
|
818
|
+
const stat = fs.statSync(MARKER_FILE);
|
|
819
|
+
const age = Date.now() - stat.mtimeMs;
|
|
820
|
+
return age < COOLDOWN_MS;
|
|
821
|
+
} catch {
|
|
822
|
+
return false;
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
function markAsRan() {
|
|
826
|
+
try {
|
|
827
|
+
const dir = path.dirname(MARKER_FILE);
|
|
828
|
+
if (!fs.existsSync(dir)) {
|
|
829
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
830
|
+
}
|
|
831
|
+
fs.writeFileSync(MARKER_FILE, (/* @__PURE__ */ new Date()).toISOString());
|
|
832
|
+
} catch {
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
function extractRulesNotice(input) {
|
|
836
|
+
if (input.tool_result) {
|
|
837
|
+
try {
|
|
838
|
+
const parsed = JSON.parse(input.tool_result);
|
|
839
|
+
if (parsed.rules_notice) return parsed.rules_notice;
|
|
840
|
+
} catch {
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
if (input.tool_response?.structuredContent) {
|
|
844
|
+
const sc = input.tool_response.structuredContent;
|
|
845
|
+
if (sc.rules_notice) return sc.rules_notice;
|
|
846
|
+
}
|
|
847
|
+
if (input.response) {
|
|
848
|
+
if (input.response.rules_notice) {
|
|
849
|
+
return input.response.rules_notice;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
function extractCwd(input) {
|
|
855
|
+
if (input.cwd) return input.cwd;
|
|
856
|
+
return process.cwd();
|
|
857
|
+
}
|
|
858
|
+
async function generateRulesForFolder(folderPath) {
|
|
859
|
+
const { generateAllRuleFiles: generateAllRuleFiles2 } = await Promise.resolve().then(() => (init_rules_templates(), rules_templates_exports));
|
|
860
|
+
await generateAllRuleFiles2({
|
|
861
|
+
folderPath,
|
|
862
|
+
editors: ["cursor", "cline", "kilo", "roo", "claude", "aider", "codex"],
|
|
863
|
+
overwriteExisting: true,
|
|
864
|
+
mode: "minimal"
|
|
865
|
+
// Use minimal mode for auto-updates
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
async function runAutoRulesHook() {
|
|
869
|
+
if (!ENABLED) {
|
|
870
|
+
process.exit(0);
|
|
871
|
+
}
|
|
872
|
+
if (hasRunRecently()) {
|
|
873
|
+
process.exit(0);
|
|
874
|
+
}
|
|
875
|
+
let inputData = "";
|
|
876
|
+
for await (const chunk of process.stdin) {
|
|
877
|
+
inputData += chunk;
|
|
878
|
+
}
|
|
879
|
+
if (!inputData.trim()) {
|
|
880
|
+
process.exit(0);
|
|
881
|
+
}
|
|
882
|
+
let input;
|
|
883
|
+
try {
|
|
884
|
+
input = JSON.parse(inputData);
|
|
885
|
+
} catch {
|
|
886
|
+
process.exit(0);
|
|
887
|
+
}
|
|
888
|
+
const toolName = input.tool_name || input.toolName || "";
|
|
889
|
+
const isContextTool = toolName.includes("init") || toolName.includes("context") || toolName.includes("session_init") || toolName.includes("context_smart");
|
|
890
|
+
if (!isContextTool) {
|
|
891
|
+
process.exit(0);
|
|
892
|
+
}
|
|
893
|
+
const rulesNotice = extractRulesNotice(input);
|
|
894
|
+
if (!rulesNotice || rulesNotice.status === "current") {
|
|
895
|
+
process.exit(0);
|
|
896
|
+
}
|
|
897
|
+
const cwd = extractCwd(input);
|
|
898
|
+
const folderPath = rulesNotice.update_args?.folder_path || cwd;
|
|
899
|
+
try {
|
|
900
|
+
await generateRulesForFolder(folderPath);
|
|
901
|
+
markAsRan();
|
|
902
|
+
} catch {
|
|
903
|
+
}
|
|
904
|
+
process.exit(0);
|
|
905
|
+
}
|
|
906
|
+
var isDirectRun = process.argv[1]?.includes("auto-rules") || process.argv[2] === "auto-rules";
|
|
907
|
+
if (isDirectRun) {
|
|
908
|
+
runAutoRulesHook().catch(() => process.exit(0));
|
|
909
|
+
}
|
|
910
|
+
export {
|
|
911
|
+
runAutoRulesHook
|
|
912
|
+
};
|