Created
May 13, 2026 12:35
-
-
Save sulco/227f144feb7ebac6da2a4d9d33a3e7ab to your computer and use it in GitHub Desktop.
npm run dev script for macos
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # @raycast.schemaVersion 1 | |
| # @raycast.title Run npm dev (Finder selection) | |
| # @raycast.mode compact | |
| # @raycast.icon π | |
| # @raycast.packageName Developer | |
| # @raycast.description Open iTerm2 in the folder currently selected in Finder and run `npm run dev` (falls back to `npm start`). | |
| set -euo pipefail | |
| # 1. Resolve target folder. | |
| # - If $1 is provided (e.g. from a Finder Quick Action), use it. | |
| # - Else query Finder: selected folder, parent of selected file, or front window's target. | |
| if [ $# -ge 1 ] && [ -n "$1" ]; then | |
| folder="$1" | |
| else | |
| folder=$(osascript <<'APPLESCRIPT' | |
| tell application "Finder" | |
| set sel to selection as list | |
| if (count of sel) is greater than 0 then | |
| set theItem to item 1 of sel | |
| set itemClass to class of theItem | |
| if itemClass is folder or itemClass is disk then | |
| return POSIX path of (theItem as alias) | |
| else | |
| return POSIX path of ((container of theItem) as alias) | |
| end if | |
| end if | |
| try | |
| set theTarget to (target of front Finder window) as alias | |
| return POSIX path of theTarget | |
| on error | |
| return "" | |
| end try | |
| end tell | |
| APPLESCRIPT | |
| ) | |
| fi | |
| # Strip any trailing slash for cleaner paths. | |
| folder="${folder%/}" | |
| if [ -z "$folder" ]; then | |
| echo "No folder selected in Finder." | |
| exit 1 | |
| fi | |
| if [ ! -f "$folder/package.json" ]; then | |
| echo "No package.json in $folder" | |
| exit 1 | |
| fi | |
| # 2. Pick the npm script: prefer "dev", fall back to "start", otherwise fail. | |
| # Parsing via node avoids brittle grep on package.json. | |
| script_name=$(NODE_PATH= node -e ' | |
| const path = require("path"); | |
| const pkg = require(path.join(process.argv[1], "package.json")); | |
| const s = pkg.scripts || {}; | |
| if (s.dev) console.log("dev"); | |
| else if (s.start) console.log("start"); | |
| ' "$folder" 2>/dev/null || true) | |
| if [ -z "$script_name" ]; then | |
| echo "Neither 'dev' nor 'start' script found in $folder/package.json" | |
| exit 1 | |
| fi | |
| # 3. Open a new iTerm2 window, cd into the folder, and run the script. | |
| # Escape backslashes and double quotes for safe AppleScript string interpolation. | |
| esc_folder=$(printf '%s' "$folder" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g') | |
| osascript <<APPLESCRIPT | |
| tell application "iTerm" | |
| activate | |
| set newWindow to (create window with default profile) | |
| tell current session of newWindow | |
| write text "cd \"$esc_folder\" && npm run $script_name" | |
| end tell | |
| end tell | |
| APPLESCRIPT | |
| echo "Started npm run $script_name in $folder" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
run-npm-dev.shA small bash script that opens a new iTerm2 window in a given project folder and runs its dev server. Designed to be
triggered two ways: from Raycast (keyboard) or from Finder right-click β Quick Actions (mouse).
What it does
Given a folder (passed as an argument, or resolved from the current Finder selection):
package.json.dev, falls back tostart, errors out if neither exists.cds into the folder, and runsnpm run <script>.Selection resolution when no argument is passed:
Each invocation opens a new iTerm2 window so multiple projects don't fight over a single tab.
Requirements
npmavailable in your iTerm2 login shell (nvm, Homebrew, Volta, whatever β it just needs to work when you open anew iTerm2 window and type
npm)Install
~/raycast-scripts/run-npm-dev.sh.chmod +x ~/raycast-scripts/run-npm-dev.shApprove both (System Settings β Privacy & Security β Automation).
Use it from Raycast (keyboard)
The script is already a valid Raycast Script Command β the
@raycast.*directives are in the header.β,β Extensions β Script Commands β + under "Script Directories" β pick the foldercontaining the script (e.g.
~/raycast-scripts).Use it from Finder right-click (Quick Action)
Create a one-step Quick Action that calls the script with the selected folder:
foldersFinder.app/bin/zshΒ (important β see "Gotchas" below)as argumentsIt now lives at
~/Library/Services/Run npm dev.workflowand appears under right-click β Quick Actions β Runnpm dev.
Optional hotkey: System Settings β Keyboard β Keyboard Shortcuts β Services β Files and Folders β assign a shortcut to
Run npm dev.
Gotchas
/bin/zsh, not/bin/bash, in the Automator step. Automator's/bin/bashruns withPATH=/usr/bin:/binand doesn't source any init files, so nvm-managed
node/npmwill be invisible inside the script./bin/zshpicksup
~/.zshenv/~/.zshrcand restores your realPATH. Symptom if you get this wrong: Automator pops up an errordialog with an empty message (
"").Finder and iTerm the first time. If you accidentally deny, re-enable in System Settings β Privacy & Security β
Automation.
grep, notnode/jq. This is intentional so the script works in stripped-PATHcontexts (Quick Actions, login items, cron, etc.) without needing a node toolchain on
PATH.Customising
osascriptblock. Equivalents for Terminal.app, Ghostty, Warp, etc. areshort β search for "AppleScript open new window run command ".
grep -qElines β e.g. add a check for"start:dev"before"dev", or swap the fallback.npm install &&beforenpm runin thewrite textline.