jinzd-ai-cli 0.4.234 → 0.4.235
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/{auth-FSTAKSYF.js → auth-PE3Z5OHS.js} +1 -1
- package/dist/{batch-T3FRX4B6.js → batch-Y7MHXVR7.js} +2 -2
- package/dist/{chunk-5DTEEWYC.js → chunk-7D5EJBHO.js} +3 -3
- package/dist/{chunk-L5PNAQ6O.js → chunk-BFTTW5LS.js} +1 -1
- package/dist/{chunk-6MJMHHRK.js → chunk-CDOQNIVV.js} +3 -3
- package/dist/{chunk-5VPRZMZB.js → chunk-DHNYGJYB.js} +2 -2
- package/dist/{chunk-E5RLXMSU.js → chunk-FYJGVFXL.js} +85 -52
- package/dist/{chunk-3KTSJ2EL.js → chunk-GDXKFWFL.js} +1 -1
- package/dist/{chunk-II6RZRTF.js → chunk-GFDRC2JZ.js} +1 -1
- package/dist/{chunk-ETJ5X6V7.js → chunk-HHYMSEWS.js} +1 -1
- package/dist/{chunk-AFT6VFMI.js → chunk-Q5GVANMH.js} +1 -1
- package/dist/{chunk-JVKAL5Q3.js → chunk-RYQBBEMM.js} +33 -3
- package/dist/{chunk-TAXIG7HH.js → chunk-WXFQ6LYN.js} +1 -1
- package/dist/{ci-GJ53GPLA.js → ci-OAFNH3MA.js} +4 -4
- package/dist/{ci-format-AXE4QCI6.js → ci-format-4LSXJNND.js} +2 -2
- package/dist/{constants-DC4EXFSB.js → constants-ERIAS7GV.js} +1 -1
- package/dist/{doctor-cli-HKREND6Q.js → doctor-cli-VFSVWZU6.js} +4 -4
- package/dist/electron-server.js +194 -130
- package/dist/{hub-LTTKRGZC.js → hub-X4EUYRIN.js} +1 -1
- package/dist/index.js +19 -19
- package/dist/{pr-4VODJVRV.js → pr-2CZN5JLE.js} +4 -4
- package/dist/{run-tests-G5BNTMWQ.js → run-tests-DXRJDPFF.js} +2 -2
- package/dist/{run-tests-QR2PYR2P.js → run-tests-YSRET52H.js} +1 -1
- package/dist/{server-64WZVZZN.js → server-5ZAXMKRI.js} +14 -13
- package/dist/{server-EO6VQHKL.js → server-FGJGXHZD.js} +4 -4
- package/dist/{task-orchestrator-4INCZMLT.js → task-orchestrator-QMERCD77.js} +4 -4
- package/dist/{usage-T3HFMNNV.js → usage-633DUDNT.js} +2 -2
- package/package.json +2 -4
package/dist/electron-server.js
CHANGED
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
VERSION,
|
|
39
39
|
buildUserIdentityPrompt,
|
|
40
40
|
runTestsTool
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-HHYMSEWS.js";
|
|
42
42
|
import {
|
|
43
43
|
hasSemanticIndex,
|
|
44
44
|
semanticSearch
|
|
@@ -70,8 +70,8 @@ import {
|
|
|
70
70
|
import express from "express";
|
|
71
71
|
import { createServer } from "http";
|
|
72
72
|
import { WebSocketServer } from "ws";
|
|
73
|
-
import { join as join28, dirname as
|
|
74
|
-
import { existsSync as
|
|
73
|
+
import { join as join28, dirname as dirname12, resolve as resolve13, relative as relative5, sep as sep3 } from "path";
|
|
74
|
+
import { existsSync as existsSync34, readFileSync as readFileSync26, readdirSync as readdirSync17, statSync as statSync15, realpathSync as realpathSync2 } from "fs";
|
|
75
75
|
import { networkInterfaces } from "os";
|
|
76
76
|
|
|
77
77
|
// src/config/config-manager.ts
|
|
@@ -1908,12 +1908,12 @@ function findPhantomClaims(content, extraMessages) {
|
|
|
1908
1908
|
const claimed = extractClaimedFilePaths(content);
|
|
1909
1909
|
if (claimed.length === 0) return [];
|
|
1910
1910
|
const normalize = (p) => p.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
1911
|
-
const
|
|
1911
|
+
const basename8 = (p) => {
|
|
1912
1912
|
const parts = normalize(p).split("/");
|
|
1913
1913
|
return parts[parts.length - 1] ?? "";
|
|
1914
1914
|
};
|
|
1915
1915
|
const written = extractWrittenFilePaths(extraMessages).map(normalize);
|
|
1916
|
-
const writtenBases = new Set(written.map(
|
|
1916
|
+
const writtenBases = new Set(written.map(basename8));
|
|
1917
1917
|
const writtenFull = new Set(written);
|
|
1918
1918
|
const bashText = extractBashCommands(extraMessages).map((c) => c.replace(/\\/g, "/").toLowerCase()).join("\n");
|
|
1919
1919
|
return claimed.filter((raw) => {
|
|
@@ -1922,8 +1922,8 @@ function findPhantomClaims(content, extraMessages) {
|
|
|
1922
1922
|
for (const w of writtenFull) {
|
|
1923
1923
|
if (w.endsWith("/" + norm2) || norm2.endsWith("/" + w)) return false;
|
|
1924
1924
|
}
|
|
1925
|
-
if (writtenBases.has(
|
|
1926
|
-
const base =
|
|
1925
|
+
if (writtenBases.has(basename8(norm2))) return false;
|
|
1926
|
+
const base = basename8(norm2);
|
|
1927
1927
|
if (base && bashText.includes(base)) return false;
|
|
1928
1928
|
return true;
|
|
1929
1929
|
});
|
|
@@ -5937,11 +5937,11 @@ ${content}`;
|
|
|
5937
5937
|
|
|
5938
5938
|
// src/tools/builtin/write-file.ts
|
|
5939
5939
|
import { appendFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
5940
|
-
import { dirname as
|
|
5940
|
+
import { dirname as dirname5 } from "path";
|
|
5941
5941
|
|
|
5942
5942
|
// src/tools/executor.ts
|
|
5943
5943
|
import chalk3 from "chalk";
|
|
5944
|
-
import { existsSync as
|
|
5944
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9 } from "fs";
|
|
5945
5945
|
import { tmpdir } from "os";
|
|
5946
5946
|
|
|
5947
5947
|
// src/core/readline-internal.ts
|
|
@@ -6310,7 +6310,8 @@ function runHook(template, vars) {
|
|
|
6310
6310
|
}
|
|
6311
6311
|
|
|
6312
6312
|
// src/tools/permissions.ts
|
|
6313
|
-
import {
|
|
6313
|
+
import { existsSync as existsSync8, realpathSync } from "fs";
|
|
6314
|
+
import { basename as basename2, dirname as dirname3, isAbsolute, resolve as resolve3 } from "path";
|
|
6314
6315
|
function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "confirm") {
|
|
6315
6316
|
for (const rule of rules) {
|
|
6316
6317
|
if (rule.tool !== "*" && rule.tool !== toolName) continue;
|
|
@@ -6355,10 +6356,28 @@ var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
|
6355
6356
|
function normalizePathForPermission(value) {
|
|
6356
6357
|
return value.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
6357
6358
|
}
|
|
6359
|
+
function canonicalizeWithNearestParent(value) {
|
|
6360
|
+
const missing = [];
|
|
6361
|
+
let cursor = resolve3(value);
|
|
6362
|
+
while (!existsSync8(cursor)) {
|
|
6363
|
+
const parent = dirname3(cursor);
|
|
6364
|
+
if (parent === cursor) return null;
|
|
6365
|
+
missing.unshift(basename2(cursor));
|
|
6366
|
+
cursor = parent;
|
|
6367
|
+
}
|
|
6368
|
+
try {
|
|
6369
|
+
return resolve3(realpathSync(cursor), ...missing);
|
|
6370
|
+
} catch {
|
|
6371
|
+
return null;
|
|
6372
|
+
}
|
|
6373
|
+
}
|
|
6358
6374
|
function isInsidePath(root, target) {
|
|
6359
6375
|
const absoluteTarget = isAbsolute(target) ? target : resolve3(root, target);
|
|
6360
|
-
const
|
|
6361
|
-
const
|
|
6376
|
+
const canonicalRoot = canonicalizeWithNearestParent(root);
|
|
6377
|
+
const canonicalTarget = canonicalizeWithNearestParent(absoluteTarget);
|
|
6378
|
+
if (!canonicalRoot || !canonicalTarget) return false;
|
|
6379
|
+
const r = normalizePathForPermission(canonicalRoot);
|
|
6380
|
+
const t = normalizePathForPermission(canonicalTarget);
|
|
6362
6381
|
return t === r || t.startsWith(`${r}/`);
|
|
6363
6382
|
}
|
|
6364
6383
|
function extractPathArg(toolName, args) {
|
|
@@ -6410,19 +6429,31 @@ function profileHardDecision(profileName, toolName, args, dangerLevel, ctx) {
|
|
|
6410
6429
|
return null;
|
|
6411
6430
|
}
|
|
6412
6431
|
if (profileName === "workspace-write") {
|
|
6413
|
-
if (dangerLevel === "destructive")
|
|
6432
|
+
if (dangerLevel === "destructive") {
|
|
6433
|
+
return { action: "confirm", reason: "destructive tools always require confirmation", profileName, hardBoundary: true };
|
|
6434
|
+
}
|
|
6414
6435
|
if (dangerLevel === "write" && isExplicitFileWriteTool(toolName)) {
|
|
6415
6436
|
const target = extractPathArg(toolName, args);
|
|
6416
|
-
if (!target)
|
|
6437
|
+
if (!target) {
|
|
6438
|
+
return { action: "confirm", reason: "file write target is not explicit", profileName, hardBoundary: true };
|
|
6439
|
+
}
|
|
6417
6440
|
const allowedRoots = getAllowedWriteRoots(ctx);
|
|
6418
6441
|
if (allowedRoots.length === 0 || !allowedRoots.some((root) => isInsidePath(root, target))) {
|
|
6419
|
-
return { action: "deny", reason: "file write target is outside workspace/temp roots", profileName };
|
|
6442
|
+
return { action: "deny", reason: "file write target is outside workspace/temp roots", profileName, hardBoundary: true };
|
|
6420
6443
|
}
|
|
6421
6444
|
}
|
|
6445
|
+
if (toolName === "bash" || toolName === "run_interactive" || toolName === "task_create") {
|
|
6446
|
+
return {
|
|
6447
|
+
action: "confirm",
|
|
6448
|
+
reason: "shell/process writes cannot be proven to stay inside workspace/temp roots",
|
|
6449
|
+
profileName,
|
|
6450
|
+
hardBoundary: true
|
|
6451
|
+
};
|
|
6452
|
+
}
|
|
6422
6453
|
return null;
|
|
6423
6454
|
}
|
|
6424
6455
|
if (profileName === "danger-full-access") {
|
|
6425
|
-
if (dangerLevel === "destructive") return { action: "confirm", reason: "destructive tools still require confirmation", profileName };
|
|
6456
|
+
if (dangerLevel === "destructive") return { action: "confirm", reason: "destructive tools still require confirmation", profileName, hardBoundary: true };
|
|
6426
6457
|
return null;
|
|
6427
6458
|
}
|
|
6428
6459
|
return null;
|
|
@@ -6434,7 +6465,8 @@ function checkPermissionWithProfile(toolName, args, dangerLevel, rules, defaultA
|
|
|
6434
6465
|
const combinedRules = [...getProfileRules(profileContext), ...rules];
|
|
6435
6466
|
const profileDefault = profileName === "legacy" ? defaultAction : getProfileDefaultAction(profileName, profileContext);
|
|
6436
6467
|
const action = checkPermission(toolName, args, dangerLevel, combinedRules, profileDefault);
|
|
6437
|
-
if (
|
|
6468
|
+
if (action === "deny") return { action, profileName };
|
|
6469
|
+
if (hard?.action === "confirm") return hard;
|
|
6438
6470
|
return { action, profileName };
|
|
6439
6471
|
}
|
|
6440
6472
|
function formatPermissionProfileWarning(profileName) {
|
|
@@ -6692,8 +6724,8 @@ var theme = new Proxy(DARK_THEME, {
|
|
|
6692
6724
|
});
|
|
6693
6725
|
|
|
6694
6726
|
// src/diagnostics/tool-stats.ts
|
|
6695
|
-
import { existsSync as
|
|
6696
|
-
import { join as join5, dirname as
|
|
6727
|
+
import { existsSync as existsSync9, readFileSync as readFileSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
6728
|
+
import { join as join5, dirname as dirname4 } from "path";
|
|
6697
6729
|
import { homedir as homedir3 } from "os";
|
|
6698
6730
|
var STATS_FILE_NAME = "tool-stats.json";
|
|
6699
6731
|
var STATS_VERSION = 1;
|
|
@@ -6708,7 +6740,7 @@ function statsFilePath() {
|
|
|
6708
6740
|
}
|
|
6709
6741
|
function load() {
|
|
6710
6742
|
const path3 = statsFilePath();
|
|
6711
|
-
if (!
|
|
6743
|
+
if (!existsSync9(path3)) {
|
|
6712
6744
|
return { version: STATS_VERSION, startedAt: (/* @__PURE__ */ new Date()).toISOString(), entries: {} };
|
|
6713
6745
|
}
|
|
6714
6746
|
try {
|
|
@@ -6770,7 +6802,7 @@ function flush() {
|
|
|
6770
6802
|
if (!dirty || state === null) return;
|
|
6771
6803
|
const path3 = statsFilePath();
|
|
6772
6804
|
try {
|
|
6773
|
-
mkdirSync5(
|
|
6805
|
+
mkdirSync5(dirname4(path3), { recursive: true });
|
|
6774
6806
|
atomicWriteFileSync(path3, JSON.stringify(state, null, 2));
|
|
6775
6807
|
dirty = false;
|
|
6776
6808
|
pendingWrites = 0;
|
|
@@ -6794,7 +6826,7 @@ function getTopUsedTools(limit = 5) {
|
|
|
6794
6826
|
}
|
|
6795
6827
|
|
|
6796
6828
|
// src/tools/action-classifier.ts
|
|
6797
|
-
import { existsSync as
|
|
6829
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "fs";
|
|
6798
6830
|
import { isAbsolute as isAbsolute2, join as join6, resolve as resolve4 } from "path";
|
|
6799
6831
|
var RECENT_DENIED_LIMIT = 50;
|
|
6800
6832
|
var recentlyDenied = [];
|
|
@@ -6837,7 +6869,7 @@ function splitShellWords(command) {
|
|
|
6837
6869
|
}
|
|
6838
6870
|
function readPackageManifest(root) {
|
|
6839
6871
|
const p = join6(root, "package.json");
|
|
6840
|
-
if (!
|
|
6872
|
+
if (!existsSync10(p)) return null;
|
|
6841
6873
|
try {
|
|
6842
6874
|
return JSON.parse(readFileSync8(p, "utf-8"));
|
|
6843
6875
|
} catch {
|
|
@@ -6856,7 +6888,7 @@ function manifestHasDependency(root, name) {
|
|
|
6856
6888
|
function lockfileMentions(root, name) {
|
|
6857
6889
|
for (const file of ["package-lock.json", "pnpm-lock.yaml", "yarn.lock"]) {
|
|
6858
6890
|
const p = join6(root, file);
|
|
6859
|
-
if (!
|
|
6891
|
+
if (!existsSync10(p)) continue;
|
|
6860
6892
|
try {
|
|
6861
6893
|
if (readFileSync8(p, "utf-8").includes(name)) return true;
|
|
6862
6894
|
} catch {
|
|
@@ -7132,14 +7164,15 @@ var ToolExecutor = class {
|
|
|
7132
7164
|
return { callId: call.id, content: message, isError: true };
|
|
7133
7165
|
}
|
|
7134
7166
|
}
|
|
7135
|
-
|
|
7167
|
+
const requiresHardConfirmation = permission.action === "confirm" && permission.hardBoundary === true;
|
|
7168
|
+
if ((networkPermission?.action === "confirm" || requiresHardConfirmation) && dangerLevel === "safe") {
|
|
7136
7169
|
this.printToolCall(call);
|
|
7137
7170
|
toolCallAlreadyPrinted = true;
|
|
7138
7171
|
const confirmed = await this.confirm(call, "write");
|
|
7139
7172
|
if (!confirmed) {
|
|
7140
7173
|
return {
|
|
7141
7174
|
callId: call.id,
|
|
7142
|
-
content: `[User cancelled] The user declined
|
|
7175
|
+
content: `[User cancelled] The user declined permission for ${call.name}. Do not retry without asking.`,
|
|
7143
7176
|
isError: true
|
|
7144
7177
|
};
|
|
7145
7178
|
}
|
|
@@ -7157,7 +7190,7 @@ var ToolExecutor = class {
|
|
|
7157
7190
|
isError: true
|
|
7158
7191
|
};
|
|
7159
7192
|
}
|
|
7160
|
-
if (classification.decision === "auto-approve") {
|
|
7193
|
+
if (classification.decision === "auto-approve" && !requiresHardConfirmation) {
|
|
7161
7194
|
this.printToolCall(call);
|
|
7162
7195
|
if (dangerLevel === "write") this.printDiffPreview(call);
|
|
7163
7196
|
console.log(theme.warning(` \u26A1 Auto-approved (/auto: ${classification.ruleId})`));
|
|
@@ -7178,7 +7211,7 @@ var ToolExecutor = class {
|
|
|
7178
7211
|
}
|
|
7179
7212
|
}
|
|
7180
7213
|
}
|
|
7181
|
-
if (this.sessionAutoApprove && dangerLevel === "write") {
|
|
7214
|
+
if (this.sessionAutoApprove && dangerLevel === "write" && !requiresHardConfirmation) {
|
|
7182
7215
|
this.printToolCall(call);
|
|
7183
7216
|
if (dangerLevel === "write") this.printDiffPreview(call);
|
|
7184
7217
|
console.log(theme.warning(" \u26A1 Auto-approved (session /yolo mode)"));
|
|
@@ -7422,7 +7455,7 @@ var ToolExecutor = class {
|
|
|
7422
7455
|
const filePath = String(call.arguments["path"] ?? "");
|
|
7423
7456
|
const newContent = String(call.arguments["content"] ?? "");
|
|
7424
7457
|
if (!filePath) return;
|
|
7425
|
-
if (
|
|
7458
|
+
if (existsSync11(filePath)) {
|
|
7426
7459
|
let oldContent;
|
|
7427
7460
|
try {
|
|
7428
7461
|
oldContent = readFileSync9(filePath, "utf-8");
|
|
@@ -7448,7 +7481,7 @@ var ToolExecutor = class {
|
|
|
7448
7481
|
}
|
|
7449
7482
|
} else if (call.name === "edit_file") {
|
|
7450
7483
|
const filePath = String(call.arguments["path"] ?? "");
|
|
7451
|
-
if (!filePath || !
|
|
7484
|
+
if (!filePath || !existsSync11(filePath)) return;
|
|
7452
7485
|
const oldStr = call.arguments["old_str"];
|
|
7453
7486
|
const newStr = call.arguments["new_str"];
|
|
7454
7487
|
if (oldStr !== void 0) {
|
|
@@ -7567,7 +7600,7 @@ var ToolExecutor = class {
|
|
|
7567
7600
|
};
|
|
7568
7601
|
|
|
7569
7602
|
// src/tools/sensitive-paths.ts
|
|
7570
|
-
import { resolve as resolve5, sep as sep2, basename as
|
|
7603
|
+
import { resolve as resolve5, sep as sep2, basename as basename3 } from "path";
|
|
7571
7604
|
import { homedir as homedir4 } from "os";
|
|
7572
7605
|
var home = homedir4();
|
|
7573
7606
|
function norm(p) {
|
|
@@ -7586,7 +7619,7 @@ function homeRel(p) {
|
|
|
7586
7619
|
function classifyWritePath(path3) {
|
|
7587
7620
|
if (!path3) return { sensitive: false };
|
|
7588
7621
|
const abs = norm(path3);
|
|
7589
|
-
const base =
|
|
7622
|
+
const base = basename3(abs);
|
|
7590
7623
|
const rel = homeRel(path3);
|
|
7591
7624
|
if (rel) {
|
|
7592
7625
|
const shellRc = /* @__PURE__ */ new Set([
|
|
@@ -7710,7 +7743,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
7710
7743
|
}
|
|
7711
7744
|
undoStack.push(filePath, `write_file${appendMode ? " (append)" : ""}: ${filePath}`);
|
|
7712
7745
|
fileCheckpoints.snapshot(filePath, ToolExecutor.currentMessageIndex);
|
|
7713
|
-
mkdirSync6(
|
|
7746
|
+
mkdirSync6(dirname5(filePath), { recursive: true });
|
|
7714
7747
|
if (appendMode) {
|
|
7715
7748
|
appendFileSync(filePath, content, encoding);
|
|
7716
7749
|
} else {
|
|
@@ -7730,7 +7763,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
|
|
|
7730
7763
|
};
|
|
7731
7764
|
|
|
7732
7765
|
// src/tools/builtin/edit-file.ts
|
|
7733
|
-
import { readFileSync as readFileSync10, existsSync as
|
|
7766
|
+
import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
|
|
7734
7767
|
|
|
7735
7768
|
// src/tools/builtin/patch-apply.ts
|
|
7736
7769
|
function parseUnifiedDiff(patch) {
|
|
@@ -8091,7 +8124,7 @@ Note: Path can be absolute or relative to cwd.`,
|
|
|
8091
8124
|
const filePath = String(args["path"] ?? args["file"] ?? "");
|
|
8092
8125
|
const encoding = args["encoding"] ?? "utf-8";
|
|
8093
8126
|
if (!filePath) throw new ToolError("edit_file", "path is required");
|
|
8094
|
-
if (!
|
|
8127
|
+
if (!existsSync12(filePath)) throw new ToolError("edit_file", `File not found: ${filePath}`);
|
|
8095
8128
|
const verdict = classifyWritePath(filePath);
|
|
8096
8129
|
if (verdict.sensitive && subAgentGuard.active) {
|
|
8097
8130
|
throw new ToolError(
|
|
@@ -8257,8 +8290,8 @@ function truncatePreview(str, maxLen = 80) {
|
|
|
8257
8290
|
}
|
|
8258
8291
|
|
|
8259
8292
|
// src/tools/builtin/list-dir.ts
|
|
8260
|
-
import { readdirSync as readdirSync4, statSync as statSync4, existsSync as
|
|
8261
|
-
import { join as join7, basename as
|
|
8293
|
+
import { readdirSync as readdirSync4, statSync as statSync4, existsSync as existsSync13 } from "fs";
|
|
8294
|
+
import { join as join7, basename as basename4 } from "path";
|
|
8262
8295
|
var listDirTool = {
|
|
8263
8296
|
definition: {
|
|
8264
8297
|
name: "list_dir",
|
|
@@ -8280,8 +8313,8 @@ var listDirTool = {
|
|
|
8280
8313
|
async execute(args) {
|
|
8281
8314
|
const dirPath = String(args["path"] ?? process.cwd());
|
|
8282
8315
|
const recursive = Boolean(args["recursive"] ?? false);
|
|
8283
|
-
if (!
|
|
8284
|
-
const targetName =
|
|
8316
|
+
if (!existsSync13(dirPath)) {
|
|
8317
|
+
const targetName = basename4(dirPath).toLowerCase();
|
|
8285
8318
|
const cwd = process.cwd();
|
|
8286
8319
|
const suggestions = [];
|
|
8287
8320
|
try {
|
|
@@ -8358,7 +8391,7 @@ function formatSize(bytes) {
|
|
|
8358
8391
|
}
|
|
8359
8392
|
|
|
8360
8393
|
// src/tools/builtin/grep-files.ts
|
|
8361
|
-
import { readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync5, existsSync as
|
|
8394
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync5, existsSync as existsSync14 } from "fs";
|
|
8362
8395
|
import { readFile } from "fs/promises";
|
|
8363
8396
|
import { join as join8, relative } from "path";
|
|
8364
8397
|
var grepFilesTool = {
|
|
@@ -8411,7 +8444,7 @@ Supports regex. Automatically skips node_modules, dist, .git directories.`,
|
|
|
8411
8444
|
const contextLines = Math.max(0, Number(args["context_lines"] ?? 0));
|
|
8412
8445
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 50));
|
|
8413
8446
|
if (!pattern) throw new ToolError("grep_files", "pattern is required");
|
|
8414
|
-
if (!
|
|
8447
|
+
if (!existsSync14(rootPath)) throw new ToolError("grep_files", `Path not found: ${rootPath}`);
|
|
8415
8448
|
const MAX_PATTERN_LENGTH = 1e3;
|
|
8416
8449
|
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
8417
8450
|
throw new ToolError("grep_files", `Pattern too long (${pattern.length} chars, max ${MAX_PATTERN_LENGTH}). Use a shorter pattern.`);
|
|
@@ -8595,8 +8628,8 @@ function searchInFile(fullPath, displayPath2, regex, contextLines, maxResults, r
|
|
|
8595
8628
|
}
|
|
8596
8629
|
|
|
8597
8630
|
// src/tools/builtin/glob-files.ts
|
|
8598
|
-
import { readdirSync as readdirSync6, statSync as statSync6, existsSync as
|
|
8599
|
-
import { join as join9, relative as relative2, basename as
|
|
8631
|
+
import { readdirSync as readdirSync6, statSync as statSync6, existsSync as existsSync15 } from "fs";
|
|
8632
|
+
import { join as join9, relative as relative2, basename as basename5 } from "path";
|
|
8600
8633
|
var globFilesTool = {
|
|
8601
8634
|
definition: {
|
|
8602
8635
|
name: "glob_files",
|
|
@@ -8629,7 +8662,7 @@ Results sorted by most recent modification time. Automatically skips node_module
|
|
|
8629
8662
|
const rootPath = String(args["path"] ?? process.cwd());
|
|
8630
8663
|
const maxResults = Math.max(1, Number(args["max_results"] ?? 100));
|
|
8631
8664
|
if (!pattern) throw new ToolError("glob_files", "pattern is required");
|
|
8632
|
-
if (!
|
|
8665
|
+
if (!existsSync15(rootPath)) throw new ToolError("glob_files", `Path not found: ${rootPath}`);
|
|
8633
8666
|
const regex = globToRegex(pattern);
|
|
8634
8667
|
const matches = [];
|
|
8635
8668
|
collectMatchingFiles(rootPath, rootPath, regex, matches, maxResults);
|
|
@@ -8712,7 +8745,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
|
|
|
8712
8745
|
collectMatchingFiles(fullPath, rootPath, regex, results, maxResults);
|
|
8713
8746
|
} else if (entry.isFile()) {
|
|
8714
8747
|
const relPath = relative2(rootPath, fullPath).replace(/\\/g, "/");
|
|
8715
|
-
if (regex.test(relPath) || regex.test(
|
|
8748
|
+
if (regex.test(relPath) || regex.test(basename5(relPath))) {
|
|
8716
8749
|
try {
|
|
8717
8750
|
const stat = statSync6(fullPath);
|
|
8718
8751
|
results.push({ relPath, absPath: fullPath, mtime: stat.mtimeMs });
|
|
@@ -9447,7 +9480,7 @@ ${preamble}`;
|
|
|
9447
9480
|
|
|
9448
9481
|
// src/tools/builtin/save-last-response.ts
|
|
9449
9482
|
import { mkdirSync as mkdirSync7, unlinkSync as unlinkSync4, rmdirSync as rmdirSync2 } from "fs";
|
|
9450
|
-
import { dirname as
|
|
9483
|
+
import { dirname as dirname6 } from "path";
|
|
9451
9484
|
var lastResponseStore = { content: "" };
|
|
9452
9485
|
function cleanupRejectedTeeFile(filePath) {
|
|
9453
9486
|
try {
|
|
@@ -9455,7 +9488,7 @@ function cleanupRejectedTeeFile(filePath) {
|
|
|
9455
9488
|
} catch {
|
|
9456
9489
|
}
|
|
9457
9490
|
try {
|
|
9458
|
-
rmdirSync2(
|
|
9491
|
+
rmdirSync2(dirname6(filePath));
|
|
9459
9492
|
} catch {
|
|
9460
9493
|
}
|
|
9461
9494
|
}
|
|
@@ -9496,7 +9529,7 @@ Any of these triggers means use save_last_response, NOT write_file:
|
|
|
9496
9529
|
throw new ToolError("save_last_response", "No content to save: AI has not produced any response yet, or the last response was empty.");
|
|
9497
9530
|
}
|
|
9498
9531
|
undoStack.push(filePath, `save_last_response: ${filePath}`);
|
|
9499
|
-
mkdirSync7(
|
|
9532
|
+
mkdirSync7(dirname6(filePath), { recursive: true });
|
|
9500
9533
|
atomicWriteFileSync(filePath, content);
|
|
9501
9534
|
const lines = content.split("\n").length;
|
|
9502
9535
|
return `File saved: ${filePath} (${lines} lines, ${content.length} bytes)`;
|
|
@@ -9508,13 +9541,13 @@ import { join as join12 } from "path";
|
|
|
9508
9541
|
import { homedir as homedir5 } from "os";
|
|
9509
9542
|
|
|
9510
9543
|
// src/memory/persistent-memory.ts
|
|
9511
|
-
import { existsSync as
|
|
9544
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync12 } from "fs";
|
|
9512
9545
|
import { randomUUID, createHash as createHash2 } from "crypto";
|
|
9513
|
-
import { dirname as
|
|
9546
|
+
import { dirname as dirname7, join as join11, resolve as resolve6 } from "path";
|
|
9514
9547
|
|
|
9515
9548
|
// src/tools/git-context.ts
|
|
9516
9549
|
import { execSync as execSync2 } from "child_process";
|
|
9517
|
-
import { existsSync as
|
|
9550
|
+
import { existsSync as existsSync16 } from "fs";
|
|
9518
9551
|
import { join as join10 } from "path";
|
|
9519
9552
|
function runGit(cmd, cwd) {
|
|
9520
9553
|
try {
|
|
@@ -9532,7 +9565,7 @@ function getGitRoot(cwd = process.cwd()) {
|
|
|
9532
9565
|
return runGit("rev-parse --show-toplevel", cwd);
|
|
9533
9566
|
}
|
|
9534
9567
|
function getGitContext(cwd = process.cwd()) {
|
|
9535
|
-
if (!
|
|
9568
|
+
if (!existsSync16(join10(cwd, ".git"))) {
|
|
9536
9569
|
const result = runGit("rev-parse --git-dir", cwd);
|
|
9537
9570
|
if (!result) return null;
|
|
9538
9571
|
}
|
|
@@ -9643,7 +9676,7 @@ function normalizeEntry(value) {
|
|
|
9643
9676
|
}
|
|
9644
9677
|
function legacyEntriesFromMarkdown(configDir) {
|
|
9645
9678
|
const file = memoryMarkdownPath(configDir);
|
|
9646
|
-
if (!
|
|
9679
|
+
if (!existsSync17(file)) return [];
|
|
9647
9680
|
const content = readFileSync12(file, "utf-8").trim();
|
|
9648
9681
|
if (!content) return [];
|
|
9649
9682
|
const parts = content.split(/\n(?=##\s+\d{4}-\d{2}-\d{2})/g);
|
|
@@ -9660,7 +9693,7 @@ ${chunk}`).digest("hex").slice(0, 12);
|
|
|
9660
9693
|
}
|
|
9661
9694
|
function loadMemoryEntries(configDir) {
|
|
9662
9695
|
const file = memoryStorePath(configDir);
|
|
9663
|
-
if (!
|
|
9696
|
+
if (!existsSync17(file)) return legacyEntriesFromMarkdown(configDir);
|
|
9664
9697
|
const text = readFileSync12(file, "utf-8").trim();
|
|
9665
9698
|
if (!text) return [];
|
|
9666
9699
|
const entries = [];
|
|
@@ -10108,13 +10141,13 @@ function formatResults2(query, data, _requested) {
|
|
|
10108
10141
|
}
|
|
10109
10142
|
|
|
10110
10143
|
// src/agents/agent-config.ts
|
|
10111
|
-
import { existsSync as
|
|
10144
|
+
import { existsSync as existsSync19, readdirSync as readdirSync8, readFileSync as readFileSync14 } from "fs";
|
|
10112
10145
|
import { join as join14 } from "path";
|
|
10113
10146
|
import { homedir as homedir6 } from "os";
|
|
10114
10147
|
|
|
10115
10148
|
// src/plugins/plugin-manager.ts
|
|
10116
|
-
import { existsSync as
|
|
10117
|
-
import { basename as
|
|
10149
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync9, readdirSync as readdirSync7, readFileSync as readFileSync13, cpSync, rmSync, statSync as statSync7 } from "fs";
|
|
10150
|
+
import { basename as basename6, dirname as dirname8, join as join13, resolve as resolve7 } from "path";
|
|
10118
10151
|
import { createHash as createHash3 } from "crypto";
|
|
10119
10152
|
import { z as z2 } from "zod";
|
|
10120
10153
|
var MANIFEST_RELATIVE = ".aicli-plugin/plugin.json";
|
|
@@ -10184,7 +10217,7 @@ function statePath(configDir) {
|
|
|
10184
10217
|
}
|
|
10185
10218
|
function loadState(configDir) {
|
|
10186
10219
|
const file = statePath(configDir);
|
|
10187
|
-
if (!
|
|
10220
|
+
if (!existsSync18(file)) return { version: 1, plugins: [] };
|
|
10188
10221
|
try {
|
|
10189
10222
|
const parsed = JSON.parse(readFileSync13(file, "utf-8"));
|
|
10190
10223
|
return { version: 1, plugins: Array.isArray(parsed.plugins) ? parsed.plugins : [] };
|
|
@@ -10204,10 +10237,10 @@ function readPluginManifest(manifestPath) {
|
|
|
10204
10237
|
}
|
|
10205
10238
|
function findPluginSourceDir(inputPath) {
|
|
10206
10239
|
const abs = resolve7(inputPath);
|
|
10207
|
-
const direct = statSync7(abs).isDirectory() ? abs :
|
|
10208
|
-
if (
|
|
10240
|
+
const direct = statSync7(abs).isDirectory() ? abs : dirname8(abs);
|
|
10241
|
+
if (existsSync18(pluginManifestPath(direct))) return direct;
|
|
10209
10242
|
const nested = join13(direct, ".aicli-plugin");
|
|
10210
|
-
if (
|
|
10243
|
+
if (existsSync18(join13(nested, "plugin.json"))) return direct;
|
|
10211
10244
|
throw new Error(`plugin manifest not found: ${MANIFEST_RELATIVE}`);
|
|
10212
10245
|
}
|
|
10213
10246
|
function installPlugin(configDir, inputPath) {
|
|
@@ -10215,7 +10248,7 @@ function installPlugin(configDir, inputPath) {
|
|
|
10215
10248
|
const manifest = readPluginManifest(pluginManifestPath(sourceDir));
|
|
10216
10249
|
const targetDir = join13(pluginRoot(configDir), manifest.name);
|
|
10217
10250
|
mkdirSync9(pluginRoot(configDir), { recursive: true });
|
|
10218
|
-
if (
|
|
10251
|
+
if (existsSync18(targetDir)) rmSync(targetDir, { recursive: true, force: true });
|
|
10219
10252
|
cpSync(sourceDir, targetDir, { recursive: true });
|
|
10220
10253
|
const manifestPath = pluginManifestPath(targetDir);
|
|
10221
10254
|
const hash = hashPluginManifest(manifestPath);
|
|
@@ -10273,7 +10306,7 @@ function getInstalledPlugin(configDir, name) {
|
|
|
10273
10306
|
}
|
|
10274
10307
|
function listInstalledPlugins(configDir) {
|
|
10275
10308
|
const root = pluginRoot(configDir);
|
|
10276
|
-
if (!
|
|
10309
|
+
if (!existsSync18(root)) return [];
|
|
10277
10310
|
const state2 = loadState(configDir);
|
|
10278
10311
|
const out = [];
|
|
10279
10312
|
for (const entry of readdirSync7(root)) {
|
|
@@ -10284,7 +10317,7 @@ function listInstalledPlugins(configDir) {
|
|
|
10284
10317
|
continue;
|
|
10285
10318
|
}
|
|
10286
10319
|
const manifestPath = pluginManifestPath(dir);
|
|
10287
|
-
if (!
|
|
10320
|
+
if (!existsSync18(manifestPath)) continue;
|
|
10288
10321
|
try {
|
|
10289
10322
|
const manifest = readPluginManifest(manifestPath);
|
|
10290
10323
|
const hash = hashPluginManifest(manifestPath);
|
|
@@ -10324,7 +10357,7 @@ function uniqueDirs(plugin, rels) {
|
|
|
10324
10357
|
for (const rel of rels) {
|
|
10325
10358
|
const abs = resolve7(plugin.dir, rel);
|
|
10326
10359
|
if (!abs.startsWith(resolve7(plugin.dir))) continue;
|
|
10327
|
-
if (
|
|
10360
|
+
if (existsSync18(abs)) dirs.add(statSync7(abs).isDirectory() ? abs : dirname8(abs));
|
|
10328
10361
|
}
|
|
10329
10362
|
return [...dirs];
|
|
10330
10363
|
}
|
|
@@ -10487,7 +10520,7 @@ function parseAgentConfig(raw, source, path3) {
|
|
|
10487
10520
|
return cfg;
|
|
10488
10521
|
}
|
|
10489
10522
|
function loadAgentDir(dir, source) {
|
|
10490
|
-
if (!
|
|
10523
|
+
if (!existsSync19(dir)) return [];
|
|
10491
10524
|
const out = [];
|
|
10492
10525
|
for (const file of readdirSync8(dir)) {
|
|
10493
10526
|
if (!file.endsWith(".json")) continue;
|
|
@@ -11219,13 +11252,13 @@ var taskStopTool = {
|
|
|
11219
11252
|
|
|
11220
11253
|
// src/tools/builtin/git-tools.ts
|
|
11221
11254
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
11222
|
-
import { existsSync as
|
|
11255
|
+
import { existsSync as existsSync20 } from "fs";
|
|
11223
11256
|
import { join as join15 } from "path";
|
|
11224
11257
|
function assertGitRepo(cwd) {
|
|
11225
11258
|
let dir = cwd;
|
|
11226
11259
|
const root = dir.split(/[\\/]/)[0] + (dir.includes("\\") ? "\\" : "/");
|
|
11227
11260
|
while (dir && dir !== root) {
|
|
11228
|
-
if (
|
|
11261
|
+
if (existsSync20(join15(dir, ".git"))) return;
|
|
11229
11262
|
const parent = join15(dir, "..");
|
|
11230
11263
|
if (parent === dir) break;
|
|
11231
11264
|
dir = parent;
|
|
@@ -11491,7 +11524,7 @@ ${commitOutput.trim()}`;
|
|
|
11491
11524
|
};
|
|
11492
11525
|
|
|
11493
11526
|
// src/tools/builtin/notebook-edit.ts
|
|
11494
|
-
import { readFileSync as readFileSync15, existsSync as
|
|
11527
|
+
import { readFileSync as readFileSync15, existsSync as existsSync21 } from "fs";
|
|
11495
11528
|
import { writeFile } from "fs/promises";
|
|
11496
11529
|
import { resolve as resolve8, extname as extname2 } from "path";
|
|
11497
11530
|
var notebookEditTool = {
|
|
@@ -11546,7 +11579,7 @@ var notebookEditTool = {
|
|
|
11546
11579
|
if (extname2(absPath).toLowerCase() !== ".ipynb") {
|
|
11547
11580
|
throw new ToolError("notebook_edit", "path must point to a .ipynb file");
|
|
11548
11581
|
}
|
|
11549
|
-
if (!
|
|
11582
|
+
if (!existsSync21(absPath)) {
|
|
11550
11583
|
throw new ToolError("notebook_edit", `Notebook not found: ${filePath}`);
|
|
11551
11584
|
}
|
|
11552
11585
|
const raw = readFileSync15(absPath, "utf-8");
|
|
@@ -11966,7 +11999,7 @@ function estimateToolDefinitionTokens(def) {
|
|
|
11966
11999
|
|
|
11967
12000
|
// src/tools/registry.ts
|
|
11968
12001
|
import { pathToFileURL } from "url";
|
|
11969
|
-
import { existsSync as
|
|
12002
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync10, readdirSync as readdirSync9 } from "fs";
|
|
11970
12003
|
import { join as join16 } from "path";
|
|
11971
12004
|
var ToolRegistry = class {
|
|
11972
12005
|
tools = /* @__PURE__ */ new Map();
|
|
@@ -12128,7 +12161,7 @@ var ToolRegistry = class {
|
|
|
12128
12161
|
* Returns the number of successfully loaded plugins.
|
|
12129
12162
|
*/
|
|
12130
12163
|
async loadPlugins(pluginsDir, allowPlugins = false) {
|
|
12131
|
-
if (!
|
|
12164
|
+
if (!existsSync22(pluginsDir)) {
|
|
12132
12165
|
try {
|
|
12133
12166
|
mkdirSync10(pluginsDir, { recursive: true });
|
|
12134
12167
|
} catch {
|
|
@@ -12705,12 +12738,12 @@ var McpManager = class {
|
|
|
12705
12738
|
};
|
|
12706
12739
|
|
|
12707
12740
|
// src/skills/manager.ts
|
|
12708
|
-
import { existsSync as
|
|
12741
|
+
import { existsSync as existsSync23, readdirSync as readdirSync10, mkdirSync as mkdirSync11, statSync as statSync8 } from "fs";
|
|
12709
12742
|
import { join as join17 } from "path";
|
|
12710
12743
|
|
|
12711
12744
|
// src/skills/types.ts
|
|
12712
12745
|
import { readFileSync as readFileSync16 } from "fs";
|
|
12713
|
-
import { basename as
|
|
12746
|
+
import { basename as basename7 } from "path";
|
|
12714
12747
|
function parseSimpleYaml(yaml) {
|
|
12715
12748
|
const result = {};
|
|
12716
12749
|
for (const line of yaml.split("\n")) {
|
|
@@ -12739,7 +12772,7 @@ function parseSkillFile(filePath) {
|
|
|
12739
12772
|
if (!frontmatterMatch) {
|
|
12740
12773
|
return {
|
|
12741
12774
|
meta: {
|
|
12742
|
-
name:
|
|
12775
|
+
name: basename7(filePath, ".md"),
|
|
12743
12776
|
description: ""
|
|
12744
12777
|
},
|
|
12745
12778
|
content: raw.trim(),
|
|
@@ -12750,7 +12783,7 @@ function parseSkillFile(filePath) {
|
|
|
12750
12783
|
const parsed = parseSimpleYaml(yaml);
|
|
12751
12784
|
return {
|
|
12752
12785
|
meta: {
|
|
12753
|
-
name: parsed["name"] ??
|
|
12786
|
+
name: parsed["name"] ?? basename7(filePath, ".md"),
|
|
12754
12787
|
description: parsed["description"] ?? "",
|
|
12755
12788
|
tools: parsed["tools"] ? parseYamlArray(parsed["tools"]) : void 0
|
|
12756
12789
|
},
|
|
@@ -12779,7 +12812,7 @@ var SkillManager = class {
|
|
|
12779
12812
|
return this.skills.size;
|
|
12780
12813
|
}
|
|
12781
12814
|
loadSkillDir(dir, createIfMissing) {
|
|
12782
|
-
if (!
|
|
12815
|
+
if (!existsSync23(dir)) {
|
|
12783
12816
|
if (createIfMissing) {
|
|
12784
12817
|
try {
|
|
12785
12818
|
mkdirSync11(dir, { recursive: true });
|
|
@@ -12803,7 +12836,7 @@ var SkillManager = class {
|
|
|
12803
12836
|
try {
|
|
12804
12837
|
if (statSync8(fullPath).isDirectory()) {
|
|
12805
12838
|
const skillMd = join17(fullPath, "SKILL.md");
|
|
12806
|
-
if (
|
|
12839
|
+
if (existsSync23(skillMd)) filePath = skillMd;
|
|
12807
12840
|
else continue;
|
|
12808
12841
|
} else {
|
|
12809
12842
|
continue;
|
|
@@ -12862,7 +12895,7 @@ var SkillManager = class {
|
|
|
12862
12895
|
// src/web/tool-executor-web.ts
|
|
12863
12896
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
12864
12897
|
import { tmpdir as tmpdir2 } from "os";
|
|
12865
|
-
import { existsSync as
|
|
12898
|
+
import { existsSync as existsSync24, readFileSync as readFileSync17 } from "fs";
|
|
12866
12899
|
var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
12867
12900
|
constructor(registry, ws) {
|
|
12868
12901
|
this.registry = registry;
|
|
@@ -13001,7 +13034,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13001
13034
|
if (call.name === "write_file") {
|
|
13002
13035
|
const filePath = String(call.arguments["path"] ?? "");
|
|
13003
13036
|
const newContent = String(call.arguments["content"] ?? "");
|
|
13004
|
-
if (filePath &&
|
|
13037
|
+
if (filePath && existsSync24(filePath)) {
|
|
13005
13038
|
try {
|
|
13006
13039
|
const old = readFileSync17(filePath, "utf-8");
|
|
13007
13040
|
return renderDiff(old, newContent, { filePath });
|
|
@@ -13159,12 +13192,13 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13159
13192
|
return { callId: call.id, content: message, isError: true };
|
|
13160
13193
|
}
|
|
13161
13194
|
}
|
|
13162
|
-
|
|
13195
|
+
const requiresHardConfirmation = permission.action === "confirm" && permission.hardBoundary === true;
|
|
13196
|
+
if ((networkPermission?.action === "confirm" || requiresHardConfirmation) && dangerLevel === "safe") {
|
|
13163
13197
|
this.sendToolCallStart(call);
|
|
13164
13198
|
toolCallStarted = true;
|
|
13165
13199
|
const confirmed = await this.confirm(call, "write");
|
|
13166
13200
|
if (!confirmed) {
|
|
13167
|
-
const rejectionMsg = `[User cancelled] The user declined
|
|
13201
|
+
const rejectionMsg = `[User cancelled] The user declined permission for ${call.name}. Do not retry without asking.`;
|
|
13168
13202
|
this.sendToolCallResult(call, rejectionMsg, true);
|
|
13169
13203
|
return { callId: call.id, content: rejectionMsg, isError: true };
|
|
13170
13204
|
}
|
|
@@ -13181,7 +13215,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13181
13215
|
this.sendToolCallResult(call, rejectionMsg, true);
|
|
13182
13216
|
return { callId: call.id, content: rejectionMsg, isError: true };
|
|
13183
13217
|
}
|
|
13184
|
-
if (classification.decision === "auto-approve") {
|
|
13218
|
+
if (classification.decision === "auto-approve" && !requiresHardConfirmation) {
|
|
13185
13219
|
this.send({ type: "info", message: `\u26A1 Auto-approved (/auto: ${classification.ruleId})` });
|
|
13186
13220
|
try {
|
|
13187
13221
|
const rawContent = await runTool(tool, call.arguments, call.name);
|
|
@@ -13199,7 +13233,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13199
13233
|
}
|
|
13200
13234
|
}
|
|
13201
13235
|
}
|
|
13202
|
-
if (this.sessionAutoApprove && dangerLevel === "write") {
|
|
13236
|
+
if (this.sessionAutoApprove && dangerLevel === "write" && !requiresHardConfirmation) {
|
|
13203
13237
|
try {
|
|
13204
13238
|
const rawContent = await runTool(tool, call.arguments, call.name);
|
|
13205
13239
|
const content = truncateOutput(rawContent, call.name);
|
|
@@ -13306,7 +13340,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
13306
13340
|
};
|
|
13307
13341
|
|
|
13308
13342
|
// src/repl/dev-state.ts
|
|
13309
|
-
import { existsSync as
|
|
13343
|
+
import { existsSync as existsSync25, readFileSync as readFileSync18, unlinkSync as unlinkSync5, mkdirSync as mkdirSync12 } from "fs";
|
|
13310
13344
|
import { join as join18 } from "path";
|
|
13311
13345
|
import { homedir as homedir7 } from "os";
|
|
13312
13346
|
function getDevStatePath() {
|
|
@@ -13314,7 +13348,7 @@ function getDevStatePath() {
|
|
|
13314
13348
|
}
|
|
13315
13349
|
function loadDevState() {
|
|
13316
13350
|
const path3 = getDevStatePath();
|
|
13317
|
-
if (!
|
|
13351
|
+
if (!existsSync25(path3)) return null;
|
|
13318
13352
|
const content = readFileSync18(path3, "utf-8").trim();
|
|
13319
13353
|
return content || null;
|
|
13320
13354
|
}
|
|
@@ -13572,7 +13606,7 @@ function autoTrimSessionIfNeeded(session, sizeLimit = SESSION_SIZE_LIMIT) {
|
|
|
13572
13606
|
}
|
|
13573
13607
|
|
|
13574
13608
|
// src/core/context-files.ts
|
|
13575
|
-
import { existsSync as
|
|
13609
|
+
import { existsSync as existsSync26, readFileSync as readFileSync19 } from "fs";
|
|
13576
13610
|
import { join as join19, relative as relative3, resolve as resolve9 } from "path";
|
|
13577
13611
|
function uniqueNonEmpty(values) {
|
|
13578
13612
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -13651,7 +13685,7 @@ function findFirstContextFile(level, dir, cwd, candidates, maxBytes) {
|
|
|
13651
13685
|
const skipped = [];
|
|
13652
13686
|
for (const candidate of candidates) {
|
|
13653
13687
|
const filePath = join19(dir, candidate);
|
|
13654
|
-
if (!
|
|
13688
|
+
if (!existsSync26(filePath)) continue;
|
|
13655
13689
|
const result = readContextFile(level, filePath, cwd, maxBytes);
|
|
13656
13690
|
if (result.skipped) skipped.push(result.skipped);
|
|
13657
13691
|
if (result.layer) return { layer: result.layer, skipped };
|
|
@@ -13678,7 +13712,7 @@ function loadContextFiles(options) {
|
|
|
13678
13712
|
});
|
|
13679
13713
|
return { layers: [], mergedContent: "", skipped, totalChars: 0, totalBytes: 0, maxBytes, candidates };
|
|
13680
13714
|
}
|
|
13681
|
-
if (!
|
|
13715
|
+
if (!existsSync26(filePath)) {
|
|
13682
13716
|
skipped.push({
|
|
13683
13717
|
level: "single",
|
|
13684
13718
|
filePath,
|
|
@@ -13730,10 +13764,10 @@ function loadContextFiles(options) {
|
|
|
13730
13764
|
|
|
13731
13765
|
// src/web/session-handler.ts
|
|
13732
13766
|
import { mkdirSync as mkdirSync16, createWriteStream as createWriteStream3 } from "fs";
|
|
13733
|
-
import { join as join26, dirname as
|
|
13767
|
+
import { join as join26, dirname as dirname11 } from "path";
|
|
13734
13768
|
|
|
13735
13769
|
// src/repl/commands/project-init.ts
|
|
13736
|
-
import { existsSync as
|
|
13770
|
+
import { existsSync as existsSync27, readFileSync as readFileSync20, readdirSync as readdirSync11, statSync as statSync9 } from "fs";
|
|
13737
13771
|
import { join as join20 } from "path";
|
|
13738
13772
|
var SCAN_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
13739
13773
|
"node_modules",
|
|
@@ -13817,7 +13851,7 @@ function scanProject(cwd) {
|
|
|
13817
13851
|
configFiles: [],
|
|
13818
13852
|
directoryStructure: ""
|
|
13819
13853
|
};
|
|
13820
|
-
const check = (file) =>
|
|
13854
|
+
const check = (file) => existsSync27(join20(cwd, file));
|
|
13821
13855
|
const configCandidates = [
|
|
13822
13856
|
"package.json",
|
|
13823
13857
|
"tsconfig.json",
|
|
@@ -14619,8 +14653,8 @@ async function handlePlan(args, ctx) {
|
|
|
14619
14653
|
}
|
|
14620
14654
|
|
|
14621
14655
|
// src/web/commands/_shared.ts
|
|
14622
|
-
import { existsSync as
|
|
14623
|
-
import { join as join24, resolve as resolve10, dirname as
|
|
14656
|
+
import { existsSync as existsSync30, readFileSync as readFileSync22, writeFileSync as writeFileSync3, mkdirSync as mkdirSync14, readdirSync as readdirSync13, statSync as statSync12, createWriteStream } from "fs";
|
|
14657
|
+
import { join as join24, resolve as resolve10, dirname as dirname9 } from "path";
|
|
14624
14658
|
|
|
14625
14659
|
// src/cli/review-prompts.ts
|
|
14626
14660
|
function buildReviewPrompt(diff, gitContextStr, detailed) {
|
|
@@ -14692,13 +14726,13 @@ function readGitDiff(options = {}) {
|
|
|
14692
14726
|
}
|
|
14693
14727
|
|
|
14694
14728
|
// src/diagnostics/doctor-report.ts
|
|
14695
|
-
import { existsSync as
|
|
14729
|
+
import { existsSync as existsSync29, statSync as statSync11 } from "fs";
|
|
14696
14730
|
import { join as join23 } from "path";
|
|
14697
14731
|
import { arch as arch2, platform as platform7, release as release2 } from "os";
|
|
14698
14732
|
|
|
14699
14733
|
// src/diagnostics/crash-log.ts
|
|
14700
14734
|
import {
|
|
14701
|
-
existsSync as
|
|
14735
|
+
existsSync as existsSync28,
|
|
14702
14736
|
mkdirSync as mkdirSync13,
|
|
14703
14737
|
readdirSync as readdirSync12,
|
|
14704
14738
|
readFileSync as readFileSync21,
|
|
@@ -14719,7 +14753,7 @@ function truncate(s, n) {
|
|
|
14719
14753
|
}
|
|
14720
14754
|
function listRecentCrashes(limit = 10, configDir) {
|
|
14721
14755
|
const dir = getLogsDir(configDir);
|
|
14722
|
-
if (!
|
|
14756
|
+
if (!existsSync28(dir)) return [];
|
|
14723
14757
|
const files = [];
|
|
14724
14758
|
let names;
|
|
14725
14759
|
try {
|
|
@@ -14752,7 +14786,7 @@ function listRecentCrashes(limit = 10, configDir) {
|
|
|
14752
14786
|
}
|
|
14753
14787
|
function getConfigDirUsage(configDir) {
|
|
14754
14788
|
const base = configDir ?? join22(homedir8(), CONFIG_DIR_NAME);
|
|
14755
|
-
if (!
|
|
14789
|
+
if (!existsSync28(base)) return { totalBytes: 0, entries: [] };
|
|
14756
14790
|
const entries = [];
|
|
14757
14791
|
let total = 0;
|
|
14758
14792
|
let names;
|
|
@@ -14787,7 +14821,7 @@ function dirSize(path3) {
|
|
|
14787
14821
|
|
|
14788
14822
|
// src/diagnostics/doctor-report.ts
|
|
14789
14823
|
function checkFile(label, path3) {
|
|
14790
|
-
const exists =
|
|
14824
|
+
const exists = existsSync29(path3);
|
|
14791
14825
|
let sizeBytes = null;
|
|
14792
14826
|
if (exists) {
|
|
14793
14827
|
try {
|
|
@@ -14885,7 +14919,7 @@ function buildDoctorReport(options) {
|
|
|
14885
14919
|
mcp: {
|
|
14886
14920
|
enabled: config.get("mcpEnabled"),
|
|
14887
14921
|
configured: Object.keys(mcpServers).length,
|
|
14888
|
-
projectConfigExists:
|
|
14922
|
+
projectConfigExists: existsSync29(join23(projectRoot, MCP_PROJECT_CONFIG_NAME)),
|
|
14889
14923
|
statuses: options.mcpStatuses ?? []
|
|
14890
14924
|
},
|
|
14891
14925
|
recentCrashes: listRecentCrashes(5, configDir),
|
|
@@ -15755,7 +15789,7 @@ ${activated.meta.description || ""}` });
|
|
|
15755
15789
|
async function handleCommands(_args, ctx) {
|
|
15756
15790
|
const configDir = ctx.config.getConfigDir();
|
|
15757
15791
|
const commandsDir = join24(configDir, CUSTOM_COMMANDS_DIR_NAME);
|
|
15758
|
-
if (!
|
|
15792
|
+
if (!existsSync30(commandsDir)) {
|
|
15759
15793
|
ctx.send({ type: "info", message: `No custom commands directory.
|
|
15760
15794
|
Create: ${commandsDir}/ with .md files.` });
|
|
15761
15795
|
return;
|
|
@@ -15855,7 +15889,7 @@ async function handleSecurityReview(args, ctx) {
|
|
|
15855
15889
|
async function handleTest(args, ctx) {
|
|
15856
15890
|
ctx.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
15857
15891
|
try {
|
|
15858
|
-
const { executeTests } = await import("./run-tests-
|
|
15892
|
+
const { executeTests } = await import("./run-tests-YSRET52H.js");
|
|
15859
15893
|
const argStr = args.join(" ").trim();
|
|
15860
15894
|
let testArgs = {};
|
|
15861
15895
|
if (argStr) {
|
|
@@ -15885,7 +15919,7 @@ async function handleDiff(args, ctx) {
|
|
|
15885
15919
|
let modifiedFiles = 0;
|
|
15886
15920
|
const diffLines2 = [];
|
|
15887
15921
|
for (const [filePath, { earliest }] of fileMap) {
|
|
15888
|
-
const currentContent =
|
|
15922
|
+
const currentContent = existsSync30(filePath) ? (() => {
|
|
15889
15923
|
try {
|
|
15890
15924
|
return readFileSync22(filePath, "utf-8");
|
|
15891
15925
|
} catch {
|
|
@@ -15924,7 +15958,7 @@ async function handleInit(args, ctx) {
|
|
|
15924
15958
|
const cwd = process.cwd();
|
|
15925
15959
|
const targetPath = join24(cwd, "AICLI.md");
|
|
15926
15960
|
const force = args.includes("--force");
|
|
15927
|
-
if (
|
|
15961
|
+
if (existsSync30(targetPath) && !force) {
|
|
15928
15962
|
ctx.send({ type: "info", message: `AICLI.md already exists at ${targetPath}
|
|
15929
15963
|
Use /init --force to overwrite.` });
|
|
15930
15964
|
return;
|
|
@@ -16108,7 +16142,7 @@ Use /add-dir remove to clear.` : "No directories added.\nUsage: /add-dir <path>
|
|
|
16108
16142
|
return;
|
|
16109
16143
|
}
|
|
16110
16144
|
const dirPath = resolve10(sub);
|
|
16111
|
-
if (!
|
|
16145
|
+
if (!existsSync30(dirPath)) {
|
|
16112
16146
|
ctx.send({ type: "error", message: `Directory not found: ${dirPath}` });
|
|
16113
16147
|
return;
|
|
16114
16148
|
}
|
|
@@ -17183,7 +17217,7 @@ Try: /compact to reduce context, /clear to reset, or switch to a larger-context
|
|
|
17183
17217
|
this.send({ type: "response_done", content, usage });
|
|
17184
17218
|
if (pendingTeeSave && isCleanDocumentBody(content)) {
|
|
17185
17219
|
try {
|
|
17186
|
-
mkdirSync16(
|
|
17220
|
+
mkdirSync16(dirname11(pendingTeeSave), { recursive: true });
|
|
17187
17221
|
const bodyToSave = stripOuterCodeFence(content);
|
|
17188
17222
|
atomicWriteFileSync(pendingTeeSave, bodyToSave);
|
|
17189
17223
|
undoStack.push(pendingTeeSave, `save_last_response (deferred): ${pendingTeeSave}`);
|
|
@@ -17359,7 +17393,7 @@ ${summaryContent}`,
|
|
|
17359
17393
|
let isError = false;
|
|
17360
17394
|
let summary;
|
|
17361
17395
|
try {
|
|
17362
|
-
mkdirSync16(
|
|
17396
|
+
mkdirSync16(dirname11(saveToFile), { recursive: true });
|
|
17363
17397
|
fileStream = createWriteStream3(saveToFile);
|
|
17364
17398
|
const teeSystemPrompt = stripToolCallReminder(systemPrompt ?? "") + CONTENT_ONLY_STREAM_REMINDER;
|
|
17365
17399
|
const teeExtraMessages = extraMessages.length > 0 ? [...extraMessages, { role: "user", content: TEE_FINAL_USER_NUDGE }] : [{ role: "user", content: TEE_FINAL_USER_NUDGE }];
|
|
@@ -17934,8 +17968,8 @@ async function setupProxy(configProxy) {
|
|
|
17934
17968
|
}
|
|
17935
17969
|
|
|
17936
17970
|
// src/web/auth.ts
|
|
17937
|
-
import { existsSync as
|
|
17938
|
-
import { join as join27 } from "path";
|
|
17971
|
+
import { existsSync as existsSync33, readFileSync as readFileSync25, writeFileSync as writeFileSync6, mkdirSync as mkdirSync17, readdirSync as readdirSync16, copyFileSync } from "fs";
|
|
17972
|
+
import { isAbsolute as isAbsolute3, join as join27, relative as relative4 } from "path";
|
|
17939
17973
|
import { createHmac, randomBytes, timingSafeEqual, pbkdf2Sync } from "crypto";
|
|
17940
17974
|
var USERS_FILE = "users.json";
|
|
17941
17975
|
var TOKEN_EXPIRY_HOURS = 24;
|
|
@@ -18133,7 +18167,7 @@ var AuthManager = class {
|
|
|
18133
18167
|
if (err) return err;
|
|
18134
18168
|
const userDir = this.getUserDataDir(username);
|
|
18135
18169
|
const globalConfig = join27(this.baseDir, "config.json");
|
|
18136
|
-
if (
|
|
18170
|
+
if (existsSync33(globalConfig)) {
|
|
18137
18171
|
try {
|
|
18138
18172
|
const content = readFileSync25(globalConfig, "utf-8");
|
|
18139
18173
|
writeFileSync6(join27(userDir, "config.json"), content, "utf-8");
|
|
@@ -18141,7 +18175,7 @@ var AuthManager = class {
|
|
|
18141
18175
|
}
|
|
18142
18176
|
}
|
|
18143
18177
|
const globalMemory = join27(this.baseDir, "memory.md");
|
|
18144
|
-
if (
|
|
18178
|
+
if (existsSync33(globalMemory)) {
|
|
18145
18179
|
try {
|
|
18146
18180
|
const content = readFileSync25(globalMemory, "utf-8");
|
|
18147
18181
|
writeFileSync6(join27(userDir, "memory.md"), content, "utf-8");
|
|
@@ -18149,7 +18183,7 @@ var AuthManager = class {
|
|
|
18149
18183
|
}
|
|
18150
18184
|
}
|
|
18151
18185
|
const globalHistory = join27(this.baseDir, "history");
|
|
18152
|
-
if (
|
|
18186
|
+
if (existsSync33(globalHistory)) {
|
|
18153
18187
|
try {
|
|
18154
18188
|
const files = readdirSync16(globalHistory).filter((f) => f.endsWith(".json"));
|
|
18155
18189
|
const userHistory = join27(userDir, "history");
|
|
@@ -18166,10 +18200,19 @@ var AuthManager = class {
|
|
|
18166
18200
|
}
|
|
18167
18201
|
// ── Private methods ────────────────────────────────────────────
|
|
18168
18202
|
loadOrCreate() {
|
|
18169
|
-
if (
|
|
18203
|
+
if (existsSync33(this.usersFile)) {
|
|
18170
18204
|
try {
|
|
18171
|
-
|
|
18172
|
-
|
|
18205
|
+
const parsed = JSON.parse(readFileSync25(this.usersFile, "utf-8"));
|
|
18206
|
+
if (!this.isValidUsersDB(parsed)) {
|
|
18207
|
+
throw new Error("database structure is invalid");
|
|
18208
|
+
}
|
|
18209
|
+
return parsed;
|
|
18210
|
+
} catch (err) {
|
|
18211
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
18212
|
+
throw new Error(
|
|
18213
|
+
`Authentication database is unreadable or corrupt: ${this.usersFile} (${detail}). Refusing to start without authentication; restore or remove the file explicitly.`,
|
|
18214
|
+
{ cause: err }
|
|
18215
|
+
);
|
|
18173
18216
|
}
|
|
18174
18217
|
}
|
|
18175
18218
|
const db = {
|
|
@@ -18180,6 +18223,27 @@ var AuthManager = class {
|
|
|
18180
18223
|
this.saveDB(db);
|
|
18181
18224
|
return db;
|
|
18182
18225
|
}
|
|
18226
|
+
isValidUsersDB(value) {
|
|
18227
|
+
if (!value || typeof value !== "object") return false;
|
|
18228
|
+
const db = value;
|
|
18229
|
+
if (db.version !== 1 || typeof db.secret !== "string" || db.secret.length < 32 || !Array.isArray(db.users)) {
|
|
18230
|
+
return false;
|
|
18231
|
+
}
|
|
18232
|
+
const usernames = /* @__PURE__ */ new Set();
|
|
18233
|
+
for (const user of db.users) {
|
|
18234
|
+
if (!user || typeof user !== "object") return false;
|
|
18235
|
+
const record = user;
|
|
18236
|
+
if (typeof record.username !== "string" || !/^[a-z0-9_-]{2,32}$/.test(record.username) || usernames.has(record.username) || typeof record.passwordHash !== "string" || record.passwordHash.length === 0 || typeof record.salt !== "string" || record.salt.length === 0 || typeof record.createdAt !== "string" || typeof record.dataDir !== "string" || record.dataDir.length === 0 || isAbsolute3(record.dataDir)) {
|
|
18237
|
+
return false;
|
|
18238
|
+
}
|
|
18239
|
+
const dataDirFromBase = relative4(this.baseDir, join27(this.baseDir, record.dataDir));
|
|
18240
|
+
if (dataDirFromBase.startsWith("..") || isAbsolute3(dataDirFromBase)) return false;
|
|
18241
|
+
if (record.hashVersion !== void 0 && record.hashVersion !== 1 && record.hashVersion !== 2) return false;
|
|
18242
|
+
if (record.tokensRevokedBefore !== void 0 && !Number.isFinite(record.tokensRevokedBefore)) return false;
|
|
18243
|
+
usernames.add(record.username);
|
|
18244
|
+
}
|
|
18245
|
+
return true;
|
|
18246
|
+
}
|
|
18183
18247
|
save() {
|
|
18184
18248
|
this.saveDB(this.db);
|
|
18185
18249
|
}
|
|
@@ -18216,7 +18280,7 @@ function getModuleDir() {
|
|
|
18216
18280
|
if (typeof import.meta?.url === "string") {
|
|
18217
18281
|
const url = new URL(import.meta.url);
|
|
18218
18282
|
const filePath = url.pathname.replace(/^\/([A-Z]:)/i, "$1");
|
|
18219
|
-
return
|
|
18283
|
+
return dirname12(filePath);
|
|
18220
18284
|
}
|
|
18221
18285
|
} catch {
|
|
18222
18286
|
}
|
|
@@ -18289,7 +18353,7 @@ async function startWebServer(options = {}) {
|
|
|
18289
18353
|
}
|
|
18290
18354
|
let skillManager = null;
|
|
18291
18355
|
const skillsDir = join28(config.getConfigDir(), SKILLS_DIR_NAME);
|
|
18292
|
-
if (
|
|
18356
|
+
if (existsSync34(skillsDir)) {
|
|
18293
18357
|
skillManager = new SkillManager(skillsDir, config.get("ui").skillSizeWarn);
|
|
18294
18358
|
skillManager.loadSkills(pluginAssets.skillDirs);
|
|
18295
18359
|
const count = skillManager.listSkills().length;
|
|
@@ -18361,13 +18425,13 @@ async function startWebServer(options = {}) {
|
|
|
18361
18425
|
};
|
|
18362
18426
|
const moduleDir = getModuleDir();
|
|
18363
18427
|
let clientDir = join28(moduleDir, "web", "client");
|
|
18364
|
-
if (!
|
|
18428
|
+
if (!existsSync34(clientDir)) {
|
|
18365
18429
|
clientDir = join28(moduleDir, "client");
|
|
18366
18430
|
}
|
|
18367
|
-
if (!
|
|
18431
|
+
if (!existsSync34(clientDir)) {
|
|
18368
18432
|
clientDir = join28(moduleDir, "..", "..", "src", "web", "client");
|
|
18369
18433
|
}
|
|
18370
|
-
if (!
|
|
18434
|
+
if (!existsSync34(clientDir)) {
|
|
18371
18435
|
clientDir = join28(process.cwd(), "src", "web", "client");
|
|
18372
18436
|
}
|
|
18373
18437
|
console.log(` Static files: ${clientDir}`);
|
|
@@ -18440,8 +18504,8 @@ async function startWebServer(options = {}) {
|
|
|
18440
18504
|
const prefix = req.query.prefix || "";
|
|
18441
18505
|
const targetDir = join28(cwd, prefix);
|
|
18442
18506
|
try {
|
|
18443
|
-
const canonicalTarget =
|
|
18444
|
-
const canonicalCwd =
|
|
18507
|
+
const canonicalTarget = realpathSync2(resolve13(targetDir));
|
|
18508
|
+
const canonicalCwd = realpathSync2(resolve13(cwd));
|
|
18445
18509
|
if (!canonicalTarget.startsWith(canonicalCwd + sep3) && canonicalTarget !== canonicalCwd) {
|
|
18446
18510
|
res.json({ files: [] });
|
|
18447
18511
|
return;
|
|
@@ -18455,7 +18519,7 @@ async function startWebServer(options = {}) {
|
|
|
18455
18519
|
const entries = readdirSync17(targetDir, { withFileTypes: true });
|
|
18456
18520
|
const files = entries.filter((e) => !SKIP.has(e.name) && !e.name.startsWith(".")).slice(0, 50).map((e) => ({
|
|
18457
18521
|
name: e.name,
|
|
18458
|
-
path:
|
|
18522
|
+
path: relative5(cwd, join28(targetDir, e.name)).replace(/\\/g, "/"),
|
|
18459
18523
|
isDir: e.isDirectory()
|
|
18460
18524
|
}));
|
|
18461
18525
|
res.json({ files });
|
|
@@ -18496,13 +18560,13 @@ async function startWebServer(options = {}) {
|
|
|
18496
18560
|
const authUser = req._authUser;
|
|
18497
18561
|
const histDir = authUser ? getUserShared(authUser).config.getHistoryDir() : config.getHistoryDir();
|
|
18498
18562
|
const filePath = join28(histDir, `${id}.json`);
|
|
18499
|
-
if (!
|
|
18563
|
+
if (!existsSync34(filePath)) {
|
|
18500
18564
|
res.status(404).json({ error: "Session not found" });
|
|
18501
18565
|
return;
|
|
18502
18566
|
}
|
|
18503
18567
|
try {
|
|
18504
|
-
const canonicalFile =
|
|
18505
|
-
const canonicalDir =
|
|
18568
|
+
const canonicalFile = realpathSync2(filePath);
|
|
18569
|
+
const canonicalDir = realpathSync2(histDir);
|
|
18506
18570
|
if (!canonicalFile.startsWith(canonicalDir + sep3)) {
|
|
18507
18571
|
res.status(404).json({ error: "Session not found" });
|
|
18508
18572
|
return;
|
|
@@ -18526,8 +18590,8 @@ async function startWebServer(options = {}) {
|
|
|
18526
18590
|
const cwd = process.cwd();
|
|
18527
18591
|
const fullPath = resolve13(join28(cwd, filePath));
|
|
18528
18592
|
try {
|
|
18529
|
-
const canonicalFull =
|
|
18530
|
-
const canonicalCwd =
|
|
18593
|
+
const canonicalFull = realpathSync2(fullPath);
|
|
18594
|
+
const canonicalCwd = realpathSync2(resolve13(cwd));
|
|
18531
18595
|
if (!canonicalFull.startsWith(canonicalCwd + sep3) && canonicalFull !== canonicalCwd) {
|
|
18532
18596
|
res.json({ error: "Access denied" });
|
|
18533
18597
|
return;
|
|
@@ -18798,14 +18862,14 @@ function resolveProjectMcpPath() {
|
|
|
18798
18862
|
const gitRoot = getGitRoot(cwd);
|
|
18799
18863
|
const projectRoot = gitRoot ?? cwd;
|
|
18800
18864
|
const configPath = join28(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
18801
|
-
return
|
|
18865
|
+
return existsSync34(configPath) ? configPath : null;
|
|
18802
18866
|
}
|
|
18803
18867
|
function loadProjectMcpConfig() {
|
|
18804
18868
|
const cwd = process.cwd();
|
|
18805
18869
|
const gitRoot = getGitRoot(cwd);
|
|
18806
18870
|
const projectRoot = gitRoot ?? cwd;
|
|
18807
18871
|
const configPath = join28(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
18808
|
-
if (!
|
|
18872
|
+
if (!existsSync34(configPath)) return null;
|
|
18809
18873
|
try {
|
|
18810
18874
|
const raw = JSON.parse(readFileSync26(configPath, "utf-8"));
|
|
18811
18875
|
return raw.mcpServers ?? raw;
|