@cleocode/cleo 2026.6.2 → 2026.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -55892,7 +55892,7 @@ import {
55892
55892
  refreshPkceToken
55893
55893
  } from "@cleocode/core/llm/oauth/pkce.js";
55894
55894
  import { getKimiCodeMshHeaders } from "@cleocode/core/llm/provider-registry/builtin/kimi-code.js";
55895
- import { getProviderProfile } from "@cleocode/core/llm/provider-registry/index.js";
55895
+ import { getProviderProfile, listProviders } from "@cleocode/core/llm/provider-registry/index.js";
55896
55896
  async function runLlmLogin(provider, opts) {
55897
55897
  const meta = { operation: "llm.login", timestamp: (/* @__PURE__ */ new Date()).toISOString() };
55898
55898
  const profile = await getProviderProfile(provider);
@@ -55901,31 +55901,43 @@ async function runLlmLogin(provider, opts) {
55901
55901
  return _runKimiCodeLogin(opts, meta);
55902
55902
  }
55903
55903
  if (oauthMode === "pkce") {
55904
- return _runPkceLogin(provider, profile.oauth, opts, meta);
55904
+ return _runPkceLogin(profile.name, profile.oauth, opts, meta);
55905
55905
  }
55906
55906
  return {
55907
55907
  success: false,
55908
55908
  error: {
55909
55909
  code: "E_NOT_IMPLEMENTED",
55910
55910
  codeName: "E_NOT_IMPLEMENTED",
55911
- message: `OAuth login for '${provider}' is not yet wired. Supported providers: 'anthropic' (PKCE), 'kimi-code' (device-code). To add credentials for other providers use 'cleo llm add <provider> --api-key-stdin'.`
55911
+ message: `OAuth login for '${provider}' is not yet wired. ${await _supportedOauthProvidersHint()} For any other provider, add an API key with 'cleo llm add <provider> --api-key-stdin'.`
55912
55912
  },
55913
55913
  meta
55914
55914
  };
55915
55915
  }
55916
+ async function _supportedOauthProvidersHint() {
55917
+ try {
55918
+ const profiles = await listProviders();
55919
+ const oauthable = profiles.flatMap((p) => p.oauth ? [`'${p.name}' (${p.oauth.mode})`] : []);
55920
+ return oauthable.length > 0 ? `Providers with OAuth login: ${oauthable.join(", ")}.` : "No providers currently expose OAuth login.";
55921
+ } catch {
55922
+ return "Providers with OAuth login: 'anthropic' (pkce), 'openai' (pkce), 'kimi-code' (device-code).";
55923
+ }
55924
+ }
55916
55925
  async function _runPkceLogin(provider, oauthCfg, opts, meta) {
55917
55926
  const { codeVerifier, codeChallenge } = await generatePkcePair();
55918
55927
  const state = _generateState();
55919
55928
  const isHeadless = opts.headless || process.env["CLEO_HEADLESS"] === "1";
55920
- const port = isHeadless ? 0 : await _findFreePort();
55921
- const redirectUri = isHeadless ? oauthCfg.redirectUri ?? "http://localhost" : `http://localhost:${port}/callback`;
55929
+ const fixedPort = isHeadless ? null : _parseFixedLoopbackPort(oauthCfg.redirectUri);
55930
+ const port = isHeadless ? 0 : fixedPort ?? await _findFreePort();
55931
+ const randomRedirect = `http://localhost:${port}/callback`;
55932
+ const redirectUri = isHeadless ? oauthCfg.redirectUri ?? "http://localhost" : fixedPort != null ? oauthCfg.redirectUri ?? randomRedirect : randomRedirect;
55922
55933
  const authUrl = buildAuthorizationUrl({
55923
55934
  authorizationEndpoint: oauthCfg.authorizationEndpoint ?? "",
55924
55935
  clientId: oauthCfg.clientId,
55925
55936
  redirectUri,
55926
55937
  scope: oauthCfg.scope ?? "",
55927
55938
  codeChallenge,
55928
- state
55939
+ state,
55940
+ extraParams: oauthCfg.extraAuthParams
55929
55941
  });
55930
55942
  let code;
55931
55943
  if (isHeadless) {
@@ -55962,6 +55974,7 @@ async function _runPkceLogin(provider, oauthCfg, opts, meta) {
55962
55974
  process.stderr.write("\r Authorization approved. \n\n");
55963
55975
  const label = opts.label ?? "oauth-login";
55964
55976
  const expiresAt = typeof tokens.expiresIn === "number" ? Date.now() + tokens.expiresIn * 1e3 : void 0;
55977
+ const oauthExtraHeaders = provider === "anthropic" ? { "anthropic-beta": "oauth-2025-04-20" } : void 0;
55965
55978
  try {
55966
55979
  await addCredential({
55967
55980
  provider,
@@ -55972,7 +55985,7 @@ async function _runPkceLogin(provider, oauthCfg, opts, meta) {
55972
55985
  expiresAt,
55973
55986
  priority: 10,
55974
55987
  source: "oauth-pkce",
55975
- extraHeaders: { "anthropic-beta": "oauth-2025-04-20" }
55988
+ ...oauthExtraHeaders ? { extraHeaders: oauthExtraHeaders } : {}
55976
55989
  });
55977
55990
  } catch (err) {
55978
55991
  const msg = err instanceof Error ? err.message : String(err);
@@ -55992,6 +56005,18 @@ async function _runPkceLogin(provider, oauthCfg, opts, meta) {
55992
56005
  meta
55993
56006
  };
55994
56007
  }
56008
+ function _parseFixedLoopbackPort(redirectUri) {
56009
+ if (!redirectUri) return null;
56010
+ try {
56011
+ const u = new URL(redirectUri);
56012
+ const isLoopback = u.hostname === "localhost" || u.hostname === "127.0.0.1";
56013
+ if (!isLoopback || !u.port) return null;
56014
+ const port = Number(u.port);
56015
+ return Number.isInteger(port) && port > 0 ? port : null;
56016
+ } catch {
56017
+ return null;
56018
+ }
56019
+ }
55995
56020
  async function _headlessPkceFlow(provider, authUrl) {
55996
56021
  process.stderr.write("\n");
55997
56022
  process.stderr.write(` Provider: ${provider}
@@ -56278,11 +56303,11 @@ __export(llm_exports, {
56278
56303
  });
56279
56304
  import { pushWarning as pushWarning7 } from "@cleocode/core";
56280
56305
  async function getListProviders() {
56281
- const { listProviders } = await import(
56306
+ const { listProviders: listProviders2 } = await import(
56282
56307
  /* webpackIgnore: true */
56283
56308
  "@cleocode/core/llm/provider-registry"
56284
56309
  );
56285
- return listProviders;
56310
+ return listProviders2;
56286
56311
  }
56287
56312
  async function readApiKeyFromStdin() {
56288
56313
  if (process.stdin.isTTY) return "";
@@ -56593,8 +56618,8 @@ var init_llm3 = __esm({
56593
56618
  }
56594
56619
  },
56595
56620
  async run() {
56596
- const listProviders = await getListProviders();
56597
- const profiles = await listProviders();
56621
+ const listProviders2 = await getListProviders();
56622
+ const profiles = await listProviders2();
56598
56623
  const providers = profiles.map((p) => ({
56599
56624
  name: p.name,
56600
56625
  displayName: p.displayName,
@@ -56654,12 +56679,12 @@ var init_llm3 = __esm({
56654
56679
  loginCommand = defineCommand({
56655
56680
  meta: {
56656
56681
  name: "login",
56657
- description: "Authenticate with a provider via OAuth device-code flow. Supported providers: anthropic (MVP). Prints the verification URL and user code, then polls until the user approves."
56682
+ description: "Authenticate an LLM provider via OAuth. PKCE (browser): anthropic, openai/codex. Device-code: kimi-code. Example: `cleo llm login openai`. For any other provider use `cleo llm add <provider> --api-key-stdin`. Prompts/URLs go to stderr; the result is a human line on a terminal or a JSON envelope when piped/--json."
56658
56683
  },
56659
56684
  args: {
56660
56685
  provider: {
56661
56686
  type: "positional",
56662
- description: "Provider to authenticate with (e.g. anthropic)",
56687
+ description: "Provider to authenticate: anthropic | openai | codex | kimi-code",
56663
56688
  required: true
56664
56689
  },
56665
56690
  label: {