Composer shows a disabled send button instead of Stop while the CLI is starting
メンテナーはふだん 1 日以内に返信
@22chiragmodh がすでに取り組んでいます。
2026年11月6日 から。
評価
この issue はまだ評価されていません。
説明
Problem
When a message has to start the session's CLI first (the first message of a session, a session whose CLI stopped, a repository launch that creates a worktree), the composer shows a grayed-out send button for a few seconds instead of the stop button. During that time the user cannot stop the turn, and the "Creating worktree" status is not shown either.
Found by reading the code on main (b4ee8b36). Please reproduce it first; the quickest way is a new session in a git project with "new worktree" on, where startup takes longest.
Cause
- On send, the desktop sets
chatState: 'thinking'optimistically and clears the composer (chatStore.ts). The stop button shows. - The server's
deliverUserTurnawaitsensureCliSessionStarted(handler.ts). When the CLI is not running this takes seconds. - Startup changes session state (process phase, workspace, worktree status), and each change is pushed to clients as a
session_patch. - On every patch the desktop recomputes
chatStatefrom the server's state (chatStore.ts).turn.phaseis stillidle, sochatStategoes back toidle: send button, disabled because the composer is empty. - Only after the CLI started and the message was sent does the server apply
turn_started(handler.ts), and the stop button comes back.
Session state is owned by the server, so the server must say "a turn is under way" for the whole window. The fix is not a client-side guard against the mirror.
Proposed design
1. A new turn phase starting. SessionState.turn.phase becomes 'idle' | 'starting' | 'running' | 'awaiting_permission': the message was accepted and the server is waiting for the CLI. Add a reducer event (e.g. turn_starting { at }). turn_started and the CLI's session_state_changed: running move it to running and keep its startedAt, so the elapsed time counts from the send.
2. Decide "own turn or queue" when the message is accepted. Today deliverUserTurn checks turnQueue.shouldQueue after the CLI started. With starting counted as "not idle", the message that started the turn would queue behind itself. Move the decision before any await (after the /clear handling):
- queue path: as today (wait for the CLI, then send with priority
later); - own turn: apply
turn_starting, then wait for runtime transitions and CLI startup, then send and applyturn_started.
A second message sent while the first one is still starting takes the queue path. It must reach the CLI after the first message.
3. Process startup must not wipe the starting turn. applyProcessPhase resets turn to idle when the process phase becomes starting, stopped or failed (reducer.ts). Keep a starting turn through the process's starting phase. Still reset it on stopped and failed.
4. Every way out of the startup window ends the turn. Startup failure, CLI_RESTART_FAILED after a runtime transition, and CLI_NOT_RUNNING when sending must all leave the turn idle. Otherwise the client is stuck on the stop button. Use one exit path in deliverUserTurn, not a turn_ended copied into each branch.
5. Stop during startup. Make it behave like Stop right after a message reaches a running CLI: the message stays in the conversation, and the turn is interrupted. The server records the stop and ends the turn at once. When the CLI is up, it sends the message and interrupts immediately. Expect one pitfall: the CLI then reports running before it reports the interrupted result, which would bring the stop button back for a moment. The pipeline's existing stopRequested handling is where to deal with that. Don't kill the starting process.
6. Desktop and H5. Treat starting as busy (chatStateFromMirror → thinking, isTurnRunning, StreamingIndicator). Show the existing "Creating worktree" status during startup. Update the SessionState type on both sides. H5 uses the same frontend.
Check the other readers of turn.phase. Most already test !== 'idle', so starting counts as busy automatically. Confirm each one is right:
handler.ts: artifact turn tracking, restart deferral (deferRestartUntilTurnEnds), the runtime check;sessionLinksService.ts: whether the parent is running (for reports), therunningflag in ListSessions;turnQueueService.ts;browserHost/runtime.ts;- the reducer.
Acceptance
- From the moment the message is sent until the turn ends, the composer shows the stop button. No idle frame appears in between, on the desktop or on H5.
- A second client and a client that reconnects during startup both see the turn as under way.
- A CLI startup failure leaves the session idle and shows the error.
- Stop during startup leaves the session idle, without the stop button flashing back. The message stays in history.
- Two messages sent during startup arrive in order: the first starts a turn and the second is queued.
- Messages from other sessions (
originset) that start a stopped CLI behave the same way. - Tests:
- server: reducer (
turn_starting, processstartingkeeps it,stopped/failedclear it),deliverUserTurn(state during startup, failure, Stop during startup, second message during startup); - desktop: a patch that arrives during startup keeps the stop button.
- server: reducer (
- Check both themes if the status text changes. Add a CHANGELOG entry under
Fixed.
Relevant docs: session state design (turn state section) and session links design (queued messages). Update the session state doc with the new phase.
- 主要言語
- TypeScript
- スター
- 490
- フォーク
- 47
- 平均マージ
- 8時間 51分
- マージ済み PR(30日)
- 91
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
GoDiao/dreamcoder のほかの issue
-
[good first issue] UX polish — friendlier copy for error toasts and empty states対応中かも @iamcipherdev が 22 日前に担当しました。 オープンarea:i18n area:ux difficulty:1 good first issue mentor-available
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
GoDiao/dreamcoder#9 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
Add more provider presets (Groq / OpenRouter / SiliconFlow / etc.)再び着手できるかも @01iamysf が 29 日前に担当しましたが、オープン中のプルリクエストはありません。 オープンarea:desktop area:provider difficulty:1 good first issue mentor-available
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
GoDiao/dreamcoder#6 · コメント 6 件 ·
メンテナーはふだん 1 日以内に返信
-
enhancement rfc
難易度 5/5 1週間以上 初心者へのやさしさ 28/100
GoDiao/dreamcoder#241 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
area:desktop enhancement rfc
難易度 5/5 1週間以上 初心者へのやさしさ 8/100
GoDiao/dreamcoder#234 ·
メンテナーはふだん 1 日以内に返信
-
Context usage indicator counts base64 images as text and shows several times too many tokens対応中かも @Oscar-Williams が 6 日前に担当しました。 オープンarea:desktop bug good first issue help wanted
難易度 3/5 1〜2日 初心者へのやさしさ 70/100
GoDiao/dreamcoder#230 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
GoDiao/dreamcoder の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
langchain-ai/langchainjs#12157 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
activescott/home-infra-k8s-flux#511 ·
メンテナーはふだん 1 日以内に返信
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
lingdojo/kana-dojo#33753 · コメント 1 件 · リアクション 5 件 ·
メンテナーはふだん 1 日以内に返信
-
android:player
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信
-
follow-up needs-triage S3: minor
難易度 1/5 1〜3時間 初心者へのやさしさ 85/100
manaflow-ai/cmux#38032 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信