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,48 @@
import { describe, expect, it, vi } from "vitest";
const githubCopilotLoginCommand = vi.fn();
vi.mock("../commands/models.js", async () => {
const actual = (await vi.importActual<typeof import("../commands/models.js")>(
"../commands/models.js",
)) as typeof import("../commands/models.js");
return {
...actual,
githubCopilotLoginCommand,
};
});
describe("models cli", () => {
it("registers github-copilot login command", async () => {
const { Command } = await import("commander");
const { registerModelsCli } = await import("./models-cli.js");
const program = new Command();
registerModelsCli(program);
const models = program.commands.find((cmd) => cmd.name() === "models");
expect(models).toBeTruthy();
const auth = models?.commands.find((cmd) => cmd.name() === "auth");
expect(auth).toBeTruthy();
const login = auth?.commands.find(
(cmd) => cmd.name() === "login-github-copilot",
);
expect(login).toBeTruthy();
await program.parseAsync(
["models", "auth", "login-github-copilot", "--yes"],
{
from: "user",
},
);
expect(githubCopilotLoginCommand).toHaveBeenCalledTimes(1);
expect(githubCopilotLoginCommand).toHaveBeenCalledWith(
expect.objectContaining({ yes: true }),
expect.any(Object),
);
});
});

View File

@@ -1,6 +1,7 @@
import type { Command } from "commander";
import {
githubCopilotLoginCommand,
modelsAliasesAddCommand,
modelsAliasesListCommand,
modelsAliasesRemoveCommand,
@@ -374,6 +375,31 @@ export function registerModelsCli(program: Command) {
}
});
auth
.command("login-github-copilot")
.description(
"Login to GitHub Copilot via GitHub device flow (TTY required)",
)
.option(
"--profile-id <id>",
"Auth profile id (default: github-copilot:github)",
)
.option("--yes", "Overwrite existing profile without prompting", false)
.action(async (opts) => {
try {
await githubCopilotLoginCommand(
{
profileId: opts.profileId as string | undefined,
yes: Boolean(opts.yes),
},
defaultRuntime,
);
} catch (err) {
defaultRuntime.error(String(err));
defaultRuntime.exit(1);
}
});
const order = auth
.command("order")
.description("Manage per-agent auth profile order overrides");