@cleocode/cleo 2026.5.64 → 2026.5.66
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 +218 -2
- package/dist/cli/index.js.map +2 -2
- package/package.json +10 -10
package/dist/cli/index.js
CHANGED
|
@@ -44054,11 +44054,153 @@ var init_list = __esm({
|
|
|
44054
44054
|
}
|
|
44055
44055
|
});
|
|
44056
44056
|
|
|
44057
|
+
// packages/cleo/src/cli/commands/llm-login.ts
|
|
44058
|
+
import { addCredential } from "@cleocode/core/llm/credentials-store.js";
|
|
44059
|
+
import {
|
|
44060
|
+
DeviceCodeAuthError,
|
|
44061
|
+
DeviceCodeTimeoutError,
|
|
44062
|
+
getAnthropicDeviceCodeConfig,
|
|
44063
|
+
pollForToken,
|
|
44064
|
+
startDeviceCodeFlow
|
|
44065
|
+
} from "@cleocode/core/llm/oauth/device-code.js";
|
|
44066
|
+
async function runLlmLogin(provider, opts) {
|
|
44067
|
+
const meta = { operation: "llm.login", timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
44068
|
+
if (provider !== "anthropic") {
|
|
44069
|
+
return {
|
|
44070
|
+
success: false,
|
|
44071
|
+
error: {
|
|
44072
|
+
code: "E_NOT_IMPLEMENTED",
|
|
44073
|
+
codeName: "E_NOT_IMPLEMENTED",
|
|
44074
|
+
message: `OAuth device-code login for '${provider}' is not yet wired. 'anthropic' is the only supported provider in the current MVP. To add credentials for other providers use 'cleo llm add <provider> --api-key-stdin'.`
|
|
44075
|
+
},
|
|
44076
|
+
meta
|
|
44077
|
+
};
|
|
44078
|
+
}
|
|
44079
|
+
const cfg = getAnthropicDeviceCodeConfig();
|
|
44080
|
+
let startResp;
|
|
44081
|
+
try {
|
|
44082
|
+
startResp = await startDeviceCodeFlow(cfg);
|
|
44083
|
+
} catch (err) {
|
|
44084
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
44085
|
+
return {
|
|
44086
|
+
success: false,
|
|
44087
|
+
error: {
|
|
44088
|
+
code: "E_DEVICE_CODE_START_FAILED",
|
|
44089
|
+
codeName: "E_DEVICE_CODE_START_FAILED",
|
|
44090
|
+
message: `Failed to initiate device-code OAuth flow: ${msg}`
|
|
44091
|
+
},
|
|
44092
|
+
meta
|
|
44093
|
+
};
|
|
44094
|
+
}
|
|
44095
|
+
process.stderr.write("\n");
|
|
44096
|
+
process.stderr.write(
|
|
44097
|
+
` Visit: ${startResp.verificationUriComplete ?? startResp.verificationUri}
|
|
44098
|
+
`
|
|
44099
|
+
);
|
|
44100
|
+
process.stderr.write(` Enter code: ${startResp.userCode}
|
|
44101
|
+
`);
|
|
44102
|
+
process.stderr.write("\n");
|
|
44103
|
+
process.stderr.write(
|
|
44104
|
+
` Waiting for authorization (up to ${Math.round(startResp.expiresIn / 60)} min)...
|
|
44105
|
+
`
|
|
44106
|
+
);
|
|
44107
|
+
let tokenResp;
|
|
44108
|
+
try {
|
|
44109
|
+
tokenResp = await pollForToken(cfg, startResp, {
|
|
44110
|
+
onPending: (elapsed) => {
|
|
44111
|
+
process.stderr.write(`\r Polling... ${elapsed}s elapsed`);
|
|
44112
|
+
}
|
|
44113
|
+
});
|
|
44114
|
+
} catch (err) {
|
|
44115
|
+
process.stderr.write("\n");
|
|
44116
|
+
if (err instanceof DeviceCodeTimeoutError) {
|
|
44117
|
+
return {
|
|
44118
|
+
success: false,
|
|
44119
|
+
error: {
|
|
44120
|
+
code: "E_DEVICE_CODE_TIMEOUT",
|
|
44121
|
+
codeName: "E_DEVICE_CODE_TIMEOUT",
|
|
44122
|
+
message: err.message
|
|
44123
|
+
},
|
|
44124
|
+
meta
|
|
44125
|
+
};
|
|
44126
|
+
}
|
|
44127
|
+
if (err instanceof DeviceCodeAuthError) {
|
|
44128
|
+
return {
|
|
44129
|
+
success: false,
|
|
44130
|
+
error: {
|
|
44131
|
+
code: "E_DEVICE_CODE_AUTH_FAILED",
|
|
44132
|
+
codeName: "E_DEVICE_CODE_AUTH_FAILED",
|
|
44133
|
+
message: err.message
|
|
44134
|
+
},
|
|
44135
|
+
meta
|
|
44136
|
+
};
|
|
44137
|
+
}
|
|
44138
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
44139
|
+
return {
|
|
44140
|
+
success: false,
|
|
44141
|
+
error: {
|
|
44142
|
+
code: "E_DEVICE_CODE_POLL_FAILED",
|
|
44143
|
+
codeName: "E_DEVICE_CODE_POLL_FAILED",
|
|
44144
|
+
message: `Polling for device code token failed: ${msg}`
|
|
44145
|
+
},
|
|
44146
|
+
meta
|
|
44147
|
+
};
|
|
44148
|
+
}
|
|
44149
|
+
process.stderr.write("\r Authorization approved. \n\n");
|
|
44150
|
+
const label = opts.label ?? "oauth-login";
|
|
44151
|
+
const expiresAt = typeof tokenResp.expiresIn === "number" ? Date.now() + tokenResp.expiresIn * 1e3 : void 0;
|
|
44152
|
+
try {
|
|
44153
|
+
await addCredential({
|
|
44154
|
+
provider: "anthropic",
|
|
44155
|
+
label,
|
|
44156
|
+
authType: "oauth",
|
|
44157
|
+
accessToken: tokenResp.accessToken,
|
|
44158
|
+
refreshToken: tokenResp.refreshToken,
|
|
44159
|
+
expiresAt,
|
|
44160
|
+
priority: 10,
|
|
44161
|
+
source: "oauth-device-code",
|
|
44162
|
+
extraHeaders: { "anthropic-beta": "oauth-2025-04-20" }
|
|
44163
|
+
});
|
|
44164
|
+
} catch (err) {
|
|
44165
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
44166
|
+
return {
|
|
44167
|
+
success: false,
|
|
44168
|
+
error: {
|
|
44169
|
+
code: "E_CREDENTIAL_STORE_FAILED",
|
|
44170
|
+
codeName: "E_CREDENTIAL_STORE_FAILED",
|
|
44171
|
+
message: `Failed to store credential in pool: ${msg}`
|
|
44172
|
+
},
|
|
44173
|
+
meta
|
|
44174
|
+
};
|
|
44175
|
+
}
|
|
44176
|
+
return {
|
|
44177
|
+
success: true,
|
|
44178
|
+
data: {
|
|
44179
|
+
provider: "anthropic",
|
|
44180
|
+
label,
|
|
44181
|
+
expiresIn: tokenResp.expiresIn
|
|
44182
|
+
},
|
|
44183
|
+
meta
|
|
44184
|
+
};
|
|
44185
|
+
}
|
|
44186
|
+
var init_llm_login = __esm({
|
|
44187
|
+
"packages/cleo/src/cli/commands/llm-login.ts"() {
|
|
44188
|
+
"use strict";
|
|
44189
|
+
}
|
|
44190
|
+
});
|
|
44191
|
+
|
|
44057
44192
|
// packages/cleo/src/cli/commands/llm.ts
|
|
44058
44193
|
var llm_exports = {};
|
|
44059
44194
|
__export(llm_exports, {
|
|
44060
44195
|
llmCommand: () => llmCommand
|
|
44061
44196
|
});
|
|
44197
|
+
async function getListProviders() {
|
|
44198
|
+
const { listProviders } = await import(
|
|
44199
|
+
/* webpackIgnore: true */
|
|
44200
|
+
"@cleocode/core/llm/provider-registry"
|
|
44201
|
+
);
|
|
44202
|
+
return listProviders;
|
|
44203
|
+
}
|
|
44062
44204
|
async function readApiKeyFromStdin() {
|
|
44063
44205
|
if (process.stdin.isTTY) return "";
|
|
44064
44206
|
process.stdin.setEncoding("utf-8");
|
|
@@ -44085,12 +44227,14 @@ function makeLlmSubcommand(opts) {
|
|
|
44085
44227
|
}
|
|
44086
44228
|
});
|
|
44087
44229
|
}
|
|
44088
|
-
var API_KEY_FLAG_DEPRECATION, addCommand5, listCommand10, removeCommand3, useCommand, profileCommand, testCommand, whoamiCommand, llmCommand;
|
|
44230
|
+
var API_KEY_FLAG_DEPRECATION, addCommand5, listCommand10, removeCommand3, useCommand, profileCommand, testCommand, whoamiCommand, listProvidersCommand, loginCommand, llmCommand;
|
|
44089
44231
|
var init_llm3 = __esm({
|
|
44090
44232
|
"packages/cleo/src/cli/commands/llm.ts"() {
|
|
44091
44233
|
"use strict";
|
|
44092
44234
|
init_dist();
|
|
44093
44235
|
init_cli();
|
|
44236
|
+
init_renderers();
|
|
44237
|
+
init_llm_login();
|
|
44094
44238
|
API_KEY_FLAG_DEPRECATION = "[warning] --api-key exposes the secret to 'ps' listings and shell history. Prefer --api-key-stdin or --api-key-env=NAME for production use.";
|
|
44095
44239
|
addCommand5 = defineCommand({
|
|
44096
44240
|
meta: {
|
|
@@ -44331,6 +44475,76 @@ var init_llm3 = __esm({
|
|
|
44331
44475
|
...args["role"] !== void 0 && args["role"] !== "" ? { role: args["role"] } : {}
|
|
44332
44476
|
})
|
|
44333
44477
|
});
|
|
44478
|
+
listProvidersCommand = defineCommand({
|
|
44479
|
+
meta: {
|
|
44480
|
+
name: "list-providers",
|
|
44481
|
+
description: "List all registered LLM provider profiles (builtins + user plugins from $CLEO_HOME/plugins/model-providers/)."
|
|
44482
|
+
},
|
|
44483
|
+
args: {
|
|
44484
|
+
json: {
|
|
44485
|
+
type: "boolean",
|
|
44486
|
+
description: "Output as JSON"
|
|
44487
|
+
}
|
|
44488
|
+
},
|
|
44489
|
+
async run() {
|
|
44490
|
+
const listProviders = await getListProviders();
|
|
44491
|
+
const profiles = await listProviders();
|
|
44492
|
+
const providers = profiles.map((p) => ({
|
|
44493
|
+
name: p.name,
|
|
44494
|
+
displayName: p.displayName,
|
|
44495
|
+
authTypes: p.authTypes,
|
|
44496
|
+
defaultModel: p.defaultModel,
|
|
44497
|
+
baseUrl: p.baseUrl
|
|
44498
|
+
}));
|
|
44499
|
+
cliOutput(
|
|
44500
|
+
{ providers },
|
|
44501
|
+
{
|
|
44502
|
+
command: "llm-list-providers",
|
|
44503
|
+
operation: "llm.listProviders"
|
|
44504
|
+
}
|
|
44505
|
+
);
|
|
44506
|
+
}
|
|
44507
|
+
});
|
|
44508
|
+
loginCommand = defineCommand({
|
|
44509
|
+
meta: {
|
|
44510
|
+
name: "login",
|
|
44511
|
+
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."
|
|
44512
|
+
},
|
|
44513
|
+
args: {
|
|
44514
|
+
provider: {
|
|
44515
|
+
type: "positional",
|
|
44516
|
+
description: "Provider to authenticate with (e.g. anthropic)",
|
|
44517
|
+
required: true
|
|
44518
|
+
},
|
|
44519
|
+
label: {
|
|
44520
|
+
type: "string",
|
|
44521
|
+
description: "Human-readable label for the stored credential (default: 'oauth-login'). Must be unique within the provider. Use distinct labels when storing multiple OAuth sessions."
|
|
44522
|
+
},
|
|
44523
|
+
json: {
|
|
44524
|
+
type: "boolean",
|
|
44525
|
+
description: "Output result as JSON"
|
|
44526
|
+
}
|
|
44527
|
+
},
|
|
44528
|
+
async run({ args }) {
|
|
44529
|
+
const a = args;
|
|
44530
|
+
const provider = String(a["provider"] ?? "");
|
|
44531
|
+
const label = typeof a["label"] === "string" && a["label"] ? a["label"] : void 0;
|
|
44532
|
+
const jsonOutput = a["json"] === true;
|
|
44533
|
+
const result = await runLlmLogin(provider, { label });
|
|
44534
|
+
if (jsonOutput) {
|
|
44535
|
+
process.stdout.write(`${JSON.stringify(result, null, 2)}
|
|
44536
|
+
`);
|
|
44537
|
+
} else if (result.success && result.data) {
|
|
44538
|
+
process.stdout.write(
|
|
44539
|
+
`Logged in to ${result.data.provider} as '${result.data.label}'` + (result.data.expiresIn != null ? ` (expires in ${Math.round(result.data.expiresIn / 60)} min)` : "") + "\n"
|
|
44540
|
+
);
|
|
44541
|
+
} else if (result.error) {
|
|
44542
|
+
process.stderr.write(`[error] ${result.error.message}
|
|
44543
|
+
`);
|
|
44544
|
+
process.exit(1);
|
|
44545
|
+
}
|
|
44546
|
+
}
|
|
44547
|
+
});
|
|
44334
44548
|
llmCommand = defineCommand({
|
|
44335
44549
|
meta: {
|
|
44336
44550
|
name: "llm",
|
|
@@ -44339,11 +44553,13 @@ var init_llm3 = __esm({
|
|
|
44339
44553
|
subCommands: {
|
|
44340
44554
|
add: addCommand5,
|
|
44341
44555
|
list: listCommand10,
|
|
44556
|
+
login: loginCommand,
|
|
44342
44557
|
remove: removeCommand3,
|
|
44343
44558
|
use: useCommand,
|
|
44344
44559
|
profile: profileCommand,
|
|
44345
44560
|
test: testCommand,
|
|
44346
|
-
whoami: whoamiCommand
|
|
44561
|
+
whoami: whoamiCommand,
|
|
44562
|
+
"list-providers": listProvidersCommand
|
|
44347
44563
|
},
|
|
44348
44564
|
async run({ cmd, rawArgs }) {
|
|
44349
44565
|
const firstArg = rawArgs?.find((a) => !a.startsWith("-"));
|