dskcode 0.1.39 → 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.39",
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 上"立即保存"按钮或异常退出前的最后兜底。
@@ -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,16 +7715,16 @@ 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
7729
  paddingX: 1,
7017
7730
  flexDirection: "column",
@@ -7019,51 +7732,51 @@ function ChatSession({
7019
7732
  justifyContent: !hasConversationStarted ? "center" : "flex-end",
7020
7733
  children: !hasConversationStarted ? (
7021
7734
  /* ===== 首页:Logo + 状态概况 ===== */
7022
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "center", children: [
7735
+ /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", alignItems: "center", children: [
7023
7736
  LOGO_LINES.map((line, i) => {
7024
7737
  const colorIndex = (i + offset) % CYBER_PALETTE.length;
7025
- 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);
7026
7739
  }),
7027
- /* @__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: [
7028
7741
  "\u{1F4E6} v",
7029
7742
  VERSION
7030
7743
  ] }) }),
7031
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7032
- /* @__PURE__ */ jsxs11(Text12, { color: "#00ff41", children: [
7744
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7745
+ /* @__PURE__ */ jsxs12(Text13, { color: "#00ff41", children: [
7033
7746
  "\u2714 ",
7034
7747
  skillCount,
7035
7748
  " Skills"
7036
7749
  ] }),
7037
- /* @__PURE__ */ jsxs11(Text12, { color: "#00ffff", children: [
7750
+ /* @__PURE__ */ jsxs12(Text13, { color: "#00ffff", children: [
7038
7751
  "\u2139 ",
7039
7752
  toolCount,
7040
7753
  " \u5DE5\u5177"
7041
7754
  ] }),
7042
- /* @__PURE__ */ jsxs11(Text12, { color: "#00ffff", children: [
7755
+ /* @__PURE__ */ jsxs12(Text13, { color: "#00ffff", children: [
7043
7756
  "\u{1F527} ",
7044
7757
  SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
7045
7758
  ] }),
7046
- thinkingEnabled && /* @__PURE__ */ jsxs11(Text12, { color: "#ff9800", children: [
7759
+ thinkingEnabled && /* @__PURE__ */ jsxs12(Text13, { color: "#ff9800", children: [
7047
7760
  "\u{1F9E0} \u6DF1\u5EA6\u601D\u8003 ",
7048
7761
  thinkingEffort === "max" ? "Max" : "High"
7049
7762
  ] }),
7050
- 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" })
7051
7764
  ] }),
7052
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7053
- 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: [
7054
7767
  "\u{1F4B0} \u4F59\u989D \xA5",
7055
7768
  balance.toFixed(2)
7056
- ] }) : balanceLoading ? /* @__PURE__ */ jsx11(Text12, { color: "yellow", children: "\u23F3 \u67E5\u8BE2\u4F59\u989D..." }) : null,
7057
- 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: [
7058
7771
  "\u{1F4CA} \u4ECA\u65E5 \xA5",
7059
7772
  todayCost.toFixed(2)
7060
7773
  ] })
7061
7774
  ] }),
7062
- verbose && /* @__PURE__ */ jsx11(Text12, { color: "#ff1493", children: "\u26A1 Verbose" })
7775
+ verbose && /* @__PURE__ */ jsx12(Text13, { color: "#ff1493", children: "\u26A1 Verbose" })
7063
7776
  ] })
7064
7777
  ) : hasReasoningPanel ? (
7065
7778
  /* ===== 流式思考中(纯文本,无边框) ===== */
7066
- /* @__PURE__ */ jsx11(Text12, { dimColor: true, wrap: "wrap", children: (() => {
7779
+ /* @__PURE__ */ jsx12(Text13, { dimColor: true, wrap: "wrap", children: (() => {
7067
7780
  const full = joinReasoningSegments(currentReasoning);
7068
7781
  const maxContentLines = 11;
7069
7782
  const lines = full.split("\n");
@@ -7075,30 +7788,31 @@ function ChatSession({
7075
7788
  })() })
7076
7789
  ) : (
7077
7790
  /* ===== 对话中(无思考):会话状态面板 ===== */
7078
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "center", children: [
7079
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", bold: true, children: "\u{1F4AC} \u5BF9\u8BDD\u8FDB\u884C\u4E2D" }),
7080
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7081
- /* @__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: [
7082
7795
  "\u{1F4DD} \u6D88\u606F ",
7083
7796
  displayMessages.length,
7084
7797
  " \u6761"
7085
7798
  ] }),
7086
- sessionCost > 0 && /* @__PURE__ */ jsxs11(Text12, { color: "cyan", children: [
7799
+ sessionCost > 0 && /* @__PURE__ */ jsxs12(Text13, { color: "cyan", children: [
7087
7800
  "\u{1F4B0} \u4F1A\u8BDD \xA5",
7088
7801
  sessionCost.toFixed(4)
7089
- ] })
7802
+ ] }),
7803
+ contextStats && /* @__PURE__ */ jsx12(ContextUsageBar, { stats: contextStats })
7090
7804
  ] }),
7091
- /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7092
- /* @__PURE__ */ jsxs11(Text12, { color: "#808080", children: [
7805
+ /* @__PURE__ */ jsxs12(Box12, { marginTop: 1, flexDirection: "column", alignItems: "center", children: [
7806
+ /* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
7093
7807
  "\u{1F527} ",
7094
7808
  SUPPORTED_MODELS[activeModel]?.displayName ?? activeModel
7095
7809
  ] }),
7096
- thinkingEnabled && /* @__PURE__ */ jsxs11(Text12, { color: "#ff9800", children: [
7810
+ thinkingEnabled && /* @__PURE__ */ jsxs12(Text13, { color: "#ff9800", children: [
7097
7811
  "\u{1F9E0} ",
7098
7812
  thinkingEffort === "max" ? "Max" : "High"
7099
7813
  ] })
7100
7814
  ] }),
7101
- 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: [
7102
7816
  "\u{1F4B0} \xA5",
7103
7817
  balance.toFixed(2)
7104
7818
  ] }) })
@@ -7108,47 +7822,46 @@ function ChatSession({
7108
7822
  )
7109
7823
  }
7110
7824
  ),
7111
- /* @__PURE__ */ jsx11(Box11, { width: 1, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { color: "#444", children: "\u2502" }) }),
7112
- useMemo(() => /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", flexGrow: 1, children: [
7113
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", flexGrow: 1, children: [
7114
- !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: [
7115
7828
  cmdTips.length > 0 && (() => {
7116
7829
  const tip = cmdTips[cmdTipIndex % cmdTips.length];
7117
7830
  if (!tip) return null;
7118
7831
  const text = `${tip.name} ${tip.desc}`;
7119
- return /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, alignSelf: "center", children: [
7120
- /* @__PURE__ */ jsx11(Text12, { color: "#808080", children: "\u{1F4A1} " }),
7121
- 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 })
7122
7835
  ] });
7123
7836
  })(),
7124
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1 }),
7125
- /* @__PURE__ */ jsx11(AnimatedLogo, { panelWidth: rightContentWidth })
7837
+ /* @__PURE__ */ jsx12(Box12, { flexGrow: 1 }),
7838
+ /* @__PURE__ */ jsx12(AnimatedLogo, { panelWidth: rightContentWidth })
7126
7839
  ] }),
