@24klynx/cli 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{config-Des0z-k9.mjs → config-Braj-aBw.mjs} +3 -3
- package/dist/config-Braj-aBw.mjs.map +1 -0
- package/dist/config-D9DbomLt.mjs +2 -0
- package/dist/context-BmZ8VEan.mjs.map +1 -1
- package/dist/{env-CeeZcoDI.mjs → env-jKIO_4zX.mjs} +2 -2
- package/dist/env-jKIO_4zX.mjs.map +1 -0
- package/dist/{headless-launcher-I8NWyD6k.mjs → headless-launcher-CnSrw3bm.mjs} +4 -4
- package/dist/headless-launcher-CnSrw3bm.mjs.map +1 -0
- package/dist/index.d.mts +8 -8
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +12 -10
- package/dist/index.mjs.map +1 -1
- package/dist/{process-lifecycle-Dg6n2QS-.mjs → process-lifecycle-kdV53L3o.mjs} +9 -9
- package/dist/process-lifecycle-kdV53L3o.mjs.map +1 -0
- package/package.json +10 -10
- package/dist/config-D-xVXTXi.mjs +0 -2
- package/dist/config-Des0z-k9.mjs.map +0 -1
- package/dist/env-CeeZcoDI.mjs.map +0 -1
- package/dist/headless-launcher-I8NWyD6k.mjs.map +0 -1
- package/dist/process-lifecycle-Dg6n2QS-.mjs.map +0 -1
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["httpsRequest","loadSessionMessages","getMostRecentSessionId","truncate","blockToMarkdown","formatSessionAsMarkdown","loadSessionMessages","getMostRecentSessionId","getMostRecentSessionId"],"sources":["../src/args.ts","../src/catalog.ts","../src/debug.ts","../src/doctor/runner.ts","../src/crestodian/runner.ts","../src/commands/session.ts","../src/entry.ts","../src/memory-monitor.ts","../src/update-check.ts","../src/snapshot-store.ts","../src/tui-launcher.ts","../src/worker-pool.ts","../src/commands/plugin.ts","../src/commands/git-commit.ts","../src/commands/git-review.ts","../src/commands/git-pr-comments.ts","../src/commands/git-issue.ts","../src/commands/git-autofix.ts","../src/commands/git-diff.ts","../src/commands/ant-trace.ts","../src/commands/debug-tool-call.ts","../src/commands/tasks.ts","../src/commands/heapdump.ts","../src/commands/perf-issue.ts","../src/commands/share.ts","../src/commands/export.ts","../src/commands/tag.ts","../src/commands/copy.ts"],"sourcesContent":["/**\n * CLI argument parsing — commander setup with all sub‑commands.\n *\n * Each command defers its handler to a lazily‑loaded module\n * so startup remains fast (Phase 1 ≤ 1.5s).\n */\n\nimport { Command } from \"commander\";\n\n// ── Public API ───────────────────────────────────────\n\n/** Create the full CLI program with all sub‑commands registered. */\nexport function createProgram(): Command {\n const program = new Command();\n\n program.name(\"lynx\").description(\"AI CLI — 多渠道 Agent 网关\").version(\"0.0.0\");\n\n // ── Sub‑commands ──────────────────────────────────\n\n // doctor — system health check\n program\n .command(\"doctor\")\n .description(\"运行系统健康检查\")\n .action(async () => {\n const { runDoctor } = await import(\"./doctor/runner.js\");\n await runDoctor();\n });\n\n // crestodian — non‑interactive LLM query\n program\n .command(\"crestodian\")\n .description(\"非交互式 LLM 查询\")\n .requiredOption(\"--message <text>\", \"要发送的消息\")\n .option(\"--model <model>\", \"要使用的模型\")\n .action(async (opts) => {\n const { runCrestodian } = await import(\"./crestodian/runner.js\");\n await runCrestodian(opts.message, opts.model);\n });\n\n // session — list/resume/fork sessions\n program\n .command(\"sessions\")\n .description(\"列出、恢复或派生会话\")\n .option(\"--action <action>\", \"list | resume <id> | fork <id> | delete <id>\", \"list\")\n .option(\"--id <id>\", \"Session ID for resume/fork/delete\")\n .option(\"--label <label>\", \"New label for fork\")\n .action(async (opts) => {\n const { handleSessionCommand } = await import(\"./commands/session.js\");\n await handleSessionCommand(opts);\n });\n\n // config — show/set configuration\n program\n .command(\"config\")\n .description(\"显示或设置配置项\")\n .option(\"--show\", \"Show current configuration\")\n .option(\"--set <key>\", \"Set a configuration key\")\n .option(\"--value <value>\", \"Value for --set\")\n .option(\"--path\", \"Show config file path\")\n .action(async (opts) => {\n const { handleConfigCommand } = await import(\"./commands/config.js\");\n await handleConfigCommand(opts);\n });\n\n // start — launch in headless background mode (no TUI)\n program\n .command(\"start\")\n .description(\"以无头后台模式启动(无 TUI)\")\n .option(\"--headless\", \"以无头模式运行(守护进程模式必需)\")\n .option(\"--feishu-app-id <id>\", \"飞书 App ID(覆盖 FEISHU_APP_ID 环境变量)\")\n .option(\"--feishu-app-secret <secret>\", \"飞书 App Secret(覆盖 FEISHU_APP_SECRET 环境变量)\")\n .option(\"--model <model>\", \"要使用的模型\")\n .option(\"--verbose\", \"启用详细日志\")\n .action(async (opts) => {\n if (!opts.headless) {\n process.stderr.write(\"错误:'lynx start' 需要 --headless 参数。\\n\");\n process.stderr.write(\"用法:lynx start --headless [--verbose]\\n\");\n process.exitCode = 1;\n return;\n }\n const { startHeadless } = await import(\"./headless-launcher.js\");\n const feishu =\n opts.feishuAppId && opts.feishuAppSecret\n ? { appId: opts.feishuAppId, appSecret: opts.feishuAppSecret }\n : undefined;\n await startHeadless({\n model: opts.model,\n verbose: opts.verbose,\n feishu,\n });\n });\n\n // plugin — manage plugins (list/enable/disable/install/remove)\n program\n .command(\"plugin\")\n .description(\"管理插件(列出、启用、禁用、安装、移除)\")\n .option(\"--list\", \"List installed plugins\")\n .option(\"--enable <name>\", \"Enable a plugin\")\n .option(\"--disable <name>\", \"Disable a plugin\")\n .option(\"--install <path>\", \"Install a plugin from a local path\")\n .option(\"--remove <name>\", \"Remove an installed plugin\")\n .action(async (opts) => {\n const { handlePluginCommand } = await import(\"./commands/plugin.js\");\n await handlePluginCommand(opts);\n });\n\n // share — 将会话导出为 Markdown 文件\n program\n .command(\"share\")\n .description(\"将会话导出为可分享的 Markdown 文件\")\n .option(\"--session-id <id>\", \"要导出的会话 ID(默认最近一次会话)\")\n .option(\"--output <path>\", \"输出文件路径\")\n .action(async (opts) => {\n const { handleShareCommand } = await import(\"./commands/share.js\");\n const result = await handleShareCommand(opts);\n process.stdout.write(`${result.output}\\n`);\n });\n\n // export — 多格式导出会话\n program\n .command(\"export\")\n .description(\"以多种格式导出会话(markdown / json / html)\")\n .option(\"--session-id <id>\", \"要导出的会话 ID(默认最近一次会话)\")\n .option(\"--format <fmt>\", \"输出格式:markdown、json 或 html\", \"markdown\")\n .option(\"--output <path>\", \"输出文件路径\")\n .action(async (opts) => {\n const { handleExportCommand } = await import(\"./commands/export.js\");\n const result = await handleExportCommand(opts);\n process.stdout.write(`${result.output}\\n`);\n });\n\n // tag — 会话标签管理\n program\n .command(\"tag\")\n .description(\"为会话添加、移除或列出标签\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认最近一次会话)\")\n .option(\"--tag <tag>\", \"标签内容\")\n .option(\"--action <action>\", \"操作:add、remove 或 list\", \"list\")\n .action(async (opts) => {\n const { handleTagCommand } = await import(\"./commands/tag.js\");\n const result = await handleTagCommand(opts);\n process.stdout.write(`${result.output}\\n`);\n });\n\n // copy — 复制助手回复到剪贴板\n program\n .command(\"copy\")\n .description(\"将最后一条助手回复复制到系统剪贴板\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认最近一次会话)\")\n .option(\"--index <n>\", \"从末尾倒数第几条消息(默认 0 = 最后一条)\", \"0\")\n .action(async (opts) => {\n const { handleCopyCommand } = await import(\"./commands/copy.js\");\n const result = await handleCopyCommand({\n sessionId: opts.sessionId,\n index: opts.index ? Number(opts.index) : 0,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // clear — 清空当前会话消息\n program\n .command(\"clear\")\n .description(\"清空当前会话消息,开始全新对话\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认当前会话)\")\n .action(async (opts) => {\n const { handleClearCommand } = await import(\"./commands/clear.js\");\n const result = handleClearCommand({ sessionId: opts.sessionId });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // env — 显示环境变量\n program\n .command(\"env\")\n .description(\"显示 Lynx 环境变量和运行环境信息\")\n .action(async () => {\n const { handleEnvCommand } = await import(\"./commands/env.js\");\n const result = handleEnvCommand();\n process.stdout.write(`${result.output}\\n`);\n });\n\n // context — IDE 连接状态\n program\n .command(\"context\")\n .description(\"显示 IDE 连接状态和活跃文件信息\")\n .action(async () => {\n const { handleContextCommand } = await import(\"./commands/context.js\");\n const result = handleContextCommand();\n process.stdout.write(`${result.output}\\n`);\n });\n\n // context-viz — 上下文窗口可视化\n program\n .command(\"context-viz\")\n .description(\"可视化当前上下文窗口的 token 使用情况\")\n .action(async () => {\n const { handleContextVizCommand } = await import(\"./commands/context-viz.js\");\n const result = handleContextVizCommand();\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // stats — 会话统计\n program\n .command(\"stats\")\n .description(\"会话统计信息(token 消耗、工具调用频率等)\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认当前会话)\")\n .option(\"--period <period>\", \"统计时间范围:today、week 或 all\", \"all\")\n .action(async (opts) => {\n const { handleStatsCommand } = await import(\"./commands/stats.js\");\n const result = handleStatsCommand({\n sessionId: opts.sessionId,\n period: opts.period,\n });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // status — 系统健康仪表盘\n program\n .command(\"status\")\n .description(\"系统健康仪表盘(MCP、Channel、Agent、磁盘等)\")\n .action(async () => {\n const { handleStatusCommand } = await import(\"./commands/status.js\");\n const result = handleStatusCommand();\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // bughunter — 只读诊断模式\n program\n .command(\"bughunter\")\n .description(\"只读诊断模式,系统排查问题并给出修复建议\")\n .option(\"--issue <text>\", \"具体的问题描述或错误消息\")\n .action(async (opts) => {\n const { handleBughunterCommand } = await import(\"./commands/bughunter.js\");\n const result = handleBughunterCommand({ issue: opts.issue });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // upgrade — 自助升级\n program\n .command(\"upgrade\")\n .description(\"自助升级 Lynx 到最新版本\")\n .option(\"--check\", \"仅检查依赖更新,不执行升级\")\n .option(\"--version <ver>\", \"指定目标版本(暂未实现)\")\n .action(async (opts) => {\n const { handleUpgradeCommand } = await import(\"./commands/upgrade.js\");\n const result = handleUpgradeCommand({\n check: opts.check,\n version: opts.version,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // sandbox-toggle — 切换沙箱模式\n program\n .command(\"sandbox-toggle\")\n .description(\"切换 Bash 沙箱模式开关(启用 / 禁用)\")\n .option(\"--enable\", \"强制启用沙箱\")\n .option(\"--disable\", \"强制禁用沙箱\")\n .action(async (opts) => {\n const { handleSandboxToggleCommand } = await import(\"./commands/sandbox-toggle.js\");\n const result = handleSandboxToggleCommand({\n enable: opts.enable,\n disable: opts.disable,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // privacy — 隐私设置\n program\n .command(\"privacy\")\n .description(\"隐私设置面板(允许列表、禁止列表、分析共享)\")\n .option(\"--show\", \"显示当前隐私设置\")\n .option(\"--allow <domain>\", \"将域名添加到允许列表\")\n .option(\"--deny <domain>\", \"将域名添加到禁止列表\")\n .action(async (opts) => {\n const { handlePrivacyCommand } = await import(\"./commands/privacy.js\");\n const result = handlePrivacyCommand({\n show: opts.show,\n allow: opts.allow,\n deny: opts.deny,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // branch — Git 分支管理\n program\n .command(\"branch\")\n .description(\"管理 Git 分支:列出、创建、切换、删除\")\n .option(\"--action <action>\", \"操作类型:list、create、switch 或 delete\", \"list\")\n .option(\"--name <name>\", \"分支名称(create / switch / delete 时必填)\")\n .option(\"--base <base>\", \"创建分支时的基准分支(仅 create 时有效)\")\n .action(async (opts) => {\n const { handleBranchCommand } = await import(\"./commands/git-branch.js\");\n const result = handleBranchCommand({\n action: opts.action,\n name: opts.name,\n base: opts.base,\n });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // memory — 记忆管理\n program\n .command(\"memory\")\n .description(\"记忆管理 — 列出、搜索、添加、删除、去重、导出记忆\")\n .option(\"--action <action>\", \"操作:list(默认)、search、add、delete、compact、export\", \"list\")\n .option(\"--query <query>\", \"搜索查询词或条目名称\")\n .option(\"--name <name>\", \"条目名称(用于 add/delete)\")\n .action(async (opts) => {\n const { handleMemoryCommand } = await import(\"./commands/memory.js\");\n const result = handleMemoryCommand({\n action: opts.action,\n query: opts.query,\n name: opts.name,\n });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // break-cache — 清除缓存\n program\n .command(\"break-cache\")\n .description(\"清除指定缓存(prompt / transcript / tool / all)\")\n .option(\"--cache <type>\", \"缓存类型:prompt、transcript、tool 或 all\", \"all\")\n .action(async (opts) => {\n const { handleBreakCacheCommand } = await import(\"./commands/break-cache.js\");\n const result = await handleBreakCacheCommand({ cache: opts.cache });\n process.stdout.write(`${result.output}\\n`);\n });\n\n return program;\n}\n\n/** Parse argv and run the matching command. */\nexport async function runCli(argv: string[] = process.argv): Promise<void> {\n const program = createProgram();\n await program.parseAsync(argv);\n}\n","/**\n * CommandCatalog — structured command registration with\n * per‑command policy (permission mode, tool visibility, etc.).\n *\n * Each command is registered with a name, handler, and a set\n * of policies that control how the agent behaves while executing\n * that command.\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CommandPolicy {\n /** Permission mode for this command. */\n permissionMode: \"default\" | \"auto\" | \"yolo\" | \"headless\" | \"plan\";\n /** Which tools are visible when this command runs. */\n allowedTools?: string[];\n /** Can this command modify files? */\n allowWrites: boolean;\n}\n\nexport interface CommandEntry {\n name: string;\n description: string;\n policy: CommandPolicy;\n /** Lazily‑loaded handler module path. */\n handlerPath: string;\n}\n\n// ── Built‑in policy defaults ─────────────────────────\n\nconst READONLY: CommandPolicy = {\n permissionMode: \"default\",\n allowWrites: false,\n};\n\nconst FULL_ACCESS: CommandPolicy = {\n permissionMode: \"auto\",\n allowWrites: true,\n};\n\n// ── Catalog ──────────────────────────────────────────\n\n/** The master list of registered commands. */\nexport const CATALOG: CommandEntry[] = [\n {\n name: \"doctor\",\n description: \"Run system health checks\",\n policy: READONLY,\n handlerPath: \"./doctor/runner.js\",\n },\n {\n name: \"crestodian\",\n description: \"Non‑interactive LLM query\",\n policy: { ...READONLY, permissionMode: \"headless\" },\n handlerPath: \"./crestodian/runner.js\",\n },\n {\n name: \"sessions\",\n description: \"List, resume, or fork sessions\",\n policy: { ...FULL_ACCESS, allowedTools: [] },\n handlerPath: \"./commands/session.js\",\n },\n {\n name: \"config\",\n description: \"Show or set configuration values\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/config.js\",\n },\n {\n name: \"plugin\",\n description: \"Manage installed plugins (list, install, remove, enable, disable)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/plugin.js\",\n },\n {\n name: \"sed\",\n description: \"在文件上进行正则查找替换\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"read_file\", \"write_file\"],\n allowWrites: true,\n },\n handlerPath: \"./commands/sed-edit.js\",\n },\n {\n name: \"commit\",\n description: \"创建 Git 提交并推送(约定式提交)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-commit.js\",\n },\n {\n name: \"branch\",\n description: \"管理 Git 分支:列出、创建、切换、删除\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-branch.js\",\n },\n {\n name: \"review\",\n description: \"审查 GitHub Pull Request 变更\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-review.js\",\n },\n {\n name: \"pr-comments\",\n description: \"处理 PR 审查评论(修改代码或回复确认)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-pr-comments.js\",\n },\n {\n name: \"issue\",\n description: \"管理 GitHub Issue(创建、列出、查看)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-issue.js\",\n },\n {\n name: \"autofix-pr\",\n description: \"自动修复 PR 问题(开发中)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-autofix.js\",\n },\n {\n name: \"diff\",\n description: \"展示 Git 工作区变更(未暂存和已暂存)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-diff.js\",\n },\n {\n name: \"ant-trace\",\n description: \"工具调用链追踪可视化\",\n policy: READONLY,\n handlerPath: \"./commands/ant-trace.js\",\n },\n {\n name: \"debug-tool-call\",\n description: \"单步工具调用调试器\",\n policy: READONLY,\n handlerPath: \"./commands/debug-tool-call.js\",\n },\n {\n name: \"tasks\",\n description: \"后台任务监视与控制(列出、取消、查看详情)\",\n policy: READONLY,\n handlerPath: \"./commands/tasks.js\",\n },\n {\n name: \"heapdump\",\n description: \"生成 V8 堆快照用于内存泄漏诊断\",\n policy: READONLY,\n handlerPath: \"./commands/heapdump.js\",\n },\n {\n name: \"memory\",\n description: \"记忆管理 — 列出、搜索、添加、删除、去重、导出记忆\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"memory_write\"],\n allowWrites: true,\n },\n handlerPath: \"./commands/memory.js\",\n },\n {\n name: \"break-cache\",\n description: \"清除指定缓存(prompt / transcript / tool / all)\",\n policy: READONLY,\n handlerPath: \"./commands/break-cache.js\",\n },\n {\n name: \"perf-issue\",\n description: \"性能问题诊断与健康检查\",\n policy: READONLY,\n handlerPath: \"./commands/perf-issue.js\",\n },\n {\n name: \"share\",\n description: \"将会话导出为可分享的 Markdown 文件\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/share.js\",\n },\n {\n name: \"export\",\n description: \"以多种格式导出会话(markdown / json / html)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/export.js\",\n },\n {\n name: \"tag\",\n description: \"为会话添加、移除或列出标签\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/tag.js\",\n },\n {\n name: \"copy\",\n description: \"将最后一条助手回复复制到系统剪贴板\",\n policy: READONLY,\n handlerPath: \"./commands/copy.js\",\n },\n {\n name: \"clear\",\n description: \"清空当前会话消息,开始全新对话\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [],\n allowWrites: false,\n },\n handlerPath: \"./commands/clear.js\",\n },\n {\n name: \"env\",\n description: \"显示 Lynx 环境变量和运行环境信息\",\n policy: READONLY,\n handlerPath: \"./commands/env.js\",\n },\n {\n name: \"context\",\n description: \"显示 IDE 连接状态和活跃文件信息\",\n policy: READONLY,\n handlerPath: \"./commands/context.js\",\n },\n {\n name: \"context-viz\",\n description: \"可视化当前上下文窗口的 token 使用情况\",\n policy: READONLY,\n handlerPath: \"./commands/context-viz.js\",\n },\n {\n name: \"stats\",\n description: \"会话统计信息(token 消耗、工具调用频率等)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [],\n allowWrites: false,\n },\n handlerPath: \"./commands/stats.js\",\n },\n {\n name: \"status\",\n description: \"系统健康仪表盘(MCP、Channel、Agent、磁盘等)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [],\n allowWrites: false,\n },\n handlerPath: \"./commands/status.js\",\n },\n {\n name: \"bughunter\",\n description: \"只读诊断模式,系统排查问题并给出修复建议\",\n policy: READONLY,\n handlerPath: \"./commands/bughunter.js\",\n },\n {\n name: \"upgrade\",\n description: \"自助升级 Lynx 到最新版本\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/upgrade.js\",\n },\n {\n name: \"sandbox-toggle\",\n description: \"切换 Bash 沙箱模式开关(启用 / 禁用)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/sandbox-toggle.js\",\n },\n {\n name: \"privacy-settings\",\n description: \"隐私设置面板(允许列表、禁止列表、分析共享)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/privacy.js\",\n },\n];\n\n/** Look up a command by name. */\nexport function findCommand(name: string): CommandEntry | undefined {\n return CATALOG.find((c) => c.name === name);\n}\n","/**\n * Debug logging infrastructure — writes structured JSONL logs\n * to disk for post‑mortem analysis.\n *\n * Uses pino for formatting and rotation. Production logs are\n * JSONL with daily rotation; development uses pino‑pretty.\n */\n\nimport { createWriteStream, existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n// ── Types ────────────────────────────────────────────\n\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport interface DebugLogger {\n trace(msg: string, data?: unknown): void;\n debug(msg: string, data?: unknown): void;\n info(msg: string, data?: unknown): void;\n warn(msg: string, data?: unknown): void;\n error(msg: string, data?: unknown): void;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n};\n\nfunction formatLine(level: LogLevel, msg: string, data?: unknown): string {\n const entry = {\n time: new Date().toISOString(),\n level,\n msg,\n ...(data !== undefined ? { data } : {}),\n };\n return JSON.stringify(entry);\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Create a file‑based debug logger.\n *\n * @param logDir Directory for log files (defaults to ~/.lynx/logs).\n * @param minLevel Minimum level to emit.\n */\nexport function createDebugLogger(logDir: string, minLevel: LogLevel = \"info\"): DebugLogger {\n if (!existsSync(logDir)) {\n mkdirSync(logDir, { recursive: true });\n }\n\n const logPath = join(logDir, `lynx-debug.jsonl`);\n const stream = createWriteStream(logPath, { flags: \"a\" });\n const minRank = LEVEL_ORDER[minLevel];\n\n function log(level: LogLevel, msg: string, data?: unknown): void {\n if (LEVEL_ORDER[level] < minRank) return;\n stream.write(formatLine(level, msg, data) + \"\\n\");\n }\n\n return {\n trace(msg, data) {\n log(\"trace\", msg, data);\n },\n debug(msg, data) {\n log(\"debug\", msg, data);\n },\n info(msg, data) {\n log(\"info\", msg, data);\n },\n warn(msg, data) {\n log(\"warn\", msg, data);\n },\n error(msg, data) {\n log(\"error\", msg, data);\n },\n };\n}\n","/**\n * Doctor — system health checks.\n *\n * Runs a series of diagnostic checks and prints a report.\n * Each check returns pass/fail with an optional detail message.\n */\n\nimport { existsSync, accessSync, mkdirSync, constants } from \"node:fs\";\nimport { resolvePaths, openDatabase, migrate } from \"@lynx/core\";\nimport { platform, release, cpus } from \"node:os\";\nimport { dirname } from \"node:path\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CheckResult {\n name: string;\n passed: boolean;\n detail?: string;\n}\n\nexport interface DoctorReport {\n checks: CheckResult[];\n allPassed: boolean;\n}\n\n// ── Checks ────────────────────────────────────────────\n\nfunction checkNodeVersion(): CheckResult {\n const version = process.version;\n const major = parseInt(version.slice(1).split(\".\")[0]!, 10);\n const passed = major >= 22;\n return {\n name: \"Node.js ≥ 22\",\n passed,\n detail: passed ? version : `${version} (need ≥ 22.19.0)`,\n };\n}\n\nfunction checkPlatform(): CheckResult {\n return {\n name: \"Platform support\",\n passed: true,\n detail: `${platform()} ${release()} (${cpus().length} CPUs)`,\n };\n}\n\nfunction checkHomeDir(): CheckResult {\n const paths = resolvePaths();\n let passed = existsSync(paths.home);\n if (!passed) {\n try {\n mkdirSync(paths.home, { recursive: true });\n passed = true;\n } catch {\n // Will report as failed below\n }\n }\n return {\n name: \"Home directory exists\",\n passed,\n detail: paths.home,\n };\n}\n\nfunction checkConfigDir(): CheckResult {\n const paths = resolvePaths();\n const configDir = dirname(paths.configFile);\n let passed = existsSync(configDir);\n if (!passed) {\n try {\n mkdirSync(configDir, { recursive: true });\n passed = true;\n } catch {\n // Will report as failed below\n }\n }\n return {\n name: \"Config directory exists\",\n passed,\n detail: configDir,\n };\n}\n\nfunction checkDataDir(): CheckResult {\n const paths = resolvePaths();\n const dataDir = dirname(paths.stateDb);\n try {\n if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true });\n accessSync(dataDir, constants.W_OK);\n return { name: \"Data directory writable\", passed: true, detail: dataDir };\n } catch {\n return { name: \"Data directory writable\", passed: false, detail: `Cannot write to ${dataDir}` };\n }\n}\n\nfunction checkDatabase(): CheckResult {\n try {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n migrate(db);\n const row = db.prepare(\"SELECT sqlite_version() as v\").get() as { v: string } | undefined;\n db.close();\n return { name: \"SQLite database\", passed: true, detail: `v${row?.v}` };\n } catch (err) {\n return {\n name: \"SQLite database\",\n passed: false,\n detail: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nfunction checkSessionsTable(): CheckResult {\n try {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n migrate(db);\n const count = db.prepare(\"SELECT COUNT(*) as c FROM sessions\").get() as\n | { c: number }\n | undefined;\n db.close();\n return { name: \"Sessions table\", passed: true, detail: `${count?.c ?? 0} sessions` };\n } catch (err) {\n return {\n name: \"Sessions table\",\n passed: false,\n detail: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\n/** All registered checks, in display order. */\nconst CHECKS: Array<() => CheckResult> = [\n checkNodeVersion,\n checkPlatform,\n checkHomeDir,\n checkConfigDir,\n checkDataDir,\n checkDatabase,\n checkSessionsTable,\n];\n\n// ── Public API ───────────────────────────────────────\n\n/** Run all health checks and return the report. */\nexport function runChecks(): DoctorReport {\n const checks: CheckResult[] = [];\n for (const fn of CHECKS) {\n checks.push(fn());\n }\n const allPassed = checks.every((c) => c.passed);\n return { checks, allPassed };\n}\n\n/** Print the doctor report to stdout. */\nexport function printReport(report: DoctorReport): void {\n for (const check of report.checks) {\n const icon = check.passed ? \"✓\" : \"✗\";\n process.stdout.write(`${icon} ${check.name}`);\n if (check.detail) {\n process.stdout.write(` (${check.detail})`);\n }\n process.stdout.write(\"\\n\");\n }\n\n process.stdout.write(\"\\n\");\n process.stdout.write(report.allPassed ? \"All checks passed.\\n\" : \"Some checks failed.\\n\");\n}\n\n/** Entry point for the `lynx doctor` command. */\nexport async function runDoctor(): Promise<void> {\n const report = runChecks();\n printReport(report);\n process.exitCode = report.allPassed ? 0 : 1;\n}\n","/**\n * Crestodian — non‑interactive LLM query mode.\n *\n * Takes a message from CLI args, sends it to the LLM provider,\n * and prints the response to stdout. No TUI, no interaction.\n *\n * This is the `node lynx.mjs crestodian --message \"...\"` path.\n */\n\nimport type { ChatMessage } from \"@lynx/llm\";\nimport { assembleSystemPrompt } from \"@lynx/agent\";\nimport { loadConfig, resolveConfigEnv, resolveProvider } from \"../commands/config.js\";\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Run a non‑interactive query against the LLM.\n *\n * Reads API keys from environment variables (DEEPSEEK_API_KEY\n * or OPENAI_API_KEY) and streams the response to stdout.\n */\nexport async function runCrestodian(message: string, _model?: string): Promise<void> {\n if (!message) {\n process.stderr.write(\"Error: --message is required\\n\");\n process.exitCode = 1;\n return;\n }\n\n // 加载配置 → 注入 env → 按模型名自动选 Provider\n const config = loadConfig();\n resolveConfigEnv(config);\n\n let provider;\n try {\n provider = resolveProvider(config);\n } catch (err) {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = 1;\n return;\n }\n\n const systemPrompt = assembleSystemPrompt(\n {\n model: config.model,\n systemPrompt: \"You are Lynx, an AI assistant. Be helpful and concise.\",\n maxTokens: 8192,\n maxCompactionFailures: 3,\n budget: { maxTokens: Infinity, maxUsd: Infinity, maxTurns: Infinity },\n provider,\n },\n /* visibleTools */ [],\n );\n\n const messages: ChatMessage[] = [{ role: \"user\", content: [{ type: \"text\", text: message }] }];\n const controller = new AbortController();\n\n try {\n const stream = provider.stream(\n \"deepseek-v4-pro\",\n messages,\n systemPrompt,\n [],\n controller.signal,\n );\n\n for await (const event of stream) {\n if (event.type === \"text_delta\") {\n process.stdout.write(event.text);\n }\n }\n process.stdout.write(\"\\n\");\n } catch (err) {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = 1;\n }\n}\n","/**\n * Session command — list, resume, fork, and delete sessions\n * from the command line.\n *\n * Uses SessionManager for persistence and SessionPicker for\n * interactive selection when no ID is provided.\n */\n\nimport { openDatabase, resolvePaths, asSessionId } from \"@lynx/core\";\nimport type { Message } from \"@lynx/core\";\nimport { createSessionManager } from \"@lynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface SessionCommandOptions {\n action: string;\n id?: string;\n label?: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** Print text content blocks from messages to stdout. */\nfunction printSessionText(messages: Message[]): void {\n for (const msg of messages) {\n for (const block of msg.content) {\n if (block.type === \"text\" && block.text) {\n process.stdout.write(block.text + \"\\n\");\n }\n }\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Handle the `lynx sessions` command. */\nexport async function handleSessionCommand(opts: SessionCommandOptions): Promise<void> {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n const mgr = createSessionManager(db);\n\n try {\n switch (opts.action) {\n case \"list\": {\n const sessions = mgr.list();\n if (sessions.length === 0) {\n process.stdout.write(\"No sessions found.\\n\");\n } else {\n for (const s of sessions) {\n const label = s.label ?? \"(untitled)\";\n const msgCount = s.messages.length;\n const updated = new Date(s.updatedAt).toISOString();\n process.stdout.write(`${s.id} ${label} ${msgCount} msgs ${updated}\\n`);\n }\n }\n break;\n }\n case \"resume\": {\n if (!opts.id) {\n process.stderr.write(\"Error: --id is required for resume\\n\");\n process.exitCode = 1;\n return;\n }\n const session = mgr.load(asSessionId(opts.id));\n if (!session) {\n process.stderr.write(`Session not found: ${opts.id}\\n`);\n process.exitCode = 1;\n return;\n }\n // Print session content to stdout for piping\n printSessionText(session.messages);\n break;\n }\n case \"fork\": {\n if (!opts.id) {\n process.stderr.write(\"Error: --id is required for fork\\n\");\n process.exitCode = 1;\n return;\n }\n const forked = mgr.fork(asSessionId(opts.id), opts.label);\n process.stdout.write(`Forked: ${forked.id}\\n`);\n break;\n }\n case \"delete\": {\n if (!opts.id) {\n process.stderr.write(\"Error: --id is required for delete\\n\");\n process.exitCode = 1;\n return;\n }\n mgr.delete(asSessionId(opts.id));\n process.stdout.write(`Deleted: ${opts.id}\\n`);\n break;\n }\n default:\n process.stderr.write(`Unknown action: ${opts.action}\\n`);\n process.exitCode = 1;\n }\n } finally {\n mgr.destroy();\n db.close();\n }\n}\n","/**\n * Unified entry point — the first code that runs after `lynx.mjs`.\n *\n * Responsibilities:\n * 1. Version check (bail early if Node.js < 22.19).\n * 2. Parse CLI args and route to the correct handler.\n * 3. For interactive mode: bootstrap services + launch TUI.\n * 4. For sub‑commands: lazily import the handler.\n *\n * This file intentionally avoids importing heavy modules\n * (Ink, provider implementations) at the top level so that\n * `lynx --version` returns in < 100 ms.\n */\n\n// ── Phase 0: Version guard ────────────────────────────\n\nfunction guardNodeVersion(): void {\n const v = process.version.slice(1).split(\".\").map(Number);\n const major = v[0]!;\n const minor = v[1] ?? 0;\n if (major < 22 || (major === 22 && minor < 19)) {\n process.stderr.write(`Lynx requires Node.js ≥ 22.19.0 (found ${process.version})\\n`);\n process.exit(1);\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Main entry point. Invoked from `lynx.mjs`. */\nexport async function main(argv: string[] = process.argv): Promise<void> {\n guardNodeVersion();\n\n const userArgs = argv.slice(2);\n\n // Flags that should route to the CLI parser, not TUI.\n const cliOnlyFlags = new Set([\"--help\", \"-h\", \"--version\", \"-V\"]);\n const hasCliFlag = userArgs.some((a) => cliOnlyFlags.has(a));\n\n // If no sub‑command is given and no CLI flags, launch the interactive TUI.\n const hasSubcommand = userArgs.some((a) => !a.startsWith(\"-\"));\n\n if (!hasSubcommand && !hasCliFlag) {\n const { launchTui } = await import(\"./tui-launcher.js\");\n await launchTui();\n return;\n }\n\n const { runCli } = await import(\"./args.js\");\n await runCli(argv);\n}\n","/**\n * MemoryMonitor — proactive heap sampling with three‑level alerting.\n *\n * Samples `process.memoryUsage().heapUsed` on a configurable interval\n * (default 30s) and fires alerts at user‑defined thresholds. Each alert\n * level triggers a distinct action: warn → GC hint, danger → compaction,\n * fatal → cache flush.\n *\n * Design (§5.9j):\n * - 30s heap sampling interval\n * - 3‑level alert:\n * 700 MB → warn: trigger GC + auto compact context\n * 900 MB → danger: force snip compaction\n * 950 MB → fatal: release all caches + notify user\n * - Uses global.gc() when available (requires --expose-gc)\n * - Emits structured events for integration with status bar\n */\n\nimport { EventEmitter } from \"node:events\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Alert severity levels. */\nexport type MemoryAlertLevel = \"warn\" | \"danger\" | \"fatal\";\n\n/** A memory alert event. */\nexport interface MemoryAlert {\n level: MemoryAlertLevel;\n /** Current heap usage in bytes. */\n heapUsed: number;\n /** Heap usage as percentage of configured threshold. */\n percentage: number;\n /** Threshold that was breached in bytes. */\n threshold: number;\n /** ISO timestamp of the sample. */\n timestamp: string;\n}\n\n/** Configuration for the memory monitor. */\nexport interface MemoryMonitorConfig {\n /** Sampling interval in ms. Default: 30_000. */\n intervalMs?: number;\n /** Warn threshold in bytes. Default: 700 * 1024 * 1024. */\n warnThreshold?: number;\n /** Danger threshold in bytes. Default: 900 * 1024 * 1024. */\n dangerThreshold?: number;\n /** Fatal threshold in bytes. Default: 950 * 1024 * 1024. */\n fatalThreshold?: number;\n}\n\n/** Current memory snapshot. */\nexport interface MemorySnapshot {\n heapUsed: number;\n heapTotal: number;\n external: number;\n rss: number;\n timestamp: string;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst MB = 1024 * 1024;\nconst DEFAULT_INTERVAL_MS = 30_000;\nconst DEFAULT_WARN_MB = 700;\nconst DEFAULT_DANGER_MB = 900;\nconst DEFAULT_FATAL_MB = 950;\n\n// ── MemoryMonitor ───────────────────────────────────\n\n/**\n * Proactive heap monitor with three‑level alerting.\n *\n * Usage:\n * ```ts\n * const monitor = new MemoryMonitor({ intervalMs: 30_000 });\n * monitor.on(\"alert\", (alert) => {\n * if (alert.level === \"fatal\") console.error(\"OOM imminent!\");\n * });\n * monitor.start();\n * ```\n */\nexport class MemoryMonitor extends EventEmitter {\n private config: Required<MemoryMonitorConfig>;\n private timer: ReturnType<typeof setInterval> | null = null;\n private running = false;\n\n /** Track the last alert level to avoid repeated warnings. */\n private lastAlertLevel: MemoryAlertLevel | null = null;\n\n constructor(config: MemoryMonitorConfig = {}) {\n super();\n this.config = {\n intervalMs: config.intervalMs ?? DEFAULT_INTERVAL_MS,\n warnThreshold: config.warnThreshold ?? DEFAULT_WARN_MB * MB,\n dangerThreshold: config.dangerThreshold ?? DEFAULT_DANGER_MB * MB,\n fatalThreshold: config.fatalThreshold ?? DEFAULT_FATAL_MB * MB,\n };\n }\n\n // ── Events — typed wrappers around EventEmitter.on ──\n\n /** Emitted when a memory alert is triggered. */\n onAlert(listener: (alert: MemoryAlert) => void): this {\n return super.on(\"alert\", listener);\n }\n\n /** Emitted on each sample (for dashboards). */\n onSample(listener: (snapshot: MemorySnapshot) => void): this {\n return super.on(\"sample\", listener);\n }\n\n /** Emitted when compaction is requested. */\n onCompact(listener: (info: { reason: string; heapUsed: number }) => void): this {\n return super.on(\"compact\", listener);\n }\n\n /** Emitted when caches should be flushed. */\n onFlushCaches(listener: (info: { reason: string; heapUsed: number }) => void): this {\n return super.on(\"flush_caches\", listener);\n }\n\n // ── Public API ──────────────────────────────────\n\n /** Start periodic heap sampling. No‑op if already running. */\n start(): void {\n if (this.running) return;\n this.running = true;\n\n // Take an immediate sample\n this.sample();\n\n this.timer = setInterval(() => {\n this.sample();\n }, this.config.intervalMs);\n this.timer.unref(); // Don't block process exit\n }\n\n /** Stop periodic sampling. */\n stop(): void {\n this.running = false;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.lastAlertLevel = null;\n }\n\n /** Take a manual snapshot and return it. */\n snapshot(): MemorySnapshot {\n const mem = process.memoryUsage();\n return {\n heapUsed: mem.heapUsed,\n heapTotal: mem.heapTotal,\n external: mem.external,\n rss: mem.rss,\n timestamp: new Date().toISOString(),\n };\n }\n\n // ── Internals ───────────────────────────────────\n\n /** Sample heap usage and fire alerts if thresholds are breached. */\n private sample(): void {\n const snap = this.snapshot();\n this.emit(\"sample\", snap);\n\n const { heapUsed } = snap;\n const { warnThreshold, dangerThreshold, fatalThreshold } = this.config;\n\n let level: MemoryAlertLevel | null = null;\n let threshold = 0;\n\n if (heapUsed >= fatalThreshold) {\n level = \"fatal\";\n threshold = fatalThreshold;\n } else if (heapUsed >= dangerThreshold) {\n level = \"danger\";\n threshold = dangerThreshold;\n } else if (heapUsed >= warnThreshold) {\n level = \"warn\";\n threshold = warnThreshold;\n }\n\n if (level) {\n // Suppress repeated alerts at the same level\n if (level === this.lastAlertLevel) return;\n this.lastAlertLevel = level;\n\n const alert: MemoryAlert = {\n level,\n heapUsed,\n percentage: Math.round((heapUsed / threshold) * 100),\n threshold,\n timestamp: snap.timestamp,\n };\n\n this.emit(\"alert\", alert);\n this.actOnAlert(alert);\n } else if (this.lastAlertLevel) {\n // Memory dropped back below thresholds — reset\n this.lastAlertLevel = null;\n }\n }\n\n /** Execute the appropriate action for each alert level. */\n private actOnAlert(alert: MemoryAlert): void {\n switch (alert.level) {\n case \"warn\": {\n // Trigger GC if available\n this.triggerGc();\n break;\n }\n case \"danger\": {\n // Force GC and signal compaction\n this.triggerGc();\n this.emit(\"compact\", { reason: \"memory_pressure\", heapUsed: alert.heapUsed });\n break;\n }\n case \"fatal\": {\n // Aggressive GC + signal cache flush\n this.triggerGc();\n // Second GC pass after a tick\n setImmediate(() => this.triggerGc());\n this.emit(\"flush_caches\", { reason: \"oom_imminent\", heapUsed: alert.heapUsed });\n break;\n }\n }\n }\n\n /** Trigger V8 garbage collection if --expose-gc is enabled. */\n private triggerGc(): void {\n if (typeof global.gc === \"function\") {\n try {\n global.gc();\n } catch {\n // GC may throw if called at an unsafe time — ignore\n }\n }\n }\n}\n","/**\n * UpdateChecker — asynchronous, non‑blocking version check.\n *\n * Queries npm and GitHub for the latest Lynx release and compares\n * against the running version. Designed to never block startup:\n * the check runs in the background and fires a callback when\n * complete.\n *\n * Design (§5.9k):\n * - Async, non‑blocking — fire and forget\n * - O_EXCL lock — only one check runs at a time per process\n * - Dual channel: npm registry + GitHub releases\n * - GitHub as fallback when npm is slow or unreachable\n * - Result cached for the session lifetime\n * - Respects NO_UPDATE_CHECK env var\n */\n\nimport { request as httpsRequest } from \"node:https\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Result of an update check. */\nexport interface UpdateResult {\n /** Current installed version. */\n current: string;\n /** Latest available version, or null if unknown. */\n latest: string | null;\n /** Whether a newer version is available. */\n hasUpdate: boolean;\n /** Release notes URL for the latest version. */\n releaseUrl: string | null;\n /** Time the check was performed (ISO string). */\n checkedAt: string;\n /** Which channel provided the result. */\n source: \"npm\" | \"github\" | \"cache\" | \"error\";\n /** Error message if the check failed. */\n error?: string;\n}\n\n/** Configuration for the update checker. */\nexport interface UpdateCheckConfig {\n /** Current version string (e.g. \"0.1.0\"). */\n currentVersion: string;\n /** npm package name. Default: \"lynx\". */\n packageName?: string;\n /** GitHub repository in \"owner/repo\" format. Default: \"loongcrown/lynx\". */\n githubRepo?: string;\n /** Timeout per request in ms. Default: 5_000. */\n timeoutMs?: number;\n /** Cache duration in ms. Default: 3_600_000 (1 hour). */\n cacheTtlMs?: number;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst DEFAULT_TIMEOUT_MS = 5_000;\nconst DEFAULT_CACHE_TTL_MS = 3_600_000;\n\n// ── Module state ────────────────────────────────────\n\nlet lastResult: UpdateResult | null = null;\nlet checkInProgress: Promise<UpdateResult> | null = null;\n\n// ── Public API ─────────────────────────────────────\n\n/**\n * Check for updates asynchronously.\n *\n * Only one check runs at a time — concurrent calls return the\n * same Promise. Results are cached for the configured TTL.\n *\n * Callers should never await this at startup — fire‑and‑forget\n * and read the result from the cache on next call.\n */\nexport function checkForUpdates(config: UpdateCheckConfig): Promise<UpdateResult> {\n // Return cached result if still fresh\n if (lastResult) {\n const age = Date.now() - new Date(lastResult.checkedAt).getTime();\n const ttl = config.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;\n if (age < ttl) {\n return Promise.resolve({ ...lastResult, source: \"cache\" as const });\n }\n }\n\n // Return in‑progress check\n if (checkInProgress) return checkInProgress;\n\n // Respect opt‑out\n if (process.env.NO_UPDATE_CHECK) {\n const result: UpdateResult = {\n current: config.currentVersion,\n latest: null,\n hasUpdate: false,\n releaseUrl: null,\n checkedAt: new Date().toISOString(),\n source: \"error\",\n error: \"Update check disabled via NO_UPDATE_CHECK\",\n };\n return Promise.resolve(result);\n }\n\n checkInProgress = runUpdateCheck(config)\n .then((result) => {\n lastResult = result;\n return result;\n })\n .finally(() => {\n checkInProgress = null;\n });\n\n return checkInProgress;\n}\n\n/**\n * Synchronously return the last cached update result.\n * Returns null if no check has been performed yet.\n */\nexport function getLastUpdateResult(): UpdateResult | null {\n return lastResult;\n}\n\n/**\n * Clear the cached update result (for testing).\n */\nexport function clearUpdateCache(): void {\n lastResult = null;\n}\n\n// ── Internals ───────────────────────────────────────\n\n/**\n * Run the update check against npm, falling back to GitHub.\n */\nasync function runUpdateCheck(config: UpdateCheckConfig): Promise<UpdateResult> {\n const pkg = config.packageName ?? \"lynx\";\n const repo = config.githubRepo ?? \"loongcrown/lynx\";\n const timeout = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n // Try npm first\n try {\n const npmResult = await checkNpm(pkg, timeout);\n return buildResult(config.currentVersion, npmResult, \"npm\");\n } catch {\n // npm failed — try GitHub\n }\n\n // Fall back to GitHub\n try {\n const ghResult = await checkGitHub(repo, timeout);\n return buildResult(config.currentVersion, ghResult, \"github\");\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n current: config.currentVersion,\n latest: null,\n hasUpdate: false,\n releaseUrl: null,\n checkedAt: new Date().toISOString(),\n source: \"error\",\n error: message,\n };\n }\n}\n\n/**\n * Check the npm registry for the latest version.\n */\nfunction checkNpm(packageName: string, timeoutMs: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;\n const req = httpsRequest(\n url,\n {\n method: \"GET\",\n timeout: timeoutMs,\n headers: { Accept: \"application/json\" },\n },\n (res) => {\n let body = \"\";\n res.on(\"data\", (chunk: Buffer) => {\n body += chunk.toString();\n });\n res.on(\"end\", () => {\n try {\n const data = JSON.parse(body);\n const version = data.version as string;\n if (!version || typeof version !== \"string\") {\n reject(new Error(\"Invalid npm response: missing version field\"));\n return;\n }\n resolve(version);\n } catch (err) {\n reject(err instanceof Error ? err : new Error(\"Failed to parse npm response\"));\n }\n });\n },\n );\n\n req.on(\"error\", reject);\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"npm request timed out\"));\n });\n req.end();\n });\n}\n\n/**\n * Check GitHub releases for the latest version tag.\n */\nfunction checkGitHub(repo: string, timeoutMs: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const url = `https://api.github.com/repos/${repo}/releases/latest`;\n const req = httpsRequest(\n url,\n {\n method: \"GET\",\n timeout: timeoutMs,\n headers: {\n Accept: \"application/vnd.github+json\",\n \"User-Agent\": \"Lynx-Update-Checker/1.0\",\n },\n },\n (res) => {\n let body = \"\";\n res.on(\"data\", (chunk: Buffer) => {\n body += chunk.toString();\n });\n res.on(\"end\", () => {\n try {\n const data = JSON.parse(body);\n const tag = data.tag_name as string;\n if (!tag || typeof tag !== \"string\") {\n reject(new Error(\"Invalid GitHub response: missing tag_name field\"));\n return;\n }\n // Strip leading 'v' if present\n const version = tag.startsWith(\"v\") ? tag.slice(1) : tag;\n resolve(version);\n } catch (err) {\n reject(err instanceof Error ? err : new Error(\"Failed to parse GitHub response\"));\n }\n });\n },\n );\n\n req.on(\"error\", reject);\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"GitHub request timed out\"));\n });\n req.end();\n });\n}\n\n/**\n * Compare two semver strings and build the result.\n */\nfunction buildResult(current: string, latest: string, source: \"npm\" | \"github\"): UpdateResult {\n const hasUpdate = compareVersions(latest, current) > 0;\n return {\n current,\n latest,\n hasUpdate,\n releaseUrl:\n source === \"github\"\n ? `https://github.com/loongcrown/lynx/releases/latest`\n : `https://www.npmjs.com/package/lynx/v/${latest}`,\n checkedAt: new Date().toISOString(),\n source,\n };\n}\n\n/**\n * Simple semver comparison (supports major.minor.patch only).\n *\n * Returns positive if a > b, negative if a < b, 0 if equal.\n */\nfunction compareVersions(a: string, b: string): number {\n const aParts = a.split(\".\").map(Number);\n const bParts = b.split(\".\").map(Number);\n const len = Math.max(aParts.length, bParts.length);\n\n for (let i = 0; i < len; i++) {\n const aVal = aParts[i] ?? 0;\n const bVal = bParts[i] ?? 0;\n if (aVal > bVal) return 1;\n if (aVal < bVal) return -1;\n }\n\n return 0;\n}\n","/**\n * SnapshotStore — lightweight file-based snapshot persistence.\n *\n * Snapshots are serialised session checkpoints stored as JSON\n * files in the snapshots directory. Each snapshot captures the\n * session label, message list, and workspace at a point in time.\n *\n * Used by the SnapshotBrowser (/snapshots) to list and restore\n * previous session states.\n */\n\nimport {\n existsSync,\n readFileSync,\n writeFileSync,\n readdirSync,\n mkdirSync,\n unlinkSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Session, Message } from \"@lynx/core\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface StoredSnapshot {\n id: string;\n label: string;\n timestamp: number;\n workspace: string;\n /** Serialised messages at capture time. */\n messages: Message[];\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Create a snapshot store backed by a directory on disk.\n *\n * The directory is created on first write if it doesn't exist.\n * Snapshots are stored as individual JSON files named `<id>.json`.\n */\nexport function createSnapshotStore(snapshotsDir: string) {\n return {\n /**\n * Capture a new snapshot of a session's current state.\n *\n * Returns the StoredSnapshot that was written to disk.\n */\n capture(session: Session): StoredSnapshot {\n const id = crypto.randomUUID();\n const snapshot: StoredSnapshot = {\n id,\n label: session.label ?? \"untitled\",\n timestamp: Date.now(),\n workspace: session.workspace ?? \"\",\n messages: [...session.messages],\n };\n\n mkdirSync(snapshotsDir, { recursive: true });\n const filePath = join(snapshotsDir, `${id}.json`);\n writeFileSync(filePath, JSON.stringify(snapshot, null, 2), \"utf-8\");\n\n return snapshot;\n },\n\n /**\n * List all stored snapshots, sorted newest-first.\n *\n * Returns only metadata (no message bodies) for efficient listing.\n */\n list(): Array<{ id: string; timestamp: number; label: string }> {\n let entries: string[];\n try {\n entries = readdirSync(snapshotsDir);\n } catch {\n return [];\n }\n\n const snapshots: Array<{ id: string; timestamp: number; label: string }> = [];\n\n for (const entry of entries) {\n if (!entry.endsWith(\".json\")) continue;\n const id = entry.replace(/\\.json$/, \"\");\n const filePath = join(snapshotsDir, entry);\n\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const snap = JSON.parse(raw) as StoredSnapshot;\n snapshots.push({\n id: snap.id,\n timestamp: snap.timestamp,\n label: snap.label,\n });\n } catch {\n // Skip corrupted snapshots\n }\n }\n\n // Newest first\n snapshots.sort((a, b) => b.timestamp - a.timestamp);\n return snapshots;\n },\n\n /**\n * Load a full snapshot by ID (includes message bodies).\n *\n * Returns null if the snapshot doesn't exist or is corrupted.\n */\n load(id: string): StoredSnapshot | null {\n const filePath = join(snapshotsDir, `${id}.json`);\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as StoredSnapshot;\n } catch {\n return null;\n }\n },\n\n /**\n * Delete a snapshot by ID.\n *\n * No-op if the snapshot doesn't exist.\n */\n delete(id: string): void {\n try {\n unlinkSync(join(snapshotsDir, `${id}.json`));\n } catch {\n // Already deleted or never existed — no-op\n }\n },\n };\n}\n\nexport type SnapshotStore = ReturnType<typeof createSnapshotStore>;\n","/**\n * TUI launcher — boots the application and renders the Ink UI.\n *\n * This module is lazily loaded only when the user enters\n * interactive mode (no sub‑command given).\n */\n\nimport { fileURLToPath } from \"node:url\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { bootstrap } from \"./bootstrap.js\";\nimport { resolvePaths, asSessionId } from \"@lynx/core\";\nimport { loadConfig, resolveConfigEnv, resolveProvider } from \"./commands/config.js\";\nimport type {\n TuiCallbacks,\n TuiStreamEvent,\n TuiModelInfo,\n McpConnectionInfo,\n PluginInfo,\n SkillInfo,\n ContextInfo,\n UsageInfo,\n} from \"@lynx/tui\";\nimport { runPhase2WithContext } from \"./startup.js\";\nimport { enterFullscreen, exitFullscreen } from \"./terminal-mode.js\";\nimport { installProcessLifecycle } from \"./process-lifecycle.js\";\nimport { saveConfig } from \"./commands/config.js\";\nimport { MemoryMonitor } from \"./memory-monitor.js\";\nimport { checkForUpdates } from \"./update-check.js\";\nimport { createSnapshotStore } from \"./snapshot-store.js\";\nimport type { TaskEntry } from \"@lynx/tui\";\n\n// ── Cost estimation ──────────────────────────────────\n\n/** Approximate USD per 1M input tokens. */\nconst INPUT_PRICE_PER_1M: Record<string, number> = {\n \"deepseek-chat\": 0.27,\n \"deepseek-reasoner\": 0.55,\n \"gpt-4o\": 2.5,\n \"gpt-4o-mini\": 0.15,\n \"o3-mini\": 1.1,\n \"claude-sonnet-4-20250514\": 3.0,\n \"claude-haiku-3-5\": 0.8,\n \"claude-opus-4-20250514\": 15.0,\n};\n\n/** Approximate USD per 1M output tokens. */\nconst OUTPUT_PRICE_PER_1M: Record<string, number> = {\n \"deepseek-chat\": 1.1,\n \"deepseek-reasoner\": 2.19,\n \"gpt-4o\": 10.0,\n \"gpt-4o-mini\": 0.6,\n \"o3-mini\": 4.4,\n \"claude-sonnet-4-20250514\": 15.0,\n \"claude-haiku-3-5\": 4.0,\n \"claude-opus-4-20250514\": 75.0,\n};\n\n/**\n * Estimate the USD cost for a given token count.\n *\n * Uses approximate 70/30 input/output split and model‑specific pricing.\n * Falls back to $1.0/$4.0 per million for unknown models.\n */\nfunction estimateCost(model: string, totalTokens: number): number {\n if (totalTokens <= 0) return 0;\n const inputPrice = INPUT_PRICE_PER_1M[model] ?? 1.0;\n const outputPrice = OUTPUT_PRICE_PER_1M[model] ?? 4.0;\n const inputTokens = Math.floor(totalTokens * 0.7);\n const outputTokens = Math.floor(totalTokens * 0.3);\n return (inputTokens / 1_000_000) * inputPrice + (outputTokens / 1_000_000) * outputPrice;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Launch the interactive TUI.\n *\n * Phase 1: bootstrap services (DB, sessions, tools, agent engine).\n * Phase 2: render the Ink TUI.\n */\nexport async function launchTui(): Promise<void> {\n const paths = resolvePaths();\n\n // 加载配置 → 注入 env → 按模型名自动选 Provider\n const config = loadConfig();\n resolveConfigEnv(config);\n const provider = resolveProvider(config);\n\n // Resolve built‑in skills directory relative to the lynx-agent package\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const builtinSkillsDir = join(__dirname, \"..\", \"..\", \"lynx-agent\", \"skills\");\n\n const ctx = bootstrap({\n homeDir: paths.home,\n provider,\n model: process.env.LYNX_MODEL ?? config.model,\n skillsDir: builtinSkillsDir,\n workspace: process.cwd(),\n });\n\n const sessions = ctx.sessionMgr.list();\n\n // Pick the most recent session or create a new one\n const activeSession =\n sessions.length > 0 ? sessions[0]! : ctx.sessionMgr.create(\"default\", process.cwd());\n\n // ── Abort layer state (3‑layer Ctrl+C) ──────────\n let abortLayer = 0;\n let currentAbortController: AbortController | null = null;\n let isStreaming = false;\n\n const resetAbortLayer = () => {\n abortLayer = 0;\n };\n\n const getAbortLayer = () => abortLayer;\n\n const incrementAbortLayer = () => {\n abortLayer++;\n return abortLayer;\n };\n\n // ── Process lifecycle ─────────────────────────\n installProcessLifecycle({\n ctx,\n onAbortLl: () => {\n ctx.engine.abort();\n },\n onAbortTool: () => {\n // Layer 2: abort running tool (engine handles internally)\n ctx.engine.abort();\n },\n getAbortLayer,\n incrementAbortLayer,\n resetAbortLayer,\n isStreaming: () => isStreaming,\n });\n\n // Build TUI callbacks bridging to the agent engine\n // Build model list for the TUI model picker\n const providerModels: TuiModelInfo[] = ctx.provider.listModels().map((m) => ({\n id: m.id,\n label: m.label,\n contextWindow: m.contextWindow,\n maxOutput: m.maxOutput,\n inputPrice: INPUT_PRICE_PER_1M[m.id],\n outputPrice: OUTPUT_PRICE_PER_1M[m.id],\n }));\n\n const callbacks: TuiCallbacks = {\n async *onInput(message: string): AsyncGenerator<TuiStreamEvent, void, void> {\n // Reset abort layer on new message\n resetAbortLayer();\n isStreaming = true;\n\n // Create a user message\n const userMsg = {\n id: crypto.randomUUID() as never,\n role: \"user\" as const,\n content: [{ type: \"text\" as const, text: message }],\n timestamp: Date.now(),\n turnIndex: 0,\n };\n\n currentAbortController = new AbortController();\n const signal = currentAbortController.signal;\n\n let turnCompleted = false;\n let reasoningStart: number | null = null;\n let reasoningText = \"\";\n\n /** End reasoning tracking, yielding a status event with duration and text if reasoning was active. */\n const endReasoning = (): TuiStreamEvent | null => {\n if (reasoningStart === null) return null;\n const durationMs = Date.now() - reasoningStart;\n const text = reasoningText;\n reasoningStart = null;\n reasoningText = \"\";\n return { type: \"reasoning_status\", status: \"ended\", durationMs, text };\n };\n\n try {\n for await (const event of ctx.engine.submit(activeSession, userMsg, signal)) {\n // Map agent stream events to TUI stream events\n switch (event.type) {\n case \"text_delta\": {\n const rEnd = endReasoning();\n if (rEnd) yield rEnd;\n yield { type: \"text_delta\", text: event.text };\n break;\n }\n case \"reasoning_delta\":\n if (reasoningStart === null) {\n reasoningStart = Date.now();\n yield { type: \"reasoning_status\", status: \"started\" };\n }\n reasoningText += event.text;\n break;\n case \"tool_use_start\": {\n const rEnd = endReasoning();\n if (rEnd) yield rEnd;\n yield { type: \"tool_use\", name: event.name, callId: event.callId };\n break;\n }\n case \"tool_result\":\n yield { type: \"tool_result\", callId: event.toolUseId, content: event.content };\n break;\n case \"tool_recap\":\n yield {\n type: \"tool_recap\",\n summary: event.summary,\n toolCount: event.toolCount,\n durationMs: event.durationMs,\n };\n break;\n case \"error\":\n yield { type: \"error\", message: event.message };\n break;\n case \"done\": {\n const rEnd = endReasoning();\n if (rEnd) yield rEnd;\n turnCompleted = true;\n const totalTokens = event.totalTokens ?? 0;\n // Approximate cost: 70% input, 30% output pricing\n const costUsd = estimateCost(ctx.agentConfig.model, totalTokens);\n yield { type: \"done\", totalTokens, costUsd };\n break;\n }\n }\n }\n\n // Auto-capture snapshot after a successful turn\n if (turnCompleted && activeSession.messages.length > 0) {\n try {\n snapshotStore.capture(activeSession);\n } catch {\n // Best-effort — don't block the UI on snapshot failure\n }\n }\n } catch (err) {\n yield {\n type: \"error\",\n message: err instanceof Error ? err.message : String(err),\n };\n } finally {\n isStreaming = false;\n currentAbortController = null;\n }\n },\n\n onSessionPick(sessionId: string): void {\n const session = ctx.sessionMgr.load(asSessionId(sessionId));\n if (session) {\n // Session switching will be handled by the TUI state\n process.stdout.write(`Switched to session: ${session.label ?? sessionId}\\n`);\n }\n },\n\n onPermissionReply(requestId: string, approved: boolean): void {\n ctx.permissionBridge.handleReply(requestId, approved);\n },\n\n onAbort(): void {\n ctx.engine.abort();\n },\n\n onModelPick(modelId: string): void {\n ctx.agentConfig.model = modelId;\n // Persist to config\n const cfg = loadConfig();\n cfg.model = modelId;\n saveConfig(cfg);\n },\n\n onConfigChange(key: string, value: unknown): void {\n const cfg = loadConfig();\n if (key === \"model\" && typeof value === \"string\") {\n cfg.model = value;\n } else if (key === \"theme\" && typeof value === \"string\") {\n cfg.theme = value;\n }\n saveConfig(cfg);\n },\n\n onThemeChange(themeName: string): void {\n // Persist to config (setTheme() is called by the TUI directly)\n const cfg = loadConfig();\n cfg.theme = themeName;\n saveConfig(cfg);\n },\n\n // ── Session CRUD ─────────────────────────────────\n\n onSessionCreate(label: string): void {\n ctx.sessionMgr.create(label, workspace);\n },\n\n onSessionFork(newLabel: string): void {\n ctx.sessionMgr.fork(activeSession.id, newLabel);\n },\n\n onSessionRename(newLabel: string): void {\n ctx.sessionMgr.rename(activeSession.id, newLabel);\n },\n\n onSessionDelete(sessionId: string): void {\n ctx.sessionMgr.delete(asSessionId(sessionId));\n },\n\n onSessionResume(sessionId: string): void {\n const resumed = ctx.sessionMgr.load(asSessionId(sessionId));\n if (resumed) {\n process.stdout.write(`Resumed session: ${resumed.label}\\n`);\n }\n },\n\n onSessionCompact(): void {\n // Trigger compaction on the engine for the active session\n ctx.engine.compact(activeSession);\n },\n\n // ── Data panels ────────────────────────────────\n\n async onRequestDiff() {\n // Run git diff in the workspace directory\n try {\n const { execSync } = await import(\"node:child_process\");\n const output = execSync(\"git diff --name-status\", {\n cwd: workspace,\n encoding: \"utf-8\",\n timeout: 5000,\n });\n const files: Array<{ path: string; status: string; diff: string }> = [];\n const lines = output.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n const parts = line.split(\"\\t\");\n const status = (parts[0] ?? \"?\").charAt(0);\n const path = parts.length > 1 ? parts.slice(1).join(\"\\t\") : line;\n // Get per-file diff\n let diff = \"\";\n try {\n diff = execSync(`git diff -- \"${path}\"`, {\n cwd: workspace,\n encoding: \"utf-8\",\n timeout: 3000,\n });\n } catch {\n diff = \"(diff unavailable)\";\n }\n files.push({ path, status, diff });\n }\n return files;\n } catch {\n return [];\n }\n },\n\n async onRequestSnapshots() {\n return snapshotStore.list();\n },\n\n async onRequestTasks() {\n return [...phase2Tasks];\n },\n\n async onOpenExternalEditor(currentText: string): Promise<string | null> {\n const editor = process.env.EDITOR ?? process.env.VISUAL ?? \"notepad\";\n const { writeFileSync, readFileSync, unlinkSync } = await import(\"node:fs\");\n const { tmpdir } = await import(\"node:os\");\n const { join } = await import(\"node:path\");\n const { randomUUID } = await import(\"node:crypto\");\n const { execSync } = await import(\"node:child_process\");\n\n const tmpPath = join(tmpdir(), `lynx-editor-${randomUUID()}.md`);\n\n try {\n writeFileSync(tmpPath, currentText || \"# Lynx Editor\\n\\n\", \"utf-8\");\n execSync(`${editor} \"${tmpPath}\"`, { stdio: \"inherit\", timeout: 300_000 });\n const edited = readFileSync(tmpPath, \"utf-8\");\n // Remove the template header if the user didn't change it\n return edited === \"# Lynx Editor\\n\\n\" && currentText === \"\" ? null : edited;\n } catch {\n return null;\n } finally {\n try {\n unlinkSync(tmpPath);\n } catch {\n /* best effort */\n }\n }\n },\n };\n\n // ── Phase 2 task tracker (for /tasks panel) ─────────────────\n const phase2Tasks: TaskEntry[] = [];\n\n // ── Snapshot store ──────────────────────────────────────────\n const snapshotStore = createSnapshotStore(paths.snapshotsDir);\n const workspace = process.cwd();\n const userHome = homedir();\n\n /** Build MCP connection info from the connection manager. */\n function buildMcpConnections(): McpConnectionInfo[] {\n return ctx.mcpManager.listConnections().map((c) => ({\n name: c.serverName,\n status: c.status,\n toolCount: c.tools.length,\n detail: c.errorMessage ?? c.status,\n transport: c.transport,\n authStatus: c.authStatus,\n resourceCount: c.resourceCount,\n tools: c.toolsMeta,\n resources: c.resources,\n }));\n }\n\n /** Build plugin info from manifest registry and loader state. */\n function buildPlugins(): PluginInfo[] {\n const loaded = new Set(ctx.pluginRegistry.loader.listLoaded());\n return ctx.pluginRegistry.manifestRegistry.listAll().map((e) => ({\n name: e.manifest.name,\n version: e.manifest.version,\n description: e.manifest.description ?? \"\",\n loaded: loaded.has(e.manifest.name),\n }));\n }\n\n /** Build skill info from the skill registry, annotating source origin. */\n function buildSkills(): SkillInfo[] {\n return ctx.skillRegistry.list().map((s) => {\n let source: SkillInfo[\"source\"] = \"builtin\";\n if (s.path.startsWith(userHome)) source = \"user\";\n else if (s.path.startsWith(workspace)) source = \"project\";\n return { name: s.name, description: s.description, source };\n });\n }\n\n /** Build context summary for /context panel. */\n function buildContextInfo(): ContextInfo {\n return {\n memoryFacts: ctx.memoryFacts.length,\n rules: ctx.rules.length,\n skills: ctx.skills.length,\n model: ctx.agentConfig.model,\n workspace,\n sessionLabel: activeSession.label,\n };\n }\n\n /** Build usage statistics for /usage panel. */\n function buildUsageInfo(): UsageInfo {\n const model = ctx.agentConfig.model;\n const inputPrice = INPUT_PRICE_PER_1M[model];\n const outputPrice = OUTPUT_PRICE_PER_1M[model];\n const pricing =\n inputPrice !== undefined && outputPrice !== undefined\n ? `${model}: $${inputPrice}/M input · $${outputPrice}/M output`\n : `${model}: pricing N/A`;\n return {\n tokensUsed: 0,\n costUsd: 0,\n budgetMaxTokens: ctx.agentConfig.budget.maxTokens,\n budgetMaxUsd: ctx.agentConfig.budget.maxUsd,\n turns: 0,\n modelPricing: pricing,\n };\n }\n\n // Render the Ink TUI\n // Hoisted so the catch block can clean up after a crash.\n let memoryMonitor: MemoryMonitor | null = null;\n\n try {\n // Enter fullscreen alt buffer + mouse tracking\n enterFullscreen();\n\n const React = await import(\"react\");\n const { render } = await import(\"ink\");\n const { App } = await import(\"@lynx/tui\");\n\n const { unmount, waitUntilExit } = render(\n React.createElement(App, {\n callbacks,\n session: activeSession,\n sessions,\n models: providerModels,\n currentModel: ctx.agentConfig.model,\n columns: process.stdout.columns ?? 80,\n rows: process.stdout.rows ?? 24,\n showWelcome: true,\n onPermissionReady: (handler) => {\n ctx.permissionBridge.setTuiHandler(handler);\n },\n mcpConnections: buildMcpConnections(),\n plugins: buildPlugins(),\n skills: buildSkills(),\n contextInfo: buildContextInfo(),\n usageInfo: buildUsageInfo(),\n }),\n );\n\n // Phase 2: background tasks (scan extensions, connect MCP, load memory).\n // Fire‑and‑forget — don't block the TUI. Results populate the /tasks panel.\n runPhase2WithContext(ctx, paths)\n .then((results) => {\n const statusMap: Record<string, TaskEntry[\"status\"]> = { true: \"done\", false: \"failed\" };\n for (const r of results) {\n phase2Tasks.push({\n id: `phase2-${r.name}`,\n name: r.name,\n status: statusMap[String(r.ok)] ?? \"failed\",\n error: r.error,\n });\n }\n })\n .catch(() => {\n // Errors are already logged by the task runner\n });\n\n // ── Memory monitor — proactive heap sampling ──\n memoryMonitor = new MemoryMonitor();\n memoryMonitor.onAlert((alert) => {\n process.stderr.write(\n `[lynx] Memory ${alert.level}: ${Math.round(alert.heapUsed / 1024 / 1024)}MB ` +\n `(${alert.percentage}% of threshold)\\n`,\n );\n });\n memoryMonitor.start();\n\n // ── Update check — non‑blocking background check ──\n checkForUpdates({ currentVersion: \"0.1.0\" })\n .then((result) => {\n if (result.hasUpdate) {\n process.stderr.write(\n `[lynx] Update available: ${result.current} → ${result.latest} ` +\n `(${result.releaseUrl})\\n`,\n );\n }\n })\n .catch(() => {\n // Update check is best‑effort — never block or crash\n });\n\n // Keep the process alive until the TUI exits\n await waitUntilExit();\n\n // Cleanup: stop monitors, exit fullscreen, unmount, destroy services\n memoryMonitor.stop();\n exitFullscreen();\n unmount();\n ctx.destroy();\n } catch (err) {\n process.stderr.write(\n `Failed to start TUI: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n // Recover terminal from alt‑buffer mode so the user isn't stuck\n try {\n memoryMonitor?.stop();\n } catch {\n // Best effort\n }\n try {\n exitFullscreen();\n } catch {\n // Terminal may already be gone\n }\n try {\n ctx.destroy();\n } catch {\n // Best effort\n }\n process.exitCode = 1;\n }\n}\n","/**\n * WorkerPool — bounded thread pool for CPU‑bound tasks.\n *\n * Manages a fixed number of worker threads (2‑8) with a FIFO task\n * queue. All workers share the same worker script; tasks differ\n * only by their postMessage payload.\n *\n * Design:\n * - Fixed pool size, configurable at creation time\n * - FIFO queue — tasks are executed in submission order\n * - Auto‑restart — crashed workers replaced up to maxRetries times\n * - Idle shrink — workers idle for > 30s are terminated (min 2 kept)\n * - Graceful shutdown — drain remaining tasks before exit\n */\n\nimport { Worker } from \"node:worker_threads\";\n\n// ── Types ────────────────────────────────────────────\n\n/** A unit of work submitted to the pool. */\nexport interface PoolTask<T = unknown> {\n /** Unique task identifier. */\n id: string;\n /** Data passed to the worker via postMessage. */\n workerData?: T;\n /** Resolve the task with the worker's result. */\n resolve: (result: unknown) => void;\n /** Reject the task on failure. */\n reject: (error: Error) => void;\n /** Number of times this task has been retried after worker crash. */\n retries: number;\n}\n\n/** Configuration for the worker pool. */\nexport interface WorkerPoolConfig {\n /** Path to the worker script that all workers execute. */\n workerScript: string | URL;\n /** Number of workers in the pool (clamped to 2‑8). Default: 2. */\n size?: number;\n /** Max restarts per worker before the pool rejects queued tasks. Default: 3. */\n maxRetries?: number;\n /** Idle timeout in ms before shrinking a worker. Default: 30_000. */\n idleTimeoutMs?: number;\n}\n\n/** Status of the worker pool for introspection. */\nexport interface PoolStatus {\n size: number;\n active: number;\n idle: number;\n queued: number;\n totalRestarts: number;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst MIN_POOL_SIZE = 2;\nconst MAX_POOL_SIZE = 8;\nconst DEFAULT_SIZE = 2;\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_IDLE_MS = 30_000;\n\n// ── Worker entry ─────────────────────────────────────\n\ninterface WorkerEntry {\n worker: Worker;\n busy: boolean;\n restarts: number;\n idleTimer: ReturnType<typeof setTimeout> | null;\n}\n\n// ── WorkerPool ───────────────────────────────────────\n\n/**\n * Bounded worker thread pool.\n *\n * Usage:\n * ```ts\n * const pool = new WorkerPool({ workerScript: \"./heavy-task.js\", size: 4 });\n * const result = await pool.enqueue({ input: 42 });\n * await pool.shutdown();\n * ```\n */\nexport class WorkerPool {\n private config: Required<Omit<WorkerPoolConfig, \"workerScript\">>;\n private workerScript: string | URL;\n private queue: PoolTask[] = [];\n private workers = new Map<number, WorkerEntry>();\n private runningTasks = new Map<number, PoolTask>();\n private nextWorkerId = 0;\n private destroyed = false;\n private totalRestarts = 0;\n\n constructor(config: WorkerPoolConfig) {\n const size = Math.min(MAX_POOL_SIZE, Math.max(MIN_POOL_SIZE, config.size ?? DEFAULT_SIZE));\n this.config = {\n size,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n idleTimeoutMs: config.idleTimeoutMs ?? DEFAULT_IDLE_MS,\n };\n this.workerScript = config.workerScript;\n\n for (let i = 0; i < size; i++) {\n this.spawnWorker();\n }\n }\n\n // ── Public API ──────────────────────────────────\n\n /**\n * Enqueue a task for execution.\n *\n * Returns a Promise that resolves with the worker's result\n * or rejects if the pool is destroyed.\n */\n enqueue<TResult = unknown>(data?: unknown): Promise<TResult> {\n if (this.destroyed) {\n return Promise.reject(new Error(\"WorkerPool is destroyed\"));\n }\n\n return new Promise<TResult>((resolve, reject) => {\n const task: PoolTask = {\n id: `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n workerData: data,\n resolve: resolve as (result: unknown) => void,\n reject,\n retries: 0,\n };\n\n this.queue.push(task);\n this.drain();\n });\n }\n\n /** Current pool status for monitoring. */\n status(): PoolStatus {\n let active = 0;\n let idle = 0;\n for (const w of this.workers.values()) {\n if (w.busy) active++;\n else idle++;\n }\n return {\n size: this.workers.size,\n active,\n idle,\n queued: this.queue.length,\n totalRestarts: this.totalRestarts,\n };\n }\n\n /**\n * Gracefully shut down the pool.\n *\n * Waits for active tasks to finish, then terminates all workers.\n * Queued tasks that haven't started are rejected.\n */\n async shutdown(): Promise<void> {\n this.destroyed = true;\n\n // Reject all queued tasks\n for (const task of this.queue) {\n task.reject(new Error(\"WorkerPool shut down\"));\n }\n this.queue.length = 0;\n\n // Terminate all workers\n for (const entry of this.workers.values()) {\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n await entry.worker.terminate();\n }\n this.workers.clear();\n }\n\n // ── Internals ───────────────────────────────────\n\n /** Spawn a new worker thread. */\n private spawnWorker(): number {\n const id = this.nextWorkerId++;\n\n let worker: Worker;\n try {\n worker = new Worker(this.workerScript, { workerData: { poolId: id } });\n } catch {\n // Worker script not found or invalid — defer error to enqueue\n return -1;\n }\n\n worker.on(\"error\", (_err) => {\n this.handleWorkerCrash(id);\n });\n\n worker.on(\"messageerror\", () => {\n this.handleWorkerCrash(id);\n });\n\n worker.on(\"exit\", (code) => {\n if (code !== 0) {\n this.handleWorkerCrash(id);\n }\n });\n\n const idleTimer = this.startIdleTimer(id);\n\n this.workers.set(id, { worker, busy: false, restarts: 0, idleTimer });\n return id;\n }\n\n /** Replace a crashed worker and re-queue or reject its active task. */\n private handleWorkerCrash(id: number): void {\n const entry = this.workers.get(id);\n if (!entry) return;\n\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n\n entry.restarts++;\n this.totalRestarts++;\n\n // Terminate and remove the crashed worker\n entry.worker.terminate().catch(() => {});\n this.workers.delete(id);\n\n // Handle any task that was running on the crashed worker\n const activeTask = this.runningTasks.get(id);\n if (activeTask) {\n this.runningTasks.delete(id);\n activeTask.retries++;\n if (activeTask.retries > this.config.maxRetries) {\n activeTask.reject(new Error(`Task failed after ${activeTask.retries} worker crashes`));\n } else {\n // Re-queue the task for another worker to pick up\n this.queue.unshift(activeTask);\n }\n }\n\n // Replace the worker if pool is still alive\n if (!this.destroyed && this.workers.size < this.config.size) {\n this.spawnWorker();\n }\n\n this.drain();\n }\n\n /** Try to dequeue and execute pending tasks. */\n private drain(): void {\n if (this.destroyed) return;\n\n // Find an idle worker\n for (const [id, entry] of this.workers) {\n if (!entry.busy && this.queue.length > 0) {\n const task = this.queue.shift();\n if (!task) return;\n\n entry.busy = true;\n if (entry.idleTimer) {\n clearTimeout(entry.idleTimer);\n entry.idleTimer = null;\n }\n\n this.runTask(id, entry.worker, task);\n return; // One task per drain — next tick picks up the rest\n }\n }\n\n // If no tasks and we have idle workers, try to shrink\n if (this.queue.length === 0) {\n this.maybeShrink();\n }\n }\n\n /** Execute a single task on a worker. */\n private runTask(workerId: number, worker: Worker, task: PoolTask): void {\n this.runningTasks.set(workerId, task);\n\n const onMessage = (result: unknown) => {\n cleanup();\n task.resolve(result);\n const entry = this.workers.get(workerId);\n if (entry) {\n entry.busy = false;\n entry.idleTimer = this.startIdleTimer(workerId);\n }\n this.drain();\n };\n\n const onError = (err: Error) => {\n cleanup();\n task.reject(err);\n const entry = this.workers.get(workerId);\n if (entry) {\n entry.busy = false;\n entry.idleTimer = this.startIdleTimer(workerId);\n }\n this.drain();\n };\n\n const cleanup = () => {\n this.runningTasks.delete(workerId);\n worker.removeListener(\"message\", onMessage);\n worker.removeListener(\"error\", onError);\n };\n\n worker.once(\"message\", onMessage);\n worker.once(\"error\", onError);\n\n worker.postMessage({ taskId: task.id, data: task.workerData });\n }\n\n /** Start or reset the idle timer for a worker. */\n private startIdleTimer(workerId: number): ReturnType<typeof setTimeout> {\n return setTimeout(() => {\n this.shrinkWorker(workerId);\n }, this.config.idleTimeoutMs);\n }\n\n /** Attempt to shrink idle workers if above minimum. */\n private maybeShrink(): void {\n const idleIds: number[] = [];\n for (const [id, entry] of this.workers) {\n if (!entry.busy) idleIds.push(id);\n }\n\n // Keep at least MIN_POOL_SIZE workers\n while (idleIds.length > MIN_POOL_SIZE && this.workers.size > MIN_POOL_SIZE) {\n const id = idleIds.pop()!;\n this.shrinkWorker(id);\n }\n }\n\n /** Terminate a specific idle worker. */\n private shrinkWorker(workerId: number): void {\n const entry = this.workers.get(workerId);\n if (!entry || entry.busy) return;\n if (this.workers.size <= MIN_POOL_SIZE) return;\n\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.worker.terminate().catch(() => {});\n this.workers.delete(workerId);\n }\n}\n","/**\n * Plugin command — manage installed plugins.\n *\n * Sub‑commands:\n * list — list installed plugins with status\n * enable <name> — enable a disabled plugin\n * disable <name> — disable a plugin (without uninstalling)\n * install <path> — install a plugin from a local path\n * remove <name> — uninstall a plugin\n */\n\nimport {\n readdirSync,\n readFileSync,\n existsSync,\n writeFileSync,\n mkdirSync,\n renameSync,\n} from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { resolvePaths } from \"@lynx/core\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface PluginCommandOptions {\n list?: boolean;\n enable?: string;\n disable?: string;\n install?: string;\n remove?: string;\n}\n\ninterface PluginManifest {\n name: string;\n version: string;\n description?: string;\n type: \"tool\" | \"channel\" | \"provider\";\n}\n\ninterface InstalledPlugin {\n name: string;\n version: string;\n description: string;\n type: string;\n enabled: boolean;\n path: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** Path to the installed‑plugins registry JSON file. */\nfunction registryPath(): string {\n const paths = resolvePaths();\n return join(paths.home, \"plugins.json\");\n}\n\n/** Path to the Lynx extensions directory. */\nfunction extensionsDir(): string {\n const paths = resolvePaths();\n return join(paths.home, \"extensions\");\n}\n\nfunction loadRegistry(): Record<string, InstalledPlugin> {\n const path = registryPath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n const backupPath = path + \".bak\";\n renameSync(path, backupPath);\n process.stderr.write(\n `[lynx] 警告:插件注册表已损坏,已备份到 ${backupPath}。正在使用默认配置。\\n`,\n );\n return {};\n }\n}\n\nfunction saveRegistry(reg: Record<string, InstalledPlugin>): void {\n const path = registryPath();\n const dir = dirname(path);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n const tmp = path + \".tmp\";\n writeFileSync(tmp, JSON.stringify(reg, null, 2) + \"\\n\", \"utf-8\");\n renameSync(tmp, path);\n}\n\nfunction readManifest(pluginDir: string): PluginManifest | null {\n const manifestPath = join(pluginDir, \"manifest.json\");\n if (!existsSync(manifestPath)) return null;\n try {\n return JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/** Scan the extensions directory for installed plugins. */\nfunction scanInstalled(): Map<string, string> {\n const dir = extensionsDir();\n const result = new Map<string, string>();\n if (!existsSync(dir)) return result;\n\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return result;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n try {\n const stat = require(\"node:fs\").statSync(fullPath);\n if (!stat.isDirectory()) continue;\n } catch {\n continue;\n }\n\n const manifest = readManifest(fullPath);\n if (manifest) {\n result.set(manifest.name, fullPath);\n }\n }\n\n return result;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Handle the `lynx plugin` command. */\nexport async function handlePluginCommand(opts: PluginCommandOptions): Promise<void> {\n if (opts.list) {\n await listPlugins();\n return;\n }\n\n if (opts.enable) {\n await setPluginEnabled(opts.enable, true);\n return;\n }\n\n if (opts.disable) {\n await setPluginEnabled(opts.disable, false);\n return;\n }\n\n if (opts.install) {\n await installPlugin(opts.install);\n return;\n }\n\n if (opts.remove) {\n await removePlugin(opts.remove);\n return;\n }\n\n // Default: list\n await listPlugins();\n}\n\n// ── Sub‑commands ────────────────────────────────────\n\nasync function listPlugins(): Promise<void> {\n const installed = scanInstalled();\n const registry = loadRegistry();\n\n if (installed.size === 0) {\n process.stdout.write(\"No plugins installed.\\n\");\n process.stdout.write(`Extensions directory: ${extensionsDir()}\\n`);\n return;\n }\n\n const lines: string[] = [];\n for (const [name, dirPath] of installed) {\n const manifest = readManifest(dirPath);\n const record = registry[name];\n const enabled = record?.enabled ?? true;\n const version = manifest?.version ?? \"unknown\";\n const type = manifest?.type ?? \"unknown\";\n const desc = manifest?.description ?? \"\";\n const status = enabled ? \"enabled\" : \"disabled\";\n lines.push(\n `${status === \"disabled\" ? \"○\" : \"✓\"} ${name}@${version} (${type}) ${status} — ${desc}`,\n );\n lines.push(` path: ${dirPath}`);\n }\n\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\n}\n\nasync function setPluginEnabled(name: string, enabled: boolean): Promise<void> {\n const registry = loadRegistry();\n const installed = scanInstalled();\n\n if (!installed.has(name)) {\n process.stderr.write(`Plugin \"${name}\" is not installed.\\n`);\n process.exitCode = 1;\n return;\n }\n\n registry[name] = {\n name,\n version: readManifest(installed.get(name)!)?.version ?? \"unknown\",\n description: readManifest(installed.get(name)!)?.description ?? \"\",\n type: readManifest(installed.get(name)!)?.type ?? \"unknown\",\n enabled,\n path: installed.get(name)!,\n };\n\n saveRegistry(registry);\n const action = enabled ? \"enabled\" : \"disabled\";\n process.stdout.write(`Plugin \"${name}\" ${action}.\\n`);\n}\n\nasync function installPlugin(sourcePath: string): Promise<void> {\n const manifest = readManifest(sourcePath);\n if (!manifest) {\n process.stderr.write(`No valid manifest.json found at \"${sourcePath}\".\\n`);\n process.exitCode = 1;\n return;\n }\n\n const targetDir = join(extensionsDir(), manifest.name);\n\n if (existsSync(targetDir)) {\n process.stderr.write(\n `Plugin \"${manifest.name}\" is already installed at \"${targetDir}\".\\n` +\n `Use \"lynx plugin remove ${manifest.name}\" first to reinstall.\\n`,\n );\n process.exitCode = 1;\n return;\n }\n\n // Simple copy: read all files from source and write to target\n // For a real implementation, this would use a proper copy utility\n const { cpSync } = await import(\"node:fs\");\n try {\n mkdirSync(dirname(targetDir), { recursive: true });\n cpSync(sourcePath, targetDir, { recursive: true });\n } catch (err) {\n process.stderr.write(\n `Failed to copy plugin: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exitCode = 1;\n return;\n }\n\n const registry = loadRegistry();\n registry[manifest.name] = {\n name: manifest.name,\n version: manifest.version,\n description: manifest.description ?? \"\",\n type: manifest.type,\n enabled: true,\n path: targetDir,\n };\n saveRegistry(registry);\n\n process.stdout.write(\n `Plugin \"${manifest.name}@${manifest.version}\" installed to \"${targetDir}\".\\n`,\n );\n}\n\nasync function removePlugin(name: string): Promise<void> {\n const registry = loadRegistry();\n const installed = scanInstalled();\n const dirPath = installed.get(name);\n\n if (!dirPath) {\n process.stderr.write(`Plugin \"${name}\" is not installed.\\n`);\n process.exitCode = 1;\n return;\n }\n\n // Remove the plugin directory\n const { rmSync } = await import(\"node:fs\");\n try {\n rmSync(dirPath, { recursive: true, force: true });\n } catch (err) {\n process.stderr.write(\n `Failed to remove plugin directory: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exitCode = 1;\n return;\n }\n\n // Remove from registry\n delete registry[name];\n saveRegistry(registry);\n\n process.stdout.write(`Plugin \"${name}\" removed.\\n`);\n}\n","/**\n * /commit 命令 — 创建 Git 提交并推送。\n *\n * 生成中文指令,引导模型执行完整的提交工作流:\n * 1. 检查工作区状态和变更摘要\n * 2. 基于用户消息(或自动生成)创建约定式提交\n * 3. git add → git commit → git push\n * 4. --all 标志表示暂存所有变更\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CommitCommandArgs {\n /** 用户自定义的提交消息(可选,省略时自动生成)。 */\n message?: string;\n /** 是否暂存所有变更(git add -A)。 */\n all?: boolean;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /commit 命令,返回一段中文指令引导模型完成提交。\n */\nexport function handleCommitCommand(args: CommitCommandArgs): { instruction: string } {\n const { message, all } = args;\n\n const steps: string[] = [\n \"# Git 提交任务\",\n \"\",\n \"请按以下步骤完成提交:\",\n \"\",\n \"1. 先运行 `git status` 查看当前工作区状态\",\n \"2. 运行 `git diff --stat` 查看变更文件摘要\",\n \"3. 运行 `git diff` 查看具体变更内容,根据变更内容生成有意义的提交消息\",\n ];\n\n if (all) {\n steps.push(\"4. 运行 `git add -A` 暂存所有变更(包括新增、修改和删除)\");\n } else {\n steps.push(\"4. 运行 `git add <files>` 暂存需要提交的文件(请根据 diff 内容选择合适的文件)\");\n }\n\n if (message && message.trim().length > 0) {\n steps.push(`5. 运行 \\`git commit -m \"${message}\"\\` 创建提交`);\n } else {\n steps.push(\n '5. 运行 `git commit -m \"<生成的提交消息>\"` 创建提交(使用约定式提交格式:feat/fix/refactor/chore + 中文描述)',\n );\n }\n\n steps.push(\n \"6. 运行 `git push` 推送到远程仓库\",\n \"\",\n \"注意事项:\",\n \"- 提交消息使用约定式提交格式:类型用英文(feat/fix/refactor/chore/docs/test),描述用中文\",\n \"- 每次提交后立即执行 git push\",\n \"- 如果推送失败(如远程有更新),先执行 git pull --rebase 再推送\",\n \"- 不要提交 .env 文件或包含密钥的配置文件\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /review 命令 — 审查 GitHub Pull Request。\n *\n * 生成中文指令,引导模型获取 PR 变更并给出结构化审查意见:\n * 1. 获取 PR 信息(列表或详情)\n * 2. 获取 PR diff 内容\n * 3. 系统化分析:bug、风格、测试、安全\n * 4. 输出结构化审查报告\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface ReviewCommandArgs {\n /** PR 编号(可选,省略时列出所有待审查的 PR)。 */\n number?: number;\n /** 目标分支(用于 gh pr list 的 --base 过滤)。 */\n base?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /review 命令,返回一段中文指令引导模型完成代码审查。\n */\nexport function handleReviewCommand(args: ReviewCommandArgs): { instruction: string } {\n const { number, base } = args;\n\n const steps: string[] = [\"# GitHub PR 审查任务\", \"\", \"请按以下步骤完成 PR 审查:\", \"\"];\n\n if (number !== undefined) {\n steps.push(\n `1. 运行 \\`gh pr view ${number} --json number,title,author,body,state,additions,deletions,files\\` 获取 PR #${number} 的详细信息`,\n `2. 运行 \\`gh pr diff ${number}\\` 获取 PR #${number} 的完整变更内容`,\n );\n } else {\n const baseFilter = base ? ` --base ${base}` : \"\";\n steps.push(\n `1. 运行 \\`gh pr list --state open --limit 10${baseFilter}\\` 列出待审查的 PR`,\n \"2. 选择一个需要审查的 PR,运行 `gh pr diff <number>` 获取完整变更内容\",\n );\n }\n\n steps.push(\n \"\",\n \"3. 系统化分析变更内容(按以下维度):\",\n \"\",\n \" a) 正确性:逻辑错误、边界条件处理、空值/null 检查、竞态条件\",\n \" b) 安全性:输入校验、注入风险、密钥泄露、权限检查\",\n \" c) 代码风格:命名规范、函数长度、嵌套层级、重复代码\",\n \" d) 测试:测试覆盖率、边界情况覆盖、错误路径测试\",\n \" e) 架构:模块耦合度、接口设计、依赖方向是否正确\",\n \" f) 性能:不必要的循环、大对象分配、阻塞 IO\",\n \"\",\n \"4. 输出结构化审查报告:\",\n \"\",\n \" - 总体评价(1-2 句话总结)\",\n \" - 严重问题(必须修复才能合并)\",\n \" - 建议改进(推荐但不阻塞合并)\",\n \" - 亮点(做得好的地方)\",\n \"\",\n \"注意:审查要具体,引用具体文件和行号。\",\n \"如果 PR 描述中有验收标准,逐条检查是否满足。\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /pr-comments 命令 — 处理 PR 审查评论。\n *\n * 生成中文指令,引导模型:\n * 1. 获取 PR 所有评论\n * 2. 处理未解决的评论(修改代码)\n * 3. 回复已解决的评论(确认)\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface PrCommentsCommandArgs {\n /** PR 编号(可选,省略时从最近 PR 推断)。 */\n number?: number;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /pr-comments 命令,返回一段中文指令引导模型处理 PR 评论。\n */\nexport function handlePrCommentsCommand(args: PrCommentsCommandArgs): { instruction: string } {\n const { number } = args;\n\n const steps: string[] = [\"# PR 评论处理任务\", \"\", \"请按以下步骤处理 PR 审查评论:\", \"\"];\n\n if (number !== undefined) {\n steps.push(\n `1. 运行 \\`gh pr view ${number} --comments\\` 获取 PR #${number} 的所有评论`,\n `2. 运行 \\`gh pr view ${number} --json reviewRequests,reviews\\` 查看审查状态`,\n );\n } else {\n steps.push(\n \"1. 运行 `gh pr list --state open --limit 5` 找到当前活跃的 PR\",\n \"2. 对目标 PR 运行 `gh pr view <number> --comments` 获取所有评论\",\n );\n }\n\n steps.push(\n \"\",\n \"3. 逐条处理评论:\",\n \"\",\n \" 对于未解决的评论(需要代码修改):\",\n \" - 理解评论指出的问题\",\n \" - 使用 read_file 读取相关文件,确认上下文\",\n \" - 使用 edit_file 或 write_file 进行针对性修改\",\n \" - 修改后使用 gh api 回复评论说明修改内容\",\n \"\",\n \" 对于已解决的评论(无需修改):\",\n ' - 添加简短回复确认处理完毕(如 \"已修复,感谢指正\")',\n \"\",\n \"4. 所有评论处理完后,运行 `gh pr view <number> --comments` 确认没有遗漏\",\n \"\",\n \"注意:\",\n \"- 一次修改尽量覆盖多条相关评论,减少提交次数\",\n \"- 如有不理解的评论,标记出来请求澄清\",\n \"- 修改完成后简要总结所有变更\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /issue 命令 — 管理 GitHub Issue。\n *\n * 生成中文指令,引导模型执行 Issue 操作:\n * create — 创建新 Issue\n * list — 列出仓库 Issue\n * view — 查看指定 Issue 详情\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface IssueCommandArgs {\n /** 操作类型:create 创建、list 列出、view 查看。 */\n action?: \"create\" | \"list\" | \"view\";\n /** Issue 标题(create 时使用)。 */\n title?: string;\n /** Issue 编号(view 时使用)。 */\n number?: number;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /issue 命令,返回一段中文指令引导模型完成 Issue 操作。\n */\nexport function handleIssueCommand(args: IssueCommandArgs): { instruction: string } {\n const { action = \"list\", title, number } = args;\n\n const steps: string[] = [];\n\n switch (action) {\n case \"create\": {\n steps.push(\"# 创建 GitHub Issue\", \"\", \"请按以下步骤创建新 Issue:\", \"\");\n if (title && title.trim().length > 0) {\n steps.push(\n \"1. 基于以下标题编写详细的 Issue 正文(包括问题描述、复现步骤、预期行为、环境信息)\",\n ` 标题:${title}`,\n );\n } else {\n steps.push(\n \"1. 首先了解需要创建什么 Issue——分析当前上下文,确定 Issue 的主题和内容\",\n \"2. 编写 Issue 正文(包括问题描述、复现步骤、预期行为、环境信息)\",\n );\n }\n steps.push(\n \"\",\n `3. 运行 \\`gh issue create --title \"<标题>\" --body \"<正文>\"\\` 创建 Issue`,\n \"\",\n \"注意:\",\n \"- 如果是 Bug 报告,需要包含:环境、复现步骤、实际行为、预期行为\",\n \"- 如果是功能请求,需要包含:动机、方案描述、替代方案\",\n \"- 描述要清晰具体,让维护者无需追问即可理解\",\n );\n break;\n }\n\n case \"view\": {\n if (number !== undefined) {\n steps.push(\n \"# 查看 GitHub Issue\",\n \"\",\n `1. 运行 \\`gh issue view ${number}\\` 查看 Issue #${number} 详情`,\n `2. 运行 \\`gh issue view ${number} --comments\\` 查看所有评论`,\n \"3. 总结 Issue 关键信息:标题、状态、标签、提出者、讨论要点\",\n );\n } else {\n steps.push(\n \"# 查看 GitHub Issue\",\n \"\",\n \"1. 运行 `gh issue list --state open --limit 10` 列出活跃 Issue\",\n \"2. 选择一个 Issue,运行 `gh issue view <number>` 查看详情\",\n \"3. 总结 Issue 关键信息\",\n );\n }\n break;\n }\n\n case \"list\":\n default: {\n steps.push(\n \"# 列出 GitHub Issue\",\n \"\",\n \"1. 运行 `gh issue list --state open --limit 20` 列出活跃 Issue\",\n \"2. 以结构化表格展示:编号、标题、标签、状态、负责人、更新时间\",\n \"3. 可选:添加 --label <name> 按标签过滤,或 --assignee <user> 按负责人过滤\",\n );\n break;\n }\n }\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /autofix-pr 命令 — 自动修复 PR 问题。\n *\n * ⚠️ 功能正在开发中,当前为占位实现。\n * 后续将与 gh cli 集成,实现自动分析 PR 失败检查并生成修复方案。\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface AutoFixCommandArgs {\n /** PR 编号(可选)。 */\n number?: number;\n /** 要修复的问题描述(可选)。 */\n issue?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /autofix-pr 命令。\n *\n * 当前为占位实现,返回开发中提示信息。\n * 后续将实现完整的自动修复管线。\n */\nexport function handleAutoFixCommand(_args: AutoFixCommandArgs): { instruction: string } {\n return {\n instruction: \"自动修复功能正在开发中,暂不可用。请关注后续版本更新。\",\n };\n}\n","/**\n * /diff 命令 — 展示 Git 工作区变更。\n *\n * 生成中文指令,引导模型:\n * 1. 运行 git diff 获取未暂存变更\n * 2. 运行 git diff --staged 获取已暂存变更\n * 3. 以结构化格式展示,高亮关键变更\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface DiffCommandArgs {\n /** 是否仅显示已暂存的变更(git diff --staged)。 */\n staged?: boolean;\n /** 指定要查看 diff 的文件列表(可选)。 */\n files?: string[];\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /diff 命令,返回一段中文指令引导模型展示代码变更。\n */\nexport function handleDiffCommand(args: DiffCommandArgs): { instruction: string } {\n const { staged, files } = args;\n\n const steps: string[] = [\"# Git 变更查看任务\", \"\", \"请按以下步骤展示工作区变更:\", \"\"];\n\n if (staged) {\n steps.push(\"1. 运行 `git diff --staged --stat` 查看已暂存变更的文件摘要\");\n if (files && files.length > 0) {\n const fileList = files.map((f) => `\"${f}\"`).join(\" \");\n steps.push(`2. 运行 \\`git diff --staged -- ${fileList}\\` 查看指定文件的已暂存变更详情`);\n } else {\n steps.push(\"2. 运行 `git diff --staged` 查看所有已暂存变更详情\");\n }\n } else {\n steps.push(\"1. 运行 `git diff --stat` 查看未暂存变更的文件摘要\");\n steps.push(\"2. 运行 `git status --short` 查看工作区状态概览\");\n if (files && files.length > 0) {\n const fileList = files.map((f) => `\"${f}\"`).join(\" \");\n steps.push(`3. 运行 \\`git diff -- ${fileList}\\` 查看指定文件的变更详情`);\n } else {\n steps.push(\"3. 运行 `git diff` 查看所有未暂存变更详情\");\n }\n steps.push(\"4. 运行 `git diff --staged --stat` 同时查看已暂存变更(如有)\");\n }\n\n steps.push(\n \"\",\n \"5. 以结构化格式展示变更:\",\n \"\",\n \" - 变更文件列表(按状态分类:新增 A、修改 M、删除 D、重命名 R)\",\n \" - 每个文件的核心变更摘要(增减行数、主要修改内容)\",\n \" - 高亮关键变更(如公共 API 签名修改、配置变更、新增依赖)\",\n \" - 如有安全问题提醒(如密钥硬编码、不安全依赖版本)\",\n \"\",\n \"注意:\",\n \"- 如果 diff 输出过长,优先展示关键文件的变更\",\n \"- 对于二进制文件变更,说明文件名和大小变化即可\",\n \"- 如果没有任何变更,明确告知用户工作区干净\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /ant-trace — 工具调用链追踪可视化。\n *\n * 返回 model instruction,指示模型从会话历史中提取 tool_use / tool_result 配对,\n * 构建父子调用树并标注耗时与错误。TUI 层用 local-jsx 渲染为可折叠树形组件。\n *\n * 用法:/ant-trace [--session <id>] 默认追踪当前会话。\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface AntTraceOptions {\n /** 可选:要追踪的会话 ID,默认当前会话。 */\n sessionId?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /ant-trace 命令。\n *\n * 返回一条 model instruction,驱动模型检查会话历史中的\n * 工具调用链并生成结构化诊断输出。\n */\nexport function handleAntTraceCommand(opts: AntTraceOptions): { instruction: string } {\n const scope = opts.sessionId ? `会话 ${opts.sessionId}` : \"当前会话\";\n\n const instruction = `请对${scope}中的工具调用链进行全面追踪分析,输出结构化调用树。\n\n### 分析步骤\n\n1. **扫描消息**:遍历会话中所有消息,找出 tool_use 和 tool_result 块。\n2. **构建调用树**:根据 tool_use 的父子关系(通过 callId / parentCallId 关联)构建树状结构。\n3. **计算耗时**:为每个工具调用计算从 tool_use 到对应 tool_result 的时间差。\n4. **标记异常**:对以下情况高亮标注:\n - 非零 exitCode 的调用\n - 返回 error 的调用\n - 耗时超过 10 秒的调用(慢调用)\n - 被 abort 中断的调用\n5. **输出格式**:以缩进文本树形式呈现,包含:\n - 工具名称\n - 调用耗时(ms)\n - 输入摘要(截断至 80 字符)\n - 输出摘要(截断至 80 字符)\n - 状态标记:✓ 成功 / ✗ 失败 / ⚠ 慢调用 / ⊗ 已中断\n\n### 输出示例\n\n\\`\\`\\`\nant-trace — ${scope} 工具调用链\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n└─ todo_write (12ms) ✓\n ├─ 输入: {\"todos\": [...]}\n └─ 输出: todos updated\n\n└─ read_file (45ms) ✓\n ├─ 输入: {\"file_path\": \"...\"}\n └─ 输出: 156 lines read\n\n└─ bash:npm test (3420ms) ⚠ 慢调用\n ├─ 输入: {\"command\": \"npm test\"}\n └─ 输出: Tests: 12 passed, 1 failed\n └─ grep (180ms) ✗ 失败\n ├─ 输入: {\"pattern\": \"error\"}\n └─ 错误: exit code 1\n\n═══════════════════════════════\n总计:15 次工具调用,13 成功,1 失败,1 慢调用\n总耗时:3,847ms\n\\`\\`\\`\n\n请先通过搜索会话消息构建调用树,再输出分析结果。`;\n\n return { instruction };\n}\n","/**\n * /debug-tool-call — 单步工具调用调试器。\n *\n * 用于排查单个工具调用的输入、输出、错误和耗时细分。\n * 支持按工具名称或步骤索引定位调用,不带参数时列出最近的调用概览。\n *\n * 用法:\n * /debug-tool-call 列出最近调用\n * /debug-tool-call --tool <name> 查看指定工具的最后一次调用\n * /debug-tool-call --step <index> 查看指定步骤索引处的工具调用\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface DebugToolCallOptions {\n /** 按工具名称过滤,查看该工具的最后一次调用详情。 */\n tool?: string;\n /** 按步骤索引定位(从 1 开始),查看该步骤的工具调用。 */\n step?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /debug-tool-call 命令。\n *\n * 返回一条 model instruction,驱动模型检查会话历史中的\n * 工具调用并输出调试信息。\n */\nexport function handleDebugToolCall(opts: DebugToolCallOptions): { instruction: string } {\n if (opts.tool) {\n const toolName = opts.tool;\n return {\n instruction: `请调试工具 \"${toolName}\" 在当前会话中最后一次调用的完整详情。\n\n### 分析要求\n\n1. **定位调用**:在会话消息中搜索最后一个 tool_use 名称为 \"${toolName}\" 的调用。\n2. **展示完整输入**:格式化输出完整的 input JSON(不做截断)。\n3. **展示完整输出**:格式化输出 tool_result 的完整内容。\n4. **错误诊断**:如果调用返回错误或非零退出码,分析可能原因:\n - 输入参数是否有问题?\n - 环境(路径、权限、网络)是否有问题?\n - 是否有并发竞争?\n5. **耗时细分**:如果可用,将耗时分解为:\n - 网络往返时间(如有)\n - 进程启动时间(如适用)\n - 实际处理时间\n - 总耗时\n\n### 输出格式\n\n\\`\\`\\`\ndebug-tool-call: ${toolName}\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n状态:✓ 成功 / ✗ 失败\n\n📥 完整输入:\n{完整 JSON}\n\n📤 完整输出:\n{完整输出内容}\n\n⏱ 耗时细分:\n 总计:235ms\n └─ 网络:12ms\n └─ 处理:210ms\n └─ 其他:13ms\n\n🔍 诊断结论:\n{分析结论或\"无异常\"}\n\\`\\`\\`\n\n如果找不到该工具的调用记录,请明确报告。`,\n };\n }\n\n if (opts.step) {\n const stepIdx = opts.step;\n return {\n instruction: `请展示会话中步骤 ${stepIdx} 处的所有工具调用详情。\n\n### 步骤定义\n\n步骤按时间顺序编号(从 1 开始),每个步骤包含该轮对话中调用的所有工具。\n步骤 ${stepIdx} 可能包含多个并行或串行的工具调用。\n\n### 分析要求\n\n1. **列出所有调用**:该步骤中所有的 tool_use 名称和 callId。\n2. **逐一展示详情**:\n - 输入参数(完整 JSON)\n - 输出内容(完整文本)\n - 执行耗时(ms)\n - 成功/失败状态\n3. **步骤总结**:\n - 调用数量\n - 成功/失败统计\n - 总耗时\n\n### 输出格式\n\n\\`\\`\\`\ndebug-tool-call: 步骤 ${stepIdx}\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n本步骤共 N 次工具调用(M 成功 / K 失败)\n\n── 调用 1:<工具名> ──────────────────\n状态:✓\n输入:{...}\n输出:{...}\n耗时:120ms\n\n── 调用 2:<工具名> ──────────────────\n状态:✗ 失败\n输入:{...}\n错误:...\n耗时:45ms\n\\`\\`\\`\n\n如果步骤 ${stepIdx} 不存在,请报告可用步骤范围。`,\n };\n }\n\n // 默认:列出最近的工具调用概览\n return {\n instruction: `请列出当前会话中最近的工具调用概览(最多 20 条)。\n\n### 输出格式\n\n以编号列表展示,每条包含:\n- 步骤编号(可用作 --step 参数)\n- 工具名称\n- 调用耗时(ms)\n- 状态图标(✓ / ✗ / ⚠)\n- 输入摘要(截断至 60 字符)\n\n\\`\\`\\`\ndebug-tool-call: 最近调用概览\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n#1 步骤 1 todo_write 12ms ✓ {\"todos\": [...]}\n#2 步骤 1 read_file 45ms ✓ {\"file_path\": \"src/...\"}\n#3 步骤 2 bash 3420ms ⚠ {\"command\": \"npm t...\"}\n#4 步骤 2 grep 180ms ✗ {\"pattern\": \"err...\"}\n#5 步骤 3 write_file 23ms ✓ {\"file_path\": \"src/...\"}\n\n────────────────────────────────\n共 15 次调用。使用 --step <N> 查看某步骤详情,--tool <name> 查看特定工具详情。\n\\`\\`\\`\n\n请根据会话消息生成上述列表。`,\n };\n}\n","/**\n * /tasks — 后台任务监视与控制。\n *\n * 列出当前后台任务状态,支持取消运行中的任务和查看任务详情。\n * 该命令与 TUI 层的 TasksPanel 组件配合使用:\n * - list:打开任务面板,展示实时状态(带色彩编码)\n * - cancel:通过 taskId 取消指定任务\n * - detail:展示任务的完整输出流\n *\n * 用法:\n * /tasks 列出所有任务(默认)\n * /tasks --action cancel --taskId <id> 取消任务\n * /tasks --action detail --taskId <id> 查看任务详情\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface TasksCommandOptions {\n /** 操作类型:list(默认)、cancel、detail。 */\n action?: string;\n /** cancel 或 detail 操作时必填。 */\n taskId?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /tasks 命令。\n *\n * 根据 action 返回不同的 model instruction,驱动模型\n * 执行相应的任务管理操作。\n */\nexport function handleTasksCommand(opts: TasksCommandOptions): { instruction: string } {\n const action = opts.action ?? \"list\";\n\n switch (action) {\n case \"cancel\": {\n if (!opts.taskId) {\n return {\n instruction:\n \"请提示用户:取消任务需要提供 --taskId 参数。例如:/tasks --action cancel --taskId <id>\",\n };\n }\n return {\n instruction: `请取消任务 \"${opts.taskId}\"。\n\n### 操作步骤\n\n1. 使用 task 工具的 cancel 操作取消该任务。\n2. 如果任务不存在或已经结束,报告给用户。\n3. 如果取消成功,确认并展示任务在取消前的状态。\n\n### 输出格式\n\n\\`\\`\\`\n取消任务:${opts.taskId}\n━━━━━━━━━━━━━━━━━━━━\n状态:已取消\n任务名称:<name>\n运行时长:<duration>\n\\`\\`\\``,\n };\n }\n\n case \"detail\": {\n if (!opts.taskId) {\n return {\n instruction:\n \"请提示用户:查看任务详情需要提供 --taskId 参数。例如:/tasks --action detail --taskId <id>\",\n };\n }\n return {\n instruction: `请展示任务 \"${opts.taskId}\" 的完整详情。\n\n### 内容要求\n\n1. **基本信息**:任务 ID、名称、状态、创建时间、运行时长\n2. **输入参数**:任务启动时的完整输入\n3. **输出流**:任务执行期间产生的所有输出(stdout + stderr)\n4. **错误信息**:如果任务失败,展示完整错误堆栈\n5. **子任务**:如果该任务包含子任务,列出子任务树\n\n### 输出格式\n\n\\`\\`\\`\n任务详情:${opts.taskId}\n━━━━━━━━━━━━━━━━━━━━━━\n\n📋 基本信息\n 名称:<任务名称>\n 状态:运行中 / 完成 / 失败 / 排队中\n 创建:<ISO 时间>\n 运行时长:<duration>\n\n📥 输入参数\n{完整 JSON}\n\n📤 输出流\n────────────────────────\n{完整 stdout 输出}\n────────────────────────\n{如 stderr 有内容则展示}\n\n❌ 错误信息\n{如有}\n\\`\\`\\``,\n };\n }\n\n default: {\n // list — 展示所有后台任务\n return {\n instruction: `请列出当前所有后台任务的状态概览。\n\n### 内容要求\n\n展示以下信息(每项任务一行):\n- **状态图标**:\n - ⟳ 运行中(青色高亮)\n - ○ 排队中(灰色)\n - ✓ 完成(绿色)\n - ✗ 失败(红色)\n- **进度条**:运行中的任务展示完成百分比(如 \"[████████░░] 80%\")\n- **任务名称**\n- **运行时长**(运行中的任务)\n- **错误摘要**(失败的任务,截断至一行)\n- **取消按钮**:对运行中的任务提示可用 \"/tasks cancel --taskId <id>\" 取消\n\n### 输出格式\n\n\\`\\`\\`\n任务面板\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n⟳ phase2-scanExtensions [████████░░] 80% 已运行 3s\n✓ phase2-preloadSkills 完成 (1.2s)\n✗ phase2-connectMcpServers 失败 — 连接超时\n○ phase2-loadMemory 排队中\n✓ phase2-initChannels 完成 (0.8s)\n\n────────────────────────────────────────────\n共 5 个任务:1 运行中,1 排队,2 完成,1 失败\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n📌 提示:\n /tasks --action detail --taskId <id> 查看任务完整输出\n /tasks --action cancel --taskId <id> 取消运行中的任务\n\\`\\`\\`\n\n请调用 task 工具的 list 操作获取任务列表,然后按上述格式输出。`,\n };\n }\n }\n}\n","/**\n * /heapdump — V8 堆快照,用于内存泄漏诊断。\n *\n * 调用 Node.js 内置的 writeHeapSnapshot() 生成 .heapsnapshot 文件,\n * 保存到 ~/.lynx/heapdumps/ 目录下。可在 Chrome DevTools 的\n * Memory 面板中加载分析。\n *\n * 用法:/heapdump\n */\n\nimport { writeHeapSnapshot } from \"node:v8\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { existsSync, mkdirSync } from \"node:fs\";\n\n// ── Constants ────────────────────────────────────────\n\n/** 堆快照输出目录 */\nconst HEAPDUMP_DIR = join(homedir(), \".lynx\", \"heapdumps\");\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /heapdump 命令。\n *\n * 生成立即堆快照并返回文件路径。这是 local 类型命令——\n * 不经过模型,直接在 CLI 进程中执行。\n */\nexport async function handleHeapdumpCommand(): Promise<{ output: string }> {\n // 确保输出目录存在\n if (!existsSync(HEAPDUMP_DIR)) {\n try {\n mkdirSync(HEAPDUMP_DIR, { recursive: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n output: `错误:无法创建堆快照目录 ${HEAPDUMP_DIR}:${message}`,\n };\n }\n }\n\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const filepath = join(HEAPDUMP_DIR, `heap-${timestamp}.heapsnapshot`);\n\n try {\n const filename = writeHeapSnapshot(filepath);\n // writeHeapSnapshot 会在文件名后追加进程 ID,因此使用它返回的实际文件名\n return {\n output:\n `堆快照已保存到:${filename}\\n\\n` +\n `共 ${getDumpCount()} 个快照文件。\\n` +\n `分析步骤:\\n` +\n ` 1. 打开 Chrome DevTools\\n` +\n ` 2. 切换到 Memory 面板\\n` +\n ` 3. 点击 \"Load\" 加载 \"${filename}\"\\n` +\n ` 4. 按 Retained Size 排序查找内存泄漏`,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n output: `错误:堆快照生成失败:${message}`,\n };\n }\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/**\n * 获取 dump 目录下的快照文件数量(用于提示用户定期清理)。\n */\nfunction getDumpCount(): number {\n try {\n const { readdirSync } = require(\"node:fs\");\n const entries = readdirSync(HEAPDUMP_DIR);\n return entries.filter((f: string) => f.endsWith(\".heapsnapshot\")).length;\n } catch {\n return -1;\n }\n}\n","/**\n * /perf-issue — 性能问题诊断。\n *\n * 返回 model instruction,驱动模型分析性能问题、检查日志、\n * 筛查慢调用和内存使用模式,并给出优化建议。\n *\n * 用法:\n * /perf-issue 通用性能健康检查\n * /perf-issue --issue <描述> 针对具体问题的诊断\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface PerfIssueOptions {\n /** 可选:用户描述的具体性能问题。不提供则执行通用健康检查。 */\n issue?: string;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst HEALTH_CHECK_INSTRUCTION = `请对当前会话进行全面的性能健康检查,输出诊断报告。\n\n### 检查项目\n\n1. **慢调用筛查**\n - 扫描会话中所有 tool_use/tool_result 对\n - 计算每次工具调用的耗时\n - 标记耗时 > 5 秒的\"慢调用\"和 > 30 秒的\"极慢调用\"\n - 分析慢调用的公共模式(相同的工具?相似的输入?特定时间段?)\n\n2. **日志分析**\n - 检查 ~/.lynx/logs/ 目录下的最新日志文件\n - 查找错误、警告和超时记录\n - 查找重复出现的模式(如每 30 秒的重试风暴)\n - 提取关键性能指标(如 MCP 连接延迟、模型响应延迟)\n\n3. **内存使用模式**\n - 查看最近的内存监控数据(如有)\n - 检查是否存在持续增长的内存趋势(可能泄漏)\n - 注意 heapUsed 在短时间内陡增的模式\n\n4. **会话效率**\n - 统计工具调用次数和总耗时\n - 计算\"有效工具调用比\"(有产出的调用 / 总调用)\n - 识别冗余调用(重复读取同一文件、重复搜索相同模式)\n\n5. **优化建议**\n - 针对发现的问题给出具体优化建议\n - 按优先级排序:高(立即修复)、中(下次迭代)、低(长期优化)\n\n### 输出格式\n\n\\`\\`\\`\n性能健康检查报告\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n📊 会话概况\n 会话时长:<duration>\n 工具调用:N 次\n 总耗时:<X>ms\n 平均耗时:<Y>ms/调用\n\n🐢 慢调用(共 N 个)\n #1 todo_write 5.2s ⚠ 超过阈值\n #2 bash 32.1s 🔴 极慢\n\n📋 日志摘要\n [WARN] MCP 连接超时 — 出现 3 次\n [ERROR] 文件未找到 — 出现 1 次\n\n🧠 内存\n 当前堆使用:<X>MB\n 趋势:稳定 / 上升(12% 增长)\n 风险等级:低 / 中 / 高\n\n📈 效率分析\n 有效调用率:85%(17/20)\n 冗余调用:2 次(重复读取同一文件)\n\n💡 优化建议\n 🔴 [高] 合并对同一文件的多次读取\n 🟡 [中] 为频繁搜索添加缓存\n 🟢 [低] 考虑减少 todo_write 的调用频率\n\\`\\`\\``;\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /perf-issue 命令。\n *\n * 返回 model instruction,驱动模型执行性能诊断分析。\n */\nexport function handlePerfIssueCommand(opts: PerfIssueOptions): { instruction: string } {\n if (opts.issue) {\n return {\n instruction: `请诊断以下性能问题:\"${opts.issue}\"\n\n### 诊断步骤\n\n1. **复现分析**:根据问题描述,推测最可能的性能瓶颈点。\n2. **日志排查**:检查 ~/.lynx/logs/ 目录下相关日志,搜索与问题相关的错误或警告。\n3. **调用链分析**:如果在会话历史中,查找与问题描述相关的工具调用,分析其耗时特征。\n4. **系统资源**:检查当前进程的 CPU 和内存使用情况。\n5. **环境因素**:考虑网络延迟、磁盘 I/O、第三方服务响应时间等外部因素。\n6. **根因分析**:给出最可能的根因(不超过 3 个)。\n7. **解决方案**:针对每个根因给出具体的修复步骤。\n\n### 输出格式\n\n\\`\\`\\`\n性能诊断:${opts.issue}\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n🔍 问题复现\n{分析}\n\n📊 数据支撑\n{日志片段、耗时数据、调用链}\n\n🎯 根因分析\n 1. <最可能的根因>\n 2. <次要可能性>\n 3. <边缘情况>\n\n🛠 解决方案\n 方案 1:<具体步骤>\n 方案 2:<具体步骤>\n 方案 3:<具体步骤>\n\n📌 验证方法\n{如何确认问题已解决}\n\\`\\`\\`\n\n请按上述步骤执行诊断,优先检查日志和当前会话数据。`,\n };\n }\n\n return { instruction: HEALTH_CHECK_INSTRUCTION };\n}\n","/**\n * /share — 将会话导出为可分享的 Markdown 文件。\n *\n * 从 ~/.lynx/sessions/{sessionId}.json 读取消息,\n * 格式化为干净的 Markdown 后写入 ~/.lynx/exports/ 目录。\n */\n\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { openDatabase, resolvePaths } from \"@lynx/core\";\nimport type { Message, ContentBlock } from \"@lynx/core\";\nimport { getLastSession } from \"@lynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface ShareCommandOptions {\n sessionId?: string;\n output?: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 从 JSON 文件加载会话消息。 */\nfunction loadSessionMessages(sessionId: string): Message[] {\n const messagesPath = join(homedir(), \".lynx\", \"sessions\", `${sessionId}.json`);\n if (!existsSync(messagesPath)) {\n throw new Error(`会话消息文件未找到:${messagesPath}`);\n }\n const raw = readFileSync(messagesPath, \"utf-8\");\n const data = JSON.parse(raw);\n return data.messages ?? [];\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/** 截断过长文本,保留开头和结尾的提示。 */\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n const half = Math.floor(maxLen / 2);\n return text.slice(0, half) + \"\\n...(内容已截断)...\\n\" + text.slice(-half);\n}\n\n/** 将内容块转为适合嵌入 Markdown 的文本。 */\nfunction blockToMarkdown(block: ContentBlock): string {\n switch (block.type) {\n case \"text\":\n return block.text;\n case \"tool_use\":\n return `_**调用工具:** ${block.name}_\\n\\`\\`\\`json\\n${JSON.stringify(block.input, null, 2)}\\n\\`\\`\\``;\n case \"tool_result\":\n if (block.isError) {\n return `<details><summary>工具执行出错</summary>\\n\\n\\`\\`\\`\\n${block.content}\\n\\`\\`\\`\\n</details>`;\n }\n return `<details><summary>工具执行结果</summary>\\n\\n\\`\\`\\`\\n${truncate(block.content, 3000)}\\n\\`\\`\\`\\n</details>`;\n case \"reasoning\":\n return `<details><summary>思考过程</summary>\\n\\n${block.text}\\n</details>`;\n default:\n return \"\";\n }\n}\n\n/** 将会话消息列表格式化为 Markdown。 */\nfunction formatSessionAsMarkdown(messages: Message[], sessionLabel: string): string {\n const lines: string[] = [];\n lines.push(`# ${sessionLabel}`);\n lines.push(\"\");\n lines.push(`> 导出时间:${new Date().toISOString()}`);\n lines.push(`> 消息总数:${messages.length}`);\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n for (const msg of messages) {\n // 跳过纯系统消息\n if (msg.role === \"system\") continue;\n\n const roleLabel = msg.role === \"user\" ? \"用户\" : \"Lynx\";\n const emoji = msg.role === \"user\" ? \"🧑\" : \"🤖\";\n\n lines.push(`### ${emoji} ${roleLabel}`);\n lines.push(\"\");\n\n for (const block of msg.content) {\n const md = blockToMarkdown(block);\n if (md) lines.push(md);\n }\n\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /share 命令。\n *\n * 将会话消息导出为 Markdown 文件,方便分享。\n * 默认导出最近一次会话,可通过 --session-id 指定。\n */\nexport async function handleShareCommand(opts: ShareCommandOptions): Promise<{ output: string }> {\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const messages = loadSessionMessages(sessionId);\n\n if (messages.length === 0) {\n return { output: `会话 ${sessionId} 中没有消息。` };\n }\n\n const markdown = formatSessionAsMarkdown(messages, `会话 ${sessionId}`);\n\n const exportsDir = join(homedir(), \".lynx\", \"exports\");\n if (!existsSync(exportsDir)) {\n mkdirSync(exportsDir, { mode: 0o700, recursive: true });\n }\n\n const outputPath = opts.output ?? join(exportsDir, `session-${sessionId}.md`);\n const outputDir = dirname(outputPath);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { mode: 0o700, recursive: true });\n }\n\n writeFileSync(outputPath, markdown, \"utf-8\");\n return { output: `会话已导出到:${outputPath}` };\n}\n","/**\n * /export — 以多种格式导出会话。\n *\n * 支持三种输出格式:\n * - markdown:与 /share 相同,格式化为可读的 Markdown\n * - json:导出原始消息数组(格式化 JSON)\n * - html:将 Markdown 包裹在基础 HTML 模板中\n */\n\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { openDatabase, resolvePaths } from \"@lynx/core\";\nimport type { Message, ContentBlock } from \"@lynx/core\";\nimport { getLastSession } from \"@lynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface ExportCommandOptions {\n sessionId?: string;\n format?: \"markdown\" | \"json\" | \"html\";\n output?: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 从 JSON 文件加载会话消息。 */\nfunction loadSessionMessages(sessionId: string): Message[] {\n const messagesPath = join(homedir(), \".lynx\", \"sessions\", `${sessionId}.json`);\n if (!existsSync(messagesPath)) {\n throw new Error(`会话消息文件未找到:${messagesPath}`);\n }\n const raw = readFileSync(messagesPath, \"utf-8\");\n const data = JSON.parse(raw);\n return data.messages ?? [];\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/** 截断过长文本。 */\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n const half = Math.floor(maxLen / 2);\n return text.slice(0, half) + \"\\n...(内容已截断)...\\n\" + text.slice(-half);\n}\n\n/** 将内容块转为适合嵌入 Markdown 的文本。 */\nfunction blockToMarkdown(block: ContentBlock): string {\n switch (block.type) {\n case \"text\":\n return block.text;\n case \"tool_use\":\n return `_**调用工具:** ${block.name}_\\n\\`\\`\\`json\\n${JSON.stringify(block.input, null, 2)}\\n\\`\\`\\``;\n case \"tool_result\":\n if (block.isError) {\n return `<details><summary>工具执行出错</summary>\\n\\n\\`\\`\\`\\n${block.content}\\n\\`\\`\\`\\n</details>`;\n }\n return `<details><summary>工具执行结果</summary>\\n\\n\\`\\`\\`\\n${truncate(block.content, 3000)}\\n\\`\\`\\`\\n</details>`;\n case \"reasoning\":\n return `<details><summary>思考过程</summary>\\n\\n${block.text}\\n</details>`;\n default:\n return \"\";\n }\n}\n\n/** 将会话消息列表格式化为 Markdown。 */\nfunction formatSessionAsMarkdown(messages: Message[], sessionId: string): string {\n const lines: string[] = [];\n lines.push(`# 会话 ${sessionId}`);\n lines.push(\"\");\n lines.push(`> 导出时间:${new Date().toISOString()}`);\n lines.push(`> 消息总数:${messages.length}`);\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n for (const msg of messages) {\n if (msg.role === \"system\") continue;\n\n const roleLabel = msg.role === \"user\" ? \"用户\" : \"Lynx\";\n const emoji = msg.role === \"user\" ? \"🧑\" : \"🤖\";\n\n lines.push(`### ${emoji} ${roleLabel}`);\n lines.push(\"\");\n\n for (const block of msg.content) {\n const md = blockToMarkdown(block);\n if (md) lines.push(md);\n }\n\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/** 将 Markdown 包裹在 HTML 模板中。 */\nfunction wrapMarkdownInHtml(markdown: string, sessionId: string): string {\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Lynx 会话导出 — ${sessionId}</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n max-width: 900px;\n margin: 0 auto;\n padding: 2rem;\n line-height: 1.7;\n color: #1a1a1a;\n background: #fafafa;\n }\n h1 { font-size: 2rem; margin-bottom: 0.5rem; color: #111; }\n blockquote { border-left: 4px solid #ddd; padding-left: 1rem; color: #666; margin: 1rem 0; }\n hr { border: none; border-top: 1px solid #e0e0e0; margin: 2rem 0; }\n h3 { font-size: 1.1rem; margin: 1.5rem 0 0.5rem; color: #333; }\n pre {\n background: #f0f0f0;\n border-radius: 6px;\n padding: 1rem;\n overflow-x: auto;\n font-size: 0.9rem;\n }\n code { font-family: \"SF Mono\", \"Fira Code\", \"Fira Mono\", Menlo, Consolas, monospace; font-size: 0.9em; }\n details {\n background: #f5f5f5;\n border-radius: 6px;\n padding: 0.75rem 1rem;\n margin: 0.5rem 0;\n }\n details summary { cursor: pointer; font-weight: 600; color: #555; }\n details pre { margin-top: 0.5rem; }\n .meta { color: #888; font-size: 0.9rem; }\n </style>\n</head>\n<body>\n${markdown}\n</body>\n</html>`;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /export 命令。\n *\n * 以指定格式导出会话,支持 markdown / json / html。\n * 默认导出最近一次会话为 markdown 格式。\n */\nexport async function handleExportCommand(opts: ExportCommandOptions): Promise<{ output: string }> {\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const messages = loadSessionMessages(sessionId);\n\n if (messages.length === 0) {\n return { output: `会话 ${sessionId} 中没有消息。` };\n }\n\n const format = opts.format ?? \"markdown\";\n const exportsDir = join(homedir(), \".lynx\", \"exports\");\n if (!existsSync(exportsDir)) mkdirSync(exportsDir, { mode: 0o700, recursive: true });\n\n const defaultOutput = join(\n exportsDir,\n `session-${sessionId}.${format === \"html\" ? \"html\" : format === \"json\" ? \"json\" : \"md\"}`,\n );\n const outputPath = opts.output ?? defaultOutput;\n const outputDir = dirname(outputPath);\n if (!existsSync(outputDir)) mkdirSync(outputDir, { mode: 0o700, recursive: true });\n\n let content: string;\n\n switch (format) {\n case \"markdown\": {\n content = formatSessionAsMarkdown(messages, sessionId);\n break;\n }\n case \"json\": {\n content = JSON.stringify(messages, null, 2);\n break;\n }\n case \"html\": {\n const md = formatSessionAsMarkdown(messages, sessionId);\n content = wrapMarkdownInHtml(md, sessionId);\n break;\n }\n default: {\n return { output: `不支持的导出格式:${format}。请使用 markdown、json 或 html。` };\n }\n }\n\n writeFileSync(outputPath, content, \"utf-8\");\n return { output: `会话已导出到:${outputPath}(格式:${format})` };\n}\n","/**\n * /tag — 为会话打标签,用于分类管理。\n *\n * 标签数据存储在 ~/.lynx/session-tags.json 中。\n * 支持三种操作:\n * - add:为指定会话添加标签\n * - remove:移除指定标签\n * - list:列出所有带标签的会话,或指定会话的所有标签\n */\n\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { openDatabase, resolvePaths } from \"@lynx/core\";\nimport { getLastSession } from \"@lynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface TagCommandOptions {\n sessionId?: string;\n tag?: string;\n action?: \"add\" | \"remove\" | \"list\";\n}\n\n/** 标签存储格式:{ sessionId: string[] } */\ntype TagsStore = Record<string, string[]>;\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 获取标签文件路径。 */\nfunction tagsFilePath(): string {\n return join(homedir(), \".lynx\", \"session-tags.json\");\n}\n\n/** 加载所有标签数据。 */\nfunction loadTags(): TagsStore {\n const path = tagsFilePath();\n if (!existsSync(path)) return {};\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as TagsStore;\n } catch {\n return {};\n }\n}\n\n/** 保存标签数据。 */\nfunction saveTags(tags: TagsStore): void {\n const path = tagsFilePath();\n const dir = dirname(path);\n if (!existsSync(dir)) mkdirSync(dir, { mode: 0o700, recursive: true });\n writeFileSync(path, JSON.stringify(tags, null, 2), \"utf-8\");\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/**\n * 从数据库获取会话的 label(用于 list 展示)。\n * 如果数据库不可用或会话不存在,返回 sessionId。\n */\nfunction getSessionLabel(sessionId: string): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const stmt = db.prepare(\"SELECT label FROM sessions WHERE id = ?\");\n const row = stmt.get(sessionId) as { label: string } | undefined;\n return row?.label ?? sessionId;\n } catch {\n return sessionId;\n } finally {\n db.close();\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /tag 命令。\n *\n * 为会话添加、移除或列出标签。\n * 默认操作为 list;add/remove 需要提供 --tag 参数。\n */\nexport async function handleTagCommand(opts: TagCommandOptions): Promise<{ output: string }> {\n const action = opts.action ?? \"list\";\n const tags = loadTags();\n\n switch (action) {\n case \"add\": {\n if (!opts.tag || opts.tag.trim().length === 0) {\n return { output: \"错误:请使用 --tag 指定要添加的标签。\" };\n }\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const normalizedTag = opts.tag.trim();\n\n if (!tags[sessionId]) {\n tags[sessionId] = [];\n }\n if (tags[sessionId].includes(normalizedTag)) {\n return { output: `会话 ${sessionId} 已有标签 \"${normalizedTag}\"。` };\n }\n\n tags[sessionId].push(normalizedTag);\n saveTags(tags);\n return { output: `已为会话 ${sessionId} 添加标签 \"${normalizedTag}\"。` };\n }\n\n case \"remove\": {\n if (!opts.tag || opts.tag.trim().length === 0) {\n return { output: \"错误:请使用 --tag 指定要移除的标签。\" };\n }\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const normalizedTag = opts.tag.trim();\n\n if (!tags[sessionId] || !tags[sessionId].includes(normalizedTag)) {\n return { output: `会话 ${sessionId} 没有标签 \"${normalizedTag}\"。` };\n }\n\n tags[sessionId] = tags[sessionId].filter((t) => t !== normalizedTag);\n // 清理空数组\n if (tags[sessionId].length === 0) {\n delete tags[sessionId];\n }\n saveTags(tags);\n return { output: `已从会话 ${sessionId} 移除标签 \"${normalizedTag}\"。` };\n }\n\n case \"list\": {\n if (opts.sessionId) {\n // 列出指定会话的所有标签\n const sessionTags = tags[opts.sessionId];\n if (!sessionTags || sessionTags.length === 0) {\n return { output: `会话 ${opts.sessionId} 没有标签。` };\n }\n const label = getSessionLabel(opts.sessionId);\n return {\n output: `会话 ${opts.sessionId}(${label})的标签:\\n${sessionTags.map((t) => ` - ${t}`).join(\"\\n\")}`,\n };\n }\n\n // 列出所有带标签的会话\n const entries = Object.entries(tags);\n if (entries.length === 0) {\n return { output: \"没有任何已打标签的会话。\" };\n }\n\n const lines: string[] = [];\n for (const [sid, sessionTags] of entries) {\n if (sessionTags.length === 0) continue;\n const label = getSessionLabel(sid);\n lines.push(`${sid}(${label}):${sessionTags.join(\", \")}`);\n }\n\n if (lines.length === 0) {\n return { output: \"没有任何已打标签的会话。\" };\n }\n\n return { output: lines.join(\"\\n\") };\n }\n\n default:\n return { output: `未知操作:${action}。请使用 add、remove 或 list。` };\n }\n}\n","/**\n * /copy — 将最后一条助手回复复制到剪贴板。\n *\n * 从会话中提取指定索引(从末尾倒数)的助手消息文本,\n * 通过平台对应的剪贴板命令写入系统剪贴板。\n *\n * 支持平台:Windows(PowerShell)、macOS(pbcopy)、\n * Linux(xclip 或 wl-copy)。\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { openDatabase, resolvePaths } from \"@lynx/core\";\nimport type { Message } from \"@lynx/core\";\nimport { getLastSession } from \"@lynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CopyCommandOptions {\n sessionId?: string;\n /** 从末尾倒数第几条消息(0 = 最后一条,默认 0)。 */\n index?: number;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 从 JSON 文件加载会话消息。 */\nfunction loadSessionMessages(sessionId: string): Message[] {\n const messagesPath = join(homedir(), \".lynx\", \"sessions\", `${sessionId}.json`);\n if (!existsSync(messagesPath)) {\n throw new Error(`会话消息文件未找到:${messagesPath}`);\n }\n const raw = readFileSync(messagesPath, \"utf-8\");\n const data = JSON.parse(raw);\n return data.messages ?? [];\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/**\n * 从消息中提取纯文本内容(仅 text 类型的内容块)。\n * 跳过 tool_use、tool_result 和 reasoning 块。\n */\nfunction extractTextContent(msg: Message): string {\n const parts: string[] = [];\n for (const block of msg.content) {\n if (block.type === \"text\" && block.text) {\n parts.push(block.text);\n }\n }\n return parts.join(\"\\n\\n\");\n}\n\n/**\n * 检测当前平台并返回对应的剪贴板命令。\n * 返回 [命令, args...] 或 null(不支持的平台)。\n */\nfunction getClipboardCommand(): [string, string[]] | null {\n const platform = process.platform;\n\n if (platform === \"win32\") {\n return [\"powershell\", [\"-Command\", \"Set-Clipboard -Value $input\"]];\n }\n\n if (platform === \"darwin\") {\n return [\"pbcopy\", []];\n }\n\n if (platform === \"linux\") {\n // 优先检测 wl-copy(Wayland)\n try {\n execSync(\"which wl-copy 2>/dev/null || command -v wl-copy 2>/dev/null\", {\n stdio: \"ignore\",\n });\n return [\"wl-copy\", []];\n } catch {\n // 检测 xclip(X11)\n try {\n execSync(\"which xclip 2>/dev/null || command -v xclip 2>/dev/null\", {\n stdio: \"ignore\",\n });\n return [\"xclip\", [\"-selection\", \"clipboard\"]];\n } catch {\n return null;\n }\n }\n }\n\n return null;\n}\n\n/**\n * 将文本写入系统剪贴板。\n * 使用管道将内容传入剪贴板命令的 stdin。\n */\nfunction copyToClipboard(text: string): boolean {\n const cmd = getClipboardCommand();\n if (!cmd) {\n return false;\n }\n\n const [command, args] = cmd;\n try {\n // 处理 PowerShell 的特殊 $input 语法:需要通过管道传入\n if (process.platform === \"win32\") {\n // Windows:使用 StreamWriter 通过管道传入\n execSync(\n `powershell -Command \"$input = [System.IO.StreamReader]::new([System.Console]::OpenStandardInput()).ReadToEnd(); Set-Clipboard -Value $input\"`,\n { input: text, stdio: \"pipe\", timeout: 10_000 },\n );\n } else {\n // Unix:直接通过 stdin 管道传入\n const child = execSync(`${command} ${args.join(\" \")}`, {\n input: text,\n stdio: \"pipe\",\n timeout: 10_000,\n });\n if (child.length > 0) {\n // pbcopy 通常无输出,如果有输出可能是错误\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /copy 命令。\n *\n * 将指定索引(从末尾倒数)的助手消息文本复制到系统剪贴板。\n * 默认复制最后一条助手回复。\n */\nexport async function handleCopyCommand(opts: CopyCommandOptions): Promise<{ output: string }> {\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const messages = loadSessionMessages(sessionId);\n\n if (messages.length === 0) {\n return { output: `会话 ${sessionId} 中没有消息。` };\n }\n\n // 收集所有助手消息(从末尾倒数)\n const assistantMessages = messages.filter((m) => m.role === \"assistant\").toReversed();\n\n if (assistantMessages.length === 0) {\n return { output: `会话 ${sessionId} 中没有助手回复。` };\n }\n\n const index = opts.index ?? 0;\n if (index < 0 || index >= assistantMessages.length) {\n return {\n output: `索引 ${index} 超出范围。会话共有 ${assistantMessages.length} 条助手回复(有效索引:0 到 ${assistantMessages.length - 1})。`,\n };\n }\n\n const targetMessage = assistantMessages[index];\n const text = extractTextContent(targetMessage);\n\n if (!text || text.trim().length === 0) {\n return { output: `助手回复 #${index} 不包含文本内容(可能只有工具调用或思考过程)。` };\n }\n\n const success = copyToClipboard(text);\n if (!success) {\n return {\n output:\n \"无法复制到剪贴板。请确认已安装剪贴板工具:\\n\" +\n \" Windows:PowerShell 5.0+\\n\" +\n \" macOS:系统自带 pbcopy\\n\" +\n \" Linux:请安装 xclip 或 wl-clipboard\",\n };\n }\n\n const preview = text.length > 80 ? text.slice(0, 80) + \"...\" : text;\n return { output: `已复制助手回复 #${index} 到剪贴板。\\n预览:${preview}` };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["httpsRequest","loadSessionMessages","getMostRecentSessionId","truncate","blockToMarkdown","formatSessionAsMarkdown","loadSessionMessages","getMostRecentSessionId","getMostRecentSessionId"],"sources":["../src/args.ts","../src/catalog.ts","../src/debug.ts","../src/doctor/runner.ts","../src/crestodian/runner.ts","../src/commands/session.ts","../src/entry.ts","../src/memory-monitor.ts","../src/update-check.ts","../src/snapshot-store.ts","../src/tui-launcher.ts","../src/worker-pool.ts","../src/commands/plugin.ts","../src/commands/git-commit.ts","../src/commands/git-review.ts","../src/commands/git-pr-comments.ts","../src/commands/git-issue.ts","../src/commands/git-autofix.ts","../src/commands/git-diff.ts","../src/commands/ant-trace.ts","../src/commands/debug-tool-call.ts","../src/commands/tasks.ts","../src/commands/heapdump.ts","../src/commands/perf-issue.ts","../src/commands/share.ts","../src/commands/export.ts","../src/commands/tag.ts","../src/commands/copy.ts"],"sourcesContent":["/**\n * CLI argument parsing — commander setup with all sub‑commands.\n *\n * Each command defers its handler to a lazily‑loaded module\n * so startup remains fast (Phase 1 ≤ 1.5s).\n */\n\nimport { Command } from \"commander\";\nimport { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { dirname, join } from \"node:path\";\n\n// Resolve version from package.json so it always matches the published version\nconst pkgPath = join(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\nconst version = JSON.parse(readFileSync(pkgPath, \"utf-8\")).version as string;\n\n// ── Public API ───────────────────────────────────────\n\n/** Create the full CLI program with all sub‑commands registered. */\nexport function createProgram(): Command {\n const program = new Command();\n\n program.name(\"lynx\").description(\"AI CLI — 多渠道 Agent 网关\").version(version);\n\n // ── Sub‑commands ──────────────────────────────────\n\n // doctor — system health check\n program\n .command(\"doctor\")\n .description(\"运行系统健康检查\")\n .action(async () => {\n const { runDoctor } = await import(\"./doctor/runner.js\");\n await runDoctor();\n });\n\n // crestodian — non‑interactive LLM query\n program\n .command(\"crestodian\")\n .description(\"非交互式 LLM 查询\")\n .requiredOption(\"--message <text>\", \"要发送的消息\")\n .option(\"--model <model>\", \"要使用的模型\")\n .action(async (opts) => {\n const { runCrestodian } = await import(\"./crestodian/runner.js\");\n await runCrestodian(opts.message, opts.model);\n });\n\n // session — list/resume/fork sessions\n program\n .command(\"sessions\")\n .description(\"列出、恢复或派生会话\")\n .option(\"--action <action>\", \"list | resume <id> | fork <id> | delete <id>\", \"list\")\n .option(\"--id <id>\", \"Session ID for resume/fork/delete\")\n .option(\"--label <label>\", \"New label for fork\")\n .action(async (opts) => {\n const { handleSessionCommand } = await import(\"./commands/session.js\");\n await handleSessionCommand(opts);\n });\n\n // config — show/set configuration\n program\n .command(\"config\")\n .description(\"显示或设置配置项\")\n .option(\"--show\", \"Show current configuration\")\n .option(\"--set <key>\", \"Set a configuration key\")\n .option(\"--value <value>\", \"Value for --set\")\n .option(\"--path\", \"Show config file path\")\n .action(async (opts) => {\n const { handleConfigCommand } = await import(\"./commands/config.js\");\n await handleConfigCommand(opts);\n });\n\n // start — launch in headless background mode (no TUI)\n program\n .command(\"start\")\n .description(\"以无头后台模式启动(无 TUI)\")\n .option(\"--headless\", \"以无头模式运行(守护进程模式必需)\")\n .option(\"--feishu-app-id <id>\", \"飞书 App ID(覆盖 FEISHU_APP_ID 环境变量)\")\n .option(\"--feishu-app-secret <secret>\", \"飞书 App Secret(覆盖 FEISHU_APP_SECRET 环境变量)\")\n .option(\"--model <model>\", \"要使用的模型\")\n .option(\"--verbose\", \"启用详细日志\")\n .action(async (opts) => {\n if (!opts.headless) {\n process.stderr.write(\"错误:'lynx start' 需要 --headless 参数。\\n\");\n process.stderr.write(\"用法:lynx start --headless [--verbose]\\n\");\n process.exitCode = 1;\n return;\n }\n const { startHeadless } = await import(\"./headless-launcher.js\");\n const feishu =\n opts.feishuAppId && opts.feishuAppSecret\n ? { appId: opts.feishuAppId, appSecret: opts.feishuAppSecret }\n : undefined;\n await startHeadless({\n model: opts.model,\n verbose: opts.verbose,\n feishu,\n });\n });\n\n // plugin — manage plugins (list/enable/disable/install/remove)\n program\n .command(\"plugin\")\n .description(\"管理插件(列出、启用、禁用、安装、移除)\")\n .option(\"--list\", \"List installed plugins\")\n .option(\"--enable <name>\", \"Enable a plugin\")\n .option(\"--disable <name>\", \"Disable a plugin\")\n .option(\"--install <path>\", \"Install a plugin from a local path\")\n .option(\"--remove <name>\", \"Remove an installed plugin\")\n .action(async (opts) => {\n const { handlePluginCommand } = await import(\"./commands/plugin.js\");\n await handlePluginCommand(opts);\n });\n\n // share — 将会话导出为 Markdown 文件\n program\n .command(\"share\")\n .description(\"将会话导出为可分享的 Markdown 文件\")\n .option(\"--session-id <id>\", \"要导出的会话 ID(默认最近一次会话)\")\n .option(\"--output <path>\", \"输出文件路径\")\n .action(async (opts) => {\n const { handleShareCommand } = await import(\"./commands/share.js\");\n const result = await handleShareCommand(opts);\n process.stdout.write(`${result.output}\\n`);\n });\n\n // export — 多格式导出会话\n program\n .command(\"export\")\n .description(\"以多种格式导出会话(markdown / json / html)\")\n .option(\"--session-id <id>\", \"要导出的会话 ID(默认最近一次会话)\")\n .option(\"--format <fmt>\", \"输出格式:markdown、json 或 html\", \"markdown\")\n .option(\"--output <path>\", \"输出文件路径\")\n .action(async (opts) => {\n const { handleExportCommand } = await import(\"./commands/export.js\");\n const result = await handleExportCommand(opts);\n process.stdout.write(`${result.output}\\n`);\n });\n\n // tag — 会话标签管理\n program\n .command(\"tag\")\n .description(\"为会话添加、移除或列出标签\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认最近一次会话)\")\n .option(\"--tag <tag>\", \"标签内容\")\n .option(\"--action <action>\", \"操作:add、remove 或 list\", \"list\")\n .action(async (opts) => {\n const { handleTagCommand } = await import(\"./commands/tag.js\");\n const result = await handleTagCommand(opts);\n process.stdout.write(`${result.output}\\n`);\n });\n\n // copy — 复制助手回复到剪贴板\n program\n .command(\"copy\")\n .description(\"将最后一条助手回复复制到系统剪贴板\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认最近一次会话)\")\n .option(\"--index <n>\", \"从末尾倒数第几条消息(默认 0 = 最后一条)\", \"0\")\n .action(async (opts) => {\n const { handleCopyCommand } = await import(\"./commands/copy.js\");\n const result = await handleCopyCommand({\n sessionId: opts.sessionId,\n index: opts.index ? Number(opts.index) : 0,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // clear — 清空当前会话消息\n program\n .command(\"clear\")\n .description(\"清空当前会话消息,开始全新对话\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认当前会话)\")\n .action(async (opts) => {\n const { handleClearCommand } = await import(\"./commands/clear.js\");\n const result = handleClearCommand({ sessionId: opts.sessionId });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // env — 显示环境变量\n program\n .command(\"env\")\n .description(\"显示 Lynx 环境变量和运行环境信息\")\n .action(async () => {\n const { handleEnvCommand } = await import(\"./commands/env.js\");\n const result = handleEnvCommand();\n process.stdout.write(`${result.output}\\n`);\n });\n\n // context — IDE 连接状态\n program\n .command(\"context\")\n .description(\"显示 IDE 连接状态和活跃文件信息\")\n .action(async () => {\n const { handleContextCommand } = await import(\"./commands/context.js\");\n const result = handleContextCommand();\n process.stdout.write(`${result.output}\\n`);\n });\n\n // context-viz — 上下文窗口可视化\n program\n .command(\"context-viz\")\n .description(\"可视化当前上下文窗口的 token 使用情况\")\n .action(async () => {\n const { handleContextVizCommand } = await import(\"./commands/context-viz.js\");\n const result = handleContextVizCommand();\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // stats — 会话统计\n program\n .command(\"stats\")\n .description(\"会话统计信息(token 消耗、工具调用频率等)\")\n .option(\"--session-id <id>\", \"目标会话 ID(默认当前会话)\")\n .option(\"--period <period>\", \"统计时间范围:today、week 或 all\", \"all\")\n .action(async (opts) => {\n const { handleStatsCommand } = await import(\"./commands/stats.js\");\n const result = handleStatsCommand({\n sessionId: opts.sessionId,\n period: opts.period,\n });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // status — 系统健康仪表盘\n program\n .command(\"status\")\n .description(\"系统健康仪表盘(MCP、Channel、Agent、磁盘等)\")\n .action(async () => {\n const { handleStatusCommand } = await import(\"./commands/status.js\");\n const result = handleStatusCommand();\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // bughunter — 只读诊断模式\n program\n .command(\"bughunter\")\n .description(\"只读诊断模式,系统排查问题并给出修复建议\")\n .option(\"--issue <text>\", \"具体的问题描述或错误消息\")\n .action(async (opts) => {\n const { handleBughunterCommand } = await import(\"./commands/bughunter.js\");\n const result = handleBughunterCommand({ issue: opts.issue });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // upgrade — 自助升级\n program\n .command(\"upgrade\")\n .description(\"自助升级 Lynx 到最新版本\")\n .option(\"--check\", \"仅检查依赖更新,不执行升级\")\n .option(\"--version <ver>\", \"指定目标版本(暂未实现)\")\n .action(async (opts) => {\n const { handleUpgradeCommand } = await import(\"./commands/upgrade.js\");\n const result = handleUpgradeCommand({\n check: opts.check,\n version: opts.version,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // sandbox-toggle — 切换沙箱模式\n program\n .command(\"sandbox-toggle\")\n .description(\"切换 Bash 沙箱模式开关(启用 / 禁用)\")\n .option(\"--enable\", \"强制启用沙箱\")\n .option(\"--disable\", \"强制禁用沙箱\")\n .action(async (opts) => {\n const { handleSandboxToggleCommand } = await import(\"./commands/sandbox-toggle.js\");\n const result = handleSandboxToggleCommand({\n enable: opts.enable,\n disable: opts.disable,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // privacy — 隐私设置\n program\n .command(\"privacy\")\n .description(\"隐私设置面板(允许列表、禁止列表、分析共享)\")\n .option(\"--show\", \"显示当前隐私设置\")\n .option(\"--allow <domain>\", \"将域名添加到允许列表\")\n .option(\"--deny <domain>\", \"将域名添加到禁止列表\")\n .action(async (opts) => {\n const { handlePrivacyCommand } = await import(\"./commands/privacy.js\");\n const result = handlePrivacyCommand({\n show: opts.show,\n allow: opts.allow,\n deny: opts.deny,\n });\n process.stdout.write(`${result.output}\\n`);\n });\n\n // branch — Git 分支管理\n program\n .command(\"branch\")\n .description(\"管理 Git 分支:列出、创建、切换、删除\")\n .option(\"--action <action>\", \"操作类型:list、create、switch 或 delete\", \"list\")\n .option(\"--name <name>\", \"分支名称(create / switch / delete 时必填)\")\n .option(\"--base <base>\", \"创建分支时的基准分支(仅 create 时有效)\")\n .action(async (opts) => {\n const { handleBranchCommand } = await import(\"./commands/git-branch.js\");\n const result = handleBranchCommand({\n action: opts.action,\n name: opts.name,\n base: opts.base,\n });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // memory — 记忆管理\n program\n .command(\"memory\")\n .description(\"记忆管理 — 列出、搜索、添加、删除、去重、导出记忆\")\n .option(\"--action <action>\", \"操作:list(默认)、search、add、delete、compact、export\", \"list\")\n .option(\"--query <query>\", \"搜索查询词或条目名称\")\n .option(\"--name <name>\", \"条目名称(用于 add/delete)\")\n .action(async (opts) => {\n const { handleMemoryCommand } = await import(\"./commands/memory.js\");\n const result = handleMemoryCommand({\n action: opts.action,\n query: opts.query,\n name: opts.name,\n });\n process.stdout.write(`${result.instruction}\\n`);\n });\n\n // break-cache — 清除缓存\n program\n .command(\"break-cache\")\n .description(\"清除指定缓存(prompt / transcript / tool / all)\")\n .option(\"--cache <type>\", \"缓存类型:prompt、transcript、tool 或 all\", \"all\")\n .action(async (opts) => {\n const { handleBreakCacheCommand } = await import(\"./commands/break-cache.js\");\n const result = await handleBreakCacheCommand({ cache: opts.cache });\n process.stdout.write(`${result.output}\\n`);\n });\n\n return program;\n}\n\n/** Parse argv and run the matching command. */\nexport async function runCli(argv: string[] = process.argv): Promise<void> {\n const program = createProgram();\n await program.parseAsync(argv);\n}\n","/**\n * CommandCatalog — structured command registration with\n * per‑command policy (permission mode, tool visibility, etc.).\n *\n * Each command is registered with a name, handler, and a set\n * of policies that control how the agent behaves while executing\n * that command.\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CommandPolicy {\n /** Permission mode for this command. */\n permissionMode: \"default\" | \"auto\" | \"yolo\" | \"headless\" | \"plan\";\n /** Which tools are visible when this command runs. */\n allowedTools?: string[];\n /** Can this command modify files? */\n allowWrites: boolean;\n}\n\nexport interface CommandEntry {\n name: string;\n description: string;\n policy: CommandPolicy;\n /** Lazily‑loaded handler module path. */\n handlerPath: string;\n}\n\n// ── Built‑in policy defaults ─────────────────────────\n\nconst READONLY: CommandPolicy = {\n permissionMode: \"default\",\n allowWrites: false,\n};\n\nconst FULL_ACCESS: CommandPolicy = {\n permissionMode: \"auto\",\n allowWrites: true,\n};\n\n// ── Catalog ──────────────────────────────────────────\n\n/** The master list of registered commands. */\nexport const CATALOG: CommandEntry[] = [\n {\n name: \"doctor\",\n description: \"Run system health checks\",\n policy: READONLY,\n handlerPath: \"./doctor/runner.js\",\n },\n {\n name: \"crestodian\",\n description: \"Non‑interactive LLM query\",\n policy: { ...READONLY, permissionMode: \"headless\" },\n handlerPath: \"./crestodian/runner.js\",\n },\n {\n name: \"sessions\",\n description: \"List, resume, or fork sessions\",\n policy: { ...FULL_ACCESS, allowedTools: [] },\n handlerPath: \"./commands/session.js\",\n },\n {\n name: \"config\",\n description: \"Show or set configuration values\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/config.js\",\n },\n {\n name: \"plugin\",\n description: \"Manage installed plugins (list, install, remove, enable, disable)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/plugin.js\",\n },\n {\n name: \"sed\",\n description: \"在文件上进行正则查找替换\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"read_file\", \"write_file\"],\n allowWrites: true,\n },\n handlerPath: \"./commands/sed-edit.js\",\n },\n {\n name: \"commit\",\n description: \"创建 Git 提交并推送(约定式提交)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-commit.js\",\n },\n {\n name: \"branch\",\n description: \"管理 Git 分支:列出、创建、切换、删除\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-branch.js\",\n },\n {\n name: \"review\",\n description: \"审查 GitHub Pull Request 变更\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-review.js\",\n },\n {\n name: \"pr-comments\",\n description: \"处理 PR 审查评论(修改代码或回复确认)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-pr-comments.js\",\n },\n {\n name: \"issue\",\n description: \"管理 GitHub Issue(创建、列出、查看)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-issue.js\",\n },\n {\n name: \"autofix-pr\",\n description: \"自动修复 PR 问题(开发中)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-autofix.js\",\n },\n {\n name: \"diff\",\n description: \"展示 Git 工作区变更(未暂存和已暂存)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/git-diff.js\",\n },\n {\n name: \"ant-trace\",\n description: \"工具调用链追踪可视化\",\n policy: READONLY,\n handlerPath: \"./commands/ant-trace.js\",\n },\n {\n name: \"debug-tool-call\",\n description: \"单步工具调用调试器\",\n policy: READONLY,\n handlerPath: \"./commands/debug-tool-call.js\",\n },\n {\n name: \"tasks\",\n description: \"后台任务监视与控制(列出、取消、查看详情)\",\n policy: READONLY,\n handlerPath: \"./commands/tasks.js\",\n },\n {\n name: \"heapdump\",\n description: \"生成 V8 堆快照用于内存泄漏诊断\",\n policy: READONLY,\n handlerPath: \"./commands/heapdump.js\",\n },\n {\n name: \"memory\",\n description: \"记忆管理 — 列出、搜索、添加、删除、去重、导出记忆\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"memory_write\"],\n allowWrites: true,\n },\n handlerPath: \"./commands/memory.js\",\n },\n {\n name: \"break-cache\",\n description: \"清除指定缓存(prompt / transcript / tool / all)\",\n policy: READONLY,\n handlerPath: \"./commands/break-cache.js\",\n },\n {\n name: \"perf-issue\",\n description: \"性能问题诊断与健康检查\",\n policy: READONLY,\n handlerPath: \"./commands/perf-issue.js\",\n },\n {\n name: \"share\",\n description: \"将会话导出为可分享的 Markdown 文件\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/share.js\",\n },\n {\n name: \"export\",\n description: \"以多种格式导出会话(markdown / json / html)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/export.js\",\n },\n {\n name: \"tag\",\n description: \"为会话添加、移除或列出标签\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/tag.js\",\n },\n {\n name: \"copy\",\n description: \"将最后一条助手回复复制到系统剪贴板\",\n policy: READONLY,\n handlerPath: \"./commands/copy.js\",\n },\n {\n name: \"clear\",\n description: \"清空当前会话消息,开始全新对话\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [],\n allowWrites: false,\n },\n handlerPath: \"./commands/clear.js\",\n },\n {\n name: \"env\",\n description: \"显示 Lynx 环境变量和运行环境信息\",\n policy: READONLY,\n handlerPath: \"./commands/env.js\",\n },\n {\n name: \"context\",\n description: \"显示 IDE 连接状态和活跃文件信息\",\n policy: READONLY,\n handlerPath: \"./commands/context.js\",\n },\n {\n name: \"context-viz\",\n description: \"可视化当前上下文窗口的 token 使用情况\",\n policy: READONLY,\n handlerPath: \"./commands/context-viz.js\",\n },\n {\n name: \"stats\",\n description: \"会话统计信息(token 消耗、工具调用频率等)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [],\n allowWrites: false,\n },\n handlerPath: \"./commands/stats.js\",\n },\n {\n name: \"status\",\n description: \"系统健康仪表盘(MCP、Channel、Agent、磁盘等)\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [],\n allowWrites: false,\n },\n handlerPath: \"./commands/status.js\",\n },\n {\n name: \"bughunter\",\n description: \"只读诊断模式,系统排查问题并给出修复建议\",\n policy: READONLY,\n handlerPath: \"./commands/bughunter.js\",\n },\n {\n name: \"upgrade\",\n description: \"自助升级 Lynx 到最新版本\",\n policy: {\n permissionMode: \"default\",\n allowedTools: [\"bash\"],\n allowWrites: false,\n },\n handlerPath: \"./commands/upgrade.js\",\n },\n {\n name: \"sandbox-toggle\",\n description: \"切换 Bash 沙箱模式开关(启用 / 禁用)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/sandbox-toggle.js\",\n },\n {\n name: \"privacy-settings\",\n description: \"隐私设置面板(允许列表、禁止列表、分析共享)\",\n policy: { ...READONLY, allowWrites: true },\n handlerPath: \"./commands/privacy.js\",\n },\n];\n\n/** Look up a command by name. */\nexport function findCommand(name: string): CommandEntry | undefined {\n return CATALOG.find((c) => c.name === name);\n}\n","/**\n * Debug logging infrastructure — writes structured JSONL logs\n * to disk for post‑mortem analysis.\n *\n * Uses pino for formatting and rotation. Production logs are\n * JSONL with daily rotation; development uses pino‑pretty.\n */\n\nimport { createWriteStream, existsSync, mkdirSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n// ── Types ────────────────────────────────────────────\n\nexport type LogLevel = \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport interface DebugLogger {\n trace(msg: string, data?: unknown): void;\n debug(msg: string, data?: unknown): void;\n info(msg: string, data?: unknown): void;\n warn(msg: string, data?: unknown): void;\n error(msg: string, data?: unknown): void;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\nconst LEVEL_ORDER: Record<LogLevel, number> = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n};\n\nfunction formatLine(level: LogLevel, msg: string, data?: unknown): string {\n const entry = {\n time: new Date().toISOString(),\n level,\n msg,\n ...(data !== undefined ? { data } : {}),\n };\n return JSON.stringify(entry);\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Create a file‑based debug logger.\n *\n * @param logDir Directory for log files (defaults to ~/.lynx/logs).\n * @param minLevel Minimum level to emit.\n */\nexport function createDebugLogger(logDir: string, minLevel: LogLevel = \"info\"): DebugLogger {\n if (!existsSync(logDir)) {\n mkdirSync(logDir, { recursive: true });\n }\n\n const logPath = join(logDir, `lynx-debug.jsonl`);\n const stream = createWriteStream(logPath, { flags: \"a\" });\n const minRank = LEVEL_ORDER[minLevel];\n\n function log(level: LogLevel, msg: string, data?: unknown): void {\n if (LEVEL_ORDER[level] < minRank) return;\n stream.write(formatLine(level, msg, data) + \"\\n\");\n }\n\n return {\n trace(msg, data) {\n log(\"trace\", msg, data);\n },\n debug(msg, data) {\n log(\"debug\", msg, data);\n },\n info(msg, data) {\n log(\"info\", msg, data);\n },\n warn(msg, data) {\n log(\"warn\", msg, data);\n },\n error(msg, data) {\n log(\"error\", msg, data);\n },\n };\n}\n","/**\n * Doctor — system health checks.\n *\n * Runs a series of diagnostic checks and prints a report.\n * Each check returns pass/fail with an optional detail message.\n */\n\nimport { existsSync, accessSync, mkdirSync, constants } from \"node:fs\";\nimport { resolvePaths, openDatabase, migrate } from \"@24klynx/core\";\nimport { platform, release, cpus } from \"node:os\";\nimport { dirname } from \"node:path\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CheckResult {\n name: string;\n passed: boolean;\n detail?: string;\n}\n\nexport interface DoctorReport {\n checks: CheckResult[];\n allPassed: boolean;\n}\n\n// ── Checks ────────────────────────────────────────────\n\nfunction checkNodeVersion(): CheckResult {\n const version = process.version;\n const major = parseInt(version.slice(1).split(\".\")[0]!, 10);\n const passed = major >= 22;\n return {\n name: \"Node.js ≥ 22\",\n passed,\n detail: passed ? version : `${version} (need ≥ 22.19.0)`,\n };\n}\n\nfunction checkPlatform(): CheckResult {\n return {\n name: \"Platform support\",\n passed: true,\n detail: `${platform()} ${release()} (${cpus().length} CPUs)`,\n };\n}\n\nfunction checkHomeDir(): CheckResult {\n const paths = resolvePaths();\n let passed = existsSync(paths.home);\n if (!passed) {\n try {\n mkdirSync(paths.home, { recursive: true });\n passed = true;\n } catch {\n // Will report as failed below\n }\n }\n return {\n name: \"Home directory exists\",\n passed,\n detail: paths.home,\n };\n}\n\nfunction checkConfigDir(): CheckResult {\n const paths = resolvePaths();\n const configDir = dirname(paths.configFile);\n let passed = existsSync(configDir);\n if (!passed) {\n try {\n mkdirSync(configDir, { recursive: true });\n passed = true;\n } catch {\n // Will report as failed below\n }\n }\n return {\n name: \"Config directory exists\",\n passed,\n detail: configDir,\n };\n}\n\nfunction checkDataDir(): CheckResult {\n const paths = resolvePaths();\n const dataDir = dirname(paths.stateDb);\n try {\n if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true });\n accessSync(dataDir, constants.W_OK);\n return { name: \"Data directory writable\", passed: true, detail: dataDir };\n } catch {\n return { name: \"Data directory writable\", passed: false, detail: `Cannot write to ${dataDir}` };\n }\n}\n\nfunction checkDatabase(): CheckResult {\n try {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n migrate(db);\n const row = db.prepare(\"SELECT sqlite_version() as v\").get() as { v: string } | undefined;\n db.close();\n return { name: \"SQLite database\", passed: true, detail: `v${row?.v}` };\n } catch (err) {\n return {\n name: \"SQLite database\",\n passed: false,\n detail: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\nfunction checkSessionsTable(): CheckResult {\n try {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n migrate(db);\n const count = db.prepare(\"SELECT COUNT(*) as c FROM sessions\").get() as\n | { c: number }\n | undefined;\n db.close();\n return { name: \"Sessions table\", passed: true, detail: `${count?.c ?? 0} sessions` };\n } catch (err) {\n return {\n name: \"Sessions table\",\n passed: false,\n detail: err instanceof Error ? err.message : String(err),\n };\n }\n}\n\n/** All registered checks, in display order. */\nconst CHECKS: Array<() => CheckResult> = [\n checkNodeVersion,\n checkPlatform,\n checkHomeDir,\n checkConfigDir,\n checkDataDir,\n checkDatabase,\n checkSessionsTable,\n];\n\n// ── Public API ───────────────────────────────────────\n\n/** Run all health checks and return the report. */\nexport function runChecks(): DoctorReport {\n const checks: CheckResult[] = [];\n for (const fn of CHECKS) {\n checks.push(fn());\n }\n const allPassed = checks.every((c) => c.passed);\n return { checks, allPassed };\n}\n\n/** Print the doctor report to stdout. */\nexport function printReport(report: DoctorReport): void {\n for (const check of report.checks) {\n const icon = check.passed ? \"✓\" : \"✗\";\n process.stdout.write(`${icon} ${check.name}`);\n if (check.detail) {\n process.stdout.write(` (${check.detail})`);\n }\n process.stdout.write(\"\\n\");\n }\n\n process.stdout.write(\"\\n\");\n process.stdout.write(report.allPassed ? \"All checks passed.\\n\" : \"Some checks failed.\\n\");\n}\n\n/** Entry point for the `lynx doctor` command. */\nexport async function runDoctor(): Promise<void> {\n const report = runChecks();\n printReport(report);\n process.exitCode = report.allPassed ? 0 : 1;\n}\n","/**\n * Crestodian — non‑interactive LLM query mode.\n *\n * Takes a message from CLI args, sends it to the LLM provider,\n * and prints the response to stdout. No TUI, no interaction.\n *\n * This is the `node lynx.mjs crestodian --message \"...\"` path.\n */\n\nimport type { ChatMessage } from \"@24klynx/llm\";\nimport { assembleSystemPrompt } from \"@24klynx/agent\";\nimport { loadConfig, resolveConfigEnv, resolveProvider } from \"../commands/config.js\";\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Run a non‑interactive query against the LLM.\n *\n * Reads API keys from environment variables (DEEPSEEK_API_KEY\n * or OPENAI_API_KEY) and streams the response to stdout.\n */\nexport async function runCrestodian(message: string, _model?: string): Promise<void> {\n if (!message) {\n process.stderr.write(\"Error: --message is required\\n\");\n process.exitCode = 1;\n return;\n }\n\n // 加载配置 → 注入 env → 按模型名自动选 Provider\n const config = loadConfig();\n resolveConfigEnv(config);\n\n let provider;\n try {\n provider = resolveProvider(config);\n } catch (err) {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = 1;\n return;\n }\n\n const systemPrompt = assembleSystemPrompt(\n {\n model: config.model,\n systemPrompt: \"You are Lynx, an AI assistant. Be helpful and concise.\",\n maxTokens: 8192,\n maxCompactionFailures: 3,\n budget: { maxTokens: Infinity, maxUsd: Infinity, maxTurns: Infinity },\n provider,\n },\n /* visibleTools */ [],\n );\n\n const messages: ChatMessage[] = [{ role: \"user\", content: [{ type: \"text\", text: message }] }];\n const controller = new AbortController();\n\n try {\n const stream = provider.stream(\n \"deepseek-v4-pro\",\n messages,\n systemPrompt,\n [],\n controller.signal,\n );\n\n for await (const event of stream) {\n if (event.type === \"text_delta\") {\n process.stdout.write(event.text);\n }\n }\n process.stdout.write(\"\\n\");\n } catch (err) {\n process.stderr.write(`Error: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exitCode = 1;\n }\n}\n","/**\n * Session command — list, resume, fork, and delete sessions\n * from the command line.\n *\n * Uses SessionManager for persistence and SessionPicker for\n * interactive selection when no ID is provided.\n */\n\nimport { openDatabase, resolvePaths, asSessionId } from \"@24klynx/core\";\nimport type { Message } from \"@24klynx/core\";\nimport { createSessionManager } from \"@24klynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface SessionCommandOptions {\n action: string;\n id?: string;\n label?: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** Print text content blocks from messages to stdout. */\nfunction printSessionText(messages: Message[]): void {\n for (const msg of messages) {\n for (const block of msg.content) {\n if (block.type === \"text\" && block.text) {\n process.stdout.write(block.text + \"\\n\");\n }\n }\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Handle the `lynx sessions` command. */\nexport async function handleSessionCommand(opts: SessionCommandOptions): Promise<void> {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n const mgr = createSessionManager(db);\n\n try {\n switch (opts.action) {\n case \"list\": {\n const sessions = mgr.list();\n if (sessions.length === 0) {\n process.stdout.write(\"No sessions found.\\n\");\n } else {\n for (const s of sessions) {\n const label = s.label ?? \"(untitled)\";\n const msgCount = s.messages.length;\n const updated = new Date(s.updatedAt).toISOString();\n process.stdout.write(`${s.id} ${label} ${msgCount} msgs ${updated}\\n`);\n }\n }\n break;\n }\n case \"resume\": {\n if (!opts.id) {\n process.stderr.write(\"Error: --id is required for resume\\n\");\n process.exitCode = 1;\n return;\n }\n const session = mgr.load(asSessionId(opts.id));\n if (!session) {\n process.stderr.write(`Session not found: ${opts.id}\\n`);\n process.exitCode = 1;\n return;\n }\n // Print session content to stdout for piping\n printSessionText(session.messages);\n break;\n }\n case \"fork\": {\n if (!opts.id) {\n process.stderr.write(\"Error: --id is required for fork\\n\");\n process.exitCode = 1;\n return;\n }\n const forked = mgr.fork(asSessionId(opts.id), opts.label);\n process.stdout.write(`Forked: ${forked.id}\\n`);\n break;\n }\n case \"delete\": {\n if (!opts.id) {\n process.stderr.write(\"Error: --id is required for delete\\n\");\n process.exitCode = 1;\n return;\n }\n mgr.delete(asSessionId(opts.id));\n process.stdout.write(`Deleted: ${opts.id}\\n`);\n break;\n }\n default:\n process.stderr.write(`Unknown action: ${opts.action}\\n`);\n process.exitCode = 1;\n }\n } finally {\n mgr.destroy();\n db.close();\n }\n}\n","/**\n * Unified entry point — the first code that runs after `lynx.mjs`.\n *\n * Responsibilities:\n * 1. Version check (bail early if Node.js < 22.19).\n * 2. Parse CLI args and route to the correct handler.\n * 3. For interactive mode: bootstrap services + launch TUI.\n * 4. For sub‑commands: lazily import the handler.\n *\n * This file intentionally avoids importing heavy modules\n * (Ink, provider implementations) at the top level so that\n * `lynx --version` returns in < 100 ms.\n */\n\n// ── Phase 0: Version guard ────────────────────────────\n\nfunction guardNodeVersion(): void {\n const v = process.version.slice(1).split(\".\").map(Number);\n const major = v[0]!;\n const minor = v[1] ?? 0;\n if (major < 22 || (major === 22 && minor < 19)) {\n process.stderr.write(`Lynx requires Node.js ≥ 22.19.0 (found ${process.version})\\n`);\n process.exit(1);\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Main entry point. Invoked from `lynx.mjs`. */\nexport async function main(argv: string[] = process.argv): Promise<void> {\n guardNodeVersion();\n\n const userArgs = argv.slice(2);\n\n // Flags that should route to the CLI parser, not TUI.\n const cliOnlyFlags = new Set([\"--help\", \"-h\", \"--version\", \"-V\"]);\n const hasCliFlag = userArgs.some((a) => cliOnlyFlags.has(a));\n\n // If no sub‑command is given and no CLI flags, launch the interactive TUI.\n const hasSubcommand = userArgs.some((a) => !a.startsWith(\"-\"));\n\n if (!hasSubcommand && !hasCliFlag) {\n const { launchTui } = await import(\"./tui-launcher.js\");\n await launchTui();\n return;\n }\n\n const { runCli } = await import(\"./args.js\");\n await runCli(argv);\n}\n","/**\n * MemoryMonitor — proactive heap sampling with three‑level alerting.\n *\n * Samples `process.memoryUsage().heapUsed` on a configurable interval\n * (default 30s) and fires alerts at user‑defined thresholds. Each alert\n * level triggers a distinct action: warn → GC hint, danger → compaction,\n * fatal → cache flush.\n *\n * Design (§5.9j):\n * - 30s heap sampling interval\n * - 3‑level alert:\n * 700 MB → warn: trigger GC + auto compact context\n * 900 MB → danger: force snip compaction\n * 950 MB → fatal: release all caches + notify user\n * - Uses global.gc() when available (requires --expose-gc)\n * - Emits structured events for integration with status bar\n */\n\nimport { EventEmitter } from \"node:events\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Alert severity levels. */\nexport type MemoryAlertLevel = \"warn\" | \"danger\" | \"fatal\";\n\n/** A memory alert event. */\nexport interface MemoryAlert {\n level: MemoryAlertLevel;\n /** Current heap usage in bytes. */\n heapUsed: number;\n /** Heap usage as percentage of configured threshold. */\n percentage: number;\n /** Threshold that was breached in bytes. */\n threshold: number;\n /** ISO timestamp of the sample. */\n timestamp: string;\n}\n\n/** Configuration for the memory monitor. */\nexport interface MemoryMonitorConfig {\n /** Sampling interval in ms. Default: 30_000. */\n intervalMs?: number;\n /** Warn threshold in bytes. Default: 700 * 1024 * 1024. */\n warnThreshold?: number;\n /** Danger threshold in bytes. Default: 900 * 1024 * 1024. */\n dangerThreshold?: number;\n /** Fatal threshold in bytes. Default: 950 * 1024 * 1024. */\n fatalThreshold?: number;\n}\n\n/** Current memory snapshot. */\nexport interface MemorySnapshot {\n heapUsed: number;\n heapTotal: number;\n external: number;\n rss: number;\n timestamp: string;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst MB = 1024 * 1024;\nconst DEFAULT_INTERVAL_MS = 30_000;\nconst DEFAULT_WARN_MB = 700;\nconst DEFAULT_DANGER_MB = 900;\nconst DEFAULT_FATAL_MB = 950;\n\n// ── MemoryMonitor ───────────────────────────────────\n\n/**\n * Proactive heap monitor with three‑level alerting.\n *\n * Usage:\n * ```ts\n * const monitor = new MemoryMonitor({ intervalMs: 30_000 });\n * monitor.on(\"alert\", (alert) => {\n * if (alert.level === \"fatal\") console.error(\"OOM imminent!\");\n * });\n * monitor.start();\n * ```\n */\nexport class MemoryMonitor extends EventEmitter {\n private config: Required<MemoryMonitorConfig>;\n private timer: ReturnType<typeof setInterval> | null = null;\n private running = false;\n\n /** Track the last alert level to avoid repeated warnings. */\n private lastAlertLevel: MemoryAlertLevel | null = null;\n\n constructor(config: MemoryMonitorConfig = {}) {\n super();\n this.config = {\n intervalMs: config.intervalMs ?? DEFAULT_INTERVAL_MS,\n warnThreshold: config.warnThreshold ?? DEFAULT_WARN_MB * MB,\n dangerThreshold: config.dangerThreshold ?? DEFAULT_DANGER_MB * MB,\n fatalThreshold: config.fatalThreshold ?? DEFAULT_FATAL_MB * MB,\n };\n }\n\n // ── Events — typed wrappers around EventEmitter.on ──\n\n /** Emitted when a memory alert is triggered. */\n onAlert(listener: (alert: MemoryAlert) => void): this {\n return super.on(\"alert\", listener);\n }\n\n /** Emitted on each sample (for dashboards). */\n onSample(listener: (snapshot: MemorySnapshot) => void): this {\n return super.on(\"sample\", listener);\n }\n\n /** Emitted when compaction is requested. */\n onCompact(listener: (info: { reason: string; heapUsed: number }) => void): this {\n return super.on(\"compact\", listener);\n }\n\n /** Emitted when caches should be flushed. */\n onFlushCaches(listener: (info: { reason: string; heapUsed: number }) => void): this {\n return super.on(\"flush_caches\", listener);\n }\n\n // ── Public API ──────────────────────────────────\n\n /** Start periodic heap sampling. No‑op if already running. */\n start(): void {\n if (this.running) return;\n this.running = true;\n\n // Take an immediate sample\n this.sample();\n\n this.timer = setInterval(() => {\n this.sample();\n }, this.config.intervalMs);\n this.timer.unref(); // Don't block process exit\n }\n\n /** Stop periodic sampling. */\n stop(): void {\n this.running = false;\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n this.lastAlertLevel = null;\n }\n\n /** Take a manual snapshot and return it. */\n snapshot(): MemorySnapshot {\n const mem = process.memoryUsage();\n return {\n heapUsed: mem.heapUsed,\n heapTotal: mem.heapTotal,\n external: mem.external,\n rss: mem.rss,\n timestamp: new Date().toISOString(),\n };\n }\n\n // ── Internals ───────────────────────────────────\n\n /** Sample heap usage and fire alerts if thresholds are breached. */\n private sample(): void {\n const snap = this.snapshot();\n this.emit(\"sample\", snap);\n\n const { heapUsed } = snap;\n const { warnThreshold, dangerThreshold, fatalThreshold } = this.config;\n\n let level: MemoryAlertLevel | null = null;\n let threshold = 0;\n\n if (heapUsed >= fatalThreshold) {\n level = \"fatal\";\n threshold = fatalThreshold;\n } else if (heapUsed >= dangerThreshold) {\n level = \"danger\";\n threshold = dangerThreshold;\n } else if (heapUsed >= warnThreshold) {\n level = \"warn\";\n threshold = warnThreshold;\n }\n\n if (level) {\n // Suppress repeated alerts at the same level\n if (level === this.lastAlertLevel) return;\n this.lastAlertLevel = level;\n\n const alert: MemoryAlert = {\n level,\n heapUsed,\n percentage: Math.round((heapUsed / threshold) * 100),\n threshold,\n timestamp: snap.timestamp,\n };\n\n this.emit(\"alert\", alert);\n this.actOnAlert(alert);\n } else if (this.lastAlertLevel) {\n // Memory dropped back below thresholds — reset\n this.lastAlertLevel = null;\n }\n }\n\n /** Execute the appropriate action for each alert level. */\n private actOnAlert(alert: MemoryAlert): void {\n switch (alert.level) {\n case \"warn\": {\n // Trigger GC if available\n this.triggerGc();\n break;\n }\n case \"danger\": {\n // Force GC and signal compaction\n this.triggerGc();\n this.emit(\"compact\", { reason: \"memory_pressure\", heapUsed: alert.heapUsed });\n break;\n }\n case \"fatal\": {\n // Aggressive GC + signal cache flush\n this.triggerGc();\n // Second GC pass after a tick\n setImmediate(() => this.triggerGc());\n this.emit(\"flush_caches\", { reason: \"oom_imminent\", heapUsed: alert.heapUsed });\n break;\n }\n }\n }\n\n /** Trigger V8 garbage collection if --expose-gc is enabled. */\n private triggerGc(): void {\n if (typeof global.gc === \"function\") {\n try {\n global.gc();\n } catch {\n // GC may throw if called at an unsafe time — ignore\n }\n }\n }\n}\n","/**\n * UpdateChecker — asynchronous, non‑blocking version check.\n *\n * Queries npm and GitHub for the latest Lynx release and compares\n * against the running version. Designed to never block startup:\n * the check runs in the background and fires a callback when\n * complete.\n *\n * Design (§5.9k):\n * - Async, non‑blocking — fire and forget\n * - O_EXCL lock — only one check runs at a time per process\n * - Dual channel: npm registry + GitHub releases\n * - GitHub as fallback when npm is slow or unreachable\n * - Result cached for the session lifetime\n * - Respects NO_UPDATE_CHECK env var\n */\n\nimport { request as httpsRequest } from \"node:https\";\n\n// ── Types ────────────────────────────────────────────\n\n/** Result of an update check. */\nexport interface UpdateResult {\n /** Current installed version. */\n current: string;\n /** Latest available version, or null if unknown. */\n latest: string | null;\n /** Whether a newer version is available. */\n hasUpdate: boolean;\n /** Release notes URL for the latest version. */\n releaseUrl: string | null;\n /** Time the check was performed (ISO string). */\n checkedAt: string;\n /** Which channel provided the result. */\n source: \"npm\" | \"github\" | \"cache\" | \"error\";\n /** Error message if the check failed. */\n error?: string;\n}\n\n/** Configuration for the update checker. */\nexport interface UpdateCheckConfig {\n /** Current version string (e.g. \"0.1.0\"). */\n currentVersion: string;\n /** npm package name. Default: \"lynx\". */\n packageName?: string;\n /** GitHub repository in \"owner/repo\" format. Default: \"loongcrown/lynx\". */\n githubRepo?: string;\n /** Timeout per request in ms. Default: 5_000. */\n timeoutMs?: number;\n /** Cache duration in ms. Default: 3_600_000 (1 hour). */\n cacheTtlMs?: number;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst DEFAULT_TIMEOUT_MS = 5_000;\nconst DEFAULT_CACHE_TTL_MS = 3_600_000;\n\n// ── Module state ────────────────────────────────────\n\nlet lastResult: UpdateResult | null = null;\nlet checkInProgress: Promise<UpdateResult> | null = null;\n\n// ── Public API ─────────────────────────────────────\n\n/**\n * Check for updates asynchronously.\n *\n * Only one check runs at a time — concurrent calls return the\n * same Promise. Results are cached for the configured TTL.\n *\n * Callers should never await this at startup — fire‑and‑forget\n * and read the result from the cache on next call.\n */\nexport function checkForUpdates(config: UpdateCheckConfig): Promise<UpdateResult> {\n // Return cached result if still fresh\n if (lastResult) {\n const age = Date.now() - new Date(lastResult.checkedAt).getTime();\n const ttl = config.cacheTtlMs ?? DEFAULT_CACHE_TTL_MS;\n if (age < ttl) {\n return Promise.resolve({ ...lastResult, source: \"cache\" as const });\n }\n }\n\n // Return in‑progress check\n if (checkInProgress) return checkInProgress;\n\n // Respect opt‑out\n if (process.env.NO_UPDATE_CHECK) {\n const result: UpdateResult = {\n current: config.currentVersion,\n latest: null,\n hasUpdate: false,\n releaseUrl: null,\n checkedAt: new Date().toISOString(),\n source: \"error\",\n error: \"Update check disabled via NO_UPDATE_CHECK\",\n };\n return Promise.resolve(result);\n }\n\n checkInProgress = runUpdateCheck(config)\n .then((result) => {\n lastResult = result;\n return result;\n })\n .finally(() => {\n checkInProgress = null;\n });\n\n return checkInProgress;\n}\n\n/**\n * Synchronously return the last cached update result.\n * Returns null if no check has been performed yet.\n */\nexport function getLastUpdateResult(): UpdateResult | null {\n return lastResult;\n}\n\n/**\n * Clear the cached update result (for testing).\n */\nexport function clearUpdateCache(): void {\n lastResult = null;\n}\n\n// ── Internals ───────────────────────────────────────\n\n/**\n * Run the update check against npm, falling back to GitHub.\n */\nasync function runUpdateCheck(config: UpdateCheckConfig): Promise<UpdateResult> {\n const pkg = config.packageName ?? \"lynx\";\n const repo = config.githubRepo ?? \"loongcrown/lynx\";\n const timeout = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n // Try npm first\n try {\n const npmResult = await checkNpm(pkg, timeout);\n return buildResult(config.currentVersion, npmResult, \"npm\");\n } catch {\n // npm failed — try GitHub\n }\n\n // Fall back to GitHub\n try {\n const ghResult = await checkGitHub(repo, timeout);\n return buildResult(config.currentVersion, ghResult, \"github\");\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n current: config.currentVersion,\n latest: null,\n hasUpdate: false,\n releaseUrl: null,\n checkedAt: new Date().toISOString(),\n source: \"error\",\n error: message,\n };\n }\n}\n\n/**\n * Check the npm registry for the latest version.\n */\nfunction checkNpm(packageName: string, timeoutMs: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;\n const req = httpsRequest(\n url,\n {\n method: \"GET\",\n timeout: timeoutMs,\n headers: { Accept: \"application/json\" },\n },\n (res) => {\n let body = \"\";\n res.on(\"data\", (chunk: Buffer) => {\n body += chunk.toString();\n });\n res.on(\"end\", () => {\n try {\n const data = JSON.parse(body);\n const version = data.version as string;\n if (!version || typeof version !== \"string\") {\n reject(new Error(\"Invalid npm response: missing version field\"));\n return;\n }\n resolve(version);\n } catch (err) {\n reject(err instanceof Error ? err : new Error(\"Failed to parse npm response\"));\n }\n });\n },\n );\n\n req.on(\"error\", reject);\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"npm request timed out\"));\n });\n req.end();\n });\n}\n\n/**\n * Check GitHub releases for the latest version tag.\n */\nfunction checkGitHub(repo: string, timeoutMs: number): Promise<string> {\n return new Promise((resolve, reject) => {\n const url = `https://api.github.com/repos/${repo}/releases/latest`;\n const req = httpsRequest(\n url,\n {\n method: \"GET\",\n timeout: timeoutMs,\n headers: {\n Accept: \"application/vnd.github+json\",\n \"User-Agent\": \"Lynx-Update-Checker/1.0\",\n },\n },\n (res) => {\n let body = \"\";\n res.on(\"data\", (chunk: Buffer) => {\n body += chunk.toString();\n });\n res.on(\"end\", () => {\n try {\n const data = JSON.parse(body);\n const tag = data.tag_name as string;\n if (!tag || typeof tag !== \"string\") {\n reject(new Error(\"Invalid GitHub response: missing tag_name field\"));\n return;\n }\n // Strip leading 'v' if present\n const version = tag.startsWith(\"v\") ? tag.slice(1) : tag;\n resolve(version);\n } catch (err) {\n reject(err instanceof Error ? err : new Error(\"Failed to parse GitHub response\"));\n }\n });\n },\n );\n\n req.on(\"error\", reject);\n req.on(\"timeout\", () => {\n req.destroy();\n reject(new Error(\"GitHub request timed out\"));\n });\n req.end();\n });\n}\n\n/**\n * Compare two semver strings and build the result.\n */\nfunction buildResult(current: string, latest: string, source: \"npm\" | \"github\"): UpdateResult {\n const hasUpdate = compareVersions(latest, current) > 0;\n return {\n current,\n latest,\n hasUpdate,\n releaseUrl:\n source === \"github\"\n ? `https://github.com/loongcrown/lynx/releases/latest`\n : `https://www.npmjs.com/package/lynx/v/${latest}`,\n checkedAt: new Date().toISOString(),\n source,\n };\n}\n\n/**\n * Simple semver comparison (supports major.minor.patch only).\n *\n * Returns positive if a > b, negative if a < b, 0 if equal.\n */\nfunction compareVersions(a: string, b: string): number {\n const aParts = a.split(\".\").map(Number);\n const bParts = b.split(\".\").map(Number);\n const len = Math.max(aParts.length, bParts.length);\n\n for (let i = 0; i < len; i++) {\n const aVal = aParts[i] ?? 0;\n const bVal = bParts[i] ?? 0;\n if (aVal > bVal) return 1;\n if (aVal < bVal) return -1;\n }\n\n return 0;\n}\n","/**\n * SnapshotStore — lightweight file-based snapshot persistence.\n *\n * Snapshots are serialised session checkpoints stored as JSON\n * files in the snapshots directory. Each snapshot captures the\n * session label, message list, and workspace at a point in time.\n *\n * Used by the SnapshotBrowser (/snapshots) to list and restore\n * previous session states.\n */\n\nimport {\n existsSync,\n readFileSync,\n writeFileSync,\n readdirSync,\n mkdirSync,\n unlinkSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Session, Message } from \"@24klynx/core\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface StoredSnapshot {\n id: string;\n label: string;\n timestamp: number;\n workspace: string;\n /** Serialised messages at capture time. */\n messages: Message[];\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Create a snapshot store backed by a directory on disk.\n *\n * The directory is created on first write if it doesn't exist.\n * Snapshots are stored as individual JSON files named `<id>.json`.\n */\nexport function createSnapshotStore(snapshotsDir: string) {\n return {\n /**\n * Capture a new snapshot of a session's current state.\n *\n * Returns the StoredSnapshot that was written to disk.\n */\n capture(session: Session): StoredSnapshot {\n const id = crypto.randomUUID();\n const snapshot: StoredSnapshot = {\n id,\n label: session.label ?? \"untitled\",\n timestamp: Date.now(),\n workspace: session.workspace ?? \"\",\n messages: [...session.messages],\n };\n\n mkdirSync(snapshotsDir, { recursive: true });\n const filePath = join(snapshotsDir, `${id}.json`);\n writeFileSync(filePath, JSON.stringify(snapshot, null, 2), \"utf-8\");\n\n return snapshot;\n },\n\n /**\n * List all stored snapshots, sorted newest-first.\n *\n * Returns only metadata (no message bodies) for efficient listing.\n */\n list(): Array<{ id: string; timestamp: number; label: string }> {\n let entries: string[];\n try {\n entries = readdirSync(snapshotsDir);\n } catch {\n return [];\n }\n\n const snapshots: Array<{ id: string; timestamp: number; label: string }> = [];\n\n for (const entry of entries) {\n if (!entry.endsWith(\".json\")) continue;\n const id = entry.replace(/\\.json$/, \"\");\n const filePath = join(snapshotsDir, entry);\n\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const snap = JSON.parse(raw) as StoredSnapshot;\n snapshots.push({\n id: snap.id,\n timestamp: snap.timestamp,\n label: snap.label,\n });\n } catch {\n // Skip corrupted snapshots\n }\n }\n\n // Newest first\n snapshots.sort((a, b) => b.timestamp - a.timestamp);\n return snapshots;\n },\n\n /**\n * Load a full snapshot by ID (includes message bodies).\n *\n * Returns null if the snapshot doesn't exist or is corrupted.\n */\n load(id: string): StoredSnapshot | null {\n const filePath = join(snapshotsDir, `${id}.json`);\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n return JSON.parse(raw) as StoredSnapshot;\n } catch {\n return null;\n }\n },\n\n /**\n * Delete a snapshot by ID.\n *\n * No-op if the snapshot doesn't exist.\n */\n delete(id: string): void {\n try {\n unlinkSync(join(snapshotsDir, `${id}.json`));\n } catch {\n // Already deleted or never existed — no-op\n }\n },\n };\n}\n\nexport type SnapshotStore = ReturnType<typeof createSnapshotStore>;\n","/**\n * TUI launcher — boots the application and renders the Ink UI.\n *\n * This module is lazily loaded only when the user enters\n * interactive mode (no sub‑command given).\n */\n\nimport { fileURLToPath } from \"node:url\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { bootstrap } from \"./bootstrap.js\";\nimport { resolvePaths, asSessionId } from \"@24klynx/core\";\nimport { loadConfig, resolveConfigEnv, resolveProvider } from \"./commands/config.js\";\nimport type {\n TuiCallbacks,\n TuiStreamEvent,\n TuiModelInfo,\n McpConnectionInfo,\n PluginInfo,\n SkillInfo,\n ContextInfo,\n UsageInfo,\n} from \"@24klynx/tui\";\nimport { runPhase2WithContext } from \"./startup.js\";\nimport { enterFullscreen, exitFullscreen } from \"./terminal-mode.js\";\nimport { installProcessLifecycle } from \"./process-lifecycle.js\";\nimport { saveConfig } from \"./commands/config.js\";\nimport { MemoryMonitor } from \"./memory-monitor.js\";\nimport { checkForUpdates } from \"./update-check.js\";\nimport { createSnapshotStore } from \"./snapshot-store.js\";\nimport type { TaskEntry } from \"@24klynx/tui\";\n\n// ── Cost estimation ──────────────────────────────────\n\n/** Approximate USD per 1M input tokens. */\nconst INPUT_PRICE_PER_1M: Record<string, number> = {\n \"deepseek-chat\": 0.27,\n \"deepseek-reasoner\": 0.55,\n \"gpt-4o\": 2.5,\n \"gpt-4o-mini\": 0.15,\n \"o3-mini\": 1.1,\n \"claude-sonnet-4-20250514\": 3.0,\n \"claude-haiku-3-5\": 0.8,\n \"claude-opus-4-20250514\": 15.0,\n};\n\n/** Approximate USD per 1M output tokens. */\nconst OUTPUT_PRICE_PER_1M: Record<string, number> = {\n \"deepseek-chat\": 1.1,\n \"deepseek-reasoner\": 2.19,\n \"gpt-4o\": 10.0,\n \"gpt-4o-mini\": 0.6,\n \"o3-mini\": 4.4,\n \"claude-sonnet-4-20250514\": 15.0,\n \"claude-haiku-3-5\": 4.0,\n \"claude-opus-4-20250514\": 75.0,\n};\n\n/**\n * Estimate the USD cost for a given token count.\n *\n * Uses approximate 70/30 input/output split and model‑specific pricing.\n * Falls back to $1.0/$4.0 per million for unknown models.\n */\nfunction estimateCost(model: string, totalTokens: number): number {\n if (totalTokens <= 0) return 0;\n const inputPrice = INPUT_PRICE_PER_1M[model] ?? 1.0;\n const outputPrice = OUTPUT_PRICE_PER_1M[model] ?? 4.0;\n const inputTokens = Math.floor(totalTokens * 0.7);\n const outputTokens = Math.floor(totalTokens * 0.3);\n return (inputTokens / 1_000_000) * inputPrice + (outputTokens / 1_000_000) * outputPrice;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * Launch the interactive TUI.\n *\n * Phase 1: bootstrap services (DB, sessions, tools, agent engine).\n * Phase 2: render the Ink TUI.\n */\nexport async function launchTui(): Promise<void> {\n const paths = resolvePaths();\n\n // 加载配置 → 注入 env → 按模型名自动选 Provider\n const config = loadConfig();\n resolveConfigEnv(config);\n const provider = resolveProvider(config);\n\n // Resolve built‑in skills directory relative to the lynx-agent package\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n const builtinSkillsDir = join(__dirname, \"..\", \"..\", \"lynx-agent\", \"skills\");\n\n const ctx = bootstrap({\n homeDir: paths.home,\n provider,\n model: process.env.LYNX_MODEL ?? config.model,\n skillsDir: builtinSkillsDir,\n workspace: process.cwd(),\n });\n\n const sessions = ctx.sessionMgr.list();\n\n // Pick the most recent session or create a new one\n const activeSession =\n sessions.length > 0 ? sessions[0]! : ctx.sessionMgr.create(\"default\", process.cwd());\n\n // ── Abort layer state (3‑layer Ctrl+C) ──────────\n let abortLayer = 0;\n let currentAbortController: AbortController | null = null;\n let isStreaming = false;\n\n const resetAbortLayer = () => {\n abortLayer = 0;\n };\n\n const getAbortLayer = () => abortLayer;\n\n const incrementAbortLayer = () => {\n abortLayer++;\n return abortLayer;\n };\n\n // ── Process lifecycle ─────────────────────────\n installProcessLifecycle({\n ctx,\n onAbortLl: () => {\n ctx.engine.abort();\n },\n onAbortTool: () => {\n // Layer 2: abort running tool (engine handles internally)\n ctx.engine.abort();\n },\n getAbortLayer,\n incrementAbortLayer,\n resetAbortLayer,\n isStreaming: () => isStreaming,\n });\n\n // Build TUI callbacks bridging to the agent engine\n // Build model list for the TUI model picker\n const providerModels: TuiModelInfo[] = ctx.provider.listModels().map((m) => ({\n id: m.id,\n label: m.label,\n contextWindow: m.contextWindow,\n maxOutput: m.maxOutput,\n inputPrice: INPUT_PRICE_PER_1M[m.id],\n outputPrice: OUTPUT_PRICE_PER_1M[m.id],\n }));\n\n const callbacks: TuiCallbacks = {\n async *onInput(message: string): AsyncGenerator<TuiStreamEvent, void, void> {\n // Reset abort layer on new message\n resetAbortLayer();\n isStreaming = true;\n\n // Create a user message\n const userMsg = {\n id: crypto.randomUUID() as never,\n role: \"user\" as const,\n content: [{ type: \"text\" as const, text: message }],\n timestamp: Date.now(),\n turnIndex: 0,\n };\n\n currentAbortController = new AbortController();\n const signal = currentAbortController.signal;\n\n let turnCompleted = false;\n let reasoningStart: number | null = null;\n let reasoningText = \"\";\n\n /** End reasoning tracking, yielding a status event with duration and text if reasoning was active. */\n const endReasoning = (): TuiStreamEvent | null => {\n if (reasoningStart === null) return null;\n const durationMs = Date.now() - reasoningStart;\n const text = reasoningText;\n reasoningStart = null;\n reasoningText = \"\";\n return { type: \"reasoning_status\", status: \"ended\", durationMs, text };\n };\n\n try {\n for await (const event of ctx.engine.submit(activeSession, userMsg, signal)) {\n // Map agent stream events to TUI stream events\n switch (event.type) {\n case \"text_delta\": {\n const rEnd = endReasoning();\n if (rEnd) yield rEnd;\n yield { type: \"text_delta\", text: event.text };\n break;\n }\n case \"reasoning_delta\":\n if (reasoningStart === null) {\n reasoningStart = Date.now();\n yield { type: \"reasoning_status\", status: \"started\" };\n }\n reasoningText += event.text;\n break;\n case \"tool_use_start\": {\n const rEnd = endReasoning();\n if (rEnd) yield rEnd;\n yield { type: \"tool_use\", name: event.name, callId: event.callId };\n break;\n }\n case \"tool_result\":\n yield { type: \"tool_result\", callId: event.toolUseId, content: event.content };\n break;\n case \"tool_recap\":\n yield {\n type: \"tool_recap\",\n summary: event.summary,\n toolCount: event.toolCount,\n durationMs: event.durationMs,\n };\n break;\n case \"error\":\n yield { type: \"error\", message: event.message };\n break;\n case \"done\": {\n const rEnd = endReasoning();\n if (rEnd) yield rEnd;\n turnCompleted = true;\n const totalTokens = event.totalTokens ?? 0;\n // Approximate cost: 70% input, 30% output pricing\n const costUsd = estimateCost(ctx.agentConfig.model, totalTokens);\n yield { type: \"done\", totalTokens, costUsd };\n break;\n }\n }\n }\n\n // Auto-capture snapshot after a successful turn\n if (turnCompleted && activeSession.messages.length > 0) {\n try {\n snapshotStore.capture(activeSession);\n } catch {\n // Best-effort — don't block the UI on snapshot failure\n }\n }\n } catch (err) {\n yield {\n type: \"error\",\n message: err instanceof Error ? err.message : String(err),\n };\n } finally {\n isStreaming = false;\n currentAbortController = null;\n }\n },\n\n onSessionPick(sessionId: string): void {\n const session = ctx.sessionMgr.load(asSessionId(sessionId));\n if (session) {\n // Session switching will be handled by the TUI state\n process.stdout.write(`Switched to session: ${session.label ?? sessionId}\\n`);\n }\n },\n\n onPermissionReply(requestId: string, approved: boolean): void {\n ctx.permissionBridge.handleReply(requestId, approved);\n },\n\n onAbort(): void {\n ctx.engine.abort();\n },\n\n onModelPick(modelId: string): void {\n ctx.agentConfig.model = modelId;\n // Persist to config\n const cfg = loadConfig();\n cfg.model = modelId;\n saveConfig(cfg);\n },\n\n onConfigChange(key: string, value: unknown): void {\n const cfg = loadConfig();\n if (key === \"model\" && typeof value === \"string\") {\n cfg.model = value;\n } else if (key === \"theme\" && typeof value === \"string\") {\n cfg.theme = value;\n }\n saveConfig(cfg);\n },\n\n onThemeChange(themeName: string): void {\n // Persist to config (setTheme() is called by the TUI directly)\n const cfg = loadConfig();\n cfg.theme = themeName;\n saveConfig(cfg);\n },\n\n // ── Session CRUD ─────────────────────────────────\n\n onSessionCreate(label: string): void {\n ctx.sessionMgr.create(label, workspace);\n },\n\n onSessionFork(newLabel: string): void {\n ctx.sessionMgr.fork(activeSession.id, newLabel);\n },\n\n onSessionRename(newLabel: string): void {\n ctx.sessionMgr.rename(activeSession.id, newLabel);\n },\n\n onSessionDelete(sessionId: string): void {\n ctx.sessionMgr.delete(asSessionId(sessionId));\n },\n\n onSessionResume(sessionId: string): void {\n const resumed = ctx.sessionMgr.load(asSessionId(sessionId));\n if (resumed) {\n process.stdout.write(`Resumed session: ${resumed.label}\\n`);\n }\n },\n\n onSessionCompact(): void {\n // Trigger compaction on the engine for the active session\n ctx.engine.compact(activeSession);\n },\n\n // ── Data panels ────────────────────────────────\n\n async onRequestDiff() {\n // Run git diff in the workspace directory\n try {\n const { execSync } = await import(\"node:child_process\");\n const output = execSync(\"git diff --name-status\", {\n cwd: workspace,\n encoding: \"utf-8\",\n timeout: 5000,\n });\n const files: Array<{ path: string; status: string; diff: string }> = [];\n const lines = output.trim().split(\"\\n\").filter(Boolean);\n for (const line of lines) {\n const parts = line.split(\"\\t\");\n const status = (parts[0] ?? \"?\").charAt(0);\n const path = parts.length > 1 ? parts.slice(1).join(\"\\t\") : line;\n // Get per-file diff\n let diff = \"\";\n try {\n diff = execSync(`git diff -- \"${path}\"`, {\n cwd: workspace,\n encoding: \"utf-8\",\n timeout: 3000,\n });\n } catch {\n diff = \"(diff unavailable)\";\n }\n files.push({ path, status, diff });\n }\n return files;\n } catch {\n return [];\n }\n },\n\n async onRequestSnapshots() {\n return snapshotStore.list();\n },\n\n async onRequestTasks() {\n return [...phase2Tasks];\n },\n\n async onOpenExternalEditor(currentText: string): Promise<string | null> {\n const editor = process.env.EDITOR ?? process.env.VISUAL ?? \"notepad\";\n const { writeFileSync, readFileSync, unlinkSync } = await import(\"node:fs\");\n const { tmpdir } = await import(\"node:os\");\n const { join } = await import(\"node:path\");\n const { randomUUID } = await import(\"node:crypto\");\n const { execSync } = await import(\"node:child_process\");\n\n const tmpPath = join(tmpdir(), `lynx-editor-${randomUUID()}.md`);\n\n try {\n writeFileSync(tmpPath, currentText || \"# Lynx Editor\\n\\n\", \"utf-8\");\n execSync(`${editor} \"${tmpPath}\"`, { stdio: \"inherit\", timeout: 300_000 });\n const edited = readFileSync(tmpPath, \"utf-8\");\n // Remove the template header if the user didn't change it\n return edited === \"# Lynx Editor\\n\\n\" && currentText === \"\" ? null : edited;\n } catch {\n return null;\n } finally {\n try {\n unlinkSync(tmpPath);\n } catch {\n /* best effort */\n }\n }\n },\n };\n\n // ── Phase 2 task tracker (for /tasks panel) ─────────────────\n const phase2Tasks: TaskEntry[] = [];\n\n // ── Snapshot store ──────────────────────────────────────────\n const snapshotStore = createSnapshotStore(paths.snapshotsDir);\n const workspace = process.cwd();\n const userHome = homedir();\n\n /** Build MCP connection info from the connection manager. */\n function buildMcpConnections(): McpConnectionInfo[] {\n return ctx.mcpManager.listConnections().map((c) => ({\n name: c.serverName,\n status: c.status,\n toolCount: c.tools.length,\n detail: c.errorMessage ?? c.status,\n transport: c.transport,\n authStatus: c.authStatus,\n resourceCount: c.resourceCount,\n tools: c.toolsMeta,\n resources: c.resources,\n }));\n }\n\n /** Build plugin info from manifest registry and loader state. */\n function buildPlugins(): PluginInfo[] {\n const loaded = new Set(ctx.pluginRegistry.loader.listLoaded());\n return ctx.pluginRegistry.manifestRegistry.listAll().map((e) => ({\n name: e.manifest.name,\n version: e.manifest.version,\n description: e.manifest.description ?? \"\",\n loaded: loaded.has(e.manifest.name),\n }));\n }\n\n /** Build skill info from the skill registry, annotating source origin. */\n function buildSkills(): SkillInfo[] {\n return ctx.skillRegistry.list().map((s) => {\n let source: SkillInfo[\"source\"] = \"builtin\";\n if (s.path.startsWith(userHome)) source = \"user\";\n else if (s.path.startsWith(workspace)) source = \"project\";\n return { name: s.name, description: s.description, source };\n });\n }\n\n /** Build context summary for /context panel. */\n function buildContextInfo(): ContextInfo {\n return {\n memoryFacts: ctx.memoryFacts.length,\n rules: ctx.rules.length,\n skills: ctx.skills.length,\n model: ctx.agentConfig.model,\n workspace,\n sessionLabel: activeSession.label,\n };\n }\n\n /** Build usage statistics for /usage panel. */\n function buildUsageInfo(): UsageInfo {\n const model = ctx.agentConfig.model;\n const inputPrice = INPUT_PRICE_PER_1M[model];\n const outputPrice = OUTPUT_PRICE_PER_1M[model];\n const pricing =\n inputPrice !== undefined && outputPrice !== undefined\n ? `${model}: $${inputPrice}/M input · $${outputPrice}/M output`\n : `${model}: pricing N/A`;\n return {\n tokensUsed: 0,\n costUsd: 0,\n budgetMaxTokens: ctx.agentConfig.budget.maxTokens,\n budgetMaxUsd: ctx.agentConfig.budget.maxUsd,\n turns: 0,\n modelPricing: pricing,\n };\n }\n\n // Render the Ink TUI\n // Hoisted so the catch block can clean up after a crash.\n let memoryMonitor: MemoryMonitor | null = null;\n\n try {\n // Enter fullscreen alt buffer + mouse tracking\n enterFullscreen();\n\n const React = await import(\"react\");\n const { render } = await import(\"ink\");\n const { App } = await import(\"@24klynx/tui\");\n\n const { unmount, waitUntilExit } = render(\n React.createElement(App, {\n callbacks,\n session: activeSession,\n sessions,\n models: providerModels,\n currentModel: ctx.agentConfig.model,\n columns: process.stdout.columns ?? 80,\n rows: process.stdout.rows ?? 24,\n showWelcome: true,\n onPermissionReady: (handler) => {\n ctx.permissionBridge.setTuiHandler(handler);\n },\n mcpConnections: buildMcpConnections(),\n plugins: buildPlugins(),\n skills: buildSkills(),\n contextInfo: buildContextInfo(),\n usageInfo: buildUsageInfo(),\n }),\n );\n\n // Phase 2: background tasks (scan extensions, connect MCP, load memory).\n // Fire‑and‑forget — don't block the TUI. Results populate the /tasks panel.\n runPhase2WithContext(ctx, paths)\n .then((results) => {\n const statusMap: Record<string, TaskEntry[\"status\"]> = { true: \"done\", false: \"failed\" };\n for (const r of results) {\n phase2Tasks.push({\n id: `phase2-${r.name}`,\n name: r.name,\n status: statusMap[String(r.ok)] ?? \"failed\",\n error: r.error,\n });\n }\n })\n .catch(() => {\n // Errors are already logged by the task runner\n });\n\n // ── Memory monitor — proactive heap sampling ──\n memoryMonitor = new MemoryMonitor();\n memoryMonitor.onAlert((alert) => {\n process.stderr.write(\n `[lynx] Memory ${alert.level}: ${Math.round(alert.heapUsed / 1024 / 1024)}MB ` +\n `(${alert.percentage}% of threshold)\\n`,\n );\n });\n memoryMonitor.start();\n\n // ── Update check — non‑blocking background check ──\n checkForUpdates({ currentVersion: \"0.1.0\" })\n .then((result) => {\n if (result.hasUpdate) {\n process.stderr.write(\n `[lynx] Update available: ${result.current} → ${result.latest} ` +\n `(${result.releaseUrl})\\n`,\n );\n }\n })\n .catch(() => {\n // Update check is best‑effort — never block or crash\n });\n\n // Keep the process alive until the TUI exits\n await waitUntilExit();\n\n // Cleanup: stop monitors, exit fullscreen, unmount, destroy services\n memoryMonitor.stop();\n exitFullscreen();\n unmount();\n ctx.destroy();\n } catch (err) {\n process.stderr.write(\n `Failed to start TUI: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n // Recover terminal from alt‑buffer mode so the user isn't stuck\n try {\n memoryMonitor?.stop();\n } catch {\n // Best effort\n }\n try {\n exitFullscreen();\n } catch {\n // Terminal may already be gone\n }\n try {\n ctx.destroy();\n } catch {\n // Best effort\n }\n process.exitCode = 1;\n }\n}\n","/**\n * WorkerPool — bounded thread pool for CPU‑bound tasks.\n *\n * Manages a fixed number of worker threads (2‑8) with a FIFO task\n * queue. All workers share the same worker script; tasks differ\n * only by their postMessage payload.\n *\n * Design:\n * - Fixed pool size, configurable at creation time\n * - FIFO queue — tasks are executed in submission order\n * - Auto‑restart — crashed workers replaced up to maxRetries times\n * - Idle shrink — workers idle for > 30s are terminated (min 2 kept)\n * - Graceful shutdown — drain remaining tasks before exit\n */\n\nimport { Worker } from \"node:worker_threads\";\n\n// ── Types ────────────────────────────────────────────\n\n/** A unit of work submitted to the pool. */\nexport interface PoolTask<T = unknown> {\n /** Unique task identifier. */\n id: string;\n /** Data passed to the worker via postMessage. */\n workerData?: T;\n /** Resolve the task with the worker's result. */\n resolve: (result: unknown) => void;\n /** Reject the task on failure. */\n reject: (error: Error) => void;\n /** Number of times this task has been retried after worker crash. */\n retries: number;\n}\n\n/** Configuration for the worker pool. */\nexport interface WorkerPoolConfig {\n /** Path to the worker script that all workers execute. */\n workerScript: string | URL;\n /** Number of workers in the pool (clamped to 2‑8). Default: 2. */\n size?: number;\n /** Max restarts per worker before the pool rejects queued tasks. Default: 3. */\n maxRetries?: number;\n /** Idle timeout in ms before shrinking a worker. Default: 30_000. */\n idleTimeoutMs?: number;\n}\n\n/** Status of the worker pool for introspection. */\nexport interface PoolStatus {\n size: number;\n active: number;\n idle: number;\n queued: number;\n totalRestarts: number;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst MIN_POOL_SIZE = 2;\nconst MAX_POOL_SIZE = 8;\nconst DEFAULT_SIZE = 2;\nconst DEFAULT_MAX_RETRIES = 3;\nconst DEFAULT_IDLE_MS = 30_000;\n\n// ── Worker entry ─────────────────────────────────────\n\ninterface WorkerEntry {\n worker: Worker;\n busy: boolean;\n restarts: number;\n idleTimer: ReturnType<typeof setTimeout> | null;\n}\n\n// ── WorkerPool ───────────────────────────────────────\n\n/**\n * Bounded worker thread pool.\n *\n * Usage:\n * ```ts\n * const pool = new WorkerPool({ workerScript: \"./heavy-task.js\", size: 4 });\n * const result = await pool.enqueue({ input: 42 });\n * await pool.shutdown();\n * ```\n */\nexport class WorkerPool {\n private config: Required<Omit<WorkerPoolConfig, \"workerScript\">>;\n private workerScript: string | URL;\n private queue: PoolTask[] = [];\n private workers = new Map<number, WorkerEntry>();\n private runningTasks = new Map<number, PoolTask>();\n private nextWorkerId = 0;\n private destroyed = false;\n private totalRestarts = 0;\n\n constructor(config: WorkerPoolConfig) {\n const size = Math.min(MAX_POOL_SIZE, Math.max(MIN_POOL_SIZE, config.size ?? DEFAULT_SIZE));\n this.config = {\n size,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n idleTimeoutMs: config.idleTimeoutMs ?? DEFAULT_IDLE_MS,\n };\n this.workerScript = config.workerScript;\n\n for (let i = 0; i < size; i++) {\n this.spawnWorker();\n }\n }\n\n // ── Public API ──────────────────────────────────\n\n /**\n * Enqueue a task for execution.\n *\n * Returns a Promise that resolves with the worker's result\n * or rejects if the pool is destroyed.\n */\n enqueue<TResult = unknown>(data?: unknown): Promise<TResult> {\n if (this.destroyed) {\n return Promise.reject(new Error(\"WorkerPool is destroyed\"));\n }\n\n return new Promise<TResult>((resolve, reject) => {\n const task: PoolTask = {\n id: `task-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n workerData: data,\n resolve: resolve as (result: unknown) => void,\n reject,\n retries: 0,\n };\n\n this.queue.push(task);\n this.drain();\n });\n }\n\n /** Current pool status for monitoring. */\n status(): PoolStatus {\n let active = 0;\n let idle = 0;\n for (const w of this.workers.values()) {\n if (w.busy) active++;\n else idle++;\n }\n return {\n size: this.workers.size,\n active,\n idle,\n queued: this.queue.length,\n totalRestarts: this.totalRestarts,\n };\n }\n\n /**\n * Gracefully shut down the pool.\n *\n * Waits for active tasks to finish, then terminates all workers.\n * Queued tasks that haven't started are rejected.\n */\n async shutdown(): Promise<void> {\n this.destroyed = true;\n\n // Reject all queued tasks\n for (const task of this.queue) {\n task.reject(new Error(\"WorkerPool shut down\"));\n }\n this.queue.length = 0;\n\n // Terminate all workers\n for (const entry of this.workers.values()) {\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n await entry.worker.terminate();\n }\n this.workers.clear();\n }\n\n // ── Internals ───────────────────────────────────\n\n /** Spawn a new worker thread. */\n private spawnWorker(): number {\n const id = this.nextWorkerId++;\n\n let worker: Worker;\n try {\n worker = new Worker(this.workerScript, { workerData: { poolId: id } });\n } catch {\n // Worker script not found or invalid — defer error to enqueue\n return -1;\n }\n\n worker.on(\"error\", (_err) => {\n this.handleWorkerCrash(id);\n });\n\n worker.on(\"messageerror\", () => {\n this.handleWorkerCrash(id);\n });\n\n worker.on(\"exit\", (code) => {\n if (code !== 0) {\n this.handleWorkerCrash(id);\n }\n });\n\n const idleTimer = this.startIdleTimer(id);\n\n this.workers.set(id, { worker, busy: false, restarts: 0, idleTimer });\n return id;\n }\n\n /** Replace a crashed worker and re-queue or reject its active task. */\n private handleWorkerCrash(id: number): void {\n const entry = this.workers.get(id);\n if (!entry) return;\n\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n\n entry.restarts++;\n this.totalRestarts++;\n\n // Terminate and remove the crashed worker\n entry.worker.terminate().catch(() => {});\n this.workers.delete(id);\n\n // Handle any task that was running on the crashed worker\n const activeTask = this.runningTasks.get(id);\n if (activeTask) {\n this.runningTasks.delete(id);\n activeTask.retries++;\n if (activeTask.retries > this.config.maxRetries) {\n activeTask.reject(new Error(`Task failed after ${activeTask.retries} worker crashes`));\n } else {\n // Re-queue the task for another worker to pick up\n this.queue.unshift(activeTask);\n }\n }\n\n // Replace the worker if pool is still alive\n if (!this.destroyed && this.workers.size < this.config.size) {\n this.spawnWorker();\n }\n\n this.drain();\n }\n\n /** Try to dequeue and execute pending tasks. */\n private drain(): void {\n if (this.destroyed) return;\n\n // Find an idle worker\n for (const [id, entry] of this.workers) {\n if (!entry.busy && this.queue.length > 0) {\n const task = this.queue.shift();\n if (!task) return;\n\n entry.busy = true;\n if (entry.idleTimer) {\n clearTimeout(entry.idleTimer);\n entry.idleTimer = null;\n }\n\n this.runTask(id, entry.worker, task);\n return; // One task per drain — next tick picks up the rest\n }\n }\n\n // If no tasks and we have idle workers, try to shrink\n if (this.queue.length === 0) {\n this.maybeShrink();\n }\n }\n\n /** Execute a single task on a worker. */\n private runTask(workerId: number, worker: Worker, task: PoolTask): void {\n this.runningTasks.set(workerId, task);\n\n const onMessage = (result: unknown) => {\n cleanup();\n task.resolve(result);\n const entry = this.workers.get(workerId);\n if (entry) {\n entry.busy = false;\n entry.idleTimer = this.startIdleTimer(workerId);\n }\n this.drain();\n };\n\n const onError = (err: Error) => {\n cleanup();\n task.reject(err);\n const entry = this.workers.get(workerId);\n if (entry) {\n entry.busy = false;\n entry.idleTimer = this.startIdleTimer(workerId);\n }\n this.drain();\n };\n\n const cleanup = () => {\n this.runningTasks.delete(workerId);\n worker.removeListener(\"message\", onMessage);\n worker.removeListener(\"error\", onError);\n };\n\n worker.once(\"message\", onMessage);\n worker.once(\"error\", onError);\n\n worker.postMessage({ taskId: task.id, data: task.workerData });\n }\n\n /** Start or reset the idle timer for a worker. */\n private startIdleTimer(workerId: number): ReturnType<typeof setTimeout> {\n return setTimeout(() => {\n this.shrinkWorker(workerId);\n }, this.config.idleTimeoutMs);\n }\n\n /** Attempt to shrink idle workers if above minimum. */\n private maybeShrink(): void {\n const idleIds: number[] = [];\n for (const [id, entry] of this.workers) {\n if (!entry.busy) idleIds.push(id);\n }\n\n // Keep at least MIN_POOL_SIZE workers\n while (idleIds.length > MIN_POOL_SIZE && this.workers.size > MIN_POOL_SIZE) {\n const id = idleIds.pop()!;\n this.shrinkWorker(id);\n }\n }\n\n /** Terminate a specific idle worker. */\n private shrinkWorker(workerId: number): void {\n const entry = this.workers.get(workerId);\n if (!entry || entry.busy) return;\n if (this.workers.size <= MIN_POOL_SIZE) return;\n\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.worker.terminate().catch(() => {});\n this.workers.delete(workerId);\n }\n}\n","/**\n * Plugin command — manage installed plugins.\n *\n * Sub‑commands:\n * list — list installed plugins with status\n * enable <name> — enable a disabled plugin\n * disable <name> — disable a plugin (without uninstalling)\n * install <path> — install a plugin from a local path\n * remove <name> — uninstall a plugin\n */\n\nimport {\n readdirSync,\n readFileSync,\n existsSync,\n writeFileSync,\n mkdirSync,\n renameSync,\n} from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { resolvePaths } from \"@24klynx/core\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface PluginCommandOptions {\n list?: boolean;\n enable?: string;\n disable?: string;\n install?: string;\n remove?: string;\n}\n\ninterface PluginManifest {\n name: string;\n version: string;\n description?: string;\n type: \"tool\" | \"channel\" | \"provider\";\n}\n\ninterface InstalledPlugin {\n name: string;\n version: string;\n description: string;\n type: string;\n enabled: boolean;\n path: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** Path to the installed‑plugins registry JSON file. */\nfunction registryPath(): string {\n const paths = resolvePaths();\n return join(paths.home, \"plugins.json\");\n}\n\n/** Path to the Lynx extensions directory. */\nfunction extensionsDir(): string {\n const paths = resolvePaths();\n return join(paths.home, \"extensions\");\n}\n\nfunction loadRegistry(): Record<string, InstalledPlugin> {\n const path = registryPath();\n if (!existsSync(path)) return {};\n try {\n return JSON.parse(readFileSync(path, \"utf-8\"));\n } catch {\n const backupPath = path + \".bak\";\n renameSync(path, backupPath);\n process.stderr.write(\n `[lynx] 警告:插件注册表已损坏,已备份到 ${backupPath}。正在使用默认配置。\\n`,\n );\n return {};\n }\n}\n\nfunction saveRegistry(reg: Record<string, InstalledPlugin>): void {\n const path = registryPath();\n const dir = dirname(path);\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n const tmp = path + \".tmp\";\n writeFileSync(tmp, JSON.stringify(reg, null, 2) + \"\\n\", \"utf-8\");\n renameSync(tmp, path);\n}\n\nfunction readManifest(pluginDir: string): PluginManifest | null {\n const manifestPath = join(pluginDir, \"manifest.json\");\n if (!existsSync(manifestPath)) return null;\n try {\n return JSON.parse(readFileSync(manifestPath, \"utf-8\"));\n } catch {\n return null;\n }\n}\n\n/** Scan the extensions directory for installed plugins. */\nfunction scanInstalled(): Map<string, string> {\n const dir = extensionsDir();\n const result = new Map<string, string>();\n if (!existsSync(dir)) return result;\n\n let entries: string[];\n try {\n entries = readdirSync(dir);\n } catch {\n return result;\n }\n\n for (const entry of entries) {\n const fullPath = join(dir, entry);\n try {\n const stat = require(\"node:fs\").statSync(fullPath);\n if (!stat.isDirectory()) continue;\n } catch {\n continue;\n }\n\n const manifest = readManifest(fullPath);\n if (manifest) {\n result.set(manifest.name, fullPath);\n }\n }\n\n return result;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/** Handle the `lynx plugin` command. */\nexport async function handlePluginCommand(opts: PluginCommandOptions): Promise<void> {\n if (opts.list) {\n await listPlugins();\n return;\n }\n\n if (opts.enable) {\n await setPluginEnabled(opts.enable, true);\n return;\n }\n\n if (opts.disable) {\n await setPluginEnabled(opts.disable, false);\n return;\n }\n\n if (opts.install) {\n await installPlugin(opts.install);\n return;\n }\n\n if (opts.remove) {\n await removePlugin(opts.remove);\n return;\n }\n\n // Default: list\n await listPlugins();\n}\n\n// ── Sub‑commands ────────────────────────────────────\n\nasync function listPlugins(): Promise<void> {\n const installed = scanInstalled();\n const registry = loadRegistry();\n\n if (installed.size === 0) {\n process.stdout.write(\"No plugins installed.\\n\");\n process.stdout.write(`Extensions directory: ${extensionsDir()}\\n`);\n return;\n }\n\n const lines: string[] = [];\n for (const [name, dirPath] of installed) {\n const manifest = readManifest(dirPath);\n const record = registry[name];\n const enabled = record?.enabled ?? true;\n const version = manifest?.version ?? \"unknown\";\n const type = manifest?.type ?? \"unknown\";\n const desc = manifest?.description ?? \"\";\n const status = enabled ? \"enabled\" : \"disabled\";\n lines.push(\n `${status === \"disabled\" ? \"○\" : \"✓\"} ${name}@${version} (${type}) ${status} — ${desc}`,\n );\n lines.push(` path: ${dirPath}`);\n }\n\n process.stdout.write(lines.join(\"\\n\") + \"\\n\");\n}\n\nasync function setPluginEnabled(name: string, enabled: boolean): Promise<void> {\n const registry = loadRegistry();\n const installed = scanInstalled();\n\n if (!installed.has(name)) {\n process.stderr.write(`Plugin \"${name}\" is not installed.\\n`);\n process.exitCode = 1;\n return;\n }\n\n registry[name] = {\n name,\n version: readManifest(installed.get(name)!)?.version ?? \"unknown\",\n description: readManifest(installed.get(name)!)?.description ?? \"\",\n type: readManifest(installed.get(name)!)?.type ?? \"unknown\",\n enabled,\n path: installed.get(name)!,\n };\n\n saveRegistry(registry);\n const action = enabled ? \"enabled\" : \"disabled\";\n process.stdout.write(`Plugin \"${name}\" ${action}.\\n`);\n}\n\nasync function installPlugin(sourcePath: string): Promise<void> {\n const manifest = readManifest(sourcePath);\n if (!manifest) {\n process.stderr.write(`No valid manifest.json found at \"${sourcePath}\".\\n`);\n process.exitCode = 1;\n return;\n }\n\n const targetDir = join(extensionsDir(), manifest.name);\n\n if (existsSync(targetDir)) {\n process.stderr.write(\n `Plugin \"${manifest.name}\" is already installed at \"${targetDir}\".\\n` +\n `Use \"lynx plugin remove ${manifest.name}\" first to reinstall.\\n`,\n );\n process.exitCode = 1;\n return;\n }\n\n // Simple copy: read all files from source and write to target\n // For a real implementation, this would use a proper copy utility\n const { cpSync } = await import(\"node:fs\");\n try {\n mkdirSync(dirname(targetDir), { recursive: true });\n cpSync(sourcePath, targetDir, { recursive: true });\n } catch (err) {\n process.stderr.write(\n `Failed to copy plugin: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exitCode = 1;\n return;\n }\n\n const registry = loadRegistry();\n registry[manifest.name] = {\n name: manifest.name,\n version: manifest.version,\n description: manifest.description ?? \"\",\n type: manifest.type,\n enabled: true,\n path: targetDir,\n };\n saveRegistry(registry);\n\n process.stdout.write(\n `Plugin \"${manifest.name}@${manifest.version}\" installed to \"${targetDir}\".\\n`,\n );\n}\n\nasync function removePlugin(name: string): Promise<void> {\n const registry = loadRegistry();\n const installed = scanInstalled();\n const dirPath = installed.get(name);\n\n if (!dirPath) {\n process.stderr.write(`Plugin \"${name}\" is not installed.\\n`);\n process.exitCode = 1;\n return;\n }\n\n // Remove the plugin directory\n const { rmSync } = await import(\"node:fs\");\n try {\n rmSync(dirPath, { recursive: true, force: true });\n } catch (err) {\n process.stderr.write(\n `Failed to remove plugin directory: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n process.exitCode = 1;\n return;\n }\n\n // Remove from registry\n delete registry[name];\n saveRegistry(registry);\n\n process.stdout.write(`Plugin \"${name}\" removed.\\n`);\n}\n","/**\n * /commit 命令 — 创建 Git 提交并推送。\n *\n * 生成中文指令,引导模型执行完整的提交工作流:\n * 1. 检查工作区状态和变更摘要\n * 2. 基于用户消息(或自动生成)创建约定式提交\n * 3. git add → git commit → git push\n * 4. --all 标志表示暂存所有变更\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CommitCommandArgs {\n /** 用户自定义的提交消息(可选,省略时自动生成)。 */\n message?: string;\n /** 是否暂存所有变更(git add -A)。 */\n all?: boolean;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /commit 命令,返回一段中文指令引导模型完成提交。\n */\nexport function handleCommitCommand(args: CommitCommandArgs): { instruction: string } {\n const { message, all } = args;\n\n const steps: string[] = [\n \"# Git 提交任务\",\n \"\",\n \"请按以下步骤完成提交:\",\n \"\",\n \"1. 先运行 `git status` 查看当前工作区状态\",\n \"2. 运行 `git diff --stat` 查看变更文件摘要\",\n \"3. 运行 `git diff` 查看具体变更内容,根据变更内容生成有意义的提交消息\",\n ];\n\n if (all) {\n steps.push(\"4. 运行 `git add -A` 暂存所有变更(包括新增、修改和删除)\");\n } else {\n steps.push(\"4. 运行 `git add <files>` 暂存需要提交的文件(请根据 diff 内容选择合适的文件)\");\n }\n\n if (message && message.trim().length > 0) {\n steps.push(`5. 运行 \\`git commit -m \"${message}\"\\` 创建提交`);\n } else {\n steps.push(\n '5. 运行 `git commit -m \"<生成的提交消息>\"` 创建提交(使用约定式提交格式:feat/fix/refactor/chore + 中文描述)',\n );\n }\n\n steps.push(\n \"6. 运行 `git push` 推送到远程仓库\",\n \"\",\n \"注意事项:\",\n \"- 提交消息使用约定式提交格式:类型用英文(feat/fix/refactor/chore/docs/test),描述用中文\",\n \"- 每次提交后立即执行 git push\",\n \"- 如果推送失败(如远程有更新),先执行 git pull --rebase 再推送\",\n \"- 不要提交 .env 文件或包含密钥的配置文件\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /review 命令 — 审查 GitHub Pull Request。\n *\n * 生成中文指令,引导模型获取 PR 变更并给出结构化审查意见:\n * 1. 获取 PR 信息(列表或详情)\n * 2. 获取 PR diff 内容\n * 3. 系统化分析:bug、风格、测试、安全\n * 4. 输出结构化审查报告\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface ReviewCommandArgs {\n /** PR 编号(可选,省略时列出所有待审查的 PR)。 */\n number?: number;\n /** 目标分支(用于 gh pr list 的 --base 过滤)。 */\n base?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /review 命令,返回一段中文指令引导模型完成代码审查。\n */\nexport function handleReviewCommand(args: ReviewCommandArgs): { instruction: string } {\n const { number, base } = args;\n\n const steps: string[] = [\"# GitHub PR 审查任务\", \"\", \"请按以下步骤完成 PR 审查:\", \"\"];\n\n if (number !== undefined) {\n steps.push(\n `1. 运行 \\`gh pr view ${number} --json number,title,author,body,state,additions,deletions,files\\` 获取 PR #${number} 的详细信息`,\n `2. 运行 \\`gh pr diff ${number}\\` 获取 PR #${number} 的完整变更内容`,\n );\n } else {\n const baseFilter = base ? ` --base ${base}` : \"\";\n steps.push(\n `1. 运行 \\`gh pr list --state open --limit 10${baseFilter}\\` 列出待审查的 PR`,\n \"2. 选择一个需要审查的 PR,运行 `gh pr diff <number>` 获取完整变更内容\",\n );\n }\n\n steps.push(\n \"\",\n \"3. 系统化分析变更内容(按以下维度):\",\n \"\",\n \" a) 正确性:逻辑错误、边界条件处理、空值/null 检查、竞态条件\",\n \" b) 安全性:输入校验、注入风险、密钥泄露、权限检查\",\n \" c) 代码风格:命名规范、函数长度、嵌套层级、重复代码\",\n \" d) 测试:测试覆盖率、边界情况覆盖、错误路径测试\",\n \" e) 架构:模块耦合度、接口设计、依赖方向是否正确\",\n \" f) 性能:不必要的循环、大对象分配、阻塞 IO\",\n \"\",\n \"4. 输出结构化审查报告:\",\n \"\",\n \" - 总体评价(1-2 句话总结)\",\n \" - 严重问题(必须修复才能合并)\",\n \" - 建议改进(推荐但不阻塞合并)\",\n \" - 亮点(做得好的地方)\",\n \"\",\n \"注意:审查要具体,引用具体文件和行号。\",\n \"如果 PR 描述中有验收标准,逐条检查是否满足。\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /pr-comments 命令 — 处理 PR 审查评论。\n *\n * 生成中文指令,引导模型:\n * 1. 获取 PR 所有评论\n * 2. 处理未解决的评论(修改代码)\n * 3. 回复已解决的评论(确认)\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface PrCommentsCommandArgs {\n /** PR 编号(可选,省略时从最近 PR 推断)。 */\n number?: number;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /pr-comments 命令,返回一段中文指令引导模型处理 PR 评论。\n */\nexport function handlePrCommentsCommand(args: PrCommentsCommandArgs): { instruction: string } {\n const { number } = args;\n\n const steps: string[] = [\"# PR 评论处理任务\", \"\", \"请按以下步骤处理 PR 审查评论:\", \"\"];\n\n if (number !== undefined) {\n steps.push(\n `1. 运行 \\`gh pr view ${number} --comments\\` 获取 PR #${number} 的所有评论`,\n `2. 运行 \\`gh pr view ${number} --json reviewRequests,reviews\\` 查看审查状态`,\n );\n } else {\n steps.push(\n \"1. 运行 `gh pr list --state open --limit 5` 找到当前活跃的 PR\",\n \"2. 对目标 PR 运行 `gh pr view <number> --comments` 获取所有评论\",\n );\n }\n\n steps.push(\n \"\",\n \"3. 逐条处理评论:\",\n \"\",\n \" 对于未解决的评论(需要代码修改):\",\n \" - 理解评论指出的问题\",\n \" - 使用 read_file 读取相关文件,确认上下文\",\n \" - 使用 edit_file 或 write_file 进行针对性修改\",\n \" - 修改后使用 gh api 回复评论说明修改内容\",\n \"\",\n \" 对于已解决的评论(无需修改):\",\n ' - 添加简短回复确认处理完毕(如 \"已修复,感谢指正\")',\n \"\",\n \"4. 所有评论处理完后,运行 `gh pr view <number> --comments` 确认没有遗漏\",\n \"\",\n \"注意:\",\n \"- 一次修改尽量覆盖多条相关评论,减少提交次数\",\n \"- 如有不理解的评论,标记出来请求澄清\",\n \"- 修改完成后简要总结所有变更\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /issue 命令 — 管理 GitHub Issue。\n *\n * 生成中文指令,引导模型执行 Issue 操作:\n * create — 创建新 Issue\n * list — 列出仓库 Issue\n * view — 查看指定 Issue 详情\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface IssueCommandArgs {\n /** 操作类型:create 创建、list 列出、view 查看。 */\n action?: \"create\" | \"list\" | \"view\";\n /** Issue 标题(create 时使用)。 */\n title?: string;\n /** Issue 编号(view 时使用)。 */\n number?: number;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /issue 命令,返回一段中文指令引导模型完成 Issue 操作。\n */\nexport function handleIssueCommand(args: IssueCommandArgs): { instruction: string } {\n const { action = \"list\", title, number } = args;\n\n const steps: string[] = [];\n\n switch (action) {\n case \"create\": {\n steps.push(\"# 创建 GitHub Issue\", \"\", \"请按以下步骤创建新 Issue:\", \"\");\n if (title && title.trim().length > 0) {\n steps.push(\n \"1. 基于以下标题编写详细的 Issue 正文(包括问题描述、复现步骤、预期行为、环境信息)\",\n ` 标题:${title}`,\n );\n } else {\n steps.push(\n \"1. 首先了解需要创建什么 Issue——分析当前上下文,确定 Issue 的主题和内容\",\n \"2. 编写 Issue 正文(包括问题描述、复现步骤、预期行为、环境信息)\",\n );\n }\n steps.push(\n \"\",\n `3. 运行 \\`gh issue create --title \"<标题>\" --body \"<正文>\"\\` 创建 Issue`,\n \"\",\n \"注意:\",\n \"- 如果是 Bug 报告,需要包含:环境、复现步骤、实际行为、预期行为\",\n \"- 如果是功能请求,需要包含:动机、方案描述、替代方案\",\n \"- 描述要清晰具体,让维护者无需追问即可理解\",\n );\n break;\n }\n\n case \"view\": {\n if (number !== undefined) {\n steps.push(\n \"# 查看 GitHub Issue\",\n \"\",\n `1. 运行 \\`gh issue view ${number}\\` 查看 Issue #${number} 详情`,\n `2. 运行 \\`gh issue view ${number} --comments\\` 查看所有评论`,\n \"3. 总结 Issue 关键信息:标题、状态、标签、提出者、讨论要点\",\n );\n } else {\n steps.push(\n \"# 查看 GitHub Issue\",\n \"\",\n \"1. 运行 `gh issue list --state open --limit 10` 列出活跃 Issue\",\n \"2. 选择一个 Issue,运行 `gh issue view <number>` 查看详情\",\n \"3. 总结 Issue 关键信息\",\n );\n }\n break;\n }\n\n case \"list\":\n default: {\n steps.push(\n \"# 列出 GitHub Issue\",\n \"\",\n \"1. 运行 `gh issue list --state open --limit 20` 列出活跃 Issue\",\n \"2. 以结构化表格展示:编号、标题、标签、状态、负责人、更新时间\",\n \"3. 可选:添加 --label <name> 按标签过滤,或 --assignee <user> 按负责人过滤\",\n );\n break;\n }\n }\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /autofix-pr 命令 — 自动修复 PR 问题。\n *\n * ⚠️ 功能正在开发中,当前为占位实现。\n * 后续将与 gh cli 集成,实现自动分析 PR 失败检查并生成修复方案。\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface AutoFixCommandArgs {\n /** PR 编号(可选)。 */\n number?: number;\n /** 要修复的问题描述(可选)。 */\n issue?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /autofix-pr 命令。\n *\n * 当前为占位实现,返回开发中提示信息。\n * 后续将实现完整的自动修复管线。\n */\nexport function handleAutoFixCommand(_args: AutoFixCommandArgs): { instruction: string } {\n return {\n instruction: \"自动修复功能正在开发中,暂不可用。请关注后续版本更新。\",\n };\n}\n","/**\n * /diff 命令 — 展示 Git 工作区变更。\n *\n * 生成中文指令,引导模型:\n * 1. 运行 git diff 获取未暂存变更\n * 2. 运行 git diff --staged 获取已暂存变更\n * 3. 以结构化格式展示,高亮关键变更\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface DiffCommandArgs {\n /** 是否仅显示已暂存的变更(git diff --staged)。 */\n staged?: boolean;\n /** 指定要查看 diff 的文件列表(可选)。 */\n files?: string[];\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /diff 命令,返回一段中文指令引导模型展示代码变更。\n */\nexport function handleDiffCommand(args: DiffCommandArgs): { instruction: string } {\n const { staged, files } = args;\n\n const steps: string[] = [\"# Git 变更查看任务\", \"\", \"请按以下步骤展示工作区变更:\", \"\"];\n\n if (staged) {\n steps.push(\"1. 运行 `git diff --staged --stat` 查看已暂存变更的文件摘要\");\n if (files && files.length > 0) {\n const fileList = files.map((f) => `\"${f}\"`).join(\" \");\n steps.push(`2. 运行 \\`git diff --staged -- ${fileList}\\` 查看指定文件的已暂存变更详情`);\n } else {\n steps.push(\"2. 运行 `git diff --staged` 查看所有已暂存变更详情\");\n }\n } else {\n steps.push(\"1. 运行 `git diff --stat` 查看未暂存变更的文件摘要\");\n steps.push(\"2. 运行 `git status --short` 查看工作区状态概览\");\n if (files && files.length > 0) {\n const fileList = files.map((f) => `\"${f}\"`).join(\" \");\n steps.push(`3. 运行 \\`git diff -- ${fileList}\\` 查看指定文件的变更详情`);\n } else {\n steps.push(\"3. 运行 `git diff` 查看所有未暂存变更详情\");\n }\n steps.push(\"4. 运行 `git diff --staged --stat` 同时查看已暂存变更(如有)\");\n }\n\n steps.push(\n \"\",\n \"5. 以结构化格式展示变更:\",\n \"\",\n \" - 变更文件列表(按状态分类:新增 A、修改 M、删除 D、重命名 R)\",\n \" - 每个文件的核心变更摘要(增减行数、主要修改内容)\",\n \" - 高亮关键变更(如公共 API 签名修改、配置变更、新增依赖)\",\n \" - 如有安全问题提醒(如密钥硬编码、不安全依赖版本)\",\n \"\",\n \"注意:\",\n \"- 如果 diff 输出过长,优先展示关键文件的变更\",\n \"- 对于二进制文件变更,说明文件名和大小变化即可\",\n \"- 如果没有任何变更,明确告知用户工作区干净\",\n );\n\n return { instruction: steps.join(\"\\n\") };\n}\n","/**\n * /ant-trace — 工具调用链追踪可视化。\n *\n * 返回 model instruction,指示模型从会话历史中提取 tool_use / tool_result 配对,\n * 构建父子调用树并标注耗时与错误。TUI 层用 local-jsx 渲染为可折叠树形组件。\n *\n * 用法:/ant-trace [--session <id>] 默认追踪当前会话。\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface AntTraceOptions {\n /** 可选:要追踪的会话 ID,默认当前会话。 */\n sessionId?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /ant-trace 命令。\n *\n * 返回一条 model instruction,驱动模型检查会话历史中的\n * 工具调用链并生成结构化诊断输出。\n */\nexport function handleAntTraceCommand(opts: AntTraceOptions): { instruction: string } {\n const scope = opts.sessionId ? `会话 ${opts.sessionId}` : \"当前会话\";\n\n const instruction = `请对${scope}中的工具调用链进行全面追踪分析,输出结构化调用树。\n\n### 分析步骤\n\n1. **扫描消息**:遍历会话中所有消息,找出 tool_use 和 tool_result 块。\n2. **构建调用树**:根据 tool_use 的父子关系(通过 callId / parentCallId 关联)构建树状结构。\n3. **计算耗时**:为每个工具调用计算从 tool_use 到对应 tool_result 的时间差。\n4. **标记异常**:对以下情况高亮标注:\n - 非零 exitCode 的调用\n - 返回 error 的调用\n - 耗时超过 10 秒的调用(慢调用)\n - 被 abort 中断的调用\n5. **输出格式**:以缩进文本树形式呈现,包含:\n - 工具名称\n - 调用耗时(ms)\n - 输入摘要(截断至 80 字符)\n - 输出摘要(截断至 80 字符)\n - 状态标记:✓ 成功 / ✗ 失败 / ⚠ 慢调用 / ⊗ 已中断\n\n### 输出示例\n\n\\`\\`\\`\nant-trace — ${scope} 工具调用链\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n└─ todo_write (12ms) ✓\n ├─ 输入: {\"todos\": [...]}\n └─ 输出: todos updated\n\n└─ read_file (45ms) ✓\n ├─ 输入: {\"file_path\": \"...\"}\n └─ 输出: 156 lines read\n\n└─ bash:npm test (3420ms) ⚠ 慢调用\n ├─ 输入: {\"command\": \"npm test\"}\n └─ 输出: Tests: 12 passed, 1 failed\n └─ grep (180ms) ✗ 失败\n ├─ 输入: {\"pattern\": \"error\"}\n └─ 错误: exit code 1\n\n═══════════════════════════════\n总计:15 次工具调用,13 成功,1 失败,1 慢调用\n总耗时:3,847ms\n\\`\\`\\`\n\n请先通过搜索会话消息构建调用树,再输出分析结果。`;\n\n return { instruction };\n}\n","/**\n * /debug-tool-call — 单步工具调用调试器。\n *\n * 用于排查单个工具调用的输入、输出、错误和耗时细分。\n * 支持按工具名称或步骤索引定位调用,不带参数时列出最近的调用概览。\n *\n * 用法:\n * /debug-tool-call 列出最近调用\n * /debug-tool-call --tool <name> 查看指定工具的最后一次调用\n * /debug-tool-call --step <index> 查看指定步骤索引处的工具调用\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface DebugToolCallOptions {\n /** 按工具名称过滤,查看该工具的最后一次调用详情。 */\n tool?: string;\n /** 按步骤索引定位(从 1 开始),查看该步骤的工具调用。 */\n step?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /debug-tool-call 命令。\n *\n * 返回一条 model instruction,驱动模型检查会话历史中的\n * 工具调用并输出调试信息。\n */\nexport function handleDebugToolCall(opts: DebugToolCallOptions): { instruction: string } {\n if (opts.tool) {\n const toolName = opts.tool;\n return {\n instruction: `请调试工具 \"${toolName}\" 在当前会话中最后一次调用的完整详情。\n\n### 分析要求\n\n1. **定位调用**:在会话消息中搜索最后一个 tool_use 名称为 \"${toolName}\" 的调用。\n2. **展示完整输入**:格式化输出完整的 input JSON(不做截断)。\n3. **展示完整输出**:格式化输出 tool_result 的完整内容。\n4. **错误诊断**:如果调用返回错误或非零退出码,分析可能原因:\n - 输入参数是否有问题?\n - 环境(路径、权限、网络)是否有问题?\n - 是否有并发竞争?\n5. **耗时细分**:如果可用,将耗时分解为:\n - 网络往返时间(如有)\n - 进程启动时间(如适用)\n - 实际处理时间\n - 总耗时\n\n### 输出格式\n\n\\`\\`\\`\ndebug-tool-call: ${toolName}\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n状态:✓ 成功 / ✗ 失败\n\n📥 完整输入:\n{完整 JSON}\n\n📤 完整输出:\n{完整输出内容}\n\n⏱ 耗时细分:\n 总计:235ms\n └─ 网络:12ms\n └─ 处理:210ms\n └─ 其他:13ms\n\n🔍 诊断结论:\n{分析结论或\"无异常\"}\n\\`\\`\\`\n\n如果找不到该工具的调用记录,请明确报告。`,\n };\n }\n\n if (opts.step) {\n const stepIdx = opts.step;\n return {\n instruction: `请展示会话中步骤 ${stepIdx} 处的所有工具调用详情。\n\n### 步骤定义\n\n步骤按时间顺序编号(从 1 开始),每个步骤包含该轮对话中调用的所有工具。\n步骤 ${stepIdx} 可能包含多个并行或串行的工具调用。\n\n### 分析要求\n\n1. **列出所有调用**:该步骤中所有的 tool_use 名称和 callId。\n2. **逐一展示详情**:\n - 输入参数(完整 JSON)\n - 输出内容(完整文本)\n - 执行耗时(ms)\n - 成功/失败状态\n3. **步骤总结**:\n - 调用数量\n - 成功/失败统计\n - 总耗时\n\n### 输出格式\n\n\\`\\`\\`\ndebug-tool-call: 步骤 ${stepIdx}\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n本步骤共 N 次工具调用(M 成功 / K 失败)\n\n── 调用 1:<工具名> ──────────────────\n状态:✓\n输入:{...}\n输出:{...}\n耗时:120ms\n\n── 调用 2:<工具名> ──────────────────\n状态:✗ 失败\n输入:{...}\n错误:...\n耗时:45ms\n\\`\\`\\`\n\n如果步骤 ${stepIdx} 不存在,请报告可用步骤范围。`,\n };\n }\n\n // 默认:列出最近的工具调用概览\n return {\n instruction: `请列出当前会话中最近的工具调用概览(最多 20 条)。\n\n### 输出格式\n\n以编号列表展示,每条包含:\n- 步骤编号(可用作 --step 参数)\n- 工具名称\n- 调用耗时(ms)\n- 状态图标(✓ / ✗ / ⚠)\n- 输入摘要(截断至 60 字符)\n\n\\`\\`\\`\ndebug-tool-call: 最近调用概览\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n#1 步骤 1 todo_write 12ms ✓ {\"todos\": [...]}\n#2 步骤 1 read_file 45ms ✓ {\"file_path\": \"src/...\"}\n#3 步骤 2 bash 3420ms ⚠ {\"command\": \"npm t...\"}\n#4 步骤 2 grep 180ms ✗ {\"pattern\": \"err...\"}\n#5 步骤 3 write_file 23ms ✓ {\"file_path\": \"src/...\"}\n\n────────────────────────────────\n共 15 次调用。使用 --step <N> 查看某步骤详情,--tool <name> 查看特定工具详情。\n\\`\\`\\`\n\n请根据会话消息生成上述列表。`,\n };\n}\n","/**\n * /tasks — 后台任务监视与控制。\n *\n * 列出当前后台任务状态,支持取消运行中的任务和查看任务详情。\n * 该命令与 TUI 层的 TasksPanel 组件配合使用:\n * - list:打开任务面板,展示实时状态(带色彩编码)\n * - cancel:通过 taskId 取消指定任务\n * - detail:展示任务的完整输出流\n *\n * 用法:\n * /tasks 列出所有任务(默认)\n * /tasks --action cancel --taskId <id> 取消任务\n * /tasks --action detail --taskId <id> 查看任务详情\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface TasksCommandOptions {\n /** 操作类型:list(默认)、cancel、detail。 */\n action?: string;\n /** cancel 或 detail 操作时必填。 */\n taskId?: string;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /tasks 命令。\n *\n * 根据 action 返回不同的 model instruction,驱动模型\n * 执行相应的任务管理操作。\n */\nexport function handleTasksCommand(opts: TasksCommandOptions): { instruction: string } {\n const action = opts.action ?? \"list\";\n\n switch (action) {\n case \"cancel\": {\n if (!opts.taskId) {\n return {\n instruction:\n \"请提示用户:取消任务需要提供 --taskId 参数。例如:/tasks --action cancel --taskId <id>\",\n };\n }\n return {\n instruction: `请取消任务 \"${opts.taskId}\"。\n\n### 操作步骤\n\n1. 使用 task 工具的 cancel 操作取消该任务。\n2. 如果任务不存在或已经结束,报告给用户。\n3. 如果取消成功,确认并展示任务在取消前的状态。\n\n### 输出格式\n\n\\`\\`\\`\n取消任务:${opts.taskId}\n━━━━━━━━━━━━━━━━━━━━\n状态:已取消\n任务名称:<name>\n运行时长:<duration>\n\\`\\`\\``,\n };\n }\n\n case \"detail\": {\n if (!opts.taskId) {\n return {\n instruction:\n \"请提示用户:查看任务详情需要提供 --taskId 参数。例如:/tasks --action detail --taskId <id>\",\n };\n }\n return {\n instruction: `请展示任务 \"${opts.taskId}\" 的完整详情。\n\n### 内容要求\n\n1. **基本信息**:任务 ID、名称、状态、创建时间、运行时长\n2. **输入参数**:任务启动时的完整输入\n3. **输出流**:任务执行期间产生的所有输出(stdout + stderr)\n4. **错误信息**:如果任务失败,展示完整错误堆栈\n5. **子任务**:如果该任务包含子任务,列出子任务树\n\n### 输出格式\n\n\\`\\`\\`\n任务详情:${opts.taskId}\n━━━━━━━━━━━━━━━━━━━━━━\n\n📋 基本信息\n 名称:<任务名称>\n 状态:运行中 / 完成 / 失败 / 排队中\n 创建:<ISO 时间>\n 运行时长:<duration>\n\n📥 输入参数\n{完整 JSON}\n\n📤 输出流\n────────────────────────\n{完整 stdout 输出}\n────────────────────────\n{如 stderr 有内容则展示}\n\n❌ 错误信息\n{如有}\n\\`\\`\\``,\n };\n }\n\n default: {\n // list — 展示所有后台任务\n return {\n instruction: `请列出当前所有后台任务的状态概览。\n\n### 内容要求\n\n展示以下信息(每项任务一行):\n- **状态图标**:\n - ⟳ 运行中(青色高亮)\n - ○ 排队中(灰色)\n - ✓ 完成(绿色)\n - ✗ 失败(红色)\n- **进度条**:运行中的任务展示完成百分比(如 \"[████████░░] 80%\")\n- **任务名称**\n- **运行时长**(运行中的任务)\n- **错误摘要**(失败的任务,截断至一行)\n- **取消按钮**:对运行中的任务提示可用 \"/tasks cancel --taskId <id>\" 取消\n\n### 输出格式\n\n\\`\\`\\`\n任务面板\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n⟳ phase2-scanExtensions [████████░░] 80% 已运行 3s\n✓ phase2-preloadSkills 完成 (1.2s)\n✗ phase2-connectMcpServers 失败 — 连接超时\n○ phase2-loadMemory 排队中\n✓ phase2-initChannels 完成 (0.8s)\n\n────────────────────────────────────────────\n共 5 个任务:1 运行中,1 排队,2 完成,1 失败\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n📌 提示:\n /tasks --action detail --taskId <id> 查看任务完整输出\n /tasks --action cancel --taskId <id> 取消运行中的任务\n\\`\\`\\`\n\n请调用 task 工具的 list 操作获取任务列表,然后按上述格式输出。`,\n };\n }\n }\n}\n","/**\n * /heapdump — V8 堆快照,用于内存泄漏诊断。\n *\n * 调用 Node.js 内置的 writeHeapSnapshot() 生成 .heapsnapshot 文件,\n * 保存到 ~/.lynx/heapdumps/ 目录下。可在 Chrome DevTools 的\n * Memory 面板中加载分析。\n *\n * 用法:/heapdump\n */\n\nimport { writeHeapSnapshot } from \"node:v8\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { existsSync, mkdirSync } from \"node:fs\";\n\n// ── Constants ────────────────────────────────────────\n\n/** 堆快照输出目录 */\nconst HEAPDUMP_DIR = join(homedir(), \".lynx\", \"heapdumps\");\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /heapdump 命令。\n *\n * 生成立即堆快照并返回文件路径。这是 local 类型命令——\n * 不经过模型,直接在 CLI 进程中执行。\n */\nexport async function handleHeapdumpCommand(): Promise<{ output: string }> {\n // 确保输出目录存在\n if (!existsSync(HEAPDUMP_DIR)) {\n try {\n mkdirSync(HEAPDUMP_DIR, { recursive: true });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n output: `错误:无法创建堆快照目录 ${HEAPDUMP_DIR}:${message}`,\n };\n }\n }\n\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n const filepath = join(HEAPDUMP_DIR, `heap-${timestamp}.heapsnapshot`);\n\n try {\n const filename = writeHeapSnapshot(filepath);\n // writeHeapSnapshot 会在文件名后追加进程 ID,因此使用它返回的实际文件名\n return {\n output:\n `堆快照已保存到:${filename}\\n\\n` +\n `共 ${getDumpCount()} 个快照文件。\\n` +\n `分析步骤:\\n` +\n ` 1. 打开 Chrome DevTools\\n` +\n ` 2. 切换到 Memory 面板\\n` +\n ` 3. 点击 \"Load\" 加载 \"${filename}\"\\n` +\n ` 4. 按 Retained Size 排序查找内存泄漏`,\n };\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n output: `错误:堆快照生成失败:${message}`,\n };\n }\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/**\n * 获取 dump 目录下的快照文件数量(用于提示用户定期清理)。\n */\nfunction getDumpCount(): number {\n try {\n const { readdirSync } = require(\"node:fs\");\n const entries = readdirSync(HEAPDUMP_DIR);\n return entries.filter((f: string) => f.endsWith(\".heapsnapshot\")).length;\n } catch {\n return -1;\n }\n}\n","/**\n * /perf-issue — 性能问题诊断。\n *\n * 返回 model instruction,驱动模型分析性能问题、检查日志、\n * 筛查慢调用和内存使用模式,并给出优化建议。\n *\n * 用法:\n * /perf-issue 通用性能健康检查\n * /perf-issue --issue <描述> 针对具体问题的诊断\n */\n\n// ── Types ────────────────────────────────────────────\n\nexport interface PerfIssueOptions {\n /** 可选:用户描述的具体性能问题。不提供则执行通用健康检查。 */\n issue?: string;\n}\n\n// ── Constants ────────────────────────────────────────\n\nconst HEALTH_CHECK_INSTRUCTION = `请对当前会话进行全面的性能健康检查,输出诊断报告。\n\n### 检查项目\n\n1. **慢调用筛查**\n - 扫描会话中所有 tool_use/tool_result 对\n - 计算每次工具调用的耗时\n - 标记耗时 > 5 秒的\"慢调用\"和 > 30 秒的\"极慢调用\"\n - 分析慢调用的公共模式(相同的工具?相似的输入?特定时间段?)\n\n2. **日志分析**\n - 检查 ~/.lynx/logs/ 目录下的最新日志文件\n - 查找错误、警告和超时记录\n - 查找重复出现的模式(如每 30 秒的重试风暴)\n - 提取关键性能指标(如 MCP 连接延迟、模型响应延迟)\n\n3. **内存使用模式**\n - 查看最近的内存监控数据(如有)\n - 检查是否存在持续增长的内存趋势(可能泄漏)\n - 注意 heapUsed 在短时间内陡增的模式\n\n4. **会话效率**\n - 统计工具调用次数和总耗时\n - 计算\"有效工具调用比\"(有产出的调用 / 总调用)\n - 识别冗余调用(重复读取同一文件、重复搜索相同模式)\n\n5. **优化建议**\n - 针对发现的问题给出具体优化建议\n - 按优先级排序:高(立即修复)、中(下次迭代)、低(长期优化)\n\n### 输出格式\n\n\\`\\`\\`\n性能健康检查报告\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n📊 会话概况\n 会话时长:<duration>\n 工具调用:N 次\n 总耗时:<X>ms\n 平均耗时:<Y>ms/调用\n\n🐢 慢调用(共 N 个)\n #1 todo_write 5.2s ⚠ 超过阈值\n #2 bash 32.1s 🔴 极慢\n\n📋 日志摘要\n [WARN] MCP 连接超时 — 出现 3 次\n [ERROR] 文件未找到 — 出现 1 次\n\n🧠 内存\n 当前堆使用:<X>MB\n 趋势:稳定 / 上升(12% 增长)\n 风险等级:低 / 中 / 高\n\n📈 效率分析\n 有效调用率:85%(17/20)\n 冗余调用:2 次(重复读取同一文件)\n\n💡 优化建议\n 🔴 [高] 合并对同一文件的多次读取\n 🟡 [中] 为频繁搜索添加缓存\n 🟢 [低] 考虑减少 todo_write 的调用频率\n\\`\\`\\``;\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /perf-issue 命令。\n *\n * 返回 model instruction,驱动模型执行性能诊断分析。\n */\nexport function handlePerfIssueCommand(opts: PerfIssueOptions): { instruction: string } {\n if (opts.issue) {\n return {\n instruction: `请诊断以下性能问题:\"${opts.issue}\"\n\n### 诊断步骤\n\n1. **复现分析**:根据问题描述,推测最可能的性能瓶颈点。\n2. **日志排查**:检查 ~/.lynx/logs/ 目录下相关日志,搜索与问题相关的错误或警告。\n3. **调用链分析**:如果在会话历史中,查找与问题描述相关的工具调用,分析其耗时特征。\n4. **系统资源**:检查当前进程的 CPU 和内存使用情况。\n5. **环境因素**:考虑网络延迟、磁盘 I/O、第三方服务响应时间等外部因素。\n6. **根因分析**:给出最可能的根因(不超过 3 个)。\n7. **解决方案**:针对每个根因给出具体的修复步骤。\n\n### 输出格式\n\n\\`\\`\\`\n性能诊断:${opts.issue}\n━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n🔍 问题复现\n{分析}\n\n📊 数据支撑\n{日志片段、耗时数据、调用链}\n\n🎯 根因分析\n 1. <最可能的根因>\n 2. <次要可能性>\n 3. <边缘情况>\n\n🛠 解决方案\n 方案 1:<具体步骤>\n 方案 2:<具体步骤>\n 方案 3:<具体步骤>\n\n📌 验证方法\n{如何确认问题已解决}\n\\`\\`\\`\n\n请按上述步骤执行诊断,优先检查日志和当前会话数据。`,\n };\n }\n\n return { instruction: HEALTH_CHECK_INSTRUCTION };\n}\n","/**\n * /share — 将会话导出为可分享的 Markdown 文件。\n *\n * 从 ~/.lynx/sessions/{sessionId}.json 读取消息,\n * 格式化为干净的 Markdown 后写入 ~/.lynx/exports/ 目录。\n */\n\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { openDatabase, resolvePaths } from \"@24klynx/core\";\nimport type { Message, ContentBlock } from \"@24klynx/core\";\nimport { getLastSession } from \"@24klynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface ShareCommandOptions {\n sessionId?: string;\n output?: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 从 JSON 文件加载会话消息。 */\nfunction loadSessionMessages(sessionId: string): Message[] {\n const messagesPath = join(homedir(), \".lynx\", \"sessions\", `${sessionId}.json`);\n if (!existsSync(messagesPath)) {\n throw new Error(`会话消息文件未找到:${messagesPath}`);\n }\n const raw = readFileSync(messagesPath, \"utf-8\");\n const data = JSON.parse(raw);\n return data.messages ?? [];\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/** 截断过长文本,保留开头和结尾的提示。 */\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n const half = Math.floor(maxLen / 2);\n return text.slice(0, half) + \"\\n...(内容已截断)...\\n\" + text.slice(-half);\n}\n\n/** 将内容块转为适合嵌入 Markdown 的文本。 */\nfunction blockToMarkdown(block: ContentBlock): string {\n switch (block.type) {\n case \"text\":\n return block.text;\n case \"tool_use\":\n return `_**调用工具:** ${block.name}_\\n\\`\\`\\`json\\n${JSON.stringify(block.input, null, 2)}\\n\\`\\`\\``;\n case \"tool_result\":\n if (block.isError) {\n return `<details><summary>工具执行出错</summary>\\n\\n\\`\\`\\`\\n${block.content}\\n\\`\\`\\`\\n</details>`;\n }\n return `<details><summary>工具执行结果</summary>\\n\\n\\`\\`\\`\\n${truncate(block.content, 3000)}\\n\\`\\`\\`\\n</details>`;\n case \"reasoning\":\n return `<details><summary>思考过程</summary>\\n\\n${block.text}\\n</details>`;\n default:\n return \"\";\n }\n}\n\n/** 将会话消息列表格式化为 Markdown。 */\nfunction formatSessionAsMarkdown(messages: Message[], sessionLabel: string): string {\n const lines: string[] = [];\n lines.push(`# ${sessionLabel}`);\n lines.push(\"\");\n lines.push(`> 导出时间:${new Date().toISOString()}`);\n lines.push(`> 消息总数:${messages.length}`);\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n for (const msg of messages) {\n // 跳过纯系统消息\n if (msg.role === \"system\") continue;\n\n const roleLabel = msg.role === \"user\" ? \"用户\" : \"Lynx\";\n const emoji = msg.role === \"user\" ? \"🧑\" : \"🤖\";\n\n lines.push(`### ${emoji} ${roleLabel}`);\n lines.push(\"\");\n\n for (const block of msg.content) {\n const md = blockToMarkdown(block);\n if (md) lines.push(md);\n }\n\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /share 命令。\n *\n * 将会话消息导出为 Markdown 文件,方便分享。\n * 默认导出最近一次会话,可通过 --session-id 指定。\n */\nexport async function handleShareCommand(opts: ShareCommandOptions): Promise<{ output: string }> {\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const messages = loadSessionMessages(sessionId);\n\n if (messages.length === 0) {\n return { output: `会话 ${sessionId} 中没有消息。` };\n }\n\n const markdown = formatSessionAsMarkdown(messages, `会话 ${sessionId}`);\n\n const exportsDir = join(homedir(), \".lynx\", \"exports\");\n if (!existsSync(exportsDir)) {\n mkdirSync(exportsDir, { mode: 0o700, recursive: true });\n }\n\n const outputPath = opts.output ?? join(exportsDir, `session-${sessionId}.md`);\n const outputDir = dirname(outputPath);\n if (!existsSync(outputDir)) {\n mkdirSync(outputDir, { mode: 0o700, recursive: true });\n }\n\n writeFileSync(outputPath, markdown, \"utf-8\");\n return { output: `会话已导出到:${outputPath}` };\n}\n","/**\n * /export — 以多种格式导出会话。\n *\n * 支持三种输出格式:\n * - markdown:与 /share 相同,格式化为可读的 Markdown\n * - json:导出原始消息数组(格式化 JSON)\n * - html:将 Markdown 包裹在基础 HTML 模板中\n */\n\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { openDatabase, resolvePaths } from \"@24klynx/core\";\nimport type { Message, ContentBlock } from \"@24klynx/core\";\nimport { getLastSession } from \"@24klynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface ExportCommandOptions {\n sessionId?: string;\n format?: \"markdown\" | \"json\" | \"html\";\n output?: string;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 从 JSON 文件加载会话消息。 */\nfunction loadSessionMessages(sessionId: string): Message[] {\n const messagesPath = join(homedir(), \".lynx\", \"sessions\", `${sessionId}.json`);\n if (!existsSync(messagesPath)) {\n throw new Error(`会话消息文件未找到:${messagesPath}`);\n }\n const raw = readFileSync(messagesPath, \"utf-8\");\n const data = JSON.parse(raw);\n return data.messages ?? [];\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/** 截断过长文本。 */\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n const half = Math.floor(maxLen / 2);\n return text.slice(0, half) + \"\\n...(内容已截断)...\\n\" + text.slice(-half);\n}\n\n/** 将内容块转为适合嵌入 Markdown 的文本。 */\nfunction blockToMarkdown(block: ContentBlock): string {\n switch (block.type) {\n case \"text\":\n return block.text;\n case \"tool_use\":\n return `_**调用工具:** ${block.name}_\\n\\`\\`\\`json\\n${JSON.stringify(block.input, null, 2)}\\n\\`\\`\\``;\n case \"tool_result\":\n if (block.isError) {\n return `<details><summary>工具执行出错</summary>\\n\\n\\`\\`\\`\\n${block.content}\\n\\`\\`\\`\\n</details>`;\n }\n return `<details><summary>工具执行结果</summary>\\n\\n\\`\\`\\`\\n${truncate(block.content, 3000)}\\n\\`\\`\\`\\n</details>`;\n case \"reasoning\":\n return `<details><summary>思考过程</summary>\\n\\n${block.text}\\n</details>`;\n default:\n return \"\";\n }\n}\n\n/** 将会话消息列表格式化为 Markdown。 */\nfunction formatSessionAsMarkdown(messages: Message[], sessionId: string): string {\n const lines: string[] = [];\n lines.push(`# 会话 ${sessionId}`);\n lines.push(\"\");\n lines.push(`> 导出时间:${new Date().toISOString()}`);\n lines.push(`> 消息总数:${messages.length}`);\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n\n for (const msg of messages) {\n if (msg.role === \"system\") continue;\n\n const roleLabel = msg.role === \"user\" ? \"用户\" : \"Lynx\";\n const emoji = msg.role === \"user\" ? \"🧑\" : \"🤖\";\n\n lines.push(`### ${emoji} ${roleLabel}`);\n lines.push(\"\");\n\n for (const block of msg.content) {\n const md = blockToMarkdown(block);\n if (md) lines.push(md);\n }\n\n lines.push(\"\");\n lines.push(\"---\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/** 将 Markdown 包裹在 HTML 模板中。 */\nfunction wrapMarkdownInHtml(markdown: string, sessionId: string): string {\n return `<!DOCTYPE html>\n<html lang=\"zh-CN\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Lynx 会话导出 — ${sessionId}</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n max-width: 900px;\n margin: 0 auto;\n padding: 2rem;\n line-height: 1.7;\n color: #1a1a1a;\n background: #fafafa;\n }\n h1 { font-size: 2rem; margin-bottom: 0.5rem; color: #111; }\n blockquote { border-left: 4px solid #ddd; padding-left: 1rem; color: #666; margin: 1rem 0; }\n hr { border: none; border-top: 1px solid #e0e0e0; margin: 2rem 0; }\n h3 { font-size: 1.1rem; margin: 1.5rem 0 0.5rem; color: #333; }\n pre {\n background: #f0f0f0;\n border-radius: 6px;\n padding: 1rem;\n overflow-x: auto;\n font-size: 0.9rem;\n }\n code { font-family: \"SF Mono\", \"Fira Code\", \"Fira Mono\", Menlo, Consolas, monospace; font-size: 0.9em; }\n details {\n background: #f5f5f5;\n border-radius: 6px;\n padding: 0.75rem 1rem;\n margin: 0.5rem 0;\n }\n details summary { cursor: pointer; font-weight: 600; color: #555; }\n details pre { margin-top: 0.5rem; }\n .meta { color: #888; font-size: 0.9rem; }\n </style>\n</head>\n<body>\n${markdown}\n</body>\n</html>`;\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /export 命令。\n *\n * 以指定格式导出会话,支持 markdown / json / html。\n * 默认导出最近一次会话为 markdown 格式。\n */\nexport async function handleExportCommand(opts: ExportCommandOptions): Promise<{ output: string }> {\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const messages = loadSessionMessages(sessionId);\n\n if (messages.length === 0) {\n return { output: `会话 ${sessionId} 中没有消息。` };\n }\n\n const format = opts.format ?? \"markdown\";\n const exportsDir = join(homedir(), \".lynx\", \"exports\");\n if (!existsSync(exportsDir)) mkdirSync(exportsDir, { mode: 0o700, recursive: true });\n\n const defaultOutput = join(\n exportsDir,\n `session-${sessionId}.${format === \"html\" ? \"html\" : format === \"json\" ? \"json\" : \"md\"}`,\n );\n const outputPath = opts.output ?? defaultOutput;\n const outputDir = dirname(outputPath);\n if (!existsSync(outputDir)) mkdirSync(outputDir, { mode: 0o700, recursive: true });\n\n let content: string;\n\n switch (format) {\n case \"markdown\": {\n content = formatSessionAsMarkdown(messages, sessionId);\n break;\n }\n case \"json\": {\n content = JSON.stringify(messages, null, 2);\n break;\n }\n case \"html\": {\n const md = formatSessionAsMarkdown(messages, sessionId);\n content = wrapMarkdownInHtml(md, sessionId);\n break;\n }\n default: {\n return { output: `不支持的导出格式:${format}。请使用 markdown、json 或 html。` };\n }\n }\n\n writeFileSync(outputPath, content, \"utf-8\");\n return { output: `会话已导出到:${outputPath}(格式:${format})` };\n}\n","/**\n * /tag — 为会话打标签,用于分类管理。\n *\n * 标签数据存储在 ~/.lynx/session-tags.json 中。\n * 支持三种操作:\n * - add:为指定会话添加标签\n * - remove:移除指定标签\n * - list:列出所有带标签的会话,或指定会话的所有标签\n */\n\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { openDatabase, resolvePaths } from \"@24klynx/core\";\nimport { getLastSession } from \"@24klynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface TagCommandOptions {\n sessionId?: string;\n tag?: string;\n action?: \"add\" | \"remove\" | \"list\";\n}\n\n/** 标签存储格式:{ sessionId: string[] } */\ntype TagsStore = Record<string, string[]>;\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 获取标签文件路径。 */\nfunction tagsFilePath(): string {\n return join(homedir(), \".lynx\", \"session-tags.json\");\n}\n\n/** 加载所有标签数据。 */\nfunction loadTags(): TagsStore {\n const path = tagsFilePath();\n if (!existsSync(path)) return {};\n try {\n const raw = readFileSync(path, \"utf-8\");\n return JSON.parse(raw) as TagsStore;\n } catch {\n return {};\n }\n}\n\n/** 保存标签数据。 */\nfunction saveTags(tags: TagsStore): void {\n const path = tagsFilePath();\n const dir = dirname(path);\n if (!existsSync(dir)) mkdirSync(dir, { mode: 0o700, recursive: true });\n writeFileSync(path, JSON.stringify(tags, null, 2), \"utf-8\");\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/**\n * 从数据库获取会话的 label(用于 list 展示)。\n * 如果数据库不可用或会话不存在,返回 sessionId。\n */\nfunction getSessionLabel(sessionId: string): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const stmt = db.prepare(\"SELECT label FROM sessions WHERE id = ?\");\n const row = stmt.get(sessionId) as { label: string } | undefined;\n return row?.label ?? sessionId;\n } catch {\n return sessionId;\n } finally {\n db.close();\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /tag 命令。\n *\n * 为会话添加、移除或列出标签。\n * 默认操作为 list;add/remove 需要提供 --tag 参数。\n */\nexport async function handleTagCommand(opts: TagCommandOptions): Promise<{ output: string }> {\n const action = opts.action ?? \"list\";\n const tags = loadTags();\n\n switch (action) {\n case \"add\": {\n if (!opts.tag || opts.tag.trim().length === 0) {\n return { output: \"错误:请使用 --tag 指定要添加的标签。\" };\n }\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const normalizedTag = opts.tag.trim();\n\n if (!tags[sessionId]) {\n tags[sessionId] = [];\n }\n if (tags[sessionId].includes(normalizedTag)) {\n return { output: `会话 ${sessionId} 已有标签 \"${normalizedTag}\"。` };\n }\n\n tags[sessionId].push(normalizedTag);\n saveTags(tags);\n return { output: `已为会话 ${sessionId} 添加标签 \"${normalizedTag}\"。` };\n }\n\n case \"remove\": {\n if (!opts.tag || opts.tag.trim().length === 0) {\n return { output: \"错误:请使用 --tag 指定要移除的标签。\" };\n }\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const normalizedTag = opts.tag.trim();\n\n if (!tags[sessionId] || !tags[sessionId].includes(normalizedTag)) {\n return { output: `会话 ${sessionId} 没有标签 \"${normalizedTag}\"。` };\n }\n\n tags[sessionId] = tags[sessionId].filter((t) => t !== normalizedTag);\n // 清理空数组\n if (tags[sessionId].length === 0) {\n delete tags[sessionId];\n }\n saveTags(tags);\n return { output: `已从会话 ${sessionId} 移除标签 \"${normalizedTag}\"。` };\n }\n\n case \"list\": {\n if (opts.sessionId) {\n // 列出指定会话的所有标签\n const sessionTags = tags[opts.sessionId];\n if (!sessionTags || sessionTags.length === 0) {\n return { output: `会话 ${opts.sessionId} 没有标签。` };\n }\n const label = getSessionLabel(opts.sessionId);\n return {\n output: `会话 ${opts.sessionId}(${label})的标签:\\n${sessionTags.map((t) => ` - ${t}`).join(\"\\n\")}`,\n };\n }\n\n // 列出所有带标签的会话\n const entries = Object.entries(tags);\n if (entries.length === 0) {\n return { output: \"没有任何已打标签的会话。\" };\n }\n\n const lines: string[] = [];\n for (const [sid, sessionTags] of entries) {\n if (sessionTags.length === 0) continue;\n const label = getSessionLabel(sid);\n lines.push(`${sid}(${label}):${sessionTags.join(\", \")}`);\n }\n\n if (lines.length === 0) {\n return { output: \"没有任何已打标签的会话。\" };\n }\n\n return { output: lines.join(\"\\n\") };\n }\n\n default:\n return { output: `未知操作:${action}。请使用 add、remove 或 list。` };\n }\n}\n","/**\n * /copy — 将最后一条助手回复复制到剪贴板。\n *\n * 从会话中提取指定索引(从末尾倒数)的助手消息文本,\n * 通过平台对应的剪贴板命令写入系统剪贴板。\n *\n * 支持平台:Windows(PowerShell)、macOS(pbcopy)、\n * Linux(xclip 或 wl-copy)。\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { openDatabase, resolvePaths } from \"@24klynx/core\";\nimport type { Message } from \"@24klynx/core\";\nimport { getLastSession } from \"@24klynx/session\";\n\n// ── Types ────────────────────────────────────────────\n\nexport interface CopyCommandOptions {\n sessionId?: string;\n /** 从末尾倒数第几条消息(0 = 最后一条,默认 0)。 */\n index?: number;\n}\n\n// ── Helpers ──────────────────────────────────────────\n\n/** 从 JSON 文件加载会话消息。 */\nfunction loadSessionMessages(sessionId: string): Message[] {\n const messagesPath = join(homedir(), \".lynx\", \"sessions\", `${sessionId}.json`);\n if (!existsSync(messagesPath)) {\n throw new Error(`会话消息文件未找到:${messagesPath}`);\n }\n const raw = readFileSync(messagesPath, \"utf-8\");\n const data = JSON.parse(raw);\n return data.messages ?? [];\n}\n\n/** 从数据库获取最近一次会话的 ID。 */\nfunction getMostRecentSessionId(): string {\n const paths = resolvePaths();\n const db = openDatabase({ dbPath: paths.stateDb });\n try {\n const session = getLastSession(db);\n if (!session) {\n throw new Error(\"未找到任何会话记录。\");\n }\n return session.id;\n } finally {\n db.close();\n }\n}\n\n/**\n * 从消息中提取纯文本内容(仅 text 类型的内容块)。\n * 跳过 tool_use、tool_result 和 reasoning 块。\n */\nfunction extractTextContent(msg: Message): string {\n const parts: string[] = [];\n for (const block of msg.content) {\n if (block.type === \"text\" && block.text) {\n parts.push(block.text);\n }\n }\n return parts.join(\"\\n\\n\");\n}\n\n/**\n * 检测当前平台并返回对应的剪贴板命令。\n * 返回 [命令, args...] 或 null(不支持的平台)。\n */\nfunction getClipboardCommand(): [string, string[]] | null {\n const platform = process.platform;\n\n if (platform === \"win32\") {\n return [\"powershell\", [\"-Command\", \"Set-Clipboard -Value $input\"]];\n }\n\n if (platform === \"darwin\") {\n return [\"pbcopy\", []];\n }\n\n if (platform === \"linux\") {\n // 优先检测 wl-copy(Wayland)\n try {\n execSync(\"which wl-copy 2>/dev/null || command -v wl-copy 2>/dev/null\", {\n stdio: \"ignore\",\n });\n return [\"wl-copy\", []];\n } catch {\n // 检测 xclip(X11)\n try {\n execSync(\"which xclip 2>/dev/null || command -v xclip 2>/dev/null\", {\n stdio: \"ignore\",\n });\n return [\"xclip\", [\"-selection\", \"clipboard\"]];\n } catch {\n return null;\n }\n }\n }\n\n return null;\n}\n\n/**\n * 将文本写入系统剪贴板。\n * 使用管道将内容传入剪贴板命令的 stdin。\n */\nfunction copyToClipboard(text: string): boolean {\n const cmd = getClipboardCommand();\n if (!cmd) {\n return false;\n }\n\n const [command, args] = cmd;\n try {\n // 处理 PowerShell 的特殊 $input 语法:需要通过管道传入\n if (process.platform === \"win32\") {\n // Windows:使用 StreamWriter 通过管道传入\n execSync(\n `powershell -Command \"$input = [System.IO.StreamReader]::new([System.Console]::OpenStandardInput()).ReadToEnd(); Set-Clipboard -Value $input\"`,\n { input: text, stdio: \"pipe\", timeout: 10_000 },\n );\n } else {\n // Unix:直接通过 stdin 管道传入\n const child = execSync(`${command} ${args.join(\" \")}`, {\n input: text,\n stdio: \"pipe\",\n timeout: 10_000,\n });\n if (child.length > 0) {\n // pbcopy 通常无输出,如果有输出可能是错误\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n// ── Public API ───────────────────────────────────────\n\n/**\n * 处理 /copy 命令。\n *\n * 将指定索引(从末尾倒数)的助手消息文本复制到系统剪贴板。\n * 默认复制最后一条助手回复。\n */\nexport async function handleCopyCommand(opts: CopyCommandOptions): Promise<{ output: string }> {\n const sessionId = opts.sessionId ?? getMostRecentSessionId();\n const messages = loadSessionMessages(sessionId);\n\n if (messages.length === 0) {\n return { output: `会话 ${sessionId} 中没有消息。` };\n }\n\n // 收集所有助手消息(从末尾倒数)\n const assistantMessages = messages.filter((m) => m.role === \"assistant\").toReversed();\n\n if (assistantMessages.length === 0) {\n return { output: `会话 ${sessionId} 中没有助手回复。` };\n }\n\n const index = opts.index ?? 0;\n if (index < 0 || index >= assistantMessages.length) {\n return {\n output: `索引 ${index} 超出范围。会话共有 ${assistantMessages.length} 条助手回复(有效索引:0 到 ${assistantMessages.length - 1})。`,\n };\n }\n\n const targetMessage = assistantMessages[index];\n const text = extractTextContent(targetMessage);\n\n if (!text || text.trim().length === 0) {\n return { output: `助手回复 #${index} 不包含文本内容(可能只有工具调用或思考过程)。` };\n }\n\n const success = copyToClipboard(text);\n if (!success) {\n return {\n output:\n \"无法复制到剪贴板。请确认已安装剪贴板工具:\\n\" +\n \" Windows:PowerShell 5.0+\\n\" +\n \" macOS:系统自带 pbcopy\\n\" +\n \" Linux:请安装 xclip 或 wl-clipboard\",\n };\n }\n\n const preview = text.length > 80 ? text.slice(0, 80) + \"...\" : text;\n return { output: `已复制助手回复 #${index} 到剪贴板。\\n预览:${preview}` };\n}\n"],"mappings":"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"}
|