Replace token-paste with native device-code/PKCE provider sign-in

Implement the official OAuth login flows natively (ported from pi-ai's
reference): GitHub Copilot device-code, GPT account (ChatGPT Codex) and
Google Antigravity authorization-code + PKCE via a loopback callback server.
Obtained credentials are stored as JSON through the existing secret vault.
Onboarding and Settings now run the real sign-in instead of pasting an
access token.
This commit is contained in:
ZacharyZhang-NY committed 2026-05-29 20:08:55 -04:00
1 parent d5bf6c6b5f
commit 49a9f16221
24 files changed
+1057 -64

No files matched your search

+21
View File
@@ -184,6 +184,27 @@ export interface LaunchProviderSignInInput {
employeeId: string;
}
export interface StartProviderOAuthInput {
providerKey: string;
enterpriseDomain?: string | null;
/** Present when connecting an existing org's provider (Settings); absent
* during onboarding, where the obtained credential is returned to the caller. */
orgId?: string;
providerId?: string;
employeeId?: string;
model?: string | null;
}
export interface StartProviderOAuthResult {
/** The obtained credential JSON when no org context was supplied, else null
* (the credential was already stored). */
secret: string | null;
}
export interface CancelProviderOAuthInput {
providerKey: string;
}
export interface CheckProviderHealthInput {
orgId: string;
providerId: string;
+18 -1
View File
@@ -14,6 +14,9 @@ import type {
CreateLegalHoldInput,
CreateMigrationReportInput,
CheckProviderHealthInput,
StartProviderOAuthInput,
StartProviderOAuthResult,
CancelProviderOAuthInput,
MarkChatSpaceReadInput,
CreateOrganizationInput,
CreateProviderResponseInput,
@@ -58,9 +61,21 @@ import type {
} from "./commands";
import type { ProviderStreamRendererEvent } from "./provider-request-domain";
export type ProviderOAuthPhase = "authorize" | "progress" | "active" | "error" | "cancelled";
export interface ProviderOAuthEvent {
type: "provider-oauth";
providerKey: string;
phase: ProviderOAuthPhase;
url?: string;
instructions?: string;
message?: string;
}
export type RendererEvent =
| { type: "snapshot-changed" }
| { type: "provider-response-stream"; event: ProviderStreamRendererEvent };
| { type: "provider-response-stream"; event: ProviderStreamRendererEvent }
| ProviderOAuthEvent;
export interface DesktopApi {
loadSnapshot(): Promise<DesktopResult<AppSnapshot>>;
@@ -85,6 +100,8 @@ export interface DesktopApi {
saveProviderCredential(input: SaveProviderCredentialInput): Promise<DesktopResult<AppSnapshot>>;
revokeProviderCredential(input: RevokeProviderCredentialInput): Promise<DesktopResult<AppSnapshot>>;
launchProviderSignIn(input: LaunchProviderSignInInput): Promise<DesktopResult<null>>;
startProviderOAuth(input: StartProviderOAuthInput): Promise<DesktopResult<StartProviderOAuthResult>>;
cancelProviderOAuth(input: CancelProviderOAuthInput): Promise<DesktopResult<null>>;
checkProviderHealth(input: CheckProviderHealthInput): Promise<DesktopResult<AppSnapshot>>;
updateProviderPolicy(input: UpdateProviderPolicyInput): Promise<DesktopResult<AppSnapshot>>;
openExternalUrl(url: string): Promise<DesktopResult<null>>;
+2
View File
@@ -21,6 +21,8 @@ export const IPC_CHANNELS = {
saveProviderCredential: "agentcompany:save-provider-credential",
revokeProviderCredential: "agentcompany:revoke-provider-credential",
launchProviderSignIn: "agentcompany:launch-provider-sign-in",
startProviderOAuth: "agentcompany:start-provider-oauth",
cancelProviderOAuth: "agentcompany:cancel-provider-oauth",
checkProviderHealth: "agentcompany:check-provider-health",
updateProviderPolicy: "agentcompany:update-provider-policy",
openExternalUrl: "agentcompany:open-external-url",
@@ -44,8 +44,8 @@ const RAW_CATALOG: Omit<ProviderCatalogEntry, "models">[] = [
authType: PROVIDER_AUTH_TYPE.OAUTH_PKCE,
defaultModel: "claude-opus-4-5",
capabilityTags: ["account", "coding"],
signInUrl: "https://github.com/login",
credentialHelp: "Sign in, then copy the personal access token (scope copilot) from github.com → Settings → Developer settings.",
signInUrl: "https://github.com/login/device",
credentialHelp: "Sign in with the GitHub device code shown here — no token to copy.",
},
{
key: "google-antigravity",
@@ -54,7 +54,7 @@ const RAW_CATALOG: Omit<ProviderCatalogEntry, "models">[] = [
defaultModel: "claude-sonnet-4-5",
capabilityTags: ["account", "coding"],
signInUrl: "https://antigravity.google/",
credentialHelp: "Sign in to Antigravity, then paste the session token shown in the dashboard.",
credentialHelp: "Sign in with your Google account in the browser; AgentCompany finishes the handshake.",
},
{
key: "gpt-account",
@@ -63,7 +63,7 @@ const RAW_CATALOG: Omit<ProviderCatalogEntry, "models">[] = [
defaultModel: "gpt-5.3-codex",
capabilityTags: ["codex", "subscription"],
signInUrl: "https://chatgpt.com/codex",
credentialHelp: "Sign in to ChatGPT Plus/Pro, then paste the session access token from chatgpt.com/codex/settings.",
credentialHelp: "Sign in to ChatGPT Plus/Pro in the browser; AgentCompany finishes the handshake.",
},
{
key: "azure-openai",