codeam-cli 2.4.2 → 2.4.4

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,24 @@ 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.2] — 2026-05-03
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Codespace machine picker + auto-install gh; deploy doc (v2.4.2)
12
+
13
+ ## [2.4.1] — 2026-05-03
14
+
15
+ ### Added
16
+
17
+ - **cli:** Interactive `claude login` fallback when no local config (v2.4.1)
18
+
19
+ ## [2.4.0] — 2026-05-03
20
+
21
+ ### Added
22
+
23
+ - **cli:** `codeam deploy` — provision a paired cloud workspace in one command (v2.4.0)
24
+
7
25
  ## [2.2.2] — 2026-05-02
8
26
 
9
27
  ### 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.2",
182
+ version: "2.4.4",
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";
@@ -5113,21 +5121,72 @@ var GitHubCodespacesProvider = class {
5113
5121
  );
5114
5122
  }
5115
5123
  }
5124
+ let isAuthed = false;
5116
5125
  try {
5117
5126
  await execFileP2("gh", ["auth", "status"], { maxBuffer: MAX_BUFFER });
5118
- return;
5127
+ isAuthed = true;
5119
5128
  } catch {
5120
5129
  }
5121
- await new Promise((resolve2, reject) => {
5122
- const proc = (0, import_child_process5.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
5123
- stdio: "inherit"
5130
+ if (!isAuthed) {
5131
+ resetStdinForChild();
5132
+ await new Promise((resolve2, reject) => {
5133
+ const proc = (0, import_child_process5.spawn)("gh", ["auth", "login", "-s", "codespace,repo,read:user"], {
5134
+ stdio: "inherit"
5135
+ });
5136
+ proc.on("exit", (code) => {
5137
+ if (code === 0) resolve2();
5138
+ else reject(new Error("gh auth login failed."));
5139
+ });
5140
+ proc.on("error", reject);
5124
5141
  });
5125
- proc.on("exit", (code) => {
5126
- if (code === 0) resolve2();
5127
- else reject(new Error("gh auth login failed."));
5142
+ return;
5143
+ }
5144
+ const hasScope = await this.hasCodespaceScope();
5145
+ if (!hasScope) {
5146
+ wt(
5147
+ [
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
+ ].join("\n"),
5152
+ "One more permission needed"
5153
+ );
5154
+ resetStdinForChild();
5155
+ await new Promise((resolve2, reject) => {
5156
+ const proc = (0, import_child_process5.spawn)(
5157
+ "gh",
5158
+ ["auth", "refresh", "-h", "github.com", "-s", "codespace"],
5159
+ { stdio: "inherit" }
5160
+ );
5161
+ proc.on("exit", (code) => {
5162
+ if (code === 0) resolve2();
5163
+ else reject(new Error("gh auth refresh failed \u2014 re-run `gh auth refresh -h github.com -s codespace` manually."));
5164
+ });
5165
+ proc.on("error", reject);
5128
5166
  });
5129
- proc.on("error", reject);
5130
- });
5167
+ }
5168
+ }
5169
+ /**
5170
+ * Check whether the current `gh` token includes the `codespace`
5171
+ * OAuth scope. We hit `/user` with `-i` so GitHub echoes the granted
5172
+ * scopes back in the `X-OAuth-Scopes` response header — the most
5173
+ * authoritative source (more reliable than scraping `gh auth status`,
5174
+ * whose format has shifted across `gh` versions).
5175
+ */
5176
+ async hasCodespaceScope() {
5177
+ try {
5178
+ const { stdout } = await execFileP2(
5179
+ "gh",
5180
+ ["api", "-i", "user"],
5181
+ { maxBuffer: MAX_BUFFER }
5182
+ );
5183
+ const m = stdout.match(/^x-oauth-scopes:\s*(.+)$/im);
5184
+ if (!m) return false;
5185
+ const scopes = m[1].split(",").map((s) => s.trim().toLowerCase());
5186
+ return scopes.includes("codespace");
5187
+ } catch {
5188
+ return false;
5189
+ }
5131
5190
  }
5132
5191
  /**
5133
5192
  * Try to install the `gh` CLI for the user. Opt-in via a confirm
@@ -5208,15 +5267,15 @@ var GitHubCodespacesProvider = class {
5208
5267
  initialValue: true
5209
5268
  });
5210
5269
  if (q(proceed) || !proceed) return;
5211
- const installStep = fe();
5212
- installStep.start(`Installing gh via ${installCmd.describe}\u2026`);
5270
+ O2.step(`Installing gh via ${installCmd.describe}\u2026`);
5271
+ resetStdinForChild();
5213
5272
  const ok = await new Promise((resolve2) => {
5214
5273
  const proc = (0, import_child_process5.spawn)(installCmd.exe, installCmd.args, { stdio: "inherit" });
5215
5274
  proc.on("exit", (code) => resolve2(code === 0));
5216
5275
  proc.on("error", () => resolve2(false));
5217
5276
  });
5218
- if (ok) installStep.stop("\u2713 gh installed");
5219
- else installStep.stop("\u2717 gh install failed");
5277
+ if (ok) O2.success("gh installed");
5278
+ else O2.error("gh install failed");
5220
5279
  }
5221
5280
  async listProjects() {
5222
5281
  const { stdout } = await execFileP2(
@@ -5357,6 +5416,7 @@ var GitHubCodespacesProvider = class {
5357
5416
  }
5358
5417
  }
5359
5418
  async streamCommand(workspaceId, command2) {
5419
+ resetStdinForChild();
5360
5420
  return new Promise((resolve2, reject) => {
5361
5421
  const proc = (0, import_child_process5.spawn)(
5362
5422
  "gh",
@@ -5394,13 +5454,12 @@ async function deploy() {
5394
5454
  pt("No provider selected.");
5395
5455
  process.exit(0);
5396
5456
  }
5397
- const authStep = fe();
5398
- authStep.start(`Authorizing with ${provider.displayName}\u2026`);
5457
+ O2.step(`Authorizing with ${provider.displayName}\u2026`);
5399
5458
  try {
5400
5459
  await provider.authorize();
5401
- authStep.stop(`\u2713 Authorized with ${provider.displayName}`);
5460
+ O2.success(`Authorized with ${provider.displayName}`);
5402
5461
  } catch (err) {
5403
- authStep.stop(`\u2717 Authorization failed`);
5462
+ O2.error("Authorization failed");
5404
5463
  pt(err instanceof Error ? err.message : String(err));
5405
5464
  process.exit(1);
5406
5465
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.4.2",
3
+ "version": "2.4.4",
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": {