dskcode 0.1.39 → 0.1.41
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/dist/index.js +1621 -244
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -805,9 +805,9 @@ var LOGO_LINES = [
|
|
|
805
805
|
];
|
|
806
806
|
|
|
807
807
|
// src/ui/ChatSession.tsx
|
|
808
|
-
import { Box as
|
|
808
|
+
import { Box as Box12, Text as Text13, useInput, Static } from "ink";
|
|
809
809
|
import TextInput from "ink-text-input";
|
|
810
|
-
import { useEffect as useEffect5, useState as useState5, useCallback as useCallback2, useMemo, useRef as useRef4 } from "react";
|
|
810
|
+
import { useEffect as useEffect5, useState as useState5, useCallback as useCallback2, useMemo as useMemo2, useRef as useRef4 } from "react";
|
|
811
811
|
|
|
812
812
|
// src/ui/useDoubleCtrlC.ts
|
|
813
813
|
import { useState as useState2, useCallback, useEffect as useEffect2, useRef } from "react";
|
|
@@ -838,7 +838,7 @@ function useDoubleCtrlC(onExit) {
|
|
|
838
838
|
}
|
|
839
839
|
|
|
840
840
|
// src/ui/ChatSession.tsx
|
|
841
|
-
import
|
|
841
|
+
import InkSpinner4 from "ink-spinner";
|
|
842
842
|
|
|
843
843
|
// src/ui/AssistantMessage.tsx
|
|
844
844
|
import { Box as Box5, Text as Text6 } from "ink";
|
|
@@ -1160,23 +1160,207 @@ function formatMoney(yuan) {
|
|
|
1160
1160
|
|
|
1161
1161
|
// src/ui/ToolCallBlock.tsx
|
|
1162
1162
|
import { Box as Box3, Text as Text4 } from "ink";
|
|
1163
|
-
|
|
1164
|
-
|
|
1163
|
+
|
|
1164
|
+
// src/agent/tool-call-summary.ts
|
|
1165
|
+
var SENSITIVE_KEYS = /* @__PURE__ */ new Set([
|
|
1166
|
+
"password",
|
|
1167
|
+
"token",
|
|
1168
|
+
"apikey",
|
|
1169
|
+
"api_key",
|
|
1170
|
+
"secret",
|
|
1171
|
+
"authorization",
|
|
1172
|
+
"auth",
|
|
1173
|
+
"credential",
|
|
1174
|
+
"credentials",
|
|
1175
|
+
"private_key",
|
|
1176
|
+
"privatekey"
|
|
1177
|
+
]);
|
|
1178
|
+
function templateToolCall(toolName, args) {
|
|
1179
|
+
if (!isPlainObject(args)) {
|
|
1180
|
+
return `${toolName}()`;
|
|
1181
|
+
}
|
|
1182
|
+
switch (toolName) {
|
|
1183
|
+
case "read_file":
|
|
1184
|
+
return `${toolName}(path=${shortStr(args.path)})`;
|
|
1185
|
+
case "write_file":
|
|
1186
|
+
return `${toolName}(path=${shortStr(args.path)})`;
|
|
1187
|
+
case "edit_file":
|
|
1188
|
+
return `${toolName}(path=${shortStr(args.path)}, old_text=${shortStr(args.old_text, 30)})`;
|
|
1189
|
+
case "multi_edit": {
|
|
1190
|
+
const edits = Array.isArray(args.edits) ? args.edits.length : 0;
|
|
1191
|
+
return `${toolName}(path=${shortStr(args.path)}, edits=${edits})`;
|
|
1192
|
+
}
|
|
1193
|
+
case "delete_range": {
|
|
1194
|
+
return `${toolName}(path=${shortStr(args.path)})`;
|
|
1195
|
+
}
|
|
1196
|
+
case "bash":
|
|
1197
|
+
return `${toolName}(command=${shortStr(args.command, 60)})`;
|
|
1198
|
+
case "ls":
|
|
1199
|
+
return `${toolName}(path=${shortStr(args.path ?? ".")})`;
|
|
1200
|
+
case "glob":
|
|
1201
|
+
return `${toolName}(pattern=${shortStr(args.pattern)})`;
|
|
1202
|
+
case "grep":
|
|
1203
|
+
return `${toolName}(pattern=${shortStr(args.pattern)}, path=${shortStr(args.path ?? ".")})`;
|
|
1204
|
+
case "fetch":
|
|
1205
|
+
return `${toolName}(url=${shortStr(args.url, 60)})`;
|
|
1206
|
+
default:
|
|
1207
|
+
const keys = Object.keys(args);
|
|
1208
|
+
if (keys.length === 0) return `${toolName}()`;
|
|
1209
|
+
const preview = keys.slice(0, 4).map((k) => `${k}=\u2026`).join(", ");
|
|
1210
|
+
const more = keys.length > 4 ? `, +${keys.length - 4}` : "";
|
|
1211
|
+
return `${toolName}(${preview}${more})`;
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
function maskSensitive(args) {
|
|
1215
|
+
return maskRecursive(args, /* @__PURE__ */ new WeakSet());
|
|
1216
|
+
}
|
|
1217
|
+
function maskRecursive(value, seen) {
|
|
1218
|
+
if (value === null || value === void 0) return value;
|
|
1219
|
+
if (typeof value !== "object") return value;
|
|
1220
|
+
const obj = value;
|
|
1221
|
+
if (seen.has(obj)) return "****";
|
|
1222
|
+
seen.add(obj);
|
|
1223
|
+
if (Array.isArray(value)) {
|
|
1224
|
+
return value.map((v) => maskRecursive(v, seen));
|
|
1225
|
+
}
|
|
1226
|
+
const out = {};
|
|
1227
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
1228
|
+
if (SENSITIVE_KEYS.has(k.toLowerCase())) {
|
|
1229
|
+
out[k] = "****";
|
|
1230
|
+
} else {
|
|
1231
|
+
out[k] = maskRecursive(v, seen);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
return out;
|
|
1235
|
+
}
|
|
1236
|
+
function formatArgsForDisplay(args, opts = {}) {
|
|
1237
|
+
const valueMaxLen = opts.valueMaxLen ?? 80;
|
|
1238
|
+
const doMask = opts.maskSensitive !== false;
|
|
1239
|
+
const maxKeys = opts.maxKeys ?? 6;
|
|
1240
|
+
if (!isPlainObject(args)) {
|
|
1241
|
+
const s = formatValue(args, valueMaxLen);
|
|
1242
|
+
return s;
|
|
1243
|
+
}
|
|
1244
|
+
const masked = doMask ? maskSensitive(args) : args;
|
|
1245
|
+
const entries = Object.entries(masked);
|
|
1246
|
+
const shown = entries.slice(0, maxKeys);
|
|
1247
|
+
const lines = shown.map(([k, v]) => `${k}: ${formatValue(v, valueMaxLen)}`);
|
|
1248
|
+
if (entries.length > maxKeys) {
|
|
1249
|
+
lines.push(`+${entries.length - maxKeys} more`);
|
|
1250
|
+
}
|
|
1251
|
+
return lines.join("\n");
|
|
1252
|
+
}
|
|
1253
|
+
function formatValue(v, maxLen = 80) {
|
|
1254
|
+
if (v === null) return "null";
|
|
1255
|
+
if (v === void 0) return "undefined";
|
|
1256
|
+
if (typeof v === "string") {
|
|
1257
|
+
return v.length > maxLen ? v.slice(0, maxLen - 1) + "\u2026" : v;
|
|
1258
|
+
}
|
|
1259
|
+
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
|
1260
|
+
if (Array.isArray(v)) {
|
|
1261
|
+
if (v.length <= 3) return JSON.stringify(v);
|
|
1262
|
+
return `[\u2026${v.length} items\u2026]`;
|
|
1263
|
+
}
|
|
1264
|
+
if (typeof v === "object") {
|
|
1265
|
+
const obj = v;
|
|
1266
|
+
const keys = Object.keys(obj);
|
|
1267
|
+
if (keys.length <= 3) return JSON.stringify(obj);
|
|
1268
|
+
return `{\u2026${keys.length} keys\u2026}`;
|
|
1269
|
+
}
|
|
1270
|
+
return JSON.stringify(v);
|
|
1271
|
+
}
|
|
1272
|
+
function shortStr(v, maxLen = 40) {
|
|
1273
|
+
if (v === void 0 || v === null) return String(v);
|
|
1274
|
+
if (typeof v !== "string") return formatValue(v, maxLen);
|
|
1275
|
+
if (v.length === 0) return "(\u7A7A)";
|
|
1276
|
+
if (v.length > maxLen) return v.slice(0, maxLen - 1) + "\u2026";
|
|
1277
|
+
return v;
|
|
1278
|
+
}
|
|
1279
|
+
function isPlainObject(v) {
|
|
1280
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// src/agent/tool-call-parser.ts
|
|
1284
|
+
function parseToolCallArgs(raw) {
|
|
1285
|
+
if (raw === "" || raw === void 0 || raw === null) {
|
|
1286
|
+
return { ok: true, args: {}, fixed: "" };
|
|
1287
|
+
}
|
|
1165
1288
|
try {
|
|
1166
|
-
const
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1289
|
+
const args = JSON.parse(raw);
|
|
1290
|
+
return { ok: true, args, fixed: raw };
|
|
1291
|
+
} catch (firstErr) {
|
|
1292
|
+
const fixed = fixStreamedJson(raw);
|
|
1293
|
+
try {
|
|
1294
|
+
const args = JSON.parse(fixed);
|
|
1295
|
+
return { ok: true, args, fixed };
|
|
1296
|
+
} catch (secondErr) {
|
|
1297
|
+
const firstMsg = firstErr instanceof Error ? firstErr.message : String(firstErr);
|
|
1298
|
+
if (isLikelyPartialJson(firstMsg, raw)) {
|
|
1299
|
+
return {
|
|
1300
|
+
ok: false,
|
|
1301
|
+
reason: "PARTIAL",
|
|
1302
|
+
partial: raw,
|
|
1303
|
+
hint: "\u53C2\u6570 JSON \u5C1A\u672A\u6536\u5168\uFF0C\u6D41\u5F0F\u62FC\u63A5\u4E2D\uFF1B\u53EF\u80FD\u662F\u7F51\u7EDC/\u5FC3\u8DF3\u5BFC\u81F4\u534A\u622A"
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
return {
|
|
1307
|
+
ok: false,
|
|
1308
|
+
reason: "INVALID_JSON",
|
|
1309
|
+
raw,
|
|
1310
|
+
error: firstMsg
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
function fixStreamedJson(partial) {
|
|
1316
|
+
let end = partial.length;
|
|
1317
|
+
let backslashes = 0;
|
|
1318
|
+
for (let i = partial.length - 1; i >= 0; i--) {
|
|
1319
|
+
if (partial[i] === "\\") backslashes++;
|
|
1320
|
+
else break;
|
|
1321
|
+
}
|
|
1322
|
+
if (backslashes % 2 === 1) end--;
|
|
1323
|
+
let json = partial.slice(0, end);
|
|
1324
|
+
const stack = [];
|
|
1325
|
+
let inString = false;
|
|
1326
|
+
let escaped = false;
|
|
1327
|
+
for (let i = 0; i < json.length; i++) {
|
|
1328
|
+
const ch = json[i];
|
|
1329
|
+
if (escaped) {
|
|
1330
|
+
escaped = false;
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
if (ch === "\\") {
|
|
1334
|
+
escaped = true;
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1337
|
+
if (ch === '"') {
|
|
1338
|
+
inString = !inString;
|
|
1339
|
+
continue;
|
|
1340
|
+
}
|
|
1341
|
+
if (inString) continue;
|
|
1342
|
+
if (ch === "{") stack.push("}");
|
|
1343
|
+
else if (ch === "[") stack.push("]");
|
|
1344
|
+
else if (ch === "}" || ch === "]") stack.pop();
|
|
1176
1345
|
}
|
|
1346
|
+
if (inString) json += '"';
|
|
1347
|
+
while (stack.length > 0) json += stack.pop();
|
|
1348
|
+
return json;
|
|
1177
1349
|
}
|
|
1178
|
-
function
|
|
1179
|
-
|
|
1350
|
+
function isLikelyPartialJson(errMsg, raw) {
|
|
1351
|
+
if (errMsg.includes("Unexpected end of JSON")) return true;
|
|
1352
|
+
if (errMsg.includes("Unterminated string")) return true;
|
|
1353
|
+
if (raw.length < 5) return true;
|
|
1354
|
+
return false;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
// src/ui/ToolCallBlock.tsx
|
|
1358
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1359
|
+
function ToolCallBlock({ call, parsedArgs, schemaIssues }) {
|
|
1360
|
+
const resolvedArgs = parsedArgs ?? resolveArgsFromRaw(call.arguments);
|
|
1361
|
+
const safeArgs = maskSensitive(resolvedArgs);
|
|
1362
|
+
const summary = templateToolCall(call.name, safeArgs);
|
|
1363
|
+
const argsDisplay = formatArgsForDisplay(safeArgs);
|
|
1180
1364
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 3, marginTop: 1, children: [
|
|
1181
1365
|
/* @__PURE__ */ jsxs3(Box3, { children: [
|
|
1182
1366
|
/* @__PURE__ */ jsxs3(Text4, { dimColor: true, children: [
|
|
@@ -1188,9 +1372,34 @@ function ToolCallBlock({ call }) {
|
|
|
1188
1372
|
"\u2500".repeat(Math.max(1, 30 - call.name.length))
|
|
1189
1373
|
] })
|
|
1190
1374
|
] }),
|
|
1191
|
-
/* @__PURE__ */
|
|
1375
|
+
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 2, children: [
|
|
1376
|
+
/* @__PURE__ */ jsx3(Text4, { dimColor: true, children: summary }),
|
|
1377
|
+
/* @__PURE__ */ jsx3(Text4, { dimColor: true, children: argsDisplay })
|
|
1378
|
+
] }),
|
|
1379
|
+
schemaIssues && schemaIssues.length > 0 && /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginLeft: 2, children: [
|
|
1380
|
+
/* @__PURE__ */ jsxs3(Text4, { color: "yellow", children: [
|
|
1381
|
+
"\u26A0 schema \u95EE\u9898\uFF08",
|
|
1382
|
+
schemaIssues.length,
|
|
1383
|
+
"\uFF09"
|
|
1384
|
+
] }),
|
|
1385
|
+
schemaIssues.slice(0, 3).map((issue, i) => /* @__PURE__ */ jsxs3(Text4, { color: "yellow", children: [
|
|
1386
|
+
" - ",
|
|
1387
|
+
issue.message
|
|
1388
|
+
] }, i)),
|
|
1389
|
+
schemaIssues.length > 3 && /* @__PURE__ */ jsxs3(Text4, { color: "yellow", children: [
|
|
1390
|
+
" ...\u8FD8\u6709 ",
|
|
1391
|
+
schemaIssues.length - 3,
|
|
1392
|
+
" \u6761"
|
|
1393
|
+
] })
|
|
1394
|
+
] })
|
|
1192
1395
|
] });
|
|
1193
1396
|
}
|
|
1397
|
+
function resolveArgsFromRaw(raw) {
|
|
1398
|
+
if (!raw) return {};
|
|
1399
|
+
const parsed = parseToolCallArgs(raw);
|
|
1400
|
+
if (parsed.ok) return parsed.args;
|
|
1401
|
+
return {};
|
|
1402
|
+
}
|
|
1194
1403
|
|
|
1195
1404
|
// src/ui/HighlightedText.tsx
|
|
1196
1405
|
import { Box as Box4, Text as Text5 } from "ink";
|
|
@@ -1981,10 +2190,214 @@ function TodoListPanel({ items }) {
|
|
|
1981
2190
|
] });
|
|
1982
2191
|
}
|
|
1983
2192
|
|
|
2193
|
+
// src/ui/CompactionProgress.tsx
|
|
2194
|
+
import { Box as Box10, Text as Text11 } from "ink";
|
|
2195
|
+
import InkSpinner3 from "ink-spinner";
|
|
2196
|
+
import { useMemo } from "react";
|
|
2197
|
+
import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2198
|
+
function estimateProgress(state) {
|
|
2199
|
+
if (state.phase === "idle") return 0;
|
|
2200
|
+
if (state.phase === "done") return 100;
|
|
2201
|
+
if (state.phase === "error") return 100;
|
|
2202
|
+
const p = state.progress;
|
|
2203
|
+
if (!p) return 5;
|
|
2204
|
+
if (p.type === "start") {
|
|
2205
|
+
return 10;
|
|
2206
|
+
}
|
|
2207
|
+
if (p.type === "summary_delta") {
|
|
2208
|
+
const ratio = Math.min(p.totalSoFar.length / 800, 1);
|
|
2209
|
+
return Math.min(10 + ratio * 80, 90);
|
|
2210
|
+
}
|
|
2211
|
+
if (p.type === "fallback") {
|
|
2212
|
+
return 95;
|
|
2213
|
+
}
|
|
2214
|
+
return 5;
|
|
2215
|
+
}
|
|
2216
|
+
function phaseLabel(state) {
|
|
2217
|
+
if (state.phase === "error") {
|
|
2218
|
+
return { icon: "\u2717", text: "\u538B\u7F29\u51FA\u9519", color: "#ff6347" };
|
|
2219
|
+
}
|
|
2220
|
+
if (state.phase === "done") {
|
|
2221
|
+
if (state.strategy === "fallback") {
|
|
2222
|
+
return { icon: "\u2714", text: "\u538B\u7F29\u5B8C\u6210\uFF08\u672C\u5730\u515C\u5E95\uFF09", color: "#ff9800" };
|
|
2223
|
+
}
|
|
2224
|
+
return { icon: "\u2714", text: "\u538B\u7F29\u5B8C\u6210", color: "#00ff41" };
|
|
2225
|
+
}
|
|
2226
|
+
const p = state.progress;
|
|
2227
|
+
if (!p) {
|
|
2228
|
+
return { icon: "\u280B", text: "\u51C6\u5907\u538B\u7F29...", color: "#00ffff" };
|
|
2229
|
+
}
|
|
2230
|
+
if (p.type === "start") {
|
|
2231
|
+
return { icon: "\u280B", text: `\u51C6\u5907\u6458\u8981 ${p.droppedTurns} \u4E2A\u65E7\u56DE\u5408...`, color: "#00ffff" };
|
|
2232
|
+
}
|
|
2233
|
+
if (p.type === "summary_delta") {
|
|
2234
|
+
return { icon: "\u280B", text: "\u8C03\u7528 LLM \u751F\u6210\u6458\u8981...", color: "#00ffff" };
|
|
2235
|
+
}
|
|
2236
|
+
if (p.type === "fallback") {
|
|
2237
|
+
return { icon: "\u26A0", text: `LLM \u6458\u8981\u5931\u8D25\uFF0C\u4F7F\u7528\u672C\u5730\u515C\u5E95\uFF1A${p.reason}`, color: "#ff9800" };
|
|
2238
|
+
}
|
|
2239
|
+
return { icon: "\u280B", text: "\u538B\u7F29\u4E2D...", color: "#00ffff" };
|
|
2240
|
+
}
|
|
2241
|
+
function ProgressBar({ percent, color }) {
|
|
2242
|
+
const WIDTH = 24;
|
|
2243
|
+
const filled = Math.round(percent / 100 * WIDTH);
|
|
2244
|
+
const empty = WIDTH - filled;
|
|
2245
|
+
return /* @__PURE__ */ jsxs10(Text11, { children: [
|
|
2246
|
+
/* @__PURE__ */ jsx10(Text11, { color, children: "\u2588".repeat(filled) }),
|
|
2247
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#444444", children: "\u2591".repeat(empty) }),
|
|
2248
|
+
/* @__PURE__ */ jsxs10(Text11, { color, children: [
|
|
2249
|
+
" ",
|
|
2250
|
+
percent.toFixed(0),
|
|
2251
|
+
"%"
|
|
2252
|
+
] })
|
|
2253
|
+
] });
|
|
2254
|
+
}
|
|
2255
|
+
function PhaseSteps({ state }) {
|
|
2256
|
+
const step = (() => {
|
|
2257
|
+
if (state.phase === "idle") return 0;
|
|
2258
|
+
if (state.phase === "error") {
|
|
2259
|
+
const p2 = state.progress;
|
|
2260
|
+
if (p2?.type === "summary_delta" || p2?.type === "start") return 1;
|
|
2261
|
+
return 2;
|
|
2262
|
+
}
|
|
2263
|
+
if (state.phase === "done") return 3;
|
|
2264
|
+
const p = state.progress;
|
|
2265
|
+
if (!p || p.type === "start") return 0;
|
|
2266
|
+
if (p.type === "summary_delta") return 1;
|
|
2267
|
+
if (p.type === "fallback") return 2;
|
|
2268
|
+
return 2;
|
|
2269
|
+
})();
|
|
2270
|
+
const labels = ["\u542F\u52A8", "LLM \u6458\u8981", "\u5E94\u7528\u538B\u7F29", "\u5B8C\u6210"];
|
|
2271
|
+
return /* @__PURE__ */ jsx10(Box10, { children: labels.map((label, i) => {
|
|
2272
|
+
const isCurrent = i === step;
|
|
2273
|
+
const isDone = i < step;
|
|
2274
|
+
const marker = isDone ? "\u2713" : isCurrent ? "\u25B8" : "\xB7";
|
|
2275
|
+
const color = isDone ? "#00ff41" : isCurrent ? "#00ffff" : "#444444";
|
|
2276
|
+
return /* @__PURE__ */ jsxs10(Box10, { marginRight: 1, children: [
|
|
2277
|
+
/* @__PURE__ */ jsxs10(Text11, { color, children: [
|
|
2278
|
+
marker,
|
|
2279
|
+
" ",
|
|
2280
|
+
label
|
|
2281
|
+
] }),
|
|
2282
|
+
i < labels.length - 1 && /* @__PURE__ */ jsx10(Text11, { color: "#444444", children: " \u2192 " })
|
|
2283
|
+
] }, label);
|
|
2284
|
+
}) });
|
|
2285
|
+
}
|
|
2286
|
+
function SummaryPreview({ text, contentWidth }) {
|
|
2287
|
+
const MAX_LINES = 4;
|
|
2288
|
+
const MAX_LINE_WIDTH = Math.max(contentWidth - 6, 20);
|
|
2289
|
+
if (!text) {
|
|
2290
|
+
return /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: " (\u7B49\u5F85 LLM \u8F93\u51FA...)" });
|
|
2291
|
+
}
|
|
2292
|
+
const lines = wrapByWidth2(text, MAX_LINE_WIDTH);
|
|
2293
|
+
const kept = lines.slice(-MAX_LINES);
|
|
2294
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: kept.map((line, i) => /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
|
|
2295
|
+
" ",
|
|
2296
|
+
line
|
|
2297
|
+
] }, i)) });
|
|
2298
|
+
}
|
|
2299
|
+
function wrapByWidth2(text, maxWidth) {
|
|
2300
|
+
if (text === "") return [];
|
|
2301
|
+
if (maxWidth <= 0) return [text];
|
|
2302
|
+
const result = [];
|
|
2303
|
+
for (const para of text.split("\n")) {
|
|
2304
|
+
if (para.length === 0) {
|
|
2305
|
+
result.push("");
|
|
2306
|
+
continue;
|
|
2307
|
+
}
|
|
2308
|
+
let buf = "";
|
|
2309
|
+
let bufWidth = 0;
|
|
2310
|
+
for (const ch of para) {
|
|
2311
|
+
const cp2 = ch.codePointAt(0);
|
|
2312
|
+
const w = cp2 > 11904 ? 2 : 1;
|
|
2313
|
+
if (bufWidth + w > maxWidth && buf.length > 0) {
|
|
2314
|
+
result.push(buf);
|
|
2315
|
+
buf = ch;
|
|
2316
|
+
bufWidth = w;
|
|
2317
|
+
} else {
|
|
2318
|
+
buf += ch;
|
|
2319
|
+
bufWidth += w;
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
if (buf.length > 0) result.push(buf);
|
|
2323
|
+
}
|
|
2324
|
+
return result;
|
|
2325
|
+
}
|
|
2326
|
+
function fmtNum(n) {
|
|
2327
|
+
return n.toLocaleString();
|
|
2328
|
+
}
|
|
2329
|
+
function CompactionProgress({ state, contentWidth }) {
|
|
2330
|
+
const percent = useMemo(() => estimateProgress(state), [state]);
|
|
2331
|
+
const phase = useMemo(() => phaseLabel(state), [state]);
|
|
2332
|
+
const summaryText = state.progress?.type === "summary_delta" ? state.progress.totalSoFar : state.progress?.type === "fallback" ? state.progress.fallbackSummary : state.phase === "done" && state.strategy === "summary" ? "" : "";
|
|
2333
|
+
const finalSummary = state.phase === "done" && state.strategy === "summary" ? state.progress?.type === "summary_delta" ? state.progress.totalSoFar : "" : summaryText;
|
|
2334
|
+
const titleColor = state.phase === "error" ? "#ff6347" : "#00ffff";
|
|
2335
|
+
return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
|
|
2336
|
+
/* @__PURE__ */ jsx10(Box10, { width: 1, backgroundColor: "#9b59b6", flexShrink: 0 }),
|
|
2337
|
+
/* @__PURE__ */ jsxs10(Box10, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: [
|
|
2338
|
+
/* @__PURE__ */ jsxs10(Box10, { children: [
|
|
2339
|
+
/* @__PURE__ */ jsx10(Text11, { bold: true, color: titleColor, children: "\u{1F5DC} \u4E0A\u4E0B\u6587\u538B\u7F29" }),
|
|
2340
|
+
/* @__PURE__ */ jsx10(Box10, { flexGrow: 1 }),
|
|
2341
|
+
state.phase === "running" && /* @__PURE__ */ jsxs10(Text11, { color: phase.color, children: [
|
|
2342
|
+
/* @__PURE__ */ jsx10(InkSpinner3, { type: "dots" }),
|
|
2343
|
+
" ",
|
|
2344
|
+
phase.text
|
|
2345
|
+
] }),
|
|
2346
|
+
state.phase === "done" && /* @__PURE__ */ jsxs10(Text11, { color: phase.color, children: [
|
|
2347
|
+
phase.icon,
|
|
2348
|
+
" ",
|
|
2349
|
+
phase.text
|
|
2350
|
+
] }),
|
|
2351
|
+
state.phase === "error" && /* @__PURE__ */ jsxs10(Text11, { color: phase.color, children: [
|
|
2352
|
+
phase.icon,
|
|
2353
|
+
" ",
|
|
2354
|
+
phase.text
|
|
2355
|
+
] })
|
|
2356
|
+
] }),
|
|
2357
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
2358
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#808080", children: "\u8FDB\u5EA6: " }),
|
|
2359
|
+
/* @__PURE__ */ jsx10(ProgressBar, { percent, color: state.phase === "error" ? "#ff6347" : phase.color })
|
|
2360
|
+
] }),
|
|
2361
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(PhaseSteps, { state }) }),
|
|
2362
|
+
(state.beforeTokens !== void 0 || state.droppedTurns !== void 0) && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
2363
|
+
state.droppedTurns !== void 0 && /* @__PURE__ */ jsxs10(Text11, { color: "#00ff41", children: [
|
|
2364
|
+
"\u{1F4CA} \u56DE\u5408: ",
|
|
2365
|
+
state.droppedTurns,
|
|
2366
|
+
" \u6298\u53E0 \u2192 ",
|
|
2367
|
+
state.keptTurns ?? 0,
|
|
2368
|
+
" \u4FDD\u7559"
|
|
2369
|
+
] }),
|
|
2370
|
+
state.beforeTokens !== void 0 && /* @__PURE__ */ jsxs10(Text11, { color: "#ff9800", children: [
|
|
2371
|
+
"\u{1F4E6} token: ",
|
|
2372
|
+
fmtNum(state.beforeTokens),
|
|
2373
|
+
state.afterTokens !== void 0 && /* @__PURE__ */ jsxs10(Fragment2, { children: [
|
|
2374
|
+
" \u2192 ",
|
|
2375
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#00ff41", bold: true, children: fmtNum(state.afterTokens) }),
|
|
2376
|
+
/* @__PURE__ */ jsxs10(Text11, { color: "#808080", children: [
|
|
2377
|
+
" (\u8282\u7701 ",
|
|
2378
|
+
((state.beforeTokens - state.afterTokens) / Math.max(state.beforeTokens, 1) * 100).toFixed(1),
|
|
2379
|
+
"%)"
|
|
2380
|
+
] })
|
|
2381
|
+
] })
|
|
2382
|
+
] })
|
|
2383
|
+
] }),
|
|
2384
|
+
(state.phase === "running" || state.phase === "done") && finalSummary && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
|
|
2385
|
+
/* @__PURE__ */ jsx10(Text11, { color: "#808080", children: "\u2504\u2504\u2504 LLM \u6458\u8981\u9884\u89C8 \u2504\u2504\u2504" }),
|
|
2386
|
+
/* @__PURE__ */ jsx10(SummaryPreview, { text: finalSummary, contentWidth })
|
|
2387
|
+
] }),
|
|
2388
|
+
state.phase === "done" && state.strategy === "fallback" && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text11, { color: "#ff9800", children: "\u26A0 LLM \u6458\u8981\u5931\u8D25\uFF0C\u4F7F\u7528\u672C\u5730\u515C\u5E95\u6458\u8981\u3002\u538B\u7F29\u5DF2\u751F\u6548\u4F46\u6458\u8981\u8D28\u91CF\u8F83\u4F4E\u3002" }) }),
|
|
2389
|
+
state.phase === "error" && state.errorMessage && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { color: "#ff6347", children: [
|
|
2390
|
+
"\u26A0 ",
|
|
2391
|
+
state.errorMessage
|
|
2392
|
+
] }) })
|
|
2393
|
+
] })
|
|
2394
|
+
] }) });
|
|
2395
|
+
}
|
|
2396
|
+
|
|
1984
2397
|
// package.json
|
|
1985
2398
|
var package_default = {
|
|
1986
2399
|
name: "dskcode",
|
|
1987
|
-
version: "0.1.
|
|
2400
|
+
version: "0.1.41",
|
|
1988
2401
|
repository: {
|
|
1989
2402
|
type: "git",
|
|
1990
2403
|
url: "git+https://github.com/Awu12277/deepseek-agent-cli/tree/main"
|
|
@@ -2020,9 +2433,8 @@ var package_default = {
|
|
|
2020
2433
|
"lint:fix": "oxlint --fix src/ tests/",
|
|
2021
2434
|
format: "prettier --write src/ tests/",
|
|
2022
2435
|
"format:check": "prettier --check src/ tests/",
|
|
2023
|
-
test: "vitest run",
|
|
2024
|
-
"test:
|
|
2025
|
-
"test:coverage": "vitest run --coverage",
|
|
2436
|
+
test: "vitest run --exclude 'tests/checkpoint.test.ts' --exclude 'tests/session-rewind.test.ts'",
|
|
2437
|
+
"test:checkpoint": "vitest run tests/checkpoint.test.ts tests/session-rewind.test.ts",
|
|
2026
2438
|
prepublishOnly: "npm run build && npm run test"
|
|
2027
2439
|
},
|
|
2028
2440
|
dependencies: {
|
|
@@ -2033,7 +2445,8 @@ var package_default = {
|
|
|
2033
2445
|
ink: "^7.1.0",
|
|
2034
2446
|
"ink-spinner": "^5.0.0",
|
|
2035
2447
|
"ink-text-input": "^6.0.0",
|
|
2036
|
-
react: "^19.2.7"
|
|
2448
|
+
react: "^19.2.7",
|
|
2449
|
+
zod: "^3.25.76"
|
|
2037
2450
|
},
|
|
2038
2451
|
devDependencies: {
|
|
2039
2452
|
"@types/node": "^22.14.0",
|
|
@@ -2267,6 +2680,246 @@ function buildApiMessages(systemPrompt, history) {
|
|
|
2267
2680
|
];
|
|
2268
2681
|
}
|
|
2269
2682
|
|
|
2683
|
+
// src/agent/compactor.ts
|
|
2684
|
+
var DEFAULT_AUTO_COMPACT_RATIO = 0.85;
|
|
2685
|
+
var DEFAULT_PRESERVE_ROUNDS = 6;
|
|
2686
|
+
var DEFAULT_MIN_TURNS_TO_COMPACT = 8;
|
|
2687
|
+
var SUMMARY_SENTINEL = "[history-summary]";
|
|
2688
|
+
var SUMMARY_SYSTEM_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u7684\u5BF9\u8BDD\u6458\u8981\u52A9\u624B\u3002\u4F60\u7684\u4EFB\u52A1\u662F\u628A\u591A\u8F6E\u5BF9\u8BDD\u5386\u53F2\u538B\u7F29\u6210\u7ED3\u6784\u5316\u4E2D\u6587\u6458\u8981\u3002
|
|
2689
|
+
|
|
2690
|
+
\u6458\u8981\u5FC5\u987B\u4FDD\u7559\u4EE5\u4E0B\u4FE1\u606F\uFF08\u6309\u91CD\u8981\u6027\u6392\u5E8F\uFF09\uFF1A
|
|
2691
|
+
1. \u7528\u6237\u7684\u6838\u5FC3\u76EE\u6807\u4E0E\u6700\u7EC8\u610F\u56FE
|
|
2692
|
+
2. \u5DF2\u5B8C\u6210\u7684\u5173\u952E\u51B3\u7B56\uFF08\u5982\u9009\u4E86\u54EA\u4E2A\u65B9\u6848\u3001\u6539\u4E86\u54EA\u4E9B\u6587\u4EF6\u3001\u4E3A\u4EC0\u4E48\u8FD9\u4E48\u6539\uFF09
|
|
2693
|
+
3. \u6D89\u53CA\u7684\u5177\u4F53\u6587\u4EF6\u8DEF\u5F84\uFF08\u7EDD\u5BF9/\u76F8\u5BF9\u8DEF\u5F84\u90FD\u8981\u4FDD\u7559\uFF09
|
|
2694
|
+
4. \u51FA\u73B0\u8FC7\u7684\u9519\u8BEF\u4FE1\u606F\u4E0E\u89E3\u51B3\u65B9\u6848
|
|
2695
|
+
5. \u5C1A\u672A\u5B8C\u6210\u7684\u5DE5\u4F5C / \u5F85\u529E\u4E8B\u9879
|
|
2696
|
+
6. \u91CD\u8981\u7684\u6280\u672F\u7EA6\u675F\uFF08\u5982"\u4E0D\u80FD\u7528 XX \u5E93"\uFF09
|
|
2697
|
+
|
|
2698
|
+
\u683C\u5F0F\u8981\u6C42\uFF1A
|
|
2699
|
+
- \u7528\u7EAF\u6587\u672C\uFF0C\u4E0D\u8981 markdown \u6807\u9898\u5206\u7EA7
|
|
2700
|
+
- \u6BCF\u6761\u4FE1\u606F\u72EC\u7ACB\u6210\u884C\uFF0C\u65B9\u4FBF\u540E\u7EED\u6309\u884C\u89E3\u6790
|
|
2701
|
+
- \u603B\u957F\u5EA6\u63A7\u5236\u5728 2000 \u5B57\u4EE5\u5185
|
|
2702
|
+
- \u4E0D\u9700\u8981\u5BA2\u5957\u8BDD\u3001\u4E0D\u9700\u8981"\u4EE5\u4E0B\u662F\u6458\u8981"\u7B49\u5F00\u5934
|
|
2703
|
+
`;
|
|
2704
|
+
var PER_MESSAGE_TEXT_LIMIT = 500;
|
|
2705
|
+
var FALLBACK_USER_PREVIEW = 60;
|
|
2706
|
+
function estimateMessageTokens2(msg) {
|
|
2707
|
+
let text = msg.content;
|
|
2708
|
+
if (msg.toolCalls) {
|
|
2709
|
+
for (const tc of msg.toolCalls) {
|
|
2710
|
+
text += tc.name + tc.arguments;
|
|
2711
|
+
}
|
|
2712
|
+
}
|
|
2713
|
+
return estimateTokens(text) + 10;
|
|
2714
|
+
}
|
|
2715
|
+
function estimateMessagesTokens(messages) {
|
|
2716
|
+
let sum = 0;
|
|
2717
|
+
for (const m of messages) sum += estimateMessageTokens2(m);
|
|
2718
|
+
return sum;
|
|
2719
|
+
}
|
|
2720
|
+
function getContextStats(messages, contextWindow) {
|
|
2721
|
+
const estimatedTokens = estimateMessagesTokens(messages);
|
|
2722
|
+
const ratio = contextWindow > 0 ? estimatedTokens / contextWindow : 0;
|
|
2723
|
+
return {
|
|
2724
|
+
messageCount: messages.length,
|
|
2725
|
+
estimatedTokens,
|
|
2726
|
+
contextWindow,
|
|
2727
|
+
ratio,
|
|
2728
|
+
headroom: contextWindow - estimatedTokens
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
function shouldAutoCompact(messages, opts) {
|
|
2732
|
+
const turns = groupIntoTurns(messages);
|
|
2733
|
+
const minTurns = opts.minTurnsToCompact ?? DEFAULT_MIN_TURNS_TO_COMPACT;
|
|
2734
|
+
if (turns.length < minTurns) return false;
|
|
2735
|
+
const ratio = opts.autoCompactRatio ?? DEFAULT_AUTO_COMPACT_RATIO;
|
|
2736
|
+
const stats = getContextStats(messages, opts.contextWindow);
|
|
2737
|
+
return stats.ratio >= ratio;
|
|
2738
|
+
}
|
|
2739
|
+
function turnsToPromptText(turns) {
|
|
2740
|
+
const lines = [];
|
|
2741
|
+
for (let i = 0; i < turns.length; i++) {
|
|
2742
|
+
const turn = turns[i];
|
|
2743
|
+
lines.push(`--- \u7B2C ${i + 1} \u56DE\u5408 ---`);
|
|
2744
|
+
for (const msg of turn) {
|
|
2745
|
+
const head = `[${msg.role}]`;
|
|
2746
|
+
const body = msg.content.length > PER_MESSAGE_TEXT_LIMIT ? msg.content.slice(0, PER_MESSAGE_TEXT_LIMIT) + `\u2026(\u5DF2\u622A\u65AD,\u539F\u957F ${msg.content.length})` : msg.content;
|
|
2747
|
+
lines.push(`${head} ${body}`);
|
|
2748
|
+
if (msg.toolCalls) {
|
|
2749
|
+
for (const tc of msg.toolCalls) {
|
|
2750
|
+
lines.push(` tool_call: ${tc.name}(${tc.arguments})`);
|
|
2751
|
+
}
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
return lines.join("\n");
|
|
2756
|
+
}
|
|
2757
|
+
function fallbackSummary(turns) {
|
|
2758
|
+
const lines = ["\u3010\u672C\u5730\u6458\u8981\uFF08LLM \u8C03\u7528\u5931\u8D25\u65F6\u515C\u5E95\uFF09\u3011"];
|
|
2759
|
+
for (let i = 0; i < turns.length; i++) {
|
|
2760
|
+
const turn = turns[i];
|
|
2761
|
+
const userMsg = turn.find((m) => m.role === "user");
|
|
2762
|
+
if (userMsg) {
|
|
2763
|
+
const preview = userMsg.content.slice(0, FALLBACK_USER_PREVIEW);
|
|
2764
|
+
lines.push(`\u56DE\u5408${i + 1} \u7528\u6237: ${preview}`);
|
|
2765
|
+
}
|
|
2766
|
+
const toolCalls = [];
|
|
2767
|
+
for (const m of turn) {
|
|
2768
|
+
if (m.toolCalls) for (const tc of m.toolCalls) toolCalls.push({ name: tc.name, argsRaw: tc.arguments });
|
|
2769
|
+
}
|
|
2770
|
+
if (toolCalls.length > 0) {
|
|
2771
|
+
const summaries = toolCalls.map((tc) => {
|
|
2772
|
+
const parsed = parseToolCallArgs(tc.argsRaw);
|
|
2773
|
+
if (!parsed.ok) {
|
|
2774
|
+
return `${tc.name}(\u89E3\u6790\u5931\u8D25)`;
|
|
2775
|
+
}
|
|
2776
|
+
return templateToolCall(tc.name, maskSensitive(parsed.args));
|
|
2777
|
+
});
|
|
2778
|
+
lines.push(` \u8C03\u7528\u5DE5\u5177: ${summaries.join("; ")}`);
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
return lines.join("\n");
|
|
2782
|
+
}
|
|
2783
|
+
async function summarizeOldTurns(oldTurns, opts) {
|
|
2784
|
+
if (oldTurns.length === 0) return "";
|
|
2785
|
+
const promptText = turnsToPromptText(oldTurns);
|
|
2786
|
+
try {
|
|
2787
|
+
const messages = [
|
|
2788
|
+
{ role: "system", content: SUMMARY_SYSTEM_PROMPT },
|
|
2789
|
+
{
|
|
2790
|
+
role: "user",
|
|
2791
|
+
content: `\u8BF7\u628A\u4EE5\u4E0B ${oldTurns.length} \u8F6E\u5BF9\u8BDD\u5386\u53F2\u538B\u7F29\u6210\u7ED3\u6784\u5316\u6458\u8981\uFF1A
|
|
2792
|
+
|
|
2793
|
+
${promptText}`
|
|
2794
|
+
}
|
|
2795
|
+
];
|
|
2796
|
+
const stream = opts.provider.chat(messages, {
|
|
2797
|
+
...opts.signal ? { signal: opts.signal } : {},
|
|
2798
|
+
// 摘要场景压低温度,输出更稳定
|
|
2799
|
+
temperature: 0.2
|
|
2800
|
+
});
|
|
2801
|
+
let summary = "";
|
|
2802
|
+
for await (const chunk of stream) {
|
|
2803
|
+
if (chunk.content) {
|
|
2804
|
+
summary += chunk.content;
|
|
2805
|
+
if (opts.onProgress) {
|
|
2806
|
+
try {
|
|
2807
|
+
opts.onProgress({
|
|
2808
|
+
type: "summary_delta",
|
|
2809
|
+
delta: chunk.content,
|
|
2810
|
+
totalSoFar: summary
|
|
2811
|
+
});
|
|
2812
|
+
} catch {
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
if (!summary.trim()) {
|
|
2818
|
+
const fb = fallbackSummary(oldTurns);
|
|
2819
|
+
if (opts.onProgress) {
|
|
2820
|
+
try {
|
|
2821
|
+
opts.onProgress({
|
|
2822
|
+
type: "fallback",
|
|
2823
|
+
reason: "LLM \u8FD4\u56DE\u7A7A\u5B57\u7B26\u4E32",
|
|
2824
|
+
fallbackSummary: fb
|
|
2825
|
+
});
|
|
2826
|
+
} catch {
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
return fb;
|
|
2830
|
+
}
|
|
2831
|
+
return summary.trim();
|
|
2832
|
+
} catch (err) {
|
|
2833
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2834
|
+
const fb = fallbackSummary(oldTurns);
|
|
2835
|
+
if (opts.onProgress) {
|
|
2836
|
+
try {
|
|
2837
|
+
opts.onProgress({
|
|
2838
|
+
type: "fallback",
|
|
2839
|
+
reason: errMsg,
|
|
2840
|
+
fallbackSummary: fb
|
|
2841
|
+
});
|
|
2842
|
+
} catch {
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
return fb;
|
|
2846
|
+
}
|
|
2847
|
+
}
|
|
2848
|
+
function buildSummaryMessage(summary) {
|
|
2849
|
+
return {
|
|
2850
|
+
role: "system",
|
|
2851
|
+
content: `${SUMMARY_SENTINEL}
|
|
2852
|
+
${summary}`
|
|
2853
|
+
};
|
|
2854
|
+
}
|
|
2855
|
+
async function compactContext(messages, opts) {
|
|
2856
|
+
const beforeTokens = estimateMessagesTokens(messages);
|
|
2857
|
+
const turns = groupIntoTurns(messages);
|
|
2858
|
+
const minTurns = opts.minTurnsToCompact ?? DEFAULT_MIN_TURNS_TO_COMPACT;
|
|
2859
|
+
const preserveRounds = opts.preserveRecentRounds ?? DEFAULT_PRESERVE_ROUNDS;
|
|
2860
|
+
if (turns.length < minTurns) {
|
|
2861
|
+
return {
|
|
2862
|
+
messages: messages.slice(),
|
|
2863
|
+
summary: "",
|
|
2864
|
+
droppedTurns: 0,
|
|
2865
|
+
keptTurns: turns.length,
|
|
2866
|
+
beforeTokens,
|
|
2867
|
+
afterTokens: beforeTokens
|
|
2868
|
+
};
|
|
2869
|
+
}
|
|
2870
|
+
if (turns.length <= preserveRounds) {
|
|
2871
|
+
return {
|
|
2872
|
+
messages: messages.slice(),
|
|
2873
|
+
summary: "",
|
|
2874
|
+
droppedTurns: 0,
|
|
2875
|
+
keptTurns: turns.length,
|
|
2876
|
+
beforeTokens,
|
|
2877
|
+
afterTokens: beforeTokens
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2880
|
+
const splitAt = turns.length - preserveRounds;
|
|
2881
|
+
const oldTurns = turns.slice(0, splitAt);
|
|
2882
|
+
const keptTurns = turns.slice(splitAt);
|
|
2883
|
+
if (opts.onProgress) {
|
|
2884
|
+
try {
|
|
2885
|
+
opts.onProgress({
|
|
2886
|
+
type: "start",
|
|
2887
|
+
droppedTurns: oldTurns.length,
|
|
2888
|
+
beforeTokens
|
|
2889
|
+
});
|
|
2890
|
+
} catch {
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
const summary = await summarizeOldTurns(oldTurns, opts);
|
|
2894
|
+
const newMessages = [buildSummaryMessage(summary)];
|
|
2895
|
+
for (const turn of keptTurns) {
|
|
2896
|
+
for (const msg of turn) {
|
|
2897
|
+
newMessages.push(msg);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
const afterTokens = estimateMessagesTokens(newMessages);
|
|
2901
|
+
if (opts.onProgress) {
|
|
2902
|
+
try {
|
|
2903
|
+
opts.onProgress({
|
|
2904
|
+
type: "done",
|
|
2905
|
+
droppedTurns: oldTurns.length,
|
|
2906
|
+
keptTurns: keptTurns.length,
|
|
2907
|
+
beforeTokens,
|
|
2908
|
+
afterTokens
|
|
2909
|
+
});
|
|
2910
|
+
} catch {
|
|
2911
|
+
}
|
|
2912
|
+
}
|
|
2913
|
+
return {
|
|
2914
|
+
messages: newMessages,
|
|
2915
|
+
summary,
|
|
2916
|
+
droppedTurns: oldTurns.length,
|
|
2917
|
+
keptTurns: keptTurns.length,
|
|
2918
|
+
beforeTokens,
|
|
2919
|
+
afterTokens
|
|
2920
|
+
};
|
|
2921
|
+
}
|
|
2922
|
+
|
|
2270
2923
|
// src/tool/registry.ts
|
|
2271
2924
|
var ToolRegistry = class {
|
|
2272
2925
|
#tools = /* @__PURE__ */ new Map();
|
|
@@ -2433,6 +3086,326 @@ var ToolRegistry = class {
|
|
|
2433
3086
|
}
|
|
2434
3087
|
};
|
|
2435
3088
|
|
|
3089
|
+
// src/tool/zod-schema-validator.ts
|
|
3090
|
+
import { z } from "zod";
|
|
3091
|
+
function zodSafeValidate(args, schema) {
|
|
3092
|
+
const result = schema.safeParse(args);
|
|
3093
|
+
if (result.success) {
|
|
3094
|
+
return { ok: true, issues: [] };
|
|
3095
|
+
}
|
|
3096
|
+
const issues = result.error.issues.map(
|
|
3097
|
+
(zi) => zodIssueToValidationIssue(zi, args)
|
|
3098
|
+
);
|
|
3099
|
+
return { ok: issues.length === 0, issues };
|
|
3100
|
+
}
|
|
3101
|
+
function zodIssueToValidationIssue(zi, rootArgs) {
|
|
3102
|
+
const path = formatPath(zi.path);
|
|
3103
|
+
const expected = formatExpected(zi);
|
|
3104
|
+
const received = describeReceived(rootArgs, zi.path);
|
|
3105
|
+
const message = formatMessage(path, expected, received, zi);
|
|
3106
|
+
return { path, expected, received, message };
|
|
3107
|
+
}
|
|
3108
|
+
function formatPath(path) {
|
|
3109
|
+
if (path.length === 0) return "$";
|
|
3110
|
+
let out = "$";
|
|
3111
|
+
for (const seg of path) {
|
|
3112
|
+
if (typeof seg === "number") {
|
|
3113
|
+
out += `[${seg}]`;
|
|
3114
|
+
} else if (typeof seg === "string") {
|
|
3115
|
+
out += `.${seg}`;
|
|
3116
|
+
} else {
|
|
3117
|
+
out += "[]";
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
return out;
|
|
3121
|
+
}
|
|
3122
|
+
function formatExpected(zi) {
|
|
3123
|
+
switch (zi.code) {
|
|
3124
|
+
case "invalid_type": {
|
|
3125
|
+
const exp = zi.expected;
|
|
3126
|
+
return exp;
|
|
3127
|
+
}
|
|
3128
|
+
case "too_small": {
|
|
3129
|
+
const t = zi.type;
|
|
3130
|
+
const min = zi.minimum;
|
|
3131
|
+
if (t === "string") return `length >= ${min}`;
|
|
3132
|
+
if (t === "array") return `length >= ${min}`;
|
|
3133
|
+
if (t === "number") return `>= ${min}`;
|
|
3134
|
+
return `>= ${min}`;
|
|
3135
|
+
}
|
|
3136
|
+
case "too_big": {
|
|
3137
|
+
const t = zi.type;
|
|
3138
|
+
const max = zi.maximum;
|
|
3139
|
+
if (t === "string") return `length <= ${max}`;
|
|
3140
|
+
if (t === "array") return `length <= ${max}`;
|
|
3141
|
+
if (t === "number") return `<= ${max}`;
|
|
3142
|
+
return `<= ${max}`;
|
|
3143
|
+
}
|
|
3144
|
+
case "invalid_enum_value": {
|
|
3145
|
+
const opts = zi.options;
|
|
3146
|
+
return `enum[${opts.map((o) => JSON.stringify(o)).join(",")}]`;
|
|
3147
|
+
}
|
|
3148
|
+
case "invalid_string": {
|
|
3149
|
+
const v = zi.validation;
|
|
3150
|
+
return `string ${v}`;
|
|
3151
|
+
}
|
|
3152
|
+
case "unrecognized_keys": {
|
|
3153
|
+
const keys = zi.keys;
|
|
3154
|
+
return `\u672A\u5728 schema \u4E2D\u5B9A\u4E49: ${keys.join(",")}`;
|
|
3155
|
+
}
|
|
3156
|
+
case "invalid_literal": {
|
|
3157
|
+
const exp = zi.expected;
|
|
3158
|
+
return `literal[${JSON.stringify(exp)}]`;
|
|
3159
|
+
}
|
|
3160
|
+
default:
|
|
3161
|
+
return zi.code;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
function describeReceived(rootArgs, path) {
|
|
3165
|
+
let cur = rootArgs;
|
|
3166
|
+
for (const seg of path) {
|
|
3167
|
+
if (cur === null || cur === void 0) return "undefined";
|
|
3168
|
+
if (typeof cur !== "object") return "undefined";
|
|
3169
|
+
if (typeof seg === "number") {
|
|
3170
|
+
if (!Array.isArray(cur)) return "undefined";
|
|
3171
|
+
cur = cur[seg];
|
|
3172
|
+
} else if (typeof seg === "string") {
|
|
3173
|
+
cur = cur[seg];
|
|
3174
|
+
} else {
|
|
3175
|
+
return "undefined";
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
if (cur === null) return "null";
|
|
3179
|
+
if (cur === void 0) return "undefined";
|
|
3180
|
+
if (typeof cur === "string") {
|
|
3181
|
+
return cur.length > 60 ? JSON.stringify(cur.slice(0, 57) + "...") : JSON.stringify(cur);
|
|
3182
|
+
}
|
|
3183
|
+
if (typeof cur === "number" || typeof cur === "boolean") return JSON.stringify(cur);
|
|
3184
|
+
if (Array.isArray(cur)) return `array(len=${cur.length})`;
|
|
3185
|
+
if (typeof cur === "object") {
|
|
3186
|
+
const keys = Object.keys(cur);
|
|
3187
|
+
return `object{keys=${keys.length}}`;
|
|
3188
|
+
}
|
|
3189
|
+
return typeof cur;
|
|
3190
|
+
}
|
|
3191
|
+
function formatMessage(path, expected, received, zi) {
|
|
3192
|
+
if (zi.code === "invalid_type") {
|
|
3193
|
+
return `${path} \u5E94\u4E3A ${expected}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3194
|
+
}
|
|
3195
|
+
if (zi.code === "too_small") {
|
|
3196
|
+
const t = zi.type;
|
|
3197
|
+
const min = zi.minimum;
|
|
3198
|
+
if (t === "string") return `${path} \u957F\u5EA6\u5E94 >= ${min}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3199
|
+
if (t === "array") return `${path} \u957F\u5EA6\u5E94 >= ${min}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3200
|
+
if (t === "number") return `${path} \u5E94 >= ${min}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3201
|
+
return `${path} \u5E94 >= ${min}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3202
|
+
}
|
|
3203
|
+
if (zi.code === "too_big") {
|
|
3204
|
+
const t = zi.type;
|
|
3205
|
+
const max = zi.maximum;
|
|
3206
|
+
if (t === "string") return `${path} \u957F\u5EA6\u5E94 <= ${max}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3207
|
+
if (t === "array") return `${path} \u957F\u5EA6\u5E94 <= ${max}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3208
|
+
if (t === "number") return `${path} \u5E94 <= ${max}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3209
|
+
return `${path} \u5E94 <= ${max}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3210
|
+
}
|
|
3211
|
+
if (zi.code === "invalid_enum_value") {
|
|
3212
|
+
return `${path} \u5E94\u4E3A enum \u503C\u4E4B\u4E00\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3213
|
+
}
|
|
3214
|
+
if (zi.code === "unrecognized_keys") {
|
|
3215
|
+
const keys = zi.keys;
|
|
3216
|
+
return `${path} \u4E0D\u5141\u8BB8\u952E: ${keys.join(", ")}`;
|
|
3217
|
+
}
|
|
3218
|
+
if (zi.code === "invalid_literal") {
|
|
3219
|
+
return `${path} \u5E94\u4E3A ${expected}\uFF0C\u5B9E\u9645\u4E3A ${received}`;
|
|
3220
|
+
}
|
|
3221
|
+
if (zi.code === "invalid_string") {
|
|
3222
|
+
return `${path} \u4E0D\u5339\u914D ${expected}`;
|
|
3223
|
+
}
|
|
3224
|
+
return `${path} ${zi.message}\uFF08\u671F\u671B ${expected}\uFF0C\u5B9E\u9645 ${received}\uFF09`;
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3227
|
+
// src/tool/schema-validator.ts
|
|
3228
|
+
function validateArgs(args, schema) {
|
|
3229
|
+
if (isZodSchema(schema)) {
|
|
3230
|
+
return zodSafeValidate(args, schema);
|
|
3231
|
+
}
|
|
3232
|
+
const issues = [];
|
|
3233
|
+
if (!isPlainObject2(schema)) {
|
|
3234
|
+
return { ok: true, issues };
|
|
3235
|
+
}
|
|
3236
|
+
if (schema.type !== void 0 && schema.type !== "object") {
|
|
3237
|
+
return { ok: true, issues };
|
|
3238
|
+
}
|
|
3239
|
+
validateObject(args, schema, "$", issues);
|
|
3240
|
+
return { ok: issues.length === 0, issues };
|
|
3241
|
+
}
|
|
3242
|
+
function isZodSchema(schema) {
|
|
3243
|
+
if (schema === null || typeof schema !== "object") return false;
|
|
3244
|
+
const obj = schema;
|
|
3245
|
+
return "_def" in obj && typeof obj.parse === "function" && typeof obj.safeParse === "function";
|
|
3246
|
+
}
|
|
3247
|
+
function validateObject(value, schema, path, issues) {
|
|
3248
|
+
if (!isPlainObject2(value)) {
|
|
3249
|
+
issues.push({
|
|
3250
|
+
path,
|
|
3251
|
+
expected: "object",
|
|
3252
|
+
received: describe(value),
|
|
3253
|
+
message: `${path} \u5E94\u4E3A object\uFF0C\u5B9E\u9645\u4E3A ${describe(value)}`
|
|
3254
|
+
});
|
|
3255
|
+
return;
|
|
3256
|
+
}
|
|
3257
|
+
for (const key of schema.required ?? []) {
|
|
3258
|
+
if (!(key in value)) {
|
|
3259
|
+
issues.push({
|
|
3260
|
+
path: `${path}.${key}`,
|
|
3261
|
+
expected: "present",
|
|
3262
|
+
received: "missing",
|
|
3263
|
+
message: `${path}.${key} \u662F\u5FC5\u586B\u5B57\u6BB5`
|
|
3264
|
+
});
|
|
3265
|
+
}
|
|
3266
|
+
}
|
|
3267
|
+
const props = schema.properties ?? {};
|
|
3268
|
+
const additional = schema.additionalProperties;
|
|
3269
|
+
for (const [k, v] of Object.entries(value)) {
|
|
3270
|
+
const propSchema = props[k];
|
|
3271
|
+
if (propSchema === void 0) {
|
|
3272
|
+
if (additional === false) {
|
|
3273
|
+
issues.push({
|
|
3274
|
+
path: `${path}.${k}`,
|
|
3275
|
+
expected: "\u672A\u5728 schema \u4E2D\u5B9A\u4E49",
|
|
3276
|
+
received: describe(v),
|
|
3277
|
+
message: `${path}.${k} \u4E0D\u5728\u5141\u8BB8\u5B57\u6BB5\u4E2D`
|
|
3278
|
+
});
|
|
3279
|
+
}
|
|
3280
|
+
continue;
|
|
3281
|
+
}
|
|
3282
|
+
validateProperty(v, propSchema, `${path}.${k}`, issues);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
function validateProperty(value, schema, path, issues) {
|
|
3286
|
+
if (schema.type !== void 0) {
|
|
3287
|
+
const actual = jsonTypeOf(value);
|
|
3288
|
+
if (!typeMatches(actual, schema.type)) {
|
|
3289
|
+
issues.push({
|
|
3290
|
+
path,
|
|
3291
|
+
expected: schema.type,
|
|
3292
|
+
received: describe(value),
|
|
3293
|
+
message: `${path} \u5E94\u4E3A ${schema.type}\uFF0C\u5B9E\u9645\u4E3A ${actual}`
|
|
3294
|
+
});
|
|
3295
|
+
return;
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
if (schema.enum && schema.enum.length > 0) {
|
|
3299
|
+
if (!isScalar(value)) {
|
|
3300
|
+
issues.push({
|
|
3301
|
+
path,
|
|
3302
|
+
expected: `enum[${schema.enum.map((e) => JSON.stringify(e)).join(",")}]`,
|
|
3303
|
+
received: describe(value),
|
|
3304
|
+
message: `${path} \u5E94\u4E3A enum \u503C\u4E4B\u4E00\uFF0C\u5B9E\u9645\u4E3A ${describe(value)}`
|
|
3305
|
+
});
|
|
3306
|
+
} else if (!schema.enum.includes(value)) {
|
|
3307
|
+
issues.push({
|
|
3308
|
+
path,
|
|
3309
|
+
expected: `enum[${schema.enum.map((e) => JSON.stringify(e)).join(",")}]`,
|
|
3310
|
+
received: describe(value),
|
|
3311
|
+
message: `${path} \u5E94\u4E3A enum \u503C\u4E4B\u4E00\uFF0C\u5B9E\u9645\u4E3A ${JSON.stringify(value)}`
|
|
3312
|
+
});
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
if (typeof value === "number") {
|
|
3316
|
+
if (schema.minimum !== void 0 && value < schema.minimum) {
|
|
3317
|
+
issues.push({
|
|
3318
|
+
path,
|
|
3319
|
+
expected: `>= ${schema.minimum}`,
|
|
3320
|
+
received: String(value),
|
|
3321
|
+
message: `${path} \u5E94 >= ${schema.minimum}\uFF0C\u5B9E\u9645\u4E3A ${value}`
|
|
3322
|
+
});
|
|
3323
|
+
}
|
|
3324
|
+
if (schema.maximum !== void 0 && value > schema.maximum) {
|
|
3325
|
+
issues.push({
|
|
3326
|
+
path,
|
|
3327
|
+
expected: `<= ${schema.maximum}`,
|
|
3328
|
+
received: String(value),
|
|
3329
|
+
message: `${path} \u5E94 <= ${schema.maximum}\uFF0C\u5B9E\u9645\u4E3A ${value}`
|
|
3330
|
+
});
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
if (typeof value === "string") {
|
|
3334
|
+
if (schema.minLength !== void 0 && value.length < schema.minLength) {
|
|
3335
|
+
issues.push({
|
|
3336
|
+
path,
|
|
3337
|
+
expected: `length >= ${schema.minLength}`,
|
|
3338
|
+
received: `length ${value.length}`,
|
|
3339
|
+
message: `${path} \u957F\u5EA6\u5E94 >= ${schema.minLength}\uFF0C\u5B9E\u9645\u4E3A ${value.length}`
|
|
3340
|
+
});
|
|
3341
|
+
}
|
|
3342
|
+
if (schema.maxLength !== void 0 && value.length > schema.maxLength) {
|
|
3343
|
+
issues.push({
|
|
3344
|
+
path,
|
|
3345
|
+
expected: `length <= ${schema.maxLength}`,
|
|
3346
|
+
received: `length ${value.length}`,
|
|
3347
|
+
message: `${path} \u957F\u5EA6\u5E94 <= ${schema.maxLength}\uFF0C\u5B9E\u9645\u4E3A ${value.length}`
|
|
3348
|
+
});
|
|
3349
|
+
}
|
|
3350
|
+
if (schema.pattern !== void 0) {
|
|
3351
|
+
try {
|
|
3352
|
+
const re = new RegExp(schema.pattern);
|
|
3353
|
+
if (!re.test(value)) {
|
|
3354
|
+
issues.push({
|
|
3355
|
+
path,
|
|
3356
|
+
expected: `pattern ${schema.pattern}`,
|
|
3357
|
+
received: describe(value),
|
|
3358
|
+
message: `${path} \u4E0D\u5339\u914D pattern ${schema.pattern}`
|
|
3359
|
+
});
|
|
3360
|
+
}
|
|
3361
|
+
} catch {
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
if (schema.properties !== void 0) {
|
|
3366
|
+
validateObject(value, schema, path, issues);
|
|
3367
|
+
}
|
|
3368
|
+
if (schema.items !== void 0 && Array.isArray(value)) {
|
|
3369
|
+
for (let i = 0; i < value.length; i++) {
|
|
3370
|
+
validateProperty(value[i], schema.items, `${path}[${i}]`, issues);
|
|
3371
|
+
}
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
function isPlainObject2(v) {
|
|
3375
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3376
|
+
}
|
|
3377
|
+
function isScalar(v) {
|
|
3378
|
+
return v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean";
|
|
3379
|
+
}
|
|
3380
|
+
function jsonTypeOf(v) {
|
|
3381
|
+
if (v === null) return "null";
|
|
3382
|
+
if (Array.isArray(v)) return "array";
|
|
3383
|
+
if (typeof v === "object") return "object";
|
|
3384
|
+
if (typeof v === "number") return Number.isInteger(v) ? "integer" : "number";
|
|
3385
|
+
return typeof v;
|
|
3386
|
+
}
|
|
3387
|
+
function typeMatches(actual, expected) {
|
|
3388
|
+
if (actual === expected) return true;
|
|
3389
|
+
if (expected === "integer" && actual === "number") return true;
|
|
3390
|
+
if (expected === "number" && actual === "integer") return true;
|
|
3391
|
+
return false;
|
|
3392
|
+
}
|
|
3393
|
+
function describe(v) {
|
|
3394
|
+
if (v === null) return "null";
|
|
3395
|
+
if (v === void 0) return "undefined";
|
|
3396
|
+
if (typeof v === "string") {
|
|
3397
|
+
const s = v.length > 60 ? v.slice(0, 57) + "..." : v;
|
|
3398
|
+
return JSON.stringify(s);
|
|
3399
|
+
}
|
|
3400
|
+
if (typeof v === "number" || typeof v === "boolean") return JSON.stringify(v);
|
|
3401
|
+
if (Array.isArray(v)) return `array(len=${v.length})`;
|
|
3402
|
+
if (typeof v === "object") {
|
|
3403
|
+
const keys = Object.keys(v);
|
|
3404
|
+
return `object{keys=${keys.length}}`;
|
|
3405
|
+
}
|
|
3406
|
+
return typeof v;
|
|
3407
|
+
}
|
|
3408
|
+
|
|
2436
3409
|
// src/agent/tool-executor.ts
|
|
2437
3410
|
var ToolExecutor = class {
|
|
2438
3411
|
/** 工具注册表(只读引用) */
|
|
@@ -2559,11 +3532,38 @@ var ToolExecutor = class {
|
|
|
2559
3532
|
record: { name: toolName, success: false, error: "TOOL_NOT_FOUND", timestamp }
|
|
2560
3533
|
};
|
|
2561
3534
|
}
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
3535
|
+
const parsed = parseToolCallArgs(tc.arguments ?? "");
|
|
3536
|
+
if (!parsed.ok) {
|
|
3537
|
+
if (parsed.reason === "PARTIAL") {
|
|
3538
|
+
const errMsg2 = `\u5DE5\u5177 "${toolName}" \u53C2\u6570\u5C1A\u672A\u6536\u5168\uFF0C\u672C\u8F6E\u8DF3\u8FC7\uFF08\u6D41\u5F0F\u5206\u7247\u5BFC\u81F4\uFF09\uFF1A${parsed.hint}`;
|
|
3539
|
+
return {
|
|
3540
|
+
item: {
|
|
3541
|
+
name: toolName,
|
|
3542
|
+
callId: tc.id,
|
|
3543
|
+
result: { success: false, data: errMsg2, error: "PARTIAL_JSON" }
|
|
3544
|
+
},
|
|
3545
|
+
record: { name: toolName, success: false, error: "PARTIAL_JSON", timestamp }
|
|
3546
|
+
};
|
|
3547
|
+
}
|
|
3548
|
+
const errMsg = `\u5DE5\u5177 "${toolName}" \u53C2\u6570\u4E0D\u662F\u5408\u6CD5 JSON\uFF1A${parsed.error}
|
|
3549
|
+
\u539F\u6587: ${parsed.raw.slice(0, 200)}`;
|
|
3550
|
+
return {
|
|
3551
|
+
item: {
|
|
3552
|
+
name: toolName,
|
|
3553
|
+
callId: tc.id,
|
|
3554
|
+
result: { success: false, data: errMsg, error: "INVALID_JSON" }
|
|
3555
|
+
},
|
|
3556
|
+
record: { name: toolName, success: false, error: "INVALID_JSON", timestamp }
|
|
3557
|
+
};
|
|
3558
|
+
}
|
|
3559
|
+
const toolArgs = parsed.args;
|
|
3560
|
+
let schemaIssues;
|
|
3561
|
+
const schemaToCheck = tool.schema ?? tool.parameters;
|
|
3562
|
+
if (schemaToCheck) {
|
|
3563
|
+
const validation = validateArgs(toolArgs, schemaToCheck);
|
|
3564
|
+
if (!validation.ok) {
|
|
3565
|
+
schemaIssues = validation.issues;
|
|
3566
|
+
}
|
|
2567
3567
|
}
|
|
2568
3568
|
const gateResult = await this.#gate.check(toolName, toolArgs);
|
|
2569
3569
|
if (!gateResult) {
|
|
@@ -2583,10 +3583,29 @@ var ToolExecutor = class {
|
|
|
2583
3583
|
}
|
|
2584
3584
|
}
|
|
2585
3585
|
try {
|
|
2586
|
-
|
|
3586
|
+
let result = await this.#invokeTool(tool, toolArgs);
|
|
3587
|
+
if (schemaIssues && schemaIssues.length > 0) {
|
|
3588
|
+
const issuesText = schemaIssues.map((i) => ` - ${i.message}`).join("\n");
|
|
3589
|
+
const tag = result.success ? "[schema \u8B66\u544A]" : "[schema \u95EE\u9898]";
|
|
3590
|
+
result = {
|
|
3591
|
+
...result,
|
|
3592
|
+
data: `${result.data}
|
|
3593
|
+
|
|
3594
|
+
${tag} \u53C2\u6570\u4E0D\u7B26\u5408 schema\uFF1A
|
|
3595
|
+
${issuesText}`,
|
|
3596
|
+
issues: schemaIssues
|
|
3597
|
+
};
|
|
3598
|
+
}
|
|
3599
|
+
const record = {
|
|
3600
|
+
name: toolName,
|
|
3601
|
+
success: result.success,
|
|
3602
|
+
error: result.error,
|
|
3603
|
+
timestamp,
|
|
3604
|
+
...schemaIssues ? { issues: schemaIssues } : {}
|
|
3605
|
+
};
|
|
2587
3606
|
return {
|
|
2588
3607
|
item: { name: toolName, callId: tc.id, result },
|
|
2589
|
-
record
|
|
3608
|
+
record
|
|
2590
3609
|
};
|
|
2591
3610
|
} catch (err) {
|
|
2592
3611
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -2685,7 +3704,7 @@ var Reflector = class {
|
|
|
2685
3704
|
const reflections = [];
|
|
2686
3705
|
for (const item of items) {
|
|
2687
3706
|
if (item.result.success) continue;
|
|
2688
|
-
const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#ruleTextNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots);
|
|
3707
|
+
const r = this.#ruleRepeatedFailure(item) ?? this.#ruleFileNotFound(item) ?? this.#ruleTextNotFound(item) ?? this.#rulePermissionDenied(item) ?? this.#ruleOutOfWriteRoot(item, ctx.writeRoots) ?? this.#ruleInvalidArgs(item);
|
|
2689
3708
|
if (r) reflections.push(r);
|
|
2690
3709
|
if (reflections.length >= this.#maxReflections) break;
|
|
2691
3710
|
}
|
|
@@ -2827,6 +3846,25 @@ var Reflector = class {
|
|
|
2827
3846
|
if (text.length <= this.#maxHintChars) return text;
|
|
2828
3847
|
return text.slice(0, this.#maxHintChars - 3) + "...";
|
|
2829
3848
|
}
|
|
3849
|
+
/**
|
|
3850
|
+
* R5 INVALID_ARGS:参数不符合工具的 JSON Schema。
|
|
3851
|
+
*
|
|
3852
|
+
* 阶段 2 新增:tool-executor 校验后会把 issues 放进 result.issues,
|
|
3853
|
+
* 这里读取并生成反思。注意是 warn-only,不阻塞工具继续执行。
|
|
3854
|
+
*
|
|
3855
|
+
* @pure 仅读入参
|
|
3856
|
+
*/
|
|
3857
|
+
#ruleInvalidArgs(item) {
|
|
3858
|
+
const issues = item.result.issues;
|
|
3859
|
+
if (!issues || issues.length === 0) return null;
|
|
3860
|
+
const shown = issues.slice(0, 3).map((i) => i.message).join("; ");
|
|
3861
|
+
const more = issues.length > 3 ? `\uFF08\u53E6\u6709 ${issues.length - 3} \u6761\uFF09` : "";
|
|
3862
|
+
return {
|
|
3863
|
+
category: "invalid_args",
|
|
3864
|
+
toolName: item.name,
|
|
3865
|
+
hint: `\`${item.name}\` \u53C2\u6570\u4E0D\u7B26\u5408 schema\uFF1A${shown}${more}\u3002\u8BF7\u68C0\u67E5\u5FC5\u586B\u5B57\u6BB5\u3001\u7C7B\u578B\u4E0E enum \u767D\u540D\u5355\u3002`
|
|
3866
|
+
};
|
|
3867
|
+
}
|
|
2830
3868
|
};
|
|
2831
3869
|
|
|
2832
3870
|
// src/agent/tool-definitions.ts
|
|
@@ -3342,7 +4380,12 @@ async function restoreToClean(cwd) {
|
|
|
3342
4380
|
async function discardCheckpoint(checkpoint) {
|
|
3343
4381
|
if (!checkpoint.isGitRepo || !checkpoint.stashSha) return;
|
|
3344
4382
|
const { cwd, stashSha } = checkpoint;
|
|
3345
|
-
|
|
4383
|
+
let shas;
|
|
4384
|
+
try {
|
|
4385
|
+
shas = await listStashShas(cwd);
|
|
4386
|
+
} catch {
|
|
4387
|
+
return;
|
|
4388
|
+
}
|
|
3346
4389
|
const idx = shas.indexOf(stashSha);
|
|
3347
4390
|
if (idx < 0) return;
|
|
3348
4391
|
try {
|
|
@@ -3539,11 +4582,19 @@ var ConversationLogger = class _ConversationLogger {
|
|
|
3539
4582
|
this.log({ ts: Date.now(), type: "reasoning", content, round });
|
|
3540
4583
|
}
|
|
3541
4584
|
/** 记录工具调用 */
|
|
3542
|
-
logToolCall(name, callId, args, round) {
|
|
3543
|
-
this.log({
|
|
4585
|
+
logToolCall(name, callId, args, round, parsedArgs) {
|
|
4586
|
+
this.log({
|
|
4587
|
+
ts: Date.now(),
|
|
4588
|
+
type: "tool_call",
|
|
4589
|
+
name,
|
|
4590
|
+
callId,
|
|
4591
|
+
arguments: args,
|
|
4592
|
+
...parsedArgs !== void 0 ? { parsedArgs } : {},
|
|
4593
|
+
round
|
|
4594
|
+
});
|
|
3544
4595
|
}
|
|
3545
4596
|
/** 记录工具结果 */
|
|
3546
|
-
logToolResult(name, callId, success, data, error, elapsed, round) {
|
|
4597
|
+
logToolResult(name, callId, success, data, error, elapsed, round, schemaIssues) {
|
|
3547
4598
|
this.log({
|
|
3548
4599
|
ts: Date.now(),
|
|
3549
4600
|
type: "tool_result",
|
|
@@ -3553,6 +4604,7 @@ var ConversationLogger = class _ConversationLogger {
|
|
|
3553
4604
|
data: truncate(data),
|
|
3554
4605
|
...error ? { error } : {},
|
|
3555
4606
|
...elapsed !== void 0 ? { elapsed } : {},
|
|
4607
|
+
...schemaIssues ? { schemaIssues } : {},
|
|
3556
4608
|
round
|
|
3557
4609
|
});
|
|
3558
4610
|
}
|
|
@@ -3716,13 +4768,17 @@ var Session = class _Session {
|
|
|
3716
4768
|
maxToolRounds: options?.maxToolRounds ?? 20,
|
|
3717
4769
|
reservedForOutput: options?.reservedForOutput ?? 4096,
|
|
3718
4770
|
preserveRecentRounds: options?.preserveRecentRounds ?? 10,
|
|
4771
|
+
autoCompactRatio: options?.autoCompactRatio ?? DEFAULT_AUTO_COMPACT_RATIO,
|
|
4772
|
+
preserveRecentRoundsOnCompact: options?.preserveRecentRoundsOnCompact ?? DEFAULT_PRESERVE_ROUNDS,
|
|
4773
|
+
minTurnsToCompact: options?.minTurnsToCompact ?? DEFAULT_MIN_TURNS_TO_COMPACT,
|
|
3719
4774
|
projectContext: options?.projectContext,
|
|
3720
4775
|
gate: options?.gate ?? new AlwaysAllowGate(),
|
|
3721
4776
|
writeRoots: options?.writeRoots ?? [options?.cwd ?? process.cwd()],
|
|
3722
4777
|
enableCheckpoint: options?.enableCheckpoint ?? true,
|
|
3723
4778
|
enableLog: options?.enableLog ?? true,
|
|
3724
4779
|
enableReflection: options?.enableReflection !== false,
|
|
3725
|
-
enableHarness: options?.enableHarness !== false
|
|
4780
|
+
enableHarness: options?.enableHarness !== false,
|
|
4781
|
+
enableAutoCompact: options?.enableAutoCompact !== false
|
|
3726
4782
|
};
|
|
3727
4783
|
this.#sessionId = options?.sessionId ?? SessionStore.newId();
|
|
3728
4784
|
this.#store = options?.store === false ? null : options?.store ?? new SessionStore();
|
|
@@ -3823,6 +4879,19 @@ var Session = class _Session {
|
|
|
3823
4879
|
} catch {
|
|
3824
4880
|
}
|
|
3825
4881
|
}
|
|
4882
|
+
if (this.#options.enableAutoCompact) {
|
|
4883
|
+
const compaction = await this.#maybeAutoCompact();
|
|
4884
|
+
if (compaction) {
|
|
4885
|
+
yield {
|
|
4886
|
+
type: "compaction",
|
|
4887
|
+
droppedTurns: compaction.droppedTurns,
|
|
4888
|
+
keptTurns: compaction.keptTurns,
|
|
4889
|
+
beforeTokens: compaction.beforeTokens,
|
|
4890
|
+
afterTokens: compaction.afterTokens,
|
|
4891
|
+
strategy: compaction.strategy
|
|
4892
|
+
};
|
|
4893
|
+
}
|
|
4894
|
+
}
|
|
3826
4895
|
const startTime = Date.now();
|
|
3827
4896
|
let toolRounds = 0;
|
|
3828
4897
|
const toolExecutor = this.#buildToolExecutor();
|
|
@@ -4077,6 +5146,79 @@ ${item.result.diff.patch}`;
|
|
|
4077
5146
|
this.#checkpoints.clear();
|
|
4078
5147
|
this.#lastRoundResults = null;
|
|
4079
5148
|
}
|
|
5149
|
+
// -------------------------------------------------------------------------
|
|
5150
|
+
// 上下文压缩(Compactor) — P0-1 实施
|
|
5151
|
+
// -------------------------------------------------------------------------
|
|
5152
|
+
/**
|
|
5153
|
+
* 获取当前上下文的统计信息(消息数、估算 token、占窗口比例)。
|
|
5154
|
+
* 用于 UI 状态栏展示和自动压缩阈值判断。
|
|
5155
|
+
*
|
|
5156
|
+
* @returns ContextStats;contextWindow 取自当前模型的 meta.contextWindow
|
|
5157
|
+
*
|
|
5158
|
+
* @pure 不修改任何状态
|
|
5159
|
+
*/
|
|
5160
|
+
getContextStats() {
|
|
5161
|
+
const meta = getModelMeta(this.#provider.model());
|
|
5162
|
+
return getContextStats(this.#messages, meta.contextWindow);
|
|
5163
|
+
}
|
|
5164
|
+
/**
|
|
5165
|
+
* 手动触发上下文压缩。
|
|
5166
|
+
* 与自动压缩逻辑复用同一个 compactContext();若回合数过少则返回空结果(droppedTurns=0)。
|
|
5167
|
+
* 可被 UI 的 /compact 命令调用。
|
|
5168
|
+
*
|
|
5169
|
+
* @param onProgress — 可选进度回调(UI 实时展示压缩进度)
|
|
5170
|
+
* @returns 压缩结果;droppedTurns=0 表示无实际压缩发生
|
|
5171
|
+
*
|
|
5172
|
+
* @sideEffect 可能调一次 provider.chat()(LLM 摘要);成功后改写 #messages
|
|
5173
|
+
*/
|
|
5174
|
+
async compact(onProgress) {
|
|
5175
|
+
const meta = getModelMeta(this.#provider.model());
|
|
5176
|
+
const result = await compactContext(this.#messages, {
|
|
5177
|
+
contextWindow: meta.contextWindow,
|
|
5178
|
+
autoCompactRatio: this.#options.autoCompactRatio,
|
|
5179
|
+
preserveRecentRounds: this.#options.preserveRecentRoundsOnCompact,
|
|
5180
|
+
minTurnsToCompact: this.#options.minTurnsToCompact,
|
|
5181
|
+
provider: this.#provider,
|
|
5182
|
+
signal: this.#abortController.signal,
|
|
5183
|
+
...onProgress ? { onProgress } : {}
|
|
5184
|
+
});
|
|
5185
|
+
if (result.droppedTurns > 0) {
|
|
5186
|
+
this.#messages.length = 0;
|
|
5187
|
+
for (const m of result.messages) this.#messages.push(m);
|
|
5188
|
+
this.#checkpoints.clear();
|
|
5189
|
+
this.#persist();
|
|
5190
|
+
}
|
|
5191
|
+
return result;
|
|
5192
|
+
}
|
|
5193
|
+
/**
|
|
5194
|
+
* chat() 入口调用的自动压缩检查。
|
|
5195
|
+
* 仅在 enableAutoCompact=true 且应自动压缩时执行;否则返回 null。
|
|
5196
|
+
* 策略与 compact() 相同;返回值额外补上 strategy("summary" | "fallback")供 chat 事件使用。
|
|
5197
|
+
*
|
|
5198
|
+
* @returns 压缩结果;未压缩时返回 null
|
|
5199
|
+
*
|
|
5200
|
+
* @sideEffect 同 compact()
|
|
5201
|
+
*/
|
|
5202
|
+
async #maybeAutoCompact() {
|
|
5203
|
+
const meta = getModelMeta(this.#provider.model());
|
|
5204
|
+
const opts = {
|
|
5205
|
+
contextWindow: meta.contextWindow,
|
|
5206
|
+
autoCompactRatio: this.#options.autoCompactRatio,
|
|
5207
|
+
preserveRecentRounds: this.#options.preserveRecentRoundsOnCompact,
|
|
5208
|
+
minTurnsToCompact: this.#options.minTurnsToCompact,
|
|
5209
|
+
provider: this.#provider,
|
|
5210
|
+
signal: this.#abortController.signal
|
|
5211
|
+
};
|
|
5212
|
+
if (!shouldAutoCompact(this.#messages, opts)) return null;
|
|
5213
|
+
const result = await compactContext(this.#messages, opts);
|
|
5214
|
+
if (result.droppedTurns === 0) return null;
|
|
5215
|
+
const strategy = result.summary.includes("\u672C\u5730\u6458\u8981") ? "fallback" : "summary";
|
|
5216
|
+
this.#messages.length = 0;
|
|
5217
|
+
for (const m of result.messages) this.#messages.push(m);
|
|
5218
|
+
this.#checkpoints.clear();
|
|
5219
|
+
this.#persist();
|
|
5220
|
+
return { ...result, strategy };
|
|
5221
|
+
}
|
|
4080
5222
|
/**
|
|
4081
5223
|
* 立即把当前状态写入持久化(不等 500ms debounce)。
|
|
4082
5224
|
* 用于 UI 上"立即保存"按钮或异常退出前的最后兜底。
|
|
@@ -5913,9 +7055,9 @@ function joinReasoningSegments(segments) {
|
|
|
5913
7055
|
}
|
|
5914
7056
|
|
|
5915
7057
|
// src/ui/AnimatedLogo.tsx
|
|
5916
|
-
import { Box as
|
|
7058
|
+
import { Box as Box11, Text as Text12 } from "ink";
|
|
5917
7059
|
import { useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
|
|
5918
|
-
import { jsx as
|
|
7060
|
+
import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
5919
7061
|
var LOGO_LINES2 = [
|
|
5920
7062
|
" \u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2584 \u2584\u2584",
|
|
5921
7063
|
" \u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\u2584\u2580\u2588\u2588\u2588\u2580\u2580",
|
|
@@ -5944,14 +7086,14 @@ function AnimatedLogo({ panelWidth }) {
|
|
|
5944
7086
|
const leftClip = Math.max(0, -pos);
|
|
5945
7087
|
const rightClip = Math.max(0, pos + LOGO_WIDTH - panelWidth);
|
|
5946
7088
|
const padding = Math.max(0, pos);
|
|
5947
|
-
return /* @__PURE__ */
|
|
7089
|
+
return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", alignItems: "flex-start", children: LOGO_LINES2.map((line, i) => /* @__PURE__ */ jsxs11(Text12, { color: LOGO_COLOR, bold: true, children: [
|
|
5948
7090
|
" ".repeat(padding),
|
|
5949
7091
|
line.slice(leftClip, LOGO_WIDTH - rightClip)
|
|
5950
7092
|
] }, i)) });
|
|
5951
7093
|
}
|
|
5952
7094
|
|
|
5953
7095
|
// src/ui/ChatSession.tsx
|
|
5954
|
-
import { Fragment as
|
|
7096
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
5955
7097
|
var PHASE_CONFIG = {
|
|
5956
7098
|
thinking: { icon: "\u{1F9E0}", label: "\u601D\u8003\u4E2D", color: "#ff9800" },
|
|
5957
7099
|
generating: { icon: "\u2728", label: "\u751F\u6210\u4E2D", color: "#00ff41" },
|
|
@@ -6026,6 +7168,13 @@ registerCommand("/rewind", {
|
|
|
6026
7168
|
content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /rewind \u67E5\u770B\u53EF\u56DE\u9000\u7684\u68C0\u67E5\u70B9\u5217\u8868\uFF0C\u6216 /rewind <\u5E8F\u53F7> \u76F4\u63A5\u56DE\u9000\uFF081 = \u6700\u65B0\uFF0C2 = \u4E0A\u4E00\u6B21\uFF0C\u4F9D\u6B64\u7C7B\u63A8\uFF09"
|
|
6027
7169
|
})
|
|
6028
7170
|
});
|
|
7171
|
+
registerCommand("/compact", {
|
|
7172
|
+
desc: "\u538B\u7F29\u4E0A\u4E0B\u6587\uFF1A\u6458\u8981\u65E7\u56DE\u5408\u5E76\u4FDD\u7559\u6700\u8FD1 N \u8F6E",
|
|
7173
|
+
handler: () => ({
|
|
7174
|
+
kind: "text",
|
|
7175
|
+
content: "\u8BF7\u76F4\u63A5\u8F93\u5165 /compact \u624B\u52A8\u538B\u7F29\u4E0A\u4E0B\u6587\uFF08\u9700\u5F53\u524D\u4E0D\u5904\u4E8E\u751F\u6210\u4E2D\uFF09"
|
|
7176
|
+
})
|
|
7177
|
+
});
|
|
6029
7178
|
var STREAMING_PLACEHOLDERS = [
|
|
6030
7179
|
"\u8BA9\u5B50\u5F39\u98DE\u4E00\u4F1A\u513F...",
|
|
6031
7180
|
"\u9A6C\u4E0A\u5C31\u597D...",
|
|
@@ -6069,6 +7218,7 @@ function ChatSession({
|
|
|
6069
7218
|
const [balance, setBalance] = useState5(null);
|
|
6070
7219
|
const [balanceLoading, setBalanceLoading] = useState5(false);
|
|
6071
7220
|
const [todayCost, setTodayCost] = useState5(null);
|
|
7221
|
+
const [contextStats, setContextStats] = useState5(null);
|
|
6072
7222
|
const [isStreaming, setIsStreaming] = useState5(false);
|
|
6073
7223
|
const [streamingPhase, setStreamingPhase] = useState5(null);
|
|
6074
7224
|
const [streamingPlaceholder, setStreamingPlaceholder] = useState5("");
|
|
@@ -6099,7 +7249,7 @@ function ChatSession({
|
|
|
6099
7249
|
const [toolChoice, setToolChoice] = useState5(
|
|
6100
7250
|
void 0
|
|
6101
7251
|
);
|
|
6102
|
-
const sessionCost =
|
|
7252
|
+
const sessionCost = useMemo2(() => {
|
|
6103
7253
|
return displayMessages.reduce((sum, msg) => {
|
|
6104
7254
|
if (msg.assistantDetail?.cost) {
|
|
6105
7255
|
return sum + msg.assistantDetail.cost;
|
|
@@ -6128,6 +7278,12 @@ function ChatSession({
|
|
|
6128
7278
|
const [selectingModel, setSelectingModel] = useState5(false);
|
|
6129
7279
|
const [modelSelectIndex, setModelSelectIndex] = useState5(0);
|
|
6130
7280
|
const modelOptions = ["deepseek-v4-flash", "deepseek-v4-pro"];
|
|
7281
|
+
const [compactionState, setCompactionState] = useState5({
|
|
7282
|
+
phase: "idle",
|
|
7283
|
+
progress: null
|
|
7284
|
+
});
|
|
7285
|
+
const compactionSettleTimerRef = useRef4(null);
|
|
7286
|
+
const compactionStrategyRef = useRef4(void 0);
|
|
6131
7287
|
const sessionRef = useRef4(null);
|
|
6132
7288
|
const abortRef = useRef4(null);
|
|
6133
7289
|
const currentContentRef = useRef4("");
|
|
@@ -6148,7 +7304,33 @@ function ChatSession({
|
|
|
6148
7304
|
clearTimeout(rewindHintTimerRef.current);
|
|
6149
7305
|
rewindHintTimerRef.current = null;
|
|
6150
7306
|
}
|
|
7307
|
+
if (compactionSettleTimerRef.current) {
|
|
7308
|
+
clearTimeout(compactionSettleTimerRef.current);
|
|
7309
|
+
compactionSettleTimerRef.current = null;
|
|
7310
|
+
}
|
|
7311
|
+
};
|
|
7312
|
+
}, []);
|
|
7313
|
+
useEffect5(() => {
|
|
7314
|
+
const refresh = () => {
|
|
7315
|
+
const session = sessionRef.current;
|
|
7316
|
+
if (!session) {
|
|
7317
|
+
setContextStats(null);
|
|
7318
|
+
return;
|
|
7319
|
+
}
|
|
7320
|
+
try {
|
|
7321
|
+
const s = session.getContextStats();
|
|
7322
|
+
setContextStats({
|
|
7323
|
+
tokens: s.estimatedTokens,
|
|
7324
|
+
ratio: s.ratio,
|
|
7325
|
+
contextWindow: s.contextWindow
|
|
7326
|
+
});
|
|
7327
|
+
} catch {
|
|
7328
|
+
setContextStats(null);
|
|
7329
|
+
}
|
|
6151
7330
|
};
|
|
7331
|
+
refresh();
|
|
7332
|
+
const id = setInterval(refresh, 3e3);
|
|
7333
|
+
return () => clearInterval(id);
|
|
6152
7334
|
}, []);
|
|
6153
7335
|
useEffect5(() => {
|
|
6154
7336
|
if (todoHideTimerRef.current) {
|
|
@@ -6641,6 +7823,146 @@ function ChatSession({
|
|
|
6641
7823
|
setInput("");
|
|
6642
7824
|
return;
|
|
6643
7825
|
}
|
|
7826
|
+
if (cmdLower === "/compact") {
|
|
7827
|
+
if (isStreaming) {
|
|
7828
|
+
setDisplayMessages((prev) => [
|
|
7829
|
+
...prev,
|
|
7830
|
+
{ role: "user", content: trimmed },
|
|
7831
|
+
{ role: "assistant", content: "\u26A0 \u6B63\u5728\u751F\u6210\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5 /compact\u3002" }
|
|
7832
|
+
]);
|
|
7833
|
+
setInput("");
|
|
7834
|
+
return;
|
|
7835
|
+
}
|
|
7836
|
+
if (!sessionRef.current) {
|
|
7837
|
+
setDisplayMessages((prev) => [
|
|
7838
|
+
...prev,
|
|
7839
|
+
{ role: "user", content: trimmed },
|
|
7840
|
+
{ role: "assistant", content: "\u26A0 Session \u672A\u5C31\u7EEA\uFF0C\u65E0\u6CD5\u538B\u7F29\u3002" }
|
|
7841
|
+
]);
|
|
7842
|
+
setInput("");
|
|
7843
|
+
return;
|
|
7844
|
+
}
|
|
7845
|
+
setInput("");
|
|
7846
|
+
setDisplayMessages((prev) => [...prev, { role: "user", content: trimmed }]);
|
|
7847
|
+
setCompactionState({
|
|
7848
|
+
phase: "running",
|
|
7849
|
+
progress: null,
|
|
7850
|
+
beforeTokens: void 0,
|
|
7851
|
+
afterTokens: void 0,
|
|
7852
|
+
droppedTurns: void 0,
|
|
7853
|
+
keptTurns: void 0,
|
|
7854
|
+
strategy: void 0,
|
|
7855
|
+
errorMessage: void 0
|
|
7856
|
+
});
|
|
7857
|
+
try {
|
|
7858
|
+
const result = await sessionRef.current.compact(
|
|
7859
|
+
(event) => {
|
|
7860
|
+
setCompactionState((prev) => {
|
|
7861
|
+
if (event.type === "start") {
|
|
7862
|
+
return {
|
|
7863
|
+
...prev,
|
|
7864
|
+
phase: "running",
|
|
7865
|
+
progress: event,
|
|
7866
|
+
beforeTokens: event.beforeTokens,
|
|
7867
|
+
droppedTurns: event.droppedTurns
|
|
7868
|
+
};
|
|
7869
|
+
}
|
|
7870
|
+
if (event.type === "summary_delta") {
|
|
7871
|
+
return {
|
|
7872
|
+
...prev,
|
|
7873
|
+
phase: "running",
|
|
7874
|
+
progress: event
|
|
7875
|
+
};
|
|
7876
|
+
}
|
|
7877
|
+
if (event.type === "fallback") {
|
|
7878
|
+
compactionStrategyRef.current = "fallback";
|
|
7879
|
+
return {
|
|
7880
|
+
...prev,
|
|
7881
|
+
phase: "running",
|
|
7882
|
+
progress: event,
|
|
7883
|
+
strategy: "fallback"
|
|
7884
|
+
};
|
|
7885
|
+
}
|
|
7886
|
+
if (event.type === "done") {
|
|
7887
|
+
const finalStrategy = compactionStrategyRef.current === "fallback" ? "fallback" : "summary";
|
|
7888
|
+
compactionStrategyRef.current = finalStrategy;
|
|
7889
|
+
return {
|
|
7890
|
+
...prev,
|
|
7891
|
+
phase: "done",
|
|
7892
|
+
progress: event,
|
|
7893
|
+
droppedTurns: event.droppedTurns,
|
|
7894
|
+
keptTurns: event.keptTurns,
|
|
7895
|
+
beforeTokens: event.beforeTokens,
|
|
7896
|
+
afterTokens: event.afterTokens,
|
|
7897
|
+
strategy: finalStrategy
|
|
7898
|
+
};
|
|
7899
|
+
}
|
|
7900
|
+
return prev;
|
|
7901
|
+
});
|
|
7902
|
+
}
|
|
7903
|
+
);
|
|
7904
|
+
if (result.droppedTurns === 0) {
|
|
7905
|
+
setCompactionState((prev) => ({
|
|
7906
|
+
...prev,
|
|
7907
|
+
phase: "done",
|
|
7908
|
+
progress: prev.progress,
|
|
7909
|
+
droppedTurns: 0,
|
|
7910
|
+
keptTurns: result.keptTurns,
|
|
7911
|
+
beforeTokens: result.beforeTokens,
|
|
7912
|
+
afterTokens: result.afterTokens,
|
|
7913
|
+
strategy: void 0
|
|
7914
|
+
}));
|
|
7915
|
+
if (compactionSettleTimerRef.current) {
|
|
7916
|
+
clearTimeout(compactionSettleTimerRef.current);
|
|
7917
|
+
}
|
|
7918
|
+
compactionSettleTimerRef.current = setTimeout(() => {
|
|
7919
|
+
setCompactionState({ phase: "idle", progress: null });
|
|
7920
|
+
setDisplayMessages((prev) => [
|
|
7921
|
+
...prev,
|
|
7922
|
+
{
|
|
7923
|
+
role: "assistant",
|
|
7924
|
+
content: "\u2139 \u5F53\u524D\u5BF9\u8BDD\u592A\u77ED\uFF0C\u65E0\u9700\u538B\u7F29\uFF08\u5C11\u4E8E\u6700\u5C0F\u56DE\u5408\u6570 \u6216 \u90FD\u5728\u4FDD\u7559\u533A\u5185\uFF09\u3002"
|
|
7925
|
+
}
|
|
7926
|
+
]);
|
|
7927
|
+
}, 2500);
|
|
7928
|
+
} else {
|
|
7929
|
+
if (compactionSettleTimerRef.current) {
|
|
7930
|
+
clearTimeout(compactionSettleTimerRef.current);
|
|
7931
|
+
}
|
|
7932
|
+
compactionSettleTimerRef.current = setTimeout(() => {
|
|
7933
|
+
const ratioSaved = ((result.beforeTokens - result.afterTokens) / Math.max(result.beforeTokens, 1) * 100).toFixed(1);
|
|
7934
|
+
const strategyNote = compactionStrategyRef.current === "fallback" ? "\n\u26A0 \u6458\u8981\u4E3A\u672C\u5730\u5151\u5E95\uFF08LLM \u4E0D\u53EF\u7528\uFF09" : "";
|
|
7935
|
+
setCompactionState({ phase: "idle", progress: null });
|
|
7936
|
+
compactionStrategyRef.current = void 0;
|
|
7937
|
+
setDisplayMessages((prev) => [
|
|
7938
|
+
...prev,
|
|
7939
|
+
{
|
|
7940
|
+
role: "assistant",
|
|
7941
|
+
content: `\u2714 \u538B\u7F29\u5B8C\u6210\uFF1A${result.droppedTurns} \u56DE\u5408 \u2192 ${result.keptTurns} \u56DE\u5408\uFF08\u8282\u7701 ${ratioSaved}% token\uFF09${strategyNote}`
|
|
7942
|
+
}
|
|
7943
|
+
]);
|
|
7944
|
+
}, 4e3);
|
|
7945
|
+
}
|
|
7946
|
+
} catch (err) {
|
|
7947
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
7948
|
+
setCompactionState((prev) => ({
|
|
7949
|
+
...prev,
|
|
7950
|
+
phase: "error",
|
|
7951
|
+
errorMessage: msg
|
|
7952
|
+
}));
|
|
7953
|
+
if (compactionSettleTimerRef.current) {
|
|
7954
|
+
clearTimeout(compactionSettleTimerRef.current);
|
|
7955
|
+
}
|
|
7956
|
+
compactionSettleTimerRef.current = setTimeout(() => {
|
|
7957
|
+
setCompactionState({ phase: "idle", progress: null });
|
|
7958
|
+
setDisplayMessages((prev) => [
|
|
7959
|
+
...prev,
|
|
7960
|
+
{ role: "assistant", content: `\u26A0 \u538B\u7F29\u5931\u8D25\uFF1A${msg}` }
|
|
7961
|
+
]);
|
|
7962
|
+
}, 3e3);
|
|
7963
|
+
}
|
|
7964
|
+
return;
|
|
7965
|
+
}
|
|
6644
7966
|
if (cmdLower === "/model") {
|
|
6645
7967
|
const curIdx = modelOptions.indexOf(activeModel);
|
|
6646
7968
|
setModelSelectIndex(curIdx >= 0 ? curIdx : 0);
|
|
@@ -6829,6 +8151,12 @@ function ChatSession({
|
|
|
6829
8151
|
todoHideTimerRef.current = null;
|
|
6830
8152
|
}
|
|
6831
8153
|
setTodoPanelVisible(false);
|
|
8154
|
+
setCompactionState({ phase: "idle", progress: null });
|
|
8155
|
+
compactionStrategyRef.current = void 0;
|
|
8156
|
+
if (compactionSettleTimerRef.current) {
|
|
8157
|
+
clearTimeout(compactionSettleTimerRef.current);
|
|
8158
|
+
compactionSettleTimerRef.current = null;
|
|
8159
|
+
}
|
|
6832
8160
|
const session = sessionRef.current;
|
|
6833
8161
|
const abortController = new AbortController();
|
|
6834
8162
|
abortRef.current = abortController;
|
|
@@ -7002,16 +8330,16 @@ function ChatSession({
|
|
|
7002
8330
|
setTodayCost(externalCostTracker.todayTotalCost);
|
|
7003
8331
|
}
|
|
7004
8332
|
}, [isStreaming, externalCostTracker]);
|
|
7005
|
-
return /* @__PURE__ */
|
|
7006
|
-
/* @__PURE__ */
|
|
7007
|
-
/* @__PURE__ */
|
|
7008
|
-
|
|
8333
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
|
|
8334
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", flexGrow: 1, children: [
|
|
8335
|
+
/* @__PURE__ */ jsx12(
|
|
8336
|
+
Box12,
|
|
7009
8337
|
{
|
|
7010
8338
|
width: leftPanelWidth,
|
|
7011
8339
|
flexShrink: 0,
|
|
7012
8340
|
flexDirection: "column",
|
|
7013
|
-
children: /* @__PURE__ */
|
|
7014
|
-
|
|
8341
|
+
children: /* @__PURE__ */ jsx12(
|
|
8342
|
+
Box12,
|
|
7015
8343
|
{
|
|
7016
8344
|
paddingX: 1,
|
|
7017
8345
|
flexDirection: "column",
|
|
@@ -7019,51 +8347,51 @@ function ChatSession({
|
|
|
7019
8347
|
justifyContent: !hasConversationStarted ? "center" : "flex-end",
|
|
7020
8348
|
children: !hasConversationStarted ? (
|
|
7021
8349
|
/* ===== 首页:Logo + 状态概况 ===== */
|
|
7022
|
-
/* @__PURE__ */
|
|
8350
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", alignItems: "center", children: [
|
|
7023
8351
|
LOGO_LINES.map((line, i) => {
|
|
7024
8352
|
const colorIndex = (i + offset) % CYBER_PALETTE.length;
|
|
7025
|
-
return /* @__PURE__ */
|
|
8353
|
+
return /* @__PURE__ */ jsx12(Text13, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }, i);
|
|
7026
8354
|
}),
|
|
7027
|
-
/* @__PURE__ */
|
|
8355
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
|
|
7028
8356
|
"\u{1F4E6} v",
|
|
7029
8357
|
VERSION
|
|
7030
8358
|
] }) }),
|
|
7031
|
-
/* @__PURE__ */
|
|
7032
|
-
/* @__PURE__ */
|
|
8359
|
+
/* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
|
|
8360
|
+
/* @__PURE__ */ jsxs12(Text13, { color: "#00ff41", children: [
|
|
7033
8361
|
"\u2714 ",
|
|
7034
8362
|
skillCount,
|
|
7035
8363
|
" Skills"
|
|
7036
8364
|
] }),
|
|
7037
|
-
/* @__PURE__ */
|
|
8365
|
+
/* @__PURE__ */ jsxs12(Text13, { color: "#00ffff", children: [
|
|
7038
8366
|
"\u2139 ",
|
|
7039
8367
|
toolCount,
|
|
7040
8368
|
" \u5DE5\u5177"
|
|
7041
8369
|
] }),
|
|
7042
|
-
/* @__PURE__ */
|
|
8370
|
+
/* @__PURE__ */ jsxs12(Text13, { color: "#00ffff", children: [
|
|
7043
8371
|
"\u{1F527} ",
|
|
7044
8372
|
SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
|
|
7045
8373
|
] }),
|
|
7046
|
-
thinkingEnabled && /* @__PURE__ */
|
|
8374
|
+
thinkingEnabled && /* @__PURE__ */ jsxs12(Text13, { color: "#ff9800", children: [
|
|
7047
8375
|
"\u{1F9E0} \u6DF1\u5EA6\u601D\u8003 ",
|
|
7048
8376
|
thinkingEffort === "max" ? "Max" : "High"
|
|
7049
8377
|
] }),
|
|
7050
|
-
sessionMode === "plan" && /* @__PURE__ */
|
|
8378
|
+
sessionMode === "plan" && /* @__PURE__ */ jsx12(Text13, { color: "#ff69b4", bold: true, children: "\u{1F4CB} \u8BA1\u5212\u6A21\u5F0F" })
|
|
7051
8379
|
] }),
|
|
7052
|
-
/* @__PURE__ */
|
|
7053
|
-
balance !== null ? /* @__PURE__ */
|
|
8380
|
+
/* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
|
|
8381
|
+
balance !== null ? /* @__PURE__ */ jsxs12(Text13, { color: "yellow", children: [
|
|
7054
8382
|
"\u{1F4B0} \u4F59\u989D \xA5",
|
|
7055
8383
|
balance.toFixed(2)
|
|
7056
|
-
] }) : balanceLoading ? /* @__PURE__ */
|
|
7057
|
-
todayCost !== null && /* @__PURE__ */
|
|
8384
|
+
] }) : balanceLoading ? /* @__PURE__ */ jsx12(Text13, { color: "yellow", children: "\u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : null,
|
|
8385
|
+
todayCost !== null && /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
|
|
7058
8386
|
"\u{1F4CA} \u4ECA\u65E5 \xA5",
|
|
7059
8387
|
todayCost.toFixed(2)
|
|
7060
8388
|
] })
|
|
7061
8389
|
] }),
|
|
7062
|
-
verbose && /* @__PURE__ */
|
|
8390
|
+
verbose && /* @__PURE__ */ jsx12(Text13, { color: "#ff1493", children: "\u26A1 Verbose" })
|
|
7063
8391
|
] })
|
|
7064
8392
|
) : hasReasoningPanel ? (
|
|
7065
8393
|
/* ===== 流式思考中(纯文本,无边框) ===== */
|
|
7066
|
-
/* @__PURE__ */
|
|
8394
|
+
/* @__PURE__ */ jsx12(Text13, { dimColor: true, wrap: "wrap", children: (() => {
|
|
7067
8395
|
const full = joinReasoningSegments(currentReasoning);
|
|
7068
8396
|
const maxContentLines = 11;
|
|
7069
8397
|
const lines = full.split("\n");
|
|
@@ -7075,30 +8403,31 @@ function ChatSession({
|
|
|
7075
8403
|
})() })
|
|
7076
8404
|
) : (
|
|
7077
8405
|
/* ===== 对话中(无思考):会话状态面板 ===== */
|
|
7078
|
-
/* @__PURE__ */
|
|
7079
|
-
/* @__PURE__ */
|
|
7080
|
-
/* @__PURE__ */
|
|
7081
|
-
/* @__PURE__ */
|
|
8406
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", alignItems: "center", children: [
|
|
8407
|
+
/* @__PURE__ */ jsx12(Text13, { color: "#00ffff", bold: true, children: "\u{1F4AC} \u5BF9\u8BDD\u8FDB\u884C\u4E2D" }),
|
|
8408
|
+
/* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
|
|
8409
|
+
/* @__PURE__ */ jsxs12(Text13, { color: "#00ff41", children: [
|
|
7082
8410
|
"\u{1F4DD} \u6D88\u606F ",
|
|
7083
8411
|
displayMessages.length,
|
|
7084
8412
|
" \u6761"
|
|
7085
8413
|
] }),
|
|
7086
|
-
sessionCost > 0 && /* @__PURE__ */
|
|
8414
|
+
sessionCost > 0 && /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
|
|
7087
8415
|
"\u{1F4B0} \u4F1A\u8BDD \xA5",
|
|
7088
8416
|
sessionCost.toFixed(4)
|
|
7089
|
-
] })
|
|
8417
|
+
] }),
|
|
8418
|
+
contextStats && /* @__PURE__ */ jsx12(ContextUsageBar, { stats: contextStats })
|
|
7090
8419
|
] }),
|
|
7091
|
-
/* @__PURE__ */
|
|
7092
|
-
/* @__PURE__ */
|
|
8420
|
+
/* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
|
|
8421
|
+
/* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
|
|
7093
8422
|
"\u{1F527} ",
|
|
7094
8423
|
SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
|
|
7095
8424
|
] }),
|
|
7096
|
-
thinkingEnabled && /* @__PURE__ */
|
|
8425
|
+
thinkingEnabled && /* @__PURE__ */ jsxs12(Text13, { color: "#ff9800", children: [
|
|
7097
8426
|
"\u{1F9E0} ",
|
|
7098
8427
|
thinkingEffort === "max" ? "Max" : "High"
|
|
7099
8428
|
] })
|
|
7100
8429
|
] }),
|
|
7101
|
-
balance !== null && /* @__PURE__ */
|
|
8430
|
+
balance !== null && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: "yellow", children: [
|
|
7102
8431
|
"\u{1F4B0} \xA5",
|
|
7103
8432
|
balance.toFixed(2)
|
|
7104
8433
|
] }) })
|
|
@@ -7108,47 +8437,46 @@ function ChatSession({
|
|
|
7108
8437
|
)
|
|
7109
8438
|
}
|
|
7110
8439
|
),
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
!hasConversationStarted && /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "flex-start", flexGrow: 1, paddingBottom: 1, children: [
|
|
8440
|
+
useMemo2(() => /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", flexGrow: 1, children: [
|
|
8441
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", flexGrow: 1, children: [
|
|
8442
|
+
!hasConversationStarted && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", alignItems: "flex-start", flexGrow: 1, paddingBottom: 1, children: [
|
|
7115
8443
|
cmdTips.length > 0 && (() => {
|
|
7116
8444
|
const tip = cmdTips[cmdTipIndex % cmdTips.length];
|
|
7117
8445
|
if (!tip) return null;
|
|
7118
8446
|
const text = `${tip.name} ${tip.desc}`;
|
|
7119
|
-
return /* @__PURE__ */
|
|
7120
|
-
/* @__PURE__ */
|
|
7121
|
-
cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */
|
|
8447
|
+
return /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, alignSelf: "center", children: [
|
|
8448
|
+
/* @__PURE__ */ jsx12(Text13, { color: "#808080", children: "\u{1F4A1} " }),
|
|
8449
|
+
cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx12(Text13, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx12(Text13, { color: "#808080", children: text })
|
|
7122
8450
|
] });
|
|
7123
8451
|
})(),
|
|
7124
|
-
/* @__PURE__ */
|
|
7125
|
-
/* @__PURE__ */
|
|
8452
|
+
/* @__PURE__ */ jsx12(Box12, { flexGrow: 1 }),
|
|
8453
|
+
/* @__PURE__ */ jsx12(AnimatedLogo, { panelWidth: rightContentWidth })
|
|
7126
8454
|
] }),
|
|
7127
|
-
/* @__PURE__ */
|
|
7128
|
-
/* @__PURE__ */
|
|
8455
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
8456
|
+
/* @__PURE__ */ jsx12(Static, { items: displayMessages, children: (msg, i) => {
|
|
7129
8457
|
if (msg.role === "user") {
|
|
7130
|
-
return /* @__PURE__ */
|
|
7131
|
-
/* @__PURE__ */
|
|
7132
|
-
/* @__PURE__ */
|
|
7133
|
-
/* @__PURE__ */
|
|
7134
|
-
/* @__PURE__ */
|
|
8458
|
+
return /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", children: [
|
|
8459
|
+
/* @__PURE__ */ jsx12(Box12, { width: 1, backgroundColor: "#FF8C00", flexShrink: 0 }),
|
|
8460
|
+
/* @__PURE__ */ jsx12(Box12, { flexGrow: 1, paddingLeft: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
|
|
8461
|
+
/* @__PURE__ */ jsx12(Box12, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#FF8C00", children: "\u{1F4AC}" }) }),
|
|
8462
|
+
/* @__PURE__ */ jsx12(Box12, { flexGrow: 1, children: /* @__PURE__ */ jsx12(Text13, { wrap: "wrap", children: msg.content }) })
|
|
7135
8463
|
] }) })
|
|
7136
8464
|
] }, i);
|
|
7137
8465
|
}
|
|
7138
8466
|
if (msg.role === "tool") {
|
|
7139
|
-
return /* @__PURE__ */
|
|
7140
|
-
/* @__PURE__ */
|
|
7141
|
-
/* @__PURE__ */
|
|
7142
|
-
/* @__PURE__ */
|
|
7143
|
-
/* @__PURE__ */
|
|
7144
|
-
/* @__PURE__ */
|
|
8467
|
+
return /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", children: [
|
|
8468
|
+
/* @__PURE__ */ jsx12(Box12, { width: 1, backgroundColor: "#666666", flexShrink: 0 }),
|
|
8469
|
+
/* @__PURE__ */ jsxs12(Box12, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: [
|
|
8470
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
|
|
8471
|
+
/* @__PURE__ */ jsx12(Box12, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u{1F527}" }) }),
|
|
8472
|
+
/* @__PURE__ */ jsx12(Box12, { flexGrow: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, wrap: "wrap", children: msg.content }) })
|
|
7145
8473
|
] }),
|
|
7146
|
-
msg.diff && /* @__PURE__ */
|
|
8474
|
+
msg.diff && /* @__PURE__ */ jsx12(DiffPreview, { diff: msg.diff })
|
|
7147
8475
|
] })
|
|
7148
8476
|
] }, i);
|
|
7149
8477
|
}
|
|
7150
8478
|
const detail = msg.assistantDetail;
|
|
7151
|
-
return /* @__PURE__ */
|
|
8479
|
+
return /* @__PURE__ */ jsx12(
|
|
7152
8480
|
AssistantMessage,
|
|
7153
8481
|
{
|
|
7154
8482
|
content: msg.content,
|
|
@@ -7162,7 +8490,7 @@ function ChatSession({
|
|
|
7162
8490
|
i
|
|
7163
8491
|
);
|
|
7164
8492
|
} }, staticKey),
|
|
7165
|
-
isStreaming && /* @__PURE__ */
|
|
8493
|
+
isStreaming && /* @__PURE__ */ jsx12(
|
|
7166
8494
|
AssistantMessage,
|
|
7167
8495
|
{
|
|
7168
8496
|
content: currentContent,
|
|
@@ -7173,49 +8501,56 @@ function ChatSession({
|
|
|
7173
8501
|
model: _streamingModel
|
|
7174
8502
|
}
|
|
7175
8503
|
),
|
|
7176
|
-
|
|
8504
|
+
compactionState.phase !== "idle" && /* @__PURE__ */ jsx12(
|
|
8505
|
+
CompactionProgress,
|
|
8506
|
+
{
|
|
8507
|
+
state: compactionState,
|
|
8508
|
+
contentWidth: rightContentWidth
|
|
8509
|
+
}
|
|
8510
|
+
),
|
|
8511
|
+
!isStreaming && streamError && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs12(Text13, { color: "red", children: [
|
|
7177
8512
|
"\u26A0 ",
|
|
7178
8513
|
streamError
|
|
7179
8514
|
] }) })
|
|
7180
8515
|
] }),
|
|
7181
|
-
todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */
|
|
8516
|
+
todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx12(TodoListPanel, { items: todoSnapshot })
|
|
7182
8517
|
] }),
|
|
7183
|
-
selectingModel ? /* @__PURE__ */
|
|
7184
|
-
/* @__PURE__ */
|
|
7185
|
-
/* @__PURE__ */
|
|
7186
|
-
/* @__PURE__ */
|
|
8518
|
+
selectingModel ? /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
|
|
8519
|
+
/* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
|
|
8520
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
8521
|
+
/* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
|
|
7187
8522
|
modelOptions.map((id, i) => {
|
|
7188
8523
|
const meta = SUPPORTED_MODELS[id];
|
|
7189
8524
|
const isCurrent = id === activeModel;
|
|
7190
8525
|
const isSelected = i === modelSelectIndex;
|
|
7191
8526
|
const marker = isSelected ? " > " : " ";
|
|
7192
8527
|
const suffix = isCurrent ? " (\u5F53\u524D)" : "";
|
|
7193
|
-
return /* @__PURE__ */
|
|
7194
|
-
/* @__PURE__ */
|
|
8528
|
+
return /* @__PURE__ */ jsxs12(Box12, { children: [
|
|
8529
|
+
/* @__PURE__ */ jsxs12(Text13, { color: isSelected ? "#00ff41" : void 0, bold: isSelected, children: [
|
|
7195
8530
|
marker,
|
|
7196
8531
|
meta.displayName,
|
|
7197
8532
|
suffix
|
|
7198
8533
|
] }),
|
|
7199
|
-
isSelected && /* @__PURE__ */
|
|
8534
|
+
isSelected && /* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
|
|
7200
8535
|
" \u2014 ",
|
|
7201
8536
|
id
|
|
7202
8537
|
] })
|
|
7203
8538
|
] }, id);
|
|
7204
8539
|
}),
|
|
7205
|
-
/* @__PURE__ */
|
|
8540
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
|
|
7206
8541
|
] }),
|
|
7207
|
-
/* @__PURE__ */
|
|
7208
|
-
] }) : rewindSelecting ? /* @__PURE__ */
|
|
7209
|
-
/* @__PURE__ */
|
|
7210
|
-
/* @__PURE__ */
|
|
7211
|
-
/* @__PURE__ */
|
|
8542
|
+
/* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
|
|
8543
|
+
] }) : rewindSelecting ? /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
|
|
8544
|
+
/* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
|
|
8545
|
+
/* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
|
|
8546
|
+
/* @__PURE__ */ jsx12(Text13, { bold: true, color: "#ff9800", children: "\u9009\u62E9\u8981\u56DE\u9000\u7684\u68C0\u67E5\u70B9\uFF1A" }),
|
|
7212
8547
|
rewindList.map((cp2, i) => {
|
|
7213
8548
|
const isSelected = i === rewindSelectIndex;
|
|
7214
8549
|
const marker = isSelected ? " > " : " ";
|
|
7215
8550
|
const time = new Date(cp2.timestamp).toLocaleTimeString();
|
|
7216
8551
|
const preview = cp2.preview || "(\u7A7A)";
|
|
7217
8552
|
const tag = cp2.isGitRepo ? "" : " [\u975E git\uFF0C\u4EC5\u5BF9\u8BDD]";
|
|
7218
|
-
return /* @__PURE__ */
|
|
8553
|
+
return /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: isSelected ? "#ff9800" : void 0, bold: isSelected, children: [
|
|
7219
8554
|
marker,
|
|
7220
8555
|
"#",
|
|
7221
8556
|
i + 1,
|
|
@@ -7227,21 +8562,25 @@ function ChatSession({
|
|
|
7227
8562
|
"`"
|
|
7228
8563
|
] }) }, cp2.index);
|
|
7229
8564
|
}),
|
|
7230
|
-
/* @__PURE__ */
|
|
8565
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
|
|
7231
8566
|
] }),
|
|
7232
|
-
/* @__PURE__ */
|
|
7233
|
-
] }) : /* @__PURE__ */
|
|
7234
|
-
(hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */
|
|
8567
|
+
/* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
|
|
8568
|
+
] }) : /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
8569
|
+
(hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */ jsx12(Box12, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs12(Text13, { bold: true, color: PHASE_CONFIG[streamingPhase].color, children: [
|
|
7235
8570
|
PHASE_CONFIG[streamingPhase].icon,
|
|
7236
8571
|
" ",
|
|
7237
8572
|
PHASE_CONFIG[streamingPhase].label,
|
|
7238
8573
|
" ",
|
|
7239
|
-
/* @__PURE__ */
|
|
7240
|
-
] }) }) : rewindHintPhase === "visible" ? /* @__PURE__ */
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
8574
|
+
/* @__PURE__ */ jsx12(InkSpinner4, { type: "dots" })
|
|
8575
|
+
] }) }) : rewindHintPhase === "visible" ? /* @__PURE__ */ jsx12(Box12, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx12(Text13, { color: "#808080", children: "\u21A9 /rewind 1 \u53EF\u64A4\u56DE\u672C\u6B21\u4FEE\u6539" }) }) : contextStats && contextStats.ratio > 0.85 ? /* @__PURE__ */ jsx12(Box12, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs12(Text13, { color: "#ff9800", children: [
|
|
8576
|
+
"\u{1F4DA} \u4E0A\u4E0B\u6587\u5DF2\u7528 ",
|
|
8577
|
+
(contextStats.ratio * 100).toFixed(0),
|
|
8578
|
+
"%\uFF0C\u8F93\u5165 /compact \u53EF\u624B\u52A8\u538B\u7F29"
|
|
8579
|
+
] }) }) : null,
|
|
8580
|
+
/* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
|
|
8581
|
+
/* @__PURE__ */ jsxs12(Box12, { children: [
|
|
8582
|
+
/* @__PURE__ */ jsx12(Box12, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
|
|
8583
|
+
/* @__PURE__ */ jsx12(Box12, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx12(Text13, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx12(Text13, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx12(Text13, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx12(Text13, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx12(
|
|
7245
8584
|
TextInput,
|
|
7246
8585
|
{
|
|
7247
8586
|
value: input,
|
|
@@ -7252,9 +8591,9 @@ function ChatSession({
|
|
|
7252
8591
|
inputKey
|
|
7253
8592
|
) })
|
|
7254
8593
|
] }),
|
|
7255
|
-
/* @__PURE__ */
|
|
7256
|
-
/* @__PURE__ */
|
|
7257
|
-
/* @__PURE__ */
|
|
8594
|
+
/* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
|
|
8595
|
+
/* @__PURE__ */ jsx12(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
|
|
8596
|
+
/* @__PURE__ */ jsx12(FileSelector, { files, input, selectedIndex: fileSelectIndex })
|
|
7258
8597
|
] })
|
|
7259
8598
|
] }), [
|
|
7260
8599
|
displayMessages,
|
|
@@ -7302,15 +8641,53 @@ function ChatSession({
|
|
|
7302
8641
|
doubleCtrlC
|
|
7303
8642
|
])
|
|
7304
8643
|
] }),
|
|
7305
|
-
doubleCtrlC && !isStreaming && /* @__PURE__ */
|
|
7306
|
-
isStreaming && /* @__PURE__ */
|
|
8644
|
+
doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
|
|
8645
|
+
isStreaming && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
|
|
8646
|
+
] });
|
|
8647
|
+
}
|
|
8648
|
+
var CONTEXT_BAR_WIDTH = 12;
|
|
8649
|
+
function classifyContextRatio(ratio) {
|
|
8650
|
+
if (ratio >= 0.85) return "danger";
|
|
8651
|
+
if (ratio >= 0.6) return "warning";
|
|
8652
|
+
return "safe";
|
|
8653
|
+
}
|
|
8654
|
+
function contextLevelColor(level) {
|
|
8655
|
+
switch (level) {
|
|
8656
|
+
case "danger":
|
|
8657
|
+
return "#ff6347";
|
|
8658
|
+
// 红色
|
|
8659
|
+
case "warning":
|
|
8660
|
+
return "#ffcc00";
|
|
8661
|
+
// 黄色
|
|
8662
|
+
case "safe":
|
|
8663
|
+
return "#00ff41";
|
|
8664
|
+
}
|
|
8665
|
+
}
|
|
8666
|
+
function ContextUsageBar({
|
|
8667
|
+
stats
|
|
8668
|
+
}) {
|
|
8669
|
+
const level = classifyContextRatio(stats.ratio);
|
|
8670
|
+
const color = contextLevelColor(level);
|
|
8671
|
+
const filled = Math.min(
|
|
8672
|
+
CONTEXT_BAR_WIDTH,
|
|
8673
|
+
// 只要 ratio > 0 就至少 1 格 █,避免“占用极少”时空条被误读为“未使用”
|
|
8674
|
+
Math.max(stats.ratio > 0 ? 1 : 0, Math.round(stats.ratio * CONTEXT_BAR_WIDTH))
|
|
8675
|
+
);
|
|
8676
|
+
const empty = CONTEXT_BAR_WIDTH - filled;
|
|
8677
|
+
return /* @__PURE__ */ jsxs12(Text13, { color, children: [
|
|
8678
|
+
"\u{1F4DA} ",
|
|
8679
|
+
/* @__PURE__ */ jsx12(Text13, { color, children: "\u2588".repeat(filled) }),
|
|
8680
|
+
/* @__PURE__ */ jsx12(Text13, { color: "#444444", children: "\u2591".repeat(empty) }),
|
|
8681
|
+
" ",
|
|
8682
|
+
(stats.ratio * 100).toFixed(1),
|
|
8683
|
+
"%"
|
|
7307
8684
|
] });
|
|
7308
8685
|
}
|
|
7309
8686
|
|
|
7310
8687
|
// src/ui/GamePicker.tsx
|
|
7311
|
-
import { Box as
|
|
8688
|
+
import { Box as Box13, Text as Text14, useInput as useInput2 } from "ink";
|
|
7312
8689
|
import { useState as useState6, useCallback as useCallback3 } from "react";
|
|
7313
|
-
import { jsx as
|
|
8690
|
+
import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
7314
8691
|
function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
7315
8692
|
const [selectedIndex, setSelectedIndex] = useState6(0);
|
|
7316
8693
|
const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
|
|
@@ -7338,18 +8715,18 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
|
|
|
7338
8715
|
[games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC]
|
|
7339
8716
|
)
|
|
7340
8717
|
);
|
|
7341
|
-
return /* @__PURE__ */
|
|
7342
|
-
/* @__PURE__ */
|
|
7343
|
-
/* @__PURE__ */
|
|
8718
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
8719
|
+
/* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text14, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
|
|
8720
|
+
/* @__PURE__ */ jsx13(Box13, { flexDirection: "column", children: games.map((game, index) => {
|
|
7344
8721
|
const isSelected = index === selectedIndex;
|
|
7345
|
-
return /* @__PURE__ */
|
|
7346
|
-
/* @__PURE__ */
|
|
7347
|
-
/* @__PURE__ */
|
|
7348
|
-
/* @__PURE__ */
|
|
8722
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", children: [
|
|
8723
|
+
/* @__PURE__ */ jsx13(Box13, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx13(Text14, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx13(Text14, { children: " " }) }),
|
|
8724
|
+
/* @__PURE__ */ jsx13(Box13, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx13(Text14, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
|
|
8725
|
+
/* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text14, { color: "#888888", children: game.description }) })
|
|
7349
8726
|
] }, game.id);
|
|
7350
8727
|
}) }),
|
|
7351
|
-
/* @__PURE__ */
|
|
7352
|
-
doubleCtrlC && /* @__PURE__ */
|
|
8728
|
+
/* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
|
|
8729
|
+
doubleCtrlC && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
7353
8730
|
] });
|
|
7354
8731
|
}
|
|
7355
8732
|
|
|
@@ -7366,9 +8743,9 @@ function listGames() {
|
|
|
7366
8743
|
}
|
|
7367
8744
|
|
|
7368
8745
|
// src/game/brick-breaker/index.tsx
|
|
7369
|
-
import { Box as
|
|
8746
|
+
import { Box as Box14, Text as Text15, useInput as useInput3, render as render2 } from "ink";
|
|
7370
8747
|
import { useState as useState7, useEffect as useEffect6, useRef as useRef5, useCallback as useCallback4 } from "react";
|
|
7371
|
-
import { jsx as
|
|
8748
|
+
import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
7372
8749
|
var GAME_WIDTH = 40;
|
|
7373
8750
|
var GAME_HEIGHT = 18;
|
|
7374
8751
|
var PADDLE_WIDTH = 9;
|
|
@@ -7558,49 +8935,49 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
7558
8935
|
const board = buildBoard(s);
|
|
7559
8936
|
const def = getLevel(s.level);
|
|
7560
8937
|
void tick2;
|
|
7561
|
-
return /* @__PURE__ */
|
|
7562
|
-
/* @__PURE__ */
|
|
7563
|
-
/* @__PURE__ */
|
|
8938
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
8939
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", children: [
|
|
8940
|
+
/* @__PURE__ */ jsx14(Box14, { width: 20, children: /* @__PURE__ */ jsxs14(Text15, { children: [
|
|
7564
8941
|
"\u5173\u5361 ",
|
|
7565
8942
|
s.level,
|
|
7566
8943
|
": ",
|
|
7567
|
-
/* @__PURE__ */
|
|
8944
|
+
/* @__PURE__ */ jsx14(Text15, { color: "cyan", children: def.desc })
|
|
7568
8945
|
] }) }),
|
|
7569
|
-
/* @__PURE__ */
|
|
8946
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { children: [
|
|
7570
8947
|
"\u5206\u6570: ",
|
|
7571
|
-
/* @__PURE__ */
|
|
8948
|
+
/* @__PURE__ */ jsx14(Text15, { color: "yellow", children: String(s.score).padStart(3, "0") })
|
|
7572
8949
|
] }) }),
|
|
7573
|
-
/* @__PURE__ */
|
|
8950
|
+
/* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { children: [
|
|
7574
8951
|
"\u751F\u547D: ",
|
|
7575
|
-
/* @__PURE__ */
|
|
8952
|
+
/* @__PURE__ */ jsx14(Text15, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
|
|
7576
8953
|
] }) }),
|
|
7577
|
-
/* @__PURE__ */
|
|
8954
|
+
/* @__PURE__ */ jsx14(Box14, { width: 10, children: /* @__PURE__ */ jsxs14(Text15, { children: [
|
|
7578
8955
|
"\u7816\u5757: ",
|
|
7579
|
-
/* @__PURE__ */
|
|
8956
|
+
/* @__PURE__ */ jsx14(Text15, { color: "cyan", children: aliveCount })
|
|
7580
8957
|
] }) }),
|
|
7581
|
-
/* @__PURE__ */
|
|
8958
|
+
/* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: s.paused ? "gray" : "green", children: [
|
|
7582
8959
|
"[",
|
|
7583
8960
|
s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
|
|
7584
8961
|
"]"
|
|
7585
8962
|
] }) })
|
|
7586
8963
|
] }),
|
|
7587
|
-
/* @__PURE__ */
|
|
7588
|
-
/* @__PURE__ */
|
|
8964
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
|
|
8965
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
7589
8966
|
"\u250C",
|
|
7590
8967
|
"\u2500".repeat(GAME_WIDTH),
|
|
7591
8968
|
"\u2510"
|
|
7592
8969
|
] }),
|
|
7593
|
-
/* @__PURE__ */
|
|
7594
|
-
/* @__PURE__ */
|
|
8970
|
+
/* @__PURE__ */ jsx14(Text15, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
|
|
8971
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
7595
8972
|
"\u2514",
|
|
7596
8973
|
"\u2500".repeat(GAME_WIDTH),
|
|
7597
8974
|
"\u2518"
|
|
7598
8975
|
] })
|
|
7599
8976
|
] }),
|
|
7600
|
-
selectingLevel && /* @__PURE__ */
|
|
7601
|
-
/* @__PURE__ */
|
|
7602
|
-
/* @__PURE__ */
|
|
7603
|
-
/* @__PURE__ */
|
|
8977
|
+
selectingLevel && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
|
|
8978
|
+
/* @__PURE__ */ jsx14(Text15, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
|
|
8979
|
+
/* @__PURE__ */ jsx14(Box14, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx14(Box14, { width: 22, children: /* @__PURE__ */ jsxs14(Text15, { children: [
|
|
8980
|
+
/* @__PURE__ */ jsx14(Text15, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
|
|
7604
8981
|
". ",
|
|
7605
8982
|
lv.desc,
|
|
7606
8983
|
" (",
|
|
@@ -7609,16 +8986,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
|
|
|
7609
8986
|
lv.cols,
|
|
7610
8987
|
")"
|
|
7611
8988
|
] }) }, i)) }),
|
|
7612
|
-
/* @__PURE__ */
|
|
8989
|
+
/* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
|
|
7613
8990
|
] }),
|
|
7614
|
-
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */
|
|
7615
|
-
/* @__PURE__ */
|
|
7616
|
-
/* @__PURE__ */
|
|
8991
|
+
!selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
8992
|
+
/* @__PURE__ */ jsx14(Text15, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
|
|
8993
|
+
/* @__PURE__ */ jsxs14(Text15, { children: [
|
|
7617
8994
|
" \u5206\u6570: ",
|
|
7618
|
-
/* @__PURE__ */
|
|
8995
|
+
/* @__PURE__ */ jsx14(Text15, { color: "yellow", children: s.score })
|
|
7619
8996
|
] })
|
|
7620
8997
|
] }),
|
|
7621
|
-
!selectingLevel && /* @__PURE__ */
|
|
8998
|
+
!selectingLevel && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
|
|
7622
8999
|
] });
|
|
7623
9000
|
}
|
|
7624
9001
|
var brick_breaker_default = {
|
|
@@ -7628,7 +9005,7 @@ var brick_breaker_default = {
|
|
|
7628
9005
|
play: async () => {
|
|
7629
9006
|
await new Promise((resolve2) => {
|
|
7630
9007
|
const { unmount } = render2(
|
|
7631
|
-
/* @__PURE__ */
|
|
9008
|
+
/* @__PURE__ */ jsx14(BrickBreakerGame, { onExit: () => {
|
|
7632
9009
|
unmount();
|
|
7633
9010
|
resolve2();
|
|
7634
9011
|
} })
|
|
@@ -7638,9 +9015,9 @@ var brick_breaker_default = {
|
|
|
7638
9015
|
};
|
|
7639
9016
|
|
|
7640
9017
|
// src/game/coder-check/index.tsx
|
|
7641
|
-
import { Box as
|
|
9018
|
+
import { Box as Box15, Text as Text16, useInput as useInput4, render as render3 } from "ink";
|
|
7642
9019
|
import { useState as useState8, useEffect as useEffect7, useRef as useRef6, useCallback as useCallback5 } from "react";
|
|
7643
|
-
import { jsx as
|
|
9020
|
+
import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
7644
9021
|
var GAME_W = 66;
|
|
7645
9022
|
var GAME_H = 20;
|
|
7646
9023
|
var SCORE_H = 6;
|
|
@@ -8111,44 +9488,44 @@ function CoderCheck({ onExit: _onExit }) {
|
|
|
8111
9488
|
const scoreLines = buildScoreLines(scoreStr);
|
|
8112
9489
|
const view = buildGameView(s, scoreLines, scoreColor, s.message);
|
|
8113
9490
|
void tick2;
|
|
8114
|
-
return /* @__PURE__ */
|
|
8115
|
-
/* @__PURE__ */
|
|
9491
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, children: [
|
|
9492
|
+
/* @__PURE__ */ jsx15(Box15, { flexDirection: "row", children: /* @__PURE__ */ jsxs15(Text16, { children: [
|
|
8116
9493
|
"\u751F\u547D ",
|
|
8117
|
-
/* @__PURE__ */
|
|
9494
|
+
/* @__PURE__ */ jsx15(Text16, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
|
|
8118
9495
|
" ",
|
|
8119
9496
|
"\u901F\u5EA6 ",
|
|
8120
|
-
/* @__PURE__ */
|
|
9497
|
+
/* @__PURE__ */ jsxs15(Text16, { color: "cyan", children: [
|
|
8121
9498
|
"Lv.",
|
|
8122
9499
|
Math.floor(s.speed * 10)
|
|
8123
9500
|
] })
|
|
8124
9501
|
] }) }),
|
|
8125
|
-
!s.gameOver && s.target && /* @__PURE__ */
|
|
9502
|
+
!s.gameOver && s.target && /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text16, { children: [
|
|
8126
9503
|
"\u6253\u5B57: ",
|
|
8127
|
-
/* @__PURE__ */
|
|
8128
|
-
/* @__PURE__ */
|
|
9504
|
+
/* @__PURE__ */ jsx15(Text16, { color: "green", children: s.typed }),
|
|
9505
|
+
/* @__PURE__ */ jsx15(Text16, { color: "white", children: s.target.slice(s.typed.length) })
|
|
8129
9506
|
] }) }),
|
|
8130
|
-
/* @__PURE__ */
|
|
8131
|
-
/* @__PURE__ */
|
|
9507
|
+
/* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
|
|
9508
|
+
/* @__PURE__ */ jsxs15(Text16, { children: [
|
|
8132
9509
|
"\u250C",
|
|
8133
9510
|
"\u2500".repeat(GAME_W),
|
|
8134
9511
|
"\u2510"
|
|
8135
9512
|
] }),
|
|
8136
|
-
view.map((row, i) => /* @__PURE__ */
|
|
8137
|
-
/* @__PURE__ */
|
|
9513
|
+
view.map((row, i) => /* @__PURE__ */ jsx15(Text16, { children: `\u2502${row}\u2502` }, i)),
|
|
9514
|
+
/* @__PURE__ */ jsxs15(Text16, { children: [
|
|
8138
9515
|
"\u2514",
|
|
8139
9516
|
"\u2500".repeat(GAME_W),
|
|
8140
9517
|
"\u2518"
|
|
8141
9518
|
] })
|
|
8142
9519
|
] }),
|
|
8143
|
-
s.gameOver && /* @__PURE__ */
|
|
8144
|
-
/* @__PURE__ */
|
|
8145
|
-
/* @__PURE__ */
|
|
9520
|
+
s.gameOver && /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, children: [
|
|
9521
|
+
/* @__PURE__ */ jsx15(Text16, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
|
|
9522
|
+
/* @__PURE__ */ jsxs15(Text16, { children: [
|
|
8146
9523
|
" \u5F97\u5206: ",
|
|
8147
|
-
/* @__PURE__ */
|
|
9524
|
+
/* @__PURE__ */ jsx15(Text16, { color: "yellow", children: s.score }),
|
|
8148
9525
|
" r \u91CD\u5F00 q \u9000\u51FA"
|
|
8149
9526
|
] })
|
|
8150
9527
|
] }),
|
|
8151
|
-
/* @__PURE__ */
|
|
9528
|
+
/* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
|
|
8152
9529
|
] });
|
|
8153
9530
|
}
|
|
8154
9531
|
var coder_check_default = {
|
|
@@ -8158,7 +9535,7 @@ var coder_check_default = {
|
|
|
8158
9535
|
play: async () => {
|
|
8159
9536
|
await new Promise((resolve2) => {
|
|
8160
9537
|
const { unmount } = render3(
|
|
8161
|
-
/* @__PURE__ */
|
|
9538
|
+
/* @__PURE__ */ jsx15(CoderCheck, { onExit: () => {
|
|
8162
9539
|
unmount();
|
|
8163
9540
|
resolve2();
|
|
8164
9541
|
} })
|
|
@@ -8538,12 +9915,12 @@ import { render as render4 } from "ink";
|
|
|
8538
9915
|
import chalk5 from "chalk";
|
|
8539
9916
|
|
|
8540
9917
|
// src/stock/StockList.tsx
|
|
8541
|
-
import { Box as
|
|
8542
|
-
import { useState as useState9, useCallback as useCallback6, useEffect as useEffect8, useMemo as
|
|
9918
|
+
import { Box as Box16, Text as Text17, useInput as useInput5 } from "ink";
|
|
9919
|
+
import { useState as useState9, useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo3 } from "react";
|
|
8543
9920
|
import asciichart from "asciichart";
|
|
8544
9921
|
import os from "os";
|
|
8545
9922
|
import { join as join10 } from "path";
|
|
8546
|
-
import { jsx as
|
|
9923
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
8547
9924
|
var SETTINGS_PATH = join10(os.homedir(), ".dskcode", "settings.json");
|
|
8548
9925
|
function toFileUrl(p) {
|
|
8549
9926
|
const norm = p.replace(/\\/g, "/");
|
|
@@ -8660,7 +10037,7 @@ function StockList({ codes, onExit, onBackToChat }) {
|
|
|
8660
10037
|
);
|
|
8661
10038
|
const [dimMode, setDimMode] = useState9(false);
|
|
8662
10039
|
const [sortOrder, setSortOrder] = useState9("default");
|
|
8663
|
-
const sortedStocks =
|
|
10040
|
+
const sortedStocks = useMemo3(() => {
|
|
8664
10041
|
if (sortOrder === "default") return stocks;
|
|
8665
10042
|
return [...stocks].toSorted(
|
|
8666
10043
|
(a, b) => sortOrder === "desc" ? b.changePercent - a.changePercent : a.changePercent - b.changePercent
|
|
@@ -8762,64 +10139,64 @@ function StockList({ codes, onExit, onBackToChat }) {
|
|
|
8762
10139
|
);
|
|
8763
10140
|
if (detailView) {
|
|
8764
10141
|
if (detailLoading) {
|
|
8765
|
-
return /* @__PURE__ */
|
|
10142
|
+
return /* @__PURE__ */ jsx16(Box16, { paddingLeft: 1, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
|
|
8766
10143
|
}
|
|
8767
10144
|
return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
|
|
8768
10145
|
}
|
|
8769
10146
|
const cp2 = (c) => dimMode ? { dimColor: true } : { color: c };
|
|
8770
|
-
return /* @__PURE__ */
|
|
8771
|
-
/* @__PURE__ */
|
|
8772
|
-
/* @__PURE__ */
|
|
8773
|
-
/* @__PURE__ */
|
|
10147
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
|
|
10148
|
+
/* @__PURE__ */ jsxs16(Box16, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
10149
|
+
/* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
|
|
10150
|
+
/* @__PURE__ */ jsxs16(Text17, { dimColor: true, children: [
|
|
8774
10151
|
" \u{1F550} ",
|
|
8775
10152
|
currentTime
|
|
8776
10153
|
] }),
|
|
8777
|
-
/* @__PURE__ */
|
|
10154
|
+
/* @__PURE__ */ jsx16(Text17, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
|
|
8778
10155
|
] }),
|
|
8779
|
-
/* @__PURE__ */
|
|
8780
|
-
/* @__PURE__ */
|
|
8781
|
-
/* @__PURE__ */
|
|
8782
|
-
/* @__PURE__ */
|
|
8783
|
-
/* @__PURE__ */
|
|
8784
|
-
/* @__PURE__ */
|
|
10156
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
10157
|
+
/* @__PURE__ */ jsx16(Box16, { width: 3 }),
|
|
10158
|
+
/* @__PURE__ */ jsx16(Box16, { width: 9, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u4EE3\u7801" }) }),
|
|
10159
|
+
/* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u540D\u79F0" }) }),
|
|
10160
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
|
|
10161
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsxs16(Text17, { dimColor: true, children: [
|
|
8785
10162
|
"\u6DA8\u8DCC\u5E45",
|
|
8786
10163
|
sortOrder === "desc" ? " \u25BC" : sortOrder === "asc" ? " \u25B2" : ""
|
|
8787
10164
|
] }) }),
|
|
8788
|
-
/* @__PURE__ */
|
|
8789
|
-
/* @__PURE__ */
|
|
8790
|
-
/* @__PURE__ */
|
|
8791
|
-
/* @__PURE__ */
|
|
10165
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
|
|
10166
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6700\u9AD8" }) }),
|
|
10167
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6700\u4F4E" }) }),
|
|
10168
|
+
/* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
|
|
8792
10169
|
] }),
|
|
8793
|
-
/* @__PURE__ */
|
|
8794
|
-
/* @__PURE__ */
|
|
10170
|
+
/* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
|
|
10171
|
+
/* @__PURE__ */ jsx16(Box16, { flexDirection: "column", children: sortedStocks.map((stock, index) => {
|
|
8795
10172
|
const isSelected = index === selectedIndex;
|
|
8796
10173
|
const isUp = stock.changePercent >= 0;
|
|
8797
10174
|
const color = isUp ? "#ff1493" : "#00ff41";
|
|
8798
|
-
return /* @__PURE__ */
|
|
8799
|
-
/* @__PURE__ */
|
|
8800
|
-
/* @__PURE__ */
|
|
8801
|
-
/* @__PURE__ */
|
|
8802
|
-
/* @__PURE__ */
|
|
8803
|
-
/* @__PURE__ */
|
|
10175
|
+
return /* @__PURE__ */ jsxs16(Box16, { children: [
|
|
10176
|
+
/* @__PURE__ */ jsx16(Box16, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx16(Text17, { children: " " }) }),
|
|
10177
|
+
/* @__PURE__ */ jsx16(Box16, { width: 9, children: /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
|
|
10178
|
+
/* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
|
|
10179
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
|
|
10180
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsxs16(Text17, { ...cp2(color), children: [
|
|
8804
10181
|
isUp ? "+" : "",
|
|
8805
10182
|
stock.changePercent.toFixed(2),
|
|
8806
10183
|
"%"
|
|
8807
10184
|
] }) }),
|
|
8808
|
-
/* @__PURE__ */
|
|
10185
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsxs16(Text17, { ...cp2(color), children: [
|
|
8809
10186
|
isUp ? "+" : "",
|
|
8810
10187
|
stock.changeAmount.toFixed(3)
|
|
8811
10188
|
] }) }),
|
|
8812
|
-
/* @__PURE__ */
|
|
8813
|
-
/* @__PURE__ */
|
|
8814
|
-
/* @__PURE__ */
|
|
10189
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
|
|
10190
|
+
/* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
|
|
10191
|
+
/* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text17, { ...cp2("#888888"), children: formatAmount(stock.amount) }) })
|
|
8815
10192
|
] }, stock.code);
|
|
8816
10193
|
}) }),
|
|
8817
|
-
/* @__PURE__ */
|
|
8818
|
-
/* @__PURE__ */
|
|
8819
|
-
/* @__PURE__ */
|
|
8820
|
-
/* @__PURE__ */
|
|
10194
|
+
/* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 o \u6392\u5E8F h \u7F6E\u7070/\u6062\u590D q \u8FD4\u56DE` }) }),
|
|
10195
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
10196
|
+
/* @__PURE__ */ jsx16(Text17, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
|
|
10197
|
+
/* @__PURE__ */ jsx16(Text17, { ...cp2("#c792ea"), children: osc8Link(toFileUrl(SETTINGS_PATH), SETTINGS_PATH) })
|
|
8821
10198
|
] }),
|
|
8822
|
-
doubleCtrlC && /* @__PURE__ */
|
|
10199
|
+
doubleCtrlC && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2("#ff1493"), children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
|
|
8823
10200
|
] });
|
|
8824
10201
|
}
|
|
8825
10202
|
function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
@@ -8837,33 +10214,33 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
8837
10214
|
raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
|
|
8838
10215
|
chartLines = raw.split("\n");
|
|
8839
10216
|
}
|
|
8840
|
-
return /* @__PURE__ */
|
|
8841
|
-
/* @__PURE__ */
|
|
8842
|
-
/* @__PURE__ */
|
|
8843
|
-
/* @__PURE__ */
|
|
10217
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingLeft: 1, children: [
|
|
10218
|
+
/* @__PURE__ */ jsxs16(Box16, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
10219
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
10220
|
+
/* @__PURE__ */ jsxs16(Text17, { bold: true, color: "#00ffff", children: [
|
|
8844
10221
|
" \u{1F4CA} ",
|
|
8845
10222
|
stock.name,
|
|
8846
10223
|
" "
|
|
8847
10224
|
] }),
|
|
8848
|
-
/* @__PURE__ */
|
|
8849
|
-
currentTime && /* @__PURE__ */
|
|
10225
|
+
/* @__PURE__ */ jsx16(Text17, { dimColor: true, children: stock.code }),
|
|
10226
|
+
currentTime && /* @__PURE__ */ jsxs16(Text17, { dimColor: true, children: [
|
|
8850
10227
|
" \u{1F550} ",
|
|
8851
10228
|
currentTime
|
|
8852
10229
|
] })
|
|
8853
10230
|
] }),
|
|
8854
|
-
/* @__PURE__ */
|
|
10231
|
+
/* @__PURE__ */ jsx16(Text17, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
|
|
8855
10232
|
] }),
|
|
8856
|
-
/* @__PURE__ */
|
|
8857
|
-
/* @__PURE__ */
|
|
8858
|
-
/* @__PURE__ */
|
|
10233
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
10234
|
+
/* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
|
|
10235
|
+
/* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { bold: true, color: colorCode, children: [
|
|
8859
10236
|
arrow,
|
|
8860
10237
|
" ",
|
|
8861
10238
|
formatPrice(stock.price)
|
|
8862
10239
|
] }) })
|
|
8863
10240
|
] }),
|
|
8864
|
-
/* @__PURE__ */
|
|
8865
|
-
/* @__PURE__ */
|
|
8866
|
-
/* @__PURE__ */
|
|
10241
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
10242
|
+
/* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
|
|
10243
|
+
/* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { color: colorCode, children: [
|
|
8867
10244
|
isUp ? "+" : "",
|
|
8868
10245
|
stock.changePercent.toFixed(2),
|
|
8869
10246
|
"%",
|
|
@@ -8872,8 +10249,8 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
|
|
|
8872
10249
|
stock.changeAmount.toFixed(3)
|
|
8873
10250
|
] }) })
|
|
8874
10251
|
] }),
|
|
8875
|
-
chartLines.length > 0 && /* @__PURE__ */
|
|
8876
|
-
/* @__PURE__ */
|
|
10252
|
+
chartLines.length > 0 && /* @__PURE__ */ jsx16(Box16, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text17, { color: colorCode, children: line || " " }) }, i)) }),
|
|
10253
|
+
/* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
|
|
8877
10254
|
] });
|
|
8878
10255
|
}
|
|
8879
10256
|
|
|
@@ -8958,7 +10335,7 @@ async function scanProjectFiles(baseDir, dir) {
|
|
|
8958
10335
|
}
|
|
8959
10336
|
|
|
8960
10337
|
// src/cli/index.tsx
|
|
8961
|
-
import { jsx as
|
|
10338
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
8962
10339
|
var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
|
|
8963
10340
|
function createCli() {
|
|
8964
10341
|
const program2 = new Command();
|
|
@@ -9060,7 +10437,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
9060
10437
|
const freshResult = await loadAndValidate();
|
|
9061
10438
|
const codeList = codes && codes.length > 0 ? codes : freshResult.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
|
|
9062
10439
|
const app = renderApp(
|
|
9063
|
-
/* @__PURE__ */
|
|
10440
|
+
/* @__PURE__ */ jsx17(
|
|
9064
10441
|
StockList,
|
|
9065
10442
|
{
|
|
9066
10443
|
codes: codeList,
|
|
@@ -9089,7 +10466,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
9089
10466
|
}
|
|
9090
10467
|
const selectedGame = await new Promise((resolve2) => {
|
|
9091
10468
|
const { unmount } = render4(
|
|
9092
|
-
/* @__PURE__ */
|
|
10469
|
+
/* @__PURE__ */ jsx17(
|
|
9093
10470
|
GamePicker,
|
|
9094
10471
|
{
|
|
9095
10472
|
games,
|
|
@@ -9129,7 +10506,7 @@ async function startChat(ctx, costTracker) {
|
|
|
9129
10506
|
);
|
|
9130
10507
|
const model = defaultProvider?.model ?? "deepseek-v4-flash";
|
|
9131
10508
|
const chatApp = renderApp(
|
|
9132
|
-
/* @__PURE__ */
|
|
10509
|
+
/* @__PURE__ */ jsx17(
|
|
9133
10510
|
ChatSession,
|
|
9134
10511
|
{
|
|
9135
10512
|
skillCount,
|
|
@@ -9147,7 +10524,7 @@ async function startChat(ctx, costTracker) {
|
|
|
9147
10524
|
initGames();
|
|
9148
10525
|
const games = listGames();
|
|
9149
10526
|
const { unmount } = render4(
|
|
9150
|
-
/* @__PURE__ */
|
|
10527
|
+
/* @__PURE__ */ jsx17(
|
|
9151
10528
|
GamePicker,
|
|
9152
10529
|
{
|
|
9153
10530
|
games,
|
|
@@ -9171,7 +10548,7 @@ async function startChat(ctx, costTracker) {
|
|
|
9171
10548
|
setImmediate(() => {
|
|
9172
10549
|
const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
|
|
9173
10550
|
const stockApp = renderApp(
|
|
9174
|
-
/* @__PURE__ */
|
|
10551
|
+
/* @__PURE__ */ jsx17(
|
|
9175
10552
|
StockList,
|
|
9176
10553
|
{
|
|
9177
10554
|
codes: defaultStockCodes,
|