mirror of
https://github.com/morluto/rea.git
synced 2026-11-14 18:52:48 +00:00
fix(setup): show a known manual step in the interactive dry run
The approval prompt now discloses a client's manual completion step, but the interactive TTY dry run still printed only the planned file changes, so `rea setup --dry-run --client grok_bot` hid the Grok Bot connector step. The dry-run renderer now prints the planned result's remediation the same way. Refs #7692 Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
1 parent
bbad1db998
commit
cf58037726
3 files changed
+62
-26
No files matched your search
@@ -94,9 +94,17 @@ export const renderSetupProgress = (event: SetupProgressEvent): void => {
|
||||
};
|
||||
|
||||
/** Show the resolved dry-run plan to a human at an interactive terminal. */
|
||||
export const renderSetupDryRun = (actions: readonly SetupAction[]): void => {
|
||||
export const renderSetupDryRun = (
|
||||
actions: readonly SetupAction[],
|
||||
remediation?: string,
|
||||
): void => {
|
||||
intro("REA setup plan", promptStreams);
|
||||
renderPreflight(actions);
|
||||
// A known manual step belongs to the plan, as it does at approval.
|
||||
if (remediation !== undefined) {
|
||||
writeLine("│");
|
||||
writeLine(`│ ${remediation}`);
|
||||
}
|
||||
outro("Dry run complete. No changes were made.", promptStreams);
|
||||
};
|
||||
|
||||
|
||||
@@ -282,7 +282,8 @@ const runSetupCommand = async (
|
||||
!input.formatExplicit &&
|
||||
hasInteractiveTerminal()
|
||||
) {
|
||||
if (result.status === "planned") renderSetupDryRun(result.plannedActions);
|
||||
if (result.status === "planned")
|
||||
renderSetupDryRun(result.plannedActions, result.remediation);
|
||||
else renderInteractiveSetupResult(result, environment);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -277,38 +277,47 @@ const runSetupInTty = async (
|
||||
return { exitCode, output };
|
||||
};
|
||||
|
||||
const manualConnectorFixture = async (): Promise<{
|
||||
readonly home: string;
|
||||
readonly environment: NodeJS.ProcessEnv;
|
||||
}> => {
|
||||
const home = await createTestTempDirectory("rea-cli-setup-manual-");
|
||||
const bin = join(home, "bin");
|
||||
await mkdir(bin);
|
||||
const hopper = join(bin, "hopper");
|
||||
await writeFile(hopper, "#!/bin/sh\necho 'Hopper Disassembler v6.0.0'\n", {
|
||||
mode: 0o755,
|
||||
});
|
||||
// Linux's executable probe runs ldd before accepting this inert launcher.
|
||||
await writeFile(join(bin, "ldd"), "#!/bin/sh\nexit 0\n", { mode: 0o755 });
|
||||
for (const runner of ["npx", "npm", "bun"])
|
||||
await writeFile(join(bin, runner), "#!/bin/sh\nexit 99\n", {
|
||||
mode: 0o755,
|
||||
});
|
||||
return {
|
||||
home,
|
||||
environment: {
|
||||
PATH: `${bin}:${process.env.PATH ?? ""}`,
|
||||
HOPPER_LAUNCHER_PATH: hopper,
|
||||
DSH_HOME: join(home, ".dsh"),
|
||||
DSH_AGENTS_HOME: join(home, ".dsh-agents"),
|
||||
XDG_DATA_HOME: join(home, ".local/share"),
|
||||
XDG_CACHE_HOME: join(home, ".cache"),
|
||||
XDG_STATE_HOME: join(home, ".local/state"),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
describe("manual connector approval", () => {
|
||||
it.skipIf(process.platform === "win32").each([true, false])(
|
||||
"discloses the manual step before approval (apply: %s)",
|
||||
async (approved) => {
|
||||
const home = await createTestTempDirectory("rea-cli-setup-manual-");
|
||||
const bin = join(home, "bin");
|
||||
await mkdir(bin);
|
||||
const hopper = join(bin, "hopper");
|
||||
await writeFile(
|
||||
hopper,
|
||||
"#!/bin/sh\necho 'Hopper Disassembler v6.0.0'\n",
|
||||
{ mode: 0o755 },
|
||||
);
|
||||
// Linux's executable probe runs ldd before accepting this inert launcher.
|
||||
await writeFile(join(bin, "ldd"), "#!/bin/sh\nexit 0\n", { mode: 0o755 });
|
||||
for (const runner of ["npx", "npm", "bun"])
|
||||
await writeFile(join(bin, runner), "#!/bin/sh\nexit 99\n", {
|
||||
mode: 0o755,
|
||||
});
|
||||
const { home, environment } = await manualConnectorFixture();
|
||||
const { output, exitCode } = await runSetupInTty(
|
||||
home,
|
||||
["--client", "grok_bot"],
|
||||
approved,
|
||||
{
|
||||
PATH: `${bin}:${process.env.PATH ?? ""}`,
|
||||
HOPPER_LAUNCHER_PATH: hopper,
|
||||
DSH_HOME: join(home, ".dsh"),
|
||||
DSH_AGENTS_HOME: join(home, ".dsh-agents"),
|
||||
XDG_DATA_HOME: join(home, ".local/share"),
|
||||
XDG_CACHE_HOME: join(home, ".cache"),
|
||||
XDG_STATE_HOME: join(home, ".local/state"),
|
||||
},
|
||||
environment,
|
||||
);
|
||||
const prompt = output.indexOf("Apply this change?");
|
||||
const remediation = manualRegistrationRemediation("grok_bot");
|
||||
@@ -328,6 +337,24 @@ describe("manual connector approval", () => {
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it.skipIf(process.platform === "win32")(
|
||||
"shows the manual step in a TTY dry run",
|
||||
async () => {
|
||||
const { home, environment } = await manualConnectorFixture();
|
||||
const { output, exitCode } = await runSetupInTty(
|
||||
home,
|
||||
["--dry-run", "--client", "grok_bot"],
|
||||
undefined,
|
||||
environment,
|
||||
);
|
||||
const remediation = manualRegistrationRemediation("grok_bot");
|
||||
expect(remediation).toBeDefined();
|
||||
expect(exitCode, output).toBe(0);
|
||||
expect(output).toContain(remediation);
|
||||
expect(output).toContain("Dry run complete. No changes were made.");
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("TTY setup dry run", () => {
|
||||
|
||||
Reference in new issue
Block a user