jinzd-ai-cli 0.4.264 → 0.4.266
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 +59 -37
- package/README.zh-CN.md +63 -41
- package/dist/{batch-Q22M55UP.js → batch-FQU6HK3Z.js} +2 -2
- package/dist/{chunk-VT6NRDD2.js → chunk-23SJVOQD.js} +6 -2
- package/dist/{chunk-K7HQLXXQ.js → chunk-3O4VLKD4.js} +1 -1
- package/dist/chunk-5C76XDDF.js +78 -0
- package/dist/chunk-6YZEZFX5.js +40 -0
- package/dist/{chunk-TL5MD5XU.js → chunk-AUEX6RNY.js} +17 -1
- package/dist/{chunk-IAIUXBB5.js → chunk-CEJUB4YV.js} +1 -1
- package/dist/{chunk-4T4KHPRD.js → chunk-FA3HGXXM.js} +1 -1
- package/dist/{chunk-BMSBFK7J.js → chunk-FIDEG2PG.js} +4 -4
- package/dist/{chunk-UQP2BNQT.js → chunk-GWOZET2E.js} +1 -1
- package/dist/{chunk-JVUYKO4V.js → chunk-LGJ7EX2F.js} +1 -1
- package/dist/{chunk-TANTNIGP.js → chunk-LHY7ST6X.js} +1 -1
- package/dist/{chunk-QCZFHQHY.js → chunk-N2E6GFLZ.js} +1 -1
- package/dist/{chunk-U4XQIP7Z.js → chunk-QW76RX6G.js} +1 -1
- package/dist/{chunk-UGJIRJ4H.js → chunk-TJNBSR3I.js} +1 -1
- package/dist/{chunk-IEYR2BGG.js → chunk-UCHND2K6.js} +65 -2
- package/dist/{chunk-QG4NG7KJ.js → chunk-V4D7YD24.js} +9 -2
- package/dist/{chunk-3ARPAVNV.js → chunk-VOIOUJXI.js} +11 -3
- package/dist/{chunk-DYONT23T.js → chunk-XEVURCAM.js} +13 -8
- package/dist/{chunk-53SOOMYG.js → chunk-Y2X24VYB.js} +24 -95
- package/dist/{ci-RMEIHZJL.js → ci-GZH3QMME.js} +6 -5
- package/dist/{ci-format-UCFSWVG5.js → ci-format-VKP2MGYJ.js} +2 -2
- package/dist/{constants-Z2R2BKUY.js → constants-ICAF6I3J.js} +1 -1
- package/dist/{doctor-cli-64L7BBK7.js → doctor-cli-CO6BJWRW.js} +5 -5
- package/dist/electron-server.js +127 -26
- package/dist/{hub-P7D6VDCK.js → hub-4APIRQ73.js} +8 -4
- package/dist/{hub-server-QGUSMN22.js → hub-server-RF6LURXY.js} +3 -1
- package/dist/index.js +125 -582
- package/dist/{persistent-memory-CELKJM4U.js → persistent-memory-YD3SHSUH.js} +2 -2
- package/dist/{persistent-memory-QX6C2JAR.js → persistent-memory-YPO25MOP.js} +2 -2
- package/dist/{pr-DJP53EZV.js → pr-CDOPCAPK.js} +15 -10
- package/dist/{run-tests-CK44KRY3.js → run-tests-4XRHKHN5.js} +2 -2
- package/dist/{run-tests-A2YM4U2U.js → run-tests-QNNP2HCD.js} +2 -2
- package/dist/{server-XYVL7A33.js → server-53GM3CRH.js} +34 -29
- package/dist/{server-GUV2HZ7N.js → server-B4A7LHZ5.js} +6 -5
- package/dist/setup-wizard-S55ICNHH.js +483 -0
- package/dist/{task-orchestrator-5RT5EH2J.js → task-orchestrator-WNV6PT6Z.js} +10 -7
- package/dist/{usage-LGPJ4UAW.js → usage-E3FEYSBU.js} +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
CostTracker
|
|
4
|
-
} from "./chunk-QG4NG7KJ.js";
|
|
5
2
|
import {
|
|
6
3
|
McpManager,
|
|
7
4
|
SNAPSHOT_PROMPT,
|
|
8
5
|
SkillManager,
|
|
6
|
+
applyThinkCommand,
|
|
9
7
|
autoTrimSessionIfNeeded,
|
|
10
8
|
buildInitPrompt,
|
|
11
9
|
clearDevState,
|
|
@@ -17,7 +15,10 @@ import {
|
|
|
17
15
|
scanProject,
|
|
18
16
|
sessionHasMeaningfulContent,
|
|
19
17
|
setupProxy
|
|
20
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UCHND2K6.js";
|
|
19
|
+
import {
|
|
20
|
+
CostTracker
|
|
21
|
+
} from "./chunk-V4D7YD24.js";
|
|
21
22
|
import {
|
|
22
23
|
computeCost,
|
|
23
24
|
formatCost,
|
|
@@ -27,6 +28,12 @@ import {
|
|
|
27
28
|
buildReviewPrompt,
|
|
28
29
|
buildSecurityReviewPrompt
|
|
29
30
|
} from "./chunk-HLWUDRBO.js";
|
|
31
|
+
import {
|
|
32
|
+
NO_THINKING,
|
|
33
|
+
applyThinkingFlag,
|
|
34
|
+
chatParamsFrom,
|
|
35
|
+
thinkingParamsFor
|
|
36
|
+
} from "./chunk-6YZEZFX5.js";
|
|
30
37
|
import {
|
|
31
38
|
ToolExecutor,
|
|
32
39
|
ToolRegistry,
|
|
@@ -38,7 +45,6 @@ import {
|
|
|
38
45
|
formatPermissionProfileWarning,
|
|
39
46
|
getRecentlyDeniedAutoActions,
|
|
40
47
|
googleSearchContext,
|
|
41
|
-
initTheme,
|
|
42
48
|
isInterrupted,
|
|
43
49
|
lastResponseStore,
|
|
44
50
|
renderDiff,
|
|
@@ -48,9 +54,8 @@ import {
|
|
|
48
54
|
setContextWindow,
|
|
49
55
|
setMaxOutputCap,
|
|
50
56
|
spawnAgentContext,
|
|
51
|
-
theme,
|
|
52
57
|
undoStack
|
|
53
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-Y2X24VYB.js";
|
|
54
59
|
import {
|
|
55
60
|
addMemoryEntry,
|
|
56
61
|
backupMemoryStore,
|
|
@@ -76,11 +81,15 @@ import {
|
|
|
76
81
|
touchMemoryReferences,
|
|
77
82
|
updateMemoryApproval,
|
|
78
83
|
updateMemoryEntry
|
|
79
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-3O4VLKD4.js";
|
|
80
85
|
import "./chunk-GLSR2NR3.js";
|
|
81
86
|
import "./chunk-UUSRWSSX.js";
|
|
82
87
|
import "./chunk-CKH4KQ4E.js";
|
|
83
88
|
import "./chunk-BXP6YZ2P.js";
|
|
89
|
+
import {
|
|
90
|
+
initTheme,
|
|
91
|
+
theme
|
|
92
|
+
} from "./chunk-5C76XDDF.js";
|
|
84
93
|
import {
|
|
85
94
|
SessionManager,
|
|
86
95
|
getContentText
|
|
@@ -90,14 +99,14 @@ import {
|
|
|
90
99
|
formatDoctorReport,
|
|
91
100
|
loadContextFiles,
|
|
92
101
|
writeCrashLog
|
|
93
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-FIDEG2PG.js";
|
|
94
103
|
import {
|
|
95
104
|
ProviderRegistry,
|
|
96
105
|
listBuiltInProviderMetadata
|
|
97
|
-
} from "./chunk-
|
|
106
|
+
} from "./chunk-AUEX6RNY.js";
|
|
98
107
|
import {
|
|
99
108
|
ConfigManager
|
|
100
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-CEJUB4YV.js";
|
|
101
110
|
import {
|
|
102
111
|
describePlugin,
|
|
103
112
|
getActivePluginAssets,
|
|
@@ -114,7 +123,7 @@ import {
|
|
|
114
123
|
trustHook,
|
|
115
124
|
trustPlugin,
|
|
116
125
|
untrustHook
|
|
117
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-QW76RX6G.js";
|
|
118
127
|
import {
|
|
119
128
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
120
129
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -148,7 +157,7 @@ import {
|
|
|
148
157
|
import {
|
|
149
158
|
fileCheckpoints
|
|
150
159
|
} from "./chunk-4BKXL7SM.js";
|
|
151
|
-
import "./chunk-
|
|
160
|
+
import "./chunk-N2E6GFLZ.js";
|
|
152
161
|
import {
|
|
153
162
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
154
163
|
AUTHOR,
|
|
@@ -167,7 +176,7 @@ import {
|
|
|
167
176
|
SKILLS_DIR_NAME,
|
|
168
177
|
VERSION,
|
|
169
178
|
buildUserIdentityPrompt
|
|
170
|
-
} from "./chunk-
|
|
179
|
+
} from "./chunk-LGJ7EX2F.js";
|
|
171
180
|
import {
|
|
172
181
|
buildChatIndex,
|
|
173
182
|
clearChatIndex,
|
|
@@ -237,7 +246,10 @@ Now produce the title (\u2264 12 Chinese chars or \u2264 6 English words):`,
|
|
|
237
246
|
systemPrompt: SYSTEM_PROMPT,
|
|
238
247
|
stream: false,
|
|
239
248
|
maxTokens: 40,
|
|
240
|
-
temperature: 0.3
|
|
249
|
+
temperature: 0.3,
|
|
250
|
+
// 生成标题不值得付推理成本;显式关而不是靠「未配置即关」的默认兜底——
|
|
251
|
+
// 默认值是产品决策,哪天再变,靠默认的调用点会跟着一起变贵(审计 P0-01)。
|
|
252
|
+
...NO_THINKING
|
|
241
253
|
});
|
|
242
254
|
const title = sanitizeTitle(resp.content);
|
|
243
255
|
if (!title) return;
|
|
@@ -1141,46 +1153,24 @@ function createProviderCommands() {
|
|
|
1141
1153
|
description: "Toggle Extended Thinking mode (deep reasoning for supported models)",
|
|
1142
1154
|
usage: "/think [on|off|low|high|max|status]",
|
|
1143
1155
|
execute(args, ctx) {
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
ctx.
|
|
1147
|
-
ctx.
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
ctx.
|
|
1156
|
-
|
|
1157
|
-
console.log();
|
|
1158
|
-
return;
|
|
1159
|
-
}
|
|
1160
|
-
if (sub === "low" || sub === "high" || sub === "max") {
|
|
1161
|
-
ctx.setThinkingMode(true);
|
|
1162
|
-
ctx.setThinkingEffort(sub);
|
|
1163
|
-
ctx.renderer.printSuccess(`Extended Thinking enabled (effort: ${sub}).`);
|
|
1164
|
-
console.log();
|
|
1165
|
-
return;
|
|
1166
|
-
}
|
|
1167
|
-
if (sub === "status") {
|
|
1168
|
-
const mode = ctx.getThinkingMode();
|
|
1169
|
-
const label = mode === true ? theme.accent("ON (runtime override)") : mode === false ? theme.dim("OFF (runtime override)") : theme.dim("using config value");
|
|
1170
|
-
console.log(` Extended Thinking: ${label}`);
|
|
1171
|
-
console.log(` Reasoning effort: ${ctx.getThinkingEffort() ?? "using config/default (high for DeepSeek V4)"}`);
|
|
1172
|
-
console.log();
|
|
1173
|
-
return;
|
|
1174
|
-
}
|
|
1175
|
-
const current = ctx.getThinkingMode();
|
|
1176
|
-
if (current === true) {
|
|
1177
|
-
ctx.setThinkingMode(false);
|
|
1178
|
-
ctx.renderer.printSuccess("Extended Thinking disabled.");
|
|
1156
|
+
const outcome = applyThinkCommand(args[0], {
|
|
1157
|
+
runtimeThinking: ctx.getThinkingMode(),
|
|
1158
|
+
runtimeEffort: ctx.getThinkingEffort(),
|
|
1159
|
+
configuredThinking: ctx.getConfiguredThinking(),
|
|
1160
|
+
configuredEffort: ctx.getConfiguredThinkingEffort(),
|
|
1161
|
+
supportsEffort: ctx.getProviderSupportsReasoningEffort(),
|
|
1162
|
+
provider: ctx.getCurrentProvider()
|
|
1163
|
+
});
|
|
1164
|
+
if (outcome.changed) {
|
|
1165
|
+
ctx.setThinkingMode(outcome.runtimeThinking);
|
|
1166
|
+
ctx.setThinkingEffort(outcome.runtimeEffort);
|
|
1167
|
+
ctx.renderer.printSuccess(outcome.effective ? `${outcome.summary} \u{1F4AD}` : outcome.summary);
|
|
1168
|
+
} else if (outcome.summary.startsWith("Unknown")) {
|
|
1169
|
+
console.log(theme.warning(` ${outcome.summary}`));
|
|
1179
1170
|
} else {
|
|
1180
|
-
|
|
1181
|
-
ctx.renderer.printSuccess("Extended Thinking enabled \u{1F4AD}");
|
|
1182
|
-
console.log(theme.dim(" Use /think off to disable."));
|
|
1171
|
+
console.log(` ${outcome.effective ? theme.accent(outcome.summary) : theme.dim(outcome.summary)}`);
|
|
1183
1172
|
}
|
|
1173
|
+
for (const line of outcome.details) console.log(theme.dim(` ${line}`));
|
|
1184
1174
|
console.log();
|
|
1185
1175
|
}
|
|
1186
1176
|
},
|
|
@@ -1340,12 +1330,12 @@ No tools match "${filter}".
|
|
|
1340
1330
|
return;
|
|
1341
1331
|
}
|
|
1342
1332
|
if (sub === "install") {
|
|
1343
|
-
const
|
|
1344
|
-
if (!
|
|
1333
|
+
const input = args[1];
|
|
1334
|
+
if (!input) {
|
|
1345
1335
|
ctx.renderer.printInfo("Usage: /plugin install <path-to-plugin-dir>");
|
|
1346
1336
|
return;
|
|
1347
1337
|
}
|
|
1348
|
-
const plugin = installPlugin(configDir,
|
|
1338
|
+
const plugin = installPlugin(configDir, input);
|
|
1349
1339
|
ctx.renderer.printSuccess(`Installed plugin ${plugin.name}@${plugin.manifest.version}. Run /plugin trust ${plugin.name}, then /plugin enable ${plugin.name}.`);
|
|
1350
1340
|
return;
|
|
1351
1341
|
}
|
|
@@ -1407,7 +1397,7 @@ No tools match "${filter}".
|
|
|
1407
1397
|
const { join: join6 } = await import("path");
|
|
1408
1398
|
const { existsSync: existsSync6 } = await import("fs");
|
|
1409
1399
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
|
|
1410
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
1400
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-ICAF6I3J.js");
|
|
1411
1401
|
const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
|
|
1412
1402
|
const cwd = process.cwd();
|
|
1413
1403
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
@@ -2395,7 +2385,7 @@ function createReviewCommands() {
|
|
|
2395
2385
|
usage: "/test [command|filter]",
|
|
2396
2386
|
async execute(args, ctx) {
|
|
2397
2387
|
try {
|
|
2398
|
-
const { executeTests } = await import("./run-tests-
|
|
2388
|
+
const { executeTests } = await import("./run-tests-QNNP2HCD.js");
|
|
2399
2389
|
const argStr = args.join(" ").trim();
|
|
2400
2390
|
let testArgs = {};
|
|
2401
2391
|
if (argStr) {
|
|
@@ -3782,17 +3772,20 @@ ${text}
|
|
|
3782
3772
|
}
|
|
3783
3773
|
const provider = ctx.getCurrentProvider();
|
|
3784
3774
|
const model = ctx.getCurrentModel();
|
|
3785
|
-
const cost = computeCost(provider, model, usage);
|
|
3786
3775
|
const pricing = getPricing(provider, model);
|
|
3776
|
+
const accrued = ctx.getSessionAccruedCost();
|
|
3777
|
+
const usedAccrual = accrued.usd > 0;
|
|
3778
|
+
const cost = usedAccrual ? accrued.usd : computeCost(provider, model, usage);
|
|
3787
3779
|
let savings = null;
|
|
3788
|
-
|
|
3780
|
+
const liveCost = computeCost(provider, model, usage);
|
|
3781
|
+
if (liveCost != null && pricing && cacheRead > 0) {
|
|
3789
3782
|
const costWithoutCache = computeCost(provider, model, {
|
|
3790
3783
|
inputTokens: usage.inputTokens + cacheRead,
|
|
3791
3784
|
outputTokens: usage.outputTokens,
|
|
3792
3785
|
cacheCreationTokens: cacheCreate,
|
|
3793
3786
|
cacheReadTokens: 0
|
|
3794
3787
|
});
|
|
3795
|
-
if (costWithoutCache != null) savings = costWithoutCache -
|
|
3788
|
+
if (costWithoutCache != null) savings = costWithoutCache - liveCost;
|
|
3796
3789
|
}
|
|
3797
3790
|
console.log();
|
|
3798
3791
|
console.log(theme.heading(" \u{1F4B0} Session Cost & Token Usage"));
|
|
@@ -3812,6 +3805,11 @@ ${text}
|
|
|
3812
3805
|
console.log(theme.dim(" " + "\u2500".repeat(48)));
|
|
3813
3806
|
if (cost != null) {
|
|
3814
3807
|
console.log(theme.dim(" Cost : ") + chalk3.bold.cyan(formatCost(cost).padStart(12)));
|
|
3808
|
+
if (usedAccrual && accrued.incomplete) {
|
|
3809
|
+
console.log(theme.dim(" (partial \u2014 some turns had unknown pricing)"));
|
|
3810
|
+
} else if (!usedAccrual) {
|
|
3811
|
+
console.log(theme.dim(" (estimated at current rates)"));
|
|
3812
|
+
}
|
|
3815
3813
|
if (savings != null && savings > 0) {
|
|
3816
3814
|
console.log(
|
|
3817
3815
|
theme.dim(" Cache savings : ") + chalk3.green(`-${formatCost(savings)}`.padStart(12)) + theme.dim(` (vs no cache)`)
|
|
@@ -4484,482 +4482,6 @@ var streamToFileContext = {
|
|
|
4484
4482
|
extraMessages: []
|
|
4485
4483
|
};
|
|
4486
4484
|
|
|
4487
|
-
// src/repl/setup-wizard.ts
|
|
4488
|
-
import { password, select, input, confirm } from "@inquirer/prompts";
|
|
4489
|
-
var PROVIDERS = [
|
|
4490
|
-
{ value: "claude", name: "Claude (Anthropic)" },
|
|
4491
|
-
{ value: "gemini", name: "Gemini (Google)" },
|
|
4492
|
-
{ value: "deepseek", name: "DeepSeek" },
|
|
4493
|
-
{ value: "zhipu", name: "Zhipu (GLM)" },
|
|
4494
|
-
{ value: "kimi", name: "Kimi (Moonshot AI)" },
|
|
4495
|
-
{ value: "minimax", name: "MiniMax (\u6D77\u87BA)" },
|
|
4496
|
-
{ value: "qwen", name: "Qwen (Alibaba Cloud)" },
|
|
4497
|
-
{ value: "openai", name: "OpenAI" },
|
|
4498
|
-
{ value: "openrouter", name: "OpenRouter" },
|
|
4499
|
-
{ value: "ollama", name: "Ollama (Local)" }
|
|
4500
|
-
];
|
|
4501
|
-
var NO_KEY_PROVIDERS = /* @__PURE__ */ new Set(["ollama"]);
|
|
4502
|
-
var OLLAMA_DEFAULT_HOST = "http://localhost:11434";
|
|
4503
|
-
function maskKey(key) {
|
|
4504
|
-
if (key.length <= 10) return "****";
|
|
4505
|
-
return key.slice(0, 6) + "****" + key.slice(-4);
|
|
4506
|
-
}
|
|
4507
|
-
function errorMessage(err) {
|
|
4508
|
-
if (err instanceof Error && err.message) return err.message;
|
|
4509
|
-
return String(err ?? "unknown error");
|
|
4510
|
-
}
|
|
4511
|
-
var SetupWizard = class {
|
|
4512
|
-
constructor(config) {
|
|
4513
|
-
this.config = config;
|
|
4514
|
-
}
|
|
4515
|
-
config;
|
|
4516
|
-
async runFirstRun() {
|
|
4517
|
-
console.log(theme.heading("\nWelcome to ai-cli!\n"));
|
|
4518
|
-
console.log("Let's get to know you first, then set up your AI provider.\n");
|
|
4519
|
-
try {
|
|
4520
|
-
await this.setupProfile();
|
|
4521
|
-
console.log();
|
|
4522
|
-
const providerId = await select({
|
|
4523
|
-
message: "Which AI provider do you want to set up first?",
|
|
4524
|
-
choices: PROVIDERS
|
|
4525
|
-
});
|
|
4526
|
-
await this.setupProvider(providerId);
|
|
4527
|
-
this.config.set("defaultProvider", providerId);
|
|
4528
|
-
this.config.save();
|
|
4529
|
-
const nickname = this.config.get("userProfile")?.nickname;
|
|
4530
|
-
const greeting = nickname ? `Setup complete, ${nickname}!` : "Setup complete!";
|
|
4531
|
-
console.log(theme.success(`
|
|
4532
|
-
${greeting} Starting ai-cli...
|
|
4533
|
-
`));
|
|
4534
|
-
return true;
|
|
4535
|
-
} catch (err) {
|
|
4536
|
-
const message = errorMessage(err);
|
|
4537
|
-
const canceled = /user force closed|interrupted|cancel|aborted/i.test(message);
|
|
4538
|
-
if (canceled) {
|
|
4539
|
-
console.log(theme.warning("\nSetup canceled. Run aicli config to try again.\n"));
|
|
4540
|
-
} else {
|
|
4541
|
-
console.log(theme.error(`
|
|
4542
|
-
First-run setup failed: ${message}`));
|
|
4543
|
-
console.log(theme.dim(`Config directory: ${this.config.getConfigDir()}`));
|
|
4544
|
-
console.log(theme.dim("Run aicli config to retry, or aicli doctor to inspect provider/config health.\n"));
|
|
4545
|
-
}
|
|
4546
|
-
return false;
|
|
4547
|
-
}
|
|
4548
|
-
}
|
|
4549
|
-
async runFull() {
|
|
4550
|
-
console.log(theme.heading("\nai-cli Configuration\n"));
|
|
4551
|
-
let running = true;
|
|
4552
|
-
while (running) {
|
|
4553
|
-
const currentProxy = this.config.get("proxy") ?? "";
|
|
4554
|
-
const proxyStatus = currentProxy ? theme.success(`[${currentProxy}]`) : theme.dim("[not configured]");
|
|
4555
|
-
const googleKeyStatus = this.config.getApiKey("google-search") ? theme.success("[configured]") : theme.dim("[not configured]");
|
|
4556
|
-
const profileName = this.config.get("userProfile")?.nickname || this.config.get("userProfile")?.name;
|
|
4557
|
-
const profileStatus = profileName ? theme.success(`[${profileName}]`) : theme.dim("[not configured]");
|
|
4558
|
-
const yoloOn = this.config.get("alwaysYolo") === true;
|
|
4559
|
-
const mcpOff = this.config.get("mcpEnabled") === false;
|
|
4560
|
-
const behaviorFlags = [];
|
|
4561
|
-
if (yoloOn) behaviorFlags.push("YOLO on");
|
|
4562
|
-
if (mcpOff) behaviorFlags.push("MCP off");
|
|
4563
|
-
const behaviorStatus = behaviorFlags.length ? theme.warning(`[${behaviorFlags.join(", ")}]`) : theme.dim("[default]");
|
|
4564
|
-
const action = await select({
|
|
4565
|
-
message: "What would you like to configure?",
|
|
4566
|
-
choices: [
|
|
4567
|
-
{ value: "profile", name: `Edit your profile (identity) ${profileStatus}` },
|
|
4568
|
-
{ value: "apikey", name: "Manage API key for a provider" },
|
|
4569
|
-
{ value: "default", name: "Change default provider" },
|
|
4570
|
-
{ value: "proxy", name: `Configure proxy (HTTP/HTTPS) ${proxyStatus}` },
|
|
4571
|
-
{ value: "google", name: `Configure Google Search (API Key + CX) ${googleKeyStatus}` },
|
|
4572
|
-
{ value: "behavior", name: `Behavior toggles (YOLO, MCP, ...) ${behaviorStatus}` },
|
|
4573
|
-
{ value: "preset", name: "Apply task preset (safe review, workspace coding, local-only, team web)" },
|
|
4574
|
-
{ value: "done", name: "Done" }
|
|
4575
|
-
]
|
|
4576
|
-
});
|
|
4577
|
-
if (action === "profile") {
|
|
4578
|
-
await this.setupProfile();
|
|
4579
|
-
} else if (action === "proxy") {
|
|
4580
|
-
await this.setupProxy();
|
|
4581
|
-
} else if (action === "google") {
|
|
4582
|
-
await this.setupGoogleSearch();
|
|
4583
|
-
} else if (action === "behavior") {
|
|
4584
|
-
await this.setupBehavior();
|
|
4585
|
-
} else if (action === "preset") {
|
|
4586
|
-
await this.setupPreset();
|
|
4587
|
-
} else if (action === "apikey") {
|
|
4588
|
-
const choicesWithStatus = PROVIDERS.map((p) => {
|
|
4589
|
-
if (NO_KEY_PROVIDERS.has(p.value)) {
|
|
4590
|
-
return { value: p.value, name: `${p.name} ${theme.dim("[no API key needed]")}` };
|
|
4591
|
-
}
|
|
4592
|
-
const existingKey = this.config.getApiKey(p.value);
|
|
4593
|
-
const status = existingKey ? theme.success(`[${maskKey(existingKey)}]`) : theme.dim("[not configured]");
|
|
4594
|
-
return { value: p.value, name: `${p.name} ${status}` };
|
|
4595
|
-
});
|
|
4596
|
-
const providerId = await select({
|
|
4597
|
-
message: "Select provider:",
|
|
4598
|
-
choices: choicesWithStatus
|
|
4599
|
-
});
|
|
4600
|
-
await this.setupProvider(providerId);
|
|
4601
|
-
} else if (action === "default") {
|
|
4602
|
-
const providerId = await select({
|
|
4603
|
-
message: "Select default provider:",
|
|
4604
|
-
choices: PROVIDERS
|
|
4605
|
-
});
|
|
4606
|
-
this.config.set("defaultProvider", providerId);
|
|
4607
|
-
this.config.save();
|
|
4608
|
-
console.log(theme.success(`Default provider set to: ${providerId}
|
|
4609
|
-
`));
|
|
4610
|
-
} else {
|
|
4611
|
-
running = false;
|
|
4612
|
-
}
|
|
4613
|
-
}
|
|
4614
|
-
}
|
|
4615
|
-
async setupPreset() {
|
|
4616
|
-
const preset = await select({
|
|
4617
|
-
message: "Choose a task-oriented preset:",
|
|
4618
|
-
choices: [
|
|
4619
|
-
{ value: "safe-review", name: "Safe review only - read-only tools, network confirm" },
|
|
4620
|
-
{ value: "workspace-coding", name: "Workspace coding - write in workspace with confirmations" },
|
|
4621
|
-
{ value: "local-ollama", name: "Local-only Ollama - local provider, external network denied" },
|
|
4622
|
-
{ value: "team-web", name: "Team Web UI - workspace coding plus auth reminder" }
|
|
4623
|
-
]
|
|
4624
|
-
});
|
|
4625
|
-
const currentNetwork = this.config.get("networkPolicy");
|
|
4626
|
-
if (preset === "safe-review") {
|
|
4627
|
-
this.config.set("defaultPermissionProfile", "read-only");
|
|
4628
|
-
this.config.set("alwaysYolo", false);
|
|
4629
|
-
this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "confirm", tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "confirm", web_search: "confirm", google_search: "confirm", mcp: "confirm" } });
|
|
4630
|
-
console.log(theme.success("Preset applied: Safe review only. Writes require denial/confirmation according to the read-only profile."));
|
|
4631
|
-
} else if (preset === "workspace-coding") {
|
|
4632
|
-
this.config.set("defaultPermissionProfile", "workspace-write");
|
|
4633
|
-
this.config.set("alwaysYolo", false);
|
|
4634
|
-
this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "confirm", tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "confirm", web_search: "confirm", google_search: "confirm", mcp: "confirm" } });
|
|
4635
|
-
console.log(theme.success("Preset applied: Workspace coding. File writes stay inside the workspace and sensitive actions still ask."));
|
|
4636
|
-
} else if (preset === "local-ollama") {
|
|
4637
|
-
this.config.set("defaultProvider", "ollama");
|
|
4638
|
-
this.config.set("defaultPermissionProfile", "workspace-write");
|
|
4639
|
-
this.config.set("alwaysYolo", false);
|
|
4640
|
-
this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "deny", allowPrivateNetwork: true, tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "deny", web_search: "deny", google_search: "deny", mcp: "confirm" } });
|
|
4641
|
-
console.log(theme.success("Preset applied: Local-only Ollama. External web/search is denied; private network is allowed for local services."));
|
|
4642
|
-
} else {
|
|
4643
|
-
this.config.set("defaultPermissionProfile", "workspace-write");
|
|
4644
|
-
this.config.set("alwaysYolo", false);
|
|
4645
|
-
this.config.set("networkPolicy", { ...currentNetwork, enabled: true, defaultAction: "confirm", tools: { ...currentNetwork.tools, shell: "confirm", web_fetch: "confirm", web_search: "confirm", google_search: "confirm", mcp: "confirm" } });
|
|
4646
|
-
console.log(theme.warning("Preset applied: Team Web UI. Start Web with auth enabled and put it behind your normal TLS/reverse proxy boundary."));
|
|
4647
|
-
}
|
|
4648
|
-
this.config.save();
|
|
4649
|
-
console.log(theme.dim("Review changes with aicli doctor or aicli config.\n"));
|
|
4650
|
-
}
|
|
4651
|
-
async setupProvider(providerId) {
|
|
4652
|
-
if (NO_KEY_PROVIDERS.has(providerId)) {
|
|
4653
|
-
await this.setupOllama();
|
|
4654
|
-
return;
|
|
4655
|
-
}
|
|
4656
|
-
const provider = PROVIDERS.find((p) => p.value === providerId);
|
|
4657
|
-
const displayName = provider?.name ?? providerId;
|
|
4658
|
-
const existingKey = this.config.getApiKey(providerId);
|
|
4659
|
-
console.log(`
|
|
4660
|
-
Managing ${displayName} API Key`);
|
|
4661
|
-
if (existingKey) {
|
|
4662
|
-
console.log(theme.dim(` Current: ${maskKey(existingKey)}`));
|
|
4663
|
-
} else {
|
|
4664
|
-
console.log(theme.dim(" Current: (not configured)"));
|
|
4665
|
-
}
|
|
4666
|
-
const choices = existingKey ? [
|
|
4667
|
-
{ value: "keep", name: "Keep current key" },
|
|
4668
|
-
{ value: "fingerprint", name: `Copy masked fingerprint (${maskKey(existingKey)})` },
|
|
4669
|
-
{ value: "change", name: "Update key" }
|
|
4670
|
-
] : [{ value: "change", name: "Enter key" }, { value: "skip", name: "Skip" }];
|
|
4671
|
-
const action = await select({
|
|
4672
|
-
message: "Action:",
|
|
4673
|
-
choices
|
|
4674
|
-
});
|
|
4675
|
-
if (action === "fingerprint" && existingKey) {
|
|
4676
|
-
console.log(theme.dim(`
|
|
4677
|
-
Fingerprint: ${maskKey(existingKey)}`));
|
|
4678
|
-
console.log(theme.dim(" Full secrets are not printed. Use Update key to replace it.\n"));
|
|
4679
|
-
return;
|
|
4680
|
-
} else if (action === "keep" || action === "skip") {
|
|
4681
|
-
return;
|
|
4682
|
-
}
|
|
4683
|
-
const newKey = await password({
|
|
4684
|
-
message: `Enter ${displayName} API key:`,
|
|
4685
|
-
validate: (val) => val.length > 0 || "API key cannot be empty"
|
|
4686
|
-
});
|
|
4687
|
-
this.config.setApiKey(providerId, newKey);
|
|
4688
|
-
console.log(theme.success(`API key saved for ${displayName}: ${maskKey(newKey)}
|
|
4689
|
-
`));
|
|
4690
|
-
}
|
|
4691
|
-
/** Ollama 专用配置:检测连通性、发现本地模型、可选自定义地址 */
|
|
4692
|
-
async setupOllama() {
|
|
4693
|
-
console.log(theme.heading("\n\u{1F999} Ollama (Local) Configuration"));
|
|
4694
|
-
console.log(theme.dim(" Ollama runs AI models locally \u2014 no API key needed."));
|
|
4695
|
-
console.log(theme.dim(" Install: https://ollama.com\n"));
|
|
4696
|
-
const customBaseUrls = this.config.get("customBaseUrls") ?? {};
|
|
4697
|
-
const currentHost = customBaseUrls["ollama"] ? customBaseUrls["ollama"].replace(/\/v1\/?$/, "") : OLLAMA_DEFAULT_HOST;
|
|
4698
|
-
const ollamaHost = await input({
|
|
4699
|
-
message: "Ollama server address:",
|
|
4700
|
-
default: currentHost,
|
|
4701
|
-
validate: (val) => {
|
|
4702
|
-
if (!val) return "Address cannot be empty";
|
|
4703
|
-
if (!val.startsWith("http://") && !val.startsWith("https://")) {
|
|
4704
|
-
return "Must start with http:// or https://";
|
|
4705
|
-
}
|
|
4706
|
-
return true;
|
|
4707
|
-
}
|
|
4708
|
-
});
|
|
4709
|
-
const host = ollamaHost.replace(/\/+$/, "");
|
|
4710
|
-
console.log(theme.dim(`
|
|
4711
|
-
Connecting to ${host}...`));
|
|
4712
|
-
let models = [];
|
|
4713
|
-
try {
|
|
4714
|
-
const res = await fetch(`${host}/api/tags`, { signal: AbortSignal.timeout(5e3) });
|
|
4715
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
4716
|
-
const data = await res.json();
|
|
4717
|
-
models = data.models ?? [];
|
|
4718
|
-
} catch {
|
|
4719
|
-
console.log(theme.error(` \u2717 Cannot connect to Ollama at ${host}`));
|
|
4720
|
-
console.log(theme.dim(" Make sure Ollama is running: ollama serve\n"));
|
|
4721
|
-
return;
|
|
4722
|
-
}
|
|
4723
|
-
if (models.length === 0) {
|
|
4724
|
-
console.log(theme.warning(" \u26A0 Ollama is running but no models installed."));
|
|
4725
|
-
console.log(theme.dim(" Install a model: ollama pull llama3.1\n"));
|
|
4726
|
-
return;
|
|
4727
|
-
}
|
|
4728
|
-
console.log(theme.success(` \u2713 Connected! Found ${models.length} model(s):
|
|
4729
|
-
`));
|
|
4730
|
-
for (const m of models) {
|
|
4731
|
-
const size = m.details?.parameter_size ?? `${(m.size / 1e9).toFixed(1)}GB`;
|
|
4732
|
-
console.log(` \u2022 ${m.name} ${theme.dim(`(${size})`)}`);
|
|
4733
|
-
}
|
|
4734
|
-
console.log();
|
|
4735
|
-
if (host !== OLLAMA_DEFAULT_HOST) {
|
|
4736
|
-
const urls = { ...customBaseUrls, ollama: `${host}/v1` };
|
|
4737
|
-
this.config.set("customBaseUrls", urls);
|
|
4738
|
-
}
|
|
4739
|
-
this.config.save();
|
|
4740
|
-
console.log(theme.success(" Ollama configured! Use /provider ollama to switch.\n"));
|
|
4741
|
-
}
|
|
4742
|
-
async setupProxy() {
|
|
4743
|
-
const current = this.config.get("proxy") ?? "";
|
|
4744
|
-
console.log("\nHTTP/HTTPS Proxy Configuration");
|
|
4745
|
-
console.log(theme.dim(" Used for providers that require a proxy (e.g. Gemini in China)"));
|
|
4746
|
-
if (current) {
|
|
4747
|
-
console.log(theme.dim(` Current: ${current}`));
|
|
4748
|
-
}
|
|
4749
|
-
const action = await select({
|
|
4750
|
-
message: "Action:",
|
|
4751
|
-
choices: current ? [
|
|
4752
|
-
{ value: "keep", name: "Keep current" },
|
|
4753
|
-
{ value: "change", name: "Update" },
|
|
4754
|
-
{ value: "clear", name: "Remove proxy" }
|
|
4755
|
-
] : [
|
|
4756
|
-
{ value: "change", name: "Set proxy" },
|
|
4757
|
-
{ value: "skip", name: "Skip" }
|
|
4758
|
-
]
|
|
4759
|
-
});
|
|
4760
|
-
if (action === "keep" || action === "skip") return;
|
|
4761
|
-
if (action === "clear") {
|
|
4762
|
-
this.config.set("proxy", void 0);
|
|
4763
|
-
this.config.save();
|
|
4764
|
-
console.log(theme.success("Proxy cleared.\n"));
|
|
4765
|
-
return;
|
|
4766
|
-
}
|
|
4767
|
-
const proxyUrl = await input({
|
|
4768
|
-
message: "Enter proxy URL (e.g. http://127.0.0.1:10809):",
|
|
4769
|
-
default: current || void 0,
|
|
4770
|
-
validate: (val) => {
|
|
4771
|
-
if (!val) return "Proxy URL cannot be empty";
|
|
4772
|
-
if (!val.startsWith("http://") && !val.startsWith("https://")) {
|
|
4773
|
-
return "Must start with http:// or https://";
|
|
4774
|
-
}
|
|
4775
|
-
return true;
|
|
4776
|
-
}
|
|
4777
|
-
});
|
|
4778
|
-
this.config.set("proxy", proxyUrl);
|
|
4779
|
-
this.config.save();
|
|
4780
|
-
console.log(theme.success(`Proxy saved: ${proxyUrl}
|
|
4781
|
-
`));
|
|
4782
|
-
}
|
|
4783
|
-
/** Behavior toggles — alwaysYolo, mcpEnabled, and friends (v0.4.126+). */
|
|
4784
|
-
async setupBehavior() {
|
|
4785
|
-
let running = true;
|
|
4786
|
-
while (running) {
|
|
4787
|
-
const yoloOn = this.config.get("alwaysYolo") === true;
|
|
4788
|
-
const mcpEnabled = this.config.get("mcpEnabled") !== false;
|
|
4789
|
-
const yoloStatus = yoloOn ? theme.warning("[ON]") : theme.dim("[off]");
|
|
4790
|
-
const mcpStatus = mcpEnabled ? theme.success("[enabled]") : theme.warning("[disabled]");
|
|
4791
|
-
console.log(theme.heading("\n\u2699 Behavior Toggles\n"));
|
|
4792
|
-
const action = await select({
|
|
4793
|
-
message: "Which toggle?",
|
|
4794
|
-
choices: [
|
|
4795
|
-
{ value: "yolo", name: `alwaysYolo ${yoloStatus}` },
|
|
4796
|
-
{ value: "mcp", name: `mcpEnabled ${mcpStatus}` },
|
|
4797
|
-
{ value: "done", name: "Done" }
|
|
4798
|
-
]
|
|
4799
|
-
});
|
|
4800
|
-
if (action === "yolo") {
|
|
4801
|
-
await this.toggleAlwaysYolo();
|
|
4802
|
-
} else if (action === "mcp") {
|
|
4803
|
-
await this.toggleMcpEnabled();
|
|
4804
|
-
} else {
|
|
4805
|
-
running = false;
|
|
4806
|
-
}
|
|
4807
|
-
}
|
|
4808
|
-
}
|
|
4809
|
-
async toggleAlwaysYolo() {
|
|
4810
|
-
const current = this.config.get("alwaysYolo") === true;
|
|
4811
|
-
console.log(" alwaysYolo: " + (current ? theme.warning("ON") : theme.dim("off")));
|
|
4812
|
-
console.log(
|
|
4813
|
-
theme.dim(
|
|
4814
|
-
" When ON, REPL starts with sessionAutoApprove enabled \u2014 write\n tools (write_file/edit_file, etc.) run without confirmation prompts. Destructive tools still require confirmation. Only enable this\n if you fully trust the working directory you run aicli in.\n"
|
|
4815
|
-
)
|
|
4816
|
-
);
|
|
4817
|
-
const next = await confirm({
|
|
4818
|
-
message: current ? "Keep alwaysYolo enabled?" : "Enable alwaysYolo (skip write confirmations; destructive still confirms)?",
|
|
4819
|
-
default: current
|
|
4820
|
-
});
|
|
4821
|
-
if (next === current) {
|
|
4822
|
-
console.log(theme.dim(" No change.\n"));
|
|
4823
|
-
return;
|
|
4824
|
-
}
|
|
4825
|
-
this.config.set("alwaysYolo", next);
|
|
4826
|
-
this.config.save();
|
|
4827
|
-
if (next) {
|
|
4828
|
-
console.log(theme.warning(" \u26A1 alwaysYolo enabled \u2014 confirmations will be skipped on next REPL start.\n"));
|
|
4829
|
-
} else {
|
|
4830
|
-
console.log(theme.success(" alwaysYolo disabled \u2014 confirmations restored on next REPL start.\n"));
|
|
4831
|
-
}
|
|
4832
|
-
}
|
|
4833
|
-
async toggleMcpEnabled() {
|
|
4834
|
-
const current = this.config.get("mcpEnabled") !== false;
|
|
4835
|
-
console.log(" mcpEnabled: " + (current ? theme.success("enabled") : theme.warning("disabled")));
|
|
4836
|
-
console.log(
|
|
4837
|
-
theme.dim(
|
|
4838
|
-
" Global switch for the MCP (Model Context Protocol) subsystem. When disabled,\n REPL startup skips loadProjectMcpConfig() and mcpManager.connectAll() \u2014\n no MCP servers are spawned, no MCP tools appear in the tool list, faster boot.\n Per-server entries in config.mcpServers are preserved but ignored. Disable this\n if you don't use MCP and want a leaner startup / smaller tool schema.\n"
|
|
4839
|
-
)
|
|
4840
|
-
);
|
|
4841
|
-
const next = await confirm({
|
|
4842
|
-
message: current ? "Keep MCP enabled?" : "Re-enable MCP?",
|
|
4843
|
-
default: current
|
|
4844
|
-
});
|
|
4845
|
-
if (next === current) {
|
|
4846
|
-
console.log(theme.dim(" No change.\n"));
|
|
4847
|
-
return;
|
|
4848
|
-
}
|
|
4849
|
-
this.config.set("mcpEnabled", next);
|
|
4850
|
-
this.config.save();
|
|
4851
|
-
if (next) {
|
|
4852
|
-
console.log(theme.success(" MCP enabled \u2014 servers will connect on next REPL start.\n"));
|
|
4853
|
-
} else {
|
|
4854
|
-
console.log(theme.warning(" \u{1F50C} MCP disabled \u2014 no MCP servers will load on next REPL start.\n"));
|
|
4855
|
-
}
|
|
4856
|
-
}
|
|
4857
|
-
async setupGoogleSearch() {
|
|
4858
|
-
console.log("\nGoogle Custom Search Configuration");
|
|
4859
|
-
console.log(theme.dim(" Enables AI to search the web via google_search tool"));
|
|
4860
|
-
console.log(theme.dim(" Requires: API Key + Search Engine ID (cx)"));
|
|
4861
|
-
console.log(theme.dim(" Get API Key: https://console.cloud.google.com/apis/credentials"));
|
|
4862
|
-
console.log(theme.dim(" Get CX: https://programmablesearchengine.google.com/"));
|
|
4863
|
-
const existingKey = this.config.getApiKey("google-search");
|
|
4864
|
-
if (existingKey) {
|
|
4865
|
-
console.log(theme.dim(`
|
|
4866
|
-
API Key: ${maskKey(existingKey)}`));
|
|
4867
|
-
} else {
|
|
4868
|
-
console.log(theme.dim("\n API Key: (not configured)"));
|
|
4869
|
-
}
|
|
4870
|
-
const keyAction = await select({
|
|
4871
|
-
message: "API Key:",
|
|
4872
|
-
choices: existingKey ? [
|
|
4873
|
-
{ value: "keep", name: "Keep current" },
|
|
4874
|
-
{ value: "change", name: "Update API Key" }
|
|
4875
|
-
] : [
|
|
4876
|
-
{ value: "change", name: "Enter API Key" },
|
|
4877
|
-
{ value: "skip", name: "Skip" }
|
|
4878
|
-
]
|
|
4879
|
-
});
|
|
4880
|
-
if (keyAction === "change") {
|
|
4881
|
-
const newKey = await password({
|
|
4882
|
-
message: "Enter Google API Key:",
|
|
4883
|
-
validate: (val) => val.length > 0 || "API key cannot be empty"
|
|
4884
|
-
});
|
|
4885
|
-
this.config.setApiKey("google-search", newKey);
|
|
4886
|
-
console.log(theme.success(` API Key saved: ${maskKey(newKey)}`));
|
|
4887
|
-
}
|
|
4888
|
-
const existingCx = this.config.get("googleSearchEngineId") ?? "";
|
|
4889
|
-
if (existingCx) {
|
|
4890
|
-
console.log(theme.dim(`
|
|
4891
|
-
Search Engine ID: ${existingCx}`));
|
|
4892
|
-
} else {
|
|
4893
|
-
console.log(theme.dim("\n Search Engine ID: (not configured)"));
|
|
4894
|
-
}
|
|
4895
|
-
const cxAction = await select({
|
|
4896
|
-
message: "Search Engine ID (cx):",
|
|
4897
|
-
choices: existingCx ? [
|
|
4898
|
-
{ value: "keep", name: "Keep current" },
|
|
4899
|
-
{ value: "change", name: "Update CX" }
|
|
4900
|
-
] : [
|
|
4901
|
-
{ value: "change", name: "Enter CX" },
|
|
4902
|
-
{ value: "skip", name: "Skip" }
|
|
4903
|
-
]
|
|
4904
|
-
});
|
|
4905
|
-
if (cxAction === "change") {
|
|
4906
|
-
const newCx = await input({
|
|
4907
|
-
message: "Enter Search Engine ID (cx):",
|
|
4908
|
-
default: existingCx || void 0,
|
|
4909
|
-
validate: (val) => val.length > 0 || "Search Engine ID cannot be empty"
|
|
4910
|
-
});
|
|
4911
|
-
this.config.set("googleSearchEngineId", newCx);
|
|
4912
|
-
this.config.save();
|
|
4913
|
-
console.log(theme.success(` Search Engine ID saved: ${newCx}`));
|
|
4914
|
-
}
|
|
4915
|
-
console.log();
|
|
4916
|
-
}
|
|
4917
|
-
/** 收集用户身份档案 — aicli 的 "灵魂" 功能 */
|
|
4918
|
-
async setupProfile() {
|
|
4919
|
-
const existing = this.config.get("userProfile") ?? {};
|
|
4920
|
-
console.log(theme.heading("\n\u{1F464} Your Profile"));
|
|
4921
|
-
console.log(theme.dim(" This helps AI know who you are \u2014 across all providers and sessions.\n"));
|
|
4922
|
-
const name = await input({
|
|
4923
|
-
message: "Your name:",
|
|
4924
|
-
default: existing.name || void 0
|
|
4925
|
-
});
|
|
4926
|
-
const nickname = await input({
|
|
4927
|
-
message: "Preferred nickname (AI will call you this):",
|
|
4928
|
-
default: existing.nickname || void 0
|
|
4929
|
-
});
|
|
4930
|
-
const role = await input({
|
|
4931
|
-
message: 'Your role (e.g. "Full-stack developer", "Student"):',
|
|
4932
|
-
default: existing.role || void 0
|
|
4933
|
-
});
|
|
4934
|
-
const bio = await input({
|
|
4935
|
-
message: "Brief intro (1-2 sentences about your background):",
|
|
4936
|
-
default: existing.bio || void 0
|
|
4937
|
-
});
|
|
4938
|
-
const interestsStr = await input({
|
|
4939
|
-
message: "Interests / tech stack (comma-separated):",
|
|
4940
|
-
default: existing.interests?.join(", ") || void 0
|
|
4941
|
-
});
|
|
4942
|
-
const locale = await input({
|
|
4943
|
-
message: 'Preferred language (e.g. "zh-CN", "en", "ja"):',
|
|
4944
|
-
default: existing.locale || void 0
|
|
4945
|
-
});
|
|
4946
|
-
const profile = {};
|
|
4947
|
-
if (name) profile.name = name;
|
|
4948
|
-
if (nickname) profile.nickname = nickname;
|
|
4949
|
-
if (role) profile.role = role;
|
|
4950
|
-
if (bio) profile.bio = bio;
|
|
4951
|
-
if (interestsStr) profile.interests = interestsStr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
4952
|
-
if (locale) profile.locale = locale;
|
|
4953
|
-
if (existing.extra) profile.extra = existing.extra;
|
|
4954
|
-
this.config.set("userProfile", profile);
|
|
4955
|
-
this.config.save();
|
|
4956
|
-
const displayName = nickname || name || "User";
|
|
4957
|
-
console.log(theme.success(`
|
|
4958
|
-
Profile saved! AI will know you as "${displayName}".
|
|
4959
|
-
`));
|
|
4960
|
-
}
|
|
4961
|
-
};
|
|
4962
|
-
|
|
4963
4485
|
// src/repl/custom-commands.ts
|
|
4964
4486
|
import { existsSync as existsSync3, readFileSync as readFileSync2, readdirSync, mkdirSync as mkdirSync3 } from "fs";
|
|
4965
4487
|
import { join as join3, extname } from "path";
|
|
@@ -5225,12 +4747,12 @@ var IMAGE_MIME = {
|
|
|
5225
4747
|
};
|
|
5226
4748
|
var MAX_IMAGE_BYTES = 10 * 1024 * 1024;
|
|
5227
4749
|
var MAX_PATH_SPACE_TOKENS = 8;
|
|
5228
|
-
function expandUnquotedPath(
|
|
4750
|
+
function expandUnquotedPath(input, pathStart, rawPath, cwd) {
|
|
5229
4751
|
const plain = { raw: rawPath, consumed: rawPath.length };
|
|
5230
4752
|
if (existsSync4(resolve2(cwd, rawPath))) return plain;
|
|
5231
4753
|
let acc = rawPath;
|
|
5232
4754
|
let consumed = rawPath.length;
|
|
5233
|
-
let rest =
|
|
4755
|
+
let rest = input.slice(pathStart + rawPath.length);
|
|
5234
4756
|
for (let i = 0; i < MAX_PATH_SPACE_TOKENS; i++) {
|
|
5235
4757
|
const next = /^([ \t]+)(\S+)/.exec(rest);
|
|
5236
4758
|
if (!next) break;
|
|
@@ -5241,18 +4763,18 @@ function expandUnquotedPath(input2, pathStart, rawPath, cwd) {
|
|
|
5241
4763
|
}
|
|
5242
4764
|
return plain;
|
|
5243
4765
|
}
|
|
5244
|
-
function parseAtReferences(
|
|
4766
|
+
function parseAtReferences(input, cwd) {
|
|
5245
4767
|
const atPattern = /@(?:"([^"]+)"|'([^']+)'|(\S+))/g;
|
|
5246
4768
|
const refs = [];
|
|
5247
4769
|
const imageParts = [];
|
|
5248
|
-
let textBody =
|
|
4770
|
+
let textBody = input;
|
|
5249
4771
|
let match;
|
|
5250
|
-
while ((match = atPattern.exec(
|
|
4772
|
+
while ((match = atPattern.exec(input)) !== null) {
|
|
5251
4773
|
let rawPath = match[1] ?? match[2] ?? match[3] ?? "";
|
|
5252
4774
|
let matchedText = match[0];
|
|
5253
4775
|
if (match[3] !== void 0) {
|
|
5254
4776
|
const pathStart = match.index + 1;
|
|
5255
|
-
const expanded = expandUnquotedPath(
|
|
4777
|
+
const expanded = expandUnquotedPath(input, pathStart, rawPath, cwd);
|
|
5256
4778
|
if (expanded.consumed > rawPath.length) {
|
|
5257
4779
|
rawPath = expanded.raw;
|
|
5258
4780
|
matchedText = "@" + expanded.raw;
|
|
@@ -5321,7 +4843,7 @@ function removePreviousGrapheme(line, cursor) {
|
|
|
5321
4843
|
cursor: start
|
|
5322
4844
|
};
|
|
5323
4845
|
}
|
|
5324
|
-
function installUnicodeBackspaceRepair(
|
|
4846
|
+
function installUnicodeBackspaceRepair(input, rl, shouldHandle = () => true) {
|
|
5325
4847
|
const editable = rl;
|
|
5326
4848
|
let previous = { line: editable.line, cursor: editable.cursor };
|
|
5327
4849
|
const onKeypress = (_character, key) => {
|
|
@@ -5336,20 +4858,8 @@ function installUnicodeBackspaceRepair(input2, rl, shouldHandle = () => true) {
|
|
|
5336
4858
|
}
|
|
5337
4859
|
previous = current;
|
|
5338
4860
|
};
|
|
5339
|
-
|
|
5340
|
-
return () =>
|
|
5341
|
-
}
|
|
5342
|
-
|
|
5343
|
-
// src/repl/chat-params.ts
|
|
5344
|
-
function chatParamsFrom(params) {
|
|
5345
|
-
return {
|
|
5346
|
-
temperature: params.temperature,
|
|
5347
|
-
maxTokens: params.maxTokens,
|
|
5348
|
-
timeout: params.timeout,
|
|
5349
|
-
thinking: params.thinking,
|
|
5350
|
-
thinkingEffort: params.thinkingEffort,
|
|
5351
|
-
thinkingBudget: params.thinkingBudget
|
|
5352
|
-
};
|
|
4861
|
+
input.on("keypress", onKeypress);
|
|
4862
|
+
return () => input.off("keypress", onKeypress);
|
|
5353
4863
|
}
|
|
5354
4864
|
|
|
5355
4865
|
// src/core/model-router.ts
|
|
@@ -5721,6 +5231,13 @@ var Repl = class {
|
|
|
5721
5231
|
/** 本次会话累计 token 用量 */
|
|
5722
5232
|
sessionTokenUsage = { inputTokens: 0, outputTokens: 0, cacheCreationTokens: 0, cacheReadTokens: 0 };
|
|
5723
5233
|
unknownPricingWarnings = /* @__PURE__ */ new Set();
|
|
5234
|
+
/**
|
|
5235
|
+
* 本会话按**调用时刻**费率累计的成本(美元)。峰谷计价下,事后拿聚合用量现算
|
|
5236
|
+
* 会给出错的数字——闲时跑的会话在峰时查看会被按峰价显示(审计 P3-01)。
|
|
5237
|
+
*/
|
|
5238
|
+
sessionAccruedCostUsd = 0;
|
|
5239
|
+
/** 本会话是否出现过定价未知的调用(此时累计值不完整,展示层需据实说明) */
|
|
5240
|
+
sessionCostIncomplete = false;
|
|
5724
5241
|
/** Fold a single-request TokenUsage (with optional cache fields) into sessionTokenUsage + cost tracker.
|
|
5725
5242
|
* modelOverride lets the smart router attribute cost to the actually-used model
|
|
5726
5243
|
* when it differs from the UI-selected currentModel. */
|
|
@@ -5738,7 +5255,9 @@ var Repl = class {
|
|
|
5738
5255
|
this.renderer.printInfo(`Cost notice: pricing is unknown for ${key}. Tokens are tracked, but cost is excluded from totals. Run aicli usage to review unknown-priced models.`);
|
|
5739
5256
|
}
|
|
5740
5257
|
}
|
|
5741
|
-
this.costTracker.addCost(this.currentProvider, effectiveModel, u);
|
|
5258
|
+
const priced = this.costTracker.addCost(this.currentProvider, effectiveModel, u);
|
|
5259
|
+
if (priced === null) this.sessionCostIncomplete = true;
|
|
5260
|
+
else this.sessionAccruedCostUsd += priced;
|
|
5742
5261
|
}
|
|
5743
5262
|
/** 启动时检测到的 Git 分支(无 git 仓库时为 null) */
|
|
5744
5263
|
gitBranch = null;
|
|
@@ -6160,7 +5679,8 @@ ${ctxLine}` : "")
|
|
|
6160
5679
|
const skillTag = activeSkill ? theme.toolCall(`[${activeSkill.meta.name}]`) : "";
|
|
6161
5680
|
const planTag = this.planMode ? theme.warning("[PLAN]") : "";
|
|
6162
5681
|
const modelParams = this.getModelParams();
|
|
6163
|
-
const
|
|
5682
|
+
const showsEffort = this.providers.get(this.currentProvider)?.supportsReasoningEffort ?? false;
|
|
5683
|
+
const thinkTag = modelParams.thinking ? theme.accent(showsEffort ? `[THINK:${modelParams.thinkingEffort ?? "high"}]` : "[THINK]") : "";
|
|
6164
5684
|
const promptStr = theme.success(`[${this.currentProvider}]`) + skillTag + planTag + thinkTag + chalk5.white(" > ");
|
|
6165
5685
|
this.rl.setPrompt(promptStr);
|
|
6166
5686
|
}
|
|
@@ -6488,8 +6008,8 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6488
6008
|
let processing = false;
|
|
6489
6009
|
let pasteTimer = null;
|
|
6490
6010
|
const PASTE_DEBOUNCE_MS = 50;
|
|
6491
|
-
const processInput = async (
|
|
6492
|
-
if (!
|
|
6011
|
+
const processInput = async (input) => {
|
|
6012
|
+
if (!input) {
|
|
6493
6013
|
this.showPrompt();
|
|
6494
6014
|
return;
|
|
6495
6015
|
}
|
|
@@ -6499,10 +6019,10 @@ Session '${this.resumeSessionId}' not found.
|
|
|
6499
6019
|
const savedOutput = rlAny.output;
|
|
6500
6020
|
rlAny.output = null;
|
|
6501
6021
|
try {
|
|
6502
|
-
if (
|
|
6503
|
-
await this.handleCommand(
|
|
6022
|
+
if (input.startsWith("/")) {
|
|
6023
|
+
await this.handleCommand(input);
|
|
6504
6024
|
} else {
|
|
6505
|
-
await this.handleChat(
|
|
6025
|
+
await this.handleChat(input);
|
|
6506
6026
|
}
|
|
6507
6027
|
} catch (err) {
|
|
6508
6028
|
this.renderer.renderError(err);
|
|
@@ -7169,7 +6689,13 @@ Session '${this.resumeSessionId}' not found.
|
|
|
7169
6689
|
spinner.stop();
|
|
7170
6690
|
this.renderer.renderResponse(response.content);
|
|
7171
6691
|
lastResponseStore.content = response.content;
|
|
7172
|
-
session.addMessage({
|
|
6692
|
+
session.addMessage({
|
|
6693
|
+
role: "assistant",
|
|
6694
|
+
content: response.content,
|
|
6695
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
6696
|
+
// 非流式路径同样要落 reasoningContent,否则 V4 thinking 的多轮推理断链(审计 P1-02)
|
|
6697
|
+
...response.reasoningContent ? { reasoningContent: response.reasoningContent } : {}
|
|
6698
|
+
});
|
|
7173
6699
|
this.events.emit("message.after", { content: response.content });
|
|
7174
6700
|
if (response.usage) {
|
|
7175
6701
|
this.addSessionUsage(response.usage, effectiveModel);
|
|
@@ -7852,8 +7378,8 @@ Tip: You can continue the conversation by asking the AI to proceed.`
|
|
|
7852
7378
|
await this.checkContextPressure();
|
|
7853
7379
|
}
|
|
7854
7380
|
}
|
|
7855
|
-
async handleCommand(
|
|
7856
|
-
const parts =
|
|
7381
|
+
async handleCommand(input) {
|
|
7382
|
+
const parts = input.slice(1).split(" ");
|
|
7857
7383
|
const cmdName = parts[0].toLowerCase();
|
|
7858
7384
|
const args = parts.slice(1);
|
|
7859
7385
|
const cmd = this.commands.get(cmdName);
|
|
@@ -7949,7 +7475,10 @@ Tip: You can continue the conversation by asking the AI to proceed.`
|
|
|
7949
7475
|
cacheCreationTokens: 0,
|
|
7950
7476
|
cacheReadTokens: 0
|
|
7951
7477
|
};
|
|
7478
|
+
this.sessionAccruedCostUsd = 0;
|
|
7479
|
+
this.sessionCostIncomplete = false;
|
|
7952
7480
|
},
|
|
7481
|
+
getSessionAccruedCost: () => ({ usd: this.sessionAccruedCostUsd, incomplete: this.sessionCostIncomplete }),
|
|
7953
7482
|
getGitBranch: () => this.gitBranch,
|
|
7954
7483
|
getLastResponse: () => lastResponseStore.content,
|
|
7955
7484
|
runSetupWizard: async () => {
|
|
@@ -7957,6 +7486,7 @@ Tip: You can continue the conversation by asking the AI to proceed.`
|
|
|
7957
7486
|
rlAny.output = process.stdout;
|
|
7958
7487
|
process.stdin.resume();
|
|
7959
7488
|
try {
|
|
7489
|
+
const { SetupWizard } = await import("./setup-wizard-S55ICNHH.js");
|
|
7960
7490
|
const wizard = new SetupWizard(this.config);
|
|
7961
7491
|
await wizard.runFull();
|
|
7962
7492
|
} finally {
|
|
@@ -7977,6 +7507,9 @@ Tip: You can continue the conversation by asking the AI to proceed.`
|
|
|
7977
7507
|
this.runtimeThinking = value;
|
|
7978
7508
|
this.refreshPrompt();
|
|
7979
7509
|
},
|
|
7510
|
+
getProviderSupportsReasoningEffort: () => this.providers.get(this.currentProvider)?.supportsReasoningEffort ?? false,
|
|
7511
|
+
getConfiguredThinking: () => this.config.get("modelParams")[this.currentModel]?.thinking,
|
|
7512
|
+
getConfiguredThinkingEffort: () => this.config.get("modelParams")[this.currentModel]?.thinkingEffort,
|
|
7980
7513
|
getThinkingEffort: () => this.runtimeThinkingEffort,
|
|
7981
7514
|
setThinkingEffort: (value) => {
|
|
7982
7515
|
this.runtimeThinkingEffort = value;
|
|
@@ -8115,7 +7648,7 @@ process.on("unhandledRejection", (reason) => {
|
|
|
8115
7648
|
});
|
|
8116
7649
|
var builtInProviderIds = listBuiltInProviderMetadata().map(({ id }) => id).join("/");
|
|
8117
7650
|
program.name("aicli").description("Cross-platform REPL-style AI CLI with multi-provider support").version(VERSION);
|
|
8118
|
-
program.option("--provider <name>", `AI provider to use (${builtInProviderIds}, or any custom provider)`).option("-m, --model <name>", "Model to use").option("-p, --prompt <text>", "Headless mode: send a single prompt and exit (reads stdin as context if piped)").option("--system <prompt>", "System prompt override (headless mode)").option("--json", "Output result as JSON object (headless mode only)").option("--output-format <format>", "Output format: text (default) | streaming-json (NDJSON per-chunk, headless only)").option("--no-stream", "Disable streaming output").option("--allowed-tools <tools>", "Comma-separated whitelist of tools (e.g. bash,read_file)").option("--blocked-tools <tools>", "Comma-separated blacklist of tools (e.g. bash,write_file)").option("--resume <id>", "Resume a previous session by ID (prefix match supported)").option("--max-tool-rounds <n>", "Max agentic tool-call rounds per conversation (default: 200)").action(async (options) => {
|
|
7651
|
+
program.option("--provider <name>", `AI provider to use (${builtInProviderIds}, or any custom provider)`).option("-m, --model <name>", "Model to use").option("-p, --prompt <text>", "Headless mode: send a single prompt and exit (reads stdin as context if piped)").option("--system <prompt>", "System prompt override (headless mode)").option("--json", "Output result as JSON object (headless mode only)").option("--output-format <format>", "Output format: text (default) | streaming-json (NDJSON per-chunk, headless only)").option("--no-stream", "Disable streaming output").option("--allowed-tools <tools>", "Comma-separated whitelist of tools (e.g. bash,read_file)").option("--blocked-tools <tools>", "Comma-separated blacklist of tools (e.g. bash,write_file)").option("--resume <id>", "Resume a previous session by ID (prefix match supported)").option("--max-tool-rounds <n>", "Max agentic tool-call rounds per conversation (default: 200)").option("--think <mode>", "Thinking for this run: off | on | low | high | max (default: follow config)").action(async (options) => {
|
|
8119
7652
|
if (options.prompt !== void 0) {
|
|
8120
7653
|
await runHeadless(options);
|
|
8121
7654
|
} else {
|
|
@@ -8124,6 +7657,7 @@ program.option("--provider <name>", `AI provider to use (${builtInProviderIds},
|
|
|
8124
7657
|
});
|
|
8125
7658
|
program.command("config").description("Configure API keys and preferences").action(async () => {
|
|
8126
7659
|
const config = new ConfigManager();
|
|
7660
|
+
const { SetupWizard } = await import("./setup-wizard-S55ICNHH.js");
|
|
8127
7661
|
const wizard = new SetupWizard(config);
|
|
8128
7662
|
await wizard.runFull();
|
|
8129
7663
|
console.log("Configuration saved.");
|
|
@@ -8162,7 +7696,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
8162
7696
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
8163
7697
|
process.exit(1);
|
|
8164
7698
|
}
|
|
8165
|
-
const { startWebServer } = await import("./server-
|
|
7699
|
+
const { startWebServer } = await import("./server-53GM3CRH.js");
|
|
8166
7700
|
await startWebServer({ port, host: options.host });
|
|
8167
7701
|
});
|
|
8168
7702
|
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) => {
|
|
@@ -8329,11 +7863,11 @@ program.command("sessions").description("List recent conversation sessions").opt
|
|
|
8329
7863
|
console.log(footer + "\n");
|
|
8330
7864
|
});
|
|
8331
7865
|
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) => {
|
|
8332
|
-
const { runUsageCli } = await import("./usage-
|
|
7866
|
+
const { runUsageCli } = await import("./usage-E3FEYSBU.js");
|
|
8333
7867
|
await runUsageCli(options);
|
|
8334
7868
|
});
|
|
8335
7869
|
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) => {
|
|
8336
|
-
const { runDoctorCli } = await import("./doctor-cli-
|
|
7870
|
+
const { runDoctorCli } = await import("./doctor-cli-CO6BJWRW.js");
|
|
8337
7871
|
const argv = process.argv.slice(2);
|
|
8338
7872
|
await runDoctorCli({
|
|
8339
7873
|
json: !!options.json || argv.includes("--json"),
|
|
@@ -8342,7 +7876,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
|
|
|
8342
7876
|
});
|
|
8343
7877
|
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) => {
|
|
8344
7878
|
try {
|
|
8345
|
-
const batch = await import("./batch-
|
|
7879
|
+
const batch = await import("./batch-FQU6HK3Z.js");
|
|
8346
7880
|
switch (action) {
|
|
8347
7881
|
case "submit":
|
|
8348
7882
|
if (!arg) {
|
|
@@ -8385,7 +7919,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
|
|
|
8385
7919
|
}
|
|
8386
7920
|
});
|
|
8387
7921
|
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) => {
|
|
8388
|
-
const { startMcpServer } = await import("./server-
|
|
7922
|
+
const { startMcpServer } = await import("./server-B4A7LHZ5.js");
|
|
8389
7923
|
await startMcpServer({
|
|
8390
7924
|
allowDestructive: !!options.allowDestructive,
|
|
8391
7925
|
allowOutsideCwd: !!options.allowOutsideCwd,
|
|
@@ -8398,7 +7932,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
|
|
|
8398
7932
|
console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
|
|
8399
7933
|
process.exit(1);
|
|
8400
7934
|
}
|
|
8401
|
-
const { runPrCli } = await import("./pr-
|
|
7935
|
+
const { runPrCli } = await import("./pr-CDOPCAPK.js");
|
|
8402
7936
|
const result = await runPrCli({
|
|
8403
7937
|
action,
|
|
8404
7938
|
target,
|
|
@@ -8418,8 +7952,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
|
|
|
8418
7952
|
process.exit(result.exitCode);
|
|
8419
7953
|
});
|
|
8420
7954
|
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 or URL; diff fetched via gh pr diff <value>", (v) => /^#?\d+$/.test(v) ? parseInt(v.replace(/^#/, ""), 10) : v).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)").option("--json", "Output a structured JSON report").option("--markdown", "Output Markdown report (default)").option("--sarif", "Output SARIF 2.1.0 for code scanning artifacts").option("--fail-on-security-high", "Fail when the security review contains HIGH/CRITICAL findings (default)").option("--no-fail-on-security-high", "Do not fail on security HIGH/CRITICAL findings").option("--fail-on-test-failure", "Fail when the report mentions test failures (default)").option("--no-fail-on-test-failure", "Do not fail on test failure findings").option("--fail-on-lint-failure", "Fail when the report mentions lint/typecheck failures (default)").option("--no-fail-on-lint-failure", "Do not fail on lint/typecheck failure findings").action(async (options) => {
|
|
8421
|
-
const { runCi } = await import("./ci-
|
|
8422
|
-
const { formatCiResult } = await import("./ci-format-
|
|
7955
|
+
const { runCi } = await import("./ci-GZH3QMME.js");
|
|
7956
|
+
const { formatCiResult } = await import("./ci-format-VKP2MGYJ.js");
|
|
8423
7957
|
const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
|
|
8424
7958
|
if (formats > 1) {
|
|
8425
7959
|
console.error("Choose only one output format: --json, --markdown, or --sarif.");
|
|
@@ -8577,7 +8111,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
|
|
|
8577
8111
|
config.get("customProviders"),
|
|
8578
8112
|
config.getConfigDir()
|
|
8579
8113
|
);
|
|
8580
|
-
const { startHub } = await import("./hub-
|
|
8114
|
+
const { startHub } = await import("./hub-4APIRQ73.js");
|
|
8581
8115
|
await startHub(
|
|
8582
8116
|
{
|
|
8583
8117
|
topic: topic ?? "",
|
|
@@ -8679,6 +8213,10 @@ ${options.prompt}` : options.prompt;
|
|
|
8679
8213
|
const maxTokens = modelParams.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
8680
8214
|
const timeout = modelParams.timeout ?? 6e4;
|
|
8681
8215
|
const temperature = modelParams.temperature;
|
|
8216
|
+
const thinkingParams = applyThinkingFlag(
|
|
8217
|
+
thinkingParamsFor(allModelParams, model),
|
|
8218
|
+
options.think
|
|
8219
|
+
);
|
|
8682
8220
|
let systemPrompt = options.system;
|
|
8683
8221
|
if (!systemPrompt) {
|
|
8684
8222
|
const contextConfig = config.get("context");
|
|
@@ -8711,7 +8249,8 @@ ${loaded.mergedContent}` : void 0
|
|
|
8711
8249
|
stream: true,
|
|
8712
8250
|
temperature,
|
|
8713
8251
|
maxTokens,
|
|
8714
|
-
timeout
|
|
8252
|
+
timeout,
|
|
8253
|
+
...thinkingParams
|
|
8715
8254
|
});
|
|
8716
8255
|
let fullContent = "";
|
|
8717
8256
|
let finalUsage;
|
|
@@ -8741,7 +8280,8 @@ ${loaded.mergedContent}` : void 0
|
|
|
8741
8280
|
stream: false,
|
|
8742
8281
|
temperature,
|
|
8743
8282
|
maxTokens,
|
|
8744
|
-
timeout
|
|
8283
|
+
timeout,
|
|
8284
|
+
...thinkingParams
|
|
8745
8285
|
});
|
|
8746
8286
|
const out = {
|
|
8747
8287
|
content: response.content,
|
|
@@ -8758,7 +8298,8 @@ ${loaded.mergedContent}` : void 0
|
|
|
8758
8298
|
stream: true,
|
|
8759
8299
|
temperature,
|
|
8760
8300
|
maxTokens,
|
|
8761
|
-
timeout
|
|
8301
|
+
timeout,
|
|
8302
|
+
...thinkingParams
|
|
8762
8303
|
});
|
|
8763
8304
|
for await (const chunk of stream) {
|
|
8764
8305
|
if (chunk.done) break;
|
|
@@ -8773,7 +8314,8 @@ ${loaded.mergedContent}` : void 0
|
|
|
8773
8314
|
stream: false,
|
|
8774
8315
|
temperature,
|
|
8775
8316
|
maxTokens,
|
|
8776
|
-
timeout
|
|
8317
|
+
timeout,
|
|
8318
|
+
...thinkingParams
|
|
8777
8319
|
});
|
|
8778
8320
|
process.stdout.write(response.content + "\n");
|
|
8779
8321
|
}
|
|
@@ -8789,6 +8331,7 @@ async function startRepl(options) {
|
|
|
8789
8331
|
const config = new ConfigManager();
|
|
8790
8332
|
await setupProxy(config.get("proxy"));
|
|
8791
8333
|
if (config.isFirstRun()) {
|
|
8334
|
+
const { SetupWizard } = await import("./setup-wizard-S55ICNHH.js");
|
|
8792
8335
|
const wizard = new SetupWizard(config);
|
|
8793
8336
|
const configured = await wizard.runFirstRun();
|
|
8794
8337
|
if (!configured) {
|