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.
- package/README.md +10 -8
- package/README.zh-CN.md +5 -5
- package/dist/{batch-3T44NFLG.js → batch-MFPYHOIL.js} +4 -4
- package/dist/{chunk-TD7JEHCR.js → chunk-7JWT3KXO.js} +390 -23
- package/dist/{chunk-SQB66GP6.js → chunk-BNERFXVO.js} +12 -9
- package/dist/{chunk-J22B3OSQ.js → chunk-DJ35G5VO.js} +1 -1
- package/dist/{chunk-VWYUB22Y.js → chunk-E2ZWWE6Q.js} +1 -1
- package/dist/{chunk-KV4GYNEA.js → chunk-GRJNQJA5.js} +5 -3
- package/dist/{chunk-QDY72ABW.js → chunk-HZQVX7VF.js} +5 -3
- package/dist/{chunk-O6UFCEUZ.js → chunk-K3CF65QH.js} +12 -9
- package/dist/{chunk-2OVMMSGQ.js → chunk-NEPFADHX.js} +10 -9
- package/dist/{chunk-P7JY3SWA.js → chunk-NWP7C6CC.js} +1 -1
- package/dist/{chunk-TM4MS63K.js → chunk-P6MTFCXB.js} +14 -6
- package/dist/{ci-6QWBVRJX.js → ci-QLJUDLMY.js} +3 -2
- package/dist/{constants-SZTQNN7K.js → constants-47OR72MV.js} +3 -1
- package/dist/{doctor-cli-I2Y2YR4V.js → doctor-cli-32COMA5K.js} +4 -4
- package/dist/electron-server.js +652 -457
- package/dist/{hub-XVPFBODB.js → hub-3NWJUCLK.js} +1 -1
- package/dist/index.js +128 -376
- package/dist/{indexer-AKWMYNJI.js → indexer-2AG4G6B5.js} +1 -1
- package/dist/{indexer-BMYUUDLH.js → indexer-4WWS3VIL.js} +1 -1
- package/dist/{run-tests-HZ2CRCTZ.js → run-tests-NT2UIUVB.js} +1 -1
- package/dist/{run-tests-D5SNUBYX.js → run-tests-UT7RZ7Y3.js} +2 -2
- package/dist/{server-PVKLPRUP.js → server-AIHVMLNU.js} +5 -5
- package/dist/{server-4EFTRFTN.js → server-E5D54DIZ.js} +87 -306
- package/dist/{task-orchestrator-2A5VCFLS.js → task-orchestrator-BFDSTSOH.js} +5 -5
- package/dist/{usage-Q24E5636.js → usage-P4B2RZKL.js} +2 -2
- 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-
|
|
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-
|
|
42
|
+
} from "./chunk-NEPFADHX.js";
|
|
39
43
|
import "./chunk-T2NL5ZIA.js";
|
|
40
44
|
import "./chunk-BXP6YZ2P.js";
|
|
41
|
-
import "./chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
148
|
-
import { join as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
1519
|
-
console.log(" 2. Project : <git-root>/
|
|
1520
|
-
console.log(" 3. Local : <cwd>/
|
|
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:
|
|
1833
|
-
const { existsSync:
|
|
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-
|
|
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 =
|
|
1653
|
+
const mcpPath = join5(projectRoot, MCP_PROJECT_CONFIG_NAME2);
|
|
1840
1654
|
console.log();
|
|
1841
|
-
if (!
|
|
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 =
|
|
1988
|
+
const targetPath = join2(cwd, "AICLI.md");
|
|
2175
1989
|
const force = args.includes("--force");
|
|
2176
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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 =
|
|
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 (!
|
|
2950
|
+
if (!existsSync2(memoryFile)) {
|
|
3139
2951
|
ctx.renderer.printInfo("Memory is empty (memory.md not found)");
|
|
3140
2952
|
return;
|
|
3141
2953
|
}
|
|
3142
|
-
const content =
|
|
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
|
-
|
|
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 (!
|
|
2986
|
+
if (!existsSync2(memoryFile)) {
|
|
3174
2987
|
ctx.renderer.printInfo("Memory is already empty");
|
|
3175
2988
|
return;
|
|
3176
2989
|
}
|
|
3177
2990
|
try {
|
|
3178
|
-
|
|
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 =
|
|
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(` (${
|
|
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",
|
|
3221
|
-
checkFile("memory.md",
|
|
3222
|
-
checkFile("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 =
|
|
3199
|
+
const currentContent = existsSync2(filePath) ? (() => {
|
|
3387
3200
|
try {
|
|
3388
|
-
return
|
|
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:
|
|
3515
|
-
const { join:
|
|
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 =
|
|
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
|
|
4205
|
-
import { join as
|
|
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 =
|
|
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
|
|
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
|
|
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 (!
|
|
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
|
|
4076
|
+
for (const file of readdirSync(this.commandsDir)) {
|
|
4265
4077
|
if (extname(file) !== ".md") continue;
|
|
4266
|
-
const cmd = parseCommandFile(
|
|
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 (!
|
|
4383
|
+
if (!existsSync4(absPath)) {
|
|
4572
4384
|
refs.push({ path: rawPath, type: "notfound" });
|
|
4573
4385
|
continue;
|
|
4574
4386
|
}
|
|
4575
4387
|
if (mime) {
|
|
4576
|
-
const fileSize =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
4661
|
+
const fullPath = join4(dir, name);
|
|
4849
4662
|
let st;
|
|
4850
4663
|
try {
|
|
4851
|
-
st =
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
4958
|
-
if (!
|
|
4743
|
+
const mcpPath = join4(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
4744
|
+
if (!existsSync4(mcpPath)) return null;
|
|
4959
4745
|
try {
|
|
4960
|
-
const raw = JSON.parse(
|
|
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
|
|
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
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
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 =
|
|
5065
|
-
if (!
|
|
5066
|
-
let content =
|
|
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 =
|
|
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 =
|
|
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-
|
|
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 (!
|
|
6098
|
-
const entries =
|
|
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 =
|
|
6105
|
-
const stat =
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
|
|
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 {
|