codeam-cli 2.60.13 → 2.60.15

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/index.js +209 -53
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.60.14] — 2026-07-08
8
+
9
+ ### Added
10
+
11
+ - **cli:** Add Kimi Code (Moonshot) as a native ACP agent
12
+
13
+ ## [2.60.13] — 2026-07-08
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Pair-auto must never be a local/baton session (agent_banner regression)
18
+
7
19
  ## [2.60.12] — 2026-07-08
8
20
 
9
21
  ### Fixed
package/dist/index.js CHANGED
@@ -389,6 +389,23 @@ var AGENT_REGISTRY = {
389
389
  headroomWrappable: false,
390
390
  // Native ACP server: `gemini --skip-trust --acp`.
391
391
  acp: true
392
+ },
393
+ kimi: {
394
+ id: "kimi",
395
+ displayName: "Kimi Code",
396
+ binaryName: "kimi",
397
+ enabled: true,
398
+ // API key (KIMI_API_KEY, + optional KIMI_BASE_URL) is the shipping auth —
399
+ // fully documented, no reverse-engineering. OAuth `/login` (login-state at
400
+ // ~/.kimi-code/credentials/<name>.json, base https://api.kimi.com/coding/)
401
+ // is declared so it can land later without a wire change, but capturing
402
+ // that blob server-side is a separate reverse-engineering spike (phase 2).
403
+ supportedAuthKinds: ["api_key", "oauth_token"],
404
+ preferredAuthKind: "api_key",
405
+ // Moonshot's `kimi` is not listed by `headroom wrap --help` — runs native.
406
+ headroomWrappable: false,
407
+ // Native ACP server: `kimi acp` (stdio JSON-RPC, answers `initialize`).
408
+ acp: true
392
409
  }
393
410
  };
