swarm-ui: stop a claude login whose dialog closed while it was starting
This commit is contained in:
parent
20e2f53592
commit
41cc2f5e8e
3 changed files with 24 additions and 1 deletions
|
|
@ -2,7 +2,8 @@
|
||||||
// login minter. Opening it starts the login (`POST …/claude-login`), which
|
// login minter. Opening it starts the login (`POST …/claude-login`), which
|
||||||
// answers with the URL claude printed; the operator opens it and pastes the
|
// answers with the URL claude printed; the operator opens it and pastes the
|
||||||
// code back (`POST …/claude-login/code`). Closing it while the code is
|
// code back (`POST …/claude-login/code`). Closing it while the code is
|
||||||
// still awaited stops the login (`DELETE …/claude-login`).
|
// still awaited stops the login (`DELETE …/claude-login`). Closing while the
|
||||||
|
// start is still in flight stops it once the start answers.
|
||||||
//
|
//
|
||||||
// Mounted only while open, so each open is a fresh login.
|
// Mounted only while open, so each open is a fresh login.
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
|
@ -18,6 +19,7 @@ import {
|
||||||
claudeLoginPath,
|
claudeLoginPath,
|
||||||
leavesLoginRunning,
|
leavesLoginRunning,
|
||||||
pastedCode,
|
pastedCode,
|
||||||
|
startOutlivedDialog,
|
||||||
type LoginStep,
|
type LoginStep,
|
||||||
} from "./ClaudeLoginSteps.js";
|
} from "./ClaudeLoginSteps.js";
|
||||||
import "./ClaudeLoginDialog.css";
|
import "./ClaudeLoginDialog.css";
|
||||||
|
|
@ -42,6 +44,10 @@ export function ClaudeLoginDialog({
|
||||||
try {
|
try {
|
||||||
const r = await fetch(claudeLoginPath(agent), { method: "POST" });
|
const r = await fetch(claudeLoginPath(agent), { method: "POST" });
|
||||||
const problem = await problemOf(r);
|
const problem = await problemOf(r);
|
||||||
|
if (startOutlivedDialog(live, problem)) {
|
||||||
|
void fetch(claudeLoginPath(agent), { method: "DELETE" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
const next = afterStart(
|
const next = afterStart(
|
||||||
problem ? { problem } : ((await r.json()) as { url: string }),
|
problem ? { problem } : ((await r.json()) as { url: string }),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,16 @@ export function leavesLoginRunning(s: LoginStep): boolean {
|
||||||
return s.step === "code";
|
return s.step === "code";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whether a start that answered after the dialog went away left a login
|
||||||
|
// running: it did unless the start itself failed. The dialog stops it then,
|
||||||
|
// since nothing is left to.
|
||||||
|
export function startOutlivedDialog(
|
||||||
|
dialogLive: boolean,
|
||||||
|
problem: ProblemDetails | null,
|
||||||
|
): boolean {
|
||||||
|
return !dialogLive && problem === null;
|
||||||
|
}
|
||||||
|
|
||||||
// What the code form may submit: the pasted code without surrounding
|
// What the code form may submit: the pasted code without surrounding
|
||||||
// whitespace, or nothing.
|
// whitespace, or nothing.
|
||||||
export function pastedCode(raw: string): string | null {
|
export function pastedCode(raw: string): string | null {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
claudeLoginPath,
|
claudeLoginPath,
|
||||||
leavesLoginRunning,
|
leavesLoginRunning,
|
||||||
pastedCode,
|
pastedCode,
|
||||||
|
startOutlivedDialog,
|
||||||
} from "../src/agent/claude-login/ClaudeLoginSteps.ts";
|
} from "../src/agent/claude-login/ClaudeLoginSteps.ts";
|
||||||
|
|
||||||
test("the routes name the agent, escaped", () => {
|
test("the routes name the agent, escaped", () => {
|
||||||
|
|
@ -48,6 +49,12 @@ test("only a login waiting for its code is stopped on close", () => {
|
||||||
assert.equal(leavesLoginRunning({ step: "stored" }), false);
|
assert.equal(leavesLoginRunning({ step: "stored" }), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("a start that answers after the dialog closed is stopped, unless it failed", () => {
|
||||||
|
assert.equal(startOutlivedDialog(false, null), true);
|
||||||
|
assert.equal(startOutlivedDialog(true, null), false);
|
||||||
|
assert.equal(startOutlivedDialog(false, { detail: "no minter" }), false);
|
||||||
|
});
|
||||||
|
|
||||||
test("a pasted code is trimmed, and a blank one is nothing", () => {
|
test("a pasted code is trimmed, and a blank one is nothing", () => {
|
||||||
assert.equal(pastedCode(" abc-def \n"), "abc-def");
|
assert.equal(pastedCode(" abc-def \n"), "abc-def");
|
||||||
assert.equal(pastedCode(" \n "), null);
|
assert.equal(pastedCode(" \n "), null);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue