dskcode 0.1.38 → 0.1.40

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 CHANGED
@@ -805,9 +805,9 @@ var LOGO_LINES = [
805
805
  ];
806
806
 
807
807
  // src/ui/ChatSession.tsx
808
- import { Box as Box11, Text as Text12, useInput, Static } from "ink";
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 InkSpinner3 from "ink-spinner";
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";
@@ -1981,10 +1981,214 @@ function TodoListPanel({ items }) {
1981
1981
  ] });
1982
1982
  }
1983
1983
 
1984
+ // src/ui/CompactionProgress.tsx
1985
+ import { Box as Box10, Text as Text11 } from "ink";
1986
+ import InkSpinner3 from "ink-spinner";
1987
+ import { useMemo } from "react";
1988
+ import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
1989
+ function estimateProgress(state) {
1990
+ if (state.phase === "idle") return 0;
1991
+ if (state.phase === "done") return 100;
1992
+ if (state.phase === "error") return 100;
1993
+ const p = state.progress;
1994
+ if (!p) return 5;
1995
+ if (p.type === "start") {
1996
+ return 10;
1997
+ }
1998
+ if (p.type === "summary_delta") {
1999
+ const ratio = Math.min(p.totalSoFar.length / 800, 1);
2000
+ return Math.min(10 + ratio * 80, 90);
2001
+ }
2002
+ if (p.type === "fallback") {
2003
+ return 95;
2004
+ }
2005
+ return 5;
2006
+ }
2007
+ function phaseLabel(state) {
2008
+ if (state.phase === "error") {
2009
+ return { icon: "\u2717", text: "\u538B\u7F29\u51FA\u9519", color: "#ff6347" };
2010
+ }
2011
+ if (state.phase === "done") {
2012
+ if (state.strategy === "fallback") {
2013
+ return { icon: "\u2714", text: "\u538B\u7F29\u5B8C\u6210\uFF08\u672C\u5730\u515C\u5E95\uFF09", color: "#ff9800" };
2014
+ }
2015
+ return { icon: "\u2714", text: "\u538B\u7F29\u5B8C\u6210", color: "#00ff41" };
2016
+ }
2017
+ const p = state.progress;
2018
+ if (!p) {
2019
+ return { icon: "\u280B", text: "\u51C6\u5907\u538B\u7F29...", color: "#00ffff" };
2020
+ }
2021
+ if (p.type === "start") {
2022
+ return { icon: "\u280B", text: `\u51C6\u5907\u6458\u8981 ${p.droppedTurns} \u4E2A\u65E7\u56DE\u5408...`, color: "#00ffff" };
2023
+ }
2024
+ if (p.type === "summary_delta") {
2025
+ return { icon: "\u280B", text: "\u8C03\u7528 LLM \u751F\u6210\u6458\u8981...", color: "#00ffff" };
2026
+ }
2027
+ if (p.type === "fallback") {
2028
+ return { icon: "\u26A0", text: `LLM \u6458\u8981\u5931\u8D25\uFF0C\u4F7F\u7528\u672C\u5730\u515C\u5E95\uFF1A${p.reason}`, color: "#ff9800" };
2029
+ }
2030
+ return { icon: "\u280B", text: "\u538B\u7F29\u4E2D...", color: "#00ffff" };
2031
+ }
2032
+ function ProgressBar({ percent, color }) {
2033
+ const WIDTH = 24;
2034
+ const filled = Math.round(percent / 100 * WIDTH);
2035
+ const empty = WIDTH - filled;
2036
+ return /* @__PURE__ */ jsxs10(Text11, { children: [
2037
+ /* @__PURE__ */ jsx10(Text11, { color, children: "\u2588".repeat(filled) }),
2038
+ /* @__PURE__ */ jsx10(Text11, { color: "#444444", children: "\u2591".repeat(empty) }),
2039
+ /* @__PURE__ */ jsxs10(Text11, { color, children: [
2040
+ " ",
2041
+ percent.toFixed(0),
2042
+ "%"
2043
+ ] })
2044
+ ] });
2045
+ }
2046
+ function PhaseSteps({ state }) {
2047
+ const step = (() => {
2048
+ if (state.phase === "idle") return 0;
2049
+ if (state.phase === "error") {
2050
+ const p2 = state.progress;
2051
+ if (p2?.type === "summary_delta" || p2?.type === "start") return 1;
2052
+ return 2;
2053
+ }
2054
+ if (state.phase === "done") return 3;
2055
+ const p = state.progress;
2056
+ if (!p || p.type === "start") return 0;
2057
+ if (p.type === "summary_delta") return 1;
2058
+ if (p.type === "fallback") return 2;
2059
+ return 2;
2060
+ })();
2061
+ const labels = ["\u542F\u52A8", "LLM \u6458\u8981", "\u5E94\u7528\u538B\u7F29", "\u5B8C\u6210"];
2062
+ return /* @__PURE__ */ jsx10(Box10, { children: labels.map((label, i) => {
2063
+ const isCurrent = i === step;
2064
+ const isDone = i < step;
2065
+ const marker = isDone ? "\u2713" : isCurrent ? "\u25B8" : "\xB7";
2066
+ const color = isDone ? "#00ff41" : isCurrent ? "#00ffff" : "#444444";
2067
+ return /* @__PURE__ */ jsxs10(Box10, { marginRight: 1, children: [
2068
+ /* @__PURE__ */ jsxs10(Text11, { color, children: [
2069
+ marker,
2070
+ " ",
2071
+ label
2072
+ ] }),
2073
+ i < labels.length - 1 && /* @__PURE__ */ jsx10(Text11, { color: "#444444", children: " \u2192 " })
2074
+ ] }, label);
2075
+ }) });
2076
+ }
2077
+ function SummaryPreview({ text, contentWidth }) {
2078
+ const MAX_LINES = 4;
2079
+ const MAX_LINE_WIDTH = Math.max(contentWidth - 6, 20);
2080
+ if (!text) {
2081
+ return /* @__PURE__ */ jsx10(Text11, { dimColor: true, children: " (\u7B49\u5F85 LLM \u8F93\u51FA...)" });
2082
+ }
2083
+ const lines = wrapByWidth2(text, MAX_LINE_WIDTH);
2084
+ const kept = lines.slice(-MAX_LINES);
2085
+ return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: kept.map((line, i) => /* @__PURE__ */ jsxs10(Text11, { dimColor: true, children: [
2086
+ " ",
2087
+ line
2088
+ ] }, i)) });
2089
+ }
2090
+ function wrapByWidth2(text, maxWidth) {
2091
+ if (text === "") return [];
2092
+ if (maxWidth <= 0) return [text];
2093
+ const result = [];
2094
+ for (const para of text.split("\n")) {
2095
+ if (para.length === 0) {
2096
+ result.push("");
2097
+ continue;
2098
+ }
2099
+ let buf = "";
2100
+ let bufWidth = 0;
2101
+ for (const ch of para) {
2102
+ const cp2 = ch.codePointAt(0);
2103
+ const w = cp2 > 11904 ? 2 : 1;
2104
+ if (bufWidth + w > maxWidth && buf.length > 0) {
2105
+ result.push(buf);
2106
+ buf = ch;
2107
+ bufWidth = w;
2108
+ } else {
2109
+ buf += ch;
2110
+ bufWidth += w;
2111
+ }
2112
+ }
2113
+ if (buf.length > 0) result.push(buf);
2114
+ }
2115
+ return result;
2116
+ }
2117
+ function fmtNum(n) {
2118
+ return n.toLocaleString();
2119
+ }
2120
+ function CompactionProgress({ state, contentWidth }) {
2121
+ const percent = useMemo(() => estimateProgress(state), [state]);
2122
+ const phase = useMemo(() => phaseLabel(state), [state]);
2123
+ const summaryText = state.progress?.type === "summary_delta" ? state.progress.totalSoFar : state.progress?.type === "fallback" ? state.progress.fallbackSummary : state.phase === "done" && state.strategy === "summary" ? "" : "";
2124
+ const finalSummary = state.phase === "done" && state.strategy === "summary" ? state.progress?.type === "summary_delta" ? state.progress.totalSoFar : "" : summaryText;
2125
+ const titleColor = state.phase === "error" ? "#ff6347" : "#00ffff";
2126
+ return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsxs10(Box10, { flexDirection: "row", children: [
2127
+ /* @__PURE__ */ jsx10(Box10, { width: 1, backgroundColor: "#9b59b6", flexShrink: 0 }),
2128
+ /* @__PURE__ */ jsxs10(Box10, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: [
2129
+ /* @__PURE__ */ jsxs10(Box10, { children: [
2130
+ /* @__PURE__ */ jsx10(Text11, { bold: true, color: titleColor, children: "\u{1F5DC} \u4E0A\u4E0B\u6587\u538B\u7F29" }),
2131
+ /* @__PURE__ */ jsx10(Box10, { flexGrow: 1 }),
2132
+ state.phase === "running" && /* @__PURE__ */ jsxs10(Text11, { color: phase.color, children: [
2133
+ /* @__PURE__ */ jsx10(InkSpinner3, { type: "dots" }),
2134
+ " ",
2135
+ phase.text
2136
+ ] }),
2137
+ state.phase === "done" && /* @__PURE__ */ jsxs10(Text11, { color: phase.color, children: [
2138
+ phase.icon,
2139
+ " ",
2140
+ phase.text
2141
+ ] }),
2142
+ state.phase === "error" && /* @__PURE__ */ jsxs10(Text11, { color: phase.color, children: [
2143
+ phase.icon,
2144
+ " ",
2145
+ phase.text
2146
+ ] })
2147
+ ] }),
2148
+ /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
2149
+ /* @__PURE__ */ jsx10(Text11, { color: "#808080", children: "\u8FDB\u5EA6: " }),
2150
+ /* @__PURE__ */ jsx10(ProgressBar, { percent, color: state.phase === "error" ? "#ff6347" : phase.color })
2151
+ ] }),
2152
+ /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(PhaseSteps, { state }) }),
2153
+ (state.beforeTokens !== void 0 || state.droppedTurns !== void 0) && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
2154
+ state.droppedTurns !== void 0 && /* @__PURE__ */ jsxs10(Text11, { color: "#00ff41", children: [
2155
+ "\u{1F4CA} \u56DE\u5408: ",
2156
+ state.droppedTurns,
2157
+ " \u6298\u53E0 \u2192 ",
2158
+ state.keptTurns ?? 0,
2159
+ " \u4FDD\u7559"
2160
+ ] }),
2161
+ state.beforeTokens !== void 0 && /* @__PURE__ */ jsxs10(Text11, { color: "#ff9800", children: [
2162
+ "\u{1F4E6} token: ",
2163
+ fmtNum(state.beforeTokens),
2164
+ state.afterTokens !== void 0 && /* @__PURE__ */ jsxs10(Fragment2, { children: [
2165
+ " \u2192 ",
2166
+ /* @__PURE__ */ jsx10(Text11, { color: "#00ff41", bold: true, children: fmtNum(state.afterTokens) }),
2167
+ /* @__PURE__ */ jsxs10(Text11, { color: "#808080", children: [
2168
+ " (\u8282\u7701 ",
2169
+ ((state.beforeTokens - state.afterTokens) / Math.max(state.beforeTokens, 1) * 100).toFixed(1),
2170
+ "%)"
2171
+ ] })
2172
+ ] })
2173
+ ] })
2174
+ ] }),
2175
+ (state.phase === "running" || state.phase === "done") && finalSummary && /* @__PURE__ */ jsxs10(Box10, { marginTop: 1, flexDirection: "column", children: [
2176
+ /* @__PURE__ */ jsx10(Text11, { color: "#808080", children: "\u2504\u2504\u2504 LLM \u6458\u8981\u9884\u89C8 \u2504\u2504\u2504" }),
2177
+ /* @__PURE__ */ jsx10(SummaryPreview, { text: finalSummary, contentWidth })
2178
+ ] }),
2179
+ 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" }) }),
2180
+ state.phase === "error" && state.errorMessage && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text11, { color: "#ff6347", children: [
2181
+ "\u26A0 ",
2182
+ state.errorMessage
2183
+ ] }) })
2184
+ ] })
2185
+ ] }) });
2186
+ }
2187
+
1984
2188
  // package.json
1985
2189
  var package_default = {
1986
2190
  name: "dskcode",
1987
- version: "0.1.38",
2191
+ version: "0.1.40",
1988
2192
  repository: {
1989
2193
  type: "git",
1990
2194
  url: "git+https://github.com/Awu12277/deepseek-agent-cli/tree/main"
@@ -2267,6 +2471,239 @@ function buildApiMessages(systemPrompt, history) {
2267
2471
  ];
2268
2472
  }
2269
2473
 
2474
+ // src/agent/compactor.ts
2475
+ var DEFAULT_AUTO_COMPACT_RATIO = 0.85;
2476
+ var DEFAULT_PRESERVE_ROUNDS = 6;
2477
+ var DEFAULT_MIN_TURNS_TO_COMPACT = 8;
2478
+ var SUMMARY_SENTINEL = "[history-summary]";
2479
+ 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
2480
+
2481
+ \u6458\u8981\u5FC5\u987B\u4FDD\u7559\u4EE5\u4E0B\u4FE1\u606F\uFF08\u6309\u91CD\u8981\u6027\u6392\u5E8F\uFF09\uFF1A
2482
+ 1. \u7528\u6237\u7684\u6838\u5FC3\u76EE\u6807\u4E0E\u6700\u7EC8\u610F\u56FE
2483
+ 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
2484
+ 3. \u6D89\u53CA\u7684\u5177\u4F53\u6587\u4EF6\u8DEF\u5F84\uFF08\u7EDD\u5BF9/\u76F8\u5BF9\u8DEF\u5F84\u90FD\u8981\u4FDD\u7559\uFF09
2485
+ 4. \u51FA\u73B0\u8FC7\u7684\u9519\u8BEF\u4FE1\u606F\u4E0E\u89E3\u51B3\u65B9\u6848
2486
+ 5. \u5C1A\u672A\u5B8C\u6210\u7684\u5DE5\u4F5C / \u5F85\u529E\u4E8B\u9879
2487
+ 6. \u91CD\u8981\u7684\u6280\u672F\u7EA6\u675F\uFF08\u5982"\u4E0D\u80FD\u7528 XX \u5E93"\uFF09
2488
+
2489
+ \u683C\u5F0F\u8981\u6C42\uFF1A
2490
+ - \u7528\u7EAF\u6587\u672C\uFF0C\u4E0D\u8981 markdown \u6807\u9898\u5206\u7EA7
2491
+ - \u6BCF\u6761\u4FE1\u606F\u72EC\u7ACB\u6210\u884C\uFF0C\u65B9\u4FBF\u540E\u7EED\u6309\u884C\u89E3\u6790
2492
+ - \u603B\u957F\u5EA6\u63A7\u5236\u5728 2000 \u5B57\u4EE5\u5185
2493
+ - \u4E0D\u9700\u8981\u5BA2\u5957\u8BDD\u3001\u4E0D\u9700\u8981"\u4EE5\u4E0B\u662F\u6458\u8981"\u7B49\u5F00\u5934
2494
+ `;
2495
+ var PER_MESSAGE_TEXT_LIMIT = 500;
2496
+ var FALLBACK_USER_PREVIEW = 60;
2497
+ function estimateMessageTokens2(msg) {
2498
+ let text = msg.content;
2499
+ if (msg.toolCalls) {
2500
+ for (const tc of msg.toolCalls) {
2501
+ text += tc.name + tc.arguments;
2502
+ }
2503
+ }
2504
+ return estimateTokens(text) + 10;
2505
+ }
2506
+ function estimateMessagesTokens(messages) {
2507
+ let sum = 0;
2508
+ for (const m of messages) sum += estimateMessageTokens2(m);
2509
+ return sum;
2510
+ }
2511
+ function getContextStats(messages, contextWindow) {
2512
+ const estimatedTokens = estimateMessagesTokens(messages);
2513
+ const ratio = contextWindow > 0 ? estimatedTokens / contextWindow : 0;
2514
+ return {
2515
+ messageCount: messages.length,
2516
+ estimatedTokens,
2517
+ contextWindow,
2518
+ ratio,
2519
+ headroom: contextWindow - estimatedTokens
2520
+ };
2521
+ }
2522
+ function shouldAutoCompact(messages, opts) {
2523
+ const turns = groupIntoTurns(messages);
2524
+ const minTurns = opts.minTurnsToCompact ?? DEFAULT_MIN_TURNS_TO_COMPACT;
2525
+ if (turns.length < minTurns) return false;
2526
+ const ratio = opts.autoCompactRatio ?? DEFAULT_AUTO_COMPACT_RATIO;
2527
+ const stats = getContextStats(messages, opts.contextWindow);
2528
+ return stats.ratio >= ratio;
2529
+ }
2530
+ function turnsToPromptText(turns) {
2531
+ const lines = [];
2532
+ for (let i = 0; i < turns.length; i++) {
2533
+ const turn = turns[i];
2534
+ lines.push(`--- \u7B2C ${i + 1} \u56DE\u5408 ---`);
2535
+ for (const msg of turn) {
2536
+ const head = `[${msg.role}]`;
2537
+ 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;
2538
+ lines.push(`${head} ${body}`);
2539
+ if (msg.toolCalls) {
2540
+ for (const tc of msg.toolCalls) {
2541
+ lines.push(` tool_call: ${tc.name}(${tc.arguments})`);
2542
+ }
2543
+ }
2544
+ }
2545
+ }
2546
+ return lines.join("\n");
2547
+ }
2548
+ function fallbackSummary(turns) {
2549
+ const lines = ["\u3010\u672C\u5730\u6458\u8981\uFF08LLM \u8C03\u7528\u5931\u8D25\u65F6\u515C\u5E95\uFF09\u3011"];
2550
+ for (let i = 0; i < turns.length; i++) {
2551
+ const turn = turns[i];
2552
+ const userMsg = turn.find((m) => m.role === "user");
2553
+ if (userMsg) {
2554
+ const preview = userMsg.content.slice(0, FALLBACK_USER_PREVIEW);
2555
+ lines.push(`\u56DE\u5408${i + 1} \u7528\u6237: ${preview}`);
2556
+ }
2557
+ const toolNames = /* @__PURE__ */ new Set();
2558
+ for (const m of turn) {
2559
+ if (m.toolCalls) for (const tc of m.toolCalls) toolNames.add(tc.name);
2560
+ }
2561
+ if (toolNames.size > 0) {
2562
+ lines.push(` \u8C03\u7528\u5DE5\u5177: ${[...toolNames].join(", ")}`);
2563
+ }
2564
+ }
2565
+ return lines.join("\n");
2566
+ }
2567
+ async function summarizeOldTurns(oldTurns, opts) {
2568
+ if (oldTurns.length === 0) return "";
2569
+ const promptText = turnsToPromptText(oldTurns);
2570
+ try {
2571
+ const messages = [
2572
+ { role: "system", content: SUMMARY_SYSTEM_PROMPT },
2573
+ {
2574
+ role: "user",
2575
+ content: `\u8BF7\u628A\u4EE5\u4E0B ${oldTurns.length} \u8F6E\u5BF9\u8BDD\u5386\u53F2\u538B\u7F29\u6210\u7ED3\u6784\u5316\u6458\u8981\uFF1A
2576
+
2577
+ ${promptText}`
2578
+ }
2579
+ ];
2580
+ const stream = opts.provider.chat(messages, {
2581
+ ...opts.signal ? { signal: opts.signal } : {},
2582
+ // 摘要场景压低温度,输出更稳定
2583
+ temperature: 0.2
2584
+ });
2585
+ let summary = "";
2586
+ for await (const chunk of stream) {
2587
+ if (chunk.content) {
2588
+ summary += chunk.content;
2589
+ if (opts.onProgress) {
2590
+ try {
2591
+ opts.onProgress({
2592
+ type: "summary_delta",
2593
+ delta: chunk.content,
2594
+ totalSoFar: summary
2595
+ });
2596
+ } catch {
2597
+ }
2598
+ }
2599
+ }
2600
+ }
2601
+ if (!summary.trim()) {
2602
+ const fb = fallbackSummary(oldTurns);
2603
+ if (opts.onProgress) {
2604
+ try {
2605
+ opts.onProgress({
2606
+ type: "fallback",
2607
+ reason: "LLM \u8FD4\u56DE\u7A7A\u5B57\u7B26\u4E32",
2608
+ fallbackSummary: fb
2609
+ });
2610
+ } catch {
2611
+ }
2612
+ }
2613
+ return fb;
2614
+ }
2615
+ return summary.trim();
2616
+ } catch (err) {
2617
+ const errMsg = err instanceof Error ? err.message : String(err);
2618
+ const fb = fallbackSummary(oldTurns);
2619
+ if (opts.onProgress) {
2620
+ try {
2621
+ opts.onProgress({
2622
+ type: "fallback",
2623
+ reason: errMsg,
2624
+ fallbackSummary: fb
2625
+ });
2626
+ } catch {
2627
+ }
2628
+ }
2629
+ return fb;
2630
+ }
2631
+ }
2632
+ function buildSummaryMessage(summary) {
2633
+ return {
2634
+ role: "system",
2635
+ content: `${SUMMARY_SENTINEL}
2636
+ ${summary}`
2637
+ };
2638
+ }
2639
+ async function compactContext(messages, opts) {
2640
+ const beforeTokens = estimateMessagesTokens(messages);
2641
+ const turns = groupIntoTurns(messages);
2642
+ const minTurns = opts.minTurnsToCompact ?? DEFAULT_MIN_TURNS_TO_COMPACT;
2643
+ const preserveRounds = opts.preserveRecentRounds ?? DEFAULT_PRESERVE_ROUNDS;
2644
+ if (turns.length < minTurns) {
2645
+ return {
2646
+ messages: messages.slice(),
2647
+ summary: "",
2648
+ droppedTurns: 0,
2649
+ keptTurns: turns.length,
2650
+ beforeTokens,
2651
+ afterTokens: beforeTokens
2652
+ };
2653
+ }
2654
+ if (turns.length <= preserveRounds) {
2655
+ return {
2656
+ messages: messages.slice(),
2657
+ summary: "",
2658
+ droppedTurns: 0,
2659
+ keptTurns: turns.length,
2660
+ beforeTokens,
2661
+ afterTokens: beforeTokens
2662
+ };
2663
+ }
2664
+ const splitAt = turns.length - preserveRounds;
2665
+ const oldTurns = turns.slice(0, splitAt);
2666
+ const keptTurns = turns.slice(splitAt);
2667
+ if (opts.onProgress) {
2668
+ try {
2669
+ opts.onProgress({
2670
+ type: "start",
2671
+ droppedTurns: oldTurns.length,
2672
+ beforeTokens
2673
+ });
2674
+ } catch {
2675
+ }
2676
+ }
2677
+ const summary = await summarizeOldTurns(oldTurns, opts);
2678
+ const newMessages = [buildSummaryMessage(summary)];
2679
+ for (const turn of keptTurns) {
2680
+ for (const msg of turn) {
2681
+ newMessages.push(msg);
2682
+ }
2683
+ }
2684
+ const afterTokens = estimateMessagesTokens(newMessages);
2685
+ if (opts.onProgress) {
2686
+ try {
2687
+ opts.onProgress({
2688
+ type: "done",
2689
+ droppedTurns: oldTurns.length,
2690
+ keptTurns: keptTurns.length,
2691
+ beforeTokens,
2692
+ afterTokens
2693
+ });
2694
+ } catch {
2695
+ }
2696
+ }
2697
+ return {
2698
+ messages: newMessages,
2699
+ summary,
2700
+ droppedTurns: oldTurns.length,
2701
+ keptTurns: keptTurns.length,
2702
+ beforeTokens,
2703
+ afterTokens
2704
+ };
2705
+ }
2706
+
2270
2707
  // src/tool/registry.ts
2271
2708
  var ToolRegistry = class {
2272
2709
  #tools = /* @__PURE__ */ new Map();
@@ -3716,13 +4153,17 @@ var Session = class _Session {
3716
4153
  maxToolRounds: options?.maxToolRounds ?? 20,
3717
4154
  reservedForOutput: options?.reservedForOutput ?? 4096,
3718
4155
  preserveRecentRounds: options?.preserveRecentRounds ?? 10,
4156
+ autoCompactRatio: options?.autoCompactRatio ?? DEFAULT_AUTO_COMPACT_RATIO,
4157
+ preserveRecentRoundsOnCompact: options?.preserveRecentRoundsOnCompact ?? DEFAULT_PRESERVE_ROUNDS,
4158
+ minTurnsToCompact: options?.minTurnsToCompact ?? DEFAULT_MIN_TURNS_TO_COMPACT,
3719
4159
  projectContext: options?.projectContext,
3720
4160
  gate: options?.gate ?? new AlwaysAllowGate(),
3721
4161
  writeRoots: options?.writeRoots ?? [options?.cwd ?? process.cwd()],
3722
4162
  enableCheckpoint: options?.enableCheckpoint ?? true,
3723
4163
  enableLog: options?.enableLog ?? true,
3724
4164
  enableReflection: options?.enableReflection !== false,
3725
- enableHarness: options?.enableHarness !== false
4165
+ enableHarness: options?.enableHarness !== false,
4166
+ enableAutoCompact: options?.enableAutoCompact !== false
3726
4167
  };
3727
4168
  this.#sessionId = options?.sessionId ?? SessionStore.newId();
3728
4169
  this.#store = options?.store === false ? null : options?.store ?? new SessionStore();
@@ -3823,6 +4264,19 @@ var Session = class _Session {
3823
4264
  } catch {
3824
4265
  }
3825
4266
  }
4267
+ if (this.#options.enableAutoCompact) {
4268
+ const compaction = await this.#maybeAutoCompact();
4269
+ if (compaction) {
4270
+ yield {
4271
+ type: "compaction",
4272
+ droppedTurns: compaction.droppedTurns,
4273
+ keptTurns: compaction.keptTurns,
4274
+ beforeTokens: compaction.beforeTokens,
4275
+ afterTokens: compaction.afterTokens,
4276
+ strategy: compaction.strategy
4277
+ };
4278
+ }
4279
+ }
3826
4280
  const startTime = Date.now();
3827
4281
  let toolRounds = 0;
3828
4282
  const toolExecutor = this.#buildToolExecutor();
@@ -4077,6 +4531,79 @@ ${item.result.diff.patch}`;
4077
4531
  this.#checkpoints.clear();
4078
4532
  this.#lastRoundResults = null;
4079
4533
  }
