codeam-cli 2.39.36 → 2.39.37
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 +6 -0
- package/dist/index.js +52 -107
- package/package.json +1 -1
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.39.36] — 2026-06-18
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Preview dev-server run command rewrites pnpm/bun → npm run
|
|
12
|
+
|
|
7
13
|
## [2.39.35] — 2026-06-18
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
498
498
|
// package.json
|
|
499
499
|
var package_default = {
|
|
500
500
|
name: "codeam-cli",
|
|
501
|
-
version: "2.39.
|
|
501
|
+
version: "2.39.37",
|
|
502
502
|
description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
|
|
503
503
|
type: "commonjs",
|
|
504
504
|
main: "dist/index.js",
|
|
@@ -5908,7 +5908,7 @@ function readAnonId() {
|
|
|
5908
5908
|
}
|
|
5909
5909
|
function superProperties() {
|
|
5910
5910
|
return {
|
|
5911
|
-
cliVersion: true ? "2.39.
|
|
5911
|
+
cliVersion: true ? "2.39.37" : "0.0.0-dev",
|
|
5912
5912
|
nodeVersion: process.version,
|
|
5913
5913
|
platform: process.platform,
|
|
5914
5914
|
arch: process.arch,
|
|
@@ -16538,34 +16538,6 @@ function downloadUrlForPlatform() {
|
|
|
16538
16538
|
var import_child_process11 = require("child_process");
|
|
16539
16539
|
var import_util3 = require("util");
|
|
16540
16540
|
var execFileP4 = (0, import_util3.promisify)(import_child_process11.execFile);
|
|
16541
|
-
function isCodespaceSession(env = process.env) {
|
|
16542
|
-
return Boolean(env.CODESPACE_NAME);
|
|
16543
|
-
}
|
|
16544
|
-
function buildCodespaceUrl(codespaceName, port) {
|
|
16545
|
-
return `https://${codespaceName}-${port}.app.github.dev`;
|
|
16546
|
-
}
|
|
16547
|
-
async function setPortPublic(codespaceName, port) {
|
|
16548
|
-
await execFileP4("gh", [
|
|
16549
|
-
"codespace",
|
|
16550
|
-
"ports",
|
|
16551
|
-
"visibility",
|
|
16552
|
-
`${port}:public`,
|
|
16553
|
-
"-c",
|
|
16554
|
-
codespaceName
|
|
16555
|
-
]);
|
|
16556
|
-
}
|
|
16557
|
-
async function waitForCodespacePortReady(url, timeoutMs = 15e3) {
|
|
16558
|
-
const start2 = Date.now();
|
|
16559
|
-
while (Date.now() - start2 < timeoutMs) {
|
|
16560
|
-
try {
|
|
16561
|
-
const res = await fetch(url, { method: "HEAD" });
|
|
16562
|
-
if (res.status < 500) return;
|
|
16563
|
-
} catch {
|
|
16564
|
-
}
|
|
16565
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
16566
|
-
}
|
|
16567
|
-
throw new Error(`Codespace forwarded URL ${url} not reachable after ${timeoutMs}ms.`);
|
|
16568
|
-
}
|
|
16569
16541
|
|
|
16570
16542
|
// src/services/preview/config-file.ts
|
|
16571
16543
|
var import_promises4 = __toESM(require("fs/promises"));
|
|
@@ -19115,7 +19087,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
19115
19087
|
emitProgress("READY_DETECTED", `port ${detection.port}`);
|
|
19116
19088
|
emitProgress(
|
|
19117
19089
|
"TUNNEL_STARTING",
|
|
19118
|
-
detection.framework === "Expo" ? "Expo (self-tunnelled)" :
|
|
19090
|
+
detection.framework === "Expo" ? "Expo (self-tunnelled)" : "cloudflared quick tunnel"
|
|
19119
19091
|
);
|
|
19120
19092
|
let tunnel = null;
|
|
19121
19093
|
let url;
|
|
@@ -19141,41 +19113,6 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
19141
19113
|
return;
|
|
19142
19114
|
}
|
|
19143
19115
|
url = expoUrl;
|
|
19144
|
-
} else if (isCodespaceSession()) {
|
|
19145
|
-
const codespaceName = process.env.CODESPACE_NAME;
|
|
19146
|
-
try {
|
|
19147
|
-
await setPortPublic(codespaceName, detection.port);
|
|
19148
|
-
} catch (e) {
|
|
19149
|
-
try {
|
|
19150
|
-
devServer.kill("SIGTERM");
|
|
19151
|
-
} catch {
|
|
19152
|
-
}
|
|
19153
|
-
void postPreviewEvent({
|
|
19154
|
-
sessionId: ctx.sessionId,
|
|
19155
|
-
pluginId: ctx.pluginId,
|
|
19156
|
-
pluginAuthToken,
|
|
19157
|
-
type: "preview_error",
|
|
19158
|
-
payload: { stage: "tunnel", message: `Failed to flip port public: ${e.message}` }
|
|
19159
|
-
});
|
|
19160
|
-
return;
|
|
19161
|
-
}
|
|
19162
|
-
url = buildCodespaceUrl(codespaceName, detection.port);
|
|
19163
|
-
try {
|
|
19164
|
-
await waitForCodespacePortReady(url, 15e3);
|
|
19165
|
-
} catch (e) {
|
|
19166
|
-
try {
|
|
19167
|
-
devServer.kill("SIGTERM");
|
|
19168
|
-
} catch {
|
|
19169
|
-
}
|
|
19170
|
-
void postPreviewEvent({
|
|
19171
|
-
sessionId: ctx.sessionId,
|
|
19172
|
-
pluginId: ctx.pluginId,
|
|
19173
|
-
pluginAuthToken,
|
|
19174
|
-
type: "preview_error",
|
|
19175
|
-
payload: { stage: "tunnel", message: e.message }
|
|
19176
|
-
});
|
|
19177
|
-
return;
|
|
19178
|
-
}
|
|
19179
19116
|
} else {
|
|
19180
19117
|
let bin;
|
|
19181
19118
|
try {
|
|
@@ -19194,48 +19131,56 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
19194
19131
|
});
|
|
19195
19132
|
return;
|
|
19196
19133
|
}
|
|
19197
|
-
|
|
19198
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
19199
|
-
});
|
|
19134
|
+
const MAX_TUNNEL_ATTEMPTS = 3;
|
|
19200
19135
|
let parsedUrl = null;
|
|
19201
|
-
|
|
19202
|
-
|
|
19203
|
-
if (
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
|
|
19208
|
-
tunnel.stdout.on("data", onTunnelChunk);
|
|
19209
|
-
const tunnelDeadline = Date.now() + 45e3;
|
|
19210
|
-
while (!parsedUrl && Date.now() < tunnelDeadline) {
|
|
19211
|
-
await new Promise((r) => setTimeout(r, 250));
|
|
19212
|
-
}
|
|
19213
|
-
if (!parsedUrl) {
|
|
19214
|
-
try {
|
|
19215
|
-
tunnel.kill("SIGTERM");
|
|
19216
|
-
} catch {
|
|
19136
|
+
let lastTunnelErr = "cloudflared did not emit a URL within 45s";
|
|
19137
|
+
for (let attempt = 1; attempt <= MAX_TUNNEL_ATTEMPTS && !parsedUrl; attempt += 1) {
|
|
19138
|
+
if (attempt > 1) {
|
|
19139
|
+
emitProgress(
|
|
19140
|
+
"TUNNEL_STARTING",
|
|
19141
|
+
`cloudflared quick tunnel (retry ${attempt}/${MAX_TUNNEL_ATTEMPTS})`
|
|
19142
|
+
);
|
|
19217
19143
|
}
|
|
19218
|
-
|
|
19219
|
-
|
|
19220
|
-
|
|
19144
|
+
const candidate = (0, import_child_process18.spawn)(
|
|
19145
|
+
bin,
|
|
19146
|
+
["tunnel", "--url", `http://localhost:${detection.port}`],
|
|
19147
|
+
{ stdio: ["ignore", "pipe", "pipe"] }
|
|
19148
|
+
);
|
|
19149
|
+
let candidateUrl = null;
|
|
19150
|
+
const onTunnelChunk = (chunk) => {
|
|
19151
|
+
const s = chunk.toString();
|
|
19152
|
+
if (!candidateUrl) candidateUrl = parseCloudflaredUrl(s);
|
|
19153
|
+
const trimmed = s.replace(/\n+$/g, "");
|
|
19154
|
+
if (trimmed.length > 0) log.info("preview", `cloudflared: ${trimmed}`);
|
|
19155
|
+
};
|
|
19156
|
+
candidate.stderr.on("data", onTunnelChunk);
|
|
19157
|
+
candidate.stdout.on("data", onTunnelChunk);
|
|
19158
|
+
const urlDeadline = Date.now() + 45e3;
|
|
19159
|
+
while (!candidateUrl && Date.now() < urlDeadline) {
|
|
19160
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
19161
|
+
}
|
|
19162
|
+
if (!candidateUrl) {
|
|
19163
|
+
lastTunnelErr = "cloudflared did not emit a URL within 45s";
|
|
19164
|
+
try {
|
|
19165
|
+
candidate.kill("SIGTERM");
|
|
19166
|
+
} catch {
|
|
19167
|
+
}
|
|
19168
|
+
continue;
|
|
19221
19169
|
}
|
|
19222
|
-
void postPreviewEvent({
|
|
19223
|
-
sessionId: ctx.sessionId,
|
|
19224
|
-
pluginId: ctx.pluginId,
|
|
19225
|
-
pluginAuthToken,
|
|
19226
|
-
type: "preview_error",
|
|
19227
|
-
payload: { stage: "tunnel", message: "cloudflared did not emit a URL within 45s." }
|
|
19228
|
-
});
|
|
19229
|
-
return;
|
|
19230
|
-
}
|
|
19231
|
-
try {
|
|
19232
|
-
await waitForCloudflaredReady(parsedUrl, 6e4);
|
|
19233
|
-
log.info("preview", `cloudflared probe: ${parsedUrl} reachable from CLI host`);
|
|
19234
|
-
} catch (e) {
|
|
19235
19170
|
try {
|
|
19236
|
-
|
|
19237
|
-
|
|
19171
|
+
await waitForCloudflaredReady(candidateUrl, 4e4);
|
|
19172
|
+
log.info("preview", `cloudflared probe: ${candidateUrl} reachable from CLI host`);
|
|
19173
|
+
tunnel = candidate;
|
|
19174
|
+
parsedUrl = candidateUrl;
|
|
19175
|
+
} catch (e) {
|
|
19176
|
+
lastTunnelErr = e.message;
|
|
19177
|
+
try {
|
|
19178
|
+
candidate.kill("SIGTERM");
|
|
19179
|
+
} catch {
|
|
19180
|
+
}
|
|
19238
19181
|
}
|
|
19182
|
+
}
|
|
19183
|
+
if (!parsedUrl) {
|
|
19239
19184
|
try {
|
|
19240
19185
|
devServer.kill("SIGTERM");
|
|
19241
19186
|
} catch {
|
|
@@ -19247,7 +19192,7 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
19247
19192
|
type: "preview_error",
|
|
19248
19193
|
payload: {
|
|
19249
19194
|
stage: "tunnel",
|
|
19250
|
-
message: `Tunnel
|
|
19195
|
+
message: `Tunnel did not become reachable after ${MAX_TUNNEL_ATTEMPTS} attempts (${lastTunnelErr}). Cloudflare Quick Tunnels occasionally fail to register \u2014 please retry.`
|
|
19251
19196
|
}
|
|
19252
19197
|
});
|
|
19253
19198
|
return;
|
|
@@ -27187,7 +27132,7 @@ function checkChokidar() {
|
|
|
27187
27132
|
}
|
|
27188
27133
|
async function doctor(args2 = []) {
|
|
27189
27134
|
const json = args2.includes("--json");
|
|
27190
|
-
const cliVersion = true ? "2.39.
|
|
27135
|
+
const cliVersion = true ? "2.39.37" : "0.0.0-dev";
|
|
27191
27136
|
const apiBase2 = resolveApiBaseUrl();
|
|
27192
27137
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
27193
27138
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -27386,7 +27331,7 @@ async function completion(args2) {
|
|
|
27386
27331
|
// src/commands/version.ts
|
|
27387
27332
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
27388
27333
|
function version2() {
|
|
27389
|
-
const v = true ? "2.39.
|
|
27334
|
+
const v = true ? "2.39.37" : "unknown";
|
|
27390
27335
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
27391
27336
|
}
|
|
27392
27337
|
|
|
@@ -27672,7 +27617,7 @@ function checkForUpdates() {
|
|
|
27672
27617
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
27673
27618
|
if (process.env.CI) return;
|
|
27674
27619
|
if (!process.stdout.isTTY) return;
|
|
27675
|
-
const current = true ? "2.39.
|
|
27620
|
+
const current = true ? "2.39.37" : null;
|
|
27676
27621
|
if (!current) return;
|
|
27677
27622
|
const cache = readCache();
|
|
27678
27623
|
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.39.
|
|
3
|
+
"version": "2.39.37",
|
|
4
4
|
"description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "dist/index.js",
|