Skip to content

CLI: Implement decoupled config file strategy - #2793

Merged
bcotrim merged 23 commits into
trunkfrom
stu-1350-decoupled-config-dev
Mar 23, 2026
Merged

CLI: Implement decoupled config file strategy#2793
bcotrim merged 23 commits into
trunkfrom
stu-1350-decoupled-config-dev

Conversation

@bcotrim

@bcotrim bcotrim commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Used AI to resolve merge conflicts with trunk

Proposed Changes

This is the development branch for STU-1350. It will mostly be reviewed in separate PRs, with the exclusion of fixes and adjustments needed from trunk merges.
List of PRs:

Testing Instructions

  • TBD

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?
bcotrim and others added 2 commits March 11, 2026 16:29
* STU-1350: Read site data from CLI instead of appdata

Studio now reads site data via `site list --format json` at startup
and maintains state through CLI events subscriber. Removes direct
appdata reads for site details, simplifies SiteServer create/start
flows, and removes waitForSiteEvent synchronization.

* Fix lint: indentation in index.test.ts

* Fix typecheck: narrow SiteDetails union before accessing url

* Remove dead url branch in SiteServer.create — events subscriber handles it

* Address PR review feedback: shared schemas, keyValuePair output, simplify start/delete
@bcotrim bcotrim changed the title Merge trunk and resolve config decoupling work Mar 13, 2026
@bcotrim bcotrim self-assigned this Mar 13, 2026
bcotrim and others added 17 commits March 13, 2026 08:37
* STU-1350: Read site data from CLI instead of appdata

Studio now reads site data via `site list --format json` at startup
and maintains state through CLI events subscriber. Removes direct
appdata reads for site details, simplifies SiteServer create/start
flows, and removes waitForSiteEvent synchronization.

* Fix lint: indentation in index.test.ts

* STU-1350: Move CLI site data to dedicated cli.json config file

Split site data from appdata-v1.json into a new CLI-owned config at ~/.studio/cli.json.
Studio now reads sites exclusively via `studio site list` and _events. The CLI is the
source of truth for site configuration. Auth tokens, snapshots, locale remain in appdata.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* Fix delete test after trunk merge: use saveCliConfig instead of saveAppdata

* Extend require-lock-before-save eslint rule to support cli-config lock/save pairs

* Use shared lockfile constants and extract DEFAULT_CLI_CONFIG

* Fix typecheck: narrow SiteDetails union before accessing url

* Remove dead url branch in SiteServer.create — events subscriber handles it

* Fix lint: remove extra blank line in cli-config.ts

* triggert ci

* Update e2e tests to read site data from cli.json

* Address PR review feedback for cli-config

- Use structuredClone for DEFAULT_CLI_CONFIG deep copy
- Rename daemon-paths.ts to paths.ts, extract STUDIO_CLI_HOME
- Split config schema for version mismatch detection
- Improve readCliConfig error handling with version check
- Rename removeSite to removeSiteFromConfig
- Revert UPDATED event handler to warn for unknown sites

* Fix AI files to import site functions from cli-config instead of appdata

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
* Apply decoupled config strategy to preview sites (STU-1350)

- CLI stores/reads preview site data from cli.json instead of appdata
- Studio reads preview sites via CLI commands (preview list --format json)
- Added preview set command for updating snapshot settings (--name)
- Added --name option to preview create command
- Moved refreshSnapshots to store initialization with test guard
- Fixed snapshot-slice test mock setup to avoid module-load timing issues

* Emit snapshot events to Studio via _events for realtime updates

* Move snapshot name generation from cli-config to preview create command

* Split cli-config.ts into folder structure (core, sites, snapshots)

* Rename site-events to cli-events and enrich snapshot events with inline data (STU-1350)

* Fix snapshot update infinite loop and preview set error handling

* Unify CLI event emitter, share event schemas in cli-events, and clean up daemon-client (STU-1350)

* trigger ci

* Fix import order lint errors in core.ts and site-server.ts

* Address PR review: add stdout json output, addSnapshot action, reusable usage count helper, fix listener state bug

* Remove barrel file, replace z.nativeEnum with z.enum, update imports to direct paths

* Fix import order in cli-events.ts and remove unused test imports
* Wire auth and locale to shared.json, AI settings to cli.json

Move auth token reads/writes from appdata to shared-config for Desktop+CLI. Move locale reads/writes to shared-config (Desktop saves, CLI reads). Move aiProvider and anthropicApiKey from shared-config to cli-config (CLI-only). Remove auth and locale fields from appdata schema and types since they're now in separate files. Update all imports and tests accordingly.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* Move CLI telemetry stats from appdata to cli-config

* Fix import order lint errors

* Remove CLI appdata dependency and move infrastructure paths to ~/.studio

* Revert server-files and certificate paths to appdata directory

* Watch shared config for auth changes from CLI

* Align shared config watcher with user-data watcher pattern

* trigger ci

* Address PR review feedback: events-based auth, rename types, deduplicate schemas

