jinzd-ai-cli 0.4.209 → 0.4.211
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -6
- package/README.zh-CN.md +45 -5
- package/dist/{batch-45WLJUVP.js → batch-DE4RXKZD.js} +2 -2
- package/dist/{chunk-EN63JA7N.js → chunk-6NS6643Y.js} +1 -1
- package/dist/{chunk-D6M4E7SH.js → chunk-BE6ERF7M.js} +1 -1
- package/dist/{chunk-ATNYI6JL.js → chunk-C3OU2OPF.js} +374 -22
- package/dist/{chunk-UPMBIS4T.js → chunk-E5XCM4A6.js} +5 -3
- package/dist/{chunk-STIEOOOL.js → chunk-JBWA73GK.js} +1 -1
- package/dist/{chunk-DUZRQXIP.js → chunk-UOROWTGG.js} +45 -6
- package/dist/{chunk-JVLRMIHA.js → chunk-ZOPYREL5.js} +312 -38
- package/dist/{chunk-EYID2AIR.js → chunk-ZY2N2N6T.js} +5 -3
- package/dist/{ci-PUE3MQ7J.js → ci-XMUEX526.js} +2 -2
- package/dist/{constants-VTZLKDAG.js → constants-AWTIQIWG.js} +3 -1
- package/dist/{doctor-cli-IU6FSVLF.js → doctor-cli-SSI6ETFT.js} +4 -4
- package/dist/electron-server.js +1006 -471
- package/dist/{hub-4ETK4R2J.js → hub-INUJND2G.js} +1 -1
- package/dist/index.js +137 -367
- package/dist/{run-tests-NDS2IEMK.js → run-tests-3MHWUF43.js} +2 -2
- package/dist/{run-tests-UAS5NJBM.js → run-tests-PACN4UYX.js} +1 -1
- package/dist/{server-72SAPLPS.js → server-7USZJJAH.js} +4 -4
- package/dist/{server-4URLNC7P.js → server-BTSKOPQI.js} +139 -311
- package/dist/{task-orchestrator-6PZTB35T.js → task-orchestrator-OV4O25MX.js} +4 -4
- package/dist/{usage-ZNCKGF6U.js → usage-T2P6FTE7.js} +2 -2
- package/dist/web/client/app.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
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,
|
|
15
13
|
readGitDiff,
|
|
16
14
|
saveDevState,
|
|
15
|
+
scanProject,
|
|
17
16
|
sessionHasMeaningfulContent,
|
|
18
17
|
setupProxy
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-C3OU2OPF.js";
|
|
19
|
+
import {
|
|
20
|
+
buildReviewPrompt,
|
|
21
|
+
buildSecurityReviewPrompt
|
|
22
|
+
} from "./chunk-HLWUDRBO.js";
|
|
20
23
|
import {
|
|
21
24
|
ToolExecutor,
|
|
22
25
|
ToolRegistry,
|
|
23
26
|
askUserContext,
|
|
24
27
|
cleanupRejectedTeeFile,
|
|
25
28
|
estimateTokens,
|
|
29
|
+
formatPermissionProfileWarning,
|
|
26
30
|
googleSearchContext,
|
|
27
31
|
initTheme,
|
|
28
32
|
isInterrupted,
|
|
@@ -36,10 +40,10 @@ import {
|
|
|
36
40
|
spawnAgentContext,
|
|
37
41
|
theme,
|
|
38
42
|
undoStack
|
|
39
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-ZOPYREL5.js";
|
|
40
44
|
import "./chunk-T2NL5ZIA.js";
|
|
41
45
|
import "./chunk-BXP6YZ2P.js";
|
|
42
|
-
import "./chunk-
|
|
46
|
+
import "./chunk-6NS6643Y.js";
|
|
43
47
|
import {
|
|
44
48
|
SessionManager,
|
|
45
49
|
getContentText
|
|
@@ -56,7 +60,7 @@ import {
|
|
|
56
60
|
getConfigDirUsage,
|
|
57
61
|
listRecentCrashes,
|
|
58
62
|
writeCrashLog
|
|
59
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-BE6ERF7M.js";
|
|
60
64
|
import {
|
|
61
65
|
ProviderRegistry
|
|
62
66
|
} from "./chunk-QMXC327F.js";
|
|
@@ -65,7 +69,7 @@ import {
|
|
|
65
69
|
getTopFailingTools,
|
|
66
70
|
getTopUsedTools,
|
|
67
71
|
installFlushOnExit
|
|
68
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-JBWA73GK.js";
|
|
69
73
|
import {
|
|
70
74
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
71
75
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -87,7 +91,7 @@ import {
|
|
|
87
91
|
} from "./chunk-XPBEJB27.js";
|
|
88
92
|
import {
|
|
89
93
|
ConfigManager
|
|
90
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-UOROWTGG.js";
|
|
91
95
|
import {
|
|
92
96
|
AuthError,
|
|
93
97
|
ProviderError,
|
|
@@ -98,7 +102,6 @@ import {
|
|
|
98
102
|
AUTHOR,
|
|
99
103
|
AUTHOR_EMAIL,
|
|
100
104
|
CONFIG_DIR_NAME,
|
|
101
|
-
CONTEXT_FILE_CANDIDATES,
|
|
102
105
|
CONTEXT_PRESSURE_THRESHOLD,
|
|
103
106
|
CUSTOM_COMMANDS_DIR_NAME,
|
|
104
107
|
DEFAULT_MAX_TOKENS,
|
|
@@ -114,7 +117,7 @@ import {
|
|
|
114
117
|
SKILLS_DIR_NAME,
|
|
115
118
|
VERSION,
|
|
116
119
|
buildUserIdentityPrompt
|
|
117
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-E5XCM4A6.js";
|
|
118
121
|
import {
|
|
119
122
|
formatGitContextForPrompt,
|
|
120
123
|
getGitContext,
|
|
@@ -145,8 +148,8 @@ import { program } from "commander";
|
|
|
145
148
|
|
|
146
149
|
// src/repl/repl.ts
|
|
147
150
|
import * as readline from "readline";
|
|
148
|
-
import { existsSync as
|
|
149
|
-
import { join as
|
|
151
|
+
import { existsSync as existsSync4, readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync3, mkdirSync as mkdirSync4 } from "fs";
|
|
152
|
+
import { join as join4, resolve as resolve2, extname as extname2, dirname as dirname3, basename as basename2 } from "path";
|
|
150
153
|
import chalk4 from "chalk";
|
|
151
154
|
|
|
152
155
|
// src/session/title-generator.ts
|
|
@@ -638,10 +641,10 @@ Error${typeName}: ${lines.join("\n")}
|
|
|
638
641
|
};
|
|
639
642
|
|
|
640
643
|
// src/repl/commands/index.ts
|
|
641
|
-
import { writeFileSync, mkdirSync as mkdirSync2, existsSync as
|
|
644
|
+
import { writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync2, readFileSync, statSync as statSync2 } from "fs";
|
|
642
645
|
import { execSync as execSync2 } from "child_process";
|
|
643
646
|
import { platform } from "os";
|
|
644
|
-
import { resolve, dirname as dirname2, join as
|
|
647
|
+
import { resolve, dirname as dirname2, join as join2, basename } from "path";
|
|
645
648
|
import chalk2 from "chalk";
|
|
646
649
|
|
|
647
650
|
// src/repl/clipboard.ts
|
|
@@ -731,195 +734,6 @@ function getClipboardHint() {
|
|
|
731
734
|
return "";
|
|
732
735
|
}
|
|
733
736
|
|
|
734
|
-
// src/repl/commands/project-init.ts
|
|
735
|
-
import { existsSync as existsSync2, readFileSync, readdirSync, statSync as statSync2 } from "fs";
|
|
736
|
-
import { join as join2 } from "path";
|
|
737
|
-
var SCAN_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
738
|
-
"node_modules",
|
|
739
|
-
".git",
|
|
740
|
-
"dist",
|
|
741
|
-
"build",
|
|
742
|
-
"out",
|
|
743
|
-
"target",
|
|
744
|
-
".next",
|
|
745
|
-
".nuxt",
|
|
746
|
-
"__pycache__",
|
|
747
|
-
".venv",
|
|
748
|
-
"venv",
|
|
749
|
-
".tox",
|
|
750
|
-
".mypy_cache",
|
|
751
|
-
".pytest_cache",
|
|
752
|
-
".gradle",
|
|
753
|
-
".idea",
|
|
754
|
-
".vscode",
|
|
755
|
-
".vs",
|
|
756
|
-
"coverage",
|
|
757
|
-
".cache",
|
|
758
|
-
".parcel-cache",
|
|
759
|
-
"dist-cjs",
|
|
760
|
-
"release",
|
|
761
|
-
".output",
|
|
762
|
-
".turbo",
|
|
763
|
-
"vendor"
|
|
764
|
-
]);
|
|
765
|
-
function scanDirTree(dir, maxDepth = 2, maxEntries = 80) {
|
|
766
|
-
const lines = [];
|
|
767
|
-
let count = 0;
|
|
768
|
-
const walk = (d, prefix, depth) => {
|
|
769
|
-
if (depth > maxDepth || count >= maxEntries) return;
|
|
770
|
-
let entries;
|
|
771
|
-
try {
|
|
772
|
-
entries = readdirSync(d);
|
|
773
|
-
} catch {
|
|
774
|
-
return;
|
|
775
|
-
}
|
|
776
|
-
const filtered = entries.filter((e) => !e.startsWith(".") && !SCAN_SKIP_DIRS.has(e));
|
|
777
|
-
const sorted = filtered.sort((a, b) => {
|
|
778
|
-
let aIsDir = false, bIsDir = false;
|
|
779
|
-
try {
|
|
780
|
-
aIsDir = statSync2(join2(d, a)).isDirectory();
|
|
781
|
-
} catch {
|
|
782
|
-
}
|
|
783
|
-
try {
|
|
784
|
-
bIsDir = statSync2(join2(d, b)).isDirectory();
|
|
785
|
-
} catch {
|
|
786
|
-
}
|
|
787
|
-
if (aIsDir !== bIsDir) return aIsDir ? -1 : 1;
|
|
788
|
-
return a.localeCompare(b);
|
|
789
|
-
});
|
|
790
|
-
for (let i = 0; i < sorted.length && count < maxEntries; i++) {
|
|
791
|
-
const name = sorted[i];
|
|
792
|
-
const fullPath = join2(d, name);
|
|
793
|
-
const isLast = i === sorted.length - 1;
|
|
794
|
-
const connector = isLast ? "+-- " : "|-- ";
|
|
795
|
-
let isDir;
|
|
796
|
-
try {
|
|
797
|
-
isDir = statSync2(fullPath).isDirectory();
|
|
798
|
-
} catch {
|
|
799
|
-
continue;
|
|
800
|
-
}
|
|
801
|
-
lines.push(prefix + connector + name + (isDir ? "/" : ""));
|
|
802
|
-
count++;
|
|
803
|
-
if (isDir) {
|
|
804
|
-
walk(fullPath, prefix + (isLast ? " " : "| "), depth + 1);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
};
|
|
808
|
-
walk(dir, "", 0);
|
|
809
|
-
if (count >= maxEntries) lines.push("... (truncated)");
|
|
810
|
-
return lines.join("\n");
|
|
811
|
-
}
|
|
812
|
-
function scanProject(cwd) {
|
|
813
|
-
const info = {
|
|
814
|
-
type: "unknown",
|
|
815
|
-
language: "unknown",
|
|
816
|
-
configFiles: [],
|
|
817
|
-
directoryStructure: ""
|
|
818
|
-
};
|
|
819
|
-
const check = (file) => existsSync2(join2(cwd, file));
|
|
820
|
-
const configCandidates = [
|
|
821
|
-
"package.json",
|
|
822
|
-
"tsconfig.json",
|
|
823
|
-
"Cargo.toml",
|
|
824
|
-
"pyproject.toml",
|
|
825
|
-
"setup.py",
|
|
826
|
-
"requirements.txt",
|
|
827
|
-
"go.mod",
|
|
828
|
-
"pom.xml",
|
|
829
|
-
"build.gradle",
|
|
830
|
-
"build.gradle.kts",
|
|
831
|
-
"CMakeLists.txt",
|
|
832
|
-
"Makefile",
|
|
833
|
-
".csproj",
|
|
834
|
-
".sln",
|
|
835
|
-
"composer.json",
|
|
836
|
-
"Gemfile",
|
|
837
|
-
"mix.exs",
|
|
838
|
-
"deno.json",
|
|
839
|
-
"bun.lockb"
|
|
840
|
-
];
|
|
841
|
-
info.configFiles = configCandidates.filter(check);
|
|
842
|
-
if (check("package.json")) {
|
|
843
|
-
info.type = "node";
|
|
844
|
-
info.language = check("tsconfig.json") ? "TypeScript" : "JavaScript";
|
|
845
|
-
try {
|
|
846
|
-
const pkg = JSON.parse(readFileSync(join2(cwd, "package.json"), "utf-8"));
|
|
847
|
-
const scripts = pkg.scripts ?? {};
|
|
848
|
-
info.buildCommand = scripts.build ? "npm run build" : void 0;
|
|
849
|
-
info.testCommand = scripts.test ? "npm test" : void 0;
|
|
850
|
-
info.devCommand = scripts.dev ? "npm run dev" : void 0;
|
|
851
|
-
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
852
|
-
if (allDeps["react"]) info.framework = "React";
|
|
853
|
-
else if (allDeps["vue"]) info.framework = "Vue";
|
|
854
|
-
else if (allDeps["@angular/core"]) info.framework = "Angular";
|
|
855
|
-
else if (allDeps["next"]) info.framework = "Next.js";
|
|
856
|
-
else if (allDeps["nuxt"]) info.framework = "Nuxt";
|
|
857
|
-
else if (allDeps["express"]) info.framework = "Express";
|
|
858
|
-
else if (allDeps["fastify"]) info.framework = "Fastify";
|
|
859
|
-
else if (allDeps["svelte"]) info.framework = "Svelte";
|
|
860
|
-
} catch {
|
|
861
|
-
}
|
|
862
|
-
} else if (check("Cargo.toml")) {
|
|
863
|
-
info.type = "rust";
|
|
864
|
-
info.language = "Rust";
|
|
865
|
-
info.buildCommand = "cargo build";
|
|
866
|
-
info.testCommand = "cargo test";
|
|
867
|
-
} else if (check("pyproject.toml") || check("setup.py") || check("requirements.txt")) {
|
|
868
|
-
info.type = "python";
|
|
869
|
-
info.language = "Python";
|
|
870
|
-
info.testCommand = check("pytest.ini") || check("pyproject.toml") ? "pytest" : "python -m unittest";
|
|
871
|
-
} else if (check("go.mod")) {
|
|
872
|
-
info.type = "go";
|
|
873
|
-
info.language = "Go";
|
|
874
|
-
info.buildCommand = "go build ./...";
|
|
875
|
-
info.testCommand = "go test ./...";
|
|
876
|
-
} else if (check("pom.xml")) {
|
|
877
|
-
info.type = "java";
|
|
878
|
-
info.language = "Java";
|
|
879
|
-
info.buildCommand = "mvn package";
|
|
880
|
-
info.testCommand = "mvn test";
|
|
881
|
-
} else if (check("build.gradle") || check("build.gradle.kts")) {
|
|
882
|
-
info.type = "java";
|
|
883
|
-
info.language = "Java/Kotlin";
|
|
884
|
-
info.buildCommand = "./gradlew build";
|
|
885
|
-
info.testCommand = "./gradlew test";
|
|
886
|
-
}
|
|
887
|
-
info.directoryStructure = scanDirTree(cwd);
|
|
888
|
-
return info;
|
|
889
|
-
}
|
|
890
|
-
function buildInitPrompt(info, cwd) {
|
|
891
|
-
const parts = [
|
|
892
|
-
"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.",
|
|
893
|
-
"\n## Project Info\n",
|
|
894
|
-
`- Working directory: ${cwd}`,
|
|
895
|
-
`- Type: ${info.type}`,
|
|
896
|
-
`- Language: ${info.language}`
|
|
897
|
-
];
|
|
898
|
-
if (info.framework) parts.push(`- Framework: ${info.framework}`);
|
|
899
|
-
if (info.buildCommand) parts.push(`- Build command: ${info.buildCommand}`);
|
|
900
|
-
if (info.testCommand) parts.push(`- Test command: ${info.testCommand}`);
|
|
901
|
-
if (info.devCommand) parts.push(`- Dev command: ${info.devCommand}`);
|
|
902
|
-
parts.push(`
|
|
903
|
-
## Detected Config Files
|
|
904
|
-
${info.configFiles.map((f) => `- ${f}`).join("\n")}`);
|
|
905
|
-
parts.push(`
|
|
906
|
-
## Directory Structure
|
|
907
|
-
\`\`\`
|
|
908
|
-
${info.directoryStructure}
|
|
909
|
-
\`\`\``);
|
|
910
|
-
parts.push(`
|
|
911
|
-
## Requirements
|
|
912
|
-
Please generate a structured Markdown file containing:
|
|
913
|
-
1. Project overview (one-sentence summary)
|
|
914
|
-
2. Tech stack
|
|
915
|
-
3. Project structure description (based on the directory structure above)
|
|
916
|
-
4. Common commands (build, test, dev, etc.)
|
|
917
|
-
5. Code style and conventions (inferred from config files)
|
|
918
|
-
|
|
919
|
-
Output the Markdown content directly, do not wrap the entire file in a code block. Keep it concise, within 200 lines.`);
|
|
920
|
-
return parts.join("\n");
|
|
921
|
-
}
|
|
922
|
-
|
|
923
737
|
// src/repl/commands/index.ts
|
|
924
738
|
function fmtCtx(tokens) {
|
|
925
739
|
if (tokens >= 1e6) return `${Math.round(tokens / 1e5) / 10}M`;
|
|
@@ -1489,7 +1303,7 @@ No commands match "${filter}".
|
|
|
1489
1303
|
{
|
|
1490
1304
|
name: "context",
|
|
1491
1305
|
description: "Show or reload hierarchical context files",
|
|
1492
|
-
usage: "/context [reload]",
|
|
1306
|
+
usage: "/context [status|reload]",
|
|
1493
1307
|
execute(args, ctx) {
|
|
1494
1308
|
const sub = args[0];
|
|
1495
1309
|
if (sub === "reload") {
|
|
@@ -1499,7 +1313,7 @@ No commands match "${filter}".
|
|
|
1499
1313
|
const summary = layers2.map((l) => `${l.level}:${l.charCount}`).join(", ");
|
|
1500
1314
|
ctx.renderer.printSuccess(`Context reloaded: ${layers2.length} layer(s) (${summary} chars)`);
|
|
1501
1315
|
} else {
|
|
1502
|
-
ctx.renderer.printInfo("No context file found. Place AICLI.md or
|
|
1316
|
+
ctx.renderer.printInfo("No context file found. Place AICLI.md, CLAUDE.md, or AGENTS.md in your project root or ~/.aicli/.");
|
|
1503
1317
|
}
|
|
1504
1318
|
return;
|
|
1505
1319
|
}
|
|
@@ -1509,16 +1323,16 @@ No commands match "${filter}".
|
|
|
1509
1323
|
console.log(" Context layers:");
|
|
1510
1324
|
const levelLabels = { global: "Global ", project: "Project", local: "Local " };
|
|
1511
1325
|
for (const l of layers) {
|
|
1512
|
-
console.log(` ${levelLabels[l.level] ?? l.level} : ${l.filePath} (${l.charCount} chars)`);
|
|
1326
|
+
console.log(` ${levelLabels[l.level] ?? l.level} : ${l.displayPath ?? l.filePath} (${l.charCount} chars${l.truncated ? ", truncated" : ""})`);
|
|
1513
1327
|
}
|
|
1514
1328
|
const totalChars = layers.reduce((s, l) => s + l.charCount, 0);
|
|
1515
1329
|
console.log(` Total : ${totalChars} chars (${layers.length} layer${layers.length > 1 ? "s" : ""})`);
|
|
1516
1330
|
} else {
|
|
1517
1331
|
console.log(" No context files loaded.");
|
|
1518
1332
|
console.log(" Hierarchical context search order:");
|
|
1519
|
-
console.log(" 1. Global : ~/.aicli/AICLI.md
|
|
1520
|
-
console.log(" 2. Project : <git-root>/
|
|
1521
|
-
console.log(" 3. Local : <cwd>/
|
|
1333
|
+
console.log(" 1. Global : ~/.aicli/AICLI.override.md, AGENTS.override.md, AICLI.md, CLAUDE.md, or AGENTS.md");
|
|
1334
|
+
console.log(" 2. Project : <git-root>/same candidate order");
|
|
1335
|
+
console.log(" 3. Local : <cwd>/same candidate order (when cwd \u2260 project root)");
|
|
1522
1336
|
}
|
|
1523
1337
|
console.log();
|
|
1524
1338
|
}
|
|
@@ -1540,6 +1354,8 @@ No commands match "${filter}".
|
|
|
1540
1354
|
console.log(` Provider : ${ctx.getCurrentProvider()}`);
|
|
1541
1355
|
console.log(` Model : ${currentModel}`);
|
|
1542
1356
|
console.log(` Ctx Win : ${ctxStr}`);
|
|
1357
|
+
console.log(" PermProf : " + (ctx.config.get("defaultPermissionProfile") ?? "legacy"));
|
|
1358
|
+
console.log(" Network : " + (ctx.config.get("networkPolicy")?.enabled ?? false ? "on" : "off"));
|
|
1543
1359
|
console.log(` Messages : ${session?.messages.length ?? 0}`);
|
|
1544
1360
|
console.log(` Session : ${session?.id.slice(0, 8) ?? "none"}`);
|
|
1545
1361
|
if (layers.length > 0) {
|
|
@@ -1830,16 +1646,16 @@ No tools match "${filter}".
|
|
|
1830
1646
|
usage: "/mcp [reconnect [serverId] | trust-project]",
|
|
1831
1647
|
async execute(args, ctx) {
|
|
1832
1648
|
if (args[0] === "trust-project") {
|
|
1833
|
-
const { join:
|
|
1834
|
-
const { existsSync:
|
|
1649
|
+
const { join: join5 } = await import("path");
|
|
1650
|
+
const { existsSync: existsSync5 } = await import("fs");
|
|
1835
1651
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
|
|
1836
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1652
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-AWTIQIWG.js");
|
|
1837
1653
|
const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
|
|
1838
1654
|
const cwd = process.cwd();
|
|
1839
1655
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
1840
|
-
const mcpPath =
|
|
1656
|
+
const mcpPath = join5(projectRoot, MCP_PROJECT_CONFIG_NAME2);
|
|
1841
1657
|
console.log();
|
|
1842
|
-
if (!
|
|
1658
|
+
if (!existsSync5(mcpPath)) {
|
|
1843
1659
|
console.log(theme.dim(` No .mcp.json in ${projectRoot}.`));
|
|
1844
1660
|
console.log();
|
|
1845
1661
|
return;
|
|
@@ -2172,9 +1988,9 @@ No tools match "${filter}".
|
|
|
2172
1988
|
usage: "/init [--force]",
|
|
2173
1989
|
async execute(args, ctx) {
|
|
2174
1990
|
const cwd = process.cwd();
|
|
2175
|
-
const targetPath =
|
|
1991
|
+
const targetPath = join2(cwd, "AICLI.md");
|
|
2176
1992
|
const force = args.includes("--force");
|
|
2177
|
-
if (
|
|
1993
|
+
if (existsSync2(targetPath) && !force) {
|
|
2178
1994
|
ctx.renderer.printInfo(`AICLI.md already exists at ${targetPath}`);
|
|
2179
1995
|
ctx.renderer.printInfo("Use /init --force to overwrite, or edit it manually.");
|
|
2180
1996
|
return;
|
|
@@ -2892,7 +2708,7 @@ ${hint}` : "")
|
|
|
2892
2708
|
usage: "/test [command|filter]",
|
|
2893
2709
|
async execute(args, ctx) {
|
|
2894
2710
|
try {
|
|
2895
|
-
const { executeTests } = await import("./run-tests-
|
|
2711
|
+
const { executeTests } = await import("./run-tests-3MHWUF43.js");
|
|
2896
2712
|
const argStr = args.join(" ").trim();
|
|
2897
2713
|
let testArgs = {};
|
|
2898
2714
|
if (argStr) {
|
|
@@ -3050,7 +2866,7 @@ ${hint}` : "")
|
|
|
3050
2866
|
description: "Persistent memory (memory.md) + chat memory recall index (v0.4.89+)",
|
|
3051
2867
|
usage: "/memory [show|add <text>|clear|path|rebuild|refresh|status|recall <query>|index-clear]",
|
|
3052
2868
|
async execute(args, ctx) {
|
|
3053
|
-
const memoryFile =
|
|
2869
|
+
const memoryFile = join2(ctx.config.getConfigDir(), MEMORY_FILE_NAME);
|
|
3054
2870
|
const sub = args[0] ?? "show";
|
|
3055
2871
|
if (sub === "rebuild" || sub === "refresh") {
|
|
3056
2872
|
const full = sub === "rebuild";
|
|
@@ -3134,11 +2950,11 @@ ${hint}` : "")
|
|
|
3134
2950
|
return;
|
|
3135
2951
|
}
|
|
3136
2952
|
if (sub === "show" || sub === "view") {
|
|
3137
|
-
if (!
|
|
2953
|
+
if (!existsSync2(memoryFile)) {
|
|
3138
2954
|
ctx.renderer.printInfo("Memory is empty (memory.md not found)");
|
|
3139
2955
|
return;
|
|
3140
2956
|
}
|
|
3141
|
-
const content =
|
|
2957
|
+
const content = readFileSync(memoryFile, "utf-8").trim();
|
|
3142
2958
|
if (!content) {
|
|
3143
2959
|
ctx.renderer.printInfo("Memory is empty");
|
|
3144
2960
|
return;
|
|
@@ -3163,14 +2979,14 @@ ${text}
|
|
|
3163
2979
|
`;
|
|
3164
2980
|
try {
|
|
3165
2981
|
mkdirSync2(dirname2(memoryFile), { recursive: true });
|
|
3166
|
-
const previous =
|
|
2982
|
+
const previous = existsSync2(memoryFile) ? readFileSync(memoryFile, "utf-8") : "";
|
|
3167
2983
|
atomicWriteFileSync(memoryFile, previous + entry);
|
|
3168
2984
|
ctx.renderer.printSuccess(`Added to memory: "${text.slice(0, 60)}${text.length > 60 ? "\u2026" : ""}"`);
|
|
3169
2985
|
} catch (err) {
|
|
3170
2986
|
ctx.renderer.renderError(`Failed to write memory: ${err instanceof Error ? err.message : String(err)}`);
|
|
3171
2987
|
}
|
|
3172
2988
|
} else if (sub === "clear") {
|
|
3173
|
-
if (!
|
|
2989
|
+
if (!existsSync2(memoryFile)) {
|
|
3174
2990
|
ctx.renderer.printInfo("Memory is already empty");
|
|
3175
2991
|
return;
|
|
3176
2992
|
}
|
|
@@ -3206,20 +3022,20 @@ ${text}
|
|
|
3206
3022
|
console.log(theme.heading("Config Files:"));
|
|
3207
3023
|
console.log(` Dir: ${theme.accent(configDir)}`);
|
|
3208
3024
|
const checkFile = (label, filePath) => {
|
|
3209
|
-
const exists =
|
|
3025
|
+
const exists = existsSync2(filePath);
|
|
3210
3026
|
const icon = exists ? theme.success("\u2713") : theme.dim("\u2013");
|
|
3211
3027
|
let extra = "";
|
|
3212
3028
|
if (exists) {
|
|
3213
3029
|
try {
|
|
3214
|
-
extra = theme.dim(` (${
|
|
3030
|
+
extra = theme.dim(` (${statSync2(filePath).size} bytes)`);
|
|
3215
3031
|
} catch {
|
|
3216
3032
|
}
|
|
3217
3033
|
}
|
|
3218
3034
|
console.log(` ${icon} ${label.padEnd(14)} ${exists ? filePath : theme.dim("(not found)")}${extra}`);
|
|
3219
3035
|
};
|
|
3220
|
-
checkFile("config.json",
|
|
3221
|
-
checkFile("memory.md",
|
|
3222
|
-
checkFile("dev-state.md",
|
|
3036
|
+
checkFile("config.json", join2(configDir, "config.json"));
|
|
3037
|
+
checkFile("memory.md", join2(configDir, MEMORY_FILE_NAME));
|
|
3038
|
+
checkFile("dev-state.md", join2(configDir, "dev-state.md"));
|
|
3223
3039
|
console.log();
|
|
3224
3040
|
const mcpManager = ctx.getMcpManager();
|
|
3225
3041
|
if (mcpManager) {
|
|
@@ -3383,9 +3199,9 @@ ${text}
|
|
|
3383
3199
|
let newFiles = 0;
|
|
3384
3200
|
let modifiedFiles = 0;
|
|
3385
3201
|
for (const [filePath, { earliest }] of fileMap) {
|
|
3386
|
-
const currentContent =
|
|
3202
|
+
const currentContent = existsSync2(filePath) ? (() => {
|
|
3387
3203
|
try {
|
|
3388
|
-
return
|
|
3204
|
+
return readFileSync(filePath, "utf-8");
|
|
3389
3205
|
} catch {
|
|
3390
3206
|
return null;
|
|
3391
3207
|
}
|
|
@@ -3488,6 +3304,8 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
|
|
|
3488
3304
|
console.log(` redactOnSave : ${security.redactOnSave ? theme.success("on") : theme.warning("off")}`);
|
|
3489
3305
|
console.log(` redactOnSend : ${security.redactOnSend ? theme.success("on") : theme.dim("off")}`);
|
|
3490
3306
|
console.log(` mode : ${security.mode}`);
|
|
3307
|
+
console.log(" profile : " + (ctx.config.get("defaultPermissionProfile") ?? "legacy"));
|
|
3308
|
+
console.log(" network : " + (ctx.config.get("networkPolicy")?.enabled ?? false ? "on" : "off"));
|
|
3491
3309
|
console.log(` patterns : ${DEFAULT_PATTERNS.length} built-in + ${security.customPatterns?.length ?? 0} custom`);
|
|
3492
3310
|
console.log(` last save : ${ctx.sessions.lastRedactionHits} hit(s) redacted`);
|
|
3493
3311
|
console.log();
|
|
@@ -3511,12 +3329,12 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
|
|
|
3511
3329
|
if (scanAll) {
|
|
3512
3330
|
const metas = ctx.sessions.listSessions();
|
|
3513
3331
|
console.log(theme.info(` Scanning ${metas.length} session(s)\u2026`));
|
|
3514
|
-
const { readFileSync:
|
|
3515
|
-
const { join:
|
|
3332
|
+
const { readFileSync: readFileSync4 } = await import("fs");
|
|
3333
|
+
const { join: join5 } = await import("path");
|
|
3516
3334
|
const historyDir = ctx.config.getHistoryDir();
|
|
3517
3335
|
for (const m of metas) {
|
|
3518
3336
|
try {
|
|
3519
|
-
const content =
|
|
3337
|
+
const content = readFileSync4(join5(historyDir, `${m.id}.json`), "utf-8");
|
|
3520
3338
|
const hits2 = scanString(content, opts);
|
|
3521
3339
|
if (hits2.length) {
|
|
3522
3340
|
filesWithHits++;
|
|
@@ -4201,12 +4019,12 @@ Managing ${displayName} API Key`);
|
|
|
4201
4019
|
};
|
|
4202
4020
|
|
|
4203
4021
|
// src/repl/custom-commands.ts
|
|
4204
|
-
import { existsSync as
|
|
4205
|
-
import { join as
|
|
4022
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync, mkdirSync as mkdirSync3 } from "fs";
|
|
4023
|
+
import { join as join3, extname } from "path";
|
|
4206
4024
|
function parseCommandFile(filePath) {
|
|
4207
4025
|
let content;
|
|
4208
4026
|
try {
|
|
4209
|
-
content =
|
|
4027
|
+
content = readFileSync2(filePath, "utf-8");
|
|
4210
4028
|
} catch {
|
|
4211
4029
|
return null;
|
|
4212
4030
|
}
|
|
@@ -4230,7 +4048,7 @@ function expandTemplate(template, args) {
|
|
|
4230
4048
|
result = result.replace(/\{\{input\}\}/g, args.join(" "));
|
|
4231
4049
|
result = result.replace(/\{\{file:([^}]+)\}\}/g, (_m, p) => {
|
|
4232
4050
|
try {
|
|
4233
|
-
return
|
|
4051
|
+
return readFileSync2(p.trim(), "utf-8");
|
|
4234
4052
|
} catch {
|
|
4235
4053
|
return `[Error: cannot read ${p.trim()}]`;
|
|
4236
4054
|
}
|
|
@@ -4255,14 +4073,14 @@ var CustomCommandManager = class {
|
|
|
4255
4073
|
commands = /* @__PURE__ */ new Map();
|
|
4256
4074
|
loadCommands() {
|
|
4257
4075
|
this.commands.clear();
|
|
4258
|
-
if (!
|
|
4076
|
+
if (!existsSync3(this.commandsDir)) {
|
|
4259
4077
|
mkdirSync3(this.commandsDir, { recursive: true });
|
|
4260
4078
|
return 0;
|
|
4261
4079
|
}
|
|
4262
4080
|
let count = 0;
|
|
4263
|
-
for (const file of
|
|
4081
|
+
for (const file of readdirSync(this.commandsDir)) {
|
|
4264
4082
|
if (extname(file) !== ".md") continue;
|
|
4265
|
-
const cmd = parseCommandFile(
|
|
4083
|
+
const cmd = parseCommandFile(join3(this.commandsDir, file));
|
|
4266
4084
|
if (cmd) {
|
|
4267
4085
|
this.commands.set(cmd.meta.name, cmd);
|
|
4268
4086
|
count++;
|
|
@@ -4567,17 +4385,17 @@ function parseAtReferences(input2, cwd) {
|
|
|
4567
4385
|
const absPath = resolve2(cwd, rawPath);
|
|
4568
4386
|
const ext = extname2(rawPath).toLowerCase();
|
|
4569
4387
|
const mime = IMAGE_MIME[ext];
|
|
4570
|
-
if (!
|
|
4388
|
+
if (!existsSync4(absPath)) {
|
|
4571
4389
|
refs.push({ path: rawPath, type: "notfound" });
|
|
4572
4390
|
continue;
|
|
4573
4391
|
}
|
|
4574
4392
|
if (mime) {
|
|
4575
|
-
const fileSize =
|
|
4393
|
+
const fileSize = statSync3(absPath).size;
|
|
4576
4394
|
if (fileSize > MAX_IMAGE_BYTES) {
|
|
4577
4395
|
refs.push({ path: rawPath, type: "toolarge" });
|
|
4578
4396
|
continue;
|
|
4579
4397
|
}
|
|
4580
|
-
const data =
|
|
4398
|
+
const data = readFileSync3(absPath).toString("base64");
|
|
4581
4399
|
imageParts.push({
|
|
4582
4400
|
type: "image_url",
|
|
4583
4401
|
image_url: { url: `data:${mime};base64,${data}` }
|
|
@@ -4585,7 +4403,7 @@ function parseAtReferences(input2, cwd) {
|
|
|
4585
4403
|
refs.push({ path: rawPath, type: "image" });
|
|
4586
4404
|
textBody = textBody.replace(match[0], "").trim();
|
|
4587
4405
|
} else {
|
|
4588
|
-
const content =
|
|
4406
|
+
const content = readFileSync3(absPath, "utf-8");
|
|
4589
4407
|
const inlined = `
|
|
4590
4408
|
|
|
4591
4409
|
[File: ${rawPath}]
|
|
@@ -4643,10 +4461,17 @@ var Repl = class {
|
|
|
4643
4461
|
this.toolRegistry = new ToolRegistry();
|
|
4644
4462
|
this.toolExecutor = new ToolExecutor(this.toolRegistry);
|
|
4645
4463
|
this.toolExecutor.setReadline(this.rl);
|
|
4464
|
+
const permissionProfileName = this.config.get("defaultPermissionProfile") ?? "legacy";
|
|
4465
|
+
const permissionProfiles = this.config.get("permissionProfiles") ?? {};
|
|
4646
4466
|
this.toolExecutor.setConfig({
|
|
4647
4467
|
hookConfig: this.config.get("hooks") ?? void 0,
|
|
4648
4468
|
permissionRules: this.config.get("permissionRules") ?? [],
|
|
4649
|
-
defaultPermission: this.config.get("defaultPermission") ?? "confirm"
|
|
4469
|
+
defaultPermission: this.config.get("defaultPermission") ?? "confirm",
|
|
4470
|
+
permissionProfileName,
|
|
4471
|
+
permissionProfile: permissionProfiles[permissionProfileName],
|
|
4472
|
+
allowedPermissionProfiles: this.config.get("allowedPermissionProfiles") ?? [],
|
|
4473
|
+
workspaceRoot: process.cwd(),
|
|
4474
|
+
networkPolicy: this.config.get("networkPolicy")
|
|
4650
4475
|
});
|
|
4651
4476
|
if (this.config.get("alwaysYolo") === true) {
|
|
4652
4477
|
this.toolExecutor.sessionAutoApprove = true;
|
|
@@ -4677,6 +4502,7 @@ var Repl = class {
|
|
|
4677
4502
|
};
|
|
4678
4503
|
/** 当前加载的层级上下文(全局/项目/子目录) */
|
|
4679
4504
|
contextLayers = [];
|
|
4505
|
+
contextLoadResult = null;
|
|
4680
4506
|
/** 本次会话累计 token 用量 */
|
|
4681
4507
|
sessionTokenUsage = { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
4682
4508
|
/** Fold a single-request TokenUsage (with optional cache fields) into sessionTokenUsage + cost tracker.
|
|
@@ -4803,19 +4629,19 @@ var Repl = class {
|
|
|
4803
4629
|
if (depth > 2 || entryCount >= MAX_TREE_ENTRIES) return;
|
|
4804
4630
|
let entries;
|
|
4805
4631
|
try {
|
|
4806
|
-
entries =
|
|
4632
|
+
entries = readdirSync2(dir);
|
|
4807
4633
|
} catch {
|
|
4808
4634
|
return;
|
|
4809
4635
|
}
|
|
4810
4636
|
const filtered = entries.filter((e) => !SKIP_DIRS_SET.has(e));
|
|
4811
4637
|
for (let i = 0; i < filtered.length && entryCount < MAX_TREE_ENTRIES; i++) {
|
|
4812
4638
|
const name = filtered[i];
|
|
4813
|
-
const fullPath =
|
|
4639
|
+
const fullPath = join4(dir, name);
|
|
4814
4640
|
const isLast = i === filtered.length - 1;
|
|
4815
4641
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4816
4642
|
let isDir;
|
|
4817
4643
|
try {
|
|
4818
|
-
isDir =
|
|
4644
|
+
isDir = statSync3(fullPath).isDirectory();
|
|
4819
4645
|
} catch {
|
|
4820
4646
|
continue;
|
|
4821
4647
|
}
|
|
@@ -4837,17 +4663,17 @@ ${treeLines.join("\n")}`
|
|
|
4837
4663
|
if (totalChars >= MAX_TOTAL_CHARS) return;
|
|
4838
4664
|
let entries;
|
|
4839
4665
|
try {
|
|
4840
|
-
entries =
|
|
4666
|
+
entries = readdirSync2(dir);
|
|
4841
4667
|
} catch {
|
|
4842
4668
|
return;
|
|
4843
4669
|
}
|
|
4844
4670
|
for (const name of entries) {
|
|
4845
4671
|
if (totalChars >= MAX_TOTAL_CHARS) break;
|
|
4846
4672
|
if (SKIP_DIRS_SET.has(name)) continue;
|
|
4847
|
-
const fullPath =
|
|
4673
|
+
const fullPath = join4(dir, name);
|
|
4848
4674
|
let st;
|
|
4849
4675
|
try {
|
|
4850
|
-
st =
|
|
4676
|
+
st = statSync3(fullPath);
|
|
4851
4677
|
} catch {
|
|
4852
4678
|
continue;
|
|
4853
4679
|
}
|
|
@@ -4859,7 +4685,7 @@ ${treeLines.join("\n")}`
|
|
|
4859
4685
|
if (!TEXT_EXTS.has(ext) && !isSpecial) continue;
|
|
4860
4686
|
if (st.size > MAX_FILE_CHARS * 3) continue;
|
|
4861
4687
|
try {
|
|
4862
|
-
let content =
|
|
4688
|
+
let content = readFileSync3(fullPath, "utf-8");
|
|
4863
4689
|
if (content.length > MAX_FILE_CHARS) {
|
|
4864
4690
|
content = content.slice(0, MAX_FILE_CHARS) + `
|
|
4865
4691
|
... (truncated, ${content.length} chars total)`;
|
|
@@ -4889,12 +4715,12 @@ ${content}
|
|
|
4889
4715
|
*/
|
|
4890
4716
|
addExtraContextDir(dirPath) {
|
|
4891
4717
|
const absPath = resolve2(dirPath);
|
|
4892
|
-
if (!
|
|
4718
|
+
if (!existsSync4(absPath)) {
|
|
4893
4719
|
return { success: false, charCount: 0, added: false, error: `Directory not found: ${dirPath}` };
|
|
4894
4720
|
}
|
|
4895
4721
|
let isDir;
|
|
4896
4722
|
try {
|
|
4897
|
-
isDir =
|
|
4723
|
+
isDir = statSync3(absPath).isDirectory();
|
|
4898
4724
|
} catch {
|
|
4899
4725
|
return { success: false, charCount: 0, added: false, error: `Cannot access: ${dirPath}` };
|
|
4900
4726
|
}
|
|
@@ -4917,33 +4743,6 @@ ${content}
|
|
|
4917
4743
|
this.extraContextDirs.splice(idx, 1);
|
|
4918
4744
|
return true;
|
|
4919
4745
|
}
|
|
4920
|
-
/**
|
|
4921
|
-
* 在指定目录中按候选文件名列表查找第一个存在且非空的上下文文件。
|
|
4922
|
-
* 返回 { filePath, content } 或 null。
|
|
4923
|
-
*/
|
|
4924
|
-
findContextFile(dir, candidates = CONTEXT_FILE_CANDIDATES) {
|
|
4925
|
-
for (const candidate of candidates) {
|
|
4926
|
-
const fullPath = join5(dir, candidate);
|
|
4927
|
-
if (existsSync5(fullPath)) {
|
|
4928
|
-
const content = readFileSync4(fullPath, "utf-8").trim();
|
|
4929
|
-
if (content) return { filePath: fullPath, content };
|
|
4930
|
-
}
|
|
4931
|
-
}
|
|
4932
|
-
return null;
|
|
4933
|
-
}
|
|
4934
|
-
/**
|
|
4935
|
-
* 加载层级上下文文件系统。
|
|
4936
|
-
*
|
|
4937
|
-
* 三层级结构(按顺序拼接):
|
|
4938
|
-
* 1. 全局层 ~/.aicli/AICLI.md — 所有项目通用的个人偏好
|
|
4939
|
-
* 2. 项目层 <git-root>/AICLI.md — 项目级规则(提交到 git 供团队共享)
|
|
4940
|
-
* 3. 子目录层 <cwd>/AICLI.md — 当前工作子目录的特定指令
|
|
4941
|
-
*
|
|
4942
|
-
* contextFile 配置语义:
|
|
4943
|
-
* - 'auto'(默认):启用三层级自动发现
|
|
4944
|
-
* - false:禁用所有上下文加载
|
|
4945
|
-
* - 具体文件名:仅加载 cwd 下的指定文件(回退到旧的单文件行为)
|
|
4946
|
-
*/
|
|
4947
4746
|
/**
|
|
4948
4747
|
* 加载项目级 .mcp.json 文件(位于 git 根目录或 cwd)。
|
|
4949
4748
|
* 格式兼容 Claude Desktop:`{ "mcpServers": { ... } }`
|
|
@@ -4953,10 +4752,10 @@ ${content}
|
|
|
4953
4752
|
const cwd = process.cwd();
|
|
4954
4753
|
const gitRoot = getGitRoot(cwd);
|
|
4955
4754
|
const projectRoot = gitRoot ?? cwd;
|
|
4956
|
-
const mcpPath =
|
|
4957
|
-
if (!
|
|
4755
|
+
const mcpPath = join4(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
4756
|
+
if (!existsSync4(mcpPath)) return null;
|
|
4958
4757
|
try {
|
|
4959
|
-
const raw = JSON.parse(
|
|
4758
|
+
const raw = JSON.parse(readFileSync3(mcpPath, "utf-8"));
|
|
4960
4759
|
const servers = raw?.mcpServers;
|
|
4961
4760
|
if (!servers || typeof servers !== "object") {
|
|
4962
4761
|
process.stderr.write(
|
|
@@ -4990,79 +4789,25 @@ ${content}
|
|
|
4990
4789
|
}
|
|
4991
4790
|
}
|
|
4992
4791
|
loadHierarchicalContext() {
|
|
4993
|
-
const
|
|
4994
|
-
if (setting === false) return { layers: [], mergedContent: "" };
|
|
4792
|
+
const contextConfig = this.config.get("context");
|
|
4995
4793
|
const cwd = process.cwd();
|
|
4996
|
-
if (setting !== "auto") {
|
|
4997
|
-
const fullPath = resolve2(cwd, String(setting));
|
|
4998
|
-
if (!fullPath.startsWith(resolve2(cwd))) {
|
|
4999
|
-
process.stderr.write(
|
|
5000
|
-
`[Warning] contextFile path "${setting}" is outside current directory, ignoring.
|
|
5001
|
-
`
|
|
5002
|
-
);
|
|
5003
|
-
return { layers: [], mergedContent: "" };
|
|
5004
|
-
}
|
|
5005
|
-
if (existsSync5(fullPath)) {
|
|
5006
|
-
const content = readFileSync4(fullPath, "utf-8").trim();
|
|
5007
|
-
if (content) {
|
|
5008
|
-
const layer = {
|
|
5009
|
-
level: "project",
|
|
5010
|
-
filePath: setting,
|
|
5011
|
-
content,
|
|
5012
|
-
charCount: content.length
|
|
5013
|
-
};
|
|
5014
|
-
return { layers: [layer], mergedContent: content };
|
|
5015
|
-
}
|
|
5016
|
-
}
|
|
5017
|
-
return { layers: [], mergedContent: "" };
|
|
5018
|
-
}
|
|
5019
|
-
const layers = [];
|
|
5020
|
-
const configDir = this.config.getConfigDir();
|
|
5021
|
-
const globalCtx = this.findContextFile(configDir);
|
|
5022
|
-
if (globalCtx) {
|
|
5023
|
-
layers.push({
|
|
5024
|
-
level: "global",
|
|
5025
|
-
filePath: globalCtx.filePath,
|
|
5026
|
-
content: globalCtx.content,
|
|
5027
|
-
charCount: globalCtx.content.length
|
|
5028
|
-
});
|
|
5029
|
-
}
|
|
5030
4794
|
const gitRoot = getGitRoot(cwd);
|
|
5031
4795
|
const projectRoot = gitRoot ?? cwd;
|
|
5032
|
-
const
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
const normalizedRoot = resolve2(projectRoot);
|
|
5043
|
-
if (normalizedCwd !== normalizedRoot) {
|
|
5044
|
-
const localCtx = this.findContextFile(cwd);
|
|
5045
|
-
if (localCtx) {
|
|
5046
|
-
layers.push({
|
|
5047
|
-
level: "local",
|
|
5048
|
-
filePath: localCtx.filePath,
|
|
5049
|
-
content: localCtx.content,
|
|
5050
|
-
charCount: localCtx.content.length
|
|
5051
|
-
});
|
|
5052
|
-
}
|
|
5053
|
-
}
|
|
5054
|
-
const mergedContent = layers.map((l) => l.content).join("\n\n---\n\n");
|
|
5055
|
-
return { layers, mergedContent };
|
|
4796
|
+
const result = loadContextFiles({
|
|
4797
|
+
cwd,
|
|
4798
|
+
configDir: this.config.getConfigDir(),
|
|
4799
|
+
projectRoot,
|
|
4800
|
+
setting: this.config.get("contextFile"),
|
|
4801
|
+
fallbackFilenames: contextConfig.projectDocFallbackFilenames,
|
|
4802
|
+
maxBytes: contextConfig.projectDocMaxBytes
|
|
4803
|
+
});
|
|
4804
|
+
this.contextLoadResult = result;
|
|
4805
|
+
return { layers: result.layers, mergedContent: result.mergedContent };
|
|
5056
4806
|
}
|
|
5057
|
-
/**
|
|
5058
|
-
* 加载持久记忆内容(~/.aicli/memory.md)。
|
|
5059
|
-
* 不存在或为空时返回 null。
|
|
5060
|
-
* 超过 MEMORY_MAX_CHARS 时只取末尾最新部分。
|
|
5061
|
-
*/
|
|
5062
4807
|
loadMemoryContent() {
|
|
5063
|
-
const memoryPath =
|
|
5064
|
-
if (!
|
|
5065
|
-
let content =
|
|
4808
|
+
const memoryPath = join4(this.config.getConfigDir(), MEMORY_FILE_NAME);
|
|
4809
|
+
if (!existsSync4(memoryPath)) return null;
|
|
4810
|
+
let content = readFileSync3(memoryPath, "utf-8").trim();
|
|
5066
4811
|
if (!content) return null;
|
|
5067
4812
|
if (content.length > MEMORY_MAX_CHARS) {
|
|
5068
4813
|
content = content.slice(-MEMORY_MAX_CHARS);
|
|
@@ -5397,6 +5142,11 @@ Session '${this.resumeSessionId}' not found.
|
|
|
5397
5142
|
theme.warning(" \u26A1 YOLO mode ON (alwaysYolo=true in config) \u2014 write tools auto-approved; destructive tools still require confirmation.\n")
|
|
5398
5143
|
);
|
|
5399
5144
|
}
|
|
5145
|
+
const permissionProfileWarning = formatPermissionProfileWarning(this.config.get("defaultPermissionProfile") ?? "legacy");
|
|
5146
|
+
if (permissionProfileWarning) {
|
|
5147
|
+
process.stdout.write(theme.warning(` ${permissionProfileWarning}
|
|
5148
|
+
`));
|
|
5149
|
+
}
|
|
5400
5150
|
const cfgOutputCap = this.config.get("maxToolOutputChars");
|
|
5401
5151
|
if (typeof cfgOutputCap === "number" && cfgOutputCap > 0) setMaxOutputCap(cfgOutputCap);
|
|
5402
5152
|
if (welcomeModelInfo?.contextWindow) setContextWindow(welcomeModelInfo.contextWindow);
|
|
@@ -5450,14 +5200,14 @@ Session '${this.resumeSessionId}' not found.
|
|
|
5450
5200
|
process.stdout.write(theme.dim(` \u{1F50C} Plugins loaded: ${pluginCount} tool(s) from plugins/
|
|
5451
5201
|
`));
|
|
5452
5202
|
}
|
|
5453
|
-
const skillsDir =
|
|
5203
|
+
const skillsDir = join4(this.config.getConfigDir(), SKILLS_DIR_NAME);
|
|
5454
5204
|
this.skillManager = new SkillManager(skillsDir, this.config.get("ui").skillSizeWarn);
|
|
5455
5205
|
const skillCount = this.skillManager.loadSkills();
|
|
5456
5206
|
if (skillCount > 0) {
|
|
5457
5207
|
process.stdout.write(theme.dim(` \u{1F3AF} Skills: ${skillCount} available (use /skill to manage)
|
|
5458
5208
|
`));
|
|
5459
5209
|
}
|
|
5460
|
-
const commandsDir =
|
|
5210
|
+
const commandsDir = join4(this.config.getConfigDir(), CUSTOM_COMMANDS_DIR_NAME);
|
|
5461
5211
|
this.customCommandManager = new CustomCommandManager(commandsDir);
|
|
5462
5212
|
const customCmdCount = this.customCommandManager.loadCommands();
|
|
5463
5213
|
if (customCmdCount > 0) {
|
|
@@ -6093,15 +5843,15 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6093
5843
|
const dir = normalized.includes("/") ? dirname3(normalized) : ".";
|
|
6094
5844
|
const prefix = normalized.includes("/") ? basename2(normalized) : normalized;
|
|
6095
5845
|
const absDir = resolve2(process.cwd(), dir);
|
|
6096
|
-
if (!
|
|
6097
|
-
const entries =
|
|
5846
|
+
if (!existsSync4(absDir)) return [];
|
|
5847
|
+
const entries = readdirSync2(absDir);
|
|
6098
5848
|
const results = [];
|
|
6099
5849
|
for (const entry of entries) {
|
|
6100
5850
|
if (entry.startsWith(".")) continue;
|
|
6101
5851
|
if (!entry.toLowerCase().startsWith(prefix.toLowerCase())) continue;
|
|
6102
5852
|
try {
|
|
6103
|
-
const fullPath =
|
|
6104
|
-
const stat =
|
|
5853
|
+
const fullPath = join4(absDir, entry);
|
|
5854
|
+
const stat = statSync3(fullPath);
|
|
6105
5855
|
const rel = dir === "." ? entry : `${dir}/${entry}`;
|
|
6106
5856
|
results.push(stat.isDirectory() ? `${rel}/` : rel);
|
|
6107
5857
|
} catch {
|
|
@@ -7270,7 +7020,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7270
7020
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7271
7021
|
process.exit(1);
|
|
7272
7022
|
}
|
|
7273
|
-
const { startWebServer } = await import("./server-
|
|
7023
|
+
const { startWebServer } = await import("./server-BTSKOPQI.js");
|
|
7274
7024
|
await startWebServer({ port, host: options.host });
|
|
7275
7025
|
});
|
|
7276
7026
|
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) => {
|
|
@@ -7437,16 +7187,16 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7437
7187
|
console.log(footer + "\n");
|
|
7438
7188
|
});
|
|
7439
7189
|
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) => {
|
|
7440
|
-
const { runUsageCli } = await import("./usage-
|
|
7190
|
+
const { runUsageCli } = await import("./usage-T2P6FTE7.js");
|
|
7441
7191
|
await runUsageCli(options);
|
|
7442
7192
|
});
|
|
7443
7193
|
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) => {
|
|
7444
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7194
|
+
const { runDoctorCli } = await import("./doctor-cli-SSI6ETFT.js");
|
|
7445
7195
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7446
7196
|
});
|
|
7447
7197
|
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) => {
|
|
7448
7198
|
try {
|
|
7449
|
-
const batch = await import("./batch-
|
|
7199
|
+
const batch = await import("./batch-DE4RXKZD.js");
|
|
7450
7200
|
switch (action) {
|
|
7451
7201
|
case "submit":
|
|
7452
7202
|
if (!arg) {
|
|
@@ -7489,7 +7239,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7489
7239
|
}
|
|
7490
7240
|
});
|
|
7491
7241
|
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) => {
|
|
7492
|
-
const { startMcpServer } = await import("./server-
|
|
7242
|
+
const { startMcpServer } = await import("./server-7USZJJAH.js");
|
|
7493
7243
|
await startMcpServer({
|
|
7494
7244
|
allowDestructive: !!options.allowDestructive,
|
|
7495
7245
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7498,7 +7248,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
|
|
|
7498
7248
|
});
|
|
7499
7249
|
});
|
|
7500
7250
|
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) => {
|
|
7501
|
-
const { runCi } = await import("./ci-
|
|
7251
|
+
const { runCi } = await import("./ci-XMUEX526.js");
|
|
7502
7252
|
const result = await runCi({
|
|
7503
7253
|
pr: options.pr,
|
|
7504
7254
|
base: options.base,
|
|
@@ -7644,7 +7394,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7644
7394
|
}),
|
|
7645
7395
|
config.get("customProviders")
|
|
7646
7396
|
);
|
|
7647
|
-
const { startHub } = await import("./hub-
|
|
7397
|
+
const { startHub } = await import("./hub-INUJND2G.js");
|
|
7648
7398
|
await startHub(
|
|
7649
7399
|
{
|
|
7650
7400
|
topic: topic ?? "",
|
|
@@ -7744,7 +7494,27 @@ ${options.prompt}` : options.prompt;
|
|
|
7744
7494
|
const maxTokens = modelParams.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
7745
7495
|
const timeout = modelParams.timeout ?? 6e4;
|
|
7746
7496
|
const temperature = modelParams.temperature;
|
|
7747
|
-
|
|
7497
|
+
let systemPrompt = options.system;
|
|
7498
|
+
if (!systemPrompt) {
|
|
7499
|
+
const contextConfig = config.get("context");
|
|
7500
|
+
const cwd = process.cwd();
|
|
7501
|
+
const gitRoot = getGitRoot(cwd);
|
|
7502
|
+
const loaded = loadContextFiles({
|
|
7503
|
+
cwd,
|
|
7504
|
+
configDir: config.getConfigDir(),
|
|
7505
|
+
projectRoot: gitRoot ?? cwd,
|
|
7506
|
+
setting: config.get("contextFile"),
|
|
7507
|
+
fallbackFilenames: contextConfig.projectDocFallbackFilenames,
|
|
7508
|
+
maxBytes: contextConfig.projectDocMaxBytes
|
|
7509
|
+
});
|
|
7510
|
+
const parts = [
|
|
7511
|
+
config.get("session").systemPrompt,
|
|
7512
|
+
loaded.mergedContent ? `# Project Context
|
|
7513
|
+
|
|
7514
|
+
${loaded.mergedContent}` : void 0
|
|
7515
|
+
].filter(Boolean);
|
|
7516
|
+
systemPrompt = parts.length > 0 ? parts.join("\n\n---\n\n") : void 0;
|
|
7517
|
+
}
|
|
7748
7518
|
const isStreamingJson = options.outputFormat === "streaming-json";
|
|
7749
7519
|
const useStream = options.stream !== false && !options.json && !isStreamingJson;
|
|
7750
7520
|
try {
|