mirror of
https://github.com/morluto/rea.git
synced 2026-11-08 07:46:28 +00:00
fix(cli): await browser scenario cleanup on interrupts
Translate browser scenario CLI interrupts into cancellation and await owned provider cleanup. Preserve authenticated observations and cancelled steps with conventional exit codes 130/143. Refs #1771.
This commit is contained in:
1 parent
0bdc7a40ac
commit
aaeadf2d4c
3 files changed
+258
-49
No files matched your search
@@ -2,6 +2,7 @@ import { Cli } from "incur";
|
||||
import { z } from "zod";
|
||||
|
||||
import { captureBrowserScenario } from "./application/BrowserScenarioCaptureService.js";
|
||||
import { withCommandCancellation } from "./cli/commandCancellation.js";
|
||||
import { CLI_COMMANDS } from "./cliCommandNames.js";
|
||||
import { parseCliJsonInput, resolveCliJsonPaths } from "./cliJsonInput.js";
|
||||
import { logCliCommand } from "./cliLogging.js";
|
||||
@@ -31,58 +32,63 @@ export const registerBrowserScenarioCommands = (
|
||||
.describe("Inline browser scenario JSON or JSON file path"),
|
||||
}),
|
||||
run: ({ args }) =>
|
||||
logCliCommand(logger, CLI_COMMANDS.captureBrowserScenario, async () => {
|
||||
const input = await parseCliJsonInput(args.inputJson, OPERATION);
|
||||
if (!input.ok) return input.error;
|
||||
const scenario = browserScenarioSchema.safeParse(
|
||||
resolveCliJsonPaths(input.value, [["browser", "executable_path"]]),
|
||||
);
|
||||
if (!scenario.success)
|
||||
return cliError(
|
||||
new AnalysisInputError(
|
||||
OPERATION,
|
||||
{ cause: scenario.error },
|
||||
projectInputIssues(scenario.error.issues, input.value),
|
||||
),
|
||||
withCommandCancellation((signal) =>
|
||||
logCliCommand(logger, CLI_COMMANDS.captureBrowserScenario, async () => {
|
||||
const input = await parseCliJsonInput(args.inputJson, OPERATION);
|
||||
if (!input.ok) return input.error;
|
||||
const scenario = browserScenarioSchema.safeParse(
|
||||
resolveCliJsonPaths(input.value, [["browser", "executable_path"]]),
|
||||
);
|
||||
// Load Playwright only for this command, not during CLI startup.
|
||||
const { createBrowserScenarioProvider } =
|
||||
await import("./composition/browserScenario.js");
|
||||
const provider = createBrowserScenarioProvider(environment);
|
||||
let result:
|
||||
| Awaited<ReturnType<typeof captureBrowserScenario>>
|
||||
| undefined;
|
||||
try {
|
||||
result = await captureBrowserScenario(provider, scenario.data);
|
||||
return result.ok ? result.value : cliError(result.error);
|
||||
} finally {
|
||||
if (!scenario.success)
|
||||
return cliError(
|
||||
new AnalysisInputError(
|
||||
OPERATION,
|
||||
{ cause: scenario.error },
|
||||
projectInputIssues(scenario.error.issues, input.value),
|
||||
),
|
||||
);
|
||||
// Load Playwright only for this command, not during CLI startup.
|
||||
const { createBrowserScenarioProvider } =
|
||||
await import("./composition/browserScenario.js");
|
||||
const provider = createBrowserScenarioProvider(environment);
|
||||
let result:
|
||||
| Awaited<ReturnType<typeof captureBrowserScenario>>
|
||||
| undefined;
|
||||
try {
|
||||
await provider?.close?.();
|
||||
} catch (cause: unknown) {
|
||||
// Failed captures already retain their primary error and partial
|
||||
// observations. A cleanup retry must not replace that outcome.
|
||||
if (result?.ok)
|
||||
throw new BrowserObservationError(OPERATION, "cleanup_failed", {
|
||||
cause,
|
||||
cleanup:
|
||||
cause instanceof AnalysisError && cause.cleanup !== undefined
|
||||
? cause.cleanup
|
||||
: {
|
||||
reason:
|
||||
cause instanceof Error
|
||||
? cause.message
|
||||
: String(cause),
|
||||
resources:
|
||||
cause instanceof AnalysisError &&
|
||||
cause.cleanupResources.length > 0
|
||||
? cause.cleanupResources
|
||||
: ["browser_transport"],
|
||||
},
|
||||
partialObservation: result.value,
|
||||
});
|
||||
result = await captureBrowserScenario(provider, scenario.data, {
|
||||
signal,
|
||||
});
|
||||
return result.ok ? result.value : cliError(result.error);
|
||||
} finally {
|
||||
try {
|
||||
await provider?.close?.();
|
||||
} catch (cause: unknown) {
|
||||
// Failed captures already retain their primary error and partial
|
||||
// observations. A cleanup retry must not replace that outcome.
|
||||
if (result?.ok)
|
||||
throw new BrowserObservationError(OPERATION, "cleanup_failed", {
|
||||
cause,
|
||||
cleanup:
|
||||
cause instanceof AnalysisError &&
|
||||
cause.cleanup !== undefined
|
||||
? cause.cleanup
|
||||
: {
|
||||
reason:
|
||||
cause instanceof Error
|
||||
? cause.message
|
||||
: String(cause),
|
||||
resources:
|
||||
cause instanceof AnalysisError &&
|
||||
cause.cleanupResources.length > 0
|
||||
? cause.cleanupResources
|
||||
: ["browser_transport"],
|
||||
},
|
||||
partialObservation: result.value,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
}),
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user