codeam-cli 2.4.33 → 2.4.34

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/index.js CHANGED
@@ -519,9 +519,9 @@ var require_windowsPtyAgent = __commonJS({
519
519
  "use strict";
520
520
  Object.defineProperty(exports2, "__esModule", { value: true });
521
521
  exports2.argsToCommandLine = exports2.WindowsPtyAgent = void 0;
522
- var fs9 = require("fs");
523
- var os8 = require("os");
524
- var path16 = require("path");
522
+ var fs11 = require("fs");
523
+ var os10 = require("os");
524
+ var path18 = require("path");
525
525
  var child_process_1 = require("child_process");
526
526
  var net_1 = require("net");
527
527
  var windowsConoutConnection_1 = require_windowsConoutConnection();
@@ -557,7 +557,7 @@ var require_windowsPtyAgent = __commonJS({
557
557
  }
558
558
  }
559
559
  this._ptyNative = this._useConpty ? conptyNative : winptyNative;
560
- cwd = path16.resolve(cwd);
560
+ cwd = path18.resolve(cwd);
561
561
  var commandLine = argsToCommandLine(file, args2);
562
562
  var term;
563
563
  if (this._useConpty) {
@@ -578,7 +578,7 @@ var require_windowsPtyAgent = __commonJS({
578
578
  this._outSocket.on("connect", function() {
579
579
  _this._outSocket.emit("ready_datapipe");
580
580
  });
581
- var inSocketFD = fs9.openSync(term.conin, "w");
581
+ var inSocketFD = fs11.openSync(term.conin, "w");
582
582
  this._inSocket = new net_1.Socket({
583
583
  fd: inSocketFD,
584
584
  readable: false,
@@ -679,7 +679,7 @@ var require_windowsPtyAgent = __commonJS({
679
679
  WindowsPtyAgent2.prototype._getConsoleProcessList = function() {
680
680
  var _this = this;
681
681
  return new Promise(function(resolve2) {
682
- var agent = child_process_1.fork(path16.join(__dirname, "conpty_console_list_agent"), [_this._innerPid.toString()]);
682
+ var agent = child_process_1.fork(path18.join(__dirname, "conpty_console_list_agent"), [_this._innerPid.toString()]);
683
683
  agent.on("message", function(message) {
684
684
  clearTimeout(timeout);
685
685
  resolve2(message.consoleProcessList);
@@ -702,7 +702,7 @@ var require_windowsPtyAgent = __commonJS({
702
702
  configurable: true
703
703
  });
704
704
  WindowsPtyAgent2.prototype._getWindowsBuildNumber = function() {
705
- var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(os8.release());
705
+ var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(os10.release());
706
706
  var buildNumber = 0;
707
707
  if (osVersion && osVersion.length === 4) {
708
708
  buildNumber = parseInt(osVersion[3]);
@@ -1012,15 +1012,15 @@ var require_unixTerminal = __commonJS({
1012
1012
  })();
1013
1013
  Object.defineProperty(exports2, "__esModule", { value: true });
1014
1014
  exports2.UnixTerminal = void 0;
1015
- var fs9 = require("fs");
1016
- var path16 = require("path");
1015
+ var fs11 = require("fs");
1016
+ var path18 = require("path");
1017
1017
  var tty = require("tty");
1018
1018
  var terminal_1 = require_terminal();
1019
1019
  var utils_1 = require_utils();
1020
1020
  var native = utils_1.loadNativeModule("pty");
1021
1021
  var pty = native.module;
1022
1022
  var helperPath = native.dir + "/spawn-helper";
1023
- helperPath = path16.resolve(__dirname, helperPath);
1023
+ helperPath = path18.resolve(__dirname, helperPath);
1024
1024
  helperPath = helperPath.replace("app.asar", "app.asar.unpacked");
1025
1025
  helperPath = helperPath.replace("node_modules.asar", "node_modules.asar.unpacked");
1026
1026
  var DEFAULT_FILE = "sh";
@@ -1275,7 +1275,7 @@ var require_unixTerminal = __commonJS({
1275
1275
  return;
1276
1276
  }
1277
1277
  var task = this._writeQueue[0];
1278
- fs9.write(this._fd, task.buffer, task.offset, function(err, written) {
1278
+ fs11.write(this._fd, task.buffer, task.offset, function(err, written) {
1279
1279
  if (err) {
1280
1280
  if ("code" in err && err.code === "EAGAIN") {
1281
1281
  _this._writeImmediate = setImmediate(function() {
@@ -1390,9 +1390,9 @@ var require_src = __commonJS({
1390
1390
  });
1391
1391
 
1392
1392
  // src/commands/start.ts
1393
- var fs7 = __toESM(require("fs"));
1394
- var os6 = __toESM(require("os"));
1395
- var path10 = __toESM(require("path"));
1393
+ var fs8 = __toESM(require("fs"));
1394
+ var os7 = __toESM(require("os"));
1395
+ var path11 = __toESM(require("path"));
1396
1396
  var import_crypto = require("crypto");
1397
1397
  var import_child_process5 = require("child_process");
1398
1398
  var import_picocolors2 = __toESM(require("picocolors"));
@@ -1482,8 +1482,9 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
1482
1482
  // package.json
1483
1483
  var package_default = {
1484
1484
  name: "codeam-cli",
1485
- version: "2.4.33",
1485
+ version: "2.4.34",
1486
1486
  description: "Remote control Claude Code (and other AI coding agents) from your mobile phone. Pair your device, send prompts, stream responses in real-time, and approve commands \u2014 from anywhere.",
1487
+ type: "commonjs",
1487
1488
  main: "dist/index.js",
1488
1489
  bin: {
1489
1490
  codeam: "dist/index.js"
@@ -1611,6 +1612,60 @@ function computePollDelay({ baseMs, failures }) {
1611
1612
  return Math.round(jitter);
1612
1613
  }
1613
1614
 
1615
+ // src/services/logger.ts
1616
+ var fs2 = __toESM(require("fs"));
1617
+ var os2 = __toESM(require("os"));
1618
+ var path2 = __toESM(require("path"));
1619
+ var LEVELS = { silent: 0, error: 1, warn: 2, info: 3, debug: 4, trace: 5 };
1620
+ function currentLevel() {
1621
+ if (process.env.CODEAM_DEBUG === "1") return LEVELS.trace;
1622
+ const raw = (process.env.CODEAM_LOG ?? "error").toLowerCase();
1623
+ return LEVELS[raw] ?? LEVELS.error;
1624
+ }
1625
+ var fileEnabled = process.env.CODEAM_DEBUG === "1" || process.env.CODEAM_LOG === "debug" || process.env.CODEAM_LOG === "trace";
1626
+ var debugFilePath = path2.join(os2.homedir(), ".codeam", "debug.log");
1627
+ var fileInitialized = false;
1628
+ function appendToFile(line) {
1629
+ if (!fileEnabled) return;
1630
+ try {
1631
+ if (!fileInitialized) {
1632
+ fs2.mkdirSync(path2.dirname(debugFilePath), { recursive: true });
1633
+ fs2.writeFileSync(
1634
+ debugFilePath,
1635
+ `=== codeam debug log \u2014 pid ${process.pid} \u2014 ${(/* @__PURE__ */ new Date()).toISOString()} ===
1636
+ platform=${process.platform} node=${process.version} cwd=${process.cwd()}
1637
+
1638
+ `
1639
+ );
1640
+ fileInitialized = true;
1641
+ }
1642
+ fs2.appendFileSync(debugFilePath, line);
1643
+ } catch {
1644
+ }
1645
+ }
1646
+ function emit(level, tag, msg, err) {
1647
+ if (LEVELS[level] > currentLevel()) return;
1648
+ const detail = err instanceof Error ? `: ${err.message}` : err !== void 0 ? `: ${String(err)}` : "";
1649
+ const line = `[codeam:${level}] ${tag} \u2014 ${msg}${detail}
1650
+ `;
1651
+ process.stderr.write(line);
1652
+ if (LEVELS[level] >= LEVELS.debug) {
1653
+ appendToFile(`${(/* @__PURE__ */ new Date()).toISOString()} ${line}`);
1654
+ }
1655
+ }
1656
+ var log = {
1657
+ error: (tag, msg, err) => emit("error", tag, msg, err),
1658
+ warn: (tag, msg, err) => emit("warn", tag, msg, err),
1659
+ info: (tag, msg, err) => emit("info", tag, msg, err),
1660
+ debug: (tag, msg, err) => emit("debug", tag, msg, err),
1661
+ /**
1662
+ * Verbose pipeline breadcrumb. Only fires when CODEAM_LOG=trace or
1663
+ * CODEAM_DEBUG=1, so call sites can be liberal — they have zero
1664
+ * cost in normal runs.
1665
+ */
1666
+ trace: (tag, msg, err) => emit("trace", tag, msg, err)
1667
+ };
1668
+
1614
1669
  // src/services/websocket.service.ts
1615
1670
  var API_BASE = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
1616
1671
  var WS_URL = API_BASE.replace("https://", "wss://").replace("http://", "ws://") + "/api/ws";
@@ -1640,6 +1695,7 @@ var WebSocketService = class {
1640
1695
  try {
1641
1696
  this.client = new import_ws.default(WS_URL);
1642
1697
  this.client.on("open", () => {
1698
+ log.trace("ws", `connected to ${WS_URL}`);
1643
1699
  this._connected = true;
1644
1700
  this.reconnectAttempts = 0;
1645
1701
  this.client.send(JSON.stringify({
@@ -1653,12 +1709,18 @@ var WebSocketService = class {
1653
1709
  this.client.on("message", (raw) => {
1654
1710
  try {
1655
1711
  const msg = JSON.parse(raw.toString());
1656
- if (msg.type === "pong" || msg.type === "auth_success" || msg.type === "auth_error") return;
1712
+ if (msg.type === "pong" || msg.type === "auth_success" || msg.type === "auth_error") {
1713
+ log.trace("ws", `meta msg type=${msg.type}`);
1714
+ return;
1715
+ }
1716
+ log.trace("ws", `dispatch msg type=${msg.type}`);
1657
1717
  this.handlers.forEach((h) => h.onMessage(msg.type, msg.payload ?? {}));
1658
- } catch {
1718
+ } catch (err) {
1719
+ log.trace("ws", "malformed message", err);
1659
1720
  }
1660
1721
  });
1661
- this.client.on("close", () => {
1722
+ this.client.on("close", (code, reason) => {
1723
+ log.trace("ws", `closed code=${code} reason=${reason?.toString() || "(empty)"}`);
1662
1724
  this._connected = false;
1663
1725
  this.stopHeartbeat();
1664
1726
  this.handlers.forEach((h) => h.onDisconnected());
@@ -1668,9 +1730,11 @@ var WebSocketService = class {
1668
1730
  this.reconnectTimer = setTimeout(() => this.connect(), delay);
1669
1731
  }
1670
1732
  });
1671
- this.client.on("error", () => {
1733
+ this.client.on("error", (err) => {
1734
+ log.trace("ws", "error", err);
1672
1735
  });
1673
- } catch {
1736
+ } catch (err) {
1737
+ log.trace("ws", "sync connect threw", err);
1674
1738
  }
1675
1739
  }
1676
1740
  send(type, payload) {
@@ -1706,7 +1770,7 @@ var WebSocketService = class {
1706
1770
  // src/services/pairing.service.ts
1707
1771
  var https = __toESM(require("https"));
1708
1772
  var http = __toESM(require("http"));
1709
- var os2 = __toESM(require("os"));
1773
+ var os3 = __toESM(require("os"));
1710
1774
  var API_BASE2 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
1711
1775
  async function requestCode(pluginId) {
1712
1776
  try {
@@ -1716,7 +1780,7 @@ async function requestCode(pluginId) {
1716
1780
  pluginId,
1717
1781
  ideName: "Terminal (codeam-cli)",
1718
1782
  ideVersion: package_default.version,
1719
- hostname: os2.hostname(),
1783
+ hostname: os3.hostname(),
1720
1784
  runtime,
1721
1785
  ...codespaceName ? { codespaceName } : {}
1722
1786
  });
@@ -1880,7 +1944,10 @@ var CommandRelayService = class {
1880
1944
  _running = false;
1881
1945
  pollTimer = null;
1882
1946
  heartbeatTimer = null;
1947
+ agentsTimer = null;
1883
1948
  consecutiveFailures = 0;
1949
+ /** True once `/api/plugin/agents` has accepted at least one report. */
1950
+ agentsRegistered = false;
1884
1951
  start() {
1885
1952
  if (this.pollTimer) {
1886
1953
  clearTimeout(this.pollTimer);
@@ -1890,11 +1957,19 @@ var CommandRelayService = class {
1890
1957
  clearInterval(this.heartbeatTimer);
1891
1958
  this.heartbeatTimer = null;
1892
1959
  }
1960
+ if (this.agentsTimer) {
1961
+ clearInterval(this.agentsTimer);
1962
+ this.agentsTimer = null;
1963
+ }
1893
1964
  this._running = true;
1965
+ this.agentsRegistered = false;
1894
1966
  this.sendHeartbeat(true);
1895
1967
  this.heartbeatTimer = setInterval(() => this.sendHeartbeat(true), 2e4);
1896
1968
  void this.pollLoop();
1897
1969
  this.reportAgents();
1970
+ this.agentsTimer = setInterval(() => {
1971
+ if (this._running && !this.agentsRegistered) this.reportAgents();
1972
+ }, 5e3);
1898
1973
  }
1899
1974
  stop() {
1900
1975
  if (!this._running) return;
@@ -1907,6 +1982,10 @@ var CommandRelayService = class {
1907
1982
  clearInterval(this.heartbeatTimer);
1908
1983
  this.heartbeatTimer = null;
1909
1984
  }
1985
+ if (this.agentsTimer) {
1986
+ clearInterval(this.agentsTimer);
1987
+ this.agentsTimer = null;
1988
+ }
1910
1989
  this.sendHeartbeat(false).catch(() => {
1911
1990
  });
1912
1991
  }
@@ -1932,32 +2011,43 @@ var CommandRelayService = class {
1932
2011
  const commands = data?.data;
1933
2012
  this.consecutiveFailures = 0;
1934
2013
  if (!Array.isArray(commands)) return;
2014
+ if (commands.length > 0) {
2015
+ log.trace("relay", `poll received ${commands.length} command(s)`);
2016
+ }
1935
2017
  for (const obj of commands) {
1936
2018
  try {
2019
+ log.trace("relay", `dispatch type=${obj.type} id=${obj.id}`);
1937
2020
  await this.onCommand({
1938
2021
  id: obj.id,
1939
2022
  sessionId: obj.sessionId,
1940
2023
  type: obj.type,
1941
2024
  payload: obj.payload ?? {}
1942
2025
  });
1943
- } catch {
2026
+ } catch (err) {
2027
+ log.trace("relay", `command handler threw`, err);
1944
2028
  }
1945
2029
  }
1946
- } catch {
2030
+ } catch (err) {
1947
2031
  this.consecutiveFailures += 1;
2032
+ log.trace(
2033
+ "relay",
2034
+ `poll failed (failures=${this.consecutiveFailures})`,
2035
+ err
2036
+ );
1948
2037
  }
1949
2038
  }
1950
2039
  async sendHeartbeat(online) {
1951
2040
  await _postJson(`${API_BASE3}/api/plugin/heartbeat`, {
1952
2041
  pluginId: this.pluginId,
1953
2042
  online
1954
- }).catch(() => {
1955
- });
2043
+ }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
1956
2044
  }
1957
2045
  reportAgents() {
1958
2046
  _postJson(`${API_BASE3}/api/plugin/agents`, {
1959
2047
  pluginId: this.pluginId,
1960
2048
  agents: [{ id: "claude-code", name: "Claude Code", icon: "\u{1F916}", installed: true }]
2049
+ }).then(() => {
2050
+ this.agentsRegistered = true;
1961
2051
  }).catch(() => {
1962
2052
  });
1963
2053
  }
@@ -1965,24 +2055,24 @@ var CommandRelayService = class {
1965
2055
 
1966
2056
  // src/services/pty/unix.strategy.ts
1967
2057
  var import_child_process = require("child_process");
1968
- var fs3 = __toESM(require("fs"));
1969
- var os3 = __toESM(require("os"));
1970
- var path3 = __toESM(require("path"));
2058
+ var fs4 = __toESM(require("fs"));
2059
+ var os4 = __toESM(require("os"));
2060
+ var path4 = __toESM(require("path"));
1971
2061
 
1972
2062
  // src/services/pty/types.ts
1973
- var fs2 = __toESM(require("fs"));
1974
- var path2 = __toESM(require("path"));
2063
+ var fs3 = __toESM(require("fs"));
2064
+ var path3 = __toESM(require("path"));
1975
2065
  function findInPath(name) {
1976
2066
  const isWin = process.platform === "win32";
1977
- const dirs = (process.env.PATH ?? "").split(path2.delimiter).filter(Boolean);
1978
- const hasExt = path2.extname(name).length > 0;
2067
+ const dirs = (process.env.PATH ?? "").split(path3.delimiter).filter(Boolean);
2068
+ const hasExt = path3.extname(name).length > 0;
1979
2069
  const candidates = isWin && !hasExt ? [`${name}.exe`, `${name}.cmd`, `${name}.bat`, `${name}.ps1`, name] : [name];
1980
- const accessFlag = isWin ? fs2.constants.F_OK : fs2.constants.X_OK;
2070
+ const accessFlag = isWin ? fs3.constants.F_OK : fs3.constants.X_OK;
1981
2071
  for (const dir of dirs) {
1982
2072
  for (const candidate of candidates) {
1983
- const full = path2.join(dir, candidate);
2073
+ const full = path3.join(dir, candidate);
1984
2074
  try {
1985
- fs2.accessSync(full, accessFlag);
2075
+ fs3.accessSync(full, accessFlag);
1986
2076
  return full;
1987
2077
  } catch {
1988
2078
  }
@@ -2066,8 +2156,8 @@ var UnixPtyStrategy = class {
2066
2156
  }
2067
2157
  const cols = process.stdout.columns || 220;
2068
2158
  const rows = process.stdout.rows || 50;
2069
- this.helperPath = path3.join(os3.tmpdir(), "codeam-pty-helper.py");
2070
- fs3.writeFileSync(this.helperPath, PYTHON_PTY_HELPER, { mode: 420 });
2159
+ this.helperPath = path4.join(os4.tmpdir(), "codeam-pty-helper.py");
2160
+ fs4.writeFileSync(this.helperPath, PYTHON_PTY_HELPER, { mode: 420 });
2071
2161
  this.proc = (0, import_child_process.spawn)(python, [this.helperPath, cmd, ...args2], {
2072
2162
  stdio: ["pipe", "pipe", "inherit"],
2073
2163
  cwd,
@@ -2196,7 +2286,7 @@ var UnixPtyStrategy = class {
2196
2286
  removeTempFile() {
2197
2287
  if (this.helperPath) {
2198
2288
  try {
2199
- fs3.unlinkSync(this.helperPath);
2289
+ fs4.unlinkSync(this.helperPath);
2200
2290
  } catch {
2201
2291
  }
2202
2292
  this.helperPath = null;
@@ -2268,9 +2358,9 @@ var WindowsPtyStrategy = class {
2268
2358
  };
2269
2359
 
2270
2360
  // src/services/pty/windows-conpty.strategy.ts
2271
- var path4 = __toESM(require("path"));
2361
+ var path5 = __toESM(require("path"));
2272
2362
  function loadNodePty() {
2273
- const vendoredPath = path4.join(__dirname, "vendor", "node-pty");
2363
+ const vendoredPath = path5.join(__dirname, "vendor", "node-pty");
2274
2364
  try {
2275
2365
  return require(vendoredPath);
2276
2366
  } catch (vendorErr) {
@@ -2320,11 +2410,17 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
2320
2410
  useConpty: true,
2321
2411
  conptyInheritCursor: false
2322
2412
  });
2413
+ let traceCount = 0;
2323
2414
  this.dataSub = this.pty.onData((data) => {
2324
2415
  process.stdout.write(data);
2325
2416
  this.opts.onData(data);
2417
+ traceCount++;
2418
+ if (traceCount <= 5 || traceCount % 50 === 0) {
2419
+ log.trace("conpty", `onData #${traceCount} ${data.length}B`);
2420
+ }
2326
2421
  });
2327
2422
  this.exitSub = this.pty.onExit(({ exitCode }) => {
2423
+ log.trace("conpty", `claude exited code=${exitCode ?? 0}`);
2328
2424
  this.dispose();
2329
2425
  this.opts.onExit(exitCode ?? 0);
2330
2426
  });
@@ -2384,8 +2480,8 @@ var WindowsConPtyStrategy = class _WindowsConPtyStrategy {
2384
2480
 
2385
2481
  // src/services/claude-installer.ts
2386
2482
  var import_child_process3 = require("child_process");
2387
- var path5 = __toESM(require("path"));
2388
- var os4 = __toESM(require("os"));
2483
+ var path6 = __toESM(require("path"));
2484
+ var os5 = __toESM(require("os"));
2389
2485
 
2390
2486
  // ../../node_modules/@clack/prompts/dist/index.mjs
2391
2487
  var dist_exports = {};
@@ -4299,17 +4395,17 @@ ${c2}
4299
4395
 
4300
4396
  // src/services/claude-installer.ts
4301
4397
  function probeInstallDirs() {
4302
- const home = os4.homedir();
4398
+ const home = os5.homedir();
4303
4399
  if (process.platform === "win32") {
4304
4400
  return [
4305
- path5.join(home, ".claude", "local"),
4306
- path5.join(home, "AppData", "Local", "AnthropicClaude"),
4307
- path5.join(home, "AppData", "Local", "Programs", "AnthropicClaude")
4401
+ path6.join(home, ".claude", "local"),
4402
+ path6.join(home, "AppData", "Local", "AnthropicClaude"),
4403
+ path6.join(home, "AppData", "Local", "Programs", "AnthropicClaude")
4308
4404
  ];
4309
4405
  }
4310
4406
  return [
4311
- path5.join(home, ".local", "bin"),
4312
- path5.join(home, ".claude", "local"),
4407
+ path6.join(home, ".local", "bin"),
4408
+ path6.join(home, ".claude", "local"),
4313
4409
  "/usr/local/bin"
4314
4410
  ];
4315
4411
  }
@@ -4318,7 +4414,7 @@ function isAvailable() {
4318
4414
  }
4319
4415
  function augmentPath() {
4320
4416
  const dirs = probeInstallDirs();
4321
- const sep2 = path5.delimiter;
4417
+ const sep2 = path6.delimiter;
4322
4418
  const current = process.env.PATH ?? "";
4323
4419
  const existing = new Set(current.split(sep2).filter(Boolean));
4324
4420
  const additions = dirs.filter((d3) => !existing.has(d3));
@@ -4376,12 +4472,12 @@ async function ensureClaudeInstalled() {
4376
4472
  }
4377
4473
 
4378
4474
  // src/services/claude-resolver.ts
4379
- var path6 = __toESM(require("path"));
4475
+ var path7 = __toESM(require("path"));
4380
4476
  function buildClaudeLaunch(extraArgs = []) {
4381
4477
  const found = findInPath("claude") ?? findInPath("claude-code");
4382
4478
  if (!found) return null;
4383
4479
  if (process.platform === "win32") {
4384
- const ext = path6.extname(found).toLowerCase();
4480
+ const ext = path7.extname(found).toLowerCase();
4385
4481
  if (ext === ".cmd" || ext === ".bat") {
4386
4482
  return { cmd: "cmd.exe", args: ["/c", found, ...extraArgs] };
4387
4483
  }
@@ -4429,11 +4525,13 @@ var ClaudeService = class {
4429
4525
  }
4430
4526
  }
4431
4527
  if (process.platform === "win32") {
4528
+ log.trace("claude", `spawn (win32) cmd=${launch.cmd} args=${launch.args.join(" ")}`);
4432
4529
  const conpty = WindowsConPtyStrategy.tryCreate(this.strategyOpts);
4433
4530
  if (conpty) {
4434
4531
  try {
4435
4532
  conpty.spawn(launch.cmd, this.opts.cwd, launch.args);
4436
4533
  this.strategy = conpty;
4534
+ log.trace("claude", "ConPTY spawn ok");
4437
4535
  return;
4438
4536
  } catch (err) {
4439
4537
  const msg = err instanceof Error ? err.message : String(err);
@@ -4473,8 +4571,12 @@ var ClaudeService = class {
4473
4571
  * a fresh event-loop tick, after React has flushed the text into input state.
4474
4572
  */
4475
4573
  sendCommand(text) {
4476
- if (!this.strategy) return;
4574
+ if (!this.strategy) {
4575
+ log.trace("claude", "sendCommand dropped (no strategy)");
4576
+ return;
4577
+ }
4477
4578
  const s = this.strategy;
4579
+ log.trace("claude", `sendCommand text=${text.length}B`);
4478
4580
  s.write(text);
4479
4581
  setTimeout(() => s.write("\r"), 50);
4480
4582
  }
@@ -4548,12 +4650,12 @@ var https2 = __toESM(require("https"));
4548
4650
  var http2 = __toESM(require("http"));
4549
4651
 
4550
4652
  // ../../packages/shared/src/protocol/parseChrome.ts
4551
- var SPINNER_RE = /^[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]\s/;
4653
+ var SPINNER_RE = /^(?:[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]|🔴|🟠|🟡|🟢|🔵|🟣|🟤|⚫|⚪|🌀|💭|✨)\s/u;
4552
4654
  var BULLET_TOOL_RE = /^•\s+(?:Read(?:ing)?|Edit(?:ing)?|Writ(?:e|ing)|Bash|Runn(?:ing)?|Search(?:ing)?|Glob(?:bing)?|Grep(?:ping)?|Creat(?:e|ing)|Execut(?:e|ing)|Task|Agent|NotebookEdit)\b/i;
4553
4655
  var TREE_LINE_RE = /^└\s/;
4554
- var STATUS_LINE_RE = /^\+\s/;
4656
+ var STATUS_LINE_RE = /^(?:\+|[🔴🟠🟡🟢🔵🟣🟤⚫⚪🌀💭✨])\s/u;
4555
4657
  function isChromeLine(line) {
4556
- const t2 = line.trim();
4658
+ const t2 = line.replace(/️/g, "").trim();
4557
4659
  if (!t2) return false;
4558
4660
  if (/^[─━—═─\-]{3,}$/.test(t2)) return true;
4559
4661
  if (SPINNER_RE.test(t2)) return true;
@@ -4578,7 +4680,7 @@ function isChromeLine(line) {
4578
4680
  return false;
4579
4681
  }
4580
4682
  function parseChromeLine(line) {
4581
- const t2 = line.trim();
4683
+ const t2 = line.replace(/️/g, "").trim();
4582
4684
  if (!t2) return null;
4583
4685
  if (/^[─━—═─\-]{3,}$/.test(t2)) return null;
4584
4686
  if (/^[❯>]\s*$/.test(t2)) return null;
@@ -4982,6 +5084,7 @@ var OutputService = class _OutputService {
4982
5084
  this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
4983
5085
  }
4984
5086
  newTurn() {
5087
+ log.trace("outputSvc", "newTurn() \u2014 activating output stream");
4985
5088
  this.stopPoll();
4986
5089
  this.rawBuffer = "";
4987
5090
  this.lastSentContent = "";
@@ -5019,9 +5122,11 @@ var OutputService = class _OutputService {
5019
5122
  const printable2 = raw.replace(/\x1B\[[^@-~]*[@-~]/g, "").replace(/[\x00-\x1F\x7F]/g, "");
5020
5123
  if (printable2.trim()) {
5021
5124
  this.terminalTurnPending = true;
5125
+ log.trace("outputSvc", `terminal-turn detected (idle, ${raw.length}B)`);
5022
5126
  this.onTerminalTurnDetected?.();
5023
5127
  }
5024
5128
  }
5129
+ log.trace("outputSvc", `push dropped (inactive, ${raw.length}B)`);
5025
5130
  return;
5026
5131
  }
5027
5132
  this.rawBuffer += raw;
@@ -5031,6 +5136,10 @@ var OutputService = class _OutputService {
5031
5136
  this.tryExtractSessionId(printable);
5032
5137
  this.tryDetectRateLimit(printable);
5033
5138
  }
5139
+ log.trace(
5140
+ "outputSvc",
5141
+ `push +${raw.length}B (buf=${this.rawBuffer.length}B printable=${printable.trim().length})`
5142
+ );
5034
5143
  }
5035
5144
  /** Extract Claude conversation ID from output text (e.g., from /cost command or session resume) */
5036
5145
  tryExtractSessionId(text) {
@@ -5073,6 +5182,10 @@ var OutputService = class _OutputService {
5073
5182
  const selector = detectSelector(lines) ?? detectListSelector(lines);
5074
5183
  if (selector) {
5075
5184
  const idleMs2 = this.lastPushTime > 0 ? now - this.lastPushTime : elapsed;
5185
+ log.trace(
5186
+ "outputSvc",
5187
+ `tick selector found (idleMs=${idleMs2}, options=${selector.options.length})`
5188
+ );
5076
5189
  if (idleMs2 >= _OutputService.SELECTOR_IDLE_MS) {
5077
5190
  this.stopPoll();
5078
5191
  this.active = false;
@@ -5083,10 +5196,18 @@ var OutputService = class _OutputService {
5083
5196
  }
5084
5197
  const content = filterChrome(lines).join("\n").replace(/\n{3,}/g, "\n\n").trim();
5085
5198
  if (!content) {
5199
+ log.trace(
5200
+ "outputSvc",
5201
+ `tick empty content (raw=${this.rawBuffer.length}B lines=${lines.length} elapsed=${elapsed}ms)`
5202
+ );
5086
5203
  if (elapsed >= _OutputService.EMPTY_TIMEOUT_MS) this.finalize();
5087
5204
  return;
5088
5205
  }
5089
5206
  const idleMs = this.lastPushTime > 0 ? now - this.lastPushTime : elapsed;
5207
+ log.trace(
5208
+ "outputSvc",
5209
+ `tick content (raw=${this.rawBuffer.length}B lines=${lines.length} content=${content.length} idleMs=${idleMs})`
5210
+ );
5090
5211
  if (idleMs >= _OutputService.IDLE_MS) {
5091
5212
  this.finalize();
5092
5213
  return;
@@ -5153,15 +5274,33 @@ var OutputService = class _OutputService {
5153
5274
  if (this.pluginAuthToken) {
5154
5275
  headers["X-Plugin-Auth-Token"] = this.pluginAuthToken;
5155
5276
  }
5277
+ log.trace(
5278
+ "outputSvc",
5279
+ `postChunk type=${body.type ?? "(clear)"} done=${body.done === true} bytes=${payload.length}`
5280
+ );
5156
5281
  return new Promise((resolve2) => {
5157
5282
  const attempt = (attemptsLeft) => {
5158
5283
  _transport2.sendOutputChunk(`${API_BASE4}/api/commands/output`, headers, payload).then(({ statusCode, body: resBody }) => {
5284
+ log.trace("outputSvc", `postChunk status=${statusCode}`);
5285
+ if (statusCode === 410 || statusCode === 404 && /SESSION_NOT_FOUND|SESSION_GONE/.test(resBody)) {
5286
+ if (this.active) {
5287
+ process.stderr.write("[codeam] session was deleted/disconnected \u2014 stopping output stream.\n");
5288
+ this.dispose();
5289
+ }
5290
+ resolve2();
5291
+ return;
5292
+ }
5159
5293
  if (statusCode >= 400) {
5160
5294
  process.stderr.write(`[codeam] output API error ${statusCode}: ${resBody}
5161
5295
  `);
5162
5296
  }
5163
5297
  resolve2();
5164
- }).catch(() => {
5298
+ }).catch((err) => {
5299
+ log.trace(
5300
+ "outputSvc",
5301
+ `postChunk error (retries left=${attemptsLeft})`,
5302
+ err
5303
+ );
5165
5304
  if (attemptsLeft > 0) {
5166
5305
  const delay = 200 * (maxRetries - attemptsLeft + 1);
5167
5306
  setTimeout(() => attempt(attemptsLeft - 1), delay);
@@ -5220,33 +5359,12 @@ function _sendOutputChunk(url, headers, payload) {
5220
5359
  }
5221
5360
 
5222
5361
  // src/services/history.service.ts
5223
- var fs4 = __toESM(require("fs"));
5224
- var path7 = __toESM(require("path"));
5225
- var os5 = __toESM(require("os"));
5362
+ var fs5 = __toESM(require("fs"));
5363
+ var path8 = __toESM(require("path"));
5364
+ var os6 = __toESM(require("os"));
5226
5365
  var https3 = __toESM(require("https"));
5227
5366
  var http3 = __toESM(require("http"));
5228
5367
  var import_zod = require("zod");
5229
-
5230
- // src/services/logger.ts
5231
- var LEVELS = { silent: 0, error: 1, warn: 2, info: 3, debug: 4 };
5232
- function currentLevel() {
5233
- const raw = (process.env.CODEAM_LOG ?? "error").toLowerCase();
5234
- return LEVELS[raw] ?? LEVELS.error;
5235
- }
5236
- function emit(level, tag, msg, err) {
5237
- if (LEVELS[level] > currentLevel()) return;
5238
- const detail = err instanceof Error ? `: ${err.message}` : err !== void 0 ? `: ${String(err)}` : "";
5239
- process.stderr.write(`[codeam:${level}] ${tag} \u2014 ${msg}${detail}
5240
- `);
5241
- }
5242
- var log = {
5243
- error: (tag, msg, err) => emit("error", tag, msg, err),
5244
- warn: (tag, msg, err) => emit("warn", tag, msg, err),
5245
- info: (tag, msg, err) => emit("info", tag, msg, err),
5246
- debug: (tag, msg, err) => emit("debug", tag, msg, err)
5247
- };
5248
-
5249
- // src/services/history.service.ts
5250
5368
  var historyRecordSchema = import_zod.z.object({
5251
5369
  type: import_zod.z.string().optional(),
5252
5370
  timestamp: import_zod.z.union([import_zod.z.string(), import_zod.z.number()]).optional(),
@@ -5259,7 +5377,25 @@ var historyRecordSchema = import_zod.z.object({
5259
5377
  }).passthrough();
5260
5378
  var API_BASE5 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
5261
5379
  function encodeCwd(cwd) {
5262
- return cwd.replace(/\//g, "-");
5380
+ return cwd.replace(/[\\/:]/g, "-");
5381
+ }
5382
+ function findProjectDir(cwd) {
5383
+ const projectsRoot = path8.join(os6.homedir(), ".claude", "projects");
5384
+ const primary = path8.join(projectsRoot, encodeCwd(cwd));
5385
+ if (fs5.existsSync(primary)) return primary;
5386
+ try {
5387
+ const entries = fs5.readdirSync(projectsRoot, { withFileTypes: true });
5388
+ const wanted = encodeCwd(cwd);
5389
+ for (const e of entries) {
5390
+ if (!e.isDirectory()) continue;
5391
+ const candidate = e.name.replace(/-+/g, "-");
5392
+ if (candidate === wanted.replace(/-+/g, "-")) {
5393
+ return path8.join(projectsRoot, e.name);
5394
+ }
5395
+ }
5396
+ } catch {
5397
+ }
5398
+ return null;
5263
5399
  }
5264
5400
  function extractText(content) {
5265
5401
  if (typeof content === "string") return content;
@@ -5273,7 +5409,7 @@ function parseJsonl(filePath) {
5273
5409
  const messages = [];
5274
5410
  let raw;
5275
5411
  try {
5276
- raw = fs4.readFileSync(filePath, "utf8");
5412
+ raw = fs5.readFileSync(filePath, "utf8");
5277
5413
  } catch (err) {
5278
5414
  if (err.code !== "ENOENT") {
5279
5415
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -5377,7 +5513,7 @@ var HistoryService = class {
5377
5513
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
5378
5514
  }
5379
5515
  get projectDir() {
5380
- return path7.join(os5.homedir(), ".claude", "projects", encodeCwd(this.cwd));
5516
+ return findProjectDir(this.cwd) ?? path8.join(os6.homedir(), ".claude", "projects", encodeCwd(this.cwd));
5381
5517
  }
5382
5518
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
5383
5519
  setCurrentConversationId(id) {
@@ -5389,7 +5525,7 @@ var HistoryService = class {
5389
5525
  /** Return the current message count in the active conversation. */
5390
5526
  getCurrentMessageCount() {
5391
5527
  if (!this.currentConversationId) return 0;
5392
- const filePath = path7.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5528
+ const filePath = path8.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5393
5529
  return parseJsonl(filePath).length;
5394
5530
  }
5395
5531
  /**
@@ -5400,7 +5536,7 @@ var HistoryService = class {
5400
5536
  const deadline = Date.now() + timeoutMs;
5401
5537
  while (Date.now() < deadline) {
5402
5538
  if (!this.currentConversationId) return null;
5403
- const filePath = path7.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5539
+ const filePath = path8.join(this.projectDir, `${this.currentConversationId}.jsonl`);
5404
5540
  const messages = parseJsonl(filePath);
5405
5541
  if (messages.length > previousCount) {
5406
5542
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -5415,15 +5551,15 @@ var HistoryService = class {
5415
5551
  detectCurrentConversation() {
5416
5552
  const dir = this.projectDir;
5417
5553
  try {
5418
- const files = fs4.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
5554
+ const files = fs5.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
5419
5555
  try {
5420
- return { name: e.name, mtime: fs4.statSync(path7.join(dir, e.name)).mtimeMs };
5556
+ return { name: e.name, mtime: fs5.statSync(path8.join(dir, e.name)).mtimeMs };
5421
5557
  } catch {
5422
5558
  return { name: e.name, mtime: 0 };
5423
5559
  }
5424
5560
  }).sort((a, b) => b.mtime - a.mtime);
5425
5561
  if (files.length > 0) {
5426
- this.currentConversationId = path7.basename(files[0].name, ".jsonl");
5562
+ this.currentConversationId = path8.basename(files[0].name, ".jsonl");
5427
5563
  }
5428
5564
  } catch {
5429
5565
  }
@@ -5455,13 +5591,13 @@ var HistoryService = class {
5455
5591
  const dir = this.projectDir;
5456
5592
  let entries;
5457
5593
  try {
5458
- entries = fs4.readdirSync(dir, { withFileTypes: true });
5594
+ entries = fs5.readdirSync(dir, { withFileTypes: true });
5459
5595
  } catch {
5460
5596
  return null;
5461
5597
  }
5462
5598
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
5463
5599
  try {
5464
- return { name: e.name, mtime: fs4.statSync(path7.join(dir, e.name)).mtimeMs };
5600
+ return { name: e.name, mtime: fs5.statSync(path8.join(dir, e.name)).mtimeMs };
5465
5601
  } catch {
5466
5602
  return { name: e.name, mtime: 0 };
5467
5603
  }
@@ -5469,12 +5605,12 @@ var HistoryService = class {
5469
5605
  if (files.length === 0) return null;
5470
5606
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
5471
5607
  if (!files.some((f) => f.name === targetFile)) return null;
5472
- return this.extractUsageFromFile(path7.join(dir, targetFile));
5608
+ return this.extractUsageFromFile(path8.join(dir, targetFile));
5473
5609
  }
5474
5610
  extractUsageFromFile(filePath) {
5475
5611
  let raw;
5476
5612
  try {
5477
- raw = fs4.readFileSync(filePath, "utf8");
5613
+ raw = fs5.readFileSync(filePath, "utf8");
5478
5614
  } catch {
5479
5615
  return null;
5480
5616
  }
@@ -5519,9 +5655,9 @@ var HistoryService = class {
5519
5655
  let totalCost = 0;
5520
5656
  let files;
5521
5657
  try {
5522
- files = fs4.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
5658
+ files = fs5.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
5523
5659
  try {
5524
- return fs4.statSync(path7.join(projectDir, f)).mtimeMs >= monthStartMs;
5660
+ return fs5.statSync(path8.join(projectDir, f)).mtimeMs >= monthStartMs;
5525
5661
  } catch {
5526
5662
  return false;
5527
5663
  }
@@ -5532,7 +5668,7 @@ var HistoryService = class {
5532
5668
  for (const file of files) {
5533
5669
  let raw;
5534
5670
  try {
5535
- raw = fs4.readFileSync(path7.join(projectDir, file), "utf8");
5671
+ raw = fs5.readFileSync(path8.join(projectDir, file), "utf8");
5536
5672
  } catch {
5537
5673
  continue;
5538
5674
  }
@@ -5567,23 +5703,23 @@ var HistoryService = class {
5567
5703
  const dir = this.projectDir;
5568
5704
  let entries;
5569
5705
  try {
5570
- entries = fs4.readdirSync(dir, { withFileTypes: true });
5706
+ entries = fs5.readdirSync(dir, { withFileTypes: true });
5571
5707
  } catch {
5572
5708
  return;
5573
5709
  }
5574
5710
  const sessions2 = [];
5575
5711
  for (const entry of entries) {
5576
5712
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
5577
- const id = path7.basename(entry.name, ".jsonl");
5578
- const filePath = path7.join(dir, entry.name);
5713
+ const id = path8.basename(entry.name, ".jsonl");
5714
+ const filePath = path8.join(dir, entry.name);
5579
5715
  let mtime = Date.now();
5580
5716
  try {
5581
- mtime = fs4.statSync(filePath).mtimeMs;
5717
+ mtime = fs5.statSync(filePath).mtimeMs;
5582
5718
  } catch {
5583
5719
  }
5584
5720
  let summary = "";
5585
5721
  try {
5586
- const raw = fs4.readFileSync(filePath, "utf8");
5722
+ const raw = fs5.readFileSync(filePath, "utf8");
5587
5723
  for (const line of raw.split("\n")) {
5588
5724
  if (!line.trim()) continue;
5589
5725
  try {
@@ -5616,7 +5752,7 @@ var HistoryService = class {
5616
5752
  * showing an empty conversation.
5617
5753
  */
5618
5754
  async loadConversation(sessionId) {
5619
- const filePath = path7.join(this.projectDir, `${sessionId}.jsonl`);
5755
+ const filePath = path8.join(this.projectDir, `${sessionId}.jsonl`);
5620
5756
  const messages = parseJsonl(filePath);
5621
5757
  if (messages.length === 0) return;
5622
5758
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -5671,8 +5807,8 @@ function parsePayload(schema, raw) {
5671
5807
  }
5672
5808
 
5673
5809
  // src/services/file-ops.service.ts
5674
- var fs5 = __toESM(require("fs/promises"));
5675
- var path8 = __toESM(require("path"));
5810
+ var fs6 = __toESM(require("fs/promises"));
5811
+ var path9 = __toESM(require("path"));
5676
5812
  var MAX_FILE_BYTES = 5 * 1024 * 1024;
5677
5813
  var MAX_WALK_DEPTH = 6;
5678
5814
  var MAX_VISITED_DIRS = 5e3;
@@ -5707,12 +5843,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
5707
5843
  "__pycache__"
5708
5844
  ]);
5709
5845
  function isUnder(parent, candidate) {
5710
- const rel = path8.relative(parent, candidate);
5711
- return rel === "" || !rel.startsWith("..") && !path8.isAbsolute(rel);
5846
+ const rel = path9.relative(parent, candidate);
5847
+ return rel === "" || !rel.startsWith("..") && !path9.isAbsolute(rel);
5712
5848
  }
5713
5849
  async function isExistingFile(absPath) {
5714
5850
  try {
5715
- const stat3 = await fs5.stat(absPath);
5851
+ const stat3 = await fs6.stat(absPath);
5716
5852
  return stat3.isFile();
5717
5853
  } catch {
5718
5854
  return false;
@@ -5725,13 +5861,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
5725
5861
  ctx.visited++;
5726
5862
  let entries = [];
5727
5863
  try {
5728
- entries = await fs5.readdir(dir, { withFileTypes: true });
5864
+ entries = await fs6.readdir(dir, { withFileTypes: true });
5729
5865
  } catch {
5730
5866
  return;
5731
5867
  }
5732
5868
  for (const e of entries) {
5733
5869
  if (!e.isFile()) continue;
5734
- const full = path8.join(dir, e.name);
5870
+ const full = path9.join(dir, e.name);
5735
5871
  if (needleVariants.some((needle) => full.endsWith(needle))) {
5736
5872
  ctx.matches.push(full);
5737
5873
  if (ctx.matches.length >= ctx.cap) return;
@@ -5741,21 +5877,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
5741
5877
  if (!e.isDirectory()) continue;
5742
5878
  if (SUBDIR_IGNORE.has(e.name)) continue;
5743
5879
  if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
5744
- await walkForSuffix(path8.join(dir, e.name), needleVariants, depth + 1, ctx);
5880
+ await walkForSuffix(path9.join(dir, e.name), needleVariants, depth + 1, ctx);
5745
5881
  if (ctx.matches.length >= ctx.cap) return;
5746
5882
  }
5747
5883
  }
5748
5884
  async function findFile(rawPath) {
5749
5885
  const cwd = process.cwd();
5750
- if (path8.isAbsolute(rawPath)) {
5751
- const abs = path8.normalize(rawPath);
5886
+ if (path9.isAbsolute(rawPath)) {
5887
+ const abs = path9.normalize(rawPath);
5752
5888
  if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
5753
5889
  }
5754
- const direct = path8.resolve(cwd, rawPath);
5890
+ const direct = path9.resolve(cwd, rawPath);
5755
5891
  if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
5756
- const normalized = path8.normalize(rawPath).replace(/^[./\\]+/, "");
5892
+ const normalized = path9.normalize(rawPath).replace(/^[./\\]+/, "");
5757
5893
  const needles = [
5758
- `${path8.sep}${normalized}`,
5894
+ `${path9.sep}${normalized}`,
5759
5895
  `/${normalized}`
5760
5896
  ].filter((v, i, a) => a.indexOf(v) === i);
5761
5897
  const ctx = { visited: 0, matches: [], cap: 16 };
@@ -5769,7 +5905,7 @@ async function findWriteTarget(rawPath) {
5769
5905
  const found = await findFile(rawPath);
5770
5906
  if (found) return found;
5771
5907
  const cwd = process.cwd();
5772
- const fallback = path8.isAbsolute(rawPath) ? path8.normalize(rawPath) : path8.resolve(cwd, rawPath);
5908
+ const fallback = path9.isAbsolute(rawPath) ? path9.normalize(rawPath) : path9.resolve(cwd, rawPath);
5773
5909
  if (!isUnder(cwd, fallback)) return null;
5774
5910
  return fallback;
5775
5911
  }
@@ -5786,11 +5922,11 @@ async function readProjectFile(rawPath) {
5786
5922
  if (!abs) {
5787
5923
  return { error: `File not found in the project tree: ${rawPath}` };
5788
5924
  }
5789
- const stat3 = await fs5.stat(abs);
5925
+ const stat3 = await fs6.stat(abs);
5790
5926
  if (stat3.size > MAX_FILE_BYTES) {
5791
5927
  return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
5792
5928
  }
5793
- const buf = await fs5.readFile(abs);
5929
+ const buf = await fs6.readFile(abs);
5794
5930
  if (looksBinary(buf)) {
5795
5931
  return { error: "Binary file \u2014 refusing to open in a code editor." };
5796
5932
  }
@@ -5809,8 +5945,8 @@ async function writeProjectFile(rawPath, content) {
5809
5945
  if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
5810
5946
  return { error: "Content too large." };
5811
5947
  }
5812
- await fs5.mkdir(path8.dirname(abs), { recursive: true });
5813
- await fs5.writeFile(abs, content, "utf-8");
5948
+ await fs6.mkdir(path9.dirname(abs), { recursive: true });
5949
+ await fs6.writeFile(abs, content, "utf-8");
5814
5950
  return { ok: true };
5815
5951
  } catch (e) {
5816
5952
  const msg = e instanceof Error ? e.message : "Write failed";
@@ -5821,8 +5957,8 @@ async function writeProjectFile(rawPath, content) {
5821
5957
  // src/services/project-ops.service.ts
5822
5958
  var import_child_process4 = require("child_process");
5823
5959
  var import_util = require("util");
5824
- var fs6 = __toESM(require("fs/promises"));
5825
- var path9 = __toESM(require("path"));
5960
+ var fs7 = __toESM(require("fs/promises"));
5961
+ var path10 = __toESM(require("path"));
5826
5962
  var execFileP = (0, import_util.promisify)(import_child_process4.execFile);
5827
5963
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
5828
5964
  "node_modules",
@@ -5870,7 +6006,7 @@ async function listProjectFiles(opts = {}) {
5870
6006
  }
5871
6007
  let entries = [];
5872
6008
  try {
5873
- entries = await fs6.readdir(dir, { withFileTypes: true });
6009
+ entries = await fs7.readdir(dir, { withFileTypes: true });
5874
6010
  } catch {
5875
6011
  return;
5876
6012
  }
@@ -5880,18 +6016,18 @@ async function listProjectFiles(opts = {}) {
5880
6016
  return;
5881
6017
  }
5882
6018
  if (PROJECT_IGNORE.has(e.name)) continue;
5883
- const full = path9.join(dir, e.name);
6019
+ const full = path10.join(dir, e.name);
5884
6020
  if (e.isDirectory()) {
5885
6021
  if (depth >= 12) continue;
5886
6022
  await walk(full, depth + 1);
5887
6023
  } else if (e.isFile()) {
5888
- const rel = path9.relative(root, full);
6024
+ const rel = path10.relative(root, full);
5889
6025
  if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
5890
6026
  continue;
5891
6027
  }
5892
6028
  let size = 0;
5893
6029
  try {
5894
- const st3 = await fs6.stat(full);
6030
+ const st3 = await fs7.stat(full);
5895
6031
  size = st3.size;
5896
6032
  } catch {
5897
6033
  }
@@ -5993,8 +6129,8 @@ async function gitStatus(cwd) {
5993
6129
  let hasMergeInProgress = false;
5994
6130
  try {
5995
6131
  const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
5996
- const mergeHead = path9.isAbsolute(gitDir) ? path9.join(gitDir, "MERGE_HEAD") : path9.join(root, gitDir, "MERGE_HEAD");
5997
- await fs6.access(mergeHead);
6132
+ const mergeHead = path10.isAbsolute(gitDir) ? path10.join(gitDir, "MERGE_HEAD") : path10.join(root, gitDir, "MERGE_HEAD");
6133
+ await fs7.access(mergeHead);
5998
6134
  hasMergeInProgress = true;
5999
6135
  } catch {
6000
6136
  }
@@ -6071,8 +6207,8 @@ async function gitResolve(file, side, cwd) {
6071
6207
  function saveFilesTemp(files) {
6072
6208
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
6073
6209
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
6074
- const tmpPath = path10.join(os6.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
6075
- fs7.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
6210
+ const tmpPath = path11.join(os7.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
6211
+ fs8.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
6076
6212
  return tmpPath;
6077
6213
  });
6078
6214
  }
@@ -6145,8 +6281,8 @@ try:
6145
6281
  sys.exit((st>>8)&0xFF)
6146
6282
  except Exception:sys.exit(0)
6147
6283
  `;
6148
- const helperPath = path10.join(os6.tmpdir(), "codeam-quota-helper.py");
6149
- fs7.writeFileSync(helperPath, helperScript, { mode: 420 });
6284
+ const helperPath = path11.join(os7.tmpdir(), "codeam-quota-helper.py");
6285
+ fs8.writeFileSync(helperPath, helperScript, { mode: 420 });
6150
6286
  const python = findInPath("python3") ?? findInPath("python");
6151
6287
  if (!python) {
6152
6288
  quotaFetchInProgress = false;
@@ -6178,7 +6314,7 @@ except Exception:sys.exit(0)
6178
6314
  } catch {
6179
6315
  }
6180
6316
  try {
6181
- fs7.unlinkSync(helperPath);
6317
+ fs8.unlinkSync(helperPath);
6182
6318
  } catch {
6183
6319
  }
6184
6320
  quotaFetchInProgress = false;
@@ -6228,7 +6364,7 @@ except Exception:sys.exit(0)
6228
6364
  setTimeout(() => {
6229
6365
  for (const p2 of paths) {
6230
6366
  try {
6231
- fs7.unlinkSync(p2);
6367
+ fs8.unlinkSync(p2);
6232
6368
  } catch {
6233
6369
  }
6234
6370
  }
@@ -6271,6 +6407,25 @@ except Exception:sys.exit(0)
6271
6407
  }
6272
6408
  break;
6273
6409
  }
6410
+ case "session_terminated": {
6411
+ showInfo("Session was deleted from the app \u2014 exiting.");
6412
+ try {
6413
+ claude.kill();
6414
+ } catch {
6415
+ }
6416
+ try {
6417
+ const proc = (0, import_child_process5.spawn)("bash", ["-lc", "pm2 delete codeam-pair >/dev/null 2>&1 || true"], {
6418
+ detached: true,
6419
+ stdio: "ignore"
6420
+ });
6421
+ proc.unref();
6422
+ } catch {
6423
+ }
6424
+ outputSvc.dispose();
6425
+ relay.stop();
6426
+ ws.disconnect();
6427
+ process.exit(0);
6428
+ }
6274
6429
  case "shutdown_session": {
6275
6430
  try {
6276
6431
  await relay.sendResult(cmd.id, "success", { ok: true });
@@ -6451,7 +6606,7 @@ except Exception:sys.exit(0)
6451
6606
  setTimeout(() => {
6452
6607
  for (const p2 of paths) {
6453
6608
  try {
6454
- fs7.unlinkSync(p2);
6609
+ fs8.unlinkSync(p2);
6455
6610
  } catch {
6456
6611
  }
6457
6612
  }
@@ -6746,9 +6901,9 @@ async function logout() {
6746
6901
 
6747
6902
  // src/commands/deploy.ts
6748
6903
  var import_child_process10 = require("child_process");
6749
- var fs8 = __toESM(require("fs"));
6750
- var os7 = __toESM(require("os"));
6751
- var path15 = __toESM(require("path"));
6904
+ var fs9 = __toESM(require("fs"));
6905
+ var os8 = __toESM(require("os"));
6906
+ var path16 = __toESM(require("path"));
6752
6907
  var import_util6 = require("util");
6753
6908
  var import_picocolors9 = __toESM(require("picocolors"));
6754
6909
 
@@ -6756,7 +6911,7 @@ var import_picocolors9 = __toESM(require("picocolors"));
6756
6911
  var import_child_process6 = require("child_process");
6757
6912
  var import_util2 = require("util");
6758
6913
  var import_picocolors7 = __toESM(require("picocolors"));
6759
- var path11 = __toESM(require("path"));
6914
+ var path12 = __toESM(require("path"));
6760
6915
  var execFileP2 = (0, import_util2.promisify)(import_child_process6.execFile);
6761
6916
  var MAX_BUFFER = 8 * 1024 * 1024;
6762
6917
  function resetStdinForChild() {
@@ -7245,7 +7400,7 @@ var GitHubCodespacesProvider = class {
7245
7400
  });
7246
7401
  }
7247
7402
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
7248
- const remoteDir = path11.posix.dirname(remotePath);
7403
+ const remoteDir = path12.posix.dirname(remotePath);
7249
7404
  const parts = [
7250
7405
  `mkdir -p ${shellQuote(remoteDir)}`,
7251
7406
  `cat > ${shellQuote(remotePath)}`
@@ -7315,7 +7470,7 @@ function shellQuote(s) {
7315
7470
  // src/services/providers/gitpod.ts
7316
7471
  var import_child_process7 = require("child_process");
7317
7472
  var import_util3 = require("util");
7318
- var path12 = __toESM(require("path"));
7473
+ var path13 = __toESM(require("path"));
7319
7474
  var import_picocolors8 = __toESM(require("picocolors"));
7320
7475
  var execFileP3 = (0, import_util3.promisify)(import_child_process7.execFile);
7321
7476
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -7555,7 +7710,7 @@ var GitpodProvider = class {
7555
7710
  });
7556
7711
  }
7557
7712
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
7558
- const remoteDir = path12.posix.dirname(remotePath);
7713
+ const remoteDir = path13.posix.dirname(remotePath);
7559
7714
  const parts = [
7560
7715
  `mkdir -p ${shellQuote2(remoteDir)}`,
7561
7716
  `cat > ${shellQuote2(remotePath)}`
@@ -7591,7 +7746,7 @@ function shellQuote2(s) {
7591
7746
  // src/services/providers/gitlab-workspaces.ts
7592
7747
  var import_child_process8 = require("child_process");
7593
7748
  var import_util4 = require("util");
7594
- var path13 = __toESM(require("path"));
7749
+ var path14 = __toESM(require("path"));
7595
7750
  var execFileP4 = (0, import_util4.promisify)(import_child_process8.execFile);
7596
7751
  var MAX_BUFFER3 = 8 * 1024 * 1024;
7597
7752
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -7851,7 +8006,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
7851
8006
  }
7852
8007
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
7853
8008
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
7854
- const remoteDir = path13.posix.dirname(remotePath);
8009
+ const remoteDir = path14.posix.dirname(remotePath);
7855
8010
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
7856
8011
  if (options.mode != null) {
7857
8012
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -7919,7 +8074,7 @@ function shellQuote3(s) {
7919
8074
  // src/services/providers/railway.ts
7920
8075
  var import_child_process9 = require("child_process");
7921
8076
  var import_util5 = require("util");
7922
- var path14 = __toESM(require("path"));
8077
+ var path15 = __toESM(require("path"));
7923
8078
  var execFileP5 = (0, import_util5.promisify)(import_child_process9.execFile);
7924
8079
  var MAX_BUFFER4 = 8 * 1024 * 1024;
7925
8080
  function resetStdinForChild4() {
@@ -8155,7 +8310,7 @@ var RailwayProvider = class {
8155
8310
  if (!projectId || !serviceId) {
8156
8311
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
8157
8312
  }
8158
- const remoteDir = path14.posix.dirname(remotePath);
8313
+ const remoteDir = path15.posix.dirname(remotePath);
8159
8314
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
8160
8315
  if (options.mode != null) {
8161
8316
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -8347,7 +8502,7 @@ async function deploy() {
8347
8502
  process.exit(1);
8348
8503
  }
8349
8504
  }
8350
- const localClaudeDir = path15.join(os7.homedir(), ".claude");
8505
+ const localClaudeDir = path16.join(os8.homedir(), ".claude");
8351
8506
  const localCredsKind = await detectLocalClaudeCredentials(localClaudeDir);
8352
8507
  let bridged = "none";
8353
8508
  if (localCredsKind !== "none") {
@@ -8391,7 +8546,7 @@ async function deploy() {
8391
8546
  process.exit(1);
8392
8547
  }
8393
8548
  claudeStep.stop("\u2713 Claude CLI installed");
8394
- const haveLocalClaude = fs8.existsSync(localClaudeDir) && fs8.statSync(localClaudeDir).isDirectory();
8549
+ const haveLocalClaude = fs9.existsSync(localClaudeDir) && fs9.statSync(localClaudeDir).isDirectory();
8395
8550
  if (haveLocalClaude) {
8396
8551
  const copyStep = fe();
8397
8552
  copyStep.start("Copying local Claude config to workspace\u2026");
@@ -8445,10 +8600,10 @@ async function deploy() {
8445
8600
  }
8446
8601
  }
8447
8602
  if (bridged !== "none") {
8448
- const localClaudeJson = path15.join(os7.homedir(), ".claude.json");
8449
- if (fs8.existsSync(localClaudeJson)) {
8603
+ const localClaudeJson = path16.join(os8.homedir(), ".claude.json");
8604
+ if (fs9.existsSync(localClaudeJson)) {
8450
8605
  try {
8451
- const contents = fs8.readFileSync(localClaudeJson);
8606
+ const contents = fs9.readFileSync(localClaudeJson);
8452
8607
  await provider.uploadFile(
8453
8608
  workspace.id,
8454
8609
  "/home/codespace/.claude.json",
@@ -8638,7 +8793,7 @@ async function runRemoteClaudeLogin(provider, workspaceId) {
8638
8793
  }
8639
8794
  }
8640
8795
  async function detectLocalClaudeCredentials(localClaudeDir) {
8641
- if (fs8.existsSync(path15.join(localClaudeDir, ".credentials.json"))) {
8796
+ if (fs9.existsSync(path16.join(localClaudeDir, ".credentials.json"))) {
8642
8797
  return "flat-file";
8643
8798
  }
8644
8799
  if (process.platform === "darwin") {
@@ -8671,8 +8826,8 @@ async function verifyClaudeAuth(provider, workspaceId) {
8671
8826
  }
8672
8827
  }
8673
8828
  async function bridgeClaudeCredentials(provider, workspaceId, localClaudeDir) {
8674
- const fileBased = path15.join(localClaudeDir, ".credentials.json");
8675
- if (fs8.existsSync(fileBased)) return "flat-file";
8829
+ const fileBased = path16.join(localClaudeDir, ".credentials.json");
8830
+ if (fs9.existsSync(fileBased)) return "flat-file";
8676
8831
  if (process.platform === "darwin") {
8677
8832
  try {
8678
8833
  const { stdout } = await execFileP6(
@@ -8877,10 +9032,172 @@ async function stopWorkspaceFromLocal(target) {
8877
9032
  }
8878
9033
  }
8879
9034
 
9035
+ // src/commands/version.ts
9036
+ var import_picocolors11 = __toESM(require("picocolors"));
9037
+ function version() {
9038
+ const v = true ? "2.4.34" : "unknown";
9039
+ console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
9040
+ }
9041
+
9042
+ // src/commands/help.ts
9043
+ var import_picocolors12 = __toESM(require("picocolors"));
9044
+ function help() {
9045
+ const lines = [
9046
+ "",
9047
+ ` ${import_picocolors12.default.bold(import_picocolors12.default.magenta("codeam-cli"))} ${import_picocolors12.default.dim("\u2014 Claude Code remote control")}`,
9048
+ "",
9049
+ ` ${import_picocolors12.default.bold("Usage")}`,
9050
+ ` ${import_picocolors12.default.cyan("codeam")} ${import_picocolors12.default.dim("[command]")}`,
9051
+ "",
9052
+ ` ${import_picocolors12.default.bold("Commands")}`,
9053
+ ` ${import_picocolors12.default.white("codeam")} ${import_picocolors12.default.dim("start Claude Code with mobile control")}`,
9054
+ ` ${import_picocolors12.default.white("codeam pair")} ${import_picocolors12.default.dim("pair a new mobile device")}`,
9055
+ ` ${import_picocolors12.default.white("codeam sessions")} ${import_picocolors12.default.dim("list paired devices")}`,
9056
+ ` ${import_picocolors12.default.white("codeam status")} ${import_picocolors12.default.dim("show connection info")}`,
9057
+ ` ${import_picocolors12.default.white("codeam logout")} ${import_picocolors12.default.dim("remove all paired sessions")}`,
9058
+ ` ${import_picocolors12.default.white("codeam deploy")} ${import_picocolors12.default.dim("provision a cloud workspace (Codespaces) and pair it")}`,
9059
+ ` ${import_picocolors12.default.white("codeam deploy ls")} ${import_picocolors12.default.dim("list deployed cloud workspaces")}`,
9060
+ ` ${import_picocolors12.default.white("codeam deploy stop")} ${import_picocolors12.default.dim("stop a deployed workspace session")}`,
9061
+ "",
9062
+ ` ${import_picocolors12.default.bold("Flags")}`,
9063
+ ` ${import_picocolors12.default.white("-v, --version")} ${import_picocolors12.default.dim("print the CLI version")}`,
9064
+ ` ${import_picocolors12.default.white("-h, --help")} ${import_picocolors12.default.dim("show this help")}`,
9065
+ "",
9066
+ ` ${import_picocolors12.default.bold("Links")}`,
9067
+ ` ${import_picocolors12.default.dim("Docs:")} ${import_picocolors12.default.green("https://www.codeagent-mobile.com")}`,
9068
+ ` ${import_picocolors12.default.dim("Issues:")} ${import_picocolors12.default.green("https://github.com/edgar-durand/codeagent-mobile-clients/issues")}`,
9069
+ ""
9070
+ ];
9071
+ process.stdout.write(lines.join("\n") + "\n");
9072
+ }
9073
+
9074
+ // src/lib/updateNotifier.ts
9075
+ var fs10 = __toESM(require("fs"));
9076
+ var os9 = __toESM(require("os"));
9077
+ var path17 = __toESM(require("path"));
9078
+ var https4 = __toESM(require("https"));
9079
+ var import_picocolors13 = __toESM(require("picocolors"));
9080
+ var PKG_NAME = "codeam-cli";
9081
+ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
9082
+ var TTL_MS = 24 * 60 * 60 * 1e3;
9083
+ var REQUEST_TIMEOUT_MS = 1500;
9084
+ function cachePath() {
9085
+ const dir = path17.join(os9.homedir(), ".codeam");
9086
+ return path17.join(dir, "update-check.json");
9087
+ }
9088
+ function readCache() {
9089
+ try {
9090
+ const raw = fs10.readFileSync(cachePath(), "utf8");
9091
+ const parsed = JSON.parse(raw);
9092
+ if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
9093
+ return parsed;
9094
+ } catch {
9095
+ return null;
9096
+ }
9097
+ }
9098
+ function writeCache(cache) {
9099
+ try {
9100
+ const file = cachePath();
9101
+ fs10.mkdirSync(path17.dirname(file), { recursive: true });
9102
+ fs10.writeFileSync(file, JSON.stringify(cache));
9103
+ } catch {
9104
+ }
9105
+ }
9106
+ function compareSemver(a, b) {
9107
+ const stripPre = (s) => s.split("-")[0];
9108
+ const aParts = stripPre(a).split(".").map(Number);
9109
+ const bParts = stripPre(b).split(".").map(Number);
9110
+ for (let i = 0; i < 3; i++) {
9111
+ const ai = aParts[i] ?? 0;
9112
+ const bi = bParts[i] ?? 0;
9113
+ if (Number.isNaN(ai) || Number.isNaN(bi)) return 0;
9114
+ if (ai > bi) return 1;
9115
+ if (ai < bi) return -1;
9116
+ }
9117
+ return 0;
9118
+ }
9119
+ function fetchLatest() {
9120
+ return new Promise((resolve2) => {
9121
+ const req = https4.get(
9122
+ REGISTRY_URL,
9123
+ { headers: { Accept: "application/json" }, timeout: REQUEST_TIMEOUT_MS },
9124
+ (res) => {
9125
+ if (res.statusCode !== 200) {
9126
+ res.resume();
9127
+ resolve2(null);
9128
+ return;
9129
+ }
9130
+ let buf = "";
9131
+ res.setEncoding("utf8");
9132
+ res.on("data", (chunk) => {
9133
+ buf += chunk;
9134
+ });
9135
+ res.on("end", () => {
9136
+ try {
9137
+ const json = JSON.parse(buf);
9138
+ if (typeof json.version === "string") {
9139
+ resolve2(json.version);
9140
+ } else {
9141
+ resolve2(null);
9142
+ }
9143
+ } catch {
9144
+ resolve2(null);
9145
+ }
9146
+ });
9147
+ }
9148
+ );
9149
+ req.on("timeout", () => {
9150
+ req.destroy();
9151
+ resolve2(null);
9152
+ });
9153
+ req.on("error", () => resolve2(null));
9154
+ });
9155
+ }
9156
+ function notifyIfStale(currentVersion, latest) {
9157
+ if (compareSemver(latest, currentVersion) <= 0) return;
9158
+ const arrow = import_picocolors13.default.dim("\u2192");
9159
+ const cmd = import_picocolors13.default.cyan("npm install -g codeam-cli");
9160
+ const lines = [
9161
+ "",
9162
+ ` ${import_picocolors13.default.yellow("\u25CF")} ${import_picocolors13.default.bold("Update available")} ${import_picocolors13.default.dim(currentVersion)} ${arrow} ${import_picocolors13.default.green(latest)}`,
9163
+ ` Run ${cmd} to upgrade.`,
9164
+ ""
9165
+ ];
9166
+ process.stderr.write(lines.join("\n"));
9167
+ }
9168
+ function checkForUpdates() {
9169
+ if (process.env.NODE_ENV === "test") return;
9170
+ if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
9171
+ if (process.env.CI) return;
9172
+ if (!process.stdout.isTTY) return;
9173
+ const current = true ? "2.4.34" : null;
9174
+ if (!current) return;
9175
+ const cache = readCache();
9176
+ const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
9177
+ if (fresh && cache) {
9178
+ notifyIfStale(current, cache.latest);
9179
+ return;
9180
+ }
9181
+ void fetchLatest().then((latest) => {
9182
+ if (!latest) return;
9183
+ writeCache({ fetchedAt: Date.now(), latest });
9184
+ });
9185
+ }
9186
+
8880
9187
  // src/index.ts
8881
9188
  var [, , command, ...args] = process.argv;
8882
9189
  async function main() {
9190
+ const isMetaCommand = command === "--version" || command === "-v" || command === "version" || command === "--help" || command === "-h" || command === "help";
9191
+ if (!isMetaCommand) checkForUpdates();
8883
9192
  switch (command) {
9193
+ case "--version":
9194
+ case "-v":
9195
+ case "version":
9196
+ return version();
9197
+ case "--help":
9198
+ case "-h":
9199
+ case "help":
9200
+ return help();
8884
9201
  case "pair":
8885
9202
  return pair();
8886
9203
  case "sessions":