dskcode 0.1.5 → 0.1.7
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 +576 -128
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
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/useDoubleCtrlC.ts","../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 type { DskcodeContext } 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 DskcodeContext | 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 startChat(ctx);\r\n });\r\n\r\n function startChat(\r\n ctx: DskcodeContext | undefined,\r\n ) {\r\n const chatApp = 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 onLaunchGame={() => {\r\n chatApp.unmount();\r\n setImmediate(() => {\r\n initGames();\r\n const games = listGames();\r\n const { unmount } = render(\r\n <GamePicker\r\n games={games}\r\n onSelect={async (game: Game) => {\r\n unmount();\r\n await game.play();\r\n // 游戏结束后返回对话\r\n startChat(ctx);\r\n }}\r\n onBackToChat={() => {\r\n unmount();\r\n setImmediate(() => startChat(ctx));\r\n }}\r\n />,\r\n { exitOnCtrlC: false },\r\n );\r\n });\r\n }}\r\n onLaunchStock={() => {\r\n chatApp.unmount();\r\n setImmediate(() => {\r\n // 使用配置中的自选股列表或兜底默认值\r\n const defaultStockCodes = ctx?.config.stock?.symbols?.map((s) => s.code)\r\n ?? [\"sh000001\", \"sz399006\", \"sh601688\"];\r\n const stockApp = renderApp(\r\n <StockList\r\n codes={defaultStockCodes}\r\n onBackToChat={() => {\r\n stockApp.unmount();\r\n setImmediate(() => startChat(ctx));\r\n }}\r\n onExit={() => process.exit(0)}\r\n />,\r\n );\r\n });\r\n }}\r\n />,\r\n );\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 ctx = (this as unknown as Record<string, unknown>).dskcodeCtx as DskcodeContext | undefined;\r\n const codeList = codes && codes.length > 0\r\n ? codes\r\n : ctx?.config.stock?.symbols?.map((s) => s.code)\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 { exitOnCtrlC: false },\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\n * 目前暂未使用,保留以备 plugin 配置 URL 校验时使用。\r\n */\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\n */\r\nfunction applyEnvVars(config: Config): Config {\r\n // 浅拷贝以避免修改原始对象\r\n const result: Config = { ...config, providers: [...config.providers] };\r\n\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 switch (configKey) {\r\n case \"verbose\":\r\n case \"defaultProvider\": {\r\n (result as unknown as Record<string, unknown>)[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 (result as unknown as Record<string, unknown>)[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 (result as unknown as Record<string, unknown>)[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 deepseekIdx = result.providers.findIndex((p) => p.name === \"deepseek\");\r\n if (deepseekIdx !== -1) {\r\n const existing = result.providers[deepseekIdx]!;\r\n if (!existing.apiKey) {\r\n result.providers[deepseekIdx] = { ...existing, apiKey };\r\n }\r\n } else {\r\n // 如果没有 deepseek provider,自动创建一个\r\n result.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 result;\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\n */\r\nexport function applyCliOverrides(config: Config, flags: CliFlags): Config {\r\n const result: Config = { ...config, providers: [...config.providers] };\r\n\r\n if (flags.verbose !== undefined) {\r\n result.verbose = flags.verbose;\r\n }\r\n if (flags.model !== undefined) {\r\n // 将 --model 的值映射为标准 model 名称\r\n // 如果用户指定了 --model,覆盖 defaultProvider 中配置的 model\r\n const providerIdx = result.providers.findIndex(\r\n (p) => p.name === result.defaultProvider,\r\n );\r\n if (providerIdx !== -1) {\r\n result.providers[providerIdx] = {\r\n ...result.providers[providerIdx]!,\r\n model: flags.model,\r\n };\r\n }\r\n }\r\n if (flags.maxTokens !== undefined && flags.maxTokens > 0) {\r\n result.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 result.temperature = flags.temperature;\r\n }\r\n return result;\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. maxTokens 范围校验\r\n if (config.maxTokens !== undefined && config.maxTokens < 1) {\r\n errors.push({\r\n field: \"maxTokens\",\r\n message: \"maxTokens 必须大于等于 1。\",\r\n });\r\n }\r\n\r\n // 6. 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(() => {\r\n void (async () => {\r\n try {\r\n const config = await loadConfig(configPath);\r\n callback(config);\r\n } catch {\r\n // 重载失败时不回调,等待下一次变更\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 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: { 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 * API Key 最小长度校验值。\r\n * DeepSeek 的 Key 通常以 sk- 开头,长度远超 10 位。\r\n */\r\nconst MIN_API_KEY_LENGTH = 10;\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(chalk.yellow(\"\\n ⚠ 未检测到 API Key 配置\"));\r\n console.log(chalk.dim(\" 你可以通过以下任一方式配置:\"));\r\n console.log(chalk.dim(\" · 环境变量: export DEEPSEEK_API_KEY=sk-xxx\"));\r\n console.log(chalk.dim(\" · 配置文件: ~/.dskcode/settings.json\"));\r\n console.log(chalk.dim(\" · 下面直接输入,自动保存到全局配置\\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 let resolved = false;\r\n\r\n const cleanup = () => {\r\n if (resolved) return;\r\n resolved = true;\r\n process.stdin.removeListener(\"keypress\", onKeypress);\r\n rl.close();\r\n };\r\n\r\n const onKeypress = (_: unknown, key: { ctrl?: boolean; name?: string }) => {\r\n if (key.ctrl && key.name === \"c\") {\r\n cleanup();\r\n resolve(null);\r\n }\r\n };\r\n\r\n process.stdin.on(\"keypress\", onKeypress);\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 < MIN_API_KEY_LENGTH) {\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 // exitOnCtrlC: false — 让组件自行处理 Ctrl+C(双击退出)\r\n const { waitUntilExit, clear, unmount } = render(node, { exitOnCtrlC: false });\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\n/** 赛博朋克调色板 — 多处组件复用 */\r\nexport const CYBER_PALETTE = [\"#00ffff\", \"#ff00ff\", \"#00ff41\", \"#ff1493\", \"#8b00ff\"] as const;\r\n\r\n/** ASCII LOGO 行 — 多处组件复用 */\r\nexport const LOGO_LINES = [\r\n \" ██████╗ ███████╗██╗ ██╗\",\r\n \" ██╔══██╗██╔════╝██║ ██╔╝\",\r\n \" ██║ ██║███████╗█████╔╝ \",\r\n \" ██║ ██║╚════██║██╔═██╗ \",\r\n \" ██████╔╝███████║██║ ██╗\",\r\n \" ╚═════╝ ╚══════╝╚═╝ ╚═╝\",\r\n] as const;\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, useInput } from \"ink\";\r\nimport TextInput from \"ink-text-input\";\r\nimport { useEffect, useState, useCallback } from \"react\";\r\nimport { useDoubleCtrlC } from \"./useDoubleCtrlC.js\";\r\nimport { CYBER_PALETTE, LOGO_LINES } from \"./DskcodeSplash.js\";\r\n\r\n/** 命令处理结果的类型,支持文本响应和动作跳转 */\r\nexport type CommandAction =\r\n | { kind: \"text\"; content: string }\r\n | { kind: \"exit\" }\r\n | { kind: \"clear\" }\r\n | { kind: \"navigate\"; target: \"game\" | \"stock\" };\r\n\r\nexport interface ChatCommand {\r\n desc: string;\r\n handler: () => CommandAction;\r\n}\r\n\r\n/** 命令注册表,支持动态注册新命令 */\r\nconst commandRegistry = new Map<string, ChatCommand>();\r\n\r\n/** 注册一个命令 */\r\nexport function registerCommand(name: string, cmd: ChatCommand): void {\r\n commandRegistry.set(name, cmd);\r\n}\r\n\r\n/** 获取所有已注册命令(用于 /help 生成帮助文本) */\r\nfunction getRegisteredCommands(): Map<string, ChatCommand> {\r\n return commandRegistry;\r\n}\r\n\r\n// 注册内置命令\r\nregisterCommand(\"/exit\", { desc: \"退出对话\", handler: () => ({ kind: \"exit\" }) });\r\nregisterCommand(\"/quit\", { desc: \"退出对话\", handler: () => ({ kind: \"exit\" }) });\r\nregisterCommand(\"/help\", {\r\n desc: \"显示帮助信息\",\r\n handler: () => {\r\n const commands = getRegisteredCommands();\r\n const lines = [\"可用命令:\"];\r\n for (const [name, cmd] of commands) {\r\n lines.push(` ${name.padEnd(16)}${cmd.desc}`);\r\n }\r\n return { kind: \"text\", content: lines.join(\"\\n\") };\r\n },\r\n});\r\nregisterCommand(\"/clear\", { desc: \"清空对话历史\", handler: () => ({ kind: \"clear\" }) });\r\nregisterCommand(\"/version\", { desc: \"显示版本信息\", handler: () => ({ kind: \"text\", content: \"dskcode v0.0.0\" }) });\r\nregisterCommand(\"/game\", { desc: \"启动游戏\", handler: () => ({ kind: \"navigate\", target: \"game\" }) });\r\nregisterCommand(\"/stock\", { desc: \"查看股票行情\", handler: () => ({ kind: \"navigate\", target: \"stock\" }) });\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 onLaunchGame?: () => void;\r\n onLaunchStock?: () => void;\r\n}\r\n\r\nexport function ChatSession({ providerCount, toolCount, verbose, onLaunchGame, onLaunchStock }: 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 const { doubleCtrlC, handleCtrlC } = useDoubleCtrlC(() => process.exit(0));\r\n\r\n // 捕获 Ctrl+C,启用\"双击退出\"交互\r\n useInput(\r\n useCallback(\r\n (input, key) => {\r\n if (input === \"c\" && key.ctrl) {\r\n handleCtrlC();\r\n }\r\n },\r\n [handleCtrlC],\r\n ),\r\n );\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 = commandRegistry.get(trimmed.toLowerCase());\r\n if (cmd) {\r\n const result = cmd.handler();\r\n\r\n switch (result.kind) {\r\n case \"exit\":\r\n process.exit(0);\r\n return;\r\n case \"clear\":\r\n setMessages([]);\r\n setInput(\"\");\r\n return;\r\n case \"navigate\":\r\n setInput(\"\");\r\n if (result.target === \"game\") {\r\n onLaunchGame?.();\r\n } else if (result.target === \"stock\") {\r\n onLaunchStock?.();\r\n }\r\n return;\r\n case \"text\":\r\n setMessages((prev) => [\r\n ...prev,\r\n { role: \"user\", content: trimmed },\r\n { role: \"assistant\", content: result.content },\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: `未知命令:${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 }, [onLaunchGame, onLaunchStock]);\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\r\n {/* 双击 Ctrl+C 退出提示 */}\r\n {doubleCtrlC && (\r\n <Box marginTop={1}>\r\n <Text color=\"#ff1493\" bold>\r\n {\" ⚠ 再按一次 Ctrl+C 退出 dskcode\"}\r\n </Text>\r\n </Box>\r\n )}\r\n </Box>\r\n );\r\n}\r\n","import { useState, useCallback, useEffect, useRef } from \"react\";\r\n\r\nconst CTRL_C_TIMEOUT_MS = 1500;\r\n\r\n/**\r\n * 提供\"双击 Ctrl+C 才退出\"的交互逻辑。\r\n *\r\n * - 第一次 Ctrl+C:设置提示状态,1.5 秒后自动重置\r\n * - 第二次 Ctrl+C(1.5 秒内):执行 onExit 回调\r\n *\r\n * 返回 { doubleCtrlC, handleCtrlC },组件通过 useInput 捕获\r\n * Ctrl+C 后调用 handleCtrlC,并根据 doubleCtrlC 显示提示。\r\n */\r\nexport function useDoubleCtrlC(onExit: () => void) {\r\n const [doubleCtrlC, setDoubleCtrlC] = useState(false);\r\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\r\n const onExitRef = useRef(onExit);\r\n onExitRef.current = onExit;\r\n\r\n // 组件卸载时清理定时器\r\n useEffect(() => {\r\n return () => {\r\n if (timerRef.current) clearTimeout(timerRef.current);\r\n };\r\n }, []);\r\n\r\n const handleCtrlC = useCallback(() => {\r\n if (doubleCtrlC) {\r\n // 第二次 Ctrl+C → 退出\r\n onExitRef.current();\r\n return;\r\n }\r\n\r\n // 第一次 Ctrl+C → 显示提示,启动倒计时重置\r\n setDoubleCtrlC(true);\r\n if (timerRef.current) clearTimeout(timerRef.current);\r\n timerRef.current = setTimeout(() => {\r\n setDoubleCtrlC(false);\r\n timerRef.current = null;\r\n }, CTRL_C_TIMEOUT_MS);\r\n }, [doubleCtrlC]);\r\n\r\n return { doubleCtrlC, handleCtrlC };\r\n}","import { Box, Text, useInput } from \"ink\";\r\nimport { useState, useCallback } from \"react\";\r\nimport type { Game } from \"../game/index.js\";\r\nimport { useDoubleCtrlC } from \"../ui/useDoubleCtrlC.js\";\r\n\r\ninterface GamePickerProps {\r\n games: Game[];\r\n onSelect: (game: Game) => void;\r\n onExit?: () => void;\r\n onBackToChat?: () => void;\r\n}\r\n\r\nexport function GamePicker({ games, onSelect, onExit, onBackToChat }: GamePickerProps) {\r\n const [selectedIndex, setSelectedIndex] = useState(0);\r\n\r\n const exitAction = onBackToChat ?? onExit ?? (() => process.exit(0));\r\n const { doubleCtrlC, handleCtrlC } = useDoubleCtrlC(exitAction);\r\n\r\n useInput(\r\n useCallback(\r\n (input, key) => {\r\n // Ctrl+C:双击退出\r\n if (input === \"c\" && key.ctrl) {\r\n handleCtrlC();\r\n return;\r\n }\r\n\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 if (onBackToChat) onBackToChat();\r\n else onExit?.();\r\n }\r\n },\r\n [games, selectedIndex, onSelect, onExit, onBackToChat, handleCtrlC],\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\r\n {/* 双击 Ctrl+C 退出提示 */}\r\n {doubleCtrlC && (\r\n <Box marginTop={1}>\r\n <Text color=\"#ff1493\" bold>\r\n {\" ⚠ 再按一次 Ctrl+C 退出 dskcode\"}\r\n </Text>\r\n </Box>\r\n )}\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\nimport { useDoubleCtrlC } from \"../ui/useDoubleCtrlC.js\";\r\n\r\n// ---------------------------------------------------------------------------\r\n// 分时数据接口\r\n// ---------------------------------------------------------------------------\r\n\r\n/** API 接口地址模板 */\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 normalizeApiCode(code: string): string {\r\n if (code.startsWith(\"sh\") || code.startsWith(\"sz\")) return code;\r\n if (/^60|^68|^51/.test(code)) return \"sh\" + code;\r\n if (/^00|^30|^39/.test(code)) return \"sz\" + 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}\", normalizeApiCode(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 = normalizeApiCode(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\n/** 仅用于测试环境重置缓存 */\r\nexport function _clearMinuteCache(): void {\r\n minuteCache.clear();\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 /** 按 q 时退出 */\r\n onExit: () => void;\r\n /** 按 q 时返回上级(从 chat 内跳转时使用) */\r\n onBackToChat?: () => void;\r\n}\r\n\r\nexport function StockList({ codes, onExit, onBackToChat }: 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 const { doubleCtrlC, handleCtrlC } = useDoubleCtrlC(onExit);\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 // Ctrl+C:双击退出\r\n if (input === \"c\" && key.ctrl) {\r\n handleCtrlC();\r\n return;\r\n }\r\n\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 if (onBackToChat) onBackToChat();\r\n else onExit();\r\n } else if (input === \"r\") {\r\n setCountdown(5);\r\n loadData();\r\n }\r\n },\r\n [stocks, selectedIndex, detailView, onExit, onBackToChat, loadData, handleCtrlC],\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\r\n {/* 双击 Ctrl+C 退出提示 */}\r\n {doubleCtrlC && (\r\n <Box marginTop={1}>\r\n <Text color=\"#ff1493\" bold>\r\n {\" ⚠ 再按一次 Ctrl+C 退出 dskcode\"}\r\n </Text>\r\n </Box>\r\n )}\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\n/**\r\n * 双击 Ctrl+C 退出:\r\n * 第一次 SIGINT → 提示用户再按一次\r\n * 第二次 SIGINT(1.5 秒内)→ 立即退出\r\n *\r\n * 在 ink 交互模式下,Ctrl+C 由 useInput 捕获处理,\r\n * 此处只处理 ink 未运行时的 SIGINT(如启动阶段)。\r\n */\r\nlet sigintCount = 0;\r\nlet sigintTimer: ReturnType<typeof setTimeout> | null = null;\r\n\r\n/**\r\n * 全局兜底 SIGINT 处理:双击退出。\r\n * ink 交互模式下 Ctrl+C 由 useDoubleCtrlC hook 处理,\r\n * 此处仅处理 ink 未运行时的场景(如启动阶段、异常退出后)。\r\n */\r\nprocess.on(\"SIGINT\", () => {\r\n sigintCount++;\r\n if (sigintCount >= 2) {\r\n process.exit(ExitCode.SIGINT);\r\n }\r\n process.stdout.write(\"\\n ⚠ 再按一次 Ctrl+C 退出 dskcode\\n\");\r\n if (sigintTimer) clearTimeout(sigintTimer);\r\n sigintTimer = setTimeout(() => {\r\n sigintCount = 0;\r\n }, 1500);\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","useCallback","useState","useEffect","jsx","jsxs","useState","useCallback","input","useEffect","Box","Text","Box","Text","useInput","useState","useCallback","jsx","jsxs","useState","useInput","useCallback","Box","Text","Box","Text","useInput","render","useState","useEffect","useRef","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"]}
|