fix(onboard): preserve JSON errors when no terminal is available (#129437)

This commit is contained in:
Peter Steinberger
2026-08-25 16:31:09 -07:00
committed by GitHub
parent 7782e4af5c
commit 948ae80ae6
3 changed files with 12 additions and 4 deletions
+2
View File
@@ -369,6 +369,8 @@ Output: `--suppress-gateway-token-output` disables the automatic Control UI hand
<Note>
`--json` does not imply non-interactive mode in guided or classic onboarding.
Without an interactive terminal, both onboarding modes return a structured
JSON error; add `--non-interactive --accept-risk` for automation.
With `--modern`, JSON is a one-shot OpenClaw overview and exits after that
single result. Use `--non-interactive` for other scripts.
</Note>
+9 -2
View File
@@ -270,14 +270,21 @@ describe("setupWizardCommand", () => {
it.each([
["guided", { reset: true }],
["classic", { reset: true, classic: true }],
["guided JSON", { reset: true, json: true }],
["classic JSON", { reset: true, classic: true, json: true }],
] as const)("rejects headless %s onboarding before reset", async (_label, options) => {
const runtime = makeRuntime();
mocks.hasInteractiveOnboardingTty.mockReturnValue(false);
await setupWizardCommand(options, runtime);
expect(runtime.error).toHaveBeenCalledWith(
"Onboarding needs an interactive TTY. Use `openclaw onboard --non-interactive --accept-risk ...` for automation.",
const message =
"Onboarding needs an interactive TTY. Use `openclaw onboard --non-interactive --accept-risk ...` for automation.";
expect(runtime.error).toHaveBeenCalledWith(message);
expect(vi.mocked(runtime.log).mock.calls).toEqual(
"json" in options
? [[JSON.stringify({ ok: false, phase: "options", message }, null, 2)]]
: [],
);
expect(runtime.exit).toHaveBeenCalledWith(1);
expect(mocks.readConfigFileSnapshot).not.toHaveBeenCalled();
+1 -2
View File
@@ -644,8 +644,7 @@ export async function setupWizardCommand(
if (!normalizedOpts.nonInteractive && !hasInteractiveOnboardingTty()) {
// Reset is destructive, so prove the selected interactive surface can run
// before reading or moving any operator state.
runtime.error(t("wizard.guided.ttyRequired"));
runtime.exit(1);
rejectOption(normalizedOpts, runtime, t("wizard.guided.ttyRequired"));
return;
}