codeam-cli 2.22.1 → 2.23.1

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 +241 -56
  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.23.0] — 2026-05-25
8
+
9
+ ### Added
10
+
11
+ - **cli:** AI insights — generateOneShot + handlers (PR 2 of 6) (#188)
12
+
13
+ ## [2.22.1] — 2026-05-25
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Payload.agentId — accept any string, not just the public enum (#187)
18
+
7
19
  ## [2.22.0] — 2026-05-25
8
20
 
9
21
  ### Added
package/dist/index.js CHANGED
@@ -441,7 +441,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
441
441
  // package.json
442
442
  var package_default = {
443
443
  name: "codeam-cli",
444
- version: "2.22.1",
444
+ version: "2.23.1",
445
445
  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.",
446
446
  type: "commonjs",
447
447
  main: "dist/index.js",
@@ -734,6 +734,34 @@ async function postLinkCredential(input) {
734
734
  };
735
735
  }
736
736
  }
737
+ async function postAiResult(input) {
738
+ const body = {
739
+ sessionId: input.sessionId,
740
+ pluginId: input.pluginId,
741
+ kind: input.kind,
742
+ summary: input.summary
743
+ };
744
+ if (input.turnId) body.turnId = input.turnId;
745
+ if (input.stats) body.stats = input.stats;
746
+ if (input.fileChangeId) body.fileChangeId = input.fileChangeId;
747
+ if (input.reasoning) body.reasoning = input.reasoning;
748
+ if (input.securityNote) body.securityNote = input.securityNote;
749
+ try {
750
+ await _transport.postJsonAuthed(
751
+ `${API_BASE}/api/plugin/ai-result`,
752
+ body,
753
+ input.pluginAuthToken
754
+ );
755
+ return { ok: true };
756
+ } catch (err) {
757
+ const e = err;
758
+ return {
759
+ ok: false,
760
+ status: typeof e.statusCode === "number" ? e.statusCode : 0,
761
+ message: e.message || "unknown"
762
+ };
763
+ }
764
+ }
737
765
  async function _postJsonAuthed(url, body, pluginAuthToken) {
738
766
  return new Promise((resolve5, reject) => {
739
767
  const data = JSON.stringify(body);
@@ -5740,7 +5768,7 @@ function readAnonId() {
5740
5768
  }
5741
5769
  function superProperties() {
5742
5770
  return {
5743
- cliVersion: true ? "2.22.1" : "0.0.0-dev",
5771
+ cliVersion: true ? "2.23.1" : "0.0.0-dev",
5744
5772
  nodeVersion: process.version,
5745
5773
  platform: process.platform,
5746
5774
  arch: process.arch,
@@ -9099,6 +9127,59 @@ async function fetchClaudeQuota() {
9099
9127
  });
9100
9128
  }
9101
9129
 
9130
+ // src/services/spawn-and-capture.ts
9131
+ var import_child_process6 = require("child_process");
9132
+ async function spawnAndCapture(cmd, args2, opts = {}) {
9133
+ const timeoutMs = opts.timeoutMs ?? 6e4;
9134
+ return new Promise((resolve5) => {
9135
+ let settled = false;
9136
+ const settle = (value) => {
9137
+ if (settled) return;
9138
+ settled = true;
9139
+ resolve5(value);
9140
+ };
9141
+ let child;
9142
+ try {
9143
+ child = (0, import_child_process6.spawn)(cmd, [...args2], {
9144
+ cwd: opts.cwd,
9145
+ env: opts.env ?? process.env,
9146
+ stdio: ["ignore", "pipe", "pipe"]
9147
+ });
9148
+ } catch {
9149
+ settle(null);
9150
+ return;
9151
+ }
9152
+ let stdout = "";
9153
+ child.stdout?.on("data", (chunk) => {
9154
+ stdout += chunk.toString("utf8");
9155
+ });
9156
+ child.stderr?.on("data", (chunk) => {
9157
+ opts.onStderr?.(chunk.toString("utf8"));
9158
+ });
9159
+ const timer = setTimeout(() => {
9160
+ try {
9161
+ child.kill("SIGKILL");
9162
+ } catch {
9163
+ }
9164
+ settle(null);
9165
+ }, timeoutMs);
9166
+ timer.unref();
9167
+ child.on("error", () => {
9168
+ clearTimeout(timer);
9169
+ settle(null);
9170
+ });
9171
+ child.on("exit", (code) => {
9172
+ clearTimeout(timer);
9173
+ if (code !== 0) {
9174
+ settle(null);
9175
+ return;
9176
+ }
9177
+ const trimmed = stdout.trim();
9178
+ settle(trimmed.length > 0 ? trimmed : null);
9179
+ });
9180
+ });
9181
+ }
9182
+
9102
9183
  // src/agents/claude/history.ts
9103
9184
  var fs9 = __toESM(require("fs"));
9104
9185
  var path12 = __toESM(require("path"));
@@ -9541,6 +9622,14 @@ var ClaudeRuntimeStrategy = class {
9541
9622
  loginLauncher() {
9542
9623
  return claudeLoginLauncher();
9543
9624
  }
9625
+ async generateOneShot(prompt, opts) {
9626
+ const launch = buildClaudeLaunch(["-p", prompt], this.os);
9627
+ if (!launch) return null;
9628
+ return spawnAndCapture(launch.cmd, launch.args, {
9629
+ cwd: opts?.cwd,
9630
+ timeoutMs: opts?.timeoutMs
9631
+ });
9632
+ }
9544
9633
  };
9545
9634
 
9546
9635
  // src/agents/claude/deploy.ts
@@ -9549,12 +9638,12 @@ var os13 = __toESM(require("os"));
9549
9638
  var path14 = __toESM(require("path"));
9550
9639
 
9551
9640
  // src/agents/claude/credentials.ts
9552
- var import_child_process6 = require("child_process");
9641
+ var import_child_process7 = require("child_process");
9553
9642
  var fs10 = __toESM(require("fs"));
9554
9643
  var os12 = __toESM(require("os"));
9555
9644
  var path13 = __toESM(require("path"));
9556
9645
  var import_util = require("util");
9557
- var execFileP2 = (0, import_util.promisify)(import_child_process6.execFile);
9646
+ var execFileP2 = (0, import_util.promisify)(import_child_process7.execFile);
9558
9647
  async function detectLocalClaudeCredentials() {
9559
9648
  const localClaudeDir = path13.join(os12.homedir(), ".claude");
9560
9649
  const flat = path13.join(localClaudeDir, ".credentials.json");
@@ -10424,6 +10513,15 @@ var CodexRuntimeStrategy = class {
10424
10513
  loginLauncher() {
10425
10514
  return codexLoginLauncher();
10426
10515
  }
10516
+ async generateOneShot(prompt, opts) {
10517
+ const binary = this.os.findInPath("codex");
10518
+ if (!binary) return null;
10519
+ const launch = this.os.buildLaunch(binary, ["exec", prompt]);
10520
+ return spawnAndCapture(launch.cmd, launch.args, {
10521
+ cwd: opts?.cwd,
10522
+ timeoutMs: opts?.timeoutMs
10523
+ });
10524
+ }
10427
10525
  };
10428
10526
  function resolveNpm(os26) {
10429
10527
  return os26.id === "win32" ? "npm.cmd" : "npm";
@@ -12206,7 +12304,7 @@ var HistoryService = class _HistoryService {
12206
12304
  };
12207
12305
 
12208
12306
  // src/services/file-watcher.service.ts
12209
- var import_child_process7 = require("child_process");
12307
+ var import_child_process8 = require("child_process");
12210
12308
  var fs21 = __toESM(require("fs"));
12211
12309
  var os22 = __toESM(require("os"));
12212
12310
  var path25 = __toESM(require("path"));
@@ -12744,7 +12842,7 @@ async function _runGitImpl(cwd, args2, opts = {}) {
12744
12842
  return new Promise((resolve5) => {
12745
12843
  let proc;
12746
12844
  try {
12747
- proc = (0, import_child_process7.spawn)("git", args2, { cwd, env: process.env });
12845
+ proc = (0, import_child_process8.spawn)("git", args2, { cwd, env: process.env });
12748
12846
  } catch {
12749
12847
  resolve5(null);
12750
12848
  return;
@@ -12776,7 +12874,7 @@ function _runGit(cwd, args2, opts = {}) {
12776
12874
  var import_crypto2 = require("crypto");
12777
12875
 
12778
12876
  // src/services/turn-files/git-changeset.ts
12779
- var import_child_process8 = require("child_process");
12877
+ var import_child_process9 = require("child_process");
12780
12878
  var path26 = __toESM(require("path"));
12781
12879
  async function collectRepoChangeset(opts) {
12782
12880
  const status2 = await runGit2(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
@@ -12859,7 +12957,7 @@ function defaultRunGit(cwd, args2) {
12859
12957
  return new Promise((resolve5) => {
12860
12958
  let proc;
12861
12959
  try {
12862
- proc = (0, import_child_process8.spawn)("git", args2, { cwd, env: process.env });
12960
+ proc = (0, import_child_process9.spawn)("git", args2, { cwd, env: process.env });
12863
12961
  } catch {
12864
12962
  resolve5(null);
12865
12963
  return;
@@ -13199,6 +13297,7 @@ var TurnFileAggregator = class {
13199
13297
  sessionId: entry.sessionId,
13200
13298
  pluginId: entry.pluginId,
13201
13299
  turnId: entry.turnId,
13300
+ agentId: this.opts.agentId,
13202
13301
  files: entry.files
13203
13302
  });
13204
13303
  try {
@@ -13711,13 +13810,13 @@ function fetchQuotaUsage(runtime, historySvc) {
13711
13810
  }
13712
13811
 
13713
13812
  // src/commands/start/keep-alive.ts
13714
- var import_child_process9 = require("child_process");
13813
+ var import_child_process10 = require("child_process");
13715
13814
  function buildKeepAlive(ctx) {
13716
13815
  let timer = null;
13717
13816
  async function setIdleTimeout(minutes) {
13718
13817
  if (!ctx.inCodespace || !ctx.codespaceName) return;
13719
13818
  await new Promise((resolve5) => {
13720
- const proc = (0, import_child_process9.spawn)(
13819
+ const proc = (0, import_child_process10.spawn)(
13721
13820
  "gh",
13722
13821
  [
13723
13822
  "api",
@@ -13758,7 +13857,7 @@ var fs27 = __toESM(require("fs"));
13758
13857
  var os23 = __toESM(require("os"));
13759
13858
  var path33 = __toESM(require("path"));
13760
13859
  var import_crypto5 = require("crypto");
13761
- var import_child_process13 = require("child_process");
13860
+ var import_child_process14 = require("child_process");
13762
13861
 
13763
13862
  // src/lib/payload.ts
13764
13863
  var import_zod2 = require("zod");
@@ -13823,7 +13922,34 @@ var startCommandSchema = import_zod2.z.object({
13823
13922
  // a narrow enum) because the web sends internal ids ('claude')
13824
13923
  // while the auto-link backend sends public ids ('claude_code'),
13825
13924
  // and the consuming handlers normalize themselves.
13826
- agentId: import_zod2.z.string().max(64).optional()
13925
+ //
13926
+ // `.nullable()` — the web's session page passes the literal value
13927
+ // `null` when no agent has been selected yet for the session
13928
+ // (`currentAgentId` is null before sessionAgents populates).
13929
+ // Without nullable() zod rejects the whole payload, the dispatcher
13930
+ // logs "Ignoring malformed list_models payload" and the model
13931
+ // picker / context never load.
13932
+ agentId: import_zod2.z.string().max(64).nullable().optional(),
13933
+ // `request_ai_summary` / `request_ai_insight` — backend fires
13934
+ // these on turn-end (+ file selection) when LinkedAgent.
13935
+ // aiInsightsEnabled is true. The CLI spawns the agent in
13936
+ // headless one-shot mode (`claude -p "..."` / `codex exec`) and
13937
+ // POSTs the response back to /api/plugin/ai-result.
13938
+ //
13939
+ // `prompt` (declared above for start_task) carries the LLM prompt
13940
+ // the backend pre-rendered with the diff context inlined; the
13941
+ // agent receives it verbatim. `turnId` keys the summary,
13942
+ // `fileChangeId` keys the per-file insight, `stats` is echoed
13943
+ // unchanged on the result POST so the backend doesn't have to
13944
+ // recompute (numbers came from file_changes; the agent only
13945
+ // writes the narrative).
13946
+ turnId: import_zod2.z.string().max(128).optional(),
13947
+ fileChangeId: import_zod2.z.string().max(128).optional(),
13948
+ stats: import_zod2.z.object({
13949
+ added: import_zod2.z.number().int(),
13950
+ removed: import_zod2.z.number().int(),
13951
+ complexityShift: import_zod2.z.number().int()
13952
+ }).optional()
13827
13953
  });
13828
13954
  function parsePayload2(schema, raw) {
13829
13955
  const result = schema.safeParse(raw);
@@ -13979,11 +14105,11 @@ async function writeProjectFile(rawPath, content) {
13979
14105
  }
13980
14106
 
13981
14107
  // src/services/project-ops.service.ts
13982
- var import_child_process10 = require("child_process");
14108
+ var import_child_process11 = require("child_process");
13983
14109
  var import_util2 = require("util");
13984
14110
  var fs24 = __toESM(require("fs/promises"));
13985
14111
  var path29 = __toESM(require("path"));
13986
- var execFileP3 = (0, import_util2.promisify)(import_child_process10.execFile);
14112
+ var execFileP3 = (0, import_util2.promisify)(import_child_process11.execFile);
13987
14113
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
13988
14114
  "node_modules",
13989
14115
  ".git",
@@ -14323,7 +14449,7 @@ async function jsSearchFiles(opts, cwd, cap) {
14323
14449
  }
14324
14450
 
14325
14451
  // src/services/terminal-ops.service.ts
14326
- var import_child_process11 = require("child_process");
14452
+ var import_child_process12 = require("child_process");
14327
14453
  var import_crypto4 = require("crypto");
14328
14454
  var import_path3 = __toESM(require("path"));
14329
14455
  var MAX_CONCURRENT_SESSIONS = 4;
@@ -14445,7 +14571,7 @@ function createPythonSession(id, shell, cwd, env, cols, rows) {
14445
14571
  }
14446
14572
  let child;
14447
14573
  try {
14448
- child = (0, import_child_process11.spawn)(python, ["-c", PYTHON_TERMINAL_HELPER, shell], {
14574
+ child = (0, import_child_process12.spawn)(python, ["-c", PYTHON_TERMINAL_HELPER, shell], {
14449
14575
  cwd,
14450
14576
  env: { ...env, COLUMNS: String(cols), LINES: String(rows) },
14451
14577
  stdio: ["pipe", "pipe", "pipe"]
@@ -14580,7 +14706,7 @@ function closeAllTerminals() {
14580
14706
  }
14581
14707
 
14582
14708
  // src/services/apply-file-review.service.ts
14583
- var import_child_process12 = require("child_process");
14709
+ var import_child_process13 = require("child_process");
14584
14710
  var fs25 = __toESM(require("fs"));
14585
14711
  var path31 = __toESM(require("path"));
14586
14712
  async function applyFileReview(workingDir, filePath, action) {
@@ -14622,7 +14748,7 @@ function runGit3(cwd, args2) {
14622
14748
  return new Promise((resolve5) => {
14623
14749
  let proc;
14624
14750
  try {
14625
- proc = (0, import_child_process12.spawn)("git", args2, { cwd, env: process.env });
14751
+ proc = (0, import_child_process13.spawn)("git", args2, { cwd, env: process.env });
14626
14752
  } catch (err) {
14627
14753
  resolve5({ ok: false, code: -1, stdout: "", stderr: err.message });
14628
14754
  return;
@@ -15153,7 +15279,7 @@ var sessionTerminated = (ctx) => {
15153
15279
  } catch {
15154
15280
  }
15155
15281
  try {
15156
- const proc = (0, import_child_process13.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
15282
+ const proc = (0, import_child_process14.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
15157
15283
  detached: true,
15158
15284
  stdio: "ignore"
15159
15285
  });
@@ -15175,7 +15301,7 @@ var shutdownSession = async (ctx, cmd) => {
15175
15301
  }
15176
15302
  if (ctx.keepAliveCtx.inCodespace && ctx.keepAliveCtx.codespaceName) {
15177
15303
  try {
15178
- const stopProc = (0, import_child_process13.spawn)(
15304
+ const stopProc = (0, import_child_process14.spawn)(
15179
15305
  "bash",
15180
15306
  ["-lc", `sleep 1; gh codespace stop -c ${JSON.stringify(ctx.keepAliveCtx.codespaceName)} >/dev/null 2>&1 || true`],
15181
15307
  { detached: true, stdio: "ignore" }
@@ -15185,7 +15311,7 @@ var shutdownSession = async (ctx, cmd) => {
15185
15311
  }
15186
15312
  }
15187
15313
  try {
15188
- const proc = (0, import_child_process13.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
15314
+ const proc = (0, import_child_process14.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
15189
15315
  detached: true,
15190
15316
  stdio: "ignore"
15191
15317
  });
@@ -15367,6 +15493,62 @@ var requestLinkCredentialsH = async (ctx, _cmd, parsed) => {
15367
15493
  log.trace("auto-link", `upload failed (${result.status}): ${result.message}`);
15368
15494
  }
15369
15495
  };
15496
+ var requestAiSummaryH = async (ctx, _cmd, parsed) => {
15497
+ if (!ctx.pluginAuthToken) return;
15498
+ if (typeof ctx.runtime.generateOneShot !== "function") return;
15499
+ if (!parsed.prompt || !parsed.turnId || !parsed.stats) {
15500
+ log.trace("ai-summary", "missing prompt/turnId/stats \u2014 skipping");
15501
+ return;
15502
+ }
15503
+ const text = await ctx.runtime.generateOneShot(parsed.prompt).catch((err) => {
15504
+ log.trace("ai-summary", "generateOneShot threw", err);
15505
+ return null;
15506
+ });
15507
+ if (!text) return;
15508
+ await postAiResult({
15509
+ sessionId: ctx.sessionId,
15510
+ pluginId: ctx.pluginId,
15511
+ pluginAuthToken: ctx.pluginAuthToken,
15512
+ kind: "summary",
15513
+ turnId: parsed.turnId,
15514
+ summary: text,
15515
+ stats: parsed.stats
15516
+ });
15517
+ };
15518
+ var requestAiInsightH = async (ctx, _cmd, parsed) => {
15519
+ if (!ctx.pluginAuthToken) return;
15520
+ if (typeof ctx.runtime.generateOneShot !== "function") return;
15521
+ if (!parsed.prompt || !parsed.fileChangeId) {
15522
+ log.trace("ai-insight", "missing prompt/fileChangeId \u2014 skipping");
15523
+ return;
15524
+ }
15525
+ const text = await ctx.runtime.generateOneShot(parsed.prompt).catch((err) => {
15526
+ log.trace("ai-insight", "generateOneShot threw", err);
15527
+ return null;
15528
+ });
15529
+ if (!text) return;
15530
+ const { summary, reasoning, securityNote } = parseInsightText(text);
15531
+ await postAiResult({
15532
+ sessionId: ctx.sessionId,
15533
+ pluginId: ctx.pluginId,
15534
+ pluginAuthToken: ctx.pluginAuthToken,
15535
+ kind: "insight",
15536
+ fileChangeId: parsed.fileChangeId,
15537
+ summary,
15538
+ reasoning,
15539
+ securityNote
15540
+ });
15541
+ };
15542
+ function parseInsightText(text) {
15543
+ const summaryMatch = text.match(/SUMMARY:\s*([\s\S]*?)(?=\n\s*(?:REASONING|SECURITY):|$)/i);
15544
+ const reasoningMatch = text.match(/REASONING:\s*([\s\S]*?)(?=\n\s*SECURITY:|$)/i);
15545
+ const securityMatch = text.match(/SECURITY:\s*([\s\S]*)/i);
15546
+ return {
15547
+ summary: (summaryMatch?.[1] ?? text).trim(),
15548
+ reasoning: (reasoningMatch?.[1] ?? text).trim(),
15549
+ securityNote: securityMatch?.[1]?.trim() || void 0
15550
+ };
15551
+ }
15370
15552
  var handlers = {
15371
15553
  start_task: startTask,
15372
15554
  provide_input: provideInput,
@@ -15399,7 +15581,9 @@ var handlers = {
15399
15581
  git_pull: gitPullH,
15400
15582
  git_resolve: gitResolveH,
15401
15583
  apply_file_review: applyFileReviewH,
15402
- request_link_credentials: requestLinkCredentialsH
15584
+ request_link_credentials: requestLinkCredentialsH,
15585
+ request_ai_summary: requestAiSummaryH,
15586
+ request_ai_insight: requestAiInsightH
15403
15587
  };
15404
15588
  async function dispatchCommand(ctx, cmd) {
15405
15589
  const parsed = parsePayload2(startCommandSchema, cmd.payload);
@@ -15494,6 +15678,7 @@ async function start(requestedAgent) {
15494
15678
  sessionId: session.id,
15495
15679
  pluginId,
15496
15680
  pluginAuthToken: session.pluginAuthToken,
15681
+ agentId: runtime.meta.id,
15497
15682
  dirtyTracker: dirtyTracker ?? void 0
15498
15683
  }) : null;
15499
15684
  let streamingEmitter = null;
@@ -15991,11 +16176,11 @@ async function logout() {
15991
16176
  var import_picocolors10 = __toESM(require("picocolors"));
15992
16177
 
15993
16178
  // src/services/providers/github-codespaces.ts
15994
- var import_child_process14 = require("child_process");
16179
+ var import_child_process15 = require("child_process");
15995
16180
  var import_util3 = require("util");
15996
16181
  var import_picocolors8 = __toESM(require("picocolors"));
15997
16182
  var path34 = __toESM(require("path"));
15998
- var execFileP4 = (0, import_util3.promisify)(import_child_process14.execFile);
16183
+ var execFileP4 = (0, import_util3.promisify)(import_child_process15.execFile);
15999
16184
  var MAX_BUFFER = 8 * 1024 * 1024;
16000
16185
  function resetStdinForChild() {
16001
16186
  if (process.stdin.isTTY) {
@@ -16039,7 +16224,7 @@ var GitHubCodespacesProvider = class {
16039
16224
  if (!isAuthed) {
16040
16225
  resetStdinForChild();
16041
16226
  await new Promise((resolve5, reject) => {
16042
- const proc = (0, import_child_process14.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
16227
+ const proc = (0, import_child_process15.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
16043
16228
  stdio: "inherit"
16044
16229
  });
16045
16230
  proc.on("exit", (code) => {
@@ -16073,7 +16258,7 @@ var GitHubCodespacesProvider = class {
16073
16258
  wt(noteLines.join("\n"), "One more permission needed");
16074
16259
  resetStdinForChild();
16075
16260
  const refreshCode = await new Promise((resolve5, reject) => {
16076
- const proc = (0, import_child_process14.spawn)(
16261
+ const proc = (0, import_child_process15.spawn)(
16077
16262
  "gh",
16078
16263
  ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
16079
16264
  { stdio: "inherit" }
@@ -16223,7 +16408,7 @@ var GitHubCodespacesProvider = class {
16223
16408
  O2.step(`Installing gh via ${installCmd.describe}\u2026`);
16224
16409
  resetStdinForChild();
16225
16410
  const ok = await new Promise((resolve5) => {
16226
- const proc = (0, import_child_process14.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
16411
+ const proc = (0, import_child_process15.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
16227
16412
  proc.on("exit", (code) => resolve5(code === 0));
16228
16413
  proc.on("error", () => resolve5(false));
16229
16414
  });
@@ -16250,7 +16435,7 @@ var GitHubCodespacesProvider = class {
16250
16435
  );
16251
16436
  resetStdinForChild();
16252
16437
  await new Promise((resolve5, reject) => {
16253
- const proc = (0, import_child_process14.spawn)(
16438
+ const proc = (0, import_child_process15.spawn)(
16254
16439
  "gh",
16255
16440
  ["auth", "refresh", "-h", "github.com", "-s", "repo,read:org"],
16256
16441
  { stdio: "inherit" }
@@ -16428,7 +16613,7 @@ var GitHubCodespacesProvider = class {
16428
16613
  async streamCommand(workspaceId, command2) {
16429
16614
  resetStdinForChild();
16430
16615
  return new Promise((resolve5, reject) => {
16431
- const proc = (0, import_child_process14.spawn)(
16616
+ const proc = (0, import_child_process15.spawn)(
16432
16617
  "gh",
16433
16618
  ["codespace", "ssh", "-c", workspaceId, "--", "-tt", command2],
16434
16619
  { stdio: "inherit" }
@@ -16455,11 +16640,11 @@ var GitHubCodespacesProvider = class {
16455
16640
  `mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
16456
16641
  ];
16457
16642
  await new Promise((resolve5, reject) => {
16458
- const tar = (0, import_child_process14.spawn)("tar", tarArgs, {
16643
+ const tar = (0, import_child_process15.spawn)("tar", tarArgs, {
16459
16644
  stdio: ["ignore", "pipe", "pipe"],
16460
16645
  env: tarEnv
16461
16646
  });
16462
- const ssh = (0, import_child_process14.spawn)("gh", sshArgs, {
16647
+ const ssh = (0, import_child_process15.spawn)("gh", sshArgs, {
16463
16648
  stdio: [tar.stdout, "pipe", "pipe"]
16464
16649
  });
16465
16650
  let tarErr = "";
@@ -16493,7 +16678,7 @@ var GitHubCodespacesProvider = class {
16493
16678
  }
16494
16679
  const cmd = parts.join(" && ");
16495
16680
  await new Promise((resolve5, reject) => {
16496
- const proc = (0, import_child_process14.spawn)(
16681
+ const proc = (0, import_child_process15.spawn)(
16497
16682
  "gh",
16498
16683
  ["codespace", "ssh", "-c", workspaceId, "--", cmd],
16499
16684
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -16551,11 +16736,11 @@ function shellQuote(s) {
16551
16736
  }
16552
16737
 
16553
16738
  // src/services/providers/gitpod.ts
16554
- var import_child_process15 = require("child_process");
16739
+ var import_child_process16 = require("child_process");
16555
16740
  var import_util4 = require("util");
16556
16741
  var path35 = __toESM(require("path"));
16557
16742
  var import_picocolors9 = __toESM(require("picocolors"));
16558
- var execFileP5 = (0, import_util4.promisify)(import_child_process15.execFile);
16743
+ var execFileP5 = (0, import_util4.promisify)(import_child_process16.execFile);
16559
16744
  var MAX_BUFFER2 = 8 * 1024 * 1024;
16560
16745
  function resetStdinForChild2() {
16561
16746
  if (process.stdin.isTTY) {
@@ -16595,7 +16780,7 @@ var GitpodProvider = class {
16595
16780
  );
16596
16781
  resetStdinForChild2();
16597
16782
  await new Promise((resolve5, reject) => {
16598
- const proc = (0, import_child_process15.spawn)("gitpod", ["login"], { stdio: "inherit" });
16783
+ const proc = (0, import_child_process16.spawn)("gitpod", ["login"], { stdio: "inherit" });
16599
16784
  proc.on("exit", (code) => {
16600
16785
  if (code === 0) resolve5();
16601
16786
  else reject(new Error("gitpod login failed."));
@@ -16747,7 +16932,7 @@ var GitpodProvider = class {
16747
16932
  async streamCommand(workspaceId, command2) {
16748
16933
  resetStdinForChild2();
16749
16934
  return new Promise((resolve5, reject) => {
16750
- const proc = (0, import_child_process15.spawn)(
16935
+ const proc = (0, import_child_process16.spawn)(
16751
16936
  "gitpod",
16752
16937
  ["workspace", "ssh", workspaceId, "--", "-tt", command2],
16753
16938
  { stdio: "inherit" }
@@ -16767,11 +16952,11 @@ var GitpodProvider = class {
16767
16952
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
16768
16953
  const remoteCmd = `mkdir -p ${shellQuote2(remoteDir)} && tar -xzf - -C ${shellQuote2(remoteDir)}`;
16769
16954
  await new Promise((resolve5, reject) => {
16770
- const tar = (0, import_child_process15.spawn)("tar", tarArgs, {
16955
+ const tar = (0, import_child_process16.spawn)("tar", tarArgs, {
16771
16956
  stdio: ["ignore", "pipe", "pipe"],
16772
16957
  env: tarEnv
16773
16958
  });
16774
- const ssh = (0, import_child_process15.spawn)(
16959
+ const ssh = (0, import_child_process16.spawn)(
16775
16960
  "gitpod",
16776
16961
  ["workspace", "ssh", workspaceId, "--", remoteCmd],
16777
16962
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -16803,7 +16988,7 @@ var GitpodProvider = class {
16803
16988
  }
16804
16989
  const cmd = parts.join(" && ");
16805
16990
  await new Promise((resolve5, reject) => {
16806
- const proc = (0, import_child_process15.spawn)(
16991
+ const proc = (0, import_child_process16.spawn)(
16807
16992
  "gitpod",
16808
16993
  ["workspace", "ssh", workspaceId, "--", cmd],
16809
16994
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -16827,10 +17012,10 @@ function shellQuote2(s) {
16827
17012
  }
16828
17013
 
16829
17014
  // src/services/providers/gitlab-workspaces.ts
16830
- var import_child_process16 = require("child_process");
17015
+ var import_child_process17 = require("child_process");
16831
17016
  var import_util5 = require("util");
16832
17017
  var path36 = __toESM(require("path"));
16833
- var execFileP6 = (0, import_util5.promisify)(import_child_process16.execFile);
17018
+ var execFileP6 = (0, import_util5.promisify)(import_child_process17.execFile);
16834
17019
  var MAX_BUFFER3 = 8 * 1024 * 1024;
16835
17020
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
16836
17021
  function resetStdinForChild3() {
@@ -16872,7 +17057,7 @@ var GitLabWorkspacesProvider = class {
16872
17057
  );
16873
17058
  resetStdinForChild3();
16874
17059
  await new Promise((resolve5, reject) => {
16875
- const proc = (0, import_child_process16.spawn)(
17060
+ const proc = (0, import_child_process17.spawn)(
16876
17061
  "glab",
16877
17062
  ["auth", "login", "--scopes", "api,read_user,read_repository"],
16878
17063
  { stdio: "inherit" }
@@ -17044,7 +17229,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
17044
17229
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
17045
17230
  resetStdinForChild3();
17046
17231
  return new Promise((resolve5, reject) => {
17047
- const proc = (0, import_child_process16.spawn)(
17232
+ const proc = (0, import_child_process17.spawn)(
17048
17233
  "ssh",
17049
17234
  ["-tt", "-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, command2],
17050
17235
  { stdio: "inherit" }
@@ -17065,8 +17250,8 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
17065
17250
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
17066
17251
  const remoteCmd = `mkdir -p ${shellQuote3(remoteDir)} && tar -xzf - -C ${shellQuote3(remoteDir)}`;
17067
17252
  await new Promise((resolve5, reject) => {
17068
- const tar = (0, import_child_process16.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
17069
- const ssh = (0, import_child_process16.spawn)(
17253
+ const tar = (0, import_child_process17.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
17254
+ const ssh = (0, import_child_process17.spawn)(
17070
17255
  "ssh",
17071
17256
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, remoteCmd],
17072
17257
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -17096,7 +17281,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
17096
17281
  }
17097
17282
  const cmd = parts.join(" && ");
17098
17283
  await new Promise((resolve5, reject) => {
17099
- const proc = (0, import_child_process16.spawn)(
17284
+ const proc = (0, import_child_process17.spawn)(
17100
17285
  "ssh",
17101
17286
  ["-o", "StrictHostKeyChecking=accept-new", `${workspaceId}@${sshHost}`, cmd],
17102
17287
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -17155,10 +17340,10 @@ function shellQuote3(s) {
17155
17340
  }
17156
17341
 
17157
17342
  // src/services/providers/railway.ts
17158
- var import_child_process17 = require("child_process");
17343
+ var import_child_process18 = require("child_process");
17159
17344
  var import_util6 = require("util");
17160
17345
  var path37 = __toESM(require("path"));
17161
- var execFileP7 = (0, import_util6.promisify)(import_child_process17.execFile);
17346
+ var execFileP7 = (0, import_util6.promisify)(import_child_process18.execFile);
17162
17347
  var MAX_BUFFER4 = 8 * 1024 * 1024;
17163
17348
  function resetStdinForChild4() {
17164
17349
  if (process.stdin.isTTY) {
@@ -17199,7 +17384,7 @@ var RailwayProvider = class {
17199
17384
  );
17200
17385
  resetStdinForChild4();
17201
17386
  await new Promise((resolve5, reject) => {
17202
- const proc = (0, import_child_process17.spawn)("railway", ["login"], { stdio: "inherit" });
17387
+ const proc = (0, import_child_process18.spawn)("railway", ["login"], { stdio: "inherit" });
17203
17388
  proc.on("exit", (code) => {
17204
17389
  if (code === 0) resolve5();
17205
17390
  else reject(new Error("railway login failed."));
@@ -17342,7 +17527,7 @@ var RailwayProvider = class {
17342
17527
  }
17343
17528
  resetStdinForChild4();
17344
17529
  return new Promise((resolve5, reject) => {
17345
- const proc = (0, import_child_process17.spawn)(
17530
+ const proc = (0, import_child_process18.spawn)(
17346
17531
  "railway",
17347
17532
  ["shell", "--project", projectId, "--service", serviceId, "--command", command2],
17348
17533
  { stdio: "inherit" }
@@ -17366,8 +17551,8 @@ var RailwayProvider = class {
17366
17551
  const tarEnv = { ...process.env, COPYFILE_DISABLE: "1" };
17367
17552
  const remoteCmd = `mkdir -p ${shellQuote4(remoteDir)} && tar -xzf - -C ${shellQuote4(remoteDir)}`;
17368
17553
  await new Promise((resolve5, reject) => {
17369
- const tar = (0, import_child_process17.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
17370
- const sh = (0, import_child_process17.spawn)(
17554
+ const tar = (0, import_child_process18.spawn)("tar", tarArgs, { stdio: ["ignore", "pipe", "pipe"], env: tarEnv });
17555
+ const sh = (0, import_child_process18.spawn)(
17371
17556
  "railway",
17372
17557
  ["shell", "--project", projectId, "--service", serviceId, "--command", remoteCmd],
17373
17558
  { stdio: [tar.stdout, "pipe", "pipe"] }
@@ -17400,7 +17585,7 @@ var RailwayProvider = class {
17400
17585
  }
17401
17586
  const cmd = parts.join(" && ");
17402
17587
  await new Promise((resolve5, reject) => {
17403
- const proc = (0, import_child_process17.spawn)(
17588
+ const proc = (0, import_child_process18.spawn)(
17404
17589
  "railway",
17405
17590
  ["shell", "--project", projectId, "--service", serviceId, "--command", cmd],
17406
17591
  { stdio: ["pipe", "pipe", "pipe"] }
@@ -18105,7 +18290,7 @@ function checkChokidar() {
18105
18290
  }
18106
18291
  async function doctor(args2 = []) {
18107
18292
  const json = args2.includes("--json");
18108
- const cliVersion = true ? "2.22.1" : "0.0.0-dev";
18293
+ const cliVersion = true ? "2.23.1" : "0.0.0-dev";
18109
18294
  const apiBase = resolveApiBaseUrl();
18110
18295
  const diagnosticId = (0, import_node_crypto5.randomUUID)();
18111
18296
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -18304,7 +18489,7 @@ async function completion(args2) {
18304
18489
  // src/commands/version.ts
18305
18490
  var import_picocolors13 = __toESM(require("picocolors"));
18306
18491
  function version2() {
18307
- const v = true ? "2.22.1" : "unknown";
18492
+ const v = true ? "2.23.1" : "unknown";
18308
18493
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
18309
18494
  }
18310
18495
 
@@ -18532,7 +18717,7 @@ function checkForUpdates() {
18532
18717
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
18533
18718
  if (process.env.CI) return;
18534
18719
  if (!process.stdout.isTTY) return;
18535
- const current = true ? "2.22.1" : null;
18720
+ const current = true ? "2.23.1" : null;
18536
18721
  if (!current) return;
18537
18722
  const cache = readCache();
18538
18723
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.22.1",
3
+ "version": "2.23.1",
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",