























@@ -21,6 +21,7 @@ const fsSafeMocks = vi.hoisted(() => ({
21212222const gatewayMocks = vi.hoisted(() => ({
2323callGateway: vi.fn(),
24+isGatewayCredentialsRequiredError: vi.fn(),
2425isGatewayTransportError: vi.fn(),
2526}));
2627@@ -32,6 +33,7 @@ vi.mock("../config/config.js", async () => ({
32333334vi.mock("../gateway/call.js", () => ({
3435callGateway: gatewayMocks.callGateway,
36+isGatewayCredentialsRequiredError: gatewayMocks.isGatewayCredentialsRequiredError,
3537isGatewayTransportError: gatewayMocks.isGatewayTransportError,
3638}));
3739@@ -98,6 +100,11 @@ describe("agents delete command", () => {
98100gatewayMocks.callGateway.mockRejectedValue(
99101Object.assign(new Error("closed"), { name: "GatewayTransportError" }),
100102);
103+gatewayMocks.isGatewayCredentialsRequiredError.mockReset();
104+gatewayMocks.isGatewayCredentialsRequiredError.mockImplementation(
105+(error: unknown) =>
106+error instanceof Error && error.name === "GatewayCredentialsRequiredError",
107+);
101108gatewayMocks.isGatewayTransportError.mockReset();
102109gatewayMocks.isGatewayTransportError.mockImplementation(
103110(error: unknown) => error instanceof Error && error.name === "GatewayTransportError",
@@ -150,6 +157,50 @@ describe("agents delete command", () => {
150157});
151158});
152159160+it("falls back to local deletion when the optional Gateway probe needs credentials", async () => {
161+await withStateDirEnv("openclaw-agents-delete-gateway-auth-", async ({ stateDir }) => {
162+const now = Date.now();
163+const cfg: OpenClawConfig = {
164+agents: {
165+list: [
166+{ id: "main", workspace: path.join(stateDir, "workspace-shared") },
167+{ id: "ops", workspace: path.join(stateDir, "workspace-shared") },
168+],
169+},
170+} satisfies OpenClawConfig;
171+await arrangeAgentsDeleteTest({
172+ stateDir,
173+ cfg,
174+deletedAgentId: "ops",
175+sessions: {
176+"agent:ops:main": { sessionId: "sess-ops-main", updatedAt: now + 1 },
177+"agent:main:main": { sessionId: "sess-main", updatedAt: now + 2 },
178+},
179+});
180+gatewayMocks.callGateway.mockRejectedValue(
181+Object.assign(
182+new Error("gateway agents.delete requires credentials before opening a websocket"),
183+{
184+name: "GatewayCredentialsRequiredError",
185+method: "agents.delete",
186+configPath: path.join(stateDir, "openclaw.json"),
187+},
188+),
189+);
190+191+await agentsDeleteCommand({ id: "ops", force: true, json: true }, runtime);
192+193+expect(runtime.exit).not.toHaveBeenCalled();
194+expect(gatewayMocks.callGateway).toHaveBeenCalledOnce();
195+expect(configMocks.replaceConfigFile).toHaveBeenCalledOnce();
196+const output = readJsonLogs()[0];
197+expect(output?.agentId).toBe("ops");
198+expect(output?.workspaceRetained).toBe(true);
199+expect(output?.workspaceRetainedReason).toBe("shared");
200+expect(output?.transport).toBeUndefined();
201+});
202+});
203+153204it("purges deleted agent entries from the session store", async () => {
154205await withStateDirEnv("openclaw-agents-delete-", async ({ stateDir }) => {
155206const now = Date.now();
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。