Skip to content

feat(desktop): add background preset launch mode - #5988

Closed
MikeMcQuaid wants to merge 1 commit into
ParadevAI:mainfrom
MikeMcQuaid:bg-terminal-presets
Closed

MikeMcQuaid wants to merge 1 commit into
ParadevAI:mainfrom
MikeMcQuaid:bg-terminal-presets

Conversation

@MikeMcQuaid

@MikeMcQuaid MikeMcQuaid commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

What & why

Presets that launch GUI tools (e.g. fork ., zed .) opened a foreground
terminal tab that stole focus from the CLI you were working in, needed a
manual ; exit to close themselves and showed the generic terminal glyph
in the presets bar instead of the app's icon.

For v2 workspaces this PR adds:

  • A new background execution mode: commands run in a pane-less
    host-service session with ; exit appended, so nothing opens in the
    foreground, focus stays put and the terminal exits and closes itself
    when the run finishes. While running, the session sits behind the
    existing background-terminals button (adopt or kill from there) and is
    marked so session auto-adoption leaves it alone. The preset editor
    offers the mode as a "Background" segment (single command) or "In the
    background" select entry (grouped commands); the v1 editor does not
    offer it and v1 degrades legacy data to the default new-tab behaviour.
  • A failure toast: useV2PresetExecution listens to terminal:lifecycle
    and toasts the preset name and exit code when a background run exits
    non-zero. Kills arrive as signal exits or dispose broadcasts with code
    0, so they stay silent.
  • Real app icons for GUI-tool presets: a new external.getCommandAppIcons
    procedure resolves the preset's executable via login-shell which,
    follows symlinks to the containing .app bundle and returns
    app.getFileIcon as a cached data URI. The presets bar, its manage
    dropdown and the settings rows fall back to it, so fork . shows
    Fork's icon and zed . shows Zed's. Agent icons (Claude, Codex) keep
    precedence and non-app commands keep the terminal glyph.

How I tested it

  • bun test in apps/desktop: 2296 pass; the 3 failures
    (shell-wrappers, shell-env git.test.ts) also fail on the base
    commit in this sandbox. New unit cases cover normalizeExecutionMode,
    getPresetLaunchPlan, buildBackgroundTerminalCommand,
    getPresetModeLabel and getLaunchModeValue.
  • bun run typecheck --filter=@superset/desktop --filter=@superset/local-db
    and bun run lint pass.
  • Not verified in a running app as don't know how to test locally. May be worth a
    quick visual check that Fork/Zed presets pick up their bundle icons and
    that the background-terminals button shows the session while running
    and clears once it exits.

Checklist

  • PR title follows conventional commits (type(scope): subject)
  • bun run lint and bun run typecheck pass (CI fails on lint warnings too)
  • "Allow edits from maintainers" is checked on fork PRs

Open in Stage

Summary by cubic

Adds a v2-only “background” launch mode for presets so GUI-tool commands run without opening a tab or stealing focus, and adds macOS app‑bundle icons for GUI‑tool presets like fork . and zed .. Background sessions auto‑close and show a failure toast on non‑zero exit.

  • New Features

    • Background execution: pane‑less host session behind the background‑terminals button; appends “; exit” so it closes when done; not auto‑adopted; always uses the background plan regardless of target. The v2 editor offers “Background”/“In the background”; v1 hides it and normalizes to standard tab modes.
    • Failure feedback: listens to terminal:lifecycle exits; non‑zero exits from background runs toast the preset name and code; signal kills stay silent.
    • App icons for GUI tools: external.getCommandAppIcons resolves .app bundle icons via which + Electron app.getFileIcon, caching data URIs. The presets bar (items and manage menu) and settings rows fall back to these when no agent icon matches; non‑app, path‑based, or conflicting commands keep the terminal glyph.
  • Bug Fixes

    • Opening a new terminal tab still creates a blank tab when all apply‑on‑new‑tab presets are background.

Written for commit 5a65e25. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added a Background launch mode for terminal presets, allowing commands to run without opening a terminal pane.
    • Added status updates and error notifications for background command execution.
    • Added macOS application icons for command-based presets in preset bars and terminal settings.
    • Added clearer launch-mode settings and guidance for background execution.
  • Bug Fixes

    • Improved handling and persistence of background presets, including mixed or invalid commands.
    • Improved command icon resolution and fallback behavior.

@ghost

ghost commented Jul 27, 2026

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Jul 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds background terminal preset support with editor, launch, and lifecycle handling. It also adds macOS command app-bundle icon lookup, exposes it through tRPC, and uses the result as a preset icon fallback.

Changes

Preset execution and command app icons

