@cleocode/cleo 2026.6.1 → 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 +84 -36
- package/dist/cli/index.js.map +3 -3
- package/package.json +12 -12
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(
|
|
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.
|
|
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
|
|
55921
|
-
const
|
|
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
|
-
|
|
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
|
|
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
|
|
56597
|
-
const profiles = await
|
|
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
|
|
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
|
|
56687
|
+
description: "Provider to authenticate: anthropic | openai | codex | kimi-code",
|
|
56663
56688
|
required: true
|
|
56664
56689
|
},
|
|
56665
56690
|
label: {
|
|
@@ -56675,16 +56700,18 @@ var init_llm3 = __esm({
|
|
|
56675
56700
|
const a = args;
|
|
56676
56701
|
const provider = String(a["provider"] ?? "");
|
|
56677
56702
|
const label = typeof a["label"] === "string" && a["label"] ? a["label"] : void 0;
|
|
56678
|
-
const jsonOutput = a["json"] === true;
|
|
56679
56703
|
const result = await runLlmLogin(provider, { label });
|
|
56680
|
-
if (
|
|
56681
|
-
|
|
56682
|
-
|
|
56683
|
-
|
|
56684
|
-
|
|
56685
|
-
|
|
56686
|
-
|
|
56687
|
-
|
|
56704
|
+
if (result.success && result.data) {
|
|
56705
|
+
if (isHumanOutput()) {
|
|
56706
|
+
humanLine(
|
|
56707
|
+
`Logged in to ${result.data.provider} as '${result.data.label}'` + (result.data.expiresIn != null ? ` (expires in ${Math.round(result.data.expiresIn / 60)} min)` : "")
|
|
56708
|
+
);
|
|
56709
|
+
} else {
|
|
56710
|
+
cliOutput(result.data, { command: "llm-login", operation: "llm.login" });
|
|
56711
|
+
}
|
|
56712
|
+
return;
|
|
56713
|
+
}
|
|
56714
|
+
if (result.error) {
|
|
56688
56715
|
cliError(
|
|
56689
56716
|
result.error.message,
|
|
56690
56717
|
result.error.code || 1,
|
|
@@ -56706,19 +56733,20 @@ var init_llm3 = __esm({
|
|
|
56706
56733
|
description: "Output result as JSON"
|
|
56707
56734
|
}
|
|
56708
56735
|
},
|
|
56709
|
-
async run(
|
|
56710
|
-
const jsonOutput = args["json"] === true;
|
|
56736
|
+
async run() {
|
|
56711
56737
|
const result = await runLlmRefreshCatalog();
|
|
56712
|
-
if (
|
|
56713
|
-
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
56714
|
-
`);
|
|
56715
|
-
} else if (result.success && result.data) {
|
|
56738
|
+
if (result.success && result.data) {
|
|
56716
56739
|
const d = result.data;
|
|
56717
|
-
|
|
56718
|
-
|
|
56719
|
-
`
|
|
56720
|
-
|
|
56721
|
-
|
|
56740
|
+
if (isHumanOutput()) {
|
|
56741
|
+
humanLine(
|
|
56742
|
+
`Catalog refreshed: ${d.providers} providers, ${d.models} models written to ${d.filePath}`
|
|
56743
|
+
);
|
|
56744
|
+
} else {
|
|
56745
|
+
cliOutput(result.data, { command: "llm-refresh-catalog", operation: "llm.refreshCatalog" });
|
|
56746
|
+
}
|
|
56747
|
+
return;
|
|
56748
|
+
}
|
|
56749
|
+
if (!result.success) {
|
|
56722
56750
|
cliError(
|
|
56723
56751
|
result.error?.message ?? "refresh failed",
|
|
56724
56752
|
result.error?.code ?? 1,
|
|
@@ -75791,15 +75819,34 @@ async function maybePromptFirstRun() {
|
|
|
75791
75819
|
}
|
|
75792
75820
|
}
|
|
75793
75821
|
|
|
75822
|
+
// packages/cleo/src/cli/lib/interactive-commands.ts
|
|
75823
|
+
var INTERACTIVE_COMMAND_PATHS = [
|
|
75824
|
+
["llm", "login"],
|
|
75825
|
+
["llm", "add"],
|
|
75826
|
+
["llm", "refresh-catalog"],
|
|
75827
|
+
["login"],
|
|
75828
|
+
["auth", "login"],
|
|
75829
|
+
["setup"],
|
|
75830
|
+
["init"]
|
|
75831
|
+
];
|
|
75832
|
+
function isInteractiveInvocation(argv) {
|
|
75833
|
+
const positionals = argv.filter((token) => !token.startsWith("-"));
|
|
75834
|
+
if (positionals.length === 0) return false;
|
|
75835
|
+
return INTERACTIVE_COMMAND_PATHS.some(
|
|
75836
|
+
(path6) => path6.length <= positionals.length && path6.every((seg, i) => seg === positionals[i])
|
|
75837
|
+
);
|
|
75838
|
+
}
|
|
75839
|
+
|
|
75794
75840
|
// packages/cleo/src/cli/middleware/output-format.ts
|
|
75795
75841
|
import { resolveOutputFormat } from "@cleocode/lafs";
|
|
75796
|
-
function resolveFormat(opts, defaults) {
|
|
75842
|
+
function resolveFormat(opts, defaults, tty) {
|
|
75797
75843
|
const input2 = {
|
|
75798
75844
|
jsonFlag: opts["json"] === true,
|
|
75799
75845
|
humanFlag: opts["human"] === true,
|
|
75800
75846
|
quiet: opts["quiet"] === true,
|
|
75801
75847
|
projectDefault: defaults?.projectDefault,
|
|
75802
|
-
userDefault: defaults?.userDefault
|
|
75848
|
+
userDefault: defaults?.userDefault,
|
|
75849
|
+
tty
|
|
75803
75850
|
};
|
|
75804
75851
|
return resolveOutputFormat(input2);
|
|
75805
75852
|
}
|
|
@@ -75890,7 +75937,8 @@ async function startCli() {
|
|
|
75890
75937
|
else if (arg === "--output" && i + 1 < argv.length) outputModeRaw = argv[++i];
|
|
75891
75938
|
else if (arg === "--summary") summaryFlag = true;
|
|
75892
75939
|
}
|
|
75893
|
-
const
|
|
75940
|
+
const interactiveTty = isInteractiveInvocation(argv) && process.stdout.isTTY === true;
|
|
75941
|
+
const formatResolution = resolveFormat(rawOpts, void 0, interactiveTty);
|
|
75894
75942
|
setFormatContext(formatResolution);
|
|
75895
75943
|
const fieldResolution = resolveFieldContext(rawOpts);
|
|
75896
75944
|
if (fieldResolution.mviSource === "default") {
|