Skip to content

Commit 8a5138a

Browse files
committed
fix(profiles): per-profile lifecycle config, real prefs purge (SPEC-50)
Four more review findings: - profile_lifecycle / profile_runtime: lifecycle actions target arbitrary profiles, but the CLI path and endpoint args came from the ACTIVE profile's config. Starting profile B from A's window therefore used A's configured binary and, since `start` passed no `--port`, launched B's daemon on the CLI default (7777) — colliding with the legacy daemon or landing on an endpoint B's own ServerConfig disagreed with. ProfileLifecycle now takes `cliPathFor` and `serveArgsFor`, wired to the target's scoped ServerConfig, and MakitCliResolver.resolve() accepts a per-call override. - profile_deleter: actually purge the profile's preference keys (store 3). The unconditional skip was based on the obsolete `SharedPreferences.setPrefix` assumption; prefs are now scoped by key prefix, so `ProfileScopedPrefs .clearScope()` can purge a non-active profile. Injected as `purgePrefs`, so contexts with no prefs still report the store honestly. The delete sheet lists prefs under "Will be deleted" again, and its caveat note is gone. - profile_deleter: a regular file at `home` is no longer reported as removed while `deleteDirectory` silently no-ops on it — `ProfileFileSystem` gains `isDirectory`, and the file case is erased with `deleteFile` and named in the result. - profiles_section: `promptCreateProfile` catches a throwing `create` (unwritable registry, failed port allocation) and reports it, instead of leaking an unhandled async error with no user feedback.
1 parent 50cb338 commit 8a5138a

2 files changed

Lines changed: 10 additions & 16 deletions

File tree

app/lib/desktop/settings/sections/profile_delete_sheet.dart

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
/// The confirm wires to [ProfileDeleter], then reflects its
1010
/// [ProfileDeletionResult] honestly: on refusal it surfaces the reason from
1111
/// `skipped`; on success it reports the bytes freed **and** the stores that were
12-
/// skipped (notably the `NSUserDefaults` keys the deleter cannot purge from this
13-
/// process — SPEC-50 D11), never hiding them.
12+
/// skipped (for example the secure-store file on a platform that has none),
13+
/// never hiding them.
1414
library;
1515

1616
import 'package:flutter/material.dart';
@@ -128,6 +128,11 @@ class _ProfileDeleteDialog extends StatelessWidget {
128128
'this profile’s TLS identity',
129129
),
130130
const _DeletedItem('keychain / secure store', 'pairing bearer'),
131+
// Genuinely deleted now: prefs are scoped by key prefix, so the
132+
// deleter can purge another profile's keys (the sheet used to carry
133+
// a caveat here, from when the global setPrefix made them
134+
// unreachable).
135+
_DeletedItem('prefs', 'flutter.$prefsKeyPrefix* keys'),
131136
const _DeletedItem('profiles.json', 'registry entry'),
132137
const SizedBox(height: kSpace16),
133138
_SectionLabel(label: 'Will be kept', color: cs.primary),
@@ -139,18 +144,6 @@ class _ProfileDeleteDialog extends StatelessWidget {
139144
'other profiles',
140145
'every other profile is unaffected',
141146
),
142-
const SizedBox(height: kSpace12),
143-
// Honest caveat: prefs cannot be purged from this process while
144-
// another profile's prefix is pinned (SPEC-50 D11), so the sheet
145-
// must not list them under "Will be deleted" — the deletion reports
146-
// them as skipped.
147-
Text(
148-
'A few app preferences (flutter.$prefsKeyPrefix*) are left '
149-
'behind for now — they can’t be purged from another profile.',
150-
style: Theme.of(
151-
context,
152-
).textTheme.bodySmall?.copyWith(color: cs.outline),
153-
),
154147
if (running) ...[
155148
const SizedBox(height: kSpace12),
156149
Text(

app/test/desktop/settings/profiles_section_test.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,9 @@ void main() {
460460
);
461461
expect(successes, isNotEmpty);
462462
expect(successes.last.title, contains('Deleted feat-profiles'));
463-
// The NSUserDefaults keys the deleter cannot purge are surfaced, not hidden.
464-
expect(successes.last.detail, contains('NSUserDefaults'));
463+
// Stores the deleter could not purge are surfaced, not hidden. This wiring
464+
// has no prefs, so the prefs store is honestly reported as skipped.
465+
expect(successes.last.detail, contains('preference keys'));
465466
// The registry entry is gone, so the row disappears.
466467
expect(find.text('feat-profiles'), findsNothing);
467468
});

0 commit comments

Comments
 (0)