* Fix prettier formatting in auth test

* Fix shared-config mock in tests to export authTokenSchema

* Use z.literal for config version validation, remove unused re-export, update test mocks

* Extract authTokenSchema to avoid Node.js imports in renderer bundle

* trigger ci

* Fix daemon test to use os.tmpdir() for Windows compatibility

* Make CLI event emission best-effort in auth commands

* Throw on shared config version mismatch instead of silently returning defaults

* Add line break before version mismatch error message

* Handle version mismatch errors through standard Logger flow in auth commands

* Show only display name in AI chat status bar

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
…2836)

* Migrate appdata to ~/.studio/appdata.json with extensible migration framework

* Move appdata migration from CLI to Studio Desktop

* Rewrite appdata migration to split into shared.json, cli.json, and appdata.json

* trigger ci

* Ensure .studio directory exists before lockfile and fix import order

* Fix readFile mock type to return Buffer instead of string

* Refactor appdata to store only Desktop-specific state with sites as Record<id, AppdataSiteData>

* Address PR feedback: rename to app.json and siteMetadata, use zod parsing in migration

* Fix prettier formatting in user-data test

* Fix e2e migration by respecting E2E_APP_DATA_PATH in getOldAppdataPath

* new migration interface

* studio migrations

* studio migrations

* cli migrations

* Rename appdata references, centralize config paths and lockfile constants

* Isolate e2e config directory to fix test failures

* Move site metadata cleanup to SiteServer, fix typecheck and test failures

* Add APP_CONFIG_LOCKFILE_NAME constant and fix test failures

@fredrikekelund fredrikekelund left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving because I've already reviewed all the contained PRs 👍

@bcotrim
bcotrim marked this pull request as ready for review March 23, 2026 15:34
@wpmobilebot

wpmobilebot commented Mar 23, 2026

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing cc27588 vs trunk

app-size

Metric trunk cc27588 Diff Change
App Size (Mac) 1237.48 MB 1237.54 MB +0.06 MB ⚪ 0.0%

site-editor

Metric trunk cc27588 Diff Change
load 1910 ms 1871 ms 39 ms ⚪ 0.0%

site-startup

Metric trunk cc27588 Diff Change
siteCreation 7072 ms 6055 ms 1017 ms 🟢 -14.4%
siteStartup 3944 ms 3951 ms +7 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@bcotrim
bcotrim merged commit 22d09d1 into trunk Mar 23, 2026
10 checks passed
@bcotrim
bcotrim deleted the stu-1350-decoupled-config-dev branch March 23, 2026 17:52
fredrikekelund added a commit that referenced this pull request Jun 3, 2026
## Related issues

<!--
Link a related issue to this PR. If the PR does not immediately resolve
the issue,
for example, it requires a separate deployment to production, avoid
using the "Fixes" keyword and use "Related to" instead.
-->

- Fixes STU-1478

## How AI was used in this PR

<!--
Help reviewers understand what to look for and verify that you've
reviewed the code yourself.
-->

N/A

## Proposed Changes

<!--
Explain the intent of this PR:
- What problem does it solve, or what need does it address?
- How does it affect the user (new capability, fix, performance,
accessibility, etc.)?
- Note any user-visible behavior changes or trade-offs.

Focus on the "why" and the user impact. Avoid listing modified files or
describing implementation mechanics — the diff already shows that.
-->

In #2793, we implemented a data
migration from the old `appdata-v1.json` config file to the new
decoupled file strategy (living in `~/.studio`). During that data
migration, we added Sentry logging to help us catch certain types of
errors.

Per pfHvTO-1ct-p2, we want to avoid leaving this kind of "speculative
logging" in the code for longer periods of time, so this PR removes the
`Sentry.captureException` calls. These errors would only have occurred
if the `appdata-v1.json` file didn't conform to the expected schema.
Luckily, we didn't catch any such errors.

## Testing Instructions

<!--
Add as many details as possible to help others reproduce the issue and
test the fix.
"Before / After" screenshots can also be very helpful when the change is
visual.
-->

Code review is sufficient

## Pre-merge Checklist

<!--
Complete applicable items on this checklist **before** merging into
trunk. Inapplicable items can be left unchecked.

Both the PR author and reviewer are responsible for ensuring the
checklist is completed.
-->

