jinzd-ai-cli 0.4.208 → 0.4.210

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 (28) hide show
  1. package/README.md +10 -8
  2. package/README.zh-CN.md +5 -5
  3. package/dist/{batch-3T44NFLG.js → batch-MFPYHOIL.js} +4 -4
  4. package/dist/{chunk-TD7JEHCR.js → chunk-7JWT3KXO.js} +390 -23
  5. package/dist/{chunk-SQB66GP6.js → chunk-BNERFXVO.js} +12 -9
  6. package/dist/{chunk-J22B3OSQ.js → chunk-DJ35G5VO.js} +1 -1
  7. package/dist/{chunk-VWYUB22Y.js → chunk-E2ZWWE6Q.js} +1 -1
  8. package/dist/{chunk-KV4GYNEA.js → chunk-GRJNQJA5.js} +5 -3
  9. package/dist/{chunk-QDY72ABW.js → chunk-HZQVX7VF.js} +5 -3
  10. package/dist/{chunk-O6UFCEUZ.js → chunk-K3CF65QH.js} +12 -9
  11. package/dist/{chunk-2OVMMSGQ.js → chunk-NEPFADHX.js} +10 -9
  12. package/dist/{chunk-P7JY3SWA.js → chunk-NWP7C6CC.js} +1 -1
  13. package/dist/{chunk-TM4MS63K.js → chunk-P6MTFCXB.js} +14 -6
  14. package/dist/{ci-6QWBVRJX.js → ci-QLJUDLMY.js} +3 -2
  15. package/dist/{constants-SZTQNN7K.js → constants-47OR72MV.js} +3 -1
  16. package/dist/{doctor-cli-I2Y2YR4V.js → doctor-cli-32COMA5K.js} +4 -4
  17. package/dist/electron-server.js +652 -457
  18. package/dist/{hub-XVPFBODB.js → hub-3NWJUCLK.js} +1 -1
  19. package/dist/index.js +128 -376
  20. package/dist/{indexer-AKWMYNJI.js → indexer-2AG4G6B5.js} +1 -1
  21. package/dist/{indexer-BMYUUDLH.js → indexer-4WWS3VIL.js} +1 -1
  22. package/dist/{run-tests-HZ2CRCTZ.js → run-tests-NT2UIUVB.js} +1 -1
  23. package/dist/{run-tests-D5SNUBYX.js → run-tests-UT7RZ7Y3.js} +2 -2
  24. package/dist/{server-PVKLPRUP.js → server-AIHVMLNU.js} +5 -5
  25. package/dist/{server-4EFTRFTN.js → server-E5D54DIZ.js} +87 -306
  26. package/dist/{task-orchestrator-2A5VCFLS.js → task-orchestrator-BFDSTSOH.js} +5 -5
  27. package/dist/{usage-Q24E5636.js → usage-P4B2RZKL.js} +2 -2
  28. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -1,21 +1,25 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- buildReviewPrompt,
4
- buildSecurityReviewPrompt
5
- } from "./chunk-HLWUDRBO.js";
6
2
  import {
7
3
  McpManager,
8
4
  SNAPSHOT_PROMPT,
9
5
  SkillManager,
10
6
  autoTrimSessionIfNeeded,
7
+ buildInitPrompt,
11
8
  clearDevState,
9
+ loadContextFiles,
12
10
  loadDevState,
13
11
  parseSimpleYaml,
14
12
  persistToolRound,
13
+ readGitDiff,
15
14
  saveDevState,
15
+ scanProject,
16
16
  sessionHasMeaningfulContent,
17
17
  setupProxy
18
- } from "./chunk-TD7JEHCR.js";
18
+ } from "./chunk-7JWT3KXO.js";
19
+ import {
20
+ buildReviewPrompt,
21
+ buildSecurityReviewPrompt
22
+ } from "./chunk-HLWUDRBO.js";
19
23
  import {
20
24
  ToolExecutor,
21
25
  ToolRegistry,
@@ -35,10 +39,10 @@ import {
35
39
  spawnAgentContext,
36
40
  theme,
37
41
  undoStack
38
- } from "./chunk-2OVMMSGQ.js";
42
+ } from "./chunk-NEPFADHX.js";
39
43
  import "./chunk-T2NL5ZIA.js";
40
44
  import "./chunk-BXP6YZ2P.js";
41
- import "./chunk-VWYUB22Y.js";
45
+ import "./chunk-E2ZWWE6Q.js";
42
46
  import {
43
47
  SessionManager,
44
48
  getContentText
@@ -55,7 +59,7 @@ import {
55
59
  getConfigDirUsage,
56
60
  listRecentCrashes,
57
61
  writeCrashLog
58
- } from "./chunk-P7JY3SWA.js";
62
+ } from "./chunk-NWP7C6CC.js";
59
63
  import {
60
64
  ProviderRegistry
61
65
  } from "./chunk-QMXC327F.js";
@@ -64,7 +68,7 @@ import {
64
68
  getTopFailingTools,
65
69
  getTopUsedTools,
66
70
  installFlushOnExit
67
- } from "./chunk-J22B3OSQ.js";
71
+ } from "./chunk-DJ35G5VO.js";
68
72
  import {
69
73
  CONTENT_ONLY_STREAM_REMINDER,
70
74
  TEE_FINAL_USER_NUDGE,
@@ -86,7 +90,7 @@ import {
86
90
  } from "./chunk-XPBEJB27.js";
87
91
  import {
88
92
  ConfigManager
89
- } from "./chunk-TM4MS63K.js";
93
+ } from "./chunk-P6MTFCXB.js";
90
94
  import {
91
95
  AuthError,
92
96
  ProviderError,
@@ -97,7 +101,6 @@ import {
97
101
  AUTHOR,
98
102
  AUTHOR_EMAIL,
99
103
  CONFIG_DIR_NAME,
100
- CONTEXT_FILE_CANDIDATES,
101
104
  CONTEXT_PRESSURE_THRESHOLD,
102
105
  CUSTOM_COMMANDS_DIR_NAME,
103
106
  DEFAULT_MAX_TOKENS,
@@ -113,7 +116,7 @@ import {
113
116
  SKILLS_DIR_NAME,
114
117
  VERSION,
115
118
  buildUserIdentityPrompt
116
- } from "./chunk-KV4GYNEA.js";
119
+ } from "./chunk-GRJNQJA5.js";
117
120
  import {
118
121
  formatGitContextForPrompt,
119
122
  getGitContext,
@@ -133,7 +136,7 @@ import {
133
136
  DEFAULT_PATTERNS,
134
137
  scanString
135
138
  } from "./chunk-SLSWPBK3.js";
136
- import "./chunk-O6UFCEUZ.js";
139
+ import "./chunk-K3CF65QH.js";
137
140
  import "./chunk-CKH4KQ4E.js";
138
141
  import {
139
142
  atomicWriteFileSync
@@ -144,8 +147,8 @@ import { program } from "commander";
144
147
 
145
148
  // src/repl/repl.ts
146
149
  import * as readline from "readline";
147
- import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync4, mkdirSync as mkdirSync4 } from "fs";
148
- import { join as join5, resolve as resolve2, extname as extname2, dirname as dirname3, basename as basename2 } from "path";
150
+ import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync3, mkdirSync as mkdirSync4 } from "fs";
151
+ import { join as join4, resolve as resolve2, extname as extname2, dirname as dirname3, basename as basename2 } from "path";
149
152
  import chalk4 from "chalk";
150
153
 
151
154
  // src/session/title-generator.ts
@@ -637,10 +640,10 @@ Error${typeName}: ${lines.join("\n")}
637
640
  };
