Repository navigation
feat(stagewise): support isolated dev instances - #1524
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughDevelopment builds derive unique identities and ports from the worktree path. Isolated instances use separate application data paths, seed missing profile files at startup, preserve the seed marker during resets, and support isolated data cleanup. ChangesIsolated development profile
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant Developer
participant StartIsolated
participant BackendStartup
participant SeedProfile
participant UserData
Developer->>StartIsolated: Run isolated development script
StartIsolated->>BackendStartup: Set STAGEWISE_DEV_INSTANCE=auto
BackendStartup->>SeedProfile: Seed isolated profile
SeedProfile->>UserData: Copy missing files and write marker
SeedProfile-->>BackendStartup: Return copied-file count
BackendStartup-->>Developer: Continue application startup
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
| Filename | Overview |
|---|---|
| apps/browser/build-constants.ts | Derives stable worktree-based development instance names while retaining the existing names for ordinary development and release channels. |
| apps/browser/src/backend/index.ts | Applies instance-specific Electron identity and user-data paths and seeds isolated profiles during startup. |
| apps/browser/src/backend/utils/seed-isolated-dev-profile.ts | Implements allowlisted, non-overwriting, one-time profile seeding, including Windows Local State. |
| apps/browser/src/backend/utils/app-data-reset.ts | Preserves the isolated-profile seed marker when processing an application-data reset. |
| apps/browser/scripts/clean-data.ts | Extends developer cleanup to discover isolated user-data and temporary directories and adds isolated-only scope. |
| apps/browser/vite.pages.config.ts | Assigns isolated worktrees stable pages-server and HMR ports while retaining port 5174 for ordinary development. |
Reviews (5): Last reviewed commit: "fix(stagewise): surface isolated profile..." | Re-trigger Greptile
| } | ||
|
|
||
| fs.writeFileSync(markerPath, ''); | ||
| return copiedFileCount; |
There was a problem hiding this comment.
Empty seed still marks complete
Low Severity
seedIsolatedDevProfile writes .isolated-dev-profile-seeded even when it copied nothing. If the default stagewise-dev data root exists but seed files are not there yet, a later login or preferences setup in the default profile never gets copied into the isolated instance.
Reviewed by Cursor Bugbot for commit 2b5e27e. Configure here.
There was a problem hiding this comment.
2 issues found across 9 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/browser/src/backend/utils/seed-isolated-dev-profile.ts">
<violation number="1" location="apps/browser/src/backend/utils/seed-isolated-dev-profile.ts:40">
P2: The one-shot seed copies mutable JSON files from the default dev profile with no atomicity or sync while that profile may be running concurrently, so an isolated instance can permanently inherit a partially-written/corrupt preferences or auth file (the marker then prevents any re-seed). Consider copying via temp-file+rename and re-attempting/clearing partial targets, or accepting this only as a best-effort dev convenience.</violation>
<violation number="2" location="apps/browser/src/backend/utils/seed-isolated-dev-profile.ts:44">
P2: The seed marker `.isolated-dev-profile-seeded` is written unconditionally after the copy loop, even when `copiedFileCount` is 0 because the source files simply didn't exist yet. Since subsequent calls short-circuit on `fs.existsSync(markerPath)`, if the default dev profile's login/preferences/credentials are created after the isolated instance's first run, they will never get copied over. Consider only writing the marker when at least one file was found in the source (or track missing files separately) so seeding can retry until real data becomes available.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| const sourcePath = path.join(sourceDataRoot, fileName); | ||
| const targetPath = path.join(targetDataRoot, fileName); | ||
| if (!fs.existsSync(sourcePath) || fs.existsSync(targetPath)) continue; | ||
| fs.copyFileSync(sourcePath, targetPath); |
There was a problem hiding this comment.
P2: The one-shot seed copies mutable JSON files from the default dev profile with no atomicity or sync while that profile may be running concurrently, so an isolated instance can permanently inherit a partially-written/corrupt preferences or auth file (the marker then prevents any re-seed). Consider copying via temp-file+rename and re-attempting/clearing partial targets, or accepting this only as a best-effort dev convenience.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser/src/backend/utils/seed-isolated-dev-profile.ts, line 40:
<comment>The one-shot seed copies mutable JSON files from the default dev profile with no atomicity or sync while that profile may be running concurrently, so an isolated instance can permanently inherit a partially-written/corrupt preferences or auth file (the marker then prevents any re-seed). Consider copying via temp-file+rename and re-attempting/clearing partial targets, or accepting this only as a best-effort dev convenience.</comment>
<file context>
@@ -0,0 +1,46 @@
+ const sourcePath = path.join(sourceDataRoot, fileName);
+ const targetPath = path.join(targetDataRoot, fileName);
+ if (!fs.existsSync(sourcePath) || fs.existsSync(targetPath)) continue;
+ fs.copyFileSync(sourcePath, targetPath);
+ copiedFileCount++;
+ }
</file context>
| copiedFileCount++; | ||
| } | ||
|
|
||
| fs.writeFileSync(markerPath, ''); |
There was a problem hiding this comment.
P2: The seed marker .isolated-dev-profile-seeded is written unconditionally after the copy loop, even when copiedFileCount is 0 because the source files simply didn't exist yet. Since subsequent calls short-circuit on fs.existsSync(markerPath), if the default dev profile's login/preferences/credentials are created after the isolated instance's first run, they will never get copied over. Consider only writing the marker when at least one file was found in the source (or track missing files separately) so seeding can retry until real data becomes available.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser/src/backend/utils/seed-isolated-dev-profile.ts, line 44:
<comment>The seed marker `.isolated-dev-profile-seeded` is written unconditionally after the copy loop, even when `copiedFileCount` is 0 because the source files simply didn't exist yet. Since subsequent calls short-circuit on `fs.existsSync(markerPath)`, if the default dev profile's login/preferences/credentials are created after the isolated instance's first run, they will never get copied over. Consider only writing the marker when at least one file was found in the source (or track missing files separately) so seeding can retry until real data becomes available.</comment>
<file context>
@@ -0,0 +1,46 @@
+ copiedFileCount++;
+ }
+
+ fs.writeFileSync(markerPath, '');
+ return copiedFileCount;
+}
</file context>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/browser/vite.pages.config.ts`:
- Around line 22-26: Update the port derivation around pagesPort and its related
Vite server/HMR configuration to use collision-aware per-instance allocation
instead of only applying a modulo 10,000 hash mapping. Ensure the selected
server and HMR ports remain identical, and add coverage for distinct
stagewise-dev identifiers that collide under the current mapping.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 936e370e-9602-4272-90cc-0595c1ceeffa
📒 Files selected for processing (1)
apps/browser/vite.pages.config.ts
| const pagesPort = buildConstants.__APP_BASE_NAME__.startsWith('stagewise-dev-') | ||
| ? 30000 + | ||
| (Number.parseInt(buildConstants.__APP_BASE_NAME__.slice(-8), 16) % 10000) | ||
| : 5174; | ||
|
|
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n -C 8 '__APP_BASE_NAME__|stagewise-dev-' \
apps/browser/build-constants.ts \
apps/browser/vite.pages.config.ts
python - <<'PY'
def pages_port(app_base_name):
return 30000 + (int(app_base_name[-8:], 16) % 10000)
first = 'stagewise-dev-00002710'
second = 'stagewise-dev-00004e20'
assert pages_port(first) == pages_port(second) == 30000
print(f'collision: {first}, {second} -> {pages_port(first)}')
PYRepository: stagewise-io/stagewise
Length of output: 3226
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo '## vite.pages.config.ts relevant sections'
sed -n '1,130p' apps/browser/vite.pages.config.ts
echo
echo '## build-constants.ts relevant section'
sed -n '1,70p' apps/browser/build-constants.ts
echo
echo '## devInstance usages'
rg -n -C 4 '\bdevInstance\b|__DEV_INSTANCE__|STAGEWISE_DEV|stagewise-dev' apps/browser apps -g '!node_modules' -g '!dist' -g '!build' | head -n 200
echo
echo '## deterministic port mapping samples'
python3 - <<'PY'
from pathlib import Path
path = Path('apps/browser/vite.pages.config.ts')
text = path.read_text()
print('uses slice(-8):', "slice(-8)" in text)
print('uses strictPort:', "strictPort" in text)
samples = [
'stagewise-dev-00002710',
'stagewise-dev-00004e20',
'stagewise-dev-00003938',
'stagewise-dev-00005d48',
'stagewise-dev-0004ea64',
'stagewise-dev-0006e8b4',
]
for name in samples:
port = 30000 + (int(name[-8:], 16) % 10000)
print(name, '->', port)
PYRepository: stagewise-io/stagewise
Length of output: 21425
Make isolated port allocation collision-aware.
STAGEWISE_DEV_INSTANCE=auto derives stagewise-dev-* instances from the worktree hash truncated to eight hex chars, but vite.pages.config.ts maps that suffix modulo 10,000. Different worktrees can share the same server/HMR port, and strictPort: true blocks the second instance from starting. Use collision-aware allocation or per-instance port reservation, keep the selected server and HMR ports aligned, and add a test for colliding identifiers.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/browser/vite.pages.config.ts` around lines 22 - 26, Update the port
derivation around pagesPort and its related Vite server/HMR configuration to use
collision-aware per-instance allocation instead of only applying a modulo 10,000
hash mapping. Ensure the selected server and HMR ports remain identical, and add
coverage for distinct stagewise-dev identifiers that collide under the current
mapping.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 9b04d50. Configure here.
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/browser/vite.pages.config.ts">
<violation number="1" location="apps/browser/vite.pages.config.ts:22">
P2: The derived port for isolated dev instances is computed as `30000 + (parseInt(hash.slice(-8),16) % 10000)`, which only has 10,000 possible values. Two different worktrees can hash to the same port, and since `strictPort: true` is set, the second instance will fail to start instead of falling back to another port. Consider a collision-aware allocation strategy (e.g., checking port availability and incrementing) or a larger port space to reduce collision likelihood.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| // Release channel: 'dev' | 'prerelease' | 'release' | ||
| const _releaseChannel = process.env.RELEASE_CHANNEL || 'dev'; | ||
|
|
||
| const pagesPort = buildConstants.__APP_BASE_NAME__.startsWith('stagewise-dev-') |
There was a problem hiding this comment.
P2: The derived port for isolated dev instances is computed as 30000 + (parseInt(hash.slice(-8),16) % 10000), which only has 10,000 possible values. Two different worktrees can hash to the same port, and since strictPort: true is set, the second instance will fail to start instead of falling back to another port. Consider a collision-aware allocation strategy (e.g., checking port availability and incrementing) or a larger port space to reduce collision likelihood.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser/vite.pages.config.ts, line 22:
<comment>The derived port for isolated dev instances is computed as `30000 + (parseInt(hash.slice(-8),16) % 10000)`, which only has 10,000 possible values. Two different worktrees can hash to the same port, and since `strictPort: true` is set, the second instance will fail to start instead of falling back to another port. Consider a collision-aware allocation strategy (e.g., checking port availability and incrementing) or a larger port space to reduce collision likelihood.</comment>
<file context>
@@ -19,6 +19,11 @@ const _appVersion = packageJson.version;
// Release channel: 'dev' | 'prerelease' | 'release'
const _releaseChannel = process.env.RELEASE_CHANNEL || 'dev';
+const pagesPort = buildConstants.__APP_BASE_NAME__.startsWith('stagewise-dev-')
+ ? 30000 +
+ (Number.parseInt(buildConstants.__APP_BASE_NAME__.slice(-8), 16) % 10000)
</file context>
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/browser/src/backend/utils/seed-isolated-dev-profile.ts">
<violation number="1" location="apps/browser/src/backend/utils/seed-isolated-dev-profile.ts:41">
P2: Existing Windows isolated profiles created before this change still cannot receive the default profile's `Local State`, because the persisted seed marker causes an early return before this copy runs. A versioned one-time migration or a separate missing-`Local State` check would apply the fix to already-seeded profiles without reseeding their data.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| copiedFileCount++; | ||
| } | ||
|
|
||
| if (process.platform === 'win32') { |
There was a problem hiding this comment.
P2: Existing Windows isolated profiles created before this change still cannot receive the default profile's Local State, because the persisted seed marker causes an early return before this copy runs. A versioned one-time migration or a separate missing-Local State check would apply the fix to already-seeded profiles without reseeding their data.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser/src/backend/utils/seed-isolated-dev-profile.ts, line 41:
<comment>Existing Windows isolated profiles created before this change still cannot receive the default profile's `Local State`, because the persisted seed marker causes an early return before this copy runs. A versioned one-time migration or a separate missing-`Local State` check would apply the fix to already-seeded profiles without reseeding their data.</comment>
<file context>
@@ -41,6 +38,16 @@ export function seedIsolatedDevProfile(
copiedFileCount++;
}
+ if (process.platform === 'win32') {
+ const sourcePath = path.join(sourceUserData, 'session', 'Local State');
+ const targetPath = path.join(userDataDirectory, 'session', 'Local State');
</file context>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/browser/scripts/clean-data.ts`:
- Line 168: Wrap the completion message template literal in the cleanup flow so
each source line stays within the repository’s 80-character limit, while
preserving the existing message content and interpolation values deletedCount
and tempDeletedCount.
- Around line 106-117: Update getIsolatedDirectories to catch the readdir error
explicitly, return an empty array only when its code is ENOENT, and rethrow
every other error so permission and I/O failures propagate to the cleanup flow.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 35154f63-e40b-45a2-ac0d-540a5b526c3a
📒 Files selected for processing (2)
apps/browser/scripts/clean-data.tspackage.json
| log(`\n${'='.repeat(50)}`, colors.cyan); | ||
| log( | ||
| `\n✓ Cleanup complete! Deleted ${deletedCount} userData directories and ${prodTempDeleted + devTempDeleted} temp workspace directories.`, | ||
| `\n✓ Cleanup complete! Deleted ${deletedCount} userData directories and ${tempDeletedCount} temp directories.`, |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Wrap the completion message to meet the line-width rule.
The changed template literal exceeds the 80-character limit. Split the message into shorter parts so Biome can format the code within the repository limit.
Proposed fix
log(
- `\n✓ Cleanup complete! Deleted ${deletedCount} userData directories and ${tempDeletedCount} temp directories.`,
+ [
+ '\n✓ Cleanup complete!',
+ `Deleted ${deletedCount} userData directories`,
+ `and ${tempDeletedCount} temp directories.`,
+ ].join(' '),
colors.green,
);As per coding guidelines, JavaScript/TypeScript code must maintain an 80-character line width and use Biome for formatting.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| `\n✓ Cleanup complete! Deleted ${deletedCount} userData directories and ${tempDeletedCount} temp directories.`, | |
| log( | |
| [ | |
| '\n✓ Cleanup complete!', | |
| `Deleted ${deletedCount} userData directories`, | |
| `and ${tempDeletedCount} temp directories.`, | |
| ].join(' '), | |
| colors.green, | |
| ); |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/browser/scripts/clean-data.ts` at line 168, Wrap the completion message
template literal in the cleanup flow so each source line stays within the
repository’s 80-character limit, while preserving the existing message content
and interpolation values deletedCount and tempDeletedCount.
Source: Coding guidelines
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/browser/scripts/clean-data.ts">
<violation number="1" location="apps/browser/scripts/clean-data.ts:144">
P2: The standard `pnpm clean:browser-data` (no flag) now also deletes every isolated `stagewise-dev-*` profile, not just the production and regular-dev directories it cleaned before. Since the whole point of the isolated feature is to keep per-worktree data (auth, credentials, prefs) separate and persistent across concurrent worktrees, a developer running the conventional dev-cleanup command will unexpectedly wipe all of those scoped profiles. Consider gating the isolated-dir removal behind an explicit opt-in (e.g. only clean `stagewise-dev-*` when passed a flag such as `--include-isolated`), leaving the default `clean-data` behavior unchanged, and keeping `--isolated-only` as the targeted way to clean up isolated profiles.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| if (deleted) deletedCount++; | ||
| } | ||
| } | ||
| for (const dirPath of await getIsolatedDirectories(appDataPath)) { |
There was a problem hiding this comment.
P2: The standard pnpm clean:browser-data (no flag) now also deletes every isolated stagewise-dev-* profile, not just the production and regular-dev directories it cleaned before. Since the whole point of the isolated feature is to keep per-worktree data (auth, credentials, prefs) separate and persistent across concurrent worktrees, a developer running the conventional dev-cleanup command will unexpectedly wipe all of those scoped profiles. Consider gating the isolated-dir removal behind an explicit opt-in (e.g. only clean stagewise-dev-* when passed a flag such as --include-isolated), leaving the default clean-data behavior unchanged, and keeping --isolated-only as the targeted way to clean up isolated profiles.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/browser/scripts/clean-data.ts, line 144:
<comment>The standard `pnpm clean:browser-data` (no flag) now also deletes every isolated `stagewise-dev-*` profile, not just the production and regular-dev directories it cleaned before. Since the whole point of the isolated feature is to keep per-worktree data (auth, credentials, prefs) separate and persistent across concurrent worktrees, a developer running the conventional dev-cleanup command will unexpectedly wipe all of those scoped profiles. Consider gating the isolated-dir removal behind an explicit opt-in (e.g. only clean `stagewise-dev-*` when passed a flag such as `--include-isolated`), leaving the default `clean-data` behavior unchanged, and keeping `--isolated-only` as the targeted way to clean up isolated profiles.</comment>
<file context>
@@ -103,43 +103,69 @@ async function cleanTempWorkspaces(tempBasePath: string): Promise<number> {
+ if (deleted) deletedCount++;
+ }
+ }
+ for (const dirPath of await getIsolatedDirectories(appDataPath)) {
const deleted = await deleteDirectory(dirPath);
if (deleted) deletedCount++;
</file context>


Summary
This makes it possible to run the stagewise Electron app from multiple Git worktrees at the same time, so multiple features can be developed and tested in parallel.
pnpm -F stagewise start:isolatedrecent workspaces
pnpm -F stagewise startbehavior unchangedNote
Medium Risk
Dev-only and opt-in, but it copies auth/credentials between profiles and changes Electron paths and ports; mistakes could affect local dev data or encryption on Windows.
Overview
Adds parallel dev Electron runs from multiple worktrees via
pnpm -F stagewise start:isolated, which setsSTAGEWISE_DEV_INSTANCE=autoand derives a stable 8-character ID from the worktree path.That ID drives per-instance isolation:
__APP_BASE_NAME__becomesstagewise-dev-<id>(userData, temp roots, Windows App User Model ID, single-instance lock), and the pages Vite dev server uses a stable port in the 30000–39999 range derived from the suffix. Regularstartis unchanged.First launch of an isolated profile one-time seeds missing files (auth, credentials, preferences, identity, etc.) from the default
stagewise-devprofile, with a marker so it does not repeat; app data reset keeps that marker. On Windows, devapp.setNamestays on the default dev label so copiedsession/Local Statecan work with safeStorage, while display names still show the instance ID.Cleanup adds
--isolated-onlyonclean-dataand rootclean:browser-data-isolatedto remove onlystagewise-dev-*userData and temp directories.Reviewed by Cursor Bugbot for commit 2c6f98a. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by cubic
Run multiple isolated Stagewise dev Electron instances from different Git worktrees in parallel with unique data, locks, and ports. Also improves cleanup by surfacing errors during isolated profile removal.
New Features
pnpm -F stagewise start:isolated(STAGEWISE_DEV_INSTANCE=auto) that derives an 8-char ID from the worktree.userData, temp folder, session/ports, and single-instance locks; app base name becomesstagewise-dev-<id>. Vite pages dev server and HMR use a stable port derived from the ID.stagewise-devprofile, guarded by a marker. On Windows, also copysession/Local State; keep a stable devapp.setNameso encrypted/safeStorage data works.pnpm clean:browser-data-isolated(alias ofpnpm -F stagewise clean-data --isolated-only) to remove only isolated devuserDataand temp directories.Bug Fixes
clean-dataruns.Written for commit 2c6f98a. Summary will update on new commits.
Summary by CodeRabbit
New Features
Bug Fixes
Tests