@contextstream/mcp-server 0.4.50 → 0.4.51
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 +136 -25
- package/dist/hooks/on-bash.js +190 -0
- package/dist/hooks/on-read.js +163 -0
- package/dist/hooks/on-save-intent.js +132 -0
- package/dist/hooks/on-task.js +139 -0
- package/dist/hooks/on-web.js +155 -0
- package/dist/hooks/post-compact.js +172 -0
- package/dist/hooks/runner.js +2889 -0
- package/dist/hooks/session-end.js +191 -0
- package/dist/hooks/session-init.js +174 -0
- package/dist/index.js +1994 -146
- package/dist/test-server.js +3 -0
- package/package.json +7 -4
- package/scripts/postinstall.js +56 -0
package/dist/index.js
CHANGED
|
@@ -335,7 +335,7 @@ var require_ignore = __commonJS({
|
|
|
335
335
|
// path matching.
|
|
336
336
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
337
337
|
// @returns {TestResult} true if a file is ignored
|
|
338
|
-
test(
|
|
338
|
+
test(path21, checkUnignored, mode) {
|
|
339
339
|
let ignored = false;
|
|
340
340
|
let unignored = false;
|
|
341
341
|
let matchedRule;
|
|
@@ -344,7 +344,7 @@ var require_ignore = __commonJS({
|
|
|
344
344
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
345
345
|
return;
|
|
346
346
|
}
|
|
347
|
-
const matched = rule[mode].test(
|
|
347
|
+
const matched = rule[mode].test(path21);
|
|
348
348
|
if (!matched) {
|
|
349
349
|
return;
|
|
350
350
|
}
|
|
@@ -365,17 +365,17 @@ var require_ignore = __commonJS({
|
|
|
365
365
|
var throwError = (message, Ctor) => {
|
|
366
366
|
throw new Ctor(message);
|
|
367
367
|
};
|
|
368
|
-
var checkPath = (
|
|
369
|
-
if (!isString(
|
|
368
|
+
var checkPath = (path21, originalPath, doThrow) => {
|
|
369
|
+
if (!isString(path21)) {
|
|
370
370
|
return doThrow(
|
|
371
371
|
`path must be a string, but got \`${originalPath}\``,
|
|
372
372
|
TypeError
|
|
373
373
|
);
|
|
374
374
|
}
|
|
375
|
-
if (!
|
|
375
|
+
if (!path21) {
|
|
376
376
|
return doThrow(`path must not be empty`, TypeError);
|
|
377
377
|
}
|
|
378
|
-
if (checkPath.isNotRelative(
|
|
378
|
+
if (checkPath.isNotRelative(path21)) {
|
|
379
379
|
const r = "`path.relative()`d";
|
|
380
380
|
return doThrow(
|
|
381
381
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -384,7 +384,7 @@ var require_ignore = __commonJS({
|
|
|
384
384
|
}
|
|
385
385
|
return true;
|
|
386
386
|
};
|
|
387
|
-
var isNotRelative = (
|
|
387
|
+
var isNotRelative = (path21) => REGEX_TEST_INVALID_PATH.test(path21);
|
|
388
388
|
checkPath.isNotRelative = isNotRelative;
|
|
389
389
|
checkPath.convert = (p) => p;
|
|
390
390
|
var Ignore2 = class {
|
|
@@ -414,19 +414,19 @@ var require_ignore = __commonJS({
|
|
|
414
414
|
}
|
|
415
415
|
// @returns {TestResult}
|
|
416
416
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
417
|
-
const
|
|
417
|
+
const path21 = originalPath && checkPath.convert(originalPath);
|
|
418
418
|
checkPath(
|
|
419
|
-
|
|
419
|
+
path21,
|
|
420
420
|
originalPath,
|
|
421
421
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
422
422
|
);
|
|
423
|
-
return this._t(
|
|
423
|
+
return this._t(path21, cache, checkUnignored, slices);
|
|
424
424
|
}
|
|
425
|
-
checkIgnore(
|
|
426
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
427
|
-
return this.test(
|
|
425
|
+
checkIgnore(path21) {
|
|
426
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path21)) {
|
|
427
|
+
return this.test(path21);
|
|
428
428
|
}
|
|
429
|
-
const slices =
|
|
429
|
+
const slices = path21.split(SLASH).filter(Boolean);
|
|
430
430
|
slices.pop();
|
|
431
431
|
if (slices.length) {
|
|
432
432
|
const parent = this._t(
|
|
@@ -439,18 +439,18 @@ var require_ignore = __commonJS({
|
|
|
439
439
|
return parent;
|
|
440
440
|
}
|
|
441
441
|
}
|
|
442
|
-
return this._rules.test(
|
|
442
|
+
return this._rules.test(path21, false, MODE_CHECK_IGNORE);
|
|
443
443
|
}
|
|
444
|
-
_t(
|
|
445
|
-
if (
|
|
446
|
-
return cache[
|
|
444
|
+
_t(path21, cache, checkUnignored, slices) {
|
|
445
|
+
if (path21 in cache) {
|
|
446
|
+
return cache[path21];
|
|
447
447
|
}
|
|
448
448
|
if (!slices) {
|
|
449
|
-
slices =
|
|
449
|
+
slices = path21.split(SLASH).filter(Boolean);
|
|
450
450
|
}
|
|
451
451
|
slices.pop();
|
|
452
452
|
if (!slices.length) {
|
|
453
|
-
return cache[
|
|
453
|
+
return cache[path21] = this._rules.test(path21, checkUnignored, MODE_IGNORE);
|
|
454
454
|
}
|
|
455
455
|
const parent = this._t(
|
|
456
456
|
slices.join(SLASH) + SLASH,
|
|
@@ -458,29 +458,29 @@ var require_ignore = __commonJS({
|
|
|
458
458
|
checkUnignored,
|
|
459
459
|
slices
|
|
460
460
|
);
|
|
461
|
-
return cache[
|
|
461
|
+
return cache[path21] = parent.ignored ? parent : this._rules.test(path21, checkUnignored, MODE_IGNORE);
|
|
462
462
|
}
|
|
463
|
-
ignores(
|
|
464
|
-
return this._test(
|
|
463
|
+
ignores(path21) {
|
|
464
|
+
return this._test(path21, this._ignoreCache, false).ignored;
|
|
465
465
|
}
|
|
466
466
|
createFilter() {
|
|
467
|
-
return (
|
|
467
|
+
return (path21) => !this.ignores(path21);
|
|
468
468
|
}
|
|
469
469
|
filter(paths) {
|
|
470
470
|
return makeArray(paths).filter(this.createFilter());
|
|
471
471
|
}
|
|
472
472
|
// @returns {TestResult}
|
|
473
|
-
test(
|
|
474
|
-
return this._test(
|
|
473
|
+
test(path21) {
|
|
474
|
+
return this._test(path21, this._testCache, true);
|
|
475
475
|
}
|
|
476
476
|
};
|
|
477
477
|
var factory = (options) => new Ignore2(options);
|
|
478
|
-
var isPathValid = (
|
|
478
|
+
var isPathValid = (path21) => checkPath(path21 && checkPath.convert(path21), path21, RETURN_FALSE);
|
|
479
479
|
var setupWindows = () => {
|
|
480
480
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
481
481
|
checkPath.convert = makePosix;
|
|
482
482
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
483
|
-
checkPath.isNotRelative = (
|
|
483
|
+
checkPath.isNotRelative = (path21) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path21) || isNotRelative(path21);
|
|
484
484
|
};
|
|
485
485
|
if (
|
|
486
486
|
// Detect `process` so that it can run in browsers.
|
|
@@ -514,6 +514,7 @@ __export(hooks_config_exports, {
|
|
|
514
514
|
getClineHooksDir: () => getClineHooksDir,
|
|
515
515
|
getCursorHooksConfigPath: () => getCursorHooksConfigPath,
|
|
516
516
|
getCursorHooksDir: () => getCursorHooksDir,
|
|
517
|
+
getHookCommand: () => getHookCommand,
|
|
517
518
|
getHooksDir: () => getHooksDir,
|
|
518
519
|
getIndexStatusPath: () => getIndexStatusPath,
|
|
519
520
|
getKiloCodeHooksDir: () => getKiloCodeHooksDir,
|
|
@@ -539,6 +540,19 @@ __export(hooks_config_exports, {
|
|
|
539
540
|
import * as fs4 from "node:fs/promises";
|
|
540
541
|
import * as path5 from "node:path";
|
|
541
542
|
import { homedir as homedir2 } from "node:os";
|
|
543
|
+
import { fileURLToPath } from "node:url";
|
|
544
|
+
function getHookCommand(hookName) {
|
|
545
|
+
try {
|
|
546
|
+
const __dirname = path5.dirname(fileURLToPath(import.meta.url));
|
|
547
|
+
const indexPath = path5.join(__dirname, "index.js");
|
|
548
|
+
const fs20 = __require("node:fs");
|
|
549
|
+
if (fs20.existsSync(indexPath)) {
|
|
550
|
+
return `node ${indexPath} hook ${hookName}`;
|
|
551
|
+
}
|
|
552
|
+
} catch {
|
|
553
|
+
}
|
|
554
|
+
return `npx @contextstream/mcp-server hook ${hookName}`;
|
|
555
|
+
}
|
|
542
556
|
function getClaudeSettingsPath(scope, projectPath) {
|
|
543
557
|
if (scope === "user") {
|
|
544
558
|
return path5.join(homedir2(), ".claude", "settings.json");
|
|
@@ -558,19 +572,31 @@ function buildHooksConfig(options) {
|
|
|
558
572
|
hooks: [
|
|
559
573
|
{
|
|
560
574
|
type: "command",
|
|
561
|
-
command: "
|
|
575
|
+
command: getHookCommand("user-prompt-submit"),
|
|
562
576
|
timeout: 5
|
|
563
577
|
}
|
|
564
578
|
]
|
|
565
579
|
}
|
|
566
580
|
];
|
|
581
|
+
if (options?.includeOnSaveIntent !== false) {
|
|
582
|
+
userPromptHooks.push({
|
|
583
|
+
matcher: "*",
|
|
584
|
+
hooks: [
|
|
585
|
+
{
|
|
586
|
+
type: "command",
|
|
587
|
+
command: getHookCommand("on-save-intent"),
|
|
588
|
+
timeout: 5
|
|
589
|
+
}
|
|
590
|
+
]
|
|
591
|
+
});
|
|
592
|
+
}
|
|
567
593
|
if (options?.includeMediaAware !== false) {
|
|
568
594
|
userPromptHooks.push({
|
|
569
595
|
matcher: "*",
|
|
570
596
|
hooks: [
|
|
571
597
|
{
|
|
572
598
|
type: "command",
|
|
573
|
-
command: "
|
|
599
|
+
command: getHookCommand("media-aware"),
|
|
574
600
|
timeout: 5
|
|
575
601
|
}
|
|
576
602
|
]
|
|
@@ -583,7 +609,7 @@ function buildHooksConfig(options) {
|
|
|
583
609
|
hooks: [
|
|
584
610
|
{
|
|
585
611
|
type: "command",
|
|
586
|
-
command: "
|
|
612
|
+
command: getHookCommand("pre-tool-use"),
|
|
587
613
|
timeout: 5
|
|
588
614
|
}
|
|
589
615
|
]
|
|
@@ -594,12 +620,39 @@ function buildHooksConfig(options) {
|
|
|
594
620
|
if (options?.includePreCompact !== false) {
|
|
595
621
|
config.PreCompact = [
|
|
596
622
|
{
|
|
597
|
-
// Match both manual (/compact) and automatic compaction
|
|
598
623
|
matcher: "*",
|
|
599
624
|
hooks: [
|
|
600
625
|
{
|
|
601
626
|
type: "command",
|
|
602
|
-
command: "
|
|
627
|
+
command: getHookCommand("pre-compact"),
|
|
628
|
+
timeout: 10
|
|
629
|
+
}
|
|
630
|
+
]
|
|
631
|
+
}
|
|
632
|
+
];
|
|
633
|
+
}
|
|
634
|
+
if (options?.includeSessionInit !== false) {
|
|
635
|
+
config.SessionStart = [
|
|
636
|
+
{
|
|
637
|
+
matcher: "*",
|
|
638
|
+
hooks: [
|
|
639
|
+
{
|
|
640
|
+
type: "command",
|
|
641
|
+
command: getHookCommand("session-init"),
|
|
642
|
+
timeout: 10
|
|
643
|
+
}
|
|
644
|
+
]
|
|
645
|
+
}
|
|
646
|
+
];
|
|
647
|
+
}
|
|
648
|
+
if (options?.includeSessionEnd !== false) {
|
|
649
|
+
config.Stop = [
|
|
650
|
+
{
|
|
651
|
+
matcher: "*",
|
|
652
|
+
hooks: [
|
|
653
|
+
{
|
|
654
|
+
type: "command",
|
|
655
|
+
command: getHookCommand("session-end"),
|
|
603
656
|
timeout: 10
|
|
604
657
|
}
|
|
605
658
|
]
|
|
@@ -613,7 +666,7 @@ function buildHooksConfig(options) {
|
|
|
613
666
|
hooks: [
|
|
614
667
|
{
|
|
615
668
|
type: "command",
|
|
616
|
-
command: "
|
|
669
|
+
command: getHookCommand("post-write"),
|
|
617
670
|
timeout: 10
|
|
618
671
|
}
|
|
619
672
|
]
|
|
@@ -625,12 +678,60 @@ function buildHooksConfig(options) {
|
|
|
625
678
|
hooks: [
|
|
626
679
|
{
|
|
627
680
|
type: "command",
|
|
628
|
-
command: "
|
|
681
|
+
command: getHookCommand("auto-rules"),
|
|
629
682
|
timeout: 15
|
|
630
683
|
}
|
|
631
684
|
]
|
|
632
685
|
});
|
|
633
686
|
}
|
|
687
|
+
if (options?.includeOnBash !== false) {
|
|
688
|
+
postToolUseHooks.push({
|
|
689
|
+
matcher: "Bash",
|
|
690
|
+
hooks: [
|
|
691
|
+
{
|
|
692
|
+
type: "command",
|
|
693
|
+
command: getHookCommand("on-bash"),
|
|
694
|
+
timeout: 5
|
|
695
|
+
}
|
|
696
|
+
]
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
if (options?.includeOnTask !== false) {
|
|
700
|
+
postToolUseHooks.push({
|
|
701
|
+
matcher: "Task",
|
|
702
|
+
hooks: [
|
|
703
|
+
{
|
|
704
|
+
type: "command",
|
|
705
|
+
command: getHookCommand("on-task"),
|
|
706
|
+
timeout: 5
|
|
707
|
+
}
|
|
708
|
+
]
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
if (options?.includeOnRead !== false) {
|
|
712
|
+
postToolUseHooks.push({
|
|
713
|
+
matcher: "Read|Glob|Grep",
|
|
714
|
+
hooks: [
|
|
715
|
+
{
|
|
716
|
+
type: "command",
|
|
717
|
+
command: getHookCommand("on-read"),
|
|
718
|
+
timeout: 5
|
|
719
|
+
}
|
|
720
|
+
]
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
if (options?.includeOnWeb !== false) {
|
|
724
|
+
postToolUseHooks.push({
|
|
725
|
+
matcher: "WebFetch|WebSearch",
|
|
726
|
+
hooks: [
|
|
727
|
+
{
|
|
728
|
+
type: "command",
|
|
729
|
+
command: getHookCommand("on-web"),
|
|
730
|
+
timeout: 5
|
|
731
|
+
}
|
|
732
|
+
]
|
|
733
|
+
});
|
|
734
|
+
}
|
|
634
735
|
if (postToolUseHooks.length > 0) {
|
|
635
736
|
config.PostToolUse = postToolUseHooks;
|
|
636
737
|
}
|
|
@@ -640,17 +741,17 @@ async function installHookScripts(options) {
|
|
|
640
741
|
const hooksDir = getHooksDir();
|
|
641
742
|
await fs4.mkdir(hooksDir, { recursive: true });
|
|
642
743
|
const result = {
|
|
643
|
-
preToolUse: "
|
|
644
|
-
userPrompt: "
|
|
744
|
+
preToolUse: getHookCommand("pre-tool-use"),
|
|
745
|
+
userPrompt: getHookCommand("user-prompt-submit")
|
|
645
746
|
};
|
|
646
747
|
if (options?.includePreCompact !== false) {
|
|
647
|
-
result.preCompact = "
|
|
748
|
+
result.preCompact = getHookCommand("pre-compact");
|
|
648
749
|
}
|
|
649
750
|
if (options?.includeMediaAware !== false) {
|
|
650
|
-
result.mediaAware = "
|
|
751
|
+
result.mediaAware = getHookCommand("media-aware");
|
|
651
752
|
}
|
|
652
753
|
if (options?.includeAutoRules !== false) {
|
|
653
|
-
result.autoRules = "
|
|
754
|
+
result.autoRules = getHookCommand("auto-rules");
|
|
654
755
|
}
|
|
655
756
|
return result;
|
|
656
757
|
}
|
|
@@ -686,20 +787,20 @@ function mergeHooksIntoSettings(existingSettings, newHooks) {
|
|
|
686
787
|
async function installClaudeCodeHooks(options) {
|
|
687
788
|
const result = { scripts: [], settings: [] };
|
|
688
789
|
result.scripts.push(
|
|
689
|
-
"
|
|
690
|
-
"
|
|
790
|
+
getHookCommand("pre-tool-use"),
|
|
791
|
+
getHookCommand("user-prompt-submit")
|
|
691
792
|
);
|
|
692
793
|
if (options.includePreCompact !== false) {
|
|
693
|
-
result.scripts.push("
|
|
794
|
+
result.scripts.push(getHookCommand("pre-compact"));
|
|
694
795
|
}
|
|
695
796
|
if (options.includeMediaAware !== false) {
|
|
696
|
-
result.scripts.push("
|
|
797
|
+
result.scripts.push(getHookCommand("media-aware"));
|
|
697
798
|
}
|
|
698
799
|
if (options.includePostWrite !== false) {
|
|
699
|
-
result.scripts.push("
|
|
800
|
+
result.scripts.push(getHookCommand("post-write"));
|
|
700
801
|
}
|
|
701
802
|
if (options.includeAutoRules !== false) {
|
|
702
|
-
result.scripts.push("
|
|
803
|
+
result.scripts.push(getHookCommand("auto-rules"));
|
|
703
804
|
}
|
|
704
805
|
const hooksConfig = buildHooksConfig({
|
|
705
806
|
includePreCompact: options.includePreCompact,
|
|
@@ -977,6 +1078,8 @@ async function installCursorHookScripts(options) {
|
|
|
977
1078
|
};
|
|
978
1079
|
const filteredPreToolUse = filterContextStreamHooks(existingConfig.hooks.preToolUse);
|
|
979
1080
|
const filteredBeforeSubmit = filterContextStreamHooks(existingConfig.hooks.beforeSubmitPrompt);
|
|
1081
|
+
const preToolUseCommand = getHookCommand("pre-tool-use");
|
|
1082
|
+
const userPromptCommand = getHookCommand("user-prompt-submit");
|
|
980
1083
|
const config = {
|
|
981
1084
|
version: 1,
|
|
982
1085
|
hooks: {
|
|
@@ -984,7 +1087,7 @@ async function installCursorHookScripts(options) {
|
|
|
984
1087
|
preToolUse: [
|
|
985
1088
|
...filteredPreToolUse,
|
|
986
1089
|
{
|
|
987
|
-
command:
|
|
1090
|
+
command: preToolUseCommand,
|
|
988
1091
|
type: "command",
|
|
989
1092
|
timeout: 5,
|
|
990
1093
|
matcher: { tool_name: "Glob|Grep|search_files|list_files|ripgrep" }
|
|
@@ -993,7 +1096,7 @@ async function installCursorHookScripts(options) {
|
|
|
993
1096
|
beforeSubmitPrompt: [
|
|
994
1097
|
...filteredBeforeSubmit,
|
|
995
1098
|
{
|
|
996
|
-
command:
|
|
1099
|
+
command: userPromptCommand,
|
|
997
1100
|
type: "command",
|
|
998
1101
|
timeout: 5
|
|
999
1102
|
}
|
|
@@ -1003,8 +1106,8 @@ async function installCursorHookScripts(options) {
|
|
|
1003
1106
|
await writeCursorHooksConfig(config, options.scope, options.projectPath);
|
|
1004
1107
|
const configPath = getCursorHooksConfigPath(options.scope, options.projectPath);
|
|
1005
1108
|
return {
|
|
1006
|
-
preToolUse:
|
|
1007
|
-
beforeSubmitPrompt:
|
|
1109
|
+
preToolUse: preToolUseCommand,
|
|
1110
|
+
beforeSubmitPrompt: userPromptCommand,
|
|
1008
1111
|
config: configPath
|
|
1009
1112
|
};
|
|
1010
1113
|
}
|
|
@@ -1813,11 +1916,13 @@ esac
|
|
|
1813
1916
|
|
|
1814
1917
|
exit 0
|
|
1815
1918
|
`;
|
|
1816
|
-
CLINE_HOOK_WRAPPER = (hookName) =>
|
|
1919
|
+
CLINE_HOOK_WRAPPER = (hookName) => {
|
|
1920
|
+
const command = getHookCommand(hookName);
|
|
1921
|
+
return `#!/bin/bash
|
|
1817
1922
|
# ContextStream ${hookName} Hook Wrapper for Cline/Roo/Kilo Code
|
|
1818
|
-
|
|
1819
|
-
exec npx @contextstream/mcp-server hook ${hookName}
|
|
1923
|
+
exec ${command}
|
|
1820
1924
|
`;
|
|
1925
|
+
};
|
|
1821
1926
|
CURSOR_PRETOOLUSE_HOOK_SCRIPT = `#!/usr/bin/env python3
|
|
1822
1927
|
"""
|
|
1823
1928
|
ContextStream PreToolUse Hook for Cursor
|
|
@@ -3154,35 +3259,1274 @@ function hasPythonHooks(settingsPath) {
|
|
|
3154
3259
|
}
|
|
3155
3260
|
}
|
|
3156
3261
|
}
|
|
3157
|
-
return false;
|
|
3262
|
+
return false;
|
|
3263
|
+
} catch {
|
|
3264
|
+
return false;
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
function detectPythonHooks(cwd) {
|
|
3268
|
+
const globalSettingsPath = path12.join(homedir9(), ".claude", "settings.json");
|
|
3269
|
+
const projectSettingsPath = path12.join(cwd, ".claude", "settings.json");
|
|
3270
|
+
return {
|
|
3271
|
+
global: hasPythonHooks(globalSettingsPath),
|
|
3272
|
+
project: hasPythonHooks(projectSettingsPath)
|
|
3273
|
+
};
|
|
3274
|
+
}
|
|
3275
|
+
async function upgradeHooksForFolder(folderPath) {
|
|
3276
|
+
const { installClaudeCodeHooks: installClaudeCodeHooks3 } = await Promise.resolve().then(() => (init_hooks_config(), hooks_config_exports));
|
|
3277
|
+
await installClaudeCodeHooks3({
|
|
3278
|
+
scope: "both",
|
|
3279
|
+
projectPath: folderPath,
|
|
3280
|
+
includePreCompact: true,
|
|
3281
|
+
includeMediaAware: true,
|
|
3282
|
+
includePostWrite: true,
|
|
3283
|
+
includeAutoRules: true
|
|
3284
|
+
});
|
|
3285
|
+
}
|
|
3286
|
+
async function runAutoRulesHook() {
|
|
3287
|
+
if (!ENABLED6) {
|
|
3288
|
+
process.exit(0);
|
|
3289
|
+
}
|
|
3290
|
+
if (hasRunRecently()) {
|
|
3291
|
+
process.exit(0);
|
|
3292
|
+
}
|
|
3293
|
+
let inputData = "";
|
|
3294
|
+
for await (const chunk of process.stdin) {
|
|
3295
|
+
inputData += chunk;
|
|
3296
|
+
}
|
|
3297
|
+
if (!inputData.trim()) {
|
|
3298
|
+
process.exit(0);
|
|
3299
|
+
}
|
|
3300
|
+
let input;
|
|
3301
|
+
try {
|
|
3302
|
+
input = JSON.parse(inputData);
|
|
3303
|
+
} catch {
|
|
3304
|
+
process.exit(0);
|
|
3305
|
+
}
|
|
3306
|
+
const toolName = input.tool_name || input.toolName || "";
|
|
3307
|
+
const isContextTool = toolName.includes("init") || toolName.includes("context") || toolName.includes("session_init") || toolName.includes("context_smart");
|
|
3308
|
+
if (!isContextTool) {
|
|
3309
|
+
process.exit(0);
|
|
3310
|
+
}
|
|
3311
|
+
const cwd = extractCwd3(input);
|
|
3312
|
+
const pythonHooks = detectPythonHooks(cwd);
|
|
3313
|
+
const hasPythonHooksToUpgrade = pythonHooks.global || pythonHooks.project;
|
|
3314
|
+
const rulesNotice = extractRulesNotice(input);
|
|
3315
|
+
const rulesNeedUpdate = rulesNotice && rulesNotice.status !== "current";
|
|
3316
|
+
if (!hasPythonHooksToUpgrade && !rulesNeedUpdate) {
|
|
3317
|
+
process.exit(0);
|
|
3318
|
+
}
|
|
3319
|
+
const folderPath = rulesNotice?.update_args?.folder_path || cwd;
|
|
3320
|
+
try {
|
|
3321
|
+
await upgradeHooksForFolder(folderPath);
|
|
3322
|
+
markAsRan();
|
|
3323
|
+
} catch {
|
|
3324
|
+
}
|
|
3325
|
+
process.exit(0);
|
|
3326
|
+
}
|
|
3327
|
+
var API_URL3, API_KEY3, ENABLED6, MARKER_FILE, COOLDOWN_MS, isDirectRun6;
|
|
3328
|
+
var init_auto_rules = __esm({
|
|
3329
|
+
"src/hooks/auto-rules.ts"() {
|
|
3330
|
+
"use strict";
|
|
3331
|
+
API_URL3 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
3332
|
+
API_KEY3 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
3333
|
+
ENABLED6 = process.env.CONTEXTSTREAM_AUTO_RULES !== "false";
|
|
3334
|
+
MARKER_FILE = path12.join(homedir9(), ".contextstream", ".auto-rules-ran");
|
|
3335
|
+
COOLDOWN_MS = 4 * 60 * 60 * 1e3;
|
|
3336
|
+
isDirectRun6 = process.argv[1]?.includes("auto-rules") || process.argv[2] === "auto-rules";
|
|
3337
|
+
if (isDirectRun6) {
|
|
3338
|
+
runAutoRulesHook().catch(() => process.exit(0));
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
});
|
|
3342
|
+
|
|
3343
|
+
// src/hooks/post-compact.ts
|
|
3344
|
+
var post_compact_exports = {};
|
|
3345
|
+
__export(post_compact_exports, {
|
|
3346
|
+
runPostCompactHook: () => runPostCompactHook
|
|
3347
|
+
});
|
|
3348
|
+
import * as fs12 from "node:fs";
|
|
3349
|
+
import * as path13 from "node:path";
|
|
3350
|
+
import { homedir as homedir10 } from "node:os";
|
|
3351
|
+
function loadConfigFromMcpJson2(cwd) {
|
|
3352
|
+
let searchDir = path13.resolve(cwd);
|
|
3353
|
+
for (let i = 0; i < 5; i++) {
|
|
3354
|
+
if (!API_KEY4) {
|
|
3355
|
+
const mcpPath = path13.join(searchDir, ".mcp.json");
|
|
3356
|
+
if (fs12.existsSync(mcpPath)) {
|
|
3357
|
+
try {
|
|
3358
|
+
const content = fs12.readFileSync(mcpPath, "utf-8");
|
|
3359
|
+
const config = JSON.parse(content);
|
|
3360
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3361
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3362
|
+
API_KEY4 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3363
|
+
}
|
|
3364
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3365
|
+
API_URL4 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3366
|
+
}
|
|
3367
|
+
} catch {
|
|
3368
|
+
}
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
if (!WORKSPACE_ID2) {
|
|
3372
|
+
const csConfigPath = path13.join(searchDir, ".contextstream", "config.json");
|
|
3373
|
+
if (fs12.existsSync(csConfigPath)) {
|
|
3374
|
+
try {
|
|
3375
|
+
const content = fs12.readFileSync(csConfigPath, "utf-8");
|
|
3376
|
+
const csConfig = JSON.parse(content);
|
|
3377
|
+
if (csConfig.workspace_id) {
|
|
3378
|
+
WORKSPACE_ID2 = csConfig.workspace_id;
|
|
3379
|
+
}
|
|
3380
|
+
} catch {
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
const parentDir = path13.dirname(searchDir);
|
|
3385
|
+
if (parentDir === searchDir) break;
|
|
3386
|
+
searchDir = parentDir;
|
|
3387
|
+
}
|
|
3388
|
+
if (!API_KEY4) {
|
|
3389
|
+
const homeMcpPath = path13.join(homedir10(), ".mcp.json");
|
|
3390
|
+
if (fs12.existsSync(homeMcpPath)) {
|
|
3391
|
+
try {
|
|
3392
|
+
const content = fs12.readFileSync(homeMcpPath, "utf-8");
|
|
3393
|
+
const config = JSON.parse(content);
|
|
3394
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3395
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3396
|
+
API_KEY4 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3397
|
+
}
|
|
3398
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3399
|
+
API_URL4 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3400
|
+
}
|
|
3401
|
+
} catch {
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
async function fetchLastTranscript(sessionId) {
|
|
3407
|
+
if (!API_KEY4) {
|
|
3408
|
+
return null;
|
|
3409
|
+
}
|
|
3410
|
+
try {
|
|
3411
|
+
const controller = new AbortController();
|
|
3412
|
+
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
3413
|
+
const url = new URL(`${API_URL4}/api/v1/transcripts`);
|
|
3414
|
+
url.searchParams.set("session_id", sessionId);
|
|
3415
|
+
url.searchParams.set("limit", "1");
|
|
3416
|
+
url.searchParams.set("sort", "created_at:desc");
|
|
3417
|
+
if (WORKSPACE_ID2) {
|
|
3418
|
+
url.searchParams.set("workspace_id", WORKSPACE_ID2);
|
|
3419
|
+
}
|
|
3420
|
+
const response = await fetch(url.toString(), {
|
|
3421
|
+
method: "GET",
|
|
3422
|
+
headers: {
|
|
3423
|
+
"X-API-Key": API_KEY4
|
|
3424
|
+
},
|
|
3425
|
+
signal: controller.signal
|
|
3426
|
+
});
|
|
3427
|
+
clearTimeout(timeoutId);
|
|
3428
|
+
if (response.ok) {
|
|
3429
|
+
const data = await response.json();
|
|
3430
|
+
if (data.transcripts && data.transcripts.length > 0) {
|
|
3431
|
+
return data.transcripts[0];
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
return null;
|
|
3435
|
+
} catch {
|
|
3436
|
+
return null;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
function formatTranscriptSummary(transcript) {
|
|
3440
|
+
const messages = transcript.messages || [];
|
|
3441
|
+
const activeFiles = transcript.metadata?.active_files || [];
|
|
3442
|
+
const toolCallCount = transcript.metadata?.tool_call_count || 0;
|
|
3443
|
+
const userMessages = messages.filter((m) => m.role === "user").slice(-3).map((m) => `- "${m.content.slice(0, 100)}${m.content.length > 100 ? "..." : ""}"`).join("\n");
|
|
3444
|
+
const lastAssistant = messages.filter((m) => m.role === "assistant" && !m.content.startsWith("[Tool:")).slice(-1)[0];
|
|
3445
|
+
const lastWork = lastAssistant ? lastAssistant.content.slice(0, 300) + (lastAssistant.content.length > 300 ? "..." : "") : "None recorded";
|
|
3446
|
+
return `## Pre-Compaction State Restored
|
|
3447
|
+
|
|
3448
|
+
### Active Files (${activeFiles.length})
|
|
3449
|
+
${activeFiles.slice(0, 10).map((f) => `- ${f}`).join("\n") || "None tracked"}
|
|
3450
|
+
|
|
3451
|
+
### Recent User Requests
|
|
3452
|
+
${userMessages || "None recorded"}
|
|
3453
|
+
|
|
3454
|
+
### Last Work in Progress
|
|
3455
|
+
${lastWork}
|
|
3456
|
+
|
|
3457
|
+
### Session Stats
|
|
3458
|
+
- Tool calls: ${toolCallCount}
|
|
3459
|
+
- Messages: ${messages.length}
|
|
3460
|
+
- Saved at: ${transcript.created_at}`;
|
|
3461
|
+
}
|
|
3462
|
+
async function runPostCompactHook() {
|
|
3463
|
+
if (!ENABLED7) {
|
|
3464
|
+
process.exit(0);
|
|
3465
|
+
}
|
|
3466
|
+
let inputData = "";
|
|
3467
|
+
for await (const chunk of process.stdin) {
|
|
3468
|
+
inputData += chunk;
|
|
3469
|
+
}
|
|
3470
|
+
if (!inputData.trim()) {
|
|
3471
|
+
process.exit(0);
|
|
3472
|
+
}
|
|
3473
|
+
let input;
|
|
3474
|
+
try {
|
|
3475
|
+
input = JSON.parse(inputData);
|
|
3476
|
+
} catch {
|
|
3477
|
+
process.exit(0);
|
|
3478
|
+
}
|
|
3479
|
+
const cwd = input.cwd || process.cwd();
|
|
3480
|
+
loadConfigFromMcpJson2(cwd);
|
|
3481
|
+
const sessionId = input.session_id || "";
|
|
3482
|
+
let restoredContext = "";
|
|
3483
|
+
if (sessionId && API_KEY4) {
|
|
3484
|
+
const transcript = await fetchLastTranscript(sessionId);
|
|
3485
|
+
if (transcript) {
|
|
3486
|
+
restoredContext = formatTranscriptSummary(transcript);
|
|
3487
|
+
}
|
|
3488
|
+
}
|
|
3489
|
+
const context = `[POST-COMPACTION - Context Restored]
|
|
3490
|
+
|
|
3491
|
+
${restoredContext || "No saved state found. Starting fresh."}
|
|
3492
|
+
|
|
3493
|
+
**IMPORTANT:** Call \`mcp__contextstream__context(user_message="resuming after compaction")\` to get full context and any pending tasks.
|
|
3494
|
+
|
|
3495
|
+
The conversation was compacted to save memory. The above summary was automatically restored from ContextStream.`;
|
|
3496
|
+
console.log(
|
|
3497
|
+
JSON.stringify({
|
|
3498
|
+
hookSpecificOutput: {
|
|
3499
|
+
hookEventName: "PostCompact",
|
|
3500
|
+
additionalContext: context
|
|
3501
|
+
}
|
|
3502
|
+
})
|
|
3503
|
+
);
|
|
3504
|
+
process.exit(0);
|
|
3505
|
+
}
|
|
3506
|
+
var ENABLED7, API_URL4, API_KEY4, WORKSPACE_ID2, isDirectRun7;
|
|
3507
|
+
var init_post_compact = __esm({
|
|
3508
|
+
"src/hooks/post-compact.ts"() {
|
|
3509
|
+
"use strict";
|
|
3510
|
+
ENABLED7 = process.env.CONTEXTSTREAM_POSTCOMPACT_ENABLED !== "false";
|
|
3511
|
+
API_URL4 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
3512
|
+
API_KEY4 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
3513
|
+
WORKSPACE_ID2 = null;
|
|
3514
|
+
isDirectRun7 = process.argv[1]?.includes("post-compact") || process.argv[2] === "post-compact";
|
|
3515
|
+
if (isDirectRun7) {
|
|
3516
|
+
runPostCompactHook().catch(() => process.exit(0));
|
|
3517
|
+
}
|
|
3518
|
+
}
|
|
3519
|
+
});
|
|
3520
|
+
|
|
3521
|
+
// src/hooks/on-bash.ts
|
|
3522
|
+
var on_bash_exports = {};
|
|
3523
|
+
__export(on_bash_exports, {
|
|
3524
|
+
runOnBashHook: () => runOnBashHook
|
|
3525
|
+
});
|
|
3526
|
+
import * as fs13 from "node:fs";
|
|
3527
|
+
import * as path14 from "node:path";
|
|
3528
|
+
import { homedir as homedir11 } from "node:os";
|
|
3529
|
+
function loadConfigFromMcpJson3(cwd) {
|
|
3530
|
+
let searchDir = path14.resolve(cwd);
|
|
3531
|
+
for (let i = 0; i < 5; i++) {
|
|
3532
|
+
if (!API_KEY5) {
|
|
3533
|
+
const mcpPath = path14.join(searchDir, ".mcp.json");
|
|
3534
|
+
if (fs13.existsSync(mcpPath)) {
|
|
3535
|
+
try {
|
|
3536
|
+
const content = fs13.readFileSync(mcpPath, "utf-8");
|
|
3537
|
+
const config = JSON.parse(content);
|
|
3538
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3539
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3540
|
+
API_KEY5 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3541
|
+
}
|
|
3542
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3543
|
+
API_URL5 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3544
|
+
}
|
|
3545
|
+
} catch {
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
if (!WORKSPACE_ID3) {
|
|
3550
|
+
const csConfigPath = path14.join(searchDir, ".contextstream", "config.json");
|
|
3551
|
+
if (fs13.existsSync(csConfigPath)) {
|
|
3552
|
+
try {
|
|
3553
|
+
const content = fs13.readFileSync(csConfigPath, "utf-8");
|
|
3554
|
+
const csConfig = JSON.parse(content);
|
|
3555
|
+
if (csConfig.workspace_id) {
|
|
3556
|
+
WORKSPACE_ID3 = csConfig.workspace_id;
|
|
3557
|
+
}
|
|
3558
|
+
} catch {
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
const parentDir = path14.dirname(searchDir);
|
|
3563
|
+
if (parentDir === searchDir) break;
|
|
3564
|
+
searchDir = parentDir;
|
|
3565
|
+
}
|
|
3566
|
+
if (!API_KEY5) {
|
|
3567
|
+
const homeMcpPath = path14.join(homedir11(), ".mcp.json");
|
|
3568
|
+
if (fs13.existsSync(homeMcpPath)) {
|
|
3569
|
+
try {
|
|
3570
|
+
const content = fs13.readFileSync(homeMcpPath, "utf-8");
|
|
3571
|
+
const config = JSON.parse(content);
|
|
3572
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3573
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3574
|
+
API_KEY5 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3575
|
+
}
|
|
3576
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3577
|
+
API_URL5 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3578
|
+
}
|
|
3579
|
+
} catch {
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
async function captureCommand(command, output, exitCode, isError, sessionId) {
|
|
3585
|
+
if (!API_KEY5) return;
|
|
3586
|
+
const payload = {
|
|
3587
|
+
event_type: isError ? "bash_error" : "bash_command",
|
|
3588
|
+
title: isError ? `Bash Error: ${command.slice(0, 50)}...` : `Command: ${command.slice(0, 50)}...`,
|
|
3589
|
+
content: JSON.stringify({
|
|
3590
|
+
command,
|
|
3591
|
+
output: output.slice(0, 2e3),
|
|
3592
|
+
exit_code: exitCode,
|
|
3593
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3594
|
+
}),
|
|
3595
|
+
importance: isError ? "high" : "low",
|
|
3596
|
+
tags: isError ? ["bash", "error", "command"] : ["bash", "command"],
|
|
3597
|
+
source_type: "hook",
|
|
3598
|
+
session_id: sessionId
|
|
3599
|
+
};
|
|
3600
|
+
if (WORKSPACE_ID3) {
|
|
3601
|
+
payload.workspace_id = WORKSPACE_ID3;
|
|
3602
|
+
}
|
|
3603
|
+
try {
|
|
3604
|
+
const controller = new AbortController();
|
|
3605
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
3606
|
+
await fetch(`${API_URL5}/api/v1/memory/events`, {
|
|
3607
|
+
method: "POST",
|
|
3608
|
+
headers: {
|
|
3609
|
+
"Content-Type": "application/json",
|
|
3610
|
+
"X-API-Key": API_KEY5
|
|
3611
|
+
},
|
|
3612
|
+
body: JSON.stringify(payload),
|
|
3613
|
+
signal: controller.signal
|
|
3614
|
+
});
|
|
3615
|
+
clearTimeout(timeoutId);
|
|
3616
|
+
} catch {
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
async function suggestLesson(command, error) {
|
|
3620
|
+
const errorPatterns = [
|
|
3621
|
+
{
|
|
3622
|
+
pattern: /command not found/i,
|
|
3623
|
+
lesson: `The command "${command.split(" ")[0]}" is not installed. Check if the package needs to be installed first.`
|
|
3624
|
+
},
|
|
3625
|
+
{
|
|
3626
|
+
pattern: /permission denied/i,
|
|
3627
|
+
lesson: "Permission denied. May need sudo or to check file permissions."
|
|
3628
|
+
},
|
|
3629
|
+
{
|
|
3630
|
+
pattern: /no such file or directory/i,
|
|
3631
|
+
lesson: "Path does not exist. Verify the file/directory path before running commands."
|
|
3632
|
+
},
|
|
3633
|
+
{
|
|
3634
|
+
pattern: /EADDRINUSE|address already in use/i,
|
|
3635
|
+
lesson: "Port is already in use. Kill the existing process or use a different port."
|
|
3636
|
+
},
|
|
3637
|
+
{
|
|
3638
|
+
pattern: /npm ERR!|ERESOLVE/i,
|
|
3639
|
+
lesson: "npm dependency conflict. Try `npm install --legacy-peer-deps` or check package versions."
|
|
3640
|
+
},
|
|
3641
|
+
{
|
|
3642
|
+
pattern: /ENOENT.*package\.json/i,
|
|
3643
|
+
lesson: "No package.json found. Make sure you're in the right directory or run `npm init`."
|
|
3644
|
+
},
|
|
3645
|
+
{
|
|
3646
|
+
pattern: /git.*not a git repository/i,
|
|
3647
|
+
lesson: "Not in a git repository. Run `git init` or navigate to a git repo."
|
|
3648
|
+
}
|
|
3649
|
+
];
|
|
3650
|
+
for (const { pattern, lesson } of errorPatterns) {
|
|
3651
|
+
if (pattern.test(error)) {
|
|
3652
|
+
return lesson;
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
return null;
|
|
3656
|
+
}
|
|
3657
|
+
async function runOnBashHook() {
|
|
3658
|
+
if (!ENABLED8) {
|
|
3659
|
+
process.exit(0);
|
|
3660
|
+
}
|
|
3661
|
+
let inputData = "";
|
|
3662
|
+
for await (const chunk of process.stdin) {
|
|
3663
|
+
inputData += chunk;
|
|
3664
|
+
}
|
|
3665
|
+
if (!inputData.trim()) {
|
|
3666
|
+
process.exit(0);
|
|
3667
|
+
}
|
|
3668
|
+
let input;
|
|
3669
|
+
try {
|
|
3670
|
+
input = JSON.parse(inputData);
|
|
3671
|
+
} catch {
|
|
3672
|
+
process.exit(0);
|
|
3673
|
+
}
|
|
3674
|
+
if (input.tool_name !== "Bash") {
|
|
3675
|
+
process.exit(0);
|
|
3676
|
+
}
|
|
3677
|
+
const cwd = input.cwd || process.cwd();
|
|
3678
|
+
loadConfigFromMcpJson3(cwd);
|
|
3679
|
+
const command = input.tool_input?.command || "";
|
|
3680
|
+
const output = input.tool_result?.output || input.tool_result?.error || "";
|
|
3681
|
+
const exitCode = input.tool_result?.exit_code ?? 0;
|
|
3682
|
+
const sessionId = input.session_id || "unknown";
|
|
3683
|
+
const isError = exitCode !== 0 || !!input.tool_result?.error;
|
|
3684
|
+
captureCommand(command, output, exitCode, isError, sessionId).catch(() => {
|
|
3685
|
+
});
|
|
3686
|
+
if (isError) {
|
|
3687
|
+
const lesson = await suggestLesson(command, output);
|
|
3688
|
+
if (lesson) {
|
|
3689
|
+
console.log(
|
|
3690
|
+
JSON.stringify({
|
|
3691
|
+
hookSpecificOutput: {
|
|
3692
|
+
hookEventName: "PostToolUse",
|
|
3693
|
+
additionalContext: `[ContextStream Insight] ${lesson}`
|
|
3694
|
+
}
|
|
3695
|
+
})
|
|
3696
|
+
);
|
|
3697
|
+
process.exit(0);
|
|
3698
|
+
}
|
|
3699
|
+
}
|
|
3700
|
+
process.exit(0);
|
|
3701
|
+
}
|
|
3702
|
+
var ENABLED8, API_URL5, API_KEY5, WORKSPACE_ID3, isDirectRun8;
|
|
3703
|
+
var init_on_bash = __esm({
|
|
3704
|
+
"src/hooks/on-bash.ts"() {
|
|
3705
|
+
"use strict";
|
|
3706
|
+
ENABLED8 = process.env.CONTEXTSTREAM_BASH_HOOK_ENABLED !== "false";
|
|
3707
|
+
API_URL5 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
3708
|
+
API_KEY5 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
3709
|
+
WORKSPACE_ID3 = null;
|
|
3710
|
+
isDirectRun8 = process.argv[1]?.includes("on-bash") || process.argv[2] === "on-bash";
|
|
3711
|
+
if (isDirectRun8) {
|
|
3712
|
+
runOnBashHook().catch(() => process.exit(0));
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
});
|
|
3716
|
+
|
|
3717
|
+
// src/hooks/on-task.ts
|
|
3718
|
+
var on_task_exports = {};
|
|
3719
|
+
__export(on_task_exports, {
|
|
3720
|
+
runOnTaskHook: () => runOnTaskHook
|
|
3721
|
+
});
|
|
3722
|
+
import * as fs14 from "node:fs";
|
|
3723
|
+
import * as path15 from "node:path";
|
|
3724
|
+
import { homedir as homedir12 } from "node:os";
|
|
3725
|
+
function loadConfigFromMcpJson4(cwd) {
|
|
3726
|
+
let searchDir = path15.resolve(cwd);
|
|
3727
|
+
for (let i = 0; i < 5; i++) {
|
|
3728
|
+
if (!API_KEY6) {
|
|
3729
|
+
const mcpPath = path15.join(searchDir, ".mcp.json");
|
|
3730
|
+
if (fs14.existsSync(mcpPath)) {
|
|
3731
|
+
try {
|
|
3732
|
+
const content = fs14.readFileSync(mcpPath, "utf-8");
|
|
3733
|
+
const config = JSON.parse(content);
|
|
3734
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3735
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3736
|
+
API_KEY6 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3737
|
+
}
|
|
3738
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3739
|
+
API_URL6 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3740
|
+
}
|
|
3741
|
+
} catch {
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
if (!WORKSPACE_ID4) {
|
|
3746
|
+
const csConfigPath = path15.join(searchDir, ".contextstream", "config.json");
|
|
3747
|
+
if (fs14.existsSync(csConfigPath)) {
|
|
3748
|
+
try {
|
|
3749
|
+
const content = fs14.readFileSync(csConfigPath, "utf-8");
|
|
3750
|
+
const csConfig = JSON.parse(content);
|
|
3751
|
+
if (csConfig.workspace_id) {
|
|
3752
|
+
WORKSPACE_ID4 = csConfig.workspace_id;
|
|
3753
|
+
}
|
|
3754
|
+
} catch {
|
|
3755
|
+
}
|
|
3756
|
+
}
|
|
3757
|
+
}
|
|
3758
|
+
const parentDir = path15.dirname(searchDir);
|
|
3759
|
+
if (parentDir === searchDir) break;
|
|
3760
|
+
searchDir = parentDir;
|
|
3761
|
+
}
|
|
3762
|
+
if (!API_KEY6) {
|
|
3763
|
+
const homeMcpPath = path15.join(homedir12(), ".mcp.json");
|
|
3764
|
+
if (fs14.existsSync(homeMcpPath)) {
|
|
3765
|
+
try {
|
|
3766
|
+
const content = fs14.readFileSync(homeMcpPath, "utf-8");
|
|
3767
|
+
const config = JSON.parse(content);
|
|
3768
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3769
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3770
|
+
API_KEY6 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3771
|
+
}
|
|
3772
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3773
|
+
API_URL6 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3774
|
+
}
|
|
3775
|
+
} catch {
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
async function captureTaskInvocation(description, prompt, agentType, result, sessionId) {
|
|
3781
|
+
if (!API_KEY6) return;
|
|
3782
|
+
const payload = {
|
|
3783
|
+
event_type: "task_agent",
|
|
3784
|
+
title: `Agent: ${agentType} - ${description}`,
|
|
3785
|
+
content: JSON.stringify({
|
|
3786
|
+
description,
|
|
3787
|
+
prompt: prompt.slice(0, 1e3),
|
|
3788
|
+
agent_type: agentType,
|
|
3789
|
+
result: result.slice(0, 2e3),
|
|
3790
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3791
|
+
}),
|
|
3792
|
+
importance: "medium",
|
|
3793
|
+
tags: ["task", "agent", agentType.toLowerCase()],
|
|
3794
|
+
source_type: "hook",
|
|
3795
|
+
session_id: sessionId
|
|
3796
|
+
};
|
|
3797
|
+
if (WORKSPACE_ID4) {
|
|
3798
|
+
payload.workspace_id = WORKSPACE_ID4;
|
|
3799
|
+
}
|
|
3800
|
+
try {
|
|
3801
|
+
const controller = new AbortController();
|
|
3802
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
3803
|
+
await fetch(`${API_URL6}/api/v1/memory/events`, {
|
|
3804
|
+
method: "POST",
|
|
3805
|
+
headers: {
|
|
3806
|
+
"Content-Type": "application/json",
|
|
3807
|
+
"X-API-Key": API_KEY6
|
|
3808
|
+
},
|
|
3809
|
+
body: JSON.stringify(payload),
|
|
3810
|
+
signal: controller.signal
|
|
3811
|
+
});
|
|
3812
|
+
clearTimeout(timeoutId);
|
|
3813
|
+
} catch {
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
async function runOnTaskHook() {
|
|
3817
|
+
if (!ENABLED9) {
|
|
3818
|
+
process.exit(0);
|
|
3819
|
+
}
|
|
3820
|
+
let inputData = "";
|
|
3821
|
+
for await (const chunk of process.stdin) {
|
|
3822
|
+
inputData += chunk;
|
|
3823
|
+
}
|
|
3824
|
+
if (!inputData.trim()) {
|
|
3825
|
+
process.exit(0);
|
|
3826
|
+
}
|
|
3827
|
+
let input;
|
|
3828
|
+
try {
|
|
3829
|
+
input = JSON.parse(inputData);
|
|
3830
|
+
} catch {
|
|
3831
|
+
process.exit(0);
|
|
3832
|
+
}
|
|
3833
|
+
if (input.tool_name !== "Task") {
|
|
3834
|
+
process.exit(0);
|
|
3835
|
+
}
|
|
3836
|
+
const cwd = input.cwd || process.cwd();
|
|
3837
|
+
loadConfigFromMcpJson4(cwd);
|
|
3838
|
+
const description = input.tool_input?.description || "Unknown task";
|
|
3839
|
+
const prompt = input.tool_input?.prompt || "";
|
|
3840
|
+
const agentType = input.tool_input?.subagent_type || "general-purpose";
|
|
3841
|
+
const result = input.tool_result?.output || "";
|
|
3842
|
+
const sessionId = input.session_id || "unknown";
|
|
3843
|
+
captureTaskInvocation(description, prompt, agentType, result, sessionId).catch(() => {
|
|
3844
|
+
});
|
|
3845
|
+
process.exit(0);
|
|
3846
|
+
}
|
|
3847
|
+
var ENABLED9, API_URL6, API_KEY6, WORKSPACE_ID4, isDirectRun9;
|
|
3848
|
+
var init_on_task = __esm({
|
|
3849
|
+
"src/hooks/on-task.ts"() {
|
|
3850
|
+
"use strict";
|
|
3851
|
+
ENABLED9 = process.env.CONTEXTSTREAM_TASK_HOOK_ENABLED !== "false";
|
|
3852
|
+
API_URL6 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
3853
|
+
API_KEY6 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
3854
|
+
WORKSPACE_ID4 = null;
|
|
3855
|
+
isDirectRun9 = process.argv[1]?.includes("on-task") || process.argv[2] === "on-task";
|
|
3856
|
+
if (isDirectRun9) {
|
|
3857
|
+
runOnTaskHook().catch(() => process.exit(0));
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
});
|
|
3861
|
+
|
|
3862
|
+
// src/hooks/on-read.ts
|
|
3863
|
+
var on_read_exports = {};
|
|
3864
|
+
__export(on_read_exports, {
|
|
3865
|
+
runOnReadHook: () => runOnReadHook
|
|
3866
|
+
});
|
|
3867
|
+
import * as fs15 from "node:fs";
|
|
3868
|
+
import * as path16 from "node:path";
|
|
3869
|
+
import { homedir as homedir13 } from "node:os";
|
|
3870
|
+
function loadConfigFromMcpJson5(cwd) {
|
|
3871
|
+
let searchDir = path16.resolve(cwd);
|
|
3872
|
+
for (let i = 0; i < 5; i++) {
|
|
3873
|
+
if (!API_KEY7) {
|
|
3874
|
+
const mcpPath = path16.join(searchDir, ".mcp.json");
|
|
3875
|
+
if (fs15.existsSync(mcpPath)) {
|
|
3876
|
+
try {
|
|
3877
|
+
const content = fs15.readFileSync(mcpPath, "utf-8");
|
|
3878
|
+
const config = JSON.parse(content);
|
|
3879
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3880
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3881
|
+
API_KEY7 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3882
|
+
}
|
|
3883
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3884
|
+
API_URL7 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3885
|
+
}
|
|
3886
|
+
} catch {
|
|
3887
|
+
}
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
if (!WORKSPACE_ID5) {
|
|
3891
|
+
const csConfigPath = path16.join(searchDir, ".contextstream", "config.json");
|
|
3892
|
+
if (fs15.existsSync(csConfigPath)) {
|
|
3893
|
+
try {
|
|
3894
|
+
const content = fs15.readFileSync(csConfigPath, "utf-8");
|
|
3895
|
+
const csConfig = JSON.parse(content);
|
|
3896
|
+
if (csConfig.workspace_id) {
|
|
3897
|
+
WORKSPACE_ID5 = csConfig.workspace_id;
|
|
3898
|
+
}
|
|
3899
|
+
} catch {
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
const parentDir = path16.dirname(searchDir);
|
|
3904
|
+
if (parentDir === searchDir) break;
|
|
3905
|
+
searchDir = parentDir;
|
|
3906
|
+
}
|
|
3907
|
+
if (!API_KEY7) {
|
|
3908
|
+
const homeMcpPath = path16.join(homedir13(), ".mcp.json");
|
|
3909
|
+
if (fs15.existsSync(homeMcpPath)) {
|
|
3910
|
+
try {
|
|
3911
|
+
const content = fs15.readFileSync(homeMcpPath, "utf-8");
|
|
3912
|
+
const config = JSON.parse(content);
|
|
3913
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
3914
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
3915
|
+
API_KEY7 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
3916
|
+
}
|
|
3917
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
3918
|
+
API_URL7 = csEnv.CONTEXTSTREAM_API_URL;
|
|
3919
|
+
}
|
|
3920
|
+
} catch {
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
}
|
|
3925
|
+
async function captureExploration(toolName, target, resultSummary, sessionId) {
|
|
3926
|
+
if (!API_KEY7) return;
|
|
3927
|
+
const cacheKey = `${toolName}:${target}`;
|
|
3928
|
+
if (recentCaptures.has(cacheKey)) {
|
|
3929
|
+
return;
|
|
3930
|
+
}
|
|
3931
|
+
recentCaptures.add(cacheKey);
|
|
3932
|
+
setTimeout(() => recentCaptures.delete(cacheKey), CAPTURE_WINDOW_MS);
|
|
3933
|
+
const payload = {
|
|
3934
|
+
event_type: "file_exploration",
|
|
3935
|
+
title: `${toolName}: ${target.slice(0, 50)}`,
|
|
3936
|
+
content: JSON.stringify({
|
|
3937
|
+
tool: toolName,
|
|
3938
|
+
target,
|
|
3939
|
+
result_summary: resultSummary.slice(0, 500),
|
|
3940
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3941
|
+
}),
|
|
3942
|
+
importance: "low",
|
|
3943
|
+
tags: ["exploration", toolName.toLowerCase()],
|
|
3944
|
+
source_type: "hook",
|
|
3945
|
+
session_id: sessionId
|
|
3946
|
+
};
|
|
3947
|
+
if (WORKSPACE_ID5) {
|
|
3948
|
+
payload.workspace_id = WORKSPACE_ID5;
|
|
3949
|
+
}
|
|
3950
|
+
try {
|
|
3951
|
+
const controller = new AbortController();
|
|
3952
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
3953
|
+
await fetch(`${API_URL7}/api/v1/memory/events`, {
|
|
3954
|
+
method: "POST",
|
|
3955
|
+
headers: {
|
|
3956
|
+
"Content-Type": "application/json",
|
|
3957
|
+
"X-API-Key": API_KEY7
|
|
3958
|
+
},
|
|
3959
|
+
body: JSON.stringify(payload),
|
|
3960
|
+
signal: controller.signal
|
|
3961
|
+
});
|
|
3962
|
+
clearTimeout(timeoutId);
|
|
3963
|
+
} catch {
|
|
3964
|
+
}
|
|
3965
|
+
}
|
|
3966
|
+
async function runOnReadHook() {
|
|
3967
|
+
if (!ENABLED10) {
|
|
3968
|
+
process.exit(0);
|
|
3969
|
+
}
|
|
3970
|
+
let inputData = "";
|
|
3971
|
+
for await (const chunk of process.stdin) {
|
|
3972
|
+
inputData += chunk;
|
|
3973
|
+
}
|
|
3974
|
+
if (!inputData.trim()) {
|
|
3975
|
+
process.exit(0);
|
|
3976
|
+
}
|
|
3977
|
+
let input;
|
|
3978
|
+
try {
|
|
3979
|
+
input = JSON.parse(inputData);
|
|
3980
|
+
} catch {
|
|
3981
|
+
process.exit(0);
|
|
3982
|
+
}
|
|
3983
|
+
const toolName = input.tool_name || "";
|
|
3984
|
+
if (!["Read", "Glob", "Grep"].includes(toolName)) {
|
|
3985
|
+
process.exit(0);
|
|
3986
|
+
}
|
|
3987
|
+
const cwd = input.cwd || process.cwd();
|
|
3988
|
+
loadConfigFromMcpJson5(cwd);
|
|
3989
|
+
const sessionId = input.session_id || "unknown";
|
|
3990
|
+
let target = "";
|
|
3991
|
+
let resultSummary = "";
|
|
3992
|
+
switch (toolName) {
|
|
3993
|
+
case "Read":
|
|
3994
|
+
target = input.tool_input?.file_path || "";
|
|
3995
|
+
resultSummary = `Read file: ${target}`;
|
|
3996
|
+
break;
|
|
3997
|
+
case "Glob":
|
|
3998
|
+
target = input.tool_input?.pattern || "";
|
|
3999
|
+
const globFiles = input.tool_result?.files || [];
|
|
4000
|
+
resultSummary = `Found ${globFiles.length} files matching ${target}`;
|
|
4001
|
+
break;
|
|
4002
|
+
case "Grep":
|
|
4003
|
+
target = input.tool_input?.pattern || "";
|
|
4004
|
+
const matches = input.tool_result?.matches || 0;
|
|
4005
|
+
resultSummary = `Found ${matches} matches for "${target}"`;
|
|
4006
|
+
break;
|
|
4007
|
+
}
|
|
4008
|
+
if (target) {
|
|
4009
|
+
captureExploration(toolName, target, resultSummary, sessionId).catch(() => {
|
|
4010
|
+
});
|
|
4011
|
+
}
|
|
4012
|
+
process.exit(0);
|
|
4013
|
+
}
|
|
4014
|
+
var ENABLED10, API_URL7, API_KEY7, WORKSPACE_ID5, recentCaptures, CAPTURE_WINDOW_MS, isDirectRun10;
|
|
4015
|
+
var init_on_read = __esm({
|
|
4016
|
+
"src/hooks/on-read.ts"() {
|
|
4017
|
+
"use strict";
|
|
4018
|
+
ENABLED10 = process.env.CONTEXTSTREAM_READ_HOOK_ENABLED !== "false";
|
|
4019
|
+
API_URL7 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
4020
|
+
API_KEY7 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
4021
|
+
WORKSPACE_ID5 = null;
|
|
4022
|
+
recentCaptures = /* @__PURE__ */ new Set();
|
|
4023
|
+
CAPTURE_WINDOW_MS = 6e4;
|
|
4024
|
+
isDirectRun10 = process.argv[1]?.includes("on-read") || process.argv[2] === "on-read";
|
|
4025
|
+
if (isDirectRun10) {
|
|
4026
|
+
runOnReadHook().catch(() => process.exit(0));
|
|
4027
|
+
}
|
|
4028
|
+
}
|
|
4029
|
+
});
|
|
4030
|
+
|
|
4031
|
+
// src/hooks/on-web.ts
|
|
4032
|
+
var on_web_exports = {};
|
|
4033
|
+
__export(on_web_exports, {
|
|
4034
|
+
runOnWebHook: () => runOnWebHook
|
|
4035
|
+
});
|
|
4036
|
+
import * as fs16 from "node:fs";
|
|
4037
|
+
import * as path17 from "node:path";
|
|
4038
|
+
import { homedir as homedir14 } from "node:os";
|
|
4039
|
+
function loadConfigFromMcpJson6(cwd) {
|
|
4040
|
+
let searchDir = path17.resolve(cwd);
|
|
4041
|
+
for (let i = 0; i < 5; i++) {
|
|
4042
|
+
if (!API_KEY8) {
|
|
4043
|
+
const mcpPath = path17.join(searchDir, ".mcp.json");
|
|
4044
|
+
if (fs16.existsSync(mcpPath)) {
|
|
4045
|
+
try {
|
|
4046
|
+
const content = fs16.readFileSync(mcpPath, "utf-8");
|
|
4047
|
+
const config = JSON.parse(content);
|
|
4048
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
4049
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
4050
|
+
API_KEY8 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
4051
|
+
}
|
|
4052
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
4053
|
+
API_URL8 = csEnv.CONTEXTSTREAM_API_URL;
|
|
4054
|
+
}
|
|
4055
|
+
} catch {
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
if (!WORKSPACE_ID6) {
|
|
4060
|
+
const csConfigPath = path17.join(searchDir, ".contextstream", "config.json");
|
|
4061
|
+
if (fs16.existsSync(csConfigPath)) {
|
|
4062
|
+
try {
|
|
4063
|
+
const content = fs16.readFileSync(csConfigPath, "utf-8");
|
|
4064
|
+
const csConfig = JSON.parse(content);
|
|
4065
|
+
if (csConfig.workspace_id) {
|
|
4066
|
+
WORKSPACE_ID6 = csConfig.workspace_id;
|
|
4067
|
+
}
|
|
4068
|
+
} catch {
|
|
4069
|
+
}
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
const parentDir = path17.dirname(searchDir);
|
|
4073
|
+
if (parentDir === searchDir) break;
|
|
4074
|
+
searchDir = parentDir;
|
|
4075
|
+
}
|
|
4076
|
+
if (!API_KEY8) {
|
|
4077
|
+
const homeMcpPath = path17.join(homedir14(), ".mcp.json");
|
|
4078
|
+
if (fs16.existsSync(homeMcpPath)) {
|
|
4079
|
+
try {
|
|
4080
|
+
const content = fs16.readFileSync(homeMcpPath, "utf-8");
|
|
4081
|
+
const config = JSON.parse(content);
|
|
4082
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
4083
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
4084
|
+
API_KEY8 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
4085
|
+
}
|
|
4086
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
4087
|
+
API_URL8 = csEnv.CONTEXTSTREAM_API_URL;
|
|
4088
|
+
}
|
|
4089
|
+
} catch {
|
|
4090
|
+
}
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4094
|
+
async function captureWebResearch(toolName, target, summary, sessionId) {
|
|
4095
|
+
if (!API_KEY8) return;
|
|
4096
|
+
const payload = {
|
|
4097
|
+
event_type: "web_research",
|
|
4098
|
+
title: `${toolName}: ${target.slice(0, 60)}`,
|
|
4099
|
+
content: JSON.stringify({
|
|
4100
|
+
tool: toolName,
|
|
4101
|
+
target,
|
|
4102
|
+
summary: summary.slice(0, 1e3),
|
|
4103
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4104
|
+
}),
|
|
4105
|
+
importance: "medium",
|
|
4106
|
+
tags: ["research", "web", toolName.toLowerCase()],
|
|
4107
|
+
source_type: "hook",
|
|
4108
|
+
session_id: sessionId
|
|
4109
|
+
};
|
|
4110
|
+
if (WORKSPACE_ID6) {
|
|
4111
|
+
payload.workspace_id = WORKSPACE_ID6;
|
|
4112
|
+
}
|
|
4113
|
+
try {
|
|
4114
|
+
const controller = new AbortController();
|
|
4115
|
+
const timeoutId = setTimeout(() => controller.abort(), 3e3);
|
|
4116
|
+
await fetch(`${API_URL8}/api/v1/memory/events`, {
|
|
4117
|
+
method: "POST",
|
|
4118
|
+
headers: {
|
|
4119
|
+
"Content-Type": "application/json",
|
|
4120
|
+
"X-API-Key": API_KEY8
|
|
4121
|
+
},
|
|
4122
|
+
body: JSON.stringify(payload),
|
|
4123
|
+
signal: controller.signal
|
|
4124
|
+
});
|
|
4125
|
+
clearTimeout(timeoutId);
|
|
4126
|
+
} catch {
|
|
4127
|
+
}
|
|
4128
|
+
}
|
|
4129
|
+
async function runOnWebHook() {
|
|
4130
|
+
if (!ENABLED11) {
|
|
4131
|
+
process.exit(0);
|
|
4132
|
+
}
|
|
4133
|
+
let inputData = "";
|
|
4134
|
+
for await (const chunk of process.stdin) {
|
|
4135
|
+
inputData += chunk;
|
|
4136
|
+
}
|
|
4137
|
+
if (!inputData.trim()) {
|
|
4138
|
+
process.exit(0);
|
|
4139
|
+
}
|
|
4140
|
+
let input;
|
|
4141
|
+
try {
|
|
4142
|
+
input = JSON.parse(inputData);
|
|
4143
|
+
} catch {
|
|
4144
|
+
process.exit(0);
|
|
4145
|
+
}
|
|
4146
|
+
const toolName = input.tool_name || "";
|
|
4147
|
+
if (!["WebFetch", "WebSearch"].includes(toolName)) {
|
|
4148
|
+
process.exit(0);
|
|
4149
|
+
}
|
|
4150
|
+
const cwd = input.cwd || process.cwd();
|
|
4151
|
+
loadConfigFromMcpJson6(cwd);
|
|
4152
|
+
const sessionId = input.session_id || "unknown";
|
|
4153
|
+
let target = "";
|
|
4154
|
+
let summary = "";
|
|
4155
|
+
switch (toolName) {
|
|
4156
|
+
case "WebFetch":
|
|
4157
|
+
target = input.tool_input?.url || "";
|
|
4158
|
+
const prompt = input.tool_input?.prompt || "fetched content";
|
|
4159
|
+
const content = input.tool_result?.output || input.tool_result?.content || "";
|
|
4160
|
+
summary = `Fetched ${target} (${prompt}): ${content.slice(0, 300)}`;
|
|
4161
|
+
break;
|
|
4162
|
+
case "WebSearch":
|
|
4163
|
+
target = input.tool_input?.query || "";
|
|
4164
|
+
const results = input.tool_result?.results || [];
|
|
4165
|
+
const topResults = results.slice(0, 3).map((r) => `- ${r.title}: ${r.url}`).join("\n");
|
|
4166
|
+
summary = `Search: "${target}"
|
|
4167
|
+
Top results:
|
|
4168
|
+
${topResults}`;
|
|
4169
|
+
break;
|
|
4170
|
+
}
|
|
4171
|
+
if (target) {
|
|
4172
|
+
captureWebResearch(toolName, target, summary, sessionId).catch(() => {
|
|
4173
|
+
});
|
|
4174
|
+
}
|
|
4175
|
+
process.exit(0);
|
|
4176
|
+
}
|
|
4177
|
+
var ENABLED11, API_URL8, API_KEY8, WORKSPACE_ID6, isDirectRun11;
|
|
4178
|
+
var init_on_web = __esm({
|
|
4179
|
+
"src/hooks/on-web.ts"() {
|
|
4180
|
+
"use strict";
|
|
4181
|
+
ENABLED11 = process.env.CONTEXTSTREAM_WEB_HOOK_ENABLED !== "false";
|
|
4182
|
+
API_URL8 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
4183
|
+
API_KEY8 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
4184
|
+
WORKSPACE_ID6 = null;
|
|
4185
|
+
isDirectRun11 = process.argv[1]?.includes("on-web") || process.argv[2] === "on-web";
|
|
4186
|
+
if (isDirectRun11) {
|
|
4187
|
+
runOnWebHook().catch(() => process.exit(0));
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
});
|
|
4191
|
+
|
|
4192
|
+
// src/hooks/session-init.ts
|
|
4193
|
+
var session_init_exports = {};
|
|
4194
|
+
__export(session_init_exports, {
|
|
4195
|
+
runSessionInitHook: () => runSessionInitHook
|
|
4196
|
+
});
|
|
4197
|
+
import * as fs17 from "node:fs";
|
|
4198
|
+
import * as path18 from "node:path";
|
|
4199
|
+
import { homedir as homedir15 } from "node:os";
|
|
4200
|
+
function loadConfigFromMcpJson7(cwd) {
|
|
4201
|
+
let searchDir = path18.resolve(cwd);
|
|
4202
|
+
for (let i = 0; i < 5; i++) {
|
|
4203
|
+
if (!API_KEY9) {
|
|
4204
|
+
const mcpPath = path18.join(searchDir, ".mcp.json");
|
|
4205
|
+
if (fs17.existsSync(mcpPath)) {
|
|
4206
|
+
try {
|
|
4207
|
+
const content = fs17.readFileSync(mcpPath, "utf-8");
|
|
4208
|
+
const config = JSON.parse(content);
|
|
4209
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
4210
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
4211
|
+
API_KEY9 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
4212
|
+
}
|
|
4213
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
4214
|
+
API_URL9 = csEnv.CONTEXTSTREAM_API_URL;
|
|
4215
|
+
}
|
|
4216
|
+
if (csEnv?.CONTEXTSTREAM_WORKSPACE_ID) {
|
|
4217
|
+
WORKSPACE_ID7 = csEnv.CONTEXTSTREAM_WORKSPACE_ID;
|
|
4218
|
+
}
|
|
4219
|
+
} catch {
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
}
|
|
4223
|
+
if (!WORKSPACE_ID7 || !PROJECT_ID) {
|
|
4224
|
+
const csConfigPath = path18.join(searchDir, ".contextstream", "config.json");
|
|
4225
|
+
if (fs17.existsSync(csConfigPath)) {
|
|
4226
|
+
try {
|
|
4227
|
+
const content = fs17.readFileSync(csConfigPath, "utf-8");
|
|
4228
|
+
const csConfig = JSON.parse(content);
|
|
4229
|
+
if (csConfig.workspace_id && !WORKSPACE_ID7) {
|
|
4230
|
+
WORKSPACE_ID7 = csConfig.workspace_id;
|
|
4231
|
+
}
|
|
4232
|
+
if (csConfig.project_id && !PROJECT_ID) {
|
|
4233
|
+
PROJECT_ID = csConfig.project_id;
|
|
4234
|
+
}
|
|
4235
|
+
} catch {
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
const parentDir = path18.dirname(searchDir);
|
|
4240
|
+
if (parentDir === searchDir) break;
|
|
4241
|
+
searchDir = parentDir;
|
|
4242
|
+
}
|
|
4243
|
+
if (!API_KEY9) {
|
|
4244
|
+
const homeMcpPath = path18.join(homedir15(), ".mcp.json");
|
|
4245
|
+
if (fs17.existsSync(homeMcpPath)) {
|
|
4246
|
+
try {
|
|
4247
|
+
const content = fs17.readFileSync(homeMcpPath, "utf-8");
|
|
4248
|
+
const config = JSON.parse(content);
|
|
4249
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
4250
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
4251
|
+
API_KEY9 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
4252
|
+
}
|
|
4253
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
4254
|
+
API_URL9 = csEnv.CONTEXTSTREAM_API_URL;
|
|
4255
|
+
}
|
|
4256
|
+
} catch {
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
}
|
|
4260
|
+
}
|
|
4261
|
+
async function fetchSessionContext() {
|
|
4262
|
+
if (!API_KEY9) return null;
|
|
4263
|
+
try {
|
|
4264
|
+
const controller = new AbortController();
|
|
4265
|
+
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
4266
|
+
const url = new URL(`${API_URL9}/api/v1/context`);
|
|
4267
|
+
if (WORKSPACE_ID7) url.searchParams.set("workspace_id", WORKSPACE_ID7);
|
|
4268
|
+
if (PROJECT_ID) url.searchParams.set("project_id", PROJECT_ID);
|
|
4269
|
+
url.searchParams.set("include_rules", "true");
|
|
4270
|
+
url.searchParams.set("include_lessons", "true");
|
|
4271
|
+
url.searchParams.set("include_decisions", "true");
|
|
4272
|
+
url.searchParams.set("include_plans", "true");
|
|
4273
|
+
url.searchParams.set("limit", "5");
|
|
4274
|
+
const response = await fetch(url.toString(), {
|
|
4275
|
+
method: "GET",
|
|
4276
|
+
headers: {
|
|
4277
|
+
"X-API-Key": API_KEY9
|
|
4278
|
+
},
|
|
4279
|
+
signal: controller.signal
|
|
4280
|
+
});
|
|
4281
|
+
clearTimeout(timeoutId);
|
|
4282
|
+
if (response.ok) {
|
|
4283
|
+
return await response.json();
|
|
4284
|
+
}
|
|
4285
|
+
return null;
|
|
4286
|
+
} catch {
|
|
4287
|
+
return null;
|
|
4288
|
+
}
|
|
4289
|
+
}
|
|
4290
|
+
function formatContext(ctx) {
|
|
4291
|
+
if (!ctx) {
|
|
4292
|
+
return `[ContextStream Session Start]
|
|
4293
|
+
|
|
4294
|
+
No stored context found. Call \`mcp__contextstream__context(user_message="starting new session")\` to initialize.`;
|
|
4295
|
+
}
|
|
4296
|
+
const parts = ["[ContextStream Session Start]"];
|
|
4297
|
+
if (ctx.lessons && ctx.lessons.length > 0) {
|
|
4298
|
+
parts.push("\n## \u26A0\uFE0F Lessons from Past Mistakes");
|
|
4299
|
+
for (const lesson of ctx.lessons.slice(0, 3)) {
|
|
4300
|
+
parts.push(`- **${lesson.title}**: ${lesson.prevention}`);
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
if (ctx.active_plans && ctx.active_plans.length > 0) {
|
|
4304
|
+
parts.push("\n## \u{1F4CB} Active Plans");
|
|
4305
|
+
for (const plan of ctx.active_plans.slice(0, 3)) {
|
|
4306
|
+
parts.push(`- ${plan.title} (${plan.status})`);
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
if (ctx.pending_tasks && ctx.pending_tasks.length > 0) {
|
|
4310
|
+
parts.push("\n## \u2705 Pending Tasks");
|
|
4311
|
+
for (const task of ctx.pending_tasks.slice(0, 5)) {
|
|
4312
|
+
parts.push(`- ${task.title}`);
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
if (ctx.recent_decisions && ctx.recent_decisions.length > 0) {
|
|
4316
|
+
parts.push("\n## \u{1F4DD} Recent Decisions");
|
|
4317
|
+
for (const decision of ctx.recent_decisions.slice(0, 3)) {
|
|
4318
|
+
parts.push(`- **${decision.title}**`);
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
parts.push("\n---");
|
|
4322
|
+
parts.push('Call `mcp__contextstream__context(user_message="...")` for task-specific context.');
|
|
4323
|
+
return parts.join("\n");
|
|
4324
|
+
}
|
|
4325
|
+
async function runSessionInitHook() {
|
|
4326
|
+
if (!ENABLED12) {
|
|
4327
|
+
process.exit(0);
|
|
4328
|
+
}
|
|
4329
|
+
let inputData = "";
|
|
4330
|
+
for await (const chunk of process.stdin) {
|
|
4331
|
+
inputData += chunk;
|
|
4332
|
+
}
|
|
4333
|
+
if (!inputData.trim()) {
|
|
4334
|
+
process.exit(0);
|
|
4335
|
+
}
|
|
4336
|
+
let input;
|
|
4337
|
+
try {
|
|
4338
|
+
input = JSON.parse(inputData);
|
|
4339
|
+
} catch {
|
|
4340
|
+
process.exit(0);
|
|
4341
|
+
}
|
|
4342
|
+
const cwd = input.cwd || process.cwd();
|
|
4343
|
+
loadConfigFromMcpJson7(cwd);
|
|
4344
|
+
const context = await fetchSessionContext();
|
|
4345
|
+
const formattedContext = formatContext(context);
|
|
4346
|
+
console.log(
|
|
4347
|
+
JSON.stringify({
|
|
4348
|
+
hookSpecificOutput: {
|
|
4349
|
+
hookEventName: "SessionStart",
|
|
4350
|
+
additionalContext: formattedContext
|
|
4351
|
+
}
|
|
4352
|
+
})
|
|
4353
|
+
);
|
|
4354
|
+
process.exit(0);
|
|
4355
|
+
}
|
|
4356
|
+
var ENABLED12, API_URL9, API_KEY9, WORKSPACE_ID7, PROJECT_ID, isDirectRun12;
|
|
4357
|
+
var init_session_init = __esm({
|
|
4358
|
+
"src/hooks/session-init.ts"() {
|
|
4359
|
+
"use strict";
|
|
4360
|
+
ENABLED12 = process.env.CONTEXTSTREAM_SESSION_INIT_ENABLED !== "false";
|
|
4361
|
+
API_URL9 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
4362
|
+
API_KEY9 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
4363
|
+
WORKSPACE_ID7 = null;
|
|
4364
|
+
PROJECT_ID = null;
|
|
4365
|
+
isDirectRun12 = process.argv[1]?.includes("session-init") || process.argv[2] === "session-init";
|
|
4366
|
+
if (isDirectRun12) {
|
|
4367
|
+
runSessionInitHook().catch(() => process.exit(0));
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
});
|
|
4371
|
+
|
|
4372
|
+
// src/hooks/session-end.ts
|
|
4373
|
+
var session_end_exports = {};
|
|
4374
|
+
__export(session_end_exports, {
|
|
4375
|
+
runSessionEndHook: () => runSessionEndHook
|
|
4376
|
+
});
|
|
4377
|
+
import * as fs18 from "node:fs";
|
|
4378
|
+
import * as path19 from "node:path";
|
|
4379
|
+
import { homedir as homedir16 } from "node:os";
|
|
4380
|
+
function loadConfigFromMcpJson8(cwd) {
|
|
4381
|
+
let searchDir = path19.resolve(cwd);
|
|
4382
|
+
for (let i = 0; i < 5; i++) {
|
|
4383
|
+
if (!API_KEY10) {
|
|
4384
|
+
const mcpPath = path19.join(searchDir, ".mcp.json");
|
|
4385
|
+
if (fs18.existsSync(mcpPath)) {
|
|
4386
|
+
try {
|
|
4387
|
+
const content = fs18.readFileSync(mcpPath, "utf-8");
|
|
4388
|
+
const config = JSON.parse(content);
|
|
4389
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
4390
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
4391
|
+
API_KEY10 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
4392
|
+
}
|
|
4393
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
4394
|
+
API_URL10 = csEnv.CONTEXTSTREAM_API_URL;
|
|
4395
|
+
}
|
|
4396
|
+
} catch {
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
if (!WORKSPACE_ID8) {
|
|
4401
|
+
const csConfigPath = path19.join(searchDir, ".contextstream", "config.json");
|
|
4402
|
+
if (fs18.existsSync(csConfigPath)) {
|
|
4403
|
+
try {
|
|
4404
|
+
const content = fs18.readFileSync(csConfigPath, "utf-8");
|
|
4405
|
+
const csConfig = JSON.parse(content);
|
|
4406
|
+
if (csConfig.workspace_id) {
|
|
4407
|
+
WORKSPACE_ID8 = csConfig.workspace_id;
|
|
4408
|
+
}
|
|
4409
|
+
} catch {
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
}
|
|
4413
|
+
const parentDir = path19.dirname(searchDir);
|
|
4414
|
+
if (parentDir === searchDir) break;
|
|
4415
|
+
searchDir = parentDir;
|
|
4416
|
+
}
|
|
4417
|
+
if (!API_KEY10) {
|
|
4418
|
+
const homeMcpPath = path19.join(homedir16(), ".mcp.json");
|
|
4419
|
+
if (fs18.existsSync(homeMcpPath)) {
|
|
4420
|
+
try {
|
|
4421
|
+
const content = fs18.readFileSync(homeMcpPath, "utf-8");
|
|
4422
|
+
const config = JSON.parse(content);
|
|
4423
|
+
const csEnv = config.mcpServers?.contextstream?.env;
|
|
4424
|
+
if (csEnv?.CONTEXTSTREAM_API_KEY) {
|
|
4425
|
+
API_KEY10 = csEnv.CONTEXTSTREAM_API_KEY;
|
|
4426
|
+
}
|
|
4427
|
+
if (csEnv?.CONTEXTSTREAM_API_URL) {
|
|
4428
|
+
API_URL10 = csEnv.CONTEXTSTREAM_API_URL;
|
|
4429
|
+
}
|
|
4430
|
+
} catch {
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
function parseTranscriptStats(transcriptPath) {
|
|
4436
|
+
const stats = {
|
|
4437
|
+
messageCount: 0,
|
|
4438
|
+
toolCallCount: 0,
|
|
4439
|
+
duration: 0,
|
|
4440
|
+
filesModified: []
|
|
4441
|
+
};
|
|
4442
|
+
if (!transcriptPath || !fs18.existsSync(transcriptPath)) {
|
|
4443
|
+
return stats;
|
|
4444
|
+
}
|
|
4445
|
+
try {
|
|
4446
|
+
const content = fs18.readFileSync(transcriptPath, "utf-8");
|
|
4447
|
+
const lines = content.split("\n");
|
|
4448
|
+
let firstTimestamp = null;
|
|
4449
|
+
let lastTimestamp = null;
|
|
4450
|
+
const modifiedFiles = /* @__PURE__ */ new Set();
|
|
4451
|
+
for (const line of lines) {
|
|
4452
|
+
if (!line.trim()) continue;
|
|
4453
|
+
try {
|
|
4454
|
+
const entry = JSON.parse(line);
|
|
4455
|
+
if (entry.type === "user" || entry.type === "assistant") {
|
|
4456
|
+
stats.messageCount++;
|
|
4457
|
+
} else if (entry.type === "tool_use") {
|
|
4458
|
+
stats.toolCallCount++;
|
|
4459
|
+
if (["Write", "Edit", "NotebookEdit"].includes(entry.name || "")) {
|
|
4460
|
+
const filePath = entry.input?.file_path;
|
|
4461
|
+
if (filePath) {
|
|
4462
|
+
modifiedFiles.add(filePath);
|
|
4463
|
+
}
|
|
4464
|
+
}
|
|
4465
|
+
}
|
|
4466
|
+
if (entry.timestamp) {
|
|
4467
|
+
const ts = new Date(entry.timestamp);
|
|
4468
|
+
if (!firstTimestamp || ts < firstTimestamp) {
|
|
4469
|
+
firstTimestamp = ts;
|
|
4470
|
+
}
|
|
4471
|
+
if (!lastTimestamp || ts > lastTimestamp) {
|
|
4472
|
+
lastTimestamp = ts;
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
} catch {
|
|
4476
|
+
continue;
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
if (firstTimestamp && lastTimestamp) {
|
|
4480
|
+
stats.duration = Math.round((lastTimestamp.getTime() - firstTimestamp.getTime()) / 1e3);
|
|
4481
|
+
}
|
|
4482
|
+
stats.filesModified = Array.from(modifiedFiles);
|
|
3158
4483
|
} catch {
|
|
3159
|
-
return false;
|
|
3160
4484
|
}
|
|
4485
|
+
return stats;
|
|
3161
4486
|
}
|
|
3162
|
-
function
|
|
3163
|
-
|
|
3164
|
-
const
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
4487
|
+
async function finalizeSession(sessionId, stats, reason) {
|
|
4488
|
+
if (!API_KEY10) return;
|
|
4489
|
+
const payload = {
|
|
4490
|
+
event_type: "session_end",
|
|
4491
|
+
title: `Session Ended: ${reason}`,
|
|
4492
|
+
content: JSON.stringify({
|
|
4493
|
+
session_id: sessionId,
|
|
4494
|
+
reason,
|
|
4495
|
+
stats: {
|
|
4496
|
+
messages: stats.messageCount,
|
|
4497
|
+
tool_calls: stats.toolCallCount,
|
|
4498
|
+
duration_seconds: stats.duration,
|
|
4499
|
+
files_modified: stats.filesModified.length
|
|
4500
|
+
},
|
|
4501
|
+
files_modified: stats.filesModified.slice(0, 20),
|
|
4502
|
+
ended_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
4503
|
+
}),
|
|
4504
|
+
importance: "low",
|
|
4505
|
+
tags: ["session", "end", reason],
|
|
4506
|
+
source_type: "hook",
|
|
4507
|
+
session_id: sessionId
|
|
3168
4508
|
};
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
const { installClaudeCodeHooks: installClaudeCodeHooks3 } = await Promise.resolve().then(() => (init_hooks_config(), hooks_config_exports));
|
|
3172
|
-
await installClaudeCodeHooks3({
|
|
3173
|
-
scope: "both",
|
|
3174
|
-
projectPath: folderPath,
|
|
3175
|
-
includePreCompact: true,
|
|
3176
|
-
includeMediaAware: true,
|
|
3177
|
-
includePostWrite: true,
|
|
3178
|
-
includeAutoRules: true
|
|
3179
|
-
});
|
|
3180
|
-
}
|
|
3181
|
-
async function runAutoRulesHook() {
|
|
3182
|
-
if (!ENABLED6) {
|
|
3183
|
-
process.exit(0);
|
|
4509
|
+
if (WORKSPACE_ID8) {
|
|
4510
|
+
payload.workspace_id = WORKSPACE_ID8;
|
|
3184
4511
|
}
|
|
3185
|
-
|
|
4512
|
+
try {
|
|
4513
|
+
const controller = new AbortController();
|
|
4514
|
+
const timeoutId = setTimeout(() => controller.abort(), 5e3);
|
|
4515
|
+
await fetch(`${API_URL10}/api/v1/memory/events`, {
|
|
4516
|
+
method: "POST",
|
|
4517
|
+
headers: {
|
|
4518
|
+
"Content-Type": "application/json",
|
|
4519
|
+
"X-API-Key": API_KEY10
|
|
4520
|
+
},
|
|
4521
|
+
body: JSON.stringify(payload),
|
|
4522
|
+
signal: controller.signal
|
|
4523
|
+
});
|
|
4524
|
+
clearTimeout(timeoutId);
|
|
4525
|
+
} catch {
|
|
4526
|
+
}
|
|
4527
|
+
}
|
|
4528
|
+
async function runSessionEndHook() {
|
|
4529
|
+
if (!ENABLED13) {
|
|
3186
4530
|
process.exit(0);
|
|
3187
4531
|
}
|
|
3188
4532
|
let inputData = "";
|
|
@@ -3198,40 +4542,444 @@ async function runAutoRulesHook() {
|
|
|
3198
4542
|
} catch {
|
|
3199
4543
|
process.exit(0);
|
|
3200
4544
|
}
|
|
3201
|
-
const
|
|
3202
|
-
|
|
3203
|
-
|
|
4545
|
+
const cwd = input.cwd || process.cwd();
|
|
4546
|
+
loadConfigFromMcpJson8(cwd);
|
|
4547
|
+
const sessionId = input.session_id || "unknown";
|
|
4548
|
+
const transcriptPath = input.transcript_path || "";
|
|
4549
|
+
const reason = input.reason || "user_exit";
|
|
4550
|
+
const stats = parseTranscriptStats(transcriptPath);
|
|
4551
|
+
await finalizeSession(sessionId, stats, reason);
|
|
4552
|
+
process.exit(0);
|
|
4553
|
+
}
|
|
4554
|
+
var ENABLED13, API_URL10, API_KEY10, WORKSPACE_ID8, isDirectRun13;
|
|
4555
|
+
var init_session_end = __esm({
|
|
4556
|
+
"src/hooks/session-end.ts"() {
|
|
4557
|
+
"use strict";
|
|
4558
|
+
ENABLED13 = process.env.CONTEXTSTREAM_SESSION_END_ENABLED !== "false";
|
|
4559
|
+
API_URL10 = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
|
|
4560
|
+
API_KEY10 = process.env.CONTEXTSTREAM_API_KEY || "";
|
|
4561
|
+
WORKSPACE_ID8 = null;
|
|
4562
|
+
isDirectRun13 = process.argv[1]?.includes("session-end") || process.argv[2] === "session-end";
|
|
4563
|
+
if (isDirectRun13) {
|
|
4564
|
+
runSessionEndHook().catch(() => process.exit(0));
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
});
|
|
4568
|
+
|
|
4569
|
+
// src/hooks/on-save-intent.ts
|
|
4570
|
+
var on_save_intent_exports = {};
|
|
4571
|
+
__export(on_save_intent_exports, {
|
|
4572
|
+
runOnSaveIntentHook: () => runOnSaveIntentHook
|
|
4573
|
+
});
|
|
4574
|
+
function detectsSaveIntent(text) {
|
|
4575
|
+
const hasSaveIntent = SAVE_PATTERNS.some((p) => p.test(text));
|
|
4576
|
+
const isLocalFile = LOCAL_FILE_PATTERNS.some((p) => p.test(text));
|
|
4577
|
+
return { hasSaveIntent, isLocalFile };
|
|
4578
|
+
}
|
|
4579
|
+
async function runOnSaveIntentHook() {
|
|
4580
|
+
if (!ENABLED14) {
|
|
3204
4581
|
process.exit(0);
|
|
3205
4582
|
}
|
|
3206
|
-
|
|
3207
|
-
const
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
if (!hasPythonHooksToUpgrade && !rulesNeedUpdate) {
|
|
4583
|
+
let inputData = "";
|
|
4584
|
+
for await (const chunk of process.stdin) {
|
|
4585
|
+
inputData += chunk;
|
|
4586
|
+
}
|
|
4587
|
+
if (!inputData.trim()) {
|
|
3212
4588
|
process.exit(0);
|
|
3213
4589
|
}
|
|
3214
|
-
|
|
4590
|
+
let input;
|
|
3215
4591
|
try {
|
|
3216
|
-
|
|
3217
|
-
markAsRan();
|
|
4592
|
+
input = JSON.parse(inputData);
|
|
3218
4593
|
} catch {
|
|
4594
|
+
process.exit(0);
|
|
4595
|
+
}
|
|
4596
|
+
let prompt = input.prompt || "";
|
|
4597
|
+
if (!prompt && input.session?.messages) {
|
|
4598
|
+
for (const msg of [...input.session.messages].reverse()) {
|
|
4599
|
+
if (msg.role === "user") {
|
|
4600
|
+
if (typeof msg.content === "string") {
|
|
4601
|
+
prompt = msg.content;
|
|
4602
|
+
} else if (Array.isArray(msg.content)) {
|
|
4603
|
+
for (const block of msg.content) {
|
|
4604
|
+
if (block.type === "text" && block.text) {
|
|
4605
|
+
prompt = block.text;
|
|
4606
|
+
break;
|
|
4607
|
+
}
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
break;
|
|
4611
|
+
}
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
if (!prompt) {
|
|
4615
|
+
process.exit(0);
|
|
4616
|
+
}
|
|
4617
|
+
const { hasSaveIntent, isLocalFile } = detectsSaveIntent(prompt);
|
|
4618
|
+
if (hasSaveIntent || isLocalFile) {
|
|
4619
|
+
console.log(
|
|
4620
|
+
JSON.stringify({
|
|
4621
|
+
hookSpecificOutput: {
|
|
4622
|
+
hookEventName: "UserPromptSubmit",
|
|
4623
|
+
additionalContext: SAVE_GUIDANCE
|
|
4624
|
+
}
|
|
4625
|
+
})
|
|
4626
|
+
);
|
|
3219
4627
|
}
|
|
3220
4628
|
process.exit(0);
|
|
3221
4629
|
}
|
|
3222
|
-
var
|
|
3223
|
-
var
|
|
3224
|
-
"src/hooks/
|
|
4630
|
+
var ENABLED14, SAVE_PATTERNS, LOCAL_FILE_PATTERNS, SAVE_GUIDANCE, isDirectRun14;
|
|
4631
|
+
var init_on_save_intent = __esm({
|
|
4632
|
+
"src/hooks/on-save-intent.ts"() {
|
|
3225
4633
|
"use strict";
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
4634
|
+
ENABLED14 = process.env.CONTEXTSTREAM_SAVE_INTENT_ENABLED !== "false";
|
|
4635
|
+
SAVE_PATTERNS = [
|
|
4636
|
+
// Direct save requests
|
|
4637
|
+
/\b(save|store|record|capture|log|document|write down|note down|keep track)\b.*\b(this|that|it|the)\b/i,
|
|
4638
|
+
/\b(save|store|record|capture|log)\b.*\b(to|in|for)\b.*\b(contextstream|memory|later|reference|future)\b/i,
|
|
4639
|
+
// Document creation
|
|
4640
|
+
/\b(create|make|write|draft)\b.*\b(a|the)\b.*\b(document|doc|note|summary|report|spec|design)\b/i,
|
|
4641
|
+
/\b(document|summarize|write up)\b.*\b(this|that|the|our)\b.*\b(decision|discussion|conversation|meeting|finding)\b/i,
|
|
4642
|
+
// Memory/reference requests
|
|
4643
|
+
/\b(remember|don't forget|keep in mind|note that|important to remember)\b/i,
|
|
4644
|
+
/\bfor\s+(future|later)\s+reference\b/i,
|
|
4645
|
+
/\b(add|put)\s+(this|it|that)\s+(to|in)\s+(memory|notes|docs)\b/i,
|
|
4646
|
+
// Decision tracking
|
|
4647
|
+
/\b(we\s+)?(decided|agreed|concluded|determined)\b.*\b(to|that)\b/i,
|
|
4648
|
+
/\blet('s|s)\s+document\b/i,
|
|
4649
|
+
/\bsave\s+(this|the)\s+(decision|choice|approach)\b/i,
|
|
4650
|
+
// Implementation/design docs
|
|
4651
|
+
/\b(implementation|design|architecture|spec)\s+(doc|document|plan)\b/i,
|
|
4652
|
+
/\bwrite\s+(the|a|an)\s+.*(md|markdown|readme)\b/i
|
|
4653
|
+
];
|
|
4654
|
+
LOCAL_FILE_PATTERNS = [
|
|
4655
|
+
/\b(save|write|create)\s+(it|this|the\s+\w+)\s+(to|in|as)\s+[./~]/i,
|
|
4656
|
+
/\b(save|write)\s+to\s+.*(\.md|\.txt|\.json|docs\/|notes\/)/i,
|
|
4657
|
+
/\bcreate\s+(a|the)\s+file\b/i
|
|
4658
|
+
];
|
|
4659
|
+
SAVE_GUIDANCE = `[CONTEXTSTREAM DOCUMENT STORAGE]
|
|
4660
|
+
The user wants to save/store content. Use ContextStream instead of local files:
|
|
4661
|
+
|
|
4662
|
+
**For decisions/notes:**
|
|
4663
|
+
\`\`\`
|
|
4664
|
+
mcp__contextstream__session(
|
|
4665
|
+
action="capture",
|
|
4666
|
+
event_type="decision|note|insight",
|
|
4667
|
+
title="...",
|
|
4668
|
+
content="...",
|
|
4669
|
+
importance="high|medium|low"
|
|
4670
|
+
)
|
|
4671
|
+
\`\`\`
|
|
4672
|
+
|
|
4673
|
+
**For documents/specs:**
|
|
4674
|
+
\`\`\`
|
|
4675
|
+
mcp__contextstream__docs(
|
|
4676
|
+
action="create",
|
|
4677
|
+
title="...",
|
|
4678
|
+
content="...",
|
|
4679
|
+
doc_type="implementation|design|spec|guide"
|
|
4680
|
+
)
|
|
4681
|
+
\`\`\`
|
|
4682
|
+
|
|
4683
|
+
**For plans:**
|
|
4684
|
+
\`\`\`
|
|
4685
|
+
mcp__contextstream__session(
|
|
4686
|
+
action="capture_plan",
|
|
4687
|
+
title="...",
|
|
4688
|
+
steps=[...]
|
|
4689
|
+
)
|
|
4690
|
+
\`\`\`
|
|
4691
|
+
|
|
4692
|
+
**Why ContextStream?**
|
|
4693
|
+
- Persists across sessions (local files don't)
|
|
4694
|
+
- Searchable and retrievable
|
|
4695
|
+
- Shows up in context automatically
|
|
4696
|
+
- Can be shared with team
|
|
4697
|
+
|
|
4698
|
+
Only save to local files if user explicitly requests a specific file path.
|
|
4699
|
+
[END GUIDANCE]`;
|
|
4700
|
+
isDirectRun14 = process.argv[1]?.includes("on-save-intent") || process.argv[2] === "on-save-intent";
|
|
4701
|
+
if (isDirectRun14) {
|
|
4702
|
+
runOnSaveIntentHook().catch(() => process.exit(0));
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
});
|
|
4706
|
+
|
|
4707
|
+
// src/verify-key.ts
|
|
4708
|
+
var verify_key_exports = {};
|
|
4709
|
+
__export(verify_key_exports, {
|
|
4710
|
+
loadApiKey: () => loadApiKey,
|
|
4711
|
+
maskApiKey: () => maskApiKey2,
|
|
4712
|
+
runVerifyKey: () => runVerifyKey,
|
|
4713
|
+
validateApiKey: () => validateApiKey
|
|
4714
|
+
});
|
|
4715
|
+
import * as fs19 from "node:fs";
|
|
4716
|
+
import * as path20 from "node:path";
|
|
4717
|
+
import { homedir as homedir17 } from "node:os";
|
|
4718
|
+
function maskApiKey2(key) {
|
|
4719
|
+
if (!key || key.length < 10) return "***";
|
|
4720
|
+
const prefix = key.slice(0, 6);
|
|
4721
|
+
const suffix = key.slice(-4);
|
|
4722
|
+
return `${prefix}...${suffix}`;
|
|
4723
|
+
}
|
|
4724
|
+
function extractFromMcpConfig(config) {
|
|
4725
|
+
if (!config.mcpServers) return {};
|
|
4726
|
+
const priorityNames = ["contextstream", "ContextStream", "context-stream"];
|
|
4727
|
+
for (const name of priorityNames) {
|
|
4728
|
+
const server = config.mcpServers[name];
|
|
4729
|
+
if (server?.env?.CONTEXTSTREAM_API_KEY) {
|
|
4730
|
+
return {
|
|
4731
|
+
apiKey: server.env.CONTEXTSTREAM_API_KEY,
|
|
4732
|
+
apiUrl: server.env.CONTEXTSTREAM_API_URL
|
|
4733
|
+
};
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
for (const [, server] of Object.entries(config.mcpServers)) {
|
|
4737
|
+
if (server?.env?.CONTEXTSTREAM_API_KEY) {
|
|
4738
|
+
return {
|
|
4739
|
+
apiKey: server.env.CONTEXTSTREAM_API_KEY,
|
|
4740
|
+
apiUrl: server.env.CONTEXTSTREAM_API_URL
|
|
4741
|
+
};
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4744
|
+
return {};
|
|
4745
|
+
}
|
|
4746
|
+
function getClaudeDesktopConfigPath() {
|
|
4747
|
+
const platform = process.platform;
|
|
4748
|
+
if (platform === "darwin") {
|
|
4749
|
+
return path20.join(homedir17(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
4750
|
+
} else if (platform === "win32") {
|
|
4751
|
+
return path20.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
4752
|
+
} else {
|
|
4753
|
+
return path20.join(homedir17(), ".config", "Claude", "claude_desktop_config.json");
|
|
4754
|
+
}
|
|
4755
|
+
}
|
|
4756
|
+
function loadApiKey() {
|
|
4757
|
+
let apiKey = null;
|
|
4758
|
+
let apiUrl = "https://api.contextstream.io";
|
|
4759
|
+
let source = "none";
|
|
4760
|
+
if (process.env.CONTEXTSTREAM_API_KEY) {
|
|
4761
|
+
apiKey = process.env.CONTEXTSTREAM_API_KEY;
|
|
4762
|
+
source = "environment";
|
|
4763
|
+
if (process.env.CONTEXTSTREAM_API_URL) {
|
|
4764
|
+
apiUrl = process.env.CONTEXTSTREAM_API_URL;
|
|
4765
|
+
}
|
|
4766
|
+
return { apiKey, apiUrl, source };
|
|
4767
|
+
}
|
|
4768
|
+
let searchDir = process.cwd();
|
|
4769
|
+
for (let i = 0; i < 5; i++) {
|
|
4770
|
+
const projectMcpPath = path20.join(searchDir, ".mcp.json");
|
|
4771
|
+
if (fs19.existsSync(projectMcpPath)) {
|
|
4772
|
+
try {
|
|
4773
|
+
const content = fs19.readFileSync(projectMcpPath, "utf-8");
|
|
4774
|
+
const config = JSON.parse(content);
|
|
4775
|
+
const extracted = extractFromMcpConfig(config);
|
|
4776
|
+
if (extracted.apiKey) {
|
|
4777
|
+
apiKey = extracted.apiKey;
|
|
4778
|
+
source = `${projectMcpPath}`;
|
|
4779
|
+
if (extracted.apiUrl) {
|
|
4780
|
+
apiUrl = extracted.apiUrl;
|
|
4781
|
+
}
|
|
4782
|
+
return { apiKey, apiUrl, source };
|
|
4783
|
+
}
|
|
4784
|
+
} catch {
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
const parentDir = path20.dirname(searchDir);
|
|
4788
|
+
if (parentDir === searchDir) break;
|
|
4789
|
+
searchDir = parentDir;
|
|
4790
|
+
}
|
|
4791
|
+
const globalMcpPath = path20.join(homedir17(), ".mcp.json");
|
|
4792
|
+
if (fs19.existsSync(globalMcpPath)) {
|
|
4793
|
+
try {
|
|
4794
|
+
const content = fs19.readFileSync(globalMcpPath, "utf-8");
|
|
4795
|
+
const config = JSON.parse(content);
|
|
4796
|
+
const extracted = extractFromMcpConfig(config);
|
|
4797
|
+
if (extracted.apiKey) {
|
|
4798
|
+
apiKey = extracted.apiKey;
|
|
4799
|
+
source = "~/.mcp.json";
|
|
4800
|
+
if (extracted.apiUrl) {
|
|
4801
|
+
apiUrl = extracted.apiUrl;
|
|
4802
|
+
}
|
|
4803
|
+
return { apiKey, apiUrl, source };
|
|
4804
|
+
}
|
|
4805
|
+
} catch {
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
const cursorPaths = [
|
|
4809
|
+
path20.join(process.cwd(), ".cursor", "mcp.json"),
|
|
4810
|
+
path20.join(homedir17(), ".cursor", "mcp.json")
|
|
4811
|
+
];
|
|
4812
|
+
for (const cursorPath of cursorPaths) {
|
|
4813
|
+
if (fs19.existsSync(cursorPath)) {
|
|
4814
|
+
try {
|
|
4815
|
+
const content = fs19.readFileSync(cursorPath, "utf-8");
|
|
4816
|
+
const config = JSON.parse(content);
|
|
4817
|
+
const extracted = extractFromMcpConfig(config);
|
|
4818
|
+
if (extracted.apiKey) {
|
|
4819
|
+
apiKey = extracted.apiKey;
|
|
4820
|
+
source = cursorPath;
|
|
4821
|
+
if (extracted.apiUrl) {
|
|
4822
|
+
apiUrl = extracted.apiUrl;
|
|
4823
|
+
}
|
|
4824
|
+
return { apiKey, apiUrl, source };
|
|
4825
|
+
}
|
|
4826
|
+
} catch {
|
|
4827
|
+
}
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
const claudeDesktopPath = getClaudeDesktopConfigPath();
|
|
4831
|
+
if (fs19.existsSync(claudeDesktopPath)) {
|
|
4832
|
+
try {
|
|
4833
|
+
const content = fs19.readFileSync(claudeDesktopPath, "utf-8");
|
|
4834
|
+
const config = JSON.parse(content);
|
|
4835
|
+
const extracted = extractFromMcpConfig(config);
|
|
4836
|
+
if (extracted.apiKey) {
|
|
4837
|
+
apiKey = extracted.apiKey;
|
|
4838
|
+
source = claudeDesktopPath;
|
|
4839
|
+
if (extracted.apiUrl) {
|
|
4840
|
+
apiUrl = extracted.apiUrl;
|
|
4841
|
+
}
|
|
4842
|
+
return { apiKey, apiUrl, source };
|
|
4843
|
+
}
|
|
4844
|
+
} catch {
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
const vscodePaths = [
|
|
4848
|
+
path20.join(homedir17(), ".vscode", "mcp.json"),
|
|
4849
|
+
path20.join(homedir17(), ".codeium", "windsurf", "mcp_config.json"),
|
|
4850
|
+
path20.join(homedir17(), ".continue", "config.json")
|
|
4851
|
+
];
|
|
4852
|
+
for (const vsPath of vscodePaths) {
|
|
4853
|
+
if (fs19.existsSync(vsPath)) {
|
|
4854
|
+
try {
|
|
4855
|
+
const content = fs19.readFileSync(vsPath, "utf-8");
|
|
4856
|
+
const config = JSON.parse(content);
|
|
4857
|
+
const extracted = extractFromMcpConfig(config);
|
|
4858
|
+
if (extracted.apiKey) {
|
|
4859
|
+
apiKey = extracted.apiKey;
|
|
4860
|
+
source = vsPath;
|
|
4861
|
+
if (extracted.apiUrl) {
|
|
4862
|
+
apiUrl = extracted.apiUrl;
|
|
4863
|
+
}
|
|
4864
|
+
return { apiKey, apiUrl, source };
|
|
4865
|
+
}
|
|
4866
|
+
} catch {
|
|
4867
|
+
}
|
|
4868
|
+
}
|
|
4869
|
+
}
|
|
4870
|
+
const credentialsPath = path20.join(homedir17(), ".contextstream", "credentials.json");
|
|
4871
|
+
if (fs19.existsSync(credentialsPath)) {
|
|
4872
|
+
try {
|
|
4873
|
+
const content = fs19.readFileSync(credentialsPath, "utf-8");
|
|
4874
|
+
const creds = JSON.parse(content);
|
|
4875
|
+
if (creds.api_key) {
|
|
4876
|
+
apiKey = creds.api_key;
|
|
4877
|
+
source = "~/.contextstream/credentials.json";
|
|
4878
|
+
if (creds.api_url) {
|
|
4879
|
+
apiUrl = creds.api_url;
|
|
4880
|
+
}
|
|
4881
|
+
return { apiKey, apiUrl, source };
|
|
4882
|
+
}
|
|
4883
|
+
} catch {
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
return { apiKey, apiUrl, source };
|
|
4887
|
+
}
|
|
4888
|
+
async function validateApiKey(apiKey, apiUrl) {
|
|
4889
|
+
try {
|
|
4890
|
+
const controller = new AbortController();
|
|
4891
|
+
const timeoutId = setTimeout(() => controller.abort(), 1e4);
|
|
4892
|
+
const response = await fetch(`${apiUrl}/api/v1/auth/me`, {
|
|
4893
|
+
method: "GET",
|
|
4894
|
+
headers: {
|
|
4895
|
+
"X-API-Key": apiKey
|
|
4896
|
+
},
|
|
4897
|
+
signal: controller.signal
|
|
4898
|
+
});
|
|
4899
|
+
clearTimeout(timeoutId);
|
|
4900
|
+
if (response.ok) {
|
|
4901
|
+
const data = await response.json();
|
|
4902
|
+
return {
|
|
4903
|
+
valid: true,
|
|
4904
|
+
masked_key: maskApiKey2(apiKey),
|
|
4905
|
+
email: data.email,
|
|
4906
|
+
name: data.name || data.full_name,
|
|
4907
|
+
plan: data.plan_name || data.plan || "free",
|
|
4908
|
+
workspace_name: data.workspace?.name
|
|
4909
|
+
};
|
|
4910
|
+
} else if (response.status === 401) {
|
|
4911
|
+
return {
|
|
4912
|
+
valid: false,
|
|
4913
|
+
masked_key: maskApiKey2(apiKey),
|
|
4914
|
+
error: "Invalid or expired API key"
|
|
4915
|
+
};
|
|
4916
|
+
} else {
|
|
4917
|
+
return {
|
|
4918
|
+
valid: false,
|
|
4919
|
+
masked_key: maskApiKey2(apiKey),
|
|
4920
|
+
error: `API error: ${response.status}`
|
|
4921
|
+
};
|
|
4922
|
+
}
|
|
4923
|
+
} catch (error) {
|
|
4924
|
+
return {
|
|
4925
|
+
valid: false,
|
|
4926
|
+
masked_key: maskApiKey2(apiKey),
|
|
4927
|
+
error: `Connection error: ${error instanceof Error ? error.message : String(error)}`
|
|
4928
|
+
};
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
async function runVerifyKey(outputJson) {
|
|
4932
|
+
const { apiKey, apiUrl, source } = loadApiKey();
|
|
4933
|
+
if (!apiKey) {
|
|
4934
|
+
const result2 = {
|
|
4935
|
+
valid: false,
|
|
4936
|
+
masked_key: "",
|
|
4937
|
+
error: "No API key found. Run 'contextstream-mcp setup' to configure."
|
|
4938
|
+
};
|
|
4939
|
+
if (outputJson) {
|
|
4940
|
+
console.log(JSON.stringify(result2));
|
|
4941
|
+
} else {
|
|
4942
|
+
console.log("\u274C No API key found");
|
|
4943
|
+
console.log(" Run 'contextstream-mcp setup' to configure your API key.");
|
|
4944
|
+
}
|
|
4945
|
+
return result2;
|
|
4946
|
+
}
|
|
4947
|
+
const result = await validateApiKey(apiKey, apiUrl);
|
|
4948
|
+
if (outputJson) {
|
|
4949
|
+
console.log(JSON.stringify({ ...result, source }));
|
|
4950
|
+
} else {
|
|
4951
|
+
console.log("");
|
|
4952
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
4953
|
+
console.log(" ContextStream API Key");
|
|
4954
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
4955
|
+
console.log("");
|
|
4956
|
+
console.log(` Key: ${result.masked_key}`);
|
|
4957
|
+
console.log(` Source: ${source}`);
|
|
4958
|
+
if (result.valid) {
|
|
4959
|
+
console.log(` Status: \u2713 Valid`);
|
|
4960
|
+
if (result.email) {
|
|
4961
|
+
console.log(` Account: ${result.email}`);
|
|
4962
|
+
}
|
|
4963
|
+
if (result.name) {
|
|
4964
|
+
console.log(` Name: ${result.name}`);
|
|
4965
|
+
}
|
|
4966
|
+
if (result.plan) {
|
|
4967
|
+
console.log(` Plan: ${result.plan}`);
|
|
4968
|
+
}
|
|
4969
|
+
if (result.workspace_name) {
|
|
4970
|
+
console.log(` Workspace: ${result.workspace_name}`);
|
|
4971
|
+
}
|
|
4972
|
+
} else {
|
|
4973
|
+
console.log(` Status: \u2717 Invalid`);
|
|
4974
|
+
console.log(` Error: ${result.error}`);
|
|
3234
4975
|
}
|
|
4976
|
+
console.log("");
|
|
4977
|
+
}
|
|
4978
|
+
return result;
|
|
4979
|
+
}
|
|
4980
|
+
var init_verify_key = __esm({
|
|
4981
|
+
"src/verify-key.ts"() {
|
|
4982
|
+
"use strict";
|
|
3235
4983
|
}
|
|
3236
4984
|
});
|
|
3237
4985
|
|
|
@@ -3717,8 +5465,8 @@ function getErrorMap() {
|
|
|
3717
5465
|
|
|
3718
5466
|
// node_modules/zod/v3/helpers/parseUtil.js
|
|
3719
5467
|
var makeIssue = (params) => {
|
|
3720
|
-
const { data, path:
|
|
3721
|
-
const fullPath = [...
|
|
5468
|
+
const { data, path: path21, errorMaps, issueData } = params;
|
|
5469
|
+
const fullPath = [...path21, ...issueData.path || []];
|
|
3722
5470
|
const fullIssue = {
|
|
3723
5471
|
...issueData,
|
|
3724
5472
|
path: fullPath
|
|
@@ -3834,11 +5582,11 @@ var errorUtil;
|
|
|
3834
5582
|
|
|
3835
5583
|
// node_modules/zod/v3/types.js
|
|
3836
5584
|
var ParseInputLazyPath = class {
|
|
3837
|
-
constructor(parent, value,
|
|
5585
|
+
constructor(parent, value, path21, key) {
|
|
3838
5586
|
this._cachedPath = [];
|
|
3839
5587
|
this.parent = parent;
|
|
3840
5588
|
this.data = value;
|
|
3841
|
-
this._path =
|
|
5589
|
+
this._path = path21;
|
|
3842
5590
|
this._key = key;
|
|
3843
5591
|
}
|
|
3844
5592
|
get path() {
|
|
@@ -7288,6 +9036,9 @@ import { join } from "path";
|
|
|
7288
9036
|
var UPGRADE_COMMAND = "npm install -g @contextstream/mcp-server@latest";
|
|
7289
9037
|
var NPM_LATEST_URL = "https://registry.npmjs.org/@contextstream/mcp-server/latest";
|
|
7290
9038
|
function getVersion() {
|
|
9039
|
+
if (typeof __CONTEXTSTREAM_VERSION__ !== "undefined" && __CONTEXTSTREAM_VERSION__) {
|
|
9040
|
+
return __CONTEXTSTREAM_VERSION__;
|
|
9041
|
+
}
|
|
7291
9042
|
try {
|
|
7292
9043
|
const require2 = createRequire(import.meta.url);
|
|
7293
9044
|
const pkg = require2("../package.json");
|
|
@@ -7571,14 +9322,14 @@ var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([408, 429, 500, 502, 503, 504])
|
|
|
7571
9322
|
var MAX_RETRIES = 3;
|
|
7572
9323
|
var BASE_DELAY = 1e3;
|
|
7573
9324
|
async function sleep(ms) {
|
|
7574
|
-
return new Promise((
|
|
9325
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
7575
9326
|
}
|
|
7576
|
-
async function request(config,
|
|
9327
|
+
async function request(config, path21, options = {}) {
|
|
7577
9328
|
const { apiUrl, userAgent } = config;
|
|
7578
9329
|
const authOverride = getAuthOverride();
|
|
7579
9330
|
const apiKey = authOverride?.apiKey ?? config.apiKey;
|
|
7580
9331
|
const jwt = authOverride?.jwt ?? config.jwt;
|
|
7581
|
-
const apiPath =
|
|
9332
|
+
const apiPath = path21.startsWith("/api/") ? path21 : `/api/v1${path21}`;
|
|
7582
9333
|
const url = `${apiUrl.replace(/\/$/, "")}${apiPath}`;
|
|
7583
9334
|
const maxRetries = options.retries ?? MAX_RETRIES;
|
|
7584
9335
|
const baseDelay = options.retryDelay ?? BASE_DELAY;
|
|
@@ -7724,9 +9475,9 @@ function extractErrorCode(payload) {
|
|
|
7724
9475
|
if (typeof payload.code === "string" && payload.code.trim()) return payload.code.trim();
|
|
7725
9476
|
return null;
|
|
7726
9477
|
}
|
|
7727
|
-
function detectIntegrationProvider(
|
|
7728
|
-
if (/\/github(\/|$)/i.test(
|
|
7729
|
-
if (/\/slack(\/|$)/i.test(
|
|
9478
|
+
function detectIntegrationProvider(path21) {
|
|
9479
|
+
if (/\/github(\/|$)/i.test(path21)) return "github";
|
|
9480
|
+
if (/\/slack(\/|$)/i.test(path21)) return "slack";
|
|
7730
9481
|
return null;
|
|
7731
9482
|
}
|
|
7732
9483
|
function rewriteNotFoundMessage(input) {
|
|
@@ -8379,10 +10130,10 @@ var PROJECT_MARKERS = [
|
|
|
8379
10130
|
];
|
|
8380
10131
|
function isMultiProjectFolder(folderPath) {
|
|
8381
10132
|
try {
|
|
8382
|
-
const
|
|
10133
|
+
const fs20 = __require("fs");
|
|
8383
10134
|
const pathModule = __require("path");
|
|
8384
|
-
const rootHasGit =
|
|
8385
|
-
const entries =
|
|
10135
|
+
const rootHasGit = fs20.existsSync(pathModule.join(folderPath, ".git"));
|
|
10136
|
+
const entries = fs20.readdirSync(folderPath, { withFileTypes: true });
|
|
8386
10137
|
const subdirs = entries.filter(
|
|
8387
10138
|
(e) => e.isDirectory() && !e.name.startsWith(".") && e.name !== "node_modules"
|
|
8388
10139
|
);
|
|
@@ -8390,7 +10141,7 @@ function isMultiProjectFolder(folderPath) {
|
|
|
8390
10141
|
for (const subdir of subdirs) {
|
|
8391
10142
|
const subdirPath = pathModule.join(folderPath, subdir.name);
|
|
8392
10143
|
for (const marker of PROJECT_MARKERS) {
|
|
8393
|
-
if (
|
|
10144
|
+
if (fs20.existsSync(pathModule.join(subdirPath, marker))) {
|
|
8394
10145
|
projectSubdirs.push(subdir.name);
|
|
8395
10146
|
break;
|
|
8396
10147
|
}
|
|
@@ -10457,9 +12208,9 @@ var ContextStreamClient = class {
|
|
|
10457
12208
|
candidateParts.push("## Relevant Code\n");
|
|
10458
12209
|
currentChars += 18;
|
|
10459
12210
|
const codeEntries = code.results.map((c) => {
|
|
10460
|
-
const
|
|
12211
|
+
const path21 = c.file_path || "file";
|
|
10461
12212
|
const content = c.content?.slice(0, 150) || "";
|
|
10462
|
-
return { path:
|
|
12213
|
+
return { path: path21, entry: `\u2022 ${path21}: ${content}...
|
|
10463
12214
|
` };
|
|
10464
12215
|
});
|
|
10465
12216
|
for (const c of codeEntries) {
|
|
@@ -14169,9 +15920,9 @@ function humanizeKey(raw) {
|
|
|
14169
15920
|
const withSpaces = raw.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ");
|
|
14170
15921
|
return withSpaces.toLowerCase();
|
|
14171
15922
|
}
|
|
14172
|
-
function buildParamDescription(key,
|
|
15923
|
+
function buildParamDescription(key, path21) {
|
|
14173
15924
|
const normalized = key in DEFAULT_PARAM_DESCRIPTIONS ? key : key.toLowerCase();
|
|
14174
|
-
const parent =
|
|
15925
|
+
const parent = path21[path21.length - 1];
|
|
14175
15926
|
if (parent === "target") {
|
|
14176
15927
|
if (key === "id") return "Target identifier (module path, function id, etc.).";
|
|
14177
15928
|
if (key === "type") return "Target type (module, file, function, type, variable).";
|
|
@@ -14202,7 +15953,7 @@ function getDescription(schema) {
|
|
|
14202
15953
|
if (def?.description && def.description.trim()) return def.description;
|
|
14203
15954
|
return void 0;
|
|
14204
15955
|
}
|
|
14205
|
-
function applyParamDescriptions(schema,
|
|
15956
|
+
function applyParamDescriptions(schema, path21 = []) {
|
|
14206
15957
|
if (!(schema instanceof external_exports.ZodObject)) {
|
|
14207
15958
|
return schema;
|
|
14208
15959
|
}
|
|
@@ -14213,7 +15964,7 @@ function applyParamDescriptions(schema, path13 = []) {
|
|
|
14213
15964
|
let nextField = field;
|
|
14214
15965
|
const existingDescription = getDescription(field);
|
|
14215
15966
|
if (field instanceof external_exports.ZodObject) {
|
|
14216
|
-
const nested = applyParamDescriptions(field, [...
|
|
15967
|
+
const nested = applyParamDescriptions(field, [...path21, key]);
|
|
14217
15968
|
if (nested !== field) {
|
|
14218
15969
|
nextField = nested;
|
|
14219
15970
|
changed = true;
|
|
@@ -14225,7 +15976,7 @@ function applyParamDescriptions(schema, path13 = []) {
|
|
|
14225
15976
|
changed = true;
|
|
14226
15977
|
}
|
|
14227
15978
|
} else {
|
|
14228
|
-
nextField = nextField.describe(buildParamDescription(key,
|
|
15979
|
+
nextField = nextField.describe(buildParamDescription(key, path21));
|
|
14229
15980
|
changed = true;
|
|
14230
15981
|
}
|
|
14231
15982
|
nextShape[key] = nextField;
|
|
@@ -15145,10 +16896,12 @@ function registerTools(server, client, sessionManager) {
|
|
|
15145
16896
|
function isTeamPlanCached() {
|
|
15146
16897
|
return teamStatus.checked ? teamStatus.isTeamPlan : false;
|
|
15147
16898
|
}
|
|
15148
|
-
|
|
16899
|
+
const INTEGRATION_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
16900
|
+
let integrationStatus = { checked: false, checkedAt: 0, slack: false, github: false, notion: false };
|
|
15149
16901
|
let toolsListChangedNotified = false;
|
|
15150
16902
|
async function checkIntegrationStatus(workspaceId) {
|
|
15151
|
-
|
|
16903
|
+
const cacheAge = Date.now() - integrationStatus.checkedAt;
|
|
16904
|
+
if (integrationStatus.checked && integrationStatus.workspaceId === workspaceId && cacheAge < INTEGRATION_CACHE_TTL_MS) {
|
|
15152
16905
|
return { slack: integrationStatus.slack, github: integrationStatus.github, notion: integrationStatus.notion };
|
|
15153
16906
|
}
|
|
15154
16907
|
if (!workspaceId) {
|
|
@@ -15156,17 +16909,19 @@ function registerTools(server, client, sessionManager) {
|
|
|
15156
16909
|
}
|
|
15157
16910
|
try {
|
|
15158
16911
|
const status = await client.integrationsStatus({ workspace_id: workspaceId });
|
|
16912
|
+
const isConnectedStatus = (s) => s === "connected" || s === "syncing";
|
|
15159
16913
|
const slackConnected = status?.some(
|
|
15160
|
-
(s) => s.provider === "slack" && s.status
|
|
16914
|
+
(s) => s.provider === "slack" && isConnectedStatus(s.status)
|
|
15161
16915
|
) ?? false;
|
|
15162
16916
|
const githubConnected = status?.some(
|
|
15163
|
-
(s) => s.provider === "github" && s.status
|
|
16917
|
+
(s) => s.provider === "github" && isConnectedStatus(s.status)
|
|
15164
16918
|
) ?? false;
|
|
15165
16919
|
const notionConnected = status?.some(
|
|
15166
|
-
(s) => s.provider === "notion" && s.status
|
|
16920
|
+
(s) => s.provider === "notion" && isConnectedStatus(s.status)
|
|
15167
16921
|
) ?? false;
|
|
15168
16922
|
integrationStatus = {
|
|
15169
16923
|
checked: true,
|
|
16924
|
+
checkedAt: Date.now(),
|
|
15170
16925
|
slack: slackConnected,
|
|
15171
16926
|
github: githubConnected,
|
|
15172
16927
|
notion: notionConnected,
|
|
@@ -15185,6 +16940,7 @@ function registerTools(server, client, sessionManager) {
|
|
|
15185
16940
|
const hadNotion = integrationStatus.notion;
|
|
15186
16941
|
integrationStatus = {
|
|
15187
16942
|
checked: true,
|
|
16943
|
+
checkedAt: Date.now(),
|
|
15188
16944
|
slack: status.slack,
|
|
15189
16945
|
github: status.github,
|
|
15190
16946
|
notion: status.notion,
|
|
@@ -19798,14 +21554,15 @@ Use this to verify integrations are healthy and syncing properly.`,
|
|
|
19798
21554
|
}
|
|
19799
21555
|
const result = await client.integrationsStatus({ workspace_id: workspaceId });
|
|
19800
21556
|
if (AUTO_HIDE_INTEGRATIONS) {
|
|
21557
|
+
const isConnectedStatus = (s) => s === "connected" || s === "syncing";
|
|
19801
21558
|
const slackConnected = result?.some(
|
|
19802
|
-
(s) => s.provider === "slack" && s.status
|
|
21559
|
+
(s) => s.provider === "slack" && isConnectedStatus(s.status)
|
|
19803
21560
|
) ?? false;
|
|
19804
21561
|
const githubConnected = result?.some(
|
|
19805
|
-
(s) => s.provider === "github" && s.status
|
|
21562
|
+
(s) => s.provider === "github" && isConnectedStatus(s.status)
|
|
19806
21563
|
) ?? false;
|
|
19807
21564
|
const notionConnected = result?.some(
|
|
19808
|
-
(s) => s.provider === "notion" && s.status
|
|
21565
|
+
(s) => s.provider === "notion" && isConnectedStatus(s.status)
|
|
19809
21566
|
) ?? false;
|
|
19810
21567
|
updateIntegrationStatus({ slack: slackConnected, github: githubConnected, notion: notionConnected }, workspaceId);
|
|
19811
21568
|
}
|
|
@@ -23216,13 +24973,13 @@ Example workflow:
|
|
|
23216
24973
|
);
|
|
23217
24974
|
}
|
|
23218
24975
|
if (input.file_path) {
|
|
23219
|
-
const
|
|
24976
|
+
const fs20 = await import("fs/promises");
|
|
23220
24977
|
const pathModule = await import("path");
|
|
23221
24978
|
const filePath = input.file_path.startsWith("~") ? input.file_path.replace("~", process.env.HOME || "") : input.file_path;
|
|
23222
24979
|
const resolvedPath = pathModule.resolve(filePath);
|
|
23223
24980
|
let fileStats;
|
|
23224
24981
|
try {
|
|
23225
|
-
fileStats = await
|
|
24982
|
+
fileStats = await fs20.stat(resolvedPath);
|
|
23226
24983
|
} catch {
|
|
23227
24984
|
return errorResult(`File not found: ${resolvedPath}`);
|
|
23228
24985
|
}
|
|
@@ -23269,7 +25026,7 @@ Example workflow:
|
|
|
23269
25026
|
mime_type: mimeType,
|
|
23270
25027
|
tags: input.tags
|
|
23271
25028
|
});
|
|
23272
|
-
const fileBuffer = await
|
|
25029
|
+
const fileBuffer = await fs20.readFile(resolvedPath);
|
|
23273
25030
|
const uploadResponse = await fetch(uploadInit.upload_url, {
|
|
23274
25031
|
method: "PUT",
|
|
23275
25032
|
headers: uploadInit.headers,
|
|
@@ -24676,8 +26433,8 @@ var SessionManager = class _SessionManager {
|
|
|
24676
26433
|
/**
|
|
24677
26434
|
* Set the folder path hint (can be passed from tools that know the workspace path)
|
|
24678
26435
|
*/
|
|
24679
|
-
setFolderPath(
|
|
24680
|
-
this.folderPath =
|
|
26436
|
+
setFolderPath(path21) {
|
|
26437
|
+
this.folderPath = path21;
|
|
24681
26438
|
}
|
|
24682
26439
|
/**
|
|
24683
26440
|
* Mark that context_smart has been called in this session.
|
|
@@ -24867,7 +26624,7 @@ var SessionManager = class _SessionManager {
|
|
|
24867
26624
|
}
|
|
24868
26625
|
if (this.ideRoots.length === 0) {
|
|
24869
26626
|
const cwd = process.cwd();
|
|
24870
|
-
const
|
|
26627
|
+
const fs20 = await import("fs");
|
|
24871
26628
|
const projectIndicators = [
|
|
24872
26629
|
".git",
|
|
24873
26630
|
"package.json",
|
|
@@ -24877,7 +26634,7 @@ var SessionManager = class _SessionManager {
|
|
|
24877
26634
|
];
|
|
24878
26635
|
const hasProjectIndicator = projectIndicators.some((f) => {
|
|
24879
26636
|
try {
|
|
24880
|
-
return
|
|
26637
|
+
return fs20.existsSync(`${cwd}/${f}`);
|
|
24881
26638
|
} catch {
|
|
24882
26639
|
return false;
|
|
24883
26640
|
}
|
|
@@ -25454,9 +27211,9 @@ async function runHttpGateway() {
|
|
|
25454
27211
|
}
|
|
25455
27212
|
|
|
25456
27213
|
// src/index.ts
|
|
25457
|
-
import { existsSync as
|
|
25458
|
-
import { homedir as
|
|
25459
|
-
import { join as
|
|
27214
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
27215
|
+
import { homedir as homedir18 } from "os";
|
|
27216
|
+
import { join as join22 } from "path";
|
|
25460
27217
|
|
|
25461
27218
|
// src/setup.ts
|
|
25462
27219
|
import * as fs7 from "node:fs/promises";
|
|
@@ -26286,10 +28043,10 @@ Code: ${device.user_code}`);
|
|
|
26286
28043
|
if (poll && poll.status === "pending") {
|
|
26287
28044
|
const intervalSeconds = typeof poll.interval === "number" ? poll.interval : 5;
|
|
26288
28045
|
const waitMs = Math.max(1, intervalSeconds) * 1e3;
|
|
26289
|
-
await new Promise((
|
|
28046
|
+
await new Promise((resolve15) => setTimeout(resolve15, waitMs));
|
|
26290
28047
|
continue;
|
|
26291
28048
|
}
|
|
26292
|
-
await new Promise((
|
|
28049
|
+
await new Promise((resolve15) => setTimeout(resolve15, 1e3));
|
|
26293
28050
|
}
|
|
26294
28051
|
if (!accessToken) {
|
|
26295
28052
|
throw new Error(
|
|
@@ -26854,12 +28611,12 @@ Applying to ${projects.length} project(s)...`);
|
|
|
26854
28611
|
// src/index.ts
|
|
26855
28612
|
var ENABLE_PROMPTS2 = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
|
|
26856
28613
|
function showFirstRunMessage() {
|
|
26857
|
-
const configDir =
|
|
26858
|
-
const starShownFile =
|
|
26859
|
-
if (
|
|
28614
|
+
const configDir = join22(homedir18(), ".contextstream");
|
|
28615
|
+
const starShownFile = join22(configDir, ".star-shown");
|
|
28616
|
+
if (existsSync16(starShownFile)) {
|
|
26860
28617
|
return;
|
|
26861
28618
|
}
|
|
26862
|
-
if (!
|
|
28619
|
+
if (!existsSync16(configDir)) {
|
|
26863
28620
|
try {
|
|
26864
28621
|
mkdirSync5(configDir, { recursive: true });
|
|
26865
28622
|
} catch {
|
|
@@ -26890,13 +28647,26 @@ Usage:
|
|
|
26890
28647
|
|
|
26891
28648
|
Commands:
|
|
26892
28649
|
setup Interactive onboarding wizard (rules + workspace mapping)
|
|
28650
|
+
verify-key [--json] Verify API key and show account info
|
|
28651
|
+
update-hooks [flags] Update hooks for all editors (Claude, Cursor, Cline, Roo, Kilo)
|
|
28652
|
+
--scope=global Install hooks globally (default)
|
|
28653
|
+
--scope=project, -p Install hooks for current project only
|
|
28654
|
+
--path=/path Specify project path (implies --scope=project)
|
|
26893
28655
|
http Run HTTP MCP gateway (streamable HTTP transport)
|
|
26894
28656
|
hook pre-tool-use PreToolUse hook - blocks discovery tools, redirects to ContextStream
|
|
26895
28657
|
hook user-prompt-submit UserPromptSubmit hook - injects ContextStream rules reminder
|
|
26896
28658
|
hook media-aware Media-aware hook - detects media prompts, injects media tool guidance
|
|
26897
28659
|
hook pre-compact PreCompact hook - saves conversation state before compaction
|
|
28660
|
+
hook post-compact PostCompact hook - restores context after compaction
|
|
26898
28661
|
hook post-write PostToolUse hook - real-time file indexing after Edit/Write
|
|
26899
28662
|
hook auto-rules PostToolUse hook - auto-updates rules when behind (silent)
|
|
28663
|
+
hook on-bash PostToolUse hook - captures bash commands, learns from errors
|
|
28664
|
+
hook on-task PostToolUse hook - tracks Task agent work
|
|
28665
|
+
hook on-read PostToolUse hook - tracks file exploration (Read/Glob/Grep)
|
|
28666
|
+
hook on-web PostToolUse hook - captures web research (WebFetch/WebSearch)
|
|
28667
|
+
hook session-init SessionStart hook - full context injection on session start
|
|
28668
|
+
hook session-end Stop hook - finalizes session, saves state
|
|
28669
|
+
hook on-save-intent UserPromptSubmit hook - redirects doc saves to ContextStream
|
|
26900
28670
|
|
|
26901
28671
|
Environment variables:
|
|
26902
28672
|
CONTEXTSTREAM_API_URL Base API URL (e.g. https://api.contextstream.io)
|
|
@@ -27005,12 +28775,90 @@ async function main() {
|
|
|
27005
28775
|
await runAutoRulesHook2();
|
|
27006
28776
|
return;
|
|
27007
28777
|
}
|
|
28778
|
+
case "post-compact": {
|
|
28779
|
+
const { runPostCompactHook: runPostCompactHook2 } = await Promise.resolve().then(() => (init_post_compact(), post_compact_exports));
|
|
28780
|
+
await runPostCompactHook2();
|
|
28781
|
+
return;
|
|
28782
|
+
}
|
|
28783
|
+
case "on-bash": {
|
|
28784
|
+
const { runOnBashHook: runOnBashHook2 } = await Promise.resolve().then(() => (init_on_bash(), on_bash_exports));
|
|
28785
|
+
await runOnBashHook2();
|
|
28786
|
+
return;
|
|
28787
|
+
}
|
|
28788
|
+
case "on-task": {
|
|
28789
|
+
const { runOnTaskHook: runOnTaskHook2 } = await Promise.resolve().then(() => (init_on_task(), on_task_exports));
|
|
28790
|
+
await runOnTaskHook2();
|
|
28791
|
+
return;
|
|
28792
|
+
}
|
|
28793
|
+
case "on-read": {
|
|
28794
|
+
const { runOnReadHook: runOnReadHook2 } = await Promise.resolve().then(() => (init_on_read(), on_read_exports));
|
|
28795
|
+
await runOnReadHook2();
|
|
28796
|
+
return;
|
|
28797
|
+
}
|
|
28798
|
+
case "on-web": {
|
|
28799
|
+
const { runOnWebHook: runOnWebHook2 } = await Promise.resolve().then(() => (init_on_web(), on_web_exports));
|
|
28800
|
+
await runOnWebHook2();
|
|
28801
|
+
return;
|
|
28802
|
+
}
|
|
28803
|
+
case "session-init": {
|
|
28804
|
+
const { runSessionInitHook: runSessionInitHook2 } = await Promise.resolve().then(() => (init_session_init(), session_init_exports));
|
|
28805
|
+
await runSessionInitHook2();
|
|
28806
|
+
return;
|
|
28807
|
+
}
|
|
28808
|
+
case "session-end": {
|
|
28809
|
+
const { runSessionEndHook: runSessionEndHook2 } = await Promise.resolve().then(() => (init_session_end(), session_end_exports));
|
|
28810
|
+
await runSessionEndHook2();
|
|
28811
|
+
return;
|
|
28812
|
+
}
|
|
28813
|
+
case "on-save-intent": {
|
|
28814
|
+
const { runOnSaveIntentHook: runOnSaveIntentHook2 } = await Promise.resolve().then(() => (init_on_save_intent(), on_save_intent_exports));
|
|
28815
|
+
await runOnSaveIntentHook2();
|
|
28816
|
+
return;
|
|
28817
|
+
}
|
|
27008
28818
|
default:
|
|
27009
28819
|
console.error(`Unknown hook: ${hookName}`);
|
|
27010
|
-
console.error("Available hooks: pre-tool-use, user-prompt-submit, media-aware, pre-compact, post-write, auto-rules");
|
|
28820
|
+
console.error("Available hooks: pre-tool-use, user-prompt-submit, media-aware, pre-compact, post-compact, post-write, auto-rules, on-bash, on-task, on-read, on-web, session-init, session-end, on-save-intent");
|
|
27011
28821
|
process.exit(1);
|
|
27012
28822
|
}
|
|
27013
28823
|
}
|
|
28824
|
+
if (args[0] === "verify-key") {
|
|
28825
|
+
const { runVerifyKey: runVerifyKey2 } = await Promise.resolve().then(() => (init_verify_key(), verify_key_exports));
|
|
28826
|
+
const outputJson = args.includes("--json");
|
|
28827
|
+
const result = await runVerifyKey2(outputJson);
|
|
28828
|
+
process.exit(result.valid ? 0 : 1);
|
|
28829
|
+
}
|
|
28830
|
+
if (args[0] === "update-hooks") {
|
|
28831
|
+
const { installAllEditorHooks: installAllEditorHooks2 } = await Promise.resolve().then(() => (init_hooks_config(), hooks_config_exports));
|
|
28832
|
+
let scope = "global";
|
|
28833
|
+
let projectPath;
|
|
28834
|
+
for (const arg of args.slice(1)) {
|
|
28835
|
+
if (arg === "--scope=project" || arg === "-p") {
|
|
28836
|
+
scope = "project";
|
|
28837
|
+
projectPath = projectPath || process.cwd();
|
|
28838
|
+
} else if (arg === "--scope=global" || arg === "-g") {
|
|
28839
|
+
scope = "global";
|
|
28840
|
+
} else if (arg.startsWith("--path=")) {
|
|
28841
|
+
projectPath = arg.replace("--path=", "");
|
|
28842
|
+
scope = "project";
|
|
28843
|
+
}
|
|
28844
|
+
}
|
|
28845
|
+
const scopeLabel = scope === "project" ? `project (${projectPath || process.cwd()})` : "global";
|
|
28846
|
+
console.error(`Updating hooks for all editors (${scopeLabel})...`);
|
|
28847
|
+
try {
|
|
28848
|
+
const results = await installAllEditorHooks2({
|
|
28849
|
+
scope,
|
|
28850
|
+
projectPath: scope === "project" ? projectPath || process.cwd() : void 0
|
|
28851
|
+
});
|
|
28852
|
+
for (const result of results) {
|
|
28853
|
+
console.error(`\u2713 ${result.editor}: ${result.installed.length} hooks installed`);
|
|
28854
|
+
}
|
|
28855
|
+
console.error("\u2713 Hooks updated successfully");
|
|
28856
|
+
} catch (error) {
|
|
28857
|
+
console.error("Failed to update hooks:", error);
|
|
28858
|
+
process.exit(1);
|
|
28859
|
+
}
|
|
28860
|
+
return;
|
|
28861
|
+
}
|
|
27014
28862
|
if (!process.env.CONTEXTSTREAM_API_KEY && !process.env.CONTEXTSTREAM_JWT) {
|
|
27015
28863
|
const saved = await readSavedCredentials();
|
|
27016
28864
|
if (saved) {
|