638
641
 
639
642
  // src/repl/commands/index.ts
640
- import { writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync3, readFileSync as readFileSync2, statSync as statSync3, appendFileSync } from "fs";
643
+ import { writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync2, readFileSync, statSync as statSync2 } from "fs";
641
644
  import { execSync as execSync2 } from "child_process";
642
645
  import { platform } from "os";
643
- import { resolve, dirname as dirname2, join as join3, basename } from "path";
646
+ import { resolve, dirname as dirname2, join as join2, basename } from "path";
644
647
  import chalk2 from "chalk";
645
648
 
646
649
  // src/repl/clipboard.ts
@@ -730,195 +733,6 @@ function getClipboardHint() {
730
733
  return "";
731
734
  }
732
735
 
733
- // src/repl/commands/project-init.ts
734
- import { existsSync as existsSync2, readFileSync, readdirSync, statSync as statSync2 } from "fs";
735
- import { join as join2 } from "path";
736
- var SCAN_SKIP_DIRS = /* @__PURE__ */ new Set([
737
- "node_modules",
738
- ".git",
739
- "dist",
740
- "build",
741
- "out",
742
- "target",
743
- ".next",
744
- ".nuxt",
745
- "__pycache__",
746
- ".venv",
747
- "venv",
748
- ".tox",
749
- ".mypy_cache",
750
- ".pytest_cache",
751
- ".gradle",
752
- ".idea",
753
- ".vscode",
754
- ".vs",
755
- "coverage",
756
- ".cache",
757
- ".parcel-cache",
758
- "dist-cjs",
759
- "release",
760
- ".output",
761
- ".turbo",
762
- "vendor"
763
- ]);
764
- function scanDirTree(dir, maxDepth = 2, maxEntries = 80) {
765
- const lines = [];
766
- let count = 0;
767
- const walk = (d, prefix, depth) => {
768
- if (depth > maxDepth || count >= maxEntries) return;
769
- let entries;
770
- try {
771
- entries = readdirSync(d);
772
- } catch {
773
- return;
774
- }
775
- const filtered = entries.filter((e) => !e.startsWith(".") && !SCAN_SKIP_DIRS.has(e));
776
- const sorted = filtered.sort((a, b) => {
777
- let aIsDir = false, bIsDir = false;
778
- try {
779
- aIsDir = statSync2(join2(d, a)).isDirectory();
780
- } catch {
781
- }
782
- try {
783
- bIsDir = statSync2(join2(d, b)).isDirectory();
784
- } catch {
785
- }
786
- if (aIsDir !== bIsDir) return aIsDir ? -1 : 1;
787
- return a.localeCompare(b);
788
- });
789
- for (let i = 0; i < sorted.length && count < maxEntries; i++) {
790
- const name = sorted[i];
791
- const fullPath = join2(d, name);
792
- const isLast = i === sorted.length - 1;
793
- const connector = isLast ? "+-- " : "|-- ";
794
- let isDir;
795
- try {
796
- isDir = statSync2(fullPath).isDirectory();
797
- } catch {
798
- continue;
799
- }
800
- lines.push(prefix + connector + name + (isDir ? "/" : ""));
801
- count++;
802
- if (isDir) {
803
- walk(fullPath, prefix + (isLast ? " " : "| "), depth + 1);
804
- }
805
- }
806
- };
807
- walk(dir, "", 0);
808
- if (count >= maxEntries) lines.push("... (truncated)");
809
- return lines.join("\n");
810
- }
811
- function scanProject(cwd) {
812
- const info = {
813
- type: "unknown",
814
- language: "unknown",
815
- configFiles: [],
816
- directoryStructure: ""
817
- };
818
- const check = (file) => existsSync2(join2(cwd, file));
819
- const configCandidates = [
820
- "package.json",
821
- "tsconfig.json",
822
- "Cargo.toml",
823
- "pyproject.toml",
824
- "setup.py",
825
- "requirements.txt",
826
- "go.mod",
827
- "pom.xml",
828
- "build.gradle",
829
- "build.gradle.kts",
830
- "CMakeLists.txt",
831
- "Makefile",
832
- ".csproj",
833
- ".sln",
834
- "composer.json",
835
- "Gemfile",
836
- "mix.exs",
837
- "deno.json",
838
- "bun.lockb"
839
- ];
840
- info.configFiles = configCandidates.filter(check);
841
- if (check("package.json")) {
842
- info.type = "node";
843
- info.language = check("tsconfig.json") ? "TypeScript" : "JavaScript";
844
- try {
845
- const pkg = JSON.parse(readFileSync(join2(cwd, "package.json"), "utf-8"));
846
- const scripts = pkg.scripts ?? {};
847
- info.buildCommand = scripts.build ? "npm run build" : void 0;
848
- info.testCommand = scripts.test ? "npm test" : void 0;
849
- info.devCommand = scripts.dev ? "npm run dev" : void 0;
850
- const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
851
- if (allDeps["react"]) info.framework = "React";
852
- else if (allDeps["vue"]) info.framework = "Vue";
853
- else if (allDeps["@angular/core"]) info.framework = "Angular";
854
- else if (allDeps["next"]) info.framework = "Next.js";
855
- else if (allDeps["nuxt"]) info.framework = "Nuxt";
856
- else if (allDeps["express"]) info.framework = "Express";
857
- else if (allDeps["fastify"]) info.framework = "Fastify";
858
- else if (allDeps["svelte"]) info.framework = "Svelte";
859
- } catch {
860
- }
861
- } else if (check("Cargo.toml")) {
862
- info.type = "rust";
863
- info.language = "Rust";
864
- info.buildCommand = "cargo build";
865
- info.testCommand = "cargo test";
866
- } else if (check("pyproject.toml") || check("setup.py") || check("requirements.txt")) {
867
- info.type = "python";
868
- info.language = "Python";
869
- info.testCommand = check("pytest.ini") || check("pyproject.toml") ? "pytest" : "python -m unittest";
870
- } else if (check("go.mod")) {
871
- info.type = "go";
872
- info.language = "Go";
873
- info.buildCommand = "go build ./...";
874
- info.testCommand = "go test ./...";
875
- } else if (check("pom.xml")) {
876
- info.type = "java";
877
- info.language = "Java";
878
- info.buildCommand = "mvn package";
879
- info.testCommand = "mvn test";
880
- } else if (check("build.gradle") || check("build.gradle.kts")) {
881
- info.type = "java";
882
- info.language = "Java/Kotlin";
883
- info.buildCommand = "./gradlew build";
884
- info.testCommand = "./gradlew test";
885
- }
886
- info.directoryStructure = scanDirTree(cwd);
887
- return info;
888
- }
889
- function buildInitPrompt(info, cwd) {
890
- const parts = [
891
- "Please generate an AICLI.md context file (Markdown format) for the following project. This file will be injected into the AI conversation system prompt to help the AI understand the project structure and coding conventions.",
892
- "\n## Project Info\n",
893
- `- Working directory: ${cwd}`,
894
- `- Type: ${info.type}`,
895
- `- Language: ${info.language}`
896
- ];
897
- if (info.framework) parts.push(`- Framework: ${info.framework}`);
898
- if (info.buildCommand) parts.push(`- Build command: ${info.buildCommand}`);
899
- if (info.testCommand) parts.push(`- Test command: ${info.testCommand}`);
900
- if (info.devCommand) parts.push(`- Dev command: ${info.devCommand}`);
901
- parts.push(`
902
- ## Detected Config Files
903
- ${info.configFiles.map((f) => `- ${f}`).join("\n")}`);
904
- parts.push(`
905
- ## Directory Structure
906
- \`\`\`
907
- ${info.directoryStructure}
908
- \`\`\``);
909
- parts.push(`
910
- ## Requirements
911
- Please generate a structured Markdown file containing:
912
- 1. Project overview (one-sentence summary)
913
- 2. Tech stack
914
- 3. Project structure description (based on the directory structure above)
915
- 4. Common commands (build, test, dev, etc.)
916
- 5. Code style and conventions (inferred from config files)
917
-
918
- Output the Markdown content directly, do not wrap the entire file in a code block. Keep it concise, within 200 lines.`);
919
- return parts.join("\n");
920
- }
921
-
922
736
  // src/repl/commands/index.ts
