jinzd-ai-cli 0.4.209 → 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 +5 -5
- package/README.zh-CN.md +5 -5
- package/dist/{batch-45WLJUVP.js → batch-MFPYHOIL.js} +2 -2
- package/dist/{chunk-ATNYI6JL.js → chunk-7JWT3KXO.js} +374 -22
- package/dist/{chunk-STIEOOOL.js → chunk-DJ35G5VO.js} +1 -1
- package/dist/{chunk-EN63JA7N.js → chunk-E2ZWWE6Q.js} +1 -1
- package/dist/{chunk-UPMBIS4T.js → chunk-GRJNQJA5.js} +5 -3
- package/dist/{chunk-EYID2AIR.js → chunk-HZQVX7VF.js} +5 -3
- package/dist/{chunk-JVLRMIHA.js → chunk-NEPFADHX.js} +3 -3
- package/dist/{chunk-D6M4E7SH.js → chunk-NWP7C6CC.js} +1 -1
- package/dist/{chunk-DUZRQXIP.js → chunk-P6MTFCXB.js} +9 -4
- package/dist/{ci-PUE3MQ7J.js → ci-QLJUDLMY.js} +2 -2
- package/dist/{constants-VTZLKDAG.js → constants-47OR72MV.js} +3 -1
- package/dist/{doctor-cli-IU6FSVLF.js → doctor-cli-32COMA5K.js} +4 -4
- package/dist/electron-server.js +589 -427
- package/dist/{hub-4ETK4R2J.js → hub-3NWJUCLK.js} +1 -1
- package/dist/index.js +119 -366
- package/dist/{run-tests-UAS5NJBM.js → run-tests-NT2UIUVB.js} +1 -1
- package/dist/{run-tests-NDS2IEMK.js → run-tests-UT7RZ7Y3.js} +2 -2
- package/dist/{server-72SAPLPS.js → server-AIHVMLNU.js} +4 -4
- package/dist/{server-4URLNC7P.js → server-E5D54DIZ.js} +50 -291
- package/dist/{task-orchestrator-6PZTB35T.js → task-orchestrator-BFDSTSOH.js} +4 -4
- package/dist/{usage-ZNCKGF6U.js → usage-P4B2RZKL.js} +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,22 +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,
|
|
15
13
|
readGitDiff,
|
|
16
14
|
saveDevState,
|
|
15
|
+
scanProject,
|
|
17
16
|
sessionHasMeaningfulContent,
|
|
18
17
|
setupProxy
|
|
19
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-7JWT3KXO.js";
|
|
19
|
+
import {
|
|
20
|
+
buildReviewPrompt,
|
|
21
|
+
buildSecurityReviewPrompt
|
|
22
|
+
} from "./chunk-HLWUDRBO.js";
|
|
20
23
|
import {
|
|
21
24
|
ToolExecutor,
|
|
22
25
|
ToolRegistry,
|
|
@@ -36,10 +39,10 @@ import {
|
|
|
36
39
|
spawnAgentContext,
|
|
37
40
|
theme,
|
|
38
41
|
undoStack
|
|
39
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-NEPFADHX.js";
|
|
40
43
|
import "./chunk-T2NL5ZIA.js";
|
|
41
44
|
import "./chunk-BXP6YZ2P.js";
|
|
42
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-E2ZWWE6Q.js";
|
|
43
46
|
import {
|
|
44
47
|
SessionManager,
|
|
45
48
|
getContentText
|
|
@@ -56,7 +59,7 @@ import {
|
|
|
56
59
|
getConfigDirUsage,
|
|
57
60
|
listRecentCrashes,
|
|
58
61
|
writeCrashLog
|
|
59
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-NWP7C6CC.js";
|
|
60
63
|
import {
|
|
61
64
|
ProviderRegistry
|
|
62
65
|
} from "./chunk-QMXC327F.js";
|
|
@@ -65,7 +68,7 @@ import {
|
|
|
65
68
|
getTopFailingTools,
|
|
66
69
|
getTopUsedTools,
|
|
67
70
|
installFlushOnExit
|
|
68
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-DJ35G5VO.js";
|
|
69
72
|
import {
|
|
70
73
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
71
74
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -87,7 +90,7 @@ import {
|
|
|
87
90
|
} from "./chunk-XPBEJB27.js";
|
|
88
91
|
import {
|
|
89
92
|
ConfigManager
|
|
90
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-P6MTFCXB.js";
|
|
91
94
|
import {
|
|
92
95
|
AuthError,
|
|
93
96
|
ProviderError,
|
|
@@ -98,7 +101,6 @@ import {
|
|
|
98
101
|
AUTHOR,
|
|
99
102
|
AUTHOR_EMAIL,
|
|
100
103
|
CONFIG_DIR_NAME,
|
|
101
|
-
CONTEXT_FILE_CANDIDATES,
|
|
102
104
|
CONTEXT_PRESSURE_THRESHOLD,
|
|
103
105
|
CUSTOM_COMMANDS_DIR_NAME,
|
|
104
106
|
DEFAULT_MAX_TOKENS,
|
|
@@ -114,7 +116,7 @@ import {
|
|
|
114
116
|
SKILLS_DIR_NAME,
|
|
115
117
|
VERSION,
|
|
116
118
|
buildUserIdentityPrompt
|
|
117
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-GRJNQJA5.js";
|
|
118
120
|
import {
|
|
119
121
|
formatGitContextForPrompt,
|
|
120
122
|
getGitContext,
|
|
@@ -145,8 +147,8 @@ import { program } from "commander";
|
|
|
145
147
|
|
|
146
148
|
// src/repl/repl.ts
|
|
147
149
|
import * as readline from "readline";
|
|
148
|
-
import { existsSync as
|
|
149
|
-
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";
|
|
150
152
|
import chalk4 from "chalk";
|
|
151
153
|
|
|
152
154
|
// src/session/title-generator.ts
|
|
@@ -638,10 +640,10 @@ Error${typeName}: ${lines.join("\n")}
|
|
|
638
640
|
};
|
|
639
641
|
|
|
640
642
|
// src/repl/commands/index.ts
|
|
641
|
-
import { writeFileSync, mkdirSync as mkdirSync2, existsSync as
|
|
643
|
+
import { writeFileSync, mkdirSync as mkdirSync2, existsSync as existsSync2, readFileSync, statSync as statSync2 } from "fs";
|
|
642
644
|
import { execSync as execSync2 } from "child_process";
|
|
643
645
|
import { platform } from "os";
|
|
644
|
-
import { resolve, dirname as dirname2, join as
|
|
646
|
+
import { resolve, dirname as dirname2, join as join2, basename } from "path";
|
|
645
647
|
import chalk2 from "chalk";
|
|
646
648
|
|
|
647
649
|
// src/repl/clipboard.ts
|
|
@@ -731,195 +733,6 @@ function getClipboardHint() {
|
|
|
731
733
|
return "";
|
|
732
734
|
}
|
|
733
735
|
|
|
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
736
|
// src/repl/commands/index.ts
|
|
924
737
|
function fmtCtx(tokens) {
|
|
925
738
|
if (tokens >= 1e6) return `${Math.round(tokens / 1e5) / 10}M`;
|
|
@@ -1489,7 +1302,7 @@ No commands match "${filter}".
|
|
|
1489
1302
|
{
|
|
1490
1303
|
name: "context",
|
|
1491
1304
|
description: "Show or reload hierarchical context files",
|
|
1492
|
-
usage: "/context [reload]",
|
|
1305
|
+
usage: "/context [status|reload]",
|
|
1493
1306
|
execute(args, ctx) {
|
|
1494
1307
|
const sub = args[0];
|
|
1495
1308
|
if (sub === "reload") {
|
|
@@ -1499,7 +1312,7 @@ No commands match "${filter}".
|
|
|
1499
1312
|
const summary = layers2.map((l) => `${l.level}:${l.charCount}`).join(", ");
|
|
1500
1313
|
ctx.renderer.printSuccess(`Context reloaded: ${layers2.length} layer(s) (${summary} chars)`);
|
|
1501
1314
|
} else {
|
|
1502
|
-
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/.");
|
|
1503
1316
|
}
|
|
1504
1317
|
return;
|
|
1505
1318
|
}
|
|
@@ -1509,16 +1322,16 @@ No commands match "${filter}".
|
|
|
1509
1322
|
console.log(" Context layers:");
|
|
1510
1323
|
const levelLabels = { global: "Global ", project: "Project", local: "Local " };
|
|
1511
1324
|
for (const l of layers) {
|
|
1512
|
-
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" : ""})`);
|
|
1513
1326
|
}
|
|
1514
1327
|
const totalChars = layers.reduce((s, l) => s + l.charCount, 0);
|
|
1515
1328
|
console.log(` Total : ${totalChars} chars (${layers.length} layer${layers.length > 1 ? "s" : ""})`);
|
|
1516
1329
|
} else {
|
|
1517
1330
|
console.log(" No context files loaded.");
|
|
1518
1331
|
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>/
|
|
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)");
|
|
1522
1335
|
}
|
|
1523
1336
|
console.log();
|
|
1524
1337
|
}
|
|
@@ -1830,16 +1643,16 @@ No tools match "${filter}".
|
|
|
1830
1643
|
usage: "/mcp [reconnect [serverId] | trust-project]",
|
|
1831
1644
|
async execute(args, ctx) {
|
|
1832
1645
|
if (args[0] === "trust-project") {
|
|
1833
|
-
const { join:
|
|
1834
|
-
const { existsSync:
|
|
1646
|
+
const { join: join5 } = await import("path");
|
|
1647
|
+
const { existsSync: existsSync5 } = await import("fs");
|
|
1835
1648
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
|
|
1836
|
-
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");
|
|
1837
1650
|
const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
|
|
1838
1651
|
const cwd = process.cwd();
|
|
1839
1652
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
1840
|
-
const mcpPath =
|
|
1653
|
+
const mcpPath = join5(projectRoot, MCP_PROJECT_CONFIG_NAME2);
|
|
1841
1654
|
console.log();
|
|
1842
|
-
if (!
|
|
1655
|
+
if (!existsSync5(mcpPath)) {
|
|
1843
1656
|
console.log(theme.dim(` No .mcp.json in ${projectRoot}.`));
|
|
1844
1657
|
console.log();
|
|
1845
1658
|
return;
|
|
@@ -2172,9 +1985,9 @@ No tools match "${filter}".
|
|
|
2172
1985
|
usage: "/init [--force]",
|
|
2173
1986
|
async execute(args, ctx) {
|
|
2174
1987
|
const cwd = process.cwd();
|
|
2175
|
-
const targetPath =
|
|
1988
|
+
const targetPath = join2(cwd, "AICLI.md");
|
|
2176
1989
|
const force = args.includes("--force");
|
|
2177
|
-
if (
|
|
1990
|
+
if (existsSync2(targetPath) && !force) {
|
|
2178
1991
|
ctx.renderer.printInfo(`AICLI.md already exists at ${targetPath}`);
|
|
2179
1992
|
ctx.renderer.printInfo("Use /init --force to overwrite, or edit it manually.");
|
|
2180
1993
|
return;
|
|
@@ -2892,7 +2705,7 @@ ${hint}` : "")
|
|
|
2892
2705
|
usage: "/test [command|filter]",
|
|
2893
2706
|
async execute(args, ctx) {
|
|
2894
2707
|
try {
|
|
2895
|
-
const { executeTests } = await import("./run-tests-
|
|
2708
|
+
const { executeTests } = await import("./run-tests-UT7RZ7Y3.js");
|
|
2896
2709
|
const argStr = args.join(" ").trim();
|
|
2897
2710
|
let testArgs = {};
|
|
2898
2711
|
if (argStr) {
|
|
@@ -3050,7 +2863,7 @@ ${hint}` : "")
|
|
|
3050
2863
|
description: "Persistent memory (memory.md) + chat memory recall index (v0.4.89+)",
|
|
3051
2864
|
usage: "/memory [show|add <text>|clear|path|rebuild|refresh|status|recall <query>|index-clear]",
|
|
3052
2865
|
async execute(args, ctx) {
|
|
3053
|
-
const memoryFile =
|
|
2866
|
+
const memoryFile = join2(ctx.config.getConfigDir(), MEMORY_FILE_NAME);
|
|
3054
2867
|
const sub = args[0] ?? "show";
|
|
3055
2868
|
if (sub === "rebuild" || sub === "refresh") {
|
|
3056
2869
|
const full = sub === "rebuild";
|
|
@@ -3134,11 +2947,11 @@ ${hint}` : "")
|
|
|
3134
2947
|
return;
|
|
3135
2948
|
}
|
|
3136
2949
|
if (sub === "show" || sub === "view") {
|
|
3137
|
-
if (!
|
|
2950
|
+
if (!existsSync2(memoryFile)) {
|
|
3138
2951
|
ctx.renderer.printInfo("Memory is empty (memory.md not found)");
|
|
3139
2952
|
return;
|
|
3140
2953
|
}
|
|
3141
|
-
const content =
|
|
2954
|
+
const content = readFileSync(memoryFile, "utf-8").trim();
|
|
3142
2955
|
if (!content) {
|
|
3143
2956
|
ctx.renderer.printInfo("Memory is empty");
|
|
3144
2957
|
return;
|
|
@@ -3163,14 +2976,14 @@ ${text}
|
|
|
3163
2976
|
`;
|
|
3164
2977
|
try {
|
|
3165
2978
|
mkdirSync2(dirname2(memoryFile), { recursive: true });
|
|
3166
|
-
const previous =
|
|
2979
|
+
const previous = existsSync2(memoryFile) ? readFileSync(memoryFile, "utf-8") : "";
|
|
3167
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
|
}
|
|
@@ -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,12 +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
|
|
4017
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync, mkdirSync as mkdirSync3 } from "fs";
|
|
4018
|
+
import { join as join3, extname } from "path";
|
|
4206
4019
|
function parseCommandFile(filePath) {
|
|
4207
4020
|
let content;
|
|
4208
4021
|
try {
|
|
4209
|
-
content =
|
|
4022
|
+
content = readFileSync2(filePath, "utf-8");
|
|
4210
4023
|
} catch {
|
|
4211
4024
|
return null;
|
|
4212
4025
|
}
|
|
@@ -4230,7 +4043,7 @@ function expandTemplate(template, args) {
|
|
|
4230
4043
|
result = result.replace(/\{\{input\}\}/g, args.join(" "));
|
|
4231
4044
|
result = result.replace(/\{\{file:([^}]+)\}\}/g, (_m, p) => {
|
|
4232
4045
|
try {
|
|
4233
|
-
return
|
|
4046
|
+
return readFileSync2(p.trim(), "utf-8");
|
|
4234
4047
|
} catch {
|
|
4235
4048
|
return `[Error: cannot read ${p.trim()}]`;
|
|
4236
4049
|
}
|
|
@@ -4255,14 +4068,14 @@ var CustomCommandManager = class {
|
|
|
4255
4068
|
commands = /* @__PURE__ */ new Map();
|
|
4256
4069
|
loadCommands() {
|
|
4257
4070
|
this.commands.clear();
|
|
4258
|
-
if (!
|
|
4071
|
+
if (!existsSync3(this.commandsDir)) {
|
|
4259
4072
|
mkdirSync3(this.commandsDir, { recursive: true });
|
|
4260
4073
|
return 0;
|
|
4261
4074
|
}
|
|
4262
4075
|
let count = 0;
|
|
4263
|
-
for (const file of
|
|
4076
|
+
for (const file of readdirSync(this.commandsDir)) {
|
|
4264
4077
|
if (extname(file) !== ".md") continue;
|
|
4265
|
-
const cmd = parseCommandFile(
|
|
4078
|
+
const cmd = parseCommandFile(join3(this.commandsDir, file));
|
|
4266
4079
|
if (cmd) {
|
|
4267
4080
|
this.commands.set(cmd.meta.name, cmd);
|
|
4268
4081
|
count++;
|
|
@@ -4567,17 +4380,17 @@ function parseAtReferences(input2, cwd) {
|
|
|
4567
4380
|
const absPath = resolve2(cwd, rawPath);
|
|
4568
4381
|
const ext = extname2(rawPath).toLowerCase();
|
|
4569
4382
|
const mime = IMAGE_MIME[ext];
|
|
4570
|
-
if (!
|
|
4383
|
+
if (!existsSync4(absPath)) {
|
|
4571
4384
|
refs.push({ path: rawPath, type: "notfound" });
|
|
4572
4385
|
continue;
|
|
4573
4386
|
}
|
|
4574
4387
|
if (mime) {
|
|
4575
|
-
const fileSize =
|
|
4388
|
+
const fileSize = statSync3(absPath).size;
|
|
4576
4389
|
if (fileSize > MAX_IMAGE_BYTES) {
|
|
4577
4390
|
refs.push({ path: rawPath, type: "toolarge" });
|
|
4578
4391
|
continue;
|
|
4579
4392
|
}
|
|
4580
|
-
const data =
|
|
4393
|
+
const data = readFileSync3(absPath).toString("base64");
|
|
4581
4394
|
imageParts.push({
|
|
4582
4395
|
type: "image_url",
|
|
4583
4396
|
image_url: { url: `data:${mime};base64,${data}` }
|
|
@@ -4585,7 +4398,7 @@ function parseAtReferences(input2, cwd) {
|
|
|
4585
4398
|
refs.push({ path: rawPath, type: "image" });
|
|
4586
4399
|
textBody = textBody.replace(match[0], "").trim();
|
|
4587
4400
|
} else {
|
|
4588
|
-
const content =
|
|
4401
|
+
const content = readFileSync3(absPath, "utf-8");
|
|
4589
4402
|
const inlined = `
|
|
4590
4403
|
|
|
4591
4404
|
[File: ${rawPath}]
|
|
@@ -4677,6 +4490,7 @@ var Repl = class {
|
|
|
4677
4490
|
};
|
|
4678
4491
|
/** 当前加载的层级上下文(全局/项目/子目录) */
|
|
4679
4492
|
contextLayers = [];
|
|
4493
|
+
contextLoadResult = null;
|
|
4680
4494
|
/** 本次会话累计 token 用量 */
|
|
4681
4495
|
sessionTokenUsage = { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
4682
4496
|
/** Fold a single-request TokenUsage (with optional cache fields) into sessionTokenUsage + cost tracker.
|
|
@@ -4803,19 +4617,19 @@ var Repl = class {
|
|
|
4803
4617
|
if (depth > 2 || entryCount >= MAX_TREE_ENTRIES) return;
|
|
4804
4618
|
let entries;
|
|
4805
4619
|
try {
|
|
4806
|
-
entries =
|
|
4620
|
+
entries = readdirSync2(dir);
|
|
4807
4621
|
} catch {
|
|
4808
4622
|
return;
|
|
4809
4623
|
}
|
|
4810
4624
|
const filtered = entries.filter((e) => !SKIP_DIRS_SET.has(e));
|
|
4811
4625
|
for (let i = 0; i < filtered.length && entryCount < MAX_TREE_ENTRIES; i++) {
|
|
4812
4626
|
const name = filtered[i];
|
|
4813
|
-
const fullPath =
|
|
4627
|
+
const fullPath = join4(dir, name);
|
|
4814
4628
|
const isLast = i === filtered.length - 1;
|
|
4815
4629
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4816
4630
|
let isDir;
|
|
4817
4631
|
try {
|
|
4818
|
-
isDir =
|
|
4632
|
+
isDir = statSync3(fullPath).isDirectory();
|
|
4819
4633
|
} catch {
|
|
4820
4634
|
continue;
|
|
4821
4635
|
}
|
|
@@ -4837,17 +4651,17 @@ ${treeLines.join("\n")}`
|
|
|
4837
4651
|
if (totalChars >= MAX_TOTAL_CHARS) return;
|
|
4838
4652
|
let entries;
|
|
4839
4653
|
try {
|
|
4840
|
-
entries =
|
|
4654
|
+
entries = readdirSync2(dir);
|
|
4841
4655
|
} catch {
|
|
4842
4656
|
return;
|
|
4843
4657
|
}
|
|
4844
4658
|
for (const name of entries) {
|
|
4845
4659
|
if (totalChars >= MAX_TOTAL_CHARS) break;
|
|
4846
4660
|
if (SKIP_DIRS_SET.has(name)) continue;
|
|
4847
|
-
const fullPath =
|
|
4661
|
+
const fullPath = join4(dir, name);
|
|
4848
4662
|
let st;
|
|
4849
4663
|
try {
|
|
4850
|
-
st =
|
|
4664
|
+
st = statSync3(fullPath);
|
|
4851
4665
|
} catch {
|
|
4852
4666
|
continue;
|
|
4853
4667
|
}
|
|
@@ -4859,7 +4673,7 @@ ${treeLines.join("\n")}`
|
|
|
4859
4673
|
if (!TEXT_EXTS.has(ext) && !isSpecial) continue;
|
|
4860
4674
|
if (st.size > MAX_FILE_CHARS * 3) continue;
|
|
4861
4675
|
try {
|
|
4862
|
-
let content =
|
|
4676
|
+
let content = readFileSync3(fullPath, "utf-8");
|
|
4863
4677
|
if (content.length > MAX_FILE_CHARS) {
|
|
4864
4678
|
content = content.slice(0, MAX_FILE_CHARS) + `
|
|
4865
4679
|
... (truncated, ${content.length} chars total)`;
|
|
@@ -4889,12 +4703,12 @@ ${content}
|
|
|
4889
4703
|
*/
|
|
4890
4704
|
addExtraContextDir(dirPath) {
|
|
4891
4705
|
const absPath = resolve2(dirPath);
|
|
4892
|
-
if (!
|
|
4706
|
+
if (!existsSync4(absPath)) {
|
|
4893
4707
|
return { success: false, charCount: 0, added: false, error: `Directory not found: ${dirPath}` };
|
|
4894
4708
|
}
|
|
4895
4709
|
let isDir;
|
|
4896
4710
|
try {
|
|
4897
|
-
isDir =
|
|
4711
|
+
isDir = statSync3(absPath).isDirectory();
|
|
4898
4712
|
} catch {
|
|
4899
4713
|
return { success: false, charCount: 0, added: false, error: `Cannot access: ${dirPath}` };
|
|
4900
4714
|
}
|
|
@@ -4917,33 +4731,6 @@ ${content}
|
|
|
4917
4731
|
this.extraContextDirs.splice(idx, 1);
|
|
4918
4732
|
return true;
|
|
4919
4733
|
}
|
|
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
4734
|
/**
|
|
4948
4735
|
* 加载项目级 .mcp.json 文件(位于 git 根目录或 cwd)。
|
|
4949
4736
|
* 格式兼容 Claude Desktop:`{ "mcpServers": { ... } }`
|
|
@@ -4953,10 +4740,10 @@ ${content}
|
|
|
4953
4740
|
const cwd = process.cwd();
|
|
4954
4741
|
const gitRoot = getGitRoot(cwd);
|
|
4955
4742
|
const projectRoot = gitRoot ?? cwd;
|
|
4956
|
-
const mcpPath =
|
|
4957
|
-
if (!
|
|
4743
|
+
const mcpPath = join4(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
4744
|
+
if (!existsSync4(mcpPath)) return null;
|
|
4958
4745
|
try {
|
|
4959
|
-
const raw = JSON.parse(
|
|
4746
|
+
const raw = JSON.parse(readFileSync3(mcpPath, "utf-8"));
|
|
4960
4747
|
const servers = raw?.mcpServers;
|
|
4961
4748
|
if (!servers || typeof servers !== "object") {
|
|
4962
4749
|
process.stderr.write(
|
|
@@ -4990,79 +4777,25 @@ ${content}
|
|
|
4990
4777
|
}
|
|
4991
4778
|
}
|
|
4992
4779
|
loadHierarchicalContext() {
|
|
4993
|
-
const
|
|
4994
|
-
if (setting === false) return { layers: [], mergedContent: "" };
|
|
4780
|
+
const contextConfig = this.config.get("context");
|
|
4995
4781
|
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
4782
|
const gitRoot = getGitRoot(cwd);
|
|
5031
4783
|
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 };
|
|
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 };
|
|
5056
4794
|
}
|
|
5057
|
-
/**
|
|
5058
|
-
* 加载持久记忆内容(~/.aicli/memory.md)。
|
|
5059
|
-
* 不存在或为空时返回 null。
|
|
5060
|
-
* 超过 MEMORY_MAX_CHARS 时只取末尾最新部分。
|
|
5061
|
-
*/
|
|
5062
4795
|
loadMemoryContent() {
|
|
5063
|
-
const memoryPath =
|
|
5064
|
-
if (!
|
|
5065
|
-
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();
|
|
5066
4799
|
if (!content) return null;
|
|
5067
4800
|
if (content.length > MEMORY_MAX_CHARS) {
|
|
5068
4801
|
content = content.slice(-MEMORY_MAX_CHARS);
|
|
@@ -5450,14 +5183,14 @@ Session '${this.resumeSessionId}' not found.
|
|
|
5450
5183
|
process.stdout.write(theme.dim(` \u{1F50C} Plugins loaded: ${pluginCount} tool(s) from plugins/
|
|
5451
5184
|
`));
|
|
5452
5185
|
}
|
|
5453
|
-
const skillsDir =
|
|
5186
|
+
const skillsDir = join4(this.config.getConfigDir(), SKILLS_DIR_NAME);
|
|
5454
5187
|
this.skillManager = new SkillManager(skillsDir, this.config.get("ui").skillSizeWarn);
|
|
5455
5188
|
const skillCount = this.skillManager.loadSkills();
|
|
5456
5189
|
if (skillCount > 0) {
|
|
5457
5190
|
process.stdout.write(theme.dim(` \u{1F3AF} Skills: ${skillCount} available (use /skill to manage)
|
|
5458
5191
|
`));
|
|
5459
5192
|
}
|
|
5460
|
-
const commandsDir =
|
|
5193
|
+
const commandsDir = join4(this.config.getConfigDir(), CUSTOM_COMMANDS_DIR_NAME);
|
|
5461
5194
|
this.customCommandManager = new CustomCommandManager(commandsDir);
|
|
5462
5195
|
const customCmdCount = this.customCommandManager.loadCommands();
|
|
5463
5196
|
if (customCmdCount > 0) {
|
|
@@ -6093,15 +5826,15 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6093
5826
|
const dir = normalized.includes("/") ? dirname3(normalized) : ".";
|
|
6094
5827
|
const prefix = normalized.includes("/") ? basename2(normalized) : normalized;
|
|
6095
5828
|
const absDir = resolve2(process.cwd(), dir);
|
|
6096
|
-
if (!
|
|
6097
|
-
const entries =
|
|
5829
|
+
if (!existsSync4(absDir)) return [];
|
|
5830
|
+
const entries = readdirSync2(absDir);
|
|
6098
5831
|
const results = [];
|
|
6099
5832
|
for (const entry of entries) {
|
|
6100
5833
|
if (entry.startsWith(".")) continue;
|
|
6101
5834
|
if (!entry.toLowerCase().startsWith(prefix.toLowerCase())) continue;
|
|
6102
5835
|
try {
|
|
6103
|
-
const fullPath =
|
|
6104
|
-
const stat =
|
|
5836
|
+
const fullPath = join4(absDir, entry);
|
|
5837
|
+
const stat = statSync3(fullPath);
|
|
6105
5838
|
const rel = dir === "." ? entry : `${dir}/${entry}`;
|
|
6106
5839
|
results.push(stat.isDirectory() ? `${rel}/` : rel);
|
|
6107
5840
|
} catch {
|
|
@@ -7270,7 +7003,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
7270
7003
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
7271
7004
|
process.exit(1);
|
|
7272
7005
|
}
|
|
7273
|
-
const { startWebServer } = await import("./server-
|
|
7006
|
+
const { startWebServer } = await import("./server-E5D54DIZ.js");
|
|
7274
7007
|
await startWebServer({ port, host: options.host });
|
|
7275
7008
|
});
|
|
7276
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) => {
|
|
@@ -7437,16 +7170,16 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
7437
7170
|
console.log(footer + "\n");
|
|
7438
7171
|
});
|
|
7439
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) => {
|
|
7440
|
-
const { runUsageCli } = await import("./usage-
|
|
7173
|
+
const { runUsageCli } = await import("./usage-P4B2RZKL.js");
|
|
7441
7174
|
await runUsageCli(options);
|
|
7442
7175
|
});
|
|
7443
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) => {
|
|
7444
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7177
|
+
const { runDoctorCli } = await import("./doctor-cli-32COMA5K.js");
|
|
7445
7178
|
await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
|
|
7446
7179
|
});
|
|
7447
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) => {
|
|
7448
7181
|
try {
|
|
7449
|
-
const batch = await import("./batch-
|
|
7182
|
+
const batch = await import("./batch-MFPYHOIL.js");
|
|
7450
7183
|
switch (action) {
|
|
7451
7184
|
case "submit":
|
|
7452
7185
|
if (!arg) {
|
|
@@ -7489,7 +7222,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
7489
7222
|
}
|
|
7490
7223
|
});
|
|
7491
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) => {
|
|
7492
|
-
const { startMcpServer } = await import("./server-
|
|
7225
|
+
const { startMcpServer } = await import("./server-AIHVMLNU.js");
|
|
7493
7226
|
await startMcpServer({
|
|
7494
7227
|
allowDestructive: !!options.allowDestructive,
|
|
7495
7228
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -7498,7 +7231,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
|
|
|
7498
7231
|
});
|
|
7499
7232
|
});
|
|
7500
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) => {
|
|
7501
|
-
const { runCi } = await import("./ci-
|
|
7234
|
+
const { runCi } = await import("./ci-QLJUDLMY.js");
|
|
7502
7235
|
const result = await runCi({
|
|
7503
7236
|
pr: options.pr,
|
|
7504
7237
|
base: options.base,
|
|
@@ -7644,7 +7377,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
7644
7377
|
}),
|
|
7645
7378
|
config.get("customProviders")
|
|
7646
7379
|
);
|
|
7647
|
-
const { startHub } = await import("./hub-
|
|
7380
|
+
const { startHub } = await import("./hub-3NWJUCLK.js");
|
|
7648
7381
|
await startHub(
|
|
7649
7382
|
{
|
|
7650
7383
|
topic: topic ?? "",
|
|
@@ -7744,7 +7477,27 @@ ${options.prompt}` : options.prompt;
|
|
|
7744
7477
|
const maxTokens = modelParams.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
7745
7478
|
const timeout = modelParams.timeout ?? 6e4;
|
|
7746
7479
|
const temperature = modelParams.temperature;
|
|
7747
|
-
|
|
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
|
+
}
|
|
7748
7501
|
const isStreamingJson = options.outputFormat === "streaming-json";
|
|
7749
7502
|
const useStream = options.stream !== false && !options.json && !isStreamingJson;
|
|
7750
7503
|
try {
|