Skip to content

🤖 feat: add init + delete in-flight feedback in sidebar#2199

Open
ethanndickson wants to merge 15 commits intomainfrom
workspace-init-gvxt
Open

🤖 feat: add init + delete in-flight feedback in sidebar#2199
ethanndickson wants to merge 15 commits intomainfrom
workspace-init-gvxt

Conversation

@ethanndickson
Copy link
Member

@ethanndickson ethanndickson commented Feb 6, 2026

Summary

Improves workspace lifecycle UX and safety in the left sidebar: initialization and removal states are now visible, cancellation semantics are tightened, and Coder workspace deletion is hardened.

Background

Several workspace lifecycle gaps affected UX and safety:

  • No visual feedback during workspace initialization or removal in the sidebar
  • Canceling a Coder workspace that never actually materialized server-side caused a ~60s "deleting…" wait
  • The allowNonMuxPrefix escape hatch weakened the safety guard against deleting non-mux Coder workspaces
  • Redundant status: "creating" field duplicated the isInitializing signal

Implementation

Sidebar lifecycle feedback

  • WorkspaceListItem shows "starting…" / "deleting…" / "archiving…" states with muted styling
  • Removing/archiving workspaces are non-interactive; initializing workspaces remain selectable

Coder deletion safety

  • Removed allowNonMuxPrefix entirely — the mux- prefix guard is now absolute with no bypass
  • Mux-created workspaces always use mux-${branch} (set in CoderSSHRuntime.finalizeConfig())

Cancel-creation fast path (waitForExistenceTimeoutMs)

  • New waitForExistenceTimeoutMs option on deleteWorkspaceEventually()
  • When canceling creation, if the Coder workspace never appears within 10s (vs the full 60s timeout), treat it as success and return early
  • Trades a small risk of leaking a late-appearing workspace for much faster cancel UX

Cleanup

  • Removed redundant WorkspaceMetadata.status: "creating" field; isInitializing is the single canonical signal
  • Simplified getWorkspaceSidebarKey() to use only isInitializing

Validation

  • make static-check passes (typecheck, lint, fmt, docs links)
  • bun test src/node/services/coderService.test.ts — 68 tests pass (includes new waitForExistenceTimeoutMs short-circuit test)
  • bun test src/node/runtime/CoderSSHRuntime.test.ts — 32 tests pass

Risks

Low. The waitForExistenceTimeoutMs trades a small risk of orphaning a late-appearing Coder workspace for faster cancel UX. The 10s window is generous for detecting server-side creates that complete after CLI abort.


Generated with mux • Model: anthropic:claude-opus-4-6 • Thinking: xhigh • Cost: $173.31

P0 hardening for init cancellation:
- RemoteRuntime: pass explicit SIGTERM to SSH2 kill() (required for remote signal)
- RemoteRuntime: clean up abort listener when process exits
- DisposableProcess: treat pid <= 0 like missing pid (SSH2 shims use pid=0)
- WorkspaceListItem: add type=button and stopKeyboardPropagation to action buttons
- Integration test: increase timeouts, stop collector before removal, add stronger assertions
Remove dead metadata.status === "creating" fallbacks and rely on FrontendWorkspaceMetadata.isInitializing instead.

Also remove the unused WorkspaceMetadata.status field from the schema and update UI/tests that referenced it.

---

_Generated with `mux` • Model: `openai:gpt-5.2` • Thinking: `medium` • Cost: `$40.91`_

<!-- mux-attribution: model=openai:gpt-5.2 thinking=medium costs=40.91 -->
- Make cancel-creation affordance match other delete/archive buttons (hover-only trash icon) and keep row hover styles during initialization.
- Optimistically drop workspace metadata on remove so cancelled workspaces disappear immediately.
- Add CoderService.deleteWorkspaceEventually to retry `coder delete` across transitional states and avoid not_found races during cancel-init.
- Update Coder runtime + unit tests accordingly.

---

_Generated with `mux` • Model: `openai:gpt-5.2` • Thinking: `medium` • Cost: `$45.88`_

<!-- mux-attribution: model=openai:gpt-5.2 thinking=medium costs=45.88 -->
- enrichFrontendMetadata now populates status: "creating" when
  isInitializing is true, so the frontend's isCreating check works
- Add missing on/getInitState mocks to all test harnesses that
  construct WorkspaceService (constructor now subscribes to init-end)
Archive should abort init and still archive; update unit tests + lint.
…eoutMs

When canceling a Coder workspace that was never actually created
server-side, the 'deleting…' state previously persisted for the full
60s timeout. The root cause: waitForExistence=true treats initial
not_found as inconclusive and keeps polling until timeout.

Add a new waitForExistenceTimeoutMs option (set to 10s at the
cancel-creation callsite). If only not_found responses are seen within
this shorter window—without ever observing the workspace exist—treat
it as success and return early. The overall 60s timeout still applies
when the workspace has been observed on the server.

This trades a small risk of leaking a late-appearing workspace for
much faster cancel UX (~10s vs ~60s).
@ethanndickson
Copy link
Member Author

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Swish!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

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.

1 participant