Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ cp .env.example .env

```

### Windows notes

- Prerequisites: Node.js 22+, pnpm 10.23+. Git for Windows is useful for contributing; you do **not** need WSL or Git Bash for `pnpm install`.
- `pnpm install` runs `apps/code/scripts/postinstall.mjs` via Node (not bash), so it does not hit the System32 WSL `bash.exe` stub.
- On Windows, run `pnpm dev:agent` and `pnpm dev:code` in separate terminals. `pnpm dev` still depends on phrocs (no Windows binary yet). `pnpm dev:mprocs` is also available as an alternative.

### Running in Development

By default, `pnpm dev` uses phrocs (our custom process runner) to run the agent and code app in parallel. phrocs auto-installs on first run and reads the `mprocs.yaml` config file. The binary is downloaded to `bin/phrocs` and is git-ignored.
Expand Down
2 changes: 1 addition & 1 deletion apps/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"test": "vitest run",
"test:e2e": "playwright test --config=tests/e2e/playwright.config.ts",
"test:e2e:headed": "playwright test --config=tests/e2e/playwright.config.ts --headed",
"postinstall": "bash scripts/postinstall.sh",
"postinstall": "node scripts/postinstall.mjs",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"clean": "node ../../scripts/rimraf.mjs .vite .turbo out node_modules/.vite"
Expand Down
83 changes: 83 additions & 0 deletions apps/code/scripts/postinstall.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#!/usr/bin/env node
// Postinstall for the Electron app: rebuild native modules for Electron's ABI,
// restore spawn-helper execute bits, patch the macOS Electron display name, and
// download bundled binaries. Pure Node so Windows does not need bash/Git Bash
// (pnpm otherwise hits the System32 WSL bash stub when no distro is installed).

import { execFileSync } from "node:child_process";
import { chmodSync, existsSync, readdirSync, statSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));
// apps/code/scripts -> repo root (pnpm package cwd is apps/code, so the old
// bash script used `cd ../..` from cwd; from this file we need one more `..`).
const REPO_ROOT = join(__dirname, "..", "..", "..");
const SCRIPTS_DIR = __dirname;

function electronDistMissing(electronDist) {
if (!existsSync(electronDist)) return true;
try {
return readdirSync(electronDist).length === 0;
} catch {
return true;
}
}

// pnpm may not rerun Electron's package-level postinstall when the lockfile is
// unchanged. Repair a missing or empty dist directory here.
const electronDist = join(REPO_ROOT, "node_modules", "electron", "dist");
if (electronDistMissing(electronDist)) {
console.log(`Electron binary missing at ${electronDist} — downloading...`);
execFileSync(
process.execPath,
[join(REPO_ROOT, "node_modules", "electron", "install.js")],
{
cwd: REPO_ROOT,
stdio: "inherit",
},
);
}

console.log("Rebuilding native modules for Electron...");
execFileSync(
process.execPath,
[join(REPO_ROOT, "scripts", "rebuild-better-sqlite3-electron.mjs")],
{ cwd: REPO_ROOT, stdio: "inherit" },
);

// Restore the execute bit on node-pty's spawn-helper. pnpm extracts node-pty's
// prebuilt binaries without preserving the executable mode, so the helper lands
// without +x and posix_spawnp fails at runtime with "posix_spawnp failed" the
// first time a terminal session is opened. Skip on Windows (no POSIX +x).
if (process.platform !== "win32") {
const prebuilds = join(REPO_ROOT, "node_modules", "node-pty", "prebuilds");
if (existsSync(prebuilds)) {
for (const entry of readdirSync(prebuilds)) {
const helper = join(prebuilds, entry, "spawn-helper");
if (!existsSync(helper)) continue;
const mode = statSync(helper).mode;
if ((mode & 0o111) === 0) {
console.log(`Restoring execute bit on ${helper}`);
chmodSync(helper, mode | 0o111);
}
}
}
}

// Info.plist lives inside Electron.app — macOS only. Reuse the existing script.
if (process.platform === "darwin") {
console.log("Patching Electron app name...");
execFileSync("bash", [join(SCRIPTS_DIR, "patch-electron-name.sh")], {
cwd: REPO_ROOT,
stdio: "inherit",
});
}

console.log("Downloading binaries...");
execFileSync(process.execPath, [join(SCRIPTS_DIR, "download-binaries.mjs")], {
cwd: REPO_ROOT,
stdio: "inherit",
});

console.log("Postinstall complete.");
46 changes: 0 additions & 46 deletions apps/code/scripts/postinstall.sh

This file was deleted.

14 changes: 13 additions & 1 deletion docs/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Troubleshooting

## Windows: `pnpm install` fails with WSL bash / `execvpe(/bin/bash)`

If install dies in `apps/code` postinstall with:

```
<3>WSL (9 - Relay) ERROR: execvpe(/bin/bash) failed: No such file or directory
```

an older checkout is still running `bash scripts/postinstall.sh`, and Windows is resolving `bash` to the System32 WSL stub without a distro. Current `main` uses `node scripts/postinstall.mjs` — pull latest and re-run `pnpm install`. WSL/Git Bash are not required for install.

`pnpm dev` / phrocs on Windows is a separate issue. Prefer `pnpm dev:agent` and `pnpm dev:code` in separate terminals; `pnpm dev:mprocs` is also available as an alternative.

## Black screen during development

If the app launches but renders a blank/black screen, it's almost always a stale Vite cache.
Expand Down Expand Up @@ -45,7 +57,7 @@ If the app crashes with something like:
libc++abi: terminating due to uncaught exception of type Napi::Error
```

A native module was built for the wrong runtime. Re-run the install, which rebuilds what Electron needs via `apps/code/scripts/postinstall.sh`:
A native module was built for the wrong runtime. Re-run the install, which rebuilds what Electron needs via `apps/code/scripts/postinstall.mjs`:

```bash
pnpm install
Expand Down