codeam-cli 2.26.10 → 2.26.12
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 +12 -0
- package/dist/index.js +69 -19
- package/dist/postinstall.js +33 -0
- package/package.json +1 -1
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.26.11] — 2026-06-03
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** Emit preview_progress SSE events at each bring-up milestone (#244)
|
|
12
|
+
|
|
13
|
+
## [2.26.10] — 2026-06-03
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Cloudflared DNS probe is best-effort, no longer fails the preview (#243)
|
|
18
|
+
|
|
7
19
|
## [2.26.9] — 2026-06-03
|
|
8
20
|
|
|
9
21
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -472,7 +472,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
472
472
|
// package.json
|
|
473
473
|
var package_default = {
|
|
474
474
|
name: "codeam-cli",
|
|
475
|
-
version: "2.26.
|
|
475
|
+
version: "2.26.12",
|
|
476
476
|
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.",
|
|
477
477
|
type: "commonjs",
|
|
478
478
|
main: "dist/index.js",
|
|
@@ -5829,7 +5829,7 @@ function readAnonId() {
|
|
|
5829
5829
|
}
|
|
5830
5830
|
function superProperties() {
|
|
5831
5831
|
return {
|
|
5832
|
-
cliVersion: true ? "2.26.
|
|
5832
|
+
cliVersion: true ? "2.26.12" : "0.0.0-dev",
|
|
5833
5833
|
nodeVersion: process.version,
|
|
5834
5834
|
platform: process.platform,
|
|
5835
5835
|
arch: process.arch,
|
|
@@ -16057,25 +16057,29 @@ async function linkDryRunPreflight(ctx) {
|
|
|
16057
16057
|
}
|
|
16058
16058
|
|
|
16059
16059
|
// src/services/preview/cloudflared.ts
|
|
16060
|
+
var import_promises = require("dns/promises");
|
|
16060
16061
|
var import_fs = require("fs");
|
|
16061
|
-
var
|
|
16062
|
+
var import_promises2 = __toESM(require("fs/promises"));
|
|
16062
16063
|
var import_os7 = __toESM(require("os"));
|
|
16063
16064
|
var import_path4 = __toESM(require("path"));
|
|
16064
|
-
var
|
|
16065
|
+
var import_promises3 = require("stream/promises");
|
|
16065
16066
|
var import_which = __toESM(require("which"));
|
|
16066
16067
|
var CACHED_BINARY = import_path4.default.join(import_os7.default.homedir(), ".codeam", "bin", "cloudflared");
|
|
16067
|
-
async function waitForCloudflaredReady(url, timeoutMs =
|
|
16068
|
+
async function waitForCloudflaredReady(url, timeoutMs = 6e4) {
|
|
16069
|
+
const hostname3 = new URL(url).hostname;
|
|
16070
|
+
const resolver = new import_promises.Resolver();
|
|
16071
|
+
resolver.setServers(["1.1.1.1", "1.0.0.1"]);
|
|
16068
16072
|
const start2 = Date.now();
|
|
16069
16073
|
while (Date.now() - start2 < timeoutMs) {
|
|
16070
16074
|
try {
|
|
16071
|
-
const
|
|
16072
|
-
if (
|
|
16075
|
+
const addrs = await resolver.resolve4(hostname3);
|
|
16076
|
+
if (addrs.length > 0) return;
|
|
16073
16077
|
} catch {
|
|
16074
16078
|
}
|
|
16075
16079
|
await new Promise((r) => setTimeout(r, 500));
|
|
16076
16080
|
}
|
|
16077
16081
|
throw new Error(
|
|
16078
|
-
`
|
|
16082
|
+
`DNS for ${hostname3} did not resolve within ${timeoutMs}ms (Cloudflare Quick Tunnel registration may have failed).`
|
|
16079
16083
|
);
|
|
16080
16084
|
}
|
|
16081
16085
|
async function resolveCloudflared(opts = {}) {
|
|
@@ -16084,7 +16088,7 @@ async function resolveCloudflared(opts = {}) {
|
|
|
16084
16088
|
} catch {
|
|
16085
16089
|
}
|
|
16086
16090
|
try {
|
|
16087
|
-
await
|
|
16091
|
+
await import_promises2.default.access(CACHED_BINARY);
|
|
16088
16092
|
return CACHED_BINARY;
|
|
16089
16093
|
} catch {
|
|
16090
16094
|
}
|
|
@@ -16098,14 +16102,14 @@ async function resolveCloudflared(opts = {}) {
|
|
|
16098
16102
|
}
|
|
16099
16103
|
async function downloadCloudflared(target) {
|
|
16100
16104
|
const url = downloadUrlForPlatform();
|
|
16101
|
-
await
|
|
16105
|
+
await import_promises2.default.mkdir(import_path4.default.dirname(target), { recursive: true });
|
|
16102
16106
|
const response = await fetch(url);
|
|
16103
16107
|
if (!response.ok || !response.body) {
|
|
16104
16108
|
throw new Error(
|
|
16105
16109
|
`Failed to download cloudflared from ${url}: HTTP ${response.status}. Install manually from https://github.com/cloudflare/cloudflared/releases.`
|
|
16106
16110
|
);
|
|
16107
16111
|
}
|
|
16108
|
-
await (0,
|
|
16112
|
+
await (0, import_promises3.pipeline)(
|
|
16109
16113
|
response.body,
|
|
16110
16114
|
(0, import_fs.createWriteStream)(target, { mode: 493 })
|
|
16111
16115
|
);
|
|
@@ -16158,7 +16162,7 @@ async function waitForCodespacePortReady(url, timeoutMs = 15e3) {
|
|
|
16158
16162
|
}
|
|
16159
16163
|
|
|
16160
16164
|
// src/services/preview/config-file.ts
|
|
16161
|
-
var
|
|
16165
|
+
var import_promises4 = __toESM(require("fs/promises"));
|
|
16162
16166
|
var import_path5 = __toESM(require("path"));
|
|
16163
16167
|
var CONFIG_DIR = ".codeam";
|
|
16164
16168
|
var CONFIG_FILE = "preview.json";
|
|
@@ -16175,7 +16179,7 @@ var REQUIRED_FIELDS = [
|
|
|
16175
16179
|
async function readPreviewConfig(cwd) {
|
|
16176
16180
|
let raw;
|
|
16177
16181
|
try {
|
|
16178
|
-
raw = await
|
|
16182
|
+
raw = await import_promises4.default.readFile(configPath(cwd), "utf-8");
|
|
16179
16183
|
} catch {
|
|
16180
16184
|
return null;
|
|
16181
16185
|
}
|
|
@@ -16194,8 +16198,8 @@ async function readPreviewConfig(cwd) {
|
|
|
16194
16198
|
}
|
|
16195
16199
|
async function writePreviewConfig(cwd, detection) {
|
|
16196
16200
|
const filePath = configPath(cwd);
|
|
16197
|
-
await
|
|
16198
|
-
await
|
|
16201
|
+
await import_promises4.default.mkdir(import_path5.default.dirname(filePath), { recursive: true });
|
|
16202
|
+
await import_promises4.default.writeFile(filePath, JSON.stringify(detection, null, 2) + "\n", "utf-8");
|
|
16199
16203
|
}
|
|
16200
16204
|
|
|
16201
16205
|
// src/services/preview/parser.ts
|
|
@@ -16899,6 +16903,15 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
16899
16903
|
return;
|
|
16900
16904
|
}
|
|
16901
16905
|
const pluginAuthToken = ctx.pluginAuthToken;
|
|
16906
|
+
const emitProgress = (step, message) => {
|
|
16907
|
+
void postPreviewEvent({
|
|
16908
|
+
sessionId: ctx.sessionId,
|
|
16909
|
+
pluginId: ctx.pluginId,
|
|
16910
|
+
pluginAuthToken,
|
|
16911
|
+
type: "preview_progress",
|
|
16912
|
+
payload: { step, message, timestamp: Date.now() }
|
|
16913
|
+
});
|
|
16914
|
+
};
|
|
16902
16915
|
void (async () => {
|
|
16903
16916
|
void postPreviewEvent({
|
|
16904
16917
|
sessionId: ctx.sessionId,
|
|
@@ -16907,7 +16920,9 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
16907
16920
|
type: "preview_starting",
|
|
16908
16921
|
payload: { framework: detection.framework, port: detection.port }
|
|
16909
16922
|
});
|
|
16923
|
+
emitProgress("ENV_DETECTED", `${detection.framework}`);
|
|
16910
16924
|
for (const setup of detection.setup_commands ?? []) {
|
|
16925
|
+
emitProgress("SETUP_RUN", `${setup.cmd} ${setup.args.join(" ")}`);
|
|
16911
16926
|
const exitCode = await runOnce(setup.cmd, setup.args, process.cwd(), detection.env);
|
|
16912
16927
|
if (exitCode !== 0) {
|
|
16913
16928
|
void postPreviewEvent({
|
|
@@ -16923,11 +16938,17 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
16923
16938
|
return;
|
|
16924
16939
|
}
|
|
16925
16940
|
}
|
|
16941
|
+
emitProgress(
|
|
16942
|
+
"BOOT_SEQUENCE",
|
|
16943
|
+
`${detection.command} ${detection.args.join(" ")}`
|
|
16944
|
+
);
|
|
16926
16945
|
const devServer = (0, import_child_process15.spawn)(detection.command, detection.args, {
|
|
16927
16946
|
cwd: process.cwd(),
|
|
16928
16947
|
env: { ...process.env, ...detection.env ?? {} },
|
|
16929
16948
|
stdio: ["ignore", "pipe", "pipe"]
|
|
16930
16949
|
});
|
|
16950
|
+
emitProgress("BIND_PORT", String(detection.port));
|
|
16951
|
+
emitProgress("WAITING_FOR_READY", detection.ready_pattern);
|
|
16931
16952
|
let readyMatched = false;
|
|
16932
16953
|
let expoUrl = null;
|
|
16933
16954
|
const readyRe = new RegExp(detection.ready_pattern);
|
|
@@ -16969,6 +16990,11 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
16969
16990
|
});
|
|
16970
16991
|
return;
|
|
16971
16992
|
}
|
|
16993
|
+
emitProgress("READY_DETECTED", `port ${detection.port}`);
|
|
16994
|
+
emitProgress(
|
|
16995
|
+
"TUNNEL_STARTING",
|
|
16996
|
+
detection.framework === "Expo" ? "Expo (self-tunnelled)" : isCodespaceSession() ? "GitHub Codespaces public port" : "cloudflared quick tunnel"
|
|
16997
|
+
);
|
|
16972
16998
|
let tunnel = null;
|
|
16973
16999
|
let url;
|
|
16974
17000
|
if (detection.framework === "Expo") {
|
|
@@ -17080,9 +17106,33 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
17080
17106
|
});
|
|
17081
17107
|
return;
|
|
17082
17108
|
}
|
|
17083
|
-
|
|
17109
|
+
try {
|
|
17110
|
+
await waitForCloudflaredReady(parsedUrl, 6e4);
|
|
17111
|
+
log.info("preview", `cloudflared probe: ${parsedUrl} reachable from CLI host`);
|
|
17112
|
+
} catch (e) {
|
|
17113
|
+
try {
|
|
17114
|
+
tunnel.kill("SIGTERM");
|
|
17115
|
+
} catch {
|
|
17116
|
+
}
|
|
17117
|
+
try {
|
|
17118
|
+
devServer.kill("SIGTERM");
|
|
17119
|
+
} catch {
|
|
17120
|
+
}
|
|
17121
|
+
void postPreviewEvent({
|
|
17122
|
+
sessionId: ctx.sessionId,
|
|
17123
|
+
pluginId: ctx.pluginId,
|
|
17124
|
+
pluginAuthToken,
|
|
17125
|
+
type: "preview_error",
|
|
17126
|
+
payload: {
|
|
17127
|
+
stage: "tunnel",
|
|
17128
|
+
message: `Tunnel ${parsedUrl} did not become reachable within 60s (${e.message}). Cloudflare Quick Tunnels occasionally fail to register \u2014 retry usually succeeds.`
|
|
17129
|
+
}
|
|
17130
|
+
});
|
|
17131
|
+
return;
|
|
17132
|
+
}
|
|
17084
17133
|
url = parsedUrl;
|
|
17085
17134
|
}
|
|
17135
|
+
emitProgress("TUNNEL_READY", url);
|
|
17086
17136
|
registerPreview(ctx.sessionId, {
|
|
17087
17137
|
sessionId: ctx.sessionId,
|
|
17088
17138
|
devServer,
|
|
@@ -20137,7 +20187,7 @@ function checkChokidar() {
|
|
|
20137
20187
|
}
|
|
20138
20188
|
async function doctor(args2 = []) {
|
|
20139
20189
|
const json = args2.includes("--json");
|
|
20140
|
-
const cliVersion = true ? "2.26.
|
|
20190
|
+
const cliVersion = true ? "2.26.12" : "0.0.0-dev";
|
|
20141
20191
|
const apiBase = resolveApiBaseUrl();
|
|
20142
20192
|
const diagnosticId = (0, import_node_crypto6.randomUUID)();
|
|
20143
20193
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -20336,7 +20386,7 @@ async function completion(args2) {
|
|
|
20336
20386
|
// src/commands/version.ts
|
|
20337
20387
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
20338
20388
|
function version2() {
|
|
20339
|
-
const v = true ? "2.26.
|
|
20389
|
+
const v = true ? "2.26.12" : "unknown";
|
|
20340
20390
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
20341
20391
|
}
|
|
20342
20392
|
|
|
@@ -20564,7 +20614,7 @@ function checkForUpdates() {
|
|
|
20564
20614
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
20565
20615
|
if (process.env.CI) return;
|
|
20566
20616
|
if (!process.stdout.isTTY) return;
|
|
20567
|
-
const current = true ? "2.26.
|
|
20617
|
+
const current = true ? "2.26.12" : null;
|
|
20568
20618
|
if (!current) return;
|
|
20569
20619
|
const cache = readCache();
|
|
20570
20620
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/postinstall.ts
|
|
5
|
+
var c = {
|
|
6
|
+
reset: "\x1B[0m",
|
|
7
|
+
bold: "\x1B[1m",
|
|
8
|
+
dim: "\x1B[2m",
|
|
9
|
+
green: "\x1B[32m",
|
|
10
|
+
cyan: "\x1B[36m",
|
|
11
|
+
violet: "\x1B[35m",
|
|
12
|
+
white: "\x1B[97m"
|
|
13
|
+
};
|
|
14
|
+
var lines = [
|
|
15
|
+
"",
|
|
16
|
+
` ${c.violet}${c.bold}codeam-cli${c.reset} ${c.dim}\u2014 Claude Code remote control${c.reset}`,
|
|
17
|
+
"",
|
|
18
|
+
` ${c.dim}1.${c.reset} Pair your phone:`,
|
|
19
|
+
` ${c.cyan}codeam pair${c.reset}`,
|
|
20
|
+
"",
|
|
21
|
+
` ${c.dim}2.${c.reset} Launch Claude Code with mobile control:`,
|
|
22
|
+
` ${c.cyan}codeam${c.reset}`,
|
|
23
|
+
"",
|
|
24
|
+
` ${c.dim}Other commands:${c.reset}`,
|
|
25
|
+
` ${c.white}codeam sessions${c.reset} ${c.dim}list paired devices${c.reset}`,
|
|
26
|
+
` ${c.white}codeam status${c.reset} ${c.dim}show connection info${c.reset}`,
|
|
27
|
+
` ${c.white}codeam logout${c.reset} ${c.dim}remove all sessions${c.reset}`,
|
|
28
|
+
"",
|
|
29
|
+
` ${c.dim}Requires Claude Code:${c.reset} ${c.green}npm install -g @anthropic-ai/claude-code${c.reset}`,
|
|
30
|
+
` ${c.dim}Mobile app:${c.reset} ${c.green}https://www.codeagent-mobile.com${c.reset}`,
|
|
31
|
+
""
|
|
32
|
+
];
|
|
33
|
+
process.stdout.write(lines.join("\n") + "\n");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.26.
|
|
3
|
+
"version": "2.26.12",
|
|
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",
|