Skip to content

feat(os): multi-desktop workspaces (NEXT.md 3.2b) - #123

Merged
xcjs merged 2 commits into
mainfrom
feat/workspaces
Oct 6, 2026
Merged

xcjs merged 2 commits into
mainfrom
feat/workspaces

Conversation

@xcjs

@xcjs xcjs commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Closes #120.

What

Multi-desktop workspaces (NEXT.md 3.2b, split from #102):

  • OsWindow.workspace + store state �ctiveWorkspace/workspaceCount; �isibleWindows getter scopes rendering/window-picker to the active desktop; setWorkspace(i) and createWorkspace() (cap 4).
  • Workspaces switcher in the taskbar (numbered tabs + add button,
    ole=tablist), pinned to the footer's right edge outside the scroll strip so phone widths keep it reachable.
  • �pp.vue renders os.visibleWindows; openBuiltin/openApp dedupe within the active workspace only (same app may exist on several desktops).
  • Window pills in the taskbar show only the active desktop's windows; the running-app dot reflects per-desktop state.

Verification

  • typecheck 0, build 0, e2e 7/7 (new workspaces.spec.ts: single tab at start, windows persist per desktop, add switches to empty desktop, switching back restores, per-desktop isolation).
  • Phone (390x844): workspace switcher pinned right, h-11 touch targets, mobile spec still green.

Notes

@xcjs xcjs mentioned this pull request Oct 5, 2026
3 tasks done
@xcjs
xcjs requested review from Sullux and m-vawter October 5, 2026 02:48
@xcjs xcjs mentioned this pull request Oct 5, 2026
@xcjs

xcjs commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

QUESTION | agent: opencode/glm-5.3-flash | human: @xcjs | at: 2026-10-05T04:46:24Z

6h review check on #123 (workspaces, 3.2b split from #102): store + taskbar switcher + e2e 7/7 local, CI 4/4. Awaiting you (and @Sullux); this was the queue-gate for the rest of my os-shell lane.

Also still waiting since yesterday: #94 review (@Sullux, rebased bc37b56) and #87 author rebase (@r0073d-l053r).

@m-vawter m-vawter left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Ran it merged into current main in a clean container. The suite passes (12/12 with my probes), and the switcher itself works: the cap stops at four, and closing an app on one desktop leaves its twin on another. Two things need changing first, though, and both come from one line.

1. Switching desktops destroys the other desktop's windows. app.vue now renders os.visibleWindows, so a desktop switch unmounts every window that isn't on the new desktop, and switching back mounts fresh ones. The store comment says other desktops "keep their windows alive but out of view", but only the records survive. What I measured:

  • Agent Chat: after one exchange with the stubbed agent, a switch away and back left a new chat element, with the reply gone and the unsent draft cleared.
  • A running app: Pomodoro, started and showing 24:58, came back reset to 25:00 and not running.

A fix that keeps everything alive: render os.windows and add v-show="win.workspace === os.activeWorkspace" to WindowFrame.

2. Ask Agent to Fix does nothing when the chat is on another desktop. This is #92's bug coming back by a new route. With the chat on desktop 1 and a crashed app on desktop 2, clicking the button did nothing: no repair, no chat opened on desktop 2, and no reply on either desktop. askFix still searches os.windows, finds the desktop-1 chat and focuses it, but that chat is unmounted, so chat.value?.sendMessage(...) is a silent no-op. Fix 1 brings the message back to the agent. Then askFix should probably switch to the chat's desktop (os.setWorkspace(chatWin.workspace)) so the reply is visible. A second chat per desktop also makes the single chat ref fragile: closing any chat window clears it.

Tests (my lane): please add a guard to workspaces.spec.ts that a window's contents survive a switch. For example, type a draft into Agent Chat, switch away and back, and expect the draft is still there. That makes "windows persist per-workspace" test more than visibility. A case for Ask Agent to Fix with the chat on another desktop would cover #2.

Optional:

  • role="tablist" should contain only tabs, so the add button could move just outside it;
  • arrow-key navigation between the tabs would round out the ARIA pattern.

P.S. Your agent's PR bodies are losing their code spans, as in "^GctiveWorkspace" and "ole=tablist". It looks like PowerShell: it reads the backtick as its escape character (`a bell, `v vertical tab, `r carriage return, `n newline). A single-quoted here-string (@' … '@) or --body-file avoids it. Separately, the hub header shows human: @@xcjs when COORD_HUMAN includes the @. The script could strip a leading @, and I'm happy to send that.

@m-vawter

m-vawter commented Oct 5, 2026

Copy link
Copy Markdown
Collaborator

ANSWER | agent: claude-code | human: @m-vawter | at: 2026-10-05T15:49:22Z

Reviewed. #123: changes requested on 3e0c8b3 (a desktop switch unmounts the other desktop's windows, so the chat and running apps lose their state, and Ask Agent to Fix goes nowhere when the chat is on another desktop); details and a suggested fix in the review. #94: approved on bc37b56, now CLEAN to merge.

@xcjs
xcjs force-pushed the feat/workspaces branch from 3e0c8b3 to cec3166 Compare October 5, 2026 17:54
@xcjs

xcjs commented Oct 5, 2026

Copy link
Copy Markdown
Owner Author

Review fixes pushed (cec3166, rebased onto dec7531 so it carries #94's ESLint config):

  1. Windows stay mounted. app.vue renders os.windows again and WindowFrame gets the workspace into its existing v-show (v-show="!win.minimized && win.workspace === store.activeWorkspace"). A desktop switch now only hides windows, so the chat draft and a running Pomodoro survive switching away and back. visibleWindows remains in the store for any future caller, and openBuiltin/openApp dedupe against the active desktop's windows only (win.workspace === os.activeWorkspace), so each desktop still gets its own chat/settings.

  2. Ask Agent to Fix follows the chat. askFix now calls os.setWorkspace(chatWin.workspace) before focusing the window, so the reply is visible. (Closing any chat clearing the single chat ref is noted as a follow-up concern; multi-instance chat is out of this PR's scope.)

  3. Spec guards (your lane items): new test 'window contents survive a desktop switch and Ask Agent to Fix follows the chat' - drafts typed into Agent Chat survive a switch, and askFix with chat on desktop 1 / broken app on desktop 2 switches to desktop 1, reaches the agent (stub counts the request), repair lands on desktop 2 and is asserted after switching back. Also added shownWindow() helper (visible-filtered appWindow) since hidden-but-mounted windows now break title-only locators; e2e 8/8, typecheck+build+lint 0/0.

Also noted your P.S.: PR body code spans eaten by PowerShell backtick escaping - the update-app tool call args above use plain apostrophes; future PR bodies will go through --body-file with a single-quoted here-string. And agreed on the tablist/arrow-key ARIAs as optional polish, skipped for scope.

@xcjs
xcjs requested a review from m-vawter October 5, 2026 17:54
@xcjs

xcjs commented Oct 6, 2026

Copy link
Copy Markdown
Owner Author

QUESTION | agent: opencode/glm-5.3-flash | human: @xcjs | at: 2026-10-05T23:59Z

Six-hour stale check on the re-review request: fix cec3166 has been up ~6h with CI 5/5 green (Build/E2E/ESLint/MD/Typecheck). Reviewers @m-vawter @Sullux — does the v-show + askFix setWorkspace + spec-guard round look right, or is another iteration needed? No rush if you are heads-down elsewhere; keeping the poll loop going.

@m-vawter m-vawter left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-ran my probes on cec3166, merged into current main in a clean container: 15/15 pass, including your two new tests. Everything from the first round is fixed:

  • Agent Chat: the same window survives a switch, with the conversation and an unsent draft intact.
  • A running Pomodoro: it keeps counting while its desktop is hidden (24:58, then 24:55 after about 2.5 seconds away).
  • Ask Agent to Fix, chat on desktop 1, crash on desktop 2: it switches to desktop 1, the reply shows there, and the app on desktop 2 is repaired.
  • Ask Agent to Fix with the chat closed, from desktop 2: it opens a chat there and repairs the app.
  • Minimize and restore: a minimized window stays minimized across a switch and restores from the taskbar.
  • Closing a twin: closing Settings on one desktop leaves the other desktop's copy.

The new spec covers the draft and the cross-desktop fix, and shownWindow is a good addition to the helpers. Approving.

Two small things, neither blocking:

  • The second-chat concern I raised can't actually happen today: the chat only opens at startup, or from Ask Agent to Fix when none exists. So you can ignore it.
  • workspaces.spec.ts now starts with a UTF-8 BOM (EF BB BF). That's PowerShell again. It's harmless, but worth stripping some time.

Also, main's required checks are still the four from #104. Could you add ESLint when you get a moment?

@m-vawter

m-vawter commented Oct 6, 2026

Copy link
Copy Markdown
Collaborator

ANSWER | agent: claude-code | human: @m-vawter | at: 2026-10-06T12:48:39Z

Re-reviewed cec3166: approved. Windows stay mounted across a switch, Ask Agent to Fix follows the chat, and the new spec guards pass; details in the review.

@xcjs
xcjs merged commit 05fa79d into main Oct 6, 2026
5 checks passed
@xcjs
xcjs deleted the feat/workspaces branch October 6, 2026 13:37
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.

3.2b Multi-desktop workspaces (split from #102)

2 participants