394
411
  function getEnabledAgents() {
@@ -417,6 +434,7 @@ var PUBLIC_TO_INTERNAL = {
417
434
  aider: "aider",
418
435
  coderabbit: "coderabbit",
419
436
  gemini: "gemini",
437
+ kimi: "kimi",
420
438
  // The house agent runs Claude Code under the hood (pointed at the
421
439
  // MiniMax proxy). Its internal runtime is therefore `claude`.
422
440
  [HOUSE_AGENT_ID]: "claude"
@@ -5662,7 +5680,7 @@ function readAnonId() {
5662
5680
  }
5663
5681
  function superProperties() {
5664
5682
  return {
5665
- cliVersion: true ? "2.60.13" : "0.0.0-dev",
5683
+ cliVersion: true ? "2.60.15" : "0.0.0-dev",
5666
5684
  nodeVersion: process.version,
5667
5685
  platform: process.platform,
5668
5686
  arch: process.arch,
@@ -5843,7 +5861,7 @@ var os4 = __toESM(require("os"));
5843
5861
  // package.json
5844
5862
  var package_default = {
5845
5863
  name: "codeam-cli",
5846
- version: "2.60.13",
5864
+ version: "2.60.15",
5847
5865
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
5848
5866
  type: "commonjs",
5849
5867
  main: "dist/index.js",
@@ -6914,7 +6932,7 @@ var CommandRelayService = class {
6914
6932
  // fresh + clear the "CLI update available" banner after a self-update
6915
6933
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
6916
6934
  // pair/reconnect). Older backends ignore the extra field.
6917
- ..."2.60.13" ? { ideVersion: "2.60.13" } : {}
6935
+ ..."2.60.15" ? { ideVersion: "2.60.15" } : {}
6918
6936
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
6919
6937
  }
6920
6938
  /**
@@ -7141,10 +7159,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
7141
7159
  /[\\/]Start Menu([\\/]|$)/i,
7142
7160
  /[\\/]Templates([\\/]|$)/i
7143
7161
  ];
7144
- function isUnsafeWindowsWatchRoot(dir, homedir38) {
7162
+ function isUnsafeWindowsWatchRoot(dir, homedir39) {
7145
7163
  const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
7146
7164
  const cwd = norm(dir);
7147
- const home = norm(homedir38);
7165
+ const home = norm(homedir39);
7148
7166
  if (cwd === home) return true;
7149
7167
  if (/^[a-z]:$/.test(cwd)) return true;
7150
7168
  const sysRoots = [
@@ -14258,6 +14276,111 @@ var GeminiRuntimeStrategy = class {
14258
14276
  }
14259
14277
  };
14260
14278
 
14279
+ // src/agents/kimi/runtime.ts
14280
+ var import_node_child_process12 = require("child_process");
14281
+ var import_node_os3 = require("os");
14282
+ var import_node_path4 = require("path");
14283
+ var KIMI_CONTEXT_WINDOW = 262144;
14284
+ var KIMI_MODELS = [
14285
+ { id: "kimi-for-coding", label: "Kimi for Coding", contextWindow: KIMI_CONTEXT_WINDOW }
14286
+ ];
14287
+ function kimiCredentialsDir() {
14288
+ const root = process.env.KIMI_CODE_HOME || (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".kimi-code");
14289
+ return (0, import_node_path4.join)(root, "credentials");
14290
+ }
14291
+ var KimiRuntimeStrategy = class {
14292
+ id = "kimi";
14293
+ meta = getAgent("kimi");
14294
+ mode = "interactive";
14295
+ os;
14296
+ constructor(os48) {
14297
+ this.os = os48;
14298
+ }
14299
+ async prepareLaunch() {
14300
+ const binary = this.os.findInPath("kimi");
14301
+ if (!binary) {
14302
+ throw new Error(
14303
+ "Kimi Code CLI is not on PATH. Install it with:\n curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash\n Then run `codeam pair` again."
14304
+ );
14305
+ }
14306
+ const launch = this.os.buildLaunch(binary, []);
14307
+ return { cmd: launch.cmd, args: launch.args };
14308
+ }
14309
+ resumeLaunchArgs(_sessionId, _opts) {
14310
+ return [];
14311
+ }
14312
+ resolveHistoryDir(_cwd) {
14313
+ return null;
14314
+ }
14315
+ parseHistoryFile(_filePath) {
14316
+ return [];
14317
+ }
14318
+ getCurrentUsage(_historyDir) {
14319
+ return null;
14320
+ }
14321
+ async fetchWeeklyUsage() {
14322
+ return null;
14323
+ }
14324
+ async listModels() {
14325
+ return KIMI_MODELS;
14326
+ }
14327
+ changeModelInstruction(modelId) {
14328
+ return { type: "pty", ptyInput: `/model ${modelId}\r` };
14329
+ }
14330
+ summarizeInstruction(_mode) {
14331
+ return { ptyInput: "/compact\r" };
14332
+ }
14333
+ filterTuiOutput(lines) {
14334
+ return lines;
14335
+ }
14336
+ detectInteractivePrompt(_lines) {
14337
+ return null;
14338
+ }
14339
+ /**
14340
+ * Headless single-prompt invocation — powers `request_ai_summary` /
14341
+ * `request_ai_insight` (Files review) AND Preview detection, same as
14342
+ * claude/codex/gemini. Kimi's non-interactive print mode is
14343
+ * `kimi -p "<prompt>" --output-format text`: it streams the assistant reply
14344
+ * to stdout under the `auto` permission policy (no approval prompt) and exits.
14345
+ * Returns `null` on spawn failure / timeout / empty output so callers skip
14346
+ * silently instead of bubbling a partial reply.
14347
+ */
14348
+ async generateOneShot(prompt, opts) {
14349
+ const binary = this.os.findInPath("kimi");
14350
+ if (!binary) return null;
14351
+ const launch = this.os.buildLaunch(binary, ["-p", prompt, "--output-format", "text"]);
14352
+ return spawnAndCapture(launch.cmd, launch.args, {
14353
+ cwd: opts?.cwd,
14354
+ timeoutMs: opts?.timeoutMs
14355
+ });
14356
+ }
14357
+ credentialLocator() {
14358
+ return {
14359
+ publicId: "kimi",
14360
+ vendor: "Moonshot",
14361
+ hint: "~/.kimi-code/credentials/",
14362
+ watchPaths: () => [kimiCredentialsDir()],
14363
+ // Phase-2 OAuth capture: the `kimi` toolchain writes per-provider OAuth
14364
+ // JSON under this dir after `/login`. Until that flow is reverse-engineered
14365
+ // (blob format + refresh), file capture is a no-op — the shipping auth is
14366
+ // the API key (KIMI_API_KEY), delivered by the provisioner, not this
14367
+ // watcher. Returning null means "nothing captured here yet".
14368
+ extract: async () => null,
14369
+ validate: validateNonEmptyCredential
14370
+ };
14371
+ }
14372
+ loginLauncher() {
14373
+ return {
14374
+ async ensureInstalled() {
14375
+ return createOsStrategy().findInPath("kimi") !== null;
14376
+ },
14377
+ launch() {
14378
+ return (0, import_node_child_process12.spawn)("kimi", [], { stdio: "inherit" });
14379
+ }
14380
+ };
14381
+ }
14382
+ };
14383
+
14261
14384
  // src/agents/registry.ts
14262
14385
  var runtimeBuilders = {
14263
14386
  claude: (os48) => new ClaudeRuntimeStrategy(os48),
@@ -14265,7 +14388,8 @@ var runtimeBuilders = {
14265
14388
  coderabbit: (os48) => new CoderabbitRuntimeStrategy(os48),
14266
14389
  cursor: (os48) => new CursorRuntimeStrategy(os48),
14267
14390
  aider: (os48) => new AiderRuntimeStrategy(os48),
14268
- gemini: (os48) => new GeminiRuntimeStrategy(os48)
14391
+ gemini: (os48) => new GeminiRuntimeStrategy(os48),
14392
+ kimi: (os48) => new KimiRuntimeStrategy(os48)
14269
14393
  };
14270
14394
  var deployBuilders = {
14271
14395
  claude: () => new ClaudeDeployStrategy(),
@@ -14684,7 +14808,7 @@ async function linkDryRunPreflight(ctx) {
14684
14808
  }
14685
14809
 
14686
14810
  // src/commands/host-agent.ts
14687
- var import_node_child_process19 = require("child_process");
14811
+ var import_node_child_process20 = require("child_process");
14688
14812
  var os33 = __toESM(require("os"));
14689
14813
  var fs39 = __toESM(require("fs"));
14690
14814
  var path41 = __toESM(require("path"));
@@ -14696,8 +14820,8 @@ var path34 = __toESM(require("path"));
14696
14820
 
14697
14821
  // src/lib/restrict-to-owner.ts
14698
14822
  var import_node_fs5 = __toESM(require("fs"));
14699
- var import_node_os3 = __toESM(require("os"));
14700
- var import_node_child_process12 = require("child_process");
14823
+ var import_node_os4 = __toESM(require("os"));
14824
+ var import_node_child_process13 = require("child_process");
14701
14825
  var BROAD_WINDOWS_SIDS = [
14702
14826
  "*S-1-1-0",
14703
14827
  "*S-1-5-11",
@@ -14708,8 +14832,8 @@ var BROAD_WINDOWS_SIDS = [
14708
14832
  function restrictToOwner(filePath) {
14709
14833
  try {
14710
14834
  if (process.platform === "win32") {
14711
- const username = import_node_os3.default.userInfo().username;
14712
- (0, import_node_child_process12.execFileSync)(
14835
+ const username = import_node_os4.default.userInfo().username;
14836
+ (0, import_node_child_process13.execFileSync)(
14713
14837
  "icacls",
14714
14838
  [
14715
14839
  filePath,
@@ -14971,9 +15095,9 @@ async function reportDeployProgress(auth, deployId, step, message, sessionId) {
14971
15095
  var fs32 = __toESM(require("fs"));
14972
15096
  var os28 = __toESM(require("os"));
14973
15097
  var path35 = __toESM(require("path"));
14974
- var import_node_child_process13 = require("child_process");
15098
+ var import_node_child_process14 = require("child_process");
14975
15099
  var import_node_util4 = require("util");
14976
- var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process13.execFile);
15100
+ var execFileP4 = (0, import_node_util4.promisify)(import_node_child_process14.execFile);
14977
15101
  function isAbsolutePathTarget(target) {
14978
15102
  return path35.isAbsolute(target);
14979
15103
  }
@@ -15111,7 +15235,8 @@ var PUBLIC_TO_INTERNAL_AGENT = {
15111
15235
  cursor: "cursor",
15112
15236
  aider: "aider",
15113
15237
  coderabbit: "coderabbit",
15114
- gemini: "gemini"
15238
+ gemini: "gemini",
15239
+ kimi: "kimi"
15115
15240
  };
15116
15241
  function toInternalAgentId(publicAgentId) {
15117
15242
  return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
@@ -15204,8 +15329,23 @@ var cursorProvisioner = {
15204
15329
  return {};
15205
15330
  }
15206
15331
  };
15332
+ var kimiProvisioner = {
15333
+ write(auth, home) {
15334
+ const credentialsFiles = [
15335
+ path36.join(home, ".kimi", "credentials", "kimi-code.json"),
15336
+ path36.join(home, ".kimi-code", "credentials", "kimi-code.json")
15337
+ ];
15338
+ if (auth.kind === "api_key") {
15339
+ credentialsFiles.forEach(rmIfExists);
15340
+ return { KIMI_API_KEY: auth.value };
15341
+ }
15342
+ credentialsFiles.forEach((f) => writeFile0600(f, auth.value));
15343
+ return {};
15344
+ }
15345
+ };
15207
15346
  var PROVISIONERS = {
15208
15347
  claude: claudeProvisioner,
15348
+ kimi: kimiProvisioner,
15209
15349
  codex: codexProvisioner,
15210
15350
  gemini: geminiProvisioner,
15211
15351
  cursor: cursorProvisioner
@@ -15227,7 +15367,7 @@ function provisionAgentCredentials(publicAgentId, auth, homeDir2 = os29.homedir(
15227
15367
  }
15228
15368
 
15229
15369
  // src/commands/host/git-tooling.ts
15230
- var import_node_child_process14 = require("child_process");
15370
+ var import_node_child_process15 = require("child_process");
15231
15371
  var fs34 = __toESM(require("fs"));
15232
15372
  var os30 = __toESM(require("os"));
15233
15373
  var path37 = __toESM(require("path"));
@@ -15341,7 +15481,7 @@ var defaultGitToolingRunner = {
15341
15481
  which(cmd) {
15342
15482
  try {
15343
15483
  const probe = process.platform === "win32" ? "where" : "which";
15344
- (0, import_node_child_process14.execFileSync)(probe, [cmd], { stdio: "ignore" });
15484
+ (0, import_node_child_process15.execFileSync)(probe, [cmd], { stdio: "ignore" });
15345
15485
  return true;
15346
15486
  } catch {
15347
15487
  return false;
@@ -15349,7 +15489,7 @@ var defaultGitToolingRunner = {
15349
15489
  },
15350
15490
  run(cmd, args2, opts = {}) {
15351
15491
  return new Promise((resolve7) => {
15352
- const child = (0, import_node_child_process14.spawn)(cmd, args2, {
15492
+ const child = (0, import_node_child_process15.spawn)(cmd, args2, {
15353
15493
  stdio: [opts.input !== void 0 ? "pipe" : "ignore", "ignore", "pipe"]
15354
15494
  });
15355
15495
  let stderr = "";
@@ -15503,12 +15643,12 @@ var HeadroomStatsReporter = class {
15503
15643
  };
15504
15644
 
15505
15645
  // src/commands/host/os-packages.ts
15506
- var import_node_child_process15 = require("child_process");
15646
+ var import_node_child_process16 = require("child_process");
15507
15647
  var PM_INSTALL_TIMEOUT_MS = 18e4;
15508
15648
  var defaultHeadroomRunner = {
15509
15649
  which(cmd) {
15510
15650
  try {
15511
- (0, import_node_child_process15.execFileSync)("which", [cmd], { stdio: "ignore" });
15651
+ (0, import_node_child_process16.execFileSync)("which", [cmd], { stdio: "ignore" });
15512
15652
  return true;
15513
15653
  } catch {
15514
15654
  return false;
@@ -15517,7 +15657,7 @@ var defaultHeadroomRunner = {
15517
15657
  run(cmd, args2, opts = {}) {
15518
15658
  return new Promise((resolve7) => {
15519
15659
  const spawnEnv = opts.env ?? process.env;
15520
- const child = (0, import_node_child_process15.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"], env: spawnEnv });
15660
+ const child = (0, import_node_child_process16.spawn)(cmd, args2, { stdio: ["ignore", "pipe", "pipe"], env: spawnEnv });
15521
15661
  let stderrBuf = "";
15522
15662
  let stdoutBuf = "";
15523
15663
  let settled = false;
@@ -16024,14 +16164,14 @@ async function setupHeadroomForSelfHosted(agent, runner = defaultHeadroomRunner,
16024
16164
  }
16025
16165
 
16026
16166
  // src/commands/host/self-update.ts
16027
- var import_node_child_process17 = require("child_process");
16167
+ var import_node_child_process18 = require("child_process");
16028
16168
 
16029
16169
  // src/lib/updateNotifier.ts
16030
16170
  var fs37 = __toESM(require("fs"));
16031
16171
  var os32 = __toESM(require("os"));
16032
16172
  var path40 = __toESM(require("path"));
16033
16173
  var https6 = __toESM(require("https"));
16034
- var import_node_child_process16 = require("child_process");
16174
+ var import_node_child_process17 = require("child_process");
16035
16175
  var import_picocolors3 = __toESM(require("picocolors"));
16036
16176
  var PKG_NAME = "codeam-cli";
16037
16177
  var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
@@ -16125,7 +16265,7 @@ function notifyIfStale(currentVersion, latest) {
16125
16265
  }
16126
16266
  function isLinkedInstall() {
16127
16267
  try {
16128
- const root = (0, import_node_child_process16.execSync)("npm root -g", {
16268
+ const root = (0, import_node_child_process17.execSync)("npm root -g", {
16129
16269
  encoding: "utf8",
16130
16270
  stdio: ["ignore", "pipe", "ignore"],
16131
16271
  timeout: 2e3
@@ -16153,7 +16293,7 @@ function maybeAutoUpdate(currentVersion, latest) {
16153
16293
 
16154
16294
  `
16155
16295
  );
16156
- const install = (0, import_node_child_process16.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
16296
+ const install = (0, import_node_child_process17.spawnSync)("npm", ["install", "-g", `${PKG_NAME}@latest`], {
16157
16297
  stdio: "inherit",
16158
16298
  env: process.env
16159
16299
  });
@@ -16174,7 +16314,7 @@ function maybeAutoUpdate(currentVersion, latest) {
16174
16314
  process.stderr.write(` ${import_picocolors3.default.green("\u2713")} Updated. Resuming session...
16175
16315
 
16176
16316
  `);
16177
- const child = (0, import_node_child_process16.spawnSync)("codeam", process.argv.slice(2), {
16317
+ const child = (0, import_node_child_process17.spawnSync)("codeam", process.argv.slice(2), {
16178
16318
  stdio: "inherit",
16179
16319
  env: process.env
16180
16320
  });
@@ -16184,7 +16324,7 @@ async function autoUpgradeBeforeCriticalCommand() {
16184
16324
  if (process.env.NODE_ENV === "test") return;
16185
16325
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
16186
16326
  if (process.env.CI) return;
16187
- const current = true ? "2.60.13" : null;
16327
+ const current = true ? "2.60.15" : null;
16188
16328
  if (!current) return;
16189
16329
  const cache = readCache();
16190
16330
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -16201,7 +16341,7 @@ function checkForUpdates() {
16201
16341
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
16202
16342
  if (process.env.CI) return;
16203
16343
  if (!process.stdout.isTTY) return;
16204
- const current = true ? "2.60.13" : null;
16344
+ const current = true ? "2.60.15" : null;
16205
16345
  if (!current) return;
16206
16346
  const cache = readCache();
16207
16347
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -16221,11 +16361,11 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
16221
16361
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
16222
16362
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
16223
16363
  function currentCliVersion() {
16224
- return true ? "2.60.13" : null;
16364
+ return true ? "2.60.15" : null;
16225
16365
  }
16226
16366
  function runCmd(cmd, args2, timeoutMs) {
16227
16367
  return new Promise((resolve7) => {
16228
- (0, import_node_child_process17.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
16368
+ (0, import_node_child_process18.execFile)(cmd, args2, { timeout: timeoutMs }, (err, stdout, stderr) => {
16229
16369
  const code = err && typeof err.code === "number" ? err.code : err ? null : 0;
16230
16370
  resolve7({ code, stdout: stdout ?? "", stderr: stderr ?? "" });
16231
16371
  });
@@ -16287,11 +16427,11 @@ async function runSelfUpdate() {
16287
16427
  }
16288
16428
 
16289
16429
  // src/commands/host/teardown.ts
16290
- var import_node_child_process18 = require("child_process");
16430
+ var import_node_child_process19 = require("child_process");
16291
16431
  var fs38 = __toESM(require("fs"));
16292
16432
  var defaultDisableService = () => {
16293
16433
  try {
16294
- (0, import_node_child_process18.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
16434
+ (0, import_node_child_process19.execFileSync)("systemctl", ["disable", "--now", "codeam-host-agent"], { stdio: "ignore" });
16295
16435
  } catch {
16296
16436
  }
16297
16437
  };
@@ -16299,7 +16439,7 @@ var defaultTeardownHeadroom = () => {
16299
16439
  try {
16300
16440
  const kind = JSON.parse(fs38.readFileSync(headroomConfigPath(), "utf8")).agent;
16301
16441
  if (kind) {
16302
- (0, import_node_child_process18.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
16442
+ (0, import_node_child_process19.execFileSync)("headroom", ["unwrap", kind], { stdio: "ignore", timeout: 15e3 });
16303
16443
  }
16304
16444
  } catch {
16305
16445
  }
@@ -16457,7 +16597,7 @@ var CONTROL_AGENT_META = {
16457
16597
  headroomWrappable: false,
16458
16598
  acp: false
16459
16599
  };
16460
- var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process19.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
16600
+ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process20.spawn)(process.execPath, [process.argv[1], "pair-auto", ...args2], {
16461
16601
  cwd,
16462
16602
  env: { ...process.env, ...env },
16463
16603
  stdio: ["ignore", "pipe", "pipe"],
@@ -16937,7 +17077,7 @@ var HostAgentSupervisor = class {
16937
17077
  runAgentInstall(script) {
16938
17078
  return new Promise((resolve7) => {
16939
17079
  const home = process.env.HOME || os33.homedir();
16940
- const child = (0, import_node_child_process19.spawn)("sh", ["-c", script], {
17080
+ const child = (0, import_node_child_process20.spawn)("sh", ["-c", script], {
16941
17081
  env: { ...process.env, HOME: home },
16942
17082
  stdio: ["ignore", "pipe", "pipe"]
16943
17083
  });
@@ -17245,11 +17385,11 @@ function makeRealApplyBudgetDeps() {
17245
17385
  var import_child_process14 = require("child_process");
17246
17386
  var import_fs = require("fs");
17247
17387
  var import_promises = __toESM(require("fs/promises"));
17248
- var import_os6 = __toESM(require("os"));
17388
+ var import_os7 = __toESM(require("os"));
17249
17389
  var import_path4 = __toESM(require("path"));
17250
17390
  var import_promises2 = require("stream/promises");
17251
17391
  var import_which = __toESM(require("which"));
17252
- var CACHED_BINARY = import_path4.default.join(import_os6.default.homedir(), ".codeam", "bin", "cloudflared");
17392
+ var CACHED_BINARY = import_path4.default.join(import_os7.default.homedir(), ".codeam", "bin", "cloudflared");
17253
17393
  async function resolveCloudflared(opts = {}) {
17254
17394
  try {
17255
17395
  return await (0, import_which.default)("cloudflared");
@@ -17349,7 +17489,7 @@ function decodeTunnelToken(token) {
17349
17489
  }
17350
17490
  async function spawnNamedTunnel(bin, token, port) {
17351
17491
  const creds = decodeTunnelToken(token);
17352
- const credDir = import_path4.default.join(import_os6.default.homedir(), ".codeam");
17492
+ const credDir = import_path4.default.join(import_os7.default.homedir(), ".codeam");
17353
17493
  await import_promises.default.mkdir(credDir, { recursive: true });
17354
17494
  const credFile = import_path4.default.join(credDir, `tunnel-${creds.TunnelID}.json`);
17355
17495
  await import_promises.default.writeFile(credFile, JSON.stringify(creds), { mode: 384 });
@@ -18969,6 +19109,9 @@ var AGENT_SETUP_RECIPE = {
18969
19109
  cursor: "cursor",
18970
19110
  aider: "aider",
18971
19111
  gemini: "gemini",
19112
+ // bd 1.0.5 has no Kimi recipe → skip (like coderabbit); beads still works,
19113
+ // the agent just isn't wired natively via `bd setup`.
19114
+ kimi: null,
18972
19115
  coderabbit: null
18973
19116
  };
18974
19117
  var _provisionSeam = {
@@ -19537,10 +19680,10 @@ async function handleBeadsActionCommand(action, started) {
19537
19680
 
19538
19681
  // src/beads/config-store.ts
19539
19682
  var import_node_fs6 = __toESM(require("fs"));
19540
- var import_node_os4 = __toESM(require("os"));
19541
- var import_node_path4 = __toESM(require("path"));
19683
+ var import_node_os5 = __toESM(require("os"));
19684
+ var import_node_path5 = __toESM(require("path"));
19542
19685
  function beadsConfigPath() {
19543
- return import_node_path4.default.join(import_node_os4.default.homedir(), ".codeam", "beads-config.json");
19686
+ return import_node_path5.default.join(import_node_os5.default.homedir(), ".codeam", "beads-config.json");
19544
19687
  }
19545
19688
  function readBeadsEnabled() {
19546
19689
  try {
@@ -19553,7 +19696,7 @@ function readBeadsEnabled() {
19553
19696
  }
19554
19697
  function persistBeadsConfig(cfg) {
19555
19698
  const file = beadsConfigPath();
19556
- import_node_fs6.default.mkdirSync(import_node_path4.default.dirname(file), { recursive: true });
19699
+ import_node_fs6.default.mkdirSync(import_node_path5.default.dirname(file), { recursive: true });
19557
19700
  const tmp = `${file}.tmp`;
19558
19701
  import_node_fs6.default.writeFileSync(tmp, JSON.stringify(cfg), { mode: 384 });
19559
19702
  import_node_fs6.default.renameSync(tmp, file);
@@ -21340,7 +21483,7 @@ async function pairAuto(args2) {
21340
21483
  }
21341
21484
 
21342
21485
  // src/services/headroom/wrap-launch.ts
21343
- var import_node_child_process20 = require("child_process");
21486
+ var import_node_child_process21 = require("child_process");
21344
21487
  function wrapWithHeadroom(launch, opts) {
21345
21488
  if (!opts.enabled || !opts.headroomPresent) return launch;
21346
21489
  return {
@@ -21353,7 +21496,7 @@ var _present;
21353
21496
  function headroomPresent() {
21354
21497
  if (_present !== void 0) return Promise.resolve(_present);
21355
21498
  return new Promise((resolve7) => {
21356
- (0, import_node_child_process20.execFile)("headroom", ["--version"], (err) => {
21499
+ (0, import_node_child_process21.execFile)("headroom", ["--version"], (err) => {
21357
21500
  _present = !err;
21358
21501
  resolve7(_present);
21359
21502
  });
@@ -21707,7 +21850,7 @@ var path57 = __toESM(require("path"));
21707
21850
 
21708
21851
  // src/agents/acp/agent-binary.ts
21709
21852
  var import_fs4 = __toESM(require("fs"));
21710
- var import_os7 = __toESM(require("os"));
21853
+ var import_os8 = __toESM(require("os"));
21711
21854
  var import_path8 = __toESM(require("path"));
21712
21855
  var import_child_process25 = require("child_process");
21713
21856
  function currentPlatformKey() {
@@ -21803,7 +21946,7 @@ function resolveCursorAgentBinary(deps = {}) {
21803
21946
  const exe = import_path8.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
21804
21947
  return existsSync25(exe) ? exe : null;
21805
21948
  }
21806
- const home = deps.homedir ?? import_os7.default.homedir();
21949
+ const home = deps.homedir ?? import_os8.default.homedir();
21807
21950
  const unix = import_path8.default.posix.join(home, ".local", "bin", "cursor-agent");
21808
21951
  return existsSync25(unix) ? unix : null;
21809
21952
  }
@@ -21960,6 +22103,19 @@ var REGISTRY = {
21960
22103
  args: ["--skip-trust", "--acp"],
21961
22104
  requiresAgentBinary: "gemini",
21962
22105
  waitForBinary: (o) => waitForCommandOnPath("gemini", o)
22106
+ }),
22107
+ // Kimi Code (Moonshot) speaks ACP natively via `kimi acp` — a stdio
22108
+ // JSON-RPC server that answers `initialize` (agentInfo `Kimi Code CLI`,
22109
+ // capabilities, authMethods) and prints no TUI banner. No npm adapter, just
22110
+ // the user-installed `kimi` binary on PATH. Same {@link AdapterSpec} shape as
22111
+ // gemini/cursor. Auth (KIMI_API_KEY env, or the ~/.kimi-code/credentials
22112
+ // login-state file) reaches kimi because the ACP client spawns the adapter
22113
+ // with `env: { ...process.env, ...extraEnv }`.
22114
+ kimi: () => ({
22115
+ command: "kimi",
22116
+ args: ["acp"],
22117
+ requiresAgentBinary: "kimi",
22118
+ waitForBinary: (o) => waitForCommandOnPath("kimi", o)
21963
22119
  })
21964
22120
  };
21965
22121
  function getAcpAdapter(agent) {
@@ -22551,7 +22707,7 @@ var HistoryService = class _HistoryService {
22551
22707
  };
22552
22708
 
22553
22709
  // src/agents/acp/client.ts
22554
- var import_node_child_process21 = require("child_process");
22710
+ var import_node_child_process22 = require("child_process");
22555
22711
  var fs55 = __toESM(require("fs/promises"));
22556
22712
  var fsSync = __toESM(require("fs"));
22557
22713
  var os44 = __toESM(require("os"));
@@ -25155,7 +25311,7 @@ var AcpClient = class {
25155
25311
  "acpClient",
25156
25312
  `spawn cmd=${adapter.command} args=[${adapter.args.join(",")}] cwd=${cwd}`
25157
25313
  );
25158
- const child = (0, import_node_child_process21.spawn)(adapter.command, adapter.args, {
25314
+ const child = (0, import_node_child_process22.spawn)(adapter.command, adapter.args, {
25159
25315
  cwd,
25160
25316
  // extraEnv (e.g. CLAUDE_CODE_DISABLE_1M_CONTEXT=1 on an on-demand
25161
25317
  // re-spawn) layers over process.env; PATH stays last so the augmented
@@ -25593,12 +25749,12 @@ function buildRelaunchProxyEnv(baseEnv) {
25593
25749
  return env;
25594
25750
  }
25595
25751
  var relaunchProxyWithoutBudget = async () => {
25596
- const { spawn: spawn38 } = await import("child_process");
25752
+ const { spawn: spawn39 } = await import("child_process");
25597
25753
  killHeadroomProxy();
25598
25754
  await new Promise((r) => setTimeout(r, 500));
25599
25755
  const proxyEnv = buildRelaunchProxyEnv(process.env);
25600
25756
  try {
25601
- const proxy = spawn38(
25757
+ const proxy = spawn39(
25602
25758
  "headroom",
25603
25759
  ["proxy", "--port", "8787"],
25604
25760
  { stdio: "ignore", detached: true, env: proxyEnv }
@@ -26539,7 +26695,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
26539
26695
  // src/services/turn-files/files-outbox.ts
26540
26696
  var fs58 = __toESM(require("fs/promises"));
26541
26697
  var path62 = __toESM(require("path"));
26542
- var import_os8 = require("os");
26698
+ var import_os9 = require("os");
26543
26699
  var HOME_OUTBOX_DIR = ".codeam/outbox";
26544
26700
  var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
26545
26701
  var BACKOFF_STEPS_MS = [
@@ -26706,7 +26862,7 @@ function applyJitter(ms) {
26706
26862
  return Math.round(ms * factor);
26707
26863
  }
26708
26864
  function homeDir() {
26709
- return process.env.HOME ?? process.env.USERPROFILE ?? (0, import_os8.tmpdir)();
26865
+ return process.env.HOME ?? process.env.USERPROFILE ?? (0, import_os9.tmpdir)();
26710
26866
  }
26711
26867
 
26712
26868
  // src/services/turn-files/turn-file-aggregator.ts
@@ -33000,7 +33156,7 @@ function checkChokidar() {
33000
33156
  }
33001
33157
  async function doctor(args2 = []) {
33002
33158
  const json = args2.includes("--json");
33003
- const cliVersion = true ? "2.60.13" : "0.0.0-dev";
33159
+ const cliVersion = true ? "2.60.15" : "0.0.0-dev";
33004
33160
  const apiBase2 = resolveApiBaseUrl();
33005
33161
  const diagnosticId = (0, import_node_crypto10.randomUUID)();
33006
33162
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -33199,7 +33355,7 @@ async function completion(args2) {
33199
33355
  // src/commands/version.ts
33200
33356
  var import_picocolors15 = __toESM(require("picocolors"));
33201
33357
  function version2() {
33202
- const v = true ? "2.60.13" : "unknown";
33358
+ const v = true ? "2.60.15" : "unknown";
33203
33359
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
33204
33360
  }
33205
33361
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.60.13",
3
+ "version": "2.60.15",
4
4
  "description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",