fix(setup): wizard errors copyable above the dialog, CLI skew explained, exec transparency
Some checks failed
Security / Security check (push) Failing after 2s

Field test of the setup wizard surfaced three trust breaks in one run:
an unexplained macOS Documents permission prompt, a perceived crash,
and an error message whose copy button could not be reached.

Root causes and fixes:
- chain init failures were shown as a SnackBar, which lands BEHIND the
  wizard's modal barrier: dimmed, clipped, copy unreachable — and the
  click aimed at it hit the barrier, dismissing the whole wizard with
  all answers (the perceived crash). Errors now open a modal dialog
  ABOVE the wizard via showChainErrorDialog with a copyable detail
  block, and the wizard is no longer barrier-dismissible.
- When the resolved chain binary is older than Studio and rejects
  --plan-json, the wizard now explains the version skew in plain
  language (binary path + update path) instead of leaking a raw clap
  usage error. A missing binary gets its own localized story.
- Step 3 announces which chain binary the preview will execute; when
  that binary physically lives (symlinks resolved) in a TCC-protected
  folder, the wizard pre-explains the macOS folder prompt.

Supporting changes: FriendlyError passes through friendlyError()
unchanged so call sites can ship precise localized stories through the
shared presentation; SystemActions gains resolvedChainBinary() plus
run/resolve test seams; ChainErrorBox hugs its content instead of
filling an unbounded dialog; the wizard's answers file is written
synchronously (the async dart:io variants never complete under the
widget-test fake-async zone).

Verified: flutter analyze clean, 53 tests green (6 new wizard error-
path tests incl. clipboard round-trip), plus a live GUI walk on macOS
in dark + light with a stale binary (skew dialog, copy verified via
clipboard) and with the real binary (TCC pre-explanation with the
resolved path, full plan preview).

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-15 00:10:01 +02:00
parent 4ceb5bb567
commit c6da5025ce
11 changed files with 524 additions and 10 deletions

View file

@ -1778,6 +1778,20 @@
"setupFreeTextPrivacyRemote": "Ihre Beschreibung wird an die eingerichtete System-KI gesendet: {model} ({provider}).",
"@setupFreeTextPrivacyRemote": {"placeholders": {"model": {"type": "String"}, "provider": {"type": "String"}}},
"setupFreeTextUnavailable": "Für den Freitext-Weg braucht Ch∆In eine eingerichtete System-KI (Einstellungen → System-KI). Die Auswahl oben funktioniert immer — ganz ohne KI.",
"setupExecHint": "Für Vorschau und Einrichtung führt Studio das Programm „chain“ aus: {path}",
"@setupExecHint": {"placeholders": {"path": {"type": "String"}}},
"setupExecHintTcc": "Das Programm liegt unter {path} — macOS fragt dafür eventuell einmalig nach Zugriff auf diesen Ordner (z. B. „Dokumente“). Das ist zu erwarten und in Ordnung.",
"@setupExecHintTcc": {"placeholders": {"path": {"type": "String"}}},
"setupNoBinaryStepHint": "Das Programm „chain“ wurde auf diesem Rechner nicht gefunden — die Vorschau im nächsten Schritt wird fehlschlagen. Unter „Diagnose“ können Sie es auswählen oder Ch∆In installieren.",
"setupNoBinary": "Das Programm „chain“ wurde auf diesem Rechner nicht gefunden.",
"setupNoBinaryHint": "Ohne das Programm kann der Assistent die Einrichtung nicht anwenden. Wählen Sie es unter „Diagnose“ aus oder installieren Sie Ch∆In neu.",
"setupCliTooOld": "Das installierte „chain“-Programm ist älter als Studio und kennt diesen Assistenten noch nicht.",
"setupCliTooOldHint": "Gefunden wurde: {path}. Bitte Ch∆In aktualisieren (Seite „Diagnose“ → Update, oder im Terminal: chain update apply) und den Assistenten danach erneut öffnen.",
"@setupCliTooOldHint": {"placeholders": {"path": {"type": "String"}}},
"setupPreviewFailed": "Die Plan-Vorschau konnte nicht erstellt werden — das Programm „chain“ meldet einen Fehler.",
"setupApplyFailed": "Die Einrichtung konnte nicht angewendet werden — das Programm „chain“ meldet einen Fehler.",
"setupCliUsedBinary": "Ausgeführt wurde: {path}",
"@setupCliUsedBinary": {"placeholders": {"path": {"type": "String"}}},
"setupFreeTextParseError": "Die System-KI hat keinen verwertbaren Vorschlag geliefert. Wählen Sie oben aus dem Menü — oder versuchen Sie es noch einmal.",
"setupReflectionTitle": "So verstehe ich Ihre Aufgabe",
"setupReflectionScenario": "Worum es geht: {label}",