- [ ] Have you checked for TypeScript, React or other console errors?
fredrikekelund added a commit that referenced this pull request Jun 11, 2026
…ft (#3685)

## Related issues

<!--
Link a related issue to this PR. If the PR does not immediately resolve
the issue,
for example, it requires a separate deployment to production, avoid
using the "Fixes" keyword and use "Related to" instead.
-->

- Fixes STU-1494

## How AI was used in this PR

<!--
Help reviewers understand what to look for and verify that you've
reviewed the code yourself.
-->

Claude did the implementation over two passes, using a detailed spec
from me.

## Proposed Changes

<!--
Explain the intent of this PR:
- What problem does it solve, or what need does it address?
- How does it affect the user (new capability, fix, performance,
accessibility, etc.)?
- Note any user-visible behavior changes or trade-offs.

Focus on the "why" and the user impact. Avoid listing modified files or
describing implementation mechanics — the diff already shows that.
-->

In #2793 and related PRs, we
copied `appdata-v1.json` into three decoupled config files in
`~/.studio`. We also copied the `server-files` and `certificates`
directories to `~/.studio`.

The migration went off smoothly. This PR adds a new migration that
removes the original paths from the user's system.

## Testing Instructions

<!--
Add as many details as possible to help others reproduce the issue and
test the fix.
"Before / After" screenshots can also be very helpful when the change is
visual.
-->

1. Run `open ~/Library/Application\ Support/Studio` in a terminal.
2. Ensure that you have either an `appdata-v1.deprecated.json` file, a
`server-files` directory, or a `certificates` directory. If not, create
an empty `server-files` directory.
3. Run `npm start`.
4. Ensure that `appdata-v1.deprecated.json`, `server-files`, and
`certificates` are all removed.

## Pre-merge Checklist

<!--
Complete applicable items on this checklist **before** merging into
trunk. Inapplicable items can be left unchecked.

Both the PR author and reviewer are responsible for ensuring the
checklist is completed.
-->

- [ ] Have you checked for TypeScript, React or other console errors?
bcotrim added a commit that referenced this pull request Jul 13, 2026
## Related issues

- Related to STU-1985 (follow-up: splitting the work around #3998 into
small PRs)

## How AI was used in this PR

Implemented with Claude Code from a detailed plan (target location,
migration hook point, race handling). Code, migration tests, and
verification steps reviewed by me.

## Proposed Changes

AI chat sessions were the last piece of Studio state still living in the
Electron `userData` dir (`~/Library/Application
Support/Studio/sessions`, `%APPDATA%\Studio\sessions`) — a historical
accident: sessions shipped (#2767) just before the `~/.studio` config
split (#2793), and only the config JSONs moved. This PR consolidates
sessions under `~/.studio/sessions`, resolved via a new
`getSessionsDirectory()` helper in `well-known-paths.ts` next to the
other config paths.

Existing sessions are migrated by a shared `Migration` registered in
**both** existing migration pipelines — the CLI's (runs as yargs
middleware on every invocation) and the desktop's (runs at boot, before
the main window exists) — so it covers CLI-only and desktop-only users
alike. A lockfile serializes concurrent desktop + CLI first runs.

After moving the files, the migration **leaves a symlink at the legacy
location** (a junction on Windows — no privileges needed) pointing at
`~/.studio/sessions`. That makes the move transparent to everything that
still resolves the old path: older Studio/CLI versions running next to a
newer one keep reading *and writing* the same store, and absolute paths
persisted inside session entries (e.g. screenshot artifacts from
`take_screenshot`) keep resolving — no session data rewriting needed. If
linking fails (e.g. network-redirected `%APPDATA%`), the migration
degrades to a self-healing merge that sweeps straggler files into the
new root on every run — destination wins on collisions, cross-volume
moves fall back to copy+remove. Failures are logged with
home-dir-sanitized paths; success is silent like the other CLI
migrations.

User impact: none visible — sessions and their screenshots keep working
in both the desktop app and the CLI, from the new location, across
version skew between surfaces. The E2E path overrides
(`E2E_APP_DATA_PATH`) keep their previous semantics, and the migration
is skipped under E2E/dev sandboxes so test runs can't touch real
sessions. The experimental hosted backend's session path was updated to
match so it keeps reading the same sessions desktop/CLI write.

## Testing Instructions

1. With existing sessions under the old location (`~/Library/Application
Support/Studio/sessions`), run `npm run cli:build && node
apps/cli/dist/cli/main.mjs code sessions list` — all sessions listed,
files now under `~/.studio/sessions`, old path is now a symlink to it
(`ls -l`).
2. Run it again — idempotent no-op, same list.
3. Old-version compatibility: with the link in place, sessions written
to the old path (simulating an outdated surface) land in
`~/.studio/sessions`, and old screenshot artifacts render in the desktop
conversation view (their persisted absolute paths resolve through the
link).
4. Start the desktop app, open Studio Code — session history intact, new
sessions land under `~/.studio/sessions/YYYY/MM/DD/`.
5. Fresh setup (no old dir): sessions are created directly under
`~/.studio/sessions`.

To revert the migration between scenarios (removes the link, then moves
the sessions back so the migration runs again — bare `rm` refuses to
delete a real directory, so it only ever removes the link):

```bash
# macOS
rm ~/Library/Application\ Support/Studio/sessions && mv ~/.studio/sessions ~/Library/Application\ Support/Studio/sessions
```

```powershell
# Windows (PowerShell)
(Get-Item $env:APPDATA\Studio\sessions).Delete(); Move-Item ~\.studio\sessions $env:APPDATA\Studio\sessions
```

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants