Skip to content

Update dev-servers extension#28419

Open
tavlean wants to merge 3 commits into
raycast:mainfrom
tavlean:ext/dev-servers
Open

Update dev-servers extension#28419
tavlean wants to merge 3 commits into
raycast:mainfrom
tavlean:ext/dev-servers

Conversation

@tavlean
Copy link
Copy Markdown
Contributor

@tavlean tavlean commented May 29, 2026

Adds a Start Dev Server command for spinning up dev servers without leaving Raycast. Works from a Finder selection, from a list of recently-seen projects, or from a native folder picker.

Start Dev Server

  • From Finder: select a project folder (or any file inside one) and run Start Dev Server. The extension walks up to the nearest package.json, detects the package manager (npm / pnpm / yarn / bun), picks the right script, and spawns it with the same PATH-aware login-shell pattern used by Restart. The dashboard opens immediately and shows a "Starting…" toast that transitions to "X is running" the moment the server binds a port.
  • From recents: run the command with nothing selected in Finder and you get a picker over the projects the extension has seen running recently. Recents auto-populate from the dashboard's polling loop, with no explicit bookmarking. LRU-bounded at 30 entries. Running projects are hidden from this list (they live in the dashboard); they reappear once stopped.
  • From anywhere: the picker also exposes a Choose Folder… entry that opens the native macOS folder dialog directly, with no intermediate screen.
  • From the dashboard: the empty state offers a primary Start Dev Server action (just press from a fresh dashboard to land in the picker). Each running-server row's action panel also carries Start Dev Server (⌘N), so spinning up another project never requires bouncing back to root search.
  • Each picker row shows last-seen, git branch when applicable, and a framework tag inferred from package.json dependencies. Cached favicons appear inline once the dashboard has seen the project running, so even stopped projects keep their real icon. Per-row actions: Start, Open in Terminal (⌘T), Show in Finder (⌘⇧F), Copy Path (⌘C), Remove from Recents (⌃X).
  • Folders that no longer exist on disk are hidden this render but kept in storage so they reappear when (for example) an external drive remounts.
  • Startup logs: every spawned server's stdout+stderr is captured to a per-project log. If a server doesn't bind a port within 15s, the toast escalates to a failure with a View Startup Log action instead of silently disappearing, so a misconfigured or custom setup (e.g. portless needing sudo, a missing binary, a crashing build) is diagnosable from inside Raycast. Every running-server row also carries a View Startup Log action (⌘L) for inspecting output on demand.

Behavior

  • Script picker tries devstartdevelop first, then scans script values for known dev-server tools (Vite, Next, Astro, Nuxt, Webpack, Parcel, Gatsby, Remix, Turbo, Bun watch/hot, nodemon, tsx watch, ts-node-dev, serve, http-server, live-server). Monorepo conventions like dev:web and start:dev resolve out of the box.
  • Already running on that folder? You get one consolidated alert: X is already running. Restart? for a single target, All 3 already running. Restart them? when every selected folder is running, or 2 of 3 already running. Restart these, then start the other one? for the mixed case. No more N-alert cascades for N-folder selections.
  • The Finder selection is only honored when Finder is the frontmost app. Previously a folder selected earlier (to start one server) lingered in Finder's selection, so running the command later from another app, e.g. the browser, would silently treat that stale folder as the target and surface a spurious already running. Restart?. Now, unless you're actually in Finder, the command goes straight to the recents picker, where you can start whatever project you meant.
  • After a server is started (from Finder, the picker, or a recent), the dashboard moves the selection onto that new row, so pressing acts on the server you just launched rather than re-opening whatever was previously selected. Restart (⌘⇧R) likewise re-focuses the replacement once it binds.
  • Multi-folder selection prompts for confirmation by default, useful for monorepo siblings or a "frontend + backend" startup, with an opt-out preference for users who do this regularly.
  • New Open in browser when the port binds preference auto-opens the URL once the new server starts listening. Off by default; a one-time hint surfaces it in the in-flight toast for the first few starts.

Under the hood

  • The dashboard is the controller for the entire spawn flow. The launching command resolves a target list and hands off via launchContext, which lets the user land on the dashboard immediately and watch the spawn happen there, rather than waiting on a blank loading view for a pre-spawn fetchServers call.
  • Spawn lifecycle is a clean state machine on the dashboard: idle → pending → confirming → spawning → done. The "Starting…" toast lives on the dashboard so it's visible the whole time the user is waiting, and transitions to a green "running" state the moment every expected cwd appears in the polling loop.
  • All filesystem paths flow through canonicalCwd (a realpathSync wrapper) so symlinked project paths compare equal between Finder selections, the recents store, and lsof's view of running processes.
  • Extracted startDevServer(cwd) and killServer(pid) so the new command and the existing restart flow share one spawn path. Restart is now killServer + startDevServer.
  • The spawn passes the package manager and chosen script as separate arguments rather than building a shell string, so projects with unusual script names (spaces, punctuation) start reliably and the launch surface stays free of shell-interpolation surprises.
  • Shared tool-display.ts so the framework tag styling stays consistent across the dashboard and the picker.
  • Favicons cached onto recents for stopped-project icons are size-capped, keeping the recents store small; the live dashboard always renders the real favicon regardless.

Preferences

  • Terminal App is now a single shared preference that applies to both Dev Servers and Start Dev Server: set the terminal ⌘T opens once, and both commands honor it.

Checklist

- fix(start): focus new server and ignore stale Finder selection
- fix(dashboard): stop render-loop warning and fix Cmd+N hijacking a spawn
- style: normalize dash formatting in docs, comments, and UI strings
- docs: document Start Dev Server in README; sync changelog
- refactor: shared Terminal App preference + dashboard/start polish
- perf(recents): cap the favicon data URI persisted per project
- fix(start): harden spawn by passing the dev script as an argv
- feat(dashboard): surface startup logs when a server fails to start
- fix(dashboard): dedupe fetchServers result to avoid wasted re-renders
- docs: changelog — empty-state action, ⌘N row action, native folder picker
- feat(start): replace ChooseFolderForm with native osascript folder picker
- feat(dashboard): surface Start Dev Server from empty state and every row
- chore: post-review cleanup
- docs: changelog entry for Start Dev Server release
- feat: add Start Dev Server command
- refactor(dashboard): own the spawn flow via launchContext state machine
- chore: extract shared helpers for the upcoming spawn flow
- Changelog formatting
- Pull contributions
@raycastbot raycastbot added extension fix / improvement Label for PRs with extension's fix improvements extension: dev-servers Issues related to the dev-servers extension platform: macOS OP is author The OP of the PR is the author of the extension labels May 29, 2026
@raycastbot
Copy link
Copy Markdown
Collaborator

Thank you for the update! 🎉

We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days.

@tavlean tavlean marked this pull request as ready for review May 29, 2026 14:52
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 29, 2026

Greptile Summary

This PR adds a full Start Dev Server command to the dev-servers extension: Finder-selection probe (gated on Finder being frontmost), a recents picker backed by a new LRU store (recents.ts), and a native folder dialog via osascript. The dashboard gains a launchContext-driven spawn state machine (idle → pending → confirming → spawning → done), a 15 s startup-log escalation path, controlled cursor focus on newly spawned servers, and the shared tool-display.ts module.

  • servers.ts is refactored: restartServer is decomposed into killServer + startDevServer; pickDevScript scans package.json scripts with a value-side regexp heuristic; findProjectRoot, canonicalCwd, and spawnLogPath are extracted as shared helpers; spawn now passes package-manager and script as positional args to avoid shell-interpolation surprises; fd cleanup on spawn/error is added.
  • recents.ts introduces a recordSeenBatch read-modify-write store with LRU eviction, removeRecent (reads fresh before filtering to avoid clobbering concurrent dashboard writes), and updateRecentFavicon with a per-entry size cap.
  • package.json moves terminalApp to extension-level so both commands share a single preference, and adds autoOpenInBrowser and confirmMultiStart command-level prefs for the new command.