7127
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
7128
- /* @__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) => {
7129
7842
  if (msg.role === "user") {
7130
- return /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "row", children: [
7131
- /* @__PURE__ */ jsx11(Box11, { width: 1, backgroundColor: "#FF8C00", flexShrink: 0 }),
7132
- /* @__PURE__ */ jsx11(Box11, { flexGrow: 1, paddingLeft: 1, children: /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
7133
- /* @__PURE__ */ jsx11(Box11, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#FF8C00", children: "\u{1F4AC}" }) }),
7134
- /* @__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 }) })
7135
7848
  ] }) })
7136
7849
  ] }, i);
7137
7850
  }
7138
7851
  if (msg.role === "tool") {
7139
- return /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "row", children: [
7140
- /* @__PURE__ */ jsx11(Box11, { width: 1, backgroundColor: "#666666", flexShrink: 0 }),
7141
- /* @__PURE__ */ jsxs11(Box11, { flexGrow: 1, paddingLeft: 1, flexDirection: "column", children: [
7142
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "row", children: [
7143
- /* @__PURE__ */ jsx11(Box11, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { dimColor: true, children: "\u{1F527}" }) }),
7144
- /* @__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 }) })
7145
7858
  ] }),
7146
- msg.diff && /* @__PURE__ */ jsx11(DiffPreview, { diff: msg.diff })
7859
+ msg.diff && /* @__PURE__ */ jsx12(DiffPreview, { diff: msg.diff })
7147
7860
  ] })
7148
7861
  ] }, i);
7149
7862
  }
7150
7863
  const detail = msg.assistantDetail;
