MoonshotAI / MoonshotAI/kimi-code
[Bug] 外部编辑器被 signal 终止时被误判为成功退出
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.5k
- Forks
- 1.2k
- Avg merge
- 11h 53m
- Merged PRs (30d)
- 350
Description
你运行的 Kimi Code 版本是?
源码复现,commit 46233953795c62051b433956db60c6c218d2cede(未使用已安装 CLI 复现)。发布前已同步上游 main 并复核相关源码。
你使用的是哪个开放平台/订阅?
不适用:不涉及登录/模型请求,源码隔离复现。
你使用的是哪个模型?
不适用:未调用模型。
你的电脑平台是?
uname -mprs:Linux 6.18.38-Unraid x86_64 unknown;Node.js v26.5.1。
你遇到了什么问题?
Ctrl+G 打开编辑器,编辑器/其平台 shell 被终止,临时文件可能已有未完成内容。当前 exit 回调把 null 转为 0,随后读回文件并覆盖输入框;这不同于正常保存退出。
external-editor.ts 的 resolve(c ?? 0) 丢掉 signal;控制器仅判断 result !== undefined。正常非零退出已有测试,但 signal/null 未覆盖。
复现步骤?
- checkout
46233953795c62051b433956db60c6c218d2cede,在仓库根目录执行。 - 将以下脚本保存到仓库外的
/tmp/kimi-repro-1.mjs,执行node /tmp/kimi-repro-1.mjs。不需要登录或安装 monorepo 依赖。 - 本次实际观测:
{ code: null, signal: 'SIGTERM', resolvedByCurrentCallback: 0 }。
import fs from 'node:fs';
import { spawn } from 'node:child_process';
const source = fs.readFileSync('apps/kimi-code/src/utils/process/external-editor.ts', 'utf8');
if (!source.includes("child.on('exit', (c) => { resolve(c ?? 0); });")) throw Error('source changed');
const result = await new Promise((resolve, reject) => {
const child = spawn('kill -TERM $$', { shell: true });
child.on('error', reject);
child.on('exit', (code, signal) => resolve({ code, signal, resolvedByCurrentCallback: code ?? 0 }));
});
console.log(result);
复现边界:真实本地 shell 的 signal 退出 + 与源码完全相同的 callback 判定;不是完整 Ctrl+G/TUI 实验。
期望的行为是什么?
- 只有正常退出(code 为 0、无 signal)才读回临时文件。
- 非零退出和 signal 终止均不导入临时内容,保留原始输入;现有临时目录清理和终端恢复行为不变。
- 在现有 helper 测试中覆盖 null/SIGTERM、null/SIGINT 和正常退出。
补充信息
问题在退出判定,不要求更改 shell:true 或重构 TUI。#246/#245 处理 Windows shell 启动,不是 signal/null 误判;#1272 处理整个 TUI 的异常清理,也不是此 helper 的读回条件。
已检索当前 open/closed issues 和 PR:external editor/signal、surrogate/Unicode/truncation、MCP pagination/nextCursor/listTools 及对应源码符号。未发现与此具体路径和触发条件等价的记录;不据此保证绝无重复。
固定源码、对应测试与参考边界
- https://github.com/MoonshotAI/kimi-code/blob/46233953795c62051b433956db60c6c218d2cede/apps/kimi-code/src/utils/process/external-editor.ts#L36-L59
- https://github.com/MoonshotAI/kimi-code/blob/46233953795c62051b433956db60c6c218d2cede/apps/kimi-code/src/tui/controllers/editor-keyboard.ts#L775-L795
- https://github.com/MoonshotAI/kimi-code/blob/46233953795c62051b433956db60c6c218d2cede/apps/kimi-code/test/utils/process/external-editor.test.ts#L46-L74
- https://github.com/openai/codex/blob/5b1d6560181680f95cde95c14ed042acc02248ed/codex-rs/tui/src/external_editor.rs#L216-L229
- https://github.com/openai/codex/blob/5b1d6560181680f95cde95c14ed042acc02248ed/codex-rs/tui/src/external_editor.rs#L294-L311
借鉴只在 status.success() 时读回,不移植其沙箱目录设计。对应现有测试覆盖成功读回;未找到/未宣称 Codex 已有 signal 专项测试。
只运行上述隔离复现,未运行仓库完整测试套件或 Codex 测试;源码引用用于定位与讨论,不代表已经实现修复。
Contribution
- 我愿意自己提交修复此 bug 的 PR(请先等待维护者在本 issue 中批准)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/kimi-code/src/utils/process/external-editor.ts and the editor result handling in apps/kimi-code/src/tui/controllers/editor-keyboard.ts. Run apps/kimi-code/test/utils/process/external-editor.test.ts, then extend its coverage for null with SIGTERM, null with SIGINT, and normal exit. Done means only a zero-code, no-signal exit reads back temporary content; signal or nonzero exits preserve the original input.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 88/100