Repository navigation
NEXUS-4022: Start region chats in the New Chat editor - #2784
Conversation
325ffdd to
eefb9ac
Compare
|
🤖 Design review at This aims to keep a task’s draft and first message safe across interruptions. The patch also introduces a new task-creation view and task-specific recipient/status controls in core (draft view, recipient control). Those are additions to the product experience, beyond a contained fix to an existing flow. Under the current UI frost through the Nov 10 launch, defer the new core task experience. New UX should ship in an external plugin under the current plugin-first policy. Source-only scope review. No screenshots attached in the PR description or discussion. I did not run the app or tests, or verify native delivery/recovery, themes, window widths, enlarged text, or live keyboard/focus behavior. |
|
🤖 lets narrow this to integration with the shared New Chat flow and a durable local handoff into the existing Outbox. task state can catch up asynchronously in the plugin the Buzz thread has the flow, existing owners, required gaps and recovery cases this is a scope change request. the smaller implementation still needs validation open in Buzz (copy this URL): |
f12d20c to
c065897
Compare
A Solo region source can open the host's New chat editor for its region, optionally in a workspace. The draft keeps its own prompt, files, model and effort, and sends like an ordinary New chat: the create goes out unguarded with the region label before the first message, so the Outbox retries both after a restart. A source can narrow the agents the draft may address, and Send is refused while the source is not running and ready. Before the create, the host saves on this device how the chat started, and returns it only to that region's source until the source forgets it. The source reconciles its own records from it by channel ID. Nothing changes for hosts or plugins that do not use it. Co-authored-by: Codex <[email protected]> Co-authored-by: Claude <[email protected]> Signed-off-by: Gil Birman <[email protected]>
A contributed Solo row action used to run on click, while its menu was still open. The menu then returned focus to the row, which took focus from the dialog or composer that the action had just opened. Now the row menu runs the chosen action once its close completes. It first puts focus on the row, so the action can move focus from there. The action is dropped if the menu reopens, the row unmounts or rebinds, or the user moves focus elsewhere before the close completes. Escape and outside dismissal still return focus without running anything. Co-authored-by: Codex <[email protected]> Co-authored-by: Claude <[email protected]> Signed-off-by: Gil Birman <[email protected]>
c065897 to
a778be9
Compare
dr0uleau
left a comment
There was a problem hiding this comment.
🤖 approved with one non-blocking finding on the agent check after file upload
Updated by Codex 🤖
| // the start instead of leaving an empty chat behind. | ||
| const uploaded = await files.prepareForSend(new AbortController().signal); | ||
| if (!mounted.current) return; | ||
| regionOwner(); |
There was a problem hiding this comment.
🤖 [P2] should you recheck the source binding and draftAgent after file upload, before saving the start and creating the chat? the current check only requires a ready source. if the selected local agent becomes archived or is removed during upload, Buzz still creates the chat and sends the message. Nexus then skips task creation and forgets the start. reuse the existing eligibility check here and keep the draft and files on refusal
Updated by Codex 🤖
## Summary
Exposes the bound user's personal Solo Workspaces to plugin regions
(`2cbf04b6d`).
`ctx.soloNavigation.workspaces` takes the current region binding and
offers:
- `snapshot`: the workspace IDs and names, the catalog status, whether
creation is available, and any read error;
- `subscribe` and `refresh`;
- `create({ id, name })`.
It uses the existing Solo preference writer, so that writer's
authorization, capacity and revision checks apply. An ended binding
cannot read or write another community. Ordinary chat filing stays
host-owned. `docs/solo-regions.md` documents the contract.
### Compared with the previous version of this PR
The PR no longer contains "add primary controls and the workspace
header". It is based on #2784's branch instead of #2785's.
buzz-review-completed
## Testing
Local runs on macOS, on the stack rebased onto main `9596cd3db`:
- At this PR's head `2cbf04b6d`: `pnpm check` (Biome, TypeScript and the
design checks) and the icon check passed. Vitest for the files the flake
check selects for this PR: 436 of 438 passed in a run that shared the
machine with a Rust build; the 2 tests that timed out
(`App.profile.test.tsx`, `entity-navigation.test.tsx`) passed on rerun,
52/52 in their files.
- At the stack tip `adbdf424e`: full Vitest, 20556 passed and 23 skipped
(includes `browser-host/channel-kit.test.mjs`).
- Browser journeys at the stack tip, Chromium and WebKit: the full
`tests/browser/solo-rename.spec.mjs`, repeated 5 times, passed 120/120.
The 34 other specs that the flake check relates to the stack, run once
in each engine: 343 passed, 3 skipped by their own conditions. The full
browser suite was not run locally.
- The Nexus plugin's connected browser harness ran on the actual Buzz
web shell and plugin UI, with a simulated relay and generated
identities, before the rebase. Full run at host pin `049a9b57e` (now
`1fbd49c49`), which includes this PR: 53 passed.
**Native testing:** Gil ran the native desktop app on this stack at
`adbdf424e`, with the matching Nexus plugin build. Gil confirmed that
these native-only paths passed:
- `!` folder listing through the Tauri `repositories_folder_list`
command (#2789);
- `/` SKILL.md listing through `local_skills_list` (#2790);
- the Claude `--add-dir` folder grant (#2789);
- relay signing and Outbox retry after a native restart.
Agent testing did not reach these paths: the agent ran no native app, no
real relay and no real agent.
## Known gaps
- None specific to this PR.
Hosted or local failures that this stack does not cause:
- `tests/browser/typing.spec.mjs:290` ("a growing channel/thread
composer lifts history with it at the bottom") intermittently fails with
React error #185 on main too. Locally it failed 12 of 12 runs at
`9596cd3db` and 9 of 12 at a later main commit.
- On macOS, `cargo test -p Buzz` crashes the library test binary
(SIGSEGV), and some `host_command` deadline tests fail. Both happen the
same way at base `9596cd3db`, before this stack. Hosted Linux CI is the
reference for these.
## Test changes
Titles are compared only in the test files each range changes. Tests
that moved or were renamed are matched by title.
<details><summary>Removed by this PR's diff (0)</summary>
- none
</details>
<details><summary>Added by this PR's diff (1)</summary>
- `src/features/channel-navigation/solo-workspaces.test.ts`: projects
the existing Solo catalog and writer, preserving uncertainty and fencing
ended bindings
</details>
<details><summary>In the previous version of this PR, not carried over
(2)</summary>
- `src/features/solo/SoloDraft.test.tsx`: permits one start across
already-open drafts and preserves unresolved payload (%s)
- `src/features/solo/SoloDraft.test.tsx`: shows pending accepted-message
recovery and cancels binding when its draft region ends
</details>
Signed-off-by: Gil Birman <[email protected]>
Co-authored-by: Codex <[email protected]>
* origin/main: feat(messages): let attachment renderers open files from the host file card (block#2239) feat(charts): bundle a Charts code-block renderer (block#3226) Expose native reply grouping through Conversation.ui (block#3245) NEXUS-4163: Keep plugin-owned chat deletion in Solo (block#2787) NEXUS-4156: Expose Solo Workspaces to plugin regions (block#2786) NEXUS-4022: Start region chats in the New Chat editor (block#2784) feat(link-previews): unfurl web links below messages by default (block#3225) fix(messages): keep names in literal Markdown as written when editing (block#2834) feat(plugins): fetch a packaged managed plugin policy from a URL (block#2504) Signed-off-by: Joah Gerstenberg <[email protected]> # Conflicts: # crates/plugin-manager/tests/management.rs # docs/plugin-architecture.md
…y-untagged-reactions * origin/main: (324 commits) fix(github): show private-repo body images from signed links (#3252) NEXUS-4029: Preserve semantic chips in the core composer (#2303) Make plugin signature enforcement opt-in (#2212) NEXUS-4156: Add workspace Leads and choose a chat's workspace (#2788) feat(plugins): report conclusively retired update providers (#3263) feat(messages): let attachment renderers open files from the host file card (#2239) feat(charts): bundle a Charts code-block renderer (#3226) Expose native reply grouping through Conversation.ui (#3245) NEXUS-4163: Keep plugin-owned chat deletion in Solo (#2787) NEXUS-4156: Expose Solo Workspaces to plugin regions (#2786) NEXUS-4022: Start region chats in the New Chat editor (#2784) feat(link-previews): unfurl web links below messages by default (#3225) fix(messages): keep names in literal Markdown as written when editing (#2834) feat(plugins): fetch a packaged managed plugin policy from a URL (#2504) fix(goose): enable deferred tool loading for goose agents (#3227) fix(unread): preserve manual intent in captured explicit reads (#3228) NEXUS-4337: Expose retained plugin update reviews (#3075) feat(conversation): add a link preview slot below messages (#3219) feat(plugins): let link previews read a public page's preview fields (#3217) Let sidebar row plugins decorate ordinary Solo chats (#3222) ...
* origin/main: (121 commits) Expose Solo region state before a component mounts (#3296) fix(builderlab): say a 401 was refused, not expired, and show each sign-in failure once (#3241) feat(agents): file new Solo chats in explicit personal workspaces (#2857) perf(css): limit broad style invalidation (#3267) Delay and fade in the Bestie badge celebration (#3292) fix(github): show private-repo body images from signed links (#3252) NEXUS-4029: Preserve semantic chips in the core composer (#2303) Make plugin signature enforcement opt-in (#2212) NEXUS-4156: Add workspace Leads and choose a chat's workspace (#2788) feat(plugins): report conclusively retired update providers (#3263) feat(messages): let attachment renderers open files from the host file card (#2239) feat(charts): bundle a Charts code-block renderer (#3226) Expose native reply grouping through Conversation.ui (#3245) NEXUS-4163: Keep plugin-owned chat deletion in Solo (#2787) NEXUS-4156: Expose Solo Workspaces to plugin regions (#2786) NEXUS-4022: Start region chats in the New Chat editor (#2784) feat(link-previews): unfurl web links below messages by default (#3225) fix(messages): keep names in literal Markdown as written when editing (#2834) feat(plugins): fetch a packaged managed plugin policy from a URL (#2504) fix(goose): enable deferred tool loading for goose agents (#3227) ... Signed-off-by: Tyler Longwell <[email protected]> Co-authored-by: Eva <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Summary
Lets a Solo region source start its chats in the host's New chat editor, and fixes how a row menu action gets focus.
New Chat entry point for region sources (
45408d79c)A region source can now open the New chat editor for its region, optionally in a workspace, with
handle.openDraft(binding, { workspace?, lead? }).draftAgent.started(binding, channelId)returns it only to that region's source untilforget(binding, channelId). The source reconciles its own records from it by channel ID.Hosts and plugins that do not call these APIs see no change.
docs/solo-regions.mddocuments the contract.Row menu action focus (
a778be9bd)A contributed Solo row action used to run on click, while its menu was still open. The menu then returned focus to the row and took it from the dialog or composer the action had just opened.
Compared with the previous version of this PR
The durable task chat flow that this PR used to hold is gone: task drafts, task submission saved before the source claim, and the task-mode Outbox. Task sources now reconcile from the region draft start.
buzz-review-completed
Testing
Local runs on macOS, on the stack rebased onto main
9596cd3db:a778be9bd:pnpm check(Biome, TypeScript and the design checks) and the icon check passed. Vitest for the files the flake check selects for this PR: 497 passed.adbdf424e: full Vitest, 20556 passed and 23 skipped (includesbrowser-host/channel-kit.test.mjs).tests/browser/solo-rename.spec.mjs, repeated 5 times, passed 120/120. The 34 other specs that the flake check relates to the stack, run once in each engine: 343 passed, 3 skipped by their own conditions. The full browser suite was not run locally.049a9b57e(now1fbd49c49), which includes this PR: 53 passed. Targeted New task and workspace tests at pin797040559(nowfc6749bda): 4 passed.Native testing: Gil ran the native desktop app on this stack at
adbdf424e, with the matching Nexus plugin build. Gil confirmed that these native-only paths passed:!folder listing through the Taurirepositories_folder_listcommand (NEXUS-4029: Offer folder chips in the composer #2789);/SKILL.md listing throughlocal_skills_list(NEXUS-4033: Offer session skills in the core task composer #2790);--add-dirfolder grant (NEXUS-4029: Offer folder chips in the composer #2789);Agent testing did not reach these paths: the agent ran no native app, no real relay and no real agent.
Known gaps
Hosted or local failures that this stack does not cause:
tests/browser/typing.spec.mjs:290("a growing channel/thread composer lifts history with it at the bottom") intermittently fails with React error Add complete reaction toggles to the message menu #185 on main too. Locally it failed 12 of 12 runs at9596cd3dband 9 of 12 at a later main commit.cargo test -p Buzzcrashes the library test binary (SIGSEGV), and somehost_commanddeadline tests fail. Both happen the same way at base9596cd3db, before this stack. Hosted Linux CI is the reference for these.Test changes
Titles are compared only in the test files each range changes. Tests that moved or were renamed are matched by title.
Removed by this PR's diff (0)
Added by this PR's diff (17)
src/features/channel-navigation/SoloRegions.test.tsx: cancels selected %s %s after %s selection moves to %s during exitsrc/features/channel-navigation/SoloRegions.test.tsx: does not let late %s completion consume a new %s selectionsrc/features/channel-navigation/SoloRegions.test.tsx: drops a queued %s destination action after %s before late close completionsrc/features/channel-navigation/SoloRegions.test.tsx: drops a queued %s destination action when its menu reopens and then closes with Escapesrc/features/channel-navigation/SoloRegions.test.tsx: hands the %s destination action focus after %s menu close completessrc/features/channel-navigation/SoloRegions.test.tsx: keeps ordinary %s Escape and outside dismissal focus without running a contributionsrc/features/channel-navigation/SoloRegions.test.tsx: keeps the %s row origin and visible error after a deferred contribution rejectssrc/features/channel-navigation/SoloRegions.test.tsx: resets the chosen %s handoff on keyboard reopen before Escapesrc/features/channel-navigation/SoloRegions.test.tsx: runs selected %s Pin once from body and returns its non-navigation focus to the rowsrc/features/channel-navigation/routes.test.ts: keeps a region draft's label and refuses a malformed or linked onesrc/features/channel-navigation/solo-navigation-draft.test.ts: names a region's draft owner only while its source is running and readysrc/features/channel-navigation/solo-navigation-draft.test.ts: opens New chat for its region, and only that region reads and forgets how its chats startedsrc/features/solo/SoloDraft.test.tsx: a refused region start forgets its link and gives its prompt and files back to the region's draftsrc/features/solo/SoloDraft.test.tsx: a region draft can only address agents its source acceptssrc/features/solo/SoloDraft.test.tsx: a region draft whose link can't be saved starts nothing and keeps its prompt and filessrc/features/solo/SoloDraft.test.tsx: a region draft whose source stops while its files upload keeps the draft and can't sendsrc/features/solo/SoloDraft.test.tsx: a region's New chat starts a labeled chat its source can find, without filing itIn the previous version of this PR, not carried over (78)
src/features/channel-navigation/solo-navigation-draft.test.ts: persists one copied workspace on separate new draft identities before navigatingsrc/features/channel-navigation/solo-navigation-draft.test.ts: preserves ordinary no-workspace seed %jsrc/features/channel-navigation/solo-navigation-draft.test.ts: rechecks binding after synchronous draft-save subscribers invalidate itsrc/features/channel-navigation/solo-navigation-draft.test.ts: rechecks binding when workspace validation re-enters the hostsrc/features/channel-navigation/solo-navigation-draft.test.ts: refuses an existing UUID draft rather than overwrite itsrc/features/channel-navigation/solo-navigation-draft.test.ts: refuses an old binding before writingsrc/features/channel-navigation/solo-navigation-draft.test.ts: refuses combined workspace and primary seeds before allocating, writing or navigatingsrc/features/channel-navigation/solo-navigation-draft.test.ts: refuses malformed workspace %j without saving or navigatingsrc/features/channel-navigation/solo-navigation-draft.test.ts: refuses storage %s without navigationsrc/features/messages/MessageComposer.test.tsx: a task with a missing provider stays read-only and retains its draftsrc/features/messages/MessageComposer.test.tsx: an ineligible pasted task identity blocks the send instead of falling back to primarysrc/features/messages/MessageComposer.test.tsx: keeps task repair visible with revoked historical A, then sends only to eligible primary Bsrc/features/messages/MessageComposer.test.tsx: queued task follow-ups preserve captured primary identity (explicit=%s)src/features/messages/MessageComposer.test.tsx: rechecks task policy at queued publication after the provider is %ssrc/features/messages/MessageComposer.test.tsx: refuses captured task-draft workspace controls while %ssrc/features/messages/MessageComposer.test.tsx: task primary A survives explicit B; later Make primary B changes untagged routing without prefillsrc/features/messages/MessageComposer.test.tsx: task sends reject multiple or revoked explicit targets before admission and never fall backsrc/features/messages/MessageComposer.test.tsx: taskDraft without submission cannot bypass %s own-Solo send admissionsrc/features/messages/composer-chat-cards.test.ts: stages a card from document data another build saved and keeps it unsupportedsrc/features/messages/follow-up-persistence.test.ts: keeps a saved follow-up with task details this build cannot send, unsent and unchangedsrc/features/messages/mention-draft.test.ts: keeps a task draft's workspace and marks document data another build saved as unsupportedsrc/features/relay/channel-details.test.ts: keeps region and task-mode labels during label replacement, including rename=%ssrc/features/relay/channel-writes.test.ts: confirms a restored Solo create with a lost acknowledgement before attempting any resendsrc/features/relay/channel-writes.test.ts: resolves missing metadata for an authorized roster-only task before confirming refreshsrc/features/relay/channel-writes.test.ts: task member additions keep current policy through signing and require a fresh gate on restored retrysrc/features/relay/outbox-chat.test.ts: holds the submission lock through publication and refreshes a waiting stale ownersrc/features/relay/outbox-chat.test.ts: keeps peer cleanup after a former owner receives a late verified echosrc/features/relay/outbox-chat.test.ts: refuses a failed pair write before claim and restores no partial submissionsrc/features/relay/outbox-chat.test.ts: renews admission for saved rows and cannot use a released lock gatesrc/features/relay/outbox-chat.test.ts: reserves room for both rows before claim and permits retry after capacity is freesrc/features/relay/outbox-chat.test.ts: restores the same pair without automatic replay after %ssrc/features/relay/outbox-chat.test.ts: saves the entire pair before any signer, observer or publisher runssrc/features/relay/task-outbox.test.ts: a verified echo settles a queued whenPrepared wait without claiming local bindingsrc/features/relay/task-outbox.test.ts: keeps a refused preparation signed and retries after reload with the same content and event IDsrc/features/relay/task-outbox.test.ts: persists the signed event before binding it, and binds before local hearing or publicationsrc/features/relay/task-outbox.test.ts: restores the guarded create and first message with fresh policy and their original signed bytessrc/features/relay/task-outbox.test.ts: whenPrepared ends after durable binding and synchronous policy, without waiting for relay ACKsrc/features/relay/task-outbox.test.ts: whenPrepared rejects %s failure and retains the saved operationsrc/features/solo/SoloDraft.test.tsx: keeps another build's task draft with a staged chat link unchanged and unsent across mount, send and remount (%s)src/features/solo/SoloDraft.test.tsx: persists first-message intent before waiting for task creation (%s)src/features/solo/SoloDraft.test.tsx: prepares a task before starting it, keeps a refused draft and signs only its primary recipientsrc/features/solo/SoloDraft.test.tsx: rejects multiple task targets before preparation or creation and retains the draftsrc/features/solo/SoloDraft.test.tsx: restores workspace-only openDraft and never reseeds a removal, which undo restoressrc/features/solo/SoloDraft.test.tsx: resumes the saved task pair before prepare and transfers edits; keeps another build's task references unchanged and unsent=%ssrc/features/solo/SoloDraft.test.tsx: same-ID attachment recovery transfers only actual file edits (changed=%s)src/features/solo/SoloDraft.test.tsx: shows pending accepted-message recovery and cancels binding when its draft region endssrc/features/solo/task-mode.test.ts: admits verified owner information through only the current source policysrc/features/solo/task-mode.test.ts: applies task policy to every signed member addition, including a direct outbox retrysrc/features/solo/task-mode.test.ts: binds the exact preparation identity and revision before exposing the first eventsrc/features/solo/task-mode.test.ts: checks creation readiness at the durable binding boundary (%s)src/features/solo/task-mode.test.ts: checks the whole membership and exact explicit target before local deliverysrc/features/solo/task-mode.test.ts: does not classify a three-field destinationsrc/features/solo/task-mode.test.ts: does not grant informational admission to an event with %ssrc/features/solo/task-mode.test.ts: does not trust a copied proof-bearing eventsrc/features/solo/task-mode.test.ts: fails closed after disposal or a missing owning region while preserving legacy region chatssrc/features/solo/task-mode.test.ts: keeps %s outside informational policysrc/features/solo/task-mode.test.ts: keeps an ordinary addressed owner message when the source predicate returns falsesrc/features/solo/task-mode.test.ts: keeps foreign task-reference and live task-member guards ahead of informational policysrc/features/solo/task-mode.test.ts: keeps recipient-free publication closed when the source policy is %ssrc/features/solo/task-mode.test.ts: keeps unsigned saved draft validation on the ordinary pathsrc/features/solo/task-mode.test.ts: never binds an informational notice as the first task eventsrc/features/solo/task-mode.test.ts: rechecks an informational notice before publication after %ssrc/features/solo/task-mode.test.ts: refuses a proof-bearing addressed owner message classified as informationsrc/features/solo/task-mode.test.ts: refuses recognized information carrying a recipient even if ordinary admission would allow itsrc/features/solo/task-mode.test.ts: refuses task references another build signed, on send and first-event retry, and ignores unknown versionssrc/features/solo/task-mode.test.ts: refuses unknown roster keys, mismatched channel evidence and unreadable historical policysrc/features/solo/task-mode.test.ts: retains and retries the same signed first message after a creation wait %ssrc/features/solo/task-mode.test.ts: retains confirmed historical members without authorizing revoked recipients or additionssrc/features/solo/task-submission.test.tsx: hands off a %s draft after a shared submission completessrc/features/solo/task-submission.test.tsx: keeps a completed task draft when its %s changes during handoffsrc/features/solo/task-submission.test.tsx: keeps accepted first delivery recoverable through failed %s cleanupsrc/features/solo/task-submission.test.tsx: keeps an incomplete claim in its draft without a saved pairsrc/features/solo/task-submission.test.tsx: keeps failed staging editable and retries without consuming a source claimsrc/features/solo/task-submission.test.tsx: refuses a corrupt saved pair before another source claimsrc/features/solo/task-submission.test.tsx: refuses live eligibility revoked while the staged claim is pendingsrc/features/solo/task-submission.test.tsx: resumes the staged identity after exit %s the source claim commitstests/browser/outbox-chat.spec.mjs: a waiting chat owner keeps accepted event identities from the shared journaltests/browser/outbox-chat.spec.mjs: an unrelated save cannot restore a task pair that another page completes