jinzd-ai-cli 0.4.210 → 0.4.211
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -1
- package/README.zh-CN.md +40 -0
- package/dist/{batch-MFPYHOIL.js → batch-DE4RXKZD.js} +2 -2
- package/dist/{chunk-E2ZWWE6Q.js → chunk-6NS6643Y.js} +1 -1
- package/dist/{chunk-NWP7C6CC.js → chunk-BE6ERF7M.js} +1 -1
- package/dist/{chunk-7JWT3KXO.js → chunk-C3OU2OPF.js} +2 -2
- package/dist/{chunk-GRJNQJA5.js → chunk-E5XCM4A6.js} +1 -1
- package/dist/{chunk-DJ35G5VO.js → chunk-JBWA73GK.js} +1 -1
- package/dist/{chunk-P6MTFCXB.js → chunk-UOROWTGG.js} +37 -3
- package/dist/{chunk-NEPFADHX.js → chunk-ZOPYREL5.js} +312 -38
- package/dist/{chunk-HZQVX7VF.js → chunk-ZY2N2N6T.js} +1 -1
- package/dist/{ci-QLJUDLMY.js → ci-XMUEX526.js} +2 -2
- package/dist/{constants-47OR72MV.js → constants-AWTIQIWG.js} +1 -1
- package/dist/{doctor-cli-32COMA5K.js → doctor-cli-SSI6ETFT.js} +4 -4
- package/dist/electron-server.js +486 -113
- package/dist/{hub-3NWJUCLK.js → hub-INUJND2G.js} +1 -1
- package/dist/index.js +34 -17
- package/dist/{run-tests-UT7RZ7Y3.js → run-tests-3MHWUF43.js} +2 -2
- package/dist/{run-tests-NT2UIUVB.js → run-tests-PACN4UYX.js} +1 -1
- package/dist/{server-AIHVMLNU.js → server-7USZJJAH.js} +4 -4
- package/dist/{server-E5D54DIZ.js → server-BTSKOPQI.js} +96 -27
- package/dist/{task-orchestrator-BFDSTSOH.js → task-orchestrator-OV4O25MX.js} +4 -4
- package/dist/{usage-P4B2RZKL.js → usage-T2P6FTE7.js} +2 -2
- package/dist/web/client/app.js +1 -1
- package/package.json +1 -1
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
} from "./chunk-T2NL5ZIA.js";
|
|
6
6
|
import {
|
|
7
7
|
runTestsTool
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-6NS6643Y.js";
|
|
9
9
|
import {
|
|
10
10
|
runTool
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-JBWA73GK.js";
|
|
12
12
|
import {
|
|
13
13
|
getDangerLevel,
|
|
14
14
|
isFileWriteTool,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
SUBAGENT_ALLOWED_TOOLS,
|
|
27
27
|
SUBAGENT_DEFAULT_MAX_ROUNDS,
|
|
28
28
|
SUBAGENT_MAX_ROUNDS_LIMIT
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-E5XCM4A6.js";
|
|
30
30
|
import {
|
|
31
31
|
fileCheckpoints
|
|
32
32
|
} from "./chunk-4BKXL7SM.js";
|
|
@@ -1056,6 +1056,7 @@ import { dirname as dirname2 } from "path";
|
|
|
1056
1056
|
// src/tools/executor.ts
|
|
1057
1057
|
import chalk3 from "chalk";
|
|
1058
1058
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1059
|
+
import { tmpdir } from "os";
|
|
1059
1060
|
|
|
1060
1061
|
// src/core/readline-internal.ts
|
|
1061
1062
|
function rlInternal(rl) {
|
|
@@ -1290,6 +1291,7 @@ function runHook(template, vars) {
|
|
|
1290
1291
|
}
|
|
1291
1292
|
|
|
1292
1293
|
// src/tools/permissions.ts
|
|
1294
|
+
import { isAbsolute, resolve as resolve3 } from "path";
|
|
1293
1295
|
function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "confirm") {
|
|
1294
1296
|
for (const rule of rules) {
|
|
1295
1297
|
if (rule.tool !== "*" && rule.tool !== toolName) continue;
|
|
@@ -1310,6 +1312,225 @@ function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "co
|
|
|
1310
1312
|
}
|
|
1311
1313
|
return defaultAction;
|
|
1312
1314
|
}
|
|
1315
|
+
var BUILTIN_PROFILE_NAMES = /* @__PURE__ */ new Set(["legacy", "read-only", "workspace-write", "danger-full-access"]);
|
|
1316
|
+
var READ_ONLY_TOOLS = /* @__PURE__ */ new Set([
|
|
1317
|
+
"read_file",
|
|
1318
|
+
"list_dir",
|
|
1319
|
+
"grep_files",
|
|
1320
|
+
"glob_files",
|
|
1321
|
+
"find_symbol",
|
|
1322
|
+
"get_outline",
|
|
1323
|
+
"find_references",
|
|
1324
|
+
"search_code",
|
|
1325
|
+
"git_status",
|
|
1326
|
+
"git_diff",
|
|
1327
|
+
"git_log",
|
|
1328
|
+
"task_list",
|
|
1329
|
+
"web_fetch",
|
|
1330
|
+
"web_search",
|
|
1331
|
+
"google_search",
|
|
1332
|
+
"ask_user",
|
|
1333
|
+
"write_todos",
|
|
1334
|
+
"recall_memory"
|
|
1335
|
+
]);
|
|
1336
|
+
function normalizePathForPermission(value) {
|
|
1337
|
+
return value.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
1338
|
+
}
|
|
1339
|
+
function isInsidePath(root, target) {
|
|
1340
|
+
const absoluteTarget = isAbsolute(target) ? target : resolve3(root, target);
|
|
1341
|
+
const r = normalizePathForPermission(resolve3(root));
|
|
1342
|
+
const t = normalizePathForPermission(absoluteTarget);
|
|
1343
|
+
return t === r || t.startsWith(`${r}/`);
|
|
1344
|
+
}
|
|
1345
|
+
function extractPathArg(toolName, args) {
|
|
1346
|
+
const raw = args["path"] ?? args["filePath"] ?? args["notebook_path"];
|
|
1347
|
+
if (typeof raw === "string" && raw.trim()) return raw.trim();
|
|
1348
|
+
if (toolName === "save_last_response") {
|
|
1349
|
+
const output = args["outputPath"] ?? args["file"] ?? args["path"];
|
|
1350
|
+
if (typeof output === "string" && output.trim()) return output.trim();
|
|
1351
|
+
}
|
|
1352
|
+
return null;
|
|
1353
|
+
}
|
|
1354
|
+
function isExplicitFileWriteTool(toolName) {
|
|
1355
|
+
return toolName === "write_file" || toolName === "edit_file" || toolName === "notebook_edit" || toolName === "save_last_response";
|
|
1356
|
+
}
|
|
1357
|
+
function resolveProfileName(ctx) {
|
|
1358
|
+
const requested = ctx?.profileName ?? "legacy";
|
|
1359
|
+
if (ctx?.allowedProfiles && ctx.allowedProfiles.length > 0 && !ctx.allowedProfiles.includes(requested)) {
|
|
1360
|
+
return "legacy";
|
|
1361
|
+
}
|
|
1362
|
+
if (BUILTIN_PROFILE_NAMES.has(requested)) return requested;
|
|
1363
|
+
const ext = ctx?.profile?.extends;
|
|
1364
|
+
return ext && BUILTIN_PROFILE_NAMES.has(ext) ? ext : "legacy";
|
|
1365
|
+
}
|
|
1366
|
+
function getProfileRules(ctx) {
|
|
1367
|
+
return ctx?.profile?.rules ?? [];
|
|
1368
|
+
}
|
|
1369
|
+
function getProfileDefaultAction(name, ctx) {
|
|
1370
|
+
if (ctx?.profile?.defaultAction) return ctx.profile.defaultAction;
|
|
1371
|
+
if (name === "danger-full-access") return "auto-approve";
|
|
1372
|
+
return "confirm";
|
|
1373
|
+
}
|
|
1374
|
+
function getWorkspaceRoots(ctx) {
|
|
1375
|
+
const roots = [ctx?.workspaceRoot, ...ctx?.profile?.workspaceRoots ?? []].filter((v) => typeof v === "string" && v.trim().length > 0);
|
|
1376
|
+
return roots;
|
|
1377
|
+
}
|
|
1378
|
+
function getAllowedWriteRoots(ctx) {
|
|
1379
|
+
const roots = [...getWorkspaceRoots(ctx)];
|
|
1380
|
+
const allowTemp = ctx?.profile?.allowTemp !== false;
|
|
1381
|
+
if (allowTemp) roots.push(...ctx?.tempDirs ?? []);
|
|
1382
|
+
return roots.filter((v) => v.trim().length > 0);
|
|
1383
|
+
}
|
|
1384
|
+
function profileHardDecision(profileName, toolName, args, dangerLevel, ctx) {
|
|
1385
|
+
if (profileName === "legacy") return null;
|
|
1386
|
+
if (profileName === "read-only") {
|
|
1387
|
+
const mcpReadOnly = toolName.startsWith("mcp__") && dangerLevel === "safe";
|
|
1388
|
+
if (dangerLevel !== "safe" || !READ_ONLY_TOOLS.has(toolName) && !mcpReadOnly) {
|
|
1389
|
+
return { action: "deny", reason: "blocked by read-only permission profile", profileName };
|
|
1390
|
+
}
|
|
1391
|
+
return null;
|
|
1392
|
+
}
|
|
1393
|
+
if (profileName === "workspace-write") {
|
|
1394
|
+
if (dangerLevel === "destructive") return { action: "confirm", reason: "destructive tools always require confirmation", profileName };
|
|
1395
|
+
if (dangerLevel === "write" && isExplicitFileWriteTool(toolName)) {
|
|
1396
|
+
const target = extractPathArg(toolName, args);
|
|
1397
|
+
if (!target) return { action: "confirm", reason: "file write target is not explicit", profileName };
|
|
1398
|
+
const allowedRoots = getAllowedWriteRoots(ctx);
|
|
1399
|
+
if (allowedRoots.length === 0 || !allowedRoots.some((root) => isInsidePath(root, target))) {
|
|
1400
|
+
return { action: "deny", reason: "file write target is outside workspace/temp roots", profileName };
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
return null;
|
|
1404
|
+
}
|
|
1405
|
+
if (profileName === "danger-full-access") {
|
|
1406
|
+
if (dangerLevel === "destructive") return { action: "confirm", reason: "destructive tools still require confirmation", profileName };
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
return null;
|
|
1410
|
+
}
|
|
1411
|
+
function checkPermissionWithProfile(toolName, args, dangerLevel, rules, defaultAction = "confirm", profileContext) {
|
|
1412
|
+
const profileName = resolveProfileName(profileContext);
|
|
1413
|
+
const hard = profileHardDecision(profileName, toolName, args, dangerLevel, profileContext);
|
|
1414
|
+
if (hard?.action === "deny") return hard;
|
|
1415
|
+
const combinedRules = [...getProfileRules(profileContext), ...rules];
|
|
1416
|
+
const profileDefault = profileName === "legacy" ? defaultAction : getProfileDefaultAction(profileName, profileContext);
|
|
1417
|
+
const action = checkPermission(toolName, args, dangerLevel, combinedRules, profileDefault);
|
|
1418
|
+
if (hard?.action === "confirm" && action === "auto-approve") return hard;
|
|
1419
|
+
return { action, profileName };
|
|
1420
|
+
}
|
|
1421
|
+
function formatPermissionProfileWarning(profileName) {
|
|
1422
|
+
if (profileName === "danger-full-access") {
|
|
1423
|
+
return "\u26A0 danger-full-access permission profile is active. Write tools may auto-run; destructive tools still require confirmation.";
|
|
1424
|
+
}
|
|
1425
|
+
if (profileName === "read-only") return "Read-only permission profile is active. Write and destructive tools are blocked.";
|
|
1426
|
+
if (profileName === "workspace-write") return "Workspace-write permission profile is active. Writes outside workspace/temp roots are blocked.";
|
|
1427
|
+
return null;
|
|
1428
|
+
}
|
|
1429
|
+
var NETWORK_TOOL_HOSTS = {
|
|
1430
|
+
web_search: ["cn.bing.com", "www.google.com"],
|
|
1431
|
+
google_search: ["www.googleapis.com"]
|
|
1432
|
+
};
|
|
1433
|
+
var NETWORK_TOOL_PORTS = {
|
|
1434
|
+
web_search: [443],
|
|
1435
|
+
google_search: [443]
|
|
1436
|
+
};
|
|
1437
|
+
function networkActionToPermission(action) {
|
|
1438
|
+
if (action === "allow") return null;
|
|
1439
|
+
return action;
|
|
1440
|
+
}
|
|
1441
|
+
function domainMatches(pattern, host) {
|
|
1442
|
+
const p = pattern.trim().toLowerCase().replace(/^\*\./, "");
|
|
1443
|
+
const h = host.trim().toLowerCase().replace(/:\d+$/, "");
|
|
1444
|
+
return h === p || h.endsWith(`.${p}`);
|
|
1445
|
+
}
|
|
1446
|
+
function isPrivateNetworkHost(host) {
|
|
1447
|
+
const h = host.toLowerCase().replace(/^\[|\]$/g, "");
|
|
1448
|
+
if (h === "" || h === "localhost") return true;
|
|
1449
|
+
if (/^(127|10)\./.test(h)) return true;
|
|
1450
|
+
if (/^192\.168\./.test(h)) return true;
|
|
1451
|
+
if (/^172\.(1[6-9]|2\d|3[0-1])\./.test(h)) return true;
|
|
1452
|
+
if (/^169\.254\./.test(h)) return true;
|
|
1453
|
+
if (h === "::1" || h === "::") return true;
|
|
1454
|
+
if (/^f[cd][0-9a-f]*:/i.test(h) || /^fe[89ab][0-9a-f]*:/i.test(h)) return true;
|
|
1455
|
+
return false;
|
|
1456
|
+
}
|
|
1457
|
+
function extractNetworkHosts(toolName, args) {
|
|
1458
|
+
if (toolName === "web_fetch") {
|
|
1459
|
+
const raw = String(args["url"] ?? "").trim();
|
|
1460
|
+
try {
|
|
1461
|
+
return raw ? [new URL(raw).hostname] : [];
|
|
1462
|
+
} catch {
|
|
1463
|
+
return [];
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
return NETWORK_TOOL_HOSTS[toolName] ?? [];
|
|
1467
|
+
}
|
|
1468
|
+
function extractNetworkPorts(toolName, args) {
|
|
1469
|
+
if (toolName === "web_fetch") {
|
|
1470
|
+
const raw = String(args["url"] ?? "").trim();
|
|
1471
|
+
try {
|
|
1472
|
+
if (!raw) return [];
|
|
1473
|
+
const url = new URL(raw);
|
|
1474
|
+
if (url.port) return [Number(url.port)];
|
|
1475
|
+
return [url.protocol === "http:" ? 80 : 443];
|
|
1476
|
+
} catch {
|
|
1477
|
+
return [];
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
return NETWORK_TOOL_PORTS[toolName] ?? [];
|
|
1481
|
+
}
|
|
1482
|
+
function isShellNetworkCommand(command) {
|
|
1483
|
+
return /\b(curl|wget|aria2c|Invoke-WebRequest|Invoke-RestMethod|iwr|irm|ssh|scp|sftp|ftp|telnet|nc|ncat|netcat)\b/i.test(command) || /\b(git\s+(clone|fetch|pull|push)|npm\s+(install|publish|view)|pnpm\s+(add|install)|yarn\s+(add|install)|pip\s+install|python\s+-m\s+pip\s+install)\b/i.test(command);
|
|
1484
|
+
}
|
|
1485
|
+
function networkToolAction(toolName, policy) {
|
|
1486
|
+
if (toolName === "web_fetch") return policy.tools?.web_fetch ?? policy.defaultAction ?? "confirm";
|
|
1487
|
+
if (toolName === "web_search") return policy.tools?.web_search ?? policy.defaultAction ?? "confirm";
|
|
1488
|
+
if (toolName === "google_search") return policy.tools?.google_search ?? policy.defaultAction ?? "confirm";
|
|
1489
|
+
if (toolName.startsWith("mcp__")) return policy.tools?.mcp ?? policy.defaultAction ?? "confirm";
|
|
1490
|
+
return null;
|
|
1491
|
+
}
|
|
1492
|
+
function checkNetworkPolicy(toolName, args, policy) {
|
|
1493
|
+
if (!policy?.enabled) return null;
|
|
1494
|
+
let action = networkToolAction(toolName, policy);
|
|
1495
|
+
let reason = "network access requires confirmation";
|
|
1496
|
+
if (toolName === "bash") {
|
|
1497
|
+
const command = String(args["command"] ?? "");
|
|
1498
|
+
if (!isShellNetworkCommand(command)) return null;
|
|
1499
|
+
action = policy.tools?.shell ?? policy.defaultAction ?? "confirm";
|
|
1500
|
+
reason = "shell command may access the network";
|
|
1501
|
+
}
|
|
1502
|
+
if (!action) return null;
|
|
1503
|
+
const hosts = extractNetworkHosts(toolName, args);
|
|
1504
|
+
for (const host of hosts) {
|
|
1505
|
+
if (policy.denyDomains?.some((pattern) => domainMatches(pattern, host))) {
|
|
1506
|
+
return { action: "deny", reason: `network host "${host}" is denied by networkPolicy`, profileName: "networkPolicy" };
|
|
1507
|
+
}
|
|
1508
|
+
if (!policy.allowPrivateNetwork && isPrivateNetworkHost(host)) {
|
|
1509
|
+
return { action: "deny", reason: `network host "${host}" is private/internal`, profileName: "networkPolicy" };
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
if (hosts.length > 0 && policy.allowDomains && policy.allowDomains.length > 0) {
|
|
1513
|
+
const allAllowed = hosts.every((host) => policy.allowDomains.some((pattern) => domainMatches(pattern, host)));
|
|
1514
|
+
if (!allAllowed) {
|
|
1515
|
+
return { action: "deny", reason: `network host is not in networkPolicy.allowDomains`, profileName: "networkPolicy" };
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
const ports = extractNetworkPorts(toolName, args);
|
|
1519
|
+
for (const port of ports) {
|
|
1520
|
+
if (policy.denyPorts?.includes(port)) {
|
|
1521
|
+
return { action: "deny", reason: `network port ${port} is denied by networkPolicy`, profileName: "networkPolicy" };
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
if (ports.length > 0 && policy.allowPorts && policy.allowPorts.length > 0) {
|
|
1525
|
+
const allPortsAllowed = ports.every((port) => policy.allowPorts.includes(port));
|
|
1526
|
+
if (!allPortsAllowed) {
|
|
1527
|
+
return { action: "deny", reason: `network port is not in networkPolicy.allowPorts`, profileName: "networkPolicy" };
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1530
|
+
const permissionAction = networkActionToPermission(action);
|
|
1531
|
+
if (!permissionAction) return null;
|
|
1532
|
+
return { action: permissionAction, reason, profileName: "networkPolicy" };
|
|
1533
|
+
}
|
|
1313
1534
|
|
|
1314
1535
|
// src/tools/truncate.ts
|
|
1315
1536
|
var DEFAULT_MAX_TOOL_OUTPUT_CHARS = 12e3;
|
|
@@ -1564,11 +1785,21 @@ var ToolExecutor = class {
|
|
|
1564
1785
|
/** 权限规则(可选) */
|
|
1565
1786
|
permissionRules = [];
|
|
1566
1787
|
defaultPermission = "confirm";
|
|
1788
|
+
permissionProfileName = "legacy";
|
|
1789
|
+
permissionProfile;
|
|
1790
|
+
allowedPermissionProfiles = [];
|
|
1791
|
+
workspaceRoot = process.cwd();
|
|
1792
|
+
networkPolicy;
|
|
1567
1793
|
/** 注入 hooks 和 permission rules 配置 */
|
|
1568
1794
|
setConfig(opts) {
|
|
1569
1795
|
this.hookConfig = opts.hookConfig;
|
|
1570
1796
|
if (opts.permissionRules) this.permissionRules = opts.permissionRules;
|
|
1571
1797
|
if (opts.defaultPermission) this.defaultPermission = opts.defaultPermission;
|
|
1798
|
+
if (opts.permissionProfileName) this.permissionProfileName = opts.permissionProfileName;
|
|
1799
|
+
if (opts.permissionProfile) this.permissionProfile = opts.permissionProfile;
|
|
1800
|
+
if (opts.allowedPermissionProfiles) this.allowedPermissionProfiles = opts.allowedPermissionProfiles;
|
|
1801
|
+
if (opts.workspaceRoot) this.workspaceRoot = opts.workspaceRoot;
|
|
1802
|
+
if (opts.networkPolicy) this.networkPolicy = opts.networkPolicy;
|
|
1572
1803
|
}
|
|
1573
1804
|
async execute(call) {
|
|
1574
1805
|
return runWithSessionKey(this.sessionKey, () => this.executeInner(call));
|
|
@@ -1583,31 +1814,69 @@ var ToolExecutor = class {
|
|
|
1583
1814
|
};
|
|
1584
1815
|
}
|
|
1585
1816
|
const dangerLevel = getDangerLevel(call.name, call.arguments);
|
|
1817
|
+
let toolCallAlreadyPrinted = false;
|
|
1586
1818
|
runHook(this.hookConfig?.preToolExecution, {
|
|
1587
1819
|
tool: call.name,
|
|
1588
1820
|
dangerLevel,
|
|
1589
1821
|
args: JSON.stringify(call.arguments).slice(0, 200)
|
|
1590
1822
|
});
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1823
|
+
const permission = checkPermissionWithProfile(
|
|
1824
|
+
call.name,
|
|
1825
|
+
call.arguments,
|
|
1826
|
+
dangerLevel,
|
|
1827
|
+
this.permissionRules,
|
|
1828
|
+
this.defaultPermission,
|
|
1829
|
+
{
|
|
1830
|
+
profileName: this.permissionProfileName,
|
|
1831
|
+
profile: this.permissionProfile,
|
|
1832
|
+
allowedProfiles: this.allowedPermissionProfiles,
|
|
1833
|
+
workspaceRoot: this.workspaceRoot,
|
|
1834
|
+
tempDirs: [tmpdir()]
|
|
1595
1835
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
}
|
|
1836
|
+
);
|
|
1837
|
+
const networkPermission = checkNetworkPolicy(call.name, call.arguments, this.networkPolicy);
|
|
1838
|
+
if (networkPermission?.action === "deny") {
|
|
1839
|
+
const reason = networkPermission.reason ? ` (${networkPermission.reason})` : "";
|
|
1840
|
+
return {
|
|
1841
|
+
callId: call.id,
|
|
1842
|
+
content: `[Permission denied] Tool ${call.name} is blocked by networkPolicy${reason}. Do not retry.`,
|
|
1843
|
+
isError: true
|
|
1844
|
+
};
|
|
1845
|
+
}
|
|
1846
|
+
if (permission.action === "deny") {
|
|
1847
|
+
const reason = permission.reason ? ` (${permission.reason})` : "";
|
|
1848
|
+
return {
|
|
1849
|
+
callId: call.id,
|
|
1850
|
+
content: `[Permission denied] Tool ${call.name} is blocked by permission profile "${permission.profileName}"${reason}. Do not retry.`,
|
|
1851
|
+
isError: true
|
|
1852
|
+
};
|
|
1853
|
+
}
|
|
1854
|
+
if (permission.action === "auto-approve" && networkPermission?.action !== "confirm") {
|
|
1855
|
+
this.printToolCall(call);
|
|
1856
|
+
try {
|
|
1857
|
+
const rawContent = await runTool(tool, call.arguments, call.name);
|
|
1858
|
+
const content = truncateOutput(rawContent, call.name);
|
|
1859
|
+
const wasTruncated = content !== rawContent;
|
|
1860
|
+
this.printToolResult(call.name, rawContent, false, wasTruncated);
|
|
1861
|
+
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
|
|
1862
|
+
return { callId: call.id, content, isError: false };
|
|
1863
|
+
} catch (err) {
|
|
1864
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1865
|
+
this.printToolResult(call.name, message, true, false);
|
|
1866
|
+
runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
|
|
1867
|
+
return { callId: call.id, content: message, isError: true };
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
if (networkPermission?.action === "confirm" && dangerLevel === "safe") {
|
|
1871
|
+
this.printToolCall(call);
|
|
1872
|
+
toolCallAlreadyPrinted = true;
|
|
1873
|
+
const confirmed = await this.confirm(call, "write");
|
|
1874
|
+
if (!confirmed) {
|
|
1875
|
+
return {
|
|
1876
|
+
callId: call.id,
|
|
1877
|
+
content: `[User cancelled] The user declined network access for ${call.name}. Do not retry without asking.`,
|
|
1878
|
+
isError: true
|
|
1879
|
+
};
|
|
1611
1880
|
}
|
|
1612
1881
|
}
|
|
1613
1882
|
if (this.sessionAutoApprove && dangerLevel === "write") {
|
|
@@ -1697,6 +1966,9 @@ var ToolExecutor = class {
|
|
|
1697
1966
|
* 然后让用户 approve all / reject all / 选择性 approve。
|
|
1698
1967
|
*/
|
|
1699
1968
|
async executeBatchFileWrites(calls) {
|
|
1969
|
+
if (this.permissionProfileName !== "legacy" || this.permissionRules.length > 0) {
|
|
1970
|
+
return Promise.all(calls.map((call) => this.execute(call)));
|
|
1971
|
+
}
|
|
1700
1972
|
console.log();
|
|
1701
1973
|
console.log(theme.heading(`\u270E Batch file writes (${calls.length} files):`));
|
|
1702
1974
|
console.log(theme.dim("\u2500".repeat(50)));
|
|
@@ -1770,7 +2042,7 @@ var ToolExecutor = class {
|
|
|
1770
2042
|
rl.resume();
|
|
1771
2043
|
process.stdout.write(prompt);
|
|
1772
2044
|
this.confirming = true;
|
|
1773
|
-
return new Promise((
|
|
2045
|
+
return new Promise((resolve6) => {
|
|
1774
2046
|
let completed = false;
|
|
1775
2047
|
const cleanup = (result) => {
|
|
1776
2048
|
if (completed) return;
|
|
@@ -1780,7 +2052,7 @@ var ToolExecutor = class {
|
|
|
1780
2052
|
rl.pause();
|
|
1781
2053
|
rlAny.output = savedOutput;
|
|
1782
2054
|
this.confirming = false;
|
|
1783
|
-
|
|
2055
|
+
resolve6(result);
|
|
1784
2056
|
};
|
|
1785
2057
|
const onLine = (line) => {
|
|
1786
2058
|
const trimmed = line.trim();
|
|
@@ -1954,7 +2226,7 @@ var ToolExecutor = class {
|
|
|
1954
2226
|
rl.resume();
|
|
1955
2227
|
process.stdout.write(color("Proceed? [y/N] (type y + Enter to confirm) "));
|
|
1956
2228
|
this.confirming = true;
|
|
1957
|
-
return new Promise((
|
|
2229
|
+
return new Promise((resolve6) => {
|
|
1958
2230
|
let completed = false;
|
|
1959
2231
|
const cleanup = (answer) => {
|
|
1960
2232
|
if (completed) return;
|
|
@@ -1964,7 +2236,7 @@ var ToolExecutor = class {
|
|
|
1964
2236
|
rl.pause();
|
|
1965
2237
|
rlAny.output = savedOutput;
|
|
1966
2238
|
this.confirming = false;
|
|
1967
|
-
|
|
2239
|
+
resolve6(answer === "y");
|
|
1968
2240
|
};
|
|
1969
2241
|
const onLine = (line) => {
|
|
1970
2242
|
const trimmed = line.trim();
|
|
@@ -1992,11 +2264,11 @@ var ToolExecutor = class {
|
|
|
1992
2264
|
};
|
|
1993
2265
|
|
|
1994
2266
|
// src/tools/sensitive-paths.ts
|
|
1995
|
-
import { resolve as
|
|
2267
|
+
import { resolve as resolve4, sep as sep2, basename as basename2 } from "path";
|
|
1996
2268
|
import { homedir as homedir2 } from "os";
|
|
1997
2269
|
var home = homedir2();
|
|
1998
2270
|
function norm(p) {
|
|
1999
|
-
const abs =
|
|
2271
|
+
const abs = resolve4(p);
|
|
2000
2272
|
return process.platform === "win32" ? abs.toLowerCase() : abs;
|
|
2001
2273
|
}
|
|
2002
2274
|
function homeRel(p) {
|
|
@@ -3213,7 +3485,7 @@ var runInteractiveTool = {
|
|
|
3213
3485
|
PYTHONDONTWRITEBYTECODE: "1"
|
|
3214
3486
|
};
|
|
3215
3487
|
const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
|
|
3216
|
-
return new Promise((
|
|
3488
|
+
return new Promise((resolve6) => {
|
|
3217
3489
|
const child = spawn2(executable, cmdArgs.map(String), {
|
|
3218
3490
|
cwd: process.cwd(),
|
|
3219
3491
|
env,
|
|
@@ -3246,22 +3518,22 @@ var runInteractiveTool = {
|
|
|
3246
3518
|
setTimeout(writeNextLine, 400);
|
|
3247
3519
|
const timer = setTimeout(() => {
|
|
3248
3520
|
child.kill();
|
|
3249
|
-
|
|
3521
|
+
resolve6(`${prefixWarnings}[Timeout after ${timeout}ms]
|
|
3250
3522
|
${buildOutput(stdout, stderr)}`);
|
|
3251
3523
|
}, timeout);
|
|
3252
3524
|
child.on("close", (code) => {
|
|
3253
3525
|
clearTimeout(timer);
|
|
3254
3526
|
const output = buildOutput(stdout, stderr);
|
|
3255
3527
|
if (code !== 0 && code !== null) {
|
|
3256
|
-
|
|
3528
|
+
resolve6(`${prefixWarnings}Exit code ${code}:
|
|
3257
3529
|
${output}`);
|
|
3258
3530
|
} else {
|
|
3259
|
-
|
|
3531
|
+
resolve6(`${prefixWarnings}${output || "(no output)"}`);
|
|
3260
3532
|
}
|
|
3261
3533
|
});
|
|
3262
3534
|
child.on("error", (err) => {
|
|
3263
3535
|
clearTimeout(timer);
|
|
3264
|
-
|
|
3536
|
+
resolve6(
|
|
3265
3537
|
`${prefixWarnings}Failed to start process "${executable}": ${err.message}
|
|
3266
3538
|
Hint: On Windows, use the full path to the executable, e.g.:
|
|
3267
3539
|
C:\\Users\\Jinzd\\anaconda3\\envs\\python312\\python.exe`
|
|
@@ -4013,7 +4285,7 @@ function promptUser(rl, question) {
|
|
|
4013
4285
|
console.log();
|
|
4014
4286
|
console.log(chalk4.cyan("\u2753 ") + chalk4.bold(question));
|
|
4015
4287
|
process.stdout.write(chalk4.cyan("> "));
|
|
4016
|
-
return new Promise((
|
|
4288
|
+
return new Promise((resolve6) => {
|
|
4017
4289
|
let completed = false;
|
|
4018
4290
|
const cleanup = (answer) => {
|
|
4019
4291
|
if (completed) return;
|
|
@@ -4023,7 +4295,7 @@ function promptUser(rl, question) {
|
|
|
4023
4295
|
rl.pause();
|
|
4024
4296
|
rlAny.output = savedOutput;
|
|
4025
4297
|
askUserContext.prompting = false;
|
|
4026
|
-
|
|
4298
|
+
resolve6(answer);
|
|
4027
4299
|
};
|
|
4028
4300
|
const onLine = (line) => {
|
|
4029
4301
|
cleanup(line);
|
|
@@ -5034,7 +5306,7 @@ ${commitOutput.trim()}`;
|
|
|
5034
5306
|
// src/tools/builtin/notebook-edit.ts
|
|
5035
5307
|
import { readFileSync as readFileSync7, existsSync as existsSync11 } from "fs";
|
|
5036
5308
|
import { writeFile } from "fs/promises";
|
|
5037
|
-
import { resolve as
|
|
5309
|
+
import { resolve as resolve5, extname as extname2 } from "path";
|
|
5038
5310
|
var notebookEditTool = {
|
|
5039
5311
|
definition: {
|
|
5040
5312
|
name: "notebook_edit",
|
|
@@ -5083,7 +5355,7 @@ var notebookEditTool = {
|
|
|
5083
5355
|
if (!Number.isInteger(cellIndexRaw) || cellIndexRaw < 1) {
|
|
5084
5356
|
throw new ToolError("notebook_edit", "cell_index must be a positive integer (1-based)");
|
|
5085
5357
|
}
|
|
5086
|
-
const absPath =
|
|
5358
|
+
const absPath = resolve5(filePath);
|
|
5087
5359
|
if (extname2(absPath).toLowerCase() !== ".ipynb") {
|
|
5088
5360
|
throw new ToolError("notebook_edit", "path must point to a .ipynb file");
|
|
5089
5361
|
}
|
|
@@ -5740,7 +6012,9 @@ export {
|
|
|
5740
6012
|
groupCallsByPhase,
|
|
5741
6013
|
runSafePhases,
|
|
5742
6014
|
runHook,
|
|
5743
|
-
|
|
6015
|
+
checkPermissionWithProfile,
|
|
6016
|
+
formatPermissionProfileWarning,
|
|
6017
|
+
checkNetworkPolicy,
|
|
5744
6018
|
setMaxOutputCap,
|
|
5745
6019
|
setContextWindow,
|
|
5746
6020
|
truncateForPersist,
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
import "./chunk-XPBEJB27.js";
|
|
11
11
|
import {
|
|
12
12
|
ConfigManager
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UOROWTGG.js";
|
|
14
14
|
import "./chunk-TZQHYZKT.js";
|
|
15
15
|
import {
|
|
16
16
|
VERSION
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-E5XCM4A6.js";
|
|
18
18
|
import "./chunk-IW3Q7AE5.js";
|
|
19
19
|
|
|
20
20
|
// src/cli/ci.ts
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getConfigDirUsage,
|
|
4
4
|
listRecentCrashes
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-BE6ERF7M.js";
|
|
6
6
|
import {
|
|
7
7
|
ProviderRegistry
|
|
8
8
|
} from "./chunk-QMXC327F.js";
|
|
@@ -11,17 +11,17 @@ import {
|
|
|
11
11
|
getTopFailingTools,
|
|
12
12
|
getTopUsedTools,
|
|
13
13
|
resetStats
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JBWA73GK.js";
|
|
15
15
|
import "./chunk-XPBEJB27.js";
|
|
16
16
|
import {
|
|
17
17
|
ConfigManager
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UOROWTGG.js";
|
|
19
19
|
import "./chunk-TZQHYZKT.js";
|
|
20
20
|
import {
|
|
21
21
|
DEV_STATE_FILE_NAME,
|
|
22
22
|
MEMORY_FILE_NAME,
|
|
23
23
|
VERSION
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-E5XCM4A6.js";
|
|
25
25
|
import "./chunk-IW3Q7AE5.js";
|
|
26
26
|
|
|
27
27
|
// src/diagnostics/doctor-cli.ts
|