codeam-cli 2.26.5 → 2.26.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 +12 -0
- package/dist/index.js +129 -17
- 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.6] — 2026-06-03
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Preview shutdown is graceful + parser tolerates prose-wrapped JSON (#239)
|
|
12
|
+
|
|
13
|
+
## [2.26.5] — 2026-06-03
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **vsc-plugin:** CopilotLmStrategy matches normalized agentId `copilot` (#238)
|
|
18
|
+
|
|
7
19
|
## [2.26.4] — 2026-06-03
|
|
8
20
|
|
|
9
21
|
### Fixed
|
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.7",
|
|
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.7" : "0.0.0-dev",
|
|
5833
5833
|
nodeVersion: process.version,
|
|
5834
5834
|
platform: process.platform,
|
|
5835
5835
|
arch: process.arch,
|
|
@@ -15944,6 +15944,20 @@ var import_path4 = __toESM(require("path"));
|
|
|
15944
15944
|
var import_promises2 = require("stream/promises");
|
|
15945
15945
|
var import_which = __toESM(require("which"));
|
|
15946
15946
|
var CACHED_BINARY = import_path4.default.join(import_os7.default.homedir(), ".codeam", "bin", "cloudflared");
|
|
15947
|
+
async function waitForCloudflaredReady(url, timeoutMs = 3e4) {
|
|
15948
|
+
const start2 = Date.now();
|
|
15949
|
+
while (Date.now() - start2 < timeoutMs) {
|
|
15950
|
+
try {
|
|
15951
|
+
const res = await fetch(url, { method: "HEAD" });
|
|
15952
|
+
if (res.status < 500) return;
|
|
15953
|
+
} catch {
|
|
15954
|
+
}
|
|
15955
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
15956
|
+
}
|
|
15957
|
+
throw new Error(
|
|
15958
|
+
`Tunnel URL ${url} not reachable after ${timeoutMs}ms (DNS may still be propagating).`
|
|
15959
|
+
);
|
|
15960
|
+
}
|
|
15947
15961
|
async function resolveCloudflared(opts = {}) {
|
|
15948
15962
|
try {
|
|
15949
15963
|
return await (0, import_which.default)("cloudflared");
|
|
@@ -16074,20 +16088,64 @@ var REQUIRED_FIELDS2 = [
|
|
|
16074
16088
|
];
|
|
16075
16089
|
function safeParseDetection(raw) {
|
|
16076
16090
|
if (!raw) return null;
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16091
|
+
let parsed = tryParseObject(raw.trim());
|
|
16092
|
+
if (!parsed) {
|
|
16093
|
+
const stripped = raw.replace(/^```(?:json)?\s*/m, "").replace(/\s*```\s*$/m, "").trim();
|
|
16094
|
+
if (stripped !== raw.trim()) {
|
|
16095
|
+
parsed = tryParseObject(stripped);
|
|
16096
|
+
}
|
|
16083
16097
|
}
|
|
16084
|
-
if (
|
|
16098
|
+
if (!parsed) {
|
|
16099
|
+
const candidate = extractFirstJsonObject(raw);
|
|
16100
|
+
if (candidate) parsed = tryParseObject(candidate);
|
|
16101
|
+
}
|
|
16102
|
+
if (!parsed) return null;
|
|
16085
16103
|
const obj = parsed;
|
|
16086
16104
|
for (const field of REQUIRED_FIELDS2) {
|
|
16087
16105
|
if (!(field in obj)) return null;
|
|
16088
16106
|
}
|
|
16089
16107
|
return obj;
|
|
16090
16108
|
}
|
|
16109
|
+
function tryParseObject(s) {
|
|
16110
|
+
try {
|
|
16111
|
+
const v = JSON.parse(s);
|
|
16112
|
+
return typeof v === "object" && v !== null ? v : null;
|
|
16113
|
+
} catch {
|
|
16114
|
+
return null;
|
|
16115
|
+
}
|
|
16116
|
+
}
|
|
16117
|
+
function extractFirstJsonObject(s) {
|
|
16118
|
+
const start2 = s.indexOf("{");
|
|
16119
|
+
if (start2 < 0) return null;
|
|
16120
|
+
let depth = 0;
|
|
16121
|
+
let inString = false;
|
|
16122
|
+
let escaped = false;
|
|
16123
|
+
for (let i = start2; i < s.length; i += 1) {
|
|
16124
|
+
const c2 = s[i];
|
|
16125
|
+
if (escaped) {
|
|
16126
|
+
escaped = false;
|
|
16127
|
+
continue;
|
|
16128
|
+
}
|
|
16129
|
+
if (inString) {
|
|
16130
|
+
if (c2 === "\\") {
|
|
16131
|
+
escaped = true;
|
|
16132
|
+
} else if (c2 === '"') {
|
|
16133
|
+
inString = false;
|
|
16134
|
+
}
|
|
16135
|
+
continue;
|
|
16136
|
+
}
|
|
16137
|
+
if (c2 === '"') {
|
|
16138
|
+
inString = true;
|
|
16139
|
+
continue;
|
|
16140
|
+
}
|
|
16141
|
+
if (c2 === "{") depth += 1;
|
|
16142
|
+
else if (c2 === "}") {
|
|
16143
|
+
depth -= 1;
|
|
16144
|
+
if (depth === 0) return s.slice(start2, i + 1);
|
|
16145
|
+
}
|
|
16146
|
+
}
|
|
16147
|
+
return null;
|
|
16148
|
+
}
|
|
16091
16149
|
var CLOUDFLARED_URL_RE = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/i;
|
|
16092
16150
|
function parseCloudflaredUrl(stderr) {
|
|
16093
16151
|
const match = stderr.match(CLOUDFLARED_URL_RE);
|
|
@@ -16135,6 +16193,9 @@ async function killAllPreviews() {
|
|
|
16135
16193
|
const ids = Array.from(activePreviews.keys());
|
|
16136
16194
|
await Promise.all(ids.map((id) => killPreview(id)));
|
|
16137
16195
|
}
|
|
16196
|
+
function activePreviewSessionIds() {
|
|
16197
|
+
return Array.from(activePreviews.keys());
|
|
16198
|
+
}
|
|
16138
16199
|
|
|
16139
16200
|
// src/commands/start/handlers.ts
|
|
16140
16201
|
var pendingAttachmentFiles = /* @__PURE__ */ new Set();
|
|
@@ -16872,10 +16933,12 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
16872
16933
|
const onTunnelChunk = (chunk) => {
|
|
16873
16934
|
const s = chunk.toString();
|
|
16874
16935
|
if (!parsedUrl) parsedUrl = parseCloudflaredUrl(s);
|
|
16936
|
+
const trimmed = s.replace(/\n+$/g, "");
|
|
16937
|
+
if (trimmed.length > 0) log.info("preview", `cloudflared: ${trimmed}`);
|
|
16875
16938
|
};
|
|
16876
16939
|
tunnel.stderr.on("data", onTunnelChunk);
|
|
16877
16940
|
tunnel.stdout.on("data", onTunnelChunk);
|
|
16878
|
-
const tunnelDeadline = Date.now() +
|
|
16941
|
+
const tunnelDeadline = Date.now() + 45e3;
|
|
16879
16942
|
while (!parsedUrl && Date.now() < tunnelDeadline) {
|
|
16880
16943
|
await new Promise((r) => setTimeout(r, 250));
|
|
16881
16944
|
}
|
|
@@ -16893,7 +16956,27 @@ var previewStartH = (ctx, _cmd, parsed) => {
|
|
|
16893
16956
|
pluginId: ctx.pluginId,
|
|
16894
16957
|
pluginAuthToken,
|
|
16895
16958
|
type: "preview_error",
|
|
16896
|
-
payload: { stage: "tunnel", message: "cloudflared did not emit a URL within
|
|
16959
|
+
payload: { stage: "tunnel", message: "cloudflared did not emit a URL within 45s." }
|
|
16960
|
+
});
|
|
16961
|
+
return;
|
|
16962
|
+
}
|
|
16963
|
+
try {
|
|
16964
|
+
await waitForCloudflaredReady(parsedUrl, 3e4);
|
|
16965
|
+
} catch (e) {
|
|
16966
|
+
try {
|
|
16967
|
+
tunnel.kill("SIGTERM");
|
|
16968
|
+
} catch {
|
|
16969
|
+
}
|
|
16970
|
+
try {
|
|
16971
|
+
devServer.kill("SIGTERM");
|
|
16972
|
+
} catch {
|
|
16973
|
+
}
|
|
16974
|
+
void postPreviewEvent({
|
|
16975
|
+
sessionId: ctx.sessionId,
|
|
16976
|
+
pluginId: ctx.pluginId,
|
|
16977
|
+
pluginAuthToken,
|
|
16978
|
+
type: "preview_error",
|
|
16979
|
+
payload: { stage: "tunnel", message: e.message }
|
|
16897
16980
|
});
|
|
16898
16981
|
return;
|
|
16899
16982
|
}
|
|
@@ -16939,8 +17022,16 @@ function runOnce(cmd, args2, cwd, env) {
|
|
|
16939
17022
|
const child = (0, import_child_process15.spawn)(cmd, args2, {
|
|
16940
17023
|
cwd,
|
|
16941
17024
|
env: { ...process.env, ...env ?? {} },
|
|
16942
|
-
stdio: "
|
|
17025
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
16943
17026
|
});
|
|
17027
|
+
const tag = `setup:${cmd}`;
|
|
17028
|
+
const onChunk = (chunk) => {
|
|
17029
|
+
const text = chunk.toString().replace(/\n+$/g, "");
|
|
17030
|
+
if (text.length === 0) return;
|
|
17031
|
+
log.info("preview", `${tag}: ${text}`);
|
|
17032
|
+
};
|
|
17033
|
+
child.stdout?.on("data", onChunk);
|
|
17034
|
+
child.stderr?.on("data", onChunk);
|
|
16944
17035
|
child.once("exit", (code) => resolve5(code));
|
|
16945
17036
|
child.once("error", () => resolve5(-1));
|
|
16946
17037
|
});
|
|
@@ -17158,7 +17249,10 @@ async function start(requestedAgent) {
|
|
|
17158
17249
|
void outputSvc.sendTerminalExit(sessionId, exitCode);
|
|
17159
17250
|
}
|
|
17160
17251
|
});
|
|
17161
|
-
|
|
17252
|
+
let shuttingDown = false;
|
|
17253
|
+
async function sigintHandler() {
|
|
17254
|
+
if (shuttingDown) return;
|
|
17255
|
+
shuttingDown = true;
|
|
17162
17256
|
agent.kill();
|
|
17163
17257
|
outputSvc.dispose();
|
|
17164
17258
|
relay.stop();
|
|
@@ -17167,7 +17261,25 @@ async function start(requestedAgent) {
|
|
|
17167
17261
|
closeAllTerminals();
|
|
17168
17262
|
cleanupAttachmentTempFiles();
|
|
17169
17263
|
killActiveSpawnAndCaptureChildren();
|
|
17170
|
-
|
|
17264
|
+
const previewSessionIds = activePreviewSessionIds();
|
|
17265
|
+
try {
|
|
17266
|
+
await killAllPreviews();
|
|
17267
|
+
} catch {
|
|
17268
|
+
}
|
|
17269
|
+
const previewAuthToken = session?.pluginAuthToken;
|
|
17270
|
+
if (previewAuthToken && previewSessionIds.length > 0) {
|
|
17271
|
+
await Promise.allSettled(
|
|
17272
|
+
previewSessionIds.map(
|
|
17273
|
+
(sid) => postPreviewEvent({
|
|
17274
|
+
sessionId: sid,
|
|
17275
|
+
pluginId,
|
|
17276
|
+
pluginAuthToken: previewAuthToken,
|
|
17277
|
+
type: "preview_stopped",
|
|
17278
|
+
payload: { reason: "session_end" }
|
|
17279
|
+
})
|
|
17280
|
+
)
|
|
17281
|
+
);
|
|
17282
|
+
}
|
|
17171
17283
|
void shutdownTelemetry();
|
|
17172
17284
|
process.exit(0);
|
|
17173
17285
|
}
|
|
@@ -19924,7 +20036,7 @@ function checkChokidar() {
|
|
|
19924
20036
|
}
|
|
19925
20037
|
async function doctor(args2 = []) {
|
|
19926
20038
|
const json = args2.includes("--json");
|
|
19927
|
-
const cliVersion = true ? "2.26.
|
|
20039
|
+
const cliVersion = true ? "2.26.7" : "0.0.0-dev";
|
|
19928
20040
|
const apiBase = resolveApiBaseUrl();
|
|
19929
20041
|
const diagnosticId = (0, import_node_crypto6.randomUUID)();
|
|
19930
20042
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -20123,7 +20235,7 @@ async function completion(args2) {
|
|
|
20123
20235
|
// src/commands/version.ts
|
|
20124
20236
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
20125
20237
|
function version2() {
|
|
20126
|
-
const v = true ? "2.26.
|
|
20238
|
+
const v = true ? "2.26.7" : "unknown";
|
|
20127
20239
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
20128
20240
|
}
|
|
20129
20241
|
|
|
@@ -20351,7 +20463,7 @@ function checkForUpdates() {
|
|
|
20351
20463
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
20352
20464
|
if (process.env.CI) return;
|
|
20353
20465
|
if (!process.stdout.isTTY) return;
|
|
20354
|
-
const current = true ? "2.26.
|
|
20466
|
+
const current = true ? "2.26.7" : null;
|
|
20355
20467
|
if (!current) return;
|
|
20356
20468
|
const cache = readCache();
|
|
20357
20469
|
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.26.
|
|
3
|
+
"version": "2.26.7",
|
|
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",
|