jinzd-ai-cli 0.4.209 → 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.
@@ -5,10 +5,10 @@ import {
5
5
  } from "./chunk-T2NL5ZIA.js";
6
6
  import {
7
7
  runTestsTool
8
- } from "./chunk-EN63JA7N.js";
8
+ } from "./chunk-6NS6643Y.js";
9
9
  import {
10
10
  runTool
11
- } from "./chunk-STIEOOOL.js";
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-UPMBIS4T.js";
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
- if (this.permissionRules.length > 0) {
1592
- const action = checkPermission(call.name, call.arguments, dangerLevel, this.permissionRules, this.defaultPermission);
1593
- if (action === "deny") {
1594
- return { callId: call.id, content: `[Permission denied] Tool ${call.name} is blocked by permission rules. Do not retry.`, isError: true };
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
- if (action === "auto-approve") {
1597
- this.printToolCall(call);
1598
- try {
1599
- const rawContent = await runTool(tool, call.arguments, call.name);
1600
- const content = truncateOutput(rawContent, call.name);
1601
- const wasTruncated = content !== rawContent;
1602
- this.printToolResult(call.name, rawContent, false, wasTruncated);
1603
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
1604
- return { callId: call.id, content, isError: false };
1605
- } catch (err) {
1606
- const message = err instanceof Error ? err.message : String(err);
1607
- this.printToolResult(call.name, message, true, false);
1608
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
1609
- return { callId: call.id, content: message, isError: true };
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((resolve5) => {
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
- resolve5(result);
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((resolve5) => {
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
- resolve5(answer === "y");
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 resolve3, sep as sep2, basename as basename2 } from "path";
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 = resolve3(p);
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((resolve5) => {
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
- resolve5(`${prefixWarnings}[Timeout after ${timeout}ms]
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
- resolve5(`${prefixWarnings}Exit code ${code}:
3528
+ resolve6(`${prefixWarnings}Exit code ${code}:
3257
3529
  ${output}`);
3258
3530
  } else {
3259
- resolve5(`${prefixWarnings}${output || "(no output)"}`);
3531
+ resolve6(`${prefixWarnings}${output || "(no output)"}`);
3260
3532
  }
3261
3533
  });
3262
3534
  child.on("error", (err) => {
3263
3535
  clearTimeout(timer);
3264
- resolve5(
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((resolve5) => {
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
- resolve5(answer);
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 resolve4, extname as extname2 } from "path";
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 = resolve4(filePath);
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
- checkPermission,
6015
+ checkPermissionWithProfile,
6016
+ formatPermissionProfileWarning,
6017
+ checkNetworkPolicy,
5744
6018
  setMaxOutputCap,
5745
6019
  setContextWindow,
5746
6020
  truncateForPersist,
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.209";
9
+ var VERSION = "0.4.211";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -14,7 +14,8 @@ var HISTORY_DIR_NAME = "history";
14
14
  var PLUGINS_DIR_NAME = "plugins";
15
15
  var SKILLS_DIR_NAME = "skills";
16
16
  var CUSTOM_COMMANDS_DIR_NAME = "commands";
17
- var CONTEXT_FILE_CANDIDATES = ["AICLI.md", "CLAUDE.md"];
17
+ var CONTEXT_FILE_CANDIDATES = ["AICLI.override.md", "AGENTS.override.md", "AICLI.md", "CLAUDE.md", "AGENTS.md"];
18
+ var CONTEXT_FILE_MAX_BYTES = 32 * 1024;
18
19
  var MEMORY_FILE_NAME = "memory.md";
19
20
  var MEMORY_MAX_CHARS = 1e4;
20
21
  var DEV_STATE_FILE_NAME = "dev-state.md";
@@ -96,7 +97,7 @@ var AGENTIC_BEHAVIOR_GUIDELINE = `# Important Behavioral Guidelines
96
97
  - Only begin using write/execute tools when the user **explicitly requests** an action (e.g., "generate", "create", "modify", "run", "start", etc.).
97
98
  - **Stop when the explicit task is done \u2014 do NOT autonomously test, verify, or run what you just created.** If the user asks "write/create/save file X", finish writing the file and STOP. Do not run it, do not test it, do not "verify it works" with bash/run_interactive. The user will run it themselves and tell you if anything is wrong. Only run/test when the user explicitly says "run", "test", "execute", "try it", "verify", "make sure it works", etc.
98
99
  - **Do NOT retry the same failing command with variants.** If a command fails (exit code non-zero), report the failure to the user with a brief diagnosis and STOP. Do not loop through alternate shells, alternate quoting, alternate paths, or alternate Python invocations. The user can decide whether to retry.
99
- - Project context files (CLAUDE.md, AICLI.md) provide background information about the project. They are NOT instructions to start working. Only use them as reference when the user asks a project-related question or task.
100
+ - Project context files (AICLI.md, CLAUDE.md, AGENTS.md, and override variants) provide background information about the project. They are NOT instructions to start working. Only use them as reference when the user asks a project-related question or task.
100
101
  - If you are unsure about the user's intent, use the ask_user tool to confirm with the user, rather than assuming and executing on your own.
101
102
  - **Do NOT abuse ask_user for redundant confirmations**: When the user has already given a clear, explicit instruction (e.g., "write lesson 142", "generate file X", "create the report"), execute it immediately. Do NOT ask "are you sure?" or request details that can be found in project documents. Repeatedly asking the user to confirm wastes their time and is extremely frustrating. Only use ask_user when critical information is genuinely missing and cannot be inferred from context files.`;
102
103
  function buildUserIdentityPrompt(profile) {
@@ -549,6 +550,7 @@ export {
549
550
  SKILLS_DIR_NAME,
550
551
  CUSTOM_COMMANDS_DIR_NAME,
551
552
  CONTEXT_FILE_CANDIDATES,
553
+ CONTEXT_FILE_MAX_BYTES,
552
554
  MEMORY_FILE_NAME,
553
555
  MEMORY_MAX_CHARS,
554
556
  DEV_STATE_FILE_NAME,
@@ -10,11 +10,11 @@ import {
10
10
  import "./chunk-XPBEJB27.js";
11
11
  import {
12
12
  ConfigManager
13
- } from "./chunk-DUZRQXIP.js";
13
+ } from "./chunk-UOROWTGG.js";
14
14
  import "./chunk-TZQHYZKT.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-UPMBIS4T.js";
17
+ } from "./chunk-E5XCM4A6.js";
18
18
  import "./chunk-IW3Q7AE5.js";
19
19
 
20
20
  // src/cli/ci.ts
@@ -7,6 +7,7 @@ import {
7
7
  CONFIG_DIR_NAME,
8
8
  CONFIG_FILE_NAME,
9
9
  CONTEXT_FILE_CANDIDATES,
10
+ CONTEXT_FILE_MAX_BYTES,
10
11
  CONTEXT_PRESSURE_THRESHOLD,
11
12
  CONTEXT_WARNING_THRESHOLD,
12
13
  CUSTOM_COMMANDS_DIR_NAME,
@@ -36,7 +37,7 @@ import {
36
37
  TEST_TIMEOUT,
37
38
  VERSION,
38
39
  buildUserIdentityPrompt
39
- } from "./chunk-UPMBIS4T.js";
40
+ } from "./chunk-E5XCM4A6.js";
40
41
  export {
41
42
  AGENTIC_BEHAVIOR_GUIDELINE,
42
43
  APP_NAME,
@@ -45,6 +46,7 @@ export {
45
46
  CONFIG_DIR_NAME,
46
47
  CONFIG_FILE_NAME,
47
48
  CONTEXT_FILE_CANDIDATES,
49
+ CONTEXT_FILE_MAX_BYTES,
48
50
  CONTEXT_PRESSURE_THRESHOLD,
49
51
  CONTEXT_WARNING_THRESHOLD,
50
52
  CUSTOM_COMMANDS_DIR_NAME,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  getConfigDirUsage,
4
4
  listRecentCrashes
5
- } from "./chunk-D6M4E7SH.js";
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-STIEOOOL.js";
14
+ } from "./chunk-JBWA73GK.js";
15
15
  import "./chunk-XPBEJB27.js";
16
16
  import {
17
17
  ConfigManager
18
- } from "./chunk-DUZRQXIP.js";
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-UPMBIS4T.js";
24
+ } from "./chunk-E5XCM4A6.js";
25
25
  import "./chunk-IW3Q7AE5.js";
26
26
 
27
27
  // src/diagnostics/doctor-cli.ts