Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/specs/alert.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ Source of truth: `SettingsDialog` and `TOPICS` in `lib/src/components/SettingsDi

**Must project every Workspace, active or not.** The Activity store spans the whole Window, so what scopes it to one Workspace is the membership each mounted Wall publishes — panes ∪ doors, on every layout commit.

**Must retain TODO and attention by stable Surface ID across a Workspace move and republish membership on both sides**, without replaying notifications on remount. GUI focus acknowledges without input; CLI movement alone does not acknowledge. Pinned by `preserves Session identity, TODO and retained cwd, retires the source ref, and recomputes both unions` in `lib/src/components/WorkspaceWindow.test.tsx`.

Source of truth: `computeWorkspaceUnion` in `lib/src/lib/workspace-union.ts`; `setWorkspaceSurfaces` in `lib/src/lib/workspace-surfaces.ts`; `lib/src/lib/workspace-union.test.ts`.

Where it surfaces is host-specific:
Expand Down
2 changes: 2 additions & 0 deletions docs/specs/dor-browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -971,6 +971,8 @@ Source of truth: `lib/src/lib/platform/iframe-proxy-types.ts`,
`vscode-ext/src/message-router.ts`, `vscode-ext/src/webview-html.ts`,
`standalone/src/tauri-adapter.ts`.

A moved iframe Surface remounts at its saved URL after consent: `docs/specs/layout.md` → Moving Surfaces between Workspaces.

## Future

- Stable agent-browser profile/state persistence so pop-out preserves logins,
Expand Down
18 changes: 12 additions & 6 deletions docs/specs/dor-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,7 @@ and each host's hop in `standalone/src/tauri-adapter.ts`,

## Handle Model

`Window ⊃ Workspace ⊃ Pane ⊃ Surface` (`docs/specs/glossary.md`). **A command's
positional target is always a Surface; a container is named by `--workspace
<ref>`** ([dor workspace](#dor-workspace)). `Reserved:` no command targets
`Window ⊃ Workspace ⊃ Pane ⊃ Surface` (`docs/specs/glossary.md`). **Must treat a command's primary target as a Surface; `dor move` also takes a destination Workspace, while `--workspace <ref>` scopes the source** ([dor workspace](#dor-workspace)). `Reserved:` no command targets
another Window; a request reaches the window that owns its Surface instead
(§Standalone), and the ref grammar for one is [Future](#future).

Expand All @@ -283,12 +281,12 @@ Invariants:
layout/list positions: each Workspace starts at `surface:1` and assigns the
next number when a Surface is created/restored. The map and its counter
persist in the session snapshot, which is what keeps a retired number from
being reused (`docs/specs/transport.md` → "Persisted session types"). **Only
creation assigns a ref** — layout churn (reorder,
being reused (`docs/specs/transport.md` → "Persisted session types"). **Must assign a ref on creation or adoption into another Workspace** — layout churn (reorder,
minimize/reattach, zoom, focus), replacing an untouched terminal with a
browser Surface, and browser render-mode swaps all leave it unchanged.
**Killing a Surface retires its ref; a later target that names it must fail
rather than silently retarget.**
- **Must retire a moved Surface's source ref**, retaining its stable ID. **Must route a moved caller by that stable ID**: its cached `surface:N` refs now resolve in the destination and may name strangers; unscoped `ensure` searches there and may duplicate work left behind. Agents must use stable IDs across moves or explicitly scope the original Workspace. Print a renderer-local notice in the moved terminal with old/new handles and these scope changes, once after success, without PTY input or Activity changes; use an eight-second pane notice in alternate-screen programs.
- Surface targets also accept `title:<exact display title>`, for human recovery;
a title can drift, so automation should prefer refs from command responses or
`dor list`. Action commands (`read`, `send`, `await`, `kill`, `dor agent-browser
Expand Down Expand Up @@ -318,7 +316,7 @@ Invariants:
never a name. **A Window is `window:<label>` — its host's own name for it**
(`window:main`, `window:ws-2`), and a host with one Window answers
`window:1`; each accepts its own ref bare.
**Every Workspace has a `surface:1`**, so a Surface ref alone
Workspaces can each have a `surface:1`, so a Surface ref alone
never identifies a Workspace.
- **One Wall answers each request**, resolved in order: the Window's own verbs
([dor workspace](#dor-workspace), and `dor list --all`, which fans out to
Expand Down Expand Up @@ -457,6 +455,14 @@ Source of truth: `dor/src/commands/`, `HELP_PATTERN_TOKENS` and pre-parsing in
`lib/src/components/wall/use-dor-control.ts`; help snapshots in
`dor/test/snapshots/help/`, pinned exhaustive by `dor/test/cli-help.test.mjs`.

## dor move

**Must move one Surface within this Window through the shared move coordinator.** Syntax and response fields are owned by `dor move --help` and `MoveSurfaceRequest` / `MoveSurfaceResponse` in `dor/src/commands/types.ts`; interaction and refusal rules follow `docs/specs/layout.md` → Moving Surfaces between Workspaces.

**Must require exactly one destination: a Workspace argument or `--new`.** Never reserve the bare name `new`; `--workspace` scopes the source. CLI moves preserve focus unless `--focus` follows the pane; if the active source disappears, activate the destination in command mode. **Must refuse iframe moves unless `--dangerously-destroy-iframe-page-state` is explicit**, without a GUI prompt. Single-Workspace hosts refuse `surface.move` through `spansWorkspaces`.

Source of truth: `moveCommand` in `dor/src/commands/move.ts`; `moveSurface` in `lib/src/components/wall/surface-move.ts`. Tests: `dor/test/move.test.mjs`, `lib/src/components/WorkspaceWindow.test.tsx`.

## dor workspace

**`dor workspace` mutates and `dor list` enumerates**, so the overview has one
Expand Down
2 changes: 2 additions & 0 deletions docs/specs/dor-tool.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ The Tool-specific local boundaries are `docs/specs/security-local.md` → Dor To

**Must cold-restore an approved Tool by starting its saved command through integration-gated shell readiness**, then rediscover its port. Agent-resume commands do not override the saved Tool command. Pending approvals restore as ordinary terminals and execute nothing. **Must rebuild visible Tool metadata from its pane row when layout geometry is unusable**, rather than starting the command in a plain terminal with no serving behavior.

Dirty or pending Tools refuse Surface moves between Workspaces: `docs/specs/layout.md` → Moving Surfaces between Workspaces.

**Must retain live Tool browser params and OSC announcements in volatile Workspace-transfer content**, applying them to the destination plan without mutating the durable record. A serving iframe Tool participates in the ordinary iframe move confirmation. **Must refuse transfer while a Tool awaits approval or its browser startup has no session binding.**

**Must pause serving updates during Workspace closure or transfer**, and recheck that a Workspace remains available after asynchronous launch lookup. Approval completion must not launch into a closing or transferring Workspace.
Expand Down
19 changes: 16 additions & 3 deletions docs/specs/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ Popups share the zoomed pane’s app-background halo.

| Row | Content |
|---|---|
| Title | Derived display title, labeled Explain action, copyable source Surface ref and close at right |
| Title | Derived display title, icon-only Explain bug immediately beside the title, copyable source Surface ref and close at right |
| Dir | Home-abbreviated directory, its unlabeled absolute-path copy, native explorer action |
| Ports | One scan per opening; scanning/empty/failure states; one port inline, multiple ports in a dropdown with count beside it; labeled launch actions |
| Alerts | Source Watch and TODO controls; notification details directly below |
Expand All @@ -98,7 +98,7 @@ Popups share the zoomed pane’s app-background halo.

**Must write visible action text in the Title, Dir, and Ports rows in lowercase**, since `iframe` and `agent-browser` cannot be capitalized; proper nouns such as Finder, tooltips, and accessible names keep their case.

**Must keep the Title and Dir rows on one line.** Title: explain drops its label, the title truncates to 8 characters, the Surface ref drops to its copy icon (the tooltip keeps it), then the title truncates further. Dir: the explorer action drops its label before the directory truncates from its start, keeping its end.
**Must keep the title and its icon-only Explain bug on one line**, with the bug immediately beside the title. In Window hosts, wrap the copyable ref and Move to workspace picker together below the title; keep Dir on one line. Title: the title truncates to 8 characters, the Surface ref drops to its copy icon (the tooltip keeps it), then the title truncates further. Dir: the explorer action drops its label before the directory truncates from its start, keeping its end.

**Must focus context controls on opening.** Explicit entry into helper xterm gives it terminal keys; Escape there belongs to its program. Escape from controls closes the innermost disclosure, then context. Terminal clipboard routing uses the focused helper rather than the selected source. Actions use subdued link color and shared compact `OnOffSwitch` controls.

Expand Down Expand Up @@ -248,6 +248,19 @@ Source of truth: `deriveWorkspaceAutoName` in `lib/src/lib/workspace-autoname.ts

Source of truth: `createWorkspaceMotion` in `lib/src/components/workspace-motion.ts`; `WorkspaceMotion` in `lib/src/components/WorkspaceMotion.tsx`; `closeAll` in `lib/src/components/Wall.tsx`.

### Moving Surfaces between Workspaces

- **Must move a Pane or Door on release over another Workspace tab**, inserting beside the destination's last selected live pane. Never activate on hover; highlight valid targets. A header/ Door press owns a pane drag; a tab press owns reorder and cross-Window tear-out. Strip gaps, the source tab, and disabled targets consume the drop without a layout move or tear-out. Escape and pointer cancellation change nothing.
- **Must offer `+` and New workspace only when the source has more than one Surface**, counting Panes and Doors; create a receiving Wall with only the moved Surface. Disable the picker item and `+` drop otherwise, and refuse CLI `--new`.
- **Must offer Move to workspace in terminal and Tool context** (placement: the Title row above), using the same coordinator as dragging. **Never add a browser context menu. Never add a command-mode move binding.** Browser Surfaces move by dragging or CLI.
- **Must retain stable Surface identity and Session state while remounting in the destination Wall**: terminals keep their registry instance, browser automation reconnects, and a retained helper follows its source. Never close a departing Session. Pin a moved preview slot by removing its preview mark.
- **Must confirm plain iframe and serving iframe Tool moves before creating a destination or changing membership**, with a stable random character over the Window content area. Doors remain minimized while waiting. Show “moving this iframe will trigger a refresh and reopen at its saved URL, possibly losing page state or returning to an earlier page”; the prompted character confirms, anything else cancels. Saved URLs are last-known URLs, not necessarily the page's current location. CLI consent follows `docs/specs/dor-cli.md` → dor move.
- **Must refuse dirty Tools, pending Tool approval, browser startup, closing Surfaces/Workspaces and helper promotion**, rechecking after consent and asynchronous preparation. Dirty/pending refusals cannot be bypassed by iframe consent.
- **Must follow a GUI move into destination passthrough** (acknowledgement: `docs/specs/alert.md` → Workspace union); CLI focus policy follows `docs/specs/dor-cli.md` → dor move. Remove a source with no Panes or Doors; if Doors remain but no pane does, refill normally.
- **Must prepare before departure and roll back failed adoption**, restoring layout, Doors, parked state, selection, zoom, metadata and refs. Ref allocation belongs to `docs/specs/dor-cli.md` → Handle Model; coordinated durable publication belongs to `docs/specs/transport.md` → Persisted session types; Activity follows `docs/specs/alert.md` → Workspace union.

Source of truth: `moveSurface` in `lib/src/components/wall/surface-move.ts`; `surfaceWorkspaceDrag` in `lib/src/components/wall/surface-workspace-drag.ts`; `MoveWorkspaceAction` in `lib/src/components/wall/MoveWorkspaceAction.tsx`; `prepareSurfaceMove` / `adoptSurfaceMove` in `lib/src/components/Wall.tsx`. Tests: `lib/src/components/WorkspaceWindow.test.tsx`, `lib/src/components/wall/LathHost.test.tsx`.

### Workspace lifecycle

Each Wall renders one Workspace's Content and Baseboard (doors). Standalone mounts one Wall **per Workspace**; VS Code and the website playground mount a bare Wall with no Workspace id, which behaves exactly as a single-Workspace Window (VS Code's per-webview mapping is `docs/specs/vscode.md`).
Expand Down Expand Up @@ -565,7 +578,7 @@ Source of truth: `TerminalPane` in `lib/src/components/TerminalPane.tsx`; `Termi

A newly added leaf grows in from the boundary it was placed against; `docs/specs/tiling-engine.md` → "Animation" → Enter owns the hint and its precedence.

Shell-selection replacement shows a short fixed-position notice over the resulting pane, fading in/out over 1500ms via `.shell-spawn-notice`, suppressed to a static render under reduced motion.
Shell-selection replacement shows a fixed-position notice over the resulting pane, fading in/out over 1500ms via `.shell-spawn-notice`, suppressed to a static render under reduced motion. Surface moves reuse it in alternate-screen programs (`docs/specs/dor-cli.md` → Handle Model).

### Kill (two-phase fade + tween reclaim)

Expand Down
2 changes: 2 additions & 0 deletions docs/specs/shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ Mirrored workbench chords — the terminal still receives the key too; [vscode.m
| `⌘⇧P` / `Ctrl+Shift+P`, or `F1` (unmodified) | `workbench.action.showCommands` |
| `⌘B` / `Ctrl+B` | `workbench.action.toggleSidebarVisibility` |

Surface moves have no command-mode binding; see `docs/specs/layout.md` → Moving Surfaces between Workspaces.

The standalone host contributes no chords; `docs/specs/standalone.md` owns its native-menu contract.

## Implementation references
Expand Down
2 changes: 2 additions & 0 deletions docs/specs/terminal-context.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Source of truth: `context` in `standalone/sidecar/pty-core.js`; `terminalContext

Source of truth: `TerminalContextView` in `lib/src/components/wall/TerminalContextView.tsx`; `lib/src/stories/TerminalContext.stories.tsx` supplies sample output; `lib/src/stories/Wall.stories.tsx` exercises the live helper. `lib/src/stories/HelperPlacement.stories.tsx` checks rendered placement and real xterm input/focus retention; the gallery checks narrow controls and always-visible details. `visualSnapshot` in `lib/.storybook/preview.ts` suppresses scrollbar paint.

The Window-host workspace picker follows `docs/specs/layout.md` → Moving Surfaces between Workspaces.

## Tool context

**Must show a Tool's primary Session in Terminal Context instead of creating an auxiliary helper.** Reuse the title, directory, port, and alert presentation, showing Tool command status without helper Modify, Reset, or Promote controls; a preview slot's adds Keep open (`docs/specs/layout.md` → Pane header). Pending approval cannot open context.
Expand Down
Loading
Loading