mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-20 18:00:23 +00:00
fix: show cleanup warning when script is interrupted by Ctrl+C (#723)
Previously, when a user hit Ctrl+C during script execution, the CLI silently exited with code 130. This left users unaware that a server may have already been created and could still be running, potentially incurring charges. Now shows a warning about orphaned resources before exiting. Agent: ux-engineer Co-authored-by: A <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8140c1b61b
commit
96d96b3ef6
2 changed files with 17 additions and 4 deletions
|
|
@ -11,7 +11,7 @@ import { loadManifest } from "../manifest";
|
|||
*
|
||||
* - Exit code 127: "A required command was not found" (missing bash/curl/ssh/jq)
|
||||
* - Exit code 126: "A command was found but could not be executed" (permission denied)
|
||||
* - Exit code 130: Silent exit for Ctrl+C (user interrupt)
|
||||
* - Exit code 130: Cleanup warning + exit for Ctrl+C (user interrupt)
|
||||
* - Generic failures: "Common causes" with credential/rate-limit/dependency hints
|
||||
* - runBash: Sets SPAWN_PROMPT and SPAWN_MODE env vars when prompt is provided
|
||||
* - runBash: Resolves successfully for exit code 0
|
||||
|
|
@ -23,6 +23,7 @@ const mockManifest = createMockManifest();
|
|||
|
||||
// Mock @clack/prompts
|
||||
const mockLogError = mock(() => {});
|
||||
const mockLogWarn = mock(() => {});
|
||||
const mockLogInfo = mock(() => {});
|
||||
const mockLogStep = mock(() => {});
|
||||
const mockSpinnerStart = mock(() => {});
|
||||
|
|
@ -38,7 +39,7 @@ mock.module("@clack/prompts", () => ({
|
|||
log: {
|
||||
step: mockLogStep,
|
||||
info: mockLogInfo,
|
||||
warn: mock(() => {}),
|
||||
warn: mockLogWarn,
|
||||
error: mockLogError,
|
||||
},
|
||||
intro: mock(() => {}),
|
||||
|
|
@ -59,6 +60,7 @@ describe("execScript bash execution error handling", () => {
|
|||
beforeEach(async () => {
|
||||
consoleMocks = createConsoleMocks();
|
||||
mockLogError.mockClear();
|
||||
mockLogWarn.mockClear();
|
||||
mockLogInfo.mockClear();
|
||||
mockLogStep.mockClear();
|
||||
mockSpinnerStart.mockClear();
|
||||
|
|
@ -174,7 +176,7 @@ describe("execScript bash execution error handling", () => {
|
|||
// ── Exit code 130: Ctrl+C (user interrupt) ──────────────────────────────
|
||||
|
||||
describe("exit code 130 - user interrupt", () => {
|
||||
it("should exit silently with code 130 for Ctrl+C", async () => {
|
||||
it("should exit with code 130 and show cleanup warning for Ctrl+C", async () => {
|
||||
mockFetchWithScript("exit 130");
|
||||
await loadManifest(true);
|
||||
|
||||
|
|
@ -187,10 +189,17 @@ describe("execScript bash execution error handling", () => {
|
|||
// Should exit with 130
|
||||
expect(processExitSpy).toHaveBeenCalledWith(130);
|
||||
|
||||
// Should NOT show error messages for Ctrl+C
|
||||
// Should NOT show error messages for Ctrl+C (no "Spawn script failed")
|
||||
const clackErrors = mockLogError.mock.calls.map((c: any[]) => c.join(" "));
|
||||
const errorMessages = clackErrors.filter((e: string) => e.includes("Spawn script failed"));
|
||||
expect(errorMessages).toHaveLength(0);
|
||||
|
||||
// Should show warning about orphaned resources
|
||||
const warnMessages = mockLogWarn.mock.calls.map((c: any[]) => c.join(" "));
|
||||
const warnText = warnMessages.join("\n");
|
||||
expect(warnText).toContain("interrupted");
|
||||
expect(warnText).toContain("server");
|
||||
expect(warnText).toContain("cloud provider dashboard");
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -648,6 +648,10 @@ async function execScript(cloud: string, agent: string, prompt?: string, authHin
|
|||
} catch (err) {
|
||||
const errMsg = getErrorMessage(err);
|
||||
if (errMsg.includes("interrupted by user")) {
|
||||
console.error();
|
||||
p.log.warn("Script interrupted (Ctrl+C).");
|
||||
p.log.warn("If a server was already created, it may still be running.");
|
||||
p.log.warn(` Check your cloud provider dashboard to stop or delete any unused servers.`);
|
||||
process.exit(130);
|
||||
}
|
||||
lastErr = errMsg;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue