@contextstream/mcp-server 0.4.71 → 0.4.73
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 +904 -143
- 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.
|
|
@@ -16340,6 +16516,61 @@ ${context}`;
|
|
|
16340
16516
|
...this.indexRefreshInProgress ? { index_status: "refreshing" } : {}
|
|
16341
16517
|
};
|
|
16342
16518
|
}
|
|
16519
|
+
async getContextFast(params) {
|
|
16520
|
+
const withDefaults = this.withDefaults(params);
|
|
16521
|
+
if (!withDefaults.workspace_id) return null;
|
|
16522
|
+
try {
|
|
16523
|
+
const result = await request(this.config, "/context/hook", {
|
|
16524
|
+
body: withDefaults,
|
|
16525
|
+
timeoutMs: 5e3
|
|
16526
|
+
});
|
|
16527
|
+
const data = result?.data ?? result ?? {};
|
|
16528
|
+
return {
|
|
16529
|
+
context: data.context || "",
|
|
16530
|
+
items: Array.isArray(data.items) ? data.items : void 0,
|
|
16531
|
+
action_required: data.action_required
|
|
16532
|
+
};
|
|
16533
|
+
} catch {
|
|
16534
|
+
return null;
|
|
16535
|
+
}
|
|
16536
|
+
}
|
|
16537
|
+
async getVcsRepos(params) {
|
|
16538
|
+
try {
|
|
16539
|
+
const result = await request(this.config, `/integrations/workspaces/${params.workspace_id}/vcs/repos`, {
|
|
16540
|
+
method: "GET",
|
|
16541
|
+
timeoutMs: 3e3
|
|
16542
|
+
});
|
|
16543
|
+
return Array.isArray(result?.data) ? result.data : Array.isArray(result) ? result : [];
|
|
16544
|
+
} catch {
|
|
16545
|
+
return [];
|
|
16546
|
+
}
|
|
16547
|
+
}
|
|
16548
|
+
async getVcsResource(params) {
|
|
16549
|
+
const qs = params.per_page ? `?per_page=${params.per_page}` : "";
|
|
16550
|
+
try {
|
|
16551
|
+
const result = await request(this.config, `/integrations/workspaces/${params.workspace_id}/vcs/${params.path}${qs}`, {
|
|
16552
|
+
method: "GET",
|
|
16553
|
+
timeoutMs: 4e3
|
|
16554
|
+
});
|
|
16555
|
+
return Array.isArray(result?.data) ? result.data : Array.isArray(result) ? result : [];
|
|
16556
|
+
} catch {
|
|
16557
|
+
return [];
|
|
16558
|
+
}
|
|
16559
|
+
}
|
|
16560
|
+
async vcsApiRequest(params) {
|
|
16561
|
+
const queryParts = [];
|
|
16562
|
+
if (params.query) {
|
|
16563
|
+
for (const [k, v] of Object.entries(params.query)) {
|
|
16564
|
+
if (v !== void 0 && v !== null) queryParts.push(`${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
|
|
16565
|
+
}
|
|
16566
|
+
}
|
|
16567
|
+
const qs = queryParts.length > 0 ? `?${queryParts.join("&")}` : "";
|
|
16568
|
+
const url = `/integrations/workspaces/${params.workspace_id}/vcs/${params.path}${qs}`;
|
|
16569
|
+
return request(this.config, url, {
|
|
16570
|
+
method: params.method,
|
|
16571
|
+
...params.body ? { body: params.body } : {}
|
|
16572
|
+
});
|
|
16573
|
+
}
|
|
16343
16574
|
/**
|
|
16344
16575
|
* Get high-priority lessons that should be surfaced proactively.
|
|
16345
16576
|
* Returns critical and high severity lessons for warnings.
|
|
@@ -17775,7 +18006,7 @@ ${context}`;
|
|
|
17775
18006
|
import * as fs6 from "node:fs";
|
|
17776
18007
|
import * as path7 from "node:path";
|
|
17777
18008
|
import { execFile } from "node:child_process";
|
|
17778
|
-
import { homedir as
|
|
18009
|
+
import { homedir as homedir6 } from "node:os";
|
|
17779
18010
|
import { promisify as promisify2 } from "node:util";
|
|
17780
18011
|
init_files();
|
|
17781
18012
|
init_rules_templates();
|
|
@@ -18360,9 +18591,9 @@ function resolveTodoCompletionUpdate(input) {
|
|
|
18360
18591
|
// src/hot-paths.ts
|
|
18361
18592
|
import * as fs5 from "node:fs";
|
|
18362
18593
|
import * as path6 from "node:path";
|
|
18363
|
-
import { homedir as
|
|
18594
|
+
import { homedir as homedir5 } from "node:os";
|
|
18364
18595
|
var STORE_VERSION = 1;
|
|
18365
|
-
var STORE_DIR = path6.join(
|
|
18596
|
+
var STORE_DIR = path6.join(homedir5(), ".contextstream");
|
|
18366
18597
|
var STORE_FILE = path6.join(STORE_DIR, "hot-paths.json");
|
|
18367
18598
|
var MAX_PATHS_PER_SCOPE = 400;
|
|
18368
18599
|
var HALF_LIFE_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
@@ -18808,9 +19039,9 @@ var RULES_PROJECT_FILES = {
|
|
|
18808
19039
|
aider: ".aider.conf.yml"
|
|
18809
19040
|
};
|
|
18810
19041
|
var RULES_GLOBAL_FILES = {
|
|
18811
|
-
codex: [path7.join(
|
|
18812
|
-
kilo: [path7.join(
|
|
18813
|
-
roo: [path7.join(
|
|
19042
|
+
codex: [path7.join(homedir6(), ".codex", "AGENTS.md")],
|
|
19043
|
+
kilo: [path7.join(homedir6(), ".kilocode", "rules", "contextstream.md")],
|
|
19044
|
+
roo: [path7.join(homedir6(), ".roo", "rules", "contextstream.md")]
|
|
18814
19045
|
};
|
|
18815
19046
|
var rulesNoticeCache = /* @__PURE__ */ new Map();
|
|
18816
19047
|
function compareVersions2(v1, v2) {
|
|
@@ -19973,6 +20204,7 @@ function parsePositiveInt(raw, fallback) {
|
|
|
19973
20204
|
var OUTPUT_FORMAT = process.env.CONTEXTSTREAM_OUTPUT_FORMAT || "compact";
|
|
19974
20205
|
var COMPACT_OUTPUT = OUTPUT_FORMAT === "compact";
|
|
19975
20206
|
var SHOW_TIMING = process.env.CONTEXTSTREAM_SHOW_TIMING === "true" || process.env.CONTEXTSTREAM_SHOW_TIMING === "1";
|
|
20207
|
+
var CONCISE_TOOL_TEXT = process.env.CONTEXTSTREAM_CONCISE_TOOL_TEXT?.toLowerCase() !== "false";
|
|
19976
20208
|
var INCLUDE_STRUCTURED_CONTENT = parseBoolEnvDefault(
|
|
19977
20209
|
process.env.CONTEXTSTREAM_INCLUDE_STRUCTURED_CONTENT,
|
|
19978
20210
|
true
|
|
@@ -19989,6 +20221,73 @@ function maybeStripStructuredContent(result) {
|
|
|
19989
20221
|
const { structuredContent: _structuredContent, ...rest } = result;
|
|
19990
20222
|
return rest;
|
|
19991
20223
|
}
|
|
20224
|
+
function formatTypedLessons(items, compact) {
|
|
20225
|
+
if (items.length === 0) return "";
|
|
20226
|
+
const MAX = 5;
|
|
20227
|
+
const entries = items.slice(0, MAX).map((item) => {
|
|
20228
|
+
const sev = item.score >= 0.8 ? "CRIT" : item.score >= 0.5 ? "HIGH" : "note";
|
|
20229
|
+
return compact ? `[LESSON:${sev}] ${item.value}` : `Lesson (${sev}): ${item.value}`;
|
|
20230
|
+
});
|
|
20231
|
+
return entries.join("\n");
|
|
20232
|
+
}
|
|
20233
|
+
function formatTypedPreferences(items, compact) {
|
|
20234
|
+
if (items.length === 0) return "";
|
|
20235
|
+
const MAX = 5;
|
|
20236
|
+
const entries = items.slice(0, MAX).map(
|
|
20237
|
+
(item) => compact ? `[PREF] ${item.value}` : `Preference: ${item.value}`
|
|
20238
|
+
);
|
|
20239
|
+
return entries.join("\n");
|
|
20240
|
+
}
|
|
20241
|
+
function formatTypedVcs(items, compact) {
|
|
20242
|
+
if (items.length === 0) return "";
|
|
20243
|
+
const MAX = 5;
|
|
20244
|
+
const entries = items.slice(0, MAX).map(
|
|
20245
|
+
(item) => compact ? `[VCS] ${item.value}` : `VCS: ${item.value}`
|
|
20246
|
+
);
|
|
20247
|
+
return entries.join("\n");
|
|
20248
|
+
}
|
|
20249
|
+
function formatTypedSkills(items, compact) {
|
|
20250
|
+
if (items.length === 0) return "";
|
|
20251
|
+
const MAX = 5;
|
|
20252
|
+
const entries = items.slice(0, MAX).map(
|
|
20253
|
+
(item) => compact ? `[SKILL] ${item.value}` : `Skill: ${item.value}`
|
|
20254
|
+
);
|
|
20255
|
+
return entries.join("\n");
|
|
20256
|
+
}
|
|
20257
|
+
function formatTypedSnapshots(items, compact) {
|
|
20258
|
+
if (items.length === 0) return "";
|
|
20259
|
+
const MAX = 3;
|
|
20260
|
+
const entries = items.slice(0, MAX).map(
|
|
20261
|
+
(item) => compact ? `[SNAPSHOT] ${item.value}` : `Transcript snapshot: ${item.value}`
|
|
20262
|
+
);
|
|
20263
|
+
return entries.join("\n");
|
|
20264
|
+
}
|
|
20265
|
+
function hasServerVcsItems(items) {
|
|
20266
|
+
if (!items || items.length === 0) return false;
|
|
20267
|
+
return items.some((i) => resolveItemKind(i) === "vcs");
|
|
20268
|
+
}
|
|
20269
|
+
var WARM_CACHE_TTL_MS = 3e4;
|
|
20270
|
+
var warmCacheEntry = null;
|
|
20271
|
+
function getWarmCacheKey(workspaceId, projectId) {
|
|
20272
|
+
return `${workspaceId || ""}:${projectId || ""}`;
|
|
20273
|
+
}
|
|
20274
|
+
function getWarmCache(workspaceId, projectId) {
|
|
20275
|
+
if (!warmCacheEntry) return null;
|
|
20276
|
+
const key = getWarmCacheKey(workspaceId, projectId);
|
|
20277
|
+
if (warmCacheEntry.key !== key) return null;
|
|
20278
|
+
if (Date.now() - warmCacheEntry.timestamp > WARM_CACHE_TTL_MS) {
|
|
20279
|
+
warmCacheEntry = null;
|
|
20280
|
+
return null;
|
|
20281
|
+
}
|
|
20282
|
+
return warmCacheEntry.result;
|
|
20283
|
+
}
|
|
20284
|
+
function setWarmCache(workspaceId, projectId, result) {
|
|
20285
|
+
warmCacheEntry = {
|
|
20286
|
+
key: getWarmCacheKey(workspaceId, projectId),
|
|
20287
|
+
timestamp: Date.now(),
|
|
20288
|
+
result
|
|
20289
|
+
};
|
|
20290
|
+
}
|
|
19992
20291
|
var CONSOLIDATED_MODE = process.env.CONTEXTSTREAM_CONSOLIDATED !== "false";
|
|
19993
20292
|
var CONSOLIDATED_TOOLS = /* @__PURE__ */ new Set([
|
|
19994
20293
|
"init",
|
|
@@ -20351,6 +20650,8 @@ function setupClientDetection(server) {
|
|
|
20351
20650
|
}
|
|
20352
20651
|
function registerTools(server, client, sessionManager, options) {
|
|
20353
20652
|
const upgradeUrl2 = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
|
|
20653
|
+
const indexKeeper = new IndexKeeper();
|
|
20654
|
+
indexKeeper.attach(client);
|
|
20354
20655
|
const toolSurfaceProfile = normalizeToolSurfaceProfile(
|
|
20355
20656
|
options?.toolSurfaceProfile || process.env.CONTEXTSTREAM_TOOL_SURFACE_PROFILE
|
|
20356
20657
|
);
|
|
@@ -20968,6 +21269,13 @@ Next step: ${createCommand}`
|
|
|
20968
21269
|
function isNotFoundError(error) {
|
|
20969
21270
|
return error instanceof HttpError && error.status === 404;
|
|
20970
21271
|
}
|
|
21272
|
+
function isAccessDeniedError(error) {
|
|
21273
|
+
return error instanceof HttpError && (error.status === 403 || error.status === 401);
|
|
21274
|
+
}
|
|
21275
|
+
function isScopeInvalidResult(result) {
|
|
21276
|
+
const data = result?.data ?? result ?? {};
|
|
21277
|
+
return data.scope_is_valid === false || data.scope_invalid === true || typeof data.error === "string" && data.error.includes("project_access_denied");
|
|
21278
|
+
}
|
|
20971
21279
|
function isRequiresIngestEndpointError(error) {
|
|
20972
21280
|
if (!(error instanceof HttpError)) return false;
|
|
20973
21281
|
if (error.status !== 400) return false;
|
|
@@ -20983,6 +21291,100 @@ Next step: ${createCommand}`
|
|
|
20983
21291
|
(t) => /[A-Z][a-z]/.test(t) || t.includes("_") || t.includes(".") || t.includes("::")
|
|
20984
21292
|
);
|
|
20985
21293
|
}
|
|
21294
|
+
function isArtifactLikePath(filePath) {
|
|
21295
|
+
const normalized = filePath.toLowerCase().replace(/\\/g, "/");
|
|
21296
|
+
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/");
|
|
21297
|
+
}
|
|
21298
|
+
function queryExplicitlyTargetsArtifacts(query) {
|
|
21299
|
+
const lower = query.toLowerCase();
|
|
21300
|
+
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");
|
|
21301
|
+
}
|
|
21302
|
+
function shouldFilterArtifactPaths(mode, query) {
|
|
21303
|
+
if (mode === "pattern" || mode === "exhaustive") return false;
|
|
21304
|
+
if (queryExplicitlyTargetsArtifacts(query)) return false;
|
|
21305
|
+
return true;
|
|
21306
|
+
}
|
|
21307
|
+
const MIRROR_PREFIXES = [
|
|
21308
|
+
"contextstream-ai-brain-export/",
|
|
21309
|
+
"contextstream/",
|
|
21310
|
+
"web/users/"
|
|
21311
|
+
];
|
|
21312
|
+
function canonicalizeRepoPath(filePath) {
|
|
21313
|
+
let normalized = filePath.replace(/\\/g, "/");
|
|
21314
|
+
while (normalized.startsWith("./")) {
|
|
21315
|
+
normalized = normalized.slice(2);
|
|
21316
|
+
}
|
|
21317
|
+
for (const prefix of MIRROR_PREFIXES) {
|
|
21318
|
+
if (normalized.startsWith(prefix)) {
|
|
21319
|
+
normalized = normalized.slice(prefix.length);
|
|
21320
|
+
break;
|
|
21321
|
+
}
|
|
21322
|
+
}
|
|
21323
|
+
if (normalized.startsWith(".claude/worktrees/")) {
|
|
21324
|
+
const rest = normalized.slice(".claude/worktrees/".length);
|
|
21325
|
+
const slashIdx = rest.indexOf("/");
|
|
21326
|
+
if (slashIdx >= 0) {
|
|
21327
|
+
normalized = rest.slice(slashIdx + 1);
|
|
21328
|
+
}
|
|
21329
|
+
}
|
|
21330
|
+
const projectsIdx = normalized.indexOf("/projects/");
|
|
21331
|
+
if (projectsIdx >= 0) {
|
|
21332
|
+
const afterProjects = normalized.slice(projectsIdx + "/projects/".length);
|
|
21333
|
+
const uuidEndIdx = afterProjects.indexOf("/");
|
|
21334
|
+
if (uuidEndIdx >= 0 && /^[0-9a-f-]{36}/i.test(afterProjects)) {
|
|
21335
|
+
normalized = afterProjects.slice(uuidEndIdx + 1);
|
|
21336
|
+
}
|
|
21337
|
+
}
|
|
21338
|
+
return normalized;
|
|
21339
|
+
}
|
|
21340
|
+
function extractSymbolAnchors(query) {
|
|
21341
|
+
const tokens = query.split(/\s+/).filter(Boolean);
|
|
21342
|
+
const anchors = [];
|
|
21343
|
+
for (const t of tokens) {
|
|
21344
|
+
const cleaned = t.replace(/^["'`]+|["'`]+$/g, "");
|
|
21345
|
+
if (!cleaned) continue;
|
|
21346
|
+
const hasMixedCase = /[a-z]/.test(cleaned) && /[A-Z]/.test(cleaned);
|
|
21347
|
+
const hasUnderscore = cleaned.includes("_");
|
|
21348
|
+
const hasNamespaceSep = cleaned.includes("::") || cleaned.includes(".");
|
|
21349
|
+
const isAllCaps = cleaned.length >= 3 && /^[A-Z0-9_]+$/.test(cleaned);
|
|
21350
|
+
if (hasMixedCase || hasUnderscore || hasNamespaceSep || isAllCaps) {
|
|
21351
|
+
anchors.push(cleaned);
|
|
21352
|
+
}
|
|
21353
|
+
}
|
|
21354
|
+
return anchors;
|
|
21355
|
+
}
|
|
21356
|
+
function applySymbolAnchorRerank(results, anchors) {
|
|
21357
|
+
if (anchors.length === 0 || results.length === 0) return results;
|
|
21358
|
+
const lowerAnchors = anchors.map((a) => a.toLowerCase());
|
|
21359
|
+
const scored = results.map((r, idx) => {
|
|
21360
|
+
const fp = (r.file_path || "").toLowerCase();
|
|
21361
|
+
const content = (r.content || "").toLowerCase();
|
|
21362
|
+
let anchorHits = 0;
|
|
21363
|
+
for (const anchor of lowerAnchors) {
|
|
21364
|
+
if (fp.includes(anchor) || content.includes(anchor)) anchorHits++;
|
|
21365
|
+
}
|
|
21366
|
+
const isNoisy = isArtifactLikePath(r.file_path || "");
|
|
21367
|
+
return { item: r, anchorHits, isNoisy, originalIdx: idx };
|
|
21368
|
+
});
|
|
21369
|
+
scored.sort((a, b) => {
|
|
21370
|
+
if (b.anchorHits !== a.anchorHits) return b.anchorHits - a.anchorHits;
|
|
21371
|
+
if (a.isNoisy !== b.isNoisy) return a.isNoisy ? 1 : -1;
|
|
21372
|
+
return a.originalIdx - b.originalIdx;
|
|
21373
|
+
});
|
|
21374
|
+
return scored.map((s) => s.item);
|
|
21375
|
+
}
|
|
21376
|
+
function deduplicateSearchResults(results) {
|
|
21377
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21378
|
+
return results.filter((r) => {
|
|
21379
|
+
const fp = r.file_path ? canonicalizeRepoPath(r.file_path) : "";
|
|
21380
|
+
const startLine = r.start_line || r.metadata?.start_line || "";
|
|
21381
|
+
const key = fp ? `${fp}:${startLine}` : "";
|
|
21382
|
+
if (!key) return true;
|
|
21383
|
+
if (seen.has(key)) return false;
|
|
21384
|
+
seen.add(key);
|
|
21385
|
+
return true;
|
|
21386
|
+
});
|
|
21387
|
+
}
|
|
20986
21388
|
async function runLocalRipgrep(query, cwd, limit = 10) {
|
|
20987
21389
|
try {
|
|
20988
21390
|
const pattern = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -25521,7 +25923,7 @@ This saves ~80% tokens compared to including full chat history.`,
|
|
|
25521
25923
|
project_id: external_exports.string().uuid().optional(),
|
|
25522
25924
|
max_tokens: external_exports.number().optional().describe("Maximum tokens for context (default: 800)"),
|
|
25523
25925
|
format: external_exports.enum(["minified", "readable", "structured"]).optional().describe("Context format (default: minified)"),
|
|
25524
|
-
mode: external_exports.enum(["standard", "pack"]).optional().describe("Context
|
|
25926
|
+
mode: external_exports.enum(["standard", "pack", "fast"]).optional().describe("Context mode: standard (default), pack (includes code context), fast (cached quick response)"),
|
|
25525
25927
|
distill: external_exports.boolean().optional().describe("Use distillation for context pack (default: true)"),
|
|
25526
25928
|
session_tokens: external_exports.number().optional().describe("Cumulative session token count for context pressure calculation"),
|
|
25527
25929
|
context_threshold: external_exports.number().optional().describe("Custom context window threshold (defaults to 70k)"),
|
|
@@ -25612,21 +26014,149 @@ This saves ~80% tokens compared to including full chat history.`,
|
|
|
25612
26014
|
if (!clientName && detectedClientInfo) {
|
|
25613
26015
|
clientName = detectedClientInfo.name;
|
|
25614
26016
|
}
|
|
25615
|
-
const
|
|
25616
|
-
|
|
25617
|
-
|
|
25618
|
-
|
|
25619
|
-
|
|
25620
|
-
|
|
25621
|
-
|
|
25622
|
-
|
|
25623
|
-
|
|
25624
|
-
|
|
25625
|
-
|
|
25626
|
-
|
|
25627
|
-
|
|
25628
|
-
|
|
25629
|
-
}
|
|
26017
|
+
const conversationTurns = sessionManager?.getConversationTurns() ?? 0;
|
|
26018
|
+
const isFastMode = input.mode === "fast";
|
|
26019
|
+
const folderPathCtx = resolveFolderPath(void 0, sessionManager);
|
|
26020
|
+
if (isFastMode && workspaceId) {
|
|
26021
|
+
const fastResult = await client.getContextFast({ workspace_id: workspaceId, project_id: projectId });
|
|
26022
|
+
if (fastResult && fastResult.context) {
|
|
26023
|
+
const roundTripMs2 = Date.now() - startTime;
|
|
26024
|
+
const timingStr2 = SHOW_TIMING ? ` | ${roundTripMs2}ms` : "";
|
|
26025
|
+
return {
|
|
26026
|
+
content: [{ type: "text", text: `${fastResult.context}
|
|
26027
|
+
---
|
|
26028
|
+
fast mode${timingStr2}` }]
|
|
26029
|
+
};
|
|
26030
|
+
}
|
|
26031
|
+
}
|
|
26032
|
+
const cachedResult = conversationTurns >= 2 ? getWarmCache(workspaceId, projectId) : null;
|
|
26033
|
+
let proactiveVcsPromise;
|
|
26034
|
+
if (conversationTurns <= 3 && workspaceId && !isFastMode) {
|
|
26035
|
+
proactiveVcsPromise = (async () => {
|
|
26036
|
+
const repos = await client.getVcsRepos({ workspace_id: workspaceId, per_page: 10 });
|
|
26037
|
+
if (repos.length === 0) return { repos: [], pulls: [], issues: [], activity: [], notifications: [] };
|
|
26038
|
+
const pullPromises = repos.slice(0, 5).map(
|
|
26039
|
+
(r) => client.getVcsResource({ workspace_id: workspaceId, path: `repos/${r.id || r.repo_id}/pulls`, per_page: 5 })
|
|
26040
|
+
);
|
|
26041
|
+
const issuePromises = repos.slice(0, 5).map(
|
|
26042
|
+
(r) => client.getVcsResource({ workspace_id: workspaceId, path: `repos/${r.id || r.repo_id}/issues`, per_page: 5 })
|
|
26043
|
+
);
|
|
26044
|
+
const [pullResults, issueResults] = await Promise.all([
|
|
26045
|
+
Promise.all(pullPromises),
|
|
26046
|
+
Promise.all(issuePromises)
|
|
26047
|
+
]);
|
|
26048
|
+
return {
|
|
26049
|
+
repos,
|
|
26050
|
+
pulls: pullResults.flat(),
|
|
26051
|
+
issues: issueResults.flat(),
|
|
26052
|
+
activity: [],
|
|
26053
|
+
notifications: []
|
|
26054
|
+
};
|
|
26055
|
+
})().catch(() => ({ repos: [], pulls: [], issues: [], activity: [], notifications: [] }));
|
|
26056
|
+
}
|
|
26057
|
+
let recentChangesPromise;
|
|
26058
|
+
if (conversationTurns <= 2 && folderPathCtx && !CONCISE_TOOL_TEXT && !isFastMode) {
|
|
26059
|
+
recentChangesPromise = (async () => {
|
|
26060
|
+
try {
|
|
26061
|
+
const { stdout: stdout2 } = await execFileAsync("git", [
|
|
26062
|
+
"log",
|
|
26063
|
+
"--oneline",
|
|
26064
|
+
"--format=%h %s (%ar)",
|
|
26065
|
+
"-n5"
|
|
26066
|
+
], { cwd: folderPathCtx, timeout: 3e3, maxBuffer: 64 * 1024 });
|
|
26067
|
+
return stdout2.trim();
|
|
26068
|
+
} catch {
|
|
26069
|
+
return "";
|
|
26070
|
+
}
|
|
26071
|
+
})();
|
|
26072
|
+
}
|
|
26073
|
+
let result;
|
|
26074
|
+
if (cachedResult) {
|
|
26075
|
+
result = cachedResult;
|
|
26076
|
+
const fastOverlay = await client.getContextFast({ workspace_id: workspaceId, project_id: projectId });
|
|
26077
|
+
if (fastOverlay?.context) {
|
|
26078
|
+
result = { ...result, context: result.context + "\n" + fastOverlay.context };
|
|
26079
|
+
if (fastOverlay.items && Array.isArray(fastOverlay.items)) {
|
|
26080
|
+
result.items = [...result.items || [], ...fastOverlay.items];
|
|
26081
|
+
}
|
|
26082
|
+
}
|
|
26083
|
+
} else {
|
|
26084
|
+
result = await client.getSmartContext({
|
|
26085
|
+
user_message: input.user_message,
|
|
26086
|
+
workspace_id: workspaceId,
|
|
26087
|
+
project_id: projectId,
|
|
26088
|
+
max_tokens: input.max_tokens,
|
|
26089
|
+
format: input.format,
|
|
26090
|
+
mode: input.mode === "fast" ? "standard" : input.mode,
|
|
26091
|
+
distill: input.distill,
|
|
26092
|
+
session_tokens: sessionTokens,
|
|
26093
|
+
context_threshold: contextThreshold,
|
|
26094
|
+
save_exchange: input.save_exchange,
|
|
26095
|
+
session_id: sessionId,
|
|
26096
|
+
client_name: clientName,
|
|
26097
|
+
assistant_message: input.assistant_message
|
|
26098
|
+
});
|
|
26099
|
+
if (workspaceId) {
|
|
26100
|
+
setWarmCache(workspaceId, projectId, result);
|
|
26101
|
+
}
|
|
26102
|
+
}
|
|
26103
|
+
const typedItems = Array.isArray(result.items) ? result.items : [];
|
|
26104
|
+
const hasTypedItems = typedItems.length > 0;
|
|
26105
|
+
const compact = COMPACT_OUTPUT || CONCISE_TOOL_TEXT;
|
|
26106
|
+
let typedContextBlock = "";
|
|
26107
|
+
if (hasTypedItems) {
|
|
26108
|
+
const parts = [];
|
|
26109
|
+
const prefItems = filterItemsByKind(typedItems, "preference");
|
|
26110
|
+
const lessonItems = filterItemsByKind(typedItems, "lesson");
|
|
26111
|
+
const vcsItems = filterItemsByKind(typedItems, "vcs");
|
|
26112
|
+
const skillItems = filterItemsByKind(typedItems, "skill");
|
|
26113
|
+
const snapItems = filterItemsByKind(typedItems, "transcript_snapshot");
|
|
26114
|
+
const prefText = formatTypedPreferences(prefItems, compact);
|
|
26115
|
+
if (prefText) parts.push(prefText);
|
|
26116
|
+
const lessonText = formatTypedLessons(lessonItems, compact);
|
|
26117
|
+
if (lessonText) parts.push(lessonText);
|
|
26118
|
+
const vcsText = formatTypedVcs(vcsItems, compact);
|
|
26119
|
+
if (vcsText) parts.push(vcsText);
|
|
26120
|
+
const skillText = formatTypedSkills(skillItems, compact);
|
|
26121
|
+
if (skillText) parts.push(skillText);
|
|
26122
|
+
if (conversationTurns <= 3) {
|
|
26123
|
+
const snapText = formatTypedSnapshots(snapItems, compact);
|
|
26124
|
+
if (snapText) parts.push(snapText);
|
|
26125
|
+
}
|
|
26126
|
+
if (parts.length > 0) {
|
|
26127
|
+
typedContextBlock = "\n" + parts.join("\n") + "\n";
|
|
26128
|
+
}
|
|
26129
|
+
}
|
|
26130
|
+
let proactiveVcsBlock = "";
|
|
26131
|
+
if (proactiveVcsPromise) {
|
|
26132
|
+
try {
|
|
26133
|
+
const vcsCtx = await proactiveVcsPromise;
|
|
26134
|
+
if (!hasServerVcsItems(typedItems) && (vcsCtx.pulls.length > 0 || vcsCtx.issues.length > 0)) {
|
|
26135
|
+
const vParts = [];
|
|
26136
|
+
if (vcsCtx.pulls.length > 0) {
|
|
26137
|
+
vParts.push(compact ? `[VCS] ${vcsCtx.pulls.length} open PR(s)` : `Open PRs: ${vcsCtx.pulls.length}`);
|
|
26138
|
+
}
|
|
26139
|
+
if (vcsCtx.issues.length > 0) {
|
|
26140
|
+
vParts.push(compact ? `[VCS] ${vcsCtx.issues.length} open issue(s)` : `Open issues: ${vcsCtx.issues.length}`);
|
|
26141
|
+
}
|
|
26142
|
+
if (vParts.length > 0) proactiveVcsBlock = "\n" + vParts.join("\n");
|
|
26143
|
+
}
|
|
26144
|
+
} catch {
|
|
26145
|
+
}
|
|
26146
|
+
}
|
|
26147
|
+
let recentChangesBlock = "";
|
|
26148
|
+
if (recentChangesPromise) {
|
|
26149
|
+
try {
|
|
26150
|
+
const changes = await recentChangesPromise;
|
|
26151
|
+
if (changes) {
|
|
26152
|
+
recentChangesBlock = compact ? `
|
|
26153
|
+
[RECENT_CHANGES] ${changes.split("\n").slice(0, 3).join("; ")}` : `
|
|
26154
|
+
[RECENT_CHANGES]
|
|
26155
|
+
${changes}`;
|
|
26156
|
+
}
|
|
26157
|
+
} catch {
|
|
26158
|
+
}
|
|
26159
|
+
}
|
|
25630
26160
|
if (sessionManager && result.token_estimate) {
|
|
25631
26161
|
sessionManager.addTokens(result.token_estimate);
|
|
25632
26162
|
}
|
|
@@ -25792,7 +26322,7 @@ ${versionWarningLine}` : "",
|
|
|
25792
26322
|
// Reinforce context() must be called every message
|
|
25793
26323
|
searchRulesLine
|
|
25794
26324
|
].filter(Boolean).join("");
|
|
25795
|
-
const finalContext = postCompactContext + result.context;
|
|
26325
|
+
const finalContext = postCompactContext + result.context + typedContextBlock + proactiveVcsBlock + recentChangesBlock;
|
|
25796
26326
|
const textParts = [
|
|
25797
26327
|
finalContext,
|
|
25798
26328
|
footer,
|
|
@@ -26807,6 +27337,12 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
26807
27337
|
if (authError) return authError;
|
|
26808
27338
|
client.checkAndIndexChangedFiles().catch(() => {
|
|
26809
27339
|
});
|
|
27340
|
+
const folderPathForKeeper = resolveFolderPath(void 0, sessionManager);
|
|
27341
|
+
const projectIdForKeeper = resolveProjectId(void 0);
|
|
27342
|
+
if (folderPathForKeeper && projectIdForKeeper) {
|
|
27343
|
+
indexKeeper.tick(projectIdForKeeper, folderPathForKeeper).catch(() => {
|
|
27344
|
+
});
|
|
27345
|
+
}
|
|
26810
27346
|
const startTime = Date.now();
|
|
26811
27347
|
const modeInput = input.mode || "auto";
|
|
26812
27348
|
const modeRecommendation = recommendSearchMode(input.query);
|
|
@@ -26833,12 +27369,12 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
26833
27369
|
const project = await client.getProject(explicitProjectId);
|
|
26834
27370
|
const projectWorkspaceId = normalizeUuid(project?.workspace_id || project?.workspaceId);
|
|
26835
27371
|
if (workspaceId && projectWorkspaceId && projectWorkspaceId !== workspaceId) {
|
|
26836
|
-
explicitProjectScopeNote = `Explicit project_id ${explicitProjectId} belongs to workspace
|
|
27372
|
+
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
27373
|
explicitProjectId = void 0;
|
|
26838
27374
|
}
|
|
26839
27375
|
} catch (error) {
|
|
26840
27376
|
if (isNotFoundError(error)) {
|
|
26841
|
-
explicitProjectScopeNote = `Explicit project_id ${explicitProjectId} was not found
|
|
27377
|
+
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
27378
|
explicitProjectId = void 0;
|
|
26843
27379
|
} else {
|
|
26844
27380
|
throw error;
|
|
@@ -27098,6 +27634,10 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27098
27634
|
hot_paths_hint: hotPathsHint,
|
|
27099
27635
|
output_format: input.output_format || suggestOutputFormat(input.query, requestedMode === "team" ? "hybrid" : requestedMode)
|
|
27100
27636
|
});
|
|
27637
|
+
let parallelRgPromise;
|
|
27638
|
+
if (containsCodeIdentifiers(input.query) && folderPath && requestedMode !== "pattern") {
|
|
27639
|
+
parallelRgPromise = runLocalRipgrep(input.query, folderPath, input.limit || 10);
|
|
27640
|
+
}
|
|
27101
27641
|
if (requestedMode === "team") {
|
|
27102
27642
|
try {
|
|
27103
27643
|
const teamResult = await runSearchForMode("team", {
|
|
@@ -27125,6 +27665,18 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27125
27665
|
try {
|
|
27126
27666
|
const modeResult = await runSearchForMode(requestedMode, paramsForCandidate);
|
|
27127
27667
|
const envelope = extractSearchEnvelope(modeResult.result);
|
|
27668
|
+
if (isScopeInvalidResult(modeResult.result)) {
|
|
27669
|
+
if (!selected) {
|
|
27670
|
+
selected = {
|
|
27671
|
+
index,
|
|
27672
|
+
project_id: candidateProjectId,
|
|
27673
|
+
result: modeResult.result,
|
|
27674
|
+
executedMode: modeResult.executedMode,
|
|
27675
|
+
fallbackNote: modeResult.fallbackNote
|
|
27676
|
+
};
|
|
27677
|
+
}
|
|
27678
|
+
continue;
|
|
27679
|
+
}
|
|
27128
27680
|
if (explicitProjectId && index === 0 && envelope.results.length === 0) {
|
|
27129
27681
|
explicitScopeHadNoResults = true;
|
|
27130
27682
|
}
|
|
@@ -27148,7 +27700,7 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27148
27700
|
};
|
|
27149
27701
|
}
|
|
27150
27702
|
} catch (error) {
|
|
27151
|
-
if (isNotFoundError(error)) {
|
|
27703
|
+
if (isNotFoundError(error) || isAccessDeniedError(error)) {
|
|
27152
27704
|
continue;
|
|
27153
27705
|
}
|
|
27154
27706
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
@@ -27224,7 +27776,59 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27224
27776
|
const docsFallback = requestedMode !== "team" && isDocLookupQuery(input.query) && extractSearchEnvelope(selected.result).results.length === 0 ? await findDocsFallback(workspaceId, candidateProjectIds, input.query, input.limit) : void 0;
|
|
27225
27777
|
const roundTripMs = Date.now() - startTime;
|
|
27226
27778
|
let { results, total } = extractSearchEnvelope(selected.result);
|
|
27227
|
-
|
|
27779
|
+
const scopeInvalid = isScopeInvalidResult(selected.result);
|
|
27780
|
+
for (const r of results) {
|
|
27781
|
+
if (r.file_path) {
|
|
27782
|
+
const canonical = canonicalizeRepoPath(r.file_path);
|
|
27783
|
+
if (canonical !== r.file_path) r.file_path = canonical;
|
|
27784
|
+
}
|
|
27785
|
+
}
|
|
27786
|
+
results = deduplicateSearchResults(results);
|
|
27787
|
+
if (shouldFilterArtifactPaths(selected.executedMode, input.query) && results.length > 0) {
|
|
27788
|
+
const beforeLen = results.length;
|
|
27789
|
+
results = results.filter(
|
|
27790
|
+
(r) => r.file_path ? !isArtifactLikePath(r.file_path) : true
|
|
27791
|
+
);
|
|
27792
|
+
if (results.length < beforeLen) {
|
|
27793
|
+
modeFallbackNote = appendNote(
|
|
27794
|
+
modeFallbackNote,
|
|
27795
|
+
`Filtered ${beforeLen - results.length} artifact/generated path(s).`
|
|
27796
|
+
);
|
|
27797
|
+
}
|
|
27798
|
+
}
|
|
27799
|
+
if (results.length === 0 && !scopeInvalid) {
|
|
27800
|
+
const escalationModes = (() => {
|
|
27801
|
+
switch (selected.executedMode) {
|
|
27802
|
+
case "semantic":
|
|
27803
|
+
return ["hybrid", "keyword"];
|
|
27804
|
+
case "hybrid":
|
|
27805
|
+
return ["keyword"];
|
|
27806
|
+
case "keyword":
|
|
27807
|
+
return ["hybrid"];
|
|
27808
|
+
default:
|
|
27809
|
+
return [];
|
|
27810
|
+
}
|
|
27811
|
+
})();
|
|
27812
|
+
for (const escMode of escalationModes) {
|
|
27813
|
+
try {
|
|
27814
|
+
const escResult = await runSearchForMode(escMode, {
|
|
27815
|
+
...baseParams,
|
|
27816
|
+
workspace_id: workspaceId,
|
|
27817
|
+
project_id: selected.project_id
|
|
27818
|
+
});
|
|
27819
|
+
const escEnvelope = extractSearchEnvelope(escResult.result);
|
|
27820
|
+
if (escEnvelope.results.length > 0) {
|
|
27821
|
+
results = escEnvelope.results;
|
|
27822
|
+
total = escEnvelope.total;
|
|
27823
|
+
modeFallbackNote = appendNote(modeFallbackNote, `${selected.executedMode} returned 0 results; escalated to ${escMode}.`);
|
|
27824
|
+
break;
|
|
27825
|
+
}
|
|
27826
|
+
} catch {
|
|
27827
|
+
}
|
|
27828
|
+
}
|
|
27829
|
+
}
|
|
27830
|
+
const parallelCoversFallback = !!parallelRgPromise && selected.executedMode !== "pattern";
|
|
27831
|
+
if (results.length === 0 && folderPath && !parallelCoversFallback) {
|
|
27228
27832
|
const rgResults = await runLocalRipgrep(input.query, folderPath, input.limit || 10);
|
|
27229
27833
|
if (rgResults.length > 0) {
|
|
27230
27834
|
results = rgResults.map((r) => ({
|
|
@@ -27241,6 +27845,24 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27241
27845
|
);
|
|
27242
27846
|
}
|
|
27243
27847
|
}
|
|
27848
|
+
if (parallelRgPromise) {
|
|
27849
|
+
try {
|
|
27850
|
+
const parallelRgResults = await parallelRgPromise;
|
|
27851
|
+
if (parallelRgResults.length > 0) {
|
|
27852
|
+
const existingPaths = new Set(results.map((r) => r.file_path).filter(Boolean));
|
|
27853
|
+
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" }));
|
|
27854
|
+
if (newEntries.length > 0) {
|
|
27855
|
+
results = [...results, ...newEntries];
|
|
27856
|
+
}
|
|
27857
|
+
}
|
|
27858
|
+
} catch {
|
|
27859
|
+
}
|
|
27860
|
+
}
|
|
27861
|
+
const symbolAnchors = extractSymbolAnchors(input.query);
|
|
27862
|
+
if (symbolAnchors.length > 0 && results.length > 1) {
|
|
27863
|
+
results = applySymbolAnchorRerank(results, symbolAnchors);
|
|
27864
|
+
}
|
|
27865
|
+
total = results.length;
|
|
27244
27866
|
const resultPaths = results.map((item) => typeof item?.file_path === "string" ? item.file_path : "").filter(Boolean);
|
|
27245
27867
|
if (resultPaths.length > 0) {
|
|
27246
27868
|
globalHotPathStore.recordPaths(
|
|
@@ -27255,13 +27877,13 @@ Output formats: full (default, includes content), paths (file paths only - 80% t
|
|
|
27255
27877
|
} else {
|
|
27256
27878
|
lines.push(`\u{1F50D} ${total} results for "${input.query}"`);
|
|
27257
27879
|
}
|
|
27258
|
-
if (modeAutoSelected) {
|
|
27880
|
+
if (modeAutoSelected && !(CONCISE_TOOL_TEXT && results.length > 0)) {
|
|
27259
27881
|
lines.push(`Mode auto-selected: \`${requestedMode}\`. ${modeRecommendation.reason}`);
|
|
27260
27882
|
}
|
|
27261
|
-
if (modeFallbackNote) {
|
|
27883
|
+
if (modeFallbackNote && !(CONCISE_TOOL_TEXT && results.length > 0)) {
|
|
27262
27884
|
lines.push(modeFallbackNote);
|
|
27263
27885
|
}
|
|
27264
|
-
if (hotPathsHint?.entries?.length) {
|
|
27886
|
+
if (hotPathsHint?.entries?.length && !CONCISE_TOOL_TEXT) {
|
|
27265
27887
|
lines.push(
|
|
27266
27888
|
`Hot-path hint active (${hotPathsHint.entries.length} paths, confidence ${(hotPathsHint.confidence * 100).toFixed(0)}%).`
|
|
27267
27889
|
);
|
|
@@ -29941,6 +30563,19 @@ ${formatContent(response)}`
|
|
|
29941
30563
|
}
|
|
29942
30564
|
const validPath = await validateReadableDirectory(ingestPath);
|
|
29943
30565
|
if (!validPath.ok) {
|
|
30566
|
+
try {
|
|
30567
|
+
const pathExists = await fs6.promises.stat(ingestPath).then(() => true).catch(() => false);
|
|
30568
|
+
if (!pathExists) {
|
|
30569
|
+
const apiResult = await client.ingestFromPath(projectId, ingestPath, {
|
|
30570
|
+
force: input.force
|
|
30571
|
+
});
|
|
30572
|
+
return {
|
|
30573
|
+
content: [{ type: "text", text: `Delegated ingest to API for path: ${ingestPath}
|
|
30574
|
+
${formatContent(apiResult)}` }]
|
|
30575
|
+
};
|
|
30576
|
+
}
|
|
30577
|
+
} catch {
|
|
30578
|
+
}
|
|
29944
30579
|
return errorResult(validPath.error);
|
|
29945
30580
|
}
|
|
29946
30581
|
const ingestOptions = {
|
|
@@ -31525,13 +32160,35 @@ Each domain tool has an 'action' parameter for specific operations.` : "";
|
|
|
31525
32160
|
"vcs",
|
|
31526
32161
|
{
|
|
31527
32162
|
title: "Version Control",
|
|
31528
|
-
description: `Git version control
|
|
32163
|
+
description: `Git version control and remote repo operations.
|
|
32164
|
+
|
|
32165
|
+
Local git actions: status, diff, log, blame, branches, stash_list
|
|
32166
|
+
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
32167
|
inputSchema: external_exports.object({
|
|
31530
|
-
action: external_exports.
|
|
31531
|
-
|
|
31532
|
-
|
|
31533
|
-
|
|
31534
|
-
|
|
32168
|
+
action: external_exports.string().describe("VCS action to perform"),
|
|
32169
|
+
workspace_id: external_exports.string().uuid().optional().describe("Workspace ID for remote VCS actions"),
|
|
32170
|
+
repo_ref: external_exports.string().optional().describe("Repository reference (owner/repo) for remote actions"),
|
|
32171
|
+
repo_id: external_exports.string().optional().describe("Repository ID for remote actions"),
|
|
32172
|
+
path: external_exports.string().optional().describe("File path for diff/blame/tree/blob"),
|
|
32173
|
+
ref: external_exports.string().optional().describe("Git ref (branch, tag, commit)"),
|
|
32174
|
+
base_ref: external_exports.string().optional().describe("Base ref for compare_refs"),
|
|
32175
|
+
limit: external_exports.number().optional().describe("Max entries (default: 20)"),
|
|
32176
|
+
staged: external_exports.boolean().optional().describe("Show staged changes only (for diff)"),
|
|
32177
|
+
pull_number: external_exports.number().optional().describe("Pull request number"),
|
|
32178
|
+
issue_number: external_exports.number().optional().describe("Issue number"),
|
|
32179
|
+
notification_id: external_exports.string().optional().describe("Notification ID"),
|
|
32180
|
+
link_id: external_exports.string().optional().describe("Link ID"),
|
|
32181
|
+
automation_id: external_exports.string().optional().describe("Automation ID"),
|
|
32182
|
+
title: external_exports.string().optional().describe("Title for create_issue"),
|
|
32183
|
+
body: external_exports.string().optional().describe("Body content"),
|
|
32184
|
+
state: external_exports.string().optional().describe("State filter (open/closed)"),
|
|
32185
|
+
labels: external_exports.array(external_exports.string()).optional().describe("Labels for issues"),
|
|
32186
|
+
per_page: external_exports.number().optional().describe("Results per page"),
|
|
32187
|
+
page: external_exports.number().optional().describe("Page number"),
|
|
32188
|
+
event: external_exports.string().optional().describe("Review event (APPROVE/REQUEST_CHANGES/COMMENT)"),
|
|
32189
|
+
provider: external_exports.string().optional().describe("VCS provider (github/gitlab/bitbucket)"),
|
|
32190
|
+
query: external_exports.string().optional().describe("Search query"),
|
|
32191
|
+
data: external_exports.record(external_exports.any()).optional().describe("Additional data for create/update operations")
|
|
31535
32192
|
})
|
|
31536
32193
|
},
|
|
31537
32194
|
async (input) => {
|
|
@@ -31551,60 +32208,164 @@ Each domain tool has an 'action' parameter for specific operations.` : "";
|
|
|
31551
32208
|
throw err;
|
|
31552
32209
|
}
|
|
31553
32210
|
};
|
|
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
|
-
|
|
32211
|
+
const localActions = /* @__PURE__ */ new Set(["status", "diff", "log", "blame", "branches", "stash_list"]);
|
|
32212
|
+
if (localActions.has(input.action)) {
|
|
32213
|
+
switch (input.action) {
|
|
32214
|
+
case "status": {
|
|
32215
|
+
const output = await runGit(["status", "--porcelain=v2", "--branch"]);
|
|
32216
|
+
return { content: [{ type: "text", text: output || "Working tree clean." }] };
|
|
32217
|
+
}
|
|
32218
|
+
case "diff": {
|
|
32219
|
+
const args = ["diff"];
|
|
32220
|
+
if (input.staged) args.push("--staged");
|
|
32221
|
+
if (input.ref) args.push(input.ref);
|
|
32222
|
+
if (input.path) args.push("--", input.path);
|
|
32223
|
+
const output = await runGit(args);
|
|
32224
|
+
return { content: [{ type: "text", text: output || "No changes." }] };
|
|
32225
|
+
}
|
|
32226
|
+
case "log": {
|
|
32227
|
+
const limit = input.limit || 20;
|
|
32228
|
+
const args = ["log", `--max-count=${limit}`, "--format=%H %ai %an <%ae>%n %s", "--no-decorate"];
|
|
32229
|
+
if (input.ref) args.push(input.ref);
|
|
32230
|
+
if (input.path) args.push("--", input.path);
|
|
32231
|
+
const output = await runGit(args);
|
|
32232
|
+
return { content: [{ type: "text", text: output || "No commits." }] };
|
|
32233
|
+
}
|
|
32234
|
+
case "blame": {
|
|
32235
|
+
if (!input.path) return errorResult("blame requires: path");
|
|
32236
|
+
const args = ["blame", "--porcelain", input.path];
|
|
32237
|
+
if (input.ref) args.splice(1, 0, input.ref);
|
|
32238
|
+
const output = await runGit(args);
|
|
32239
|
+
const summaryLines = [];
|
|
32240
|
+
const blameLines = output.split("\n");
|
|
32241
|
+
let currentCommit = "";
|
|
32242
|
+
let currentAuthor = "";
|
|
32243
|
+
let lineNum = 0;
|
|
32244
|
+
for (const line of blameLines) {
|
|
32245
|
+
if (/^[0-9a-f]{40}\s/.test(line)) {
|
|
32246
|
+
const parts = line.split(" ");
|
|
32247
|
+
currentCommit = parts[0].slice(0, 8);
|
|
32248
|
+
lineNum = parseInt(parts[2] || "0", 10);
|
|
32249
|
+
} else if (line.startsWith("author ")) {
|
|
32250
|
+
currentAuthor = line.slice(7);
|
|
32251
|
+
} else if (line.startsWith(" ")) {
|
|
32252
|
+
summaryLines.push(`${currentCommit} (${currentAuthor}) L${lineNum}: ${line.slice(1)}`);
|
|
32253
|
+
}
|
|
32254
|
+
}
|
|
32255
|
+
return { content: [{ type: "text", text: summaryLines.join("\n") || output }] };
|
|
32256
|
+
}
|
|
32257
|
+
case "branches": {
|
|
32258
|
+
const output = await runGit(["branch", "-a", "--format=%(refname:short) %(objectname:short) %(subject)"]);
|
|
32259
|
+
return { content: [{ type: "text", text: output || "No branches." }] };
|
|
32260
|
+
}
|
|
32261
|
+
case "stash_list": {
|
|
32262
|
+
const output = await runGit(["stash", "list"]);
|
|
32263
|
+
return { content: [{ type: "text", text: output || "No stashes." }] };
|
|
32264
|
+
}
|
|
32265
|
+
default:
|
|
32266
|
+
return errorResult(`Unknown local vcs action: ${input.action}`);
|
|
31605
32267
|
}
|
|
32268
|
+
}
|
|
32269
|
+
let wsId = resolveWorkspaceId(input.workspace_id);
|
|
32270
|
+
if (!wsId) {
|
|
32271
|
+
return errorResult("Remote VCS actions require a workspace_id. Call init() first or pass workspace_id.");
|
|
32272
|
+
}
|
|
32273
|
+
const resolveRepoPath = () => {
|
|
32274
|
+
if (input.repo_id) return `repos/${input.repo_id}`;
|
|
32275
|
+
if (input.repo_ref) return `repos/${encodeURIComponent(input.repo_ref)}`;
|
|
32276
|
+
return "repos";
|
|
32277
|
+
};
|
|
32278
|
+
const repoPath = resolveRepoPath();
|
|
32279
|
+
const q = {
|
|
32280
|
+
state: input.state,
|
|
32281
|
+
per_page: input.per_page,
|
|
32282
|
+
page: input.page
|
|
32283
|
+
};
|
|
32284
|
+
switch (input.action) {
|
|
32285
|
+
case "list_repos":
|
|
32286
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: "repos", query: q })) }] };
|
|
32287
|
+
case "get_repo":
|
|
32288
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: repoPath })) }] };
|
|
32289
|
+
case "sync_repo":
|
|
32290
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/sync` })) }] };
|
|
32291
|
+
case "list_pulls":
|
|
32292
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls`, query: q })) }] };
|
|
32293
|
+
case "get_pull":
|
|
32294
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}` })) }] };
|
|
32295
|
+
case "get_pull_diff":
|
|
32296
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/diff` })) }] };
|
|
32297
|
+
case "get_pull_comments":
|
|
32298
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/comments` })) }] };
|
|
32299
|
+
case "get_pull_commits":
|
|
32300
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/commits` })) }] };
|
|
32301
|
+
case "get_pull_checks":
|
|
32302
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/checks` })) }] };
|
|
32303
|
+
case "get_pull_summary":
|
|
32304
|
+
case "summarize_pull":
|
|
32305
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/pulls/${input.pull_number}/summary` })) }] };
|
|
32306
|
+
case "review_pull":
|
|
32307
|
+
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 } })) }] };
|
|
32308
|
+
case "comment_pull":
|
|
32309
|
+
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 } })) }] };
|
|
32310
|
+
case "merge_pull":
|
|
32311
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: `${repoPath}/pulls/${input.pull_number}/merge`, body: input.data })) }] };
|
|
32312
|
+
case "list_issues":
|
|
32313
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/issues`, query: q })) }] };
|
|
32314
|
+
case "get_issue":
|
|
32315
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/issues/${input.issue_number}` })) }] };
|
|
32316
|
+
case "create_issue":
|
|
32317
|
+
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 } })) }] };
|
|
32318
|
+
case "update_issue":
|
|
32319
|
+
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 } })) }] };
|
|
32320
|
+
case "comment_issue":
|
|
32321
|
+
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 } })) }] };
|
|
32322
|
+
case "list_commits":
|
|
32323
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/commits`, query: { ...q, ref: input.ref } })) }] };
|
|
32324
|
+
case "get_commit":
|
|
32325
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/commits/${input.ref}` })) }] };
|
|
32326
|
+
case "get_commit_diff":
|
|
32327
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/commits/${input.ref}/diff` })) }] };
|
|
32328
|
+
case "compare_refs":
|
|
32329
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/compare/${input.base_ref}...${input.ref}` })) }] };
|
|
32330
|
+
case "list_branches_remote":
|
|
32331
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/branches`, query: q })) }] };
|
|
32332
|
+
case "list_tags":
|
|
32333
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/tags`, query: q })) }] };
|
|
32334
|
+
case "get_tree":
|
|
32335
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/tree`, query: { ref: input.ref, path: input.path } })) }] };
|
|
32336
|
+
case "get_blob":
|
|
32337
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/blob`, query: { ref: input.ref, path: input.path } })) }] };
|
|
32338
|
+
case "search_code":
|
|
32339
|
+
case "search_vcs":
|
|
32340
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/search`, query: { q: input.query, ...q } })) }] };
|
|
32341
|
+
case "get_activity":
|
|
32342
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/activity`, query: { limit: input.limit } })) }] };
|
|
32343
|
+
case "list_notifications":
|
|
32344
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: "notifications", query: q })) }] };
|
|
32345
|
+
case "mark_notification_read":
|
|
32346
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: `notifications/${input.notification_id}/read` })) }] };
|
|
32347
|
+
case "mark_all_notifications_read":
|
|
32348
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: "notifications/read-all" })) }] };
|
|
32349
|
+
case "list_links":
|
|
32350
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/links` })) }] };
|
|
32351
|
+
case "create_link":
|
|
32352
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/links`, body: input.data })) }] };
|
|
32353
|
+
case "delete_link":
|
|
32354
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "DELETE", path: `${repoPath}/links/${input.link_id}` })) }] };
|
|
32355
|
+
case "list_automations":
|
|
32356
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "GET", path: `${repoPath}/automations` })) }] };
|
|
32357
|
+
case "create_automation":
|
|
32358
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/automations`, body: input.data })) }] };
|
|
32359
|
+
case "update_automation":
|
|
32360
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "PUT", path: `${repoPath}/automations/${input.automation_id}`, body: input.data })) }] };
|
|
32361
|
+
case "delete_automation":
|
|
32362
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "DELETE", path: `${repoPath}/automations/${input.automation_id}` })) }] };
|
|
32363
|
+
case "register_webhook":
|
|
32364
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "POST", path: `${repoPath}/webhooks`, body: input.data })) }] };
|
|
32365
|
+
case "unregister_webhook":
|
|
32366
|
+
return { content: [{ type: "text", text: formatContent(await client.vcsApiRequest({ workspace_id: wsId, method: "DELETE", path: `${repoPath}/webhooks`, body: input.data })) }] };
|
|
31606
32367
|
default:
|
|
31607
|
-
return errorResult(`Unknown vcs action: ${input.action}
|
|
32368
|
+
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
32369
|
}
|
|
31609
32370
|
}
|
|
31610
32371
|
);
|
|
@@ -33403,13 +34164,13 @@ async function runHttpGateway() {
|
|
|
33403
34164
|
// src/index.ts
|
|
33404
34165
|
init_version();
|
|
33405
34166
|
import { existsSync as existsSync16, mkdirSync as mkdirSync8, writeFileSync as writeFileSync9 } from "fs";
|
|
33406
|
-
import { homedir as
|
|
34167
|
+
import { homedir as homedir20 } from "os";
|
|
33407
34168
|
import { join as join22 } from "path";
|
|
33408
34169
|
|
|
33409
34170
|
// src/setup.ts
|
|
33410
34171
|
import * as fs8 from "node:fs/promises";
|
|
33411
34172
|
import * as path9 from "node:path";
|
|
33412
|
-
import { homedir as
|
|
34173
|
+
import { homedir as homedir8 } from "node:os";
|
|
33413
34174
|
import { stdin, stdout } from "node:process";
|
|
33414
34175
|
import { createInterface } from "node:readline/promises";
|
|
33415
34176
|
init_rules_templates();
|
|
@@ -33418,12 +34179,12 @@ init_version();
|
|
|
33418
34179
|
// src/credentials.ts
|
|
33419
34180
|
import * as fs7 from "node:fs/promises";
|
|
33420
34181
|
import * as path8 from "node:path";
|
|
33421
|
-
import { homedir as
|
|
34182
|
+
import { homedir as homedir7 } from "node:os";
|
|
33422
34183
|
function normalizeApiUrl(input) {
|
|
33423
34184
|
return String(input ?? "").trim().replace(/\/+$/, "");
|
|
33424
34185
|
}
|
|
33425
34186
|
function credentialsFilePath() {
|
|
33426
|
-
return path8.join(
|
|
34187
|
+
return path8.join(homedir7(), ".contextstream", "credentials.json");
|
|
33427
34188
|
}
|
|
33428
34189
|
function isRecord(value) {
|
|
33429
34190
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -33702,7 +34463,7 @@ async function upsertTextFile(filePath, content, _marker) {
|
|
|
33702
34463
|
return replaced.status;
|
|
33703
34464
|
}
|
|
33704
34465
|
function globalRulesPathForEditor(editor) {
|
|
33705
|
-
const home =
|
|
34466
|
+
const home = homedir8();
|
|
33706
34467
|
switch (editor) {
|
|
33707
34468
|
case "codex":
|
|
33708
34469
|
return path9.join(home, ".codex", "AGENTS.md");
|
|
@@ -33737,7 +34498,7 @@ async function anyPathExists(paths) {
|
|
|
33737
34498
|
return false;
|
|
33738
34499
|
}
|
|
33739
34500
|
async function isCodexInstalled() {
|
|
33740
|
-
const home =
|
|
34501
|
+
const home = homedir8();
|
|
33741
34502
|
const envHome = process.env.CODEX_HOME;
|
|
33742
34503
|
const candidates = [
|
|
33743
34504
|
envHome,
|
|
@@ -33748,7 +34509,7 @@ async function isCodexInstalled() {
|
|
|
33748
34509
|
return anyPathExists(candidates);
|
|
33749
34510
|
}
|
|
33750
34511
|
function openCodeConfigPath() {
|
|
33751
|
-
const home =
|
|
34512
|
+
const home = homedir8();
|
|
33752
34513
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
33753
34514
|
if (process.platform === "win32") {
|
|
33754
34515
|
const appData = process.env.APPDATA || path9.join(home, "AppData", "Roaming");
|
|
@@ -33760,7 +34521,7 @@ function openCodeConfigPath() {
|
|
|
33760
34521
|
async function isOpenCodeInstalled() {
|
|
33761
34522
|
const configPath = openCodeConfigPath();
|
|
33762
34523
|
const configDir = path9.dirname(configPath);
|
|
33763
|
-
const home =
|
|
34524
|
+
const home = homedir8();
|
|
33764
34525
|
const candidates = [
|
|
33765
34526
|
configDir,
|
|
33766
34527
|
configPath,
|
|
@@ -33770,7 +34531,7 @@ async function isOpenCodeInstalled() {
|
|
|
33770
34531
|
return anyPathExists(candidates);
|
|
33771
34532
|
}
|
|
33772
34533
|
async function isClaudeInstalled() {
|
|
33773
|
-
const home =
|
|
34534
|
+
const home = homedir8();
|
|
33774
34535
|
const candidates = [path9.join(home, ".claude"), path9.join(home, ".config", "claude")];
|
|
33775
34536
|
const desktopConfig = claudeDesktopConfigPath();
|
|
33776
34537
|
if (desktopConfig) candidates.push(desktopConfig);
|
|
@@ -33783,7 +34544,7 @@ async function isClaudeInstalled() {
|
|
|
33783
34544
|
return anyPathExists(candidates);
|
|
33784
34545
|
}
|
|
33785
34546
|
async function isClineInstalled() {
|
|
33786
|
-
const home =
|
|
34547
|
+
const home = homedir8();
|
|
33787
34548
|
const candidates = [
|
|
33788
34549
|
path9.join(home, "Documents", "Cline"),
|
|
33789
34550
|
path9.join(home, ".cline"),
|
|
@@ -33792,7 +34553,7 @@ async function isClineInstalled() {
|
|
|
33792
34553
|
return anyPathExists(candidates);
|
|
33793
34554
|
}
|
|
33794
34555
|
async function isCopilotInstalled() {
|
|
33795
|
-
const home =
|
|
34556
|
+
const home = homedir8();
|
|
33796
34557
|
const candidates = [
|
|
33797
34558
|
path9.join(home, ".copilot"),
|
|
33798
34559
|
path9.join(home, ".config", "github-copilot"),
|
|
@@ -33802,7 +34563,7 @@ async function isCopilotInstalled() {
|
|
|
33802
34563
|
return anyPathExists(candidates);
|
|
33803
34564
|
}
|
|
33804
34565
|
async function isKiloInstalled() {
|
|
33805
|
-
const home =
|
|
34566
|
+
const home = homedir8();
|
|
33806
34567
|
const candidates = [
|
|
33807
34568
|
kiloConfigDir(),
|
|
33808
34569
|
path9.join(home, ".kilocode"),
|
|
@@ -33811,17 +34572,17 @@ async function isKiloInstalled() {
|
|
|
33811
34572
|
return anyPathExists(candidates);
|
|
33812
34573
|
}
|
|
33813
34574
|
async function isRooInstalled() {
|
|
33814
|
-
const home =
|
|
34575
|
+
const home = homedir8();
|
|
33815
34576
|
const candidates = [path9.join(home, ".roo"), path9.join(home, ".config", "roo")];
|
|
33816
34577
|
return anyPathExists(candidates);
|
|
33817
34578
|
}
|
|
33818
34579
|
async function isAiderInstalled() {
|
|
33819
|
-
const home =
|
|
34580
|
+
const home = homedir8();
|
|
33820
34581
|
const candidates = [path9.join(home, ".aider.conf.yml"), path9.join(home, ".config", "aider")];
|
|
33821
34582
|
return anyPathExists(candidates);
|
|
33822
34583
|
}
|
|
33823
34584
|
async function isCursorInstalled() {
|
|
33824
|
-
const home =
|
|
34585
|
+
const home = homedir8();
|
|
33825
34586
|
const candidates = [path9.join(home, ".cursor")];
|
|
33826
34587
|
if (process.platform === "darwin") {
|
|
33827
34588
|
candidates.push("/Applications/Cursor.app");
|
|
@@ -33844,7 +34605,7 @@ async function isCursorInstalled() {
|
|
|
33844
34605
|
return anyPathExists(candidates);
|
|
33845
34606
|
}
|
|
33846
34607
|
async function isWindsurfInstalled() {
|
|
33847
|
-
const home =
|
|
34608
|
+
const home = homedir8();
|
|
33848
34609
|
const candidates = [path9.join(home, ".codeium", "windsurf")];
|
|
33849
34610
|
if (process.platform === "darwin") {
|
|
33850
34611
|
candidates.push("/Applications/Windsurf.app");
|
|
@@ -33867,7 +34628,7 @@ async function isWindsurfInstalled() {
|
|
|
33867
34628
|
return anyPathExists(candidates);
|
|
33868
34629
|
}
|
|
33869
34630
|
async function isAntigravityInstalled() {
|
|
33870
|
-
const home =
|
|
34631
|
+
const home = homedir8();
|
|
33871
34632
|
const candidates = [path9.join(home, ".gemini")];
|
|
33872
34633
|
if (process.platform === "darwin") {
|
|
33873
34634
|
candidates.push("/Applications/Antigravity.app");
|
|
@@ -34071,7 +34832,7 @@ function buildContextStreamOpenCodeLocalServer(params) {
|
|
|
34071
34832
|
};
|
|
34072
34833
|
}
|
|
34073
34834
|
function kiloConfigDir() {
|
|
34074
|
-
const home =
|
|
34835
|
+
const home = homedir8();
|
|
34075
34836
|
if (process.platform === "win32") {
|
|
34076
34837
|
const appData = process.env.APPDATA || path9.join(home, "AppData", "Roaming");
|
|
34077
34838
|
return path9.join(appData, "kilo");
|
|
@@ -34206,7 +34967,7 @@ async function upsertOpenCodeMcpConfig(filePath, server) {
|
|
|
34206
34967
|
return before === after ? "skipped" : "updated";
|
|
34207
34968
|
}
|
|
34208
34969
|
function claudeDesktopConfigPath() {
|
|
34209
|
-
const home =
|
|
34970
|
+
const home = homedir8();
|
|
34210
34971
|
if (process.platform === "darwin") {
|
|
34211
34972
|
return path9.join(
|
|
34212
34973
|
home,
|
|
@@ -34985,7 +35746,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
34985
35746
|
if (mcpScope === "project" && editor !== "codex") continue;
|
|
34986
35747
|
try {
|
|
34987
35748
|
if (editor === "codex") {
|
|
34988
|
-
const filePath = path9.join(
|
|
35749
|
+
const filePath = path9.join(homedir8(), ".codex", "config.toml");
|
|
34989
35750
|
if (dryRun) {
|
|
34990
35751
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
34991
35752
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35001,7 +35762,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
35001
35762
|
continue;
|
|
35002
35763
|
}
|
|
35003
35764
|
if (editor === "copilot") {
|
|
35004
|
-
const filePath = path9.join(
|
|
35765
|
+
const filePath = path9.join(homedir8(), ".copilot", "mcp-config.json");
|
|
35005
35766
|
if (dryRun) {
|
|
35006
35767
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
35007
35768
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35056,7 +35817,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
35056
35817
|
continue;
|
|
35057
35818
|
}
|
|
35058
35819
|
if (editor === "cursor") {
|
|
35059
|
-
const filePath = path9.join(
|
|
35820
|
+
const filePath = path9.join(homedir8(), ".cursor", "mcp.json");
|
|
35060
35821
|
if (dryRun) {
|
|
35061
35822
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
35062
35823
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35068,7 +35829,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
35068
35829
|
continue;
|
|
35069
35830
|
}
|
|
35070
35831
|
if (editor === "windsurf") {
|
|
35071
|
-
const filePath = path9.join(
|
|
35832
|
+
const filePath = path9.join(homedir8(), ".codeium", "windsurf", "mcp_config.json");
|
|
35072
35833
|
if (dryRun) {
|
|
35073
35834
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
35074
35835
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -35338,7 +36099,7 @@ Applying to ${projects.length} project(s)...`);
|
|
|
35338
36099
|
}
|
|
35339
36100
|
if (editor === "windsurf") {
|
|
35340
36101
|
console.log(
|
|
35341
|
-
`- ${EDITOR_LABELS[editor]}: uses global MCP config only (${path9.join(
|
|
36102
|
+
`- ${EDITOR_LABELS[editor]}: uses global MCP config only (${path9.join(homedir8(), ".codeium", "windsurf", "mcp_config.json")}).`
|
|
35342
36103
|
);
|
|
35343
36104
|
continue;
|
|
35344
36105
|
}
|
|
@@ -35556,7 +36317,7 @@ Applying to ${projects.length} project(s)...`);
|
|
|
35556
36317
|
// src/index.ts
|
|
35557
36318
|
var ENABLE_PROMPTS2 = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
|
|
35558
36319
|
function showFirstRunMessage() {
|
|
35559
|
-
const configDir = join22(
|
|
36320
|
+
const configDir = join22(homedir20(), ".contextstream");
|
|
35560
36321
|
const starShownFile = join22(configDir, ".star-shown");
|
|
35561
36322
|
if (existsSync16(starShownFile)) {
|
|
35562
36323
|
return;
|