Confidence Score: 5/5

Safe to merge. The spawn state machine, recents store, and Finder-probe gating are all well-reasoned; error paths are handled throughout.

The code is structurally sound: the state machine transitions are correct, the 15 s timeout properly cleans up after the success path, positional-arg spawn prevents shell injection, removeRecent reads fresh from storage before filtering to avoid clobbering concurrent dashboard writes, and fd cleanup on spawn/error prevents descriptor leaks. The only finding is a minor UX edge case where the auto-open hint counter can advance on cancelled spawns.

No files require special attention; the one observation is in start.tsx's launchSpawn around hint-counter timing.

Important Files Changed

Filename Overview
extensions/dev-servers/src/servers.ts Refactored restart into killServer + startDevServer; added pickDevScript, findProjectRoot, canonicalCwd, and spawnLogPath; improved spawn fd cleanup and injection safety via positional args; extended SvelteKit detection to .mjs/.cjs configs.
extensions/dev-servers/src/index.tsx Adds the spawn state machine (idle→pending→confirming→spawning→done), fetchStableServers dedup, controlled selection, recents recording, SpawnLogView, and openStartCommand; restart extended to move cursor onto replacement server.
extensions/dev-servers/src/start.tsx New Start Dev Server command: Finder-selection probe (frontmost-app gated), recents picker, native folder dialog via osascript, and launchSpawn hand-off to the dashboard.
extensions/dev-servers/src/recents.ts New LRU recents store (max 30): recordSeenBatch, removeRecent (reads-fresh-then-writes pattern to avoid stale overwrite), and updateRecentFavicon with a size cap.
extensions/dev-servers/src/tool-display.ts Extracted toolLabel/toolColor from index.tsx into a shared module so both the dashboard and the new picker use the same framework tag styling.
extensions/dev-servers/package.json Adds start command entry; moves terminalApp to extension-level shared preference; adds autoOpenInBrowser and confirmMultiStart command preferences.
extensions/dev-servers/src/constants.ts New file extracting DEFAULT_TERMINAL constant so the terminal fallback is shared between the two commands and can't drift.
extensions/dev-servers/src/types.ts Minor punctuation fix in a comment; no functional changes.
extensions/dev-servers/CHANGELOG.md New entry at the top with {PR_MERGE_DATE} placeholder; previous entry renamed and reformatted with proper markdown headings.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
extensions/dev-servers/src/start.tsx:121-128
The auto-open hint counter is incremented inside `launchSpawn` before the dashboard ever shows its confirmation dialogs. If the user cancels at the "already running — restart?" prompt (or at the multi-folder confirm), the toast that would display the CTA is never created, but the counter has already advanced. After three cancelled spawns the hint is silently exhausted without the user having seen it once.

```suggestion
async function launchSpawn(
  targets: Array<{ cwd: string; name: string }>,
  options: { autoOpen: boolean; confirmMulti: boolean },
): Promise<void> {
  // Consume the hint only after the launch has been handed off, so a
  // cancelled confirm in the dashboard doesn't silently exhaust the counter
  // before the user has ever seen the CTA.
  const showAutoOpenHint = !options.autoOpen && (await maybeConsumeAutoOpenHint());
  try {
    await launchCommand({
```

Reviews (3): Last reviewed commit: "Update dev-servers extension" | Re-trigger Greptile

Comment thread extensions/dev-servers/src/index.tsx
- fix(servers): close log fd after child spawns to prevent descriptor leak
- fix(dashboard): exclude failed spawns from the expecting set
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extension: dev-servers Issues related to the dev-servers extension extension fix / improvement Label for PRs with extension's fix improvements OP is author The OP of the PR is the author of the extension platform: macOS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants