jinzd-ai-cli 0.4.329 → 0.4.331
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 +4 -4
- package/README.zh-CN.md +4 -4
- package/dist/{batch-NNYRIS4U.js → batch-OOHC5POO.js} +2 -2
- package/dist/{chunk-BRZZ3QAI.js → chunk-2BAFLDDL.js} +44 -7
- package/dist/{chunk-XF2S7LNM.js → chunk-56ME7PB2.js} +1 -1
- package/dist/{chunk-DRNRQ6SD.js → chunk-6BGW25LG.js} +1 -1
- package/dist/{chunk-E2W2MI6H.js → chunk-C6GA7H5D.js} +1 -72
- package/dist/{chunk-2CNJ25U7.js → chunk-CM5C7ZSM.js} +9 -3
- package/dist/{chunk-IUC3DRGB.js → chunk-DTVN2LDU.js} +1 -1
- package/dist/{chunk-ABIR2TGW.js → chunk-EWARNWJ4.js} +4 -4
- package/dist/{chunk-YDH5ZWOQ.js → chunk-IJNDIOOQ.js} +1 -1
- package/dist/{chunk-LSSOPLKJ.js → chunk-L3FDFFD2.js} +9 -9
- package/dist/{chunk-TYQODNI7.js → chunk-MJSK6ZYR.js} +4 -4
- package/dist/{chunk-C2Z77RTU.js → chunk-MN25ELTF.js} +15 -4
- package/dist/{chunk-72AR23R2.js → chunk-NOLK5C4U.js} +54 -2
- package/dist/{chunk-SS3PG7LP.js → chunk-Q26V2PNA.js} +1 -1
- package/dist/{chunk-I5KLH7TL.js → chunk-QFF2PTI3.js} +53 -43
- package/dist/{chunk-LKSMXCFL.js → chunk-R3XIU7NS.js} +1 -1
- package/dist/{chunk-MPCQG7LV.js → chunk-RZDRBFAB.js} +9 -7
- package/dist/{chunk-LRRBYGHE.js → chunk-TF2FNRDZ.js} +1 -1
- package/dist/chunk-W4P2KJZN.js +75 -0
- package/dist/{chunk-6UDKGZ3D.js → chunk-YCDF6FNR.js} +1 -1
- package/dist/{ci-ODKA57IG.js → ci-HNYUXJUE.js} +7 -6
- package/dist/{ci-format-QDC4XKYZ.js → ci-format-ZLBEAU7Z.js} +2 -2
- package/dist/{constants-MG7EGG5J.js → constants-4EH6Y6VI.js} +1 -1
- package/dist/{constants-BYWEJLAI.js → constants-JM6MK5SS.js} +1 -1
- package/dist/{doctor-cli-LYZSHYR6.js → doctor-cli-VCNERMX5.js} +7 -6
- package/dist/electron-server.js +292 -178
- package/dist/{hub-GRHYVLGV.js → hub-3OXLWTEP.js} +8 -18
- package/dist/{hub-server-JLC7CNP7.js → hub-server-LJWXNEWK.js} +2 -1
- package/dist/index.js +23 -21
- package/dist/{persistent-memory-OCDFR4BH.js → persistent-memory-LMVWIHMX.js} +2 -2
- package/dist/{persistent-memory-O6GWHGJH.js → persistent-memory-PAS7NAPQ.js} +2 -2
- package/dist/{pr-LDUIDU27.js → pr-IMR62OHN.js} +7 -6
- package/dist/{run-tests-YTRU22LY.js → run-tests-2TVEWCQI.js} +2 -2
- package/dist/{run-tests-LTYJACRX.js → run-tests-MQVGE6FK.js} +2 -2
- package/dist/{server-ZTFB3KMS.js → server-55X6MCGX.js} +7 -6
- package/dist/{server-2NZN22XP.js → server-6MS2NGEJ.js} +30 -20
- package/dist/{task-orchestrator-URFLWSPI.js → task-orchestrator-KIDJB7NP.js} +9 -7
- package/dist/{usage-IP6G4Q2K.js → usage-X2CQYAUA.js} +3 -3
- package/dist/web/client/app.js +19 -0
- package/dist/web/client/app.js.br +0 -0
- package/dist/web/client/app.js.gz +0 -0
- package/package.json +1 -1
package/dist/electron-server.js
CHANGED
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
touchMemoryReferences,
|
|
56
56
|
updateMemoryApproval,
|
|
57
57
|
updateMemoryEntry
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-R3XIU7NS.js";
|
|
59
59
|
import {
|
|
60
60
|
DEFAULT_PATTERNS,
|
|
61
61
|
redactJson,
|
|
@@ -81,7 +81,7 @@ import {
|
|
|
81
81
|
recoverGbkMojibake,
|
|
82
82
|
runTestsTool,
|
|
83
83
|
shellInvocation
|
|
84
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-TF2FNRDZ.js";
|
|
85
85
|
import {
|
|
86
86
|
getCurrentSessionKey,
|
|
87
87
|
getExecutionConfigDir,
|
|
@@ -123,7 +123,7 @@ import {
|
|
|
123
123
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
124
124
|
VERSION,
|
|
125
125
|
buildUserIdentityPrompt
|
|
126
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-DTVN2LDU.js";
|
|
127
127
|
|
|
128
128
|
// src/web/access.ts
|
|
129
129
|
import { randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -205,8 +205,8 @@ function imageValidationError(images) {
|
|
|
205
205
|
}
|
|
206
206
|
|
|
207
207
|
// src/web/server.ts
|
|
208
|
-
import { join as
|
|
209
|
-
import { existsSync as
|
|
208
|
+
import { join as join26, dirname as dirname12, resolve as resolve12, relative as relative6, sep as sep5, extname as extname3, resolve as resolvePath } from "path";
|
|
209
|
+
import { existsSync as existsSync32, readFileSync as readFileSync23, readdirSync as readdirSync16, statSync as statSync16, realpathSync as realpathSync3, createReadStream } from "fs";
|
|
210
210
|
import { networkInterfaces as networkInterfaces2 } from "os";
|
|
211
211
|
|
|
212
212
|
// src/config/config-manager.ts
|
|
@@ -691,8 +691,14 @@ ${err}`
|
|
|
691
691
|
"deepseek-v4-flash-vision-exp"
|
|
692
692
|
]);
|
|
693
693
|
const DEEPSEEK_TARGET = "deepseek-flash";
|
|
694
|
-
const LEGACY_KIMI = /* @__PURE__ */ new Set([
|
|
695
|
-
|
|
694
|
+
const LEGACY_KIMI = /* @__PURE__ */ new Set([
|
|
695
|
+
"kimi-k2-0711-preview",
|
|
696
|
+
"kimi-k2-turbo-preview",
|
|
697
|
+
"kimi-k2.5",
|
|
698
|
+
"kimi-k2-thinking",
|
|
699
|
+
"kimi-k2-thinking-turbo"
|
|
700
|
+
]);
|
|
701
|
+
const KIMI_TARGET = "kimi-k2.7-code";
|
|
696
702
|
const LEGACY_CLAUDE = {
|
|
697
703
|
"claude-sonnet-4-5-20250929": "claude-sonnet-5-5",
|
|
698
704
|
"claude-sonnet-4-5": "claude-sonnet-5-5",
|
|
@@ -921,7 +927,6 @@ function deepSeekCnyPricing(cacheRead, input, output) {
|
|
|
921
927
|
output: output / CNY_PER_USD
|
|
922
928
|
};
|
|
923
929
|
}
|
|
924
|
-
var DEEPSEEK_V4_PRO_ROUTED_TO_FLASH_AT = /* @__PURE__ */ new Date("2026-09-14T04:00:00.000Z");
|
|
925
930
|
var DEEPSEEK_V41_FLASH_ROUTING_CONFIRMED_AT = /* @__PURE__ */ new Date("2026-09-11T00:00:00.000Z");
|
|
926
931
|
function isDeepSeekPeakHour(at) {
|
|
927
932
|
const weekday = at.getUTCDay();
|
|
@@ -937,7 +942,6 @@ function getDeepSeekV4Pricing(model, at) {
|
|
|
937
942
|
const isPro = model.startsWith("deepseek-v4-pro");
|
|
938
943
|
const isFlash = model.startsWith("deepseek-v4-flash");
|
|
939
944
|
if (!isPro && !isFlash) return null;
|
|
940
|
-
if (isPro && at >= DEEPSEEK_V4_PRO_ROUTED_TO_FLASH_AT) return deepSeekFlash41Pricing(at);
|
|
941
945
|
if (isFlash && at >= DEEPSEEK_V41_FLASH_ROUTING_CONFIRMED_AT) return deepSeekFlash41Pricing(at);
|
|
942
946
|
if (at < DEEPSEEK_TIME_PRICING_EFFECTIVE_AT) {
|
|
943
947
|
return isPro ? deepSeekCnyPricing(0.025, 3, 6) : deepSeekCnyPricing(0.02, 1, 2);
|
|
@@ -1016,6 +1020,12 @@ var PRICING_TABLE = {
|
|
|
1016
1020
|
// Kimi K3(2026-07 旗舰,1M 上下文)官方定价 platform.kimi.ai/pricing/chat-k3:
|
|
1017
1021
|
// 输入 cache-miss $3.00 / cache-hit $0.30,输出 $15.00(/MTok)。
|
|
1018
1022
|
"kimi-k3": { input: 3, output: 15, cacheRead: 0.3 },
|
|
1023
|
+
// K2.6 / K2.7 Code:官方 platform.kimi.ai/docs/pricing/chat(2026-10-18 核对,USD/MTok)。
|
|
1024
|
+
// 国内站人民币价 ¥6.5/¥27(缓存 ¥1.1 / ¥1.3)按 ¥6.9 折算与之相差 <3%,沿用 K3 那行的美元口径。
|
|
1025
|
+
// 此前 K2.6 没有单列,前缀落到 'kimi-k2'($0.6/$2.5),输出低报约 37%。
|
|
1026
|
+
"kimi-k2.6": { input: 0.95, output: 4, cacheRead: 0.16 },
|
|
1027
|
+
"kimi-k2.7-code": { input: 0.95, output: 4, cacheRead: 0.19 },
|
|
1028
|
+
"kimi-k2.7-code-highspeed": { input: 1.9, output: 8, cacheRead: 0.38 },
|
|
1019
1029
|
// ── Zhipu GLM ─────────────────────────────────────────────────
|
|
1020
1030
|
"glm-4-plus": { input: 0.7, output: 0.7 },
|
|
1021
1031
|
"glm-4": { input: 0.14, output: 0.14 },
|
|
@@ -1037,6 +1047,11 @@ var PRICING_TABLE = {
|
|
|
1037
1047
|
// 没公布截止日期,静态表表达不了这个时间维度;高估比低估安全——预算告警早触发
|
|
1038
1048
|
// 好过晚触发。折扣期内 `/cost` 会比实际偏高约一倍,这是刻意的取舍。
|
|
1039
1049
|
"glm-5.3-flash": { input: 0.116, output: 0.406, cacheRead: 0.033 },
|
|
1050
|
+
// GLM-5.3-FlashX:官方定价页(docs.bigmodel.cn/cn/guide/start/pricing,2026-10-18 浏览器读取)
|
|
1051
|
+
// 输入 2 元、输出 7 元、缓存命中 0.57 元。必须单列——否则前缀匹配会落到上面的 glm-5.3-flash,低报 2.5 倍。
|
|
1052
|
+
"glm-5.3-flashx": { input: 2 / CNY_PER_USD, output: 7 / CNY_PER_USD, cacheRead: 0.57 / CNY_PER_USD },
|
|
1053
|
+
// GLM-4.7-Flash:官方免费(输入/输出/缓存全免)。必须单列——否则前缀落到 'glm-4'($0.14)。
|
|
1054
|
+
"glm-4.7-flash": { input: 0, output: 0, cacheRead: 0 },
|
|
1040
1055
|
// GLM-5.2:与 GLM-5.3 同价(同一定价页:8 / 28 / 缓存命中 2 元),口径修正同上。
|
|
1041
1056
|
"glm-5.2": { input: 8 / CNY_PER_USD, output: 28 / CNY_PER_USD, cacheRead: 2 / CNY_PER_USD },
|
|
1042
1057
|
// GLM-5V-Turbo(2026-04 视觉编程旗舰)官方直连 API 定价 $1.20 / $4.00。
|
|
@@ -1046,8 +1061,26 @@ var PRICING_TABLE = {
|
|
|
1046
1061
|
"glm-z1-air": { input: 0.2, output: 0.6 },
|
|
1047
1062
|
"glm-z1-flash": { input: 0, output: 0 },
|
|
1048
1063
|
// ── MiniMax (海螺) ────────────────────────────────────────────
|
|
1049
|
-
//
|
|
1050
|
-
//
|
|
1064
|
+
// 官方定价页 platform.minimax.cn/docs/guides/pricing(2026-10-18 核对,元/百万 tokens),按 ¥6.9 折算。
|
|
1065
|
+
// 本 provider 打的是国内站 api.minimaxi.com,按人民币计费。
|
|
1066
|
+
// M3 记的是「永久五折」后的价(官方原文标注永久,不同于智谱的限时折扣),≤512K 输入档;
|
|
1067
|
+
// >512K 那档见 computeCost 的 LONG_PROMPT_TIERS。M3 未公布缓存写入价,缺省按输入价(偏高估)。
|
|
1068
|
+
"minimax-m3": { input: 2.1 / CNY_PER_USD, output: 8.4 / CNY_PER_USD, cacheRead: 0.42 / CNY_PER_USD },
|
|
1069
|
+
"minimax-m2.7": { input: 2.1 / CNY_PER_USD, output: 8.4 / CNY_PER_USD, cacheRead: 0.42 / CNY_PER_USD, cacheWrite: 2.625 / CNY_PER_USD },
|
|
1070
|
+
"minimax-m2.7-highspeed": { input: 4.2 / CNY_PER_USD, output: 16.8 / CNY_PER_USD, cacheRead: 0.42 / CNY_PER_USD, cacheWrite: 2.625 / CNY_PER_USD },
|
|
1071
|
+
// M2.5 / M2.1 / M2(历史模型)同价;highspeed 变体输入输出翻倍、缓存同价。
|
|
1072
|
+
"minimax-m2": { input: 2.1 / CNY_PER_USD, output: 8.4 / CNY_PER_USD, cacheRead: 0.21 / CNY_PER_USD, cacheWrite: 2.625 / CNY_PER_USD },
|
|
1073
|
+
"minimax-m2.5-highspeed": { input: 4.2 / CNY_PER_USD, output: 16.8 / CNY_PER_USD, cacheRead: 0.21 / CNY_PER_USD, cacheWrite: 2.625 / CNY_PER_USD },
|
|
1074
|
+
"minimax-m2.1-highspeed": { input: 4.2 / CNY_PER_USD, output: 16.8 / CNY_PER_USD, cacheRead: 0.21 / CNY_PER_USD, cacheWrite: 2.625 / CNY_PER_USD },
|
|
1075
|
+
// ── Qwen(阿里云百炼,北京地域)───────────────────────────────────
|
|
1076
|
+
// 官方 help.aliyun.com/zh/model-studio/model-pricing(2026-10-18 核对,元/百万 tokens,原价),按 ¥6.9 折算。
|
|
1077
|
+
// 思考与非思考输出同价。qwen3.7-plus 当前限时 8 折,记原价(高估方向,同智谱 glm-5.3-flash 的取舍)。
|
|
1078
|
+
// 官方未给出各模型的缓存单价,不填 cacheRead,命中按输入全价算(高估方向)。
|
|
1079
|
+
// 长提示分档(qwen3.7-plus >256K、qwen-flash >128K / >256K)见 LONG_PROMPT_TIERS;此处为最低档。
|
|
1080
|
+
"qwen3.8-max": { input: 12 / CNY_PER_USD, output: 36 / CNY_PER_USD },
|
|
1081
|
+
"qwen3.7-plus": { input: 2 / CNY_PER_USD, output: 8 / CNY_PER_USD },
|
|
1082
|
+
"qwen3.8-flash": { input: 0.8 / CNY_PER_USD, output: 2.7 / CNY_PER_USD },
|
|
1083
|
+
"qwen-flash": { input: 0.15 / CNY_PER_USD, output: 1.5 / CNY_PER_USD },
|
|
1051
1084
|
// ── OpenRouter (pass-through — actual cost depends on underlying model) ──
|
|
1052
1085
|
// 绝大多数 id 仍**刻意留空**:真实价由底层模型 + OpenRouter 加价决定,静态表覆盖不了
|
|
1053
1086
|
// 396 个模型,未收录的照旧显示 "—"(未知)而不是假的 $0.00。
|
|
@@ -1102,11 +1135,21 @@ function getPricing(provider, model, at = /* @__PURE__ */ new Date()) {
|
|
|
1102
1135
|
return null;
|
|
1103
1136
|
}
|
|
1104
1137
|
var CLAUDE_HAIKU_55_LONG = { input: 0.5, output: 2.5, cacheWrite: 0.625, cacheRead: 0.05 };
|
|
1105
|
-
var
|
|
1138
|
+
var LONG_PROMPT_TIERS = [
|
|
1139
|
+
{ prefix: "claude-haiku-5-5", overTokens: 1e5, pricing: CLAUDE_HAIKU_55_LONG },
|
|
1140
|
+
{
|
|
1141
|
+
prefix: "minimax-m3",
|
|
1142
|
+
overTokens: 512e3,
|
|
1143
|
+
pricing: { input: 4.2 / CNY_PER_USD, output: 16.8 / CNY_PER_USD, cacheRead: 0.84 / CNY_PER_USD }
|
|
1144
|
+
},
|
|
1145
|
+
{ prefix: "qwen3.7-plus", overTokens: 256e3, pricing: { input: 6 / CNY_PER_USD, output: 24 / CNY_PER_USD } },
|
|
1146
|
+
{ prefix: "qwen-flash", overTokens: 256e3, pricing: { input: 1.2 / CNY_PER_USD, output: 12 / CNY_PER_USD } },
|
|
1147
|
+
{ prefix: "qwen-flash", overTokens: 128e3, pricing: { input: 0.6 / CNY_PER_USD, output: 6 / CNY_PER_USD } }
|
|
1148
|
+
];
|
|
1106
1149
|
function longPromptTier(model, usage) {
|
|
1107
|
-
|
|
1150
|
+
const key = model.toLowerCase();
|
|
1108
1151
|
const prompt = usage.inputTokens + (usage.cacheCreationTokens ?? 0) + (usage.cacheReadTokens ?? 0);
|
|
1109
|
-
return prompt >
|
|
1152
|
+
return LONG_PROMPT_TIERS.find((t) => key.startsWith(t.prefix) && prompt > t.overTokens)?.pricing ?? null;
|
|
1110
1153
|
}
|
|
1111
1154
|
function computeCost(provider, model, usage, at = /* @__PURE__ */ new Date()) {
|
|
1112
1155
|
const p = longPromptTier(model, usage) ?? getPricing(provider, model, at);
|
|
@@ -2816,12 +2859,12 @@ function findPhantomClaims(content, extraMessages) {
|
|
|
2816
2859
|
const claimed = extractClaimedFilePaths(content);
|
|
2817
2860
|
if (claimed.length === 0) return [];
|
|
2818
2861
|
const normalize = (p) => p.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
2819
|
-
const
|
|
2862
|
+
const basename12 = (p) => {
|
|
2820
2863
|
const parts = normalize(p).split("/");
|
|
2821
2864
|
return parts[parts.length - 1] ?? "";
|
|
2822
2865
|
};
|
|
2823
2866
|
const written = extractWrittenFilePaths(extraMessages).map(normalize);
|
|
2824
|
-
const writtenBases = new Set(written.map(
|
|
2867
|
+
const writtenBases = new Set(written.map(basename12));
|
|
2825
2868
|
const writtenFull = new Set(written);
|
|
2826
2869
|
const bashText = extractBashCommands(extraMessages).map((c) => c.replace(/\\/g, "/").toLowerCase()).join("\n");
|
|
2827
2870
|
return claimed.filter((raw) => {
|
|
@@ -2830,8 +2873,8 @@ function findPhantomClaims(content, extraMessages) {
|
|
|
2830
2873
|
for (const w of writtenFull) {
|
|
2831
2874
|
if (w.endsWith("/" + norm2) || norm2.endsWith("/" + w)) return false;
|
|
2832
2875
|
}
|
|
2833
|
-
if (writtenBases.has(
|
|
2834
|
-
const base =
|
|
2876
|
+
if (writtenBases.has(basename12(norm2))) return false;
|
|
2877
|
+
const base = basename12(norm2);
|
|
2835
2878
|
if (base && bashText.includes(base)) return false;
|
|
2836
2879
|
return true;
|
|
2837
2880
|
});
|
|
@@ -4447,7 +4490,9 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
|
|
|
4447
4490
|
},
|
|
4448
4491
|
{
|
|
4449
4492
|
id: "deepseek-v4-pro",
|
|
4450
|
-
|
|
4493
|
+
// 2026-09-11 官方撤回了「9-14 起路由到 Flash」,Pro 照常服务、按 Pro 价计费(见 pricing.ts)。
|
|
4494
|
+
// 价格约为 Flash 的 4 倍且不收图片,但 Flash 替代不了它的能力档,故保留。
|
|
4495
|
+
displayName: "DeepSeek V4 Pro (0813, text-only)",
|
|
4451
4496
|
contextWindow: 1048576,
|
|
4452
4497
|
supportsStreaming: true,
|
|
4453
4498
|
supportsThinking: true
|
|
@@ -4506,20 +4551,24 @@ var DeepSeekProvider = class extends OpenAICompatibleProvider {
|
|
|
4506
4551
|
var ZHIPU_CONFIG = {
|
|
4507
4552
|
id: "zhipu",
|
|
4508
4553
|
displayName: "Zhipu (GLM)",
|
|
4509
|
-
defaultModel: "glm-
|
|
4554
|
+
defaultModel: "glm-5.3-flash",
|
|
4510
4555
|
apiKeyEnvVar: "AICLI_API_KEY_ZHIPU",
|
|
4511
4556
|
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
|
|
4512
4557
|
defaultTimeout: 3e5,
|
|
4513
4558
|
models: [
|
|
4514
4559
|
{ id: "glm-5.3", displayName: "GLM-5.3 (2026-08 Flagship, 1M, Coding/Security, \u59CB\u7EC8\u601D\u8003)", contextWindow: 1048576, supportsStreaming: true, supportsThinking: true },
|
|
4560
|
+
// GLM-5.3-FlashX(2026-10):Flash 与 5.3 之间的一档,¥2/¥7、缓存命中 ¥0.57(官方定价页)。
|
|
4561
|
+
// 2026-10-18 实测:同样始终思考(`disabled` → 400/1210),`low` 档 200,base64 图片可识别。
|
|
4562
|
+
{ id: "glm-5.3-flashx", displayName: "GLM-5.3 FlashX (\u539F\u751F\u591A\u6A21\u6001, 1M, \u4EF7\u683C\u7EA6\u4E3A 5.3 \u7684 1/4, \u59CB\u7EC8\u601D\u8003)", contextWindow: 1048576, supportsStreaming: true, supportsThinking: true },
|
|
4515
4563
|
{ id: "glm-5.3-flash", displayName: "GLM-5.3 Flash (\u539F\u751F\u591A\u6A21\u6001, 1M, \u8F93\u5165\u7EA6\u4E3A 5.3 \u7684 1/10, \u59CB\u7EC8\u601D\u8003)", contextWindow: 1048576, supportsStreaming: true, supportsThinking: true },
|
|
4516
|
-
|
|
4517
|
-
{ id: "glm-
|
|
4518
|
-
// 2026-10-
|
|
4519
|
-
//
|
|
4520
|
-
//
|
|
4521
|
-
//
|
|
4522
|
-
|
|
4564
|
+
// 免费(输入/输出/缓存全免,官方定价页「更多文本模型」)。2026-10-18 实测 200,但慢(一句 ok 约 15s)。
|
|
4565
|
+
{ id: "glm-4.7-flash", displayName: "GLM-4.7 Flash (\u514D\u8D39, 200K)", contextWindow: 2e5, supportsStreaming: true }
|
|
4566
|
+
// 2026-10-18 按「老模型没有价格优势就下架」清理(端点仍可用,`/model` 照收,pricing.ts 保留费率供历史回算):
|
|
4567
|
+
// - glm-5.2:与 glm-5.3 同价(¥8/¥28/缓存 ¥2),已被取代
|
|
4568
|
+
// - glm-5v-turbo:¥5/¥22 起,比同样原生多模态的 glm-5.3-flash(¥0.8/¥2.8)贵 6–8 倍
|
|
4569
|
+
// - glm-4.6:已不在官方定价页上,且旧价高于 glm-5.3-flash
|
|
4570
|
+
// 更早的 2026-10-07 清理:glm-5.1-reasoning / glm-5.1-air 官方从未存在(取自第三方标注,同 v0.4.198
|
|
4571
|
+
// 的 `glm-5.2[1m]`),glm-5 / glm-5.1 已被取代。
|
|
4523
4572
|
]
|
|
4524
4573
|
};
|
|
4525
4574
|
var REASONING_EFFORT_MODELS = /^glm-5/i;
|
|
@@ -4585,7 +4634,10 @@ var KimiProvider = class _KimiProvider extends OpenAICompatibleProvider {
|
|
|
4585
4634
|
*/
|
|
4586
4635
|
static TEMP_1_MODELS = /* @__PURE__ */ new Set([
|
|
4587
4636
|
"kimi-k3",
|
|
4637
|
+
"kimi-k2.7-code",
|
|
4638
|
+
"kimi-k2.7-code-highspeed",
|
|
4588
4639
|
"kimi-k2.6",
|
|
4640
|
+
// 已 404 的旧 code 仍留在这里:config 自愈迁移之外的显式 `/model kimi-k2.5` 不该先撞 temperature 400
|
|
4589
4641
|
"kimi-k2.5",
|
|
4590
4642
|
"kimi-k2-thinking",
|
|
4591
4643
|
"kimi-k2-thinking-turbo"
|
|
@@ -4606,7 +4658,7 @@ var KimiProvider = class _KimiProvider extends OpenAICompatibleProvider {
|
|
|
4606
4658
|
info = {
|
|
4607
4659
|
id: "kimi",
|
|
4608
4660
|
displayName: "Kimi (Moonshot AI)",
|
|
4609
|
-
defaultModel: "kimi-k2.
|
|
4661
|
+
defaultModel: "kimi-k2.7-code",
|
|
4610
4662
|
apiKeyEnvVar: "AICLI_API_KEY_KIMI",
|
|
4611
4663
|
requiresApiKey: true,
|
|
4612
4664
|
baseUrl: this.defaultBaseUrl,
|
|
@@ -4616,39 +4668,33 @@ var KimiProvider = class _KimiProvider extends OpenAICompatibleProvider {
|
|
|
4616
4668
|
// - contextWindow 1M(1048576);code 就是 `kimi-k3`(UI 名 "K3 · Max" ≠ API code)
|
|
4617
4669
|
// - temperature 固定 1.0(已并入 TEMP_1_MODELS)
|
|
4618
4670
|
// - vision 走 base64 / ms://file-id(不收公网 URL)——本版未接图片输入路径,仅文本/工具
|
|
4619
|
-
//
|
|
4671
|
+
// 默认用 kimi-k2.7-code(K3 输出 $15/MTok,约为它的 4 倍,按需 /model kimi-k3)。
|
|
4620
4672
|
{
|
|
4621
4673
|
id: "kimi-k3",
|
|
4622
4674
|
displayName: "Kimi K3",
|
|
4623
4675
|
contextWindow: 1048576,
|
|
4624
4676
|
supportsStreaming: true
|
|
4625
4677
|
},
|
|
4626
|
-
// Kimi K2.
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
supportsStreaming: true
|
|
4632
|
-
},
|
|
4678
|
+
// Kimi K2.7 Code(官方 platform.kimi.com/docs/guide/kimi-k2-7-code-quickstart,2026-10-18 核对):
|
|
4679
|
+
// - 256K 上下文;虽名为 Coding 模型,官方写明也支持对话与 Agent 任务
|
|
4680
|
+
// - 思考默认开启且**关不掉**(关闭报错)——本 provider 不发 thinking 字段,正好不踩
|
|
4681
|
+
// - temperature 固定 1.0(已并入 TEMP_1_MODELS);tool_choice 只收 auto / none
|
|
4682
|
+
// - 价格与 K2.6 相同($0.95/$4.00),各项基准提升 10–30%,故取代 K2.6 成为默认
|
|
4633
4683
|
{
|
|
4634
|
-
id: "kimi-k2.
|
|
4635
|
-
displayName: "Kimi K2.
|
|
4684
|
+
id: "kimi-k2.7-code",
|
|
4685
|
+
displayName: "Kimi K2.7 Code",
|
|
4636
4686
|
contextWindow: 262144,
|
|
4637
4687
|
supportsStreaming: true
|
|
4638
4688
|
},
|
|
4639
|
-
//
|
|
4689
|
+
// 同一模型的高速版:输出约 5–6 倍速,价格翻倍。
|
|
4640
4690
|
{
|
|
4641
|
-
id: "kimi-k2-
|
|
4642
|
-
displayName: "Kimi K2
|
|
4643
|
-
contextWindow: 262144,
|
|
4644
|
-
supportsStreaming: true
|
|
4645
|
-
},
|
|
4646
|
-
{
|
|
4647
|
-
id: "kimi-k2-thinking-turbo",
|
|
4648
|
-
displayName: "Kimi K2 Thinking Turbo",
|
|
4691
|
+
id: "kimi-k2.7-code-highspeed",
|
|
4692
|
+
displayName: "Kimi K2.7 Code Highspeed (2x price, ~5x speed)",
|
|
4649
4693
|
contextWindow: 262144,
|
|
4650
4694
|
supportsStreaming: true
|
|
4651
4695
|
}
|
|
4696
|
+
// 2026-10-18 下架:kimi-k2.6 与 K2.7 Code 同价、已被取代(端点仍可用,`/model` 照收);
|
|
4697
|
+
// kimi-k2.5 / kimi-k2-thinking / kimi-k2-thinking-turbo 端点已 404,由 config 自愈迁移到 kimi-k2.7-code。
|
|
4652
4698
|
]
|
|
4653
4699
|
};
|
|
4654
4700
|
/**
|
|
@@ -4760,11 +4806,10 @@ var MINIMAX_CONFIG = {
|
|
|
4760
4806
|
apiKeyEnvVar: "AICLI_API_KEY_MINIMAX",
|
|
4761
4807
|
baseUrl: "https://api.minimaxi.com/v1",
|
|
4762
4808
|
models: [
|
|
4763
|
-
{ id: "MiniMax-M3", displayName: "MiniMax M3\uFF08\u65D7\u8230\uFF0C1M \u4E0A\u4E0B\u6587\uFF09", contextWindow: 1e6, supportsStreaming: true }
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
{ id: "MiniMax-M2.5-highspeed", displayName: "MiniMax M2.5 Highspeed", contextWindow: 1e6, supportsStreaming: true }
|
|
4809
|
+
{ id: "MiniMax-M3", displayName: "MiniMax M3\uFF08\u65D7\u8230\uFF0C1M \u4E0A\u4E0B\u6587\uFF09", contextWindow: 1e6, supportsStreaming: true }
|
|
4810
|
+
// 2026-10-18 按「老模型没有价格优势就下架」清理(官方定价页 platform.minimax.cn/docs/guides/pricing):
|
|
4811
|
+
// M3「永久五折」后 ¥2.1/¥8.4,与 M2.7 同价、比 M2.x highspeed 便宜一半;M2.5 / M2.1 / M2 官方已归入
|
|
4812
|
+
// 「历史模型」。端点仍可用,`/model` 照收,pricing.ts 保留费率供历史回算。
|
|
4768
4813
|
]
|
|
4769
4814
|
};
|
|
4770
4815
|
var MiniMaxProvider = createStaticProviderClass(MINIMAX_CONFIG);
|
|
@@ -4773,14 +4818,20 @@ var MiniMaxProvider = createStaticProviderClass(MINIMAX_CONFIG);
|
|
|
4773
4818
|
var QWEN_CONFIG = {
|
|
4774
4819
|
id: "qwen",
|
|
4775
4820
|
displayName: "Qwen (Alibaba Cloud)",
|
|
4776
|
-
defaultModel: "
|
|
4821
|
+
defaultModel: "qwen3.8-flash",
|
|
4777
4822
|
apiKeyEnvVar: "AICLI_API_KEY_QWEN",
|
|
4778
4823
|
baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
4824
|
+
// 2026-10-18 按百炼官方文档更新(help.aliyun.com/zh/model-studio/models、/model-pricing、/deep-thinking)。
|
|
4825
|
+
// **未经真实端点实测**(本机无 Qwen key)。三款 qwen3.x 默认开启思考、支持非流式调用、纯文本输入;
|
|
4826
|
+
// 思考与非思考输出同价。上下文按官方价格阶梯的上限 1M 记。
|
|
4779
4827
|
models: [
|
|
4780
|
-
{ id: "
|
|
4781
|
-
{ id: "
|
|
4782
|
-
{ id: "
|
|
4783
|
-
|
|
4828
|
+
{ id: "qwen3.8-max", displayName: "Qwen3.8 Max\uFF08\u65D7\u8230\uFF0C1M\uFF0C\xA512/\xA536\uFF09", contextWindow: 1e6, supportsStreaming: true },
|
|
4829
|
+
{ id: "qwen3.7-plus", displayName: "Qwen3.7 Plus\uFF081M\uFF0C\u2264256K \xA52/\xA58\uFF09", contextWindow: 1e6, supportsStreaming: true },
|
|
4830
|
+
{ id: "qwen3.8-flash", displayName: "Qwen3.8 Flash\uFF081M\uFF0C\xA50.8/\xA52.7\uFF09", contextWindow: 1e6, supportsStreaming: true },
|
|
4831
|
+
// 老模型里唯一有价格优势的:≤128K ¥0.15/¥1.5,最便宜。默认不开思考。
|
|
4832
|
+
{ id: "qwen-flash", displayName: "Qwen Flash\uFF08\u6700\u4FBF\u5B9C\uFF0C\u2264128K \xA50.15/\xA51.5\uFF09", contextWindow: 1e6, supportsStreaming: true }
|
|
4833
|
+
// 下架(端点若仍可用,`/model` 照收):qwen-max ¥2.4/¥9.6 比 qwen3.7-plus 还贵;qwen-plus 价格不如
|
|
4834
|
+
// qwen-flash、能力不如 qwen3.8-flash;qwen-turbo / qwen-coder-plus 已不在官方价格页上。
|
|
4784
4835
|
]
|
|
4785
4836
|
};
|
|
4786
4837
|
var QwenProvider = createStaticProviderClass(QWEN_CONFIG);
|
|
@@ -15953,8 +16004,12 @@ function stripConvergedMarker(content) {
|
|
|
15953
16004
|
|
|
15954
16005
|
// src/hub/agent.ts
|
|
15955
16006
|
var PASS_MARKER = "[PASS]";
|
|
16007
|
+
function stripThinkBlocks(raw) {
|
|
16008
|
+
const filter = new ThinkTagFilter();
|
|
16009
|
+
return filter.push(raw) + filter.flush();
|
|
16010
|
+
}
|
|
15956
16011
|
function parseTurn(raw) {
|
|
15957
|
-
const trimmed = raw.trim();
|
|
16012
|
+
const trimmed = stripThinkBlocks(raw).trim();
|
|
15958
16013
|
const upper = trimmed.toUpperCase();
|
|
15959
16014
|
if (upper.startsWith(PASS_MARKER) || upper === PASS_MARKER) {
|
|
15960
16015
|
return { content: "", passed: true, converged: false };
|
|
@@ -16034,6 +16089,7 @@ var HubAgent = class {
|
|
|
16034
16089
|
const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds, opts?.voteConverge);
|
|
16035
16090
|
const messages = this.buildMessages(history);
|
|
16036
16091
|
let raw = "";
|
|
16092
|
+
const thinkFilter = new ThinkTagFilter();
|
|
16037
16093
|
const stream = provider.chatStream({
|
|
16038
16094
|
messages,
|
|
16039
16095
|
model: this.modelId,
|
|
@@ -16048,13 +16104,16 @@ var HubAgent = class {
|
|
|
16048
16104
|
for await (const chunk of stream) {
|
|
16049
16105
|
if (chunk.delta) {
|
|
16050
16106
|
raw += chunk.delta;
|
|
16051
|
-
|
|
16107
|
+
const visible = thinkFilter.push(chunk.delta);
|
|
16108
|
+
if (visible) onToken?.(visible);
|
|
16052
16109
|
}
|
|
16053
16110
|
if (opts?.signal?.aborted) break;
|
|
16054
16111
|
}
|
|
16055
16112
|
} catch (error) {
|
|
16056
16113
|
if (!opts?.signal?.aborted) throw error;
|
|
16057
16114
|
}
|
|
16115
|
+
const tail = thinkFilter.flush();
|
|
16116
|
+
if (tail) onToken?.(tail);
|
|
16058
16117
|
const { content, passed, converged } = parseTurn(raw);
|
|
16059
16118
|
return {
|
|
16060
16119
|
speaker: this.role.id,
|
|
@@ -16089,7 +16148,7 @@ var HubAgent = class {
|
|
|
16089
16148
|
maxTokens: 4096,
|
|
16090
16149
|
...this.thinking ?? {}
|
|
16091
16150
|
});
|
|
16092
|
-
return response.content.trim();
|
|
16151
|
+
return stripThinkBlocks(response.content).trim();
|
|
16093
16152
|
}
|
|
16094
16153
|
// ── Private ──────────────────────────────────────────────────────
|
|
16095
16154
|
buildSystemPrompt(topic, round, maxRounds, voteConverge) {
|
|
@@ -16170,7 +16229,7 @@ Produce a structured, decision-oriented synthesis with these exact sections:
|
|
|
16170
16229
|
4. **Action Items** \u2014 concrete next steps as a checklist. For each, suggest which role/expertise should own it, e.g. "- [ ] (\u67B6\u6784\u5E08) \u8BC4\u4F30\u670D\u52A1\u62C6\u5206\u8FB9\u754C".
|
|
16171
16230
|
5. **Risks & Open Questions** \u2014 unresolved issues and what to watch.
|
|
16172
16231
|
|
|
16173
|
-
Keep it tight (within ~600 words). Use the same language as the discussion.`;
|
|
16232
|
+
Keep it tight (within ~600 words). Use the same language as the discussion \u2014 including the section headings (translate them, e.g. \u51B3\u7B56 / \u5EFA\u8BAE\u3001\u5173\u952E\u5171\u8BC6\u3001\u5206\u6B67\u70B9\u3001\u884C\u52A8\u9879\u3001\u98CE\u9669\u4E0E\u5F00\u653E\u95EE\u9898 for a Chinese discussion).`;
|
|
16174
16233
|
}
|
|
16175
16234
|
};
|
|
16176
16235
|
|
|
@@ -16546,8 +16605,57 @@ function resolveRoleProviders(roles, lookup, defaultProvider, defaultModel, avai
|
|
|
16546
16605
|
return { roles: outRoles, assignments, warnings };
|
|
16547
16606
|
}
|
|
16548
16607
|
|
|
16608
|
+
// src/hub/custom-presets.ts
|
|
16609
|
+
import { existsSync as existsSync25, readdirSync as readdirSync12, readFileSync as readFileSync18 } from "fs";
|
|
16610
|
+
import { join as join18, basename as basename10 } from "path";
|
|
16611
|
+
var CUSTOM_PRESET_PREFIX = "custom:";
|
|
16612
|
+
var HUB_ROLES_DIRNAME = "hub-roles";
|
|
16613
|
+
function parseRolesJson(parsed) {
|
|
16614
|
+
const rawRoles = Array.isArray(parsed) ? parsed : parsed?.roles;
|
|
16615
|
+
if (!Array.isArray(rawRoles) || rawRoles.length === 0) {
|
|
16616
|
+
throw new Error("roles must be a non-empty array");
|
|
16617
|
+
}
|
|
16618
|
+
return rawRoles.map((r) => ({
|
|
16619
|
+
id: r.id ?? r.name?.toLowerCase().replace(/\s+/g, "-") ?? "agent",
|
|
16620
|
+
name: r.name ?? r.id ?? "Agent",
|
|
16621
|
+
persona: r.persona ?? r.description ?? `You are ${r.name ?? "an AI assistant"}.`,
|
|
16622
|
+
...r.provider && { provider: r.provider },
|
|
16623
|
+
...r.model && { model: r.model },
|
|
16624
|
+
...r.color && { color: r.color }
|
|
16625
|
+
}));
|
|
16626
|
+
}
|
|
16627
|
+
function loadCustomPresets(configDir) {
|
|
16628
|
+
const dir = join18(configDir, HUB_ROLES_DIRNAME);
|
|
16629
|
+
const presets = [];
|
|
16630
|
+
const warnings = [];
|
|
16631
|
+
if (!existsSync25(dir)) return { presets, warnings };
|
|
16632
|
+
let files;
|
|
16633
|
+
try {
|
|
16634
|
+
files = readdirSync12(dir).filter((f) => f.toLowerCase().endsWith(".json")).sort();
|
|
16635
|
+
} catch (err) {
|
|
16636
|
+
return { presets, warnings: [`${dir}: ${err.message}`] };
|
|
16637
|
+
}
|
|
16638
|
+
for (const file of files) {
|
|
16639
|
+
const stem = basename10(file, file.slice(file.lastIndexOf(".")));
|
|
16640
|
+
try {
|
|
16641
|
+
const parsed = JSON.parse(readFileSync18(join18(dir, file), "utf-8").replace(/^/, ""));
|
|
16642
|
+
const roles = parseRolesJson(parsed);
|
|
16643
|
+
const meta = Array.isArray(parsed) ? {} : parsed;
|
|
16644
|
+
presets.push({
|
|
16645
|
+
id: `${CUSTOM_PRESET_PREFIX}${stem}`,
|
|
16646
|
+
name: typeof meta.name === "string" && meta.name.trim() ? meta.name.trim() : stem,
|
|
16647
|
+
description: typeof meta.description === "string" && meta.description.trim() ? meta.description.trim() : roles.map((r) => r.name).join("\xB7"),
|
|
16648
|
+
roles
|
|
16649
|
+
});
|
|
16650
|
+
} catch (err) {
|
|
16651
|
+
warnings.push(`${HUB_ROLES_DIRNAME}/${file}: ${err.message}`);
|
|
16652
|
+
}
|
|
16653
|
+
}
|
|
16654
|
+
return { presets, warnings };
|
|
16655
|
+
}
|
|
16656
|
+
|
|
16549
16657
|
// src/hub/persist.ts
|
|
16550
|
-
import { join as
|
|
16658
|
+
import { join as join19 } from "path";
|
|
16551
16659
|
function discussionToMessages(state2) {
|
|
16552
16660
|
const out = [];
|
|
16553
16661
|
const t0 = state2.messages[0]?.timestamp ?? /* @__PURE__ */ new Date();
|
|
@@ -16585,7 +16693,7 @@ async function persistDiscussion(state2, config, defaultProvider, defaultModel)
|
|
|
16585
16693
|
session.title = `[Hub] ${state2.topic.slice(0, 48)}`.replace(/\n/g, " ");
|
|
16586
16694
|
session.titleAiGenerated = true;
|
|
16587
16695
|
await sm.save();
|
|
16588
|
-
return { id: session.id, path:
|
|
16696
|
+
return { id: session.id, path: join19(config.getHistoryDir(), `${session.id}.json`) };
|
|
16589
16697
|
}
|
|
16590
16698
|
|
|
16591
16699
|
// src/core/think-command.ts
|
|
@@ -17046,8 +17154,8 @@ function costSourceNote(source2) {
|
|
|
17046
17154
|
}
|
|
17047
17155
|
|
|
17048
17156
|
// src/web/commands/_shared.ts
|
|
17049
|
-
import { existsSync as
|
|
17050
|
-
import { join as
|
|
17157
|
+
import { existsSync as existsSync28, readFileSync as readFileSync20, writeFileSync as writeFileSync3, mkdirSync as mkdirSync13, readdirSync as readdirSync14, statSync as statSync14, createWriteStream } from "fs";
|
|
17158
|
+
import { join as join22, resolve as resolve9, dirname as dirname9 } from "path";
|
|
17051
17159
|
|
|
17052
17160
|
// src/cli/review-prompts.ts
|
|
17053
17161
|
function buildReviewPrompt(diff, gitContextStr, detailed) {
|
|
@@ -17119,47 +17227,47 @@ function readGitDiff(options = {}) {
|
|
|
17119
17227
|
}
|
|
17120
17228
|
|
|
17121
17229
|
// src/diagnostics/doctor-report.ts
|
|
17122
|
-
import { existsSync as
|
|
17123
|
-
import { join as
|
|
17230
|
+
import { existsSync as existsSync27, statSync as statSync13 } from "fs";
|
|
17231
|
+
import { join as join21 } from "path";
|
|
17124
17232
|
import { arch as arch2, platform as platform5, release as release2 } from "os";
|
|
17125
17233
|
|
|
17126
17234
|
// src/diagnostics/crash-log.ts
|
|
17127
17235
|
import {
|
|
17128
|
-
existsSync as
|
|
17236
|
+
existsSync as existsSync26,
|
|
17129
17237
|
mkdirSync as mkdirSync12,
|
|
17130
|
-
readdirSync as
|
|
17131
|
-
readFileSync as
|
|
17238
|
+
readdirSync as readdirSync13,
|
|
17239
|
+
readFileSync as readFileSync19,
|
|
17132
17240
|
statSync as statSync12,
|
|
17133
17241
|
unlinkSync as unlinkSync6,
|
|
17134
17242
|
writeFileSync as writeFileSync2
|
|
17135
17243
|
} from "fs";
|
|
17136
|
-
import { join as
|
|
17244
|
+
import { join as join20 } from "path";
|
|
17137
17245
|
import { homedir as homedir7, platform as platform4, release, arch } from "os";
|
|
17138
17246
|
var LOGS_DIR_NAME = "logs";
|
|
17139
17247
|
var CRASH_LOG_PREFIX = "crash-";
|
|
17140
17248
|
function getLogsDir(configDir) {
|
|
17141
|
-
const base = configDir ??
|
|
17142
|
-
return
|
|
17249
|
+
const base = configDir ?? join20(homedir7(), CONFIG_DIR_NAME);
|
|
17250
|
+
return join20(base, LOGS_DIR_NAME);
|
|
17143
17251
|
}
|
|
17144
17252
|
function truncate(s, n) {
|
|
17145
17253
|
return s.length <= n ? s : s.slice(0, n) + "\u2026";
|
|
17146
17254
|
}
|
|
17147
17255
|
function listRecentCrashes(limit = 10, configDir) {
|
|
17148
17256
|
const dir = getLogsDir(configDir);
|
|
17149
|
-
if (!
|
|
17257
|
+
if (!existsSync26(dir)) return [];
|
|
17150
17258
|
const files = [];
|
|
17151
17259
|
let names;
|
|
17152
17260
|
try {
|
|
17153
|
-
names =
|
|
17261
|
+
names = readdirSync13(dir);
|
|
17154
17262
|
} catch {
|
|
17155
17263
|
return [];
|
|
17156
17264
|
}
|
|
17157
17265
|
for (const name of names) {
|
|
17158
17266
|
if (!name.startsWith(CRASH_LOG_PREFIX) || !name.endsWith(".log")) continue;
|
|
17159
|
-
const full =
|
|
17267
|
+
const full = join20(dir, name);
|
|
17160
17268
|
try {
|
|
17161
17269
|
const st = statSync12(full);
|
|
17162
|
-
const head =
|
|
17270
|
+
const head = readFileSync19(full, "utf-8").split("\n").slice(0, 20);
|
|
17163
17271
|
const tsLine = head.find((l) => l.startsWith("timestamp:"));
|
|
17164
17272
|
const kindLine = head.find((l) => l.startsWith("kind:"));
|
|
17165
17273
|
const msgIdx = head.findIndex((l) => l.trim() === "## message");
|
|
@@ -17178,18 +17286,18 @@ function listRecentCrashes(limit = 10, configDir) {
|
|
|
17178
17286
|
return files.slice(0, limit);
|
|
17179
17287
|
}
|
|
17180
17288
|
function getConfigDirUsage(configDir) {
|
|
17181
|
-
const base = configDir ??
|
|
17182
|
-
if (!
|
|
17289
|
+
const base = configDir ?? join20(homedir7(), CONFIG_DIR_NAME);
|
|
17290
|
+
if (!existsSync26(base)) return { totalBytes: 0, entries: [] };
|
|
17183
17291
|
const entries = [];
|
|
17184
17292
|
let total = 0;
|
|
17185
17293
|
let names;
|
|
17186
17294
|
try {
|
|
17187
|
-
names =
|
|
17295
|
+
names = readdirSync13(base);
|
|
17188
17296
|
} catch {
|
|
17189
17297
|
return { totalBytes: 0, entries: [] };
|
|
17190
17298
|
}
|
|
17191
17299
|
for (const name of names) {
|
|
17192
|
-
const full =
|
|
17300
|
+
const full = join20(base, name);
|
|
17193
17301
|
const bytes = dirSize(full);
|
|
17194
17302
|
entries.push({ name, bytes });
|
|
17195
17303
|
total += bytes;
|
|
@@ -17203,8 +17311,8 @@ function dirSize(path3) {
|
|
|
17203
17311
|
if (st.isFile()) return st.size;
|
|
17204
17312
|
if (!st.isDirectory()) return 0;
|
|
17205
17313
|
let sum = 0;
|
|
17206
|
-
for (const name of
|
|
17207
|
-
sum += dirSize(
|
|
17314
|
+
for (const name of readdirSync13(path3)) {
|
|
17315
|
+
sum += dirSize(join20(path3, name));
|
|
17208
17316
|
}
|
|
17209
17317
|
return sum;
|
|
17210
17318
|
} catch {
|
|
@@ -17214,7 +17322,7 @@ function dirSize(path3) {
|
|
|
17214
17322
|
|
|
17215
17323
|
// src/diagnostics/doctor-report.ts
|
|
17216
17324
|
function checkFile(label, path3) {
|
|
17217
|
-
const exists =
|
|
17325
|
+
const exists = existsSync27(path3);
|
|
17218
17326
|
let sizeBytes = null;
|
|
17219
17327
|
if (exists) {
|
|
17220
17328
|
try {
|
|
@@ -17257,12 +17365,12 @@ function buildDoctorReport(options) {
|
|
|
17257
17365
|
configDir,
|
|
17258
17366
|
providers: options.providers.listAll().map((p) => ({ id: p.id, displayName: p.displayName, configured: p.configured })),
|
|
17259
17367
|
files: [
|
|
17260
|
-
checkFile("config.json",
|
|
17261
|
-
checkFile("memory.md",
|
|
17262
|
-
checkFile("memory.jsonl",
|
|
17263
|
-
checkFile("dev-state.md",
|
|
17264
|
-
checkFile("hooks-trust.json",
|
|
17265
|
-
checkFile("plugin-state.json",
|
|
17368
|
+
checkFile("config.json", join21(configDir, "config.json")),
|
|
17369
|
+
checkFile("memory.md", join21(configDir, MEMORY_FILE_NAME)),
|
|
17370
|
+
checkFile("memory.jsonl", join21(configDir, "memory.jsonl")),
|
|
17371
|
+
checkFile("dev-state.md", join21(configDir, DEV_STATE_FILE_NAME)),
|
|
17372
|
+
checkFile("hooks-trust.json", join21(configDir, "hooks-trust.json")),
|
|
17373
|
+
checkFile("plugin-state.json", join21(configDir, "plugins", "plugin-state.json"))
|
|
17266
17374
|
],
|
|
17267
17375
|
context: {
|
|
17268
17376
|
enabled: contextSetting !== false,
|
|
@@ -17297,7 +17405,7 @@ function buildDoctorReport(options) {
|
|
|
17297
17405
|
disabled: hooks.filter((h) => h.disabled).length
|
|
17298
17406
|
},
|
|
17299
17407
|
plugins: {
|
|
17300
|
-
root:
|
|
17408
|
+
root: join21(configDir, "plugins"),
|
|
17301
17409
|
installed: plugins.length,
|
|
17302
17410
|
active: activeAssets.plugins.length,
|
|
17303
17411
|
invalid: plugins.filter((p) => !p.valid).length,
|
|
@@ -17312,7 +17420,7 @@ function buildDoctorReport(options) {
|
|
|
17312
17420
|
mcp: {
|
|
17313
17421
|
enabled: config.get("mcpEnabled"),
|
|
17314
17422
|
configured: Object.keys(mcpServers).length,
|
|
17315
|
-
projectConfigExists:
|
|
17423
|
+
projectConfigExists: existsSync27(join21(projectRoot, MCP_PROJECT_CONFIG_NAME)),
|
|
17316
17424
|
statuses: options.mcpStatuses ?? []
|
|
17317
17425
|
},
|
|
17318
17426
|
recentCrashes: listRecentCrashes(5, configDir),
|
|
@@ -17834,7 +17942,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
|
|
|
17834
17942
|
Cost: ${formatCost(cost)}` : "";
|
|
17835
17943
|
let memoryLine = "";
|
|
17836
17944
|
try {
|
|
17837
|
-
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-
|
|
17945
|
+
const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-LMVWIHMX.js");
|
|
17838
17946
|
const pending = countPendingMemories2(ctx.config.getConfigDir());
|
|
17839
17947
|
if (pending > 0) memoryLine = `
|
|
17840
17948
|
Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
|
|
@@ -18575,7 +18683,7 @@ async function handlePlugin(args, ctx) {
|
|
|
18575
18683
|
lines.push("");
|
|
18576
18684
|
}
|
|
18577
18685
|
if (pluginTools.length > 0) {
|
|
18578
|
-
const legacyDir =
|
|
18686
|
+
const legacyDir = join22(configDir, PLUGINS_DIR_NAME);
|
|
18579
18687
|
lines.push(`**Legacy JS tools** (${pluginTools.length}):`);
|
|
18580
18688
|
lines.push(`Dir: ${legacyDir}`);
|
|
18581
18689
|
for (const t of pluginTools) lines.push(` \u2022 ${t.definition.name} \u2014 ${t.definition.description}`);
|
|
@@ -18715,14 +18823,14 @@ ${note}` : head });
|
|
|
18715
18823
|
}
|
|
18716
18824
|
async function handleCommands(_args, ctx) {
|
|
18717
18825
|
const configDir = ctx.config.getConfigDir();
|
|
18718
|
-
const commandsDir =
|
|
18719
|
-
if (!
|
|
18826
|
+
const commandsDir = join22(configDir, CUSTOM_COMMANDS_DIR_NAME);
|
|
18827
|
+
if (!existsSync28(commandsDir)) {
|
|
18720
18828
|
ctx.send({ type: "info", message: `No custom commands directory.
|
|
18721
18829
|
Create: ${commandsDir}/ with .md files.` });
|
|
18722
18830
|
return;
|
|
18723
18831
|
}
|
|
18724
18832
|
try {
|
|
18725
|
-
const files =
|
|
18833
|
+
const files = readdirSync14(commandsDir).filter((f) => f.endsWith(".md"));
|
|
18726
18834
|
if (files.length === 0) {
|
|
18727
18835
|
ctx.send({ type: "info", message: `No custom commands found in ${commandsDir}
|
|
18728
18836
|
Add .md files to create commands.` });
|
|
@@ -18822,7 +18930,7 @@ async function handleTest(args, ctx) {
|
|
|
18822
18930
|
const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
|
|
18823
18931
|
testArgs = isCommand ? { command: argStr } : { filter: argStr };
|
|
18824
18932
|
}
|
|
18825
|
-
const runTests = ctx.runTests ?? (await import("./run-tests-
|
|
18933
|
+
const runTests = ctx.runTests ?? (await import("./run-tests-MQVGE6FK.js")).executeTests;
|
|
18826
18934
|
const report = await runTests(testArgs);
|
|
18827
18935
|
ctx.send({ type: "info", message: report });
|
|
18828
18936
|
} catch (err) {
|
|
@@ -18846,9 +18954,9 @@ async function handleDiff(args, ctx) {
|
|
|
18846
18954
|
let modifiedFiles = 0;
|
|
18847
18955
|
const diffLines2 = [];
|
|
18848
18956
|
for (const [filePath, { earliest }] of fileMap) {
|
|
18849
|
-
const currentContent =
|
|
18957
|
+
const currentContent = existsSync28(filePath) ? (() => {
|
|
18850
18958
|
try {
|
|
18851
|
-
return
|
|
18959
|
+
return readFileSync20(filePath, "utf-8");
|
|
18852
18960
|
} catch {
|
|
18853
18961
|
return null;
|
|
18854
18962
|
}
|
|
@@ -18883,9 +18991,9 @@ async function handleDiff(args, ctx) {
|
|
|
18883
18991
|
}
|
|
18884
18992
|
async function handleInit(args, ctx) {
|
|
18885
18993
|
const cwd = process.cwd();
|
|
18886
|
-
const targetPath =
|
|
18994
|
+
const targetPath = join22(cwd, "AICLI.md");
|
|
18887
18995
|
const force = args.includes("--force");
|
|
18888
|
-
if (
|
|
18996
|
+
if (existsSync28(targetPath) && !force) {
|
|
18889
18997
|
ctx.send({ type: "info", message: `AICLI.md already exists at ${targetPath}
|
|
18890
18998
|
Use /init --force to overwrite.` });
|
|
18891
18999
|
return;
|
|
@@ -19213,7 +19321,7 @@ async function handleMemory(args, ctx) {
|
|
|
19213
19321
|
}
|
|
19214
19322
|
if (intent.kind === "status") {
|
|
19215
19323
|
const { getChatIndexStatus: getChatIndexStatus2 } = await import("./chat-index-RLVLQRRC.js");
|
|
19216
|
-
const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-
|
|
19324
|
+
const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-LMVWIHMX.js");
|
|
19217
19325
|
const memories = listMemoryEntries2(configDir, { includeExpired: true, includeRejected: true });
|
|
19218
19326
|
const injected = formatMemoryForPrompt2(configDir, process.cwd(), ctx.config.get("memory")?.maxChars);
|
|
19219
19327
|
const view = buildMemoryStatusView({
|
|
@@ -19236,7 +19344,7 @@ async function handleMemory(args, ctx) {
|
|
|
19236
19344
|
return;
|
|
19237
19345
|
}
|
|
19238
19346
|
if (intent.kind === "recall") {
|
|
19239
|
-
const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-
|
|
19347
|
+
const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-LMVWIHMX.js");
|
|
19240
19348
|
const { searchChatMemory: searchChatMemory2 } = await import("./chat-index-RLVLQRRC.js");
|
|
19241
19349
|
const persistentHits = searchPersistentMemories2(configDir, intent.query, process.cwd(), 3);
|
|
19242
19350
|
if (persistentHits.length > 0) {
|
|
@@ -19357,7 +19465,7 @@ async function handleMemory(args, ctx) {
|
|
|
19357
19465
|
ctx.handleMemoryManage(intent.action, args[1], intent.action === "expire" ? args[2] : void 0);
|
|
19358
19466
|
} else if (intent.kind === "export") {
|
|
19359
19467
|
if (args[1] === "md") {
|
|
19360
|
-
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-
|
|
19468
|
+
const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-LMVWIHMX.js");
|
|
19361
19469
|
ctx.send({
|
|
19362
19470
|
type: "export_data",
|
|
19363
19471
|
format: "md",
|
|
@@ -19395,7 +19503,7 @@ Use /add-dir remove to clear.` : "No directories added.\nUsage: /add-dir <path>
|
|
|
19395
19503
|
return;
|
|
19396
19504
|
}
|
|
19397
19505
|
const dirPath = resolve9(sub);
|
|
19398
|
-
if (!
|
|
19506
|
+
if (!existsSync28(dirPath)) {
|
|
19399
19507
|
ctx.send({ type: "error", message: `Directory not found: ${dirPath}` });
|
|
19400
19508
|
return;
|
|
19401
19509
|
}
|
|
@@ -20360,16 +20468,16 @@ No tools match "${filter}".
|
|
|
20360
20468
|
usage: "/mcp [reconnect [serverId] | trust-project]",
|
|
20361
20469
|
async execute(args, ctx) {
|
|
20362
20470
|
if (args[0] === "trust-project") {
|
|
20363
|
-
const { join:
|
|
20364
|
-
const { existsSync:
|
|
20471
|
+
const { join: join27 } = await import("path");
|
|
20472
|
+
const { existsSync: existsSync33 } = await import("fs");
|
|
20365
20473
|
const { getGitRoot: getGitRoot2 } = await import("./git-context-VNCA2GU7.js");
|
|
20366
|
-
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-
|
|
20474
|
+
const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-JM6MK5SS.js");
|
|
20367
20475
|
const { approveProject, hashMcpFile } = await import("./project-trust-6CJB5ZMX.js");
|
|
20368
20476
|
const cwd = process.cwd();
|
|
20369
20477
|
const projectRoot = getGitRoot2(cwd) ?? cwd;
|
|
20370
|
-
const mcpPath =
|
|
20478
|
+
const mcpPath = join27(projectRoot, MCP_PROJECT_CONFIG_NAME2);
|
|
20371
20479
|
console.log();
|
|
20372
|
-
if (!
|
|
20480
|
+
if (!existsSync33(mcpPath)) {
|
|
20373
20481
|
console.log(theme.dim(` No .mcp.json in ${projectRoot}.`));
|
|
20374
20482
|
console.log();
|
|
20375
20483
|
return;
|
|
@@ -20804,12 +20912,12 @@ ${outcome.summary}
|
|
|
20804
20912
|
if (scanAll) {
|
|
20805
20913
|
const metas = ctx.sessions.listSessions();
|
|
20806
20914
|
console.log(theme.info(` Scanning ${metas.length} session(s)\u2026`));
|
|
20807
|
-
const { readFileSync:
|
|
20808
|
-
const { join:
|
|
20915
|
+
const { readFileSync: readFileSync24 } = await import("fs");
|
|
20916
|
+
const { join: join27 } = await import("path");
|
|
20809
20917
|
const historyDir = ctx.config.getHistoryDir();
|
|
20810
20918
|
for (const m of metas) {
|
|
20811
20919
|
try {
|
|
20812
|
-
const content =
|
|
20920
|
+
const content = readFileSync24(join27(historyDir, `${m.id}.json`), "utf-8");
|
|
20813
20921
|
const hits2 = scanString(content, opts);
|
|
20814
20922
|
if (hits2.length) {
|
|
20815
20923
|
filesWithHits++;
|
|
@@ -20856,8 +20964,8 @@ ${outcome.summary}
|
|
|
20856
20964
|
}
|
|
20857
20965
|
|
|
20858
20966
|
// src/repl/commands/review-commands.ts
|
|
20859
|
-
import { existsSync as
|
|
20860
|
-
import { join as
|
|
20967
|
+
import { existsSync as existsSync29, readFileSync as readFileSync21, writeFileSync as writeFileSync4 } from "fs";
|
|
20968
|
+
import { join as join23 } from "path";
|
|
20861
20969
|
function createReviewCommands() {
|
|
20862
20970
|
return [
|
|
20863
20971
|
{
|
|
@@ -21216,9 +21324,9 @@ function createReviewCommands() {
|
|
|
21216
21324
|
usage: "/init [--force]",
|
|
21217
21325
|
async execute(args, ctx) {
|
|
21218
21326
|
const cwd = process.cwd();
|
|
21219
|
-
const targetPath =
|
|
21327
|
+
const targetPath = join23(cwd, "AICLI.md");
|
|
21220
21328
|
const force = args.includes("--force");
|
|
21221
|
-
if (
|
|
21329
|
+
if (existsSync29(targetPath) && !force) {
|
|
21222
21330
|
ctx.renderer.printInfo(`AICLI.md already exists at ${targetPath}`);
|
|
21223
21331
|
ctx.renderer.printInfo("Use /init --force to overwrite, or edit it manually.");
|
|
21224
21332
|
return;
|
|
@@ -21282,7 +21390,7 @@ function createReviewCommands() {
|
|
|
21282
21390
|
usage: "/test [command|filter]",
|
|
21283
21391
|
async execute(args, ctx) {
|
|
21284
21392
|
try {
|
|
21285
|
-
const { executeTests } = await import("./run-tests-
|
|
21393
|
+
const { executeTests } = await import("./run-tests-MQVGE6FK.js");
|
|
21286
21394
|
const argStr = args.join(" ").trim();
|
|
21287
21395
|
let testArgs = {};
|
|
21288
21396
|
if (argStr) {
|
|
@@ -21317,9 +21425,9 @@ function createReviewCommands() {
|
|
|
21317
21425
|
let newFiles = 0;
|
|
21318
21426
|
let modifiedFiles = 0;
|
|
21319
21427
|
for (const [filePath, { earliest }] of fileMap) {
|
|
21320
|
-
const currentContent =
|
|
21428
|
+
const currentContent = existsSync29(filePath) ? (() => {
|
|
21321
21429
|
try {
|
|
21322
|
-
return
|
|
21430
|
+
return readFileSync21(filePath, "utf-8");
|
|
21323
21431
|
} catch {
|
|
21324
21432
|
return null;
|
|
21325
21433
|
}
|
|
@@ -22481,17 +22589,17 @@ function createSessionCommands() {
|
|
|
22481
22589
|
}
|
|
22482
22590
|
|
|
22483
22591
|
// src/repl/commands/misc-commands.ts
|
|
22484
|
-
import { basename as
|
|
22592
|
+
import { basename as basename11 } from "path";
|
|
22485
22593
|
import { platform as platform8 } from "os";
|
|
22486
22594
|
|
|
22487
22595
|
// src/repl/clipboard.ts
|
|
22488
22596
|
import { execSync as execSync3 } from "child_process";
|
|
22489
|
-
import { existsSync as
|
|
22597
|
+
import { existsSync as existsSync30, statSync as statSync15, unlinkSync as unlinkSync7 } from "fs";
|
|
22490
22598
|
import { tmpdir as tmpdir3 } from "os";
|
|
22491
|
-
import { join as
|
|
22599
|
+
import { join as join24 } from "path";
|
|
22492
22600
|
var CLIPBOARD_TIMEOUT = 5e3;
|
|
22493
22601
|
function readClipboardImage() {
|
|
22494
|
-
const outPath =
|
|
22602
|
+
const outPath = join24(tmpdir3(), `aicli-paste-${Date.now()}.png`);
|
|
22495
22603
|
try {
|
|
22496
22604
|
if (process.platform === "win32") {
|
|
22497
22605
|
_readWin32(outPath);
|
|
@@ -22504,7 +22612,7 @@ function readClipboardImage() {
|
|
|
22504
22612
|
_cleanup(outPath);
|
|
22505
22613
|
return null;
|
|
22506
22614
|
}
|
|
22507
|
-
if (!
|
|
22615
|
+
if (!existsSync30(outPath) || statSync15(outPath).size === 0) {
|
|
22508
22616
|
_cleanup(outPath);
|
|
22509
22617
|
return null;
|
|
22510
22618
|
}
|
|
@@ -22557,7 +22665,7 @@ function _readLinux(outPath) {
|
|
|
22557
22665
|
}
|
|
22558
22666
|
function _cleanup(path3) {
|
|
22559
22667
|
try {
|
|
22560
|
-
if (
|
|
22668
|
+
if (existsSync30(path3)) unlinkSync7(path3);
|
|
22561
22669
|
} catch {
|
|
22562
22670
|
}
|
|
22563
22671
|
}
|
|
@@ -22827,7 +22935,7 @@ ${hint}` : "")
|
|
|
22827
22935
|
return;
|
|
22828
22936
|
}
|
|
22829
22937
|
const description = args.join(" ").trim() || "Please describe this image";
|
|
22830
|
-
ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${
|
|
22938
|
+
ctx.renderer.printSuccess(`\u{1F4CB} Image loaded: ${basename11(imgPath)}`);
|
|
22831
22939
|
await ctx.sendAsChat(`@${imgPath} ${description}`);
|
|
22832
22940
|
}
|
|
22833
22941
|
},
|
|
@@ -23383,6 +23491,11 @@ var SessionHandler = class _SessionHandler {
|
|
|
23383
23491
|
costCnyPerUsd: CNY_PER_USD,
|
|
23384
23492
|
costPricingUnknown,
|
|
23385
23493
|
providers: providerList,
|
|
23494
|
+
hubPresets: loadCustomPresets(this.config.getConfigDir()).presets.map((p) => ({
|
|
23495
|
+
id: p.id,
|
|
23496
|
+
name: p.name,
|
|
23497
|
+
description: p.description
|
|
23498
|
+
})),
|
|
23386
23499
|
branches,
|
|
23387
23500
|
activeBranchId: sess?.activeBranchId ?? "main",
|
|
23388
23501
|
agents: listAgentRuns().slice(0, 20).map((run) => ({
|
|
@@ -23636,7 +23749,8 @@ var SessionHandler = class _SessionHandler {
|
|
|
23636
23749
|
this.send({ type: "error", message: "Hub topic is required." });
|
|
23637
23750
|
return;
|
|
23638
23751
|
}
|
|
23639
|
-
const
|
|
23752
|
+
const presetId = msg.preset ?? "brainstorm";
|
|
23753
|
+
const preset = presetId.startsWith(CUSTOM_PRESET_PREFIX) ? loadCustomPresets(this.config.getConfigDir()).presets.find((p) => p.id === presetId) : getPreset(presetId);
|
|
23640
23754
|
if (!preset) {
|
|
23641
23755
|
this.send({ type: "error", message: `Unknown preset "${msg.preset}".` });
|
|
23642
23756
|
return;
|
|
@@ -24839,8 +24953,8 @@ async function setupProxy(configProxy) {
|
|
|
24839
24953
|
}
|
|
24840
24954
|
|
|
24841
24955
|
// src/web/auth.ts
|
|
24842
|
-
import { existsSync as
|
|
24843
|
-
import { isAbsolute as isAbsolute3, join as
|
|
24956
|
+
import { existsSync as existsSync31, readFileSync as readFileSync22, mkdirSync as mkdirSync16, readdirSync as readdirSync15, openSync, closeSync, unlinkSync as unlinkSync8 } from "fs";
|
|
24957
|
+
import { isAbsolute as isAbsolute3, join as join25, relative as relative5 } from "path";
|
|
24844
24958
|
import { createHmac, randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2, pbkdf2Sync, pbkdf2 } from "crypto";
|
|
24845
24959
|
var USERS_FILE = "users.json";
|
|
24846
24960
|
var TOKEN_EXPIRY_HOURS = 24;
|
|
@@ -24856,7 +24970,7 @@ var AuthManager = class {
|
|
|
24856
24970
|
loadedRaw;
|
|
24857
24971
|
constructor(baseDir) {
|
|
24858
24972
|
this.baseDir = baseDir;
|
|
24859
|
-
this.usersFile =
|
|
24973
|
+
this.usersFile = join25(baseDir, USERS_FILE);
|
|
24860
24974
|
this.db = this.loadOrCreate();
|
|
24861
24975
|
}
|
|
24862
24976
|
// ── Public API ─────────────────────────────────────────────────
|
|
@@ -24898,10 +25012,10 @@ var AuthManager = class {
|
|
|
24898
25012
|
}
|
|
24899
25013
|
const salt = prepared?.salt ?? randomBytes2(16).toString("hex");
|
|
24900
25014
|
const passwordHash = prepared?.hash ?? this.hashPassword(password, salt);
|
|
24901
|
-
const dataDir =
|
|
24902
|
-
const fullDataDir =
|
|
25015
|
+
const dataDir = join25(USERS_DIR, username);
|
|
25016
|
+
const fullDataDir = join25(this.baseDir, dataDir);
|
|
24903
25017
|
mkdirSync16(fullDataDir, { recursive: true, mode: 448 });
|
|
24904
|
-
mkdirSync16(
|
|
25018
|
+
mkdirSync16(join25(fullDataDir, "history"), { recursive: true, mode: 448 });
|
|
24905
25019
|
const user = {
|
|
24906
25020
|
username,
|
|
24907
25021
|
passwordHash,
|
|
@@ -25061,7 +25175,7 @@ var AuthManager = class {
|
|
|
25061
25175
|
this.refresh();
|
|
25062
25176
|
const user = this.db.users.find((u) => u.username === username);
|
|
25063
25177
|
if (!user) throw new Error(`User not found: ${username}`);
|
|
25064
|
-
return
|
|
25178
|
+
return join25(this.baseDir, user.dataDir);
|
|
25065
25179
|
}
|
|
25066
25180
|
/** List all usernames */
|
|
25067
25181
|
listUsers() {
|
|
@@ -25100,30 +25214,30 @@ var AuthManager = class {
|
|
|
25100
25214
|
const err = this.register(username, password);
|
|
25101
25215
|
if (err) return err;
|
|
25102
25216
|
const userDir = this.getUserDataDir(username);
|
|
25103
|
-
const globalConfig =
|
|
25104
|
-
if (
|
|
25217
|
+
const globalConfig = join25(this.baseDir, "config.json");
|
|
25218
|
+
if (existsSync31(globalConfig)) {
|
|
25105
25219
|
try {
|
|
25106
|
-
const content =
|
|
25107
|
-
atomicWriteFileSync(
|
|
25220
|
+
const content = readFileSync22(globalConfig, "utf-8");
|
|
25221
|
+
atomicWriteFileSync(join25(userDir, "config.json"), content, { mode: 384 });
|
|
25108
25222
|
} catch {
|
|
25109
25223
|
}
|
|
25110
25224
|
}
|
|
25111
|
-
const globalMemory =
|
|
25112
|
-
if (
|
|
25225
|
+
const globalMemory = join25(this.baseDir, "memory.md");
|
|
25226
|
+
if (existsSync31(globalMemory)) {
|
|
25113
25227
|
try {
|
|
25114
|
-
const content =
|
|
25115
|
-
atomicWriteFileSync(
|
|
25228
|
+
const content = readFileSync22(globalMemory, "utf-8");
|
|
25229
|
+
atomicWriteFileSync(join25(userDir, "memory.md"), content, { mode: 384 });
|
|
25116
25230
|
} catch {
|
|
25117
25231
|
}
|
|
25118
25232
|
}
|
|
25119
|
-
const globalHistory =
|
|
25120
|
-
if (
|
|
25233
|
+
const globalHistory = join25(this.baseDir, "history");
|
|
25234
|
+
if (existsSync31(globalHistory)) {
|
|
25121
25235
|
try {
|
|
25122
|
-
const files =
|
|
25123
|
-
const userHistory =
|
|
25236
|
+
const files = readdirSync15(globalHistory).filter((f) => f.endsWith(".json"));
|
|
25237
|
+
const userHistory = join25(userDir, "history");
|
|
25124
25238
|
for (const f of files) {
|
|
25125
25239
|
try {
|
|
25126
|
-
atomicWriteFileSync(
|
|
25240
|
+
atomicWriteFileSync(join25(userHistory, f), readFileSync22(join25(globalHistory, f), "utf8"), { mode: 384 });
|
|
25127
25241
|
} catch {
|
|
25128
25242
|
}
|
|
25129
25243
|
}
|
|
@@ -25134,16 +25248,16 @@ var AuthManager = class {
|
|
|
25134
25248
|
}
|
|
25135
25249
|
// ── Private methods ────────────────────────────────────────────
|
|
25136
25250
|
refresh() {
|
|
25137
|
-
const raw =
|
|
25251
|
+
const raw = readFileSync22(this.usersFile, "utf8");
|
|
25138
25252
|
const parsed = JSON.parse(raw);
|
|
25139
25253
|
if (!this.isValidUsersDB(parsed)) throw new Error("Authentication database is invalid; access refused");
|
|
25140
25254
|
this.db = parsed;
|
|
25141
25255
|
this.loadedRaw = raw;
|
|
25142
25256
|
}
|
|
25143
25257
|
loadOrCreate() {
|
|
25144
|
-
if (
|
|
25258
|
+
if (existsSync31(this.usersFile)) {
|
|
25145
25259
|
try {
|
|
25146
|
-
const raw =
|
|
25260
|
+
const raw = readFileSync22(this.usersFile, "utf-8");
|
|
25147
25261
|
const parsed = JSON.parse(raw);
|
|
25148
25262
|
if (!this.isValidUsersDB(parsed)) {
|
|
25149
25263
|
throw new Error("database structure is invalid");
|
|
@@ -25179,7 +25293,7 @@ var AuthManager = class {
|
|
|
25179
25293
|
if (typeof record.username !== "string" || !/^[a-z0-9_-]{2,32}$/.test(record.username) || usernames.has(record.username) || typeof record.passwordHash !== "string" || record.passwordHash.length === 0 || typeof record.salt !== "string" || record.salt.length === 0 || typeof record.createdAt !== "string" || typeof record.dataDir !== "string" || record.dataDir.length === 0 || isAbsolute3(record.dataDir)) {
|
|
25180
25294
|
return false;
|
|
25181
25295
|
}
|
|
25182
|
-
const dataDirFromBase = relative5(this.baseDir,
|
|
25296
|
+
const dataDirFromBase = relative5(this.baseDir, join25(this.baseDir, record.dataDir));
|
|
25183
25297
|
if (dataDirFromBase.startsWith("..") || isAbsolute3(dataDirFromBase)) return false;
|
|
25184
25298
|
if (record.hashVersion !== void 0 && record.hashVersion !== 1 && record.hashVersion !== 2) return false;
|
|
25185
25299
|
if (record.tokensRevokedBefore !== void 0 && !Number.isFinite(record.tokensRevokedBefore)) return false;
|
|
@@ -25195,7 +25309,7 @@ var AuthManager = class {
|
|
|
25195
25309
|
const lock = this.usersFile + ".lock";
|
|
25196
25310
|
const fd = openSync(lock, "wx", 384);
|
|
25197
25311
|
try {
|
|
25198
|
-
const current =
|
|
25312
|
+
const current = existsSync31(this.usersFile) ? readFileSync22(this.usersFile, "utf8") : void 0;
|
|
25199
25313
|
if (current !== this.loadedRaw) throw new Error("Authentication database changed concurrently; retry the operation");
|
|
25200
25314
|
const raw = JSON.stringify(db, null, 2);
|
|
25201
25315
|
atomicWriteFileSync(this.usersFile, raw, { mode: 384 });
|
|
@@ -25329,8 +25443,8 @@ async function startWebServer(options = {}) {
|
|
|
25329
25443
|
}
|
|
25330
25444
|
}
|
|
25331
25445
|
let skillManager = null;
|
|
25332
|
-
const skillsDir =
|
|
25333
|
-
if (
|
|
25446
|
+
const skillsDir = join26(config.getConfigDir(), SKILLS_DIR_NAME);
|
|
25447
|
+
if (existsSync32(skillsDir)) {
|
|
25334
25448
|
skillManager = new SkillManager(skillsDir, config.get("ui").skillSizeWarn);
|
|
25335
25449
|
skillManager.loadSkills(pluginAssets.skillDirs);
|
|
25336
25450
|
const count = skillManager.listSkills().length;
|
|
@@ -25423,15 +25537,15 @@ async function startWebServer(options = {}) {
|
|
|
25423
25537
|
next();
|
|
25424
25538
|
};
|
|
25425
25539
|
const moduleDir = getModuleDir();
|
|
25426
|
-
let clientDir =
|
|
25427
|
-
if (!
|
|
25428
|
-
clientDir =
|
|
25540
|
+
let clientDir = join26(moduleDir, "web", "client");
|
|
25541
|
+
if (!existsSync32(clientDir)) {
|
|
25542
|
+
clientDir = join26(moduleDir, "client");
|
|
25429
25543
|
}
|
|
25430
|
-
if (!
|
|
25431
|
-
clientDir =
|
|
25544
|
+
if (!existsSync32(clientDir)) {
|
|
25545
|
+
clientDir = join26(moduleDir, "..", "..", "src", "web", "client");
|
|
25432
25546
|
}
|
|
25433
|
-
if (!
|
|
25434
|
-
clientDir =
|
|
25547
|
+
if (!existsSync32(clientDir)) {
|
|
25548
|
+
clientDir = join26(process.cwd(), "src", "web", "client");
|
|
25435
25549
|
}
|
|
25436
25550
|
console.log(` Static files: ${clientDir}`);
|
|
25437
25551
|
const PRECOMPRESSED_TYPES = {
|
|
@@ -25451,14 +25565,14 @@ async function startWebServer(options = {}) {
|
|
|
25451
25565
|
const encoding = /\bbr\b/.test(accept) ? "br" : /\bgzip\b/.test(accept) ? "gzip" : null;
|
|
25452
25566
|
if (!encoding) return next();
|
|
25453
25567
|
const target = resolvePath(clientDir, `.${req.path}`) + (encoding === "br" ? ".br" : ".gz");
|
|
25454
|
-
if (!target.startsWith(clientDir) || !
|
|
25568
|
+
if (!target.startsWith(clientDir) || !existsSync32(target)) return next();
|
|
25455
25569
|
res.setHeader("Content-Type", contentType);
|
|
25456
25570
|
res.setHeader("Content-Encoding", encoding);
|
|
25457
25571
|
res.setHeader("Vary", "Accept-Encoding");
|
|
25458
25572
|
if (req.path.startsWith("/vendor/")) res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
|
25459
25573
|
createReadStream(target).pipe(res);
|
|
25460
25574
|
});
|
|
25461
|
-
app.use("/vendor", express.static(
|
|
25575
|
+
app.use("/vendor", express.static(join26(clientDir, "vendor"), { maxAge: "1y", immutable: true }));
|
|
25462
25576
|
app.use(express.static(clientDir));
|
|
25463
25577
|
app.get("/api/status", (_req, res) => {
|
|
25464
25578
|
res.json({
|
|
@@ -25549,7 +25663,7 @@ async function startWebServer(options = {}) {
|
|
|
25549
25663
|
app.get("/api/files", requireAuth, (req, res) => {
|
|
25550
25664
|
const cwd = process.cwd();
|
|
25551
25665
|
const prefix = req.query.prefix || "";
|
|
25552
|
-
const targetDir =
|
|
25666
|
+
const targetDir = join26(cwd, prefix);
|
|
25553
25667
|
try {
|
|
25554
25668
|
const canonicalTarget = realpathSync3(resolve12(targetDir));
|
|
25555
25669
|
const canonicalCwd = realpathSync3(resolve12(cwd));
|
|
@@ -25563,10 +25677,10 @@ async function startWebServer(options = {}) {
|
|
|
25563
25677
|
}
|
|
25564
25678
|
try {
|
|
25565
25679
|
const SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "dist-cjs", "release", "__pycache__", ".next", ".nuxt", "coverage", ".cache"]);
|
|
25566
|
-
const entries =
|
|
25680
|
+
const entries = readdirSync16(targetDir, { withFileTypes: true });
|
|
25567
25681
|
const files = entries.filter((e) => !SKIP.has(e.name) && !e.name.startsWith(".")).slice(0, 50).map((e) => ({
|
|
25568
25682
|
name: e.name,
|
|
25569
|
-
path: relative6(cwd,
|
|
25683
|
+
path: relative6(cwd, join26(targetDir, e.name)).replace(/\\/g, "/"),
|
|
25570
25684
|
isDir: e.isDirectory()
|
|
25571
25685
|
}));
|
|
25572
25686
|
res.json({ files });
|
|
@@ -25606,8 +25720,8 @@ async function startWebServer(options = {}) {
|
|
|
25606
25720
|
try {
|
|
25607
25721
|
const authUser = req._authUser;
|
|
25608
25722
|
const histDir = authUser ? getUserShared(authUser).config.getHistoryDir() : config.getHistoryDir();
|
|
25609
|
-
const filePath =
|
|
25610
|
-
if (!
|
|
25723
|
+
const filePath = join26(histDir, `${id}.json`);
|
|
25724
|
+
if (!existsSync32(filePath)) {
|
|
25611
25725
|
res.status(404).json({ error: "Session not found" });
|
|
25612
25726
|
return;
|
|
25613
25727
|
}
|
|
@@ -25622,7 +25736,7 @@ async function startWebServer(options = {}) {
|
|
|
25622
25736
|
res.status(404).json({ error: "Session not found" });
|
|
25623
25737
|
return;
|
|
25624
25738
|
}
|
|
25625
|
-
const data = JSON.parse(
|
|
25739
|
+
const data = JSON.parse(readFileSync23(filePath, "utf-8"));
|
|
25626
25740
|
res.json({ session: data });
|
|
25627
25741
|
} catch (err) {
|
|
25628
25742
|
res.status(500).json({ error: err instanceof Error ? err.message : String(err) });
|
|
@@ -25635,7 +25749,7 @@ async function startWebServer(options = {}) {
|
|
|
25635
25749
|
return;
|
|
25636
25750
|
}
|
|
25637
25751
|
const cwd = process.cwd();
|
|
25638
|
-
const fullPath = resolve12(
|
|
25752
|
+
const fullPath = resolve12(join26(cwd, filePath));
|
|
25639
25753
|
try {
|
|
25640
25754
|
const canonicalFull = realpathSync3(fullPath);
|
|
25641
25755
|
assertReadablePath(canonicalFull);
|
|
@@ -25654,7 +25768,7 @@ async function startWebServer(options = {}) {
|
|
|
25654
25768
|
res.json({ error: `File too large (${(stat.size / 1024).toFixed(0)} KB, max 512 KB)` });
|
|
25655
25769
|
return;
|
|
25656
25770
|
}
|
|
25657
|
-
const content =
|
|
25771
|
+
const content = readFileSync23(fullPath, "utf-8");
|
|
25658
25772
|
res.json({ content, size: stat.size });
|
|
25659
25773
|
} catch {
|
|
25660
25774
|
res.json({ error: "Cannot read file" });
|
|
@@ -25991,17 +26105,17 @@ function resolveProjectMcpPath() {
|
|
|
25991
26105
|
const cwd = process.cwd();
|
|
25992
26106
|
const gitRoot = getGitRoot(cwd);
|
|
25993
26107
|
const projectRoot = gitRoot ?? cwd;
|
|
25994
|
-
const configPath =
|
|
25995
|
-
return
|
|
26108
|
+
const configPath = join26(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
26109
|
+
return existsSync32(configPath) ? configPath : null;
|
|
25996
26110
|
}
|
|
25997
26111
|
function loadProjectMcpConfig() {
|
|
25998
26112
|
const cwd = process.cwd();
|
|
25999
26113
|
const gitRoot = getGitRoot(cwd);
|
|
26000
26114
|
const projectRoot = gitRoot ?? cwd;
|
|
26001
|
-
const configPath =
|
|
26002
|
-
if (!
|
|
26115
|
+
const configPath = join26(projectRoot, MCP_PROJECT_CONFIG_NAME);
|
|
26116
|
+
if (!existsSync32(configPath)) return null;
|
|
26003
26117
|
try {
|
|
26004
|
-
const raw = JSON.parse(
|
|
26118
|
+
const raw = JSON.parse(readFileSync23(configPath, "utf-8"));
|
|
26005
26119
|
return raw.mcpServers ?? raw;
|
|
26006
26120
|
} catch {
|
|
26007
26121
|
return null;
|