923
737
  function fmtCtx(tokens) {
924
738
  if (tokens >= 1e6) return `${Math.round(tokens / 1e5) / 10}M`;
@@ -1488,7 +1302,7 @@ No commands match "${filter}".
1488
1302
  {
1489
1303
  name: "context",
1490
1304
  description: "Show or reload hierarchical context files",
1491
- usage: "/context [reload]",
1305
+ usage: "/context [status|reload]",
1492
1306
  execute(args, ctx) {
1493
1307
  const sub = args[0];
1494
1308
  if (sub === "reload") {
@@ -1498,7 +1312,7 @@ No commands match "${filter}".
1498
1312
  const summary = layers2.map((l) => `${l.level}:${l.charCount}`).join(", ");
1499
1313
  ctx.renderer.printSuccess(`Context reloaded: ${layers2.length} layer(s) (${summary} chars)`);
1500
1314
  } else {
1501
- ctx.renderer.printInfo("No context file found. Place AICLI.md or CLAUDE.md in your project root or ~/.aicli/.");
1315
+ ctx.renderer.printInfo("No context file found. Place AICLI.md, CLAUDE.md, or AGENTS.md in your project root or ~/.aicli/.");
1502
1316
  }
1503
1317
  return;
1504
1318
  }
@@ -1508,16 +1322,16 @@ No commands match "${filter}".
1508
1322
  console.log(" Context layers:");
1509
1323
  const levelLabels = { global: "Global ", project: "Project", local: "Local " };
1510
1324
  for (const l of layers) {
1511
- console.log(` ${levelLabels[l.level] ?? l.level} : ${l.filePath} (${l.charCount} chars)`);
1325
+ console.log(` ${levelLabels[l.level] ?? l.level} : ${l.displayPath ?? l.filePath} (${l.charCount} chars${l.truncated ? ", truncated" : ""})`);
1512
1326
  }
1513
1327
  const totalChars = layers.reduce((s, l) => s + l.charCount, 0);
1514
1328
  console.log(` Total : ${totalChars} chars (${layers.length} layer${layers.length > 1 ? "s" : ""})`);
1515
1329
  } else {
1516
1330
  console.log(" No context files loaded.");
1517
1331
  console.log(" Hierarchical context search order:");
1518
- console.log(" 1. Global : ~/.aicli/AICLI.md (or CLAUDE.md)");
1519
- console.log(" 2. Project : <git-root>/AICLI.md");
1520
- console.log(" 3. Local : <cwd>/AICLI.md (when cwd \u2260 project root)");
1332
+ console.log(" 1. Global : ~/.aicli/AICLI.override.md, AGENTS.override.md, AICLI.md, CLAUDE.md, or AGENTS.md");
1333
+ console.log(" 2. Project : <git-root>/same candidate order");
1334
+ console.log(" 3. Local : <cwd>/same candidate order (when cwd \u2260 project root)");
1521
1335
  }
1522
1336
  console.log();
1523
1337
  }
@@ -1829,16 +1643,16 @@ No tools match "${filter}".
1829
1643
  usage: "/mcp [reconnect [serverId] | trust-project]",
