codeam-cli 2.4.3 → 2.4.5

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,18 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.4.3] — 2026-05-03
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Refresh missing `codespace` scope on existing gh logins (v2.4.3)
12
+
13
+ ## [2.4.2] — 2026-05-03
14
+
15
+ ### Fixed
16
+
17
+ - **cli:** Codespace machine picker + auto-install gh; deploy doc (v2.4.2)
18
+
7
19
  ## [2.4.1] — 2026-05-03
8
20
 
9
21
  ### Added
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.3",
182
+ version: "2.4.5",
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: {
@@ -5088,6 +5088,14 @@ var import_util2 = require("util");
5088
5088
  var import_picocolors7 = __toESM(require("picocolors"));
5089
5089
  var execFileP2 = (0, import_util2.promisify)(import_child_process5.execFile);
5090
5090
  var MAX_BUFFER = 8 * 1024 * 1024;
5091
+ function resetStdinForChild() {
5092
+ if (process.stdin.isTTY) {
5093
+ try {
5094
+ process.stdin.setRawMode(false);
5095
+ } catch {
5096
+ }
5097
+ }
5098
+ }
5091
5099
  var GitHubCodespacesProvider = class {
5092
5100
  id = "github-codespaces";
5093
5101
  displayName = "GitHub Codespaces";
@@ -5120,6 +5128,7 @@ var GitHubCodespacesProvider = class {
5120
5128
  } catch {
5121
5129
  }
5122
5130
  if (!isAuthed) {
5131
+ resetStdinForChild();
5123
5132
  await new Promise((resolve2, reject) => {
5124
5133
  const proc = (0, import_child_process5.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
5125
5134
  stdio: "inherit"
@@ -5134,26 +5143,71 @@ var GitHubCodespacesProvider = class {
5134
5143
  }
5135
5144
  const hasScope = await this.hasCodespaceScope();
5136
5145
  if (!hasScope) {
5137
- wt(
5138
- [
5139
- "Your existing GitHub login is missing the `codespace` scope.",
5140
- "I'll run `gh auth refresh` to add it \u2014 your browser will open",
5141
- "for a one-tap approval."
5142
- ].join("\n"),
5143
- "One more permission needed"
5144
- );
5145
- await new Promise((resolve2, reject) => {
5146
+ const expectedUser = await this.getActiveGhUser();
5147
+ const noteLines = [
5148
+ "Your existing GitHub login is missing the `codespace` scope.",
5149
+ "I'll run `gh auth refresh` to add it \u2014 your browser will open",
5150
+ "for a one-tap approval."
5151
+ ];
5152
+ if (expectedUser) {
5153
+ noteLines.push("");
5154
+ noteLines.push(
5155
+ `${import_picocolors7.default.yellow("\u26A0")} Sign in as ${import_picocolors7.default.cyan(expectedUser)} in the browser.`
5156
+ );
5157
+ noteLines.push(
5158
+ " If a different GitHub account is already signed in, sign out"
5159
+ );
5160
+ noteLines.push(
5161
+ " of it first \u2014 or open the URL in an incognito/private window."
5162
+ );
5163
+ }
5164
+ wt(noteLines.join("\n"), "One more permission needed");
5165
+ resetStdinForChild();
5166
+ const refreshCode = await new Promise((resolve2, reject) => {
5146
5167
  const proc = (0, import_child_process5.spawn)(
5147
5168
  "gh",
5148
5169
  ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
5149
5170
  { stdio: "inherit" }
5150
5171
  );
5151
- proc.on("exit", (code) => {
5152
- if (code === 0) resolve2();
5153
- else reject(new Error("gh auth refresh failed \u2014 re-run `gh auth refresh -h github.com -s codespace` manually."));
5154
- });
5172
+ proc.on("exit", (code) => resolve2(code ?? 1));
5155
5173
  proc.on("error", reject);
5156
5174
  });
5175
+ if (refreshCode !== 0) {
5176
+ const lines = [
5177
+ "The browser approval came back for a different GitHub account",
5178
+ `than the one gh is configured for${expectedUser ? ` (${import_picocolors7.default.cyan(expectedUser)})` : ""}.`,
5179
+ "",
5180
+ "To recover:",
5181
+ " 1. Open https://github.com and sign out of any non-target",
5182
+ ` account${expectedUser ? ` (or open the URL in an incognito window)` : ""}.`,
5183
+ " 2. Re-run codeam deploy.",
5184
+ "",
5185
+ "You can also grant the scope manually first and skip this step",
5186
+ "on the next run:",
5187
+ ` ${import_picocolors7.default.cyan("gh auth refresh -h github.com -s codespace")}`
5188
+ ];
5189
+ throw new Error(lines.join("\n"));
5190
+ }
5191
+ }
5192
+ }
5193
+ /**
5194
+ * Return the GitHub login that the current `gh` token belongs to,
5195
+ * or `null` if the call fails. Used to tell the user which account
5196
+ * they need to authenticate as in the browser when refreshing
5197
+ * scopes — multi-account browser sessions are the #1 cause of
5198
+ * `gh auth refresh` failures.
5199
+ */
5200
+ async getActiveGhUser() {
5201
+ try {
5202
+ const { stdout } = await execFileP2(
5203
+ "gh",
5204
+ ["api", "user", "--jq", ".login"],
5205
+ { maxBuffer: MAX_BUFFER }
5206
+ );
5207
+ const login = stdout.trim();
5208
+ return login.length > 0 ? login : null;
5209
+ } catch {
5210
+ return null;
5157
5211
  }
5158
5212
  }
5159
5213
  /**
@@ -5257,15 +5311,15 @@ var GitHubCodespacesProvider = class {
5257
5311
  initialValue: true
5258
5312
  });
5259
5313
  if (q(proceed) || !proceed) return;
5260
- const installStep = fe();
5261
- installStep.start(`Installing gh via ${installCmd.describe}\u2026`);
5314
+ O2.step(`Installing gh via ${installCmd.describe}\u2026`);
5315
+ resetStdinForChild();
5262
5316
  const ok = await new Promise((resolve2) => {
5263
5317
  const proc = (0, import_child_process5.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
5264
5318
  proc.on("exit", (code) => resolve2(code === 0));
5265
5319
  proc.on("error", () => resolve2(false));
5266
5320
  });
5267
- if (ok) installStep.stop("\u2713 gh installed");
5268
- else installStep.stop("\u2717 gh install failed");
5321
+ if (ok) O2.success("gh installed");
5322
+ else O2.error("gh install failed");
5269
5323
  }
5270
5324
  async listProjects() {
5271
5325
  const { stdout } = await execFileP2(
@@ -5406,6 +5460,7 @@ var GitHubCodespacesProvider = class {
5406
5460
  }
5407
5461
  }
5408
5462
  async streamCommand(workspaceId, command2) {
5463
+ resetStdinForChild();
5409
5464
  return new Promise((resolve2, reject) => {
5410
5465
  const proc = (0, import_child_process5.spawn)(
5411
5466
  "gh",
@@ -5443,13 +5498,12 @@ async function deploy() {
5443
5498
  pt("No provider selected.");
5444
5499
  process.exit(0);
5445
5500
  }
5446
- const authStep = fe();
5447
- authStep.start(`Authorizing with ${provider.displayName}\u2026`);
5501
+ O2.step(`Authorizing with ${provider.displayName}\u2026`);
5448
5502
  try {
5449
5503
  await provider.authorize();
5450
- authStep.stop(`\u2713 Authorized with ${provider.displayName}`);
5504
+ O2.success(`Authorized with ${provider.displayName}`);
5451
5505
  } catch (err) {
5452
- authStep.stop(`\u2717 Authorization failed`);
5506
+ O2.error("Authorization failed");
5453
5507
  pt(err instanceof Error ? err.message : String(err));
5454
5508
  process.exit(1);
5455
5509
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.4.3",
3
+ "version": "2.4.5",
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": {