refactor(test): dedupe auth-choice e2e setup plumbing
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { RuntimeEnv } from "../runtime.js";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
import type { AuthChoice } from "./onboard-types.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
@@ -12,6 +10,12 @@ import {
|
||||
ZAI_CODING_CN_BASE_URL,
|
||||
ZAI_CODING_GLOBAL_BASE_URL,
|
||||
} from "./onboard-auth.js";
|
||||
import {
|
||||
createExitThrowingRuntime,
|
||||
createWizardPrompter,
|
||||
readAuthProfilesForAgent,
|
||||
setupAuthTestEnv,
|
||||
} from "./test-wizard-helpers.js";
|
||||
|
||||
vi.mock("../providers/github-copilot-auth.js", () => ({
|
||||
githubCopilotLoginCommand: vi.fn(async () => {}),
|
||||
@@ -27,8 +31,6 @@ vi.mock("../plugins/providers.js", () => ({
|
||||
resolvePluginProviders,
|
||||
}));
|
||||
|
||||
const noopAsync = async () => {};
|
||||
const noop = () => {};
|
||||
const authProfilePathFor = (agentDir: string) => path.join(agentDir, "auth-profiles.json");
|
||||
const requireAgentDir = () => {
|
||||
const agentDir = process.env.OPENCLAW_AGENT_DIR;
|
||||
@@ -54,6 +56,21 @@ describe("applyAuthChoice", () => {
|
||||
"CHUTES_CLIENT_ID",
|
||||
]);
|
||||
let tempStateDir: string | null = null;
|
||||
async function setupTempState() {
|
||||
const env = await setupAuthTestEnv("openclaw-auth-");
|
||||
tempStateDir = env.stateDir;
|
||||
}
|
||||
function createPrompter(overrides: Partial<WizardPrompter>): WizardPrompter {
|
||||
return createWizardPrompter(overrides, { defaultSelect: "" });
|
||||
}
|
||||
async function readAuthProfiles() {
|
||||
return await readAuthProfilesForAgent<{
|
||||
profiles?: Record<
|
||||
string,
|
||||
{ key?: string; access?: string; refresh?: string; provider?: string }
|
||||
>;
|
||||
}>(requireAgentDir());
|
||||
}
|
||||
|
||||
afterEach(async () => {
|
||||
vi.unstubAllGlobals();
|
||||
@@ -68,30 +85,12 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("does not throw when openai-codex oauth fails", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
loginOpenAICodexOAuth.mockRejectedValueOnce(new Error("oauth failed"));
|
||||
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select: vi.fn(async () => "" as never),
|
||||
multiselect: vi.fn(async () => []),
|
||||
text: vi.fn(async () => ""),
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({});
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
await expect(
|
||||
applyAuthChoice({
|
||||
@@ -105,33 +104,15 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("prompts and writes MiniMax API key when selecting minimax-api", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("sk-minimax-test");
|
||||
const select: WizardPrompter["select"] = vi.fn(
|
||||
async (params) => params.options[0]?.value as never,
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "minimax-api",
|
||||
@@ -149,42 +130,22 @@ describe("applyAuthChoice", () => {
|
||||
mode: "api_key",
|
||||
});
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["minimax:default"]?.key).toBe("sk-minimax-test");
|
||||
});
|
||||
|
||||
it("prompts and writes MiniMax API key when selecting minimax-api-key-cn", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("sk-minimax-test");
|
||||
const select: WizardPrompter["select"] = vi.fn(
|
||||
async (params) => params.options[0]?.value as never,
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "minimax-api-key-cn",
|
||||
@@ -203,42 +164,22 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
expect(result.config.models?.providers?.["minimax-cn"]?.baseUrl).toBe(MINIMAX_CN_API_BASE_URL);
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["minimax-cn:default"]?.key).toBe("sk-minimax-test");
|
||||
});
|
||||
|
||||
it("prompts and writes Synthetic API key when selecting synthetic-api-key", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("sk-synthetic-test");
|
||||
const select: WizardPrompter["select"] = vi.fn(
|
||||
async (params) => params.options[0]?.value as never,
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "synthetic-api-key",
|
||||
@@ -256,42 +197,22 @@ describe("applyAuthChoice", () => {
|
||||
mode: "api_key",
|
||||
});
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["synthetic:default"]?.key).toBe("sk-synthetic-test");
|
||||
});
|
||||
|
||||
it("prompts and writes Hugging Face API key when selecting huggingface-api-key", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("hf-test-token");
|
||||
const select: WizardPrompter["select"] = vi.fn(
|
||||
async (params) => params.options[0]?.value as never,
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "huggingface-api-key",
|
||||
@@ -310,19 +231,14 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
expect(result.config.agents?.defaults?.model?.primary).toMatch(/^huggingface\/.+/);
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["huggingface:default"]?.key).toBe("hf-test-token");
|
||||
});
|
||||
|
||||
it("prompts for Z.AI endpoint when selecting zai-api-key", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("zai-test-key");
|
||||
const select = vi.fn(async (params: { message: string }) => {
|
||||
@@ -332,23 +248,12 @@ describe("applyAuthChoice", () => {
|
||||
return "default";
|
||||
});
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
const prompter = createPrompter({
|
||||
select: select as WizardPrompter["select"],
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
});
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "zai-api-key",
|
||||
@@ -364,40 +269,24 @@ describe("applyAuthChoice", () => {
|
||||
expect(result.config.models?.providers?.zai?.baseUrl).toBe(ZAI_CODING_CN_BASE_URL);
|
||||
expect(result.config.agents?.defaults?.model?.primary).toBe("zai/glm-5");
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["zai:default"]?.key).toBe("zai-test-key");
|
||||
});
|
||||
|
||||
it("uses endpoint-specific auth choice without prompting for Z.AI endpoint", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("zai-test-key");
|
||||
const select = vi.fn(async () => "default");
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
const prompter = createPrompter({
|
||||
select: select as WizardPrompter["select"],
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
});
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "zai-coding-global",
|
||||
@@ -414,10 +303,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("maps apiKey + tokenProvider=huggingface to huggingface-api-key flow", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
delete process.env.HF_TOKEN;
|
||||
delete process.env.HUGGINGFACE_HUB_TOKEN;
|
||||
|
||||
@@ -427,23 +313,8 @@ describe("applyAuthChoice", () => {
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const confirm = vi.fn(async () => false);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm,
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text, confirm });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "apiKey",
|
||||
@@ -464,41 +335,21 @@ describe("applyAuthChoice", () => {
|
||||
expect(result.config.agents?.defaults?.model?.primary).toMatch(/^huggingface\/.+/);
|
||||
expect(text).not.toHaveBeenCalled();
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["huggingface:default"]?.key).toBe("hf-token-provider-test");
|
||||
});
|
||||
it("does not override the global default model when selecting xai-api-key without setDefaultModel", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("sk-xai-test");
|
||||
const select: WizardPrompter["select"] = vi.fn(
|
||||
async (params) => params.options[0]?.value as never,
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "xai-api-key",
|
||||
@@ -517,37 +368,17 @@ describe("applyAuthChoice", () => {
|
||||
expect(result.config.agents?.defaults?.model?.primary).toBe("openai/gpt-4o-mini");
|
||||
expect(result.agentModelOverride).toBe("xai/grok-4");
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["xai:default"]?.key).toBe("sk-xai-test");
|
||||
});
|
||||
|
||||
it("sets default model when selecting github-copilot", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select: vi.fn(async () => "" as never),
|
||||
multiselect: vi.fn(async () => []),
|
||||
text: vi.fn(async () => ""),
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({});
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const stdin = process.stdin as NodeJS.ReadStream & { isTTY?: boolean };
|
||||
const hadOwnIsTTY = Object.prototype.hasOwnProperty.call(stdin, "isTTY");
|
||||
@@ -578,33 +409,15 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("does not override the default model when selecting opencode-zen without setDefaultModel", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
const text = vi.fn().mockResolvedValue("sk-opencode-zen-test");
|
||||
const select: WizardPrompter["select"] = vi.fn(
|
||||
async (params) => params.options[0]?.value as never,
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "opencode-zen",
|
||||
@@ -629,30 +442,12 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("does not persist literal 'undefined' when Anthropic API key prompt returns undefined", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
delete process.env.ANTHROPIC_API_KEY;
|
||||
|
||||
const text = vi.fn(async () => undefined as unknown as string);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select: vi.fn(async () => "" as never),
|
||||
multiselect: vi.fn(async () => []),
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "apiKey",
|
||||
@@ -667,9 +462,7 @@ describe("applyAuthChoice", () => {
|
||||
mode: "api_key",
|
||||
});
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["anthropic:default"]?.key).toBe("");
|
||||
@@ -677,30 +470,12 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("does not persist literal 'undefined' when OpenRouter API key prompt returns undefined", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
delete process.env.OPENROUTER_API_KEY;
|
||||
|
||||
const text = vi.fn(async () => undefined as unknown as string);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select: vi.fn(async () => "" as never),
|
||||
multiselect: vi.fn(async () => []),
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ text });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "openrouter-api-key",
|
||||
@@ -715,9 +490,7 @@ describe("applyAuthChoice", () => {
|
||||
mode: "api_key",
|
||||
});
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["openrouter:default"]?.key).toBe("");
|
||||
@@ -725,10 +498,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("uses existing OPENROUTER_API_KEY when selecting openrouter-api-key", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
process.env.OPENROUTER_API_KEY = "sk-openrouter-test";
|
||||
|
||||
const text = vi.fn();
|
||||
@@ -737,23 +507,8 @@ describe("applyAuthChoice", () => {
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const confirm = vi.fn(async () => true);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm,
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text, confirm });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "openrouter-api-key",
|
||||
@@ -775,9 +530,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
expect(result.config.agents?.defaults?.model?.primary).toBe("openrouter/auto");
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["openrouter:default"]?.key).toBe("sk-openrouter-test");
|
||||
@@ -786,10 +539,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("ignores legacy LiteLLM oauth profiles when selecting litellm-api-key", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
process.env.LITELLM_API_KEY = "sk-litellm-test";
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
@@ -821,23 +571,8 @@ describe("applyAuthChoice", () => {
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const confirm = vi.fn(async () => true);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm,
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text, confirm });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "litellm-api-key",
|
||||
@@ -865,8 +600,7 @@ describe("applyAuthChoice", () => {
|
||||
mode: "api_key",
|
||||
});
|
||||
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { type?: string; key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["litellm:default"]).toMatchObject({
|
||||
@@ -876,10 +610,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("uses existing AI_GATEWAY_API_KEY when selecting ai-gateway-api-key", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
process.env.AI_GATEWAY_API_KEY = "gateway-test-key";
|
||||
|
||||
const text = vi.fn();
|
||||
@@ -888,23 +619,8 @@ describe("applyAuthChoice", () => {
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const confirm = vi.fn(async () => true);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm,
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text, confirm });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "ai-gateway-api-key",
|
||||
@@ -928,9 +644,7 @@ describe("applyAuthChoice", () => {
|
||||
"vercel-ai-gateway/anthropic/claude-opus-4.6",
|
||||
);
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["vercel-ai-gateway:default"]?.key).toBe("gateway-test-key");
|
||||
@@ -939,10 +653,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("uses existing CLOUDFLARE_AI_GATEWAY_API_KEY when selecting cloudflare-ai-gateway-api-key", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
process.env.CLOUDFLARE_AI_GATEWAY_API_KEY = "cf-gateway-test-key";
|
||||
|
||||
const text = vi
|
||||
@@ -954,23 +665,8 @@ describe("applyAuthChoice", () => {
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const confirm = vi.fn(async () => true);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm,
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text, confirm });
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "cloudflare-ai-gateway-api-key",
|
||||
@@ -994,9 +690,7 @@ describe("applyAuthChoice", () => {
|
||||
"cloudflare-ai-gateway/claude-sonnet-4-5",
|
||||
);
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { key?: string; metadata?: Record<string, string> }>;
|
||||
};
|
||||
expect(parsed.profiles?.["cloudflare-ai-gateway:default"]?.key).toBe("cf-gateway-test-key");
|
||||
@@ -1009,10 +703,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("writes Chutes OAuth credentials when selecting chutes (remote/manual)", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
process.env.SSH_TTY = "1";
|
||||
process.env.CHUTES_CLIENT_ID = "cid_test";
|
||||
|
||||
@@ -1038,13 +729,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
vi.stubGlobal("fetch", fetchSpy);
|
||||
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const runtime = createExitThrowingRuntime();
|
||||
const text: WizardPrompter["text"] = vi.fn(async (params) => {
|
||||
if (params.message === "Paste the redirect URL") {
|
||||
const lastLog = runtime.log.mock.calls.at(-1)?.[0];
|
||||
@@ -1062,16 +747,7 @@ describe("applyAuthChoice", () => {
|
||||
async (params) => params.options[0]?.value as never,
|
||||
);
|
||||
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select,
|
||||
multiselect,
|
||||
text,
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const prompter = createPrompter({ select, multiselect, text });
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "chutes",
|
||||
@@ -1091,9 +767,7 @@ describe("applyAuthChoice", () => {
|
||||
mode: "oauth",
|
||||
});
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<
|
||||
string,
|
||||
{ provider?: string; access?: string; refresh?: string; email?: string }
|
||||
@@ -1108,10 +782,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("writes Qwen credentials when selecting qwen-portal", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
resolvePluginProviders.mockReturnValue([
|
||||
{
|
||||
@@ -1154,23 +825,8 @@ describe("applyAuthChoice", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select: vi.fn(async () => "" as never),
|
||||
multiselect: vi.fn(async () => []),
|
||||
text: vi.fn(async () => ""),
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({});
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "qwen-portal",
|
||||
@@ -1190,9 +846,7 @@ describe("applyAuthChoice", () => {
|
||||
apiKey: "qwen-oauth",
|
||||
});
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { access?: string; refresh?: string; provider?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["qwen-portal:default"]).toMatchObject({
|
||||
@@ -1203,10 +857,7 @@ describe("applyAuthChoice", () => {
|
||||
});
|
||||
|
||||
it("writes MiniMax credentials when selecting minimax-portal", async () => {
|
||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||
await setupTempState();
|
||||
|
||||
resolvePluginProviders.mockReturnValue([
|
||||
{
|
||||
@@ -1249,23 +900,10 @@ describe("applyAuthChoice", () => {
|
||||
},
|
||||
]);
|
||||
|
||||
const prompter: WizardPrompter = {
|
||||
intro: vi.fn(noopAsync),
|
||||
outro: vi.fn(noopAsync),
|
||||
note: vi.fn(noopAsync),
|
||||
select: vi.fn(async () => "oauth" as never),
|
||||
multiselect: vi.fn(async () => []),
|
||||
text: vi.fn(async () => ""),
|
||||
confirm: vi.fn(async () => false),
|
||||
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||
};
|
||||
const runtime: RuntimeEnv = {
|
||||
log: vi.fn(),
|
||||
error: vi.fn(),
|
||||
exit: vi.fn((code: number) => {
|
||||
throw new Error(`exit:${code}`);
|
||||
}),
|
||||
};
|
||||
const prompter = createPrompter({
|
||||
select: vi.fn(async () => "oauth" as never) as WizardPrompter["select"],
|
||||
});
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "minimax-portal",
|
||||
@@ -1285,9 +923,7 @@ describe("applyAuthChoice", () => {
|
||||
apiKey: "minimax-oauth",
|
||||
});
|
||||
|
||||
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||
const parsed = JSON.parse(raw) as {
|
||||
const parsed = (await readAuthProfiles()) as {
|
||||
profiles?: Record<string, { access?: string; refresh?: string; provider?: string }>;
|
||||
};
|
||||
expect(parsed.profiles?.["minimax-portal:default"]).toMatchObject({
|
||||
|
||||
Reference in New Issue
Block a user