@gguf/claw
Version:
Multi-channel AI gateway with extensible messaging integrations
209 lines (203 loc) • 8.11 kB
JavaScript
import { o as createSubsystemLogger } from "./entry.js";
import { L as normalizeProviderId, b as ensureAuthProfileStore, v as upsertAuthProfile } from "./auth-profiles-DFa1zzNy.js";
import { g as loadOpenClawPlugins, h as createPluginLoaderLogger } from "./subagent-registry-C7Edpn23.js";
import { n as isWSLEnv } from "./wsl-jdLWdiKy.js";
import { r as stylePromptTitle } from "./prompt-style-DwCXob2h.js";
import { f as updateConfig } from "./shared-DpLvAirU.js";
import { d as applyAuthProfileConfig } from "./auth-token-B5F1NkdJ.js";
import { n as logConfigUpdated } from "./logging-BGewRZy0.js";
import { intro, note, outro, spinner } from "@clack/prompts";
//#region src/providers/github-copilot-auth.ts
const CLIENT_ID = "Iv1.b507a08c87ecfe98";
const DEVICE_CODE_URL = "https://github.com/login/device/code";
const ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
function parseJsonResponse(value) {
if (!value || typeof value !== "object") throw new Error("Unexpected response from GitHub");
return value;
}
async function requestDeviceCode(params) {
const body = new URLSearchParams({
client_id: CLIENT_ID,
scope: params.scope
});
const res = await fetch(DEVICE_CODE_URL, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body
});
if (!res.ok) throw new Error(`GitHub device code failed: HTTP ${res.status}`);
const json = parseJsonResponse(await res.json());
if (!json.device_code || !json.user_code || !json.verification_uri) throw new Error("GitHub device code response missing fields");
return json;
}
async function pollForAccessToken(params) {
const bodyBase = new URLSearchParams({
client_id: CLIENT_ID,
device_code: params.deviceCode,
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
});
while (Date.now() < params.expiresAt) {
const res = await fetch(ACCESS_TOKEN_URL, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: bodyBase
});
if (!res.ok) throw new Error(`GitHub device token failed: HTTP ${res.status}`);
const json = parseJsonResponse(await res.json());
if ("access_token" in json && typeof json.access_token === "string") return json.access_token;
const err = "error" in json ? json.error : "unknown";
if (err === "authorization_pending") {
await new Promise((r) => setTimeout(r, params.intervalMs));
continue;
}
if (err === "slow_down") {
await new Promise((r) => setTimeout(r, params.intervalMs + 2e3));
continue;
}
if (err === "expired_token") throw new Error("GitHub device code expired; run login again");
if (err === "access_denied") throw new Error("GitHub login cancelled");
throw new Error(`GitHub device flow error: ${err}`);
}
throw new Error("GitHub device code expired; run login again");
}
async function githubCopilotLoginCommand(opts, runtime) {
if (!process.stdin.isTTY) throw new Error("github-copilot login requires an interactive TTY.");
intro(stylePromptTitle("GitHub Copilot login"));
const profileId = opts.profileId?.trim() || "github-copilot:github";
if (ensureAuthProfileStore(void 0, { allowKeychainPrompt: false }).profiles[profileId] && !opts.yes) note(`Auth profile already exists: ${profileId}\nRe-running will overwrite it.`, stylePromptTitle("Existing credentials"));
const spin = spinner();
spin.start("Requesting device code from GitHub...");
const device = await requestDeviceCode({ scope: "read:user" });
spin.stop("Device code ready");
note([`Visit: ${device.verification_uri}`, `Code: ${device.user_code}`].join("\n"), stylePromptTitle("Authorize"));
const expiresAt = Date.now() + device.expires_in * 1e3;
const intervalMs = Math.max(1e3, device.interval * 1e3);
const polling = spinner();
polling.start("Waiting for GitHub authorization...");
const accessToken = await pollForAccessToken({
deviceCode: device.device_code,
intervalMs,
expiresAt
});
polling.stop("GitHub access token acquired");
upsertAuthProfile({
profileId,
credential: {
type: "token",
provider: "github-copilot",
token: accessToken
}
});
await updateConfig((cfg) => applyAuthProfileConfig(cfg, {
provider: "github-copilot",
profileId,
mode: "token"
}));
logConfigUpdated(runtime);
runtime.log(`Auth profile: ${profileId} (github-copilot/token)`);
outro("Done");
}
//#endregion
//#region src/plugins/providers.ts
const log = createSubsystemLogger("plugins");
function resolvePluginProviders(params) {
return loadOpenClawPlugins({
config: params.config,
workspaceDir: params.workspaceDir,
logger: createPluginLoaderLogger(log)
}).providers.map((entry) => entry.provider);
}
//#endregion
//#region src/commands/oauth-env.ts
function isRemoteEnvironment() {
if (process.env.SSH_CLIENT || process.env.SSH_TTY || process.env.SSH_CONNECTION) return true;
if (process.env.REMOTE_CONTAINERS || process.env.CODESPACES) return true;
if (process.platform === "linux" && !process.env.DISPLAY && !process.env.WAYLAND_DISPLAY && !isWSLEnv()) return true;
return false;
}
//#endregion
//#region src/commands/oauth-flow.ts
const validateRequiredInput = (value) => value.trim().length > 0 ? void 0 : "Required";
function createVpsAwareOAuthHandlers(params) {
const manualPromptMessage = params.manualPromptMessage ?? "Paste the redirect URL";
let manualCodePromise;
return {
onAuth: async ({ url }) => {
if (params.isRemote) {
params.spin.stop("OAuth URL ready");
params.runtime.log(`\nOpen this URL in your LOCAL browser:\n\n${url}\n`);
manualCodePromise = params.prompter.text({
message: manualPromptMessage,
validate: validateRequiredInput
}).then((value) => String(value));
return;
}
params.spin.update(params.localBrowserMessage);
await params.openUrl(url);
params.runtime.log(`Open: ${url}`);
},
onPrompt: async (prompt) => {
if (manualCodePromise) return manualCodePromise;
const code = await params.prompter.text({
message: prompt.message,
placeholder: prompt.placeholder,
validate: validateRequiredInput
});
return String(code);
}
};
}
//#endregion
//#region src/commands/provider-auth-helpers.ts
function resolveProviderMatch(providers, rawProvider) {
const raw = rawProvider?.trim();
if (!raw) return null;
const normalized = normalizeProviderId(raw);
return providers.find((provider) => normalizeProviderId(provider.id) === normalized) ?? providers.find((provider) => provider.aliases?.some((alias) => normalizeProviderId(alias) === normalized) ?? false) ?? null;
}
function pickAuthMethod(provider, rawMethod) {
const raw = rawMethod?.trim();
if (!raw) return null;
const normalized = raw.toLowerCase();
return provider.auth.find((method) => method.id.toLowerCase() === normalized) ?? provider.auth.find((method) => method.label.toLowerCase() === normalized) ?? null;
}
function isPlainRecord(value) {
return Boolean(value && typeof value === "object" && !Array.isArray(value));
}
function mergeConfigPatch(base, patch) {
if (!isPlainRecord(base) || !isPlainRecord(patch)) return patch;
const next = { ...base };
for (const [key, value] of Object.entries(patch)) {
const existing = next[key];
if (isPlainRecord(existing) && isPlainRecord(value)) next[key] = mergeConfigPatch(existing, value);
else next[key] = value;
}
return next;
}
function applyDefaultModel(cfg, model) {
const models = { ...cfg.agents?.defaults?.models };
models[model] = models[model] ?? {};
const existingModel = cfg.agents?.defaults?.model;
return {
...cfg,
agents: {
...cfg.agents,
defaults: {
...cfg.agents?.defaults,
models,
model: {
...existingModel && typeof existingModel === "object" && "fallbacks" in existingModel ? { fallbacks: existingModel.fallbacks } : void 0,
primary: model
}
}
}
};
}
//#endregion
export { createVpsAwareOAuthHandlers as a, githubCopilotLoginCommand as c, resolveProviderMatch as i, mergeConfigPatch as n, isRemoteEnvironment as o, pickAuthMethod as r, resolvePluginProviders as s, applyDefaultModel as t };