codeam-cli 2.4.6 → 2.4.7

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ 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.4.5] — 2026-05-03
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Clearer guidance when gh refresh hits multi-account browser (v2.4.5)
12
+
7
13
  ## [2.4.4] — 2026-05-03
8
14
 
9
15
  ### Fixed
package/dist/index.js CHANGED
@@ -179,7 +179,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
179
179
  // package.json
180
180
  var package_default = {
181
181
  name: "codeam-cli",
182
- version: "2.4.6",
182
+ version: "2.4.7",
183
183
  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.",
184
184
  main: "dist/index.js",
185
185
  bin: {
@@ -5077,15 +5077,18 @@ async function logout() {
5077
5077
  }
5078
5078
 
5079
5079
  // src/commands/deploy.ts
5080
+ var import_child_process6 = require("child_process");
5080
5081
  var fs8 = __toESM(require("fs"));
5081
5082
  var os6 = __toESM(require("os"));
5082
- var path8 = __toESM(require("path"));
5083
+ var path9 = __toESM(require("path"));
5084
+ var import_util3 = require("util");
5083
5085
  var import_picocolors8 = __toESM(require("picocolors"));
5084
5086
 
5085
5087
  // src/services/providers/github-codespaces.ts
5086
5088
  var import_child_process5 = require("child_process");
5087
5089
  var import_util2 = require("util");
5088
5090
  var import_picocolors7 = __toESM(require("picocolors"));
5091
+ var path8 = __toESM(require("path"));
5089
5092
  var execFileP2 = (0, import_util2.promisify)(import_child_process5.execFile);
5090
5093
  var MAX_BUFFER = 8 * 1024 * 1024;
5091
5094
  function resetStdinForChild() {
@@ -5471,7 +5474,12 @@ var GitHubCodespacesProvider = class {
5471
5474
  proc.on("error", reject);
5472
5475
  });
5473
5476
  }
5474
- async uploadDirectory(workspaceId, localDir, remoteDir) {
5477
+ async uploadDirectory(workspaceId, localDir, remoteDir, options = {}) {
5478
+ const tarArgs = ["-czf", "-", "-C", localDir];
5479
+ for (const pattern of options.exclude ?? []) {
5480
+ tarArgs.push(`--exclude=${pattern}`);
5481
+ }
5482
+ tarArgs.push(".");
5475
5483
  const sshArgs = [
5476
5484
  "codespace",
5477
5485
  "ssh",
@@ -5481,7 +5489,7 @@ var GitHubCodespacesProvider = class {
5481
5489
  `mkdir -p ${shellQuote(remoteDir)} && tar -xzf - -C ${shellQuote(remoteDir)}`
5482
5490
  ];
5483
5491
  await new Promise((resolve2, reject) => {
5484
- const tar = (0, import_child_process5.spawn)("tar", ["-czf", "-", "-C", localDir, "."], {
5492
+ const tar = (0, import_child_process5.spawn)("tar", tarArgs, {
5485
5493
  stdio: ["ignore", "pipe", "pipe"]
5486
5494
  });
5487
5495
  const ssh = (0, import_child_process5.spawn)("gh", sshArgs, {
@@ -5507,6 +5515,35 @@ var GitHubCodespacesProvider = class {
5507
5515
  });
5508
5516
  });
5509
5517
  }
5518
+ async uploadFile(workspaceId, remotePath, contents, options = {}) {
5519
+ const remoteDir = path8.posix.dirname(remotePath);
5520
+ const parts = [
5521
+ `mkdir -p ${shellQuote(remoteDir)}`,
5522
+ `cat > ${shellQuote(remotePath)}`
5523
+ ];
5524
+ if (options.mode != null) {
5525
+ parts.push(`chmod ${options.mode.toString(8)} ${shellQuote(remotePath)}`);
5526
+ }
5527
+ const cmd = parts.join(" && ");
5528
+ await new Promise((resolve2, reject) => {
5529
+ const proc = (0, import_child_process5.spawn)(
5530
+ "gh",
5531
+ ["codespace", "ssh", "-c", workspaceId, "--", cmd],
5532
+ { stdio: ["pipe", "pipe", "pipe"] }
5533
+ );
5534
+ let stderr = "";
5535
+ proc.stderr?.on("data", (d3) => {
5536
+ stderr += d3.toString();
5537
+ });
5538
+ proc.on("error", reject);
5539
+ proc.on("exit", (code) => {
5540
+ if (code === 0) resolve2();
5541
+ else reject(new Error(`Remote write failed: ${(stderr || `exit ${code}`).trim().slice(0, 500)}`));
5542
+ });
5543
+ proc.stdin?.write(contents);
5544
+ proc.stdin?.end();
5545
+ });
5546
+ }
5510
5547
  async listExistingWorkspaces(projectId) {
5511
5548
  try {
5512
5549
  const { stdout } = await execFileP2(
@@ -5565,6 +5602,7 @@ var PROVIDERS = [
5565
5602
  ];
5566
5603
 
5567
5604
  // src/commands/deploy.ts
5605
+ var execFileP3 = (0, import_util3.promisify)(import_child_process6.execFile);
5568
5606
  async function deploy() {
5569
5607
  console.log();
5570
5608
  mt(import_picocolors8.default.bgMagenta(import_picocolors8.default.white(" codeam deploy ")));
@@ -5711,19 +5749,74 @@ async function deploy() {
5711
5749
  process.exit(1);
5712
5750
  }
5713
5751
  claudeStep.stop("\u2713 Claude CLI installed");
5714
- const localClaudeDir = path8.join(os6.homedir(), ".claude");
5752
+ const localClaudeDir = path9.join(os6.homedir(), ".claude");
5715
5753
  const haveLocalClaude = fs8.existsSync(localClaudeDir) && fs8.statSync(localClaudeDir).isDirectory();
5716
5754
  if (haveLocalClaude) {
5717
5755
  const copyStep = fe();
5718
5756
  copyStep.start("Copying local Claude config to workspace\u2026");
5757
+ let configUploaded = false;
5719
5758
  try {
5720
- await provider.uploadDirectory(workspace.id, localClaudeDir, "/home/codespace/.claude");
5721
- copyStep.stop("\u2713 Claude config copied \u2014 no re-auth needed");
5759
+ await provider.uploadDirectory(
5760
+ workspace.id,
5761
+ localClaudeDir,
5762
+ "/home/codespace/.claude",
5763
+ {
5764
+ exclude: [
5765
+ "./projects",
5766
+ // per-project conversation history (often 700MB+)
5767
+ "./file-history",
5768
+ // per-project file diffs
5769
+ "./downloads",
5770
+ // downloaded artifacts
5771
+ "./image-cache",
5772
+ // cached images
5773
+ "./paste-cache",
5774
+ // clipboard/paste cache
5775
+ "./backups",
5776
+ // local backups
5777
+ "./shell-snapshots",
5778
+ // shell history snapshots
5779
+ "./telemetry",
5780
+ // analytics dumps
5781
+ "./statsig",
5782
+ // feature-flag cache
5783
+ "./cache",
5784
+ // generic cache dir
5785
+ "./history.jsonl",
5786
+ // global REPL history
5787
+ "./ide",
5788
+ // local IDE bridge state
5789
+ "./todos",
5790
+ // local todo state
5791
+ "./tasks"
5792
+ // local task state
5793
+ ]
5794
+ }
5795
+ );
5796
+ configUploaded = true;
5797
+ copyStep.stop("\u2713 Claude config uploaded");
5722
5798
  } catch (err) {
5723
- copyStep.stop("\u26A0 Could not copy Claude config \u2014 falling back to remote login");
5799
+ copyStep.stop("\u26A0 Could not upload Claude config \u2014 falling back to remote login");
5724
5800
  void err;
5725
5801
  await runRemoteClaudeLogin(provider, workspace.id);
5726
5802
  }
5803
+ if (configUploaded) {
5804
+ const credStep = fe();
5805
+ credStep.start("Bridging Claude credentials\u2026");
5806
+ const bridged = await bridgeClaudeCredentials(provider, workspace.id, localClaudeDir);
5807
+ switch (bridged) {
5808
+ case "flat-file":
5809
+ credStep.stop("\u2713 Credentials in tar \u2014 no re-auth needed");
5810
+ break;
5811
+ case "macos-keychain":
5812
+ credStep.stop("\u2713 Credentials extracted from macOS Keychain \u2014 no re-auth needed");
5813
+ break;
5814
+ case "none":
5815
+ credStep.stop("\u26A0 No transferable Claude credentials found \u2014 falling back to remote login");
5816
+ await runRemoteClaudeLogin(provider, workspace.id);
5817
+ break;
5818
+ }
5819
+ }
5727
5820
  } else {
5728
5821
  wt(
5729
5822
  [
@@ -5788,6 +5881,31 @@ async function runRemoteClaudeLogin(provider, workspaceId) {
5788
5881
  );
5789
5882
  }
5790
5883
  }
5884
+ async function bridgeClaudeCredentials(provider, workspaceId, localClaudeDir) {
5885
+ const fileBased = path9.join(localClaudeDir, ".credentials.json");
5886
+ if (fs8.existsSync(fileBased)) return "flat-file";
5887
+ if (process.platform === "darwin") {
5888
+ try {
5889
+ const { stdout } = await execFileP3(
5890
+ "security",
5891
+ ["find-generic-password", "-s", "Claude Code-credentials", "-w"],
5892
+ { maxBuffer: 1024 * 1024 }
5893
+ );
5894
+ const json = stdout.trim();
5895
+ if (json.length === 0) return "none";
5896
+ await provider.uploadFile(
5897
+ workspaceId,
5898
+ "/home/codespace/.claude/.credentials.json",
5899
+ json,
5900
+ { mode: 384 }
5901
+ );
5902
+ return "macos-keychain";
5903
+ } catch {
5904
+ return "none";
5905
+ }
5906
+ }
5907
+ return "none";
5908
+ }
5791
5909
  function formatLastUsed(iso) {
5792
5910
  if (!iso) return "";
5793
5911
  const t2 = Date.parse(iso);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.4.6",
3
+ "version": "2.4.7",
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
  "main": "dist/index.js",
6
6
  "bin": {