codeam-cli 2.11.0 → 2.12.0

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 +37 -0
  2. package/dist/index.js +315 -101
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,43 @@ 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.11.0] — 2026-05-13
8
+
9
+ ### Added
10
+
11
+ - **shared:** Add agent type primitives
12
+ - **shared:** Add AGENT_REGISTRY with Claude enabled
13
+ - **shared:** Export agents module + bump minor
14
+ - **cli:** Define RuntimeStrategy + DeployStrategy interfaces
15
+ - **cli:** Implement ClaudeRuntimeStrategy
16
+ - **cli:** Implement ClaudeDeployStrategy + extract credential bridge
17
+ - **cli:** Add agent to SavedSession + preferredAgent to CliConfig
18
+ - **cli:** Add parseAgentFlag + promptForAgent helpers
19
+ - **cli:** Pair accepts --agent flag + prompts + remembers preferredAgent
20
+ - **cli:** Pair-auto consumes agent from API response
21
+ - **cli:** Change_model + summarize handlers route through RuntimeStrategy
22
+
23
+ ### Changed
24
+
25
+ - **vsc-plugin:** Port JetBrains agent-strategy pattern
26
+ - **cli:** Extract Claude history parsing to agents/claude/history.ts
27
+ - **cli:** Extract Claude /usage parsing to agents/claude/quota.ts
28
+ - **cli:** Rename ClaudeService → AgentService, add registry factory
29
+ - **cli:** History + quota services delegate to RuntimeStrategy
30
+ - **cli:** Start.ts uses session.agent for runtime factory
31
+ - **cli:** Deploy uses DeployStrategy + switches to pair-auto
32
+ - **cli:** Pass args to pair command
33
+
34
+ ### Documentation
35
+
36
+ - Align CLAUDE.md + bump in-source versions to v2.10.8
37
+ - **cli:** Drop misleading codeam-login note in deploy.ts
38
+
39
+ ### Fixed
40
+
41
+ - **cli:** Reload config after addSession to avoid clobbering activeSessionId
42
+ - **cli:** Revert deploy PM2 wrapper to pair --agent=<id> (Phase 1 lacks user-JWT)
43
+
7
44
  ## [2.10.8] — 2026-05-12
8
45
 
