mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
fix(dev): make worktree setup run on Windows (#2431)
`worktree.setup` ran two POSIX-only command strings, but lifecycle commands
go through PowerShell on Windows, so worktree creation failed at:
PASEO_DEV_MANAGED_HOME=1 PASEO_DEV_SEED_HOME=... ./scripts/dev-home.sh
-> PASEO_DEV_MANAGED_HOME=1 : The term ... is not recognized
PowerShell has no `VAR=value cmd` prefix syntax. The `cp` entry was broken the
same way: `$PASEO_SOURCE_CHECKOUT_PATH` is an undefined *PowerShell* variable,
not an env var, so it expanded to empty and the copy resolved to
`/packages/server/.env`.
Neither entry can be expressed portably in a single shell string, and `bash` is
not guaranteed on Windows, so move both steps into a Node script that reads its
inputs from `process.env` — matching the existing
`node ./scripts/seed-ios-native-cache.mjs` entry. One code path, no platform
branching.
`scripts/dev-home.sh` is unchanged and still sourced by the bash service
scripts; only the setup-time seeding is ported.
One behavior change: a missing `packages/server/.env` in the source checkout is
now skipped with a log instead of aborting setup. It is untracked local config,
and the old `cp` hard-failed worktree creation for anyone without one.
Co-authored-by: ABorakati <ABorakati@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -242,6 +242,14 @@ commands use the same non-login Bash behavior on macOS/Linux, but preserve their
|
|||||||
existing `cmd.exe /c` string semantics on Windows. Service scripts are separate:
|
existing `cmd.exe /c` string semantics on Windows. Service scripts are separate:
|
||||||
they launch in a terminal and receive the service environment described below.
|
they launch in a terminal and receive the service environment described below.
|
||||||
|
|
||||||
|
Because the shell differs per platform, a lifecycle command that must run
|
||||||
|
everywhere cannot use POSIX-only syntax — `VAR=1 cmd` env prefixes, `$VAR`
|
||||||
|
expansion, `cp`/`rm`, or a `./scripts/*.sh` entrypoint all fail under PowerShell,
|
||||||
|
and `bash` is not guaranteed to exist on Windows. Put that logic in a Node script
|
||||||
|
that reads what it needs from `process.env` and invoke it as
|
||||||
|
`node ./scripts/<name>.mjs`. This repo's own setup does exactly that in
|
||||||
|
`scripts/seed-worktree-dev-state.mjs` and `scripts/seed-ios-native-cache.mjs`.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"worktree": {
|
"worktree": {
|
||||||
|
|||||||
@@ -3,10 +3,9 @@
|
|||||||
"setup": [
|
"setup": [
|
||||||
"npm ci",
|
"npm ci",
|
||||||
"node ./scripts/seed-ios-native-cache.mjs",
|
"node ./scripts/seed-ios-native-cache.mjs",
|
||||||
"PASEO_DEV_MANAGED_HOME=1 PASEO_DEV_SEED_HOME=\"$PASEO_SOURCE_CHECKOUT_PATH/.dev/paseo-home\" PASEO_HOME=\"$PWD/.dev/paseo-home\" ./scripts/dev-home.sh",
|
"node ./scripts/seed-worktree-dev-state.mjs",
|
||||||
"npm run build:server",
|
"npm run build:server",
|
||||||
"npm run build --workspace=@getpaseo/expo-two-way-audio",
|
"npm run build --workspace=@getpaseo/expo-two-way-audio"
|
||||||
"cp \"$PASEO_SOURCE_CHECKOUT_PATH/packages/server/.env\" \"$PWD/packages/server/.env\""
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
95
scripts/seed-worktree-dev-state.mjs
Normal file
95
scripts/seed-worktree-dev-state.mjs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
|
||||||
|
// Worktree setup runs through a stable script shell: bash on macOS/Linux, but PowerShell
|
||||||
|
// on Windows. POSIX-only command strings (`VAR=1 cmd` env prefixes, `$VAR` expansion, `cp`,
|
||||||
|
// `./scripts/*.sh`) cannot express this step portably, so the seeding lives in Node — the
|
||||||
|
// one interpreter every Paseo checkout already depends on.
|
||||||
|
|
||||||
|
const sourceRoot = process.env.PASEO_SOURCE_CHECKOUT_PATH;
|
||||||
|
const targetRoot = process.env.PASEO_WORKTREE_PATH || process.cwd();
|
||||||
|
|
||||||
|
if (!sourceRoot || sourceRoot === targetRoot) {
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
seedPaseoHome();
|
||||||
|
copyServerEnv();
|
||||||
|
|
||||||
|
function seedPaseoHome() {
|
||||||
|
const source = process.env.PASEO_DEV_SEED_HOME || join(sourceRoot, ".dev/paseo-home");
|
||||||
|
const target = join(targetRoot, ".dev/paseo-home");
|
||||||
|
|
||||||
|
if (!existsSync(source)) {
|
||||||
|
console.log(` Seed: skipped (${source} missing)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source === target) {
|
||||||
|
console.log(" Seed: skipped (source is target)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.PASEO_DEV_RESET_HOME === "1") {
|
||||||
|
rmSync(target, { recursive: true, force: true });
|
||||||
|
} else if (hasEntries(target)) {
|
||||||
|
console.log(` Seed: skipped (${target} already has data)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdirSync(target, { recursive: true });
|
||||||
|
console.log(` Seed: copying metadata from ${source}`);
|
||||||
|
copyJsonTree(join(source, "agents"), join(target, "agents"));
|
||||||
|
copyJsonTree(join(source, "projects"), join(target, "projects"));
|
||||||
|
|
||||||
|
const config = join(source, "config.json");
|
||||||
|
if (existsSync(config)) {
|
||||||
|
cpSync(config, join(target, "config.json"));
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(` Seed: copied metadata from ${source}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Durable JSON metadata only. Runtime files (pid files, sockets, logs) must not be copied.
|
||||||
|
function copyJsonTree(source, target) {
|
||||||
|
if (!existsSync(source)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpSync(source, target, {
|
||||||
|
recursive: true,
|
||||||
|
filter: (path) => isDirectory(path) || path.endsWith(".json"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyServerEnv() {
|
||||||
|
const source = join(sourceRoot, "packages/server/.env");
|
||||||
|
const target = join(targetRoot, "packages/server/.env");
|
||||||
|
|
||||||
|
// Untracked local config. A checkout without one is normal, so this is not a setup failure.
|
||||||
|
if (!existsSync(source)) {
|
||||||
|
console.log(` Env: skipped (${source} missing)`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdirSync(dirname(target), { recursive: true });
|
||||||
|
cpSync(source, target);
|
||||||
|
console.log(` Env: copied ${source}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasEntries(path) {
|
||||||
|
try {
|
||||||
|
return readdirSync(path).length > 0;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDirectory(path) {
|
||||||
|
try {
|
||||||
|
return statSync(path).isDirectory();
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user