feat: add GitHub Copilot provider

Copilot device login + onboarding option; model list auth detection.
This commit is contained in:
Mustafa Tag Eldeen
2026-01-11 05:19:07 +02:00
committed by Peter Steinberger
parent 717a259056
commit 3da1afed68
19 changed files with 926 additions and 1122 deletions

View File

@@ -0,0 +1,79 @@
import { describe, expect, it, vi } from "vitest";
const loadJsonFile = vi.fn();
const saveJsonFile = vi.fn();
const resolveStateDir = vi.fn().mockReturnValue("/tmp/clawdbot-state");
vi.mock("../infra/json-file.js", () => ({
loadJsonFile,
saveJsonFile,
}));
vi.mock("../config/paths.js", () => ({
resolveStateDir,
}));
describe("github-copilot token", () => {
it("derives baseUrl from token", async () => {
const { deriveCopilotApiBaseUrlFromToken } = await import(
"./github-copilot-token.js"
);
expect(
deriveCopilotApiBaseUrlFromToken("token;proxy-ep=proxy.example.com;"),
).toBe("https://api.example.com");
expect(
deriveCopilotApiBaseUrlFromToken("token;proxy-ep=https://proxy.foo.bar;"),
).toBe("https://api.foo.bar");
});
it("uses cache when token is still valid", async () => {
const now = Date.now();
loadJsonFile.mockReturnValue({
token: "cached;proxy-ep=proxy.example.com;",
expiresAt: now + 60 * 60 * 1000,
updatedAt: now,
});
const { resolveCopilotApiToken } = await import(
"./github-copilot-token.js"
);
const fetchImpl = vi.fn();
const res = await resolveCopilotApiToken({
githubToken: "gh",
fetchImpl: fetchImpl as unknown as typeof fetch,
});
expect(res.token).toBe("cached;proxy-ep=proxy.example.com;");
expect(res.baseUrl).toBe("https://api.example.com");
expect(String(res.source)).toContain("cache:");
expect(fetchImpl).not.toHaveBeenCalled();
});
it("fetches and stores token when cache is missing", async () => {
loadJsonFile.mockReturnValue(undefined);
const fetchImpl = vi.fn().mockResolvedValue({
ok: true,
status: 200,
json: async () => ({
token: "fresh;proxy-ep=https://proxy.contoso.test;",
expires_at: Math.floor(Date.now() / 1000) + 3600,
}),
});
const { resolveCopilotApiToken } = await import(
"./github-copilot-token.js"
);
const res = await resolveCopilotApiToken({
githubToken: "gh",
fetchImpl: fetchImpl as unknown as typeof fetch,
});
expect(res.token).toBe("fresh;proxy-ep=https://proxy.contoso.test;");
expect(res.baseUrl).toBe("https://api.contoso.test");
expect(saveJsonFile).toHaveBeenCalledTimes(1);
});
});