@contextstream/mcp-server 0.4.67 → 0.4.71
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 +156 -139
- package/dist/hooks/on-read.js +169 -11
- package/dist/hooks/pre-tool-use.js +87 -5
- package/dist/hooks/runner.js +110 -31
- package/dist/hooks/session-init.js +14 -13
- package/dist/hooks/user-prompt-submit.js +12 -12
- package/dist/index.js +1550 -714
- package/package.json +3 -3
|
@@ -67,6 +67,8 @@ function getOrCreateEntry(state, cwd) {
|
|
|
67
67
|
require_init: false,
|
|
68
68
|
last_context_at: void 0,
|
|
69
69
|
last_state_change_at: void 0,
|
|
70
|
+
index_wait_started_at: void 0,
|
|
71
|
+
index_wait_until: void 0,
|
|
70
72
|
updated_at: nowIso()
|
|
71
73
|
};
|
|
72
74
|
state.workspaces[cwd] = created;
|
|
@@ -96,6 +98,8 @@ function clearContextRequired(cwd) {
|
|
|
96
98
|
if (!target) return;
|
|
97
99
|
target.entry.require_context = false;
|
|
98
100
|
target.entry.last_context_at = nowIso();
|
|
101
|
+
target.entry.index_wait_started_at = void 0;
|
|
102
|
+
target.entry.index_wait_until = void 0;
|
|
99
103
|
target.entry.updated_at = nowIso();
|
|
100
104
|
writeState(state);
|
|
101
105
|
}
|
|
@@ -147,6 +151,44 @@ function isContextFreshAndClean(cwd, maxAgeSeconds) {
|
|
|
147
151
|
}
|
|
148
152
|
return true;
|
|
149
153
|
}
|
|
154
|
+
function startIndexWaitWindow(cwd, waitSeconds) {
|
|
155
|
+
if (!cwd.trim() || waitSeconds <= 0) return;
|
|
156
|
+
const state = readState();
|
|
157
|
+
const target = getOrCreateEntry(state, cwd);
|
|
158
|
+
if (!target) return;
|
|
159
|
+
const now = Date.now();
|
|
160
|
+
const existingUntil = target.entry.index_wait_until ? new Date(target.entry.index_wait_until).getTime() : NaN;
|
|
161
|
+
if (!Number.isNaN(existingUntil) && existingUntil > now) {
|
|
162
|
+
target.entry.updated_at = nowIso();
|
|
163
|
+
writeState(state);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
target.entry.index_wait_started_at = new Date(now).toISOString();
|
|
167
|
+
target.entry.index_wait_until = new Date(now + waitSeconds * 1e3).toISOString();
|
|
168
|
+
target.entry.updated_at = nowIso();
|
|
169
|
+
writeState(state);
|
|
170
|
+
}
|
|
171
|
+
function clearIndexWaitWindow(cwd) {
|
|
172
|
+
if (!cwd.trim()) return;
|
|
173
|
+
const state = readState();
|
|
174
|
+
const target = getOrCreateEntry(state, cwd);
|
|
175
|
+
if (!target) return;
|
|
176
|
+
target.entry.index_wait_started_at = void 0;
|
|
177
|
+
target.entry.index_wait_until = void 0;
|
|
178
|
+
target.entry.updated_at = nowIso();
|
|
179
|
+
writeState(state);
|
|
180
|
+
}
|
|
181
|
+
function indexWaitRemainingSeconds(cwd) {
|
|
182
|
+
if (!cwd.trim()) return null;
|
|
183
|
+
const state = readState();
|
|
184
|
+
const target = getOrCreateEntry(state, cwd);
|
|
185
|
+
if (!target?.entry.index_wait_until) return null;
|
|
186
|
+
const until = new Date(target.entry.index_wait_until).getTime();
|
|
187
|
+
if (Number.isNaN(until)) return null;
|
|
188
|
+
const remainingMs = until - Date.now();
|
|
189
|
+
if (remainingMs <= 0) return null;
|
|
190
|
+
return Math.ceil(remainingMs / 1e3);
|
|
191
|
+
}
|
|
150
192
|
|
|
151
193
|
// src/hooks/pre-tool-use.ts
|
|
152
194
|
var ENABLED = process.env.CONTEXTSTREAM_HOOK_ENABLED !== "false";
|
|
@@ -154,6 +196,9 @@ var INDEX_STATUS_FILE = path2.join(homedir2(), ".contextstream", "indexed-projec
|
|
|
154
196
|
var DEBUG_FILE = "/tmp/pretooluse-hook-debug.log";
|
|
155
197
|
var STALE_THRESHOLD_DAYS = 7;
|
|
156
198
|
var CONTEXT_FRESHNESS_SECONDS = 120;
|
|
199
|
+
var DEFAULT_INDEX_WAIT_SECONDS = 20;
|
|
200
|
+
var MIN_INDEX_WAIT_SECONDS = 15;
|
|
201
|
+
var MAX_INDEX_WAIT_SECONDS = 20;
|
|
157
202
|
var DISCOVERY_PATTERNS = ["**/*", "**/", "src/**", "lib/**", "app/**", "components/**"];
|
|
158
203
|
function isDiscoveryGlob(pattern) {
|
|
159
204
|
const patternLower = pattern.toLowerCase();
|
|
@@ -179,6 +224,33 @@ function isDiscoveryGrep(filePath) {
|
|
|
179
224
|
}
|
|
180
225
|
return false;
|
|
181
226
|
}
|
|
227
|
+
function configuredIndexWaitSeconds() {
|
|
228
|
+
const parsed = Number.parseInt(process.env.CONTEXTSTREAM_INDEX_WAIT_SECONDS ?? "", 10);
|
|
229
|
+
if (Number.isNaN(parsed)) return DEFAULT_INDEX_WAIT_SECONDS;
|
|
230
|
+
return Math.min(MAX_INDEX_WAIT_SECONDS, Math.max(MIN_INDEX_WAIT_SECONDS, parsed));
|
|
231
|
+
}
|
|
232
|
+
function isLocalDiscoveryToolDuringIndexWait(tool, toolInput) {
|
|
233
|
+
if (tool === "Glob" || tool === "Explore" || tool === "SemanticSearch" || tool === "codebase_search") {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
if (tool === "Task") {
|
|
237
|
+
const subagentTypeRaw = toolInput?.subagent_type || toolInput?.subagentType || "";
|
|
238
|
+
return subagentTypeRaw.toLowerCase().includes("explore");
|
|
239
|
+
}
|
|
240
|
+
if (tool === "Grep" || tool === "Search" || tool === "grep_search" || tool === "code_search") {
|
|
241
|
+
const filePath = toolInput?.path || "";
|
|
242
|
+
return isDiscoveryGrep(filePath);
|
|
243
|
+
}
|
|
244
|
+
if (tool === "Read" || tool === "ReadFile" || tool === "read_file") {
|
|
245
|
+
const filePath = toolInput?.file_path || toolInput?.path || toolInput?.file || toolInput?.target_file || "";
|
|
246
|
+
return isDiscoveryGrep(filePath);
|
|
247
|
+
}
|
|
248
|
+
if (tool === "list_files" || tool === "search_files" || tool === "search_files_content" || tool === "find_files" || tool === "find_by_name") {
|
|
249
|
+
const pattern = toolInput?.path || toolInput?.regex || toolInput?.pattern || toolInput?.query || "";
|
|
250
|
+
return !pattern || isDiscoveryGlob(pattern) || isDiscoveryGrep(pattern);
|
|
251
|
+
}
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
182
254
|
function isProjectIndexed(cwd) {
|
|
183
255
|
if (!fs2.existsSync(INDEX_STATUS_FILE)) {
|
|
184
256
|
return { isIndexed: false, isStale: false };
|
|
@@ -440,12 +512,22 @@ async function runPreToolUseHook() {
|
|
|
440
512
|
blockWithMessage(editorFormat, msg);
|
|
441
513
|
}
|
|
442
514
|
}
|
|
443
|
-
const { isIndexed } = isProjectIndexed(cwd);
|
|
444
|
-
fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}
|
|
445
|
-
`);
|
|
446
|
-
if (!isIndexed) {
|
|
447
|
-
fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] Project not indexed, allowing
|
|
515
|
+
const { isIndexed, isStale } = isProjectIndexed(cwd);
|
|
516
|
+
fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}, isStale=${isStale}
|
|
448
517
|
`);
|
|
518
|
+
if (isIndexed && !isStale) {
|
|
519
|
+
clearIndexWaitWindow(cwd);
|
|
520
|
+
} else {
|
|
521
|
+
const waitSeconds = configuredIndexWaitSeconds();
|
|
522
|
+
if (isLocalDiscoveryToolDuringIndexWait(tool, toolInput)) {
|
|
523
|
+
startIndexWaitWindow(cwd, waitSeconds);
|
|
524
|
+
const remaining = indexWaitRemainingSeconds(cwd);
|
|
525
|
+
if (remaining && remaining > 0) {
|
|
526
|
+
const msg = `Index refresh grace window is active (${remaining}s remaining). Keep ContextStream search-first flow: mcp__contextstream__search(mode="auto", query="..."). Do not use local discovery tools yet for stale/not-indexed projects. Retry after refresh; local fallback is allowed only after ~${waitSeconds}s if index is still unavailable.`;
|
|
527
|
+
blockWithMessage(editorFormat, msg);
|
|
528
|
+
}
|
|
529
|
+
allowTool(editorFormat, cwd, recordStateChange);
|
|
530
|
+
}
|
|
449
531
|
allowTool(editorFormat, cwd, recordStateChange);
|
|
450
532
|
}
|
|
451
533
|
if (tool === "Glob") {
|
package/dist/hooks/runner.js
CHANGED
|
@@ -76,6 +76,8 @@ function getOrCreateEntry(state, cwd) {
|
|
|
76
76
|
require_init: false,
|
|
77
77
|
last_context_at: void 0,
|
|
78
78
|
last_state_change_at: void 0,
|
|
79
|
+
index_wait_started_at: void 0,
|
|
80
|
+
index_wait_until: void 0,
|
|
79
81
|
updated_at: nowIso()
|
|
80
82
|
};
|
|
81
83
|
state.workspaces[cwd] = created;
|
|
@@ -114,6 +116,8 @@ function clearContextRequired(cwd) {
|
|
|
114
116
|
if (!target) return;
|
|
115
117
|
target.entry.require_context = false;
|
|
116
118
|
target.entry.last_context_at = nowIso();
|
|
119
|
+
target.entry.index_wait_started_at = void 0;
|
|
120
|
+
target.entry.index_wait_until = void 0;
|
|
117
121
|
target.entry.updated_at = nowIso();
|
|
118
122
|
writeState(state);
|
|
119
123
|
}
|
|
@@ -174,6 +178,44 @@ function isContextFreshAndClean(cwd, maxAgeSeconds) {
|
|
|
174
178
|
}
|
|
175
179
|
return true;
|
|
176
180
|
}
|
|
181
|
+
function startIndexWaitWindow(cwd, waitSeconds) {
|
|
182
|
+
if (!cwd.trim() || waitSeconds <= 0) return;
|
|
183
|
+
const state = readState();
|
|
184
|
+
const target = getOrCreateEntry(state, cwd);
|
|
185
|
+
if (!target) return;
|
|
186
|
+
const now = Date.now();
|
|
187
|
+
const existingUntil = target.entry.index_wait_until ? new Date(target.entry.index_wait_until).getTime() : NaN;
|
|
188
|
+
if (!Number.isNaN(existingUntil) && existingUntil > now) {
|
|
189
|
+
target.entry.updated_at = nowIso();
|
|
190
|
+
writeState(state);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
target.entry.index_wait_started_at = new Date(now).toISOString();
|
|
194
|
+
target.entry.index_wait_until = new Date(now + waitSeconds * 1e3).toISOString();
|
|
195
|
+
target.entry.updated_at = nowIso();
|
|
196
|
+
writeState(state);
|
|
197
|
+
}
|
|
198
|
+
function clearIndexWaitWindow(cwd) {
|
|
199
|
+
if (!cwd.trim()) return;
|
|
200
|
+
const state = readState();
|
|
201
|
+
const target = getOrCreateEntry(state, cwd);
|
|
202
|
+
if (!target) return;
|
|
203
|
+
target.entry.index_wait_started_at = void 0;
|
|
204
|
+
target.entry.index_wait_until = void 0;
|
|
205
|
+
target.entry.updated_at = nowIso();
|
|
206
|
+
writeState(state);
|
|
207
|
+
}
|
|
208
|
+
function indexWaitRemainingSeconds(cwd) {
|
|
209
|
+
if (!cwd.trim()) return null;
|
|
210
|
+
const state = readState();
|
|
211
|
+
const target = getOrCreateEntry(state, cwd);
|
|
212
|
+
if (!target?.entry.index_wait_until) return null;
|
|
213
|
+
const until = new Date(target.entry.index_wait_until).getTime();
|
|
214
|
+
if (Number.isNaN(until)) return null;
|
|
215
|
+
const remainingMs = until - Date.now();
|
|
216
|
+
if (remainingMs <= 0) return null;
|
|
217
|
+
return Math.ceil(remainingMs / 1e3);
|
|
218
|
+
}
|
|
177
219
|
var STATE_PATH;
|
|
178
220
|
var init_prompt_state = __esm({
|
|
179
221
|
"src/hooks/prompt-state.ts"() {
|
|
@@ -214,6 +256,33 @@ function isDiscoveryGrep(filePath) {
|
|
|
214
256
|
}
|
|
215
257
|
return false;
|
|
216
258
|
}
|
|
259
|
+
function configuredIndexWaitSeconds() {
|
|
260
|
+
const parsed = Number.parseInt(process.env.CONTEXTSTREAM_INDEX_WAIT_SECONDS ?? "", 10);
|
|
261
|
+
if (Number.isNaN(parsed)) return DEFAULT_INDEX_WAIT_SECONDS;
|
|
262
|
+
return Math.min(MAX_INDEX_WAIT_SECONDS, Math.max(MIN_INDEX_WAIT_SECONDS, parsed));
|
|
263
|
+
}
|
|
264
|
+
function isLocalDiscoveryToolDuringIndexWait(tool, toolInput) {
|
|
265
|
+
if (tool === "Glob" || tool === "Explore" || tool === "SemanticSearch" || tool === "codebase_search") {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
if (tool === "Task") {
|
|
269
|
+
const subagentTypeRaw = toolInput?.subagent_type || toolInput?.subagentType || "";
|
|
270
|
+
return subagentTypeRaw.toLowerCase().includes("explore");
|
|
271
|
+
}
|
|
272
|
+
if (tool === "Grep" || tool === "Search" || tool === "grep_search" || tool === "code_search") {
|
|
273
|
+
const filePath = toolInput?.path || "";
|
|
274
|
+
return isDiscoveryGrep(filePath);
|
|
275
|
+
}
|
|
276
|
+
if (tool === "Read" || tool === "ReadFile" || tool === "read_file") {
|
|
277
|
+
const filePath = toolInput?.file_path || toolInput?.path || toolInput?.file || toolInput?.target_file || "";
|
|
278
|
+
return isDiscoveryGrep(filePath);
|
|
279
|
+
}
|
|
280
|
+
if (tool === "list_files" || tool === "search_files" || tool === "search_files_content" || tool === "find_files" || tool === "find_by_name") {
|
|
281
|
+
const pattern = toolInput?.path || toolInput?.regex || toolInput?.pattern || toolInput?.query || "";
|
|
282
|
+
return !pattern || isDiscoveryGlob(pattern) || isDiscoveryGrep(pattern);
|
|
283
|
+
}
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
217
286
|
function isProjectIndexed(cwd) {
|
|
218
287
|
if (!fs2.existsSync(INDEX_STATUS_FILE)) {
|
|
219
288
|
return { isIndexed: false, isStale: false };
|
|
@@ -475,12 +544,22 @@ async function runPreToolUseHook() {
|
|
|
475
544
|
blockWithMessage(editorFormat, msg);
|
|
476
545
|
}
|
|
477
546
|
}
|
|
478
|
-
const { isIndexed } = isProjectIndexed(cwd);
|
|
479
|
-
fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}
|
|
480
|
-
`);
|
|
481
|
-
if (!isIndexed) {
|
|
482
|
-
fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] Project not indexed, allowing
|
|
547
|
+
const { isIndexed, isStale } = isProjectIndexed(cwd);
|
|
548
|
+
fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}, isStale=${isStale}
|
|
483
549
|
`);
|
|
550
|
+
if (isIndexed && !isStale) {
|
|
551
|
+
clearIndexWaitWindow(cwd);
|
|
552
|
+
} else {
|
|
553
|
+
const waitSeconds = configuredIndexWaitSeconds();
|
|
554
|
+
if (isLocalDiscoveryToolDuringIndexWait(tool, toolInput)) {
|
|
555
|
+
startIndexWaitWindow(cwd, waitSeconds);
|
|
556
|
+
const remaining = indexWaitRemainingSeconds(cwd);
|
|
557
|
+
if (remaining && remaining > 0) {
|
|
558
|
+
const msg = `Index refresh grace window is active (${remaining}s remaining). Keep ContextStream search-first flow: mcp__contextstream__search(mode="auto", query="..."). Do not use local discovery tools yet for stale/not-indexed projects. Retry after refresh; local fallback is allowed only after ~${waitSeconds}s if index is still unavailable.`;
|
|
559
|
+
blockWithMessage(editorFormat, msg);
|
|
560
|
+
}
|
|
561
|
+
allowTool(editorFormat, cwd, recordStateChange);
|
|
562
|
+
}
|
|
484
563
|
allowTool(editorFormat, cwd, recordStateChange);
|
|
485
564
|
}
|
|
486
565
|
if (tool === "Glob") {
|
|
@@ -572,7 +651,7 @@ async function runPreToolUseHook() {
|
|
|
572
651
|
}
|
|
573
652
|
allowTool(editorFormat, cwd, recordStateChange);
|
|
574
653
|
}
|
|
575
|
-
var ENABLED, INDEX_STATUS_FILE, DEBUG_FILE, STALE_THRESHOLD_DAYS, CONTEXT_FRESHNESS_SECONDS, DISCOVERY_PATTERNS, isDirectRun;
|
|
654
|
+
var ENABLED, INDEX_STATUS_FILE, DEBUG_FILE, STALE_THRESHOLD_DAYS, CONTEXT_FRESHNESS_SECONDS, DEFAULT_INDEX_WAIT_SECONDS, MIN_INDEX_WAIT_SECONDS, MAX_INDEX_WAIT_SECONDS, DISCOVERY_PATTERNS, isDirectRun;
|
|
576
655
|
var init_pre_tool_use = __esm({
|
|
577
656
|
"src/hooks/pre-tool-use.ts"() {
|
|
578
657
|
"use strict";
|
|
@@ -582,6 +661,9 @@ var init_pre_tool_use = __esm({
|
|
|
582
661
|
DEBUG_FILE = "/tmp/pretooluse-hook-debug.log";
|
|
583
662
|
STALE_THRESHOLD_DAYS = 7;
|
|
584
663
|
CONTEXT_FRESHNESS_SECONDS = 120;
|
|
664
|
+
DEFAULT_INDEX_WAIT_SECONDS = 20;
|
|
665
|
+
MIN_INDEX_WAIT_SECONDS = 15;
|
|
666
|
+
MAX_INDEX_WAIT_SECONDS = 20;
|
|
585
667
|
DISCOVERY_PATTERNS = ["**/*", "**/", "src/**", "lib/**", "app/**", "components/**"];
|
|
586
668
|
isDirectRun = process.argv[1]?.includes("pre-tool-use") || process.argv[2] === "pre-tool-use";
|
|
587
669
|
if (isDirectRun) {
|
|
@@ -1681,23 +1763,22 @@ Returns: \`indexed\` (true/false), \`last_indexed_at\`, \`file_count\`
|
|
|
1681
1763
|
\u2192 Use \`search(mode="auto", query="...")\`
|
|
1682
1764
|
|
|
1683
1765
|
**IF indexed=false OR last_indexed_at is stale (>7 days):**
|
|
1684
|
-
\u2192
|
|
1685
|
-
\u2192
|
|
1766
|
+
\u2192 Wait up to ~20s for background refresh, retry \`search(mode="auto", query="...")\`
|
|
1767
|
+
\u2192 After grace window: local tools are allowed if search still misses
|
|
1686
1768
|
|
|
1687
|
-
**IF search returns 0 results or errors:**
|
|
1769
|
+
**IF search still returns 0 results or errors after retry/window:**
|
|
1688
1770
|
\u2192 Fallback to local tools (Glob/Grep/Read)
|
|
1689
1771
|
|
|
1690
1772
|
### \u2705 When Local Tools (Glob/Grep/Read) Are OK:
|
|
1691
|
-
-
|
|
1692
|
-
-
|
|
1693
|
-
- ContextStream search returns 0 results
|
|
1773
|
+
- Stale/not-indexed grace window has elapsed (~20s default, configurable)
|
|
1774
|
+
- ContextStream search still returns 0 results after retry
|
|
1694
1775
|
- ContextStream returns errors
|
|
1695
1776
|
- User explicitly requests local tools
|
|
1696
1777
|
|
|
1697
1778
|
### On Session Start:
|
|
1698
1779
|
1. Call \`init(folder_path="...")\` - triggers initial indexing
|
|
1699
1780
|
2. Check \`project(action="index_status")\` before searching
|
|
1700
|
-
3. If not indexed: use local tools
|
|
1781
|
+
3. If not indexed: wait for background refresh (~20s), retry search, then use local tools only after the grace window
|
|
1701
1782
|
|
|
1702
1783
|
### After File Changes (Edit/Write/Create):
|
|
1703
1784
|
Files are NOT auto-indexed. You MUST:
|
|
@@ -1832,13 +1913,12 @@ COMMON MEMORY CALLS: list docs via memory(action="list_docs"), list lessons via
|
|
|
1832
1913
|
2. FOR CODE SEARCH: Check index status, then search appropriately
|
|
1833
1914
|
\u26A0\uFE0F BEFORE searching: mcp__contextstream__project(action="index_status")
|
|
1834
1915
|
\u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="auto", query="...") BEFORE Glob/Grep/Read/Explore/Task/EnterPlanMode
|
|
1835
|
-
\u2705 IF NOT indexed OR stale:
|
|
1836
|
-
\u2705 IF search returns 0 results:
|
|
1916
|
+
\u2705 IF NOT indexed OR stale: wait for background refresh up to ~20s, retry mcp__contextstream__search(mode="auto", query="..."), then allow local tools only after the grace window
|
|
1917
|
+
\u2705 IF search still returns 0 results after retry/window: fallback to local tools (Glob/Grep/Read)
|
|
1837
1918
|
|
|
1838
1919
|
3. WHEN LOCAL TOOLS (Glob/Grep/Read) ARE OK:
|
|
1839
|
-
\u2705
|
|
1840
|
-
\u2705
|
|
1841
|
-
\u2705 ContextStream search returns 0 results or errors
|
|
1920
|
+
\u2705 Stale/not-indexed grace window has elapsed (~20s default, configurable)
|
|
1921
|
+
\u2705 ContextStream search still returns 0 results or errors after retry
|
|
1842
1922
|
\u2705 User explicitly requests local tools
|
|
1843
1923
|
|
|
1844
1924
|
4. FOR PLANS & TASKS: Use ContextStream, not file-based plans
|
|
@@ -2540,7 +2620,7 @@ Use \`context()\` by default to get task-specific rules, lessons from past mista
|
|
|
2540
2620
|
2. **PreToolUse blocking** - If you try to use Glob/Grep/Search/Explore:
|
|
2541
2621
|
- Hook returns error: \`STOP: Use mcp__contextstream__search(mode="auto") instead\`
|
|
2542
2622
|
- **You MUST use the suggested ContextStream tool instead**
|
|
2543
|
-
|
|
2623
|
+
- For stale/not-indexed projects, wait for background refresh (up to ~20s), retry search, then allow local tools only after the grace window
|
|
2544
2624
|
|
|
2545
2625
|
3. **PostToolUse indexing** - After Edit/Write operations:
|
|
2546
2626
|
- Changed files are automatically re-indexed
|
|
@@ -2577,7 +2657,7 @@ STOP \u2192 Call search(mode="auto", query="...") FIRST
|
|
|
2577
2657
|
|
|
2578
2658
|
\u2705 **ALWAYS DO THIS:**
|
|
2579
2659
|
1. \`search(mode="auto", query="what you're looking for")\`
|
|
2580
|
-
2. Only use local tools (Glob/Grep/Read)
|
|
2660
|
+
2. Only use local tools (Glob/Grep/Read) after stale/not-indexed refresh grace window elapses (~20s) or ContextStream still returns **0 results** after retry
|
|
2581
2661
|
3. Use Read ONLY for exact file edits after you know the file path
|
|
2582
2662
|
|
|
2583
2663
|
This applies to **EVERY search** throughout the **ENTIRE conversation**, not just the first message.
|
|
@@ -2840,7 +2920,7 @@ session(action="capture", event_type="session_snapshot", title="Pre-compaction s
|
|
|
2840
2920
|
|
|
2841
2921
|
### Search & Code Intelligence (ContextStream-first)
|
|
2842
2922
|
|
|
2843
|
-
\u26A0\uFE0F **STOP: Before using Search/Glob/Grep/Read/Explore** \u2192 Call \`search(mode="auto")\` FIRST.
|
|
2923
|
+
\u26A0\uFE0F **STOP: Before using Search/Glob/Grep/Read/Explore** \u2192 Call \`search(mode="auto")\` FIRST. For stale/not-indexed projects, wait ~20s for background refresh and retry search before local fallback.
|
|
2844
2924
|
|
|
2845
2925
|
**\u274C WRONG workflow (wastes tokens, slow):**
|
|
2846
2926
|
\`\`\`
|
|
@@ -2859,7 +2939,7 @@ search(mode="auto", query="function implementation") \u2192 done (results includ
|
|
|
2859
2939
|
2. \`search(mode="auto", query="...", limit=3)\` or \`search(mode="keyword", query="<filename>", limit=3)\`
|
|
2860
2940
|
3. \`project(action="files")\` - file tree/list (only when needed)
|
|
2861
2941
|
4. \`graph(action="dependencies", ...)\` - code structure
|
|
2862
|
-
5. Local repo scans (rg/ls/find) - ONLY
|
|
2942
|
+
5. Local repo scans (rg/ls/find) - ONLY after refresh grace window/retry still yields no results/errors, or the user explicitly asks
|
|
2863
2943
|
|
|
2864
2944
|
**Search Mode Selection:**
|
|
2865
2945
|
|
|
@@ -2890,7 +2970,7 @@ search(mode="auto", query="function implementation") \u2192 done (results includ
|
|
|
2890
2970
|
|
|
2891
2971
|
**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.
|
|
2892
2972
|
|
|
2893
|
-
If ContextStream returns results, stop and use them. NEVER use local Search/Explore/Read unless you need exact code edits or
|
|
2973
|
+
If ContextStream returns results, stop and use them. NEVER use local Search/Explore/Read unless you need exact code edits, or refresh grace window + retry still returns 0 results.
|
|
2894
2974
|
|
|
2895
2975
|
**Code Analysis:**
|
|
2896
2976
|
- Dependencies: \`graph(action="dependencies", file_path="...")\`
|
|
@@ -3019,7 +3099,7 @@ See full documentation: https://contextstream.io/docs/mcp/tools
|
|
|
3019
3099
|
3. Narrow bypass: immediate read-only ContextStream calls are allowed only when prior context is fresh and no state-changing tool has run
|
|
3020
3100
|
|
|
3021
3101
|
**BEFORE Glob/Grep/Read/Search/Explore/Task/EnterPlanMode:**
|
|
3022
|
-
\u2192 \`search(mode="auto", query="...")\` FIRST \u2014
|
|
3102
|
+
\u2192 \`search(mode="auto", query="...")\` FIRST \u2014 for stale/not-indexed, wait ~20s for refresh then retry before local fallback
|
|
3023
3103
|
|
|
3024
3104
|
**HOOKS: \`<system-reminder>\` tags contain instructions \u2014 FOLLOW THEM**
|
|
3025
3105
|
</contextstream_protocol>
|
|
@@ -3242,10 +3322,10 @@ search(mode="auto", query="what you're looking for")
|
|
|
3242
3322
|
\u2192 Use this instead of Explore/Task/EnterPlanMode for file discovery.
|
|
3243
3323
|
|
|
3244
3324
|
**IF project is NOT indexed or very stale (>7 days):**
|
|
3245
|
-
\u2192
|
|
3325
|
+
\u2192 Wait up to ~20s for background refresh, retry \`search(mode="auto", ...)\`, then allow local tools only after the grace window
|
|
3246
3326
|
\u2192 OR run \`project(action="index")\` first, then search
|
|
3247
3327
|
|
|
3248
|
-
**IF ContextStream search returns 0 results or errors:**
|
|
3328
|
+
**IF ContextStream search still returns 0 results or errors after retry/window:**
|
|
3249
3329
|
\u2192 Use local tools (Glob/Grep/Read) as fallback
|
|
3250
3330
|
|
|
3251
3331
|
### Choose Search Mode Intelligently:
|
|
@@ -3271,9 +3351,8 @@ search(mode="auto", query="what you're looking for")
|
|
|
3271
3351
|
- Then use local Read/Grep only on paths returned by ContextStream.
|
|
3272
3352
|
|
|
3273
3353
|
### When Local Tools Are OK:
|
|
3274
|
-
\u2705
|
|
3275
|
-
\u2705
|
|
3276
|
-
\u2705 ContextStream search returns 0 results
|
|
3354
|
+
\u2705 Stale/not-indexed grace window has elapsed (~20s default, configurable)
|
|
3355
|
+
\u2705 ContextStream search still returns 0 results after retry
|
|
3277
3356
|
\u2705 ContextStream returns errors
|
|
3278
3357
|
\u2705 User explicitly requests local tools
|
|
3279
3358
|
|
|
@@ -3368,7 +3447,7 @@ After updating, user should restart their AI tool.
|
|
|
3368
3447
|
2. Project is indexed and \`search(mode="auto", ...)\` is retried before local fallbacks
|
|
3369
3448
|
3. Instructions file contains the current ContextStream managed block
|
|
3370
3449
|
`;
|
|
3371
|
-
NO_HOOKS_EDITORS = ["copilot", "codex", "opencode", "aider", "antigravity"];
|
|
3450
|
+
NO_HOOKS_EDITORS = ["copilot", "codex", "opencode", "aider", "antigravity", "kilo"];
|
|
3372
3451
|
TEMPLATES = {
|
|
3373
3452
|
codex: {
|
|
3374
3453
|
filename: "AGENTS.md",
|
|
@@ -3410,7 +3489,7 @@ ${rules}
|
|
|
3410
3489
|
`
|
|
3411
3490
|
},
|
|
3412
3491
|
kilo: {
|
|
3413
|
-
filename: ".
|
|
3492
|
+
filename: ".kilo/rules/contextstream.md",
|
|
3414
3493
|
description: "Kilo Code AI rules",
|
|
3415
3494
|
build: (rules) => `# Kilo Code Rules
|
|
3416
3495
|
${rules}
|
|
@@ -448,7 +448,7 @@ Use \`context()\` by default to get task-specific rules, lessons from past mista
|
|
|
448
448
|
2. **PreToolUse blocking** - If you try to use Glob/Grep/Search/Explore:
|
|
449
449
|
- Hook returns error: \`STOP: Use mcp__contextstream__search(mode="auto") instead\`
|
|
450
450
|
- **You MUST use the suggested ContextStream tool instead**
|
|
451
|
-
|
|
451
|
+
- For stale/not-indexed projects, wait for background refresh (up to ~20s), retry search, then allow local tools only after the grace window
|
|
452
452
|
|
|
453
453
|
3. **PostToolUse indexing** - After Edit/Write operations:
|
|
454
454
|
- Changed files are automatically re-indexed
|
|
@@ -485,7 +485,7 @@ STOP \u2192 Call search(mode="auto", query="...") FIRST
|
|
|
485
485
|
|
|
486
486
|
\u2705 **ALWAYS DO THIS:**
|
|
487
487
|
1. \`search(mode="auto", query="what you're looking for")\`
|
|
488
|
-
2. Only use local tools (Glob/Grep/Read)
|
|
488
|
+
2. Only use local tools (Glob/Grep/Read) after stale/not-indexed refresh grace window elapses (~20s) or ContextStream still returns **0 results** after retry
|
|
489
489
|
3. Use Read ONLY for exact file edits after you know the file path
|
|
490
490
|
|
|
491
491
|
This applies to **EVERY search** throughout the **ENTIRE conversation**, not just the first message.
|
|
@@ -748,7 +748,7 @@ session(action="capture", event_type="session_snapshot", title="Pre-compaction s
|
|
|
748
748
|
|
|
749
749
|
### Search & Code Intelligence (ContextStream-first)
|
|
750
750
|
|
|
751
|
-
\u26A0\uFE0F **STOP: Before using Search/Glob/Grep/Read/Explore** \u2192 Call \`search(mode="auto")\` FIRST.
|
|
751
|
+
\u26A0\uFE0F **STOP: Before using Search/Glob/Grep/Read/Explore** \u2192 Call \`search(mode="auto")\` FIRST. For stale/not-indexed projects, wait ~20s for background refresh and retry search before local fallback.
|
|
752
752
|
|
|
753
753
|
**\u274C WRONG workflow (wastes tokens, slow):**
|
|
754
754
|
\`\`\`
|
|
@@ -767,7 +767,7 @@ search(mode="auto", query="function implementation") \u2192 done (results includ
|
|
|
767
767
|
2. \`search(mode="auto", query="...", limit=3)\` or \`search(mode="keyword", query="<filename>", limit=3)\`
|
|
768
768
|
3. \`project(action="files")\` - file tree/list (only when needed)
|
|
769
769
|
4. \`graph(action="dependencies", ...)\` - code structure
|
|
770
|
-
5. Local repo scans (rg/ls/find) - ONLY
|
|
770
|
+
5. Local repo scans (rg/ls/find) - ONLY after refresh grace window/retry still yields no results/errors, or the user explicitly asks
|
|
771
771
|
|
|
772
772
|
**Search Mode Selection:**
|
|
773
773
|
|
|
@@ -798,7 +798,7 @@ search(mode="auto", query="function implementation") \u2192 done (results includ
|
|
|
798
798
|
|
|
799
799
|
**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.
|
|
800
800
|
|
|
801
|
-
If ContextStream returns results, stop and use them. NEVER use local Search/Explore/Read unless you need exact code edits or
|
|
801
|
+
If ContextStream returns results, stop and use them. NEVER use local Search/Explore/Read unless you need exact code edits, or refresh grace window + retry still returns 0 results.
|
|
802
802
|
|
|
803
803
|
**Code Analysis:**
|
|
804
804
|
- Dependencies: \`graph(action="dependencies", file_path="...")\`
|
|
@@ -927,7 +927,7 @@ var CONTEXTSTREAM_RULES_MINIMAL = `
|
|
|
927
927
|
3. Narrow bypass: immediate read-only ContextStream calls are allowed only when prior context is fresh and no state-changing tool has run
|
|
928
928
|
|
|
929
929
|
**BEFORE Glob/Grep/Read/Search/Explore/Task/EnterPlanMode:**
|
|
930
|
-
\u2192 \`search(mode="auto", query="...")\` FIRST \u2014
|
|
930
|
+
\u2192 \`search(mode="auto", query="...")\` FIRST \u2014 for stale/not-indexed, wait ~20s for refresh then retry before local fallback
|
|
931
931
|
|
|
932
932
|
**HOOKS: \`<system-reminder>\` tags contain instructions \u2014 FOLLOW THEM**
|
|
933
933
|
</contextstream_protocol>
|
|
@@ -1150,10 +1150,10 @@ search(mode="auto", query="what you're looking for")
|
|
|
1150
1150
|
\u2192 Use this instead of Explore/Task/EnterPlanMode for file discovery.
|
|
1151
1151
|
|
|
1152
1152
|
**IF project is NOT indexed or very stale (>7 days):**
|
|
1153
|
-
\u2192
|
|
1153
|
+
\u2192 Wait up to ~20s for background refresh, retry \`search(mode="auto", ...)\`, then allow local tools only after the grace window
|
|
1154
1154
|
\u2192 OR run \`project(action="index")\` first, then search
|
|
1155
1155
|
|
|
1156
|
-
**IF ContextStream search returns 0 results or errors:**
|
|
1156
|
+
**IF ContextStream search still returns 0 results or errors after retry/window:**
|
|
1157
1157
|
\u2192 Use local tools (Glob/Grep/Read) as fallback
|
|
1158
1158
|
|
|
1159
1159
|
### Choose Search Mode Intelligently:
|
|
@@ -1179,9 +1179,8 @@ search(mode="auto", query="what you're looking for")
|
|
|
1179
1179
|
- Then use local Read/Grep only on paths returned by ContextStream.
|
|
1180
1180
|
|
|
1181
1181
|
### When Local Tools Are OK:
|
|
1182
|
-
\u2705
|
|
1183
|
-
\u2705
|
|
1184
|
-
\u2705 ContextStream search returns 0 results
|
|
1182
|
+
\u2705 Stale/not-indexed grace window has elapsed (~20s default, configurable)
|
|
1183
|
+
\u2705 ContextStream search still returns 0 results after retry
|
|
1185
1184
|
\u2705 ContextStream returns errors
|
|
1186
1185
|
\u2705 User explicitly requests local tools
|
|
1187
1186
|
|
|
@@ -1276,7 +1275,7 @@ var ANTIGRAVITY_SUPPLEMENT = `
|
|
|
1276
1275
|
2. Project is indexed and \`search(mode="auto", ...)\` is retried before local fallbacks
|
|
1277
1276
|
3. Instructions file contains the current ContextStream managed block
|
|
1278
1277
|
`;
|
|
1279
|
-
var NO_HOOKS_EDITORS = ["copilot", "codex", "opencode", "aider", "antigravity"];
|
|
1278
|
+
var NO_HOOKS_EDITORS = ["copilot", "codex", "opencode", "aider", "antigravity", "kilo"];
|
|
1280
1279
|
var TEMPLATES = {
|
|
1281
1280
|
codex: {
|
|
1282
1281
|
filename: "AGENTS.md",
|
|
@@ -1318,7 +1317,7 @@ ${rules}
|
|
|
1318
1317
|
`
|
|
1319
1318
|
},
|
|
1320
1319
|
kilo: {
|
|
1321
|
-
filename: ".
|
|
1320
|
+
filename: ".kilo/rules/contextstream.md",
|
|
1322
1321
|
description: "Kilo Code AI rules",
|
|
1323
1322
|
build: (rules) => `# Kilo Code Rules
|
|
1324
1323
|
${rules}
|
|
@@ -1476,6 +1475,8 @@ function getOrCreateEntry(state, cwd) {
|
|
|
1476
1475
|
require_init: false,
|
|
1477
1476
|
last_context_at: void 0,
|
|
1478
1477
|
last_state_change_at: void 0,
|
|
1478
|
+
index_wait_started_at: void 0,
|
|
1479
|
+
index_wait_until: void 0,
|
|
1479
1480
|
updated_at: nowIso()
|
|
1480
1481
|
};
|
|
1481
1482
|
state.workspaces[cwd] = created;
|
|
@@ -235,6 +235,8 @@ function getOrCreateEntry(state, cwd) {
|
|
|
235
235
|
require_init: false,
|
|
236
236
|
last_context_at: void 0,
|
|
237
237
|
last_state_change_at: void 0,
|
|
238
|
+
index_wait_started_at: void 0,
|
|
239
|
+
index_wait_until: void 0,
|
|
238
240
|
updated_at: nowIso()
|
|
239
241
|
};
|
|
240
242
|
state.workspaces[cwd] = created;
|
|
@@ -298,13 +300,12 @@ var FULL_REMINDER = `[CONTEXTSTREAM RULES - MANDATORY]
|
|
|
298
300
|
2. FOR CODE SEARCH: Check index status, then search appropriately
|
|
299
301
|
\u26A0\uFE0F BEFORE searching: mcp__contextstream__project(action="index_status")
|
|
300
302
|
\u2705 IF indexed & fresh: Use mcp__contextstream__search(mode="auto", query="...") BEFORE Glob/Grep/Read/Explore/Task/EnterPlanMode
|
|
301
|
-
\u2705 IF NOT indexed OR stale:
|
|
302
|
-
\u2705 IF search returns 0 results:
|
|
303
|
+
\u2705 IF NOT indexed OR stale: wait for background refresh up to ~20s, retry mcp__contextstream__search(mode="auto", query="..."), then allow local tools only after the grace window
|
|
304
|
+
\u2705 IF search still returns 0 results after retry/window: fallback to local tools (Glob/Grep/Read)
|
|
303
305
|
|
|
304
306
|
3. WHEN LOCAL TOOLS (Glob/Grep/Read) ARE OK:
|
|
305
|
-
\u2705
|
|
306
|
-
\u2705
|
|
307
|
-
\u2705 ContextStream search returns 0 results or errors
|
|
307
|
+
\u2705 Stale/not-indexed grace window has elapsed (~20s default, configurable)
|
|
308
|
+
\u2705 ContextStream search still returns 0 results or errors after retry
|
|
308
309
|
\u2705 User explicitly requests local tools
|
|
309
310
|
|
|
310
311
|
4. FOR PLANS & TASKS: Use ContextStream, not file-based plans
|
|
@@ -727,23 +728,22 @@ Returns: \`indexed\` (true/false), \`last_indexed_at\`, \`file_count\`
|
|
|
727
728
|
\u2192 Use \`search(mode="auto", query="...")\`
|
|
728
729
|
|
|
729
730
|
**IF indexed=false OR last_indexed_at is stale (>7 days):**
|
|
730
|
-
\u2192
|
|
731
|
-
\u2192
|
|
731
|
+
\u2192 Wait up to ~20s for background refresh, retry \`search(mode="auto", query="...")\`
|
|
732
|
+
\u2192 After grace window: local tools are allowed if search still misses
|
|
732
733
|
|
|
733
|
-
**IF search returns 0 results or errors:**
|
|
734
|
+
**IF search still returns 0 results or errors after retry/window:**
|
|
734
735
|
\u2192 Fallback to local tools (Glob/Grep/Read)
|
|
735
736
|
|
|
736
737
|
### \u2705 When Local Tools (Glob/Grep/Read) Are OK:
|
|
737
|
-
-
|
|
738
|
-
-
|
|
739
|
-
- ContextStream search returns 0 results
|
|
738
|
+
- Stale/not-indexed grace window has elapsed (~20s default, configurable)
|
|
739
|
+
- ContextStream search still returns 0 results after retry
|
|
740
740
|
- ContextStream returns errors
|
|
741
741
|
- User explicitly requests local tools
|
|
742
742
|
|
|
743
743
|
### On Session Start:
|
|
744
744
|
1. Call \`init(folder_path="...")\` - triggers initial indexing
|
|
745
745
|
2. Check \`project(action="index_status")\` before searching
|
|
746
|
-
3. If not indexed: use local tools
|
|
746
|
+
3. If not indexed: wait for background refresh (~20s), retry search, then use local tools only after the grace window
|
|
747
747
|
|
|
748
748
|
### After File Changes (Edit/Write/Create):
|
|
749
749
|
Files are NOT auto-indexed. You MUST:
|