@cleocode/cleo 2026.5.67 → 2026.5.69

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
@@ -1565,6 +1565,13 @@ var init_branch_lock = __esm({
1565
1565
  }
1566
1566
  });
1567
1567
 
1568
+ // packages/contracts/src/credentials.ts
1569
+ var init_credentials = __esm({
1570
+ "packages/contracts/src/credentials.ts"() {
1571
+ "use strict";
1572
+ }
1573
+ });
1574
+
1568
1575
  // packages/contracts/src/engine-result.ts
1569
1576
  var init_engine_result = __esm({
1570
1577
  "packages/contracts/src/engine-result.ts"() {
@@ -1781,6 +1788,13 @@ var init_lafs = __esm({
1781
1788
  }
1782
1789
  });
1783
1790
 
1791
+ // packages/contracts/src/llm/plugin-llm.ts
1792
+ var init_plugin_llm = __esm({
1793
+ "packages/contracts/src/llm/plugin-llm.ts"() {
1794
+ "use strict";
1795
+ }
1796
+ });
1797
+
1784
1798
  // packages/contracts/src/operations/admin.ts
1785
1799
  var init_admin = __esm({
1786
1800
  "packages/contracts/src/operations/admin.ts"() {
@@ -2743,6 +2757,7 @@ var init_src2 = __esm({
2743
2757
  init_acceptance_gate_schema();
2744
2758
  init_attachment_schema();
2745
2759
  init_branch_lock();
2760
+ init_credentials();
2746
2761
  init_engine_result();
2747
2762
  init_errors();
2748
2763
  init_evidence_record_schema();
@@ -2750,6 +2765,7 @@ var init_src2 = __esm({
2750
2765
  init_facade();
2751
2766
  init_graph();
2752
2767
  init_lafs();
2768
+ init_plugin_llm();
2753
2769
  init_operations();
2754
2770
  init_nexus_scope_map();
2755
2771
  init_params();
@@ -16779,8 +16795,10 @@ import {
16779
16795
  generateMemoryBridgeContent,
16780
16796
  getBrainDb,
16781
16797
  getBrainNativeDb,
16798
+ OAUTH_STATUS_PROVIDERS,
16782
16799
  resolveAnthropicApiKey,
16783
16800
  resolveAnthropicApiKeySource,
16801
+ resolveProviderStatus,
16784
16802
  typedAll
16785
16803
  } from "@cleocode/core/internal";
16786
16804
  import {
@@ -17273,6 +17291,7 @@ var init_memory2 = __esm({
17273
17291
  case "llm-status": {
17274
17292
  const resolvedSource = resolveAnthropicApiKeySource();
17275
17293
  const extractionEnabled = resolveAnthropicApiKey() !== null;
17294
+ const providers = OAUTH_STATUS_PROVIDERS.map(resolveProviderStatus);
17276
17295
  let lastExtractionRun = null;
17277
17296
  try {
17278
17297
  await getBrainDb(projectRoot);
@@ -17297,7 +17316,8 @@ var init_memory2 = __esm({
17297
17316
  resolvedSource,
17298
17317
  extractionEnabled,
17299
17318
  lastExtractionRun,
17300
- testCommand: "cleo memory reflect --json"
17319
+ testCommand: "cleo memory reflect --json",
17320
+ providers
17301
17321
  }
17302
17322
  },
17303
17323
  "query",
@@ -34309,7 +34329,7 @@ var backup_inspect_exports = {};
34309
34329
  __export(backup_inspect_exports, {
34310
34330
  backupInspectSubCommand: () => backupInspectSubCommand
34311
34331
  });
34312
- import crypto from "node:crypto";
34332
+ import crypto2 from "node:crypto";
34313
34333
  import fs from "node:fs";
34314
34334
  import os from "node:os";
34315
34335
  import path from "node:path";
@@ -34357,7 +34377,7 @@ function verifyManifestHash(raw, manifest) {
34357
34377
  const intObj = obj["integrity"];
34358
34378
  intObj["manifestHash"] = "";
34359
34379
  const forHashing = JSON.stringify(obj);
34360
- const computed = crypto.createHash("sha256").update(forHashing).digest("hex");
34380
+ const computed = crypto2.createHash("sha256").update(forHashing).digest("hex");
34361
34381
  return computed === expectedHash;
34362
34382
  }
34363
34383
  function fmtBytes(bytes) {
@@ -34574,7 +34594,7 @@ var backup_exports = {};
34574
34594
  __export(backup_exports, {
34575
34595
  backupCommand: () => backupCommand
34576
34596
  });
34577
- import crypto2 from "node:crypto";
34597
+ import crypto3 from "node:crypto";
34578
34598
  import fs2 from "node:fs";
34579
34599
  import path2 from "node:path";
34580
34600
  import readline from "node:readline";
@@ -34628,7 +34648,7 @@ function sha256OfMachineKey(cleoHome) {
34628
34648
  if (!fs2.existsSync(keyPath)) {
34629
34649
  return "0".repeat(64);
34630
34650
  }
34631
- return crypto2.createHash("sha256").update(fs2.readFileSync(keyPath)).digest("hex");
34651
+ return crypto3.createHash("sha256").update(fs2.readFileSync(keyPath)).digest("hex");
34632
34652
  }
34633
34653
  var addCommand2, listCommand4, exportCommand, importCommand, backupCommand;
34634
34654
  var init_backup = __esm({
@@ -44164,28 +44184,210 @@ var init_llm_cost = __esm({
44164
44184
  });
44165
44185
 
44166
44186
  // packages/cleo/src/cli/commands/llm-login.ts
44187
+ import { spawn } from "node:child_process";
44188
+ import { createServer } from "node:http";
44167
44189
  import { addCredential } from "@cleocode/core/llm/credentials-store.js";
44168
44190
  import {
44169
44191
  DeviceCodeAuthError,
44170
44192
  DeviceCodeTimeoutError,
44171
- getAnthropicDeviceCodeConfig,
44193
+ getKimiCodeDeviceCodeConfig,
44172
44194
  pollForToken,
44173
44195
  startDeviceCodeFlow
44174
44196
  } from "@cleocode/core/llm/oauth/device-code.js";
44197
+ import {
44198
+ buildAuthorizationUrl,
44199
+ exchangePkceCode,
44200
+ generatePkcePair,
44201
+ refreshPkceToken
44202
+ } from "@cleocode/core/llm/oauth/pkce.js";
44203
+ import { getKimiCodeMshHeaders } from "@cleocode/core/llm/provider-registry/builtin/kimi-code.js";
44204
+ import { getProviderProfile } from "@cleocode/core/llm/provider-registry/index.js";
44175
44205
  async function runLlmLogin(provider, opts) {
44176
44206
  const meta = { operation: "llm.login", timestamp: (/* @__PURE__ */ new Date()).toISOString() };
44177
- if (provider !== "anthropic") {
44207
+ const profile = await getProviderProfile(provider);
44208
+ const oauthMode = profile?.oauth?.mode;
44209
+ if (provider === "kimi-code" || oauthMode === "device-code") {
44210
+ return _runKimiCodeLogin(opts, meta);
44211
+ }
44212
+ if (oauthMode === "pkce") {
44213
+ return _runPkceLogin(provider, profile.oauth, opts, meta);
44214
+ }
44215
+ return {
44216
+ success: false,
44217
+ error: {
44218
+ code: "E_NOT_IMPLEMENTED",
44219
+ codeName: "E_NOT_IMPLEMENTED",
44220
+ 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'.`
44221
+ },
44222
+ meta
44223
+ };
44224
+ }
44225
+ async function _runPkceLogin(provider, oauthCfg, opts, meta) {
44226
+ const { codeVerifier, codeChallenge } = await generatePkcePair();
44227
+ const state = _generateState();
44228
+ const isHeadless = opts.headless || process.env["CLEO_HEADLESS"] === "1";
44229
+ const port = isHeadless ? 0 : await _findFreePort();
44230
+ const redirectUri = isHeadless ? oauthCfg.redirectUri ?? "http://localhost" : `http://localhost:${port}/callback`;
44231
+ const authUrl = buildAuthorizationUrl({
44232
+ authorizationEndpoint: oauthCfg.authorizationEndpoint ?? "",
44233
+ clientId: oauthCfg.clientId,
44234
+ redirectUri,
44235
+ scope: oauthCfg.scope ?? "",
44236
+ codeChallenge,
44237
+ state
44238
+ });
44239
+ let code;
44240
+ if (isHeadless) {
44241
+ code = await _headlessPkceFlow(provider, authUrl);
44242
+ } else {
44243
+ const result = await _localCallbackPkceFlow(provider, authUrl, state, port);
44244
+ if ("error" in result) {
44245
+ return { success: false, error: result.error, meta };
44246
+ }
44247
+ code = result.code;
44248
+ }
44249
+ let tokens;
44250
+ try {
44251
+ tokens = await exchangePkceCode({
44252
+ provider,
44253
+ clientId: oauthCfg.clientId,
44254
+ code,
44255
+ codeVerifier,
44256
+ redirectUri,
44257
+ tokenEndpoint: oauthCfg.tokenEndpoint
44258
+ });
44259
+ } catch (err) {
44260
+ const msg = err instanceof Error ? err.message : String(err);
44178
44261
  return {
44179
44262
  success: false,
44180
44263
  error: {
44181
- code: "E_NOT_IMPLEMENTED",
44182
- codeName: "E_NOT_IMPLEMENTED",
44183
- 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'.`
44264
+ code: "E_PKCE_EXCHANGE_FAILED",
44265
+ codeName: "E_PKCE_EXCHANGE_FAILED",
44266
+ message: `PKCE code exchange failed: ${msg}`
44184
44267
  },
44185
44268
  meta
44186
44269
  };
44187
44270
  }
44188
- const cfg = getAnthropicDeviceCodeConfig();
44271
+ process.stderr.write("\r Authorization approved. \n\n");
44272
+ const label = opts.label ?? "oauth-login";
44273
+ const expiresAt = typeof tokens.expiresIn === "number" ? Date.now() + tokens.expiresIn * 1e3 : void 0;
44274
+ try {
44275
+ await addCredential({
44276
+ provider,
44277
+ label,
44278
+ authType: "oauth",
44279
+ accessToken: tokens.accessToken,
44280
+ refreshToken: tokens.refreshToken,
44281
+ expiresAt,
44282
+ priority: 10,
44283
+ source: "oauth-pkce",
44284
+ extraHeaders: { "anthropic-beta": "oauth-2025-04-20" }
44285
+ });
44286
+ } catch (err) {
44287
+ const msg = err instanceof Error ? err.message : String(err);
44288
+ return {
44289
+ success: false,
44290
+ error: {
44291
+ code: "E_CREDENTIAL_STORE_FAILED",
44292
+ codeName: "E_CREDENTIAL_STORE_FAILED",
44293
+ message: `Failed to store credential in pool: ${msg}`
44294
+ },
44295
+ meta
44296
+ };
44297
+ }
44298
+ return {
44299
+ success: true,
44300
+ data: { provider, label, expiresIn: tokens.expiresIn },
44301
+ meta
44302
+ };
44303
+ }
44304
+ async function _headlessPkceFlow(provider, authUrl) {
44305
+ process.stderr.write("\n");
44306
+ process.stderr.write(` Provider: ${provider}
44307
+ `);
44308
+ process.stderr.write(` Open this URL in your browser to authorize:
44309
+
44310
+ `);
44311
+ process.stderr.write(` ${authUrl}
44312
+
44313
+ `);
44314
+ process.stderr.write(
44315
+ ` After approving, paste the full redirect URL (http://localhost?code=\u2026&state=\u2026):
44316
+ `
44317
+ );
44318
+ return new Promise((resolve7, reject) => {
44319
+ let buf = "";
44320
+ process.stdin.setEncoding("utf8");
44321
+ process.stdin.once("data", (chunk) => {
44322
+ buf += String(chunk).trim();
44323
+ try {
44324
+ const url = new URL(buf);
44325
+ const code = url.searchParams.get("code");
44326
+ if (!code) {
44327
+ reject(new Error('Redirect URL is missing the "code" parameter'));
44328
+ return;
44329
+ }
44330
+ resolve7(code);
44331
+ } catch {
44332
+ reject(new Error(`Invalid redirect URL: ${buf}`));
44333
+ }
44334
+ });
44335
+ });
44336
+ }
44337
+ async function _localCallbackPkceFlow(provider, authUrl, expectedState, port) {
44338
+ return new Promise((resolve7) => {
44339
+ const server = createServer((req, res) => {
44340
+ const url = new URL(req.url ?? "/", `http://localhost:${port}`);
44341
+ const code = url.searchParams.get("code");
44342
+ const state = url.searchParams.get("state");
44343
+ const error = url.searchParams.get("error");
44344
+ res.writeHead(200, { "Content-Type": "text/html" });
44345
+ if (error) {
44346
+ res.end(`<h1>Authorization failed</h1><p>${error}</p><p>You may close this tab.</p>`);
44347
+ server.close();
44348
+ resolve7({
44349
+ error: {
44350
+ code: "E_PKCE_AUTH_DENIED",
44351
+ codeName: "E_PKCE_AUTH_DENIED",
44352
+ message: `OAuth authorization denied for '${provider}': ${error}`
44353
+ }
44354
+ });
44355
+ return;
44356
+ }
44357
+ if (!code || state !== expectedState) {
44358
+ res.end("<h1>Invalid callback</h1><p>You may close this tab.</p>");
44359
+ server.close();
44360
+ resolve7({
44361
+ error: {
44362
+ code: "E_PKCE_INVALID_CALLBACK",
44363
+ codeName: "E_PKCE_INVALID_CALLBACK",
44364
+ message: "OAuth callback received invalid code or state mismatch"
44365
+ }
44366
+ });
44367
+ return;
44368
+ }
44369
+ res.end("<h1>Authorized</h1><p>You may close this tab and return to your terminal.</p>");
44370
+ server.close();
44371
+ resolve7({ code });
44372
+ });
44373
+ server.listen(port, "localhost", () => {
44374
+ process.stderr.write("\n");
44375
+ process.stderr.write(` Provider: ${provider}
44376
+ `);
44377
+ process.stderr.write(` Open this URL to authorize (or it will open automatically):
44378
+
44379
+ `);
44380
+ process.stderr.write(` ${authUrl}
44381
+
44382
+ `);
44383
+ process.stderr.write(` Waiting for authorization callback...
44384
+ `);
44385
+ _tryOpenBrowser(authUrl);
44386
+ });
44387
+ });
44388
+ }
44389
+ async function _runKimiCodeLogin(opts, meta) {
44390
+ const cfg = getKimiCodeDeviceCodeConfig();
44189
44391
  let startResp;
44190
44392
  try {
44191
44393
  startResp = await startDeviceCodeFlow(cfg);
@@ -44196,7 +44398,7 @@ async function runLlmLogin(provider, opts) {
44196
44398
  error: {
44197
44399
  code: "E_DEVICE_CODE_START_FAILED",
44198
44400
  codeName: "E_DEVICE_CODE_START_FAILED",
44199
- message: `Failed to initiate device-code OAuth flow: ${msg}`
44401
+ message: `Failed to initiate Kimi Code device-code OAuth flow: ${msg}`
44200
44402
  },
44201
44403
  meta
44202
44404
  };
@@ -44210,7 +44412,7 @@ async function runLlmLogin(provider, opts) {
44210
44412
  `);
44211
44413
  process.stderr.write("\n");
44212
44414
  process.stderr.write(
44213
- ` Waiting for authorization (up to ${Math.round(startResp.expiresIn / 60)} min)...
44415
+ ` Waiting for Kimi Code authorization (up to ${Math.round(startResp.expiresIn / 60)} min)...
44214
44416
  `
44215
44417
  );
44216
44418
  let tokenResp;
@@ -44250,17 +44452,17 @@ async function runLlmLogin(provider, opts) {
44250
44452
  error: {
44251
44453
  code: "E_DEVICE_CODE_POLL_FAILED",
44252
44454
  codeName: "E_DEVICE_CODE_POLL_FAILED",
44253
- message: `Polling for device code token failed: ${msg}`
44455
+ message: `Polling for Kimi Code device-code token failed: ${msg}`
44254
44456
  },
44255
44457
  meta
44256
44458
  };
44257
44459
  }
44258
- process.stderr.write("\r Authorization approved. \n\n");
44460
+ process.stderr.write("\r Kimi Code authorization approved. \n\n");
44259
44461
  const label = opts.label ?? "oauth-login";
44260
44462
  const expiresAt = typeof tokenResp.expiresIn === "number" ? Date.now() + tokenResp.expiresIn * 1e3 : void 0;
44261
44463
  try {
44262
44464
  await addCredential({
44263
- provider: "anthropic",
44465
+ provider: "kimi-code",
44264
44466
  label,
44265
44467
  authType: "oauth",
44266
44468
  accessToken: tokenResp.accessToken,
@@ -44268,7 +44470,9 @@ async function runLlmLogin(provider, opts) {
44268
44470
  expiresAt,
44269
44471
  priority: 10,
44270
44472
  source: "oauth-device-code",
44271
- extraHeaders: { "anthropic-beta": "oauth-2025-04-20" }
44473
+ // The six mandatory X-Msh-* headers must be carried alongside the token
44474
+ // so every transport that picks this credential sends them automatically.
44475
+ extraHeaders: getKimiCodeMshHeaders()
44272
44476
  });
44273
44477
  } catch (err) {
44274
44478
  const msg = err instanceof Error ? err.message : String(err);
@@ -44277,7 +44481,7 @@ async function runLlmLogin(provider, opts) {
44277
44481
  error: {
44278
44482
  code: "E_CREDENTIAL_STORE_FAILED",
44279
44483
  codeName: "E_CREDENTIAL_STORE_FAILED",
44280
- message: `Failed to store credential in pool: ${msg}`
44484
+ message: `Failed to store Kimi Code credential in pool: ${msg}`
44281
44485
  },
44282
44486
  meta
44283
44487
  };
@@ -44285,13 +44489,40 @@ async function runLlmLogin(provider, opts) {
44285
44489
  return {
44286
44490
  success: true,
44287
44491
  data: {
44288
- provider: "anthropic",
44492
+ provider: "kimi-code",
44289
44493
  label,
44290
44494
  expiresIn: tokenResp.expiresIn
44291
44495
  },
44292
44496
  meta
44293
44497
  };
44294
44498
  }
44499
+ function _generateState() {
44500
+ const bytes = crypto.getRandomValues(new Uint8Array(16));
44501
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
44502
+ }
44503
+ function _findFreePort() {
44504
+ return new Promise((resolve7, reject) => {
44505
+ const srv = createServer();
44506
+ srv.listen(0, "localhost", () => {
44507
+ const addr = srv.address();
44508
+ if (!addr || typeof addr === "string") {
44509
+ srv.close();
44510
+ reject(new Error("Could not determine callback port"));
44511
+ return;
44512
+ }
44513
+ const port = addr.port;
44514
+ srv.close(() => resolve7(port));
44515
+ });
44516
+ srv.on("error", reject);
44517
+ });
44518
+ }
44519
+ function _tryOpenBrowser(url) {
44520
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
44521
+ try {
44522
+ spawn(cmd, [url], { detached: true, stdio: "ignore" }).unref();
44523
+ } catch {
44524
+ }
44525
+ }
44295
44526
  var init_llm_login = __esm({
44296
44527
  "packages/cleo/src/cli/commands/llm-login.ts"() {
44297
44528
  "use strict";
@@ -58641,7 +58872,7 @@ var web_exports = {};
58641
58872
  __export(web_exports, {
58642
58873
  webCommand: () => webCommand
58643
58874
  });
58644
- import { execFileSync as execFileSync4, spawn } from "node:child_process";
58875
+ import { execFileSync as execFileSync4, spawn as spawn2 } from "node:child_process";
58645
58876
  import { mkdir as mkdir3, open, readFile as readFile5, rm, stat, writeFile as writeFile2 } from "node:fs/promises";
58646
58877
  import { join as join24 } from "node:path";
58647
58878
  import { CleoError as CleoError12, formatError as formatError9, getCleoHome as getCleoHome2 } from "@cleocode/core";
@@ -58718,7 +58949,7 @@ Logs: ${logFile}`
58718
58949
  }
58719
58950
  }
58720
58951
  const logFileHandle = await open(logFile, "a");
58721
- const serverProcess = spawn("node", [webIndexPath], {
58952
+ const serverProcess = spawn2("node", [webIndexPath], {
58722
58953
  cwd: studioDir,
58723
58954
  env: {
58724
58955
  ...process.env,
@@ -58817,7 +59048,7 @@ var init_web = __esm({
58817
59048
  }
58818
59049
  try {
58819
59050
  if (process.platform === "win32") {
58820
- spawn("taskkill", ["/PID", String(status.pid), "/T"], { stdio: "ignore" });
59051
+ spawn2("taskkill", ["/PID", String(status.pid), "/T"], { stdio: "ignore" });
58821
59052
  } else {
58822
59053
  process.kill(status.pid, "SIGTERM");
58823
59054
  }
@@ -58830,7 +59061,7 @@ var init_web = __esm({
58830
59061
  if (isProcessRunning(status.pid)) {
58831
59062
  try {
58832
59063
  if (process.platform === "win32") {
58833
- spawn("taskkill", ["/PID", String(status.pid), "/F", "/T"], { stdio: "ignore" });
59064
+ spawn2("taskkill", ["/PID", String(status.pid), "/F", "/T"], { stdio: "ignore" });
58834
59065
  } else {
58835
59066
  process.kill(status.pid, "SIGKILL");
58836
59067
  }
@@ -58869,7 +59100,7 @@ var init_web = __esm({
58869
59100
  if (status.running && status.pid) {
58870
59101
  try {
58871
59102
  if (process.platform === "win32") {
58872
- spawn("taskkill", ["/PID", String(status.pid), "/T"], { stdio: "ignore" });
59103
+ spawn2("taskkill", ["/PID", String(status.pid), "/T"], { stdio: "ignore" });
58873
59104
  } else {
58874
59105
  process.kill(status.pid, "SIGTERM");
58875
59106
  }
@@ -58882,7 +59113,7 @@ var init_web = __esm({
58882
59113
  if (isProcessRunning(status.pid)) {
58883
59114
  try {
58884
59115
  if (process.platform === "win32") {
58885
- spawn("taskkill", ["/PID", String(status.pid), "/F", "/T"], { stdio: "ignore" });
59116
+ spawn2("taskkill", ["/PID", String(status.pid), "/F", "/T"], { stdio: "ignore" });
58886
59117
  } else {
58887
59118
  process.kill(status.pid, "SIGKILL");
58888
59119
  }
@@ -58931,11 +59162,11 @@ var init_web = __esm({
58931
59162
  const platform = process.platform;
58932
59163
  try {
58933
59164
  if (platform === "linux") {
58934
- spawn("xdg-open", [url], { detached: true, stdio: "ignore" }).unref();
59165
+ spawn2("xdg-open", [url], { detached: true, stdio: "ignore" }).unref();
58935
59166
  } else if (platform === "darwin") {
58936
- spawn("open", [url], { detached: true, stdio: "ignore" }).unref();
59167
+ spawn2("open", [url], { detached: true, stdio: "ignore" }).unref();
58937
59168
  } else if (platform === "win32") {
58938
- spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
59169
+ spawn2("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" }).unref();
58939
59170
  }
58940
59171
  } catch {
58941
59172
  }