@contextstream/mcp-server 0.4.71 → 0.4.74
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 +4 -0
- package/dist/index.js +1020 -216
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1109,6 +1109,7 @@ async function readFilesFromDirectory(rootPath, options = {}) {
|
|
|
1109
1109
|
} catch {
|
|
1110
1110
|
return;
|
|
1111
1111
|
}
|
|
1112
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
1112
1113
|
for (const entry of entries) {
|
|
1113
1114
|
if (files.length >= maxFiles) break;
|
|
1114
1115
|
const fullPath = path2.join(dir, entry.name);
|
|
@@ -1168,6 +1169,7 @@ async function* readAllFilesInBatches(rootPath, options = {}) {
|
|
|
1168
1169
|
} catch {
|
|
1169
1170
|
return;
|
|
1170
1171
|
}
|
|
1172
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
1171
1173
|
for (const entry of entries) {
|
|
1172
1174
|
const fullPath = path2.join(dir, entry.name);
|
|
1173
1175
|
const relPath = path2.join(relativePath, entry.name);
|
|
@@ -1254,6 +1256,7 @@ async function* readChangedFilesInBatches(rootPath, sinceTimestamp, options = {}
|
|
|
1254
1256
|
} catch {
|
|
1255
1257
|
return;
|
|
1256
1258
|
}
|
|
1259
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
1257
1260
|
for (const entry of entries) {
|
|
1258
1261
|
const fullPath = path2.join(dir, entry.name);
|
|
1259
1262
|
const relPath = path2.join(relativePath, entry.name);
|
|
@@ -1344,6 +1347,7 @@ async function countIndexableFiles(rootPath, options = {}) {
|
|
|
1344
1347
|
} catch {
|
|
1345
1348
|
return;
|
|
1346
1349
|
}
|
|
1350
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
1347
1351
|
for (const entry of entries) {
|
|
1348
1352
|
if (count >= maxFiles) {
|
|
1349
1353
|
stopped = true;
|
|
@@ -4896,7 +4900,7 @@ __export(post_write_exports, {
|
|
|
4896
4900
|
});
|
|
4897
4901
|
import * as fs9 from "node:fs";
|
|
4898
4902
|
import * as path10 from "node:path";
|
|
4899
|
-
import { homedir as
|
|
4903
|
+
import { homedir as homedir9 } from "node:os";
|
|
4900
4904
|
function extractFilePath(input) {
|
|
4901
4905
|
if (input.tool_input) {
|
|
4902
4906
|
const filePath = input.tool_input.file_path || input.tool_input.notebook_path || input.tool_input.path;
|
|
@@ -4966,7 +4970,7 @@ function loadApiConfig(startDir) {
|
|
|
4966
4970
|
currentDir = parentDir;
|
|
4967
4971
|
}
|
|
4968
4972
|
if (!apiKey) {
|
|
4969
|
-
const homeMcpPath = path10.join(
|
|
4973
|
+
const homeMcpPath = path10.join(homedir9(), ".mcp.json");
|
|
4970
4974
|
if (fs9.existsSync(homeMcpPath)) {
|
|
4971
4975
|
try {
|
|
4972
4976
|
const content = fs9.readFileSync(homeMcpPath, "utf-8");
|
|
@@ -5246,7 +5250,7 @@ var init_post_write = __esm({
|
|
|
5246
5250
|
// src/hooks/common.ts
|
|
5247
5251
|
import * as fs10 from "node:fs";
|
|
5248
5252
|
import * as path11 from "node:path";
|
|
5249
|
-
import { homedir as
|
|
5253
|
+
import { homedir as homedir10 } from "node:os";
|
|
5250
5254
|
function readHookInput() {
|
|
5251
5255
|
try {
|
|
5252
5256
|
return JSON.parse(fs10.readFileSync(0, "utf8"));
|
|
@@ -5311,7 +5315,7 @@ function loadHookConfig(cwd) {
|
|
|
5311
5315
|
searchDir = parentDir;
|
|
5312
5316
|
}
|
|
5313
5317
|
if (!apiKey && !jwt) {
|
|
5314
|
-
const homeMcpPath = path11.join(
|
|
5318
|
+
const homeMcpPath = path11.join(homedir10(), ".mcp.json");
|
|
5315
5319
|
if (fs10.existsSync(homeMcpPath)) {
|
|
5316
5320
|
try {
|
|
5317
5321
|
const config = JSON.parse(fs10.readFileSync(homeMcpPath, "utf8"));
|
|
@@ -5476,7 +5480,7 @@ __export(post_tool_use_failure_exports, {
|
|
|
5476
5480
|
});
|
|
5477
5481
|
import * as fs11 from "node:fs";
|
|
5478
5482
|
import * as path12 from "node:path";
|
|
5479
|
-
import { homedir as
|
|
5483
|
+
import { homedir as homedir11 } from "node:os";
|
|
5480
5484
|
function extractErrorText(input) {
|
|
5481
5485
|
return typeof input.error === "string" && input.error || typeof input.tool_error === "string" && input.tool_error || typeof input.stderr === "string" && input.stderr || "Tool execution failed";
|
|
5482
5486
|
}
|
|
@@ -5546,7 +5550,7 @@ var init_post_tool_use_failure = __esm({
|
|
|
5546
5550
|
"src/hooks/post-tool-use-failure.ts"() {
|
|
5547
5551
|
"use strict";
|
|
5548
5552
|
init_common();
|
|
5549
|
-
FAILURE_COUNTERS_FILE = path12.join(
|
|
5553
|
+
FAILURE_COUNTERS_FILE = path12.join(homedir11(), ".contextstream", "hook-failure-counts.json");
|
|
5550
5554
|
isDirectRun2 = process.argv[1]?.includes("post-tool-use-failure") || process.argv[2] === "post-tool-use-failure";
|
|
5551
5555
|
if (isDirectRun2) {
|
|
5552
5556
|
runPostToolUseFailureHook().catch(() => process.exit(0));
|
|
@@ -6003,7 +6007,7 @@ var init_teammate_idle = __esm({
|
|
|
6003
6007
|
// src/hooks/prompt-state.ts
|
|
6004
6008
|
import * as fs13 from "node:fs";
|
|
6005
6009
|
import * as path13 from "node:path";
|
|
6006
|
-
import { homedir as
|
|
6010
|
+
import { homedir as homedir12 } from "node:os";
|
|
6007
6011
|
function defaultState() {
|
|
6008
6012
|
return { workspaces: {} };
|
|
6009
6013
|
}
|
|
@@ -6205,7 +6209,7 @@ var STATE_PATH;
|
|
|
6205
6209
|
var init_prompt_state = __esm({
|
|
6206
6210
|
"src/hooks/prompt-state.ts"() {
|
|
6207
6211
|
"use strict";
|
|
6208
|
-
STATE_PATH = path13.join(
|
|
6212
|
+
STATE_PATH = path13.join(homedir12(), ".contextstream", "prompt-state.json");
|
|
6209
6213
|
}
|
|
6210
6214
|
});
|
|
6211
6215
|
|
|
@@ -6216,7 +6220,7 @@ __export(pre_tool_use_exports, {
|
|
|
6216
6220
|
});
|
|
6217
6221
|
import * as fs14 from "node:fs";
|
|
6218
6222
|
import * as path14 from "node:path";
|
|
6219
|
-
import { homedir as
|
|
6223
|
+
import { homedir as homedir13 } from "node:os";
|
|
6220
6224
|
function isDiscoveryGlob(pattern) {
|
|
6221
6225
|
const patternLower = pattern.toLowerCase();
|
|
6222
6226
|
for (const p of DISCOVERY_PATTERNS) {
|
|
@@ -6642,7 +6646,7 @@ var init_pre_tool_use = __esm({
|
|
|
6642
6646
|
"use strict";
|
|
6643
6647
|
init_prompt_state();
|
|
6644
6648
|
ENABLED2 = process.env.CONTEXTSTREAM_HOOK_ENABLED !== "false";
|
|
6645
|
-
INDEX_STATUS_FILE = path14.join(
|
|
6649
|
+
INDEX_STATUS_FILE = path14.join(homedir13(), ".contextstream", "indexed-projects.json");
|
|
6646
6650
|
DEBUG_FILE = "/tmp/pretooluse-hook-debug.log";
|
|
6647
6651
|
STALE_THRESHOLD_DAYS = 7;
|
|
6648
6652
|
CONTEXT_FRESHNESS_SECONDS = 120;
|
|
@@ -6664,7 +6668,7 @@ __export(user_prompt_submit_exports, {
|
|
|
6664
6668
|
});
|
|
6665
6669
|
import * as fs15 from "node:fs";
|
|
6666
6670
|
import * as path15 from "node:path";
|
|
6667
|
-
import { homedir as
|
|
6671
|
+
import { homedir as homedir14 } from "node:os";
|
|
6668
6672
|
function loadConfigFromMcpJson(cwd) {
|
|
6669
6673
|
let searchDir = path15.resolve(cwd);
|
|
6670
6674
|
for (let i = 0; i < 5; i++) {
|
|
@@ -6709,7 +6713,7 @@ function loadConfigFromMcpJson(cwd) {
|
|
|
6709
6713
|
searchDir = parentDir;
|
|
6710
6714
|
}
|
|
6711
6715
|
if (!API_KEY2) {
|
|
6712
|
-
const homeMcpPath = path15.join(
|
|
6716
|
+
const homeMcpPath = path15.join(homedir14(), ".mcp.json");
|
|
6713
6717
|
if (fs15.existsSync(homeMcpPath)) {
|
|
6714
6718
|
try {
|
|
6715
6719
|
const content = fs15.readFileSync(homeMcpPath, "utf-8");
|
|
@@ -7271,7 +7275,7 @@ __export(pre_compact_exports, {
|
|
|
7271
7275
|
});
|
|
7272
7276
|
import * as fs16 from "node:fs";
|
|
7273
7277
|
import * as path16 from "node:path";
|
|
7274
|
-
import { homedir as
|
|
7278
|
+
import { homedir as homedir15 } from "node:os";
|
|
7275
7279
|
function loadConfigFromMcpJson2(cwd) {
|
|
7276
7280
|
let searchDir = path16.resolve(cwd);
|
|
7277
7281
|
for (let i = 0; i < 5; i++) {
|
|
@@ -7310,7 +7314,7 @@ function loadConfigFromMcpJson2(cwd) {
|
|
|
7310
7314
|
searchDir = parentDir;
|
|
7311
7315
|
}
|
|
7312
7316
|
if (!API_KEY3) {
|
|
7313
|
-
const homeMcpPath = path16.join(
|
|
7317
|
+
const homeMcpPath = path16.join(homedir15(), ".mcp.json");
|
|
7314
7318
|
if (fs16.existsSync(homeMcpPath)) {
|
|
7315
7319
|
try {
|
|
7316
7320
|
const content = fs16.readFileSync(homeMcpPath, "utf-8");
|
|
@@ -7594,7 +7598,7 @@ __export(post_compact_exports, {
|
|
|
7594
7598
|
});
|
|
7595
7599
|
import * as fs17 from "node:fs";
|
|
7596
7600
|
import * as path17 from "node:path";
|
|
7597
|
-
import { homedir as
|
|
7601
|
+
import { homedir as homedir16 } from "node:os";
|
|
7598
7602
|
function loadConfigFromMcpJson3(cwd) {
|
|
7599
7603
|
let searchDir = path17.resolve(cwd);
|
|
7600
7604
|
for (let i = 0; i < 5; i++) {
|
|
@@ -7633,7 +7637,7 @@ function loadConfigFromMcpJson3(cwd) {
|
|
|
7633
7637
|
searchDir = parentDir;
|
|
7634
7638
|
}
|
|
7635
7639
|
if (!API_KEY4) {
|
|
7636
|
-
const homeMcpPath = path17.join(
|
|
7640
|
+
const homeMcpPath = path17.join(homedir16(), ".mcp.json");
|
|
7637
7641
|
if (fs17.existsSync(homeMcpPath)) {
|
|
7638
7642
|
try {
|
|
7639
7643
|
const content = fs17.readFileSync(homeMcpPath, "utf-8");
|
|
@@ -7772,7 +7776,7 @@ __export(session_init_exports, {
|
|
|
7772
7776
|
});
|
|
7773
7777
|
import * as fs18 from "node:fs";
|
|
7774
7778
|
import * as path18 from "node:path";
|
|
7775
|
-
import { homedir as
|
|
7779
|
+
import { homedir as homedir17 } from "node:os";
|
|
7776
7780
|
function loadConfigFromMcpJson4(cwd) {
|
|
7777
7781
|
let searchDir = path18.resolve(cwd);
|
|
7778
7782
|
for (let i = 0; i < 5; i++) {
|
|
@@ -7817,7 +7821,7 @@ function loadConfigFromMcpJson4(cwd) {
|
|
|
7817
7821
|
searchDir = parentDir;
|
|
7818
7822
|
}
|
|
7819
7823
|
if (!API_KEY5) {
|
|
7820
|
-
const homeMcpPath = path18.join(
|
|
7824
|
+
const homeMcpPath = path18.join(homedir17(), ".mcp.json");
|
|
7821
7825
|
if (fs18.existsSync(homeMcpPath)) {
|
|
7822
7826
|
try {
|
|
7823
7827
|
const content = fs18.readFileSync(homeMcpPath, "utf-8");
|
|
@@ -8076,7 +8080,7 @@ __export(session_end_exports, {
|
|
|
8076
8080
|
});
|
|
8077
8081
|
import * as fs19 from "node:fs";
|
|
8078
8082
|
import * as path19 from "node:path";
|
|
8079
|
-
import { homedir as
|
|
8083
|
+
import { homedir as homedir18 } from "node:os";
|
|
8080
8084
|
function loadConfigFromMcpJson5(cwd) {
|
|
8081
8085
|
let searchDir = path19.resolve(cwd);
|
|
8082
8086
|
for (let i = 0; i < 5; i++) {
|
|
@@ -8118,7 +8122,7 @@ function loadConfigFromMcpJson5(cwd) {
|
|
|
8118
8122
|
searchDir = parentDir;
|
|
8119
8123
|
}
|
|
8120
8124
|
if (!API_KEY6) {
|
|
8121
|
-
const homeMcpPath = path19.join(
|
|
8125
|
+
const homeMcpPath = path19.join(homedir18(), ".mcp.json");
|
|
8122
8126
|
if (fs19.existsSync(homeMcpPath)) {
|
|
8123
8127
|
try {
|
|
8124
8128
|
const content = fs19.readFileSync(homeMcpPath, "utf-8");
|
|
@@ -8508,7 +8512,7 @@ __export(verify_key_exports, {
|
|
|
8508
8512
|
});
|
|
8509
8513
|
import * as fs20 from "node:fs";
|
|
8510
8514
|
import * as path20 from "node:path";
|
|
8511
|
-
import { homedir as
|
|
8515
|
+
import { homedir as homedir19 } from "node:os";
|
|
8512
8516
|
function maskApiKey2(key) {
|
|
8513
8517
|
if (!key || key.length < 8) return "***";
|
|
8514
8518
|
const prefixMatch = key.match(/^([a-z]{2,3}_)/i);
|
|
@@ -8541,11 +8545,11 @@ function extractFromMcpConfig(config) {
|
|
|
8541
8545
|
function getClaudeDesktopConfigPath() {
|
|
8542
8546
|
const platform2 = process.platform;
|
|
8543
8547
|
if (platform2 === "darwin") {
|
|
8544
|
-
return path20.join(
|
|
8548
|
+
return path20.join(homedir19(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
8545
8549
|
} else if (platform2 === "win32") {
|
|
8546
8550
|
return path20.join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
8547
8551
|
} else {
|
|
8548
|
-
return path20.join(
|
|
8552
|
+
return path20.join(homedir19(), ".config", "Claude", "claude_desktop_config.json");
|
|
8549
8553
|
}
|
|
8550
8554
|
}
|
|
8551
8555
|
function loadApiKey() {
|
|
@@ -8583,7 +8587,7 @@ function loadApiKey() {
|
|
|
8583
8587
|
if (parentDir === searchDir) break;
|
|
8584
8588
|
searchDir = parentDir;
|
|
8585
8589
|
}
|
|
8586
|
-
const globalMcpPath = path20.join(
|
|
8590
|
+
const globalMcpPath = path20.join(homedir19(), ".mcp.json");
|
|
8587
8591
|
if (fs20.existsSync(globalMcpPath)) {
|
|
8588
8592
|
try {
|
|
8589
8593
|
const content = fs20.readFileSync(globalMcpPath, "utf-8");
|
|
@@ -8602,7 +8606,7 @@ function loadApiKey() {
|
|
|
8602
8606
|
}
|
|
8603
8607
|
const cursorPaths = [
|
|
8604
8608
|
path20.join(process.cwd(), ".cursor", "mcp.json"),
|
|
8605
|
-
path20.join(
|
|
8609
|
+
path20.join(homedir19(), ".cursor", "mcp.json")
|
|
8606
8610
|
];
|
|
8607
8611
|
for (const cursorPath of cursorPaths) {
|
|
8608
8612
|
if (fs20.existsSync(cursorPath)) {
|
|
@@ -8640,9 +8644,9 @@ function loadApiKey() {
|
|
|
8640
8644
|
}
|
|
8641
8645
|
}
|
|
8642
8646
|
const vscodePaths = [
|
|
8643
|
-
path20.join(
|
|
8644
|
-
path20.join(
|
|
8645
|
-
path20.join(
|
|
8647
|
+
path20.join(homedir19(), ".vscode", "mcp.json"),
|
|
8648
|
+
path20.join(homedir19(), ".codeium", "windsurf", "mcp_config.json"),
|
|
8649
|
+
path20.join(homedir19(), ".continue", "config.json")
|
|
8646
8650
|
];
|
|
8647
8651
|
for (const vsPath of vscodePaths) {
|
|
8648
8652
|
if (fs20.existsSync(vsPath)) {
|
|
@@ -8662,7 +8666,7 @@ function loadApiKey() {
|
|
|
8662
8666
|
}
|
|
8663
8667
|
}
|
|
8664
8668
|
}
|
|
8665
|
-
const credentialsPath = path20.join(
|
|
8669
|
+
const credentialsPath = path20.join(homedir19(), ".contextstream", "credentials.json");
|
|
8666
8670
|
if (fs20.existsSync(credentialsPath)) {
|
|
8667
8671
|
try {
|
|
8668
8672
|
const content = fs20.readFileSync(credentialsPath, "utf-8");
|
|
@@ -12888,6 +12892,7 @@ function loadConfig() {
|
|
|
12888
12892
|
// src/client.ts
|
|
12889
12893
|
import { randomUUID } from "node:crypto";
|
|
12890
12894
|
import * as path5 from "node:path";
|
|
12895
|
+
import { homedir as homedir4 } from "node:os";
|
|
12891
12896
|
|
|
12892
12897
|
// src/auth-context.ts
|
|
12893
12898
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -13476,6 +13481,59 @@ function isDecisionResult(item) {
|
|
|
13476
13481
|
if (tags.includes("decision")) return true;
|
|
13477
13482
|
return false;
|
|
13478
13483
|
}
|
|
13484
|
+
var WIRE_CODE_TO_KIND = {
|
|
13485
|
+
W: "rule",
|
|
13486
|
+
P: "rule",
|
|
13487
|
+
L: "lesson",
|
|
13488
|
+
D: "decision",
|
|
13489
|
+
M: "memory",
|
|
13490
|
+
T: "memory",
|
|
13491
|
+
VC: "vcs",
|
|
13492
|
+
PR: "preference",
|
|
13493
|
+
SK: "skill",
|
|
13494
|
+
TN: "transcript_snapshot",
|
|
13495
|
+
C: "code",
|
|
13496
|
+
F: "flash",
|
|
13497
|
+
G: "graph",
|
|
13498
|
+
I: "instruction",
|
|
13499
|
+
TS: "tool_suggestion",
|
|
13500
|
+
WA: "warning",
|
|
13501
|
+
SY: "synthesis",
|
|
13502
|
+
PK: "pack",
|
|
13503
|
+
SR: "suggested_rule",
|
|
13504
|
+
KN: "knowledge_node"
|
|
13505
|
+
};
|
|
13506
|
+
var KIND_DEFAULT_PRECEDENCE = {
|
|
13507
|
+
rule: "always",
|
|
13508
|
+
lesson: "critical",
|
|
13509
|
+
decision: "high",
|
|
13510
|
+
preference: "high",
|
|
13511
|
+
skill: "high",
|
|
13512
|
+
memory: "normal",
|
|
13513
|
+
knowledge_node: "normal",
|
|
13514
|
+
code: "normal",
|
|
13515
|
+
flash: "normal",
|
|
13516
|
+
instruction: "normal",
|
|
13517
|
+
tool_suggestion: "normal",
|
|
13518
|
+
warning: "normal",
|
|
13519
|
+
synthesis: "normal",
|
|
13520
|
+
pack: "normal",
|
|
13521
|
+
suggested_rule: "normal",
|
|
13522
|
+
vcs: "normal",
|
|
13523
|
+
transcript_snapshot: "normal",
|
|
13524
|
+
graph: "low",
|
|
13525
|
+
unknown: "low"
|
|
13526
|
+
};
|
|
13527
|
+
function resolveItemKind(item) {
|
|
13528
|
+
if (item.item_type) {
|
|
13529
|
+
const lower = item.item_type.toLowerCase();
|
|
13530
|
+
if (lower in KIND_DEFAULT_PRECEDENCE) return lower;
|
|
13531
|
+
}
|
|
13532
|
+
return WIRE_CODE_TO_KIND[item.typ] || "unknown";
|
|
13533
|
+
}
|
|
13534
|
+
function filterItemsByKind(items, kind) {
|
|
13535
|
+
return items.filter((i) => resolveItemKind(i) === kind).sort((a, b) => b.score - a.score);
|
|
13536
|
+
}
|
|
13479
13537
|
function pickString(value) {
|
|
13480
13538
|
if (typeof value !== "string") return null;
|
|
13481
13539
|
const trimmed = value.trim();
|
|
@@ -13545,6 +13603,77 @@ function isMultiProjectFolder(folderPath) {
|
|
|
13545
13603
|
return { isMultiProject: false, projectCount: 0, projectNames: [] };
|
|
13546
13604
|
}
|
|
13547
13605
|
}
|
|
13606
|
+
var INDEX_KEEPER_INCREMENTAL_INTERVAL_MS = 1e4;
|
|
13607
|
+
var INDEX_KEEPER_AGING_INTERVAL_MS = 3e5;
|
|
13608
|
+
var INDEX_KEEPER_STALE_INTERVAL_MS = 6e4;
|
|
13609
|
+
var INDEX_KEEPER_AGING_THRESHOLD_HOURS = 4;
|
|
13610
|
+
var INDEX_KEEPER_AGING_MAX_FILES = 2e4;
|
|
13611
|
+
var IndexKeeper = class {
|
|
13612
|
+
constructor() {
|
|
13613
|
+
this.lastIncremental = 0;
|
|
13614
|
+
this.lastAging = 0;
|
|
13615
|
+
this.lastStale = 0;
|
|
13616
|
+
this.client = null;
|
|
13617
|
+
}
|
|
13618
|
+
attach(client) {
|
|
13619
|
+
this.client = client;
|
|
13620
|
+
}
|
|
13621
|
+
shouldFire(lastMs, intervalMs) {
|
|
13622
|
+
return Date.now() - lastMs >= intervalMs;
|
|
13623
|
+
}
|
|
13624
|
+
async tick(projectId, folderPath) {
|
|
13625
|
+
if (!this.client || !projectId || !folderPath) return;
|
|
13626
|
+
try {
|
|
13627
|
+
await this.checkIncremental(projectId, folderPath);
|
|
13628
|
+
await this.checkAgingRefresh(projectId, folderPath);
|
|
13629
|
+
} catch {
|
|
13630
|
+
}
|
|
13631
|
+
}
|
|
13632
|
+
async checkIncremental(projectId, folderPath) {
|
|
13633
|
+
if (!this.shouldFire(this.lastIncremental, INDEX_KEEPER_INCREMENTAL_INTERVAL_MS)) return;
|
|
13634
|
+
this.lastIncremental = Date.now();
|
|
13635
|
+
if (!this.client) return;
|
|
13636
|
+
try {
|
|
13637
|
+
await this.client.checkAndIndexChangedFiles();
|
|
13638
|
+
} catch {
|
|
13639
|
+
}
|
|
13640
|
+
}
|
|
13641
|
+
async checkAgingRefresh(projectId, folderPath) {
|
|
13642
|
+
if (!this.shouldFire(this.lastAging, INDEX_KEEPER_AGING_INTERVAL_MS)) return;
|
|
13643
|
+
this.lastAging = Date.now();
|
|
13644
|
+
if (!this.client) return;
|
|
13645
|
+
const ageHours = this.client.localIndexAgeHours(folderPath);
|
|
13646
|
+
if (ageHours === null || ageHours < INDEX_KEEPER_AGING_THRESHOLD_HOURS) return;
|
|
13647
|
+
console.error(`[ContextStream] IndexKeeper: aging refresh for ${folderPath} (${ageHours}h old)`);
|
|
13648
|
+
try {
|
|
13649
|
+
await this.client.ingestLocal({
|
|
13650
|
+
projectId,
|
|
13651
|
+
rootPath: folderPath,
|
|
13652
|
+
maxFiles: INDEX_KEEPER_AGING_MAX_FILES
|
|
13653
|
+
});
|
|
13654
|
+
} catch (e) {
|
|
13655
|
+
console.error(`[ContextStream] IndexKeeper aging refresh failed:`, e);
|
|
13656
|
+
}
|
|
13657
|
+
}
|
|
13658
|
+
maybeTriggerStaleReingest(params) {
|
|
13659
|
+
if (params.freshness !== "stale") return void 0;
|
|
13660
|
+
if (!this.shouldFire(this.lastStale, INDEX_KEEPER_STALE_INTERVAL_MS)) return void 0;
|
|
13661
|
+
this.lastStale = Date.now();
|
|
13662
|
+
if (!this.client) return void 0;
|
|
13663
|
+
const client = this.client;
|
|
13664
|
+
const pid = params.projectId;
|
|
13665
|
+
const fp = params.folderPath;
|
|
13666
|
+
setImmediate(async () => {
|
|
13667
|
+
try {
|
|
13668
|
+
await client.ingestLocal({ projectId: pid, rootPath: fp });
|
|
13669
|
+
console.error(`[ContextStream] IndexKeeper: stale re-ingest completed for ${fp}`);
|
|
13670
|
+
} catch (e) {
|
|
13671
|
+
console.error(`[ContextStream] IndexKeeper stale re-ingest failed:`, e);
|
|
13672
|
+
}
|
|
13673
|
+
});
|
|
13674
|
+
return `Started background re-index for ${fp} because the current index is stale.`;
|
|
13675
|
+
}
|
|
13676
|
+
};
|
|
13548
13677
|
var ContextStreamClient = class _ContextStreamClient {
|
|
13549
13678
|
constructor(config) {
|
|
13550
13679
|
this.config = config;
|
|
@@ -14454,6 +14583,16 @@ var ContextStreamClient = class _ContextStreamClient {
|
|
|
14454
14583
|
}
|
|
14455
14584
|
});
|
|
14456
14585
|
}
|
|
14586
|
+
async ingestFromPath(projectId, pathStr, opts) {
|
|
14587
|
+
return request(this.config, `/projects/${projectId}/files/ingest-from-path`, {
|
|
14588
|
+
body: {
|
|
14589
|
+
path: pathStr,
|
|
14590
|
+
force: opts?.force ?? false,
|
|
14591
|
+
include_media: opts?.include_media ?? false,
|
|
14592
|
+
max_files: opts?.max_files
|
|
14593
|
+
}
|
|
14594
|
+
});
|
|
14595
|
+
}
|
|
14457
14596
|
/**
|
|
14458
14597
|
* High-level local ingest: reads files from disk, applies SHA-256 content
|
|
14459
14598
|
* hash filtering, batches, and sends to the API with cooldown/status handling.
|
|
@@ -14511,7 +14650,22 @@ var ContextStreamClient = class _ContextStreamClient {
|
|
|
14511
14650
|
}
|
|
14512
14651
|
}
|
|
14513
14652
|
} catch (e) {
|
|
14514
|
-
console.error(`[ContextStream] Batch ingest error:`, e);
|
|
14653
|
+
console.error(`[ContextStream] Batch ingest error (attempt 1):`, e);
|
|
14654
|
+
try {
|
|
14655
|
+
const retryResult = await this.ingestFiles(projectId, filteredBatch, ingestOptions);
|
|
14656
|
+
const data = retryResult.data;
|
|
14657
|
+
if (data) {
|
|
14658
|
+
filesIndexed += data.files_indexed ?? 0;
|
|
14659
|
+
apiSkipped += data.files_skipped ?? 0;
|
|
14660
|
+
lastStatus = data.status;
|
|
14661
|
+
if (data.status === "cooldown" || data.status === "daily_limit_exceeded") {
|
|
14662
|
+
abortedEarly = true;
|
|
14663
|
+
break;
|
|
14664
|
+
}
|
|
14665
|
+
}
|
|
14666
|
+
} catch (retryErr) {
|
|
14667
|
+
console.error(`[ContextStream] Batch ingest retry failed:`, retryErr);
|
|
14668
|
+
}
|
|
14515
14669
|
}
|
|
14516
14670
|
}
|
|
14517
14671
|
writeHashManifest(projectId, newHashes);
|
|
@@ -14564,6 +14718,28 @@ var ContextStreamClient = class _ContextStreamClient {
|
|
|
14564
14718
|
this.indexChangedFilesAsync().catch(() => {
|
|
14565
14719
|
});
|
|
14566
14720
|
}
|
|
14721
|
+
localIndexAgeHours(folderPath) {
|
|
14722
|
+
try {
|
|
14723
|
+
const resolvedFolder = path5.resolve(folderPath);
|
|
14724
|
+
const fs21 = __require("node:fs");
|
|
14725
|
+
const statusPath = path5.join(homedir4(), ".contextstream", "index-status.json");
|
|
14726
|
+
const raw = fs21.readFileSync(statusPath, "utf-8");
|
|
14727
|
+
const status = JSON.parse(raw);
|
|
14728
|
+
const projects = status.projects ?? {};
|
|
14729
|
+
for (const [projectPath, info] of Object.entries(projects)) {
|
|
14730
|
+
const resolvedProjectPath = path5.resolve(projectPath);
|
|
14731
|
+
if (resolvedFolder === resolvedProjectPath || resolvedFolder.startsWith(`${resolvedProjectPath}${path5.sep}`)) {
|
|
14732
|
+
if (info?.indexed_at) {
|
|
14733
|
+
const ageMs = Date.now() - new Date(info.indexed_at).getTime();
|
|
14734
|
+
return Math.floor(ageMs / 36e5);
|
|
14735
|
+
}
|
|
14736
|
+
}
|
|
14737
|
+
}
|
|
14738
|
+
return null;
|
|
14739
|
+
} catch {
|
|
14740
|
+
return null;
|
|
14741
|
+
}
|
|
14742
|
+
}
|
|
14567
14743
|
/**
|
|
14568
14744
|
* Internal async method to find and index changed files.
|
|
14569
14745
|
* Called by checkAndIndexChangedFiles in fire-and-forget mode.
|
|
@@ -15945,13 +16121,15 @@ var ContextStreamClient = class _ContextStreamClient {
|
|
|
15945
16121
|
for (const item of memory.items) {
|
|
15946
16122
|
const createdAt = item.created_at || "";
|
|
15947
16123
|
if (createdAt > params.since) {
|
|
15948
|
-
const
|
|
16124
|
+
const isDecision = isDecisionResult(item);
|
|
16125
|
+
const isLesson = isLessonResult(item);
|
|
16126
|
+
const type = isDecision ? "decision" : isLesson ? "lesson" : extractEffectiveEventType(item);
|
|
15949
16127
|
items.push({
|
|
15950
16128
|
type,
|
|
15951
16129
|
title: item.title || "Untitled",
|
|
15952
16130
|
created_at: createdAt
|
|
15953
16131
|
});
|
|
15954
|
-
if (
|
|
16132
|
+
if (isDecision) newDecisions++;
|
|
15955
16133
|
else newMemory++;
|
|
15956
16134
|
}
|
|
15957
16135
|
}
|
|
@@ -16340,12 +16518,90 @@ ${context}`;
|
|
|
16340
16518
|
...this.indexRefreshInProgress ? { index_status: "refreshing" } : {}
|
|
16341
16519
|
};
|
|
16342
16520
|
}
|
|
16521
|
+
async getContextFast(params) {
|
|
16522
|
+
const withDefaults = this.withDefaults(params);
|
|
16523
|
+
if (!withDefaults.workspace_id) return null;
|
|
16524
|
+
try {
|
|
16525
|
+
const result = await request(this.config, "/context/hook", {
|
|
16526
|
+
body: withDefaults,
|
|
16527
|
+
timeoutMs: 5e3
|
|
16528
|
+
});
|
|
16529
|
+
const data = result?.data ?? result ?? {};
|
|
16530
|
+
return {
|
|
16531
|
+
context: data.context || "",
|
|
16532
|
+
items: Array.isArray(data.items) ? data.items : void 0,
|
|
16533
|
+
action_required: data.action_required
|
|
16534
|
+
};
|
|
16535
|
+
} catch {
|
|
16536
|
+
return null;
|
|
16537
|
+
}
|
|
16538
|
+
}
|
|
16539
|
+
async getVcsRepos(params) {
|
|
16540
|
+
try {
|
|
16541
|
+
const result = await request(this.config, `/integrations/workspaces/${params.workspace_id}/vcs/repos`, {
|
|
16542
|
+
method: "GET",
|
|
16543
|
+
timeoutMs: 3e3
|
|
16544
|
+
});
|
|
16545
|
+
return Array.isArray(result?.data) ? result.data : Array.isArray(result) ? result : [];
|
|
16546
|
+
} catch {
|
|
16547
|
+
return [];
|
|
16548
|
+
}
|
|
16549
|
+
}
|
|
16550
|
+
async getVcsResource(params) {
|
|
16551
|
+
const qs = params.per_page ? `?per_page=${params.per_page}` : "";
|
|
16552
|
+
try {
|
|
16553
|
+
const result = await request(this.config, `/integrations/workspaces/${params.workspace_id}/vcs/${params.path}${qs}`, {
|
|
16554
|
+
method: "GET",
|
|
16555
|
+
timeoutMs: 4e3
|
|
16556
|
+
});
|
|
16557
|
+
return Array.isArray(result?.data) ? result.data : Array.isArray(result) ? result : [];
|
|
16558
|
+
} catch {
|
|
16559
|
+
return [];
|
|
16560
|
+
}
|
|
16561
|
+
}
|
|
16562
|
+
async vcsApiRequest(params) {
|
|
16563
|
+
const queryParts = [];
|
|
16564
|
+
if (params.query) {
|
|
16565
|
+
for (const [k, v] of Object.entries(params.query)) {
|
|
16566
|
+
if (v !== void 0 && v !== null) queryParts.push(`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
|
|
16567
|
+
}
|
|
16568
|
+
}
|
|
16569
|
+
const qs = queryParts.length > 0 ? `?${queryParts.join("&")}` : "";
|
|
16570
|
+
const url = `/integrations/workspaces/${params.workspace_id}/vcs/${params.path}${qs}`;
|
|
16571
|
+
return request(this.config, url, {
|
|
16572
|
+
method: params.method,
|
|
16573
|
+
...params.body ? { body: params.body } : {}
|
|
16574
|
+
});
|
|
16575
|
+
}
|
|
16343
16576
|
/**
|
|
16344
16577
|
* Get high-priority lessons that should be surfaced proactively.
|
|
16345
|
-
* Returns
|
|
16578
|
+
* Returns lessons found via semantic search, with event listing fallback.
|
|
16346
16579
|
*/
|
|
16347
16580
|
async getHighPriorityLessons(params) {
|
|
16348
16581
|
const limit = params.limit || 5;
|
|
16582
|
+
const mapLesson = (item) => {
|
|
16583
|
+
const tags = extractEventTags(item);
|
|
16584
|
+
const severityTag = tags.find((t) => t.startsWith("severity:"));
|
|
16585
|
+
const severity = severityTag?.split(":")[1] || item.metadata?.importance || "medium";
|
|
16586
|
+
const category = tags.find(
|
|
16587
|
+
(t) => [
|
|
16588
|
+
"workflow",
|
|
16589
|
+
"code_quality",
|
|
16590
|
+
"verification",
|
|
16591
|
+
"communication",
|
|
16592
|
+
"project_specific"
|
|
16593
|
+
].includes(t)
|
|
16594
|
+
) || "unknown";
|
|
16595
|
+
const content = item.content || "";
|
|
16596
|
+
const preventionMatch = content.match(/### Prevention\n([\s\S]*?)(?:\n\n|\n\*\*|$)/);
|
|
16597
|
+
const prevention = preventionMatch?.[1]?.trim() || content.slice(0, 1e3);
|
|
16598
|
+
return {
|
|
16599
|
+
title: item.title || "Lesson",
|
|
16600
|
+
severity,
|
|
16601
|
+
category,
|
|
16602
|
+
prevention
|
|
16603
|
+
};
|
|
16604
|
+
};
|
|
16349
16605
|
try {
|
|
16350
16606
|
const searchQuery = params.context_hint ? `${params.context_hint} lesson warning prevention mistake` : "lesson warning prevention mistake critical high";
|
|
16351
16607
|
const searchResult = await this.memorySearch({
|
|
@@ -16353,39 +16609,20 @@ ${context}`;
|
|
|
16353
16609
|
workspace_id: params.workspace_id,
|
|
16354
16610
|
project_id: params.project_id,
|
|
16355
16611
|
limit: limit * 2
|
|
16356
|
-
// Fetch more to filter
|
|
16357
16612
|
});
|
|
16358
|
-
if (
|
|
16359
|
-
|
|
16360
|
-
if (
|
|
16361
|
-
|
|
16362
|
-
|
|
16363
|
-
|
|
16364
|
-
|
|
16365
|
-
|
|
16366
|
-
const tags = extractEventTags(item);
|
|
16367
|
-
const severityTag = tags.find((t) => t.startsWith("severity:"));
|
|
16368
|
-
const severity = severityTag?.split(":")[1] || item.metadata?.importance || "medium";
|
|
16369
|
-
const category = tags.find(
|
|
16370
|
-
(t) => [
|
|
16371
|
-
"workflow",
|
|
16372
|
-
"code_quality",
|
|
16373
|
-
"verification",
|
|
16374
|
-
"communication",
|
|
16375
|
-
"project_specific"
|
|
16376
|
-
].includes(t)
|
|
16377
|
-
) || "unknown";
|
|
16378
|
-
const content = item.content || "";
|
|
16379
|
-
const preventionMatch = content.match(/### Prevention\n([\s\S]*?)(?:\n\n|\n\*\*|$)/);
|
|
16380
|
-
const prevention = preventionMatch?.[1]?.trim() || content.slice(0, 1e3);
|
|
16381
|
-
return {
|
|
16382
|
-
title: item.title || "Lesson",
|
|
16383
|
-
severity,
|
|
16384
|
-
category,
|
|
16385
|
-
prevention
|
|
16386
|
-
};
|
|
16613
|
+
if (searchResult?.results) {
|
|
16614
|
+
const lessons = searchResult.results.filter((item) => isLessonResult(item)).slice(0, limit).map(mapLesson);
|
|
16615
|
+
if (lessons.length > 0) return lessons;
|
|
16616
|
+
}
|
|
16617
|
+
const eventResult = await this.listMemoryEvents({
|
|
16618
|
+
workspace_id: params.workspace_id,
|
|
16619
|
+
event_type: "lesson",
|
|
16620
|
+
limit: limit * 2
|
|
16387
16621
|
});
|
|
16388
|
-
|
|
16622
|
+
if (eventResult?.items) {
|
|
16623
|
+
return eventResult.items.filter((item) => isLessonResult(item)).slice(0, limit).map(mapLesson);
|
|
16624
|
+
}
|
|
16625
|
+
return [];
|
|
16389
16626
|
} catch {
|
|
16390
16627
|
return [];
|
|
16391
16628
|
}
|
|
@@ -17775,7 +18012,7 @@ ${context}`;
|
|
|
17775
18012
|
import * as fs6 from "node:fs";
|
|
17776
18013
|
import * as path7 from "node:path";
|
|
17777
18014
|
import { execFile } from "node:child_process";
|
|
17778
|
-
import { homedir as
|
|
18015
|
+
import { homedir as homedir6 } from "node:os";
|
|
17779
18016
|
import { promisify as promisify2 } from "node:util";
|
|
17780
18017
|
init_files();
|
|
17781
18018
|
init_rules_templates();
|
|
@@ -18360,9 +18597,9 @@ function resolveTodoCompletionUpdate(input) {
|
|
|
18360
18597
|
// src/hot-paths.ts
|
|
18361
18598
|
import * as fs5 from "node:fs";
|
|
18362
18599
|
import * as path6 from "node:path";
|
|
18363
|
-
import { homedir as
|
|
18600
|
+
import { homedir as homedir5 } from "node:os";
|
|
18364
18601
|
var STORE_VERSION = 1;
|
|
18365
|
-
var STORE_DIR = path6.join(
|
|
18602
|
+
var STORE_DIR = path6.join(homedir5(), ".contextstream");
|
|
18366
18603
|
var STORE_FILE = path6.join(STORE_DIR, "hot-paths.json");
|
|
18367
18604
|
var MAX_PATHS_PER_SCOPE = 400;
|
|
18368
18605
|
var HALF_LIFE_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
@@ -18500,6 +18737,24 @@ var HotPathStore = class {
|
|
|
18500
18737
|
var globalHotPathStore = new HotPathStore();
|
|
18501
18738
|
|
|
18502
18739
|
// src/tools.ts
|
|
18740
|
+
function stringOrArray(itemSchema) {
|
|
18741
|
+
return external_exports.union([
|
|
18742
|
+
external_exports.array(itemSchema),
|
|
18743
|
+
external_exports.string().transform((val, ctx) => {
|
|
18744
|
+
try {
|
|
18745
|
+
const parsed = JSON.parse(val);
|
|
18746
|
+
if (!Array.isArray(parsed)) {
|
|
18747
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: "Expected array or JSON string of array" });
|
|
18748
|
+
return external_exports.NEVER;
|
|
18749
|
+
}
|
|
18750
|
+
return parsed;
|
|
18751
|
+
} catch {
|
|
18752
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: "Invalid JSON string for array parameter" });
|
|
18753
|
+
return external_exports.NEVER;
|
|
18754
|
+
}
|
|
18755
|
+
})
|
|
18756
|
+
]);
|
|
18757
|
+
}
|
|
18503
18758
|
var execFileAsync = promisify2(execFile);
|
|
18504
18759
|
function parseBoolEnvDefault(raw, fallback) {
|
|
18505
18760
|
if (raw === void 0) return fallback;
|
|
@@ -18808,9 +19063,9 @@ var RULES_PROJECT_FILES = {
|
|
|
18808
19063
|
aider: ".aider.conf.yml"
|
|
18809
19064
|
};
|
|
18810
19065
|
var RULES_GLOBAL_FILES = {
|
|
18811
|
-
codex: [path7.join(
|
|
18812
|
-
kilo: [path7.join(
|
|
18813
|
-
roo: [path7.join(
|
|
19066
|
+
codex: [path7.join(homedir6(), ".codex", "AGENTS.md")],
|
|
19067
|
+
kilo: [path7.join(homedir6(), ".kilocode", "rules", "contextstream.md")],
|
|
19068
|
+
roo: [path7.join(homedir6(), ".roo", "rules", "contextstream.md")]
|
|
18814
19069
|
};
|
|
18815
19070
|
var rulesNoticeCache = /* @__PURE__ */ new Map();
|
|
18816
19071
|
function compareVersions2(v1, v2) {
|
|
@@ -19973,6 +20228,7 @@ function parsePositiveInt(raw, fallback) {
|
|
|
19973
20228
|
var OUTPUT_FORMAT = process.env.CONTEXTSTREAM_OUTPUT_FORMAT || "compact";
|
|
19974
20229
|
var COMPACT_OUTPUT = OUTPUT_FORMAT === "compact";
|
|
19975
20230
|
var SHOW_TIMING = process.env.CONTEXTSTREAM_SHOW_TIMING === "true" || process.env.CONTEXTSTREAM_SHOW_TIMING === "1";
|
|
20231
|
+
var CONCISE_TOOL_TEXT = process.env.CONTEXTSTREAM_CONCISE_TOOL_TEXT?.toLowerCase() !== "false";
|
|
19976
20232
|
var INCLUDE_STRUCTURED_CONTENT = parseBoolEnvDefault(
|
|
19977
20233
|
process.env.CONTEXTSTREAM_INCLUDE_STRUCTURED_CONTENT,
|
|
19978
20234
|
true
|
|
@@ -19989,6 +20245,73 @@ function maybeStripStructuredContent(result) {
|
|
|
19989
20245
|
const { structuredContent: _structuredContent, ...rest } = result;
|
|
19990
20246
|
return rest;
|
|
19991
20247
|
}
|
|
20248
|
+
function formatTypedLessons(items, compact) {
|
|
20249
|
+
if (items.length === 0) return "";
|
|
20250
|
+
const MAX = 5;
|
|
20251
|
+
const entries = items.slice(0, MAX).map((item) => {
|
|
20252
|
+
const sev = item.score >= 0.8 ? "CRIT" : item.score >= 0.5 ? "HIGH" : "note";
|
|
20253
|
+
return compact ? `[LESSON:${sev}] ${item.value}` : `Lesson (${sev}): ${item.value}`;
|
|
20254
|
+
});
|
|
20255
|
+
return entries.join("\n");
|
|
20256
|
+
}
|
|
20257
|
+
function formatTypedPreferences(items, compact) {
|
|
20258
|
+
if (items.length === 0) return "";
|
|
20259
|
+
const MAX = 5;
|
|
20260
|
+
const entries = items.slice(0, MAX).map(
|
|
20261
|
+
(item) => compact ? `[PREF] ${item.value}` : `Preference: ${item.value}`
|
|
20262
|
+
);
|
|
20263
|
+
return entries.join("\n");
|
|
20264
|
+
}
|
|
20265
|
+
function formatTypedVcs(items, compact) {
|
|
20266
|
+
if (items.length === 0) return "";
|
|
20267
|
+
const MAX = 5;
|
|
20268
|
+
const entries = items.slice(0, MAX).map(
|
|
20269
|
+
(item) => compact ? `[VCS] ${item.value}` : `VCS: ${item.value}`
|
|
20270
|
+
);
|
|
20271
|
+
return entries.join("\n");
|
|
20272
|
+
}
|
|
20273
|
+
function formatTypedSkills(items, compact) {
|
|
20274
|
+
if (items.length === 0) return "";
|
|
20275
|
+
const MAX = 5;
|
|
20276
|
+
const entries = items.slice(0, MAX).map(
|
|
20277
|
+
(item) => compact ? `[SKILL] ${item.value}` : `Skill: ${item.value}`
|
|
20278
|
+
);
|
|
20279
|
+
return entries.join("\n");
|
|
20280
|
+
}
|
|
20281
|
+
function formatTypedSnapshots(items, compact) {
|
|
20282
|
+
if (items.length === 0) return "";
|
|
20283
|
+
const MAX = 3;
|
|
20284
|
+
const entries = items.slice(0, MAX).map(
|
|
20285
|
+
(item) => compact ? `[SNAPSHOT] ${item.value}` : `Transcript snapshot: ${item.value}`
|
|
20286
|
+
);
|
|
20287
|
+
return entries.join("\n");
|
|
20288
|
+
}
|
|
20289
|
+
function hasServerVcsItems(items) {
|
|
20290
|
+
if (!items || items.length === 0) return false;
|
|
20291
|
+
return items.some((i) => resolveItemKind(i) === "vcs");
|
|
20292
|
+
}
|
|
20293
|
+
var WARM_CACHE_TTL_MS = 3e4;
|
|
20294
|
+
var warmCacheEntry = null;
|
|
20295
|
+
function getWarmCacheKey(workspaceId, projectId) {
|
|
20296
|
+
return `${workspaceId || ""}:${projectId || ""}`;
|
|
20297
|
+
}
|
|
20298
|
+
function getWarmCache(workspaceId, projectId) {
|
|
20299
|
+
if (!warmCacheEntry) return null;
|
|
20300
|
+
const key = getWarmCacheKey(workspaceId, projectId);
|
|
20301
|
+
if (warmCacheEntry.key !== key) return null;
|
|
20302
|
+
if (Date.now() - warmCacheEntry.timestamp > WARM_CACHE_TTL_MS) {
|
|
20303
|
+
warmCacheEntry = null;
|
|
20304
|
+
return null;
|
|
20305
|
+
}
|
|
20306
|
+
return warmCacheEntry.result;
|
|
20307
|
+
}
|
|
20308
|
+
function setWarmCache(workspaceId, projectId, result) {
|
|
20309
|
+
warmCacheEntry = {
|
|
20310
|
+
key: getWarmCacheKey(workspaceId, projectId),
|
|
20311
|
+
timestamp: Date.now(),
|
|
20312
|
+
result
|
|
20313
|
+
};
|
|
20314
|
+
}
|
|
19992
20315
|
var CONSOLIDATED_MODE = process.env.CONTEXTSTREAM_CONSOLIDATED !== "false";
|
|
19993
20316
|
var CONSOLIDATED_TOOLS = /* @__PURE__ */ new Set([
|
|
19994
20317
|
"init",
|
|
@@ -20351,6 +20674,8 @@ function setupClientDetection(server) {
|
|
|
20351
20674
|
}
|
|
20352
20675
|
function registerTools(server, client, sessionManager, options) {
|
|
20353
20676
|
const upgradeUrl2 = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
|
|
20677
|
+
const indexKeeper = new IndexKeeper();
|
|
20678
|
+
indexKeeper.attach(client);
|
|
20354
20679
|
const toolSurfaceProfile = normalizeToolSurfaceProfile(
|
|
20355
20680
|
options?.toolSurfaceProfile || process.env.CONTEXTSTREAM_TOOL_SURFACE_PROFILE
|
|
20356
20681
|
);
|
|
@@ -20968,6 +21293,13 @@ Next step: ${createCommand}`
|
|
|
20968
21293
|
function isNotFoundError(error) {
|
|
20969
21294
|
return error instanceof HttpError && error.status === 404;
|
|
20970
21295
|
}
|
|
21296
|
+
function isAccessDeniedError(error) {
|
|
21297
|
+
return error instanceof HttpError && (error.status === 403 || error.status === 401);
|
|
21298
|
+
}
|
|
21299
|
+
function isScopeInvalidResult(result) {
|
|
21300
|
+
const data = result?.data ?? result ?? {};
|
|
21301
|
+
return data.scope_is_valid === false || data.scope_invalid === true || typeof data.error === "string" && data.error.includes("project_access_denied");
|
|
21302
|
+
}
|
|
20971
21303
|
function isRequiresIngestEndpointError(error) {
|
|
20972
21304
|
if (!(error instanceof HttpError)) return false;
|
|
20973
21305
|
if (error.status !== 400) return false;
|
|
@@ -20983,6 +21315,100 @@ Next step: ${createCommand}`
|
|
|
20983
21315
|
(t) => /[A-Z][a-z]/.test(t) || t.includes("_") || t.includes(".") || t.includes("::")
|
|
20984
21316
|
);
|
|
20985
21317
|
}
|
|
21318
|
+
function isArtifactLikePath(filePath) {
|
|
21319
|
+
const normalized = filePath.toLowerCase().replace(/\\/g, "/");
|
|
21320
|
+
return normalized.includes("/.next/") || normalized.includes("/.next.bak/") || normalized.includes("/node_modules/") || normalized.includes("/dist/") || normalized.includes("/build/") || normalized.includes("/target/") || normalized.includes("/coverage/") || normalized.endsWith(".js.map") || normalized.endsWith(".css.map") || normalized.endsWith(".d.ts.map") || normalized.endsWith(".min.js") || normalized.startsWith("archives-ignore/") || normalized.includes("/archives-ignore/") || normalized.startsWith("archives-") && normalized.includes("/tasks/");
|
|
21321
|
+
}
|
|
21322
|
+
function queryExplicitlyTargetsArtifacts(query) {
|
|
21323
|
+
const lower = query.toLowerCase();
|
|
21324
|
+
return lower.includes(".map") || lower.includes("source map") || lower.includes("sourcemap") || lower.includes("node_modules") || lower.includes(".next") || lower.includes("dist/") || lower.includes("build/") || lower.includes("coverage");
|
|
21325
|
+
}
|
|
21326
|
+
function shouldFilterArtifactPaths(mode, query) {
|
|
21327
|
+
if (mode === "pattern" || mode === "exhaustive") return false;
|
|
21328
|
+
if (queryExplicitlyTargetsArtifacts(query)) return false;
|
|
21329
|
+
return true;
|
|
21330
|
+
}
|
|
21331
|
+
const MIRROR_PREFIXES = [
|
|
21332
|
+
"contextstream-ai-brain-export/",
|
|
21333
|
+
"contextstream/",
|
|
21334
|
+
"web/users/"
|
|
21335
|
+
];
|
|
21336
|
+
function canonicalizeRepoPath(filePath) {
|
|
21337
|
+
let normalized = filePath.replace(/\\/g, "/");
|
|
21338
|
+
while (normalized.startsWith("./")) {
|
|
21339
|
+
normalized = normalized.slice(2);
|
|
21340
|
+
}
|
|
21341
|
+
for (const prefix of MIRROR_PREFIXES) {
|
|
21342
|
+
if (normalized.startsWith(prefix)) {
|
|
21343
|
+
normalized = normalized.slice(prefix.length);
|
|
21344
|
+
break;
|
|
21345
|
+
}
|
|
21346
|
+
}
|
|
21347
|
+
if (normalized.startsWith(".claude/worktrees/")) {
|
|
21348
|
+
const rest = normalized.slice(".claude/worktrees/".length);
|
|
21349
|
+
const slashIdx = rest.indexOf("/");
|
|
21350
|
+
if (slashIdx >= 0) {
|
|
21351
|
+
normalized = rest.slice(slashIdx + 1);
|
|
21352
|
+
}
|
|
21353
|
+
}
|
|
21354
|
+
const projectsIdx = normalized.indexOf("/projects/");
|
|
21355
|
+
if (projectsIdx >= 0) {
|
|
21356
|
+
const afterProjects = normalized.slice(projectsIdx + "/projects/".length);
|
|
21357
|
+
const uuidEndIdx = afterProjects.indexOf("/");
|
|
21358
|
+
if (uuidEndIdx >= 0 && /^[0-9a-f-]{36}/i.test(afterProjects)) {
|
|
21359
|
+
normalized = afterProjects.slice(uuidEndIdx + 1);
|
|
21360
|
+
}
|
|
21361
|
+
}
|
|
21362
|
+
return normalized;
|
|
21363
|
+
}
|
|
21364
|
+
function extractSymbolAnchors(query) {
|
|
21365
|
+
const tokens = query.split(/\s+/).filter(Boolean);
|
|
21366
|
+
const anchors = [];
|
|
21367
|
+
for (const t of tokens) {
|
|
21368
|
+
const cleaned = t.replace(/^["'`]+|["'`]+$/g, "");
|
|
21369
|
+
if (!cleaned) continue;
|
|
21370
|
+
const hasMixedCase = /[a-z]/.test(cleaned) && /[A-Z]/.test(cleaned);
|
|
21371
|
+
const hasUnderscore = cleaned.includes("_");
|
|
21372
|
+
const hasNamespaceSep = cleaned.includes("::") || cleaned.includes(".");
|
|
21373
|
+
const isAllCaps = cleaned.length >= 3 && /^[A-Z0-9_]+$/.test(cleaned);
|
|
21374
|
+
if (hasMixedCase || hasUnderscore || hasNamespaceSep || isAllCaps) {
|
|
21375
|
+
anchors.push(cleaned);
|
|
21376
|
+
}
|
|
21377
|
+
}
|
|
21378
|
+
return anchors;
|
|
21379
|
+
}
|
|
21380
|
+
function applySymbolAnchorRerank(results, anchors) {
|
|
21381
|
+
if (anchors.length === 0 || results.length === 0) return results;
|
|
21382
|
+
const lowerAnchors = anchors.map((a) => a.toLowerCase());
|
|
21383
|
+
const scored = results.map((r, idx) => {
|
|
21384
|
+
const fp = (r.file_path || "").toLowerCase();
|
|
21385
|
+
const content = (r.content || "").toLowerCase();
|
|
21386
|
+
let anchorHits = 0;
|
|
21387
|
+
for (const anchor of lowerAnchors) {
|
|
21388
|
+
if (fp.includes(anchor) || content.includes(anchor)) anchorHits++;
|
|
21389
|
+
}
|
|
21390
|
+
const isNoisy = isArtifactLikePath(r.file_path || "");
|
|
21391
|
+
return { item: r, anchorHits, isNoisy, originalIdx: idx };
|
|
21392
|
+
});
|
|
21393
|
+
scored.sort((a, b) => {
|
|
21394
|
+
if (b.anchorHits !== a.anchorHits) return b.anchorHits - a.anchorHits;
|
|
21395
|
+
if (a.isNoisy !== b.isNoisy) return a.isNoisy ? 1 : -1;
|
|
21396
|
+
return a.originalIdx - b.originalIdx;
|
|
21397
|
+
});
|
|
21398
|
+
return scored.map((s) => s.item);
|
|
21399
|
+
}
|
|
21400
|
+
function deduplicateSearchResults(results) {
|
|
21401
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21402
|
+
return results.filter((r) => {
|
|
21403
|
+
const fp = r.file_path ? canonicalizeRepoPath(r.file_path) : "";
|
|
21404
|
+
const startLine = r.start_line || r.metadata?.start_line || "";
|
|
21405
|
+
const key = fp ? `${fp}:${startLine}` : "";
|
|
21406
|
+
if (!key) return true;
|
|
21407
|
+
if (seen.has(key)) return false;
|
|
21408
|
+
seen.add(key);
|
|
21409
|
+
return true;
|
|
21410
|
+
});
|
|
21411
|
+
}
|
|
20986
21412
|
async function runLocalRipgrep(query, cwd, limit = 10) {
|
|
20987
21413
|
try {
|
|
20988
21414
|
const pattern = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -21698,7 +22124,7 @@ ${formatContent(result)}`
|
|
|
21698
22124
|
).optional().describe("Entries to push (for push)"),
|
|
21699
22125
|
increment_turn: external_exports.boolean().optional().describe("Increment turn counter (for push)"),
|
|
21700
22126
|
force_version_bump: external_exports.boolean().optional().describe("Force version bump even with no new entries (for push)"),
|
|
21701
|
-
ids:
|
|
22127
|
+
ids: stringOrArray(external_exports.string()).optional().describe("Entry IDs to acknowledge (for ack)"),
|
|
21702
22128
|
expected_version: external_exports.number().optional().describe("Expected version for checkpoint verify")
|
|
21703
22129
|
});
|
|
21704
22130
|
const instructionToolDescription = "Session-scoped instruction cache operations. Actions: bootstrap, get, push, ack, clear, stats, checkpoint, verify.";
|
|
@@ -22672,9 +23098,9 @@ Actions:
|
|
|
22672
23098
|
title: external_exports.string().optional().describe("Skill display title"),
|
|
22673
23099
|
description: external_exports.string().optional().describe("Skill description"),
|
|
22674
23100
|
instruction_body: external_exports.string().optional().describe("Markdown instruction text (the prompt)"),
|
|
22675
|
-
trigger_patterns:
|
|
23101
|
+
trigger_patterns: stringOrArray(external_exports.string()).optional().describe("Keywords/phrases for auto-activation"),
|
|
22676
23102
|
trigger_regex: external_exports.string().optional().describe("Optional regex for advanced trigger matching"),
|
|
22677
|
-
categories:
|
|
23103
|
+
categories: stringOrArray(external_exports.string()).optional().describe("Tags for discovery/filtering"),
|
|
22678
23104
|
actions: external_exports.any().optional().describe("Action steps array [{type, tool, params, ...}]"),
|
|
22679
23105
|
params: external_exports.any().optional().describe("Parameters passed to skill execution"),
|
|
22680
23106
|
dry_run: external_exports.boolean().optional().describe("Preview execution without running"),
|
|
@@ -22687,7 +23113,7 @@ Actions:
|
|
|
22687
23113
|
format: external_exports.enum(["auto", "json", "markdown", "skills_md", "cursorrules", "claude_md", "aider", "zip"]).optional().describe("Import/export format"),
|
|
22688
23114
|
source_tool: external_exports.string().optional().describe("Source tool name (for import provenance)"),
|
|
22689
23115
|
source_file: external_exports.string().optional().describe("Source filename (for import provenance)"),
|
|
22690
|
-
skill_ids:
|
|
23116
|
+
skill_ids: stringOrArray(external_exports.string()).optional().describe("Skill IDs for export"),
|
|
22691
23117
|
change_summary: external_exports.string().optional().describe("Summary of changes (for version history)"),
|
|
22692
23118
|
workspace_id: external_exports.string().optional().describe("Workspace ID (UUID)"),
|
|
22693
23119
|
project_id: external_exports.string().optional().describe("Project ID (UUID)"),
|
|
@@ -22848,7 +23274,7 @@ Actions:
|
|
|
22848
23274
|
workspace_id: external_exports.string().uuid().optional(),
|
|
22849
23275
|
project_id: external_exports.string().uuid().optional(),
|
|
22850
23276
|
limit: external_exports.number().optional(),
|
|
22851
|
-
tags:
|
|
23277
|
+
tags: stringOrArray(external_exports.string()).optional().describe("Filter events that contain ALL of these tags"),
|
|
22852
23278
|
event_type: external_exports.string().optional().describe("Filter by event type (e.g. decision, lesson, manual_note)")
|
|
22853
23279
|
})
|
|
22854
23280
|
},
|
|
@@ -22920,7 +23346,7 @@ Actions:
|
|
|
22920
23346
|
workspace_id: external_exports.string().uuid().optional(),
|
|
22921
23347
|
project_id: external_exports.string().uuid().optional(),
|
|
22922
23348
|
limit: external_exports.number().optional(),
|
|
22923
|
-
tags:
|
|
23349
|
+
tags: stringOrArray(external_exports.string()).optional().describe("Filter results that contain ALL of these tags")
|
|
22924
23350
|
})
|
|
22925
23351
|
},
|
|
22926
23352
|
async (input) => {
|
|
@@ -24306,7 +24732,7 @@ Use this to persist decisions, insights, preferences, or important information.`
|
|
|
24306
24732
|
]).describe("Type of context being captured"),
|
|
24307
24733
|
title: external_exports.string().describe("Brief title for the captured context"),
|
|
24308
24734
|
content: external_exports.string().describe("Full content/details to capture"),
|
|
24309
|
-
tags:
|
|
24735
|
+
tags: stringOrArray(external_exports.string()).optional().describe("Tags for categorization"),
|
|
24310
24736
|
importance: external_exports.enum(["low", "medium", "high", "critical"]).optional().describe("Importance level"),
|
|
24311
24737
|
provenance: external_exports.object({
|
|
24312
24738
|
repo: external_exports.string().optional(),
|
|
@@ -25284,7 +25710,7 @@ After compression, the AI can use session_recall to retrieve this context in fut
|
|
|
25284
25710
|
project_id: external_exports.string().uuid().optional(),
|
|
25285
25711
|
title: external_exports.string(),
|
|
25286
25712
|
description: external_exports.string().optional(),
|
|
25287
|
-
goals:
|
|
25713
|
+
goals: stringOrArray(external_exports.string()).optional(),
|
|
25288
25714
|
steps: external_exports.array(
|
|
25289
25715
|
external_exports.object({
|
|
25290
25716
|
id: external_exports.string(),
|
|
@@ -25295,7 +25721,7 @@ After compression, the AI can use session_recall to retrieve this context in fut
|
|
|
25295
25721
|
})
|
|
25296
25722
|
).optional(),
|
|
25297
25723
|
status: external_exports.enum(["draft", "active", "completed", "archived", "abandoned"]).optional(),
|
|
25298
|
-
tags:
|
|
25724
|
+
tags: stringOrArray(external_exports.string()).optional(),
|
|
25299
25725
|
due_at: external_exports.string().optional(),
|
|
25300
25726
|
is_personal: external_exports.boolean().optional()
|
|
25301
25727
|
})
|
|
@@ -25333,7 +25759,7 @@ After compression, the AI can use session_recall to retrieve this context in fut
|
|
|
25333
25759
|
plan_id: external_exports.string().uuid(),
|
|
25334
25760
|
title: external_exports.string().optional(),
|
|
25335
25761
|
description: external_exports.string().optional(),
|
|
25336
|
-
goals:
|
|
25762
|
+
goals: stringOrArray(external_exports.string()).optional(),
|
|
25337
25763
|
status: external_exports.enum(["draft", "active", "completed", "archived", "abandoned"]).optional()
|
|
25338
25764
|
})
|
|
25339
25765
|
},
|
|
@@ -25521,7 +25947,7 @@ This saves ~80% tokens compared to including full chat history.`,
|
|
|
25521
25947
|
project_id: external_exports.string().uuid().optional(),
|
|
25522
25948
|
max_tokens: external_exports.number().optional().describe("Maximum tokens for context (default: 800)"),
|
|
25523
25949
|
format: external_exports.enum(["minified", "readable", "structured"]).optional().describe("Context format (default: minified)"),
|
|
25524
|
-
mode: external_exports.enum(["standard", "pack"]).optional().describe("Context
|
|
25950
|
+
mode: external_exports.enum(["standard", "pack", "fast"]).optional().describe("Context mode: standard (default), pack (includes code context), fast (cached quick response)"),
|
|
25525
25951
|
distill: external_exports.boolean().optional().describe("Use distillation for context pack (default: true)"),
|
|
25526
25952
|
session_tokens: external_exports.number().optional().describe("Cumulative session token count for context pressure calculation"),
|
|
25527
25953
|
context_threshold: external_exports.number().optional().describe("Custom context window threshold (defaults to 70k)"),
|
|
@@ -25612,21 +26038,149 @@ This saves ~80% tokens compared to including full chat history.`,
|
|
|
25612
26038
|
if (!clientName && detectedClientInfo) {
|
|
25613
26039
|
clientName = detectedClientInfo.name;
|
|
25614
26040
|
}
|
|
25615
|
-
const
|
|
25616
|
-
|
|
25617
|
-
|
|
25618
|
-
|
|
25619
|
-
|
|
25620
|
-
|
|
25621
|
-
|
|
25622
|
-
|
|
25623
|
-
|
|
25624
|
-
|
|
25625
|
-
|
|
25626
|
-
|
|
25627
|
-
|
|
25628
|
-
|
|
25629
|
-
}
|
|
26041
|
+
const conversationTurns = sessionManager?.getConversationTurns() ?? 0;
|
|
26042
|
+
const isFastMode = input.mode === "fast";
|
|
26043
|
+
const folderPathCtx = resolveFolderPath(void 0, sessionManager);
|
|
26044
|
+
if (isFastMode && workspaceId) {
|
|
26045
|
+
const fastResult = await client.getContextFast({ workspace_id: workspaceId, project_id: projectId });
|
|
26046
|
+
if (fastResult && fastResult.context) {
|
|
26047
|
+
const roundTripMs2 = Date.now() - startTime;
|
|
26048
|
+
const timingStr2 = SHOW_TIMING ? ` | ${roundTripMs2}ms` : "";
|
|
26049
|
+
return {
|
|
26050
|
+
content: [{ type: "text", text: `${fastResult.context}
|
|
26051
|
+
---
|
|
26052
|
+
fast mode${timingStr2}` }]
|
|
26053
|
+
};
|
|
26054
|
+
}
|
|
26055
|
+
}
|
|
26056
|
+
const cachedResult = conversationTurns >= 2 ? getWarmCache(workspaceId, projectId) : null;
|
|
26057
|
+
let proactiveVcsPromise;
|
|
26058
|
+
if (conversationTurns <= 3 && workspaceId && !isFastMode) {
|
|
26059
|
+
proactiveVcsPromise = (async () => {
|
|
26060
|
+
const repos = await client.getVcsRepos({ workspace_id: workspaceId, per_page: 10 });
|
|
26061
|
+
if (repos.length === 0) return { repos: [], pulls: [], issues: [], activity: [], notifications: [] };
|
|
26062
|
+
const pullPromises = repos.slice(0, 5).map(
|
|
26063
|
+
(r) => client.getVcsResource({ workspace_id: workspaceId, path: `repos/${r.id || r.repo_id}/pulls`, per_page: 5 })
|
|
26064
|
+
);
|
|
26065
|
+
const issuePromises = repos.slice(0, 5).map(
|
|
26066
|
+
(r) => client.getVcsResource({ workspace_id: workspaceId, path: `repos/${r.id || r.repo_id}/issues`, per_page: 5 })
|
|
26067
|
+
);
|
|
26068
|
+
const [pullResults, issueResults] = await Promise.all([
|
|
26069
|
+
Promise.all(pullPromises),
|
|
26070
|
+
Promise.all(issuePromises)
|
|
26071
|
+
]);
|
|
26072
|
+
return {
|
|
26073
|
+
repos,
|
|
26074
|
+
pulls: pullResults.flat(),
|
|
26075
|
+
issues: issueResults.flat(),
|
|
26076
|
+
activity: [],
|
|
26077
|
+
notifications: []
|
|
26078
|
+
};
|
|
26079
|
+
})().catch(() => ({ repos: [], pulls: [], issues: [], activity: [], notifications: [] }));
|
|
26080
|
+
}
|
|
26081
|
+
let recentChangesPromise;
|
|
26082
|
+
if (conversationTurns <= 2 && folderPathCtx && !CONCISE_TOOL_TEXT && !isFastMode) {
|
|
26083
|
+
recentChangesPromise = (async () => {
|
|
26084
|
+
try {
|
|
26085
|
+
const { stdout: stdout2 } = await execFileAsync("git", [
|
|
26086
|
+
"log",
|
|
26087
|
+
"--oneline",
|
|
26088
|
+
"--format=%h %s (%ar)",
|
|
26089
|
+
"-n5"
|
|
26090
|
+
], { cwd: folderPathCtx, timeout: 3e3, maxBuffer: 64 * 1024 });
|
|
26091
|
+
return stdout2.trim();
|
|
26092
|
+
} catch {
|
|
26093
|
+
return "";
|
|
26094
|
+
}
|
|
26095
|
+
})();
|
|
26096
|
+
}
|
|
26097
|
+
let result;
|
|
26098
|
+
if (cachedResult) {
|
|
26099
|
+
result = cachedResult;
|
|
26100
|
+
const fastOverlay = await client.getContextFast({ workspace_id: workspaceId, project_id: projectId });
|
|
26101
|
+
if (fastOverlay?.context) {
|
|
26102
|
+
result = { ...result, context: result.context + "\n" + fastOverlay.context };
|
|
26103
|
+
if (fastOverlay.items && Array.isArray(fastOverlay.items)) {
|
|
26104
|
+
result.items = [...result.items || [], ...fastOverlay.items];
|
|
26105
|
+
}
|
|
26106
|
+
}
|
|
26107
|
+
} else {
|
|
26108
|
+
result = await client.getSmartContext({
|
|
26109
|
+
user_message: input.user_message,
|
|
26110
|
+
workspace_id: workspaceId,
|
|
26111
|
+
project_id: projectId,
|
|
26112
|
+
max_tokens: input.max_tokens,
|
|
26113
|
+
format: input.format,
|
|
26114
|
+
mode: input.mode === "fast" ? "standard" : input.mode,
|
|
26115
|
+
distill: input.distill,
|
|
26116
|
+
session_tokens: sessionTokens,
|
|
26117
|
+
context_threshold: contextThreshold,
|
|
26118
|
+
save_exchange: input.save_exchange,
|
|
26119
|
+
session_id: sessionId,
|
|
26120
|
+
client_name: clientName,
|
|
26121
|
+
assistant_message: input.assistant_message
|
|
26122
|
+
});
|
|
26123
|
+
if (workspaceId) {
|
|
26124
|
+
setWarmCache(workspaceId, projectId, result);
|
|
26125
|
+
}
|
|
26126
|
+
}
|
|
26127
|
+
const typedItems = Array.isArray(result.items) ? result.items : [];
|
|
26128
|
+
const hasTypedItems = typedItems.length > 0;
|
|
26129
|
+
const compact = COMPACT_OUTPUT || CONCISE_TOOL_TEXT;
|
|
26130
|
+
let typedContextBlock = "";
|
|
26131
|
+
if (hasTypedItems) {
|
|
26132
|
+
const parts = [];
|
|
26133
|
+
const prefItems = filterItemsByKind(typedItems, "preference");
|
|
26134
|
+
const lessonItems = filterItemsByKind(typedItems, "lesson");
|
|
26135
|
+
const vcsItems = filterItemsByKind(typedItems, "vcs");
|
|
26136
|
+
const skillItems = filterItemsByKind(typedItems, "skill");
|
|
26137
|
+
const snapItems = filterItemsByKind(typedItems, "transcript_snapshot");
|
|
26138
|
+
const prefText = formatTypedPreferences(prefItems, compact);
|
|
26139
|
+
if (prefText) parts.push(prefText);
|
|
26140
|
+
const lessonText = formatTypedLessons(lessonItems, compact);
|
|
26141
|
+
if (lessonText) parts.push(lessonText);
|
|
26142
|
+
const vcsText = formatTypedVcs(vcsItems, compact);
|
|
26143
|
+
if (vcsText) parts.push(vcsText);
|
|
26144
|
+
const skillText = formatTypedSkills(skillItems, compact);
|
|
26145
|
+
if (skillText) parts.push(skillText);
|
|
26146
|
+
if (conversationTurns <= 3) {
|
|
26147
|
+
const snapText = formatTypedSnapshots(snapItems, compact);
|
|
26148
|
+
if (snapText) parts.push(snapText);
|
|
26149
|
+
}
|
|
26150
|
+
if (parts.length > 0) {
|
|
26151
|
+
typedContextBlock = "\n" + parts.join("\n") + "\n";
|
|
26152
|
+
}
|
|
26153
|
+
}
|
|
26154
|
+
let proactiveVcsBlock = "";
|
|
26155
|
+
if (proactiveVcsPromise) {
|
|
26156
|
+
try {
|
|
26157
|
+
const vcsCtx = await proactiveVcsPromise;
|
|
26158
|
+
if (!hasServerVcsItems(typedItems) && (vcsCtx.pulls.length > 0 || vcsCtx.issues.length > 0)) {
|
|
26159
|
+
const vParts = [];
|
|
26160
|
+
if (vcsCtx.pulls.length > 0) {
|
|
26161
|
+
vParts.push(compact ? `[VCS] ${vcsCtx.pulls.length} open PR(s)` : `Open PRs: ${vcsCtx.pulls.length}`);
|
|
26162
|
+
}
|
|
26163
|
+
if (vcsCtx.issues.length > 0) {
|
|
26164
|
+
vParts.push(compact ? `[VCS] ${vcsCtx.issues.length} open issue(s)` : `Open issues: ${vcsCtx.issues.length}`);
|
|
26165
|
+
}
|
|
26166
|
+
if (vParts.length > 0) proactiveVcsBlock = "\n" + vParts.join("\n");
|
|
26167
|
+
}
|
|
26168
|
+
} catch {
|
|
26169
|
+
}
|
|
26170
|
+
}
|
|
26171
|
+
let recentChangesBlock = "";
|
|
26172
|
+
if (recentChangesPromise) {
|
|
26173
|
+
try {
|
|
26174
|
+
const changes = await recentChangesPromise;
|
|
26175
|
+
if (changes) {
|
|
26176
|
+
recentChangesBlock = compact ? `
|
|
26177
|
+
[RECENT_CHANGES] ${changes.split("\n").slice(0, 3).join("; ")}` : `
|
|
26178
|
+
[RECENT_CHANGES]
|
|
26179
|
+
${changes}`;
|
|
26180
|
+
}
|
|
26181
|
+
} catch {
|
|
26182
|
+
}
|
|
26183
|
+
}
|
|
25630
26184
|
if (sessionManager && result.token_estimate) {
|
|
25631
26185
|
sessionManager.addTokens(result.token_estimate);
|
|
25632
26186
|
}
|
|
@@ -25792,7 +26346,7 @@ ${versionWarningLine}` : "",
|
|
|
25792
26346
|
// Reinforce context() must be called every message
|
|
25793
26347
|
searchRulesLine
|
|
25794
26348
|
].filter(Boolean).join("");
|
|
25795
|
-
const finalContext = postCompactContext + result.context;
|
|
26349
|
+
const finalContext = postCompactContext + result.context + typedContextBlock + proactiveVcsBlock + recentChangesBlock;
|
|
25796
26350
|
const textParts = [
|
|
25797
26351
|
finalContext,
|
|
25798
26352
|
footer,
|
|
@@ -26445,7 +26999,7 @@ Example prompts:
|
|
|
26445
26999
|
workspace_id: external_exports.string().uuid().optional(),
|
|
26446
27000
|
query: external_exports.string().describe("Search query"),
|
|
26447
27001
|
limit: external_exports.number().optional().describe("Maximum results (default: 20)"),
|
|
26448
|
-
sources:
|
|
27002
|
+
sources: stringOrArray(external_exports.string()).optional().describe("Filter by source: github, slack"),
|
|
26449
27003
|
days: external_exports.number().optional().describe("Filter to results within N days"),
|
|
26450
27004
|
sort_by: external_exports.enum(["relevance", "recent", "engagement"]).optional().describe("Sort by: relevance, recent, or engagement")
|
|
26451
27005
|
})
|
|
@@ -26519,7 +27073,7 @@ Example prompts:
|
|
|
26519
27073
|
workspace_id: external_exports.string().uuid().optional(),
|
|
26520
27074
|
knowledge_type: external_exports.enum(["decision", "lesson", "fact", "insight"]).optional().describe("Filter by knowledge type"),
|
|
26521
27075
|
query: external_exports.string().optional().describe("Optional search query to filter knowledge"),
|
|
26522
|
-
sources:
|
|
27076
|
+
sources: stringOrArray(external_exports.string()).optional().describe("Filter by source: github, slack"),
|
|
26523
27077
|
limit: external_exports.number().optional().describe("Maximum items to return (default: 20)")
|
|
26524
27078
|
})
|
|
26525
27079
|
},
|
|
@@ -26684,7 +27238,7 @@ Example: Create a reminder to "Review PR #123" for tomorrow at 10am with high pr
|
|
|
26684
27238
|
content: external_exports.string().describe("Reminder details/description"),
|
|
26685
27239
|
remind_at: external_exports.string().describe('When to remind (ISO 8601 datetime, e.g., "2025-01-15T10:00:00Z")'),
|
|
26686
27240
|
priority: external_exports.enum(["low", "normal", "high", "urgent"]).optional().describe("Priority level (default: normal)"),
|
|
26687
|
-
keywords:
|
|
27241
|
+
keywords: stringOrArray(external_exports.string()).optional().describe("Keywords for contextual surfacing"),
|
|
26688
27242
|
recurrence: external_exports.enum(["daily", "weekly", "monthly"]).optional().describe("Recurrence pattern")
|
|
26689
27243
|
})
|
|
26690
27244
|
},
|
|
@@ -26807,6 +27361,12 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
26807
27361
|
if (authError) return authError;
|
|
26808
27362
|
client.checkAndIndexChangedFiles().catch(() => {
|
|
26809
27363
|
});
|
|
27364
|
+
const folderPathForKeeper = resolveFolderPath(void 0, sessionManager);
|
|
27365
|
+
const projectIdForKeeper = resolveProjectId(void 0);
|
|
27366
|
+
if (folderPathForKeeper && projectIdForKeeper) {
|
|
27367
|
+
indexKeeper.tick(projectIdForKeeper, folderPathForKeeper).catch(() => {
|
|
27368
|
+
});
|
|
27369
|
+
}
|
|
26810
27370
|
const startTime = Date.now();
|
|
26811
27371
|
const modeInput = input.mode || "auto";
|
|
26812
27372
|
const modeRecommendation = recommendSearchMode(input.query);
|
|
@@ -26833,12 +27393,12 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
26833
27393
|
const project = await client.getProject(explicitProjectId);
|
|
26834
27394
|
const projectWorkspaceId = normalizeUuid(project?.workspace_id || project?.workspaceId);
|
|
26835
27395
|
if (workspaceId && projectWorkspaceId && projectWorkspaceId !== workspaceId) {
|
|
26836
|
-
explicitProjectScopeNote = `Explicit project_id ${explicitProjectId} belongs to workspace
|
|
27396
|
+
explicitProjectScopeNote = `Explicit project_id ${explicitProjectId} belongs to a different workspace and was ignored. Do NOT pass this project_id again \u2014 omit it and let the session resolve the correct project scope automatically.`;
|
|
26837
27397
|
explicitProjectId = void 0;
|
|
26838
27398
|
}
|
|
26839
27399
|
} catch (error) {
|
|
26840
27400
|
if (isNotFoundError(error)) {
|
|
26841
|
-
explicitProjectScopeNote = `Explicit project_id ${explicitProjectId} was not found
|
|
27401
|
+
explicitProjectScopeNote = `Explicit project_id ${explicitProjectId} was not found. Do NOT pass this project_id again \u2014 omit it and let the session resolve the correct project scope automatically.`;
|
|
26842
27402
|
explicitProjectId = void 0;
|
|
26843
27403
|
} else {
|
|
26844
27404
|
throw error;
|
|
@@ -27098,6 +27658,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27098
27658
|
hot_paths_hint: hotPathsHint,
|
|
27099
27659
|
output_format: input.output_format || suggestOutputFormat(input.query, requestedMode === "team" ? "hybrid" : requestedMode)
|
|
27100
27660
|
});
|
|
27661
|
+
let parallelRgPromise;
|
|
27662
|
+
if (containsCodeIdentifiers(input.query) && folderPath && requestedMode !== "pattern") {
|
|
27663
|
+
parallelRgPromise = runLocalRipgrep(input.query, folderPath, input.limit || 10);
|
|
27664
|
+
}
|
|
27101
27665
|
if (requestedMode === "team") {
|
|
27102
27666
|
try {
|
|
27103
27667
|
const teamResult = await runSearchForMode("team", {
|
|
@@ -27125,6 +27689,18 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27125
27689
|
try {
|
|
27126
27690
|
const modeResult = await runSearchForMode(requestedMode, paramsForCandidate);
|
|
27127
27691
|
const envelope = extractSearchEnvelope(modeResult.result);
|
|
27692
|
+
if (isScopeInvalidResult(modeResult.result)) {
|
|
27693
|
+
if (!selected) {
|
|
27694
|
+
selected = {
|
|
27695
|
+
index,
|
|
27696
|
+
project_id: candidateProjectId,
|
|
27697
|
+
result: modeResult.result,
|
|
27698
|
+
executedMode: modeResult.executedMode,
|
|
27699
|
+
fallbackNote: modeResult.fallbackNote
|
|
27700
|
+
};
|
|
27701
|
+
}
|
|
27702
|
+
continue;
|
|
27703
|
+
}
|
|
27128
27704
|
if (explicitProjectId && index === 0 && envelope.results.length === 0) {
|
|
27129
27705
|
explicitScopeHadNoResults = true;
|
|
27130
27706
|
}
|
|
@@ -27148,7 +27724,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27148
27724
|
};
|
|
27149
27725
|
}
|
|
27150
27726
|
} catch (error) {
|
|
27151
|
-
if (isNotFoundError(error)) {
|
|
27727
|
+
if (isNotFoundError(error) || isAccessDeniedError(error)) {
|
|
27152
27728
|
continue;
|
|
27153
27729
|
}
|
|
27154
27730
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -27224,7 +27800,59 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27224
27800
|
const docsFallback = requestedMode !== "team" && isDocLookupQuery(input.query) && extractSearchEnvelope(selected.result).results.length === 0 ? await findDocsFallback(workspaceId, candidateProjectIds, input.query, input.limit) : void 0;
|
|
27225
27801
|
const roundTripMs = Date.now() - startTime;
|
|
27226
27802
|
let { results, total } = extractSearchEnvelope(selected.result);
|
|
27227
|
-
|
|
27803
|
+
const scopeInvalid = isScopeInvalidResult(selected.result);
|
|
27804
|
+
for (const r of results) {
|
|
27805
|
+
if (r.file_path) {
|
|
27806
|
+
const canonical = canonicalizeRepoPath(r.file_path);
|
|
27807
|
+
if (canonical !== r.file_path) r.file_path = canonical;
|
|
27808
|
+
}
|
|
27809
|
+
}
|
|
27810
|
+
results = deduplicateSearchResults(results);
|
|
27811
|
+
if (shouldFilterArtifactPaths(selected.executedMode, input.query) && results.length > 0) {
|
|
27812
|
+
const beforeLen = results.length;
|
|
27813
|
+
results = results.filter(
|
|
27814
|
+
(r) => r.file_path ? !isArtifactLikePath(r.file_path) : true
|
|
27815
|
+
);
|
|
27816
|
+
if (results.length < beforeLen) {
|
|
27817
|
+
modeFallbackNote = appendNote(
|
|
27818
|
+
modeFallbackNote,
|
|
27819
|
+
`Filtered ${beforeLen - results.length} artifact/generated path(s).`
|
|
27820
|
+
);
|
|
27821
|
+
}
|
|
27822
|
+
}
|
|
27823
|
+
if (results.length === 0 && !scopeInvalid) {
|
|
27824
|
+
const escalationModes = (() => {
|
|
27825
|
+
switch (selected.executedMode) {
|
|
27826
|
+
case "semantic":
|
|
27827
|
+
return ["hybrid", "keyword"];
|
|
27828
|
+
case "hybrid":
|
|
27829
|
+
return ["keyword"];
|
|
27830
|
+
case "keyword":
|
|
27831
|
+
return ["hybrid"];
|
|
27832
|
+
default:
|
|
27833
|
+
return [];
|
|
27834
|
+
}
|
|
27835
|
+
})();
|
|
27836
|
+
for (const escMode of escalationModes) {
|
|
27837
|
+
try {
|
|
27838
|
+
const escResult = await runSearchForMode(escMode, {
|
|
27839
|
+
...baseParams,
|
|
27840
|
+
workspace_id: workspaceId,
|
|
27841
|
+
project_id: selected.project_id
|
|
27842
|
+
});
|
|
27843
|
+
const escEnvelope = extractSearchEnvelope(escResult.result);
|
|
27844
|
+
if (escEnvelope.results.length > 0) {
|
|
27845
|
+
results = escEnvelope.results;
|
|
27846
|
+
total = escEnvelope.total;
|
|
27847
|
+
modeFallbackNote = appendNote(modeFallbackNote, `${selected.executedMode} returned 0 results; escalated to ${escMode}.`);
|
|
27848
|
+
break;
|
|
27849
|
+
}
|
|
27850
|
+
} catch {
|
|
27851
|
+
}
|
|
27852
|
+
}
|
|
27853
|
+
}
|
|
27854
|
+
const parallelCoversFallback = !!parallelRgPromise && selected.executedMode !== "pattern";
|
|
27855
|
+
if (results.length === 0 && folderPath && !parallelCoversFallback) {
|
|
27228
27856
|
const rgResults = await runLocalRipgrep(input.query, folderPath, input.limit || 10);
|
|
27229
27857
|
if (rgResults.length > 0) {
|
|
27230
27858
|
results = rgResults.map((r) => ({
|
|
@@ -27241,6 +27869,24 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27241
27869
|
);
|
|
27242
27870
|
}
|
|
27243
27871
|
}
|
|
27872
|
+
if (parallelRgPromise) {
|
|
27873
|
+
try {
|
|
27874
|
+
const parallelRgResults = await parallelRgPromise;
|
|
27875
|
+
if (parallelRgResults.length > 0) {
|
|
27876
|
+
const existingPaths = new Set(results.map((r) => r.file_path).filter(Boolean));
|
|
27877
|
+
const newEntries = parallelRgResults.filter((r) => !existingPaths.has(r.file_path)).map((r) => ({ file_path: r.file_path, start_line: r.line, content: r.content, score: r.score, source: "local_ripgrep" }));
|
|
27878
|
+
if (newEntries.length > 0) {
|
|
27879
|
+
results = [...results, ...newEntries];
|
|
27880
|
+
}
|
|
27881
|
+
}
|
|
27882
|
+
} catch {
|
|
27883
|
+
}
|
|
27884
|
+
}
|
|
27885
|
+
const symbolAnchors = extractSymbolAnchors(input.query);
|
|
27886
|
+
if (symbolAnchors.length > 0 && results.length > 1) {
|
|
27887
|
+
results = applySymbolAnchorRerank(results, symbolAnchors);
|
|
27888
|
+
}
|
|
27889
|
+
total = results.length;
|
|
27244
27890
|
const resultPaths = results.map((item) => typeof item?.file_path === "string" ? item.file_path : "").filter(Boolean);
|
|
27245
27891
|
if (resultPaths.length > 0) {
|
|
27246
27892
|
globalHotPathStore.recordPaths(
|
|
@@ -27255,13 +27901,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27255
27901
|
} else {
|
|
27256
27902
|
lines.push(`\u{1F50D} ${total} results for "${input.query}"`);
|
|
27257
27903
|
}
|
|
27258
|
-
if (modeAutoSelected) {
|
|
27904
|
+
if (modeAutoSelected && !(CONCISE_TOOL_TEXT && results.length > 0)) {
|
|
27259
27905
|
lines.push(`Mode auto-selected: \`${requestedMode}\`. ${modeRecommendation.reason}`);
|
|
27260
27906
|
}
|
|
27261
|
-
if (modeFallbackNote) {
|
|
27907
|
+
if (modeFallbackNote && !(CONCISE_TOOL_TEXT && results.length > 0)) {
|
|
27262
27908
|
lines.push(modeFallbackNote);
|
|
27263
27909
|
}
|
|
27264
|
-
if (hotPathsHint?.entries?.length) {
|
|
27910
|
+
if (hotPathsHint?.entries?.length && !CONCISE_TOOL_TEXT) {
|
|
27265
27911
|
lines.push(
|
|
27266
27912
|
`Hot-path hint active (${hotPathsHint.entries.length} paths, confidence ${(hotPathsHint.confidence * 100).toFixed(0)}%).`
|
|
27267
27913
|
);
|
|
@@ -27423,14 +28069,14 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27423
28069
|
"session_snapshot"
|
|
27424
28070
|
]).optional().describe("Event type for capture"),
|
|
27425
28071
|
importance: external_exports.enum(["low", "medium", "high", "critical"]).optional(),
|
|
27426
|
-
tags:
|
|
28072
|
+
tags: stringOrArray(external_exports.string()).optional(),
|
|
27427
28073
|
// Lesson-specific
|
|
27428
28074
|
category: external_exports.enum(["workflow", "code_quality", "verification", "communication", "project_specific"]).optional(),
|
|
27429
28075
|
trigger: external_exports.string().optional().describe("What caused the problem"),
|
|
27430
28076
|
impact: external_exports.string().optional().describe("What went wrong"),
|
|
27431
28077
|
prevention: external_exports.string().optional().describe("How to prevent in future"),
|
|
27432
28078
|
severity: external_exports.enum(["low", "medium", "high", "critical"]).optional(),
|
|
27433
|
-
keywords:
|
|
28079
|
+
keywords: stringOrArray(external_exports.string()).optional(),
|
|
27434
28080
|
// Other params
|
|
27435
28081
|
since: external_exports.string().optional().describe("ISO timestamp for delta"),
|
|
27436
28082
|
limit: external_exports.number().optional(),
|
|
@@ -27457,7 +28103,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27457
28103
|
// Plan-specific params
|
|
27458
28104
|
plan_id: external_exports.string().uuid().optional().describe("Plan ID for get_plan/update_plan"),
|
|
27459
28105
|
description: external_exports.string().optional().describe("Description for capture_plan"),
|
|
27460
|
-
goals:
|
|
28106
|
+
goals: stringOrArray(external_exports.string()).optional().describe("Goals for capture_plan"),
|
|
27461
28107
|
steps: external_exports.array(
|
|
27462
28108
|
external_exports.object({
|
|
27463
28109
|
id: external_exports.string(),
|
|
@@ -27478,7 +28124,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27478
28124
|
// Suggested rules params
|
|
27479
28125
|
rule_id: external_exports.string().uuid().optional().describe("Suggested rule ID for actions"),
|
|
27480
28126
|
rule_action: external_exports.enum(["accept", "reject", "modify"]).optional().describe("Action to perform on suggested rule"),
|
|
27481
|
-
modified_keywords:
|
|
28127
|
+
modified_keywords: stringOrArray(external_exports.string()).optional().describe("Modified keywords when action is modify"),
|
|
27482
28128
|
modified_instruction: external_exports.string().optional().describe("Modified instruction when action is modify"),
|
|
27483
28129
|
min_confidence: external_exports.number().optional().describe("Minimum confidence threshold for listing rules")
|
|
27484
28130
|
})
|
|
@@ -27579,7 +28225,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27579
28225
|
context_hint: input.query,
|
|
27580
28226
|
limit: input.limit
|
|
27581
28227
|
});
|
|
27582
|
-
let lessons = result?.data?.lessons || result?.lessons || [];
|
|
28228
|
+
let lessons = Array.isArray(result) ? result : result?.data?.lessons || result?.lessons || [];
|
|
27583
28229
|
if (Array.isArray(lessons) && lessons.length > 1) {
|
|
27584
28230
|
const seen = /* @__PURE__ */ new Set();
|
|
27585
28231
|
lessons = lessons.filter((lesson) => {
|
|
@@ -27588,10 +28234,8 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27588
28234
|
seen.add(key);
|
|
27589
28235
|
return true;
|
|
27590
28236
|
});
|
|
27591
|
-
if (result?.data?.lessons) result.data.lessons = lessons;
|
|
27592
|
-
else if (result?.lessons) result.lessons = lessons;
|
|
27593
28237
|
}
|
|
27594
|
-
const resultWithHint = Array.isArray(lessons) && lessons.length === 0 ? {
|
|
28238
|
+
const resultWithHint = Array.isArray(lessons) && lessons.length === 0 ? { lessons: [], hint: getEmptyStateHint("get_lessons") } : { lessons };
|
|
27595
28239
|
return {
|
|
27596
28240
|
content: [{ type: "text", text: formatContent(resultWithHint) }]
|
|
27597
28241
|
};
|
|
@@ -27742,6 +28386,20 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27742
28386
|
if (!input.query) {
|
|
27743
28387
|
return errorResult("decision_trace requires: query");
|
|
27744
28388
|
}
|
|
28389
|
+
const doFallback = async () => {
|
|
28390
|
+
const events = await client.listMemoryEvents({
|
|
28391
|
+
workspace_id: workspaceId,
|
|
28392
|
+
project_id: projectId,
|
|
28393
|
+
limit: 50
|
|
28394
|
+
}).catch(() => ({ items: [] }));
|
|
28395
|
+
const decisions = (events?.items || []).filter((item) => isDecisionResult(item));
|
|
28396
|
+
const queryLower = (input.query || "").toLowerCase();
|
|
28397
|
+
const matched = decisions.filter((d) => {
|
|
28398
|
+
const text = `${d.title || ""} ${d.content || ""}`.toLowerCase();
|
|
28399
|
+
return queryLower.split(/\s+/).some((w) => w.length > 2 && text.includes(w));
|
|
28400
|
+
}).slice(0, input.limit || 10);
|
|
28401
|
+
return matched;
|
|
28402
|
+
};
|
|
27745
28403
|
try {
|
|
27746
28404
|
const result = await client.decisionTrace({
|
|
27747
28405
|
workspace_id: workspaceId,
|
|
@@ -27750,23 +28408,30 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27750
28408
|
include_impact: input.include_impact,
|
|
27751
28409
|
limit: input.limit
|
|
27752
28410
|
});
|
|
28411
|
+
const resultDecisions = result?.decisions || result?.data?.decisions || [];
|
|
28412
|
+
if (Array.isArray(resultDecisions) && resultDecisions.length === 0) {
|
|
28413
|
+
const fallbackDecisions = await doFallback();
|
|
28414
|
+
if (fallbackDecisions.length > 0) {
|
|
28415
|
+
return {
|
|
28416
|
+
content: [{
|
|
28417
|
+
type: "text",
|
|
28418
|
+
text: formatContent({
|
|
28419
|
+
decisions: fallbackDecisions,
|
|
28420
|
+
total: fallbackDecisions.length,
|
|
28421
|
+
fallback_reason: "api_empty_result",
|
|
28422
|
+
hint: "Decision trace used event listing fallback because the API returned no results."
|
|
28423
|
+
})
|
|
28424
|
+
}]
|
|
28425
|
+
};
|
|
28426
|
+
}
|
|
28427
|
+
}
|
|
27753
28428
|
return {
|
|
27754
28429
|
content: [{ type: "text", text: formatContent(result) }]
|
|
27755
28430
|
};
|
|
27756
28431
|
} catch (err) {
|
|
27757
28432
|
const isTimeout = err?.message?.toLowerCase().includes("timeout") || err?.message?.toLowerCase().includes("embedding timed out");
|
|
27758
28433
|
if (!isTimeout) throw err;
|
|
27759
|
-
const
|
|
27760
|
-
workspace_id: workspaceId,
|
|
27761
|
-
project_id: projectId,
|
|
27762
|
-
limit: 50
|
|
27763
|
-
}).catch(() => ({ items: [] }));
|
|
27764
|
-
const decisions = (events?.items || []).filter((item) => isDecisionResult(item));
|
|
27765
|
-
const queryLower = input.query.toLowerCase();
|
|
27766
|
-
const matched = decisions.filter((d) => {
|
|
27767
|
-
const text = `${d.title || ""} ${d.content || ""}`.toLowerCase();
|
|
27768
|
-
return queryLower.split(/\s+/).some((w) => w.length > 2 && text.includes(w));
|
|
27769
|
-
}).slice(0, input.limit || 10);
|
|
28434
|
+
const matched = await doFallback();
|
|
27770
28435
|
return {
|
|
27771
28436
|
content: [{
|
|
27772
28437
|
type: "text",
|
|
@@ -28324,9 +28989,9 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
28324
28989
|
status: external_exports.enum(["pending", "in_progress", "completed", "blocked", "cancelled"]).optional().describe("Backward-compatible alias for task_status in task actions"),
|
|
28325
28990
|
priority: external_exports.enum(["low", "medium", "high", "urgent"]).optional().describe("Task priority"),
|
|
28326
28991
|
order: external_exports.number().optional().describe("Task order within plan"),
|
|
28327
|
-
task_ids:
|
|
28992
|
+
task_ids: stringOrArray(external_exports.string().uuid()).optional().describe("Task IDs for reorder_tasks"),
|
|
28328
28993
|
blocked_reason: external_exports.string().optional().describe("Reason when task is blocked"),
|
|
28329
|
-
tags:
|
|
28994
|
+
tags: stringOrArray(external_exports.string()).optional().describe("Tags for event or task categorization"),
|
|
28330
28995
|
// Batch import params
|
|
28331
28996
|
events: external_exports.array(
|
|
28332
28997
|
external_exports.object({
|
|
@@ -28349,7 +29014,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
28349
29014
|
symbol_name: external_exports.string().optional()
|
|
28350
29015
|
})
|
|
28351
29016
|
).optional(),
|
|
28352
|
-
tags:
|
|
29017
|
+
tags: stringOrArray(external_exports.string()).optional(),
|
|
28353
29018
|
occurred_at: external_exports.string().optional().describe("ISO timestamp for when the event occurred")
|
|
28354
29019
|
})
|
|
28355
29020
|
).optional().describe("Array of events for import_batch action"),
|
|
@@ -29941,6 +30606,19 @@ ${formatContent(response)}`
|
|
|
29941
30606
|
}
|
|
29942
30607
|
const validPath = await validateReadableDirectory(ingestPath);
|
|
29943
30608
|
if (!validPath.ok) {
|
|
30609
|
+
try {
|
|
30610
|
+
const pathExists = await fs6.promises.stat(ingestPath).then(() => true).catch(() => false);
|
|
30611
|
+
if (!pathExists) {
|
|
30612
|
+
const apiResult = await client.ingestFromPath(projectId, ingestPath, {
|
|
30613
|
+
force: input.force
|
|
30614
|
+
});
|
|
30615
|
+
return {
|
|
30616
|
+
content: [{ type: "text", text: `Delegated ingest to API for path: ${ingestPath}
|
|
30617
|
+
${formatContent(apiResult)}` }]
|
|
30618
|
+
};
|
|
30619
|
+
}
|
|
30620
|
+
} catch {
|
|
30621
|
+
}
|
|
29944
30622
|
return errorResult(validPath.error);
|
|
29945
30623
|
}
|
|
29946
30624
|
const ingestOptions = {
|
|
@@ -30050,7 +30728,7 @@ Uncommitted changes: ${changes.diff_stat.summary}
|
|
|
30050
30728
|
// Index settings params (for update)
|
|
30051
30729
|
branch_policy: external_exports.enum(["default_branch_wins", "newest_wins", "feature_branch_wins"]).optional().describe("Which branch takes priority: default_branch_wins (default), newest_wins, feature_branch_wins"),
|
|
30052
30730
|
conflict_resolution: external_exports.enum(["newest_timestamp", "default_branch", "manual"]).optional().describe("How to resolve conflicts: newest_timestamp (default), default_branch, manual"),
|
|
30053
|
-
allowed_machines:
|
|
30731
|
+
allowed_machines: stringOrArray(external_exports.string()).optional().describe("List of allowed machine IDs (empty = all allowed)"),
|
|
30054
30732
|
auto_sync_enabled: external_exports.boolean().optional().describe("Whether to auto-sync from all machines (default: true)"),
|
|
30055
30733
|
max_machines: external_exports.number().optional().describe("Maximum machines allowed to index (0 = unlimited)"),
|
|
30056
30734
|
// Pagination
|
|
@@ -30229,7 +30907,7 @@ Uncommitted changes: ${changes.diff_stat.summary}
|
|
|
30229
30907
|
remind_at: external_exports.string().optional().describe("ISO 8601 datetime"),
|
|
30230
30908
|
priority: external_exports.enum(["low", "normal", "high", "urgent"]).optional(),
|
|
30231
30909
|
recurrence: external_exports.enum(["daily", "weekly", "monthly"]).optional(),
|
|
30232
|
-
keywords:
|
|
30910
|
+
keywords: stringOrArray(external_exports.string()).optional(),
|
|
30233
30911
|
// Snooze params
|
|
30234
30912
|
until: external_exports.string().optional().describe("ISO 8601 datetime"),
|
|
30235
30913
|
// Filter params
|
|
@@ -30973,7 +31651,7 @@ Example workflow:
|
|
|
30973
31651
|
),
|
|
30974
31652
|
fps: external_exports.number().optional().describe("Frames per second for remotion format (default: 30)"),
|
|
30975
31653
|
// Common params
|
|
30976
|
-
tags:
|
|
31654
|
+
tags: stringOrArray(external_exports.string()).optional().describe("Tags to associate with media"),
|
|
30977
31655
|
limit: external_exports.number().optional().describe("Maximum results to return")
|
|
30978
31656
|
})
|
|
30979
31657
|
},
|
|
@@ -31372,7 +32050,7 @@ Content ID: ${input.content_id}`
|
|
|
31372
32050
|
category: external_exports.string().optional(),
|
|
31373
32051
|
// For editor_rules
|
|
31374
32052
|
folder_path: external_exports.string().optional(),
|
|
31375
|
-
editors:
|
|
32053
|
+
editors: stringOrArray(external_exports.string()).optional(),
|
|
31376
32054
|
mode: external_exports.enum(["minimal", "full", "bootstrap"]).optional(),
|
|
31377
32055
|
dry_run: external_exports.boolean().optional(),
|
|
31378
32056
|
workspace_id: external_exports.string().uuid().optional(),
|
|
@@ -31525,13 +32203,35 @@ Each domain tool has an 'action' parameter for specific operations.` : "";
|
|
|
31525
32203
|
"vcs",
|
|
31526
32204
|
{
|
|
31527
32205
|
title: "Version Control",
|
|
31528
|
-
description: `Git version control
|
|
32206
|
+
description: `Git version control and remote repo operations.
|
|
32207
|
+
|
|
32208
|
+
Local git actions: status, diff, log, blame, branches, stash_list
|
|
32209
|
+
Remote API actions: list_repos, get_repo, sync_repo, list_pulls, get_pull, get_pull_diff, get_pull_comments, get_pull_commits, get_pull_checks, get_pull_summary, summarize_pull, review_pull, comment_pull, merge_pull, list_issues, get_issue, create_issue, update_issue, comment_issue, list_commits, get_commit, get_commit_diff, compare_refs, list_branches_remote, list_tags, get_tree, get_blob, search_code, search_vcs, get_activity, list_notifications, mark_notification_read, mark_all_notifications_read, list_links, create_link, delete_link, list_automations, create_automation, update_automation, delete_automation, register_webhook, unregister_webhook`,
|
|
31529
32210
|
inputSchema: external_exports.object({
|
|
31530
|
-
action: external_exports.
|
|
31531
|
-
|
|
31532
|
-
|
|
31533
|
-
|
|
31534
|
-
|
|
32211
|
+
action: external_exports.string().describe("VCS action to perform"),
|
|
32212
|
+
workspace_id: external_exports.string().uuid().optional().describe("Workspace ID for remote VCS actions"),
|
|
32213
|
+
repo_ref: external_exports.string().optional().describe("Repository reference (owner/repo) for remote actions"),
|
|
32214
|
+
repo_id: external_exports.string().optional().describe("Repository ID for remote actions"),
|
|
32215
|
+
path: external_exports.string().optional().describe("File path for diff/blame/tree/blob"),
|
|
32216
|
+
ref: external_exports.string().optional().describe("Git ref (branch, tag, commit)"),
|
|
32217
|
+
base_ref: external_exports.string().optional().describe("Base ref for compare_refs"),
|
|
32218
|
+
limit: external_exports.number().optional().describe("Max entries (default: 20)"),
|
|
32219
|
+
staged: external_exports.boolean().optional().describe("Show staged changes only (for diff)"),
|
|
32220
|
+
pull_number: external_exports.number().optional().describe("Pull request number"),
|
|
32221
|
+
issue_number: external_exports.number().optional().describe("Issue number"),
|
|
32222
|
+
notification_id: external_exports.string().optional().describe("Notification ID"),
|
|
32223
|
+
link_id: external_exports.string().optional().describe("Link ID"),
|
|
32224
|
+
automation_id: external_exports.string().optional().describe("Automation ID"),
|
|
32225
|
+
title: external_exports.string().optional().describe("Title for create_issue"),
|
|
32226
|
+
body: external_exports.string().optional().describe("Body content"),
|
|
32227
|
+
state: external_exports.string().optional().describe("State filter (open/closed)"),
|
|
32228
|
+
labels: stringOrArray(external_exports.string()).optional().describe("Labels for issues"),
|
|
32229
|
+
per_page: external_exports.number().optional().describe("Results per page"),
|
|
32230
|
+
page: external_exports.number().optional().describe("Page number"),
|
|
32231
|
+
event: external_exports.string().optional().describe("Review event (APPROVE/REQUEST_CHANGES/COMMENT)"),
|
|
32232
|
+
provider: external_exports.string().optional().describe("VCS provider (github/gitlab/bitbucket)"),
|
|
32233
|
+
query: external_exports.string().optional().describe("Search query"),
|
|
32234
|
+
data: external_exports.record(external_exports.any()).optional().describe("Additional data for create/update operations")
|
|
31535
32235
|
})
|
|
31536
32236
|
},
|
|
31537
32237
|
async (input) => {
|
|
@@ -31551,60 +32251,164 @@ Each domain tool has an 'action' parameter for specific operations.` : "";
|
|
|
31551
32251
|
throw err;
|
|
31552
32252
|
}
|
|
31553
32253
|
};
|
|
31554
|
-
|
|
31555
|
-
|
|
31556
|
-
|
|
31557
|
-
|
|
31558
|
-
|
|
31559
|
-
|
|
31560
|
-
|
|
31561
|
-
|
|
31562
|
-
|
|
31563
|
-
|
|
31564
|
-
|
|
31565
|
-
|
|
31566
|
-
|
|
31567
|
-
|
|
31568
|
-
|
|
31569
|
-
|
|
31570
|
-
|
|
31571
|
-
|
|
31572
|
-
|
|
31573
|
-
|
|
31574
|
-
|
|
31575
|
-
|
|
31576
|
-
|
|
31577
|
-
|
|
31578
|
-
|
|
31579
|
-
|
|
31580
|
-
|
|
31581
|
-
|
|
31582
|
-
|
|
31583
|
-
|
|
31584
|
-
|
|
31585
|
-
|
|
31586
|
-
|
|
31587
|
-
|
|
31588
|
-
|
|
31589
|
-
|
|
31590
|
-
|
|
31591
|
-
|
|
31592
|
-
|
|
31593
|
-
|
|
31594
|
-
|
|
31595
|
-
|
|
31596
|
-
|
|
31597
|
-
|
|
31598
|
-
|
|
31599
|
-
|
|
31600
|
-
|
|
31601
|
-
|
|
31602
|
-
|
|
31603
|
-
|
|
31604
|
-
|
|
32254
|
+
const localActions = /* @__PURE__ */ new Set(["status", "diff", "log", "blame", "branches", "stash_list"]);
|
|
32255
|
+
if (localActions.has(input.action)) {
|
|
32256
|
+
switch (input.action) {
|
|
32257
|
+
case "status": {
|
|
32258
|
+
const output = await runGit(["status", "--porcelain=v2", "--branch"]);
|
|
32259
|
+
return { content: [{ type: "text", text: output || "Working tree clean." }] };
|
|
32260
|
+
}
|
|
32261
|
+
case "diff": {
|
|
32262
|
+
const args = ["diff"];
|
|
32263
|
+
if (input.staged) args.push("--staged");
|
|
32264
|
+
if (input.ref) args.push(input.ref);
|
|
32265
|
+
if (input.path) args.push("--", input.path);
|
|
32266
|
+
const output = await runGit(args);
|
|
32267
|
+
return { content: [{ type: "text", text: output || "No changes." }] };
|
|
32268
|
+
}
|
|
32269
|
+
case "log": {
|
|
32270
|
+
const limit = input.limit || 20;
|
|
32271
|
+
const args = ["log", `--max-count=${limit}`, "--format=%H %ai %an <%ae>%n %s", "--no-decorate"];
|
|
32272
|
+
if (input.ref) args.push(input.ref);
|
|
32273
|
+
if (input.path) args.push("--", input.path);
|
|
32274
|
+
const output = await runGit(args);
|
|
32275
|
+
return { content: [{ type: "text", text: output || "No commits." }] };
|
|
32276
|
+
}
|
|
32277
|
+
case "blame": {
|
|
32278
|
+
if (!input.path) return errorResult("blame requires: path");
|
|
32279
|
+
const args = ["blame", "--porcelain", input.path];
|
|
32280
|
+
if (input.ref) args.splice(1, 0, input.ref);
|
|
32281
|
+
const output = await runGit(args);
|
|
32282
|
+
const summaryLines = [];
|
|
32283
|
+
const blameLines = output.split("\n");
|
|
32284
|
+
let currentCommit = "";
|
|
32285
|
+
let currentAuthor = "";
|
|
32286
|
+
let lineNum = 0;
|
|
32287
|
+
for (const line of blameLines) {
|
|
32288
|
+
if (/^[0-9a-f]{40}\s/.test(line)) {
|
|
32289
|
+
const parts = line.split(" ");
|
|
32290
|
+
currentCommit = parts[0].slice(0, 8);
|
|
32291
|
+
lineNum = parseInt(parts[2] || "0", 10);
|
|
32292
|
+
} else if (line.startsWith("author ")) {
|
|
32293
|
+
currentAuthor = line.slice(7);
|
|
32294
|
+
} else if (line.startsWith(" ")) {
|
|
32295
|
+
summaryLines.push(`${currentCommit} (${currentAuthor}) L${lineNum}: ${line.slice(1)}`);
|
|
32296
|
+
}
|
|
32297
|
+
}
|
|
32298
|
+
return { content: [{ type: "text", text: summaryLines.join("\n") || output }] };
|
|
32299
|
+
}
|
|
32300
|
+
case "branches": {
|
|
32301
|
+
const output = await runGit(["branch", "-a", "--format=%(refname:short) %(objectname:short) %(subject)"]);
|
|
32302
|
+
return { content: [{ type: "text", text: output || "No branches." }] };
|
|
32303
|
+
}
|
|
32304
|
+
case "stash_list": {
|
|
32305
|
+
const output = await runGit(["stash", "list"]);
|
|
32306
|
+
return { content: [{ type: "text", text: output || "No stashes." }] };
|
|
32307
|
+
}
|
|
32308
|
+
default:
|
|
32309
|
+
return errorResult(`Unknown local vcs action: ${input.action}`);
|
|
31605
32310
|
}
|
|
32311
|
+
}
|
|
32312
|
+
let wsId = resolveWorkspaceId(input.workspace_id);
|
|
32313
|
+
if (!wsId) {
|
|
32314
|
+
return errorResult("Remote VCS actions require a workspace_id. Call init() first or pass workspace_id.");
|
|
32315
|
+
}
|
|
32316
|
+
const resolveRepoPath = () => {
|
|
32317
|
+
if (input.repo_id) return `repos/${input.repo_id}`;
|
|
32318
|
+
if (input.repo_ref) return `repos/${encodeURIComponent(input.repo_ref)}`;
|
|
32319
|
+
return "repos";
|
|
32320
|
+
};
|
|
32321
|
+
const repoPath = resolveRepoPath();
|
|
32322
|
+
const q = {
|
|
32323
|
+
state: input.state,
|
|
32324
|
+
per_page: input.per_page,
|
|
32325
|
+
page: input.page
|
|
32326
|
+
};
|
|
32327
|
+
switch (input.action) {
|
|
32328
|
+
case "list_repos":
|
|
32329
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: "repos", query: q })) }] };
|
|
32330
|
+
case "get_repo":
|
|
32331
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: repoPath })) }] };
|
|
32332
|
+
case "sync_repo":
|
|
32333
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/sync` })) }] };
|
|
32334
|
+
case "list_pulls":
|
|
32335
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls`, query: q })) }] };
|
|
32336
|
+
case "get_pull":
|
|
32337
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}` })) }] };
|
|
32338
|
+
case "get_pull_diff":
|
|
32339
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/diff` })) }] };
|
|
32340
|
+
case "get_pull_comments":
|
|
32341
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/comments` })) }] };
|
|
32342
|
+
case "get_pull_commits":
|
|
32343
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/commits` })) }] };
|
|
32344
|
+
case "get_pull_checks":
|
|
32345
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/checks` })) }] };
|
|
32346
|
+
case "get_pull_summary":
|
|
32347
|
+
case "summarize_pull":
|
|
32348
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/summary` })) }] };
|
|
32349
|
+
case "review_pull":
|
|
32350
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/pulls/${input.pull_number}/reviews`, body: { event: input.event || "COMMENT", body: input.body } })) }] };
|
|
32351
|
+
case "comment_pull":
|
|
32352
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/pulls/${input.pull_number}/comments`, body: { body: input.body } })) }] };
|
|
32353
|
+
case "merge_pull":
|
|
32354
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: `${repoPath}/pulls/${input.pull_number}/merge`, body: input.data })) }] };
|
|
32355
|
+
case "list_issues":
|
|
32356
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/issues`, query: q })) }] };
|
|
32357
|
+
case "get_issue":
|
|
32358
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/issues/${input.issue_number}` })) }] };
|
|
32359
|
+
case "create_issue":
|
|
32360
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/issues`, body: { title: input.title, body: input.body, labels: input.labels } })) }] };
|
|
32361
|
+
case "update_issue":
|
|
32362
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PATCH", path: `${repoPath}/issues/${input.issue_number}`, body: { title: input.title, body: input.body, state: input.state, labels: input.labels, ...input.data } })) }] };
|
|
32363
|
+
case "comment_issue":
|
|
32364
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/issues/${input.issue_number}/comments`, body: { body: input.body } })) }] };
|
|
32365
|
+
case "list_commits":
|
|
32366
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/commits`, query: { ...q, ref: input.ref } })) }] };
|
|
32367
|
+
case "get_commit":
|
|
32368
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/commits/${input.ref}` })) }] };
|
|
32369
|
+
case "get_commit_diff":
|
|
32370
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/commits/${input.ref}/diff` })) }] };
|
|
32371
|
+
case "compare_refs":
|
|
32372
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/compare/${input.base_ref}...${input.ref}` })) }] };
|
|
32373
|
+
case "list_branches_remote":
|
|
32374
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/branches`, query: q })) }] };
|
|
32375
|
+
case "list_tags":
|
|
32376
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/tags`, query: q })) }] };
|
|
32377
|
+
case "get_tree":
|
|
32378
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/tree`, query: { ref: input.ref, path: input.path } })) }] };
|
|
32379
|
+
case "get_blob":
|
|
32380
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/blob`, query: { ref: input.ref, path: input.path } })) }] };
|
|
32381
|
+
case "search_code":
|
|
32382
|
+
case "search_vcs":
|
|
32383
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/search`, query: { q: input.query, ...q } })) }] };
|
|
32384
|
+
case "get_activity":
|
|
32385
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/activity`, query: { limit: input.limit } })) }] };
|
|
32386
|
+
case "list_notifications":
|
|
32387
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: "notifications", query: q })) }] };
|
|
32388
|
+
case "mark_notification_read":
|
|
32389
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: `notifications/${input.notification_id}/read` })) }] };
|
|
32390
|
+
case "mark_all_notifications_read":
|
|
32391
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: "notifications/read-all" })) }] };
|
|
32392
|
+
case "list_links":
|
|
32393
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/links` })) }] };
|
|
32394
|
+
case "create_link":
|
|
32395
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/links`, body: input.data })) }] };
|
|
32396
|
+
case "delete_link":
|
|
32397
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "DELETE", path: `${repoPath}/links/${input.link_id}` })) }] };
|
|
32398
|
+
case "list_automations":
|
|
32399
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/automations` })) }] };
|
|
32400
|
+
case "create_automation":
|
|
32401
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/automations`, body: input.data })) }] };
|
|
32402
|
+
case "update_automation":
|
|
32403
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: `${repoPath}/automations/${input.automation_id}`, body: input.data })) }] };
|
|
32404
|
+
case "delete_automation":
|
|
32405
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "DELETE", path: `${repoPath}/automations/${input.automation_id}` })) }] };
|
|
32406
|
+
case "register_webhook":
|
|
32407
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/webhooks`, body: input.data })) }] };
|
|
32408
|
+
case "unregister_webhook":
|
|
32409
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "DELETE", path: `${repoPath}/webhooks`, body: input.data })) }] };
|
|
31606
32410
|
default:
|
|
31607
|
-
return errorResult(`Unknown vcs action: ${input.action}
|
|
32411
|
+
return errorResult(`Unknown vcs action: ${input.action}. Use 'status', 'diff', 'log', 'blame', 'branches', 'stash_list' for local git, or remote API actions like 'list_repos', 'list_pulls', 'list_issues', etc.`);
|
|
31608
32412
|
}
|
|
31609
32413
|
}
|
|
31610
32414
|
);
|
|
@@ -33403,13 +34207,13 @@ async function runHttpGateway() {
|
|
|
33403
34207
|
// src/index.ts
|
|
33404
34208
|
init_version();
|
|
33405
34209
|
import { existsSync as existsSync16, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
33406
|
-
import { homedir as
|
|
34210
|
+
import { homedir as homedir20 } from "os";
|
|
33407
34211
|
import { join as join22 } from "path";
|
|
33408
34212
|
|
|
33409
34213
|
// src/setup.ts
|
|
33410
34214
|
import * as fs8 from "node:fs/promises";
|
|
33411
34215
|
import * as path9 from "node:path";
|
|
33412
|
-
import { homedir as
|
|
34216
|
+
import { homedir as homedir8 } from "node:os";
|
|
33413
34217
|
import { stdin, stdout } from "node:process";
|
|
33414
34218
|
import { createInterface } from "node:readline/promises";
|
|
33415
34219
|
init_rules_templates();
|
|
@@ -33418,12 +34222,12 @@ init_version();
|
|
|
33418
34222
|
// src/credentials.ts
|
|
33419
34223
|
import * as fs7 from "node:fs/promises";
|
|
33420
34224
|
import * as path8 from "node:path";
|
|
33421
|
-
import { homedir as
|
|
34225
|
+
import { homedir as homedir7 } from "node:os";
|
|
33422
34226
|
function normalizeApiUrl(input) {
|
|
33423
34227
|
return String(input ?? "").trim().replace(/\/+$/, "");
|
|
33424
34228
|
}
|
|
33425
34229
|
function credentialsFilePath() {
|
|
33426
|
-
return path8.join(
|
|
34230
|
+
return path8.join(homedir7(), ".contextstream", "credentials.json");
|
|
33427
34231
|
}
|
|
33428
34232
|
function isRecord(value) {
|
|
33429
34233
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -33702,7 +34506,7 @@ async function upsertTextFile(filePath, content, _marker) {
|
|
|
33702
34506
|
return replaced.status;
|
|
33703
34507
|
}
|
|
33704
34508
|
function globalRulesPathForEditor(editor) {
|
|
33705
|
-
const home =
|
|
34509
|
+
const home = homedir8();
|
|
33706
34510
|
switch (editor) {
|
|
33707
34511
|
case "codex":
|
|
33708
34512
|
return path9.join(home, ".codex", "AGENTS.md");
|
|
@@ -33737,7 +34541,7 @@ async function anyPathExists(paths) {
|
|
|
33737
34541
|
return false;
|
|
33738
34542
|
}
|
|
33739
34543
|
async function isCodexInstalled() {
|
|
33740
|
-
const home =
|
|
34544
|
+
const home = homedir8();
|
|
33741
34545
|
const envHome = process.env.CODEX_HOME;
|
|
33742
34546
|
const candidates = [
|
|
33743
34547
|
envHome,
|
|
@@ -33748,7 +34552,7 @@ async function isCodexInstalled() {
|
|
|
33748
34552
|
return anyPathExists(candidates);
|
|
33749
34553
|
}
|
|
33750
34554
|
function openCodeConfigPath() {
|
|
33751
|
-
const home =
|
|
34555
|
+
const home = homedir8();
|
|
33752
34556
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
33753
34557
|
if (process.platform === "win32") {
|
|
33754
34558
|
const appData = process.env.APPDATA || path9.join(home, "AppData", "Roaming");
|
|
@@ -33760,7 +34564,7 @@ function openCodeConfigPath() {
|
|
|
33760
34564
|
async function isOpenCodeInstalled() {
|
|
33761
34565
|
const configPath = openCodeConfigPath();
|
|
33762
34566
|
const configDir = path9.dirname(configPath);
|
|
33763
|
-
const home =
|
|
34567
|
+
const home = homedir8();
|
|
33764
34568
|
const candidates = [
|
|
33765
34569
|
configDir,
|
|
33766
34570
|
configPath,
|
|
@@ -33770,7 +34574,7 @@ async function isOpenCodeInstalled() {
|
|
|
33770
34574
|
return anyPathExists(candidates);
|
|
33771
34575
|
}
|
|
33772
34576
|
async function isClaudeInstalled() {
|
|
33773
|
-
const home =
|
|
34577
|
+
const home = homedir8();
|
|
33774
34578
|
const candidates = [path9.join(home, ".claude"), path9.join(home, ".config", "claude")];
|
|
33775
34579
|
const desktopConfig = claudeDesktopConfigPath();
|
|
33776
34580
|
if (desktopConfig) candidates.push(desktopConfig);
|
|
@@ -33783,7 +34587,7 @@ async function isClaudeInstalled() {
|
|
|
33783
34587
|
return anyPathExists(candidates);
|
|
33784
34588
|
}
|
|
33785
34589
|
async function isClineInstalled() {
|
|
33786
|
-
const home =
|
|
34590
|
+
const home = homedir8();
|
|
33787
34591
|
const candidates = [
|
|
33788
34592
|
path9.join(home, "Documents", "Cline"),
|
|
33789
34593
|
path9.join(home, ".cline"),
|
|
@@ -33792,7 +34596,7 @@ async function isClineInstalled() {
|
|
|
33792
34596
|
return anyPathExists(candidates);
|
|
33793
34597
|
}
|
|
33794
34598
|
async function isCopilotInstalled() {
|
|
33795
|
-
const home =
|
|
34599
|
+
const home = homedir8();
|
|
33796
34600
|
const candidates = [
|
|
33797
34601
|
path9.join(home, ".copilot"),
|
|
33798
34602
|
path9.join(home, ".config", "github-copilot"),
|
|
@@ -33802,7 +34606,7 @@ async function isCopilotInstalled() {
|
|
|
33802
34606
|
return anyPathExists(candidates);
|
|
33803
34607
|
}
|
|
33804
34608
|
async function isKiloInstalled() {
|
|
33805
|
-
const home =
|
|
34609
|
+
const home = homedir8();
|
|
33806
34610
|
const candidates = [
|
|
33807
34611
|
kiloConfigDir(),
|
|
33808
34612
|
path9.join(home, ".kilocode"),
|
|
@@ -33811,17 +34615,17 @@ async function isKiloInstalled() {
|
|
|
33811
34615
|
return anyPathExists(candidates);
|
|
33812
34616
|
}
|
|
33813
34617
|
async function isRooInstalled() {
|
|
33814
|
-
const home =
|
|
34618
|
+
const home = homedir8();
|
|
33815
34619
|
const candidates = [path9.join(home, ".roo"), path9.join(home, ".config", "roo")];
|
|
33816
34620
|
return anyPathExists(candidates);
|
|
33817
34621
|
}
|
|
33818
34622
|
async function isAiderInstalled() {
|
|
33819
|
-
const home =
|
|
34623
|
+
const home = homedir8();
|
|
33820
34624
|
const candidates = [path9.join(home, ".aider.conf.yml"), path9.join(home, ".config", "aider")];
|
|
33821
34625
|
return anyPathExists(candidates);
|
|
33822
34626
|
}
|
|
33823
34627
|
async function isCursorInstalled() {
|
|
33824
|
-
const home =
|
|
34628
|
+
const home = homedir8();
|
|
33825
34629
|
const candidates = [path9.join(home, ".cursor")];
|
|
33826
34630
|
if (process.platform === "darwin") {
|
|
33827
34631
|
candidates.push("/Applications/Cursor.app");
|
|
@@ -33844,7 +34648,7 @@ async function isCursorInstalled() {
|
|
|
33844
34648
|
return anyPathExists(candidates);
|
|
33845
34649
|
}
|
|
33846
34650
|
async function isWindsurfInstalled() {
|
|
33847
|
-
const home =
|
|
34651
|
+
const home = homedir8();
|
|
33848
34652
|
const candidates = [path9.join(home, ".codeium", "windsurf")];
|
|
33849
34653
|
if (process.platform === "darwin") {
|
|
33850
34654
|
candidates.push("/Applications/Windsurf.app");
|
|
@@ -33867,7 +34671,7 @@ async function isWindsurfInstalled() {
|
|
|
33867
34671
|
return anyPathExists(candidates);
|
|
33868
34672
|
}
|
|
33869
34673
|
async function isAntigravityInstalled() {
|
|
33870
|
-
const home =
|
|
34674
|
+
const home = homedir8();
|
|
33871
34675
|
const candidates = [path9.join(home, ".gemini")];
|
|
33872
34676
|
if (process.platform === "darwin") {
|
|
33873
34677
|
candidates.push("/Applications/Antigravity.app");
|
|
@@ -34071,7 +34875,7 @@ function buildContextStreamOpenCodeLocalServer(params) {
|
|
|
34071
34875
|
};
|
|
34072
34876
|
}
|
|
34073
34877
|
function kiloConfigDir() {
|
|
34074
|
-
const home =
|
|
34878
|
+
const home = homedir8();
|
|
34075
34879
|
if (process.platform === "win32") {
|
|
34076
34880
|
const appData = process.env.APPDATA || path9.join(home, "AppData", "Roaming");
|
|
34077
34881
|
return path9.join(appData, "kilo");
|
|
@@ -34206,7 +35010,7 @@ async function upsertOpenCodeMcpConfig(filePath, server) {
|
|
|
34206
35010
|
return before === after ? "skipped" : "updated";
|
|
34207
35011
|
}
|
|
34208
35012
|
function claudeDesktopConfigPath() {
|
|
34209
|
-
const home =
|
|
35013
|
+
const home = homedir8();
|
|
34210
35014
|
if (process.platform === "darwin") {
|
|
34211
35015
|
return path9.join(
|
|
34212
35016
|
home,
|
|
@@ -34985,7 +35789,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
34985
35789
|
if (mcpScope === "project" && editor !== "codex") continue;
|
|
34986
35790
|
try {
|
|
34987
35791
|
if (editor === "codex") {
|
|
34988
|
-
const filePath = path9.join(
|
|
35792
|
+
const filePath = path9.join(homedir8(), ".codex", "config.toml");
|
|
34989
35793
|
if (dryRun) {
|
|
34990
35794
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
34991
35795
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35001,7 +35805,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
35001
35805
|
continue;
|
|
35002
35806
|
}
|
|
35003
35807
|
if (editor === "copilot") {
|
|
35004
|
-
const filePath = path9.join(
|
|
35808
|
+
const filePath = path9.join(homedir8(), ".copilot", "mcp-config.json");
|
|
35005
35809
|
if (dryRun) {
|
|
35006
35810
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
35007
35811
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35056,7 +35860,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
35056
35860
|
continue;
|
|
35057
35861
|
}
|
|
35058
35862
|
if (editor === "cursor") {
|
|
35059
|
-
const filePath = path9.join(
|
|
35863
|
+
const filePath = path9.join(homedir8(), ".cursor", "mcp.json");
|
|
35060
35864
|
if (dryRun) {
|
|
35061
35865
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
35062
35866
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35068,7 +35872,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
35068
35872
|
continue;
|
|
35069
35873
|
}
|
|
35070
35874
|
if (editor === "windsurf") {
|
|
35071
|
-
const filePath = path9.join(
|
|
35875
|
+
const filePath = path9.join(homedir8(), ".codeium", "windsurf", "mcp_config.json");
|
|
35072
35876
|
if (dryRun) {
|
|
35073
35877
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
35074
35878
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35338,7 +36142,7 @@ Applying to ${projects.length} project(s)...`);
|
|
|
35338
36142
|
}
|
|
35339
36143
|
if (editor === "windsurf") {
|
|
35340
36144
|
console.log(
|
|
35341
|
-
`- ${EDITOR_LABELS[editor]}: uses global MCP config only (${path9.join(
|
|
36145
|
+
`- ${EDITOR_LABELS[editor]}: uses global MCP config only (${path9.join(homedir8(), ".codeium", "windsurf", "mcp_config.json")}).`
|
|
35342
36146
|
);
|
|
35343
36147
|
continue;
|
|
35344
36148
|
}
|
|
@@ -35556,7 +36360,7 @@ Applying to ${projects.length} project(s)...`);
|
|
|
35556
36360
|
// src/index.ts
|
|
35557
36361
|
var ENABLE_PROMPTS2 = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
|
|
35558
36362
|
function showFirstRunMessage() {
|
|
35559
|
-
const configDir = join22(
|
|
36363
|
+
const configDir = join22(homedir20(), ".contextstream");
|
|
35560
36364
|
const starShownFile = join22(configDir, ".star-shown");
|
|
35561
36365
|
if (existsSync16(starShownFile)) {
|
|
35562
36366
|
return;
|