Layer / File(s) Summary
Background mode contracts and editor controls
packages/local-db/src/schema/zod.ts, apps/desktop/src/renderer/routes/_authenticated/providers/.../schema.ts, apps/desktop/src/renderer/routes/_authenticated/settings/terminal/..., apps/desktop/test-setup.ts, apps/desktop/src/lib/trpc/routers/settings/preset-execution-mode.test.ts
The execution-mode schema, normalizers, editor controls, preset row labels, and related tests accept and preserve "background".
Background command execution and terminal lifecycle
apps/desktop/src/renderer/stores/tabs/preset-launch.ts, apps/desktop/src/renderer/stores/tabs/preset-launch.test.ts, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/.../useV2PresetExecution.ts, .../useWorkspacePaneOpeners.ts
Background presets build chained commands ending in exit, create background terminals without panes, invalidate session caches, report failed exits, and keep preset execution moving after a blank tab is created.
Command app-icon resolution and preset rendering
apps/desktop/src/lib/trpc/routers/external/*, apps/desktop/src/renderer/hooks/useCommandAppIcons/*, apps/desktop/src/renderer/lib/preset-icon-key.ts, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/.../V2PresetsBar*, apps/desktop/src/renderer/routes/_authenticated/settings/terminal/.../PresetRow*
A cached macOS app-bundle icon resolver and tRPC query provide executable icons, which are queried and used as fallbacks in preset bars and settings rows.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title uses conventional commit format and clearly identifies the primary change: adding background preset launch mode.
Description check ✅ Passed The description explains the changes, testing results, known base failures, and checklist status with sufficient detail.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/renderer/lib/preset-icon-key.ts`:
- Around line 98-105: Update resolvePresetCommandExecutable and its command-name
extraction so path-based commands return undefined, while bare executable
commands preserve their original parsed casing. Do not reuse getExecutableName,
since it lowercases values and strips paths; ensure singleValue still returns
undefined when commands resolve to conflicting executables.

In `@packages/local-db/src/schema/zod.ts`:
- Line 83: Keep background v2-only: in packages/local-db/src/schema/zod.ts lines
83 and 93-94, separate v2 modes from EXECUTION_MODES and normalize background to
new-tab for v1. In
apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/PresetsSection.tsx
lines 14 and 384-387, use v1-compatible normalization and ensure the dialog
receives only a mode supported by its options. Update
apps/desktop/src/lib/trpc/routers/settings/preset-execution-mode.test.ts lines
49, 58, and 134 to remove background from v1 fixtures, expect fallback to
new-tab, and no longer treat background as normalized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: deae4399-523b-430a-a269-6bcec20fd93b

📥 Commits

Reviewing files that changed from the base of the PR and between 97e0446 and ce13806.

📒 Files selected for processing (22)
  • apps/desktop/src/lib/trpc/routers/external/app-icon.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/lib/trpc/routers/settings/preset-execution-mode.test.ts
  • apps/desktop/src/renderer/hooks/useCommandAppIcons/index.ts
  • apps/desktop/src/renderer/hooks/useCommandAppIcons/useCommandAppIcons.ts
  • apps/desktop/src/renderer/lib/preset-icon-key.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/V2PresetsBar/V2PresetsBar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/V2PresetsBar/components/V2PresetBarItem/V2PresetBarItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useWorkspacePaneOpeners/useWorkspacePaneOpeners.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetRow/PresetRow.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetRow/PresetRow.utils.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetRow/PresetRow.utils.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/PresetsSection.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/components/PresetEditorDialog/PresetEditorDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/components/PresetsTable/PresetsTable.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/V2PresetsSection/V2PresetsSection.tsx
  • apps/desktop/src/renderer/stores/tabs/preset-launch.test.ts
  • apps/desktop/src/renderer/stores/tabs/preset-launch.ts
  • apps/desktop/test-setup.ts
  • packages/local-db/src/schema/zod.ts

Comment thread packages/local-db/src/schema/zod.ts Resolved
@MikeMcQuaid
MikeMcQuaid force-pushed the bg-terminal-presets branch from ce13806 to 625cbd8 Compare August 1, 2026 07:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/V2PresetsSection/V2PresetsSection.tsx (1)

295-314: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not update ambiguous legacy preset snapshots.

Line 304 treats updated.presetId as a linked agent identity. The migration at Lines 267-285 correctly skips this case when multiple agent configs share that presetId. Saving either matching agent can overwrite the same legacy row's fallback command. A later launch without loaded agent config can run the wrong command.

Only sync an exact agentId match, or apply the same unique-match check before updating a legacy row.

Proposed fix
+			const matchingLegacyAgents = agents.filter(
+				(agent) => agent.presetId === updated.presetId,
+			);
 			for (const preset of serverPresetsRef.current) {
 				const row = preset as V2TerminalPresetRow;
-				if (row.agentId !== updated.id && row.agentId !== updated.presetId) {
+				const isUniqueLegacyLink =
+					row.agentId === updated.presetId &&
+					matchingLegacyAgents.length === 1;
+				if (row.agentId !== updated.id && !isUniqueLegacyLink) {
 					continue;
 				}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/V2PresetsSection/V2PresetsSection.tsx`
around lines 295 - 314, Update syncLinkedPresetSnapshots so legacy preset rows
are not synchronized through ambiguous presetId matches: only use an exact
row.agentId-to-updated.id match, or first verify that the presetId identifies a
unique agent configuration using the same check as the migration logic. Preserve
synchronization for unambiguous linked presets and avoid overwriting shared
legacy rows.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/lib/trpc/routers/external/app-icon.ts`:
- Around line 55-58: Update the getFileIcon call in the app icon retrieval flow
to use the macOS-supported normal size or omit the size option, while preserving
the existing empty-icon null handling and data URL return behavior.
- Around line 22-29: Update resolveExecutablePath to pass a finite timeout
option to execFileAsync when invoking /usr/bin/which, preventing the lookup from
hanging indefinitely. Preserve the existing error handling and null fallback for
timeout or other lookup failures.

---

Outside diff comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/V2PresetsSection/V2PresetsSection.tsx`:
- Around line 295-314: Update syncLinkedPresetSnapshots so legacy preset rows
are not synchronized through ambiguous presetId matches: only use an exact
row.agentId-to-updated.id match, or first verify that the presetId identifies a
unique agent configuration using the same check as the migration logic. Preserve
synchronization for unambiguous linked presets and avoid overwriting shared
legacy rows.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 001ba7aa-d247-4abc-9558-701db5ff7562

📥 Commits

Reviewing files that changed from the base of the PR and between ce13806 and 625cbd8.

📒 Files selected for processing (23)
  • apps/desktop/src/lib/trpc/routers/external/app-icon.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/lib/trpc/routers/settings/preset-execution-mode.test.ts
  • apps/desktop/src/renderer/hooks/useCommandAppIcons/index.ts
  • apps/desktop/src/renderer/hooks/useCommandAppIcons/useCommandAppIcons.ts
  • apps/desktop/src/renderer/lib/preset-icon-key.test.ts
  • apps/desktop/src/renderer/lib/preset-icon-key.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/V2PresetsBar/V2PresetsBar.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/V2PresetsBar/components/V2PresetBarItem/V2PresetBarItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useWorkspacePaneOpeners/useWorkspacePaneOpeners.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetRow/PresetRow.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetRow/PresetRow.utils.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetRow/PresetRow.utils.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/PresetsSection.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/components/PresetEditorDialog/PresetEditorDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/components/PresetsTable/PresetsTable.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/V2PresetsSection/V2PresetsSection.tsx
  • apps/desktop/src/renderer/stores/tabs/preset-launch.test.ts
  • apps/desktop/src/renderer/stores/tabs/preset-launch.ts
  • apps/desktop/test-setup.ts
  • packages/local-db/src/schema/zod.ts
🚧 Files skipped from review as they are similar to previous changes (11)
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetsSection/components/PresetsTable/PresetsTable.tsx
  • apps/desktop/src/lib/trpc/routers/settings/preset-execution-mode.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/terminal/components/TerminalSettings/components/PresetRow/PresetRow.utils.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/providers/CollectionsProvider/dashboardSidebarLocal/schema.ts
  • apps/desktop/src/renderer/stores/tabs/preset-launch.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
  • apps/desktop/src/renderer/hooks/useCommandAppIcons/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/V2PresetsBar/components/V2PresetBarItem/V2PresetBarItem.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/V2PresetsBar/V2PresetsBar.tsx
  • apps/desktop/src/renderer/hooks/useCommandAppIcons/useCommandAppIcons.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/hooks/useV2PresetExecution/useV2PresetExecution.ts

- Presets that launch GUI tools (e.g. `fork .`, `zed .`) stole focus
  and needed a manual `; exit` to close their terminal.
- New v2-only `background` execution mode runs preset commands in a
  pane-less session behind the background-terminals button; an
  appended `; exit` closes it when the run finishes and a non-zero
  exit surfaces as a failure toast via `terminal:lifecycle`.
- Preset bar and settings rows fall back to the macOS app-bundle
  icon for GUI-tool commands instead of the generic terminal glyph.
@MikeMcQuaid
MikeMcQuaid force-pushed the bg-terminal-presets branch from 625cbd8 to 5a65e25 Compare August 5, 2026 16:26
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@MikeMcQuaid

Copy link
Copy Markdown
Contributor Author

@Kitenite @AviPeltz should be ready now!

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