@contextstream/mcp-server 0.4.80 → 0.4.82
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 +173 -183
- package/dist/hooks/auto-rules.js +162 -17
- package/dist/hooks/post-write.js +703 -28
- package/dist/hooks/runner.js +871 -147
- package/dist/hooks/session-init.js +37 -3
- package/dist/hooks/user-prompt-submit.js +11 -4
- package/dist/index.js +24163 -23400
- package/package.json +24 -7
package/dist/hooks/auto-rules.js
CHANGED
|
@@ -5,11 +5,20 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __esm = (fn, res) => function __init() {
|
|
9
|
-
|
|
8
|
+
var __esm = (fn, res, err) => function __init() {
|
|
9
|
+
if (err) throw err[0];
|
|
10
|
+
try {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
throw err = [e], e;
|
|
14
|
+
}
|
|
10
15
|
};
|
|
11
16
|
var __commonJS = (cb, mod) => function __require() {
|
|
12
|
-
|
|
17
|
+
try {
|
|
18
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
19
|
+
} catch (e) {
|
|
20
|
+
throw mod = 0, e;
|
|
21
|
+
}
|
|
13
22
|
};
|
|
14
23
|
var __export = (target, all) => {
|
|
15
24
|
for (var name in all)
|
|
@@ -492,39 +501,96 @@ var require_ignore = __commonJS({
|
|
|
492
501
|
// src/ignore.ts
|
|
493
502
|
import * as fs from "fs";
|
|
494
503
|
import * as path from "path";
|
|
504
|
+
function isInvariantIgnoredPath(pathname) {
|
|
505
|
+
const normalized = pathname.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
506
|
+
const segments = normalized.split("/").filter(Boolean);
|
|
507
|
+
if (segments.some((segment) => INVARIANT_IGNORED_DIRECTORIES.has(segment.toLowerCase()))) {
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
const basename = (segments.at(-1) || "").toLowerCase();
|
|
511
|
+
if (INVARIANT_SECRET_FILENAMES.has(basename)) return true;
|
|
512
|
+
if (INVARIANT_SECRET_SUFFIXES.some((suffix) => basename.endsWith(suffix))) return true;
|
|
513
|
+
return (basename === ".env" || basename.startsWith(".env.")) && !ENV_TEMPLATE_ALLOWLIST.has(basename);
|
|
514
|
+
}
|
|
495
515
|
async function loadIgnorePatterns(projectRoot) {
|
|
496
516
|
const ig = (0, import_ignore.default)();
|
|
497
517
|
const patterns = [...DEFAULT_IGNORE_PATTERNS];
|
|
498
518
|
ig.add(DEFAULT_IGNORE_PATTERNS);
|
|
499
|
-
const ignoreFilePath = path.join(projectRoot, IGNORE_FILENAME);
|
|
500
519
|
let hasUserPatterns = false;
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
520
|
+
for (const filename of IGNORE_FILENAMES) {
|
|
521
|
+
try {
|
|
522
|
+
const content = await fs.promises.readFile(path.join(projectRoot, filename), "utf-8");
|
|
523
|
+
const userPatterns = content.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
524
|
+
if (userPatterns.length > 0) {
|
|
525
|
+
ig.add(userPatterns);
|
|
526
|
+
patterns.push(...userPatterns);
|
|
527
|
+
hasUserPatterns = true;
|
|
528
|
+
}
|
|
529
|
+
} catch {
|
|
508
530
|
}
|
|
509
|
-
} catch {
|
|
510
531
|
}
|
|
511
532
|
return {
|
|
512
|
-
ignores: (pathname) => ig.ignores(pathname),
|
|
533
|
+
ignores: (pathname) => isInvariantIgnoredPath(pathname) || ig.ignores(pathname),
|
|
513
534
|
patterns,
|
|
514
535
|
hasUserPatterns
|
|
515
536
|
};
|
|
516
537
|
}
|
|
517
|
-
var import_ignore,
|
|
538
|
+
var import_ignore, IGNORE_FILENAMES, INVARIANT_IGNORED_DIRECTORIES, INVARIANT_SECRET_FILENAMES, INVARIANT_SECRET_SUFFIXES, ENV_TEMPLATE_ALLOWLIST, DEFAULT_IGNORE_PATTERNS;
|
|
518
539
|
var init_ignore = __esm({
|
|
519
540
|
"src/ignore.ts"() {
|
|
520
541
|
"use strict";
|
|
521
542
|
import_ignore = __toESM(require_ignore(), 1);
|
|
522
|
-
|
|
543
|
+
IGNORE_FILENAMES = [".gitignore", ".contextignore", ".contextstream/ignore"];
|
|
544
|
+
INVARIANT_IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
|
|
545
|
+
".contextstream",
|
|
546
|
+
".claude",
|
|
547
|
+
".codex",
|
|
548
|
+
".cursor",
|
|
549
|
+
".windsurf",
|
|
550
|
+
".roo",
|
|
551
|
+
".kilocode",
|
|
552
|
+
".ssh",
|
|
553
|
+
".aws",
|
|
554
|
+
".gnupg",
|
|
555
|
+
".kube",
|
|
556
|
+
".docker"
|
|
557
|
+
]);
|
|
558
|
+
INVARIANT_SECRET_FILENAMES = /* @__PURE__ */ new Set([
|
|
559
|
+
".npmrc",
|
|
560
|
+
".pypirc",
|
|
561
|
+
".netrc",
|
|
562
|
+
".pgpass",
|
|
563
|
+
".git-credentials",
|
|
564
|
+
"id_rsa",
|
|
565
|
+
"id_ed25519",
|
|
566
|
+
"id_ecdsa",
|
|
567
|
+
"known_hosts",
|
|
568
|
+
"credentials.json",
|
|
569
|
+
"serviceaccountkey.json",
|
|
570
|
+
"auth.json"
|
|
571
|
+
]);
|
|
572
|
+
INVARIANT_SECRET_SUFFIXES = [".pem", ".key", ".p12", ".pfx", ".jks"];
|
|
573
|
+
ENV_TEMPLATE_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
574
|
+
".env.example",
|
|
575
|
+
".env.sample",
|
|
576
|
+
".env.template",
|
|
577
|
+
".env.dist",
|
|
578
|
+
".env.defaults"
|
|
579
|
+
]);
|
|
523
580
|
DEFAULT_IGNORE_PATTERNS = [
|
|
524
581
|
// Version control
|
|
525
582
|
".git/",
|
|
526
583
|
".svn/",
|
|
527
584
|
".hg/",
|
|
585
|
+
// ContextStream and AI editor/agent state. These directories can contain
|
|
586
|
+
// credentials, generated rules, caches, and nested worktrees.
|
|
587
|
+
".contextstream/",
|
|
588
|
+
".claude/",
|
|
589
|
+
".codex/",
|
|
590
|
+
".cursor/",
|
|
591
|
+
".windsurf/",
|
|
592
|
+
".roo/",
|
|
593
|
+
".kilocode/",
|
|
528
594
|
// Package managers / dependencies
|
|
529
595
|
"node_modules/",
|
|
530
596
|
"vendor/",
|
|
@@ -555,6 +621,12 @@ var init_ignore = __esm({
|
|
|
555
621
|
".idea/",
|
|
556
622
|
".vscode/",
|
|
557
623
|
".vs/",
|
|
624
|
+
// Credential stores
|
|
625
|
+
".ssh/",
|
|
626
|
+
".aws/",
|
|
627
|
+
".gnupg/",
|
|
628
|
+
".kube/",
|
|
629
|
+
".docker/",
|
|
558
630
|
// Coverage
|
|
559
631
|
"coverage/",
|
|
560
632
|
".coverage/",
|
|
@@ -568,6 +640,22 @@ var init_ignore = __esm({
|
|
|
568
640
|
"composer.lock",
|
|
569
641
|
"*.min.js",
|
|
570
642
|
"*.min.css",
|
|
643
|
+
"*.pem",
|
|
644
|
+
"*.key",
|
|
645
|
+
"*.p12",
|
|
646
|
+
"*.pfx",
|
|
647
|
+
"*.jks",
|
|
648
|
+
".npmrc",
|
|
649
|
+
".pypirc",
|
|
650
|
+
".netrc",
|
|
651
|
+
".pgpass",
|
|
652
|
+
".git-credentials",
|
|
653
|
+
"id_rsa",
|
|
654
|
+
"id_ed25519",
|
|
655
|
+
"id_ecdsa",
|
|
656
|
+
"credentials.json",
|
|
657
|
+
"serviceAccountKey.json",
|
|
658
|
+
"auth.json",
|
|
571
659
|
// OS files
|
|
572
660
|
".DS_Store",
|
|
573
661
|
"Thumbs.db"
|
|
@@ -595,6 +683,15 @@ import { exec } from "child_process";
|
|
|
595
683
|
import { promisify } from "util";
|
|
596
684
|
import * as os from "os";
|
|
597
685
|
import * as crypto from "crypto";
|
|
686
|
+
function shouldSkipSensitiveFile(name) {
|
|
687
|
+
const lower = name.toLowerCase();
|
|
688
|
+
if (SECRET_FILENAMES.has(lower)) return true;
|
|
689
|
+
if (SECRET_FILE_SUFFIXES.some((suffix) => lower.endsWith(suffix))) return true;
|
|
690
|
+
if ((lower === ".env" || lower.startsWith(".env.")) && !ENV_TEMPLATE_ALLOWLIST2.has(lower)) {
|
|
691
|
+
return true;
|
|
692
|
+
}
|
|
693
|
+
return false;
|
|
694
|
+
}
|
|
598
695
|
function getMachineId() {
|
|
599
696
|
const hostname2 = os.hostname();
|
|
600
697
|
const hash = crypto.createHash("sha256").update(hostname2).digest("hex");
|
|
@@ -701,6 +798,7 @@ function clearGitContextCache() {
|
|
|
701
798
|
gitContextCache.clear();
|
|
702
799
|
}
|
|
703
800
|
async function readFilesFromDirectory(rootPath, options = {}) {
|
|
801
|
+
if (isInvariantIgnoredPath(path2.resolve(rootPath))) return [];
|
|
704
802
|
const maxFiles = options.maxFiles ?? MAX_FILES_PER_BATCH;
|
|
705
803
|
const maxFileSize = options.maxFileSize ?? MAX_FILE_SIZE;
|
|
706
804
|
const files = [];
|
|
@@ -725,6 +823,7 @@ async function readFilesFromDirectory(rootPath, options = {}) {
|
|
|
725
823
|
await walkDir(fullPath, relPath);
|
|
726
824
|
} else if (entry.isFile()) {
|
|
727
825
|
if (IGNORE_FILES.has(entry.name)) continue;
|
|
826
|
+
if (shouldSkipSensitiveFile(entry.name)) continue;
|
|
728
827
|
if (ig.ignores(relPath)) continue;
|
|
729
828
|
const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
730
829
|
if (!CODE_EXTENSIONS.has(ext)) continue;
|
|
@@ -760,6 +859,7 @@ async function readFilesFromDirectory(rootPath, options = {}) {
|
|
|
760
859
|
return files;
|
|
761
860
|
}
|
|
762
861
|
async function* readAllFilesInBatches(rootPath, options = {}) {
|
|
862
|
+
if (isInvariantIgnoredPath(path2.resolve(rootPath))) return;
|
|
763
863
|
const maxBatchBytes = options.maxBatchBytes ?? MAX_BATCH_BYTES;
|
|
764
864
|
const largeFileThreshold = options.largeFileThreshold ?? LARGE_FILE_THRESHOLD;
|
|
765
865
|
const maxFilesPerBatch = options.maxFilesPerBatch ?? options.batchSize ?? MAX_FILES_PER_BATCH;
|
|
@@ -785,6 +885,7 @@ async function* readAllFilesInBatches(rootPath, options = {}) {
|
|
|
785
885
|
yield* walkDir(fullPath, relPath);
|
|
786
886
|
} else if (entry.isFile()) {
|
|
787
887
|
if (IGNORE_FILES.has(entry.name)) continue;
|
|
888
|
+
if (shouldSkipSensitiveFile(entry.name)) continue;
|
|
788
889
|
if (ig.ignores(relPath)) continue;
|
|
789
890
|
const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
790
891
|
if (!CODE_EXTENSIONS.has(ext)) continue;
|
|
@@ -845,6 +946,7 @@ async function* readAllFilesInBatches(rootPath, options = {}) {
|
|
|
845
946
|
}
|
|
846
947
|
}
|
|
847
948
|
async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}) {
|
|
949
|
+
if (isInvariantIgnoredPath(path2.resolve(rootPath))) return;
|
|
848
950
|
const maxBatchBytes = options.maxBatchBytes ?? MAX_BATCH_BYTES;
|
|
849
951
|
const largeFileThreshold = options.largeFileThreshold ?? LARGE_FILE_THRESHOLD;
|
|
850
952
|
const maxFilesPerBatch = options.maxFilesPerBatch ?? options.batchSize ?? MAX_FILES_PER_BATCH;
|
|
@@ -873,6 +975,7 @@ async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}
|
|
|
873
975
|
yield* walkDir(fullPath, relPath);
|
|
874
976
|
} else if (entry.isFile()) {
|
|
875
977
|
if (IGNORE_FILES.has(entry.name)) continue;
|
|
978
|
+
if (shouldSkipSensitiveFile(entry.name)) continue;
|
|
876
979
|
if (ig.ignores(relPath)) continue;
|
|
877
980
|
const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
878
981
|
if (!CODE_EXTENSIONS.has(ext)) continue;
|
|
@@ -939,6 +1042,7 @@ async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}
|
|
|
939
1042
|
);
|
|
940
1043
|
}
|
|
941
1044
|
async function countIndexableFiles(rootPath, options = {}) {
|
|
1045
|
+
if (isInvariantIgnoredPath(path2.resolve(rootPath))) return { count: 0, stopped: false };
|
|
942
1046
|
const maxFiles = options.maxFiles ?? 1;
|
|
943
1047
|
const maxFileSize = options.maxFileSize ?? MAX_FILE_SIZE;
|
|
944
1048
|
const ig = options.ignoreInstance ?? await loadIgnorePatterns(rootPath);
|
|
@@ -969,6 +1073,7 @@ async function countIndexableFiles(rootPath, options = {}) {
|
|
|
969
1073
|
await walkDir(fullPath, relPath);
|
|
970
1074
|
} else if (entry.isFile()) {
|
|
971
1075
|
if (IGNORE_FILES.has(entry.name)) continue;
|
|
1076
|
+
if (shouldSkipSensitiveFile(entry.name)) continue;
|
|
972
1077
|
if (ig.ignores(relPath)) continue;
|
|
973
1078
|
const ext = entry.name.split(".").pop()?.toLowerCase() ?? "";
|
|
974
1079
|
if (!CODE_EXTENSIONS.has(ext)) continue;
|
|
@@ -1053,7 +1158,7 @@ function deleteHashManifest(projectId) {
|
|
|
1053
1158
|
} catch {
|
|
1054
1159
|
}
|
|
1055
1160
|
}
|
|
1056
|
-
var execAsync, CODE_EXTENSIONS, IGNORE_DIRS, IGNORE_FILES, MAX_FILE_SIZE, MAX_BATCH_BYTES, LARGE_FILE_THRESHOLD, MAX_FILES_PER_BATCH, gitContextCache;
|
|
1161
|
+
var execAsync, CODE_EXTENSIONS, IGNORE_DIRS, IGNORE_FILES, SECRET_FILENAMES, SECRET_FILE_SUFFIXES, ENV_TEMPLATE_ALLOWLIST2, MAX_FILE_SIZE, MAX_BATCH_BYTES, LARGE_FILE_THRESHOLD, MAX_FILES_PER_BATCH, gitContextCache;
|
|
1057
1162
|
var init_files = __esm({
|
|
1058
1163
|
"src/files.ts"() {
|
|
1059
1164
|
"use strict";
|
|
@@ -1129,6 +1234,13 @@ var init_files = __esm({
|
|
|
1129
1234
|
IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
1130
1235
|
"node_modules",
|
|
1131
1236
|
".git",
|
|
1237
|
+
".contextstream",
|
|
1238
|
+
".claude",
|
|
1239
|
+
".codex",
|
|
1240
|
+
".cursor",
|
|
1241
|
+
".windsurf",
|
|
1242
|
+
".roo",
|
|
1243
|
+
".kilocode",
|
|
1132
1244
|
".svn",
|
|
1133
1245
|
".hg",
|
|
1134
1246
|
"target",
|
|
@@ -1156,7 +1268,18 @@ var init_files = __esm({
|
|
|
1156
1268
|
"obj",
|
|
1157
1269
|
".idea",
|
|
1158
1270
|
".vscode",
|
|
1159
|
-
".vs"
|
|
1271
|
+
".vs",
|
|
1272
|
+
".npm",
|
|
1273
|
+
".yarn",
|
|
1274
|
+
".nyc_output",
|
|
1275
|
+
// Credential directories are invariant exclusions. Their contents often
|
|
1276
|
+
// have ordinary-looking names (config, credentials, known_hosts), so a
|
|
1277
|
+
// filename-only filter is not sufficient.
|
|
1278
|
+
".ssh",
|
|
1279
|
+
".aws",
|
|
1280
|
+
".gnupg",
|
|
1281
|
+
".kube",
|
|
1282
|
+
".docker"
|
|
1160
1283
|
]);
|
|
1161
1284
|
IGNORE_FILES = /* @__PURE__ */ new Set([
|
|
1162
1285
|
".DS_Store",
|
|
@@ -1171,6 +1294,28 @@ var init_files = __esm({
|
|
|
1171
1294
|
"Gemfile.lock",
|
|
1172
1295
|
"composer.lock"
|
|
1173
1296
|
]);
|
|
1297
|
+
SECRET_FILENAMES = /* @__PURE__ */ new Set([
|
|
1298
|
+
".npmrc",
|
|
1299
|
+
".pypirc",
|
|
1300
|
+
".netrc",
|
|
1301
|
+
".pgpass",
|
|
1302
|
+
".git-credentials",
|
|
1303
|
+
"id_rsa",
|
|
1304
|
+
"id_ed25519",
|
|
1305
|
+
"id_ecdsa",
|
|
1306
|
+
"known_hosts",
|
|
1307
|
+
"credentials.json",
|
|
1308
|
+
"serviceaccountkey.json",
|
|
1309
|
+
"auth.json"
|
|
1310
|
+
]);
|
|
1311
|
+
SECRET_FILE_SUFFIXES = [".pem", ".key", ".p12", ".pfx", ".jks"];
|
|
1312
|
+
ENV_TEMPLATE_ALLOWLIST2 = /* @__PURE__ */ new Set([
|
|
1313
|
+
".env.example",
|
|
1314
|
+
".env.sample",
|
|
1315
|
+
".env.template",
|
|
1316
|
+
".env.dist",
|
|
1317
|
+
".env.defaults"
|
|
1318
|
+
]);
|
|
1174
1319
|
MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
1175
1320
|
MAX_BATCH_BYTES = 1024 * 1024;
|
|
1176
1321
|
LARGE_FILE_THRESHOLD = 2 * 1024 * 1024;
|