MoonshotAI / MoonshotAI/kimi-code
TUI /web exits the process (exit 0) instead of handing off to foreground kimi web
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 版本是?
0.39.0
你使用的是哪个开放平台/订阅?
Kimi Code(kimi login)
你使用的是哪个模型?
无关(/web 交接阶段就会退出)
你的电脑平台是?
Darwin 25.5.0 arm64 arm
你遇到了什么问题?
在 TUI 里对已有会话执行 /web 后,整个 kimi 进程以 exit 0 退出,没有停在前台 web server,也经常看不到 Kimi server ready 横幅。终端直接回到 shell。
对比:同一台机器、同一版本,在 shell 里跑 kimi web --no-open 可以一直前台挂着,127.0.0.1:58627 可访问。
复现步骤?
kimi(或kimi -S <existing-session>)进入 TUI,确认已有 session。- 输入
/web回车。 - TUI 拆掉后进程结束,exit code 0。没有持续监听的 web server。
期望的行为是什么?
文档/代码注释里的设计:TUI 退出后 同一进程变成前台 kimi web,打印 ready banner + session 深链,直到 Ctrl+C。
apps/kimi-code/src/tui/commands/web.ts:
/**
* `/web` — hand the current session off to the browser.
*
* Always starts a new server: the TUI shuts down and this process becomes the
* server, running in the foreground attached to this terminal ...
*/
export async function handleWebCommand(host: SlashCommandHost): Promise<void> {
startNewServerAfterExit(host, session.id);
await host.stop();
}
run-shell.ts 的 onExit 也会 await tui.exitForegroundTask(exitCode) 而不是立刻 process.exit。
补充信息
原因(与 #3336 不同)
/web 本身不走 Remote Control,也不读 OAuth 槽。失败发生在 TUI teardown 之后、HTTP listen 之前。
- TUI
stop()→terminal.stop()会process.stdin.pause()(packages/pi-tui/src/terminal.ts,注释说是为了避免 raw mode 关掉后 Ctrl+D 打到父 shell):
process.stdin.pause();
if (process.stdin.setRawMode) {
process.stdin.setRawMode(this.wasRaw);
}
暂停后的 stdin 不再占用 event loop。
-
onExit里shutdownTelemetry、关掉 harness/MCP 之后,再await startServerForeground()。runServerInProcess在 listen 之前有await startServer(...)。 -
runServerInProcess末尾的return new Promise<never>(() => {})并不能 维持 event loop(注释写错了)。进程活着靠的是 listen socket 以及尚未 pause 的 stdin。 -
CLI
kimi web没有先拆 TUI,stdin 仍是 ref'd TTY,所以await startServer期间进程不会退出。/web已经 pause 了 stdin、拆掉 MCP/timer,listen 还没绑上 → Node 走beforeExit,exit 0。process.exit()不会被调用,所以 catch 里的Failed to start server也打不出来。
实测:TUI /web 后进程约 1–2 秒结束;同一时刻日志会出现一次新的 query-store opening(server 开始启动),但 http.Server.listen 来不及发生。
Workaround
不要用 /web 做交接。另开终端:
kimi web
用打印的 URL 打开当前 session(/sessions/<id>#token=...)。
建议修复
在调用 exitForegroundTask / startServerForeground 之前先挡住 event loop,例如:
process.stdin.resume()(交接完成后 web server 的 listen 会接上),或- 用 ref'd
setInterval/setTimeout包住await startServer(...),listen 成功后再清掉,或 - 先 listen,再拆 TUI。
同时修正 runServerInProcess 里 “hanging Promise keeps the event loop alive” 的注释——它做不到。
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/tui/commands/web.ts and run-shell.ts to trace the handoff after host.stop(), then inspect packages/pi-tui/src/terminal.ts and the in-process server startup path. Reproduce TUI /web and compare it with kimi web --no-open. Done means the TUI hands off to a foreground web server, prints the ready banner and session URL, and remains alive until Ctrl+C.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100