jinzd-ai-cli 0.4.103 → 0.4.105

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.
Files changed (41) hide show
  1. package/README.md +1 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/{agent-client-6GX6QQDU.js → agent-client-25TIQ6AP.js} +1 -0
  4. package/dist/{auth-MSUWO6SE.js → auth-SC6KHHI3.js} +1 -0
  5. package/dist/{batch-LNTG2IRQ.js → batch-NPK4USGH.js} +3 -2
  6. package/dist/{chat-index-W2UZ34ZI.js → chat-index-7OHUKJY5.js} +1 -0
  7. package/dist/{chat-index-QKFH7ZP6.js → chat-index-ADG2GPCC.js} +1 -0
  8. package/dist/chunk-3RG5ZIWI.js +10 -0
  9. package/dist/{chunk-SN56X6RE.js → chunk-B6NUQVYK.js} +1 -1
  10. package/dist/{chunk-VOWVIR2U.js → chunk-F7XJ67XB.js} +30 -112
  11. package/dist/chunk-HOSJZMQS.js +97 -0
  12. package/dist/{chunk-OVYOYUP7.js → chunk-LVX667WL.js} +89 -36
  13. package/dist/{chunk-JHPSWYO3.js → chunk-LX5FXZVP.js} +7 -4
  14. package/dist/chunk-PDX44BCA.js +11 -0
  15. package/dist/{chunk-RZWWODW7.js → chunk-RFKT3T5S.js} +199 -74
  16. package/dist/{chunk-DGXUO7D4.js → chunk-VOF6OTZB.js} +89 -39
  17. package/dist/constants-HK5BB5EZ.js +78 -0
  18. package/dist/electron-server.js +289 -129
  19. package/dist/{file-checkpoint-CGH6OJVI.js → file-checkpoint-UHSMHCRU.js} +1 -0
  20. package/dist/{file-checkpoint-NKBHGC7L.js → file-checkpoint-ZN7KE3TN.js} +1 -0
  21. package/dist/git-context-7KIP4X2V.js +12 -0
  22. package/dist/{hub-4YGZ4XHN.js → hub-5VFGLTHY.js} +3 -2
  23. package/dist/{hub-server-BYXNQGDY.js → hub-server-AUMVPNU6.js} +1 -0
  24. package/dist/index.js +98 -47
  25. package/dist/{indexer-C7QYYHSZ.js → indexer-XGY7XGJM.js} +1 -0
  26. package/dist/{indexer-O5FCGFBJ.js → indexer-Z6AQTGBK.js} +1 -0
  27. package/dist/project-trust-EBGHD7LE.js +67 -0
  28. package/dist/project-trust-IFM7FXEV.js +68 -0
  29. package/dist/{run-tests-SN74WT4Z.js → run-tests-IMVI43CZ.js} +2 -1
  30. package/dist/{run-tests-3YOJEN2Q.js → run-tests-VQ3YZB75.js} +3 -2
  31. package/dist/{semantic-3KJPAUW6.js → semantic-FR2ZSQLY.js} +1 -0
  32. package/dist/{semantic-YDRPPVWK.js → semantic-UFKVYKFE.js} +3 -2
  33. package/dist/{server-BG4WR6RF.js → server-XDBIWNRW.js} +9 -8
  34. package/dist/{server-TNPDHGQT.js → server-ZVY3CKTJ.js} +65 -28
  35. package/dist/{store-S24SPPDZ.js → store-JDEW743P.js} +1 -0
  36. package/dist/{store-247B3TAU.js → store-Q7NMUCPP.js} +1 -0
  37. package/dist/{task-orchestrator-MUIH3XBY.js → task-orchestrator-UEZOFXQX.js} +9 -8
  38. package/dist/{vector-store-NDUFLNGN.js → vector-store-AK6J3RIA.js} +1 -0
  39. package/dist/{vector-store-QARQ2P6D.js → vector-store-MCQ77OOJ.js} +1 -0
  40. package/package.json +1 -1
  41. package/dist/{chunk-KJLJPUY2.js → chunk-3BICTI5M.js} +3 -3
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-DGXUO7D4.js";
39
+ } from "./chunk-VOF6OTZB.js";
40
40
  import {
41
41
  hasSemanticIndex,
42
42
  semanticSearch
@@ -51,12 +51,13 @@ import {
51
51
  searchChatMemory
52
52
  } from "./chunk-5S3PIG5O.js";
53
53
  import "./chunk-JV5N65KN.js";
54
+ import "./chunk-3RG5ZIWI.js";
54
55
 
55
56
  // src/web/server.ts
56
57
  import express from "express";
57
58
  import { createServer } from "http";
58
59
  import { WebSocketServer } from "ws";
59
- import { join as join15, dirname as dirname5, resolve as resolve5, relative as relative3, sep as sep2 } from "path";
60
+ import { join as join15, dirname as dirname5, resolve as resolve6, relative as relative3, sep as sep3 } from "path";
60
61
  import { existsSync as existsSync22, readFileSync as readFileSync15, readdirSync as readdirSync11, statSync as statSync9, realpathSync } from "fs";
61
62
  import { networkInterfaces } from "os";
62
63
 
@@ -512,11 +513,17 @@ function getDangerLevel(toolName, args) {
512
513
  const cmd = String(args["command"] ?? "");
513
514
  if (/\brm\s+[^\n]*(?:-\w*[rRfF]\w*|--recursive|--force)\b/.test(cmd)) return "destructive";
514
515
  if (/\brm\s+\S/.test(cmd)) return "destructive";
515
- if (/\brmdir\b|\bformat\b|\bmkfs\b/.test(cmd)) return "destructive";
516
- if (/\bRemove-Item\b.*(?:-Recurse|-Force)|\bri\s+.*-(?:Recurse|Force)\b|\brd\s+\/s\b|\brmdir\s+\/s\b/i.test(cmd)) return "destructive";
516
+ if (/\brmdir\b|\bformat\b|\bmkfs\b|\bdd\s+if=|\bshred\b|\bfdisk\b|\bparted\b/.test(cmd)) return "destructive";
517
+ if (/\bshutdown\b|\breboot\b|\bhalt\b|\bpoweroff\b/.test(cmd)) return "destructive";
518
+ if (/\bkill\s+-9\b|\bkillall\b/.test(cmd)) return "destructive";
519
+ if (/\bRemove-Item\b|\bri\s+\S/i.test(cmd)) return "destructive";
520
+ if (/\brd\s+\/s\b|\brmdir\s+\/s\b/i.test(cmd)) return "destructive";
517
521
  if (/\bdel\s+\S/.test(cmd)) return "destructive";
518
- if (/\becho\b.*>>?|\btee\b|\bcp\b|\bmv\b/.test(cmd)) return "write";
519
- if (/\bSet-Content\b|\bOut-File\b|\bAdd-Content\b|\bCopy-Item\b|\bMove-Item\b/i.test(cmd)) return "write";
522
+ if (/\bShutdown(-Computer)?\b|\bRestart-Computer\b/i.test(cmd)) return "destructive";
523
+ if (/(?:^|[\s|;&])>>?\s*\S/.test(cmd)) return "write";
524
+ if (/\btee\b|\bcp\b|\bmv\b|\bln\s+-s/.test(cmd)) return "write";
525
+ if (/\bchmod\b|\bchown\b/.test(cmd)) return "write";
526
+ if (/\bSet-Content\b|\bOut-File\b|\bAdd-Content\b|\bCopy-Item\b|\bMove-Item\b|\bSet-ItemProperty\b|\bNew-ItemProperty\b/i.test(cmd)) return "write";
520
527
  return "safe";
521
528
  }
522
529
  if (toolName === "write_file") return "write";
@@ -4053,10 +4060,10 @@ function createCell(cellType, content) {
4053
4060
  // src/tools/builtin/read-file.ts
4054
4061
  var MAX_FILE_BYTES = 10 * 1024 * 1024;
4055
4062
  function getSensitiveWarning(normalizedPath) {
4056
- const home = homedir2();
4063
+ const home2 = homedir2();
4057
4064
  const p = normalizedPath.toLowerCase();
4058
4065
  const base = basename(normalizedPath).toLowerCase();
4059
- if (normalizedPath.startsWith(home) && p.includes(".aicli") && base === "config.json") {
4066
+ if (normalizedPath.startsWith(home2) && p.includes(".aicli") && base === "config.json") {
4060
4067
  return "[\u26A0 Security Warning: This file contains API keys. Be careful not to share this content.]\n\n";
4061
4068
  }
4062
4069
  if (base === ".env" || base.startsWith(".env.") || base.endsWith(".env")) {
@@ -4550,8 +4557,14 @@ function checkPermission(toolName, args, dangerLevel, rules, defaultAction = "co
4550
4557
  if (rule.when) {
4551
4558
  if (rule.when.dangerLevel && rule.when.dangerLevel !== dangerLevel) continue;
4552
4559
  if (rule.when.pathPattern) {
4553
- const path3 = String(args["path"] ?? args["command"] ?? "");
4554
- if (!path3.includes(rule.when.pathPattern)) continue;
4560
+ if (toolName === "bash" && rule.action === "auto-approve") {
4561
+ const cmd = String(args["command"] ?? "").trim();
4562
+ if (/[;&|`$<>]/.test(cmd) || /\$\(/.test(cmd)) continue;
4563
+ if (!cmd.startsWith(rule.when.pathPattern)) continue;
4564
+ } else {
4565
+ const path3 = String(args["path"] ?? args["command"] ?? "");
4566
+ if (!path3.includes(rule.when.pathPattern)) continue;
4567
+ }
4555
4568
  }
4556
4569
  }
4557
4570
  return rule.action;
@@ -4958,7 +4971,7 @@ var ToolExecutor = class {
4958
4971
  rl.resume();
4959
4972
  process.stdout.write(prompt);
4960
4973
  this.confirming = true;
4961
- return new Promise((resolve6) => {
4974
+ return new Promise((resolve7) => {
4962
4975
  let completed = false;
4963
4976
  const cleanup = (result) => {
4964
4977
  if (completed) return;
@@ -4968,7 +4981,7 @@ var ToolExecutor = class {
4968
4981
  rl.pause();
4969
4982
  rlAny.output = savedOutput;
4970
4983
  this.confirming = false;
4971
- resolve6(result);
4984
+ resolve7(result);
4972
4985
  };
4973
4986
  const onLine = (line) => {
4974
4987
  const trimmed = line.trim();
@@ -5138,7 +5151,7 @@ var ToolExecutor = class {
5138
5151
  rl.resume();
5139
5152
  process.stdout.write(color("Proceed? [y/N] (type y + Enter to confirm) "));
5140
5153
  this.confirming = true;
5141
- return new Promise((resolve6) => {
5154
+ return new Promise((resolve7) => {
5142
5155
  let completed = false;
5143
5156
  const cleanup = (answer) => {
5144
5157
  if (completed) return;
@@ -5148,7 +5161,7 @@ var ToolExecutor = class {
5148
5161
  rl.pause();
5149
5162
  rlAny.output = savedOutput;
5150
5163
  this.confirming = false;
5151
- resolve6(answer === "y");
5164
+ resolve7(answer === "y");
5152
5165
  };
5153
5166
  const onLine = (line) => {
5154
5167
  const trimmed = line.trim();
@@ -5175,6 +5188,99 @@ var ToolExecutor = class {
5175
5188
  }
5176
5189
  };
5177
5190
 
5191
+ // src/tools/sensitive-paths.ts
5192
+ import { resolve as resolve3, sep as sep2, basename as basename2 } from "path";
5193
+ import { homedir as homedir3 } from "os";
5194
+ var home = homedir3();
5195
+ function norm(p) {
5196
+ const abs = resolve3(p);
5197
+ return process.platform === "win32" ? abs.toLowerCase() : abs;
5198
+ }
5199
+ function homeRel(p) {
5200
+ const abs = norm(p);
5201
+ const h = norm(home);
5202
+ if (abs === h) return ".";
5203
+ if (abs.startsWith(h + (process.platform === "win32" ? "\\" : "/"))) {
5204
+ return abs.slice(h.length + 1);
5205
+ }
5206
+ return null;
5207
+ }
5208
+ function classifyWritePath(path3) {
5209
+ if (!path3) return { sensitive: false };
5210
+ const abs = norm(path3);
5211
+ const base = basename2(abs);
5212
+ const rel = homeRel(path3);
5213
+ if (rel) {
5214
+ const shellRc = /* @__PURE__ */ new Set([
5215
+ ".bashrc",
5216
+ ".bash_profile",
5217
+ ".bash_login",
5218
+ ".profile",
5219
+ ".zshrc",
5220
+ ".zprofile",
5221
+ ".zshenv",
5222
+ ".zlogin",
5223
+ ".kshrc",
5224
+ ".cshrc",
5225
+ ".tcshrc",
5226
+ ".fish_config"
5227
+ ]);
5228
+ if (shellRc.has(base)) {
5229
+ return { sensitive: true, reason: `shell startup file (${rel})` };
5230
+ }
5231
+ }
5232
+ const sshDir = `${sep2}.ssh${sep2}`;
5233
+ if (abs.includes(sshDir.toLowerCase()) || abs.includes(sshDir)) {
5234
+ return { sensitive: true, reason: `SSH directory (${rel ?? abs})` };
5235
+ }
5236
+ const credPaths = [
5237
+ `${sep2}.aws${sep2}credentials`,
5238
+ `${sep2}.aws${sep2}config`,
5239
+ `${sep2}.gcp${sep2}`,
5240
+ `${sep2}.azure${sep2}`,
5241
+ `${sep2}.config${sep2}gcloud${sep2}`,
5242
+ `${sep2}.kube${sep2}config`,
5243
+ `${sep2}.docker${sep2}config.json`,
5244
+ `${sep2}.netrc`
5245
+ ];
5246
+ for (const c of credPaths) {
5247
+ const lc = process.platform === "win32" ? c.toLowerCase() : c;
5248
+ if (abs.includes(lc)) return { sensitive: true, reason: `cloud/auth credential file (${rel ?? abs})` };
5249
+ }
5250
+ if (rel && (rel === ".aicli" || rel.startsWith(".aicli" + (process.platform === "win32" ? "\\" : "/")))) {
5251
+ if (base === "config.json" || base === "users.json") {
5252
+ return { sensitive: true, reason: `ai-cli internal config (${rel})` };
5253
+ }
5254
+ }
5255
+ if (abs.includes(`${sep2}.git${sep2}hooks${sep2}`) || abs.includes(`${sep2}.git${sep2}hooks${sep2}`.toLowerCase())) {
5256
+ return { sensitive: true, reason: ".git/hooks/* \u2014 runs on next git operation" };
5257
+ }
5258
+ if (abs.includes(`${sep2}.git${sep2}config`) || abs.includes(`${sep2}.git${sep2}config`.toLowerCase())) {
5259
+ return { sensitive: true, reason: ".git/config \u2014 repository identity" };
5260
+ }
5261
+ if (process.platform !== "win32") {
5262
+ const sysPrefixes = ["/etc/", "/usr/bin/", "/usr/sbin/", "/bin/", "/sbin/", "/boot/"];
5263
+ for (const pre of sysPrefixes) {
5264
+ if (abs.startsWith(pre)) return { sensitive: true, reason: `system path (${pre})` };
5265
+ }
5266
+ } else {
5267
+ const winSys = ["c:\\windows\\system32\\", "c:\\windows\\syswow64\\", "c:\\program files\\", "c:\\program files (x86)\\"];
5268
+ for (const pre of winSys) {
5269
+ if (abs.startsWith(pre)) return { sensitive: true, reason: `system path (${pre})` };
5270
+ }
5271
+ }
5272
+ if (abs.includes(`${sep2}cron.d${sep2}`) || abs.startsWith("/etc/cron") || abs.startsWith("/var/spool/cron/")) {
5273
+ return { sensitive: true, reason: "cron scheduling" };
5274
+ }
5275
+ if (rel && (rel.startsWith("Library/LaunchAgents/") || rel.startsWith("Library/LaunchDaemons/"))) {
5276
+ return { sensitive: true, reason: "macOS launch agent" };
5277
+ }
5278
+ return { sensitive: false };
5279
+ }
5280
+ var subAgentGuard = {
5281
+ active: false
5282
+ };
5283
+
5178
5284
  // src/tools/builtin/write-file.ts
5179
5285
  var writeFileTool = {
5180
5286
  definition: {
@@ -5217,6 +5323,13 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
5217
5323
  const encoding = args["encoding"] ?? "utf-8";
5218
5324
  const appendMode = String(args["append"] ?? "false").toLowerCase() === "true";
5219
5325
  if (!filePath) throw new ToolError("write_file", "path is required");
5326
+ const verdict = classifyWritePath(filePath);
5327
+ if (verdict.sensitive && subAgentGuard.active) {
5328
+ throw new ToolError(
5329
+ "write_file",
5330
+ `Refused: sub-agents cannot write to sensitive paths \u2014 ${verdict.reason}. If this is genuinely needed, ask the parent agent to perform the write so the user can approve it.`
5331
+ );
5332
+ }
5220
5333
  undoStack.push(filePath, `write_file${appendMode ? " (append)" : ""}: ${filePath}`);
5221
5334
  fileCheckpoints.snapshot(filePath, ToolExecutor.currentMessageIndex);
5222
5335
  mkdirSync3(dirname2(filePath), { recursive: true });
@@ -5229,7 +5342,7 @@ Do NOT split a long document into many write_file(append=true) calls. That patte
5229
5342
  const mode = appendMode ? "appended" : "written";
5230
5343
  void (async () => {
5231
5344
  try {
5232
- const { updateFile } = await import("./indexer-O5FCGFBJ.js");
5345
+ const { updateFile } = await import("./indexer-Z6AQTGBK.js");
5233
5346
  await updateFile(process.cwd(), filePath);
5234
5347
  } catch {
5235
5348
  }
@@ -5601,6 +5714,13 @@ Note: Path can be absolute or relative to cwd.`,
5601
5714
  const encoding = args["encoding"] ?? "utf-8";
5602
5715
  if (!filePath) throw new ToolError("edit_file", "path is required");
5603
5716
  if (!existsSync7(filePath)) throw new ToolError("edit_file", `File not found: ${filePath}`);
5717
+ const verdict = classifyWritePath(filePath);
5718
+ if (verdict.sensitive && subAgentGuard.active) {
5719
+ throw new ToolError(
5720
+ "edit_file",
5721
+ `Refused: sub-agents cannot edit sensitive paths \u2014 ${verdict.reason}. If this is genuinely needed, ask the parent agent to perform the edit so the user can approve it.`
5722
+ );
5723
+ }
5604
5724
  const original = readFileSync6(filePath, encoding);
5605
5725
  if (args["patch"] !== void 0) {
5606
5726
  const patchText = String(args["patch"] ?? "");
@@ -5760,7 +5880,7 @@ function truncatePreview(str, maxLen = 80) {
5760
5880
 
5761
5881
  // src/tools/builtin/list-dir.ts
5762
5882
  import { readdirSync as readdirSync4, statSync as statSync3, existsSync as existsSync8 } from "fs";
5763
- import { join as join3, basename as basename2 } from "path";
5883
+ import { join as join3, basename as basename3 } from "path";
5764
5884
  var listDirTool = {
5765
5885
  definition: {
5766
5886
  name: "list_dir",
@@ -5783,7 +5903,7 @@ var listDirTool = {
5783
5903
  const dirPath = String(args["path"] ?? process.cwd());
5784
5904
  const recursive = Boolean(args["recursive"] ?? false);
5785
5905
  if (!existsSync8(dirPath)) {
5786
- const targetName = basename2(dirPath).toLowerCase();
5906
+ const targetName = basename3(dirPath).toLowerCase();
5787
5907
  const cwd = process.cwd();
5788
5908
  const suggestions = [];
5789
5909
  try {
@@ -6098,7 +6218,7 @@ function searchInFile(fullPath, displayPath, regex, contextLines, maxResults, re
6098
6218
 
6099
6219
  // src/tools/builtin/glob-files.ts
6100
6220
  import { readdirSync as readdirSync6, statSync as statSync5, existsSync as existsSync10 } from "fs";
6101
- import { join as join5, relative as relative2, basename as basename3 } from "path";
6221
+ import { join as join5, relative as relative2, basename as basename4 } from "path";
6102
6222
  var globFilesTool = {
6103
6223
  definition: {
6104
6224
  name: "glob_files",
@@ -6214,7 +6334,7 @@ function collectMatchingFiles(dirPath, rootPath, regex, results, maxResults) {
6214
6334
  collectMatchingFiles(fullPath, rootPath, regex, results, maxResults);
6215
6335
  } else if (entry.isFile()) {
6216
6336
  const relPath = relative2(rootPath, fullPath).replace(/\\/g, "/");
6217
- if (regex.test(relPath) || regex.test(basename3(relPath))) {
6337
+ if (regex.test(relPath) || regex.test(basename4(relPath))) {
6218
6338
  try {
6219
6339
  const stat = statSync5(fullPath);
6220
6340
  results.push({ relPath, absPath: fullPath, mtime: stat.mtimeMs });
@@ -6290,7 +6410,7 @@ var runInteractiveTool = {
6290
6410
  PYTHONDONTWRITEBYTECODE: "1"
6291
6411
  };
6292
6412
  const prefixWarnings = [argsTypeWarning, stdinTypeWarning].filter(Boolean).join("");
6293
- return new Promise((resolve6) => {
6413
+ return new Promise((resolve7) => {
6294
6414
  const child = spawn2(executable, cmdArgs.map(String), {
6295
6415
  cwd: process.cwd(),
6296
6416
  env,
@@ -6323,22 +6443,22 @@ var runInteractiveTool = {
6323
6443
  setTimeout(writeNextLine, 400);
6324
6444
  const timer = setTimeout(() => {
6325
6445
  child.kill();
6326
- resolve6(`${prefixWarnings}[Timeout after ${timeout}ms]
6446
+ resolve7(`${prefixWarnings}[Timeout after ${timeout}ms]
6327
6447
  ${buildOutput(stdout, stderr)}`);
6328
6448
  }, timeout);
6329
6449
  child.on("close", (code) => {
6330
6450
  clearTimeout(timer);
6331
6451
  const output = buildOutput(stdout, stderr);
6332
6452
  if (code !== 0 && code !== null) {
6333
- resolve6(`${prefixWarnings}Exit code ${code}:
6453
+ resolve7(`${prefixWarnings}Exit code ${code}:
6334
6454
  ${output}`);
6335
6455
  } else {
6336
- resolve6(`${prefixWarnings}${output || "(no output)"}`);
6456
+ resolve7(`${prefixWarnings}${output || "(no output)"}`);
6337
6457
  }
6338
6458
  });
6339
6459
  child.on("error", (err) => {
6340
6460
  clearTimeout(timer);
6341
- resolve6(
6461
+ resolve7(
6342
6462
  `${prefixWarnings}Failed to start process "${executable}": ${err.message}
6343
6463
  Hint: On Windows, use the full path to the executable, e.g.:
6344
6464
  C:\\Users\\Jinzd\\anaconda3\\envs\\python312\\python.exe`
@@ -6608,9 +6728,9 @@ Any of these triggers means use save_last_response, NOT write_file:
6608
6728
  // src/tools/builtin/save-memory.ts
6609
6729
  import { existsSync as existsSync11, statSync as statSync6, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5 } from "fs";
6610
6730
  import { join as join6 } from "path";
6611
- import { homedir as homedir3 } from "os";
6731
+ import { homedir as homedir4 } from "os";
6612
6732
  function getMemoryFilePath() {
6613
- return join6(homedir3(), CONFIG_DIR_NAME, MEMORY_FILE_NAME);
6733
+ return join6(homedir4(), CONFIG_DIR_NAME, MEMORY_FILE_NAME);
6614
6734
  }
6615
6735
  function formatTimestamp() {
6616
6736
  const now = /* @__PURE__ */ new Date();
@@ -6634,7 +6754,7 @@ var saveMemoryTool = {
6634
6754
  const content = String(args["content"] ?? "").trim();
6635
6755
  if (!content) throw new ToolError("save_memory", "content is required");
6636
6756
  const memoryPath = getMemoryFilePath();
6637
- const configDir = join6(homedir3(), CONFIG_DIR_NAME);
6757
+ const configDir = join6(homedir4(), CONFIG_DIR_NAME);
6638
6758
  if (!existsSync11(configDir)) {
6639
6759
  mkdirSync5(configDir, { recursive: true });
6640
6760
  }
@@ -6689,7 +6809,7 @@ function promptUser(rl, question) {
6689
6809
  console.log();
6690
6810
  console.log(chalk4.cyan("\u2753 ") + chalk4.bold(question));
6691
6811
  process.stdout.write(chalk4.cyan("> "));
6692
- return new Promise((resolve6) => {
6812
+ return new Promise((resolve7) => {
6693
6813
  let completed = false;
6694
6814
  const cleanup = (answer) => {
6695
6815
  if (completed) return;
@@ -6699,7 +6819,7 @@ function promptUser(rl, question) {
6699
6819
  rl.pause();
6700
6820
  rlAny.output = savedOutput;
6701
6821
  askUserContext.prompting = false;
6702
- resolve6(answer);
6822
+ resolve7(answer);
6703
6823
  };
6704
6824
  const onLine = (line) => {
6705
6825
  cleanup(line);
@@ -7196,37 +7316,43 @@ var spawnAgentTool = {
7196
7316
  if (!ctx.provider) {
7197
7317
  throw new ToolError("spawn_agent", "provider not initialized (context not injected)");
7198
7318
  }
7199
- if (singleTask) {
7200
- const { content, usage } = await runSubAgent(singleTask, maxRounds, null, ctx);
7201
- return [
7202
- "## Sub-Agent Result",
7203
- "",
7204
- content,
7205
- "",
7206
- "---",
7207
- `Token usage: ${usage.inputTokens} input, ${usage.outputTokens} output`
7208
- ].join("\n");
7319
+ const guardWasActive = subAgentGuard.active;
7320
+ subAgentGuard.active = true;
7321
+ try {
7322
+ if (singleTask) {
7323
+ const { content, usage } = await runSubAgent(singleTask, maxRounds, null, ctx);
7324
+ return [
7325
+ "## Sub-Agent Result",
7326
+ "",
7327
+ content,
7328
+ "",
7329
+ "---",
7330
+ `Token usage: ${usage.inputTokens} input, ${usage.outputTokens} output`
7331
+ ].join("\n");
7332
+ }
7333
+ console.log();
7334
+ console.log(theme.toolCall(`\u{1F916} Spawning ${tasksArr.length} sub-agents in parallel...`));
7335
+ const results = await Promise.all(
7336
+ tasksArr.map((t, i) => runSubAgent(t, maxRounds, i + 1, ctx))
7337
+ );
7338
+ const totalIn = results.reduce((s, r) => s + r.usage.inputTokens, 0);
7339
+ const totalOut = results.reduce((s, r) => s + r.usage.outputTokens, 0);
7340
+ const lines = [`## Parallel Sub-Agent Results (${results.length} agents)`, ""];
7341
+ results.forEach((r, i) => {
7342
+ lines.push(`### Sub-Agent #${i + 1}`);
7343
+ lines.push(`**Task**: ${tasksArr[i].slice(0, 200)}${tasksArr[i].length > 200 ? "..." : ""}`);
7344
+ lines.push("");
7345
+ lines.push(r.content);
7346
+ lines.push("");
7347
+ lines.push(`*Tokens: ${r.usage.inputTokens} in / ${r.usage.outputTokens} out*`);
7348
+ lines.push("");
7349
+ });
7350
+ lines.push("---");
7351
+ lines.push(`Total token usage: ${totalIn} input, ${totalOut} output`);
7352
+ return lines.join("\n");
7353
+ } finally {
7354
+ subAgentGuard.active = guardWasActive;
7209
7355
  }
7210
- console.log();
7211
- console.log(theme.toolCall(`\u{1F916} Spawning ${tasksArr.length} sub-agents in parallel...`));
7212
- const results = await Promise.all(
7213
- tasksArr.map((t, i) => runSubAgent(t, maxRounds, i + 1, ctx))
7214
- );
7215
- const totalIn = results.reduce((s, r) => s + r.usage.inputTokens, 0);
7216
- const totalOut = results.reduce((s, r) => s + r.usage.outputTokens, 0);
7217
- const lines = [`## Parallel Sub-Agent Results (${results.length} agents)`, ""];
7218
- results.forEach((r, i) => {
7219
- lines.push(`### Sub-Agent #${i + 1}`);
7220
- lines.push(`**Task**: ${tasksArr[i].slice(0, 200)}${tasksArr[i].length > 200 ? "..." : ""}`);
7221
- lines.push("");
7222
- lines.push(r.content);
7223
- lines.push("");
7224
- lines.push(`*Tokens: ${r.usage.inputTokens} in / ${r.usage.outputTokens} out*`);
7225
- lines.push("");
7226
- });
7227
- lines.push("---");
7228
- lines.push(`Total token usage: ${totalIn} input, ${totalOut} output`);
7229
- return lines.join("\n");
7230
7356
  }
7231
7357
  };
7232
7358
 
@@ -7691,7 +7817,7 @@ ${commitOutput.trim()}`;
7691
7817
  // src/tools/builtin/notebook-edit.ts
7692
7818
  import { readFileSync as readFileSync8, existsSync as existsSync13 } from "fs";
7693
7819
  import { writeFile } from "fs/promises";
7694
- import { resolve as resolve3, extname as extname2 } from "path";
7820
+ import { resolve as resolve4, extname as extname2 } from "path";
7695
7821
  var notebookEditTool = {
7696
7822
  definition: {
7697
7823
  name: "notebook_edit",
@@ -7740,7 +7866,7 @@ var notebookEditTool = {
7740
7866
  if (!Number.isInteger(cellIndexRaw) || cellIndexRaw < 1) {
7741
7867
  throw new ToolError("notebook_edit", "cell_index must be a positive integer (1-based)");
7742
7868
  }
7743
- const absPath = resolve3(filePath);
7869
+ const absPath = resolve4(filePath);
7744
7870
  if (extname2(absPath).toLowerCase() !== ".ipynb") {
7745
7871
  throw new ToolError("notebook_edit", "path must point to a .ipynb file");
7746
7872
  }
@@ -8512,7 +8638,7 @@ var McpClient = class {
8512
8638
  // 内部方法:JSON-RPC 通信
8513
8639
  // ══════════════════════════════════════════════════════════════════
8514
8640
  sendRequest(method, params) {
8515
- return new Promise((resolve6, reject) => {
8641
+ return new Promise((resolve7, reject) => {
8516
8642
  if (!this.process?.stdin?.writable) {
8517
8643
  return reject(new Error(`MCP server [${this.serverId}] stdin not writable`));
8518
8644
  }
@@ -8536,7 +8662,7 @@ var McpClient = class {
8536
8662
  this.pendingRequests.set(id, {
8537
8663
  resolve: (result) => {
8538
8664
  cleanup();
8539
- resolve6(result);
8665
+ resolve7(result);
8540
8666
  },
8541
8667
  reject: (error) => {
8542
8668
  cleanup();
@@ -8613,13 +8739,13 @@ var McpClient = class {
8613
8739
  }
8614
8740
  /** Promise 超时包装 */
8615
8741
  withTimeout(promise, ms, label) {
8616
- return new Promise((resolve6, reject) => {
8742
+ return new Promise((resolve7, reject) => {
8617
8743
  const timer = setTimeout(() => {
8618
8744
  reject(new Error(`MCP [${this.serverId}] ${label} timed out after ${ms}ms`));
8619
8745
  }, ms);
8620
8746
  promise.then((val) => {
8621
8747
  clearTimeout(timer);
8622
- resolve6(val);
8748
+ resolve7(val);
8623
8749
  }).catch((err) => {
8624
8750
  clearTimeout(timer);
8625
8751
  reject(err);
@@ -8892,7 +9018,7 @@ import { join as join9 } from "path";
8892
9018
 
8893
9019
  // src/skills/types.ts
8894
9020
  import { readFileSync as readFileSync9 } from "fs";
8895
- import { basename as basename4 } from "path";
9021
+ import { basename as basename5 } from "path";
8896
9022
  function parseSimpleYaml(yaml) {
8897
9023
  const result = {};
8898
9024
  for (const line of yaml.split("\n")) {
@@ -8921,7 +9047,7 @@ function parseSkillFile(filePath) {
8921
9047
  if (!frontmatterMatch) {
8922
9048
  return {
8923
9049
  meta: {
8924
- name: basename4(filePath, ".md"),
9050
+ name: basename5(filePath, ".md"),
8925
9051
  description: ""
8926
9052
  },
8927
9053
  content: raw.trim(),
@@ -8932,7 +9058,7 @@ function parseSkillFile(filePath) {
8932
9058
  const parsed = parseSimpleYaml(yaml);
8933
9059
  return {
8934
9060
  meta: {
8935
- name: parsed["name"] ?? basename4(filePath, ".md"),
9061
+ name: parsed["name"] ?? basename5(filePath, ".md"),
8936
9062
  description: parsed["description"] ?? "",
8937
9063
  tools: parsed["tools"] ? parseYamlArray(parsed["tools"]) : void 0
8938
9064
  },
@@ -9086,33 +9212,33 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
9086
9212
  }
9087
9213
  /** Resolve a pending confirm from client response */
9088
9214
  resolveConfirm(requestId, approved) {
9089
- const resolve6 = this.pendingConfirms.get(requestId);
9090
- if (resolve6) {
9215
+ const resolve7 = this.pendingConfirms.get(requestId);
9216
+ if (resolve7) {
9091
9217
  this.clearPendingTimer(requestId);
9092
9218
  this.pendingConfirms.delete(requestId);
9093
9219
  this.confirming = false;
9094
- resolve6(approved);
9220
+ resolve7(approved);
9095
9221
  }
9096
9222
  }
9097
9223
  /** Resolve a pending batch confirm from client response */
9098
9224
  resolveBatchConfirm(requestId, decision) {
9099
- const resolve6 = this.pendingBatchConfirms.get(requestId);
9100
- if (resolve6) {
9225
+ const resolve7 = this.pendingBatchConfirms.get(requestId);
9226
+ if (resolve7) {
9101
9227
  this.clearPendingTimer(requestId);
9102
9228
  this.pendingBatchConfirms.delete(requestId);
9103
9229
  this.confirming = false;
9104
9230
  if (decision === "all" || decision === "none") {
9105
- resolve6(decision);
9231
+ resolve7(decision);
9106
9232
  } else {
9107
- resolve6(new Set(decision));
9233
+ resolve7(new Set(decision));
9108
9234
  }
9109
9235
  }
9110
9236
  }
9111
9237
  /** Cancel all pending confirms (e.g., on disconnect) */
9112
9238
  cancelAll() {
9113
- for (const resolve6 of this.pendingConfirms.values()) resolve6(false);
9239
+ for (const resolve7 of this.pendingConfirms.values()) resolve7(false);
9114
9240
  this.pendingConfirms.clear();
9115
- for (const resolve6 of this.pendingBatchConfirms.values()) resolve6("none");
9241
+ for (const resolve7 of this.pendingBatchConfirms.values()) resolve7("none");
9116
9242
  this.pendingBatchConfirms.clear();
9117
9243
  this.confirming = false;
9118
9244
  }
@@ -9188,8 +9314,8 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
9188
9314
  diff: this.getDiffPreview(call)
9189
9315
  };
9190
9316
  this.send(msg);
9191
- return new Promise((resolve6) => {
9192
- this.pendingConfirms.set(requestId, resolve6);
9317
+ return new Promise((resolve7) => {
9318
+ this.pendingConfirms.set(requestId, resolve7);
9193
9319
  this.pendingTimers.set(requestId, setTimeout(() => {
9194
9320
  if (this.pendingConfirms.has(requestId)) {
9195
9321
  this.resolveConfirm(requestId, false);
@@ -9213,8 +9339,8 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
9213
9339
  files
9214
9340
  };
9215
9341
  this.send(msg);
9216
- return new Promise((resolve6) => {
9217
- this.pendingBatchConfirms.set(requestId, resolve6);
9342
+ return new Promise((resolve7) => {
9343
+ this.pendingBatchConfirms.set(requestId, resolve7);
9218
9344
  this.pendingTimers.set(requestId, setTimeout(() => {
9219
9345
  if (this.pendingBatchConfirms.has(requestId)) {
9220
9346
  this.resolveBatchConfirm(requestId, "none");
@@ -9365,9 +9491,9 @@ import { join as join11 } from "path";
9365
9491
  // src/repl/dev-state.ts
9366
9492
  import { existsSync as existsSync17, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync as unlinkSync3, mkdirSync as mkdirSync8 } from "fs";
9367
9493
  import { join as join10 } from "path";
9368
- import { homedir as homedir4 } from "os";
9494
+ import { homedir as homedir5 } from "os";
9369
9495
  function getDevStatePath() {
9370
- return join10(homedir4(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
9496
+ return join10(homedir5(), CONFIG_DIR_NAME, DEV_STATE_FILE_NAME);
9371
9497
  }
9372
9498
  function loadDevState() {
9373
9499
  const path3 = getDevStatePath();
@@ -9627,7 +9753,7 @@ function autoTrimSessionIfNeeded(session, sizeLimit = SESSION_SIZE_LIMIT) {
9627
9753
 
9628
9754
  // src/web/session-handler.ts
9629
9755
  import { existsSync as existsSync20, readFileSync as readFileSync13, appendFileSync as appendFileSync3, writeFileSync as writeFileSync8, mkdirSync as mkdirSync9, readdirSync as readdirSync9, statSync as statSync8, createWriteStream } from "fs";
9630
- import { join as join13, resolve as resolve4, dirname as dirname4 } from "path";
9756
+ import { join as join13, resolve as resolve5, dirname as dirname4 } from "path";
9631
9757
  import { execSync as execSync3 } from "child_process";
9632
9758
 
9633
9759
  // src/tools/git-context.ts
@@ -9861,10 +9987,10 @@ var SessionHandler = class _SessionHandler {
9861
9987
  return;
9862
9988
  }
9863
9989
  case "ask_user_response": {
9864
- const resolve6 = this.pendingAskUser.get(msg.requestId);
9865
- if (resolve6) {
9990
+ const resolve7 = this.pendingAskUser.get(msg.requestId);
9991
+ if (resolve7) {
9866
9992
  this.pendingAskUser.delete(msg.requestId);
9867
- resolve6(msg.answer);
9993
+ resolve7(msg.answer);
9868
9994
  }
9869
9995
  return;
9870
9996
  }
@@ -9875,10 +10001,10 @@ var SessionHandler = class _SessionHandler {
9875
10001
  case "memory_rebuild":
9876
10002
  return this.handleMemoryRebuild(Boolean(msg.full));
9877
10003
  case "auto_pause_response": {
9878
- const resolve6 = this.pendingAutoPause.get(msg.requestId);
9879
- if (resolve6) {
10004
+ const resolve7 = this.pendingAutoPause.get(msg.requestId);
10005
+ if (resolve7) {
9880
10006
  this.pendingAutoPause.delete(msg.requestId);
9881
- resolve6({ action: msg.action, message: msg.message });
10007
+ resolve7({ action: msg.action, message: msg.message });
9882
10008
  }
9883
10009
  return;
9884
10010
  }
@@ -9895,9 +10021,9 @@ var SessionHandler = class _SessionHandler {
9895
10021
  onDisconnect() {
9896
10022
  this.toolExecutor.cancelAll();
9897
10023
  if (this.abortController) this.abortController.abort();
9898
- for (const resolve6 of this.pendingAskUser.values()) resolve6(null);
10024
+ for (const resolve7 of this.pendingAskUser.values()) resolve7(null);
9899
10025
  this.pendingAskUser.clear();
9900
- for (const resolve6 of this.pendingAutoPause.values()) resolve6({ action: "stop" });
10026
+ for (const resolve7 of this.pendingAutoPause.values()) resolve7({ action: "stop" });
9901
10027
  this.pendingAutoPause.clear();
9902
10028
  this.saveIfNeeded();
9903
10029
  }
@@ -10281,8 +10407,9 @@ Details: ${errMsg.split("\n")[0]}
10281
10407
  const alreadyWrote = hadPreviousWriteToolCalls(extraMessages);
10282
10408
  if (hasWriteTools && !alreadyWrote && detectsHallucinatedFileOp(result.content) && round < maxToolRounds - 1) {
10283
10409
  this.send({ type: "info", message: "\u26A0 Hallucinated completion detected, forcing retry..." });
10410
+ const reasoningField = result.reasoningContent ? { reasoning_content: result.reasoningContent } : this.currentProvider === "deepseek" ? { reasoning_content: "" } : {};
10284
10411
  extraMessages.push(
10285
- { role: "assistant", content: result.content },
10412
+ { role: "assistant", content: result.content, ...reasoningField },
10286
10413
  { role: "user", content: HALLUCINATION_CORRECTION_MESSAGE }
10287
10414
  );
10288
10415
  continue;
@@ -10390,8 +10517,8 @@ ${systemPromptVolatile}` : systemPrompt;
10390
10517
  }
10391
10518
  const toolSummary = [...toolCounts.entries()].sort((a, b) => b[1] - a[1]).map(([name, count]) => count > 1 ? `${name}\xD7${count}` : name).join(", ");
10392
10519
  const requestId = `pause_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
10393
- const pauseResp = await new Promise((resolve6) => {
10394
- this.pendingAutoPause.set(requestId, resolve6);
10520
+ const pauseResp = await new Promise((resolve7) => {
10521
+ this.pendingAutoPause.set(requestId, resolve7);
10395
10522
  this.send({
10396
10523
  type: "auto_pause_request",
10397
10524
  requestId,
@@ -10526,8 +10653,8 @@ ${summaryResult.content}`,
10526
10653
  }
10527
10654
  if (chunk.done) break;
10528
10655
  }
10529
- await new Promise((resolve6, reject) => {
10530
- fileStream.end((err) => err ? reject(err) : resolve6());
10656
+ await new Promise((resolve7, reject) => {
10657
+ fileStream.end((err) => err ? reject(err) : resolve7());
10531
10658
  });
10532
10659
  const lines = fullContent.split("\n").length;
10533
10660
  const bytes = Buffer.byteLength(fullContent, "utf-8");
@@ -10542,7 +10669,7 @@ ${summaryResult.content}`,
10542
10669
  } catch (err) {
10543
10670
  if (fileStream) {
10544
10671
  try {
10545
- await new Promise((resolve6) => fileStream.end(() => resolve6()));
10672
+ await new Promise((resolve7) => fileStream.end(() => resolve7()));
10546
10673
  } catch {
10547
10674
  }
10548
10675
  }
@@ -11210,7 +11337,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11210
11337
  break;
11211
11338
  }
11212
11339
  const sub = args[0]?.toLowerCase();
11213
- const resolve6 = (ref) => {
11340
+ const resolve7 = (ref) => {
11214
11341
  const r = session.resolveBranchRef(ref);
11215
11342
  if (r.ok) return r.id;
11216
11343
  if (r.reason === "ambiguous") {
@@ -11264,7 +11391,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11264
11391
  this.send({ type: "error", message: "Usage: /branch switch <id|title>" });
11265
11392
  break;
11266
11393
  }
11267
- const id = resolve6(ref);
11394
+ const id = resolve7(ref);
11268
11395
  if (!id) break;
11269
11396
  const ok = session.switchBranch(id);
11270
11397
  if (ok) {
@@ -11284,7 +11411,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11284
11411
  this.send({ type: "error", message: "Usage: /branch delete <id|title>" });
11285
11412
  break;
11286
11413
  }
11287
- const id = resolve6(ref);
11414
+ const id = resolve7(ref);
11288
11415
  if (!id) break;
11289
11416
  const ok = session.deleteBranch(id);
11290
11417
  if (ok) {
@@ -11303,7 +11430,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11303
11430
  this.send({ type: "error", message: "Usage: /branch rename <id|title> <new title>" });
11304
11431
  break;
11305
11432
  }
11306
- const id = resolve6(ref);
11433
+ const id = resolve7(ref);
11307
11434
  if (!id) break;
11308
11435
  const ok = session.renameBranch(id, title);
11309
11436
  if (ok) {
@@ -11321,7 +11448,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11321
11448
  this.send({ type: "error", message: "Usage: /branch diff <id|title>" });
11322
11449
  break;
11323
11450
  }
11324
- const id = resolve6(ref);
11451
+ const id = resolve7(ref);
11325
11452
  if (!id) break;
11326
11453
  const d = session.diffBranches(id);
11327
11454
  if (!d) {
@@ -11363,7 +11490,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11363
11490
  this.send({ type: "error", message: "Usage: /branch cherry-pick <source-id|title> <msg-index>" });
11364
11491
  break;
11365
11492
  }
11366
- const id = resolve6(ref);
11493
+ const id = resolve7(ref);
11367
11494
  if (!id) break;
11368
11495
  const idx = parseInt(idxStr, 10);
11369
11496
  if (Number.isNaN(idx)) {
@@ -11389,9 +11516,9 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11389
11516
  case "index": {
11390
11517
  const sub = (args[0] ?? "status").toLowerCase();
11391
11518
  const root = process.cwd();
11392
- const { loadIndex: loadIndex2, clearIndex } = await import("./store-247B3TAU.js");
11393
- const { indexProject: indexProject2 } = await import("./indexer-O5FCGFBJ.js");
11394
- const { loadVectorStore, clearVectorStore } = await import("./vector-store-NDUFLNGN.js");
11519
+ const { loadIndex: loadIndex2, clearIndex } = await import("./store-Q7NMUCPP.js");
11520
+ const { indexProject: indexProject2 } = await import("./indexer-Z6AQTGBK.js");
11521
+ const { loadVectorStore, clearVectorStore } = await import("./vector-store-AK6J3RIA.js");
11395
11522
  if (sub === "status") {
11396
11523
  const idx = loadIndex2(root);
11397
11524
  const vec = loadVectorStore(root);
@@ -11440,7 +11567,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11440
11567
  message: `Building semantic index for ${idx.symbolCount} symbols\u2026 (first run downloads ~117 MB model)`
11441
11568
  });
11442
11569
  try {
11443
- const { rebuildSemanticIndex } = await import("./semantic-3KJPAUW6.js");
11570
+ const { rebuildSemanticIndex } = await import("./semantic-FR2ZSQLY.js");
11444
11571
  const stats = await rebuildSemanticIndex(root);
11445
11572
  const first = stats.modelFirstLoadMs ? ` (model load+first batch ${stats.modelFirstLoadMs}ms)` : "";
11446
11573
  this.send({
@@ -11588,7 +11715,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11588
11715
  if (rewindSub === "list" || !rewindSub) {
11589
11716
  const lines = [`Conversation messages (${session.messages.length} total):
11590
11717
  `];
11591
- const cpIndices = (await import("./file-checkpoint-CGH6OJVI.js")).fileCheckpoints.getMessageIndices();
11718
+ const cpIndices = (await import("./file-checkpoint-UHSMHCRU.js")).fileCheckpoints.getMessageIndices();
11592
11719
  for (let i = 0; i < session.messages.length; i++) {
11593
11720
  const m = session.messages[i];
11594
11721
  const text = getContentText(m.content).replace(/\n/g, " ").slice(0, 60);
@@ -11604,7 +11731,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11604
11731
  this.send({ type: "error", message: `Invalid message number: ${rewindSub}. Range: 1-${session.messages.length}` });
11605
11732
  break;
11606
11733
  }
11607
- const { fileCheckpoints: fc } = await import("./file-checkpoint-CGH6OJVI.js");
11734
+ const { fileCheckpoints: fc } = await import("./file-checkpoint-UHSMHCRU.js");
11608
11735
  const rewindRemoved = session.messages.length - rewindN;
11609
11736
  const rewindResult = fc.restoreToMessageIndex(rewindN);
11610
11737
  session.messages = session.messages.slice(0, rewindN);
@@ -11627,7 +11754,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
11627
11754
  case "test": {
11628
11755
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
11629
11756
  try {
11630
- const { executeTests } = await import("./run-tests-SN74WT4Z.js");
11757
+ const { executeTests } = await import("./run-tests-IMVI43CZ.js");
11631
11758
  const argStr = args.join(" ").trim();
11632
11759
  let testArgs = {};
11633
11760
  if (argStr) {
@@ -11812,7 +11939,7 @@ ${this.config.toFormattedJSON()}
11812
11939
  };
11813
11940
  checkLayer("Global", configDir);
11814
11941
  checkLayer("Project", projectRoot);
11815
- if (resolve4(cwd) !== resolve4(projectRoot)) {
11942
+ if (resolve5(cwd) !== resolve5(projectRoot)) {
11816
11943
  checkLayer("Subdir", cwd);
11817
11944
  }
11818
11945
  layers.push("");
@@ -11883,7 +12010,7 @@ Use /add-dir remove to clear.` : "No directories added.\nUsage: /add-dir <path>
11883
12010
  this.send({ type: "info", message: "\u2713 All added directories removed from context." });
11884
12011
  break;
11885
12012
  }
11886
- const dirPath = resolve4(sub);
12013
+ const dirPath = resolve5(sub);
11887
12014
  if (!existsSync20(dirPath)) {
11888
12015
  this.send({ type: "error", message: `Directory not found: ${dirPath}` });
11889
12016
  break;
@@ -12151,7 +12278,7 @@ Add .md files to create commands.` });
12151
12278
  return;
12152
12279
  }
12153
12280
  try {
12154
- const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-QKFH7ZP6.js");
12281
+ const { searchChatMemory: searchChatMemory2, loadChatIndex: loadChatIndex2 } = await import("./chat-index-ADG2GPCC.js");
12155
12282
  const loaded = loadChatIndex2();
12156
12283
  if (!loaded || loaded.idx.chunks.length === 0) {
12157
12284
  this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
@@ -12187,7 +12314,7 @@ Add .md files to create commands.` });
12187
12314
  }
12188
12315
  async handleMemoryStatus() {
12189
12316
  try {
12190
- const { getChatIndexStatus } = await import("./chat-index-QKFH7ZP6.js");
12317
+ const { getChatIndexStatus } = await import("./chat-index-ADG2GPCC.js");
12191
12318
  const s = getChatIndexStatus();
12192
12319
  this.send({
12193
12320
  type: "memory_status",
@@ -12212,7 +12339,7 @@ Add .md files to create commands.` });
12212
12339
  type: "info",
12213
12340
  message: full ? "\u{1F9E0} Rebuilding chat memory index (this may take a while on first run \u2014 ~117 MB embedder)." : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
12214
12341
  });
12215
- const { buildChatIndex } = await import("./chat-index-QKFH7ZP6.js");
12342
+ const { buildChatIndex } = await import("./chat-index-ADG2GPCC.js");
12216
12343
  const stats = await buildChatIndex({
12217
12344
  full,
12218
12345
  onProgress: (p) => {
@@ -12591,7 +12718,7 @@ If none found: "\u2705 No security vulnerabilities detected"`;
12591
12718
  const projectRoot = gitRoot ?? cwd;
12592
12719
  const projectCtx = this.findContextFile(projectRoot);
12593
12720
  if (projectCtx) parts.push(projectCtx);
12594
- if (resolve4(cwd) !== resolve4(projectRoot)) {
12721
+ if (resolve5(cwd) !== resolve5(projectRoot)) {
12595
12722
  const localCtx = this.findContextFile(cwd);
12596
12723
  if (localCtx) parts.push(localCtx);
12597
12724
  }
@@ -12831,7 +12958,7 @@ function getModuleDir() {
12831
12958
  }
12832
12959
  } catch {
12833
12960
  }
12834
- return resolve5(".");
12961
+ return resolve6(".");
12835
12962
  }
12836
12963
  async function startWebServer(options = {}) {
12837
12964
  const port = options.port ?? 3e3;
@@ -12860,7 +12987,18 @@ async function startWebServer(options = {}) {
12860
12987
  console.log(` Providers: ${availableProviders.map((p) => p.info.id).join(", ")}`);
12861
12988
  let mcpManager = null;
12862
12989
  const globalMcpServers = config.get("mcpServers") ?? {};
12863
- const projectMcpServers = loadProjectMcpConfig() ?? {};
12990
+ const projectMcpResolved = resolveProjectMcpPath();
12991
+ let projectMcpServers = {};
12992
+ if (projectMcpResolved) {
12993
+ const { checkTrust } = await import("./project-trust-EBGHD7LE.js");
12994
+ const verdict = checkTrust(config.getConfigDir(), projectMcpResolved);
12995
+ if (verdict.trusted) {
12996
+ projectMcpServers = loadProjectMcpConfig() ?? {};
12997
+ } else {
12998
+ console.log(` \u26A0 Project .mcp.json found at ${projectMcpResolved} but not trusted (${verdict.reason}).`);
12999
+ console.log(` Skipped to prevent unintended RCE. Run "aicli" then "/mcp trust-project" to approve.`);
13000
+ }
13001
+ }
12864
13002
  const mergedMcpServers = { ...globalMcpServers, ...projectMcpServers };
12865
13003
  if (Object.keys(mergedMcpServers).length > 0) {
12866
13004
  mcpManager = new McpManager();
@@ -12955,6 +13093,17 @@ async function startWebServer(options = {}) {
12955
13093
  });
12956
13094
  app.use(express.json());
12957
13095
  app.post("/api/auth/register", (req, res) => {
13096
+ const firstRun = !authManager.hasUsers();
13097
+ if (!firstRun) {
13098
+ const authHeader = req.headers.authorization;
13099
+ const token2 = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
13100
+ const cookieToken = parseCookie(req.headers.cookie ?? "")["aicli_token"];
13101
+ const effectiveToken = token2 ?? cookieToken;
13102
+ if (!effectiveToken || !authManager.verifyToken(effectiveToken)) {
13103
+ res.status(403).json({ error: "Registration is closed. Use `aicli user create` on the host to add users." });
13104
+ return;
13105
+ }
13106
+ }
12958
13107
  const { username, password } = req.body ?? {};
12959
13108
  if (!username || !password) {
12960
13109
  res.status(400).json({ error: "Username and password required" });
@@ -12966,7 +13115,7 @@ async function startWebServer(options = {}) {
12966
13115
  return;
12967
13116
  }
12968
13117
  const token = authManager.login(username, password);
12969
- console.log(` \u2713 User registered via API: ${username}`);
13118
+ console.log(` \u2713 User registered via API: ${username}${firstRun ? " (first-run)" : ""}`);
12970
13119
  res.cookie("aicli_token", token, { httpOnly: true, sameSite: "strict", maxAge: 7 * 24 * 3600 * 1e3 });
12971
13120
  res.json({ success: true, token, username });
12972
13121
  });
@@ -12975,9 +13124,9 @@ async function startWebServer(options = {}) {
12975
13124
  const prefix = req.query.prefix || "";
12976
13125
  const targetDir = join15(cwd, prefix);
12977
13126
  try {
12978
- const canonicalTarget = realpathSync(resolve5(targetDir));
12979
- const canonicalCwd = realpathSync(resolve5(cwd));
12980
- if (!canonicalTarget.startsWith(canonicalCwd + sep2) && canonicalTarget !== canonicalCwd) {
13127
+ const canonicalTarget = realpathSync(resolve6(targetDir));
13128
+ const canonicalCwd = realpathSync(resolve6(cwd));
13129
+ if (!canonicalTarget.startsWith(canonicalCwd + sep3) && canonicalTarget !== canonicalCwd) {
12981
13130
  res.json({ files: [] });
12982
13131
  return;
12983
13132
  }
@@ -13034,7 +13183,7 @@ async function startWebServer(options = {}) {
13034
13183
  try {
13035
13184
  const canonicalFile = realpathSync(filePath);
13036
13185
  const canonicalDir = realpathSync(histDir);
13037
- if (!canonicalFile.startsWith(canonicalDir + sep2)) {
13186
+ if (!canonicalFile.startsWith(canonicalDir + sep3)) {
13038
13187
  res.status(404).json({ error: "Session not found" });
13039
13188
  return;
13040
13189
  }
@@ -13055,11 +13204,11 @@ async function startWebServer(options = {}) {
13055
13204
  return;
13056
13205
  }
13057
13206
  const cwd = process.cwd();
13058
- const fullPath = resolve5(join15(cwd, filePath));
13207
+ const fullPath = resolve6(join15(cwd, filePath));
13059
13208
  try {
13060
13209
  const canonicalFull = realpathSync(fullPath);
13061
- const canonicalCwd = realpathSync(resolve5(cwd));
13062
- if (!canonicalFull.startsWith(canonicalCwd + sep2) && canonicalFull !== canonicalCwd) {
13210
+ const canonicalCwd = realpathSync(resolve6(cwd));
13211
+ if (!canonicalFull.startsWith(canonicalCwd + sep3) && canonicalFull !== canonicalCwd) {
13063
13212
  res.json({ error: "Access denied" });
13064
13213
  return;
13065
13214
  }
@@ -13193,6 +13342,10 @@ async function startWebServer(options = {}) {
13193
13342
  if (parsed.type === "auth") {
13194
13343
  const { action, username, password } = parsed;
13195
13344
  if (action === "register") {
13345
+ if (authManager.hasUsers() && !authenticatedUser) {
13346
+ ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Registration is closed. Use `aicli user create` on the host to add users." }));
13347
+ return;
13348
+ }
13196
13349
  const err = authManager.register(username, password);
13197
13350
  if (err) {
13198
13351
  ws.send(JSON.stringify({ type: "auth_result", success: false, error: err }));
@@ -13272,7 +13425,7 @@ async function startWebServer(options = {}) {
13272
13425
  });
13273
13426
  const MAX_PORT_ATTEMPTS = 10;
13274
13427
  let actualPort = port;
13275
- const result = await new Promise((resolve6, reject) => {
13428
+ const result = await new Promise((resolve7, reject) => {
13276
13429
  const tryListen = (attempt) => {
13277
13430
  server.once("error", (err) => {
13278
13431
  if (err.code === "EADDRINUSE" && attempt < MAX_PORT_ATTEMPTS) {
@@ -13303,7 +13456,7 @@ async function startWebServer(options = {}) {
13303
13456
  }
13304
13457
  console.log(` Press Ctrl+C to stop
13305
13458
  `);
13306
- resolve6({ port: actualPort, host, url });
13459
+ resolve7({ port: actualPort, host, url });
13307
13460
  });
13308
13461
  };
13309
13462
  tryListen(1);
@@ -13319,6 +13472,13 @@ async function startWebServer(options = {}) {
13319
13472
  });
13320
13473
  return result;
13321
13474
  }
13475
+ function resolveProjectMcpPath() {
13476
+ const cwd = process.cwd();
13477
+ const gitRoot = getGitRoot(cwd);
13478
+ const projectRoot = gitRoot ?? cwd;
13479
+ const configPath = join15(projectRoot, MCP_PROJECT_CONFIG_NAME);
13480
+ return existsSync22(configPath) ? configPath : null;
13481
+ }
13322
13482
  function loadProjectMcpConfig() {
13323
13483
  const cwd = process.cwd();
13324
13484
  const gitRoot = getGitRoot(cwd);