7151
- return /* @__PURE__ */ jsx11(
7864
+ return /* @__PURE__ */ jsx12(
7152
7865
  AssistantMessage,
7153
7866
  {
7154
7867
  content: msg.content,
@@ -7162,7 +7875,7 @@ function ChatSession({
7162
7875
  i
7163
7876
  );
7164
7877
  } }, staticKey),
7165
- isStreaming && /* @__PURE__ */ jsx11(
7878
+ isStreaming && /* @__PURE__ */ jsx12(
7166
7879
  AssistantMessage,
7167
7880
  {
7168
7881
  content: currentContent,
@@ -7173,49 +7886,56 @@ function ChatSession({
7173
7886
  model: _streamingModel
7174
7887
  }
7175
7888
  ),
7176
- !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: [
7177
7897
  "\u26A0 ",
7178
7898
  streamError
7179
7899
  ] }) })
7180
7900
  ] }),
7181
- todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx11(TodoListPanel, { items: todoSnapshot })
7901
+ todoPanelVisible && todoSnapshot.length > 0 && /* @__PURE__ */ jsx12(TodoListPanel, { items: todoSnapshot })
7182
7902
  ] }),
7183
- selectingModel ? /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
7184
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
7185
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
7186
- /* @__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" }),
7187
7907
  modelOptions.map((id, i) => {
7188
7908
  const meta = SUPPORTED_MODELS[id];
7189
7909
  const isCurrent = id === activeModel;
7190
7910
  const isSelected = i === modelSelectIndex;
7191
7911
  const marker = isSelected ? " > " : " ";
7192
7912
  const suffix = isCurrent ? " (\u5F53\u524D)" : "";
7193
- return /* @__PURE__ */ jsxs11(Box11, { children: [
7194
- /* @__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: [
7195
7915
  marker,
7196
7916
  meta.displayName,
7197
7917
  suffix
7198
7918
  ] }),
7199
- isSelected && /* @__PURE__ */ jsxs11(Text12, { color: "#808080", children: [
7919
+ isSelected && /* @__PURE__ */ jsxs12(Text13, { color: "#808080", children: [
7200
7920
  " \u2014 ",
7201
7921
  id
7202
7922
  ] })
7203
7923
  ] }, id);
7204
7924
  }),
7205
- /* @__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" }) })
7206
7926
  ] }),
7207
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
7208
- ] }) : rewindSelecting ? /* @__PURE__ */ jsxs11(Box11, { marginTop: 1, flexDirection: "column", children: [
7209
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }),
7210
- /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", marginTop: 1, children: [
7211
- /* @__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" }),
7212
7932
  rewindList.map((cp2, i) => {
7213
7933
  const isSelected = i === rewindSelectIndex;
7214
7934
  const marker = isSelected ? " > " : " ";
7215
7935
  const time = new Date(cp2.timestamp).toLocaleTimeString();
7216
7936
  const preview = cp2.preview || "(\u7A7A)";
7217
7937
  const tag = cp2.isGitRepo ? "" : " [\u975E git\uFF0C\u4EC5\u5BF9\u8BDD]";
7218
- 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: [
7219
7939
  marker,
7220
7940
  "#",
7221
7941
  i + 1,
@@ -7227,21 +7947,25 @@ function ChatSession({
7227
7947
  "`"
7228
7948
  ] }) }, cp2.index);
7229
7949
  }),
7230
- /* @__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" }) })
7231
7951
  ] }),
7232
- /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) })
7233
- ] }) : /* @__PURE__ */ jsxs11(Fragment2, { children: [
7234
- (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: [
7235
7955
  PHASE_CONFIG[streamingPhase].icon,
7236
7956
  " ",
7237
7957
  PHASE_CONFIG[streamingPhase].label,
7238
7958
  " ",
7239
- /* @__PURE__ */ jsx11(InkSpinner3, { type: "dots" })
7240
- ] }) }) : 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,
7241
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
7242
- /* @__PURE__ */ jsxs11(Box11, { children: [
7243
- /* @__PURE__ */ jsx11(Box11, { width: 4, flexShrink: 0, children: /* @__PURE__ */ jsx11(Text12, { bold: true, color: "#00ff41", children: "\u26A1" }) }),
7244
- /* @__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(
7245
7969
  TextInput,
7246
7970
  {
7247
7971
  value: input,
@@ -7252,9 +7976,9 @@ function ChatSession({
7252
7976
  inputKey
7253
7977
  ) })
7254
7978
  ] }),
7255
- /* @__PURE__ */ jsx11(Box11, { children: /* @__PURE__ */ jsx11(Text12, { color: "#00ffff", dimColor: true, children: "\u2500".repeat(rightContentWidth) }) }),
7256
- /* @__PURE__ */ jsx11(SkillSelector, { skills, input, selectedIndex: skillSelectIndex }),
7257
- /* @__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 })
7258
7982
  ] })
7259
7983
  ] }), [
7260
7984
  displayMessages,
@@ -7302,15 +8026,53 @@ function ChatSession({
7302
8026
  doubleCtrlC
7303
8027
  ])
7304
8028
  ] }),
7305
- 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" }) }),
7306
- 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
+ "%"
7307
8069
  ] });
7308
8070
  }
7309
8071
 
7310
8072
  // src/ui/GamePicker.tsx
7311
- 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";
7312
8074
  import { useState as useState6, useCallback as useCallback3 } from "react";
7313
- import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
8075
+ import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
7314
8076
  function GamePicker({ games, onSelect, onExit, onBackToChat }) {
7315
8077
  const [selectedIndex, setSelectedIndex] = useState6(0);
7316
8078
  const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));
@@ -7338,18 +8100,18 @@ function GamePicker({ games, onSelect, onExit, onBackToChat }) {
7338
8100
  [games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC]
7339
8101
  )
7340
8102
  );
7341
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", children: [
7342
- /* @__PURE__ */ jsx12(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ffff", children: "\u{1F3AE} \u6E38\u620F\u5217\u8868" }) }),
7343
- /* @__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) => {
7344
8106
  const isSelected = index === selectedIndex;
7345
- return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "row", children: [
7346
- /* @__PURE__ */ jsx12(Box12, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx12(Text13, { bold: true, color: "#00ff41", children: "\u25B8 " }) : /* @__PURE__ */ jsx12(Text13, { children: " " }) }),
7347
- /* @__PURE__ */ jsx12(Box12, { width: 20, flexShrink: 0, children: /* @__PURE__ */ jsx12(Text13, { bold: true, color: isSelected ? "#00ff41" : "#ffffff", children: game.name }) }),
7348
- /* @__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 }) })
7349
8111
  ] }, game.id);
7350
8112
  }) }),
7351
- /* @__PURE__ */ jsx12(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text13, { dimColor: true, children: " \u2191/\u2193 \u9009\u62E9 Enter \u542F\u52A8 q \u8FD4\u56DE" }) }),
7352
- 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" }) })
7353
8115
  ] });
