Skip to content

fix(desktop): keep the new-task composer's contents when the target changes - #3432

Open
shaokeyibb wants to merge 2 commits into
apache:mainfrom
shaokeyibb:fix/new-task-composer-target-carry
Open

fix(desktop): keep the new-task composer's contents when the target changes#3432
shaokeyibb wants to merge 2 commits into
apache:mainfrom
shaokeyibb:fix/new-task-composer-target-carry

Conversation

@shaokeyibb

@shaokeyibb shaokeyibb commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Everything the new-task composer holds — draft text, staged attachments, staged quotes — is
keyed by (profileId, hostId, projectId) since #3122. The workspace picker that changes the
project part sits directly under the composer, so choosing a Project re-keys all three
mid-composition and what you were writing drops out of view.

They now follow the target you pick. The buckets stay keyed per target, so #3122's
Host-scoped new-task state is unchanged — they just move with the selection instead of being
left behind under the key you navigated away from.

Two things about the approach that are not the obvious choice:

  • The move is unconditional: the target you arrive at holds what you brought and nothing
    else. Carrying only into an empty target would leave copies under keys the composer passed
    through, and one resurfaces later — send the task, come back to an empty composer, pick
    another target, and the text you just sent reappears as that target's own draft.
  • The carry keys on the new-task target, not on the composer's active key
    (activeId ?? newTaskDraftKey). A Session switch changes that active key too, and a
    Session must keep its own draft and attachments.

Three imports gained .js extensions so node --test can load the two staging hooks, which
is what the new test needs to reach them.

Fixes #3408

Verification

The same moment in both shots: a draft typed on the new-task surface, immediately after
choosing a different target in the workspace picker (both show 无项目 selected).

before-2-after-switch after-2-after-switch
  • e2e/new-task-draft-target.spec.ts (new) — real window: type, then pick a Project. Fails on
    main with Received: "", passes with the change.
  • chat-composer-region-draft-handoff.test.ts — 2 of 5 fail on main. The other three guard
    the new behaviour, and each fails against a weaker version of this fix.
  • new-task-pending-carry.test.ts (new) — attachments and quotes; 2 of 4 fail without the
    carry.
  • npm run lint, npm run format:check, npm --workspace @maka/desktop run typecheck: clean.
  • Full Playwright suite: 36 passed, 1 failed — session-workbar.spec.ts:124, which fails on a
    clean main checkout here too.
  • npm --workspace @maka/desktop run test: 13 failures, an identical set on clean main
    (EBUSY unlinking SQLite files, and a shell-script fake CLI).

Not run: any packaged-app check. My host is Windows x64, which CONTRIBUTING lists as an
unsupported target, and that is also what the 13 unit failures above are.

AI use

Select exactly one:

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: Claude Code (Claude Opus 5) — root-cause tracing, the fix, the tests and a
draft of this description. Reviewed, run and verified locally by me.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

…hanges

Draft text, staged attachments and staged quotes are all keyed by (profileId,
hostId, projectId) since apache#3122, and the workspace picker that changes the
project part sits directly under the composer — so choosing a Project re-keyed
all three mid-composition and what the user was writing dropped out of view.

Carry them to the target the user selects. The buckets stay keyed per target,
so apache#3122's Host-scoped new-task state is unchanged; they move with the
selection instead of staying behind under the key the user navigated away from.

The move is unconditional: the target arrived at holds what was brought to it
and nothing else. Carrying only into an empty target would leave copies under
every key the composer passed through, and one would resurface later — send the
task, come back to an empty composer, pick another target, and the text just
sent would reappear as that target's own draft.

The carry keys on the new-task target rather than on the composer's active key,
so a Session keeps its own draft and attachments when the target moves behind
it. Leaving the unresolved slot keeps its existing reload-lease guard: that
transition is startup settling, not a choice, and its draft may belong to one
specific target.

Fixes apache#3408

Generated-by: Claude Code (Claude Opus 5)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 21, 2026 14:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Desktop new-task composer state handoff so that changing the workspace picker target (Project) does not make in-progress composition appear to disappear. This aligns draft text plus staged attachments/quotes with the currently selected new-task target, while keeping Session-scoped state isolated.

Changes:

  • Carry the visible new-task draft across (profileId, hostId, projectId) target changes in ChatComposerRegion, with special handling for the unresolved startup key and reload-intent persistence.
  • Add a generic “pending bucket rekey” pathway for staged attachments and quotes so they move with the selected new-task target.
  • Add unit + e2e coverage to ensure the new behavior fails on main and passes with the fix.

Required Conclusion

  1. Is the current solution optimal for the actual problem? Mostly yes: it addresses the root cause (keyed buckets swapping on target change) at the correct ownership points (draft in ChatComposerRegion, staged items in the staging hooks) with minimal new abstraction.
  2. If applicable, what production code can be deleted? none identified.
  3. If applicable, what low-quality tests can be deleted or replaced? none identified.
  4. Is a deeper refactor required, and what should the final structure be? No deeper refactor required; the current split (draft vs staged buckets) is appropriate. The small shared helper hook for staged buckets is a reasonable end state.
  5. Is the reviewed revision ready to merge? Yes, assuming the inline comment is addressed or explicitly waived by the maintainer.
  6. What residual risks or verification gaps remain? Minor edge-case risk around object-map key handling in rekeyPending (prototype-chain key collisions) and typical flake risk in compositor-timing-sensitive e2e; no other verification gaps identified from the diff.

Review-relevant risks / protected areas: No direct impact identified on security/auth boundaries, licensing, releases, or governance in this diff; primary impact is user-visible Desktop behavior for draft/staging preservation.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
apps/desktop/src/renderer/use-new-task-pending-carry.ts New hook to rekey staged-item buckets when the new-task target changes.
apps/desktop/src/renderer/use-app-shell-composer-quotes.ts Plumbs new-task target key into quote staging; invokes carry hook.
apps/desktop/src/renderer/use-app-shell-composer-attachments.ts Plumbs new-task target key into attachment staging; invokes carry hook.
apps/desktop/src/renderer/chat-composer-region.tsx Carries draft text across target key changes with unresolved/reload-intent handling.
apps/desktop/src/renderer/app-shell.tsx Wires currentNewTaskDraftKey into attachments/quotes staging hooks.
apps/desktop/src/renderer/app-shell-pending-attachments.ts Adds rekeyPending helper for moving staged buckets between keys.
apps/desktop/src/main/tests/new-task-pending-carry.test.ts New unit tests asserting staged attachments/quotes move with target and don’t leak into Sessions.
apps/desktop/src/main/tests/chat-composer-region-draft-handoff.test.ts Expanded unit coverage for draft carry across target changes and reload-intent behavior.
apps/desktop/e2e/new-task-draft-target.spec.ts New e2e test validating real-window wiring: picker selection does not drop visible draft.
apps/desktop/e2e/fixtures.ts Adds a seeded project + a dedicated fixture window to support the new e2e test.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/desktop/src/renderer/app-shell-pending-attachments.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(desktop): new-task composer draft disappears when switching projects in the workspace picker

2 participants