View file

@ -1817,6 +1817,20 @@
"setupFreeTextPrivacyRemote": "Your description is sent to the configured system AI: {model} ({provider}).",
"@setupFreeTextPrivacyRemote": {"placeholders": {"model": {"type": "String"}, "provider": {"type": "String"}}},
"setupFreeTextUnavailable": "The free-text path needs a configured system AI (Settings → System AI). The choices above always work — no AI required.",
"setupExecHint": "For the preview and setup, Studio runs the “chain” program: {path}",
"@setupExecHint": {"placeholders": {"path": {"type": "String"}}},
"setupExecHintTcc": "The program lives at {path} — macOS may ask once for access to that folder (e.g. “Documents”). That is expected and fine.",
"@setupExecHintTcc": {"placeholders": {"path": {"type": "String"}}},
"setupNoBinaryStepHint": "The “chain” program could not be found on this machine — the preview in the next step will fail. You can pick it under “Doctor”, or install Ch∆In.",
"setupNoBinary": "The “chain” program could not be found on this machine.",
"setupNoBinaryHint": "Without it the assistant cannot apply the setup. Pick it under “Doctor”, or reinstall Ch∆In.",
"setupCliTooOld": "The installed “chain” program is older than Studio and does not know this assistant yet.",
"setupCliTooOldHint": "Found: {path}. Please update Ch∆In (“Doctor” page → update, or in a terminal: chain update apply) and reopen the assistant afterwards.",
"@setupCliTooOldHint": {"placeholders": {"path": {"type": "String"}}},
"setupPreviewFailed": "The plan preview could not be created — the “chain” program reported an error.",
"setupApplyFailed": "The setup could not be applied — the “chain” program reported an error.",
"setupCliUsedBinary": "Executed: {path}",
"@setupCliUsedBinary": {"placeholders": {"path": {"type": "String"}}},
"setupFreeTextParseError": "The system AI did not return a usable suggestion. Pick from the menu above — or try again.",
"setupReflectionTitle": "This is how I read your task",
"setupReflectionScenario": "What it is about: {label}",

View file

@ -5479,6 +5479,66 @@ abstract class AppLocalizations {
/// **'The free-text path needs a configured system AI (Settings → System AI). The choices above always work — no AI required.'**
String get setupFreeTextUnavailable;
/// No description provided for @setupExecHint.
///
/// In en, this message translates to:
/// **'For the preview and setup, Studio runs the “chain” program: {path}'**
String setupExecHint(String path);
/// No description provided for @setupExecHintTcc.
///
/// In en, this message translates to:
/// **'The program lives at {path} — macOS may ask once for access to that folder (e.g. “Documents”). That is expected and fine.'**
String setupExecHintTcc(String path);
/// No description provided for @setupNoBinaryStepHint.
///
/// In en, this message translates to:
/// **'The “chain” program could not be found on this machine — the preview in the next step will fail. You can pick it under “Doctor”, or install Ch∆In.'**
String get setupNoBinaryStepHint;
/// No description provided for @setupNoBinary.
///
/// In en, this message translates to:
/// **'The “chain” program could not be found on this machine.'**
String get setupNoBinary;
/// No description provided for @setupNoBinaryHint.
///
/// In en, this message translates to:
/// **'Without it the assistant cannot apply the setup. Pick it under “Doctor”, or reinstall Ch∆In.'**
String get setupNoBinaryHint;
/// No description provided for @setupCliTooOld.
///
/// In en, this message translates to:
/// **'The installed “chain” program is older than Studio and does not know this assistant yet.'**
String get setupCliTooOld;
/// No description provided for @setupCliTooOldHint.
///
/// In en, this message translates to:
/// **'Found: {path}. Please update Ch∆In (“Doctor” page → update, or in a terminal: chain update apply) and reopen the assistant afterwards.'**
String setupCliTooOldHint(String path);
/// No description provided for @setupPreviewFailed.
///
/// In en, this message translates to:
/// **'The plan preview could not be created — the “chain” program reported an error.'**
String get setupPreviewFailed;
/// No description provided for @setupApplyFailed.
///
/// In en, this message translates to:
/// **'The setup could not be applied — the “chain” program reported an error.'**
String get setupApplyFailed;
/// No description provided for @setupCliUsedBinary.
///
/// In en, this message translates to:
/// **'Executed: {path}'**
String setupCliUsedBinary(String path);
/// No description provided for @setupFreeTextParseError.
///
/// In en, this message translates to:

View file

@ -3238,6 +3238,50 @@ class AppLocalizationsDe extends AppLocalizations {
String get setupFreeTextUnavailable =>
'Für den Freitext-Weg braucht Ch∆In eine eingerichtete System-KI (Einstellungen → System-KI). Die Auswahl oben funktioniert immer — ganz ohne KI.';
@override
String setupExecHint(String path) {
return 'Für Vorschau und Einrichtung führt Studio das Programm „chain“ aus: $path';
}
@override
String setupExecHintTcc(String path) {
return 'Das Programm liegt unter $path — macOS fragt dafür eventuell einmalig nach Zugriff auf diesen Ordner (z. B. „Dokumente“). Das ist zu erwarten und in Ordnung.';
}
@override
String get setupNoBinaryStepHint =>
'Das Programm „chain“ wurde auf diesem Rechner nicht gefunden — die Vorschau im nächsten Schritt wird fehlschlagen. Unter „Diagnose“ können Sie es auswählen oder Ch∆In installieren.';
@override
String get setupNoBinary =>
'Das Programm „chain“ wurde auf diesem Rechner nicht gefunden.';
@override
String get setupNoBinaryHint =>
'Ohne das Programm kann der Assistent die Einrichtung nicht anwenden. Wählen Sie es unter „Diagnose“ aus oder installieren Sie Ch∆In neu.';
@override
String get setupCliTooOld =>
'Das installierte „chain“-Programm ist älter als Studio und kennt diesen Assistenten noch nicht.';
@override
String setupCliTooOldHint(String path) {
return 'Gefunden wurde: $path. Bitte Ch∆In aktualisieren (Seite „Diagnose“ → Update, oder im Terminal: chain update apply) und den Assistenten danach erneut öffnen.';
}
@override
String get setupPreviewFailed =>
'Die Plan-Vorschau konnte nicht erstellt werden — das Programm „chain“ meldet einen Fehler.';
@override
String get setupApplyFailed =>
'Die Einrichtung konnte nicht angewendet werden — das Programm „chain“ meldet einen Fehler.';
@override
String setupCliUsedBinary(String path) {
return 'Ausgeführt wurde: $path';
}
@override
String get setupFreeTextParseError =>
'Die System-KI hat keinen verwertbaren Vorschlag geliefert. Wählen Sie oben aus dem Menü — oder versuchen Sie es noch einmal.';

View file

@ -3234,6 +3234,50 @@ class AppLocalizationsEn extends AppLocalizations {
String get setupFreeTextUnavailable =>
'The free-text path needs a configured system AI (Settings → System AI). The choices above always work — no AI required.';
@override
String setupExecHint(String path) {
return 'For the preview and setup, Studio runs the “chain” program: $path';
}
@override
String setupExecHintTcc(String path) {
return 'The program lives at $path — macOS may ask once for access to that folder (e.g. “Documents”). That is expected and fine.';
}
@override
String get setupNoBinaryStepHint =>
'The “chain” program could not be found on this machine — the preview in the next step will fail. You can pick it under “Doctor”, or install Ch∆In.';
@override
String get setupNoBinary =>
'The “chain” program could not be found on this machine.';
@override
String get setupNoBinaryHint =>
'Without it the assistant cannot apply the setup. Pick it under “Doctor”, or reinstall Ch∆In.';
@override
String get setupCliTooOld =>
'The installed “chain” program is older than Studio and does not know this assistant yet.';
@override
String setupCliTooOldHint(String path) {
return 'Found: $path. Please update Ch∆In (“Doctor” page → update, or in a terminal: chain update apply) and reopen the assistant afterwards.';
}
@override
String get setupPreviewFailed =>
'The plan preview could not be created — the “chain” program reported an error.';
@override
String get setupApplyFailed =>
'The setup could not be applied — the “chain” program reported an error.';
@override
String setupCliUsedBinary(String path) {
return 'Executed: $path';
}
@override
String get setupFreeTextParseError =>
'The system AI did not return a usable suggestion. Pick from the menu above — or try again.';