7354
8116
  }
7355
8117
 
@@ -7366,9 +8128,9 @@ function listGames() {
7366
8128
  }
7367
8129
 
7368
8130
  // src/game/brick-breaker/index.tsx
7369
- 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";
7370
8132
  import { useState as useState7, useEffect as useEffect6, useRef as useRef5, useCallback as useCallback4 } from "react";
7371
- import { jsx as jsx13, jsxs as jsxs13 } from "react/jsx-runtime";
8133
+ import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
7372
8134
  var GAME_WIDTH = 40;
7373
8135
  var GAME_HEIGHT = 18;
7374
8136
  var PADDLE_WIDTH = 9;
@@ -7558,49 +8320,49 @@ function BrickBreakerGame({ onExit: _onExit }) {
7558
8320
  const board = buildBoard(s);
7559
8321
  const def = getLevel(s.level);
7560
8322
  void tick2;
7561
- return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
7562
- /* @__PURE__ */ jsxs13(Box13, { flexDirection: "row", children: [
7563
- /* @__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: [
7564
8326
  "\u5173\u5361 ",
7565
8327
  s.level,
7566
8328
  ": ",
7567
- /* @__PURE__ */ jsx13(Text14, { color: "cyan", children: def.desc })
8329
+ /* @__PURE__ */ jsx14(Text15, { color: "cyan", children: def.desc })
7568
8330
  ] }) }),