4534
+ // -------------------------------------------------------------------------
4535
+ // 上下文压缩(Compactor) — P0-1 实施
4536
+ // -------------------------------------------------------------------------
4537
+ /**
4538
+ * 获取当前上下文的统计信息(消息数、估算 token、占窗口比例)。
4539
+ * 用于 UI 状态栏展示和自动压缩阈值判断。
4540
+ *
4541
+ * @returns ContextStats;contextWindow 取自当前模型的 meta.contextWindow
4542
+ *
4543
+ * @pure 不修改任何状态
4544
+ */
4545
+ getContextStats() {
4546
+ const meta = getModelMeta(this.#provider.model());
4547
+ return getContextStats(this.#messages, meta.contextWindow);
4548
+ }
4549
+ /**
4550
+ * 手动触发上下文压缩。
4551
+ * 与自动压缩逻辑复用同一个 compactContext();若回合数过少则返回空结果(droppedTurns=0)。
4552
+ * 可被 UI 的 /compact 命令调用。
4553
+ *
4554
+ * @param onProgress — 可选进度回调(UI 实时展示压缩进度)
4555
+ * @returns 压缩结果;droppedTurns=0 表示无实际压缩发生
4556
+ *
4557
+ * @sideEffect 可能调一次 provider.chat()(LLM 摘要);成功后改写 #messages
4558
+ */
4559
+ async compact(onProgress) {
4560
+ const meta = getModelMeta(this.#provider.model());
4561
+ const result = await compactContext(this.#messages, {
4562
+ contextWindow: meta.contextWindow,
4563
+ autoCompactRatio: this.#options.autoCompactRatio,
4564
+ preserveRecentRounds: this.#options.preserveRecentRoundsOnCompact,
4565
+ minTurnsToCompact: this.#options.minTurnsToCompact,
4566
+ provider: this.#provider,
4567
+ signal: this.#abortController.signal,
4568
+ ...onProgress ? { onProgress } : {}
4569
+ });
4570
+ if (result.droppedTurns > 0) {
4571
+ this.#messages.length = 0;
4572
+ for (const m of result.messages) this.#messages.push(m);
4573
+ this.#checkpoints.clear();
4574
+ this.#persist();
4575
+ }
4576
+ return result;
4577
+ }
4578
+ /**
4579
+ * chat() 入口调用的自动压缩检查。
4580
+ * 仅在 enableAutoCompact=true 且应自动压缩时执行;否则返回 null。
4581
+ * 策略与 compact() 相同;返回值额外补上 strategy("summary" | "fallback")供 chat 事件使用。
4582
+ *
4583
+ * @returns 压缩结果;未压缩时返回 null
4584
+ *
4585
+ * @sideEffect 同 compact()
4586
+ */
4587
+ async #maybeAutoCompact() {
4588
+ const meta = getModelMeta(this.#provider.model());
4589
+ const opts = {
4590
+ contextWindow: meta.contextWindow,
4591
+ autoCompactRatio: this.#options.autoCompactRatio,
4592
+ preserveRecentRounds: this.#options.preserveRecentRoundsOnCompact,
4593
+ minTurnsToCompact: this.#options.minTurnsToCompact,
4594
+ provider: this.#provider,
4595
+ signal: this.#abortController.signal
4596
+ };
4597
+ if (!shouldAutoCompact(this.#messages, opts)) return null;
4598
+ const result = await compactContext(this.#messages, opts);
4599
+ if (result.droppedTurns === 0) return null;
4600
+ const strategy = result.summary.includes("\u672C\u5730\u6458\u8981") ? "fallback" : "summary";
4601
+ this.#messages.length = 0;
4602
+ for (const m of result.messages) this.#messages.push(m);
4603
+ this.#checkpoints.clear();
4604
+ this.#persist();
4605
+ return { ...result, strategy };
4606
+ }
4080
4607
  /**
4081
4608
  * 立即把当前状态写入持久化(不等 500ms debounce)。
4082
4609
  * 用于 UI 上"立即保存"按钮或异常退出前的最后兜底。
@@ -5873,15 +6400,15 @@ var GRADIENT_ANIMATION = {
5873
6400
  /** 空闲占位符动画:每帧相位步进(值越大流速越快) */
5874
6401
  idlePhaseStep: 0.06,
5875
6402
  /** 空闲占位符动画:帧间隔(ms) */
5876
- idleInterval: 40,
6403
+ idleInterval: 200,
5877
6404
  /** 流式占位符动画:每帧相位步进 */
5878
- streamingPhaseStep: 0.05,
6405
+ streamingPhaseStep: 0.2,
5879
6406
  /** 流式占位符动画:帧间隔(ms) */
5880
- streamingInterval: 40,
6407
+ streamingInterval: 200,
5881
6408
  /** 命令提示条动画:每帧相位步进 */
5882
- cmdTipPhaseStep: 0.05,
6409
+ cmdTipPhaseStep: 0.2,
5883
6410
  /** 命令提示条动画:帧间隔(ms) */
5884
- cmdTipInterval: 40
6411
+ cmdTipInterval: 200
5885
6412
  };
5886
6413
  var SKIP_CHARS = /* @__PURE__ */ new Set([" ", "~", ".", "\u3002", "\uFF01", "\u{1F447}"]);
5887
6414
  function lerpStopsToHex(t, stops) {
@@ -5913,9 +6440,9 @@ function joinReasoningSegments(segments) {
5913
6440
  }
5914
6441
 
5915
6442
  // src/ui/AnimatedLogo.tsx
5916
- import { Box as Box10, Text as Text11 } from "ink";
6443
+ import { Box as Box11, Text as Text12 } from "ink";
5917
6444
  import { useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
5918
- import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
6445
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
5919
6446
  var LOGO_LINES2 = [
5920
6447
  " \u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2588 \u2588\u2584 \u2584\u2584",
5921
6448
  " \u2584\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2584\u2584\u2580\u2588\u2588\u2588\u2580\u2580",
@@ -5944,14 +6471,14 @@ function AnimatedLogo({ panelWidth }) {
5944
6471
  const leftClip = Math.max(0, -pos);
5945
6472
  const rightClip = Math.max(0, pos + LOGO_WIDTH - panelWidth);
5946
6473
  const padding = Math.max(0, pos);
5947
- return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", alignItems: "flex-start", children: LOGO_LINES2.map((line, i) => /* @__PURE__ */ jsxs10(Text11, { color: LOGO_COLOR, bold: true, children: [
6474
+ 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
6475
  " ".repeat(padding),
5949
6476
  line.slice(leftClip, LOGO_WIDTH - rightClip)
5950
6477
  ] }, i)) });
5951
6478
  }
5952
6479
 
5953
6480
  // src/ui/ChatSession.tsx
5954
- import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
6481
+ import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
5955
6482
  var PHASE_CONFIG = {
5956
6483
  thinking: { icon: "\u{1F9E0}", label: "\u601D\u8003\u4E2D", color: "#ff9800" },
5957
6484
  generating: { icon: "\u2728", label: "\u751F\u6210\u4E2D", color: "#00ff41" },
@@ -6026,6 +6553,13 @@ registerCommand("/rewind", {
6026
6553
  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
6554
  })
6028
6555
  });
