type: runbook
status: active
timestamp: 2026-06-30
tags: [runbook, dev-server, omniroute, freellmapi, fork, windows, startup]

Start dev server from source (OmniRoute, freellmapi, any fleet fork)

Step-by-step: replace global npm install with a local cloned-fork dev server. Auto-start on Windows login, pull upstream on every launch, run via Windows Terminal tab.

Start dev server from source

Generalised procedure for migrating any fleet fork from global package install (npm install -g <pkg> / pipx install <pkg>) to running the dev server out of repos/frk/<name>. Already applied to OmniRoute and freellmapi; the pattern below works for any new fork.

When to use this

Pre-requisites

Procedure

1. Fork the upstream to chirag127

gh repo fork <upstream-org>/<upstream-name> --org chirag127 --clone=false --default-branch-only

If GitHub creates a <name>-1 because <name> was taken by an earlier fork, delete the old one first:

gh api orgs/chirag127/repos --paginate --jq '.[] | select(.name | startswith("<name>")) | "\(.name) | fork=\(.fork) | parent=\(.parent.full_name)"'
gh repo delete chirag127/<duplicate-name> --yes

Verify the canonical fork’s parent matches the desired upstream.

2. Clone into the workspace

git clone https://github.com/chirag127/<name>.git C:\D\oriz\repos\frk\<name>
cd C:\D\oriz\repos\frk\<name>
git remote add upstream https://github.com/<upstream-org>/<upstream-name>.git

3. Identify the dev command + port

Get-Content package.json | Select-String -Pattern '"(dev|start|build)"'

Find the port:

4. Write the start script

Save as C:\D\oriz\scripts\start-<name>-dev.ps1. Template — fill in the bracketed placeholders:

#Requires -Version 5.1
$ErrorActionPreference = 'Continue'
$repo = 'C:\D\oriz\repos\frk\<NAME>'
$psPath = 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe'
$serverPort = <PORT>   # e.g. 20128 for OmniRoute, 3001 for freellmapi

# Idempotency: skip if already running
$listening = Get-NetTCPConnection -LocalPort $serverPort -State Listen -ErrorAction SilentlyContinue
if ($listening) {
    Write-Host "<NAME> already on :$serverPort (PID $($listening[0].OwningProcess))" -ForegroundColor Yellow
    Start-Sleep 3
    exit 0
}

if (-not (Test-Path $repo)) { Write-Host "repo missing"; exit 1 }
Set-Location $repo

# Track lockfile state BEFORE pull (decide if install is needed)
$lockBefore = if (Test-Path '<LOCKFILE>') { (Get-FileHash '<LOCKFILE>' -Algorithm SHA256).Hash } else { '' }
$pkgBefore  = if (Test-Path 'package.json') { (Get-FileHash 'package.json' -Algorithm SHA256).Hash } else { '' }

# Pull upstream
git fetch upstream 2>&1 | Out-Null
git merge --ff-only upstream/main 2>&1 | Out-Null

# Re-hash; install only if changed
$lockAfter = if (Test-Path '<LOCKFILE>') { (Get-FileHash '<LOCKFILE>' -Algorithm SHA256).Hash } else { '' }
$pkgAfter  = if (Test-Path 'package.json') { (Get-FileHash 'package.json' -Algorithm SHA256).Hash } else { '' }
$needsInstall = (-not (Test-Path 'node_modules')) -or ($lockBefore -ne $lockAfter) -or ($pkgBefore -ne $pkgAfter)

# ABSOLUTE PATH — see rules/development/windows-shortcut-absolute-binary-paths
$pm = 'C:\Program Files\nodejs\<PM>.cmd'   # pnpm.cmd OR npm.cmd
$inner = if ($needsInstall) {
    "Write-Host 'Installing...'; & '$pm' install; & '$pm' <DEV-CMD>"
} else {
    "& '$pm' <DEV-CMD>"
}

Start-Process wt -ArgumentList "new-tab --title `"<NAME> Dev`" -d `"$repo`" `"$psPath`" -NoExit -Command `"$inner`""
Write-Host "<NAME> dev launching on http://localhost:$serverPort"
Start-Sleep 3

Replace <NAME>, <PORT>, <LOCKFILE> (pnpm-lock.yaml or package-lock.json), <PM> (pnpm or npm), <DEV-CMD> (dev or run dev).

5. Create the startup shortcut

$startupDir = [System.Environment]::GetFolderPath('Startup')
$shortcutPath = Join-Path $startupDir "<NAME> Dev.lnk"
$scriptPath = "C:\D\oriz\scripts\start-<name>-dev.ps1"

$wsh = New-Object -ComObject WScript.Shell
$lnk = $wsh.CreateShortcut($shortcutPath)
$lnk.TargetPath = "powershell.exe"
$lnk.Arguments = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$scriptPath`""
$lnk.WorkingDirectory = "C:\D\oriz"
$lnk.IconLocation = "powershell.exe,0"
$lnk.Description = "Auto-pull and start <NAME> dev server"
$lnk.Save()

6. Optional: desktop shortcut for manual trigger

$desktop = [System.Environment]::GetFolderPath('Desktop')
Copy-Item $shortcutPath (Join-Path $desktop "<NAME> Dev.lnk") -Force

7. First-time install + sanity test

& "C:\D\oriz\scripts\start-<name>-dev.ps1"

A new Windows Terminal tab should appear, run pnpm install / npm install (5-8 min one-time), then start the dev server. Visit http://localhost:<PORT> to confirm.

8. Stop the old global install

# Free the port if the old npm-installed version is still running
Get-NetTCPConnection -LocalPort <PORT> -State Listen | ForEach-Object {
    Stop-Process -Id $_.OwningProcess -Force
}
# Optionally uninstall the global
npm uninstall -g <pkg-name>

Currently applied to

Reverting (back to global install)

# Remove the startup + desktop shortcuts
Remove-Item "$([Environment]::GetFolderPath('Startup'))\<NAME> Dev.lnk"
Remove-Item "$([Environment]::GetFolderPath('Desktop'))\<NAME> Dev.lnk"

# Stop the dev server
Get-NetTCPConnection -LocalPort <PORT> -State Listen | ForEach-Object {
    Stop-Process -Id $_.OwningProcess -Force
}

# Reinstall the global
npm install -g <pkg-name>

The fork at repos/frk/<name> can stay — it’s just no longer auto-started.

Common gotchas

See also


Edit on GitHub · Back to index