@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 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("-"));