@contextstream/mcp-server 0.4.74 → 0.4.80
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/dist/hooks/auto-rules.js +42 -19
- package/dist/hooks/pre-tool-use.js +8 -83
- package/dist/hooks/runner.js +120 -106
- package/dist/hooks/session-init.js +105 -15
- package/dist/hooks/user-prompt-submit.js +6 -7
- package/dist/index.js +22291 -17789
- package/package.json +3 -3
- package/scripts/registration-smoke.mts +45 -0
package/dist/hooks/auto-rules.js
CHANGED
|
@@ -536,6 +536,13 @@ var init_ignore = __esm({
|
|
|
536
536
|
"out/",
|
|
537
537
|
".next/",
|
|
538
538
|
".nuxt/",
|
|
539
|
+
".svelte-kit/",
|
|
540
|
+
".parcel-cache/",
|
|
541
|
+
".turbo/",
|
|
542
|
+
".gradle/",
|
|
543
|
+
".cache/",
|
|
544
|
+
"bin/",
|
|
545
|
+
"obj/",
|
|
539
546
|
// Python
|
|
540
547
|
"__pycache__/",
|
|
541
548
|
".pytest_cache/",
|
|
@@ -559,6 +566,8 @@ var init_ignore = __esm({
|
|
|
559
566
|
"poetry.lock",
|
|
560
567
|
"Gemfile.lock",
|
|
561
568
|
"composer.lock",
|
|
569
|
+
"*.min.js",
|
|
570
|
+
"*.min.css",
|
|
562
571
|
// OS files
|
|
563
572
|
".DS_Store",
|
|
564
573
|
"Thumbs.db"
|
|
@@ -726,6 +735,7 @@ async function readFilesFromDirectory(rootPath, options = {}) {
|
|
|
726
735
|
const file = {
|
|
727
736
|
path: relPath,
|
|
728
737
|
content,
|
|
738
|
+
language: detectLanguage(relPath),
|
|
729
739
|
// Always include machine_id and source_modified_at
|
|
730
740
|
machine_id: gitCtx.machineId,
|
|
731
741
|
source_modified_at: stat.mtime.toISOString()
|
|
@@ -785,6 +795,7 @@ async function* readAllFilesInBatches(rootPath, options = {}) {
|
|
|
785
795
|
const file = {
|
|
786
796
|
path: relPath,
|
|
787
797
|
content,
|
|
798
|
+
language: detectLanguage(relPath),
|
|
788
799
|
sizeBytes: stat.size,
|
|
789
800
|
// Always include machine_id and source_modified_at
|
|
790
801
|
machine_id: gitCtx.machineId,
|
|
@@ -875,6 +886,7 @@ async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}
|
|
|
875
886
|
const file = {
|
|
876
887
|
path: relPath,
|
|
877
888
|
content,
|
|
889
|
+
language: detectLanguage(relPath),
|
|
878
890
|
sizeBytes: stat.size,
|
|
879
891
|
// Always include machine_id and source_modified_at
|
|
880
892
|
machine_id: gitCtx.machineId,
|
|
@@ -1125,6 +1137,11 @@ var init_files = __esm({
|
|
|
1125
1137
|
"out",
|
|
1126
1138
|
".next",
|
|
1127
1139
|
".nuxt",
|
|
1140
|
+
".svelte-kit",
|
|
1141
|
+
".parcel-cache",
|
|
1142
|
+
".turbo",
|
|
1143
|
+
".gradle",
|
|
1144
|
+
".cache",
|
|
1128
1145
|
"__pycache__",
|
|
1129
1146
|
".pytest_cache",
|
|
1130
1147
|
".mypy_cache",
|
|
@@ -1135,6 +1152,8 @@ var init_files = __esm({
|
|
|
1135
1152
|
"vendor",
|
|
1136
1153
|
"coverage",
|
|
1137
1154
|
".coverage",
|
|
1155
|
+
"bin",
|
|
1156
|
+
"obj",
|
|
1138
1157
|
".idea",
|
|
1139
1158
|
".vscode",
|
|
1140
1159
|
".vs"
|
|
@@ -1153,9 +1172,9 @@ var init_files = __esm({
|
|
|
1153
1172
|
"composer.lock"
|
|
1154
1173
|
]);
|
|
1155
1174
|
MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
1156
|
-
MAX_BATCH_BYTES =
|
|
1175
|
+
MAX_BATCH_BYTES = 1024 * 1024;
|
|
1157
1176
|
LARGE_FILE_THRESHOLD = 2 * 1024 * 1024;
|
|
1158
|
-
MAX_FILES_PER_BATCH =
|
|
1177
|
+
MAX_FILES_PER_BATCH = 20;
|
|
1159
1178
|
gitContextCache = /* @__PURE__ */ new Map();
|
|
1160
1179
|
}
|
|
1161
1180
|
});
|
|
@@ -1827,10 +1846,13 @@ async function writeIndexStatus(status) {
|
|
|
1827
1846
|
async function markProjectIndexed(projectPath, options) {
|
|
1828
1847
|
const status = await readIndexStatus();
|
|
1829
1848
|
const resolvedPath = path3.resolve(projectPath);
|
|
1849
|
+
const previous = status.projects[resolvedPath];
|
|
1830
1850
|
status.projects[resolvedPath] = {
|
|
1831
1851
|
indexed_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1832
|
-
project_id: options?.project_id,
|
|
1833
|
-
project_name: options?.project_name
|
|
1852
|
+
project_id: options?.project_id ?? previous?.project_id,
|
|
1853
|
+
project_name: options?.project_name ?? previous?.project_name,
|
|
1854
|
+
git_head: options?.git_head ?? previous?.git_head,
|
|
1855
|
+
git_remote: options?.git_remote ?? previous?.git_remote
|
|
1834
1856
|
};
|
|
1835
1857
|
await writeIndexStatus(status);
|
|
1836
1858
|
}
|
|
@@ -2014,21 +2036,22 @@ async function installCursorHookScripts(options) {
|
|
|
2014
2036
|
for (const [eventName, entries] of Object.entries(existingConfig.hooks || {})) {
|
|
2015
2037
|
cleanedHooks[eventName] = filterContextStreamHooks(entries);
|
|
2016
2038
|
}
|
|
2017
|
-
const
|
|
2018
|
-
const
|
|
2019
|
-
const
|
|
2020
|
-
const
|
|
2021
|
-
const
|
|
2022
|
-
const
|
|
2023
|
-
const
|
|
2024
|
-
const
|
|
2025
|
-
const
|
|
2026
|
-
const
|
|
2027
|
-
const
|
|
2028
|
-
const
|
|
2029
|
-
const
|
|
2030
|
-
const
|
|
2031
|
-
const
|
|
2039
|
+
const cursorHookCommand = (name) => `${getHookCommand(name)} --editor=cursor`;
|
|
2040
|
+
const preToolUseCommand = cursorHookCommand("pre-tool-use");
|
|
2041
|
+
const userPromptCommand = cursorHookCommand("user-prompt-submit");
|
|
2042
|
+
const saveIntentCommand = cursorHookCommand("on-save-intent");
|
|
2043
|
+
const postToolUseCommand = cursorHookCommand("post-tool-use");
|
|
2044
|
+
const postToolUseFailureCommand = cursorHookCommand("post-tool-use-failure");
|
|
2045
|
+
const preCompactCommand = cursorHookCommand("pre-compact");
|
|
2046
|
+
const sessionStartCommand = cursorHookCommand("session-start");
|
|
2047
|
+
const sessionEndCommand = cursorHookCommand("session-end");
|
|
2048
|
+
const stopCommand = cursorHookCommand("stop");
|
|
2049
|
+
const notificationCommand = cursorHookCommand("notification");
|
|
2050
|
+
const permissionRequestCommand = cursorHookCommand("permission-request");
|
|
2051
|
+
const subagentStartCommand = cursorHookCommand("subagent-start");
|
|
2052
|
+
const subagentStopCommand = cursorHookCommand("subagent-stop");
|
|
2053
|
+
const taskCompletedCommand = cursorHookCommand("task-completed");
|
|
2054
|
+
const teammateIdleCommand = cursorHookCommand("teammate-idle");
|
|
2032
2055
|
const config = {
|
|
2033
2056
|
version: 1,
|
|
2034
2057
|
hooks: {
|
|
@@ -151,44 +151,6 @@ function isContextFreshAndClean(cwd, maxAgeSeconds) {
|
|
|
151
151
|
}
|
|
152
152
|
return true;
|
|
153
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
|
-
}
|
|
192
154
|
|
|
193
155
|
// src/hooks/pre-tool-use.ts
|
|
194
156
|
var ENABLED = process.env.CONTEXTSTREAM_HOOK_ENABLED !== "false";
|
|
@@ -196,9 +158,6 @@ var INDEX_STATUS_FILE = path2.join(homedir2(), ".contextstream", "indexed-projec
|
|
|
196
158
|
var DEBUG_FILE = "/tmp/pretooluse-hook-debug.log";
|
|
197
159
|
var STALE_THRESHOLD_DAYS = 7;
|
|
198
160
|
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;
|
|
202
161
|
var DISCOVERY_PATTERNS = ["**/*", "**/", "src/**", "lib/**", "app/**", "components/**"];
|
|
203
162
|
function isDiscoveryGlob(pattern) {
|
|
204
163
|
const patternLower = pattern.toLowerCase();
|
|
@@ -224,33 +183,6 @@ function isDiscoveryGrep(filePath) {
|
|
|
224
183
|
}
|
|
225
184
|
return false;
|
|
226
185
|
}
|
|
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
|
-
}
|
|
254
186
|
function isProjectIndexed(cwd) {
|
|
255
187
|
if (!fs2.existsSync(INDEX_STATUS_FILE)) {
|
|
256
188
|
return { isIndexed: false, isStale: false };
|
|
@@ -420,11 +352,13 @@ function outputClineAllow() {
|
|
|
420
352
|
process.exit(0);
|
|
421
353
|
}
|
|
422
354
|
function outputCursorBlock(reason) {
|
|
423
|
-
console.log(
|
|
355
|
+
console.log(
|
|
356
|
+
JSON.stringify({ permission: "deny", agent_message: reason, user_message: reason })
|
|
357
|
+
);
|
|
424
358
|
process.exit(0);
|
|
425
359
|
}
|
|
426
360
|
function outputCursorAllow() {
|
|
427
|
-
console.log(JSON.stringify({
|
|
361
|
+
console.log(JSON.stringify({ permission: "allow" }));
|
|
428
362
|
process.exit(0);
|
|
429
363
|
}
|
|
430
364
|
function blockWithMessage(editorFormat, message) {
|
|
@@ -447,6 +381,9 @@ function allowTool(editorFormat, cwd, recordStateChange) {
|
|
|
447
381
|
process.exit(0);
|
|
448
382
|
}
|
|
449
383
|
function detectEditorFormat(input) {
|
|
384
|
+
if (process.argv.includes("--editor=cursor")) {
|
|
385
|
+
return "cursor";
|
|
386
|
+
}
|
|
450
387
|
if (input.hookName !== void 0 || input.toolName !== void 0) {
|
|
451
388
|
return "cline";
|
|
452
389
|
}
|
|
@@ -515,19 +452,7 @@ async function runPreToolUseHook() {
|
|
|
515
452
|
const { isIndexed, isStale } = isProjectIndexed(cwd);
|
|
516
453
|
fs2.appendFileSync(DEBUG_FILE, `[PreToolUse] isIndexed=${isIndexed}, isStale=${isStale}
|
|
517
454
|
`);
|
|
518
|
-
if (isIndexed
|
|
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
|
-
}
|
|
455
|
+
if (!isIndexed || isStale) {
|
|
531
456
|
allowTool(editorFormat, cwd, recordStateChange);
|
|
532
457
|
}
|
|
533
458
|
if (tool === "Glob") {
|