9
46
  ### Fixed
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 fs15 = require("fs");
523
- var os14 = require("os");
524
- var path21 = require("path");
522
+ var fs17 = require("fs");
523
+ var os16 = require("os");
524
+ var path23 = 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 = path21.resolve(cwd);
560
+ cwd = path23.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 = fs15.openSync(term.conin, "w");
581
+ var inSocketFD = fs17.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(path21.join(__dirname, "conpty_console_list_agent"), [_this._innerPid.toString()]);
682
+ var agent = child_process_1.fork(path23.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(os14.release());
705
+ var osVersion = /(\d+)\.(\d+)\.(\d+)/g.exec(os16.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 fs15 = require("fs");
1016
- var path21 = require("path");
1015
+ var fs17 = require("fs");
1016
+ var path23 = 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 = path21.resolve(__dirname, helperPath);
1023
+ helperPath = path23.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
- fs15.write(this._fd, task.buffer, task.offset, function(err, written) {
1278
+ fs17.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() {
@@ -1313,10 +1313,10 @@ var require_lib = __commonJS({
1313
1313
  } else {
1314
1314
  terminalCtor = require_unixTerminal().UnixTerminal;
1315
1315
  }
1316
- function spawn10(file, args2, opt) {
1316
+ function spawn11(file, args2, opt) {
1317
1317
  return new terminalCtor(file, args2, opt);
1318
1318
  }
1319
- exports2.spawn = spawn10;
1319
+ exports2.spawn = spawn11;
1320
1320
  function fork(file, args2, opt) {
1321
1321
  return new terminalCtor(file, args2, opt);
1322
1322
  }
@@ -1738,18 +1738,37 @@ function filterChrome(lines) {
1738
1738
 
1739
1739
  // ../../packages/shared/src/models/pricing.ts
1740
1740
  var MODEL_PRICING = {
1741
+ // ── Anthropic / Claude ────────────────────────────────────
1741
1742
  "claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
1742
1743
  "claude-opus-4": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
1743
1744
  "claude-3-5-sonnet": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
1744
1745
  "claude-3-5-haiku": { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
1745
- "claude-3-haiku": { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.3 }
1746
+ "claude-3-haiku": { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.3 },
1747
+ // ── Codex / OpenAI ────────────────────────────────────────
1748
+ // Phase 2 placeholder pricing: 0 across the board until OpenAI publishes
1749
+ // confirmed rates for the GPT-5.x catalog. Sync from
1750
+ // developers.openai.com/pricing when available.
1751
+ "gpt-5.5": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1752
+ "gpt-5.4": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1753
+ "gpt-5.4-mini": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1754
+ "gpt-5.3-codex": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1755
+ "gpt-5.2": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1756
+ "codex-auto-review": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }
1746
1757
  };
1747
1758
  var MODEL_CONTEXT_WINDOW = {
1759
+ // ── Anthropic / Claude ────────────────────────────────────
1748
1760
  "claude-opus-4": 1e6,
1749
1761
  "claude-sonnet-4": 1e6,
1750
1762
  "claude-3-5-sonnet": 2e5,
1751
1763
  "claude-3-5-haiku": 2e5,
1752
- "claude-3-haiku": 2e5
1764
+ "claude-3-haiku": 2e5,
1765
+ // ── Codex / OpenAI ────────────────────────────────────────
1766
+ "gpt-5.5": 272e3,
1767
+ "gpt-5.4": 272e3,
1768
+ "gpt-5.4-mini": 272e3,
1769
+ "gpt-5.3-codex": 272e3,
1770
+ "gpt-5.2": 272e3,
1771
+ "codex-auto-review": 272e3
1753
1772
  };
1754
1773
  var DEFAULT_CONTEXT_WINDOW = 2e5;
1755
1774
  function getPricing(model) {
@@ -1780,7 +1799,7 @@ var AGENT_REGISTRY = {
1780
1799
  id: "codex",
1781
1800
  displayName: "Codex CLI",
1782
1801
  binaryName: "codex",
1783
- enabled: false,
1802
+ enabled: true,
1784
1803
  supportedAuthKinds: ["oauth_token", "api_key"],
1785
1804
  preferredAuthKind: "oauth_token"
1786
1805
  },
@@ -1900,7 +1919,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
1900
1919
  // package.json
1901
1920
  var package_default = {
1902
1921
  name: "codeam-cli",
1903
- version: "2.11.0",
1922
+ version: "2.12.0",
1904
1923
  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.",
1905
1924
  type: "commonjs",
1906
1925
  main: "dist/index.js",
@@ -5648,13 +5667,208 @@ var ClaudeDeployStrategy = class {
5648
5667
  }
5649
5668
  };
5650
5669
 
5670
+ // src/agents/codex/runtime.ts
5671
+ var import_node_child_process = require("child_process");
5672
+
5673
+ // src/agents/codex/history.ts
5674
+ var import_node_fs2 = __toESM(require("fs"));
5675
+ var import_node_path2 = __toESM(require("path"));
5676
+ var import_node_os = __toESM(require("os"));
5677
+ function resolveHistoryDir2(_cwd, homeOverride) {
5678
+ const home = homeOverride ?? import_node_os.default.homedir();
5679
+ const codexDir = import_node_path2.default.join(home, ".codex");
5680
+ if (!import_node_fs2.default.existsSync(import_node_path2.default.join(codexDir, "history.jsonl"))) return null;
5681
+ return codexDir;
5682
+ }
5683
+ function isCodexRecord(v) {
5684
+ if (!v || typeof v !== "object") return false;
5685
+ const r = v;
5686
+ return typeof r.session_id === "string" && typeof r.ts === "number" && typeof r.text === "string";
5687
+ }
5688
+ function parseHistoryFile2(filePath) {
5689
+ const raw = import_node_fs2.default.readFileSync(filePath, "utf8");
5690
+ const out = [];
5691
+ let idx = 0;
5692
+ for (const line of raw.split("\n").filter(Boolean)) {
5693
+ let rec;
5694
+ try {
5695
+ rec = JSON.parse(line);
5696
+ } catch {
5697
+ continue;
5698
+ }
5699
+ if (!isCodexRecord(rec)) continue;
5700
+ out.push({
5701
+ id: `${rec.session_id}:${idx}`,
5702
+ role: "user",
5703
+ text: rec.text,
5704
+ timestamp: new Date(rec.ts * 1e3).toISOString()
5705
+ });
5706
+ idx++;
5707
+ }
5708
+ return out;
5709
+ }
5710
+ function getCurrentUsage2(_historyDir) {
5711
+ return null;
5712
+ }
5713
+
5714
+ // src/agents/codex/runtime.ts
5715
+ var CODEX_CONTEXT_WINDOW = 272e3;
5716
+ var CODEX_MODELS = [
5717
+ { id: "gpt-5.5", label: "GPT-5.5", contextWindow: CODEX_CONTEXT_WINDOW },
5718
+ { id: "gpt-5.4", label: "GPT-5.4", contextWindow: CODEX_CONTEXT_WINDOW },
5719
+ { id: "gpt-5.4-mini", label: "GPT-5.4 Mini", contextWindow: CODEX_CONTEXT_WINDOW },
5720
+ { id: "gpt-5.3-codex", label: "GPT-5.3 Codex", contextWindow: CODEX_CONTEXT_WINDOW },
5721
+ { id: "gpt-5.2", label: "GPT-5.2", contextWindow: CODEX_CONTEXT_WINDOW },
5722
+ { id: "codex-auto-review", label: "Codex Auto Review", contextWindow: CODEX_CONTEXT_WINDOW }
5723
+ ];
5724
+ var CodexRuntimeStrategy = class {
5725
+ id = "codex";
5726
+ meta = getAgent("codex");
5727
+ async prepareLaunch() {
5728
+ const binary = findInPath("codex");
5729
+ if (!binary) {
5730
+ await installCodexViaNpm();
5731
+ const afterInstall = findInPath("codex");
5732
+ if (!afterInstall) {
5733
+ throw new Error(
5734
+ "Could not find 'codex' on PATH after running 'npm install -g @openai/codex'. Install it manually and retry."
5735
+ );
5736
+ }
5737
+ return { cmd: afterInstall, args: [] };
5738
+ }
5739
+ return { cmd: binary, args: [] };
5740
+ }
5741
+ /** `codex resume <SESSION_ID>` — subcommand, not flag. */
5742
+ resumeLaunchArgs(sessionId) {
5743
+ return ["resume", sessionId];
5744
+ }
5745
+ resolveHistoryDir(cwd) {
5746
+ return resolveHistoryDir2(cwd);
5747
+ }
5748
+ parseHistoryFile(filePath) {
5749
+ return parseHistoryFile2(filePath);
5750
+ }
5751
+ getCurrentUsage(historyDir) {
5752
+ return getCurrentUsage2(historyDir);
5753
+ }
5754
+ /**
5755
+ * Codex's quota lives behind the `account/get_account_rate_limits` RPC,
5756
+ * not a TUI slash command. Phase 2 ships with this stubbed to null so the
5757
+ * mobile shows "—" for weekly usage on Codex sessions. A follow-up will
5758
+ * invoke the RPC directly.
5759
+ */
5760
+ async fetchWeeklyUsage() {
5761
+ return null;
5762
+ }
5763
+ async listModels() {
5764
+ return CODEX_MODELS;
5765
+ }
5766
+ changeModelInstruction(modelId) {
5767
+ return { type: "pty", ptyInput: `/model ${modelId}\r` };
5768
+ }
5769
+ /**
5770
+ * Codex has no auto-compact (`auto_compact_token_limit: null` for every
5771
+ * model). Both modes fall through to the manual `/compact` slash command.
5772
+ */
5773
+ summarizeInstruction(_mode) {
5774
+ return { ptyInput: "/compact\r" };
5775
+ }
5776
+ };
5777
+ async function installCodexViaNpm() {
5778
+ return new Promise((resolve2, reject) => {
5779
+ const npm = process.platform === "win32" ? "npm.cmd" : "npm";
5780
+ const proc = (0, import_node_child_process.spawn)(npm, ["install", "-g", "@openai/codex"], {
5781
+ stdio: "inherit"
5782
+ });
5783
+ proc.on("close", (code) => {
5784
+ if (code === 0) resolve2();
5785
+ else reject(new Error(`npm install -g @openai/codex exited ${code}`));
5786
+ });
5787
+ proc.on("error", reject);
5788
+ });
5789
+ }
5790
+
5791
+ // src/agents/codex/credentials.ts
5792
+ var import_node_fs3 = __toESM(require("fs"));
5793
+ var import_node_path3 = __toESM(require("path"));
5794
+ var import_node_os2 = __toESM(require("os"));
5795
+ async function detectLocalCodexCredentials() {
5796
+ const home = process.env.HOME ?? import_node_os2.default.homedir();
5797
+ const authJson = import_node_path3.default.join(home, ".codex", "auth.json");
5798
+ if (import_node_fs3.default.existsSync(authJson)) {
5799
+ return { source: "flat-file", description: "~/.codex/auth.json" };
5800
+ }
5801
+ if (process.env.OPENAI_API_KEY) {
5802
+ return { source: "env-var", description: "OPENAI_API_KEY env var" };
5803
+ }
5804
+ return { source: "none", description: "" };
5805
+ }
5806
+ async function bridgeLocalCodexCredentials(provider, workspaceId) {
5807
+ const home = process.env.HOME ?? import_node_os2.default.homedir();
5808
+ const authJson = import_node_path3.default.join(home, ".codex", "auth.json");
5809
+ if (import_node_fs3.default.existsSync(authJson)) {
5810
+ const contents = import_node_fs3.default.readFileSync(authJson);
5811
+ await provider.exec(workspaceId, "mkdir -p ~/.codex && chmod 700 ~/.codex");
5812
+ await provider.uploadFile(workspaceId, "/home/codespace/.codex/auth.json", contents, { mode: 384 });
5813
+ return { source: "flat-file", description: "~/.codex/auth.json" };
5814
+ }
5815
+ const key = process.env.OPENAI_API_KEY;
5816
+ if (key) {
5817
+ const escaped = key.replace(/'/g, "'\\''");
5818
+ const line = `export OPENAI_API_KEY='${escaped}'`;
5819
+ await provider.exec(workspaceId, `grep -qxF "${line}" ~/.bashrc || echo "${line}" >> ~/.bashrc`);
5820
+ return { source: "env-var", description: "OPENAI_API_KEY env var" };
5821
+ }
5822
+ return { source: "none", description: "" };
5823
+ }
5824
+ async function runRemoteCodexLogin(provider, workspaceId) {
5825
+ await provider.streamCommand(workspaceId, 'bash -lc "codex login"');
5826
+ }
5827
+ async function verifyCodexAuth(provider, workspaceId) {
5828
+ const r = await provider.exec(workspaceId, 'bash -lc "codex --version"');
5829
+ return r.code === 0;
5830
+ }
5831
+
5832
+ // src/agents/codex/deploy.ts
5833
+ var CodexDeployStrategy = class {
5834
+ id = "codex";
5835
+ async detectLocalCredentials() {
5836
+ return detectLocalCodexCredentials();
5837
+ }
5838
+ async bridgeLocalCredentials(provider, workspaceId) {
5839
+ return bridgeLocalCodexCredentials(provider, workspaceId);
5840
+ }
5841
+ async runRemoteLogin(provider, workspaceId) {
5842
+ return runRemoteCodexLogin(provider, workspaceId);
5843
+ }
5844
+ /**
5845
+ * Steps 5–7 of the existing local-deploy flow, adapted for Codex:
5846
+ * 1. Install codex via npm
5847
+ * 2. (skipped — bridge already happened before this method runs, or the
5848
+ * fallback runs via runRemoteLogin)
5849
+ * 3. Verify auth; fallback to remote login if verify fails AND no
5850
+ * credentials were bridged.
5851
+ */
5852
+ async setupOnWorkspace(provider, workspaceId, opts) {
5853
+ const installResult = await provider.exec(workspaceId, "npm install -g @openai/codex");
5854
+ if (installResult.code !== 0) {
5855
+ throw new Error(`codex install failed: ${installResult.stderr.slice(0, 500)}`);
5856
+ }
5857
+ const verified = await verifyCodexAuth(provider, workspaceId);
5858
+ if (!verified && opts.bridged === "none") {
5859
+ await runRemoteCodexLogin(provider, workspaceId);
5860
+ }
5861
+ }
5862
+ };
5863
+
5651
5864
  // src/agents/registry.ts
5652
5865
  var runtimeBuilders = {
5653
- claude: () => new ClaudeRuntimeStrategy()
5654
- // codex and copilot added in Phase 2 / later
5866
+ claude: () => new ClaudeRuntimeStrategy(),
5867
+ codex: () => new CodexRuntimeStrategy()
5655
5868
  };
5656
5869
  var deployBuilders = {
5657
- claude: () => new ClaudeDeployStrategy()
5870
+ claude: () => new ClaudeDeployStrategy(),
5871
+ codex: () => new CodexDeployStrategy()
5658
5872
  };
5659
5873
  function createRuntimeStrategy(agent) {
5660
5874
  if (!AGENT_REGISTRY[agent]?.enabled) {
@@ -6149,9 +6363,9 @@ var OutputService = class _OutputService {
6149
6363
  };
6150
6364
 
6151
6365
  // src/services/history.service.ts
6152
- var fs9 = __toESM(require("fs"));
6153
- var path12 = __toESM(require("path"));
6154
- var os10 = __toESM(require("os"));
6366
+ var fs11 = __toESM(require("fs"));
6367
+ var path14 = __toESM(require("path"));
6368
+ var os12 = __toESM(require("os"));
6155
6369
  var https4 = __toESM(require("https"));
6156
6370
  var http4 = __toESM(require("http"));
6157
6371
  var import_zod = require("zod");
@@ -6178,7 +6392,7 @@ function parseJsonl(filePath) {
6178
6392
  const messages = [];
6179
6393
  let raw;
6180
6394
  try {
6181
- raw = fs9.readFileSync(filePath, "utf8");
6395
+ raw = fs11.readFileSync(filePath, "utf8");
6182
6396
  } catch (err) {
6183
6397
  if (err.code !== "ENOENT") {
6184
6398
  log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
@@ -6312,7 +6526,7 @@ var HistoryService = class _HistoryService {
6312
6526
  return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
6313
6527
  }
6314
6528
  get projectDir() {
6315
- return this.runtime.resolveHistoryDir(this.cwd) ?? path12.join(os10.homedir(), ".claude", "projects", encodeCwd(this.cwd));
6529
+ return this.runtime.resolveHistoryDir(this.cwd) ?? path14.join(os12.homedir(), ".claude", "projects", encodeCwd(this.cwd));
6316
6530
  }
6317
6531
  /** Set the current Claude conversation ID (extracted from /cost command or session start) */
6318
6532
  setCurrentConversationId(id) {
@@ -6324,7 +6538,7 @@ var HistoryService = class _HistoryService {
6324
6538
  /** Return the current message count in the active conversation. */
6325
6539
  getCurrentMessageCount() {
6326
6540
  if (!this.currentConversationId) return 0;
6327
- const filePath = path12.join(this.projectDir, `${this.currentConversationId}.jsonl`);
6541
+ const filePath = path14.join(this.projectDir, `${this.currentConversationId}.jsonl`);
6328
6542
  return parseJsonl(filePath).length;
6329
6543
  }
6330
6544
  /**
@@ -6335,7 +6549,7 @@ var HistoryService = class _HistoryService {
6335
6549
  const deadline = Date.now() + timeoutMs;
6336
6550
  while (Date.now() < deadline) {
6337
6551
  if (!this.currentConversationId) return null;
6338
- const filePath = path12.join(this.projectDir, `${this.currentConversationId}.jsonl`);
6552
+ const filePath = path14.join(this.projectDir, `${this.currentConversationId}.jsonl`);
6339
6553
  const messages = parseJsonl(filePath);
6340
6554
  if (messages.length > previousCount) {
6341
6555
  for (let i = messages.length - 1; i >= previousCount; i--) {
@@ -6361,16 +6575,16 @@ var HistoryService = class _HistoryService {
6361
6575
  const dir = this.projectDir;
6362
6576
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
6363
6577
  try {
6364
- const files = fs9.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
6578
+ const files = fs11.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
6365
6579
  try {
6366
- const stat3 = fs9.statSync(path12.join(dir, e.name));
6580
+ const stat3 = fs11.statSync(path14.join(dir, e.name));
6367
6581
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
6368
6582
  } catch {
6369
6583
  return { name: e.name, mtime: 0, birthtime: 0 };
6370
6584
  }
6371
6585
  }).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
6372
6586
  if (files.length > 0) {
6373
- this.currentConversationId = path12.basename(files[0].name, ".jsonl");
6587
+ this.currentConversationId = path14.basename(files[0].name, ".jsonl");
6374
6588
  }
6375
6589
  } catch {
6376
6590
  }
@@ -6404,13 +6618,13 @@ var HistoryService = class _HistoryService {
6404
6618
  const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
6405
6619
  let entries;
6406
6620
  try {
6407
- entries = fs9.readdirSync(dir, { withFileTypes: true });
6621
+ entries = fs11.readdirSync(dir, { withFileTypes: true });
6408
6622
  } catch {
6409
6623
  return null;
6410
6624
  }
6411
6625
  const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
6412
6626
  try {
6413
- const stat3 = fs9.statSync(path12.join(dir, e.name));
6627
+ const stat3 = fs11.statSync(path14.join(dir, e.name));
6414
6628
  return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
6415
6629
  } catch {
6416
6630
  return { name: e.name, mtime: 0, birthtime: 0 };
@@ -6419,12 +6633,12 @@ var HistoryService = class _HistoryService {
6419
6633
  if (files.length === 0) return null;
6420
6634
  const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
6421
6635
  if (!files.some((f) => f.name === targetFile)) return null;
6422
- return this.extractUsageFromFile(path12.join(dir, targetFile));
6636
+ return this.extractUsageFromFile(path14.join(dir, targetFile));
6423
6637
  }
6424
6638
  extractUsageFromFile(filePath) {
6425
6639
  let raw;
6426
6640
  try {
6427
- raw = fs9.readFileSync(filePath, "utf8");
6641
+ raw = fs11.readFileSync(filePath, "utf8");
6428
6642
  } catch {
6429
6643
  return null;
6430
6644
  }
@@ -6469,9 +6683,9 @@ var HistoryService = class _HistoryService {
6469
6683
  let totalCost = 0;
6470
6684
  let files;
6471
6685
  try {
6472
- files = fs9.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
6686
+ files = fs11.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
6473
6687
  try {
6474
- return fs9.statSync(path12.join(projectDir, f)).mtimeMs >= monthStartMs;
6688
+ return fs11.statSync(path14.join(projectDir, f)).mtimeMs >= monthStartMs;
6475
6689
  } catch {
6476
6690
  return false;
6477
6691
  }
@@ -6482,7 +6696,7 @@ var HistoryService = class _HistoryService {
6482
6696
  for (const file of files) {
6483
6697
  let raw;
6484
6698
  try {
6485
- raw = fs9.readFileSync(path12.join(projectDir, file), "utf8");
6699
+ raw = fs11.readFileSync(path14.join(projectDir, file), "utf8");
6486
6700
  } catch {
6487
6701
  continue;
6488
6702
  }
@@ -6517,23 +6731,23 @@ var HistoryService = class _HistoryService {
6517
6731
  const dir = this.projectDir;
6518
6732
  let entries;
6519
6733
  try {
6520
- entries = fs9.readdirSync(dir, { withFileTypes: true });
6734
+ entries = fs11.readdirSync(dir, { withFileTypes: true });
6521
6735
  } catch {
6522
6736
  return;
6523
6737
  }
6524
6738
  const sessions2 = [];
6525
6739
  for (const entry of entries) {
6526
6740
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
6527
- const id = path12.basename(entry.name, ".jsonl");
6528
- const filePath = path12.join(dir, entry.name);
6741
+ const id = path14.basename(entry.name, ".jsonl");
6742
+ const filePath = path14.join(dir, entry.name);
6529
6743
  let mtime = Date.now();
6530
6744
  try {
6531
- mtime = fs9.statSync(filePath).mtimeMs;
6745
+ mtime = fs11.statSync(filePath).mtimeMs;
6532
6746
  } catch {
6533
6747
  }
6534
6748
  let summary = "";
6535
6749
  try {
6536
- const raw = fs9.readFileSync(filePath, "utf8");
6750
+ const raw = fs11.readFileSync(filePath, "utf8");
6537
6751
  for (const line of raw.split("\n")) {
6538
6752
  if (!line.trim()) continue;
6539
6753
  try {
@@ -6566,7 +6780,7 @@ var HistoryService = class _HistoryService {
6566
6780
  * showing an empty conversation.
6567
6781
  */
6568
6782
  async loadConversation(sessionId) {
6569
- const filePath = path12.join(this.projectDir, `${sessionId}.jsonl`);
6783
+ const filePath = path14.join(this.projectDir, `${sessionId}.jsonl`);
6570
6784
  const messages = parseJsonl(filePath);
6571
6785
  if (messages.length === 0) return;
6572
6786
  const totalBatches = Math.ceil(messages.length / CONVERSATION_BATCH_SIZE);
@@ -6609,7 +6823,7 @@ var HistoryService = class _HistoryService {
6609
6823
  if (!this.currentConversationId) return 0;
6610
6824
  }
6611
6825
  const sessionId = this.currentConversationId;
6612
- const filePath = path12.join(this.projectDir, `${sessionId}.jsonl`);
6826
+ const filePath = path14.join(this.projectDir, `${sessionId}.jsonl`);
6613
6827
  const messages = parseJsonl(filePath);
6614
6828
  if (messages.length === 0) return 0;
6615
6829
  const marker = this.lastUploadedUuid.get(sessionId);
@@ -6695,9 +6909,9 @@ function buildKeepAlive(ctx) {
6695
6909
  }
6696
6910
 
6697
6911
  // src/commands/start/handlers.ts
6698
- var fs12 = __toESM(require("fs"));
6699
- var os11 = __toESM(require("os"));
6700
- var path15 = __toESM(require("path"));
6912
+ var fs14 = __toESM(require("fs"));
6913
+ var os13 = __toESM(require("os"));
6914
+ var path17 = __toESM(require("path"));
6701
6915
  var import_crypto = require("crypto");
6702
6916
  var import_child_process8 = require("child_process");
6703
6917
 
@@ -6736,8 +6950,8 @@ function parsePayload(schema, raw) {
6736
6950
  }
6737
6951
 
6738
6952
  // src/services/file-ops.service.ts
6739
- var fs10 = __toESM(require("fs/promises"));
6740
- var path13 = __toESM(require("path"));
6953
+ var fs12 = __toESM(require("fs/promises"));
6954
+ var path15 = __toESM(require("path"));
6741
6955
  var MAX_FILE_BYTES = 5 * 1024 * 1024;
6742
6956
  var MAX_WALK_DEPTH = 6;
6743
6957
  var MAX_VISITED_DIRS = 5e3;
@@ -6772,12 +6986,12 @@ var SUBDIR_IGNORE = /* @__PURE__ */ new Set([
6772
6986
  "__pycache__"
6773
6987
  ]);
6774
6988
  function isUnder(parent, candidate) {
6775
- const rel = path13.relative(parent, candidate);
6776
- return rel === "" || !rel.startsWith("..") && !path13.isAbsolute(rel);
6989
+ const rel = path15.relative(parent, candidate);
6990
+ return rel === "" || !rel.startsWith("..") && !path15.isAbsolute(rel);
6777
6991
  }
6778
6992
  async function isExistingFile(absPath) {
6779
6993
  try {
6780
- const stat3 = await fs10.stat(absPath);
6994
+ const stat3 = await fs12.stat(absPath);
6781
6995
  return stat3.isFile();
6782
6996
  } catch {
6783
6997
  return false;
@@ -6790,13 +7004,13 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
6790
7004
  ctx.visited++;
6791
7005
  let entries = [];
6792
7006
  try {
6793
- entries = await fs10.readdir(dir, { withFileTypes: true });
7007
+ entries = await fs12.readdir(dir, { withFileTypes: true });
6794
7008
  } catch {
6795
7009
  return;
6796
7010
  }
6797
7011
  for (const e of entries) {
6798
7012
  if (!e.isFile()) continue;
6799
- const full = path13.join(dir, e.name);
7013
+ const full = path15.join(dir, e.name);
6800
7014
  if (needleVariants.some((needle) => full.endsWith(needle))) {
6801
7015
  ctx.matches.push(full);
6802
7016
  if (ctx.matches.length >= ctx.cap) return;
@@ -6806,21 +7020,21 @@ async function walkForSuffix(dir, needleVariants, depth, ctx) {
6806
7020
  if (!e.isDirectory()) continue;
6807
7021
  if (SUBDIR_IGNORE.has(e.name)) continue;
6808
7022
  if (e.name.startsWith(".") && SUBDIR_IGNORE.has(e.name)) continue;
6809
- await walkForSuffix(path13.join(dir, e.name), needleVariants, depth + 1, ctx);
7023
+ await walkForSuffix(path15.join(dir, e.name), needleVariants, depth + 1, ctx);
6810
7024
  if (ctx.matches.length >= ctx.cap) return;
6811
7025
  }
6812
7026
  }
6813
7027
  async function findFile(rawPath) {
6814
7028
  const cwd = process.cwd();
6815
- if (path13.isAbsolute(rawPath)) {
6816
- const abs = path13.normalize(rawPath);
7029
+ if (path15.isAbsolute(rawPath)) {
7030
+ const abs = path15.normalize(rawPath);
6817
7031
  if (isUnder(cwd, abs) && await isExistingFile(abs)) return abs;
6818
7032
  }
6819
- const direct = path13.resolve(cwd, rawPath);
7033
+ const direct = path15.resolve(cwd, rawPath);
6820
7034
  if (isUnder(cwd, direct) && await isExistingFile(direct)) return direct;
6821
- const normalized = path13.normalize(rawPath).replace(/^[./\\]+/, "");
7035
+ const normalized = path15.normalize(rawPath).replace(/^[./\\]+/, "");
6822
7036
  const needles = [
6823
- `${path13.sep}${normalized}`,
7037
+ `${path15.sep}${normalized}`,
6824
7038
  `/${normalized}`
6825
7039
  ].filter((v, i, a) => a.indexOf(v) === i);
6826
7040
  const ctx = { visited: 0, matches: [], cap: 16 };
@@ -6834,7 +7048,7 @@ async function findWriteTarget(rawPath) {
6834
7048
  const found = await findFile(rawPath);
6835
7049
  if (found) return found;
6836
7050
  const cwd = process.cwd();
6837
- const fallback = path13.isAbsolute(rawPath) ? path13.normalize(rawPath) : path13.resolve(cwd, rawPath);
7051
+ const fallback = path15.isAbsolute(rawPath) ? path15.normalize(rawPath) : path15.resolve(cwd, rawPath);
6838
7052
  if (!isUnder(cwd, fallback)) return null;
6839
7053
  return fallback;
6840
7054
  }
@@ -6851,11 +7065,11 @@ async function readProjectFile(rawPath) {
6851
7065
  if (!abs) {
6852
7066
  return { error: `File not found in the project tree: ${rawPath}` };
6853
7067
  }
6854
- const stat3 = await fs10.stat(abs);
7068
+ const stat3 = await fs12.stat(abs);
6855
7069
  if (stat3.size > MAX_FILE_BYTES) {
6856
7070
  return { error: `File too large (${(stat3.size / 1024 / 1024).toFixed(1)} MB > ${MAX_FILE_BYTES / 1024 / 1024} MB).` };
6857
7071
  }
6858
- const buf = await fs10.readFile(abs);
7072
+ const buf = await fs12.readFile(abs);
6859
7073
  if (looksBinary(buf)) {
6860
7074
  return { error: "Binary file \u2014 refusing to open in a code editor." };
6861
7075
  }
@@ -6874,8 +7088,8 @@ async function writeProjectFile(rawPath, content) {
6874
7088
  if (Buffer.byteLength(content, "utf-8") > MAX_FILE_BYTES) {
6875
7089
  return { error: "Content too large." };
6876
7090
  }
6877
- await fs10.mkdir(path13.dirname(abs), { recursive: true });
6878
- await fs10.writeFile(abs, content, "utf-8");
7091
+ await fs12.mkdir(path15.dirname(abs), { recursive: true });
7092
+ await fs12.writeFile(abs, content, "utf-8");
6879
7093
  return { ok: true };
6880
7094
  } catch (e) {
6881
7095
  const msg = e instanceof Error ? e.message : "Write failed";
@@ -6886,8 +7100,8 @@ async function writeProjectFile(rawPath, content) {
6886
7100
  // src/services/project-ops.service.ts
6887
7101
  var import_child_process7 = require("child_process");
6888
7102
  var import_util2 = require("util");
6889
- var fs11 = __toESM(require("fs/promises"));
6890
- var path14 = __toESM(require("path"));
7103
+ var fs13 = __toESM(require("fs/promises"));
7104
+ var path16 = __toESM(require("path"));
6891
7105
  var execFileP2 = (0, import_util2.promisify)(import_child_process7.execFile);
6892
7106
  var PROJECT_IGNORE = /* @__PURE__ */ new Set([
6893
7107
  "node_modules",
@@ -6935,7 +7149,7 @@ async function listProjectFiles(opts = {}) {
6935
7149
  }
6936
7150
  let entries = [];
6937
7151
  try {
6938
- entries = await fs11.readdir(dir, { withFileTypes: true });
7152
+ entries = await fs13.readdir(dir, { withFileTypes: true });
6939
7153
  } catch {
6940
7154
  return;
6941
7155
  }
@@ -6945,18 +7159,18 @@ async function listProjectFiles(opts = {}) {
6945
7159
  return;
6946
7160
  }
6947
7161
  if (PROJECT_IGNORE.has(e.name)) continue;
6948
- const full = path14.join(dir, e.name);
7162
+ const full = path16.join(dir, e.name);
6949
7163
  if (e.isDirectory()) {
6950
7164
  if (depth >= 12) continue;
6951
7165
  await walk(full, depth + 1);
6952
7166
  } else if (e.isFile()) {
6953
- const rel = path14.relative(root, full);
7167
+ const rel = path16.relative(root, full);
6954
7168
  if (q2 && !rel.toLowerCase().includes(q2) && !e.name.toLowerCase().includes(q2)) {
6955
7169
  continue;
6956
7170
  }
6957
7171
  let size = 0;
6958
7172
  try {
6959
- const st3 = await fs11.stat(full);
7173
+ const st3 = await fs13.stat(full);
6960
7174
  size = st3.size;
6961
7175
  } catch {
6962
7176
  }
@@ -7058,8 +7272,8 @@ async function gitStatus(cwd) {
7058
7272
  let hasMergeInProgress = false;
7059
7273
  try {
7060
7274
  const gitDir = (await git(["rev-parse", "--git-dir"], root)).stdout.trim();
7061
- const mergeHead = path14.isAbsolute(gitDir) ? path14.join(gitDir, "MERGE_HEAD") : path14.join(root, gitDir, "MERGE_HEAD");
7062
- await fs11.access(mergeHead);
7275
+ const mergeHead = path16.isAbsolute(gitDir) ? path16.join(gitDir, "MERGE_HEAD") : path16.join(root, gitDir, "MERGE_HEAD");
7276
+ await fs13.access(mergeHead);
7063
7277
  hasMergeInProgress = true;
7064
7278
  } catch {
7065
7279
  }
@@ -7136,8 +7350,8 @@ async function gitResolve(file, side, cwd) {
7136
7350
  function saveFilesTemp(files) {
7137
7351
  return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
7138
7352
  const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
7139
- const tmpPath = path15.join(os11.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
7140
- fs12.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
7353
+ const tmpPath = path17.join(os13.tmpdir(), `codeam-${(0, import_crypto.randomUUID)()}-${safeName}`);
7354
+ fs14.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
7141
7355
  return tmpPath;
7142
7356
  });
7143
7357
  }
@@ -7156,7 +7370,7 @@ var startTask = (ctx, _cmd, parsed) => {
7156
7370
  setTimeout(() => {
7157
7371
  for (const p2 of paths) {
7158
7372
  try {
7159
- fs12.unlinkSync(p2);
7373
+ fs14.unlinkSync(p2);
7160
7374
  } catch {
7161
7375
  }
7162
7376
  }
@@ -7615,8 +7829,8 @@ async function pair(args2 = []) {
7615
7829
  }
7616
7830
 
7617
7831
  // src/commands/pair-auto.ts
7618
- var fs13 = __toESM(require("fs"));
7619
- var os12 = __toESM(require("os"));
7832
+ var fs15 = __toESM(require("fs"));
7833
+ var os14 = __toESM(require("os"));
7620
7834
  var import_crypto3 = require("crypto");
7621
7835
  var API_BASE5 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
7622
7836
  function fail(msg) {
@@ -7633,12 +7847,12 @@ function readTokenFromArgs(args2) {
7633
7847
  }
7634
7848
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
7635
7849
  if (fileFlag) {
7636
- const path21 = fileFlag.slice("--token-file=".length);
7850
+ const path23 = fileFlag.slice("--token-file=".length);
7637
7851
  try {
7638
- const content = fs13.readFileSync(path21, "utf8").trim();
7639
- if (content.length === 0) fail(`--token-file ${path21} is empty`);
7852
+ const content = fs15.readFileSync(path23, "utf8").trim();
7853
+ if (content.length === 0) fail(`--token-file ${path23} is empty`);
7640
7854
  try {
7641
- fs13.unlinkSync(path21);
7855
+ fs15.unlinkSync(path23);
7642
7856
  } catch {
7643
7857
  }
7644
7858
  return content;
@@ -7656,7 +7870,7 @@ async function claim(token, pluginId) {
7656
7870
  pluginId,
7657
7871
  ideName: "codeam-cli (codespace)",
7658
7872
  ideVersion: process.env.npm_package_version ?? "unknown",
7659
- hostname: os12.hostname(),
7873
+ hostname: os14.hostname(),
7660
7874
  codespaceName: process.env.CODESPACE_NAME ?? ""
7661
7875
  };
7662
7876
  const res = await fetch(url, {
@@ -7808,7 +8022,7 @@ var import_picocolors9 = __toESM(require("picocolors"));
7808
8022
  var import_child_process9 = require("child_process");
7809
8023
  var import_util3 = require("util");
7810
8024
  var import_picocolors7 = __toESM(require("picocolors"));
7811
- var path16 = __toESM(require("path"));
8025
+ var path18 = __toESM(require("path"));
7812
8026
  var execFileP3 = (0, import_util3.promisify)(import_child_process9.execFile);
7813
8027
  var MAX_BUFFER = 8 * 1024 * 1024;
7814
8028
  function resetStdinForChild() {
@@ -8297,7 +8511,7 @@ var GitHubCodespacesProvider = class {
8297
8511
  });
8298
8512
  }
8299
8513
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
8300
- const remoteDir = path16.posix.dirname(remotePath);
8514
+ const remoteDir = path18.posix.dirname(remotePath);
8301
8515
  const parts = [
8302
8516
  `mkdir -p ${shellQuote(remoteDir)}`,
8303
8517
  `cat > ${shellQuote(remotePath)}`
@@ -8367,7 +8581,7 @@ function shellQuote(s) {
8367
8581
  // src/services/providers/gitpod.ts
8368
8582
  var import_child_process10 = require("child_process");
8369
8583
  var import_util4 = require("util");
8370
- var path17 = __toESM(require("path"));
8584
+ var path19 = __toESM(require("path"));
8371
8585
  var import_picocolors8 = __toESM(require("picocolors"));
8372
8586
  var execFileP4 = (0, import_util4.promisify)(import_child_process10.execFile);
8373
8587
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -8607,7 +8821,7 @@ var GitpodProvider = class {
8607
8821
  });
8608
8822
  }
8609
8823
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
8610
- const remoteDir = path17.posix.dirname(remotePath);
8824
+ const remoteDir = path19.posix.dirname(remotePath);
8611
8825
  const parts = [
8612
8826
  `mkdir -p ${shellQuote2(remoteDir)}`,
8613
8827
  `cat > ${shellQuote2(remotePath)}`
@@ -8643,7 +8857,7 @@ function shellQuote2(s) {
8643
8857
  // src/services/providers/gitlab-workspaces.ts
8644
8858
  var import_child_process11 = require("child_process");
8645
8859
  var import_util5 = require("util");
8646
- var path18 = __toESM(require("path"));
8860
+ var path20 = __toESM(require("path"));
8647
8861
  var execFileP5 = (0, import_util5.promisify)(import_child_process11.execFile);
8648
8862
  var MAX_BUFFER3 = 8 * 1024 * 1024;
8649
8863
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -8903,7 +9117,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
8903
9117
  }
8904
9118
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
8905
9119
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
8906
- const remoteDir = path18.posix.dirname(remotePath);
9120
+ const remoteDir = path20.posix.dirname(remotePath);
8907
9121
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
8908
9122
  if (options.mode != null) {
8909
9123
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -8971,7 +9185,7 @@ function shellQuote3(s) {
8971
9185
  // src/services/providers/railway.ts
8972
9186
  var import_child_process12 = require("child_process");
8973
9187
  var import_util6 = require("util");
8974
- var path19 = __toESM(require("path"));
9188
+ var path21 = __toESM(require("path"));
8975
9189
  var execFileP6 = (0, import_util6.promisify)(import_child_process12.execFile);
8976
9190
  var MAX_BUFFER4 = 8 * 1024 * 1024;
8977
9191
  function resetStdinForChild4() {
@@ -9207,7 +9421,7 @@ var RailwayProvider = class {
9207
9421
  if (!projectId || !serviceId) {
9208
9422
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
9209
9423
  }
9210
- const remoteDir = path19.posix.dirname(remotePath);
9424
+ const remoteDir = path21.posix.dirname(remotePath);
9211
9425
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
9212
9426
  if (options.mode != null) {
9213
9427
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -9749,7 +9963,7 @@ async function stopWorkspaceFromLocal(target) {
9749
9963
  // src/commands/version.ts
9750
9964
  var import_picocolors11 = __toESM(require("picocolors"));
9751
9965
  function version() {
9752
- const v = true ? "2.11.0" : "unknown";
9966
+ const v = true ? "2.12.0" : "unknown";
9753
9967
  console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
9754
9968
  }
9755
9969
 
@@ -9786,9 +10000,9 @@ function help() {
9786
10000
  }
9787
10001
 
9788
10002
  // src/lib/updateNotifier.ts
9789
- var fs14 = __toESM(require("fs"));
9790
- var os13 = __toESM(require("os"));
9791
- var path20 = __toESM(require("path"));
10003
+ var fs16 = __toESM(require("fs"));
10004
+ var os15 = __toESM(require("os"));
10005
+ var path22 = __toESM(require("path"));
9792
10006
  var https5 = __toESM(require("https"));
9793
10007
  var import_picocolors13 = __toESM(require("picocolors"));
9794
10008
  var PKG_NAME = "codeam-cli";
@@ -9796,12 +10010,12 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
9796
10010
  var TTL_MS = 24 * 60 * 60 * 1e3;
9797
10011
  var REQUEST_TIMEOUT_MS = 1500;
9798
10012
  function cachePath() {
9799
- const dir = path20.join(os13.homedir(), ".codeam");
9800
- return path20.join(dir, "update-check.json");
10013
+ const dir = path22.join(os15.homedir(), ".codeam");
10014
+ return path22.join(dir, "update-check.json");
9801
10015
  }
9802
10016
  function readCache() {
9803
10017
  try {
9804
- const raw = fs14.readFileSync(cachePath(), "utf8");
10018
+ const raw = fs16.readFileSync(cachePath(), "utf8");
9805
10019
  const parsed = JSON.parse(raw);
9806
10020
  if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
9807
10021
  return parsed;
@@ -9812,8 +10026,8 @@ function readCache() {
9812
10026
  function writeCache(cache) {
9813
10027
  try {
9814
10028
  const file = cachePath();
9815
- fs14.mkdirSync(path20.dirname(file), { recursive: true });
9816
- fs14.writeFileSync(file, JSON.stringify(cache));
10029
+ fs16.mkdirSync(path22.dirname(file), { recursive: true });
10030
+ fs16.writeFileSync(file, JSON.stringify(cache));
9817
10031
  } catch {
9818
10032
  }
9819
10033
  }
@@ -9884,7 +10098,7 @@ function checkForUpdates() {
9884
10098
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
9885
10099
  if (process.env.CI) return;
9886
10100
  if (!process.stdout.isTTY) return;
9887
- const current = true ? "2.11.0" : null;
10101
+ const current = true ? "2.12.0" : null;
9888
10102
  if (!current) return;
9889
10103
  const cache = readCache();
9890
10104
  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.11.0",
3
+ "version": "2.12.0",
4
4
  "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 — from anywhere.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",