1830
1644
  async execute(args, ctx) {
1831
1645
  if (args[0] === "trust-project") {
1832
- const { join: join6 } = await import("path");
1833
- const { existsSync: existsSync6 } = await import("fs");
1646
+ const { join: join5 } = await import("path");
1647
+ const { existsSync: existsSync5 } = await import("fs");
1834
1648
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1835
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-SZTQNN7K.js");
1649
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-47OR72MV.js");
1836
1650
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1837
1651
  const cwd = process.cwd();
1838
1652
  const projectRoot = getGitRoot2(cwd) ?? cwd;
1839
- const mcpPath = join6(projectRoot, MCP_PROJECT_CONFIG_NAME2);
1653
+ const mcpPath = join5(projectRoot, MCP_PROJECT_CONFIG_NAME2);
1840
1654
  console.log();
1841
- if (!existsSync6(mcpPath)) {
1655
+ if (!existsSync5(mcpPath)) {
1842
1656
  console.log(theme.dim(` No .mcp.json in ${projectRoot}.`));
1843
1657
  console.log();
1844
1658
  return;
@@ -2171,9 +1985,9 @@ No tools match "${filter}".
2171
1985
  usage: "/init [--force]",
2172
1986
  async execute(args, ctx) {
2173
1987
  const cwd = process.cwd();
2174
- const targetPath = join3(cwd, "AICLI.md");
1988
+ const targetPath = join2(cwd, "AICLI.md");
2175
1989
  const force = args.includes("--force");
2176
- if (existsSync3(targetPath) && !force) {
1990
+ if (existsSync2(targetPath) && !force) {
2177
1991
  ctx.renderer.printInfo(`AICLI.md already exists at ${targetPath}`);
2178
1992
  ctx.renderer.printInfo("Use /init --force to overwrite, or edit it manually.");
2179
1993
  return;
@@ -2416,8 +2230,7 @@ ${hint}` : "")
2416
2230
  const detailed = args.includes("--detailed");
2417
2231
  let diff;
2418
2232
  try {
2419
- const cmd = staged ? "git diff --staged" : "git diff";
2420
- diff = execSync2(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
2233
+ diff = readGitDiff({ staged });
2421
2234
  } catch {
2422
2235
  ctx.renderer.renderError("Failed to run git diff.");
2423
2236
  return;
@@ -2463,8 +2276,7 @@ ${hint}` : "")
2463
2276
  const staged = args.includes("--staged");
2464
2277
  let diff;
2465
2278
  try {
2466
- const cmd = staged ? "git diff --staged" : "git diff";
2467
- diff = execSync2(cmd, { encoding: "utf-8", timeout: 1e4 }).trim();
2279
+ diff = readGitDiff({ staged });
2468
2280
  } catch {
2469
2281
  ctx.renderer.renderError("Failed to run git diff.");
2470
2282
  return;
@@ -2767,7 +2579,7 @@ ${hint}` : "")
2767
2579
  const sub = (args[0] ?? "status").toLowerCase();
2768
2580
  const root = process.cwd();
2769
2581
  const { loadIndex, clearIndex } = await import("./store-MWNHVGJT.js");
2770
- const { indexProject } = await import("./indexer-AKWMYNJI.js");
2582
+ const { indexProject } = await import("./indexer-2AG4G6B5.js");
2771
2583
  const { loadVectorStore, clearVectorStore } = await import("./vector-store-BBDXB5IQ.js");
2772
2584
  if (sub === "status") {
2773
2585
  const idx = loadIndex(root);
@@ -2893,7 +2705,7 @@ ${hint}` : "")
2893
2705
  usage: "/test [command|filter]",
2894
2706
  async execute(args, ctx) {
2895
2707
  try {
2896
- const { executeTests } = await import("./run-tests-D5SNUBYX.js");
2708
+ const { executeTests } = await import("./run-tests-UT7RZ7Y3.js");
2897
2709
  const argStr = args.join(" ").trim();
2898
2710
  let testArgs = {};
2899
2711
  if (argStr) {
@@ -3051,7 +2863,7 @@ ${hint}` : "")
3051
2863
  description: "Persistent memory (memory.md) + chat memory recall index (v0.4.89+)",
3052
2864
  usage: "/memory [show|add <text>|clear|path|rebuild|refresh|status|recall <query>|index-clear]",
3053
2865
  async execute(args, ctx) {
3054
- const memoryFile = join3(ctx.config.getConfigDir(), MEMORY_FILE_NAME);
2866
+ const memoryFile = join2(ctx.config.getConfigDir(), MEMORY_FILE_NAME);
3055
2867
  const sub = args[0] ?? "show";
3056
2868
  if (sub === "rebuild" || sub === "refresh") {
3057
2869
  const full = sub === "rebuild";
@@ -3135,11 +2947,11 @@ ${hint}` : "")
3135
2947
  return;
3136
2948
  }
3137
2949
  if (sub === "show" || sub === "view") {
3138
- if (!existsSync3(memoryFile)) {
2950
+ if (!existsSync2(memoryFile)) {
3139
2951
  ctx.renderer.printInfo("Memory is empty (memory.md not found)");
3140
2952
  return;
3141
2953
  }
3142
- const content = readFileSync2(memoryFile, "utf-8").trim();
2954
+ const content = readFileSync(memoryFile, "utf-8").trim();
3143
2955
  if (!content) {
3144
2956
  ctx.renderer.printInfo("Memory is empty");
3145
2957
  return;
@@ -3164,18 +2976,19 @@ ${text}
3164
2976
  `;
3165
2977
  try {
3166
2978
  mkdirSync2(dirname2(memoryFile), { recursive: true });
3167
- appendFileSync(memoryFile, entry, "utf-8");
2979
+ const previous = existsSync2(memoryFile) ? readFileSync(memoryFile, "utf-8") : "";
2980
+ atomicWriteFileSync(memoryFile, previous + entry);
3168
2981
  ctx.renderer.printSuccess(`Added to memory: "${text.slice(0, 60)}${text.length > 60 ? "\u2026" : ""}"`);
3169
2982
  } catch (err) {
3170
2983
  ctx.renderer.renderError(`Failed to write memory: ${err instanceof Error ? err.message : String(err)}`);
3171
2984
  }
3172
2985
  } else if (sub === "clear") {
3173
- if (!existsSync3(memoryFile)) {
2986
+ if (!existsSync2(memoryFile)) {
3174
2987
  ctx.renderer.printInfo("Memory is already empty");
3175
2988
  return;
3176
2989
  }
3177
2990
  try {
3178
- writeFileSync(memoryFile, "", "utf-8");
2991
+ atomicWriteFileSync(memoryFile, "");
3179
2992
  ctx.renderer.printSuccess("Memory cleared (memory.md emptied)");
3180
2993
  } catch (err) {
3181
2994
  ctx.renderer.renderError(`Failed to clear memory: ${err instanceof Error ? err.message : String(err)}`);
@@ -3206,20 +3019,20 @@ ${text}
3206
3019
  console.log(theme.heading("Config Files:"));
3207
3020
  console.log(` Dir: ${theme.accent(configDir)}`);
3208
3021
  const checkFile = (label, filePath) => {
3209
- const exists = existsSync3(filePath);
3022
+ const exists = existsSync2(filePath);
3210
3023
  const icon = exists ? theme.success("\u2713") : theme.dim("\u2013");
3211
3024
  let extra = "";
3212
3025
  if (exists) {
3213
3026
  try {
3214
- extra = theme.dim(` (${statSync3(filePath).size} bytes)`);
3027
+ extra = theme.dim(` (${statSync2(filePath).size} bytes)`);
3215
3028
  } catch {
3216
3029
  }
3217
3030
  }
3218
3031
  console.log(` ${icon} ${label.padEnd(14)} ${exists ? filePath : theme.dim("(not found)")}${extra}`);
3219
3032
  };
3220
- checkFile("config.json", join3(configDir, "config.json"));
3221
- checkFile("memory.md", join3(configDir, MEMORY_FILE_NAME));
3222
- checkFile("dev-state.md", join3(configDir, "dev-state.md"));
3033
+ checkFile("config.json", join2(configDir, "config.json"));
3034
+ checkFile("memory.md", join2(configDir, MEMORY_FILE_NAME));
3035
+ checkFile("dev-state.md", join2(configDir, "dev-state.md"));
3223
3036
  console.log();
3224
3037
  const mcpManager = ctx.getMcpManager();
3225
3038
  if (mcpManager) {
@@ -3383,9 +3196,9 @@ ${text}
3383
3196
  let newFiles = 0;
3384
3197
  let modifiedFiles = 0;
3385
3198
  for (const [filePath, { earliest }] of fileMap) {
3386
- const currentContent = existsSync3(filePath) ? (() => {
3199
+ const currentContent = existsSync2(filePath) ? (() => {
3387
3200
  try {
3388
- return readFileSync2(filePath, "utf-8");
3201
+ return readFileSync(filePath, "utf-8");
3389
3202
  } catch {
3390
3203
  return null;
3391
3204
  }
@@ -3511,12 +3324,12 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
3511
3324
  if (scanAll) {
3512
3325
  const metas = ctx.sessions.listSessions();
3513
3326
  console.log(theme.info(` Scanning ${metas.length} session(s)\u2026`));
3514
- const { readFileSync: readFileSync5 } = await import("fs");
3515
- const { join: join6 } = await import("path");
3327
+ const { readFileSync: readFileSync4 } = await import("fs");
3328
+ const { join: join5 } = await import("path");
3516
3329
  const historyDir = ctx.config.getHistoryDir();
3517
3330
  for (const m of metas) {
3518
3331
  try {
3519
- const content = readFileSync5(join6(historyDir, `${m.id}.json`), "utf-8");
3332
+ const content = readFileSync4(join5(historyDir, `${m.id}.json`), "utf-8");
3520
3333
  const hits2 = scanString(content, opts);
3521
3334
  if (hits2.length) {
3522
3335
  filesWithHits++;
@@ -4201,13 +4014,12 @@ Managing ${displayName} API Key`);
4201
4014
  };
4202
4015
 
4203
4016
  // src/repl/custom-commands.ts
4204
- import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, mkdirSync as mkdirSync3 } from "fs";
4205
- import { join as join4, extname } from "path";
4206
- import { execSync as execSync3 } from "child_process";
4017
+ import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync, mkdirSync as mkdirSync3 } from "fs";
4018
+ import { join as join3, extname } from "path";
4207
4019
  function parseCommandFile(filePath) {
4208
4020
  let content;
4209
4021
  try {
4210
- content = readFileSync3(filePath, "utf-8");
4022
+ content = readFileSync2(filePath, "utf-8");
4211
4023
  } catch {
4212
4024
  return null;
4213
4025
  }
@@ -4231,14 +4043,14 @@ function expandTemplate(template, args) {
4231
4043
  result = result.replace(/\{\{input\}\}/g, args.join(" "));
4232
4044
  result = result.replace(/\{\{file:([^}]+)\}\}/g, (_m, p) => {
4233
4045
  try {
4234
- return readFileSync3(p.trim(), "utf-8");
4046
+ return readFileSync2(p.trim(), "utf-8");
4235
4047
  } catch {
4236
4048
  return `[Error: cannot read ${p.trim()}]`;
4237
4049
  }
4238
4050
  });
4239
4051
  result = result.replace(/\{\{git-diff\}\}/g, () => {
4240
4052
  try {
4241
- return execSync3("git diff", { encoding: "utf-8", timeout: 1e4 }).trim();
4053
+ return readGitDiff();
4242
4054
  } catch {
4243
4055
  return "[No git diff available]";
4244
4056
  }
@@ -4256,14 +4068,14 @@ var CustomCommandManager = class {
4256
4068
  commands = /* @__PURE__ */ new Map();
4257
4069
  loadCommands() {
4258
4070
  this.commands.clear();
4259
- if (!existsSync4(this.commandsDir)) {
4071
+ if (!existsSync3(this.commandsDir)) {
4260
4072
  mkdirSync3(this.commandsDir, { recursive: true });
4261
4073
  return 0;
4262
4074
  }
4263
4075
  let count = 0;
4264
- for (const file of readdirSync2(this.commandsDir)) {
4076
+ for (const file of readdirSync(this.commandsDir)) {
4265
4077
  if (extname(file) !== ".md") continue;
4266
- const cmd = parseCommandFile(join4(this.commandsDir, file));
4078
+ const cmd = parseCommandFile(join3(this.commandsDir, file));
4267
4079
  if (cmd) {
4268
4080
  this.commands.set(cmd.meta.name, cmd);
4269
4081
  count++;
@@ -4568,17 +4380,17 @@ function parseAtReferences(input2, cwd) {
4568
4380
  const absPath = resolve2(cwd, rawPath);
4569
4381
  const ext = extname2(rawPath).toLowerCase();
4570
4382
  const mime = IMAGE_MIME[ext];
4571
- if (!existsSync5(absPath)) {
4383
+ if (!existsSync4(absPath)) {
4572
4384
  refs.push({ path: rawPath, type: "notfound" });
4573
4385
  continue;
4574
4386
  }
4575
4387
  if (mime) {
4576
- const fileSize = statSync4(absPath).size;
4388
+ const fileSize = statSync3(absPath).size;
4577
4389
  if (fileSize > MAX_IMAGE_BYTES) {
4578
4390
  refs.push({ path: rawPath, type: "toolarge" });
4579
4391
  continue;
4580
4392
  }
4581
- const data = readFileSync4(absPath).toString("base64");
4393
+ const data = readFileSync3(absPath).toString("base64");
4582
4394
  imageParts.push({
4583
4395
  type: "image_url",
4584
4396
  image_url: { url: `data:${mime};base64,${data}` }
@@ -4586,7 +4398,7 @@ function parseAtReferences(input2, cwd) {
4586
4398
  refs.push({ path: rawPath, type: "image" });
4587
4399
  textBody = textBody.replace(match[0], "").trim();
4588
4400
  } else {
4589
- const content = readFileSync4(absPath, "utf-8");
4401
+ const content = readFileSync3(absPath, "utf-8");
4590
4402
  const inlined = `
4591
4403
 
4592
4404
  [File: ${rawPath}]
@@ -4678,6 +4490,7 @@ var Repl = class {
4678
4490
  };
4679
4491
  /** 当前加载的层级上下文(全局/项目/子目录) */
4680
4492
  contextLayers = [];
4493
+ contextLoadResult = null;
4681
4494
  /** 本次会话累计 token 用量 */
4682
4495
  sessionTokenUsage = { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
4683
4496
  /** Fold a single-request TokenUsage (with optional cache fields) into sessionTokenUsage + cost tracker.
@@ -4804,19 +4617,19 @@ var Repl = class {
4804
4617
  if (depth > 2 || entryCount >= MAX_TREE_ENTRIES) return;
4805
4618
  let entries;
4806
4619
  try {
4807
- entries = readdirSync3(dir);
4620
+ entries = readdirSync2(dir);
4808
4621
  } catch {
4809
4622
  return;
4810
4623
  }
4811
4624
  const filtered = entries.filter((e) => !SKIP_DIRS_SET.has(e));
4812
4625
  for (let i = 0; i < filtered.length && entryCount < MAX_TREE_ENTRIES; i++) {
4813
4626
  const name = filtered[i];
4814
- const fullPath = join5(dir, name);
4627
+ const fullPath = join4(dir, name);
4815
4628
  const isLast = i === filtered.length - 1;
4816
4629
  const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
4817
4630
  let isDir;
4818
4631
  try {
4819
- isDir = statSync4(fullPath).isDirectory();
4632
+ isDir = statSync3(fullPath).isDirectory();
4820
4633
  } catch {
4821
4634
  continue;
4822
4635
  }
@@ -4838,17 +4651,17 @@ ${treeLines.join("\n")}`
4838
4651
  if (totalChars >= MAX_TOTAL_CHARS) return;
4839
4652
  let entries;
4840
4653
  try {
4841
- entries = readdirSync3(dir);
4654
+ entries = readdirSync2(dir);
4842
4655
  } catch {
4843
4656
  return;
4844
4657
  }
4845
4658
  for (const name of entries) {
4846
4659
  if (totalChars >= MAX_TOTAL_CHARS) break;
4847
4660
  if (SKIP_DIRS_SET.has(name)) continue;
4848
- const fullPath = join5(dir, name);
4661
+ const fullPath = join4(dir, name);
4849
4662
  let st;
4850
4663
  try {
4851
- st = statSync4(fullPath);
4664
+ st = statSync3(fullPath);
4852
4665
  } catch {
4853
4666
  continue;
4854
4667
  }
@@ -4860,7 +4673,7 @@ ${treeLines.join("\n")}`
4860
4673
  if (!TEXT_EXTS.has(ext) && !isSpecial) continue;
4861
4674
  if (st.size > MAX_FILE_CHARS * 3) continue;
4862
4675
  try {
4863
- let content = readFileSync4(fullPath, "utf-8");
4676
+ let content = readFileSync3(fullPath, "utf-8");
4864
4677
  if (content.length > MAX_FILE_CHARS) {
4865
4678
  content = content.slice(0, MAX_FILE_CHARS) + `
4866
4679
  ... (truncated, ${content.length} chars total)`;
@@ -4890,12 +4703,12 @@ ${content}
4890
4703
  */
4891
4704
  addExtraContextDir(dirPath) {
4892
4705
  const absPath = resolve2(dirPath);
4893
- if (!existsSync5(absPath)) {
4706
+ if (!existsSync4(absPath)) {
4894
4707
  return { success: false, charCount: 0, added: false, error: `Directory not found: ${dirPath}` };
4895
4708
  }
4896
4709
  let isDir;
4897
4710
  try {
4898
- isDir = statSync4(absPath).isDirectory();
4711
+ isDir = statSync3(absPath).isDirectory();
4899
4712
  } catch {
4900
4713
  return { success: false, charCount: 0, added: false, error: `Cannot access: ${dirPath}` };
4901
4714
  }
@@ -4918,33 +4731,6 @@ ${content}
4918
4731
  this.extraContextDirs.splice(idx, 1);
4919
4732
  return true;
4920
4733
  }
4921
- /**
4922
- * 在指定目录中按候选文件名列表查找第一个存在且非空的上下文文件。
4923
- * 返回 { filePath, content } 或 null。
4924
- */
4925
- findContextFile(dir, candidates = CONTEXT_FILE_CANDIDATES) {
4926
- for (const candidate of candidates) {
4927
- const fullPath = join5(dir, candidate);
4928
- if (existsSync5(fullPath)) {
4929
- const content = readFileSync4(fullPath, "utf-8").trim();
4930
- if (content) return { filePath: fullPath, content };
4931
- }
4932
- }
4933
- return null;
4934
- }
4935
- /**
4936
- * 加载层级上下文文件系统。
4937
- *
4938
- * 三层级结构(按顺序拼接):
4939
- * 1. 全局层 ~/.aicli/AICLI.md — 所有项目通用的个人偏好
4940
- * 2. 项目层 <git-root>/AICLI.md — 项目级规则(提交到 git 供团队共享)
4941
- * 3. 子目录层 <cwd>/AICLI.md — 当前工作子目录的特定指令
4942
- *
4943
- * contextFile 配置语义:
4944
- * - 'auto'(默认):启用三层级自动发现
4945
- * - false:禁用所有上下文加载
4946
- * - 具体文件名:仅加载 cwd 下的指定文件(回退到旧的单文件行为)
4947
- */
4948
4734
  /**
4949
4735
  * 加载项目级 .mcp.json 文件(位于 git 根目录或 cwd)。
4950
4736
  * 格式兼容 Claude Desktop:`{ "mcpServers": { ... } }`
@@ -4954,10 +4740,10 @@ ${content}
4954
4740
  const cwd = process.cwd();
4955
4741
  const gitRoot = getGitRoot(cwd);
4956
4742
  const projectRoot = gitRoot ?? cwd;
4957
- const mcpPath = join5(projectRoot, MCP_PROJECT_CONFIG_NAME);
4958
- if (!existsSync5(mcpPath)) return null;
4743
+ const mcpPath = join4(projectRoot, MCP_PROJECT_CONFIG_NAME);
4744
+ if (!existsSync4(mcpPath)) return null;
4959
4745
  try {
4960
- const raw = JSON.parse(readFileSync4(mcpPath, "utf-8"));
4746
+ const raw = JSON.parse(readFileSync3(mcpPath, "utf-8"));
4961
4747
  const servers = raw?.mcpServers;
4962
4748
  if (!servers || typeof servers !== "object") {
4963
4749
  process.stderr.write(
@@ -4991,79 +4777,25 @@ ${content}
4991
4777
  }
4992
4778
  }
4993
4779
  loadHierarchicalContext() {
4994
- const setting = this.config.get("contextFile");
4995
- if (setting === false) return { layers: [], mergedContent: "" };
4780
+ const contextConfig = this.config.get("context");
4996
4781
  const cwd = process.cwd();
4997
- if (setting !== "auto") {
4998
- const fullPath = resolve2(cwd, String(setting));
4999
- if (!fullPath.startsWith(resolve2(cwd))) {
5000
- process.stderr.write(
5001
- `[Warning] contextFile path "${setting}" is outside current directory, ignoring.
5002
- `
5003
- );
5004
- return { layers: [], mergedContent: "" };
5005
- }
5006
- if (existsSync5(fullPath)) {
5007
- const content = readFileSync4(fullPath, "utf-8").trim();
5008
- if (content) {
5009
- const layer = {
5010
- level: "project",
5011
- filePath: setting,
5012
- content,
5013
- charCount: content.length
5014
- };
5015
- return { layers: [layer], mergedContent: content };
5016
- }
5017
- }
5018
- return { layers: [], mergedContent: "" };
5019
- }
5020
- const layers = [];
5021
- const configDir = this.config.getConfigDir();
5022
- const globalCtx = this.findContextFile(configDir);
5023
- if (globalCtx) {
5024
- layers.push({
5025
- level: "global",
5026
- filePath: globalCtx.filePath,
5027
- content: globalCtx.content,
5028
- charCount: globalCtx.content.length
5029
- });
5030
- }
5031
4782
  const gitRoot = getGitRoot(cwd);
5032
4783
  const projectRoot = gitRoot ?? cwd;
5033
- const projectCtx = this.findContextFile(projectRoot);
5034
- if (projectCtx) {
5035
- layers.push({
5036
- level: "project",
5037
- filePath: projectCtx.filePath,
5038
- content: projectCtx.content,
5039
- charCount: projectCtx.content.length
5040
- });
5041
- }
5042
- const normalizedCwd = resolve2(cwd);
5043
- const normalizedRoot = resolve2(projectRoot);
5044
- if (normalizedCwd !== normalizedRoot) {
5045
- const localCtx = this.findContextFile(cwd);
5046
- if (localCtx) {
5047
- layers.push({
5048
- level: "local",
5049
- filePath: localCtx.filePath,
5050
- content: localCtx.content,
5051
- charCount: localCtx.content.length
5052
- });
5053
- }
5054
- }
5055
- const mergedContent = layers.map((l) => l.content).join("\n\n---\n\n");
5056
- return { layers, mergedContent };
4784
+ const result = loadContextFiles({
4785
+ cwd,
4786
+ configDir: this.config.getConfigDir(),
4787
+ projectRoot,
4788
+ setting: this.config.get("contextFile"),
4789
+ fallbackFilenames: contextConfig.projectDocFallbackFilenames,
4790
+ maxBytes: contextConfig.projectDocMaxBytes
4791
+ });
4792
+ this.contextLoadResult = result;
4793
+ return { layers: result.layers, mergedContent: result.mergedContent };
5057
4794
  }
5058
- /**
5059
- * 加载持久记忆内容(~/.aicli/memory.md)。
5060
- * 不存在或为空时返回 null。
5061
- * 超过 MEMORY_MAX_CHARS 时只取末尾最新部分。
5062
- */
5063
4795
  loadMemoryContent() {
5064
- const memoryPath = join5(this.config.getConfigDir(), MEMORY_FILE_NAME);
5065
- if (!existsSync5(memoryPath)) return null;
5066
- let content = readFileSync4(memoryPath, "utf-8").trim();
4796
+ const memoryPath = join4(this.config.getConfigDir(), MEMORY_FILE_NAME);
4797
+ if (!existsSync4(memoryPath)) return null;
4798
+ let content = readFileSync3(memoryPath, "utf-8").trim();
5067
4799
  if (!content) return null;
5068
4800
  if (content.length > MEMORY_MAX_CHARS) {
5069
4801
  content = content.slice(-MEMORY_MAX_CHARS);
@@ -5451,14 +5183,14 @@ Session '${this.resumeSessionId}' not found.
5451
5183
  process.stdout.write(theme.dim(` \u{1F50C} Plugins loaded: ${pluginCount} tool(s) from plugins/
5452
5184
  `));
5453
5185
  }
5454
- const skillsDir = join5(this.config.getConfigDir(), SKILLS_DIR_NAME);
5186
+ const skillsDir = join4(this.config.getConfigDir(), SKILLS_DIR_NAME);
5455
5187
  this.skillManager = new SkillManager(skillsDir, this.config.get("ui").skillSizeWarn);
5456
5188
  const skillCount = this.skillManager.loadSkills();
5457
5189
  if (skillCount > 0) {
5458
5190
  process.stdout.write(theme.dim(` \u{1F3AF} Skills: ${skillCount} available (use /skill to manage)
5459
5191
  `));
5460
5192
  }
5461
- const commandsDir = join5(this.config.getConfigDir(), CUSTOM_COMMANDS_DIR_NAME);
5193
+ const commandsDir = join4(this.config.getConfigDir(), CUSTOM_COMMANDS_DIR_NAME);
5462
5194
  this.customCommandManager = new CustomCommandManager(commandsDir);
5463
5195
  const customCmdCount = this.customCommandManager.loadCommands();
5464
5196
  if (customCmdCount > 0) {
@@ -5467,7 +5199,7 @@ Session '${this.resumeSessionId}' not found.
5467
5199
  }
5468
5200
  void (async () => {
5469
5201
  try {
5470
- const { indexProject } = await import("./indexer-AKWMYNJI.js");
5202
+ const { indexProject } = await import("./indexer-2AG4G6B5.js");
5471
5203
  const { loadIndex } = await import("./store-MWNHVGJT.js");
5472
5204
  const root = process.cwd();
5473
5205
  const existed = loadIndex(root);
@@ -6094,15 +5826,15 @@ Session '${this.resumeSessionId}' not found.
6094
5826
  const dir = normalized.includes("/") ? dirname3(normalized) : ".";
6095
5827
  const prefix = normalized.includes("/") ? basename2(normalized) : normalized;
6096
5828
  const absDir = resolve2(process.cwd(), dir);
6097
- if (!existsSync5(absDir)) return [];
6098
- const entries = readdirSync3(absDir);
5829
+ if (!existsSync4(absDir)) return [];
5830
+ const entries = readdirSync2(absDir);
6099
5831
  const results = [];
6100
5832
  for (const entry of entries) {
6101
5833
  if (entry.startsWith(".")) continue;
6102
5834
  if (!entry.toLowerCase().startsWith(prefix.toLowerCase())) continue;
6103
5835
  try {
6104
- const fullPath = join5(absDir, entry);
6105
- const stat = statSync4(fullPath);
5836
+ const fullPath = join4(absDir, entry);
5837
+ const stat = statSync3(fullPath);
6106
5838
  const rel = dir === "." ? entry : `${dir}/${entry}`;
6107
5839
  results.push(stat.isDirectory() ? `${rel}/` : rel);
6108
5840
  } catch {
@@ -7271,7 +7003,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7271
7003
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7272
7004
  process.exit(1);
7273
7005
  }
7274
- const { startWebServer } = await import("./server-4EFTRFTN.js");
7006
+ const { startWebServer } = await import("./server-E5D54DIZ.js");
7275
7007
  await startWebServer({ port, host: options.host });
7276
7008
  });
7277
7009
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
@@ -7438,16 +7170,16 @@ program.command("sessions").description("List recent conversation sessions").opt
7438
7170
  console.log(footer + "\n");
7439
7171
  });
7440
7172
  program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
7441
- const { runUsageCli } = await import("./usage-Q24E5636.js");
7173
+ const { runUsageCli } = await import("./usage-P4B2RZKL.js");
7442
7174
  await runUsageCli(options);
7443
7175
  });
7444
7176
  program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
7445
- const { runDoctorCli } = await import("./doctor-cli-I2Y2YR4V.js");
7177
+ const { runDoctorCli } = await import("./doctor-cli-32COMA5K.js");
7446
7178
  await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
7447
7179
  });
7448
7180
  program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
7449
7181
  try {
7450
- const batch = await import("./batch-3T44NFLG.js");
7182
+ const batch = await import("./batch-MFPYHOIL.js");
7451
7183
  switch (action) {
7452
7184
  case "submit":
7453
7185
  if (!arg) {
@@ -7490,7 +7222,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7490
7222
  }
7491
7223
  });
7492
7224
  program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
7493
- const { startMcpServer } = await import("./server-PVKLPRUP.js");
7225
+ const { startMcpServer } = await import("./server-AIHVMLNU.js");
7494
7226
  await startMcpServer({
7495
7227
  allowDestructive: !!options.allowDestructive,
7496
7228
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7499,7 +7231,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
7499
7231
  });
7500
7232
  });
7501
7233
  program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number; diff fetched via `gh pr diff <num>`", (v) => parseInt(v, 10)).option("--base <ref>", "Base ref for `git diff <ref>...HEAD` (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").action(async (options) => {
7502
- const { runCi } = await import("./ci-6QWBVRJX.js");
7234
+ const { runCi } = await import("./ci-QLJUDLMY.js");
7503
7235
  const result = await runCi({
7504
7236
  pr: options.pr,
7505
7237
  base: options.base,
@@ -7645,7 +7377,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7645
7377
  }),
7646
7378
  config.get("customProviders")
7647
7379
  );
7648
- const { startHub } = await import("./hub-XVPFBODB.js");
7380
+ const { startHub } = await import("./hub-3NWJUCLK.js");
7649
7381
  await startHub(
7650
7382
  {
7651
7383
  topic: topic ?? "",
@@ -7745,7 +7477,27 @@ ${options.prompt}` : options.prompt;
7745
7477
  const maxTokens = modelParams.maxTokens ?? DEFAULT_MAX_TOKENS;
7746
7478
  const timeout = modelParams.timeout ?? 6e4;
7747
7479
  const temperature = modelParams.temperature;
7748
- const systemPrompt = options.system ?? config.get("session").systemPrompt ?? void 0;
7480
+ let systemPrompt = options.system;
7481
+ if (!systemPrompt) {
7482
+ const contextConfig = config.get("context");
7483
+ const cwd = process.cwd();
7484
+ const gitRoot = getGitRoot(cwd);
7485
+ const loaded = loadContextFiles({
7486
+ cwd,
7487
+ configDir: config.getConfigDir(),
7488
+ projectRoot: gitRoot ?? cwd,
7489
+ setting: config.get("contextFile"),
7490
+ fallbackFilenames: contextConfig.projectDocFallbackFilenames,
7491
+ maxBytes: contextConfig.projectDocMaxBytes
7492
+ });
7493
+ const parts = [
7494
+ config.get("session").systemPrompt,
7495
+ loaded.mergedContent ? `# Project Context
7496
+
7497
+ ${loaded.mergedContent}` : void 0
7498
+ ].filter(Boolean);
7499
+ systemPrompt = parts.length > 0 ? parts.join("\n\n---\n\n") : void 0;
7500
+ }
7749
7501
  const isStreamingJson = options.outputFormat === "streaming-json";
7750
7502
  const useStream = options.stream !== false && !options.json && !isStreamingJson;
7751
7503
  try {