codeam-cli 2.39.36 → 2.39.38
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 +171 -167
- 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.39.37] — 2026-06-19
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Preview always uses cloudflared + auto-retries the tunnel
|
|
12
|
+
|
|
13
|
+
## [2.39.36] — 2026-06-18
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Preview dev-server run command rewrites pnpm/bun → npm run
|
|
18
|
+
|
|
7
19
|
## [2.39.35] — 2026-06-18
|
|
8
20
|
|
|
9
21
|
### 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.38",
|
|
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.38" : "0.0.0-dev",
|
|
5912
5912
|
nodeVersion: process.version,
|
|
5913
5913
|
platform: process.platform,
|
|
5914
5914
|
arch: process.arch,
|
|
@@ -7302,10 +7302,10 @@ function buildForPlatform(platform3) {
|
|
|
7302
7302
|
var import_node_crypto4 = require("crypto");
|
|
7303
7303
|
|
|
7304
7304
|
// src/agents/claude/resolver.ts
|
|
7305
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
7306
|
-
const found =
|
|
7305
|
+
function buildClaudeLaunch(extraArgs = [], os39 = createOsStrategy()) {
|
|
7306
|
+
const found = os39.findInPath("claude") ?? os39.findInPath("claude-code");
|
|
7307
7307
|
if (!found) return null;
|
|
7308
|
-
return
|
|
7308
|
+
return os39.buildLaunch(found, extraArgs);
|
|
7309
7309
|
}
|
|
7310
7310
|
|
|
7311
7311
|
// src/agents/claude/installer.ts
|
|
@@ -9754,8 +9754,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9754
9754
|
meta = getAgent("claude");
|
|
9755
9755
|
mode = "interactive";
|
|
9756
9756
|
os;
|
|
9757
|
-
constructor(
|
|
9758
|
-
this.os =
|
|
9757
|
+
constructor(os39) {
|
|
9758
|
+
this.os = os39;
|
|
9759
9759
|
}
|
|
9760
9760
|
/**
|
|
9761
9761
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -10374,8 +10374,8 @@ function codexCredentialLocator() {
|
|
|
10374
10374
|
function codexLoginLauncher() {
|
|
10375
10375
|
return {
|
|
10376
10376
|
async ensureInstalled() {
|
|
10377
|
-
const
|
|
10378
|
-
return
|
|
10377
|
+
const os39 = createOsStrategy();
|
|
10378
|
+
return os39.findInPath("codex") !== null;
|
|
10379
10379
|
},
|
|
10380
10380
|
launch() {
|
|
10381
10381
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -10398,8 +10398,8 @@ var CodexRuntimeStrategy = class {
|
|
|
10398
10398
|
meta = getAgent("codex");
|
|
10399
10399
|
mode = "interactive";
|
|
10400
10400
|
os;
|
|
10401
|
-
constructor(
|
|
10402
|
-
this.os =
|
|
10401
|
+
constructor(os39) {
|
|
10402
|
+
this.os = os39;
|
|
10403
10403
|
}
|
|
10404
10404
|
async prepareLaunch() {
|
|
10405
10405
|
let binary = this.os.findInPath("codex");
|
|
@@ -10495,12 +10495,12 @@ var CodexRuntimeStrategy = class {
|
|
|
10495
10495
|
});
|
|
10496
10496
|
}
|
|
10497
10497
|
};
|
|
10498
|
-
function resolveNpm(
|
|
10499
|
-
return
|
|
10498
|
+
function resolveNpm(os39) {
|
|
10499
|
+
return os39.id === "win32" ? "npm.cmd" : "npm";
|
|
10500
10500
|
}
|
|
10501
|
-
async function installCodexViaNpm(
|
|
10501
|
+
async function installCodexViaNpm(os39) {
|
|
10502
10502
|
return new Promise((resolve7, reject) => {
|
|
10503
|
-
const proc = (0, import_node_child_process4.spawn)(resolveNpm(
|
|
10503
|
+
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os39), ["install", "-g", "@openai/codex"], {
|
|
10504
10504
|
stdio: "inherit"
|
|
10505
10505
|
});
|
|
10506
10506
|
proc.on("close", (code) => {
|
|
@@ -10517,16 +10517,16 @@ async function installCodexViaNpm(os38) {
|
|
|
10517
10517
|
});
|
|
10518
10518
|
});
|
|
10519
10519
|
}
|
|
10520
|
-
function augmentNpmGlobalBin(
|
|
10520
|
+
function augmentNpmGlobalBin(os39) {
|
|
10521
10521
|
try {
|
|
10522
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
10522
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os39), ["prefix", "-g"], {
|
|
10523
10523
|
stdio: ["ignore", "pipe", "ignore"]
|
|
10524
10524
|
});
|
|
10525
10525
|
if (result.status !== 0) return;
|
|
10526
10526
|
const prefix = result.stdout.toString().trim();
|
|
10527
10527
|
if (!prefix) return;
|
|
10528
|
-
const binDir =
|
|
10529
|
-
|
|
10528
|
+
const binDir = os39.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
10529
|
+
os39.augmentPath([binDir]);
|
|
10530
10530
|
} catch {
|
|
10531
10531
|
}
|
|
10532
10532
|
}
|
|
@@ -10610,9 +10610,9 @@ var import_node_child_process7 = require("child_process");
|
|
|
10610
10610
|
// src/agents/coderabbit/installer.ts
|
|
10611
10611
|
var import_node_child_process5 = require("child_process");
|
|
10612
10612
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
10613
|
-
async function ensureCoderabbitInstalled(
|
|
10614
|
-
if (
|
|
10615
|
-
if (
|
|
10613
|
+
async function ensureCoderabbitInstalled(os39) {
|
|
10614
|
+
if (os39.findInPath("coderabbit")) return true;
|
|
10615
|
+
if (os39.id === "win32") {
|
|
10616
10616
|
console.error(
|
|
10617
10617
|
"\n \u2717 CodeRabbit on Windows requires WSL.\n Install the CLI inside your WSL distribution\n (curl -fsSL https://cli.coderabbit.ai/install.sh | sh)\n then re-run `codeam link coderabbit` from WSL.\n"
|
|
10618
10618
|
);
|
|
@@ -10627,8 +10627,8 @@ async function ensureCoderabbitInstalled(os38) {
|
|
|
10627
10627
|
proc.on("error", () => resolve7(false));
|
|
10628
10628
|
});
|
|
10629
10629
|
if (!ok) return false;
|
|
10630
|
-
|
|
10631
|
-
return
|
|
10630
|
+
os39.augmentPath([`${os39.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
10631
|
+
return os39.findInPath("coderabbit") !== null;
|
|
10632
10632
|
}
|
|
10633
10633
|
|
|
10634
10634
|
// src/agents/coderabbit/link.ts
|
|
@@ -10655,10 +10655,10 @@ function coderabbitCredentialLocator() {
|
|
|
10655
10655
|
extract: extractLocalCoderabbitToken
|
|
10656
10656
|
};
|
|
10657
10657
|
}
|
|
10658
|
-
function coderabbitLoginLauncher(
|
|
10658
|
+
function coderabbitLoginLauncher(os39) {
|
|
10659
10659
|
return {
|
|
10660
10660
|
async ensureInstalled() {
|
|
10661
|
-
return ensureCoderabbitInstalled(
|
|
10661
|
+
return ensureCoderabbitInstalled(os39);
|
|
10662
10662
|
},
|
|
10663
10663
|
launch() {
|
|
10664
10664
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -10704,8 +10704,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
10704
10704
|
meta = getAgent("coderabbit");
|
|
10705
10705
|
mode = "batch";
|
|
10706
10706
|
os;
|
|
10707
|
-
constructor(
|
|
10708
|
-
this.os =
|
|
10707
|
+
constructor(os39) {
|
|
10708
|
+
this.os = os39;
|
|
10709
10709
|
}
|
|
10710
10710
|
getDefaultArgs() {
|
|
10711
10711
|
return ["review"];
|
|
@@ -10820,10 +10820,10 @@ function cursorCredentialLocator() {
|
|
|
10820
10820
|
extract: extractLocalCursorToken
|
|
10821
10821
|
};
|
|
10822
10822
|
}
|
|
10823
|
-
function cursorLoginLauncher(
|
|
10823
|
+
function cursorLoginLauncher(os39) {
|
|
10824
10824
|
return {
|
|
10825
10825
|
async ensureInstalled() {
|
|
10826
|
-
if (
|
|
10826
|
+
if (os39.findInPath("cursor-agent")) return true;
|
|
10827
10827
|
console.error(
|
|
10828
10828
|
"\n \u2717 cursor-agent binary not on PATH.\n Install Cursor (https://cursor.com/) and ensure the CLI\n plugin is enabled, then re-run `codeam link cursor`.\n"
|
|
10829
10829
|
);
|
|
@@ -10885,8 +10885,8 @@ var CursorRuntimeStrategy = class {
|
|
|
10885
10885
|
meta = getAgent("cursor");
|
|
10886
10886
|
mode = "interactive";
|
|
10887
10887
|
os;
|
|
10888
|
-
constructor(
|
|
10889
|
-
this.os =
|
|
10888
|
+
constructor(os39) {
|
|
10889
|
+
this.os = os39;
|
|
10890
10890
|
}
|
|
10891
10891
|
async prepareLaunch() {
|
|
10892
10892
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11006,10 +11006,10 @@ function aiderCredentialLocator() {
|
|
|
11006
11006
|
extract: extractLocalAiderToken
|
|
11007
11007
|
};
|
|
11008
11008
|
}
|
|
11009
|
-
function aiderLoginLauncher(
|
|
11009
|
+
function aiderLoginLauncher(os39) {
|
|
11010
11010
|
return {
|
|
11011
11011
|
async ensureInstalled() {
|
|
11012
|
-
if (
|
|
11012
|
+
if (os39.findInPath("aider")) return true;
|
|
11013
11013
|
console.error(
|
|
11014
11014
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11015
11015
|
);
|
|
@@ -11019,7 +11019,7 @@ function aiderLoginLauncher(os38) {
|
|
|
11019
11019
|
console.error(
|
|
11020
11020
|
"\n Aider has no interactive login flow.\n Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your shell,\n or re-run `codeam link aider --api-key=<your-key>`.\n"
|
|
11021
11021
|
);
|
|
11022
|
-
return (0, import_node_child_process9.spawn)(
|
|
11022
|
+
return (0, import_node_child_process9.spawn)(os39.id === "win32" ? "cmd.exe" : "sh", os39.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
11023
11023
|
stdio: "ignore"
|
|
11024
11024
|
});
|
|
11025
11025
|
}
|
|
@@ -11091,8 +11091,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11091
11091
|
meta = getAgent("aider");
|
|
11092
11092
|
mode = "interactive";
|
|
11093
11093
|
os;
|
|
11094
|
-
constructor(
|
|
11095
|
-
this.os =
|
|
11094
|
+
constructor(os39) {
|
|
11095
|
+
this.os = os39;
|
|
11096
11096
|
}
|
|
11097
11097
|
async prepareLaunch() {
|
|
11098
11098
|
const binary = this.os.findInPath("aider");
|
|
@@ -11221,8 +11221,8 @@ function geminiCredentialLocator() {
|
|
|
11221
11221
|
function geminiLoginLauncher() {
|
|
11222
11222
|
return {
|
|
11223
11223
|
async ensureInstalled() {
|
|
11224
|
-
const
|
|
11225
|
-
return
|
|
11224
|
+
const os39 = createOsStrategy();
|
|
11225
|
+
return os39.findInPath("gemini") !== null;
|
|
11226
11226
|
},
|
|
11227
11227
|
launch() {
|
|
11228
11228
|
return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -11255,8 +11255,8 @@ var GeminiRuntimeStrategy = class {
|
|
|
11255
11255
|
meta = getAgent("gemini");
|
|
11256
11256
|
mode = "interactive";
|
|
11257
11257
|
os;
|
|
11258
|
-
constructor(
|
|
11259
|
-
this.os =
|
|
11258
|
+
constructor(os39) {
|
|
11259
|
+
this.os = os39;
|
|
11260
11260
|
}
|
|
11261
11261
|
async prepareLaunch() {
|
|
11262
11262
|
const binary = this.os.findInPath("gemini");
|
|
@@ -11355,18 +11355,18 @@ var GeminiRuntimeStrategy = class {
|
|
|
11355
11355
|
|
|
11356
11356
|
// src/agents/registry.ts
|
|
11357
11357
|
var runtimeBuilders = {
|
|
11358
|
-
claude: (
|
|
11359
|
-
codex: (
|
|
11360
|
-
coderabbit: (
|
|
11361
|
-
cursor: (
|
|
11362
|
-
aider: (
|
|
11363
|
-
gemini: (
|
|
11358
|
+
claude: (os39) => new ClaudeRuntimeStrategy(os39),
|
|
11359
|
+
codex: (os39) => new CodexRuntimeStrategy(os39),
|
|
11360
|
+
coderabbit: (os39) => new CoderabbitRuntimeStrategy(os39),
|
|
11361
|
+
cursor: (os39) => new CursorRuntimeStrategy(os39),
|
|
11362
|
+
aider: (os39) => new AiderRuntimeStrategy(os39),
|
|
11363
|
+
gemini: (os39) => new GeminiRuntimeStrategy(os39)
|
|
11364
11364
|
};
|
|
11365
11365
|
var deployBuilders = {
|
|
11366
11366
|
claude: () => new ClaudeDeployStrategy(),
|
|
11367
11367
|
codex: () => new CodexDeployStrategy()
|
|
11368
11368
|
};
|
|
11369
|
-
function createAgentStrategy(agent,
|
|
11369
|
+
function createAgentStrategy(agent, os39 = createOsStrategy()) {
|
|
11370
11370
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
11371
11371
|
throw new Error(
|
|
11372
11372
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -11376,10 +11376,10 @@ function createAgentStrategy(agent, os38 = createOsStrategy()) {
|
|
|
11376
11376
|
if (!build) {
|
|
11377
11377
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
11378
11378
|
}
|
|
11379
|
-
return build(
|
|
11379
|
+
return build(os39);
|
|
11380
11380
|
}
|
|
11381
|
-
function createInteractiveAgentStrategy(agent,
|
|
11382
|
-
const s = createAgentStrategy(agent,
|
|
11381
|
+
function createInteractiveAgentStrategy(agent, os39 = createOsStrategy()) {
|
|
11382
|
+
const s = createAgentStrategy(agent, os39);
|
|
11383
11383
|
if (s.mode !== "interactive") {
|
|
11384
11384
|
throw new Error(
|
|
11385
11385
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -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"));
|
|
@@ -17337,11 +17309,11 @@ function resolveDoltInstallStrategy(platform3) {
|
|
|
17337
17309
|
}
|
|
17338
17310
|
var DOLT_RELEASE_BASE = "https://github.com/dolthub/dolt/releases/latest/download";
|
|
17339
17311
|
function doltPlatformTuple(platform3, arch2) {
|
|
17340
|
-
const
|
|
17312
|
+
const os39 = platform3 === "win32" ? "windows" : platform3 === "darwin" ? "darwin" : "linux";
|
|
17341
17313
|
const a = arch2 === "x64" ? "amd64" : arch2 === "arm64" ? "arm64" : null;
|
|
17342
17314
|
if (!a) return null;
|
|
17343
|
-
if (
|
|
17344
|
-
return `${
|
|
17315
|
+
if (os39 === "windows" && a !== "amd64") return null;
|
|
17316
|
+
return `${os39}-${a}`;
|
|
17345
17317
|
}
|
|
17346
17318
|
function resolveDoltTarballStrategy(targetDir, platform3, arch2) {
|
|
17347
17319
|
const tuple = doltPlatformTuple(platform3, arch2);
|
|
@@ -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;
|
|
@@ -19483,10 +19428,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
19483
19428
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
19484
19429
|
/[\\/]Templates([\\/]|$)/i
|
|
19485
19430
|
];
|
|
19486
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
19431
|
+
function isUnsafeWindowsWatchRoot(dir, homedir32) {
|
|
19487
19432
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
19488
19433
|
const cwd = norm(dir);
|
|
19489
|
-
const home = norm(
|
|
19434
|
+
const home = norm(homedir32);
|
|
19490
19435
|
if (cwd === home) return true;
|
|
19491
19436
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
19492
19437
|
const sysRoots = [
|
|
@@ -26539,6 +26484,7 @@ async function host(args2) {
|
|
|
26539
26484
|
|
|
26540
26485
|
// src/commands/host-agent.ts
|
|
26541
26486
|
var import_node_child_process13 = require("child_process");
|
|
26487
|
+
var os36 = __toESM(require("os"));
|
|
26542
26488
|
|
|
26543
26489
|
// src/commands/host/workspace.ts
|
|
26544
26490
|
var fs42 = __toESM(require("fs"));
|
|
@@ -26911,6 +26857,12 @@ var HostAgentSupervisor = class {
|
|
|
26911
26857
|
CODEAM_AUTO_TOKEN: payload.autoPairToken
|
|
26912
26858
|
};
|
|
26913
26859
|
}
|
|
26860
|
+
if (payload.agentInstallScript) {
|
|
26861
|
+
report("installing", "installing agent CLI");
|
|
26862
|
+
await this.runAgentInstall(payload.agentInstallScript);
|
|
26863
|
+
}
|
|
26864
|
+
const home = process.env.HOME || os36.homedir();
|
|
26865
|
+
childEnv.PATH = `${home}/.local/bin:${process.env.PATH ?? ""}`;
|
|
26914
26866
|
report("spawning", "starting agent");
|
|
26915
26867
|
const proc = this.spawnChild(childEnv, cwd, extraArgs);
|
|
26916
26868
|
const child = { deployId: payload.deployId, proc };
|
|
@@ -26946,6 +26898,58 @@ var HostAgentSupervisor = class {
|
|
|
26946
26898
|
report("failed", message);
|
|
26947
26899
|
}
|
|
26948
26900
|
}
|
|
26901
|
+
/**
|
|
26902
|
+
* Run the backend-supplied per-agent CLI install script (e.g.
|
|
26903
|
+
* `claude.ai/install.sh`, `npm i -g @openai/codex`). Best-effort + bounded:
|
|
26904
|
+
* a non-zero exit / timeout is logged but never rejects, so a box that
|
|
26905
|
+
* can't reach an installer still deploys (the chat agent runs via the
|
|
26906
|
+
* bundled ACP SDK; only `claude -p` / `codex` preview detection degrades).
|
|
26907
|
+
* HOME is forced so the installer's `~/.local/bin` resolves on a detached
|
|
26908
|
+
* host-agent whose env may lack it.
|
|
26909
|
+
*/
|
|
26910
|
+
runAgentInstall(script) {
|
|
26911
|
+
return new Promise((resolve7) => {
|
|
26912
|
+
const home = process.env.HOME || os36.homedir();
|
|
26913
|
+
const child = (0, import_node_child_process13.spawn)("sh", ["-c", script], {
|
|
26914
|
+
env: { ...process.env, HOME: home },
|
|
26915
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
26916
|
+
});
|
|
26917
|
+
const onData = (b) => {
|
|
26918
|
+
const line = b.toString().replace(/\n+$/g, "");
|
|
26919
|
+
if (line) log.info("host-agent", `agent-install: ${line}`);
|
|
26920
|
+
};
|
|
26921
|
+
child.stdout?.on("data", onData);
|
|
26922
|
+
child.stderr?.on("data", onData);
|
|
26923
|
+
let settled = false;
|
|
26924
|
+
const done = () => {
|
|
26925
|
+
if (settled) return;
|
|
26926
|
+
settled = true;
|
|
26927
|
+
resolve7();
|
|
26928
|
+
};
|
|
26929
|
+
const timer = setTimeout(() => {
|
|
26930
|
+
log.warn("host-agent", "agent install timed out (180s) \u2014 preview detection may be unavailable");
|
|
26931
|
+
try {
|
|
26932
|
+
child.kill("SIGTERM");
|
|
26933
|
+
} catch {
|
|
26934
|
+
}
|
|
26935
|
+
done();
|
|
26936
|
+
}, 18e4);
|
|
26937
|
+
child.once("exit", (code) => {
|
|
26938
|
+
clearTimeout(timer);
|
|
26939
|
+
if (code !== 0) {
|
|
26940
|
+
log.warn("host-agent", `agent install exited code=${code} \u2014 preview detection may be unavailable; agent still runs`);
|
|
26941
|
+
} else {
|
|
26942
|
+
log.info("host-agent", "agent CLI installed");
|
|
26943
|
+
}
|
|
26944
|
+
done();
|
|
26945
|
+
});
|
|
26946
|
+
child.once("error", (e) => {
|
|
26947
|
+
clearTimeout(timer);
|
|
26948
|
+
log.warn("host-agent", `agent install spawn error: ${e.message}`);
|
|
26949
|
+
done();
|
|
26950
|
+
});
|
|
26951
|
+
});
|
|
26952
|
+
}
|
|
26949
26953
|
/**
|
|
26950
26954
|
* Kill the child for the given id. The backend correlates the session it
|
|
26951
26955
|
* sends to this deploy, so the id matches the deployId we keyed on. No-op
|
|
@@ -27121,9 +27125,9 @@ function checkSessions() {
|
|
|
27121
27125
|
}
|
|
27122
27126
|
}
|
|
27123
27127
|
function checkAgentBinaries() {
|
|
27124
|
-
const
|
|
27128
|
+
const os39 = createOsStrategy();
|
|
27125
27129
|
return getEnabledAgents().map((meta) => {
|
|
27126
|
-
const found =
|
|
27130
|
+
const found = os39.findInPath(meta.binaryName);
|
|
27127
27131
|
return {
|
|
27128
27132
|
id: `agent-${meta.id}`,
|
|
27129
27133
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -27187,7 +27191,7 @@ function checkChokidar() {
|
|
|
27187
27191
|
}
|
|
27188
27192
|
async function doctor(args2 = []) {
|
|
27189
27193
|
const json = args2.includes("--json");
|
|
27190
|
-
const cliVersion = true ? "2.39.
|
|
27194
|
+
const cliVersion = true ? "2.39.38" : "0.0.0-dev";
|
|
27191
27195
|
const apiBase2 = resolveApiBaseUrl();
|
|
27192
27196
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
27193
27197
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -27386,7 +27390,7 @@ async function completion(args2) {
|
|
|
27386
27390
|
// src/commands/version.ts
|
|
27387
27391
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
27388
27392
|
function version2() {
|
|
27389
|
-
const v = true ? "2.39.
|
|
27393
|
+
const v = true ? "2.39.38" : "unknown";
|
|
27390
27394
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
27391
27395
|
}
|
|
27392
27396
|
|
|
@@ -27515,7 +27519,7 @@ var _subcommandHelpKeys = Object.keys(HELPS);
|
|
|
27515
27519
|
|
|
27516
27520
|
// src/lib/updateNotifier.ts
|
|
27517
27521
|
var fs45 = __toESM(require("fs"));
|
|
27518
|
-
var
|
|
27522
|
+
var os37 = __toESM(require("os"));
|
|
27519
27523
|
var path57 = __toESM(require("path"));
|
|
27520
27524
|
var https8 = __toESM(require("https"));
|
|
27521
27525
|
var import_node_child_process14 = require("child_process");
|
|
@@ -27525,7 +27529,7 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
27525
27529
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
27526
27530
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
27527
27531
|
function cachePath() {
|
|
27528
|
-
const dir = path57.join(
|
|
27532
|
+
const dir = path57.join(os37.homedir(), ".codeam");
|
|
27529
27533
|
return path57.join(dir, "update-check.json");
|
|
27530
27534
|
}
|
|
27531
27535
|
function readCache() {
|
|
@@ -27672,7 +27676,7 @@ function checkForUpdates() {
|
|
|
27672
27676
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
27673
27677
|
if (process.env.CI) return;
|
|
27674
27678
|
if (!process.stdout.isTTY) return;
|
|
27675
|
-
const current = true ? "2.39.
|
|
27679
|
+
const current = true ? "2.39.38" : null;
|
|
27676
27680
|
if (!current) return;
|
|
27677
27681
|
const cache = readCache();
|
|
27678
27682
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -27703,10 +27707,10 @@ var EXIT_CODE_NAMES = {
|
|
|
27703
27707
|
};
|
|
27704
27708
|
|
|
27705
27709
|
// src/index.ts
|
|
27706
|
-
var
|
|
27710
|
+
var os38 = __toESM(require("os"));
|
|
27707
27711
|
if (!process.env.HOME) {
|
|
27708
27712
|
try {
|
|
27709
|
-
const home =
|
|
27713
|
+
const home = os38.homedir();
|
|
27710
27714
|
if (home) process.env.HOME = home;
|
|
27711
27715
|
} catch {
|
|
27712
27716
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.39.
|
|
3
|
+
"version": "2.39.38",
|
|
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",
|