6556
+ registerCommand("/compact", {
6557
+ desc: "\u538B\u7F29\u4E0A\u4E0B\u6587\uFF1A\u6458\u8981\u65E7\u56DE\u5408\u5E76\u4FDD\u7559\u6700\u8FD1 N \u8F6E",
6558
+ handler: () => ({
6559
+ kind: "text",
6560
+ 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"
6561
+ })
6562
+ });
6029
6563
  var STREAMING_PLACEHOLDERS = [
6030
6564
  "\u8BA9\u5B50\u5F39\u98DE\u4E00\u4F1A\u513F...",
6031
6565
  "\u9A6C\u4E0A\u5C31\u597D...",
@@ -6069,6 +6603,7 @@ function ChatSession({
6069
6603
  const [balance, setBalance] = useState5(null);
6070
6604
  const [balanceLoading, setBalanceLoading] = useState5(false);
6071
6605
  const [todayCost, setTodayCost] = useState5(null);
6606
+ const [contextStats, setContextStats] = useState5(null);
6072
6607
  const [isStreaming, setIsStreaming] = useState5(false);
6073
6608
  const [streamingPhase, setStreamingPhase] = useState5(null);
6074
6609
  const [streamingPlaceholder, setStreamingPlaceholder] = useState5("");
@@ -6099,7 +6634,7 @@ function ChatSession({
6099
6634
  const [toolChoice, setToolChoice] = useState5(
6100
6635
  void 0
6101
6636
  );
6102
- const sessionCost = useMemo(() => {
6637
+ const sessionCost = useMemo2(() => {
6103
6638
  return displayMessages.reduce((sum, msg) => {
6104
6639
  if (msg.assistantDetail?.cost) {
6105
6640
  return sum + msg.assistantDetail.cost;
@@ -6128,6 +6663,12 @@ function ChatSession({
6128
6663
  const [selectingModel, setSelectingModel] = useState5(false);
6129
6664
  const [modelSelectIndex, setModelSelectIndex] = useState5(0);
6130
6665
  const modelOptions = ["deepseek-v4-flash", "deepseek-v4-pro"];
6666
+ const [compactionState, setCompactionState] = useState5({
6667
+ phase: "idle",
6668
+ progress: null
6669
+ });
6670
+ const compactionSettleTimerRef = useRef4(null);
6671
+ const compactionStrategyRef = useRef4(void 0);
6131
6672
  const sessionRef = useRef4(null);
6132
6673
  const abortRef = useRef4(null);
6133
6674
  const currentContentRef = useRef4("");
@@ -6148,7 +6689,33 @@ function ChatSession({
6148
6689
  clearTimeout(rewindHintTimerRef.current);
6149
6690
  rewindHintTimerRef.current = null;
6150
6691
  }
6692
+ if (compactionSettleTimerRef.current) {
6693
+ clearTimeout(compactionSettleTimerRef.current);
6694
+ compactionSettleTimerRef.current = null;
6695
+ }
6696
+ };
6697
+ }, []);
6698
+ useEffect5(() => {
6699
+ const refresh = () => {
6700
+ const session = sessionRef.current;
6701
+ if (!session) {
6702
+ setContextStats(null);
6703
+ return;
6704
+ }
6705
+ try {
6706
+ const s = session.getContextStats();
6707
+ setContextStats({
6708
+ tokens: s.estimatedTokens,
6709
+ ratio: s.ratio,
6710
+ contextWindow: s.contextWindow
6711
+ });
6712
+ } catch {
6713
+ setContextStats(null);
6714
+ }
6151
6715
  };
6716
+ refresh();
6717
+ const id = setInterval(refresh, 3e3);
6718
+ return () => clearInterval(id);
6152
6719
  }, []);
6153
6720
  useEffect5(() => {
6154
6721
  if (todoHideTimerRef.current) {
@@ -6641,6 +7208,146 @@ function ChatSession({
6641
7208
  setInput("");
6642
7209
  return;
6643
7210
  }
7211
+ if (cmdLower === "/compact") {
7212
+ if (isStreaming) {
7213
+ setDisplayMessages((prev) => [
7214
+ ...prev,
7215
+ { role: "user", content: trimmed },
7216
+ { role: "assistant", content: "\u26A0 \u6B63\u5728\u751F\u6210\u4E2D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5 /compact\u3002" }
7217
+ ]);
7218
+ setInput("");
7219
+ return;
7220
+ }
7221
+ if (!sessionRef.current) {
7222
+ setDisplayMessages((prev) => [
7223
+ ...prev,
7224
+ { role: "user", content: trimmed },
7225
+ { role: "assistant", content: "\u26A0 Session \u672A\u5C31\u7EEA\uFF0C\u65E0\u6CD5\u538B\u7F29\u3002" }
7226
+ ]);
7227
+ setInput("");
7228
+ return;
7229
+ }
7230
+ setInput("");
7231
+ setDisplayMessages((prev) => [...prev, { role: "user", content: trimmed }]);
7232
+ setCompactionState({
7233
+ phase: "running",
7234
+ progress: null,
7235
+ beforeTokens: void 0,
7236
+ afterTokens: void 0,
7237
+ droppedTurns: void 0,
7238
+ keptTurns: void 0,
7239
+ strategy: void 0,
7240
+ errorMessage: void 0
7241
+ });
7242
+ try {
7243
+ const result = await sessionRef.current.compact(
7244
+ (event) => {
7245
+ setCompactionState((prev) => {
7246
+ if (event.type === "start") {
7247
+ return {
7248
+ ...prev,
7249
+ phase: "running",
7250
+ progress: event,
7251
+ beforeTokens: event.beforeTokens,
7252
+ droppedTurns: event.droppedTurns
7253
+ };
7254
+ }
7255
+ if (event.type === "summary_delta") {
7256
+ return {
7257
+ ...prev,
7258
+ phase: "running",
7259
+ progress: event
7260
+ };
7261
+ }
7262
+ if (event.type === "fallback") {
7263
+ compactionStrategyRef.current = "fallback";
7264
+ return {
7265
+ ...prev,
7266
+ phase: "running",
7267
+ progress: event,
7268
+ strategy: "fallback"
7269
+ };
7270
+ }
7271
+ if (event.type === "done") {
7272
+ const finalStrategy = compactionStrategyRef.current === "fallback" ? "fallback" : "summary";
7273
+ compactionStrategyRef.current = finalStrategy;
7274
+ return {
7275
+ ...prev,
7276
+ phase: "done",
7277
+ progress: event,
7278
+ droppedTurns: event.droppedTurns,
7279
+ keptTurns: event.keptTurns,
7280
+ beforeTokens: event.beforeTokens,
7281
+ afterTokens: event.afterTokens,
7282
+ strategy: finalStrategy
7283
+ };
7284
+ }
7285
+ return prev;
7286
+ });
7287
+ }
7288
+ );
7289
+ if (result.droppedTurns === 0) {
7290
+ setCompactionState((prev) => ({
7291
+ ...prev,
7292
+ phase: "done",
7293
+ progress: prev.progress,
7294
+ droppedTurns: 0,
7295
+ keptTurns: result.keptTurns,
7296
+ beforeTokens: result.beforeTokens,
7297
+ afterTokens: result.afterTokens,
7298
+ strategy: void 0
7299
+ }));
7300
+ if (compactionSettleTimerRef.current) {
7301
+ clearTimeout(compactionSettleTimerRef.current);
7302
+ }
7303
+ compactionSettleTimerRef.current = setTimeout(() => {
7304
+ setCompactionState({ phase: "idle", progress: null });
7305
+ setDisplayMessages((prev) => [
7306
+ ...prev,
7307
+ {
7308
+ role: "assistant",
7309
+ 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"
7310
+ }
7311
+ ]);
7312
+ }, 2500);
7313
+ } else {
7314
+ if (compactionSettleTimerRef.current) {
7315
+ clearTimeout(compactionSettleTimerRef.current);
7316
+ }
7317
+ compactionSettleTimerRef.current = setTimeout(() => {
7318
+ const ratioSaved = ((result.beforeTokens - result.afterTokens) / Math.max(result.beforeTokens, 1) * 100).toFixed(1);
7319
+ const strategyNote = compactionStrategyRef.current === "fallback" ? "\n\u26A0 \u6458\u8981\u4E3A\u672C\u5730\u5151\u5E95\uFF08LLM \u4E0D\u53EF\u7528\uFF09" : "";
7320
+ setCompactionState({ phase: "idle", progress: null });
7321
+ compactionStrategyRef.current = void 0;
7322
+ setDisplayMessages((prev) => [
7323
+ ...prev,
7324
+ {
7325
+ role: "assistant",
7326
+ content: `\u2714 \u538B\u7F29\u5B8C\u6210\uFF1A${result.droppedTurns} \u56DE\u5408 \u2192 ${result.keptTurns} \u56DE\u5408\uFF08\u8282\u7701 ${ratioSaved}% token\uFF09${strategyNote}`
7327
+ }
7328
+ ]);
7329
+ }, 4e3);
7330
+ }
7331
+ } catch (err) {
7332
+ const msg = err instanceof Error ? err.message : String(err);
7333
+ setCompactionState((prev) => ({
7334
+ ...prev,
7335
+ phase: "error",
7336
+ errorMessage: msg
7337
+ }));
7338
+ if (compactionSettleTimerRef.current) {
7339
+ clearTimeout(compactionSettleTimerRef.current);
7340
+ }
7341
+ compactionSettleTimerRef.current = setTimeout(() => {
7342
+ setCompactionState({ phase: "idle", progress: null });
7343
+ setDisplayMessages((prev) => [
7344
+ ...prev,
7345
+ { role: "assistant", content: `\u26A0 \u538B\u7F29\u5931\u8D25\uFF1A${msg}` }
7346
+ ]);
7347
+ }, 3e3);
7348
+ }
7349
+ return;
7350
+ }
6644
7351
  if (cmdLower === "/model") {
6645
7352
  const curIdx = modelOptions.indexOf(activeModel);
6646
7353
  setModelSelectIndex(curIdx >= 0 ? curIdx : 0);
@@ -6829,6 +7536,12 @@ function ChatSession({
6829
7536
  todoHideTimerRef.current = null;
6830
7537
  }
6831
7538
  setTodoPanelVisible(false);
7539
+ setCompactionState({ phase: "idle", progress: null });
7540
+ compactionStrategyRef.current = void 0;
7541
+ if (compactionSettleTimerRef.current) {
7542
+ clearTimeout(compactionSettleTimerRef.current);
7543
+ compactionSettleTimerRef.current = null;
7544
+ }
6832
7545
  const session = sessionRef.current;
6833
7546
  const abortController = new AbortController();
6834
7547
  abortRef.current = abortController;
@@ -7002,108 +7715,104 @@ function ChatSession({
7002
7715
  setTodayCost(externalCostTracker.todayTotalCost);
7003
7716
  }
7004
7717
  }, [isStreaming, externalCostTracker]);
7005
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
7006
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", flexGrow: 1, children: [
7007
- /* @__PURE__ */ jsx11(
7008
- Box11,
7718
+ return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, children: [
7719
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", flexGrow: 1, children: [
7720
+ /* @__PURE__ */ jsx12(
7721
+ Box12,
7009
7722
  {
7010
7723
  width: leftPanelWidth,
7011
7724
  flexShrink: 0,
7012
7725
  flexDirection: "column",
7013
- children: /* @__PURE__ */ jsx11(
7014
- Box11,
7726
+ children: /* @__PURE__ */ jsx12(
7727
+ Box12,
7015
7728
  {
7016
- borderStyle: "single",
7017
- borderColor: "#333333",
7018
7729
  paddingX: 1,
7019
7730
  flexDirection: "column",
7020
7731
  flexGrow: 1,
7021
7732
  justifyContent: !hasConversationStarted ? "center" : "flex-end",
7022
7733
  children: !hasConversationStarted ? (
7023
7734
  /* ===== 首页:Logo + 状态概况 ===== */
7024
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "center", children: [
7735
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", alignItems: "center", children: [
7025
7736
  LOGO_LINES.map((line, i) => {
7026
7737
  const colorIndex = (i + offset) % CYBER_PALETTE.length;
7027
- return /* @__PURE__ */ jsx11(Text12, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }, i);
7738
+ return /* @__PURE__ */ jsx12(Text13, { bold: true, color: CYBER_PALETTE[colorIndex], children: line }, i);
7028
7739
  }),
7029
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: "#808080", children: [
7740
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
7030
7741
  "\u{1F4E6} v",
7031
7742
  VERSION
7032
7743
  ] }) }),
7033
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7034
- /* @__PURE__ */ jsxs11(Text12, { color: "#00ff41", children: [
7744
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7745
+ /* @__PURE__ */ jsxs12(Text13, { color: "#00ff41", children: [
7035
7746
  "\u2714 ",
7036
7747
  skillCount,
7037
7748
  " Skills"
7038
7749
  ] }),
7039
- /* @__PURE__ */ jsxs11(Text12, { color: "#00ffff", children: [
7750
+ /* @__PURE__ */ jsxs12(Text13, { color: "#00ffff", children: [
7040
7751
  "\u2139 ",
7041
7752
  toolCount,
7042
7753
  " \u5DE5\u5177"
7043
7754
  ] }),
7044
- /* @__PURE__ */ jsxs11(Text12, { color: "#00ffff", children: [
7755
+ /* @__PURE__ */ jsxs12(Text13, { color: "#00ffff", children: [
7045
7756
  "\u{1F527} ",
7046
7757
  SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
7047
7758
  ] }),
7048
- thinkingEnabled && /* @__PURE__ */ jsxs11(Text12, { color: "#ff9800", children: [
7759
+ thinkingEnabled && /* @__PURE__ */ jsxs12(Text13, { color: "#ff9800", children: [
7049
7760
  "\u{1F9E0} \u6DF1\u5EA6\u601D\u8003 ",
7050
7761
  thinkingEffort === "max" ? "Max" : "High"
7051
7762
  ] }),
7052
- sessionMode === "plan" && /* @__PURE__ */ jsx11(Text12, { color: "#ff69b4", bold: true, children: "\u{1F4CB} \u8BA1\u5212\u6A21\u5F0F" })
7763
+ sessionMode === "plan" && /* @__PURE__ */ jsx12(Text13, { color: "#ff69b4", bold: true, children: "\u{1F4CB} \u8BA1\u5212\u6A21\u5F0F" })
7053
7764
  ] }),
7054
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7055
- balance !== null ? /* @__PURE__ */ jsxs11(Text12, { color: "yellow", children: [
7765
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7766
+ balance !== null ? /* @__PURE__ */ jsxs12(Text13, { color: "yellow", children: [
7056
7767
  "\u{1F4B0} \u4F59\u989D \xA5",
7057
7768
  balance.toFixed(2)
7058
- ] }) : balanceLoading ? /* @__PURE__ */ jsx11(Text12, { color: "yellow", children: "\u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : null,
7059
- todayCost !== null && /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
7769
+ ] }) : balanceLoading ? /* @__PURE__ */ jsx12(Text13, { color: "yellow", children: "\u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : null,
7770
+ todayCost !== null && /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
7060
7771
  "\u{1F4CA} \u4ECA\u65E5 \xA5",
7061
7772
  todayCost.toFixed(2)
7062
7773
  ] })
7063
7774
  ] }),
7064
- verbose && /* @__PURE__ */ jsx11(Text12, { color: "#ff1493", children: "\u26A1 Verbose" })
7775
+ verbose && /* @__PURE__ */ jsx12(Text13, { color: "#ff1493", children: "\u26A1 Verbose" })
7065
7776
  ] })
7066
7777
  ) : hasReasoningPanel ? (
7067
- /* ===== 流式思考中:截断至最新12行,空行填充维持固定高度 ===== */
7068
- /* @__PURE__ */ jsxs11(Fragment2, { children: [
7069
- /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#ff9800", children: "\u{1F9E0} \u6DF1\u5EA6\u601D\u8003ing" }),
7070
- /* @__PURE__ */ jsx11(Text12, { dimColor: true, wrap: "wrap", children: (() => {
7071
- const full = joinReasoningSegments(currentReasoning);
7072
- const maxContentLines = 11;
7073
- const lines = full.split("\n");
7074
- const kept = lines.slice(-maxContentLines);
7075
- while (kept.length < maxContentLines) {
7076
- kept.unshift("");
7077
- }
7078
- return kept.join("\n");
7079
- })() })
7080
- ] })
7778
+ /* ===== 流式思考中(纯文本,无边框) ===== */
7779
+ /* @__PURE__ */ jsx12(Text13, { dimColor: true, wrap: "wrap", children: (() => {
7780
+ const full = joinReasoningSegments(currentReasoning);
7781
+ const maxContentLines = 11;
7782
+ const lines = full.split("\n");
7783
+ const kept = lines.slice(-maxContentLines);
7784
+ while (kept.length < maxContentLines) {
7785
+ kept.unshift("");
7786
+ }
7787
+ return kept.join("\n");
7788
+ })() })
7081
7789
  ) : (
7082
7790
  /* ===== 对话中(无思考):会话状态面板 ===== */
7083
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "center", children: [
7084
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", bold: true, children: "\u{1F4AC} \u5BF9\u8BDD\u8FDB\u884C\u4E2D" }),
7085
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7086
- /* @__PURE__ */ jsxs11(Text12, { color: "#00ff41", children: [
7791
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", alignItems: "center", children: [
7792
+ /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", bold: true, children: "\u{1F4AC} \u5BF9\u8BDD\u8FDB\u884C\u4E2D" }),
7793
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7794
+ /* @__PURE__ */ jsxs12(Text13, { color: "#00ff41", children: [
7087
7795
  "\u{1F4DD} \u6D88\u606F ",
7088
7796
  displayMessages.length,
7089
7797
  " \u6761"
7090
7798
  ] }),
7091
- sessionCost > 0 && /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
7799
+ sessionCost > 0 && /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
7092
7800
  "\u{1F4B0} \u4F1A\u8BDD \xA5",
7093
7801
  sessionCost.toFixed(4)
7094
- ] })
7802
+ ] }),
7803
+ contextStats && /* @__PURE__ */ jsx12(ContextUsageBar, { stats: contextStats })
7095
7804
  ] }),
7096
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7097
- /* @__PURE__ */ jsxs11(Text12, { color: "#808080", children: [
7805
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7806
+ /* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
7098
7807
  "\u{1F527} ",
7099
7808
  SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
7100
7809
  ] }),
7101
- thinkingEnabled && /* @__PURE__ */ jsxs11(Text12, { color: "#ff9800", children: [
7810
+ thinkingEnabled && /* @__PURE__ */ jsxs12(Text13, { color: "#ff9800", children: [
7102
7811
  "\u{1F9E0} ",
7103
7812
  thinkingEffort === "max" ? "Max" : "High"
7104
7813
  ] })
7105
7814
  ] }),
7106
- balance !== null && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text12, { color: "yellow", children: [
7815
+ balance !== null && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsxs12(Text13, { color: "yellow", children: [
7107
7816
  "\u{1F4B0} \xA5",
7108
7817
  balance.toFixed(2)
7109
7818
  ] }) })
@@ -7113,47 +7822,46 @@ function ChatSession({
7113
7822
  )
7114
7823
  }
7115
7824
  ),
7116
- /* @__PURE__ */ jsx11(Box11, { width: 1, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { color: "#444", children: "\u2502" }) }),
7117
- useMemo(() => /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", flexGrow: 1, children: [
7118
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", flexGrow: 1, children: [
7119
- !hasConversationStarted && /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "flex-start", flexGrow: 1, paddingBottom: 1, children: [
7825
+ useMemo2(() => /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", flexGrow: 1, children: [
7826
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", flexGrow: 1, children: [
7827
+ !hasConversationStarted && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", alignItems: "flex-start", flexGrow: 1, paddingBottom: 1, children: [
7120
7828
  cmdTips.length > 0 && (() => {
7121
7829
  const tip = cmdTips[cmdTipIndex % cmdTips.length];
7122
7830
  if (!tip) return null;
7123
7831
  const text = `${tip.name} ${tip.desc}`;
7124
- return /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, alignSelf: "center", children: [
7125
- /* @__PURE__ */ jsx11(Text12, { color: "#808080", children: "\u{1F4A1} " }),
7126
- cmdTipGradientColors.length > 0 ? text.split("").map((ch, i) => /* @__PURE__ */ jsx11(Text12, { color: cmdTipGradientColors[i] || void 0, children: ch }, i)) : /* @__PURE__ */ jsx11(Text12, { color: "#808080", children: text })
7832
+ return /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, alignSelf: "center", children: [
7833
+ /* @__PURE__ */ jsx12(Text13, { color: "#808080", children: "\u{1F4A1} " }),
7834
+ 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 })
7127
7835
  ] });
7128
7836
  })(),
7129
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1 }),
7130
- /* @__PURE__ */ jsx11(AnimatedLogo, { panelWidth: rightContentWidth })
7837
+ /* @__PURE__ */ jsx12(Box12, { flexGrow: 1 }),
7838
+ /* @__PURE__ */ jsx12(AnimatedLogo, { panelWidth: rightContentWidth })
7131
7839
  ] }),
7132
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
7133
- /* @__PURE__ */ jsx11(Static, { items: displayMessages, children: (msg, i) => {
7840
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
7841
+ /* @__PURE__ */ jsx12(Static, { items: displayMessages, children: (msg, i) => {
7134
7842
  if (msg.role === "user") {
7135
- return /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "row", children: [
7136
- /* @__PURE__ */ jsx11(Box11, { width: 1, backgroundColor: "#FF8C00", flexShrink: 0 }),
7137
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1, paddingLeft: 1, children: /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
7138
- /* @__PURE__ */ jsx11(Box11, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#FF8C00", children: "\u{1F4AC}" }) }),
7139
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1, children: /* @__PURE__ */ jsx11(Text12, { wrap: "wrap", children: msg.content }) })
7843
+ return /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", children: [
7844
+ /* @__PURE__ */ jsx12(Box12, { width: 1, backgroundColor: "#FF8C00", flexShrink: 0 }),
7845
+ /* @__PURE__ */ jsx12(Box12, { flexGrow: 1, paddingLeft: 1, children: /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
7846
+ /* @__PURE__ */ jsx12(Box12, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#FF8C00", children: "\u{1F4AC}" }) }),
7847
+ /* @__PURE__ */ jsx12(Box12, { flexGrow: 1, children: /* @__PURE__ */ jsx12(Text13, { wrap: "wrap", children: msg.content }) })
7140
7848
  ] }) })
7141
7849
  ] }, i);
7142
7850
  }
7143
7851
  if (msg.role === "tool") {
7144
- return /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "row", children: [
7145
- /* @__PURE__ */ jsx11(Box11, { width: 1, backgroundColor: "#666666", flexShrink: 0 }),
7146
- /* @__PURE__ */ jsxs11(Box11, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: [
7147
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
7148
- /* @__PURE__ */ jsx11(Box11, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u{1F527}" }) }),
7149
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, wrap: "wrap", children: msg.content }) })
7852
+ return /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "row", children: [
7853
+ /* @__PURE__ */ jsx12(Box12, { width: 1, backgroundColor: "#666666", flexShrink: 0 }),
7854
+ /* @__PURE__ */ jsxs12(Box12, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: [
7855
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
7856
+ /* @__PURE__ */ jsx12(Box12, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: "\u{1F527}" }) }),
7857
+ /* @__PURE__ */ jsx12(Box12, { flexGrow: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, wrap: "wrap", children: msg.content }) })
7150
7858
  ] }),
7151
- msg.diff && /* @__PURE__ */ jsx11(DiffPreview, { diff: msg.diff })
7859
+ msg.diff && /* @__PURE__ */ jsx12(DiffPreview, { diff: msg.diff })
7152
7860
  ] })
7153
7861
  ] }, i);
7154
7862
  }
7155
7863
  const detail = msg.assistantDetail;
7156
- return /* @__PURE__ */ jsx11(
7864
+ return /* @__PURE__ */ jsx12(
7157
7865
  AssistantMessage,
7158
7866
  {
7159
7867
  content: msg.content,
@@ -7167,7 +7875,7 @@ function ChatSession({
7167
7875
  i
7168
7876
  );
7169
7877
  } }, staticKey),
7170
- isStreaming && /* @__PURE__ */ jsx11(
7878
+ isStreaming && /* @__PURE__ */ jsx12(
7171
7879
  AssistantMessage,
7172
7880
  {
7173
7881
  content: currentContent,
@@ -7178,49 +7886,56 @@ function ChatSession({
7178
7886
  model: _streamingModel
7179
7887
  }
7180
7888
  ),
7181
- !isStreaming && streamError && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs11(Text12, { color: "red", children: [
7889
+ compactionState.phase !== "idle" && /* @__PURE__ */ jsx12(
7890
+ CompactionProgress,
7891
+ {
7892
+ state: compactionState,
7893
+ contentWidth: rightContentWidth
7894
+ }
7895
+ ),
7896
+ !isStreaming && streamError && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, marginLeft: 3, children: /* @__PURE__ */ jsxs12(Text13, { color: "red", children: [
7182
7897
  "\u26A0 ",
7183
7898
  streamError
7184
7899
  ] }) })
7185
7900
  ] }),
7186
- todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx11(TodoListPanel, { items: todoSnapshot })
7901
+ todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx12(TodoListPanel, { items: todoSnapshot })
7187
7902
  ] }),
7188
- selectingModel ? /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
7189
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
7190
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
7191
- /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
7903
+ selectingModel ? /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
7904
+ /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
7905
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
7906
+ /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ffff", children: "\u9009\u62E9\u6A21\u578B\uFF1A" }),
7192
7907
  modelOptions.map((id, i) => {
7193
7908
  const meta = SUPPORTED_MODELS[id];
7194
7909
  const isCurrent = id === activeModel;
7195
7910
  const isSelected = i === modelSelectIndex;
7196
7911
  const marker = isSelected ? " > " : " ";
7197
7912
  const suffix = isCurrent ? " (\u5F53\u524D)" : "";
7198
- return /* @__PURE__ */ jsxs11(Box11, { children: [
7199
- /* @__PURE__ */ jsxs11(Text12, { color: isSelected ? "#00ff41" : void 0, bold: isSelected, children: [
7913
+ return /* @__PURE__ */ jsxs12(Box12, { children: [
7914
+ /* @__PURE__ */ jsxs12(Text13, { color: isSelected ? "#00ff41" : void 0, bold: isSelected, children: [
7200
7915
  marker,
7201
7916
  meta.displayName,
7202
7917
  suffix
7203
7918
  ] }),
7204
- isSelected && /* @__PURE__ */ jsxs11(Text12, { color: "#808080", children: [
7919
+ isSelected && /* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
7205
7920
  " \u2014 ",
7206
7921
  id
7207
7922
  ] })
7208
7923
  ] }, id);
7209
7924
  }),
7210
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
7925
+ /* @__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" }) })
7211
7926
  ] }),
7212
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
7213
- ] }) : rewindSelecting ? /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
7214
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
7215
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
7216
- /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#ff9800", children: "\u9009\u62E9\u8981\u56DE\u9000\u7684\u68C0\u67E5\u70B9\uFF1A" }),
7927
+ /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
7928
+ ] }) : rewindSelecting ? /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", children: [
7929
+ /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
7930
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginTop: 1, children: [
7931
+ /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#ff9800", children: "\u9009\u62E9\u8981\u56DE\u9000\u7684\u68C0\u67E5\u70B9\uFF1A" }),
7217
7932
  rewindList.map((cp2, i) => {
7218
7933
  const isSelected = i === rewindSelectIndex;
7219
7934
  const marker = isSelected ? " > " : " ";
7220
7935
  const time = new Date(cp2.timestamp).toLocaleTimeString();
7221
7936
  const preview = cp2.preview || "(\u7A7A)";
7222
7937
  const tag = cp2.isGitRepo ? "" : " [\u975E git\uFF0C\u4EC5\u5BF9\u8BDD]";
7223
- return /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsxs11(Text12, { color: isSelected ? "#ff9800" : void 0, bold: isSelected, children: [
7938
+ return /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsxs12(Text13, { color: isSelected ? "#ff9800" : void 0, bold: isSelected, children: [
7224
7939
  marker,
7225
7940
  "#",
7226
7941
  i + 1,
@@ -7232,21 +7947,25 @@ function ChatSession({
7232
7947
  "`"
7233
7948
  ] }) }, cp2.index);
7234
7949
  }),
7235
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#808080", dimColor: true, children: "\u2191\u2193 \u9009\u62E9 \xB7 Enter \u786E\u8BA4 \xB7 Esc \u53D6\u6D88" }) })
7950
+ /* @__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" }) })
7236
7951
  ] }),
7237
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
7238
- ] }) : /* @__PURE__ */ jsxs11(Fragment2, { children: [
7239
- (hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */ jsx11(Box11, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs11(Text12, { bold: true, color: PHASE_CONFIG[streamingPhase].color, children: [
7952
+ /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
7953
+ ] }) : /* @__PURE__ */ jsxs12(Fragment3, { children: [
7954
+ (hasConversationStarted || sessionMode === "plan") && isStreaming && streamingPhase ? /* @__PURE__ */ jsx12(Box12, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsxs12(Text13, { bold: true, color: PHASE_CONFIG[streamingPhase].color, children: [
7240
7955
  PHASE_CONFIG[streamingPhase].icon,
7241
7956
  " ",
7242
7957
  PHASE_CONFIG[streamingPhase].label,
7243
7958
  " ",
7244
- /* @__PURE__ */ jsx11(InkSpinner3, { type: "dots" })
7245
- ] }) }) : rewindHintPhase === "visible" ? /* @__PURE__ */ jsx11(Box11, { marginTop: 1, justifyContent: "center", children: /* @__PURE__ */ jsx11(Text12, { color: "#808080", children: "\u21A9 /rewind 1 \u53EF\u64A4\u56DE\u672C\u6B21\u4FEE\u6539" }) }) : null,
7246
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
7247
- /* @__PURE__ */ jsxs11(Box11, { children: [
7248
- /* @__PURE__ */ jsx11(Box11, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
7249
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1, children: !input && !isStreaming && idlePlaceholder && gradientColors.length > 0 ? /* @__PURE__ */ jsx11(Text12, { children: idlePlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx11(Text12, { color: gradientColors[i] ?? void 0, children: ch }, i)) }) : !input && isStreaming && streamingPlaceholder && streamingGradientColors.length > 0 ? /* @__PURE__ */ jsx11(Text12, { children: streamingPlaceholder.split("").map((ch, i) => /* @__PURE__ */ jsx11(Text12, { color: streamingGradientColors[i] ?? void 0, children: ch }, i)) }) : /* @__PURE__ */ jsx11(
7959
+ /* @__PURE__ */ jsx12(InkSpinner4, { type: "dots" })
7960
+ ] }) }) : 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: [
7961
+ "\u{1F4DA} \u4E0A\u4E0B\u6587\u5DF2\u7528 ",
7962
+ (contextStats.ratio * 100).toFixed(0),
7963
+ "%\uFF0C\u8F93\u5165 /compact \u53EF\u624B\u52A8\u538B\u7F29"
7964
+ ] }) }) : null,
7965
+ /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
7966
+ /* @__PURE__ */ jsxs12(Box12, { children: [
7967
+ /* @__PURE__ */ jsx12(Box12, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
7968
+ /* @__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(
7250
7969
  TextInput,
7251
7970
  {
7252
7971
  value: input,
@@ -7257,9 +7976,9 @@ function ChatSession({
7257
7976
  inputKey
7258
7977
  ) })
7259
7978
  ] }),
7260
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
7261
- /* @__PURE__ */ jsx11(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
7262
- /* @__PURE__ */ jsx11(FileSelector, { files, input, selectedIndex: fileSelectIndex })
7979
+ /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
7980
+ /* @__PURE__ */ jsx12(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
7981
+ /* @__PURE__ */ jsx12(FileSelector, { files, input, selectedIndex: fileSelectIndex })
7263
7982
  ] })
7264
7983
  ] }), [
7265
7984
  displayMessages,
@@ -7307,15 +8026,53 @@ function ChatSession({
7307
8026
  doubleCtrlC
7308
8027
  ])
7309
8028
  ] }),
7310
- doubleCtrlC && !isStreaming && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) }),
7311
- isStreaming && /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "yellow", dimColor: true, children: " \u63D0\u793A\uFF1A\u6309 Ctrl+C \u53D6\u6D88\u5F53\u524D\u8BF7\u6C42" }) })
8029
+ 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" }) }),
8030
+ 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" }) })
8031
+ ] });
8032
+ }
8033
+ var CONTEXT_BAR_WIDTH = 12;
8034
+ function classifyContextRatio(ratio) {
8035
+ if (ratio >= 0.85) return "danger";
8036
+ if (ratio >= 0.6) return "warning";
8037
+ return "safe";
8038
+ }
8039
+ function contextLevelColor(level) {
8040
+ switch (level) {
8041
+ case "danger":
8042
+ return "#ff6347";
8043
+ // 红色
8044
+ case "warning":
8045
+ return "#ffcc00";
8046
+ // 黄色
8047
+ case "safe":
8048
+ return "#00ff41";
8049
+ }
8050
+ }
8051
+ function ContextUsageBar({
8052
+ stats
8053
+ }) {
8054
+ const level = classifyContextRatio(stats.ratio);
8055
+ const color = contextLevelColor(level);
8056
+ const filled = Math.min(
8057
+ CONTEXT_BAR_WIDTH,
8058
+ // 只要 ratio > 0 就至少 1 格 █,避免“占用极少”时空条被误读为“未使用”
8059
+ Math.max(stats.ratio > 0 ? 1 : 0, Math.round(stats.ratio * CONTEXT_BAR_WIDTH))
8060
+ );
8061
+ const empty = CONTEXT_BAR_WIDTH - filled;
8062
+ return /* @__PURE__ */ jsxs12(Text13, { color, children: [
8063
+ "\u{1F4DA} ",
8064
+ /* @__PURE__ */ jsx12(Text13, { color, children: "\u2588".repeat(filled) }),
8065
+ /* @__PURE__ */ jsx12(Text13, { color: "#444444", children: "\u2591".repeat(empty) }),
8066
+ " ",
8067
+ (stats.ratio * 100).toFixed(1),
8068
+ "%"
7312
8069
  ] });
7313
8070
  }
7314
8071
 
7315
8072
  // src/ui/GamePicker.tsx
7316
- import { Box as Box12, Text as Text13, useInput as useInput2 } from "ink";
8073
+ import { Box as Box13, Text as Text14, useInput as useInput2 } from "ink";
7317
8074
  import { useState as useState6, useCallback as useCallback3 } from "react";
7318
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
8075
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
7319
8076
  function GamePicker({ games, onSelect, onExit, onBackToChat }) {
7320
8077
  const [selectedIndex, setSelectedIndex] = useState6(0);
7321
8078
  const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
@@ -7343,18 +8100,18 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
7343
8100
  [games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC]
7344
8101
  )
7345
8102
  );
7346
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
7347
- /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
7348
- /* @__PURE__ */ jsx12(Box12, { flexDirection: "column", children: games.map((game, index) => {
8103
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
8104
+ /* @__PURE__ */ jsx13(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text14, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
8105
+ /* @__PURE__ */ jsx13(Box13, { flexDirection: "column", children: games.map((game, index) => {
7349
8106
  const isSelected = index === selectedIndex;
7350
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
7351
- /* @__PURE__ */ jsx12(Box12, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx12(Text13, { children: " " }) }),
7352
- /* @__PURE__ */ jsx12(Box12, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
7353
- /* @__PURE__ */ jsx12(Box12, { children: /* @__PURE__ */ jsx12(Text13, { color: "#888888", children: game.description }) })
8107
+ return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", children: [
8108
+ /* @__PURE__ */ jsx13(Box13, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx13(Text14, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx13(Text14, { children: " " }) }),
8109
+ /* @__PURE__ */ jsx13(Box13, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx13(Text14, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
8110
+ /* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsx13(Text14, { color: "#888888", children: game.description }) })
7354
8111
  ] }, game.id);
7355
8112
  }) }),
7356
- /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
7357
- doubleCtrlC && /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { color: "#ff1493", bold: true, children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
8113
+ /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
8114
+ 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" }) })
7358
8115
  ] });
7359
8116
  }
7360
8117
 
@@ -7371,9 +8128,9 @@ function listGames() {
7371
8128
  }
7372
8129
 
7373
8130
  // src/game/brick-breaker/index.tsx
7374
- import { Box as Box13, Text as Text14, useInput as useInput3, render as render2 } from "ink";
8131
+ import { Box as Box14, Text as Text15, useInput as useInput3, render as render2 } from "ink";
7375
8132
  import { useState as useState7, useEffect as useEffect6, useRef as useRef5, useCallback as useCallback4 } from "react";
7376
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
8133
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
7377
8134
  var GAME_WIDTH = 40;
7378
8135
  var GAME_HEIGHT = 18;
7379
8136
  var PADDLE_WIDTH = 9;
@@ -7563,49 +8320,49 @@ function BrickBreakerGame({ onExit: _onExit }) {
7563
8320
  const board = buildBoard(s);
7564
8321
  const def = getLevel(s.level);
7565
8322
  void tick2;
7566
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
7567
- /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", children: [
7568
- /* @__PURE__ */ jsx13(Box13, { width: 20, children: /* @__PURE__ */ jsxs13(Text14, { children: [
8323
+ return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
8324
+ /* @__PURE__ */ jsxs14(Box14, { flexDirection: "row", children: [
8325
+ /* @__PURE__ */ jsx14(Box14, { width: 20, children: /* @__PURE__ */ jsxs14(Text15, { children: [
7569
8326
  "\u5173\u5361 ",
7570
8327
  s.level,
7571
8328
  ": ",
7572
- /* @__PURE__ */ jsx13(Text14, { color: "cyan", children: def.desc })
8329
+ /* @__PURE__ */ jsx14(Text15, { color: "cyan", children: def.desc })
7573
8330
  ] }) }),
7574
- /* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsxs13(Text14, { children: [
8331
+ /* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { children: [
7575
8332
  "\u5206\u6570: ",
7576
- /* @__PURE__ */ jsx13(Text14, { color: "yellow", children: String(s.score).padStart(3, "0") })
8333
+ /* @__PURE__ */ jsx14(Text15, { color: "yellow", children: String(s.score).padStart(3, "0") })
7577
8334
  ] }) }),
7578
- /* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsxs13(Text14, { children: [
8335
+ /* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { children: [
7579
8336
  "\u751F\u547D: ",
7580
- /* @__PURE__ */ jsx13(Text14, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
8337
+ /* @__PURE__ */ jsx14(Text15, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) })
7581
8338
  ] }) }),
7582
- /* @__PURE__ */ jsx13(Box13, { width: 10, children: /* @__PURE__ */ jsxs13(Text14, { children: [
8339
+ /* @__PURE__ */ jsx14(Box14, { width: 10, children: /* @__PURE__ */ jsxs14(Text15, { children: [
7583
8340
  "\u7816\u5757: ",
7584
- /* @__PURE__ */ jsx13(Text14, { color: "cyan", children: aliveCount })
8341
+ /* @__PURE__ */ jsx14(Text15, { color: "cyan", children: aliveCount })
7585
8342
  ] }) }),
7586
- /* @__PURE__ */ jsx13(Box13, { children: /* @__PURE__ */ jsxs13(Text14, { color: s.paused ? "gray" : "green", children: [
8343
+ /* @__PURE__ */ jsx14(Box14, { children: /* @__PURE__ */ jsxs14(Text15, { color: s.paused ? "gray" : "green", children: [
7587
8344
  "[",
7588
8345
  s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
7589
8346
  "]"
7590
8347
  ] }) })
7591
8348
  ] }),
7592
- /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
7593
- /* @__PURE__ */ jsxs13(Text14, { children: [
8349
+ /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
8350
+ /* @__PURE__ */ jsxs14(Text15, { children: [
7594
8351
  "\u250C",
7595
8352
  "\u2500".repeat(GAME_WIDTH),
7596
8353
  "\u2510"
7597
8354
  ] }),
7598
- /* @__PURE__ */ jsx13(Text14, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
7599
- /* @__PURE__ */ jsxs13(Text14, { children: [
8355
+ /* @__PURE__ */ jsx14(Text15, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
8356
+ /* @__PURE__ */ jsxs14(Text15, { children: [
7600
8357
  "\u2514",
7601
8358
  "\u2500".repeat(GAME_WIDTH),
7602
8359
  "\u2518"
7603
8360
  ] })
7604
8361
  ] }),
7605
- selectingLevel && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
7606
- /* @__PURE__ */ jsx13(Text14, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
7607
- /* @__PURE__ */ jsx13(Box13, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx13(Box13, { width: 22, children: /* @__PURE__ */ jsxs13(Text14, { children: [
7608
- /* @__PURE__ */ jsx13(Text14, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
8362
+ selectingLevel && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
8363
+ /* @__PURE__ */ jsx14(Text15, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
8364
+ /* @__PURE__ */ jsx14(Box14, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx14(Box14, { width: 22, children: /* @__PURE__ */ jsxs14(Text15, { children: [
8365
+ /* @__PURE__ */ jsx14(Text15, { color: initialLevel === i + 1 ? "green" : "white", children: i + 1 === 10 ? "0" : String(i + 1) }),
7609
8366
  ". ",
7610
8367
  lv.desc,
7611
8368
  " (",
@@ -7614,16 +8371,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
7614
8371
  lv.cols,
7615
8372
  ")"
7616
8373
  ] }) }, i)) }),
7617
- /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
8374
+ /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6309\u6570\u5B57\u9009\u5173 q \u9000\u51FA" }) })
7618
8375
  ] }),
7619
- !selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
7620
- /* @__PURE__ */ jsx13(Text14, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
7621
- /* @__PURE__ */ jsxs13(Text14, { children: [
8376
+ !selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
8377
+ /* @__PURE__ */ jsx14(Text15, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
8378
+ /* @__PURE__ */ jsxs14(Text15, { children: [
7622
8379
  " \u5206\u6570: ",
7623
- /* @__PURE__ */ jsx13(Text14, { color: "yellow", children: s.score })
8380
+ /* @__PURE__ */ jsx14(Text15, { color: "yellow", children: s.score })
7624
8381
  ] })
7625
8382
  ] }),
7626
- !selectingLevel && /* @__PURE__ */ jsx13(Box13, { marginTop: 1, children: s.gameOver || s.win ? /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 r \u91CD\u5F00 l \u9009\u5173 q \u9000\u51FA" }) : /* @__PURE__ */ jsx13(Text14, { dimColor: true, children: "\u2190 \u2192 \u79FB\u52A8 p \u6682\u505C q \u9000\u51FA" }) })
8383
+ !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" }) })
7627
8384
  ] });
7628
8385
  }
7629
8386
  var brick_breaker_default = {
@@ -7633,7 +8390,7 @@ var brick_breaker_default = {
7633
8390
  play: async () => {
7634
8391
  await new Promise((resolve2) => {
7635
8392
  const { unmount } = render2(
7636
- /* @__PURE__ */ jsx13(BrickBreakerGame, { onExit: () => {
8393
+ /* @__PURE__ */ jsx14(BrickBreakerGame, { onExit: () => {
7637
8394
  unmount();
7638
8395
  resolve2();
7639
8396
  } })
@@ -7643,9 +8400,9 @@ var brick_breaker_default = {
7643
8400
  };
7644
8401
 
7645
8402
  // src/game/coder-check/index.tsx
7646
- import { Box as Box14, Text as Text15, useInput as useInput4, render as render3 } from "ink";
8403
+ import { Box as Box15, Text as Text16, useInput as useInput4, render as render3 } from "ink";
7647
8404
  import { useState as useState8, useEffect as useEffect7, useRef as useRef6, useCallback as useCallback5 } from "react";
7648
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
8405
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
7649
8406
  var GAME_W = 66;
7650
8407
  var GAME_H = 20;
7651
8408
  var SCORE_H = 6;
@@ -8116,44 +8873,44 @@ function CoderCheck({ onExit: _onExit }) {
8116
8873
  const scoreLines = buildScoreLines(scoreStr);
8117
8874
  const view = buildGameView(s, scoreLines, scoreColor, s.message);
8118
8875
  void tick2;
8119
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingX: 1, children: [
8120
- /* @__PURE__ */ jsx14(Box14, { flexDirection: "row", children: /* @__PURE__ */ jsxs14(Text15, { children: [
8876
+ return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingX: 1, children: [
8877
+ /* @__PURE__ */ jsx15(Box15, { flexDirection: "row", children: /* @__PURE__ */ jsxs15(Text16, { children: [
8121
8878
  "\u751F\u547D ",
8122
- /* @__PURE__ */ jsx14(Text15, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
8879
+ /* @__PURE__ */ jsx15(Text16, { color: "red", children: "\u2665".repeat(Math.max(0, s.lives)) }),
8123
8880
  " ",
8124
8881
  "\u901F\u5EA6 ",
8125
- /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
8882
+ /* @__PURE__ */ jsxs15(Text16, { color: "cyan", children: [
8126
8883
  "Lv.",
8127
8884
  Math.floor(s.speed * 10)
8128
8885
  ] })
8129
8886
  ] }) }),
8130
- !s.gameOver && s.target && /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsxs14(Text15, { children: [
8887
+ !s.gameOver && s.target && /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsxs15(Text16, { children: [
8131
8888
  "\u6253\u5B57: ",
8132
- /* @__PURE__ */ jsx14(Text15, { color: "green", children: s.typed }),
8133
- /* @__PURE__ */ jsx14(Text15, { color: "white", children: s.target.slice(s.typed.length) })
8889
+ /* @__PURE__ */ jsx15(Text16, { color: "green", children: s.typed }),
8890
+ /* @__PURE__ */ jsx15(Text16, { color: "white", children: s.target.slice(s.typed.length) })
8134
8891
  ] }) }),
8135
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
8136
- /* @__PURE__ */ jsxs14(Text15, { children: [
8892
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
8893
+ /* @__PURE__ */ jsxs15(Text16, { children: [
8137
8894
  "\u250C",
8138
8895
  "\u2500".repeat(GAME_W),
8139
8896
  "\u2510"
8140
8897
  ] }),
8141
- view.map((row, i) => /* @__PURE__ */ jsx14(Text15, { children: `\u2502${row}\u2502` }, i)),
8142
- /* @__PURE__ */ jsxs14(Text15, { children: [
8898
+ view.map((row, i) => /* @__PURE__ */ jsx15(Text16, { children: `\u2502${row}\u2502` }, i)),
8899
+ /* @__PURE__ */ jsxs15(Text16, { children: [
8143
8900
  "\u2514",
8144
8901
  "\u2500".repeat(GAME_W),
8145
8902
  "\u2518"
8146
8903
  ] })
8147
8904
  ] }),
8148
- s.gameOver && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
8149
- /* @__PURE__ */ jsx14(Text15, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
8150
- /* @__PURE__ */ jsxs14(Text15, { children: [
8905
+ s.gameOver && /* @__PURE__ */ jsxs15(Box15, { marginTop: 1, children: [
8906
+ /* @__PURE__ */ jsx15(Text16, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
8907
+ /* @__PURE__ */ jsxs15(Text16, { children: [
8151
8908
  " \u5F97\u5206: ",
8152
- /* @__PURE__ */ jsx14(Text15, { color: "yellow", children: s.score }),
8909
+ /* @__PURE__ */ jsx15(Text16, { color: "yellow", children: s.score }),
8153
8910
  " r \u91CD\u5F00 q \u9000\u51FA"
8154
8911
  ] })
8155
8912
  ] }),
8156
- /* @__PURE__ */ jsx14(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text15, { dimColor: true, children: "\u6253\u5B57\u6D88\u9664\u5355\u8BCD \u7A7A\u683C/Ctrl+P\u6682\u505C Ctrl+Q\u9000\u51FA" }) })
8913
+ /* @__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" }) })
8157
8914
  ] });
8158
8915
  }
8159
8916
  var coder_check_default = {
@@ -8163,7 +8920,7 @@ var coder_check_default = {
8163
8920
  play: async () => {
8164
8921
  await new Promise((resolve2) => {
8165
8922
  const { unmount } = render3(
8166
- /* @__PURE__ */ jsx14(CoderCheck, { onExit: () => {
8923
+ /* @__PURE__ */ jsx15(CoderCheck, { onExit: () => {
8167
8924
  unmount();
8168
8925
  resolve2();
8169
8926
  } })
@@ -8543,12 +9300,12 @@ import { render as render4 } from "ink";
8543
9300
  import chalk5 from "chalk";
8544
9301
 
8545
9302
  // src/stock/StockList.tsx
8546
- import { Box as Box15, Text as Text16, useInput as useInput5 } from "ink";
8547
- import { useState as useState9, useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo2 } from "react";
9303
+ import { Box as Box16, Text as Text17, useInput as useInput5 } from "ink";
9304
+ import { useState as useState9, useCallback as useCallback6, useEffect as useEffect8, useMemo as useMemo3 } from "react";
8548
9305
  import asciichart from "asciichart";
8549
9306
  import os from "os";
8550
9307
  import { join as join10 } from "path";
8551
- import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
9308
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
8552
9309
  var SETTINGS_PATH = join10(os.homedir(), ".dskcode", "settings.json");
8553
9310
  function toFileUrl(p) {
8554
9311
  const norm = p.replace(/\\/g, "/");
@@ -8665,7 +9422,7 @@ function StockList({ codes, onExit, onBackToChat }) {
8665
9422
  );
8666
9423
  const [dimMode, setDimMode] = useState9(false);
8667
9424
  const [sortOrder, setSortOrder] = useState9("default");
8668
- const sortedStocks = useMemo2(() => {
9425
+ const sortedStocks = useMemo3(() => {
8669
9426
  if (sortOrder === "default") return stocks;
8670
9427
  return [...stocks].toSorted(
8671
9428
  (a, b) => sortOrder === "desc" ? b.changePercent - a.changePercent : a.changePercent - b.changePercent
@@ -8767,64 +9524,64 @@ function StockList({ codes, onExit, onBackToChat }) {
8767
9524
  );
8768
9525
  if (detailView) {
8769
9526
  if (detailLoading) {
8770
- return /* @__PURE__ */ jsx15(Box15, { paddingLeft: 1, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
9527
+ return /* @__PURE__ */ jsx16(Box16, { paddingLeft: 1, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
8771
9528
  }
8772
9529
  return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
8773
9530
  }
8774
9531
  const cp2 = (c) => dimMode ? { dimColor: true } : { color: c };
8775
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
8776
- /* @__PURE__ */ jsxs15(Box15, { marginBottom: 1, justifyContent: "space-between", children: [
8777
- /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
8778
- /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
9532
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", children: [
9533
+ /* @__PURE__ */ jsxs16(Box16, { marginBottom: 1, justifyContent: "space-between", children: [
9534
+ /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
9535
+ /* @__PURE__ */ jsxs16(Text17, { dimColor: true, children: [
8779
9536
  " \u{1F550} ",
8780
9537
  currentTime
8781
9538
  ] }),
8782
- /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
9539
+ /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` ${countdown}s \u540E\u81EA\u52A8\u5237\u65B0` })
8783
9540
  ] }),
8784
- /* @__PURE__ */ jsxs15(Box15, { children: [
8785
- /* @__PURE__ */ jsx15(Box15, { width: 3 }),
8786
- /* @__PURE__ */ jsx15(Box15, { width: 9, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u4EE3\u7801" }) }),
8787
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u540D\u79F0" }) }),
8788
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
8789
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
9541
+ /* @__PURE__ */ jsxs16(Box16, { children: [
9542
+ /* @__PURE__ */ jsx16(Box16, { width: 3 }),
9543
+ /* @__PURE__ */ jsx16(Box16, { width: 9, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u4EE3\u7801" }) }),
9544
+ /* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u540D\u79F0" }) }),
9545
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
9546
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsxs16(Text17, { dimColor: true, children: [
8790
9547
  "\u6DA8\u8DCC\u5E45",
8791
9548
  sortOrder === "desc" ? " \u25BC" : sortOrder === "asc" ? " \u25B2" : ""
8792
9549
  ] }) }),
8793
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
8794
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6700\u9AD8" }) }),
8795
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6700\u4F4E" }) }),
8796
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
9550
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
9551
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6700\u9AD8" }) }),
9552
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6700\u4F4E" }) }),
9553
+ /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: "\u6210\u4EA4\u989D" }) })
8797
9554
  ] }),
8798
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
8799
- /* @__PURE__ */ jsx15(Box15, { flexDirection: "column", children: sortedStocks.map((stock, index) => {
9555
+ /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
9556
+ /* @__PURE__ */ jsx16(Box16, { flexDirection: "column", children: sortedStocks.map((stock, index) => {
8800
9557
  const isSelected = index === selectedIndex;
8801
9558
  const isUp = stock.changePercent >= 0;
8802
9559
  const color = isUp ? "#ff1493" : "#00ff41";
8803
- return /* @__PURE__ */ jsxs15(Box15, { children: [
8804
- /* @__PURE__ */ jsx15(Box15, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx15(Text16, { children: " " }) }),
8805
- /* @__PURE__ */ jsx15(Box15, { width: 9, children: /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
8806
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
8807
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
8808
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsxs15(Text16, { ...cp2(color), children: [
9560
+ return /* @__PURE__ */ jsxs16(Box16, { children: [
9561
+ /* @__PURE__ */ jsx16(Box16, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx16(Text17, { children: " " }) }),
9562
+ /* @__PURE__ */ jsx16(Box16, { width: 9, children: /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
9563
+ /* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
9564
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
9565
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsxs16(Text17, { ...cp2(color), children: [
8809
9566
  isUp ? "+" : "",
8810
9567
  stock.changePercent.toFixed(2),
8811
9568
  "%"
8812
9569
  ] }) }),
8813
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsxs15(Text16, { ...cp2(color), children: [
9570
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsxs16(Text17, { ...cp2(color), children: [
8814
9571
  isUp ? "+" : "",
8815
9572
  stock.changeAmount.toFixed(3)
8816
9573
  ] }) }),
8817
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
8818
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
8819
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text16, { ...cp2("#888888"), children: formatAmount(stock.amount) }) })
9574
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
9575
+ /* @__PURE__ */ jsx16(Box16, { width: 12, children: /* @__PURE__ */ jsx16(Text17, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
9576
+ /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsx16(Text17, { ...cp2("#888888"), children: formatAmount(stock.amount) }) })
8820
9577
  ] }, stock.code);
8821
9578
  }) }),
8822
- /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text16, { 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` }) }),
8823
- /* @__PURE__ */ jsxs15(Box15, { children: [
8824
- /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
8825
- /* @__PURE__ */ jsx15(Text16, { ...cp2("#c792ea"), children: osc8Link(toFileUrl(SETTINGS_PATH), SETTINGS_PATH) })
9579
+ /* @__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` }) }),
9580
+ /* @__PURE__ */ jsxs16(Box16, { children: [
9581
+ /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
9582
+ /* @__PURE__ */ jsx16(Text17, { ...cp2("#c792ea"), children: osc8Link(toFileUrl(SETTINGS_PATH), SETTINGS_PATH) })
8826
9583
  ] }),
8827
- doubleCtrlC && /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2("#ff1493"), children: " \u26A0 \u518D\u6309\u4E00\u6B21 Ctrl+C \u9000\u51FA dskcode" }) })
9584
+ 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" }) })
8828
9585
  ] });
8829
9586
  }
8830
9587
  function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
@@ -8842,33 +9599,33 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
8842
9599
  raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
8843
9600
  chartLines = raw.split("\n");
8844
9601
  }
8845
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingLeft: 1, children: [
8846
- /* @__PURE__ */ jsxs15(Box15, { marginBottom: 1, justifyContent: "space-between", children: [
8847
- /* @__PURE__ */ jsxs15(Box15, { children: [
8848
- /* @__PURE__ */ jsxs15(Text16, { bold: true, color: "#00ffff", children: [
9602
+ return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", paddingLeft: 1, children: [
9603
+ /* @__PURE__ */ jsxs16(Box16, { marginBottom: 1, justifyContent: "space-between", children: [
9604
+ /* @__PURE__ */ jsxs16(Box16, { children: [
9605
+ /* @__PURE__ */ jsxs16(Text17, { bold: true, color: "#00ffff", children: [
8849
9606
  " \u{1F4CA} ",
8850
9607
  stock.name,
8851
9608
  " "
8852
9609
  ] }),
8853
- /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: stock.code }),
8854
- currentTime && /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
9610
+ /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: stock.code }),
9611
+ currentTime && /* @__PURE__ */ jsxs16(Text17, { dimColor: true, children: [
8855
9612
  " \u{1F550} ",
8856
9613
  currentTime
8857
9614
  ] })
8858
9615
  ] }),
8859
- /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
9616
+ /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
8860
9617
  ] }),
8861
- /* @__PURE__ */ jsxs15(Box15, { children: [
8862
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
8863
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsxs15(Text16, { bold: true, color: colorCode, children: [
9618
+ /* @__PURE__ */ jsxs16(Box16, { children: [
9619
+ /* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
9620
+ /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { bold: true, color: colorCode, children: [
8864
9621
  arrow,
8865
9622
  " ",
8866
9623
  formatPrice(stock.price)
8867
9624
  ] }) })
8868
9625
  ] }),
8869
- /* @__PURE__ */ jsxs15(Box15, { children: [
8870
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
8871
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsxs15(Text16, { color: colorCode, children: [
9626
+ /* @__PURE__ */ jsxs16(Box16, { children: [
9627
+ /* @__PURE__ */ jsx16(Box16, { width: 16, children: /* @__PURE__ */ jsx16(Text17, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
9628
+ /* @__PURE__ */ jsx16(Box16, { children: /* @__PURE__ */ jsxs16(Text17, { color: colorCode, children: [
8872
9629
  isUp ? "+" : "",
8873
9630
  stock.changePercent.toFixed(2),
8874
9631
  "%",
@@ -8877,8 +9634,8 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
8877
9634
  stock.changeAmount.toFixed(3)
8878
9635
  ] }) })
8879
9636
  ] }),
8880
- chartLines.length > 0 && /* @__PURE__ */ jsx15(Box15, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text16, { color: colorCode, children: line || " " }) }, i)) }),
8881
- /* @__PURE__ */ jsx15(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
9637
+ 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)) }),
9638
+ /* @__PURE__ */ jsx16(Box16, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
8882
9639
  ] });
8883
9640
  }
8884
9641
 
@@ -8963,7 +9720,7 @@ async function scanProjectFiles(baseDir, dir) {
8963
9720
  }
8964
9721
 
8965
9722
  // src/cli/index.tsx
8966
- import { jsx as jsx16 } from "react/jsx-runtime";
9723
+ import { jsx as jsx17 } from "react/jsx-runtime";
8967
9724
  var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
8968
9725
  function createCli() {
8969
9726
  const program2 = new Command();
@@ -9065,7 +9822,7 @@ compdef _dskcode_completion dskcode`);
9065
9822
  const freshResult = await loadAndValidate();
9066
9823
  const codeList = codes && codes.length > 0 ? codes : freshResult.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
9067
9824
  const app = renderApp(
9068
- /* @__PURE__ */ jsx16(
9825
+ /* @__PURE__ */ jsx17(
9069
9826
  StockList,
9070
9827
  {
9071
9828
  codes: codeList,
@@ -9094,7 +9851,7 @@ compdef _dskcode_completion dskcode`);
9094
9851
  }
9095
9852
  const selectedGame = await new Promise((resolve2) => {
9096
9853
  const { unmount } = render4(
9097
- /* @__PURE__ */ jsx16(
9854
+ /* @__PURE__ */ jsx17(
9098
9855
  GamePicker,
9099
9856
  {
9100
9857
  games,
@@ -9134,7 +9891,7 @@ async function startChat(ctx, costTracker) {
9134
9891
  );
9135
9892
  const model = defaultProvider?.model ?? "deepseek-v4-flash";
9136
9893
  const chatApp = renderApp(
9137
- /* @__PURE__ */ jsx16(
9894
+ /* @__PURE__ */ jsx17(
9138
9895
  ChatSession,
9139
9896
  {
9140
9897
  skillCount,
@@ -9152,7 +9909,7 @@ async function startChat(ctx, costTracker) {
9152
9909
  initGames();
9153
9910
  const games = listGames();
9154
9911
  const { unmount } = render4(
9155
- /* @__PURE__ */ jsx16(
9912
+ /* @__PURE__ */ jsx17(
9156
9913
  GamePicker,
9157
9914
  {
9158
9915
  games,
@@ -9176,7 +9933,7 @@ async function startChat(ctx, costTracker) {
9176
9933
  setImmediate(() => {
9177
9934
  const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
9178
9935
  const stockApp = renderApp(
9179
- /* @__PURE__ */ jsx16(
9936
+ /* @__PURE__ */ jsx17(
9180
9937
  StockList,
9181
9938
  {
9182
9939
  codes: defaultStockCodes,