7569
- /* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsxs13(Text14, { children: [
8331
+ /* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { children: [
7570
8332
  "\u5206\u6570: ",
7571
- /* @__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") })
7572
8334
  ] }) }),
7573
- /* @__PURE__ */ jsx13(Box13, { width: 12, children: /* @__PURE__ */ jsxs13(Text14, { children: [
8335
+ /* @__PURE__ */ jsx14(Box14, { width: 12, children: /* @__PURE__ */ jsxs14(Text15, { children: [
7574
8336
  "\u751F\u547D: ",
7575
- /* @__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)) })
7576
8338
  ] }) }),
7577
- /* @__PURE__ */ jsx13(Box13, { width: 10, children: /* @__PURE__ */ jsxs13(Text14, { children: [
8339
+ /* @__PURE__ */ jsx14(Box14, { width: 10, children: /* @__PURE__ */ jsxs14(Text15, { children: [
7578
8340
  "\u7816\u5757: ",
7579
- /* @__PURE__ */ jsx13(Text14, { color: "cyan", children: aliveCount })
8341
+ /* @__PURE__ */ jsx14(Text15, { color: "cyan", children: aliveCount })
7580
8342
  ] }) }),
7581
- /* @__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: [
7582
8344
  "[",
7583
8345
  s.paused ? "\u6682\u505C" : "\u8FD0\u884C\u4E2D",
7584
8346
  "]"
7585
8347
  ] }) })
7586
8348
  ] }),
7587
- /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
7588
- /* @__PURE__ */ jsxs13(Text14, { children: [
8349
+ /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", children: [
8350
+ /* @__PURE__ */ jsxs14(Text15, { children: [
7589
8351
  "\u250C",
7590
8352
  "\u2500".repeat(GAME_WIDTH),
7591
8353
  "\u2510"
7592
8354
  ] }),
7593
- /* @__PURE__ */ jsx13(Text14, { children: selectingLevel ? " \x1B[90m\u9009\u62E9\u5173\u5361\u540E\u5F00\u59CB...\x1B[0m" : board }),
7594
- /* @__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: [
7595
8357
  "\u2514",
7596
8358
  "\u2500".repeat(GAME_WIDTH),
7597
8359
  "\u2518"
7598
8360
  ] })
7599
8361
  ] }),
7600
- selectingLevel && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, flexDirection: "column", children: [
7601
- /* @__PURE__ */ jsx13(Text14, { bold: true, color: "yellow", children: "\u9009\u62E9\u5173\u5361" }),
7602
- /* @__PURE__ */ jsx13(Box13, { flexDirection: "row", flexWrap: "wrap", children: LEVELS.map((lv, i) => /* @__PURE__ */ jsx13(Box13, { width: 22, children: /* @__PURE__ */ jsxs13(Text14, { children: [
7603
- /* @__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) }),
7604
8366
  ". ",
7605
8367
  lv.desc,
7606
8368
  " (",
@@ -7609,16 +8371,16 @@ function BrickBreakerGame({ onExit: _onExit }) {
7609
8371
  lv.cols,
7610
8372
  ")"
7611
8373
  ] }) }, i)) }),
7612
- /* @__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" }) })
7613
8375
  ] }),
7614
- !selectingLevel && (s.gameOver || s.win) && /* @__PURE__ */ jsxs13(Box13, { marginTop: 1, children: [
7615
- /* @__PURE__ */ jsx13(Text14, { bold: true, color: s.gameOver ? "red" : "green", children: s.gameOver ? "\u6E38\u620F\u7ED3\u675F\uFF01" : "\u606D\u559C\u901A\u5173\uFF01" }),
7616
- /* @__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: [
7617
8379
  " \u5206\u6570: ",
7618
- /* @__PURE__ */ jsx13(Text14, { color: "yellow", children: s.score })
8380
+ /* @__PURE__ */ jsx14(Text15, { color: "yellow", children: s.score })
7619
8381
  ] })
7620
8382
  ] }),
7621
- !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" }) })
7622
8384
  ] });
7623
8385
  }
7624
8386
  var brick_breaker_default = {
@@ -7628,7 +8390,7 @@ var brick_breaker_default = {
7628
8390
  play: async () => {
7629
8391
  await new Promise((resolve2) => {
7630
8392
  const { unmount } = render2(
7631
- /* @__PURE__ */ jsx13(BrickBreakerGame, { onExit: () => {
8393
+ /* @__PURE__ */ jsx14(BrickBreakerGame, { onExit: () => {
7632
8394
  unmount();
7633
8395
  resolve2();
7634
8396
  } })
@@ -7638,9 +8400,9 @@ var brick_breaker_default = {
7638
8400
  };
7639
8401
 
7640
8402
  // src/game/coder-check/index.tsx
7641
- 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";
7642
8404
  import { useState as useState8, useEffect as useEffect7, useRef as useRef6, useCallback as useCallback5 } from "react";
7643
- import { jsx as jsx14, jsxs as jsxs14 } from "react/jsx-runtime";
8405
+ import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
7644
8406
  var GAME_W = 66;
7645
8407
  var GAME_H = 20;
7646
8408
  var SCORE_H = 6;
@@ -8111,44 +8873,44 @@ function CoderCheck({ onExit: _onExit }) {
8111
8873
  const scoreLines = buildScoreLines(scoreStr);
8112
8874
  const view = buildGameView(s, scoreLines, scoreColor, s.message);
8113
8875
  void tick2;
8114
- return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", paddingX: 1, children: [
8115
- /* @__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: [
8116
8878
  "\u751F\u547D ",
8117
- /* @__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)) }),
8118
8880
  " ",
8119
8881
  "\u901F\u5EA6 ",
8120
- /* @__PURE__ */ jsxs14(Text15, { color: "cyan", children: [
8882
+ /* @__PURE__ */ jsxs15(Text16, { color: "cyan", children: [
8121
8883
  "Lv.",
8122
8884
  Math.floor(s.speed * 10)
8123
8885
  ] })
8124
8886
  ] }) }),
8125
- !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: [
8126
8888
  "\u6253\u5B57: ",
8127
- /* @__PURE__ */ jsx14(Text15, { color: "green", children: s.typed }),
8128
- /* @__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) })
8129
8891
  ] }) }),
8130
- /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
8131
- /* @__PURE__ */ jsxs14(Text15, { children: [
8892
+ /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: 1, children: [
8893
+ /* @__PURE__ */ jsxs15(Text16, { children: [
8132
8894
  "\u250C",
8133
8895
  "\u2500".repeat(GAME_W),
8134
8896
  "\u2510"
8135
8897
  ] }),
8136
- view.map((row, i) => /* @__PURE__ */ jsx14(Text15, { children: `\u2502${row}\u2502` }, i)),
8137
- /* @__PURE__ */ jsxs14(Text15, { children: [
8898
+ view.map((row, i) => /* @__PURE__ */ jsx15(Text16, { children: `\u2502${row}\u2502` }, i)),
8899
+ /* @__PURE__ */ jsxs15(Text16, { children: [
8138
8900
  "\u2514",
8139
8901
  "\u2500".repeat(GAME_W),
8140
8902
  "\u2518"
8141
8903
  ] })
8142
8904
  ] }),
8143
- s.gameOver && /* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
8144
- /* @__PURE__ */ jsx14(Text15, { bold: true, color: "red", children: "\u6E38\u620F\u7ED3\u675F\uFF01" }),
8145
- /* @__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: [
8146
8908
  " \u5F97\u5206: ",
8147
- /* @__PURE__ */ jsx14(Text15, { color: "yellow", children: s.score }),
8909
+ /* @__PURE__ */ jsx15(Text16, { color: "yellow", children: s.score }),
8148
8910
  " r \u91CD\u5F00 q \u9000\u51FA"
8149
8911
  ] })
8150
8912
  ] }),
8151
- /* @__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" }) })
8152
8914
  ] });
8153
8915
  }
8154
8916
  var coder_check_default = {
@@ -8158,7 +8920,7 @@ var coder_check_default = {
8158
8920
  play: async () => {
8159
8921
  await new Promise((resolve2) => {
8160
8922
  const { unmount } = render3(
8161
- /* @__PURE__ */ jsx14(CoderCheck, { onExit: () => {
8923
+ /* @__PURE__ */ jsx15(CoderCheck, { onExit: () => {
8162
8924
  unmount();
8163
8925
  resolve2();
8164
8926
  } })
@@ -8538,12 +9300,12 @@ import { render as render4 } from "ink";
8538
9300
  import chalk5 from "chalk";
8539
9301
 
8540
9302
  // src/stock/StockList.tsx
8541
- import { Box as Box15, Text as Text16, useInput as useInput5 } from "ink";
8542
- 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";
8543
9305
  import asciichart from "asciichart";
8544
9306
  import os from "os";
8545
9307
  import { join as join10 } from "path";
8546
- import { jsx as jsx15, jsxs as jsxs15 } from "react/jsx-runtime";
9308
+ import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
8547
9309
  var SETTINGS_PATH = join10(os.homedir(), ".dskcode", "settings.json");
8548
9310
  function toFileUrl(p) {
8549
9311
  const norm = p.replace(/\\/g, "/");
@@ -8660,7 +9422,7 @@ function StockList({ codes, onExit, onBackToChat }) {
8660
9422
  );
8661
9423
  const [dimMode, setDimMode] = useState9(false);
8662
9424
  const [sortOrder, setSortOrder] = useState9("default");
8663
- const sortedStocks = useMemo2(() => {
9425
+ const sortedStocks = useMemo3(() => {
8664
9426
  if (sortOrder === "default") return stocks;
8665
9427
  return [...stocks].toSorted(
8666
9428
  (a, b) => sortOrder === "desc" ? b.changePercent - a.changePercent : a.changePercent - b.changePercent
@@ -8762,64 +9524,64 @@ function StockList({ codes, onExit, onBackToChat }) {
8762
9524
  );
8763
9525
  if (detailView) {
8764
9526
  if (detailLoading) {
8765
- 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..." }) });
8766
9528
  }
8767
9529
  return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown, currentTime);
8768
9530
  }
8769
9531
  const cp2 = (c) => dimMode ? { dimColor: true } : { color: c };
8770
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", children: [
8771
- /* @__PURE__ */ jsxs15(Box15, { marginBottom: 1, justifyContent: "space-between", children: [
8772
- /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2("#00ffff"), children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
8773
- /* @__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: [
8774
9536
  " \u{1F550} ",
8775
9537
  currentTime
8776
9538
  ] }),
8777
- /* @__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` })
8778
9540
  ] }),
8779
- /* @__PURE__ */ jsxs15(Box15, { children: [
8780
- /* @__PURE__ */ jsx15(Box15, { width: 3 }),
8781
- /* @__PURE__ */ jsx15(Box15, { width: 9, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u4EE3\u7801" }) }),
8782
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u540D\u79F0" }) }),
8783
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
8784
- /* @__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: [
8785
9547
  "\u6DA8\u8DCC\u5E45",
8786
9548
  sortOrder === "desc" ? " \u25BC" : sortOrder === "asc" ? " \u25B2" : ""
8787
9549
  ] }) }),
8788
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
8789
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6700\u9AD8" }) }),
8790
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: "\u6700\u4F4E" }) }),
8791
- /* @__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" }) })
8792
9554
  ] }),
8793
- /* @__PURE__ */ jsx15(Box15, { children: /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
8794
- /* @__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) => {
8795
9557
  const isSelected = index === selectedIndex;
8796
9558
  const isUp = stock.changePercent >= 0;
8797
9559
  const color = isUp ? "#ff1493" : "#00ff41";
8798
- return /* @__PURE__ */ jsxs15(Box15, { children: [
8799
- /* @__PURE__ */ jsx15(Box15, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2("#00ffff"), children: "\u25B8 " }) : /* @__PURE__ */ jsx15(Text16, { children: " " }) }),
8800
- /* @__PURE__ */ jsx15(Box15, { width: 9, children: /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2(isSelected ? "#00ffff" : "#ffffff"), children: stock.code }) }),
8801
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { ...cp2(isSelected ? "#ffffff" : "#cccccc"), children: stock.name }) }),
8802
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { bold: true, ...cp2(color), children: formatPrice(stock.price) }) }),
8803
- /* @__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: [
8804
9566
  isUp ? "+" : "",
8805
9567
  stock.changePercent.toFixed(2),
8806
9568
  "%"
8807
9569
  ] }) }),
8808
- /* @__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: [
8809
9571
  isUp ? "+" : "",
8810
9572
  stock.changeAmount.toFixed(3)
8811
9573
  ] }) }),
8812
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { ...cp2("#cccccc"), children: formatPrice(stock.high) }) }),
8813
- /* @__PURE__ */ jsx15(Box15, { width: 12, children: /* @__PURE__ */ jsx15(Text16, { ...cp2("#888888"), children: formatPrice(stock.low) }) }),
8814
- /* @__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) }) })
8815
9577
  ] }, stock.code);
8816
9578
  }) }),
8817
- /* @__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` }) }),
8818
- /* @__PURE__ */ jsxs15(Box15, { children: [
8819
- /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate} \u7F16\u8F91\u81EA\u9009\u80A1: ` }),
8820
- /* @__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) })
8821
9583
  ] }),
8822
- 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" }) })
8823
9585
  ] });
8824
9586
  }
8825
9587
  function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
@@ -8837,33 +9599,33 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
8837
9599
  raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
8838
9600
  chartLines = raw.split("\n");
8839
9601
  }
8840
- return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", paddingLeft: 1, children: [
8841
- /* @__PURE__ */ jsxs15(Box15, { marginBottom: 1, justifyContent: "space-between", children: [
8842
- /* @__PURE__ */ jsxs15(Box15, { children: [
8843
- /* @__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: [
8844
9606
  " \u{1F4CA} ",
8845
9607
  stock.name,
8846
9608
  " "
8847
9609
  ] }),
8848
- /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: stock.code }),
8849
- currentTime && /* @__PURE__ */ jsxs15(Text16, { dimColor: true, children: [
9610
+ /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: stock.code }),
9611
+ currentTime && /* @__PURE__ */ jsxs16(Text17, { dimColor: true, children: [
8850
9612
  " \u{1F550} ",
8851
9613
  currentTime
8852
9614
  ] })
8853
9615
  ] }),
8854
- /* @__PURE__ */ jsx15(Text16, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
9616
+ /* @__PURE__ */ jsx16(Text17, { dimColor: true, children: `${countdown}s \u540E\u5237\u65B0` })
8855
9617
  ] }),
8856
- /* @__PURE__ */ jsxs15(Box15, { children: [
8857
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
8858
- /* @__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: [
8859
9621
  arrow,
8860
9622
  " ",
8861
9623
  formatPrice(stock.price)
8862
9624
  ] }) })
8863
9625
  ] }),
8864
- /* @__PURE__ */ jsxs15(Box15, { children: [
8865
- /* @__PURE__ */ jsx15(Box15, { width: 16, children: /* @__PURE__ */ jsx15(Text16, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
8866
- /* @__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: [
8867
9629
  isUp ? "+" : "",
8868
9630
  stock.changePercent.toFixed(2),
8869
9631
  "%",
@@ -8872,8 +9634,8 @@ function renderDetail(stock, _onBack, prices, countdown = 10, currentTime) {
8872
9634
  stock.changeAmount.toFixed(3)
8873
9635
  ] }) })
8874
9636
  ] }),
8875
- 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)) }),
8876
- /* @__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" }) })
8877
9639
  ] });
8878
9640
  }
8879
9641
 
@@ -8958,7 +9720,7 @@ async function scanProjectFiles(baseDir, dir) {
8958
9720
  }
8959
9721
 
8960
9722
  // src/cli/index.tsx
8961
- import { jsx as jsx16 } from "react/jsx-runtime";
9723
+ import { jsx as jsx17 } from "react/jsx-runtime";
8962
9724
  var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
8963
9725
  function createCli() {
8964
9726
  const program2 = new Command();
@@ -9060,7 +9822,7 @@ compdef _dskcode_completion dskcode`);
9060
9822
  const freshResult = await loadAndValidate();
9061
9823
  const codeList = codes && codes.length > 0 ? codes : freshResult.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
9062
9824
  const app = renderApp(
9063
- /* @__PURE__ */ jsx16(
9825
+ /* @__PURE__ */ jsx17(
9064
9826
  StockList,
9065
9827
  {
9066
9828
  codes: codeList,
@@ -9089,7 +9851,7 @@ compdef _dskcode_completion dskcode`);
9089
9851
  }
9090
9852
  const selectedGame = await new Promise((resolve2) => {
9091
9853
  const { unmount } = render4(
9092
- /* @__PURE__ */ jsx16(
9854
+ /* @__PURE__ */ jsx17(
9093
9855
  GamePicker,
9094
9856
  {
9095
9857
  games,
@@ -9129,7 +9891,7 @@ async function startChat(ctx, costTracker) {
9129
9891
  );
9130
9892
  const model = defaultProvider?.model ?? "deepseek-v4-flash";
9131
9893
  const chatApp = renderApp(
9132
- /* @__PURE__ */ jsx16(
9894
+ /* @__PURE__ */ jsx17(
9133
9895
  ChatSession,
9134
9896
  {
9135
9897
  skillCount,
@@ -9147,7 +9909,7 @@ async function startChat(ctx, costTracker) {
9147
9909
  initGames();
9148
9910
  const games = listGames();
9149
9911
  const { unmount } = render4(
9150
- /* @__PURE__ */ jsx16(
9912
+ /* @__PURE__ */ jsx17(
9151
9913
  GamePicker,
9152
9914
  {
9153
9915
  games,
@@ -9171,7 +9933,7 @@ async function startChat(ctx, costTracker) {
9171
9933
  setImmediate(() => {
9172
9934
  const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code) ?? ["sh000001", "sz399006", "sh601688"];
9173
9935
  const stockApp = renderApp(
9174
- /* @__PURE__ */ jsx16(
9936
+ /* @__PURE__ */ jsx17(
9175
9937
  StockList,
9176
9938
  {
9177
9939
  codes: defaultStockCodes,