Files
kandev/apps/web/components/task
João Salavisa f3daeaf416 feat(cli-mode): forward Preview chat input to PTY in passthrough sessions (#1042)
* feat(cli-mode): route Preview chat input through PTY stdin in passthrough sessions

Branch Executor.Prompt on lifecycle.Manager.IsPassthroughSession so that
follow-up prompts from any UI surface (the kanban Preview screen, mobile
session view, etc.) reach the running CLI agent via PTY stdin instead of
silently falling through to the ACP path. WritePassthroughStdin failures
propagate so Service.handlePromptError reverts session state and surfaces
the error; MarkPassthroughRunning failures are non-fatal because the data
is already in the PTY.

Closes the backend half of #989; the Preview-side UI compose box ships
in a follow-up commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* feat(cli-mode): add Preview-screen compose box for passthrough sessions (#989)

In the kanban Preview tab, render a small kandev-controlled composer below
the PassthroughTerminal when the session is is_passthrough. Submitting (Enter
or click) posts message.add over WS — the backend's Executor.Prompt routes
passthrough sessions to PTY stdin so the CLI agent actually receives it.
Shift+Enter inserts a newline; empty/whitespace input is disabled.

This closes #989 together with the previous backend commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(cli-mode): warn when dropping attachments on passthrough prompts

Code review found that a passthrough prompt carrying non-empty text and
attachments silently dropped the attachments — surprising for any UI
surface (e.g. the full-page TaskChatPanel) that lets users attach images
to a passthrough task. The plan flagged this exact "silent drop" risk.
Pass attachments into promptPassthrough and log a warning with the
count when any are dropped; empty-text-with-attachments still errors
out as before. Adds a regression-guard test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* test(cli-mode): cover passthrough composer routing end-to-end

QA pass added integration-level tests at the Service.PromptTask layer
that exercise the full wiring (real Service + real Executor, with a
mocked agent manager) for the three issue-#989 acceptance paths:
prompt-routes-to-PTY, empty-prompt-surfaces-error, and write-failure-
reverts-session. Also adds a unicode/multiline preservation guard at
the Executor.Prompt unit layer. Lives in a new file to avoid pushing
task_operations_test.go over the file-length-limit threshold.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(cli-mode): preserve composer text on send failure + clarify dispatchOnly

Addresses two pieces of PR #1042 review feedback.

1. PassthroughComposer used to clear the textarea unconditionally after
   onSubmit resolved, but the WS handler swallowed transport errors and
   resolved normally — so a network blip silently wiped the user's typed
   message with no way to retry. Add a passthrough-specific send handler
   that rethrows after toasting, and gate the setValue("") in the composer
   on success. Preserves the ACP handler's swallow-and-resolve contract
   to avoid leaking unhandled rejections into the TaskChatPanel chain.
   New regression test: "preserves the typed text when onSubmit rejects".

2. Add a one-line comment at the passthrough branch in Executor.Prompt
   explaining why dispatchOnly is not forwarded — PTY writes are inherently
   fire-and-forget, so the flag has no analogue.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(cli-mode): toast disconnect + auto-grow passthrough composer textarea

Two follow-ups from PR #1042 review on commit e403ca8e.

1. handleSendPassthroughMessage threw when getWebSocketClient() returned
   null without surfacing a toast first — Composer.submit's catch then
   preserved the typed text but the user had no idea why the send didn't
   land (greptile P1, cubic P2). Toast a "Not connected" error before
   re-throwing so the failure is visible.

2. PassthroughComposer textarea stayed 36px tall on Shift+Enter multiline
   input because rows={1} + resize-none + only a CSS-based field-sizing
   hint meant non-Chromium browsers never grew the box (Claude UX
   suggestion). Add a useLayoutEffect that resets and re-measures
   scrollHeight on every value change, capped at max-h-32 (128 px) with
   overflow-y-auto for content that exceeds the cap.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Kandev Agent <agent@kandev.dev>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 17:06:30 +01:00
..