fix: make npm run dev work on Windows (#1629)
Some checks are pending
CI / semgrep (push) Waiting to run
macOS Menubar CI / test (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
Tests / vscode (push) Waiting to run
Windows Menubar CI / check (ubuntu-latest) (push) Waiting to run
Windows Menubar CI / check (windows-latest) (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run

npm run dev now works on Windows: the NODE_OPTIONS prefix was POSIX-only, so the script runs node --no-deprecation --import tsx directly.
This commit is contained in:
Uttam Deb 2026-10-09 17:38:06 +06:00 • committed by GitHub
parent a01bf87412
commit 83a18e1308
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 88 additions and 3 deletions

View file

@ -4,7 +4,7 @@ Thanks for your interest. This document covers what you need to know to send a w
## Prerequisites
- Node.js 22.20 or newer (`engines.node` in `package.json`).
- Node.js 22.13.0 or newer (`engines.node` in `package.json`).
- npm 10 or newer (ships with recent Node).
- macOS or Linux for full provider coverage. Windows works for most providers but Cursor / Antigravity development is easier on macOS.
- Optional: Swift 6 toolchain if you are touching the macOS menubar (`mac/`).
@ -18,7 +18,19 @@ cd codeburn
npm install
```
There is no separate build step required to run the dev CLI. `npm run dev` runs `tsx` against `src/cli.ts` directly.
There is no separate build step required to run the dev CLI. `npm run dev` loads
`tsx` through Node's `--import` flag and runs `src/cli.ts` directly. The command
works with npm's default shell on Windows, macOS, and Linux; no shell configuration
or extra environment assignment is required. Deprecation warnings are suppressed
for this invocation, and any existing `NODE_OPTIONS` are retained.
Use `--` to pass CLI arguments through npm. For a quick setup check that does not
scan your session history, run:
```bash
npm run dev -- --version
npm run dev -- status --help
```
## Common Commands

View file

@ -19,7 +19,7 @@
"build:dash": "cd dash && npm ci --no-audit --no-fund --silent && npm run build",
"build:vscode": "npm --prefix vscode run build",
"package:vscode": "npm --prefix vscode run package",
"dev": "NODE_OPTIONS=--no-deprecation tsx src/cli.ts",
"dev": "node --no-deprecation --import tsx src/cli.ts",
"test": "vitest run tests --exclude \"tests/cache-refresh-lock*\"",
"test:locks": "vitest run tests/cache-refresh-lock.test.ts tests/cache-refresh-lock-corrupt-body.test.ts tests/cache-refresh-lock-process.test.ts tests/cache-refresh-lock-status-snapshot.test.ts --poolOptions.forks.singleFork=true",
"test:watch": "vitest tests --exclude \"tests/cache-refresh-lock*\"",

73
tests/dev-command.test.ts Normal file
View file

@ -0,0 +1,73 @@
import { spawnSync } from 'node:child_process'
import { mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { pathToFileURL } from 'node:url'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
const root = process.cwd()
const manifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) as {
version: string
scripts: { dev: string }
}
let fixture: string
function runDev(args: string, extraEnv: NodeJS.ProcessEnv = {}) {
// npm runs scripts through the platform's default shell and adds .bin to
// PATH. Exercise those same semantics, including cmd.exe on Windows.
return spawnSync(`${manifest.scripts.dev} ${args}`, {
cwd: fixture,
shell: true,
encoding: 'utf8',
timeout: 20_000,
env: {
...process.env,
PATH: [dirname(process.execPath), join(fixture, 'node_modules', '.bin'), process.env.PATH].join(process.platform === 'win32' ? ';' : ':'),
...extraEnv,
},
})
}
describe('development CLI command', () => {
beforeAll(() => {
// Both the checkout and executable paths can contain spaces on Windows.
fixture = mkdtempSync(join(tmpdir(), 'codeburn dev command '))
const directoryLink = process.platform === 'win32' ? 'junction' : 'dir'
symlinkSync(join(root, 'src'), join(fixture, 'src'), directoryLink)
symlinkSync(join(root, 'node_modules'), join(fixture, 'node_modules'), directoryLink)
writeFileSync(join(fixture, 'package.json'), '{"type":"module"}\n')
})
afterAll(() => rmSync(fixture, { recursive: true, force: true }))
it('runs --version through the default shell from a checkout path with spaces', () => {
const result = runDev('--version')
expect(result.error).toBeUndefined()
expect(result.status, result.stderr).toBe(0)
expect(result.stdout.trim()).toBe(manifest.version)
})
it('forwards command arguments to the CLI', () => {
const result = runDev('status --help')
expect(result.status, result.stderr).toBe(0)
expect(result.stdout).toContain('Usage: codeburn status')
expect(result.stdout).toContain('--format')
})
it('suppresses deprecation warnings while retaining inherited NODE_OPTIONS', () => {
const preload = join(fixture, 'warning.mjs')
const marker = join(fixture, 'preload-marker')
writeFileSync(preload, [
'import { writeFileSync } from "node:fs"',
`writeFileSync(${JSON.stringify(marker)}, "loaded")`,
'process.emitWarning("dev-command-fixture", "DeprecationWarning")',
].join('\n'))
const result = runDev('--version', {
NODE_OPTIONS: `--import="${pathToFileURL(preload).href}"`,
})
expect(result.status, result.stderr).toBe(0)
expect(result.stdout.trim()).toBe(manifest.version)
expect(readFileSync(marker, 'utf8')).toBe('loaded')
expect(result.stderr).not.toContain('dev-command-fixture')
})
})