dskcode 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -2
- package/dist/index.js +317 -6
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -20,6 +20,12 @@
|
|
|
20
20
|
- **权限控制** — 三级审批策略(Allow / Ask / Deny),安全可控
|
|
21
21
|
- **TOML 配置** — 多层级配置(全局 + 项目 + 环境变量 + CLI flag)
|
|
22
22
|
- **中文优先** — 界面提示、帮助信息、文档均为中文
|
|
23
|
+
- **股票行情** — `dskcode stock` 交互式 A 股行情终端,键盘选择 + 详情折线图 + 每 10 秒自动刷新
|
|
24
|
+
-
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+

|
|
28
|
+
|
|
23
29
|
- **内置小游戏** — `dskcode game` 启动游戏列表,打砖块、Coder Check 极速打字等内置游戏供休闲娱乐
|
|
24
30
|
|
|
25
31
|

|
|
@@ -55,6 +61,8 @@ npx dskcode chat
|
|
|
55
61
|
| `dskcode setup` | 运行配置向导,设置 API Key 等 |
|
|
56
62
|
| `dskcode init` | 在当前项目生成 AGENTS.md 项目记忆文件 |
|
|
57
63
|
| `dskcode game <name>` | 启动内置小游戏,不指定名称则显示交互式游戏列表 |
|
|
64
|
+
| `dskcode stock [codes...]` | 交互式股票行情,↑/↓ 选择,Enter 查看分时折线图,每 10 秒自动刷新 |
|
|
65
|
+
| `dskcode stock sh000001 sz399006` | 查看指定股票行情 |
|
|
58
66
|
| `dskcode completion` | 生成 shell 自动补全配置 |
|
|
59
67
|
|
|
60
68
|
### 全局选项
|
|
@@ -110,17 +118,96 @@ dskcode 使用 JSON 格式的配置文件,支持多层级合并:
|
|
|
110
118
|
}
|
|
111
119
|
```
|
|
112
120
|
|
|
121
|
+
### 股票行情
|
|
122
|
+
|
|
123
|
+
`dskcode stock` 启动交互式股票行情终端,基于腾讯免费行情接口,支持实时查看 A 股/指数/ETF 行情。
|
|
124
|
+
|
|
125
|
+
#### 功能
|
|
126
|
+
|
|
127
|
+
- **实时行情列表** — 涨跌彩色标识(红涨绿跌),显示最新价、涨跌幅、最高/最低价、成交量
|
|
128
|
+
- **键盘选择** — `↑/↓` 切换股票,`Enter` 查看详情
|
|
129
|
+
- **分时折线图** — 详情页展示最近 60 笔分钟线的 ASCII 折线图(直角折线风格)
|
|
130
|
+
- **自动刷新** — 列表每 5 秒刷新,详情页每 10 秒刷新,右上角显示倒计时
|
|
131
|
+
- **手动刷新** — 按 `r` 键强制刷新
|
|
132
|
+
|
|
133
|
+
#### 使用方式
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# 默认股票(上证指数 + 创业板指 + 华泰证券)
|
|
137
|
+
dskcode stock
|
|
138
|
+
|
|
139
|
+
# 指定股票代码
|
|
140
|
+
dskcode stock sh000001 sz399006 sh601688
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### 示例界面
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
📈 自选股监控 每 5s 自动刷新
|
|
147
|
+
代码 名称 最新价 涨跌幅 涨跌额 最高 最低 成交量
|
|
148
|
+
────────────────────────────────────────────────────────────────────────────
|
|
149
|
+
▸ sh000001 上证指数 3150.00 +0.35% +11.02 3160.00 3140.00 28543.0万
|
|
150
|
+
sz399006 创业板指 1820.00 -0.52% -9.50 1835.00 1815.00 9865.0万
|
|
151
|
+
sh601688 华泰证券 14.25 +1.05% +0.15 14.38 14.10 45.2万
|
|
152
|
+
|
|
153
|
+
↑/↓ 选择 Enter 详情 r 手动刷新 q 返回
|
|
154
|
+
最后更新: 14:30:00
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
按 `Enter` 进入详情页,查看 ASCII 分时折线图:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
📊 华泰证券 sh601688 每 8s 刷新
|
|
161
|
+
|
|
162
|
+
当前价 ▲ 14.25
|
|
163
|
+
涨跌幅 +1.05% +0.15
|
|
164
|
+
|
|
165
|
+
14.42 ┤ ┌─┐
|
|
166
|
+
14.34 ┤ ┌─┘ └─┐
|
|
167
|
+
14.26 ┤ ┌┘ └─┐
|
|
168
|
+
14.18 ┤─┘ └─┐
|
|
169
|
+
14.10 ┤ └──
|
|
170
|
+
|
|
171
|
+
Space/q 返回列表
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### 股票代码格式
|
|
175
|
+
|
|
176
|
+
代码需带市场前缀:
|
|
177
|
+
|
|
178
|
+
| 市场 | 格式 | 示例 |
|
|
179
|
+
|------|------|------|
|
|
180
|
+
| 上海主板 | `sh6xxxxx` | `sh601899`(紫金矿业) |
|
|
181
|
+
| 深圳主板 | `sz000xxx` | `sz000001`(平安银行) |
|
|
182
|
+
| 创业板 | `sz30xxxx` | `sz300750`(宁德时代) |
|
|
183
|
+
| 科创板 | `sh688xxx` | `sh688981`(中芯国际) |
|
|
184
|
+
| 指数 | `sh000xxx` / `sz399xxx` | `sz399300`(沪深300) |
|
|
185
|
+
| ETF | `sh5xxxxx` / `sz15xxxx` | `sh513090`(香港证券ETF) |
|
|
186
|
+
|
|
187
|
+
也可用纯数字代码,程序自动识别市场:
|
|
188
|
+
```bash
|
|
189
|
+
dskcode stock 000001 399006
|
|
190
|
+
# 000001 → sh000001(上证指数)
|
|
191
|
+
# 399006 → sz399006(创业板指)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### 数据来源
|
|
195
|
+
|
|
196
|
+
分时数据来自腾讯免费行情接口 `web.ifzq.gtimg.cn/appstock/app/minute/query`,全天 242 条分钟线(09:30~15:00)。
|
|
197
|
+
|
|
113
198
|
## 架构
|
|
114
199
|
|
|
115
200
|
```
|
|
116
201
|
src/
|
|
117
202
|
├── index.ts # 入口,shebang + 异常处理
|
|
118
203
|
├── cli/ # commander 命令路由
|
|
119
|
-
├── config/ #
|
|
120
|
-
├── provider/ # LLM Provider 接口(DeepSeek
|
|
204
|
+
├── config/ # JSON 配置加载与合并
|
|
205
|
+
├── provider/ # LLM Provider 接口(DeepSeek)
|
|
121
206
|
├── tool/ # 内置工具接口(读文件、写文件、bash 等)
|
|
122
207
|
├── plugin/ # MCP 插件管理器
|
|
123
208
|
├── agent/ # Agent 会话循环
|
|
209
|
+
├── stock/ # 股票行情(StockList 交互式行情终端 + asciichart 折线图)
|
|
210
|
+
├── game/ # 内置小游戏
|
|
124
211
|
└── ui/ # Ink 交互式终端 UI
|
|
125
212
|
```
|
|
126
213
|
|
package/dist/index.js
CHANGED
|
@@ -29,7 +29,14 @@ var defaultConfig = {
|
|
|
29
29
|
{ name: "ls", enabled: true },
|
|
30
30
|
{ name: "fetch", enabled: true }
|
|
31
31
|
],
|
|
32
|
-
plugins: []
|
|
32
|
+
plugins: [],
|
|
33
|
+
stock: {
|
|
34
|
+
symbols: [
|
|
35
|
+
{ code: "sh000001" },
|
|
36
|
+
{ code: "sz399300" },
|
|
37
|
+
{ code: "sh601899" }
|
|
38
|
+
]
|
|
39
|
+
}
|
|
33
40
|
};
|
|
34
41
|
function resolveConfigFiles(configPath) {
|
|
35
42
|
if (configPath) {
|
|
@@ -67,6 +74,9 @@ function mergeConfig(base, overlay) {
|
|
|
67
74
|
if (overlay.plugins !== void 0) {
|
|
68
75
|
result.plugins = overlay.plugins;
|
|
69
76
|
}
|
|
77
|
+
if (overlay.stock !== void 0) {
|
|
78
|
+
result.stock = overlay.stock;
|
|
79
|
+
}
|
|
70
80
|
return result;
|
|
71
81
|
}
|
|
72
82
|
var ENV_PREFIX = "DSKCODE_";
|
|
@@ -214,11 +224,12 @@ async function saveApiKey(apiKey) {
|
|
|
214
224
|
const configDir = join(home, ".dskcode");
|
|
215
225
|
const configFile = join(configDir, "settings.json");
|
|
216
226
|
await mkdir(configDir, { recursive: true });
|
|
217
|
-
let configData
|
|
227
|
+
let configData;
|
|
218
228
|
try {
|
|
219
229
|
const raw = await readFile(configFile, "utf-8");
|
|
220
230
|
configData = JSON.parse(raw);
|
|
221
231
|
} catch {
|
|
232
|
+
configData = structuredClone(defaultConfig);
|
|
222
233
|
}
|
|
223
234
|
const providers = configData.providers ?? [];
|
|
224
235
|
const existing = providers.find((p) => p.name === "deepseek");
|
|
@@ -312,6 +323,10 @@ function customHelp(program2) {
|
|
|
312
323
|
lines.push(" dskcode setup");
|
|
313
324
|
lines.push(` ${chalk.dim("# \u751F\u6210 shell \u81EA\u52A8\u8865\u5168")}`);
|
|
314
325
|
lines.push(" dskcode completion");
|
|
326
|
+
lines.push(` ${chalk.dim("# \u67E5\u770B\u81EA\u9009\u80A1\u884C\u60C5")}`);
|
|
327
|
+
lines.push(" dskcode stock");
|
|
328
|
+
lines.push(` ${chalk.dim("# \u67E5\u770B\u6307\u5B9A\u80A1\u7968\u884C\u60C5")}`);
|
|
329
|
+
lines.push(" dskcode stock sh513090 sz000001");
|
|
315
330
|
lines.push("");
|
|
316
331
|
return lines.join("\n");
|
|
317
332
|
}
|
|
@@ -1381,8 +1396,290 @@ function initGames() {
|
|
|
1381
1396
|
// src/cli/index.tsx
|
|
1382
1397
|
import { render as render4 } from "ink";
|
|
1383
1398
|
import chalk3 from "chalk";
|
|
1384
|
-
|
|
1385
|
-
|
|
1399
|
+
|
|
1400
|
+
// src/stock/StockList.tsx
|
|
1401
|
+
import { Box as Box7, Text as Text8, useInput as useInput4 } from "ink";
|
|
1402
|
+
import { useState as useState6, useCallback as useCallback5, useEffect as useEffect5 } from "react";
|
|
1403
|
+
import asciichart from "asciichart";
|
|
1404
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1405
|
+
var MINUTE_API = "https://web.ifzq.gtimg.cn/appstock/app/minute/query?code={code}&r=0.1";
|
|
1406
|
+
function toApiCode(code) {
|
|
1407
|
+
if (/^sh|^sz/.test(code)) return code;
|
|
1408
|
+
if (/^60/.test(code) || /^68/.test(code)) return "sh" + code;
|
|
1409
|
+
if (/^00/.test(code) || /^30/.test(code) || /^39/.test(code)) return "sz" + code;
|
|
1410
|
+
if (/^51/.test(code)) return "sh" + code;
|
|
1411
|
+
return "sh" + code;
|
|
1412
|
+
}
|
|
1413
|
+
async function fetchStockMinute(code) {
|
|
1414
|
+
const url = MINUTE_API.replace("{code}", toApiCode(code));
|
|
1415
|
+
try {
|
|
1416
|
+
const resp = await fetch(url);
|
|
1417
|
+
const json = await resp.json();
|
|
1418
|
+
if (json.code !== 0) return null;
|
|
1419
|
+
const stockKey = toApiCode(code);
|
|
1420
|
+
const stockData = json.data?.[stockKey];
|
|
1421
|
+
if (!stockData) return null;
|
|
1422
|
+
const rawMinutes = stockData.data?.data ?? [];
|
|
1423
|
+
const prices = [];
|
|
1424
|
+
for (const line of rawMinutes) {
|
|
1425
|
+
const parts = line.split(" ");
|
|
1426
|
+
if (parts.length >= 2) {
|
|
1427
|
+
const p = parseFloat(parts[1]);
|
|
1428
|
+
if (!isNaN(p)) prices.push(p);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
const qtKey = stockKey;
|
|
1432
|
+
const qt = stockData.qt?.[qtKey];
|
|
1433
|
+
let quote = null;
|
|
1434
|
+
if (qt && qt.length >= 35) {
|
|
1435
|
+
quote = {
|
|
1436
|
+
code,
|
|
1437
|
+
name: qt[1] ?? "",
|
|
1438
|
+
price: parseFloat(qt[3] ?? "0"),
|
|
1439
|
+
changePercent: parseFloat(qt[32] ?? "0"),
|
|
1440
|
+
changeAmount: parseFloat(qt[31] ?? "0"),
|
|
1441
|
+
high: parseFloat(qt[33] ?? "0"),
|
|
1442
|
+
low: parseFloat(qt[34] ?? "0"),
|
|
1443
|
+
volume: parseInt(qt[6] ?? "0", 10)
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
return {
|
|
1447
|
+
prices,
|
|
1448
|
+
quote,
|
|
1449
|
+
date: stockData.data?.date ?? ""
|
|
1450
|
+
};
|
|
1451
|
+
} catch {
|
|
1452
|
+
return null;
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
var minuteCache = /* @__PURE__ */ new Map();
|
|
1456
|
+
function cacheMinute(code, prices) {
|
|
1457
|
+
minuteCache.set(code, prices);
|
|
1458
|
+
}
|
|
1459
|
+
var FALLBACK_STOCKS = [
|
|
1460
|
+
{ code: "000001", name: "\u4E0A\u8BC1\u6307\u6570", price: 3150, changePercent: 0.35, changeAmount: 11.02, high: 3160, low: 3140, volume: 28543e4 },
|
|
1461
|
+
{ code: "399006", name: "\u521B\u4E1A\u677F\u6307", price: 1820, changePercent: -0.52, changeAmount: -9.5, high: 1835, low: 1815, volume: 9865e4 },
|
|
1462
|
+
{ code: "601688", name: "\u534E\u6CF0\u8BC1\u5238", price: 14.25, changePercent: 1.05, changeAmount: 0.15, high: 14.38, low: 14.1, volume: 452100 }
|
|
1463
|
+
];
|
|
1464
|
+
async function fetchStocks(codes) {
|
|
1465
|
+
const results = await Promise.all(
|
|
1466
|
+
codes.map(async (code) => {
|
|
1467
|
+
const data = await fetchStockMinute(code);
|
|
1468
|
+
if (data?.quote) {
|
|
1469
|
+
if (data.prices.length > 0) cacheMinute(code, data.prices);
|
|
1470
|
+
return data.quote;
|
|
1471
|
+
}
|
|
1472
|
+
return null;
|
|
1473
|
+
})
|
|
1474
|
+
);
|
|
1475
|
+
const real = results.filter((r) => r !== null);
|
|
1476
|
+
if (real.length > 0) return real;
|
|
1477
|
+
return FALLBACK_STOCKS;
|
|
1478
|
+
}
|
|
1479
|
+
function formatPrice(p) {
|
|
1480
|
+
return p >= 100 ? p.toFixed(2) : p.toFixed(3);
|
|
1481
|
+
}
|
|
1482
|
+
function formatVolume(v) {
|
|
1483
|
+
if (v >= 1e4) return (v / 1e4).toFixed(1) + "\u4E07";
|
|
1484
|
+
return v.toLocaleString();
|
|
1485
|
+
}
|
|
1486
|
+
function latestPoints(data, maxPoints = 60) {
|
|
1487
|
+
if (data.length <= maxPoints) return data;
|
|
1488
|
+
return data.slice(data.length - maxPoints);
|
|
1489
|
+
}
|
|
1490
|
+
function StockList({ codes, onExit }) {
|
|
1491
|
+
const [stocks, setStocks] = useState6([]);
|
|
1492
|
+
const [selectedIndex, setSelectedIndex] = useState6(0);
|
|
1493
|
+
const [loading, setLoading] = useState6(true);
|
|
1494
|
+
const [lastUpdate, setLastUpdate] = useState6("");
|
|
1495
|
+
const [detailView, setDetailView] = useState6(null);
|
|
1496
|
+
const [detailPrices, setDetailPrices] = useState6(null);
|
|
1497
|
+
const [detailLoading, setDetailLoading] = useState6(false);
|
|
1498
|
+
const [detailCountdown, setDetailCountdown] = useState6(10);
|
|
1499
|
+
const [countdown, setCountdown] = useState6(5);
|
|
1500
|
+
const loadData = useCallback5(async () => {
|
|
1501
|
+
setLoading(true);
|
|
1502
|
+
try {
|
|
1503
|
+
const data = await fetchStocks(codes ?? []);
|
|
1504
|
+
setStocks(data);
|
|
1505
|
+
setLastUpdate((/* @__PURE__ */ new Date()).toLocaleTimeString());
|
|
1506
|
+
} catch {
|
|
1507
|
+
}
|
|
1508
|
+
setLoading(false);
|
|
1509
|
+
}, [codes]);
|
|
1510
|
+
useEffect5(() => {
|
|
1511
|
+
loadData();
|
|
1512
|
+
}, [loadData]);
|
|
1513
|
+
useEffect5(() => {
|
|
1514
|
+
const interval = setInterval(() => {
|
|
1515
|
+
setCountdown((prev) => {
|
|
1516
|
+
if (prev <= 1) {
|
|
1517
|
+
loadData();
|
|
1518
|
+
return 5;
|
|
1519
|
+
}
|
|
1520
|
+
return prev - 1;
|
|
1521
|
+
});
|
|
1522
|
+
}, 1e3);
|
|
1523
|
+
return () => clearInterval(interval);
|
|
1524
|
+
}, [loadData]);
|
|
1525
|
+
useEffect5(() => {
|
|
1526
|
+
if (!detailView) {
|
|
1527
|
+
setDetailPrices(null);
|
|
1528
|
+
setDetailLoading(false);
|
|
1529
|
+
return;
|
|
1530
|
+
}
|
|
1531
|
+
const loadDetail = () => {
|
|
1532
|
+
minuteCache.delete(detailView.code);
|
|
1533
|
+
fetchStockMinute(detailView.code).then((data) => {
|
|
1534
|
+
if (data && data.prices.length > 0) {
|
|
1535
|
+
cacheMinute(detailView.code, data.prices);
|
|
1536
|
+
setDetailPrices(data.prices);
|
|
1537
|
+
}
|
|
1538
|
+
});
|
|
1539
|
+
};
|
|
1540
|
+
loadDetail();
|
|
1541
|
+
setDetailCountdown(10);
|
|
1542
|
+
const timer = setInterval(loadDetail, 1e4);
|
|
1543
|
+
return () => clearInterval(timer);
|
|
1544
|
+
}, [detailView]);
|
|
1545
|
+
useEffect5(() => {
|
|
1546
|
+
if (!detailView) return;
|
|
1547
|
+
const timer = setInterval(() => {
|
|
1548
|
+
setDetailCountdown((prev) => prev > 0 ? prev - 1 : 10);
|
|
1549
|
+
}, 1e3);
|
|
1550
|
+
return () => clearInterval(timer);
|
|
1551
|
+
}, [detailView]);
|
|
1552
|
+
useInput4(
|
|
1553
|
+
useCallback5(
|
|
1554
|
+
(input, key) => {
|
|
1555
|
+
if (detailView) {
|
|
1556
|
+
if (key.escape || input === "q" || input === " ") {
|
|
1557
|
+
setDetailView(null);
|
|
1558
|
+
}
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
if (stocks.length === 0) return;
|
|
1562
|
+
if (key.upArrow || input === "k") {
|
|
1563
|
+
setSelectedIndex((prev) => prev > 0 ? prev - 1 : stocks.length - 1);
|
|
1564
|
+
} else if (key.downArrow || input === "j") {
|
|
1565
|
+
setSelectedIndex((prev) => prev < stocks.length - 1 ? prev + 1 : 0);
|
|
1566
|
+
} else if (key.return) {
|
|
1567
|
+
const stock = stocks[selectedIndex];
|
|
1568
|
+
if (stock) setDetailView(stock);
|
|
1569
|
+
} else if (key.escape || input === "q") {
|
|
1570
|
+
onExit();
|
|
1571
|
+
} else if (input === "r") {
|
|
1572
|
+
setCountdown(5);
|
|
1573
|
+
loadData();
|
|
1574
|
+
}
|
|
1575
|
+
},
|
|
1576
|
+
[stocks, selectedIndex, detailView, onExit, loadData]
|
|
1577
|
+
)
|
|
1578
|
+
);
|
|
1579
|
+
if (detailView) {
|
|
1580
|
+
if (detailLoading) {
|
|
1581
|
+
return /* @__PURE__ */ jsx7(Box7, { paddingLeft: 1, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: " \u27F3 \u52A0\u8F7D\u5206\u65F6\u6570\u636E..." }) });
|
|
1582
|
+
}
|
|
1583
|
+
return renderDetail(detailView, () => setDetailView(null), detailPrices ?? void 0, detailCountdown);
|
|
1584
|
+
}
|
|
1585
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", children: [
|
|
1586
|
+
/* @__PURE__ */ jsxs7(Box7, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
1587
|
+
/* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ffff", children: " \u{1F4C8} \u81EA\u9009\u80A1\u76D1\u63A7" }),
|
|
1588
|
+
/* @__PURE__ */ jsx7(Text8, { dimColor: true, children: loading ? " \u27F3 \u5237\u65B0\u4E2D..." : ` \u6BCF ${countdown}s \u81EA\u52A8\u5237\u65B0` })
|
|
1589
|
+
] }),
|
|
1590
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
1591
|
+
/* @__PURE__ */ jsx7(Box7, { width: 3 }),
|
|
1592
|
+
/* @__PURE__ */ jsx7(Box7, { width: 9, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u4EE3\u7801" }) }),
|
|
1593
|
+
/* @__PURE__ */ jsx7(Box7, { width: 16, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u540D\u79F0" }) }),
|
|
1594
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u6700\u65B0\u4EF7" }) }),
|
|
1595
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u6DA8\u8DCC\u5E45" }) }),
|
|
1596
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u6DA8\u8DCC\u989D" }) }),
|
|
1597
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u6700\u9AD8" }) }),
|
|
1598
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u6700\u4F4E" }) }),
|
|
1599
|
+
/* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: "\u6210\u4EA4\u91CF" }) })
|
|
1600
|
+
] }),
|
|
1601
|
+
/* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: " " + "\u2500".repeat(100) }) }),
|
|
1602
|
+
/* @__PURE__ */ jsx7(Box7, { flexDirection: "column", children: stocks.map((stock, index) => {
|
|
1603
|
+
const isSelected = index === selectedIndex;
|
|
1604
|
+
const isUp = stock.changePercent >= 0;
|
|
1605
|
+
const color = isUp ? "#ff1493" : "#00ff41";
|
|
1606
|
+
return /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
1607
|
+
/* @__PURE__ */ jsx7(Box7, { width: 3, flexShrink: 0, children: isSelected ? /* @__PURE__ */ jsx7(Text8, { bold: true, color: "#00ffff", children: "\u25B8 " }) : /* @__PURE__ */ jsx7(Text8, { children: " " }) }),
|
|
1608
|
+
/* @__PURE__ */ jsx7(Box7, { width: 9, children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: isSelected ? "#00ffff" : "#ffffff", children: stock.code }) }),
|
|
1609
|
+
/* @__PURE__ */ jsx7(Box7, { width: 16, children: /* @__PURE__ */ jsx7(Text8, { color: isSelected ? "#ffffff" : "#cccccc", children: stock.name }) }),
|
|
1610
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { bold: true, color, children: formatPrice(stock.price) }) }),
|
|
1611
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsxs7(Text8, { color, children: [
|
|
1612
|
+
isUp ? "+" : "",
|
|
1613
|
+
stock.changePercent.toFixed(2),
|
|
1614
|
+
"%"
|
|
1615
|
+
] }) }),
|
|
1616
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsxs7(Text8, { color, children: [
|
|
1617
|
+
isUp ? "+" : "",
|
|
1618
|
+
stock.changeAmount.toFixed(3)
|
|
1619
|
+
] }) }),
|
|
1620
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { color: "#cccccc", children: formatPrice(stock.high) }) }),
|
|
1621
|
+
/* @__PURE__ */ jsx7(Box7, { width: 12, children: /* @__PURE__ */ jsx7(Text8, { color: "#cccccc", children: formatPrice(stock.low) }) }),
|
|
1622
|
+
/* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { color: "#888888", children: formatVolume(stock.volume) }) })
|
|
1623
|
+
] }, stock.code);
|
|
1624
|
+
}) }),
|
|
1625
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: ` \u2191/\u2193 \u9009\u62E9 Enter \u8BE6\u60C5 r \u624B\u52A8\u5237\u65B0 q \u8FD4\u56DE` }) }),
|
|
1626
|
+
/* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: ` \u6700\u540E\u66F4\u65B0: ${lastUpdate}` }) })
|
|
1627
|
+
] });
|
|
1628
|
+
}
|
|
1629
|
+
function renderDetail(stock, _onBack, prices, countdown = 10) {
|
|
1630
|
+
const isUp = stock.changePercent >= 0;
|
|
1631
|
+
const colorCode = isUp ? "#ff1493" : "#00ff41";
|
|
1632
|
+
const arrow = isUp ? "\u25B2" : "\u25BC";
|
|
1633
|
+
let chartLines = [];
|
|
1634
|
+
if (prices && prices.length > 0) {
|
|
1635
|
+
const chartColor = isUp ? asciichart.red : asciichart.green;
|
|
1636
|
+
const latest = latestPoints(prices, 60);
|
|
1637
|
+
let raw = asciichart.plot(latest, {
|
|
1638
|
+
height: 10,
|
|
1639
|
+
colors: [chartColor]
|
|
1640
|
+
});
|
|
1641
|
+
raw = raw.replaceAll("\u256D", "\u250C").replaceAll("\u256E", "\u2510").replaceAll("\u2570", "\u2514").replaceAll("\u256F", "\u2518");
|
|
1642
|
+
chartLines = raw.split("\n");
|
|
1643
|
+
}
|
|
1644
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", paddingLeft: 1, children: [
|
|
1645
|
+
/* @__PURE__ */ jsxs7(Box7, { marginBottom: 1, justifyContent: "space-between", children: [
|
|
1646
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
1647
|
+
/* @__PURE__ */ jsxs7(Text8, { bold: true, color: "#00ffff", children: [
|
|
1648
|
+
" \u{1F4CA} ",
|
|
1649
|
+
stock.name,
|
|
1650
|
+
" "
|
|
1651
|
+
] }),
|
|
1652
|
+
/* @__PURE__ */ jsx7(Text8, { dimColor: true, children: stock.code })
|
|
1653
|
+
] }),
|
|
1654
|
+
/* @__PURE__ */ jsx7(Text8, { dimColor: true, children: `\u6BCF ${countdown}s \u5237\u65B0` })
|
|
1655
|
+
] }),
|
|
1656
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
1657
|
+
/* @__PURE__ */ jsx7(Box7, { width: 16, children: /* @__PURE__ */ jsx7(Text8, { bold: true, color: "#888888", children: "\u5F53\u524D\u4EF7" }) }),
|
|
1658
|
+
/* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text8, { bold: true, color: colorCode, children: [
|
|
1659
|
+
arrow,
|
|
1660
|
+
" ",
|
|
1661
|
+
formatPrice(stock.price)
|
|
1662
|
+
] }) })
|
|
1663
|
+
] }),
|
|
1664
|
+
/* @__PURE__ */ jsxs7(Box7, { children: [
|
|
1665
|
+
/* @__PURE__ */ jsx7(Box7, { width: 16, children: /* @__PURE__ */ jsx7(Text8, { color: "#888888", children: "\u6DA8\u8DCC\u5E45" }) }),
|
|
1666
|
+
/* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsxs7(Text8, { color: colorCode, children: [
|
|
1667
|
+
isUp ? "+" : "",
|
|
1668
|
+
stock.changePercent.toFixed(2),
|
|
1669
|
+
"%",
|
|
1670
|
+
" ",
|
|
1671
|
+
isUp ? "+" : "",
|
|
1672
|
+
stock.changeAmount.toFixed(3)
|
|
1673
|
+
] }) })
|
|
1674
|
+
] }),
|
|
1675
|
+
chartLines.length > 0 && /* @__PURE__ */ jsx7(Box7, { marginTop: 1, flexDirection: "column", children: chartLines.map((line, i) => /* @__PURE__ */ jsx7(Box7, { children: /* @__PURE__ */ jsx7(Text8, { color: colorCode, children: line || " " }) }, i)) }),
|
|
1676
|
+
/* @__PURE__ */ jsx7(Box7, { marginTop: 1, children: /* @__PURE__ */ jsx7(Text8, { dimColor: true, children: " Space/q \u8FD4\u56DE\u5217\u8868" }) })
|
|
1677
|
+
] });
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
// src/cli/index.tsx
|
|
1681
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1682
|
+
var SUBCOMMANDS = ["chat", "run", "setup", "init", "completion", "game", "stock"];
|
|
1386
1683
|
function createCli() {
|
|
1387
1684
|
const program2 = new Command();
|
|
1388
1685
|
program2.exitOverride();
|
|
@@ -1408,7 +1705,7 @@ function createCli() {
|
|
|
1408
1705
|
ctx = { ...ctx, config: result.config };
|
|
1409
1706
|
}
|
|
1410
1707
|
const app = renderApp(
|
|
1411
|
-
/* @__PURE__ */
|
|
1708
|
+
/* @__PURE__ */ jsx8(
|
|
1412
1709
|
ChatSession,
|
|
1413
1710
|
{
|
|
1414
1711
|
providerCount: ctx?.config.providers.length ?? 1,
|
|
@@ -1455,12 +1752,26 @@ _dskcode_completion() {
|
|
|
1455
1752
|
"init:\u751F\u6210\u9879\u76EE\u8BB0\u5FC6\u6587\u4EF6"
|
|
1456
1753
|
"completion:\u8F93\u51FA shell \u81EA\u52A8\u8865\u5168\u8BF4\u660E"
|
|
1457
1754
|
"game:\u5185\u7F6E\u5C0F\u6E38\u620F"
|
|
1755
|
+
"stock:\u67E5\u770B\u81EA\u9009\u80A1\u5B9E\u65F6\u884C\u60C5"
|
|
1458
1756
|
)
|
|
1459
1757
|
_describe 'dskcode commands' commands
|
|
1460
1758
|
}
|
|
1461
1759
|
compdef _dskcode_completion dskcode`);
|
|
1462
1760
|
}
|
|
1463
1761
|
});
|
|
1762
|
+
program2.command("stock").description("\u67E5\u770B\u81EA\u9009\u80A1\u5B9E\u65F6\u884C\u60C5").argument("[codes...]", "\u80A1\u7968\u4EE3\u7801\uFF08\u7A7A\u683C\u5206\u9694\uFF09\uFF0C\u5982 513090 600519").action(async function(codes) {
|
|
1763
|
+
const codeList = codes && codes.length > 0 ? codes : ["sh000001", "sz399006", "sh601688"];
|
|
1764
|
+
const app = renderApp(
|
|
1765
|
+
/* @__PURE__ */ jsx8(
|
|
1766
|
+
StockList,
|
|
1767
|
+
{
|
|
1768
|
+
codes: codeList,
|
|
1769
|
+
onExit: () => process.exit(0)
|
|
1770
|
+
}
|
|
1771
|
+
)
|
|
1772
|
+
);
|
|
1773
|
+
await app.waitUntilExit;
|
|
1774
|
+
});
|
|
1464
1775
|
initGames();
|
|
1465
1776
|
program2.command("game").description("\u542F\u52A8\u5185\u7F6E\u5C0F\u6E38\u620F").argument("[name]", "\u6E38\u620F\u540D\u79F0\uFF0C\u4E0D\u6307\u5B9A\u5219\u663E\u793A\u4EA4\u4E92\u5F0F\u6E38\u620F\u5217\u8868").action(async function(name) {
|
|
1466
1777
|
if (name) {
|
|
@@ -1480,7 +1791,7 @@ compdef _dskcode_completion dskcode`);
|
|
|
1480
1791
|
}
|
|
1481
1792
|
const selectedGame = await new Promise((resolve) => {
|
|
1482
1793
|
const { unmount } = render4(
|
|
1483
|
-
/* @__PURE__ */
|
|
1794
|
+
/* @__PURE__ */ jsx8(
|
|
1484
1795
|
GamePicker,
|
|
1485
1796
|
{
|
|
1486
1797
|
games,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/index.tsx","../src/config/loader.ts","../src/cli/middleware.ts","../src/cli/help.ts","../src/cli/api-key-setup.ts","../src/ui/RenderScope.tsx","../src/ui/Spinner.tsx","../src/ui/StatusMessage.tsx","../src/ui/DskcodeSplash.tsx","../src/ui/ChatSession.tsx","../src/ui/GamePicker.tsx","../src/game/index.ts","../src/game/brick-breaker/index.tsx","../src/game/coder-check/index.tsx","../src/game/registry.ts","../src/cli/exit-codes.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\r\nimport { loadConfigMiddleware } from \"./middleware.js\";\r\nimport { customHelp } from \"./help.js\";\r\nimport { hasApiKey, promptForApiKey } from \"./api-key-setup.js\";\r\nimport { saveApiKey, loadAndValidate } from \"../config/index.js\";\r\nimport { renderApp, ChatSession } from \"../ui/index.js\";\r\nimport { initGames } from \"../game/registry.js\";\r\nimport { listGames, getGame } from \"../game/index.js\";\r\nimport type { Game } from \"../game/index.js\";\r\nimport { GamePicker } from \"../ui/GamePicker.js\";\r\nimport { render } from \"ink\";\r\nimport chalk from \"chalk\";\r\n\r\nconst SUBCOMMANDS = [\"chat\", \"run\", \"setup\", \"init\", \"completion\", \"game\"];\r\n\r\nexport function createCli(): Command {\r\n const program = new Command();\r\n program.exitOverride();\r\n\r\n program\r\n .name(\"dskcode\")\r\n .description(\"基于 DeepSeek 的 AI 编程助手终端工具\")\r\n .version(\"0.0.0\", \"-V, --version\", \"显示版本号\")\r\n .option(\"--verbose\", \"开启详细日志输出\")\r\n .option(\"--config <path>\", \"指定配置文件路径\");\r\n\r\n program.helpInformation = () => customHelp(program);\r\n\r\n program.hook(\"preAction\", async (thisCommand, actionCommand) => {\r\n const ctx = await loadConfigMiddleware.call(thisCommand);\r\n (actionCommand as unknown as Record<string, unknown>).dskcodeCtx = ctx;\r\n });\r\n\r\n // chat — 交互式对话\r\n program\r\n .command(\"chat\")\r\n .description(\"启动交互式对话会话\")\r\n .action(async function () {\r\n if (!process.stdin.isTTY) {\r\n console.error(\"dskcode chat 需要交互式终端。如需执行一次性任务,请使用 dskcode run。\");\r\n process.exit(1);\r\n }\r\n\r\n let ctx = (this as unknown as Record<string, unknown>).dskcodeCtx as\r\n | { verbose: boolean; config: { providers: Array<{ apiKey?: string }>; tools: unknown[] } }\r\n | undefined;\r\n\r\n // 检查 API Key,如果没有则交互式输入\r\n if (ctx && !hasApiKey(ctx.config.providers)) {\r\n const key = await promptForApiKey();\r\n if (!key) process.exit(1);\r\n\r\n // 保存到全局配置\r\n const savedPath = await saveApiKey(key);\r\n console.log(` ${chalk.green(\"✔\")} API Key 已保存到 ${chalk.dim(savedPath)}\\n`);\r\n\r\n // 重新加载配置,使新 Key 生效\r\n const result = await loadAndValidate();\r\n ctx = { ...ctx, config: result.config };\r\n }\r\n\r\n const app = renderApp(\r\n <ChatSession\r\n providerCount={ctx?.config.providers.length ?? 1}\r\n toolCount={ctx?.config.tools.length ?? 0}\r\n verbose={ctx?.verbose ?? false}\r\n />,\r\n );\r\n\r\n await app.waitUntilExit;\r\n });\r\n\r\n // run\r\n program\r\n .command(\"run\")\r\n .description(\"执行一次性任务\")\r\n .argument(\"[prompt...]\", \"任务描述\")\r\n .option(\"--model <name>\", \"指定使用的模型\")\r\n .action(async function (_prompt: string[]) {\r\n console.log(\"dskcode run — 待实现(第07章)\");\r\n });\r\n\r\n // setup\r\n program\r\n .command(\"setup\")\r\n .description(\"运行配置向导\")\r\n .option(\"--export\", \"以 JSON 格式导出配置\")\r\n .option(\"--test\", \"测试 API Key 连通性\")\r\n .action(async function () {\r\n console.log(\"dskcode setup — 待实现(第14章)\");\r\n });\r\n\r\n // init\r\n program\r\n .command(\"init\")\r\n .description(\"在当前项目下生成项目记忆文件(AGENTS.md)\")\r\n .action(async function () {\r\n console.log(\"dskcode init — 待实现(第11章)\");\r\n });\r\n\r\n // completion\r\n program\r\n .command(\"completion\")\r\n .description(\"输出 shell 自动补全配置说明(bash/zsh)\")\r\n .argument(\"[shell]\", \"shell 类型\", /^(bash|zsh)$/i)\r\n .action(async function (shell?: string) {\r\n if (!shell) {\r\n console.log(\"请指定 shell 类型:dskcode completion bash 或 dskcode completion zsh\");\r\n return;\r\n }\r\n if (shell === \"bash\") {\r\n console.log(`# dskcode bash 自动补全\r\n_dskcode_completion() {\r\n local cur=\\${COMP_WORDS[COMP_CWORD]}\r\n if [[ \\${COMP_CWORD} -eq 1 ]]; then\r\n COMPREPLY=( $(compgen -W \"${SUBCOMMANDS.join(\" \")}\" -- \"\\${cur}\") )\r\n return 0\r\n fi\r\n COMPREPLY=( $(compgen -W \"--verbose --config --model\" -- \"\\${cur}\") )\r\n}\r\ncomplete -F _dskcode_completion dskcode`);\r\n } else {\r\n console.log(`# dskcode zsh 自动补全\r\n_dskcode_completion() {\r\n local -a commands\r\n commands=(\r\n \"chat:启动交互式对话会话\"\r\n \"run:执行一次性任务\"\r\n \"setup:运行配置向导\"\r\n \"init:生成项目记忆文件\"\r\n \"completion:输出 shell 自动补全说明\"\r\n \"game:内置小游戏\"\r\n )\r\n _describe 'dskcode commands' commands\r\n}\r\ncompdef _dskcode_completion dskcode`);\r\n }\r\n });\r\n\r\n // game — 游戏模式\r\n initGames();\r\n\r\n program\r\n .command(\"game\")\r\n .description(\"启动内置小游戏\")\r\n .argument(\"[name]\", \"游戏名称,不指定则显示交互式游戏列表\")\r\n .action(async function (name?: string) {\r\n if (name) {\r\n const game = getGame(name);\r\n if (!game) {\r\n console.error(`未找到游戏 \"${name}\"。使用 dskcode game 查看可用游戏列表。`);\r\n process.exit(1);\r\n }\r\n console.log(`正在启动: ${game.name} — ${game.description}\\n`);\r\n await game.play();\r\n } else {\r\n const games = listGames();\r\n if (games.length === 0) {\r\n console.log(\"暂无可用游戏。\");\r\n return;\r\n }\r\n\r\n const selectedGame = await new Promise<Game | null>((resolve) => {\r\n const { unmount } = render(\r\n <GamePicker\r\n games={games}\r\n onSelect={(game) => {\r\n unmount();\r\n resolve(game);\r\n }}\r\n onExit={() => {\r\n unmount();\r\n resolve(null);\r\n }}\r\n />,\r\n );\r\n });\r\n\r\n if (selectedGame) {\r\n console.log(`\\n 启动游戏: ${chalk.green(selectedGame.name)}\\n`);\r\n await selectedGame.play();\r\n }\r\n }\r\n });\r\n\r\n return program;\r\n}\r\n","import { existsSync, watch } from \"node:fs\";\r\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\nimport type { Config, ProviderConfig, ToolConfig, PluginConfig } from \"./types.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// 出厂默认配置\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const defaultConfig: Config = {\r\n defaultProvider: \"deepseek\",\r\n maxTokens: 8192,\r\n temperature: 0.7,\r\n maxToolRounds: 20,\r\n providers: [\r\n {\r\n name: \"deepseek\",\r\n baseUrl: \"https://api.deepseek.com\",\r\n model: \"deepseek-v4-flash\",\r\n },\r\n ],\r\n tools: [\r\n { name: \"read_file\", enabled: true },\r\n { name: \"write_file\", enabled: true },\r\n { name: \"edit_file\", enabled: true },\r\n { name: \"bash\", enabled: true },\r\n { name: \"glob\", enabled: true },\r\n { name: \"grep\", enabled: true },\r\n { name: \"ls\", enabled: true },\r\n { name: \"fetch\", enabled: true },\r\n ],\r\n plugins: [],\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// 配置文件路径解析\r\n// ---------------------------------------------------------------------------\r\n\r\n/** 判断一个字符串是否为合法的 URL(用于区分 local path 和 url) */\r\nfunction isUrl(s: string): boolean {\r\n try {\r\n new URL(s);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 返回候选配置文件路径列表。\r\n * 若传入了 --config 路径,则只使用该路径;\r\n * 否则依次检查用户全局目录和项目本地目录。\r\n */\r\nfunction resolveConfigFiles(configPath?: string): string[] {\r\n if (configPath) {\r\n return [configPath];\r\n }\r\n\r\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"~\";\r\n return [\r\n join(home, \".dskcode\", \"settings.json\"),\r\n join(process.cwd(), \".dskcode\", \"settings.json\"),\r\n ];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 深度合并\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 将较高优先级的配置 overlay 合并到 base 之上。\r\n *\r\n * 合并规则:\r\n * - 标量字段(string / number / boolean):覆盖\r\n * - 数组字段(providers / tools / plugins):直接替换,不合并\r\n */\r\nfunction mergeConfig(base: Config, overlay: Partial<Config>): Config {\r\n const result: Config = { ...base };\r\n\r\n if (overlay.defaultProvider !== undefined) {\r\n result.defaultProvider = overlay.defaultProvider;\r\n }\r\n if (overlay.verbose !== undefined) {\r\n result.verbose = overlay.verbose;\r\n }\r\n if (overlay.maxTokens !== undefined) {\r\n result.maxTokens = overlay.maxTokens;\r\n }\r\n if (overlay.temperature !== undefined) {\r\n result.temperature = overlay.temperature;\r\n }\r\n if (overlay.maxToolRounds !== undefined) {\r\n result.maxToolRounds = overlay.maxToolRounds;\r\n }\r\n if (overlay.providers !== undefined) {\r\n result.providers = overlay.providers as ProviderConfig[];\r\n }\r\n if (overlay.tools !== undefined) {\r\n result.tools = overlay.tools as ToolConfig[];\r\n }\r\n if (overlay.plugins !== undefined) {\r\n result.plugins = overlay.plugins as PluginConfig[];\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 环境变量解析\r\n// ---------------------------------------------------------------------------\r\n\r\n/** 环境变量前缀 */\r\nconst ENV_PREFIX = \"DSKCODE_\";\r\n\r\n/** 支持的环境变量映射表 */\r\nconst ENV_MAP: Record<string, keyof Config> = {\r\n [`${ENV_PREFIX}DEFAULT_PROVIDER`]: \"defaultProvider\",\r\n [`${ENV_PREFIX}VERBOSE`]: \"verbose\",\r\n [`${ENV_PREFIX}MAX_TOKENS`]: \"maxTokens\",\r\n [`${ENV_PREFIX}TEMPERATURE`]: \"temperature\",\r\n [`${ENV_PREFIX}MAX_TOOL_ROUNDS`]: \"maxToolRounds\",\r\n};\r\n\r\n/**\r\n * 将环境变量中读取的值覆盖到配置上。\r\n * 环境变量的优先级高于 TOML 文件,但低于 CLI flag。\r\n */\r\nfunction applyEnvVars(config: Config): Config {\r\n // 1. DSKCODE_* 前缀的环境变量\r\n for (const [envKey, configKey] of Object.entries(ENV_MAP)) {\r\n const raw = process.env[envKey];\r\n if (raw === undefined) continue;\r\n\r\n const cfg = config as unknown as Record<string, unknown>;\r\n switch (configKey) {\r\n case \"verbose\":\r\n case \"defaultProvider\": {\r\n cfg[configKey] = raw;\r\n break;\r\n }\r\n case \"maxTokens\":\r\n case \"maxToolRounds\": {\r\n const n = Number(raw);\r\n if (Number.isFinite(n) && n > 0) {\r\n cfg[configKey] = n;\r\n }\r\n break;\r\n }\r\n case \"temperature\": {\r\n const n = Number(raw);\r\n if (Number.isFinite(n) && n >= 0 && n <= 2) {\r\n cfg[configKey] = n;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // 2. DEEPSEEK_API_KEY — 注入到名为 deepseek 的 provider\r\n const apiKey = process.env.DEEPSEEK_API_KEY;\r\n if (apiKey) {\r\n const deepseek = config.providers.find((p) => p.name === \"deepseek\");\r\n if (deepseek && !deepseek.apiKey) {\r\n deepseek.apiKey = apiKey;\r\n }\r\n // 如果没有 deepseek provider,自动创建一个\r\n if (!deepseek) {\r\n config.providers.unshift({\r\n name: \"deepseek\",\r\n baseUrl: \"https://api.deepseek.com\",\r\n model: \"deepseek-v4-flash\",\r\n apiKey,\r\n });\r\n }\r\n }\r\n\r\n return config;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// CLI flag 覆盖\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface CliFlags {\r\n verbose?: boolean;\r\n model?: string;\r\n maxTokens?: number;\r\n temperature?: number;\r\n}\r\n\r\n/**\r\n * 将 CLI flag 中的值覆盖到配置上。\r\n * CLI flag 的优先级最高。\r\n */\r\nexport function applyCliOverrides(config: Config, flags: CliFlags): Config {\r\n if (flags.verbose !== undefined) {\r\n config.verbose = flags.verbose;\r\n }\r\n if (flags.model !== undefined) {\r\n // 将 --model 的值映射为标准 model 名称\r\n // 如果用户指定了 --model,覆盖 defaultProvider 中配置的 model\r\n // 但保留 provider 的选择,仅修改该 provider 的 model\r\n const provider = config.providers.find(\r\n (p) => p.name === config.defaultProvider,\r\n );\r\n if (provider) {\r\n provider.model = flags.model;\r\n }\r\n }\r\n if (flags.maxTokens !== undefined && flags.maxTokens > 0) {\r\n config.maxTokens = flags.maxTokens;\r\n }\r\n if (\r\n flags.temperature !== undefined &&\r\n flags.temperature >= 0 &&\r\n flags.temperature <= 2\r\n ) {\r\n config.temperature = flags.temperature;\r\n }\r\n return config;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 配置校验\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface ConfigError {\r\n field: string;\r\n message: string;\r\n}\r\n\r\n/**\r\n * 校验配置的合法性,返回错误列表。\r\n * 返回空数组表示配置合法。\r\n */\r\nexport function validateConfig(config: Config): ConfigError[] {\r\n const errors: ConfigError[] = [];\r\n\r\n // 1. 至少需要一个 Provider\r\n if (!config.providers || config.providers.length === 0) {\r\n errors.push({\r\n field: \"providers\",\r\n message: \"至少需要配置一个 Provider。请通过配置文件或 DEEPSEEK_API_KEY 环境变量设置。\",\r\n });\r\n }\r\n\r\n // 2. 每个 Provider 必须有 name 和 model\r\n for (let i = 0; i < config.providers.length; i++) {\r\n const p = config.providers[i]!;\r\n if (!p.name) {\r\n errors.push({\r\n field: `providers[${i}].name`,\r\n message: `第 ${i + 1} 个 Provider 缺少 name 字段。`,\r\n });\r\n }\r\n if (!p.model) {\r\n errors.push({\r\n field: `providers[${i}].model`,\r\n message: `Provider \"${p.name || i}\" 缺少 model 字段。`,\r\n });\r\n }\r\n }\r\n\r\n // 3. defaultProvider 必须存在于 providers 列表中\r\n if (config.defaultProvider) {\r\n const exists = config.providers.some(\r\n (p) => p.name === config.defaultProvider,\r\n );\r\n if (!exists) {\r\n errors.push({\r\n field: \"defaultProvider\",\r\n message: `默认 Provider \"${config.defaultProvider}\" 未在 providers 中定义。`,\r\n });\r\n }\r\n }\r\n\r\n // 4. temperature 范围校验\r\n if (\r\n config.temperature !== undefined &&\r\n (config.temperature < 0 || config.temperature > 2)\r\n ) {\r\n errors.push({\r\n field: \"temperature\",\r\n message: \"temperature 必须在 0.0 ~ 2.0 之间。\",\r\n });\r\n }\r\n\r\n // 5. maxToolRounds 范围校验\r\n if (config.maxToolRounds !== undefined && config.maxToolRounds < 1) {\r\n errors.push({\r\n field: \"maxToolRounds\",\r\n message: \"maxToolRounds 必须大于等于 1。\",\r\n });\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 核心加载流程\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 从多级配置源加载并合并配置。\r\n *\r\n * 解析顺序(后加载的优先级更高):\r\n * 1. 内置默认值 —— defaultConfig\r\n * 2. 用户全局 —— ~/.dskcode/settings.json\r\n * 3. 项目本地 —— .dskcode/settings.json(或通过 --config 指定的路径)\r\n * 4. 环境变量 —— DEEPSEEK_API_KEY、DSKCODE_* 等\r\n * 5. CLI flag —— 由调用方通过 applyCliOverrides() 单独注入\r\n */\r\nexport async function loadConfig(configPath?: string): Promise<Config> {\r\n const filePaths = resolveConfigFiles(configPath);\r\n\r\n let config: Config = structuredClone(defaultConfig);\r\n\r\n // 1-3. 依次加载 JSON 配置文件\r\n for (const filePath of filePaths) {\r\n try {\r\n const raw = await readFile(filePath, \"utf-8\");\r\n const parsed = JSON.parse(raw) as Partial<Config>;\r\n config = mergeConfig(config, parsed);\r\n } catch {\r\n // 文件不存在或权限不足 — 静默跳过\r\n }\r\n }\r\n\r\n // 4. 环境变量覆盖\r\n config = applyEnvVars(config);\r\n\r\n return config;\r\n}\r\n\r\n/**\r\n * 加载配置并同时执行校验。\r\n * 校验错误不会 throw,而是通过返回值中的 errors 字段返回,\r\n * 由调用方决定如何处理(例如在 middleware 中输出警告)。\r\n */\r\nexport async function loadAndValidate(\r\n configPath?: string,\r\n): Promise<{ config: Config; errors: ConfigError[] }> {\r\n const config = await loadConfig(configPath);\r\n const errors = validateConfig(config);\r\n return { config, errors };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 配置热加载(Watch 模式)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type ConfigChangeCallback = (config: Config) => void;\r\n\r\n/**\r\n * 监听配置文件变更,在文件被修改时重新加载配置并调用回调。\r\n *\r\n * @param callback 配置变更后的回调函数\r\n * @param configPath 可选,指定配置文件路径(对应 --config flag)\r\n * @returns 一个 unwatch 函数,调用后可停止监听\r\n */\r\nexport function watchConfig(\r\n callback: ConfigChangeCallback,\r\n configPath?: string,\r\n): () => void {\r\n const filePaths = resolveConfigFiles(configPath).filter((fp) => existsSync(fp));\r\n\r\n // 如果一个文件都不存在,则监听项目本地的 .dskcode/settings.json(即使还没创建)\r\n if (filePaths.length === 0) {\r\n filePaths.push(join(process.cwd(), \".dskcode\", \"settings.json\"));\r\n }\r\n\r\n const watchers: ReturnType<typeof watch>[] = [];\r\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n for (const filePath of filePaths) {\r\n try {\r\n const watcher = watch(filePath, (eventType) => {\r\n if (eventType !== \"change\") return;\r\n\r\n // 防抖:多次连续变更只触发一次\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(async () => {\r\n try {\r\n const raw = readFile(filePath, \"utf-8\");\r\n const config = await loadConfig(configPath);\r\n callback(config);\r\n } catch {\r\n // 重载失败时不回调,等待下一次变更\r\n }\r\n }, 300);\r\n });\r\n\r\n watchers.push(watcher);\r\n } catch {\r\n // 无法监听的文件(例如还不存在)— 跳过\r\n }\r\n }\r\n\r\n return () => {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n for (const w of watchers) {\r\n w.close();\r\n }\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// API Key 持久化\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 将 API Key 保存到用户全局配置 ~/.dskcode/settings.json。\r\n * 如果文件已存在,合并写入;不存在则新建。\r\n * 返回保存的文件路径。\r\n */\r\nexport async function saveApiKey(apiKey: string): Promise<string> {\r\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"~\";\r\n const configDir = join(home, \".dskcode\");\r\n const configFile = join(configDir, \"settings.json\");\r\n\r\n // 确保目录存在\r\n await mkdir(configDir, { recursive: true });\r\n\r\n // 读取现有配置,或从空对象开始\r\n let configData: Record<string, unknown> = {};\r\n try {\r\n const raw = await readFile(configFile, \"utf-8\");\r\n configData = JSON.parse(raw);\r\n } catch {\r\n // 文件不存在,从头构建\r\n }\r\n\r\n // 更新或创建 deepseek provider\r\n const providers = (configData.providers as Array<Record<string, unknown>>) ?? [];\r\n const existing = providers.find((p) => p.name === \"deepseek\");\r\n\r\n if (existing) {\r\n existing.apiKey = apiKey;\r\n } else {\r\n providers.push({\r\n name: \"deepseek\",\r\n apiKey,\r\n baseUrl: \"https://api.deepseek.com\",\r\n model: \"deepseek-v4-flash\",\r\n });\r\n }\r\n\r\n configData.providers = providers;\r\n\r\n // 写回文件\r\n await writeFile(configFile, JSON.stringify(configData, null, 2), \"utf-8\");\r\n\r\n return configFile;\r\n}\r\n","import type { Command } from \"commander\";\r\nimport {\r\n loadAndValidate,\r\n applyCliOverrides,\r\n defaultConfig,\r\n} from \"../config/index.js\";\r\nimport type { Config } from \"../config/index.js\";\r\n\r\n/**\r\n * dskcode 运行时上下文。\r\n * 通过 commander 的 preAction hook 注入到每个命令中。\r\n */\r\nexport interface DskcodeContext {\r\n config: Config;\r\n verbose: boolean;\r\n}\r\n\r\n/**\r\n * 在 preAction hook 中加载配置并构造上下文。\r\n *\r\n * 完整的配置解析流水线:\r\n * 1. 内置默认值 —— defaultConfig\r\n * 2. 用户全局 —— ~/.dskcode/settings.json\r\n * 3. 项目本地 —— .dskcode/settings.json(或 --config 指定的路径)\r\n * 4. 环境变量 —— DEEPSEEK_API_KEY / DSKCODE_*\r\n * 5. CLI flag —— --verbose / --model 等\r\n */\r\nexport async function loadConfigMiddleware(\r\n this: Command,\r\n): Promise<DskcodeContext> {\r\n const opts = this.optsWithGlobals() as {\r\n verbose?: boolean;\r\n config?: string;\r\n model?: string;\r\n };\r\n const verbose = opts.verbose ?? false;\r\n\r\n // 1-4. 加载 TOML 文件 + 环境变量\r\n let config: Config;\r\n const errors: string[] = [];\r\n try {\r\n const result = await loadAndValidate(opts.config);\r\n config = result.config;\r\n if (result.errors.length > 0) {\r\n for (const e of result.errors) {\r\n errors.push(e.message);\r\n }\r\n }\r\n } catch {\r\n config = structuredClone(defaultConfig);\r\n }\r\n\r\n // 5. CLI flag 覆盖(优先级最高)\r\n config = applyCliOverrides(config, {\r\n verbose,\r\n model: opts.model,\r\n });\r\n\r\n // 校验错误输出(不阻断执行)\r\n if (errors.length > 0 && verbose) {\r\n for (const msg of errors) {\r\n console.error(` ⚠ ${msg}`);\r\n }\r\n }\r\n\r\n return { config, verbose };\r\n}\r\n","import type { Command } from \"commander\";\r\nimport chalk from \"chalk\";\r\n\r\nexport function customHelp(program: Command): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(\"\");\r\n lines.push(chalk.bold(\"用法:\"));\r\n lines.push(` ${chalk.cyan(\"dskcode\")} ${chalk.dim(\"[global-options]\")} ${chalk.green(\"<command>\")} ${chalk.dim(\"[options]\")}`);\r\n lines.push(\"\");\r\n\r\n const globalOpts = program.options.filter(\r\n (o) => o.long !== \"--help\" && o.long !== \"--version\" && o.long !== \"--config\",\r\n );\r\n if (globalOpts.length > 0) {\r\n lines.push(chalk.bold(\"全局选项:\"));\r\n for (const opt of globalOpts) {\r\n const flags = [opt.short, opt.long].filter(Boolean).join(\", \");\r\n lines.push(` ${chalk.cyan(flags.padEnd(24))} ${opt.description ?? \"\"}`);\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n lines.push(chalk.bold(\"内置选项:\"));\r\n for (const flag of [\"-h, --help\", \"-V, --version\"]) {\r\n const opt = program.options.find(\r\n (o) => o.long === (flag.includes(\"help\") ? \"--help\" : \"--version\"),\r\n );\r\n if (opt) {\r\n lines.push(` ${chalk.cyan(flag.padEnd(24))} ${opt.description ?? \"\"}`);\r\n }\r\n }\r\n lines.push(\"\");\r\n\r\n const cmds = program.commands.filter((c) => !c.name().startsWith(\"help\"));\r\n if (cmds.length > 0) {\r\n lines.push(chalk.bold(\"命令:\"));\r\n for (const cmd of cmds) {\r\n lines.push(` ${chalk.green(cmd.name().padEnd(24))} ${cmd.description()}`);\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n lines.push(chalk.bold(\"示例:\"));\r\n lines.push(` ${chalk.dim(\"# 启动交互式对话\")}`);\r\n lines.push(\" dskcode chat\");\r\n lines.push(` ${chalk.dim(\"# 让 AI 执行一个任务\")}`);\r\n lines.push(\" dskcode run 修改所有 TODO 注释\");\r\n lines.push(` ${chalk.dim(\"# 运行配置向导\")}`);\r\n lines.push(\" dskcode setup\");\r\n lines.push(` ${chalk.dim(\"# 生成 shell 自动补全\")}`);\r\n lines.push(\" dskcode completion\");\r\n lines.push(\"\");\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","import { createInterface } from \"node:readline\";\r\nimport chalk from \"chalk\";\r\n\r\n/**\r\n * 检测是否有可用的 API Key。\r\n * 遍历所有 provider 检查是否配置了 apiKey,同时检查 DEEPSEEK_API_KEY 环境变量。\r\n */\r\nexport function hasApiKey(providers: Array<{ apiKey?: string }>): boolean {\r\n if (providers.some((p) => p.apiKey)) return true;\r\n if (process.env.DEEPSEEK_API_KEY) return true;\r\n return false;\r\n}\r\n\r\n/**\r\n * 交互式提示用户输入 DeepSeek API Key。\r\n * 使用 Node readline 的 password 模式(输入不可见)。\r\n * 返回用户输入的 Key,如果用户取消则返回 null。\r\n */\r\nexport async function promptForApiKey(): Promise<string | null> {\r\n console.log(\r\n chalk.yellow(\"\\n ⚠ 未检测到 API Key 配置\"),\r\n );\r\n console.log(\r\n chalk.dim(\" 你可以通过以下任一方式配置:\"),\r\n );\r\n console.log(\r\n chalk.dim(\" · 环境变量: export DEEPSEEK_API_KEY=sk-xxx\"),\r\n );\r\n console.log(\r\n chalk.dim(\" · 配置文件: ~/.dskcode/settings.json\"),\r\n );\r\n console.log(\r\n chalk.dim(\" · 下面直接输入,自动保存到全局配置\\n\"),\r\n );\r\n\r\n const rl = createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n\r\n return new Promise<string | null>((resolve) => {\r\n const cleanup = () => {\r\n rl.close();\r\n };\r\n\r\n process.stdin.on(\"keypress\", (_, key) => {\r\n if (key.ctrl && key.name === \"c\") {\r\n cleanup();\r\n resolve(null);\r\n }\r\n });\r\n\r\n rl.question(\r\n ` ${chalk.cyan(\"🔑\")} ${chalk.bold(\"请输入你的 DeepSeek API Key:\")} `,\r\n (answer) => {\r\n cleanup();\r\n const trimmed = answer.trim();\r\n if (!trimmed) {\r\n console.log(chalk.red(\" ✖ API Key 不能为空\"));\r\n resolve(null);\r\n return;\r\n }\r\n if (trimmed.length < 10) {\r\n console.log(chalk.red(\" ✖ API Key 格式不正确,长度至少 10 位\"));\r\n resolve(null);\r\n return;\r\n }\r\n resolve(trimmed);\r\n },\r\n );\r\n });\r\n}\r\n","import { render } from \"ink\";\r\nimport type { ReactNode } from \"react\";\r\n\r\nexport interface RenderScopeHandle {\r\n waitUntilExit: Promise<unknown>;\r\n unmount: () => void;\r\n clear: () => void;\r\n}\r\n\r\nexport function renderApp(node: ReactNode): RenderScopeHandle {\r\n const { waitUntilExit, clear, unmount } = render(node);\r\n return { waitUntilExit: waitUntilExit(), clear, unmount };\r\n}\r\n\r\nexport async function unmountApp(handle: RenderScopeHandle): Promise<void> {\r\n handle.unmount();\r\n await new Promise((resolve) => setTimeout(resolve, 50));\r\n}\r\n","import { Text } from \"ink\";\r\nimport InkSpinner from \"ink-spinner\";\r\n\r\ninterface SpinnerProps {\r\n type?: \"dots\" | \"line\" | \"bouncingBar\" | \"aesthetic\";\r\n label?: string;\r\n}\r\n\r\nexport function Spinner({ type = \"dots\", label }: SpinnerProps) {\r\n return (\r\n <Text>\r\n <Text color=\"cyan\">\r\n <InkSpinner type={type} />\r\n </Text>\r\n {label ? <Text> {label}</Text> : null}\r\n </Text>\r\n );\r\n}\r\n","import { Box, Text } from \"ink\";\r\n\r\ntype MessageType = \"info\" | \"success\" | \"warning\" | \"error\";\r\n\r\ninterface StatusMessageProps {\r\n type?: MessageType;\r\n label: string;\r\n detail?: string;\r\n}\r\n\r\nconst STYLES: Record<MessageType, { color: string; icon: string }> = {\r\n info: { color: \"cyan\", icon: \"ℹ\" },\r\n success: { color: \"green\", icon: \"✔\" },\r\n warning: { color: \"yellow\", icon: \"⚠\" },\r\n error: { color: \"red\", icon: \"✖\" },\r\n};\r\n\r\nexport function StatusMessage({ type = \"info\", label, detail }: StatusMessageProps) {\r\n const { color, icon } = STYLES[type];\r\n return (\r\n <Box>\r\n <Text color={color}>\r\n {icon} {label}\r\n </Text>\r\n {detail ? <Text dimColor>: {detail}</Text> : null}\r\n </Box>\r\n );\r\n}\r\n","import { Box, Text } from \"ink\";\r\nimport { useEffect, useState } from \"react\";\r\n\r\nconst CYBER_PALETTE = [\"#00ffff\", \"#ff00ff\", \"#00ff41\", \"#ff1493\", \"#8b00ff\"];\r\n\r\nconst LOGO_LINES = [\r\n \" ██████╗ ███████╗██╗ ██╗\",\r\n \" ██╔══██╗██╔════╝██║ ██╔╝\",\r\n \" ██║ ██║███████╗█████╔╝ \",\r\n \" ██║ ██║╚════██║██╔═██╗ \",\r\n \" ██████╔╝███████║██║ ██╗\",\r\n \" ╚═════╝ ╚══════╝╚═╝ ╚═╝\",\r\n];\r\n\r\nexport function DskcodeSplash() {\r\n const [offset, setOffset] = useState(0);\r\n\r\n useEffect(() => {\r\n const timer = setInterval(() => {\r\n setOffset((prev) => (prev + 1) % CYBER_PALETTE.length);\r\n }, 500);\r\n return () => clearInterval(timer);\r\n }, []);\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingLeft={1}>\r\n {LOGO_LINES.map((line, i) => {\r\n const colorIndex = (i + offset) % CYBER_PALETTE.length;\r\n return (\r\n <Box key={i}>\r\n <Text bold color={CYBER_PALETTE[colorIndex]}>\r\n {line}\r\n </Text>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n );\r\n}\r\n","import { Box, Text } from \"ink\";\r\nimport TextInput from \"ink-text-input\";\r\nimport { useEffect, useState, useCallback } from \"react\";\r\n\r\nconst CYBER_PALETTE = [\"#00ffff\", \"#ff00ff\", \"#00ff41\", \"#ff1493\", \"#8b00ff\"];\r\n\r\nconst LOGO_LINES = [\r\n \" ██████╗ ███████╗██╗ ██╗\",\r\n \" ██╔══██╗██╔════╝██║ ██╔╝\",\r\n \" ██║ ██║███████╗█████╔╝ \",\r\n \" ██║ ██║╚════██║██╔═██╗ \",\r\n \" ██████╔╝███████║██║ ██╗\",\r\n \" ╚═════╝ ╚══════╝╚═╝ ╚═╝\",\r\n];\r\n\r\nconst COMMANDS: Record<string, { desc: string; handler: () => string }> = {\r\n \"/exit\": { desc: \"退出对话\", handler: () => \"\" },\r\n \"/quit\": { desc: \"退出对话\", handler: () => \"\" },\r\n \"/help\": {\r\n desc: \"显示帮助信息\",\r\n handler: () =>\r\n [\r\n \"可用命令:\",\r\n \" /exit, /quit 退出对话\",\r\n \" /help 显示此帮助\",\r\n \" /clear 清空对话历史\",\r\n \" /version 显示版本信息\",\r\n ].join(\"\\n\"),\r\n },\r\n \"/clear\": { desc: \"清空对话历史\", handler: () => \"\" },\r\n \"/version\": { desc: \"显示版本信息\", handler: () => \"dskcode v0.0.0\" },\r\n};\r\n\r\ninterface ChatMessage {\r\n role: \"user\" | \"assistant\";\r\n content: string;\r\n}\r\n\r\ninterface ChatSessionProps {\r\n providerCount: number;\r\n toolCount: number;\r\n verbose: boolean;\r\n}\r\n\r\nexport function ChatSession({ providerCount, toolCount, verbose }: ChatSessionProps) {\r\n const [offset, setOffset] = useState(0);\r\n const [messages, setMessages] = useState<ChatMessage[]>([]);\r\n const [input, setInput] = useState(\"\");\r\n\r\n useEffect(() => {\r\n const timer = setInterval(() => {\r\n setOffset((prev) => (prev + 1) % CYBER_PALETTE.length);\r\n }, 500);\r\n return () => clearInterval(timer);\r\n }, []);\r\n\r\n const handleSubmit = useCallback((value: string) => {\r\n const trimmed = value.trim();\r\n if (!trimmed) return;\r\n\r\n if (trimmed.startsWith(\"/\")) {\r\n const cmd = COMMANDS[trimmed.toLowerCase()];\r\n if (cmd) {\r\n if (trimmed.toLowerCase() === \"/exit\" || trimmed.toLowerCase() === \"/quit\") {\r\n process.exit(0);\r\n return;\r\n }\r\n if (trimmed.toLowerCase() === \"/clear\") {\r\n setMessages([]);\r\n setInput(\"\");\r\n return;\r\n }\r\n const result = cmd.handler();\r\n if (result) {\r\n setMessages((prev) => [\r\n ...prev,\r\n { role: \"user\", content: trimmed },\r\n { role: \"assistant\", content: result },\r\n ]);\r\n }\r\n setInput(\"\");\r\n return;\r\n }\r\n setMessages((prev) => [\r\n ...prev,\r\n { role: \"user\", content: trimmed },\r\n { role: \"assistant\", content: `未知命令:${trimmed}。输入 /help 查看。` },\r\n ]);\r\n setInput(\"\");\r\n return;\r\n }\r\n\r\n setMessages((prev) => [\r\n ...prev,\r\n { role: \"user\", content: trimmed },\r\n { role: \"assistant\", content: \"dskcode AI — 待实现(第07章)。当前为 CLI 框架演示模式。\" },\r\n ]);\r\n setInput(\"\");\r\n }, []);\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingLeft={1} paddingRight={1}>\r\n {/* Logo + 状态栏 — 左右布局 */}\r\n <Box flexDirection=\"row\" marginBottom={1}>\r\n {/* Logo */}\r\n <Box flexDirection=\"column\" marginRight={4}>\r\n {LOGO_LINES.map((line, i) => {\r\n const colorIndex = (i + offset) % CYBER_PALETTE.length;\r\n return (\r\n <Box key={i}>\r\n <Text bold color={CYBER_PALETTE[colorIndex]}>\r\n {line}\r\n </Text>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n\r\n {/* 状态信息 */}\r\n <Box flexDirection=\"column\" justifyContent=\"center\">\r\n <Text color=\"#00ff41\">{\" ✔ \"}已加载 {providerCount} 个 Provider</Text>\r\n <Text color=\"#00ffff\">{\" ℹ \"}已就绪 {toolCount} 个工具</Text>\r\n {verbose ? <Text color=\"#ff1493\">{\" ⚡ Verbose\"}</Text> : null}\r\n </Box>\r\n </Box>\r\n\r\n {/* Messages */}\r\n <Box flexDirection=\"column\" marginTop={1}>\r\n {messages.map((msg, i) => (\r\n <Box key={i} marginTop={1}>\r\n <Box width={8} flexShrink={0}>\r\n <Text bold color={msg.role === \"user\" ? \"#00ff41\" : \"#ff00ff\"}>\r\n {msg.role === \"user\" ? \" 👤\" : \" 🤖\"}\r\n </Text>\r\n </Box>\r\n <Box flexGrow={1}>\r\n <Text wrap=\"wrap\">{msg.content}</Text>\r\n </Box>\r\n </Box>\r\n ))}\r\n </Box>\r\n\r\n {/* Input */}\r\n <Box marginTop={1}>\r\n <Box width={8} flexShrink={0}>\r\n <Text bold color=\"#00ff41\">\r\n {\" ⚡\"}\r\n </Text>\r\n </Box>\r\n <Box flexGrow={1}>\r\n <TextInput\r\n value={input}\r\n onChange={setInput}\r\n onSubmit={handleSubmit}\r\n placeholder=\"输入你的问题...\"\r\n />\r\n </Box>\r\n </Box>\r\n\r\n <Box marginTop={1}>\r\n <Text color=\"#00ffff\" dimColor>\r\n {\" \" + \"─\".repeat(36)}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n","import { Box, Text, useInput } from \"ink\";\r\nimport { useState, useCallback } from \"react\";\r\nimport type { Game } from \"../game/index.js\";\r\n\r\ninterface GamePickerProps {\r\n games: Game[];\r\n onSelect: (game: Game) => void;\r\n onExit: () => void;\r\n}\r\n\r\nexport function GamePicker({ games, onSelect, onExit }: GamePickerProps) {\r\n const [selectedIndex, setSelectedIndex] = useState(0);\r\n\r\n useInput(\r\n useCallback(\r\n (input, key) => {\r\n if (games.length === 0) return;\r\n if (key.upArrow || input === \"k\") {\r\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : games.length - 1));\r\n } else if (key.downArrow || input === \"j\") {\r\n setSelectedIndex((prev) => (prev < games.length - 1 ? prev + 1 : 0));\r\n } else if (key.return) {\r\n const game = games[selectedIndex];\r\n if (game) onSelect(game);\r\n } else if (key.escape || input === \"q\") {\r\n onExit();\r\n }\r\n },\r\n [games, selectedIndex, onSelect, onExit],\r\n ),\r\n );\r\n\r\n return (\r\n <Box flexDirection=\"column\">\r\n <Box marginBottom={1}>\r\n <Text bold color=\"#00ffff\">\r\n 🎮 游戏列表\r\n </Text>\r\n </Box>\r\n\r\n <Box flexDirection=\"column\">\r\n {games.map((game, index) => {\r\n const isSelected = index === selectedIndex;\r\n return (\r\n <Box key={game.id} flexDirection=\"row\">\r\n <Box width={3} flexShrink={0}>\r\n {isSelected ? (\r\n <Text bold color=\"#00ff41\">\r\n {\"▸ \"}\r\n </Text>\r\n ) : (\r\n <Text>{\" \"}</Text>\r\n )}\r\n </Box>\r\n <Box width={20} flexShrink={0}>\r\n <Text bold color={isSelected ? \"#00ff41\" : \"#ffffff\"}>\r\n {game.name}\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text color=\"#888888\">{game.description}</Text>\r\n </Box>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n\r\n <Box marginTop={1}>\r\n <Text dimColor>\r\n {\" ↑/↓ 选择 Enter 启动 q 返回\"}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n","export interface Game {\r\n /** 游戏唯一标识 */\r\n id: string;\r\n /** 游戏名称 */\r\n name: string;\r\n /** 简短描述 */\r\n description: string;\r\n /** 启动游戏 */\r\n play: () => Promise<void>;\r\n}\r\n\r\nconst registry = new Map<string, Game>();\r\n\r\nexport function registerGame(game: Game): void {\r\n registry.set(game.id, game);\r\n}\r\n\r\nexport function getGame(id: string): Game | undefined {\r\n return registry.get(id);\r\n}\r\n\r\nexport function listGames(): Game[] {\r\n return Array.from(registry.values());\r\n}\r\n","import { Box, Text, useInput, render } from \"ink\";\r\nimport { useState, useEffect, useRef, useCallback } from \"react\";\r\n\r\nconst GAME_WIDTH = 40;\r\nconst GAME_HEIGHT = 18;\r\nconst PADDLE_WIDTH = 9;\r\nconst BRICK_COLORS = [166, 214, 76, 69];\r\n\r\ninterface Vec2 {\r\n x: number;\r\n y: number;\r\n}\r\n\r\ninterface Brick {\r\n x: number;\r\n y: number;\r\n w: number;\r\n alive: boolean;\r\n}\r\n\r\n// ─── 10 个关卡定义 ──────────────────────────────────────────────\r\n\r\ninterface LevelDef {\r\n rows: number;\r\n cols: number;\r\n bw: number; // 砖块宽度(格数)\r\n desc: string;\r\n // 返回 true 表示该位置有砖块\r\n pattern: (col: number, row: number, rows: number, cols: number) => boolean;\r\n}\r\n\r\nconst LEVELS: LevelDef[] = [\r\n { rows: 4, cols: 8, bw: 3, desc: \"经典 4×8\", pattern: () => true },\r\n { rows: 3, cols: 8, bw: 3, desc: \"轻松 3 层\", pattern: () => true },\r\n { rows: 6, cols: 8, bw: 3, desc: \"厚墙 6 层\", pattern: () => true },\r\n { rows: 4, cols: 8, bw: 3, desc: \"棋盘格\", pattern: (c, r) => (c + r) % 2 === 0 },\r\n { rows: 4, cols: 8, bw: 3, desc: \"金字塔\", pattern: (c, r, _, tc) => c >= r && c < tc - r },\r\n { rows: 4, cols: 8, bw: 3, desc: \"交错排列\", pattern: (c, r) => r % 2 === 0 || (c >= 1 && c <= 6) },\r\n { rows: 4, cols: 8, bw: 3, desc: \"中空边框\", pattern: (c, r, tr, tc) => r === 0 || r === tr - 1 || c === 0 || c === tc - 1 },\r\n { rows: 4, cols: 10, bw: 2, desc: \"密集 10 列\", pattern: () => true },\r\n { rows: 7, cols: 8, bw: 3, desc: \"高墙 7 层\", pattern: () => true },\r\n { rows: 8, cols: 8, bw: 3, desc: \"满屏 8 层\", pattern: () => true },\r\n];\r\n\r\nfunction getLevel(level: number): LevelDef {\r\n return LEVELS[(level - 1) % LEVELS.length] as LevelDef;\r\n}\r\n\r\nfunction createBricks(level: number): Brick[] {\r\n const def = getLevel(level);\r\n const bricks: Brick[] = [];\r\n const gap = 2;\r\n const totalW = def.cols * def.bw + (def.cols - 1) * gap;\r\n const startX = Math.floor((GAME_WIDTH - totalW) / 2);\r\n const step = def.bw + gap;\r\n\r\n for (let row = 0; row < def.rows; row++) {\r\n for (let col = 0; col < def.cols; col++) {\r\n if (def.pattern(col, row, def.rows, def.cols)) {\r\n bricks.push({\r\n x: startX + col * step,\r\n y: 2 + row * 2,\r\n w: def.bw,\r\n alive: true,\r\n });\r\n }\r\n }\r\n }\r\n return bricks;\r\n}\r\n\r\n// ─── 游戏状态 ──────────────────────────────────────────────────\r\n\r\ninterface GameState {\r\n level: number;\r\n bricks: Brick[];\r\n paddleX: number;\r\n ball: Vec2;\r\n ballDir: Vec2;\r\n score: number;\r\n lives: number;\r\n gameOver: boolean;\r\n win: boolean;\r\n paused: boolean;\r\n}\r\n\r\nfunction createInitialState(level: number): GameState {\r\n const def = getLevel(level);\r\n const totalW = def.cols * def.bw + (def.cols - 1) * 2;\r\n const startX = Math.floor((GAME_WIDTH - totalW) / 2);\r\n return {\r\n level,\r\n bricks: createBricks(level),\r\n paddleX: Math.floor(GAME_WIDTH / 2) - Math.floor(PADDLE_WIDTH / 2),\r\n ball: { x: GAME_WIDTH / 2, y: GAME_HEIGHT - 3 },\r\n ballDir: { x: 1, y: -1 },\r\n score: 0,\r\n lives: 3,\r\n gameOver: false,\r\n win: false,\r\n paused: false,\r\n };\r\n}\r\n\r\n// ─── 物理更新 ──────────────────────────────────────────────────\r\n\r\nfunction update(state: GameState): void {\r\n if (state.paused || state.gameOver || state.win) return;\r\n\r\n state.ball.x += state.ballDir.x;\r\n state.ball.y += state.ballDir.y;\r\n\r\n if (state.ball.x <= 0) { state.ball.x = 0; state.ballDir.x = 1; }\r\n if (state.ball.x >= GAME_WIDTH - 1) { state.ball.x = GAME_WIDTH - 1; state.ballDir.x = -1; }\r\n if (state.ball.y <= 0) { state.ball.y = 0; state.ballDir.y = 1; }\r\n\r\n // 挡板碰撞\r\n if (\r\n state.ball.y === GAME_HEIGHT - 1 &&\r\n state.ball.x >= state.paddleX &&\r\n state.ball.x <= state.paddleX + PADDLE_WIDTH\r\n ) {\r\n state.ballDir.y = -1;\r\n const hitPos = (state.ball.x - state.paddleX) / PADDLE_WIDTH;\r\n state.ballDir.x = hitPos < 0.5 ? -1 : 1;\r\n }\r\n\r\n // 出界\r\n if (state.ball.y > GAME_HEIGHT) {\r\n state.lives--;\r\n if (state.lives <= 0) {\r\n state.gameOver = true;\r\n } else {\r\n state.ball = { x: GAME_WIDTH / 2, y: GAME_HEIGHT - 3 };\r\n state.ballDir = { x: 1, y: -1 };\r\n state.paddleX = Math.floor(GAME_WIDTH / 2) - Math.floor(PADDLE_WIDTH / 2);\r\n }\r\n }\r\n\r\n // 砖块碰撞\r\n const hitBrick = state.bricks.find((b) => {\r\n if (!b.alive) return false;\r\n return state.ball.x >= b.x && state.ball.x < b.x + b.w && state.ball.y >= b.y && state.ball.y < b.y + 1;\r\n });\r\n\r\n if (hitBrick) {\r\n hitBrick.alive = false;\r\n state.score += 10;\r\n state.ballDir.y = -state.ballDir.y;\r\n }\r\n\r\n if (state.bricks.every((b) => !b.alive)) state.win = true;\r\n}\r\n\r\n// ─── 画面渲染(含 ANSI 颜色) ─────────────────────────────────\r\n\r\nfunction buildBoard(state: GameState): string {\r\n const lines: string[] = [];\r\n\r\n function brickColorIndex(x: number, y: number): number | undefined {\r\n const row = Math.floor((y - 2) / 2);\r\n if (row >= 0) {\r\n const b = state.bricks.find((br) => br.y === y && br.alive && x >= br.x && x < br.x + br.w);\r\n if (b) return row % BRICK_COLORS.length;\r\n }\r\n return undefined;\r\n }\r\n\r\n for (let y = 0; y < GAME_HEIGHT; y++) {\r\n let line = \"\";\r\n for (let x = 0; x < GAME_WIDTH; x++) {\r\n const isBall = state.ball.x === x && state.ball.y === y;\r\n const isPaddle = y === GAME_HEIGHT - 1 && x >= state.paddleX && x < state.paddleX + PADDLE_WIDTH;\r\n const brickRow = brickColorIndex(x, y);\r\n\r\n if (isBall) {\r\n line += \"\\x1b[97m●\\x1b[0m\";\r\n } else if (isPaddle) {\r\n line += \"\\x1b[94m▄\\x1b[0m\";\r\n } else if (brickRow !== undefined) {\r\n line += `\\x1b[38;5;${BRICK_COLORS[brickRow] as number}m▀\\x1b[0m`;\r\n } else {\r\n line += \" \";\r\n }\r\n }\r\n lines.push(line);\r\n }\r\n\r\n return lines.map((l) => `│${l}│`).join(\"\\n\");\r\n}\r\n\r\n// ─── Ink 组件 ──────────────────────────────────────────────────\r\n\r\ninterface BrickBreakerGameProps {\r\n onExit: () => void;\r\n}\r\n\r\nfunction BrickBreakerGame({ onExit: _onExit }: BrickBreakerGameProps) {\r\n const [initialLevel, setInitialLevel] = useState(1);\r\n const [selectingLevel, setSelectingLevel] = useState(true);\r\n const stateRef = useRef<GameState>(createInitialState(initialLevel));\r\n const [tick, setTick] = useState(0);\r\n const onExitRef = useRef(_onExit);\r\n onExitRef.current = _onExit;\r\n\r\n useEffect(() => {\r\n if (selectingLevel) return;\r\n const interval = setInterval(() => {\r\n update(stateRef.current);\r\n setTick((t) => t + 1);\r\n }, 80);\r\n return () => clearInterval(interval);\r\n }, [selectingLevel]);\r\n\r\n // 重新开始(保留当前关卡)\r\n const restart = useCallback((level?: number) => {\r\n const lv = level ?? stateRef.current.level;\r\n stateRef.current = createInitialState(lv);\r\n setInitialLevel(lv);\r\n setSelectingLevel(false);\r\n setTick(0);\r\n }, []);\r\n\r\n // 选关\r\n const startLevelSelect = useCallback(() => {\r\n setSelectingLevel(true);\r\n }, []);\r\n\r\n useInput(\r\n useCallback((input, key) => {\r\n const s = stateRef.current;\r\n\r\n // 选关模式\r\n if (selectingLevel) {\r\n if (input >= \"1\" && input <= \"9\") {\r\n restart(Number(input));\r\n } else if (input === \"0\") {\r\n restart(10);\r\n } else if (key.escape || input === \"q\") {\r\n onExitRef.current();\r\n }\r\n return;\r\n }\r\n\r\n if (key.leftArrow) {\r\n s.paddleX = Math.max(0, s.paddleX - 1);\r\n setTick((t) => t + 1);\r\n } else if (key.rightArrow) {\r\n s.paddleX = Math.min(GAME_WIDTH - PADDLE_WIDTH, s.paddleX + 1);\r\n setTick((t) => t + 1);\r\n } else if (input === \"p\" || input === \" \") {\r\n s.paused = !s.paused;\r\n } else if (input === \"r\") {\r\n if (s.gameOver || s.win) restart();\r\n } else if (input === \"l\") {\r\n if (s.gameOver || s.win) startLevelSelect();\r\n } else if (input === \"q\" || key.escape) {\r\n onExitRef.current();\r\n }\r\n }, [selectingLevel, restart, startLevelSelect]),\r\n );\r\n\r\n const s = stateRef.current;\r\n const aliveCount = s.bricks.filter((b) => b.alive).length;\r\n const board = buildBoard(s);\r\n const def = getLevel(s.level);\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n void tick;\r\n\r\n return (\r\n <Box flexDirection=\"column\">\r\n {/* 状态栏 */}\r\n <Box flexDirection=\"row\">\r\n <Box width={20}>\r\n <Text>\r\n 关卡 {s.level}: <Text color=\"cyan\">{def.desc}</Text>\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text>\r\n 分数: <Text color=\"yellow\">{String(s.score).padStart(3, \"0\")}</Text>\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text>\r\n 生命: <Text color=\"red\">{\"♥\".repeat(Math.max(0, s.lives))}</Text>\r\n </Text>\r\n </Box>\r\n <Box width={10}>\r\n <Text>\r\n 砖块: <Text color=\"cyan\">{aliveCount}</Text>\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text color={s.paused ? \"gray\" : \"green\"}>\r\n [{s.paused ? \"暂停\" : \"运行中\"}]\r\n </Text>\r\n </Box>\r\n </Box>\r\n\r\n {/* 游戏画面 */}\r\n <Box flexDirection=\"column\">\r\n <Text>┌{\"─\".repeat(GAME_WIDTH)}┐</Text>\r\n <Text>{selectingLevel ? \" \\x1b[90m选择关卡后开始...\\x1b[0m\" : board}</Text>\r\n <Text>└{\"─\".repeat(GAME_WIDTH)}┘</Text>\r\n </Box>\r\n\r\n {/* 选关界面 */}\r\n {selectingLevel && (\r\n <Box marginTop={1} flexDirection=\"column\">\r\n <Text bold color=\"yellow\">选择关卡</Text>\r\n <Box flexDirection=\"row\" flexWrap=\"wrap\">\r\n {LEVELS.map((lv, i) => (\r\n <Box key={i} width={22}>\r\n <Text>\r\n <Text color={initialLevel === i + 1 ? \"green\" : \"white\"}>\r\n {i + 1 === 10 ? \"0\" : String(i + 1)}\r\n </Text>\r\n . {lv.desc} ({lv.rows}×{lv.cols})\r\n </Text>\r\n </Box>\r\n ))}\r\n </Box>\r\n <Box marginTop={1}>\r\n <Text dimColor>按数字选关 q 退出</Text>\r\n </Box>\r\n </Box>\r\n )}\r\n\r\n {/* 结束/通关信息 */}\r\n {!selectingLevel && (s.gameOver || s.win) && (\r\n <Box marginTop={1}>\r\n <Text bold color={s.gameOver ? \"red\" : \"green\"}>\r\n {s.gameOver ? \"游戏结束!\" : \"恭喜通关!\"}\r\n </Text>\r\n <Text>\r\n {\" 分数: \"}<Text color=\"yellow\">{s.score}</Text>\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* 操作提示 */}\r\n {!selectingLevel && (\r\n <Box marginTop={1}>\r\n {s.gameOver || s.win ? (\r\n <Text dimColor>\r\n {\"← → 移动 r 重开 l 选关 q 退出\"}\r\n </Text>\r\n ) : (\r\n <Text dimColor>\r\n {\"← → 移动 p 暂停 q 退出\"}\r\n </Text>\r\n )}\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n}\r\n\r\n// ─── 导出 ──────────────────────────────────────────────────────\r\n\r\nexport default {\r\n id: \"brick-breaker\",\r\n name: \"Brick Breaker\",\r\n description: \"经典打砖块游戏,10 个关卡可选!\",\r\n play: async () => {\r\n await new Promise<void>((resolve) => {\r\n const { unmount } = render(\r\n <BrickBreakerGame onExit={() => { unmount(); resolve(); }} />,\r\n );\r\n });\r\n },\r\n};\r\n","import { Box, Text, useInput, render } from \"ink\";\r\nimport { useState, useEffect, useRef, useCallback } from \"react\";\r\n\r\nconst GAME_W = 66;\r\nconst GAME_H = 20; // 6 行分数 + 14 行掉落单词\r\nconst SCORE_H = 6;\r\nconst WORD_H = 14;\r\nconst MAX_WORDS = 10;\r\nconst CYBER_PALETTE = [\"#00ffff\", \"#ff00ff\", \"#00ff41\", \"#ff1493\", \"#8b00ff\"];\r\n\r\n// 3×5 像素大号数字(每个像素 = ██,每数字 6 列)\r\nconst DIGIT_ART: Record<string, string[]> = {\r\n \"0\": [\" ██████ \", \"██ ██\", \"██ ██\", \"██ ██\", \" ██████ \"],\r\n \"1\": [\" ██ \", \" ████ \", \" ██ \", \" ██ \", \" ██████ \"],\r\n \"2\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ \", \" ██████ \"],\r\n \"3\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ \", \" ██████ \"],\r\n \"4\": [\"██ ██\", \"██ ██\", \" ██████ \", \" ██ \", \" ██ \"],\r\n \"5\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ \", \" ██████ \"],\r\n \"6\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ ██\", \" ██████ \"],\r\n \"7\": [\" ██████ \", \" ██ \", \" ██ \", \" ██ \", \" ██ \"],\r\n \"8\": [\" ██████ \", \"██ ██\", \" ██████ \", \"██ ██\", \" ██████ \"],\r\n \"9\": [\" ██████ \", \"██ ██\", \" ██████ \", \" ██ \", \" ██████ \"],\r\n};\r\n\r\nfunction buildScoreLines(scoreStr: string): string[] {\r\n const lines = [\"\", \"\", \"\", \"\", \"\"];\r\n for (const ch of scoreStr) {\r\n const art = DIGIT_ART[ch] ?? DIGIT_ART[\"0\"]!;\r\n for (let r = 0; r < 5; r++) {\r\n lines[r] += \" \" + (art[r] ?? \"\");\r\n }\r\n }\r\n // 左右各留 6 格间距\r\n const pad = 6;\r\n return lines.map((l) => \" \".repeat(pad) + l);\r\n}\r\n\r\nfunction hexToRgb(hex: string): string {\r\n const r = parseInt(hex.slice(1, 3), 16);\r\n const g = parseInt(hex.slice(3, 5), 16);\r\n const b = parseInt(hex.slice(5, 7), 16);\r\n return `${r};${g};${b}`;\r\n}\r\n\r\n// ─── 200 个常见单词 ────────────────────────────────────────────\r\n\r\nconst WORDS_BANK = [\r\n // ── 框架 & 库 ──\r\n \"react\", \"vue\", \"next\", \"node\", \"axios\", \"express\", \"lodash\", \"jquery\",\r\n \"webpack\", \"vite\", \"babel\", \"eslint\", \"prettier\", \"tailwind\", \"bootstrap\",\r\n \"sass\", \"less\", \"postcss\", \"redux\", \"pinia\", \"vuex\", \"router\",\r\n \"nestjs\", \"socket\", \"graphql\", \"rest\", \"grpc\", \"prisma\", \"typeorm\",\r\n\r\n // ── 前端 ──\r\n \"html\", \"css\", \"jsx\", \"tsx\", \"dom\", \"spa\", \"ssr\", \"csr\", \"pwa\",\r\n \"component\", \"prop\", \"hook\", \"composable\", \"directive\", \"filter\", \"mixin\",\r\n \"template\", \"render\", \"virtual\", \"diff\", \"patch\", \"hydration\",\r\n \"responsive\", \"flexbox\", \"grid\", \"animation\", \"transition\",\r\n\r\n // ── 后端 ──\r\n \"api\", \"route\", \"middleware\", \"controller\", \"service\", \"module\",\r\n \"dto\", \"entity\", \"schema\", \"migration\", \"seeder\", \"factory\",\r\n \"auth\", \"jwt\", \"oauth\", \"session\", \"cookie\", \"token\", \"cors\",\r\n \"cache\", \"redis\", \"mq\", \"rabbit\", \"kafka\", \"nats\",\r\n\r\n // ── 数据库 ──\r\n \"sql\", \"mysql\", \"pg\", \"sqlite\", \"mongo\", \"redis\", \"orm\",\r\n \"table\", \"index\", \"query\", \"join\", \"union\", \"group\", \"order\",\r\n \"where\", \"having\", \"limit\", \"offset\", \"insert\", \"update\", \"delete\",\r\n\r\n // ── DevOps ──\r\n \"docker\", \"nginx\", \"linux\", \"bash\", \"shell\", \"yaml\", \"toml\",\r\n \"ci\", \"cd\", \"deploy\", \"rollback\", \"release\", \"build\", \"test\",\r\n \"lint\", \"format\", \"stage\", \"commit\", \"branch\", \"merge\", \"rebase\",\r\n\r\n // ── 数据结构 & 算法 ──\r\n \"array\", \"stack\", \"queue\", \"tree\", \"graph\", \"list\", \"map\", \"set\",\r\n \"sort\", \"search\", \"filter\", \"reduce\", \"map\", \"async\", \"await\",\r\n \"promise\", \"callback\", \"closure\", \"proxy\", \"reflect\", \"decorator\",\r\n\r\n // ── 常用操作 ──\r\n \"create\", \"read\", \"update\", \"delete\", \"crud\", \"parse\", \"stringify\",\r\n \"encode\", \"decode\", \"transform\", \"validate\", \"format\", \"parse\",\r\n \"upload\", \"download\", \"export\", \"import\", \"backup\", \"restore\",\r\n\r\n // ── 类型 & 变量 ──\r\n \"string\", \"number\", \"boolean\", \"object\", \"array\", \"tuple\", \"enum\",\r\n \"interface\", \"type\", \"class\", \"function\", \"method\", \"property\",\r\n \"public\", \"private\", \"static\", \"readonly\", \"optional\", \"abstract\",\r\n \"const\", \"let\", \"var\", \"void\", \"null\", \"undef\", \"never\", \"any\",\r\n\r\n // ── 补充 ──\r\n \"config\", \"logger\", \"monitor\", \"metric\", \"alert\", \"webhook\",\r\n \"endpoint\", \"payload\", \"header\", \"status\", \"timeout\", \"retry\",\r\n \"fallback\", \"circuit\", \"breaker\", \"throttle\", \"debounce\",\r\n \"scroll\", \"resize\", \"click\", \"hover\", \"focus\", \"blur\",\r\n];\r\n\r\nfunction randomWord(used: Set<string>): string {\r\n let w: string;\r\n do { w = WORDS_BANK[Math.floor(Math.random() * WORDS_BANK.length)] as string; }\r\n while (used.has(w));\r\n return w;\r\n}\r\n\r\n// ─── 游戏状态 ──────────────────────────────────────────────────\r\n\r\ninterface DropWord {\r\n text: string;\r\n row: number;\r\n col: number;\r\n}\r\n\r\ninterface GameState {\r\n words: DropWord[];\r\n score: number;\r\n lives: number;\r\n speed: number;\r\n spawnTimer: number;\r\n gameOver: boolean;\r\n paused: boolean;\r\n typed: string;\r\n target: string | null;\r\n combo: number;\r\n message: string;\r\n messageTimer: number;\r\n usedWords: Set<string>;\r\n}\r\n\r\nfunction createInitialState(): GameState {\r\n return {\r\n words: [],\r\n score: 0,\r\n lives: 3,\r\n speed: 0.3,\r\n spawnTimer: 0,\r\n gameOver: false,\r\n paused: false,\r\n typed: \"\",\r\n target: null,\r\n combo: 0,\r\n message: \"\",\r\n messageTimer: 0,\r\n usedWords: new Set(),\r\n };\r\n}\r\n\r\nfunction pickTarget(s: GameState): string | null {\r\n // 选取最靠左的存活单词作为目标\r\n let best: DropWord | null = null;\r\n for (const w of s.words) {\r\n if (!best || w.col < best.col) best = w;\r\n }\r\n return best?.text ?? null;\r\n}\r\n\r\n// ─── 物理更新 ──────────────────────────────────────────────────\r\n\r\nfunction update(s: GameState): void {\r\n if (s.paused || s.gameOver) return;\r\n\r\n // 生成新单词\r\n s.spawnTimer++;\r\n if (s.spawnTimer >= Math.max(20, 50 - Math.floor(s.speed * 15))) {\r\n s.spawnTimer = 0;\r\n if (s.words.length < MAX_WORDS) {\r\n const used = new Set(s.usedWords);\r\n for (const w of s.words) used.add(w.text);\r\n const text = randomWord(used);\r\n // 找空白行\r\n const usedRows = new Set(s.words.map((w) => w.row));\r\n let row = -1;\r\n for (let r = SCORE_H; r < GAME_H; r++) {\r\n if (!usedRows.has(r)) { row = r; break; }\r\n }\r\n if (row >= 0) {\r\n s.words.push({ text, row, col: GAME_W - 1 });\r\n s.usedWords.add(text);\r\n }\r\n }\r\n }\r\n\r\n // 移动单词\r\n for (const w of s.words) {\r\n w.col -= s.speed;\r\n }\r\n\r\n // 移除超出左边的 + 更新目标\r\n const before = s.words.length;\r\n s.words = s.words.filter((w) => w.col > -w.text.length);\r\n const removed = before - s.words.length;\r\n\r\n // 单词漏掉了 → 扣命\r\n if (removed > 0) {\r\n s.lives -= removed;\r\n s.typed = \"\";\r\n s.target = pickTarget(s);\r\n if (s.lives <= 0) {\r\n s.gameOver = true;\r\n s.words = [];\r\n }\r\n }\r\n\r\n // 更新目标\r\n s.target = pickTarget(s);\r\n\r\n // 消息计时\r\n if (s.messageTimer > 0) {\r\n s.messageTimer--;\r\n if (s.messageTimer <= 0) s.message = \"\";\r\n }\r\n}\r\n\r\n// ─── 画面渲染 ──────────────────────────────────────────────────\r\n\r\nfunction buildGameView(s: GameState, scoreLines: string[], scoreColor: string, message: string): string[] {\r\n const rows: string[] = [];\r\n\r\n for (let y = 0; y < GAME_H; y++) {\r\n let line = \"\";\r\n\r\n // 分数区域(前 6 行)\r\n if (y < SCORE_H) {\r\n if (y < 5) {\r\n // 数字行 — 先补足宽度再套赛博朋克色\r\n const raw = (scoreLines[y] ?? \"\").padEnd(GAME_W);\r\n line = `\\x1b[38;2;${hexToRgb(scoreColor)}m${raw}\\x1b[0m`;\r\n } else if (y === 5) {\r\n // 第 6 行:连击 / 暂停\r\n if (s.combo >= 3) {\r\n const comboText = `${s.combo}连击!`;\r\n const pad = Math.floor((GAME_W - comboText.length) / 2);\r\n const comboColor = CYBER_PALETTE[s.combo % CYBER_PALETTE.length] as string;\r\n const raw = \" \".repeat(pad) + comboText + \" \".repeat(GAME_W - pad - comboText.length);\r\n line = `\\x1b[38;2;${hexToRgb(comboColor)}m${raw}\\x1b[0m`;\r\n } else if (s.paused) {\r\n const pauseText = \"暂停\";\r\n const pad = Math.floor((GAME_W - pauseText.length) / 2);\r\n line = \" \".repeat(pad) + pauseText;\r\n line = line.padEnd(GAME_W);\r\n }\r\n }\r\n // 补全到 GAME_W 宽度\r\n line = line.padEnd(GAME_W);\r\n } else {\r\n // 单词区域\r\n // 第 1 行显示消息(如果有)\r\n if (y === SCORE_H && message) {\r\n const pad = Math.floor((GAME_W - message.length) / 2);\r\n const raw = \" \".repeat(pad) + message + \" \".repeat(GAME_W - pad - message.length);\r\n const msgColor = CYBER_PALETTE[Math.floor(Math.random() * CYBER_PALETTE.length)] as string;\r\n line = `\\x1b[38;2;${hexToRgb(msgColor)}m${raw}\\x1b[0m`;\r\n } else {\r\n for (let x = 0; x < GAME_W; x++) {\r\n const word = s.words.find((w) => {\r\n const charIdx = x - Math.floor(w.col);\r\n return charIdx >= 0 && charIdx < w.text.length && w.row === y;\r\n });\r\n if (word) {\r\n const charIdx = x - Math.floor(word.col);\r\n const ch = word.text[charIdx] as string;\r\n const isTarget = word.text === s.target;\r\n const typedIdx = s.target === word.text ? s.typed.length : 0;\r\n const isTyped = isTarget && charIdx < typedIdx;\r\n if (isTarget) {\r\n line += isTyped ? `\\x1b[92m${ch}\\x1b[0m` : `\\x1b[97m${ch}\\x1b[0m`;\r\n } else {\r\n line += `\\x1b[90m${ch}\\x1b[0m`;\r\n }\r\n } else {\r\n line += \" \";\r\n }\r\n }\r\n }\r\n }\r\n\r\n rows.push(line);\r\n }\r\n return rows;\r\n}\r\n\r\n// ─── Ink 组件 ──────────────────────────────────────────────────\r\n\r\ninterface CoderCheckProps {\r\n onExit: () => void;\r\n}\r\n\r\nfunction CoderCheck({ onExit: _onExit }: CoderCheckProps) {\r\n const stateRef = useRef<GameState>(createInitialState());\r\n const [tick, setTick] = useState(0);\r\n const [colorOffset, setColorOffset] = useState(0);\r\n const onExitRef = useRef(_onExit);\r\n onExitRef.current = _onExit;\r\n\r\n // 赛博朋克颜色动画\r\n useEffect(() => {\r\n const timer = setInterval(() => {\r\n setColorOffset((prev) => (prev + 1) % CYBER_PALETTE.length);\r\n }, 400);\r\n return () => clearInterval(timer);\r\n }, []);\r\n\r\n // 游戏循环\r\n useEffect(() => {\r\n const interval = setInterval(() => {\r\n update(stateRef.current);\r\n setTick((t) => t + 1);\r\n }, 60);\r\n return () => clearInterval(interval);\r\n }, []);\r\n\r\n useInput(\r\n useCallback((input, key) => {\r\n const s = stateRef.current;\r\n if (s.gameOver) {\r\n if (input === \"r\") {\r\n stateRef.current = createInitialState();\r\n setTick(0);\r\n } else if (input === \"q\" || key.escape) {\r\n onExitRef.current();\r\n }\r\n return;\r\n }\r\n\r\n if ((input === \"p\" && key.ctrl) || input === \" \") {\r\n s.paused = !s.paused;\r\n return;\r\n }\r\n if ((input === \"q\" && key.ctrl) || key.escape) {\r\n onExitRef.current();\r\n return;\r\n }\r\n\r\n if (s.paused) return;\r\n\r\n // 打字输入\r\n if (input.length === 1 && input >= \"a\" && input <= \"z\") {\r\n // 选取目标\r\n if (!s.target) {\r\n s.target = pickTarget(s);\r\n }\r\n if (s.target) {\r\n const nextChar = s.target[s.typed.length];\r\n if (nextChar === input) {\r\n s.typed += input;\r\n // 检查是否完成\r\n if (s.typed === s.target) {\r\n // 移除该单词\r\n s.words = s.words.filter((w) => w.text !== s.target);\r\n s.combo++;\r\n // 连击 >= 3 时以当前分数翻倍奖励\r\n const prevScore = s.score;\r\n const basePts = s.target.length;\r\n const comboBonus = s.combo >= 3 ? s.score : 0;\r\n s.score += basePts + comboBonus;\r\n s.speed = s.speed + 0.02;\r\n\r\n // 每 500 分提速\r\n const prevMilestone = Math.floor(prevScore / 500);\r\n const newMilestone = Math.floor(s.score / 500);\r\n if (newMilestone > prevMilestone) {\r\n s.speed += 0.15;\r\n }\r\n\r\n // 超过 99999 分提示通关\r\n if (s.score >= 100000 && prevScore < 100000) {\r\n s.message = \"恭喜通关! 难度最大化!\";\r\n s.messageTimer = 100;\r\n }\r\n s.typed = \"\";\r\n s.target = pickTarget(s);\r\n }\r\n } else {\r\n // 打错字符,连击中断\r\n s.combo = 0;\r\n }\r\n }\r\n }\r\n }, []),\r\n );\r\n\r\n const s = stateRef.current;\r\n const scoreColor = CYBER_PALETTE[colorOffset] as string;\r\n const scoreStr = String(s.score).padStart(5, \"0\");\r\n const scoreLines = buildScoreLines(scoreStr);\r\n const view = buildGameView(s, scoreLines, scoreColor, s.message);\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n void tick;\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingX={1}>\r\n {/* 顶栏:生命 + 速度 */}\r\n <Box flexDirection=\"row\">\r\n <Text>\r\n 生命 <Text color=\"red\">{\"♥\".repeat(Math.max(0, s.lives))}</Text>\r\n {\" \"}速度 <Text color=\"cyan\">Lv.{Math.floor(s.speed * 10)}</Text>\r\n </Text>\r\n </Box>\r\n\r\n {/* 目标单词提示 */}\r\n {!s.gameOver && s.target && (\r\n <Box marginTop={1}>\r\n <Text>\r\n 打字: <Text color=\"green\">{s.typed}</Text>\r\n <Text color=\"white\">{s.target.slice(s.typed.length)}</Text>\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* 游戏画面(含分数) */}\r\n <Box flexDirection=\"column\" marginTop={1}>\r\n <Text>┌{\"─\".repeat(GAME_W)}┐</Text>\r\n {view.map((row, i) => (\r\n <Text key={i}>{`│${row}│`}</Text>\r\n ))}\r\n <Text>└{\"─\".repeat(GAME_W)}┘</Text>\r\n </Box>\r\n\r\n {/* 游戏结束 */}\r\n {s.gameOver && (\r\n <Box marginTop={1}>\r\n <Text bold color=\"red\">\r\n 游戏结束!\r\n </Text>\r\n <Text>\r\n {\" 得分: \"}<Text color=\"yellow\">{s.score}</Text>\r\n {\" r 重开 q 退出\"}\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* 操作提示 */}\r\n <Box marginTop={1}>\r\n <Text dimColor>\r\n {\"打字消除单词 空格/Ctrl+P暂停 Ctrl+Q退出\"}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n\r\n// ─── 导出 ──────────────────────────────────────────────────────\r\n\r\nexport default {\r\n id: \"coder-check\",\r\n name: \"Coder Check\",\r\n description: \"极速打字游戏,输入单词消除它们!\",\r\n play: async () => {\r\n await new Promise<void>((resolve) => {\r\n const { unmount } = render(\r\n <CoderCheck onExit={() => { unmount(); resolve(); }} />,\r\n );\r\n });\r\n },\r\n};\r\n","import { registerGame, listGames } from \"./index.js\";\r\nimport type { Game } from \"./index.js\";\r\nimport brickBreaker from \"./brick-breaker/index.js\";\r\nimport coderCheck from \"./coder-check/index.js\";\r\n\r\n/** 在此注册所有游戏 */\r\nexport function initGames(): Game[] {\r\n registerGame(brickBreaker);\r\n registerGame(coderCheck);\r\n return listGames();\r\n}\r\n","/** dskcode 退出码规范 */\r\nexport const ExitCode = {\r\n /** 正常执行完成 */\r\n SUCCESS: 0,\r\n /** 通用错误 */\r\n GENERAL_ERROR: 1,\r\n /** 配置错误 */\r\n CONFIG_ERROR: 2,\r\n /** 用户通过 Ctrl+C 中断 */\r\n SIGINT: 130,\r\n} as const;\r\n","#!/usr/bin/env node\r\n\r\nimport { createCli } from \"./cli/index.js\";\r\nimport { ExitCode } from \"./cli/exit-codes.js\";\r\n\r\nprocess.on(\"SIGINT\", () => {\r\n process.exit(ExitCode.SIGINT);\r\n});\r\n\r\nconst program = createCli();\r\n\r\ntry {\r\n await program.parseAsync(process.argv);\r\n} catch (err: unknown) {\r\n const error = err as { exitCode?: number; code?: string };\r\n\r\n if (error.code === \"commander.helpDisplayed\" || error.code === \"commander.version\") {\r\n process.exit(error.exitCode ?? ExitCode.SUCCESS);\r\n }\r\n\r\n if (typeof error.exitCode === \"number\") {\r\n process.exit(error.exitCode);\r\n }\r\n\r\n console.error(String(err));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n}\r\n"],"mappings":"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","names":["program","chalk","Text","jsxs","Box","Text","jsx","Box","Text","useEffect","useState","jsx","jsxs","Box","Text","useState","useCallback","jsx","jsxs","Box","Text","useInput","render","useState","useEffect","useCallback","jsx","jsxs","s","Box","Text","useInput","render","useState","useEffect","useRef","useCallback","jsx","jsxs","CYBER_PALETTE","createInitialState","update","useRef","useState","useEffect","useInput","useCallback","s","jsxs","Box","jsx","Text","render","render","chalk","jsx","program"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli/index.tsx","../src/config/loader.ts","../src/cli/middleware.ts","../src/cli/help.ts","../src/cli/api-key-setup.ts","../src/ui/RenderScope.tsx","../src/ui/Spinner.tsx","../src/ui/StatusMessage.tsx","../src/ui/DskcodeSplash.tsx","../src/ui/ChatSession.tsx","../src/ui/GamePicker.tsx","../src/game/index.ts","../src/game/brick-breaker/index.tsx","../src/game/coder-check/index.tsx","../src/game/registry.ts","../src/stock/StockList.tsx","../src/cli/exit-codes.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\r\nimport { loadConfigMiddleware } from \"./middleware.js\";\r\nimport { customHelp } from \"./help.js\";\r\nimport { hasApiKey, promptForApiKey } from \"./api-key-setup.js\";\r\nimport { saveApiKey, loadAndValidate } from \"../config/index.js\";\r\nimport { renderApp, ChatSession } from \"../ui/index.js\";\r\nimport { initGames } from \"../game/registry.js\";\r\nimport { listGames, getGame } from \"../game/index.js\";\r\nimport type { Game } from \"../game/index.js\";\r\nimport { GamePicker } from \"../ui/GamePicker.js\";\r\nimport { render } from \"ink\";\r\nimport chalk from \"chalk\";\r\nimport { StockList } from \"../stock/index.js\";\r\n\r\nconst SUBCOMMANDS = [\"chat\", \"run\", \"setup\", \"init\", \"completion\", \"game\", \"stock\"];\r\n\r\nexport function createCli(): Command {\r\n const program = new Command();\r\n program.exitOverride();\r\n\r\n program\r\n .name(\"dskcode\")\r\n .description(\"基于 DeepSeek 的 AI 编程助手终端工具\")\r\n .version(\"0.0.0\", \"-V, --version\", \"显示版本号\")\r\n .option(\"--verbose\", \"开启详细日志输出\")\r\n .option(\"--config <path>\", \"指定配置文件路径\");\r\n\r\n program.helpInformation = () => customHelp(program);\r\n\r\n program.hook(\"preAction\", async (thisCommand, actionCommand) => {\r\n const ctx = await loadConfigMiddleware.call(thisCommand);\r\n (actionCommand as unknown as Record<string, unknown>).dskcodeCtx = ctx;\r\n });\r\n\r\n // chat — 交互式对话\r\n program\r\n .command(\"chat\")\r\n .description(\"启动交互式对话会话\")\r\n .action(async function () {\r\n if (!process.stdin.isTTY) {\r\n console.error(\"dskcode chat 需要交互式终端。如需执行一次性任务,请使用 dskcode run。\");\r\n process.exit(1);\r\n }\r\n\r\n let ctx = (this as unknown as Record<string, unknown>).dskcodeCtx as\r\n | { verbose: boolean; config: { providers: Array<{ apiKey?: string }>; tools: unknown[] } }\r\n | undefined;\r\n\r\n // 检查 API Key,如果没有则交互式输入\r\n if (ctx && !hasApiKey(ctx.config.providers)) {\r\n const key = await promptForApiKey();\r\n if (!key) process.exit(1);\r\n\r\n // 保存到全局配置\r\n const savedPath = await saveApiKey(key);\r\n console.log(` ${chalk.green(\"✔\")} API Key 已保存到 ${chalk.dim(savedPath)}\\n`);\r\n\r\n // 重新加载配置,使新 Key 生效\r\n const result = await loadAndValidate();\r\n ctx = { ...ctx, config: result.config };\r\n }\r\n\r\n const app = renderApp(\r\n <ChatSession\r\n providerCount={ctx?.config.providers.length ?? 1}\r\n toolCount={ctx?.config.tools.length ?? 0}\r\n verbose={ctx?.verbose ?? false}\r\n />,\r\n );\r\n\r\n await app.waitUntilExit;\r\n });\r\n\r\n // run\r\n program\r\n .command(\"run\")\r\n .description(\"执行一次性任务\")\r\n .argument(\"[prompt...]\", \"任务描述\")\r\n .option(\"--model <name>\", \"指定使用的模型\")\r\n .action(async function (_prompt: string[]) {\r\n console.log(\"dskcode run — 待实现(第07章)\");\r\n });\r\n\r\n // setup\r\n program\r\n .command(\"setup\")\r\n .description(\"运行配置向导\")\r\n .option(\"--export\", \"以 JSON 格式导出配置\")\r\n .option(\"--test\", \"测试 API Key 连通性\")\r\n .action(async function () {\r\n console.log(\"dskcode setup — 待实现(第14章)\");\r\n });\r\n\r\n // init\r\n program\r\n .command(\"init\")\r\n .description(\"在当前项目下生成项目记忆文件(AGENTS.md)\")\r\n .action(async function () {\r\n console.log(\"dskcode init — 待实现(第11章)\");\r\n });\r\n\r\n // completion\r\n program\r\n .command(\"completion\")\r\n .description(\"输出 shell 自动补全配置说明(bash/zsh)\")\r\n .argument(\"[shell]\", \"shell 类型\", /^(bash|zsh)$/i)\r\n .action(async function (shell?: string) {\r\n if (!shell) {\r\n console.log(\"请指定 shell 类型:dskcode completion bash 或 dskcode completion zsh\");\r\n return;\r\n }\r\n if (shell === \"bash\") {\r\n console.log(`# dskcode bash 自动补全\r\n_dskcode_completion() {\r\n local cur=\\${COMP_WORDS[COMP_CWORD]}\r\n if [[ \\${COMP_CWORD} -eq 1 ]]; then\r\n COMPREPLY=( $(compgen -W \"${SUBCOMMANDS.join(\" \")}\" -- \"\\${cur}\") )\r\n return 0\r\n fi\r\n COMPREPLY=( $(compgen -W \"--verbose --config --model\" -- \"\\${cur}\") )\r\n}\r\ncomplete -F _dskcode_completion dskcode`);\r\n } else {\r\n console.log(`# dskcode zsh 自动补全\r\n_dskcode_completion() {\r\n local -a commands\r\n commands=(\r\n \"chat:启动交互式对话会话\"\r\n \"run:执行一次性任务\"\r\n \"setup:运行配置向导\"\r\n \"init:生成项目记忆文件\"\r\n \"completion:输出 shell 自动补全说明\"\r\n \"game:内置小游戏\"\r\n \"stock:查看自选股实时行情\"\r\n )\r\n _describe 'dskcode commands' commands\r\n}\r\ncompdef _dskcode_completion dskcode`);\r\n }\r\n });\r\n\r\n // stock — 股票行情\r\n program\r\n .command(\"stock\")\r\n .description(\"查看自选股实时行情\")\r\n .argument(\"[codes...]\", \"股票代码(空格分隔),如 513090 600519\")\r\n .action(async function (codes: string[]) {\r\n const codeList = codes && codes.length > 0\r\n ? codes\r\n : [\"sh000001\", \"sz399006\", \"sh601688\"];\r\n\r\n const app = renderApp(\r\n <StockList\r\n codes={codeList}\r\n onExit={() => process.exit(0)}\r\n />,\r\n );\r\n\r\n await app.waitUntilExit;\r\n });\r\n\r\n // game — 游戏模式\r\n initGames();\r\n\r\n program\r\n .command(\"game\")\r\n .description(\"启动内置小游戏\")\r\n .argument(\"[name]\", \"游戏名称,不指定则显示交互式游戏列表\")\r\n .action(async function (name?: string) {\r\n if (name) {\r\n const game = getGame(name);\r\n if (!game) {\r\n console.error(`未找到游戏 \"${name}\"。使用 dskcode game 查看可用游戏列表。`);\r\n process.exit(1);\r\n }\r\n console.log(`正在启动: ${game.name} — ${game.description}\\n`);\r\n await game.play();\r\n } else {\r\n const games = listGames();\r\n if (games.length === 0) {\r\n console.log(\"暂无可用游戏。\");\r\n return;\r\n }\r\n\r\n const selectedGame = await new Promise<Game | null>((resolve) => {\r\n const { unmount } = render(\r\n <GamePicker\r\n games={games}\r\n onSelect={(game) => {\r\n unmount();\r\n resolve(game);\r\n }}\r\n onExit={() => {\r\n unmount();\r\n resolve(null);\r\n }}\r\n />,\r\n );\r\n });\r\n\r\n if (selectedGame) {\r\n console.log(`\\n 启动游戏: ${chalk.green(selectedGame.name)}\\n`);\r\n await selectedGame.play();\r\n }\r\n }\r\n });\r\n\r\n return program;\r\n}\r\n","import { existsSync, watch } from \"node:fs\";\r\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\nimport type { Config, ProviderConfig, ToolConfig, PluginConfig, StockConfig } from \"./types.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// 出厂默认配置\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const defaultConfig: Config = {\r\n defaultProvider: \"deepseek\",\r\n maxTokens: 8192,\r\n temperature: 0.7,\r\n maxToolRounds: 20,\r\n providers: [\r\n {\r\n name: \"deepseek\",\r\n baseUrl: \"https://api.deepseek.com\",\r\n model: \"deepseek-v4-flash\",\r\n },\r\n ],\r\n tools: [\r\n { name: \"read_file\", enabled: true },\r\n { name: \"write_file\", enabled: true },\r\n { name: \"edit_file\", enabled: true },\r\n { name: \"bash\", enabled: true },\r\n { name: \"glob\", enabled: true },\r\n { name: \"grep\", enabled: true },\r\n { name: \"ls\", enabled: true },\r\n { name: \"fetch\", enabled: true },\r\n ],\r\n plugins: [],\r\n stock: {\r\n symbols: [\r\n { code: \"sh000001\" },\r\n { code: \"sz399300\" },\r\n { code: \"sh601899\" },\r\n ],\r\n },\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// 配置文件路径解析\r\n// ---------------------------------------------------------------------------\r\n\r\n/** 判断一个字符串是否为合法的 URL(用于区分 local path 和 url) */\r\nfunction isUrl(s: string): boolean {\r\n try {\r\n new URL(s);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * 返回候选配置文件路径列表。\r\n * 若传入了 --config 路径,则只使用该路径;\r\n * 否则依次检查用户全局目录和项目本地目录。\r\n */\r\nfunction resolveConfigFiles(configPath?: string): string[] {\r\n if (configPath) {\r\n return [configPath];\r\n }\r\n\r\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"~\";\r\n return [\r\n join(home, \".dskcode\", \"settings.json\"),\r\n join(process.cwd(), \".dskcode\", \"settings.json\"),\r\n ];\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 深度合并\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 将较高优先级的配置 overlay 合并到 base 之上。\r\n *\r\n * 合并规则:\r\n * - 标量字段(string / number / boolean):覆盖\r\n * - 数组字段(providers / tools / plugins):直接替换,不合并\r\n */\r\nfunction mergeConfig(base: Config, overlay: Partial<Config>): Config {\r\n const result: Config = { ...base };\r\n\r\n if (overlay.defaultProvider !== undefined) {\r\n result.defaultProvider = overlay.defaultProvider;\r\n }\r\n if (overlay.verbose !== undefined) {\r\n result.verbose = overlay.verbose;\r\n }\r\n if (overlay.maxTokens !== undefined) {\r\n result.maxTokens = overlay.maxTokens;\r\n }\r\n if (overlay.temperature !== undefined) {\r\n result.temperature = overlay.temperature;\r\n }\r\n if (overlay.maxToolRounds !== undefined) {\r\n result.maxToolRounds = overlay.maxToolRounds;\r\n }\r\n if (overlay.providers !== undefined) {\r\n result.providers = overlay.providers as ProviderConfig[];\r\n }\r\n if (overlay.tools !== undefined) {\r\n result.tools = overlay.tools as ToolConfig[];\r\n }\r\n if (overlay.plugins !== undefined) {\r\n result.plugins = overlay.plugins as PluginConfig[];\r\n }\r\n if (overlay.stock !== undefined) {\r\n result.stock = overlay.stock as StockConfig;\r\n }\r\n\r\n return result;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 环境变量解析\r\n// ---------------------------------------------------------------------------\r\n\r\n/** 环境变量前缀 */\r\nconst ENV_PREFIX = \"DSKCODE_\";\r\n\r\n/** 支持的环境变量映射表 */\r\nconst ENV_MAP: Record<string, keyof Config> = {\r\n [`${ENV_PREFIX}DEFAULT_PROVIDER`]: \"defaultProvider\",\r\n [`${ENV_PREFIX}VERBOSE`]: \"verbose\",\r\n [`${ENV_PREFIX}MAX_TOKENS`]: \"maxTokens\",\r\n [`${ENV_PREFIX}TEMPERATURE`]: \"temperature\",\r\n [`${ENV_PREFIX}MAX_TOOL_ROUNDS`]: \"maxToolRounds\",\r\n};\r\n\r\n/**\r\n * 将环境变量中读取的值覆盖到配置上。\r\n * 环境变量的优先级高于 TOML 文件,但低于 CLI flag。\r\n */\r\nfunction applyEnvVars(config: Config): Config {\r\n // 1. DSKCODE_* 前缀的环境变量\r\n for (const [envKey, configKey] of Object.entries(ENV_MAP)) {\r\n const raw = process.env[envKey];\r\n if (raw === undefined) continue;\r\n\r\n const cfg = config as unknown as Record<string, unknown>;\r\n switch (configKey) {\r\n case \"verbose\":\r\n case \"defaultProvider\": {\r\n cfg[configKey] = raw;\r\n break;\r\n }\r\n case \"maxTokens\":\r\n case \"maxToolRounds\": {\r\n const n = Number(raw);\r\n if (Number.isFinite(n) && n > 0) {\r\n cfg[configKey] = n;\r\n }\r\n break;\r\n }\r\n case \"temperature\": {\r\n const n = Number(raw);\r\n if (Number.isFinite(n) && n >= 0 && n <= 2) {\r\n cfg[configKey] = n;\r\n }\r\n break;\r\n }\r\n }\r\n }\r\n\r\n // 2. DEEPSEEK_API_KEY — 注入到名为 deepseek 的 provider\r\n const apiKey = process.env.DEEPSEEK_API_KEY;\r\n if (apiKey) {\r\n const deepseek = config.providers.find((p) => p.name === \"deepseek\");\r\n if (deepseek && !deepseek.apiKey) {\r\n deepseek.apiKey = apiKey;\r\n }\r\n // 如果没有 deepseek provider,自动创建一个\r\n if (!deepseek) {\r\n config.providers.unshift({\r\n name: \"deepseek\",\r\n baseUrl: \"https://api.deepseek.com\",\r\n model: \"deepseek-v4-flash\",\r\n apiKey,\r\n });\r\n }\r\n }\r\n\r\n return config;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// CLI flag 覆盖\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface CliFlags {\r\n verbose?: boolean;\r\n model?: string;\r\n maxTokens?: number;\r\n temperature?: number;\r\n}\r\n\r\n/**\r\n * 将 CLI flag 中的值覆盖到配置上。\r\n * CLI flag 的优先级最高。\r\n */\r\nexport function applyCliOverrides(config: Config, flags: CliFlags): Config {\r\n if (flags.verbose !== undefined) {\r\n config.verbose = flags.verbose;\r\n }\r\n if (flags.model !== undefined) {\r\n // 将 --model 的值映射为标准 model 名称\r\n // 如果用户指定了 --model,覆盖 defaultProvider 中配置的 model\r\n // 但保留 provider 的选择,仅修改该 provider 的 model\r\n const provider = config.providers.find(\r\n (p) => p.name === config.defaultProvider,\r\n );\r\n if (provider) {\r\n provider.model = flags.model;\r\n }\r\n }\r\n if (flags.maxTokens !== undefined && flags.maxTokens > 0) {\r\n config.maxTokens = flags.maxTokens;\r\n }\r\n if (\r\n flags.temperature !== undefined &&\r\n flags.temperature >= 0 &&\r\n flags.temperature <= 2\r\n ) {\r\n config.temperature = flags.temperature;\r\n }\r\n return config;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 配置校验\r\n// ---------------------------------------------------------------------------\r\n\r\nexport interface ConfigError {\r\n field: string;\r\n message: string;\r\n}\r\n\r\n/**\r\n * 校验配置的合法性,返回错误列表。\r\n * 返回空数组表示配置合法。\r\n */\r\nexport function validateConfig(config: Config): ConfigError[] {\r\n const errors: ConfigError[] = [];\r\n\r\n // 1. 至少需要一个 Provider\r\n if (!config.providers || config.providers.length === 0) {\r\n errors.push({\r\n field: \"providers\",\r\n message: \"至少需要配置一个 Provider。请通过配置文件或 DEEPSEEK_API_KEY 环境变量设置。\",\r\n });\r\n }\r\n\r\n // 2. 每个 Provider 必须有 name 和 model\r\n for (let i = 0; i < config.providers.length; i++) {\r\n const p = config.providers[i]!;\r\n if (!p.name) {\r\n errors.push({\r\n field: `providers[${i}].name`,\r\n message: `第 ${i + 1} 个 Provider 缺少 name 字段。`,\r\n });\r\n }\r\n if (!p.model) {\r\n errors.push({\r\n field: `providers[${i}].model`,\r\n message: `Provider \"${p.name || i}\" 缺少 model 字段。`,\r\n });\r\n }\r\n }\r\n\r\n // 3. defaultProvider 必须存在于 providers 列表中\r\n if (config.defaultProvider) {\r\n const exists = config.providers.some(\r\n (p) => p.name === config.defaultProvider,\r\n );\r\n if (!exists) {\r\n errors.push({\r\n field: \"defaultProvider\",\r\n message: `默认 Provider \"${config.defaultProvider}\" 未在 providers 中定义。`,\r\n });\r\n }\r\n }\r\n\r\n // 4. temperature 范围校验\r\n if (\r\n config.temperature !== undefined &&\r\n (config.temperature < 0 || config.temperature > 2)\r\n ) {\r\n errors.push({\r\n field: \"temperature\",\r\n message: \"temperature 必须在 0.0 ~ 2.0 之间。\",\r\n });\r\n }\r\n\r\n // 5. maxToolRounds 范围校验\r\n if (config.maxToolRounds !== undefined && config.maxToolRounds < 1) {\r\n errors.push({\r\n field: \"maxToolRounds\",\r\n message: \"maxToolRounds 必须大于等于 1。\",\r\n });\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 核心加载流程\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 从多级配置源加载并合并配置。\r\n *\r\n * 解析顺序(后加载的优先级更高):\r\n * 1. 内置默认值 —— defaultConfig\r\n * 2. 用户全局 —— ~/.dskcode/settings.json\r\n * 3. 项目本地 —— .dskcode/settings.json(或通过 --config 指定的路径)\r\n * 4. 环境变量 —— DEEPSEEK_API_KEY、DSKCODE_* 等\r\n * 5. CLI flag —— 由调用方通过 applyCliOverrides() 单独注入\r\n */\r\nexport async function loadConfig(configPath?: string): Promise<Config> {\r\n const filePaths = resolveConfigFiles(configPath);\r\n\r\n let config: Config = structuredClone(defaultConfig);\r\n\r\n // 1-3. 依次加载 JSON 配置文件\r\n for (const filePath of filePaths) {\r\n try {\r\n const raw = await readFile(filePath, \"utf-8\");\r\n const parsed = JSON.parse(raw) as Partial<Config>;\r\n config = mergeConfig(config, parsed);\r\n } catch {\r\n // 文件不存在或权限不足 — 静默跳过\r\n }\r\n }\r\n\r\n // 4. 环境变量覆盖\r\n config = applyEnvVars(config);\r\n\r\n return config;\r\n}\r\n\r\n/**\r\n * 加载配置并同时执行校验。\r\n * 校验错误不会 throw,而是通过返回值中的 errors 字段返回,\r\n * 由调用方决定如何处理(例如在 middleware 中输出警告)。\r\n */\r\nexport async function loadAndValidate(\r\n configPath?: string,\r\n): Promise<{ config: Config; errors: ConfigError[] }> {\r\n const config = await loadConfig(configPath);\r\n const errors = validateConfig(config);\r\n return { config, errors };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 配置热加载(Watch 模式)\r\n// ---------------------------------------------------------------------------\r\n\r\nexport type ConfigChangeCallback = (config: Config) => void;\r\n\r\n/**\r\n * 监听配置文件变更,在文件被修改时重新加载配置并调用回调。\r\n *\r\n * @param callback 配置变更后的回调函数\r\n * @param configPath 可选,指定配置文件路径(对应 --config flag)\r\n * @returns 一个 unwatch 函数,调用后可停止监听\r\n */\r\nexport function watchConfig(\r\n callback: ConfigChangeCallback,\r\n configPath?: string,\r\n): () => void {\r\n const filePaths = resolveConfigFiles(configPath).filter((fp) => existsSync(fp));\r\n\r\n // 如果一个文件都不存在,则监听项目本地的 .dskcode/settings.json(即使还没创建)\r\n if (filePaths.length === 0) {\r\n filePaths.push(join(process.cwd(), \".dskcode\", \"settings.json\"));\r\n }\r\n\r\n const watchers: ReturnType<typeof watch>[] = [];\r\n let debounceTimer: ReturnType<typeof setTimeout> | undefined;\r\n\r\n for (const filePath of filePaths) {\r\n try {\r\n const watcher = watch(filePath, (eventType) => {\r\n if (eventType !== \"change\") return;\r\n\r\n // 防抖:多次连续变更只触发一次\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n debounceTimer = setTimeout(async () => {\r\n try {\r\n const raw = readFile(filePath, \"utf-8\");\r\n const config = await loadConfig(configPath);\r\n callback(config);\r\n } catch {\r\n // 重载失败时不回调,等待下一次变更\r\n }\r\n }, 300);\r\n });\r\n\r\n watchers.push(watcher);\r\n } catch {\r\n // 无法监听的文件(例如还不存在)— 跳过\r\n }\r\n }\r\n\r\n return () => {\r\n if (debounceTimer) clearTimeout(debounceTimer);\r\n for (const w of watchers) {\r\n w.close();\r\n }\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// API Key 持久化\r\n// ---------------------------------------------------------------------------\r\n\r\n/**\r\n * 将 API Key 保存到用户全局配置 ~/.dskcode/settings.json。\r\n * 如果文件已存在,合并写入;不存在则新建。\r\n * 返回保存的文件路径。\r\n */\r\nexport async function saveApiKey(apiKey: string): Promise<string> {\r\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"~\";\r\n const configDir = join(home, \".dskcode\");\r\n const configFile = join(configDir, \"settings.json\");\r\n\r\n // 确保目录存在\r\n await mkdir(configDir, { recursive: true });\r\n\r\n // 读取现有配置,或从默认配置开始\r\n let configData: Record<string, unknown>;\r\n try {\r\n const raw = await readFile(configFile, \"utf-8\");\r\n configData = JSON.parse(raw);\r\n } catch {\r\n // 文件不存在,用内置默认值填充(tools、plugins 等都会写入)\r\n configData = structuredClone(defaultConfig) as unknown as Record<string, unknown>;\r\n }\r\n\r\n // 更新或创建 deepseek provider\r\n const providers = (configData.providers as Array<Record<string, unknown>>) ?? [];\r\n const existing = providers.find((p) => p.name === \"deepseek\");\r\n\r\n if (existing) {\r\n existing.apiKey = apiKey;\r\n } else {\r\n providers.push({\r\n name: \"deepseek\",\r\n apiKey,\r\n baseUrl: \"https://api.deepseek.com\",\r\n model: \"deepseek-v4-flash\",\r\n });\r\n }\r\n\r\n configData.providers = providers;\r\n\r\n // 写回文件\r\n await writeFile(configFile, JSON.stringify(configData, null, 2), \"utf-8\");\r\n\r\n return configFile;\r\n}\r\n","import type { Command } from \"commander\";\r\nimport {\r\n loadAndValidate,\r\n applyCliOverrides,\r\n defaultConfig,\r\n} from \"../config/index.js\";\r\nimport type { Config } from \"../config/index.js\";\r\n\r\n/**\r\n * dskcode 运行时上下文。\r\n * 通过 commander 的 preAction hook 注入到每个命令中。\r\n */\r\nexport interface DskcodeContext {\r\n config: Config;\r\n verbose: boolean;\r\n}\r\n\r\n/**\r\n * 在 preAction hook 中加载配置并构造上下文。\r\n *\r\n * 完整的配置解析流水线:\r\n * 1. 内置默认值 —— defaultConfig\r\n * 2. 用户全局 —— ~/.dskcode/settings.json\r\n * 3. 项目本地 —— .dskcode/settings.json(或 --config 指定的路径)\r\n * 4. 环境变量 —— DEEPSEEK_API_KEY / DSKCODE_*\r\n * 5. CLI flag —— --verbose / --model 等\r\n */\r\nexport async function loadConfigMiddleware(\r\n this: Command,\r\n): Promise<DskcodeContext> {\r\n const opts = this.optsWithGlobals() as {\r\n verbose?: boolean;\r\n config?: string;\r\n model?: string;\r\n };\r\n const verbose = opts.verbose ?? false;\r\n\r\n // 1-4. 加载 TOML 文件 + 环境变量\r\n let config: Config;\r\n const errors: string[] = [];\r\n try {\r\n const result = await loadAndValidate(opts.config);\r\n config = result.config;\r\n if (result.errors.length > 0) {\r\n for (const e of result.errors) {\r\n errors.push(e.message);\r\n }\r\n }\r\n } catch {\r\n config = structuredClone(defaultConfig);\r\n }\r\n\r\n // 5. CLI flag 覆盖(优先级最高)\r\n config = applyCliOverrides(config, {\r\n verbose,\r\n model: opts.model,\r\n });\r\n\r\n // 校验错误输出(不阻断执行)\r\n if (errors.length > 0 && verbose) {\r\n for (const msg of errors) {\r\n console.error(` ⚠ ${msg}`);\r\n }\r\n }\r\n\r\n return { config, verbose };\r\n}\r\n","import type { Command } from \"commander\";\r\nimport chalk from \"chalk\";\r\n\r\nexport function customHelp(program: Command): string {\r\n const lines: string[] = [];\r\n\r\n lines.push(\"\");\r\n lines.push(chalk.bold(\"用法:\"));\r\n lines.push(` ${chalk.cyan(\"dskcode\")} ${chalk.dim(\"[global-options]\")} ${chalk.green(\"<command>\")} ${chalk.dim(\"[options]\")}`);\r\n lines.push(\"\");\r\n\r\n const globalOpts = program.options.filter(\r\n (o) => o.long !== \"--help\" && o.long !== \"--version\" && o.long !== \"--config\",\r\n );\r\n if (globalOpts.length > 0) {\r\n lines.push(chalk.bold(\"全局选项:\"));\r\n for (const opt of globalOpts) {\r\n const flags = [opt.short, opt.long].filter(Boolean).join(\", \");\r\n lines.push(` ${chalk.cyan(flags.padEnd(24))} ${opt.description ?? \"\"}`);\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n lines.push(chalk.bold(\"内置选项:\"));\r\n for (const flag of [\"-h, --help\", \"-V, --version\"]) {\r\n const opt = program.options.find(\r\n (o) => o.long === (flag.includes(\"help\") ? \"--help\" : \"--version\"),\r\n );\r\n if (opt) {\r\n lines.push(` ${chalk.cyan(flag.padEnd(24))} ${opt.description ?? \"\"}`);\r\n }\r\n }\r\n lines.push(\"\");\r\n\r\n const cmds = program.commands.filter((c) => !c.name().startsWith(\"help\"));\r\n if (cmds.length > 0) {\r\n lines.push(chalk.bold(\"命令:\"));\r\n for (const cmd of cmds) {\r\n lines.push(` ${chalk.green(cmd.name().padEnd(24))} ${cmd.description()}`);\r\n }\r\n lines.push(\"\");\r\n }\r\n\r\n lines.push(chalk.bold(\"示例:\"));\r\n lines.push(` ${chalk.dim(\"# 启动交互式对话\")}`);\r\n lines.push(\" dskcode chat\");\r\n lines.push(` ${chalk.dim(\"# 让 AI 执行一个任务\")}`);\r\n lines.push(\" dskcode run 修改所有 TODO 注释\");\r\n lines.push(` ${chalk.dim(\"# 运行配置向导\")}`);\r\n lines.push(\" dskcode setup\");\r\n lines.push(` ${chalk.dim(\"# 生成 shell 自动补全\")}`);\r\n lines.push(\" dskcode completion\");\r\n lines.push(` ${chalk.dim(\"# 查看自选股行情\")}`);\r\n lines.push(\" dskcode stock\");\r\n lines.push(` ${chalk.dim(\"# 查看指定股票行情\")}`);\r\n lines.push(\" dskcode stock sh513090 sz000001\");\r\n lines.push(\"\");\r\n\r\n return lines.join(\"\\n\");\r\n}\r\n","import { createInterface } from \"node:readline\";\r\nimport chalk from \"chalk\";\r\n\r\n/**\r\n * 检测是否有可用的 API Key。\r\n * 遍历所有 provider 检查是否配置了 apiKey,同时检查 DEEPSEEK_API_KEY 环境变量。\r\n */\r\nexport function hasApiKey(providers: Array<{ apiKey?: string }>): boolean {\r\n if (providers.some((p) => p.apiKey)) return true;\r\n if (process.env.DEEPSEEK_API_KEY) return true;\r\n return false;\r\n}\r\n\r\n/**\r\n * 交互式提示用户输入 DeepSeek API Key。\r\n * 使用 Node readline 的 password 模式(输入不可见)。\r\n * 返回用户输入的 Key,如果用户取消则返回 null。\r\n */\r\nexport async function promptForApiKey(): Promise<string | null> {\r\n console.log(\r\n chalk.yellow(\"\\n ⚠ 未检测到 API Key 配置\"),\r\n );\r\n console.log(\r\n chalk.dim(\" 你可以通过以下任一方式配置:\"),\r\n );\r\n console.log(\r\n chalk.dim(\" · 环境变量: export DEEPSEEK_API_KEY=sk-xxx\"),\r\n );\r\n console.log(\r\n chalk.dim(\" · 配置文件: ~/.dskcode/settings.json\"),\r\n );\r\n console.log(\r\n chalk.dim(\" · 下面直接输入,自动保存到全局配置\\n\"),\r\n );\r\n\r\n const rl = createInterface({\r\n input: process.stdin,\r\n output: process.stdout,\r\n });\r\n\r\n return new Promise<string | null>((resolve) => {\r\n const cleanup = () => {\r\n rl.close();\r\n };\r\n\r\n process.stdin.on(\"keypress\", (_, key) => {\r\n if (key.ctrl && key.name === \"c\") {\r\n cleanup();\r\n resolve(null);\r\n }\r\n });\r\n\r\n rl.question(\r\n ` ${chalk.cyan(\"🔑\")} ${chalk.bold(\"请输入你的 DeepSeek API Key:\")} `,\r\n (answer) => {\r\n cleanup();\r\n const trimmed = answer.trim();\r\n if (!trimmed) {\r\n console.log(chalk.red(\" ✖ API Key 不能为空\"));\r\n resolve(null);\r\n return;\r\n }\r\n if (trimmed.length < 10) {\r\n console.log(chalk.red(\" ✖ API Key 格式不正确,长度至少 10 位\"));\r\n resolve(null);\r\n return;\r\n }\r\n resolve(trimmed);\r\n },\r\n );\r\n });\r\n}\r\n","import { render } from \"ink\";\r\nimport type { ReactNode } from \"react\";\r\n\r\nexport interface RenderScopeHandle {\r\n waitUntilExit: Promise<unknown>;\r\n unmount: () => void;\r\n clear: () => void;\r\n}\r\n\r\nexport function renderApp(node: ReactNode): RenderScopeHandle {\r\n const { waitUntilExit, clear, unmount } = render(node);\r\n return { waitUntilExit: waitUntilExit(), clear, unmount };\r\n}\r\n\r\nexport async function unmountApp(handle: RenderScopeHandle): Promise<void> {\r\n handle.unmount();\r\n await new Promise((resolve) => setTimeout(resolve, 50));\r\n}\r\n","import { Text } from \"ink\";\r\nimport InkSpinner from \"ink-spinner\";\r\n\r\ninterface SpinnerProps {\r\n type?: \"dots\" | \"line\" | \"bouncingBar\" | \"aesthetic\";\r\n label?: string;\r\n}\r\n\r\nexport function Spinner({ type = \"dots\", label }: SpinnerProps) {\r\n return (\r\n <Text>\r\n <Text color=\"cyan\">\r\n <InkSpinner type={type} />\r\n </Text>\r\n {label ? <Text> {label}</Text> : null}\r\n </Text>\r\n );\r\n}\r\n","import { Box, Text } from \"ink\";\r\n\r\ntype MessageType = \"info\" | \"success\" | \"warning\" | \"error\";\r\n\r\ninterface StatusMessageProps {\r\n type?: MessageType;\r\n label: string;\r\n detail?: string;\r\n}\r\n\r\nconst STYLES: Record<MessageType, { color: string; icon: string }> = {\r\n info: { color: \"cyan\", icon: \"ℹ\" },\r\n success: { color: \"green\", icon: \"✔\" },\r\n warning: { color: \"yellow\", icon: \"⚠\" },\r\n error: { color: \"red\", icon: \"✖\" },\r\n};\r\n\r\nexport function StatusMessage({ type = \"info\", label, detail }: StatusMessageProps) {\r\n const { color, icon } = STYLES[type];\r\n return (\r\n <Box>\r\n <Text color={color}>\r\n {icon} {label}\r\n </Text>\r\n {detail ? <Text dimColor>: {detail}</Text> : null}\r\n </Box>\r\n );\r\n}\r\n","import { Box, Text } from \"ink\";\r\nimport { useEffect, useState } from \"react\";\r\n\r\nconst CYBER_PALETTE = [\"#00ffff\", \"#ff00ff\", \"#00ff41\", \"#ff1493\", \"#8b00ff\"];\r\n\r\nconst LOGO_LINES = [\r\n \" ██████╗ ███████╗██╗ ██╗\",\r\n \" ██╔══██╗██╔════╝██║ ██╔╝\",\r\n \" ██║ ██║███████╗█████╔╝ \",\r\n \" ██║ ██║╚════██║██╔═██╗ \",\r\n \" ██████╔╝███████║██║ ██╗\",\r\n \" ╚═════╝ ╚══════╝╚═╝ ╚═╝\",\r\n];\r\n\r\nexport function DskcodeSplash() {\r\n const [offset, setOffset] = useState(0);\r\n\r\n useEffect(() => {\r\n const timer = setInterval(() => {\r\n setOffset((prev) => (prev + 1) % CYBER_PALETTE.length);\r\n }, 500);\r\n return () => clearInterval(timer);\r\n }, []);\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingLeft={1}>\r\n {LOGO_LINES.map((line, i) => {\r\n const colorIndex = (i + offset) % CYBER_PALETTE.length;\r\n return (\r\n <Box key={i}>\r\n <Text bold color={CYBER_PALETTE[colorIndex]}>\r\n {line}\r\n </Text>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n );\r\n}\r\n","import { Box, Text } from \"ink\";\r\nimport TextInput from \"ink-text-input\";\r\nimport { useEffect, useState, useCallback } from \"react\";\r\n\r\nconst CYBER_PALETTE = [\"#00ffff\", \"#ff00ff\", \"#00ff41\", \"#ff1493\", \"#8b00ff\"];\r\n\r\nconst LOGO_LINES = [\r\n \" ██████╗ ███████╗██╗ ██╗\",\r\n \" ██╔══██╗██╔════╝██║ ██╔╝\",\r\n \" ██║ ██║███████╗█████╔╝ \",\r\n \" ██║ ██║╚════██║██╔═██╗ \",\r\n \" ██████╔╝███████║██║ ██╗\",\r\n \" ╚═════╝ ╚══════╝╚═╝ ╚═╝\",\r\n];\r\n\r\nconst COMMANDS: Record<string, { desc: string; handler: () => string }> = {\r\n \"/exit\": { desc: \"退出对话\", handler: () => \"\" },\r\n \"/quit\": { desc: \"退出对话\", handler: () => \"\" },\r\n \"/help\": {\r\n desc: \"显示帮助信息\",\r\n handler: () =>\r\n [\r\n \"可用命令:\",\r\n \" /exit, /quit 退出对话\",\r\n \" /help 显示此帮助\",\r\n \" /clear 清空对话历史\",\r\n \" /version 显示版本信息\",\r\n ].join(\"\\n\"),\r\n },\r\n \"/clear\": { desc: \"清空对话历史\", handler: () => \"\" },\r\n \"/version\": { desc: \"显示版本信息\", handler: () => \"dskcode v0.0.0\" },\r\n};\r\n\r\ninterface ChatMessage {\r\n role: \"user\" | \"assistant\";\r\n content: string;\r\n}\r\n\r\ninterface ChatSessionProps {\r\n providerCount: number;\r\n toolCount: number;\r\n verbose: boolean;\r\n}\r\n\r\nexport function ChatSession({ providerCount, toolCount, verbose }: ChatSessionProps) {\r\n const [offset, setOffset] = useState(0);\r\n const [messages, setMessages] = useState<ChatMessage[]>([]);\r\n const [input, setInput] = useState(\"\");\r\n\r\n useEffect(() => {\r\n const timer = setInterval(() => {\r\n setOffset((prev) => (prev + 1) % CYBER_PALETTE.length);\r\n }, 500);\r\n return () => clearInterval(timer);\r\n }, []);\r\n\r\n const handleSubmit = useCallback((value: string) => {\r\n const trimmed = value.trim();\r\n if (!trimmed) return;\r\n\r\n if (trimmed.startsWith(\"/\")) {\r\n const cmd = COMMANDS[trimmed.toLowerCase()];\r\n if (cmd) {\r\n if (trimmed.toLowerCase() === \"/exit\" || trimmed.toLowerCase() === \"/quit\") {\r\n process.exit(0);\r\n return;\r\n }\r\n if (trimmed.toLowerCase() === \"/clear\") {\r\n setMessages([]);\r\n setInput(\"\");\r\n return;\r\n }\r\n const result = cmd.handler();\r\n if (result) {\r\n setMessages((prev) => [\r\n ...prev,\r\n { role: \"user\", content: trimmed },\r\n { role: \"assistant\", content: result },\r\n ]);\r\n }\r\n setInput(\"\");\r\n return;\r\n }\r\n setMessages((prev) => [\r\n ...prev,\r\n { role: \"user\", content: trimmed },\r\n { role: \"assistant\", content: `未知命令:${trimmed}。输入 /help 查看。` },\r\n ]);\r\n setInput(\"\");\r\n return;\r\n }\r\n\r\n setMessages((prev) => [\r\n ...prev,\r\n { role: \"user\", content: trimmed },\r\n { role: \"assistant\", content: \"dskcode AI — 待实现(第07章)。当前为 CLI 框架演示模式。\" },\r\n ]);\r\n setInput(\"\");\r\n }, []);\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingLeft={1} paddingRight={1}>\r\n {/* Logo + 状态栏 — 左右布局 */}\r\n <Box flexDirection=\"row\" marginBottom={1}>\r\n {/* Logo */}\r\n <Box flexDirection=\"column\" marginRight={4}>\r\n {LOGO_LINES.map((line, i) => {\r\n const colorIndex = (i + offset) % CYBER_PALETTE.length;\r\n return (\r\n <Box key={i}>\r\n <Text bold color={CYBER_PALETTE[colorIndex]}>\r\n {line}\r\n </Text>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n\r\n {/* 状态信息 */}\r\n <Box flexDirection=\"column\" justifyContent=\"center\">\r\n <Text color=\"#00ff41\">{\" ✔ \"}已加载 {providerCount} 个 Provider</Text>\r\n <Text color=\"#00ffff\">{\" ℹ \"}已就绪 {toolCount} 个工具</Text>\r\n {verbose ? <Text color=\"#ff1493\">{\" ⚡ Verbose\"}</Text> : null}\r\n </Box>\r\n </Box>\r\n\r\n {/* Messages */}\r\n <Box flexDirection=\"column\" marginTop={1}>\r\n {messages.map((msg, i) => (\r\n <Box key={i} marginTop={1}>\r\n <Box width={8} flexShrink={0}>\r\n <Text bold color={msg.role === \"user\" ? \"#00ff41\" : \"#ff00ff\"}>\r\n {msg.role === \"user\" ? \" 👤\" : \" 🤖\"}\r\n </Text>\r\n </Box>\r\n <Box flexGrow={1}>\r\n <Text wrap=\"wrap\">{msg.content}</Text>\r\n </Box>\r\n </Box>\r\n ))}\r\n </Box>\r\n\r\n {/* Input */}\r\n <Box marginTop={1}>\r\n <Box width={8} flexShrink={0}>\r\n <Text bold color=\"#00ff41\">\r\n {\" ⚡\"}\r\n </Text>\r\n </Box>\r\n <Box flexGrow={1}>\r\n <TextInput\r\n value={input}\r\n onChange={setInput}\r\n onSubmit={handleSubmit}\r\n placeholder=\"输入你的问题...\"\r\n />\r\n </Box>\r\n </Box>\r\n\r\n <Box marginTop={1}>\r\n <Text color=\"#00ffff\" dimColor>\r\n {\" \" + \"─\".repeat(36)}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n","import { Box, Text, useInput } from \"ink\";\r\nimport { useState, useCallback } from \"react\";\r\nimport type { Game } from \"../game/index.js\";\r\n\r\ninterface GamePickerProps {\r\n games: Game[];\r\n onSelect: (game: Game) => void;\r\n onExit: () => void;\r\n}\r\n\r\nexport function GamePicker({ games, onSelect, onExit }: GamePickerProps) {\r\n const [selectedIndex, setSelectedIndex] = useState(0);\r\n\r\n useInput(\r\n useCallback(\r\n (input, key) => {\r\n if (games.length === 0) return;\r\n if (key.upArrow || input === \"k\") {\r\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : games.length - 1));\r\n } else if (key.downArrow || input === \"j\") {\r\n setSelectedIndex((prev) => (prev < games.length - 1 ? prev + 1 : 0));\r\n } else if (key.return) {\r\n const game = games[selectedIndex];\r\n if (game) onSelect(game);\r\n } else if (key.escape || input === \"q\") {\r\n onExit();\r\n }\r\n },\r\n [games, selectedIndex, onSelect, onExit],\r\n ),\r\n );\r\n\r\n return (\r\n <Box flexDirection=\"column\">\r\n <Box marginBottom={1}>\r\n <Text bold color=\"#00ffff\">\r\n 🎮 游戏列表\r\n </Text>\r\n </Box>\r\n\r\n <Box flexDirection=\"column\">\r\n {games.map((game, index) => {\r\n const isSelected = index === selectedIndex;\r\n return (\r\n <Box key={game.id} flexDirection=\"row\">\r\n <Box width={3} flexShrink={0}>\r\n {isSelected ? (\r\n <Text bold color=\"#00ff41\">\r\n {\"▸ \"}\r\n </Text>\r\n ) : (\r\n <Text>{\" \"}</Text>\r\n )}\r\n </Box>\r\n <Box width={20} flexShrink={0}>\r\n <Text bold color={isSelected ? \"#00ff41\" : \"#ffffff\"}>\r\n {game.name}\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text color=\"#888888\">{game.description}</Text>\r\n </Box>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n\r\n <Box marginTop={1}>\r\n <Text dimColor>\r\n {\" ↑/↓ 选择 Enter 启动 q 返回\"}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n","export interface Game {\r\n /** 游戏唯一标识 */\r\n id: string;\r\n /** 游戏名称 */\r\n name: string;\r\n /** 简短描述 */\r\n description: string;\r\n /** 启动游戏 */\r\n play: () => Promise<void>;\r\n}\r\n\r\nconst registry = new Map<string, Game>();\r\n\r\nexport function registerGame(game: Game): void {\r\n registry.set(game.id, game);\r\n}\r\n\r\nexport function getGame(id: string): Game | undefined {\r\n return registry.get(id);\r\n}\r\n\r\nexport function listGames(): Game[] {\r\n return Array.from(registry.values());\r\n}\r\n","import { Box, Text, useInput, render } from \"ink\";\r\nimport { useState, useEffect, useRef, useCallback } from \"react\";\r\n\r\nconst GAME_WIDTH = 40;\r\nconst GAME_HEIGHT = 18;\r\nconst PADDLE_WIDTH = 9;\r\nconst BRICK_COLORS = [166, 214, 76, 69];\r\n\r\ninterface Vec2 {\r\n x: number;\r\n y: number;\r\n}\r\n\r\ninterface Brick {\r\n x: number;\r\n y: number;\r\n w: number;\r\n alive: boolean;\r\n}\r\n\r\n// ─── 10 个关卡定义 ──────────────────────────────────────────────\r\n\r\ninterface LevelDef {\r\n rows: number;\r\n cols: number;\r\n bw: number; // 砖块宽度(格数)\r\n desc: string;\r\n // 返回 true 表示该位置有砖块\r\n pattern: (col: number, row: number, rows: number, cols: number) => boolean;\r\n}\r\n\r\nconst LEVELS: LevelDef[] = [\r\n { rows: 4, cols: 8, bw: 3, desc: \"经典 4×8\", pattern: () => true },\r\n { rows: 3, cols: 8, bw: 3, desc: \"轻松 3 层\", pattern: () => true },\r\n { rows: 6, cols: 8, bw: 3, desc: \"厚墙 6 层\", pattern: () => true },\r\n { rows: 4, cols: 8, bw: 3, desc: \"棋盘格\", pattern: (c, r) => (c + r) % 2 === 0 },\r\n { rows: 4, cols: 8, bw: 3, desc: \"金字塔\", pattern: (c, r, _, tc) => c >= r && c < tc - r },\r\n { rows: 4, cols: 8, bw: 3, desc: \"交错排列\", pattern: (c, r) => r % 2 === 0 || (c >= 1 && c <= 6) },\r\n { rows: 4, cols: 8, bw: 3, desc: \"中空边框\", pattern: (c, r, tr, tc) => r === 0 || r === tr - 1 || c === 0 || c === tc - 1 },\r\n { rows: 4, cols: 10, bw: 2, desc: \"密集 10 列\", pattern: () => true },\r\n { rows: 7, cols: 8, bw: 3, desc: \"高墙 7 层\", pattern: () => true },\r\n { rows: 8, cols: 8, bw: 3, desc: \"满屏 8 层\", pattern: () => true },\r\n];\r\n\r\nfunction getLevel(level: number): LevelDef {\r\n return LEVELS[(level - 1) % LEVELS.length] as LevelDef;\r\n}\r\n\r\nfunction createBricks(level: number): Brick[] {\r\n const def = getLevel(level);\r\n const bricks: Brick[] = [];\r\n const gap = 2;\r\n const totalW = def.cols * def.bw + (def.cols - 1) * gap;\r\n const startX = Math.floor((GAME_WIDTH - totalW) / 2);\r\n const step = def.bw + gap;\r\n\r\n for (let row = 0; row < def.rows; row++) {\r\n for (let col = 0; col < def.cols; col++) {\r\n if (def.pattern(col, row, def.rows, def.cols)) {\r\n bricks.push({\r\n x: startX + col * step,\r\n y: 2 + row * 2,\r\n w: def.bw,\r\n alive: true,\r\n });\r\n }\r\n }\r\n }\r\n return bricks;\r\n}\r\n\r\n// ─── 游戏状态 ──────────────────────────────────────────────────\r\n\r\ninterface GameState {\r\n level: number;\r\n bricks: Brick[];\r\n paddleX: number;\r\n ball: Vec2;\r\n ballDir: Vec2;\r\n score: number;\r\n lives: number;\r\n gameOver: boolean;\r\n win: boolean;\r\n paused: boolean;\r\n}\r\n\r\nfunction createInitialState(level: number): GameState {\r\n const def = getLevel(level);\r\n const totalW = def.cols * def.bw + (def.cols - 1) * 2;\r\n const startX = Math.floor((GAME_WIDTH - totalW) / 2);\r\n return {\r\n level,\r\n bricks: createBricks(level),\r\n paddleX: Math.floor(GAME_WIDTH / 2) - Math.floor(PADDLE_WIDTH / 2),\r\n ball: { x: GAME_WIDTH / 2, y: GAME_HEIGHT - 3 },\r\n ballDir: { x: 1, y: -1 },\r\n score: 0,\r\n lives: 3,\r\n gameOver: false,\r\n win: false,\r\n paused: false,\r\n };\r\n}\r\n\r\n// ─── 物理更新 ──────────────────────────────────────────────────\r\n\r\nfunction update(state: GameState): void {\r\n if (state.paused || state.gameOver || state.win) return;\r\n\r\n state.ball.x += state.ballDir.x;\r\n state.ball.y += state.ballDir.y;\r\n\r\n if (state.ball.x <= 0) { state.ball.x = 0; state.ballDir.x = 1; }\r\n if (state.ball.x >= GAME_WIDTH - 1) { state.ball.x = GAME_WIDTH - 1; state.ballDir.x = -1; }\r\n if (state.ball.y <= 0) { state.ball.y = 0; state.ballDir.y = 1; }\r\n\r\n // 挡板碰撞\r\n if (\r\n state.ball.y === GAME_HEIGHT - 1 &&\r\n state.ball.x >= state.paddleX &&\r\n state.ball.x <= state.paddleX + PADDLE_WIDTH\r\n ) {\r\n state.ballDir.y = -1;\r\n const hitPos = (state.ball.x - state.paddleX) / PADDLE_WIDTH;\r\n state.ballDir.x = hitPos < 0.5 ? -1 : 1;\r\n }\r\n\r\n // 出界\r\n if (state.ball.y > GAME_HEIGHT) {\r\n state.lives--;\r\n if (state.lives <= 0) {\r\n state.gameOver = true;\r\n } else {\r\n state.ball = { x: GAME_WIDTH / 2, y: GAME_HEIGHT - 3 };\r\n state.ballDir = { x: 1, y: -1 };\r\n state.paddleX = Math.floor(GAME_WIDTH / 2) - Math.floor(PADDLE_WIDTH / 2);\r\n }\r\n }\r\n\r\n // 砖块碰撞\r\n const hitBrick = state.bricks.find((b) => {\r\n if (!b.alive) return false;\r\n return state.ball.x >= b.x && state.ball.x < b.x + b.w && state.ball.y >= b.y && state.ball.y < b.y + 1;\r\n });\r\n\r\n if (hitBrick) {\r\n hitBrick.alive = false;\r\n state.score += 10;\r\n state.ballDir.y = -state.ballDir.y;\r\n }\r\n\r\n if (state.bricks.every((b) => !b.alive)) state.win = true;\r\n}\r\n\r\n// ─── 画面渲染(含 ANSI 颜色) ─────────────────────────────────\r\n\r\nfunction buildBoard(state: GameState): string {\r\n const lines: string[] = [];\r\n\r\n function brickColorIndex(x: number, y: number): number | undefined {\r\n const row = Math.floor((y - 2) / 2);\r\n if (row >= 0) {\r\n const b = state.bricks.find((br) => br.y === y && br.alive && x >= br.x && x < br.x + br.w);\r\n if (b) return row % BRICK_COLORS.length;\r\n }\r\n return undefined;\r\n }\r\n\r\n for (let y = 0; y < GAME_HEIGHT; y++) {\r\n let line = \"\";\r\n for (let x = 0; x < GAME_WIDTH; x++) {\r\n const isBall = state.ball.x === x && state.ball.y === y;\r\n const isPaddle = y === GAME_HEIGHT - 1 && x >= state.paddleX && x < state.paddleX + PADDLE_WIDTH;\r\n const brickRow = brickColorIndex(x, y);\r\n\r\n if (isBall) {\r\n line += \"\\x1b[97m●\\x1b[0m\";\r\n } else if (isPaddle) {\r\n line += \"\\x1b[94m▄\\x1b[0m\";\r\n } else if (brickRow !== undefined) {\r\n line += `\\x1b[38;5;${BRICK_COLORS[brickRow] as number}m▀\\x1b[0m`;\r\n } else {\r\n line += \" \";\r\n }\r\n }\r\n lines.push(line);\r\n }\r\n\r\n return lines.map((l) => `│${l}│`).join(\"\\n\");\r\n}\r\n\r\n// ─── Ink 组件 ──────────────────────────────────────────────────\r\n\r\ninterface BrickBreakerGameProps {\r\n onExit: () => void;\r\n}\r\n\r\nfunction BrickBreakerGame({ onExit: _onExit }: BrickBreakerGameProps) {\r\n const [initialLevel, setInitialLevel] = useState(1);\r\n const [selectingLevel, setSelectingLevel] = useState(true);\r\n const stateRef = useRef<GameState>(createInitialState(initialLevel));\r\n const [tick, setTick] = useState(0);\r\n const onExitRef = useRef(_onExit);\r\n onExitRef.current = _onExit;\r\n\r\n useEffect(() => {\r\n if (selectingLevel) return;\r\n const interval = setInterval(() => {\r\n update(stateRef.current);\r\n setTick((t) => t + 1);\r\n }, 80);\r\n return () => clearInterval(interval);\r\n }, [selectingLevel]);\r\n\r\n // 重新开始(保留当前关卡)\r\n const restart = useCallback((level?: number) => {\r\n const lv = level ?? stateRef.current.level;\r\n stateRef.current = createInitialState(lv);\r\n setInitialLevel(lv);\r\n setSelectingLevel(false);\r\n setTick(0);\r\n }, []);\r\n\r\n // 选关\r\n const startLevelSelect = useCallback(() => {\r\n setSelectingLevel(true);\r\n }, []);\r\n\r\n useInput(\r\n useCallback((input, key) => {\r\n const s = stateRef.current;\r\n\r\n // 选关模式\r\n if (selectingLevel) {\r\n if (input >= \"1\" && input <= \"9\") {\r\n restart(Number(input));\r\n } else if (input === \"0\") {\r\n restart(10);\r\n } else if (key.escape || input === \"q\") {\r\n onExitRef.current();\r\n }\r\n return;\r\n }\r\n\r\n if (key.leftArrow) {\r\n s.paddleX = Math.max(0, s.paddleX - 1);\r\n setTick((t) => t + 1);\r\n } else if (key.rightArrow) {\r\n s.paddleX = Math.min(GAME_WIDTH - PADDLE_WIDTH, s.paddleX + 1);\r\n setTick((t) => t + 1);\r\n } else if (input === \"p\" || input === \" \") {\r\n s.paused = !s.paused;\r\n } else if (input === \"r\") {\r\n if (s.gameOver || s.win) restart();\r\n } else if (input === \"l\") {\r\n if (s.gameOver || s.win) startLevelSelect();\r\n } else if (input === \"q\" || key.escape) {\r\n onExitRef.current();\r\n }\r\n }, [selectingLevel, restart, startLevelSelect]),\r\n );\r\n\r\n const s = stateRef.current;\r\n const aliveCount = s.bricks.filter((b) => b.alive).length;\r\n const board = buildBoard(s);\r\n const def = getLevel(s.level);\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n void tick;\r\n\r\n return (\r\n <Box flexDirection=\"column\">\r\n {/* 状态栏 */}\r\n <Box flexDirection=\"row\">\r\n <Box width={20}>\r\n <Text>\r\n 关卡 {s.level}: <Text color=\"cyan\">{def.desc}</Text>\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text>\r\n 分数: <Text color=\"yellow\">{String(s.score).padStart(3, \"0\")}</Text>\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text>\r\n 生命: <Text color=\"red\">{\"♥\".repeat(Math.max(0, s.lives))}</Text>\r\n </Text>\r\n </Box>\r\n <Box width={10}>\r\n <Text>\r\n 砖块: <Text color=\"cyan\">{aliveCount}</Text>\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text color={s.paused ? \"gray\" : \"green\"}>\r\n [{s.paused ? \"暂停\" : \"运行中\"}]\r\n </Text>\r\n </Box>\r\n </Box>\r\n\r\n {/* 游戏画面 */}\r\n <Box flexDirection=\"column\">\r\n <Text>┌{\"─\".repeat(GAME_WIDTH)}┐</Text>\r\n <Text>{selectingLevel ? \" \\x1b[90m选择关卡后开始...\\x1b[0m\" : board}</Text>\r\n <Text>└{\"─\".repeat(GAME_WIDTH)}┘</Text>\r\n </Box>\r\n\r\n {/* 选关界面 */}\r\n {selectingLevel && (\r\n <Box marginTop={1} flexDirection=\"column\">\r\n <Text bold color=\"yellow\">选择关卡</Text>\r\n <Box flexDirection=\"row\" flexWrap=\"wrap\">\r\n {LEVELS.map((lv, i) => (\r\n <Box key={i} width={22}>\r\n <Text>\r\n <Text color={initialLevel === i + 1 ? \"green\" : \"white\"}>\r\n {i + 1 === 10 ? \"0\" : String(i + 1)}\r\n </Text>\r\n . {lv.desc} ({lv.rows}×{lv.cols})\r\n </Text>\r\n </Box>\r\n ))}\r\n </Box>\r\n <Box marginTop={1}>\r\n <Text dimColor>按数字选关 q 退出</Text>\r\n </Box>\r\n </Box>\r\n )}\r\n\r\n {/* 结束/通关信息 */}\r\n {!selectingLevel && (s.gameOver || s.win) && (\r\n <Box marginTop={1}>\r\n <Text bold color={s.gameOver ? \"red\" : \"green\"}>\r\n {s.gameOver ? \"游戏结束!\" : \"恭喜通关!\"}\r\n </Text>\r\n <Text>\r\n {\" 分数: \"}<Text color=\"yellow\">{s.score}</Text>\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* 操作提示 */}\r\n {!selectingLevel && (\r\n <Box marginTop={1}>\r\n {s.gameOver || s.win ? (\r\n <Text dimColor>\r\n {\"← → 移动 r 重开 l 选关 q 退出\"}\r\n </Text>\r\n ) : (\r\n <Text dimColor>\r\n {\"← → 移动 p 暂停 q 退出\"}\r\n </Text>\r\n )}\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n}\r\n\r\n// ─── 导出 ──────────────────────────────────────────────────────\r\n\r\nexport default {\r\n id: \"brick-breaker\",\r\n name: \"Brick Breaker\",\r\n description: \"经典打砖块游戏,10 个关卡可选!\",\r\n play: async () => {\r\n await new Promise<void>((resolve) => {\r\n const { unmount } = render(\r\n <BrickBreakerGame onExit={() => { unmount(); resolve(); }} />,\r\n );\r\n });\r\n },\r\n};\r\n","import { Box, Text, useInput, render } from \"ink\";\r\nimport { useState, useEffect, useRef, useCallback } from \"react\";\r\n\r\nconst GAME_W = 66;\r\nconst GAME_H = 20; // 6 行分数 + 14 行掉落单词\r\nconst SCORE_H = 6;\r\nconst WORD_H = 14;\r\nconst MAX_WORDS = 10;\r\nconst CYBER_PALETTE = [\"#00ffff\", \"#ff00ff\", \"#00ff41\", \"#ff1493\", \"#8b00ff\"];\r\n\r\n// 3×5 像素大号数字(每个像素 = ██,每数字 6 列)\r\nconst DIGIT_ART: Record<string, string[]> = {\r\n \"0\": [\" ██████ \", \"██ ██\", \"██ ██\", \"██ ██\", \" ██████ \"],\r\n \"1\": [\" ██ \", \" ████ \", \" ██ \", \" ██ \", \" ██████ \"],\r\n \"2\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ \", \" ██████ \"],\r\n \"3\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ \", \" ██████ \"],\r\n \"4\": [\"██ ██\", \"██ ██\", \" ██████ \", \" ██ \", \" ██ \"],\r\n \"5\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ \", \" ██████ \"],\r\n \"6\": [\" ██████ \", \" ██ \", \" ██████ \", \" ██ ██\", \" ██████ \"],\r\n \"7\": [\" ██████ \", \" ██ \", \" ██ \", \" ██ \", \" ██ \"],\r\n \"8\": [\" ██████ \", \"██ ██\", \" ██████ \", \"██ ██\", \" ██████ \"],\r\n \"9\": [\" ██████ \", \"██ ██\", \" ██████ \", \" ██ \", \" ██████ \"],\r\n};\r\n\r\nfunction buildScoreLines(scoreStr: string): string[] {\r\n const lines = [\"\", \"\", \"\", \"\", \"\"];\r\n for (const ch of scoreStr) {\r\n const art = DIGIT_ART[ch] ?? DIGIT_ART[\"0\"]!;\r\n for (let r = 0; r < 5; r++) {\r\n lines[r] += \" \" + (art[r] ?? \"\");\r\n }\r\n }\r\n // 左右各留 6 格间距\r\n const pad = 6;\r\n return lines.map((l) => \" \".repeat(pad) + l);\r\n}\r\n\r\nfunction hexToRgb(hex: string): string {\r\n const r = parseInt(hex.slice(1, 3), 16);\r\n const g = parseInt(hex.slice(3, 5), 16);\r\n const b = parseInt(hex.slice(5, 7), 16);\r\n return `${r};${g};${b}`;\r\n}\r\n\r\n// ─── 200 个常见单词 ────────────────────────────────────────────\r\n\r\nconst WORDS_BANK = [\r\n // ── 框架 & 库 ──\r\n \"react\", \"vue\", \"next\", \"node\", \"axios\", \"express\", \"lodash\", \"jquery\",\r\n \"webpack\", \"vite\", \"babel\", \"eslint\", \"prettier\", \"tailwind\", \"bootstrap\",\r\n \"sass\", \"less\", \"postcss\", \"redux\", \"pinia\", \"vuex\", \"router\",\r\n \"nestjs\", \"socket\", \"graphql\", \"rest\", \"grpc\", \"prisma\", \"typeorm\",\r\n\r\n // ── 前端 ──\r\n \"html\", \"css\", \"jsx\", \"tsx\", \"dom\", \"spa\", \"ssr\", \"csr\", \"pwa\",\r\n \"component\", \"prop\", \"hook\", \"composable\", \"directive\", \"filter\", \"mixin\",\r\n \"template\", \"render\", \"virtual\", \"diff\", \"patch\", \"hydration\",\r\n \"responsive\", \"flexbox\", \"grid\", \"animation\", \"transition\",\r\n\r\n // ── 后端 ──\r\n \"api\", \"route\", \"middleware\", \"controller\", \"service\", \"module\",\r\n \"dto\", \"entity\", \"schema\", \"migration\", \"seeder\", \"factory\",\r\n \"auth\", \"jwt\", \"oauth\", \"session\", \"cookie\", \"token\", \"cors\",\r\n \"cache\", \"redis\", \"mq\", \"rabbit\", \"kafka\", \"nats\",\r\n\r\n // ── 数据库 ──\r\n \"sql\", \"mysql\", \"pg\", \"sqlite\", \"mongo\", \"redis\", \"orm\",\r\n \"table\", \"index\", \"query\", \"join\", \"union\", \"group\", \"order\",\r\n \"where\", \"having\", \"limit\", \"offset\", \"insert\", \"update\", \"delete\",\r\n\r\n // ── DevOps ──\r\n \"docker\", \"nginx\", \"linux\", \"bash\", \"shell\", \"yaml\", \"toml\",\r\n \"ci\", \"cd\", \"deploy\", \"rollback\", \"release\", \"build\", \"test\",\r\n \"lint\", \"format\", \"stage\", \"commit\", \"branch\", \"merge\", \"rebase\",\r\n\r\n // ── 数据结构 & 算法 ──\r\n \"array\", \"stack\", \"queue\", \"tree\", \"graph\", \"list\", \"map\", \"set\",\r\n \"sort\", \"search\", \"filter\", \"reduce\", \"map\", \"async\", \"await\",\r\n \"promise\", \"callback\", \"closure\", \"proxy\", \"reflect\", \"decorator\",\r\n\r\n // ── 常用操作 ──\r\n \"create\", \"read\", \"update\", \"delete\", \"crud\", \"parse\", \"stringify\",\r\n \"encode\", \"decode\", \"transform\", \"validate\", \"format\", \"parse\",\r\n \"upload\", \"download\", \"export\", \"import\", \"backup\", \"restore\",\r\n\r\n // ── 类型 & 变量 ──\r\n \"string\", \"number\", \"boolean\", \"object\", \"array\", \"tuple\", \"enum\",\r\n \"interface\", \"type\", \"class\", \"function\", \"method\", \"property\",\r\n \"public\", \"private\", \"static\", \"readonly\", \"optional\", \"abstract\",\r\n \"const\", \"let\", \"var\", \"void\", \"null\", \"undef\", \"never\", \"any\",\r\n\r\n // ── 补充 ──\r\n \"config\", \"logger\", \"monitor\", \"metric\", \"alert\", \"webhook\",\r\n \"endpoint\", \"payload\", \"header\", \"status\", \"timeout\", \"retry\",\r\n \"fallback\", \"circuit\", \"breaker\", \"throttle\", \"debounce\",\r\n \"scroll\", \"resize\", \"click\", \"hover\", \"focus\", \"blur\",\r\n];\r\n\r\nfunction randomWord(used: Set<string>): string {\r\n let w: string;\r\n do { w = WORDS_BANK[Math.floor(Math.random() * WORDS_BANK.length)] as string; }\r\n while (used.has(w));\r\n return w;\r\n}\r\n\r\n// ─── 游戏状态 ──────────────────────────────────────────────────\r\n\r\ninterface DropWord {\r\n text: string;\r\n row: number;\r\n col: number;\r\n}\r\n\r\ninterface GameState {\r\n words: DropWord[];\r\n score: number;\r\n lives: number;\r\n speed: number;\r\n spawnTimer: number;\r\n gameOver: boolean;\r\n paused: boolean;\r\n typed: string;\r\n target: string | null;\r\n combo: number;\r\n message: string;\r\n messageTimer: number;\r\n usedWords: Set<string>;\r\n}\r\n\r\nfunction createInitialState(): GameState {\r\n return {\r\n words: [],\r\n score: 0,\r\n lives: 3,\r\n speed: 0.3,\r\n spawnTimer: 0,\r\n gameOver: false,\r\n paused: false,\r\n typed: \"\",\r\n target: null,\r\n combo: 0,\r\n message: \"\",\r\n messageTimer: 0,\r\n usedWords: new Set(),\r\n };\r\n}\r\n\r\nfunction pickTarget(s: GameState): string | null {\r\n // 选取最靠左的存活单词作为目标\r\n let best: DropWord | null = null;\r\n for (const w of s.words) {\r\n if (!best || w.col < best.col) best = w;\r\n }\r\n return best?.text ?? null;\r\n}\r\n\r\n// ─── 物理更新 ──────────────────────────────────────────────────\r\n\r\nfunction update(s: GameState): void {\r\n if (s.paused || s.gameOver) return;\r\n\r\n // 生成新单词\r\n s.spawnTimer++;\r\n if (s.spawnTimer >= Math.max(20, 50 - Math.floor(s.speed * 15))) {\r\n s.spawnTimer = 0;\r\n if (s.words.length < MAX_WORDS) {\r\n const used = new Set(s.usedWords);\r\n for (const w of s.words) used.add(w.text);\r\n const text = randomWord(used);\r\n // 找空白行\r\n const usedRows = new Set(s.words.map((w) => w.row));\r\n let row = -1;\r\n for (let r = SCORE_H; r < GAME_H; r++) {\r\n if (!usedRows.has(r)) { row = r; break; }\r\n }\r\n if (row >= 0) {\r\n s.words.push({ text, row, col: GAME_W - 1 });\r\n s.usedWords.add(text);\r\n }\r\n }\r\n }\r\n\r\n // 移动单词\r\n for (const w of s.words) {\r\n w.col -= s.speed;\r\n }\r\n\r\n // 移除超出左边的 + 更新目标\r\n const before = s.words.length;\r\n s.words = s.words.filter((w) => w.col > -w.text.length);\r\n const removed = before - s.words.length;\r\n\r\n // 单词漏掉了 → 扣命\r\n if (removed > 0) {\r\n s.lives -= removed;\r\n s.typed = \"\";\r\n s.target = pickTarget(s);\r\n if (s.lives <= 0) {\r\n s.gameOver = true;\r\n s.words = [];\r\n }\r\n }\r\n\r\n // 更新目标\r\n s.target = pickTarget(s);\r\n\r\n // 消息计时\r\n if (s.messageTimer > 0) {\r\n s.messageTimer--;\r\n if (s.messageTimer <= 0) s.message = \"\";\r\n }\r\n}\r\n\r\n// ─── 画面渲染 ──────────────────────────────────────────────────\r\n\r\nfunction buildGameView(s: GameState, scoreLines: string[], scoreColor: string, message: string): string[] {\r\n const rows: string[] = [];\r\n\r\n for (let y = 0; y < GAME_H; y++) {\r\n let line = \"\";\r\n\r\n // 分数区域(前 6 行)\r\n if (y < SCORE_H) {\r\n if (y < 5) {\r\n // 数字行 — 先补足宽度再套赛博朋克色\r\n const raw = (scoreLines[y] ?? \"\").padEnd(GAME_W);\r\n line = `\\x1b[38;2;${hexToRgb(scoreColor)}m${raw}\\x1b[0m`;\r\n } else if (y === 5) {\r\n // 第 6 行:连击 / 暂停\r\n if (s.combo >= 3) {\r\n const comboText = `${s.combo}连击!`;\r\n const pad = Math.floor((GAME_W - comboText.length) / 2);\r\n const comboColor = CYBER_PALETTE[s.combo % CYBER_PALETTE.length] as string;\r\n const raw = \" \".repeat(pad) + comboText + \" \".repeat(GAME_W - pad - comboText.length);\r\n line = `\\x1b[38;2;${hexToRgb(comboColor)}m${raw}\\x1b[0m`;\r\n } else if (s.paused) {\r\n const pauseText = \"暂停\";\r\n const pad = Math.floor((GAME_W - pauseText.length) / 2);\r\n line = \" \".repeat(pad) + pauseText;\r\n line = line.padEnd(GAME_W);\r\n }\r\n }\r\n // 补全到 GAME_W 宽度\r\n line = line.padEnd(GAME_W);\r\n } else {\r\n // 单词区域\r\n // 第 1 行显示消息(如果有)\r\n if (y === SCORE_H && message) {\r\n const pad = Math.floor((GAME_W - message.length) / 2);\r\n const raw = \" \".repeat(pad) + message + \" \".repeat(GAME_W - pad - message.length);\r\n const msgColor = CYBER_PALETTE[Math.floor(Math.random() * CYBER_PALETTE.length)] as string;\r\n line = `\\x1b[38;2;${hexToRgb(msgColor)}m${raw}\\x1b[0m`;\r\n } else {\r\n for (let x = 0; x < GAME_W; x++) {\r\n const word = s.words.find((w) => {\r\n const charIdx = x - Math.floor(w.col);\r\n return charIdx >= 0 && charIdx < w.text.length && w.row === y;\r\n });\r\n if (word) {\r\n const charIdx = x - Math.floor(word.col);\r\n const ch = word.text[charIdx] as string;\r\n const isTarget = word.text === s.target;\r\n const typedIdx = s.target === word.text ? s.typed.length : 0;\r\n const isTyped = isTarget && charIdx < typedIdx;\r\n if (isTarget) {\r\n line += isTyped ? `\\x1b[92m${ch}\\x1b[0m` : `\\x1b[97m${ch}\\x1b[0m`;\r\n } else {\r\n line += `\\x1b[90m${ch}\\x1b[0m`;\r\n }\r\n } else {\r\n line += \" \";\r\n }\r\n }\r\n }\r\n }\r\n\r\n rows.push(line);\r\n }\r\n return rows;\r\n}\r\n\r\n// ─── Ink 组件 ──────────────────────────────────────────────────\r\n\r\ninterface CoderCheckProps {\r\n onExit: () => void;\r\n}\r\n\r\nfunction CoderCheck({ onExit: _onExit }: CoderCheckProps) {\r\n const stateRef = useRef<GameState>(createInitialState());\r\n const [tick, setTick] = useState(0);\r\n const [colorOffset, setColorOffset] = useState(0);\r\n const onExitRef = useRef(_onExit);\r\n onExitRef.current = _onExit;\r\n\r\n // 赛博朋克颜色动画\r\n useEffect(() => {\r\n const timer = setInterval(() => {\r\n setColorOffset((prev) => (prev + 1) % CYBER_PALETTE.length);\r\n }, 400);\r\n return () => clearInterval(timer);\r\n }, []);\r\n\r\n // 游戏循环\r\n useEffect(() => {\r\n const interval = setInterval(() => {\r\n update(stateRef.current);\r\n setTick((t) => t + 1);\r\n }, 60);\r\n return () => clearInterval(interval);\r\n }, []);\r\n\r\n useInput(\r\n useCallback((input, key) => {\r\n const s = stateRef.current;\r\n if (s.gameOver) {\r\n if (input === \"r\") {\r\n stateRef.current = createInitialState();\r\n setTick(0);\r\n } else if (input === \"q\" || key.escape) {\r\n onExitRef.current();\r\n }\r\n return;\r\n }\r\n\r\n if ((input === \"p\" && key.ctrl) || input === \" \") {\r\n s.paused = !s.paused;\r\n return;\r\n }\r\n if ((input === \"q\" && key.ctrl) || key.escape) {\r\n onExitRef.current();\r\n return;\r\n }\r\n\r\n if (s.paused) return;\r\n\r\n // 打字输入\r\n if (input.length === 1 && input >= \"a\" && input <= \"z\") {\r\n // 选取目标\r\n if (!s.target) {\r\n s.target = pickTarget(s);\r\n }\r\n if (s.target) {\r\n const nextChar = s.target[s.typed.length];\r\n if (nextChar === input) {\r\n s.typed += input;\r\n // 检查是否完成\r\n if (s.typed === s.target) {\r\n // 移除该单词\r\n s.words = s.words.filter((w) => w.text !== s.target);\r\n s.combo++;\r\n // 连击 >= 3 时以当前分数翻倍奖励\r\n const prevScore = s.score;\r\n const basePts = s.target.length;\r\n const comboBonus = s.combo >= 3 ? s.score : 0;\r\n s.score += basePts + comboBonus;\r\n s.speed = s.speed + 0.02;\r\n\r\n // 每 500 分提速\r\n const prevMilestone = Math.floor(prevScore / 500);\r\n const newMilestone = Math.floor(s.score / 500);\r\n if (newMilestone > prevMilestone) {\r\n s.speed += 0.15;\r\n }\r\n\r\n // 超过 99999 分提示通关\r\n if (s.score >= 100000 && prevScore < 100000) {\r\n s.message = \"恭喜通关! 难度最大化!\";\r\n s.messageTimer = 100;\r\n }\r\n s.typed = \"\";\r\n s.target = pickTarget(s);\r\n }\r\n } else {\r\n // 打错字符,连击中断\r\n s.combo = 0;\r\n }\r\n }\r\n }\r\n }, []),\r\n );\r\n\r\n const s = stateRef.current;\r\n const scoreColor = CYBER_PALETTE[colorOffset] as string;\r\n const scoreStr = String(s.score).padStart(5, \"0\");\r\n const scoreLines = buildScoreLines(scoreStr);\r\n const view = buildGameView(s, scoreLines, scoreColor, s.message);\r\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\r\n void tick;\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingX={1}>\r\n {/* 顶栏:生命 + 速度 */}\r\n <Box flexDirection=\"row\">\r\n <Text>\r\n 生命 <Text color=\"red\">{\"♥\".repeat(Math.max(0, s.lives))}</Text>\r\n {\" \"}速度 <Text color=\"cyan\">Lv.{Math.floor(s.speed * 10)}</Text>\r\n </Text>\r\n </Box>\r\n\r\n {/* 目标单词提示 */}\r\n {!s.gameOver && s.target && (\r\n <Box marginTop={1}>\r\n <Text>\r\n 打字: <Text color=\"green\">{s.typed}</Text>\r\n <Text color=\"white\">{s.target.slice(s.typed.length)}</Text>\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* 游戏画面(含分数) */}\r\n <Box flexDirection=\"column\" marginTop={1}>\r\n <Text>┌{\"─\".repeat(GAME_W)}┐</Text>\r\n {view.map((row, i) => (\r\n <Text key={i}>{`│${row}│`}</Text>\r\n ))}\r\n <Text>└{\"─\".repeat(GAME_W)}┘</Text>\r\n </Box>\r\n\r\n {/* 游戏结束 */}\r\n {s.gameOver && (\r\n <Box marginTop={1}>\r\n <Text bold color=\"red\">\r\n 游戏结束!\r\n </Text>\r\n <Text>\r\n {\" 得分: \"}<Text color=\"yellow\">{s.score}</Text>\r\n {\" r 重开 q 退出\"}\r\n </Text>\r\n </Box>\r\n )}\r\n\r\n {/* 操作提示 */}\r\n <Box marginTop={1}>\r\n <Text dimColor>\r\n {\"打字消除单词 空格/Ctrl+P暂停 Ctrl+Q退出\"}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n\r\n// ─── 导出 ──────────────────────────────────────────────────────\r\n\r\nexport default {\r\n id: \"coder-check\",\r\n name: \"Coder Check\",\r\n description: \"极速打字游戏,输入单词消除它们!\",\r\n play: async () => {\r\n await new Promise<void>((resolve) => {\r\n const { unmount } = render(\r\n <CoderCheck onExit={() => { unmount(); resolve(); }} />,\r\n );\r\n });\r\n },\r\n};\r\n","import { registerGame, listGames } from \"./index.js\";\r\nimport type { Game } from \"./index.js\";\r\nimport brickBreaker from \"./brick-breaker/index.js\";\r\nimport coderCheck from \"./coder-check/index.js\";\r\n\r\n/** 在此注册所有游戏 */\r\nexport function initGames(): Game[] {\r\n registerGame(brickBreaker);\r\n registerGame(coderCheck);\r\n return listGames();\r\n}\r\n","import { Box, Text, useInput } from \"ink\";\r\nimport { useState, useCallback, useEffect } from \"react\";\r\nimport asciichart from \"asciichart\";\r\nimport type { StockRow } from \"./types.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// 分时数据接口\r\n// ---------------------------------------------------------------------------\r\n\r\nconst MINUTE_API = \"https://web.ifzq.gtimg.cn/appstock/app/minute/query?code={code}&r=0.1\";\r\n\r\ninterface MinuteResponse {\r\n code: number;\r\n data?: Record<string, {\r\n data?: { data?: string[]; date?: string };\r\n qt?: Record<string, (string | string[])[]>;\r\n }>;\r\n}\r\n\r\n/** 把股票代码转为接口需要的格式(如 513090 → sh513090) */\r\nfunction toApiCode(code: string): string {\r\n // 已带市场前缀,直接返回\r\n if (/^sh|^sz/.test(code)) return code;\r\n if (/^60/.test(code) || /^68/.test(code)) return \"sh\" + code;\r\n if (/^00/.test(code) || /^30/.test(code) || /^39/.test(code)) return \"sz\" + code;\r\n if (/^51/.test(code)) return \"sh\" + code;\r\n return \"sh\" + code;\r\n}\r\n\r\n/**\r\n * 调用分时接口获取某只股票的全天分钟数据。\r\n * 返回 { prices: 每分钟价格数组, quote: 实时行情快照, date: 日期 }\r\n */\r\nasync function fetchStockMinute(code: string): Promise<{\r\n prices: number[];\r\n quote: StockRow | null;\r\n date: string;\r\n} | null> {\r\n const url = MINUTE_API.replace(\"{code}\", toApiCode(code));\r\n try {\r\n const resp = await fetch(url);\r\n const json = (await resp.json()) as MinuteResponse;\r\n if (json.code !== 0) return null;\r\n\r\n const stockKey = toApiCode(code);\r\n const stockData = json.data?.[stockKey];\r\n if (!stockData) return null;\r\n\r\n // 1. 分钟行情 — 用于折线图\r\n const rawMinutes = stockData.data?.data ?? [];\r\n const prices: number[] = [];\r\n for (const line of rawMinutes) {\r\n // 格式: \"HHMM price volume amount\"\r\n const parts = (line as string).split(\" \");\r\n if (parts.length >= 2) {\r\n const p = parseFloat(parts[1]!);\r\n if (!isNaN(p)) prices.push(p);\r\n }\r\n }\r\n\r\n // 2. 实时行情快照 — 用于列表\r\n const qtKey = stockKey;\r\n const qt = stockData.qt?.[qtKey] as string[] | undefined;\r\n let quote: StockRow | null = null;\r\n if (qt && qt.length >= 35) {\r\n quote = {\r\n code,\r\n name: qt[1] ?? \"\",\r\n price: parseFloat(qt[3] ?? \"0\"),\r\n changePercent: parseFloat(qt[32] ?? \"0\"),\r\n changeAmount: parseFloat(qt[31] ?? \"0\"),\r\n high: parseFloat(qt[33] ?? \"0\"),\r\n low: parseFloat(qt[34] ?? \"0\"),\r\n volume: parseInt(qt[6] ?? \"0\", 10),\r\n };\r\n }\r\n\r\n return {\r\n prices,\r\n quote,\r\n date: stockData.data?.date ?? \"\",\r\n };\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 缓存\r\n// ---------------------------------------------------------------------------\r\n\r\n/** 缓存各股票的分钟价格数据,key = 股票代码 */\r\nconst minuteCache = new Map<string, number[]>();\r\n\r\nfunction cacheMinute(code: string, prices: number[]): void {\r\n minuteCache.set(code, prices);\r\n}\r\n\r\nfunction getCachedMinutes(code: string): number[] | undefined {\r\n return minuteCache.get(code);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 演示兜底数据\r\n// ---------------------------------------------------------------------------\r\n\r\nconst FALLBACK_STOCKS: StockRow[] = [\r\n { code: \"000001\", name: \"上证指数\", price: 3150.00, changePercent: 0.35, changeAmount: 11.02, high: 3160.00, low: 3140.00, volume: 285430000 },\r\n { code: \"399006\", name: \"创业板指\", price: 1820.00, changePercent: -0.52, changeAmount: -9.50, high: 1835.00, low: 1815.00, volume: 98650000 },\r\n { code: \"601688\", name: \"华泰证券\", price: 14.25, changePercent: 1.05, changeAmount: 0.15, high: 14.38, low: 14.10, volume: 452100 },\r\n];\r\n\r\n// ---------------------------------------------------------------------------\r\n// fetchStocks — 加载列表数据\r\n// ---------------------------------------------------------------------------\r\n\r\nasync function fetchStocks(codes: string[]): Promise<StockRow[]> {\r\n const results = await Promise.all(\r\n codes.map(async (code) => {\r\n const data = await fetchStockMinute(code);\r\n if (data?.quote) {\r\n // 同时缓存分钟数据,进详情就不用再请求了\r\n if (data.prices.length > 0) cacheMinute(code, data.prices);\r\n return data.quote;\r\n }\r\n return null;\r\n }),\r\n );\r\n\r\n // 用真实数据替换,缺失的用兜底\r\n const real: StockRow[] = results.filter((r): r is StockRow => r !== null);\r\n if (real.length > 0) return real;\r\n\r\n // 全都没取到?用兜底数据\r\n return FALLBACK_STOCKS;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 格式化工具\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction formatPrice(p: number): string {\r\n return p >= 100 ? p.toFixed(2) : p.toFixed(3);\r\n}\r\n\r\nfunction formatVolume(v: number): string {\r\n if (v >= 10000) return (v / 10000).toFixed(1) + \"万\";\r\n return v.toLocaleString();\r\n}\r\n\r\n/**\r\n * 取最新 maxPoints 个点,用于绘制折线图。\r\n * 分时数据从 09:30 累积到当前时间,取尾部最新的 60 点\r\n * 能展示最近的行情走势,同时适配终端宽度。\r\n */\r\nfunction latestPoints(data: number[], maxPoints = 60): number[] {\r\n if (data.length <= maxPoints) return data;\r\n return data.slice(data.length - maxPoints);\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// StockList 组件\r\n// ---------------------------------------------------------------------------\r\n\r\ninterface StockListProps {\r\n /** 自选股代码列表 */\r\n codes?: string[];\r\n onExit: () => void;\r\n}\r\n\r\nexport function StockList({ codes, onExit }: StockListProps) {\r\n const [stocks, setStocks] = useState<StockRow[]>([]);\r\n const [selectedIndex, setSelectedIndex] = useState(0);\r\n const [loading, setLoading] = useState(true);\r\n const [lastUpdate, setLastUpdate] = useState<string>(\"\");\r\n const [detailView, setDetailView] = useState<StockRow | null>(null);\r\n const [detailPrices, setDetailPrices] = useState<number[] | null>(null);\r\n const [detailLoading, setDetailLoading] = useState(false);\r\n const [detailCountdown, setDetailCountdown] = useState(10);\r\n const [countdown, setCountdown] = useState(5);\r\n\r\n // ---------- 数据加载 ----------\r\n const loadData = useCallback(async () => {\r\n setLoading(true);\r\n try {\r\n const data = await fetchStocks(codes ?? []);\r\n setStocks(data);\r\n setLastUpdate(new Date().toLocaleTimeString());\r\n } catch {\r\n // 保持旧数据\r\n }\r\n setLoading(false);\r\n }, [codes]);\r\n\r\n // 首次加载\r\n useEffect(() => {\r\n loadData();\r\n }, [loadData]);\r\n\r\n // 5 秒自动刷新 + 倒计时\r\n useEffect(() => {\r\n const interval = setInterval(() => {\r\n setCountdown((prev) => {\r\n if (prev <= 1) {\r\n loadData();\r\n return 5;\r\n }\r\n return prev - 1;\r\n });\r\n }, 1000);\r\n return () => clearInterval(interval);\r\n }, [loadData]);\r\n\r\n // ---------- 进入详情时加载分钟数据,每 30s 自动刷新 ----------\r\n useEffect(() => {\r\n if (!detailView) {\r\n setDetailPrices(null);\r\n setDetailLoading(false);\r\n return;\r\n }\r\n\r\n const loadDetail = () => {\r\n // 清除缓存,强制走网络\r\n minuteCache.delete(detailView.code);\r\n fetchStockMinute(detailView.code).then((data) => {\r\n if (data && data.prices.length > 0) {\r\n cacheMinute(detailView.code, data.prices);\r\n setDetailPrices(data.prices);\r\n }\r\n });\r\n };\r\n\r\n // 立即加载\r\n loadDetail();\r\n\r\n // 重置倒计时\r\n setDetailCountdown(10);\r\n\r\n // 每 10 秒刷新\r\n const timer = setInterval(loadDetail, 10000);\r\n return () => clearInterval(timer);\r\n }, [detailView]);\r\n\r\n // 详情页倒计时\r\n useEffect(() => {\r\n if (!detailView) return;\r\n const timer = setInterval(() => {\r\n setDetailCountdown((prev) => (prev > 0 ? prev - 1 : 10));\r\n }, 1000);\r\n return () => clearInterval(timer);\r\n }, [detailView]);\r\n\r\n // ---------- 键盘控制 ----------\r\n useInput(\r\n useCallback(\r\n (input, key) => {\r\n if (detailView) {\r\n // 详情模式下按 Esc/q 返回列表\r\n if (key.escape || input === \"q\" || input === \" \") {\r\n setDetailView(null);\r\n }\r\n return;\r\n }\r\n\r\n if (stocks.length === 0) return;\r\n\r\n if (key.upArrow || input === \"k\") {\r\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : stocks.length - 1));\r\n } else if (key.downArrow || input === \"j\") {\r\n setSelectedIndex((prev) => (prev < stocks.length - 1 ? prev + 1 : 0));\r\n } else if (key.return) {\r\n const stock = stocks[selectedIndex];\r\n if (stock) setDetailView(stock);\r\n } else if (key.escape || input === \"q\") {\r\n onExit();\r\n } else if (input === \"r\") {\r\n setCountdown(5);\r\n loadData();\r\n }\r\n },\r\n [stocks, selectedIndex, detailView, onExit, loadData],\r\n ),\r\n );\r\n\r\n // ---------- 详情视图 ----------\r\n if (detailView) {\r\n if (detailLoading) {\r\n return (\r\n <Box paddingLeft={1}>\r\n <Text dimColor>{\" ⟳ 加载分时数据...\"}</Text>\r\n </Box>\r\n );\r\n }\r\n return renderDetail(detailView, () => setDetailView(null), detailPrices ?? undefined, detailCountdown);\r\n }\r\n\r\n // ---------- 列表视图 ----------\r\n return (\r\n <Box flexDirection=\"column\">\r\n {/* 顶部状态栏 */}\r\n <Box marginBottom={1} justifyContent=\"space-between\">\r\n <Text bold color=\"#00ffff\">\r\n {\" 📈 自选股监控\"}\r\n </Text>\r\n <Text dimColor>\r\n {loading ? \" ⟳ 刷新中...\" : ` 每 ${countdown}s 自动刷新`}\r\n </Text>\r\n </Box>\r\n\r\n {/* 表头 */}\r\n <Box>\r\n <Box width={3} />\r\n <Box width={9}>\r\n <Text dimColor>代码</Text>\r\n </Box>\r\n <Box width={16}>\r\n <Text dimColor>名称</Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text dimColor>最新价</Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text dimColor>涨跌幅</Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text dimColor>涨跌额</Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text dimColor>最高</Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text dimColor>最低</Text>\r\n </Box>\r\n <Box>\r\n <Text dimColor>成交量</Text>\r\n </Box>\r\n </Box>\r\n\r\n {/* 分隔线 */}\r\n <Box>\r\n <Text dimColor>{\" \" + \"─\".repeat(100)}</Text>\r\n </Box>\r\n\r\n {/* 股票列表 */}\r\n <Box flexDirection=\"column\">\r\n {stocks.map((stock, index) => {\r\n const isSelected = index === selectedIndex;\r\n const isUp = stock.changePercent >= 0;\r\n const color = isUp ? \"#ff1493\" : \"#00ff41\";\r\n\r\n return (\r\n <Box key={stock.code}>\r\n <Box width={3} flexShrink={0}>\r\n {isSelected ? (\r\n <Text bold color=\"#00ffff\">\r\n {\"▸ \"}\r\n </Text>\r\n ) : (\r\n <Text>{\" \"}</Text>\r\n )}\r\n </Box>\r\n <Box width={9}>\r\n <Text bold color={isSelected ? \"#00ffff\" : \"#ffffff\"}>\r\n {stock.code}\r\n </Text>\r\n </Box>\r\n <Box width={16}>\r\n <Text color={isSelected ? \"#ffffff\" : \"#cccccc\"}>\r\n {stock.name}\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text bold color={color}>\r\n {formatPrice(stock.price)}\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text color={color}>\r\n {isUp ? \"+\" : \"\"}{stock.changePercent.toFixed(2)}%\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text color={color}>\r\n {isUp ? \"+\" : \"\"}{stock.changeAmount.toFixed(3)}\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text color=\"#cccccc\">\r\n {formatPrice(stock.high)}\r\n </Text>\r\n </Box>\r\n <Box width={12}>\r\n <Text color=\"#cccccc\">\r\n {formatPrice(stock.low)}\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text color=\"#888888\">\r\n {formatVolume(stock.volume)}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n })}\r\n </Box>\r\n\r\n {/* 底栏 */}\r\n <Box marginTop={1}>\r\n <Text dimColor>\r\n {` ↑/↓ 选择 Enter 详情 r 手动刷新 q 返回`}\r\n </Text>\r\n </Box>\r\n <Box>\r\n <Text dimColor>\r\n {` 最后更新: ${lastUpdate}`}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// 详情视图(独立的渲染函数)\r\n// ---------------------------------------------------------------------------\r\n\r\nfunction renderDetail(stock: StockRow, _onBack: () => void, prices?: number[], countdown = 10) {\r\n const isUp = stock.changePercent >= 0;\r\n const colorCode = isUp ? \"#ff1493\" : \"#00ff41\";\r\n const arrow = isUp ? \"▲\" : \"▼\";\r\n\r\n // 折线图\r\n let chartLines: string[] = [];\r\n if (prices && prices.length > 0) {\r\n const chartColor = isUp ? asciichart.red : asciichart.green;\r\n // 取最新 60 条分时数据展示近期走势\r\n const latest = latestPoints(prices, 60);\r\n let raw = asciichart.plot(latest, {\r\n height: 10,\r\n colors: [chartColor],\r\n });\r\n // 弯角 → 直角,折线更硬朗\r\n raw = raw\r\n .replaceAll(\"╭\", \"┌\")\r\n .replaceAll(\"╮\", \"┐\")\r\n .replaceAll(\"╰\", \"└\")\r\n .replaceAll(\"╯\", \"┘\");\r\n chartLines = raw.split(\"\\n\");\r\n }\r\n\r\n return (\r\n <Box flexDirection=\"column\" paddingLeft={1}>\r\n {/* 标题行 — 左:名称代码,右:刷新倒计时 */}\r\n <Box marginBottom={1} justifyContent=\"space-between\">\r\n <Box>\r\n <Text bold color=\"#00ffff\">\r\n {\" 📊 \"}{stock.name}{\" \"}\r\n </Text>\r\n <Text dimColor>\r\n {stock.code}\r\n </Text>\r\n </Box>\r\n <Text dimColor>\r\n {`每 ${countdown}s 刷新`}\r\n </Text>\r\n </Box>\r\n\r\n {/* 价格摘要 */}\r\n <Box>\r\n <Box width={16}>\r\n <Text bold color=\"#888888\">当前价</Text>\r\n </Box>\r\n <Box>\r\n <Text bold color={colorCode}>\r\n {arrow} {formatPrice(stock.price)}\r\n </Text>\r\n </Box>\r\n </Box>\r\n <Box>\r\n <Box width={16}>\r\n <Text color=\"#888888\">涨跌幅</Text>\r\n </Box>\r\n <Box>\r\n <Text color={colorCode}>\r\n {isUp ? \"+\" : \"\"}{stock.changePercent.toFixed(2)}%\r\n {\" \"}\r\n {isUp ? \"+\" : \"\"}{stock.changeAmount.toFixed(3)}\r\n </Text>\r\n </Box>\r\n </Box>\r\n\r\n {/* 折线图 */}\r\n {chartLines.length > 0 && (\r\n <Box marginTop={1} flexDirection=\"column\">\r\n {chartLines.map((line, i) => (\r\n <Box key={i}>\r\n <Text color={colorCode}>\r\n {line || \" \"}\r\n </Text>\r\n </Box>\r\n ))}\r\n </Box>\r\n )}\r\n\r\n {/* 底部 */}\r\n <Box marginTop={1}>\r\n <Text dimColor>\r\n {\" Space/q 返回列表\"}\r\n </Text>\r\n </Box>\r\n </Box>\r\n );\r\n}\r\n","/** dskcode 退出码规范 */\r\nexport const ExitCode = {\r\n /** 正常执行完成 */\r\n SUCCESS: 0,\r\n /** 通用错误 */\r\n GENERAL_ERROR: 1,\r\n /** 配置错误 */\r\n CONFIG_ERROR: 2,\r\n /** 用户通过 Ctrl+C 中断 */\r\n SIGINT: 130,\r\n} as const;\r\n","#!/usr/bin/env node\r\n\r\nimport { createCli } from \"./cli/index.js\";\r\nimport { ExitCode } from \"./cli/exit-codes.js\";\r\n\r\nprocess.on(\"SIGINT\", () => {\r\n process.exit(ExitCode.SIGINT);\r\n});\r\n\r\nconst program = createCli();\r\n\r\ntry {\r\n await program.parseAsync(process.argv);\r\n} catch (err: unknown) {\r\n const error = err as { exitCode?: number; code?: string };\r\n\r\n if (error.code === \"commander.helpDisplayed\" || error.code === \"commander.version\") {\r\n process.exit(error.exitCode ?? ExitCode.SUCCESS);\r\n }\r\n\r\n if (typeof error.exitCode === \"number\") {\r\n process.exit(error.exitCode);\r\n }\r\n\r\n console.error(String(err));\r\n process.exit(ExitCode.GENERAL_ERROR);\r\n}\r\n"],"mappings":"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","names":["program","chalk","Text","jsxs","Box","Text","jsx","Box","Text","useEffect","useState","jsx","jsxs","Box","Text","useState","useCallback","jsx","jsxs","Box","Text","useInput","render","useState","useEffect","useCallback","jsx","jsxs","s","Box","Text","useInput","render","useState","useEffect","useRef","useCallback","jsx","jsxs","CYBER_PALETTE","createInitialState","update","useRef","useState","useEffect","useInput","useCallback","s","jsxs","Box","jsx","Text","render","render","chalk","Box","Text","useInput","useState","useCallback","useEffect","jsx","jsxs","useState","useCallback","useEffect","useInput","jsx","Box","Text","jsxs","jsx","program","chalk","render"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dskcode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/Awu12277/deepseek-agent-cli/tree/main"
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"prepublishOnly": "npm run build && npm run test"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
+
"asciichart": "^1.5.25",
|
|
38
39
|
"chalk": "^5.6.2",
|
|
39
40
|
"commander": "^13.1.0",
|
|
40
41
|
"ink": "^7.1.0",
|