@contextstream/mcp-server 0.4.57 → 0.4.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/auto-rules.js +72 -45
- package/dist/hooks/pre-tool-use.js +4 -4
- package/dist/hooks/runner.js +150 -114
- package/dist/hooks/session-init.js +1037 -1
- package/dist/hooks/user-prompt-submit.js +73 -64
- package/dist/index.js +15320 -14913
- package/dist/test-server.js +1 -1
- package/package.json +1 -1
package/dist/hooks/auto-rules.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
-
}) : x)(function(x) {
|
|
7
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
-
});
|
|
10
4
|
var __esm = (fn, res) => function __init() {
|
|
11
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
6
|
};
|
|
@@ -58,20 +52,31 @@ __export(hooks_config_exports, {
|
|
|
58
52
|
writeIndexStatus: () => writeIndexStatus
|
|
59
53
|
});
|
|
60
54
|
import * as fs from "node:fs/promises";
|
|
55
|
+
import * as fsSync from "node:fs";
|
|
61
56
|
import * as path from "node:path";
|
|
62
57
|
import { homedir } from "node:os";
|
|
63
58
|
import { fileURLToPath } from "node:url";
|
|
64
59
|
function getHookCommand(hookName) {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
const isWindows = process.platform === "win32";
|
|
61
|
+
if (isWindows) {
|
|
62
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
63
|
+
if (localAppData) {
|
|
64
|
+
const windowsBinaryPath = path.join(localAppData, "ContextStream", "contextstream-mcp.exe");
|
|
65
|
+
if (fsSync.existsSync(windowsBinaryPath)) {
|
|
66
|
+
return `"${windowsBinaryPath}" hook ${hookName}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
const unixBinaryPath = "/usr/local/bin/contextstream-mcp";
|
|
71
|
+
if (fsSync.existsSync(unixBinaryPath)) {
|
|
72
|
+
return `${unixBinaryPath} hook ${hookName}`;
|
|
73
|
+
}
|
|
69
74
|
}
|
|
70
75
|
try {
|
|
71
76
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
72
77
|
const indexPath = path.join(__dirname, "index.js");
|
|
73
|
-
if (
|
|
74
|
-
return `node ${indexPath} hook ${hookName}`;
|
|
78
|
+
if (fsSync.existsSync(indexPath)) {
|
|
79
|
+
return `node "${indexPath}" hook ${hookName}`;
|
|
75
80
|
}
|
|
76
81
|
} catch {
|
|
77
82
|
}
|
|
@@ -484,20 +489,43 @@ function getClineHooksDir(scope, projectPath) {
|
|
|
484
489
|
}
|
|
485
490
|
return path.join(projectPath, ".clinerules", "hooks");
|
|
486
491
|
}
|
|
492
|
+
function getHookWrapperScript(hookName) {
|
|
493
|
+
const isWindows = process.platform === "win32";
|
|
494
|
+
const command = getHookCommand(hookName);
|
|
495
|
+
if (isWindows) {
|
|
496
|
+
return {
|
|
497
|
+
content: `@echo off\r
|
|
498
|
+
${command}\r
|
|
499
|
+
`,
|
|
500
|
+
extension: ".cmd"
|
|
501
|
+
};
|
|
502
|
+
} else {
|
|
503
|
+
return {
|
|
504
|
+
content: `#!/bin/bash
|
|
505
|
+
# ContextStream ${hookName} Hook Wrapper for Cline/Roo/Kilo Code
|
|
506
|
+
exec ${command}
|
|
507
|
+
`,
|
|
508
|
+
extension: ""
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
}
|
|
487
512
|
async function installClineHookScripts(options) {
|
|
488
513
|
const hooksDir = getClineHooksDir(options.scope, options.projectPath);
|
|
489
514
|
await fs.mkdir(hooksDir, { recursive: true });
|
|
490
|
-
const
|
|
491
|
-
const
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
515
|
+
const preToolUseWrapper = getHookWrapperScript("pre-tool-use");
|
|
516
|
+
const userPromptWrapper = getHookWrapperScript("user-prompt-submit");
|
|
517
|
+
const postWriteWrapper = getHookWrapperScript("post-write");
|
|
518
|
+
const preToolUsePath = path.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
|
|
519
|
+
const userPromptPath = path.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
|
|
520
|
+
const postToolUsePath = path.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
|
|
521
|
+
await fs.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
|
|
522
|
+
await fs.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
|
|
495
523
|
const result = {
|
|
496
524
|
preToolUse: preToolUsePath,
|
|
497
525
|
userPromptSubmit: userPromptPath
|
|
498
526
|
};
|
|
499
527
|
if (options.includePostWrite !== false) {
|
|
500
|
-
await fs.writeFile(postToolUsePath,
|
|
528
|
+
await fs.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
|
|
501
529
|
result.postToolUse = postToolUsePath;
|
|
502
530
|
}
|
|
503
531
|
return result;
|
|
@@ -514,17 +542,20 @@ function getRooCodeHooksDir(scope, projectPath) {
|
|
|
514
542
|
async function installRooCodeHookScripts(options) {
|
|
515
543
|
const hooksDir = getRooCodeHooksDir(options.scope, options.projectPath);
|
|
516
544
|
await fs.mkdir(hooksDir, { recursive: true });
|
|
517
|
-
const
|
|
518
|
-
const
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
|
|
545
|
+
const preToolUseWrapper = getHookWrapperScript("pre-tool-use");
|
|
546
|
+
const userPromptWrapper = getHookWrapperScript("user-prompt-submit");
|
|
547
|
+
const postWriteWrapper = getHookWrapperScript("post-write");
|
|
548
|
+
const preToolUsePath = path.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
|
|
549
|
+
const userPromptPath = path.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
|
|
550
|
+
const postToolUsePath = path.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
|
|
551
|
+
await fs.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
|
|
552
|
+
await fs.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
|
|
522
553
|
const result = {
|
|
523
554
|
preToolUse: preToolUsePath,
|
|
524
555
|
userPromptSubmit: userPromptPath
|
|
525
556
|
};
|
|
526
557
|
if (options.includePostWrite !== false) {
|
|
527
|
-
await fs.writeFile(postToolUsePath,
|
|
558
|
+
await fs.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
|
|
528
559
|
result.postToolUse = postToolUsePath;
|
|
529
560
|
}
|
|
530
561
|
return result;
|
|
@@ -541,17 +572,20 @@ function getKiloCodeHooksDir(scope, projectPath) {
|
|
|
541
572
|
async function installKiloCodeHookScripts(options) {
|
|
542
573
|
const hooksDir = getKiloCodeHooksDir(options.scope, options.projectPath);
|
|
543
574
|
await fs.mkdir(hooksDir, { recursive: true });
|
|
544
|
-
const
|
|
545
|
-
const
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
575
|
+
const preToolUseWrapper = getHookWrapperScript("pre-tool-use");
|
|
576
|
+
const userPromptWrapper = getHookWrapperScript("user-prompt-submit");
|
|
577
|
+
const postWriteWrapper = getHookWrapperScript("post-write");
|
|
578
|
+
const preToolUsePath = path.join(hooksDir, `PreToolUse${preToolUseWrapper.extension}`);
|
|
579
|
+
const userPromptPath = path.join(hooksDir, `UserPromptSubmit${userPromptWrapper.extension}`);
|
|
580
|
+
const postToolUsePath = path.join(hooksDir, `PostToolUse${postWriteWrapper.extension}`);
|
|
581
|
+
await fs.writeFile(preToolUsePath, preToolUseWrapper.content, { mode: 493 });
|
|
582
|
+
await fs.writeFile(userPromptPath, userPromptWrapper.content, { mode: 493 });
|
|
549
583
|
const result = {
|
|
550
584
|
preToolUse: preToolUsePath,
|
|
551
585
|
userPromptSubmit: userPromptPath
|
|
552
586
|
};
|
|
553
587
|
if (options.includePostWrite !== false) {
|
|
554
|
-
await fs.writeFile(postToolUsePath,
|
|
588
|
+
await fs.writeFile(postToolUsePath, postWriteWrapper.content, { mode: 493 });
|
|
555
589
|
result.postToolUse = postToolUsePath;
|
|
556
590
|
}
|
|
557
591
|
return result;
|
|
@@ -780,7 +814,7 @@ Set environment variables:
|
|
|
780
814
|
- \`CONTEXTSTREAM_REMINDER_ENABLED=false\` - Disable UserPromptSubmit reminders
|
|
781
815
|
`.trim();
|
|
782
816
|
}
|
|
783
|
-
var PRETOOLUSE_HOOK_SCRIPT, USER_PROMPT_HOOK_SCRIPT, MEDIA_AWARE_HOOK_SCRIPT, PRECOMPACT_HOOK_SCRIPT, CLINE_PRETOOLUSE_HOOK_SCRIPT, CLINE_USER_PROMPT_HOOK_SCRIPT, CLINE_POSTTOOLUSE_HOOK_SCRIPT,
|
|
817
|
+
var PRETOOLUSE_HOOK_SCRIPT, USER_PROMPT_HOOK_SCRIPT, MEDIA_AWARE_HOOK_SCRIPT, PRECOMPACT_HOOK_SCRIPT, CLINE_PRETOOLUSE_HOOK_SCRIPT, CLINE_USER_PROMPT_HOOK_SCRIPT, CLINE_POSTTOOLUSE_HOOK_SCRIPT, CURSOR_PRETOOLUSE_HOOK_SCRIPT, CURSOR_BEFORE_SUBMIT_HOOK_SCRIPT;
|
|
784
818
|
var init_hooks_config = __esm({
|
|
785
819
|
"src/hooks-config.ts"() {
|
|
786
820
|
"use strict";
|
|
@@ -891,7 +925,7 @@ def main():
|
|
|
891
925
|
if tool == "Glob":
|
|
892
926
|
pattern = inp.get("pattern", "")
|
|
893
927
|
if is_discovery_glob(pattern):
|
|
894
|
-
print(f"STOP: Use mcp__contextstream__search(mode=\\"
|
|
928
|
+
print(f"STOP: Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of Glob.", file=sys.stderr)
|
|
895
929
|
sys.exit(2)
|
|
896
930
|
|
|
897
931
|
elif tool == "Grep" or tool == "Search":
|
|
@@ -903,12 +937,12 @@ def main():
|
|
|
903
937
|
# Specific file - suggest Read instead
|
|
904
938
|
print(f"STOP: Use Read(\\"{path}\\") to view file content, or mcp__contextstream__search(mode=\\"keyword\\", query=\\"{pattern}\\") for codebase search.", file=sys.stderr)
|
|
905
939
|
else:
|
|
906
|
-
print(f"STOP: Use mcp__contextstream__search(mode=\\"
|
|
940
|
+
print(f"STOP: Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}.", file=sys.stderr)
|
|
907
941
|
sys.exit(2)
|
|
908
942
|
|
|
909
943
|
elif tool == "Task":
|
|
910
944
|
if inp.get("subagent_type", "").lower() == "explore":
|
|
911
|
-
print("STOP: Use mcp__contextstream__search(mode=\\"
|
|
945
|
+
print("STOP: Use mcp__contextstream__search(mode=\\"auto\\") instead of Task(Explore).", file=sys.stderr)
|
|
912
946
|
sys.exit(2)
|
|
913
947
|
if inp.get("subagent_type", "").lower() == "plan":
|
|
914
948
|
print("STOP: Use mcp__contextstream__session(action=\\"capture_plan\\") for planning. ContextStream plans persist across sessions.", file=sys.stderr)
|
|
@@ -935,7 +969,7 @@ import os
|
|
|
935
969
|
ENABLED = os.environ.get("CONTEXTSTREAM_REMINDER_ENABLED", "true").lower() == "true"
|
|
936
970
|
|
|
937
971
|
REMINDER = """[CONTEXTSTREAM RULES]
|
|
938
|
-
1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="
|
|
972
|
+
1. BEFORE Glob/Grep/Read/Search: mcp__contextstream__search(mode="auto") FIRST
|
|
939
973
|
2. Call context_smart at start of EVERY response
|
|
940
974
|
3. Local tools ONLY if ContextStream returns 0 results
|
|
941
975
|
[END RULES]"""
|
|
@@ -1371,7 +1405,7 @@ def main():
|
|
|
1371
1405
|
pattern = params.get("path", "") or params.get("regex", "")
|
|
1372
1406
|
if is_discovery_glob(pattern) or is_discovery_grep(pattern):
|
|
1373
1407
|
output_block(
|
|
1374
|
-
f"Use mcp__contextstream__search(mode=\\"
|
|
1408
|
+
f"Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}. "
|
|
1375
1409
|
"ContextStream search is indexed and faster. Only use local tools if ContextStream returns 0 results.",
|
|
1376
1410
|
"[CONTEXTSTREAM] Use ContextStream search for code discovery."
|
|
1377
1411
|
)
|
|
@@ -1398,7 +1432,7 @@ import os
|
|
|
1398
1432
|
ENABLED = os.environ.get("CONTEXTSTREAM_REMINDER_ENABLED", "true").lower() == "true"
|
|
1399
1433
|
|
|
1400
1434
|
REMINDER = """[CONTEXTSTREAM RULES]
|
|
1401
|
-
1. BEFORE list_files/search_files/read_file: mcp__contextstream__search(mode="
|
|
1435
|
+
1. BEFORE list_files/search_files/read_file: mcp__contextstream__search(mode="auto") FIRST
|
|
1402
1436
|
2. Call context_smart at start of EVERY response
|
|
1403
1437
|
3. Local tools ONLY if ContextStream returns 0 results
|
|
1404
1438
|
[END RULES]"""
|
|
@@ -1440,13 +1474,6 @@ esac
|
|
|
1440
1474
|
|
|
1441
1475
|
exit 0
|
|
1442
1476
|
`;
|
|
1443
|
-
CLINE_HOOK_WRAPPER = (hookName) => {
|
|
1444
|
-
const command = getHookCommand(hookName);
|
|
1445
|
-
return `#!/bin/bash
|
|
1446
|
-
# ContextStream ${hookName} Hook Wrapper for Cline/Roo/Kilo Code
|
|
1447
|
-
exec ${command}
|
|
1448
|
-
`;
|
|
1449
|
-
};
|
|
1450
1477
|
CURSOR_PRETOOLUSE_HOOK_SCRIPT = `#!/usr/bin/env python3
|
|
1451
1478
|
"""
|
|
1452
1479
|
ContextStream PreToolUse Hook for Cursor
|
|
@@ -1556,7 +1583,7 @@ def main():
|
|
|
1556
1583
|
pattern = params.get("pattern", "") or params.get("path", "")
|
|
1557
1584
|
if is_discovery_glob(pattern):
|
|
1558
1585
|
output_deny(
|
|
1559
|
-
f"Use mcp__contextstream__search(mode=\\"
|
|
1586
|
+
f"Use mcp__contextstream__search(mode=\\"auto\\", query=\\"{pattern}\\") instead of {tool}. "
|
|
1560
1587
|
"ContextStream search is indexed and faster."
|
|
1561
1588
|
)
|
|
1562
1589
|
|
|
@@ -173,7 +173,7 @@ async function runPreToolUseHook() {
|
|
|
173
173
|
fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Glob pattern=${pattern}, isDiscovery=${isDiscoveryGlob(pattern)}
|
|
174
174
|
`);
|
|
175
175
|
if (isDiscoveryGlob(pattern)) {
|
|
176
|
-
const msg = `STOP: Use mcp__contextstream__search(mode="
|
|
176
|
+
const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of Glob.`;
|
|
177
177
|
fs.appendFileSync(DEBUG_FILE, `[PreToolUse] Intercepting discovery glob: ${msg}
|
|
178
178
|
`);
|
|
179
179
|
if (editorFormat === "cline") {
|
|
@@ -196,7 +196,7 @@ async function runPreToolUseHook() {
|
|
|
196
196
|
}
|
|
197
197
|
blockClaudeCode(msg);
|
|
198
198
|
} else {
|
|
199
|
-
const msg = `STOP: Use mcp__contextstream__search(mode="
|
|
199
|
+
const msg = `STOP: Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}.`;
|
|
200
200
|
if (editorFormat === "cline") {
|
|
201
201
|
outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
|
|
202
202
|
} else if (editorFormat === "cursor") {
|
|
@@ -208,7 +208,7 @@ async function runPreToolUseHook() {
|
|
|
208
208
|
} else if (tool === "Task") {
|
|
209
209
|
const subagentType = toolInput?.subagent_type?.toLowerCase() || "";
|
|
210
210
|
if (subagentType === "explore") {
|
|
211
|
-
const msg = 'STOP: Use mcp__contextstream__search(mode="
|
|
211
|
+
const msg = 'STOP: Use mcp__contextstream__search(mode="auto") instead of Task(Explore).';
|
|
212
212
|
if (editorFormat === "cline") {
|
|
213
213
|
outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
|
|
214
214
|
} else if (editorFormat === "cursor") {
|
|
@@ -237,7 +237,7 @@ async function runPreToolUseHook() {
|
|
|
237
237
|
if (tool === "list_files" || tool === "search_files") {
|
|
238
238
|
const pattern = toolInput?.path || toolInput?.regex || "";
|
|
239
239
|
if (isDiscoveryGlob(pattern) || isDiscoveryGrep(pattern)) {
|
|
240
|
-
const msg = `Use mcp__contextstream__search(mode="
|
|
240
|
+
const msg = `Use mcp__contextstream__search(mode="auto", query="${pattern}") instead of ${tool}. ContextStream search is indexed and faster.`;
|
|
241
241
|
if (editorFormat === "cline") {
|
|
242
242
|
outputClineBlock(msg, "[CONTEXTSTREAM] Use ContextStream search for code discovery.");
|
|
243
243
|
} else if (editorFormat === "cursor") {
|