codeam-cli 2.35.2 → 2.35.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 +17 -0
- package/dist/index.js +172 -95
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ 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.35.3] — 2026-06-10
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Symlink bd into a WRITABLE on-PATH dir (~/.local/bin) for codespaces
|
|
12
|
+
|
|
13
|
+
## [2.35.2] — 2026-06-10
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Bound preview install + add port-listening ready fallback
|
|
18
|
+
- **cli:** Stop resume_session from killing the agent dead
|
|
19
|
+
|
|
20
|
+
### Tests
|
|
21
|
+
|
|
22
|
+
- **cli:** Make linkBdOntoPath/cliBinDir provisioner tests OS-independent
|
|
23
|
+
|
|
7
24
|
## [2.35.1] — 2026-06-10
|
|
8
25
|
|
|
9
26
|
### 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.35.
|
|
501
|
+
version: "2.35.4",
|
|
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",
|
|
@@ -5898,7 +5898,7 @@ function readAnonId() {
|
|
|
5898
5898
|
}
|
|
5899
5899
|
function superProperties() {
|
|
5900
5900
|
return {
|
|
5901
|
-
cliVersion: true ? "2.35.
|
|
5901
|
+
cliVersion: true ? "2.35.4" : "0.0.0-dev",
|
|
5902
5902
|
nodeVersion: process.version,
|
|
5903
5903
|
platform: process.platform,
|
|
5904
5904
|
arch: process.arch,
|
|
@@ -7246,10 +7246,10 @@ function buildForPlatform(platform2) {
|
|
|
7246
7246
|
var import_node_crypto4 = require("crypto");
|
|
7247
7247
|
|
|
7248
7248
|
// src/agents/claude/resolver.ts
|
|
7249
|
-
function buildClaudeLaunch(extraArgs = [],
|
|
7250
|
-
const found =
|
|
7249
|
+
function buildClaudeLaunch(extraArgs = [], os31 = createOsStrategy()) {
|
|
7250
|
+
const found = os31.findInPath("claude") ?? os31.findInPath("claude-code");
|
|
7251
7251
|
if (!found) return null;
|
|
7252
|
-
return
|
|
7252
|
+
return os31.buildLaunch(found, extraArgs);
|
|
7253
7253
|
}
|
|
7254
7254
|
|
|
7255
7255
|
// src/agents/claude/installer.ts
|
|
@@ -9992,8 +9992,8 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9992
9992
|
meta = getAgent("claude");
|
|
9993
9993
|
mode = "interactive";
|
|
9994
9994
|
os;
|
|
9995
|
-
constructor(
|
|
9996
|
-
this.os =
|
|
9995
|
+
constructor(os31) {
|
|
9996
|
+
this.os = os31;
|
|
9997
9997
|
}
|
|
9998
9998
|
/**
|
|
9999
9999
|
* Claude Code's react-ink TUI enables bracketed-paste mode at
|
|
@@ -11023,8 +11023,8 @@ function codexCredentialLocator() {
|
|
|
11023
11023
|
function codexLoginLauncher() {
|
|
11024
11024
|
return {
|
|
11025
11025
|
async ensureInstalled() {
|
|
11026
|
-
const
|
|
11027
|
-
return
|
|
11026
|
+
const os31 = createOsStrategy();
|
|
11027
|
+
return os31.findInPath("codex") !== null;
|
|
11028
11028
|
},
|
|
11029
11029
|
launch() {
|
|
11030
11030
|
return (0, import_node_child_process3.spawn)("codex", ["login"], { stdio: "inherit" });
|
|
@@ -11047,8 +11047,8 @@ var CodexRuntimeStrategy = class {
|
|
|
11047
11047
|
meta = getAgent("codex");
|
|
11048
11048
|
mode = "interactive";
|
|
11049
11049
|
os;
|
|
11050
|
-
constructor(
|
|
11051
|
-
this.os =
|
|
11050
|
+
constructor(os31) {
|
|
11051
|
+
this.os = os31;
|
|
11052
11052
|
}
|
|
11053
11053
|
async prepareLaunch() {
|
|
11054
11054
|
let binary = this.os.findInPath("codex");
|
|
@@ -11154,12 +11154,12 @@ var CodexRuntimeStrategy = class {
|
|
|
11154
11154
|
});
|
|
11155
11155
|
}
|
|
11156
11156
|
};
|
|
11157
|
-
function resolveNpm(
|
|
11158
|
-
return
|
|
11157
|
+
function resolveNpm(os31) {
|
|
11158
|
+
return os31.id === "win32" ? "npm.cmd" : "npm";
|
|
11159
11159
|
}
|
|
11160
|
-
async function installCodexViaNpm(
|
|
11160
|
+
async function installCodexViaNpm(os31) {
|
|
11161
11161
|
return new Promise((resolve7, reject) => {
|
|
11162
|
-
const proc = (0, import_node_child_process4.spawn)(resolveNpm(
|
|
11162
|
+
const proc = (0, import_node_child_process4.spawn)(resolveNpm(os31), ["install", "-g", "@openai/codex"], {
|
|
11163
11163
|
stdio: "inherit"
|
|
11164
11164
|
});
|
|
11165
11165
|
proc.on("close", (code) => {
|
|
@@ -11176,16 +11176,16 @@ async function installCodexViaNpm(os30) {
|
|
|
11176
11176
|
});
|
|
11177
11177
|
});
|
|
11178
11178
|
}
|
|
11179
|
-
function augmentNpmGlobalBin(
|
|
11179
|
+
function augmentNpmGlobalBin(os31) {
|
|
11180
11180
|
try {
|
|
11181
|
-
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(
|
|
11181
|
+
const result = (0, import_node_child_process4.spawnSync)(resolveNpm(os31), ["prefix", "-g"], {
|
|
11182
11182
|
stdio: ["ignore", "pipe", "ignore"]
|
|
11183
11183
|
});
|
|
11184
11184
|
if (result.status !== 0) return;
|
|
11185
11185
|
const prefix = result.stdout.toString().trim();
|
|
11186
11186
|
if (!prefix) return;
|
|
11187
|
-
const binDir =
|
|
11188
|
-
|
|
11187
|
+
const binDir = os31.id === "win32" ? prefix : path17.join(prefix, "bin");
|
|
11188
|
+
os31.augmentPath([binDir]);
|
|
11189
11189
|
} catch {
|
|
11190
11190
|
}
|
|
11191
11191
|
}
|
|
@@ -11269,9 +11269,9 @@ var import_node_child_process7 = require("child_process");
|
|
|
11269
11269
|
// src/agents/coderabbit/installer.ts
|
|
11270
11270
|
var import_node_child_process5 = require("child_process");
|
|
11271
11271
|
var INSTALL_URL = "https://cli.coderabbit.ai/install.sh";
|
|
11272
|
-
async function ensureCoderabbitInstalled(
|
|
11273
|
-
if (
|
|
11274
|
-
if (
|
|
11272
|
+
async function ensureCoderabbitInstalled(os31) {
|
|
11273
|
+
if (os31.findInPath("coderabbit")) return true;
|
|
11274
|
+
if (os31.id === "win32") {
|
|
11275
11275
|
console.error(
|
|
11276
11276
|
"\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"
|
|
11277
11277
|
);
|
|
@@ -11286,8 +11286,8 @@ async function ensureCoderabbitInstalled(os30) {
|
|
|
11286
11286
|
proc.on("error", () => resolve7(false));
|
|
11287
11287
|
});
|
|
11288
11288
|
if (!ok) return false;
|
|
11289
|
-
|
|
11290
|
-
return
|
|
11289
|
+
os31.augmentPath([`${os31.homeDir()}/.local/bin`, "/opt/homebrew/bin"]);
|
|
11290
|
+
return os31.findInPath("coderabbit") !== null;
|
|
11291
11291
|
}
|
|
11292
11292
|
|
|
11293
11293
|
// src/agents/coderabbit/link.ts
|
|
@@ -11314,10 +11314,10 @@ function coderabbitCredentialLocator() {
|
|
|
11314
11314
|
extract: extractLocalCoderabbitToken
|
|
11315
11315
|
};
|
|
11316
11316
|
}
|
|
11317
|
-
function coderabbitLoginLauncher(
|
|
11317
|
+
function coderabbitLoginLauncher(os31) {
|
|
11318
11318
|
return {
|
|
11319
11319
|
async ensureInstalled() {
|
|
11320
|
-
return ensureCoderabbitInstalled(
|
|
11320
|
+
return ensureCoderabbitInstalled(os31);
|
|
11321
11321
|
},
|
|
11322
11322
|
launch() {
|
|
11323
11323
|
return (0, import_node_child_process6.spawn)("coderabbit", ["login"], { stdio: "inherit" });
|
|
@@ -11363,8 +11363,8 @@ var CoderabbitRuntimeStrategy = class {
|
|
|
11363
11363
|
meta = getAgent("coderabbit");
|
|
11364
11364
|
mode = "batch";
|
|
11365
11365
|
os;
|
|
11366
|
-
constructor(
|
|
11367
|
-
this.os =
|
|
11366
|
+
constructor(os31) {
|
|
11367
|
+
this.os = os31;
|
|
11368
11368
|
}
|
|
11369
11369
|
getDefaultArgs() {
|
|
11370
11370
|
return ["review"];
|
|
@@ -11479,10 +11479,10 @@ function cursorCredentialLocator() {
|
|
|
11479
11479
|
extract: extractLocalCursorToken
|
|
11480
11480
|
};
|
|
11481
11481
|
}
|
|
11482
|
-
function cursorLoginLauncher(
|
|
11482
|
+
function cursorLoginLauncher(os31) {
|
|
11483
11483
|
return {
|
|
11484
11484
|
async ensureInstalled() {
|
|
11485
|
-
if (
|
|
11485
|
+
if (os31.findInPath("cursor-agent")) return true;
|
|
11486
11486
|
console.error(
|
|
11487
11487
|
"\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"
|
|
11488
11488
|
);
|
|
@@ -11544,8 +11544,8 @@ var CursorRuntimeStrategy = class {
|
|
|
11544
11544
|
meta = getAgent("cursor");
|
|
11545
11545
|
mode = "interactive";
|
|
11546
11546
|
os;
|
|
11547
|
-
constructor(
|
|
11548
|
-
this.os =
|
|
11547
|
+
constructor(os31) {
|
|
11548
|
+
this.os = os31;
|
|
11549
11549
|
}
|
|
11550
11550
|
async prepareLaunch() {
|
|
11551
11551
|
const binary = this.os.findInPath("cursor-agent");
|
|
@@ -11665,10 +11665,10 @@ function aiderCredentialLocator() {
|
|
|
11665
11665
|
extract: extractLocalAiderToken
|
|
11666
11666
|
};
|
|
11667
11667
|
}
|
|
11668
|
-
function aiderLoginLauncher(
|
|
11668
|
+
function aiderLoginLauncher(os31) {
|
|
11669
11669
|
return {
|
|
11670
11670
|
async ensureInstalled() {
|
|
11671
|
-
if (
|
|
11671
|
+
if (os31.findInPath("aider")) return true;
|
|
11672
11672
|
console.error(
|
|
11673
11673
|
"\n \u2717 aider binary not on PATH.\n Install Aider:\n pip install aider-chat\n then re-run `codeam link aider`.\n"
|
|
11674
11674
|
);
|
|
@@ -11678,7 +11678,7 @@ function aiderLoginLauncher(os30) {
|
|
|
11678
11678
|
console.error(
|
|
11679
11679
|
"\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"
|
|
11680
11680
|
);
|
|
11681
|
-
return (0, import_node_child_process9.spawn)(
|
|
11681
|
+
return (0, import_node_child_process9.spawn)(os31.id === "win32" ? "cmd.exe" : "sh", os31.id === "win32" ? ["/c", "exit", "0"] : ["-c", "exit 0"], {
|
|
11682
11682
|
stdio: "ignore"
|
|
11683
11683
|
});
|
|
11684
11684
|
}
|
|
@@ -11750,8 +11750,8 @@ var AiderRuntimeStrategy = class {
|
|
|
11750
11750
|
meta = getAgent("aider");
|
|
11751
11751
|
mode = "interactive";
|
|
11752
11752
|
os;
|
|
11753
|
-
constructor(
|
|
11754
|
-
this.os =
|
|
11753
|
+
constructor(os31) {
|
|
11754
|
+
this.os = os31;
|
|
11755
11755
|
}
|
|
11756
11756
|
async prepareLaunch() {
|
|
11757
11757
|
const binary = this.os.findInPath("aider");
|
|
@@ -11880,8 +11880,8 @@ function geminiCredentialLocator() {
|
|
|
11880
11880
|
function geminiLoginLauncher() {
|
|
11881
11881
|
return {
|
|
11882
11882
|
async ensureInstalled() {
|
|
11883
|
-
const
|
|
11884
|
-
return
|
|
11883
|
+
const os31 = createOsStrategy();
|
|
11884
|
+
return os31.findInPath("gemini") !== null;
|
|
11885
11885
|
},
|
|
11886
11886
|
launch() {
|
|
11887
11887
|
return (0, import_node_child_process10.spawn)("gemini", ["auth", "login"], { stdio: "inherit" });
|
|
@@ -11914,8 +11914,8 @@ var GeminiRuntimeStrategy = class {
|
|
|
11914
11914
|
meta = getAgent("gemini");
|
|
11915
11915
|
mode = "interactive";
|
|
11916
11916
|
os;
|
|
11917
|
-
constructor(
|
|
11918
|
-
this.os =
|
|
11917
|
+
constructor(os31) {
|
|
11918
|
+
this.os = os31;
|
|
11919
11919
|
}
|
|
11920
11920
|
async prepareLaunch() {
|
|
11921
11921
|
const binary = this.os.findInPath("gemini");
|
|
@@ -12015,18 +12015,18 @@ var GeminiRuntimeStrategy = class {
|
|
|
12015
12015
|
|
|
12016
12016
|
// src/agents/registry.ts
|
|
12017
12017
|
var runtimeBuilders = {
|
|
12018
|
-
claude: (
|
|
12019
|
-
codex: (
|
|
12020
|
-
coderabbit: (
|
|
12021
|
-
cursor: (
|
|
12022
|
-
aider: (
|
|
12023
|
-
gemini: (
|
|
12018
|
+
claude: (os31) => new ClaudeRuntimeStrategy(os31),
|
|
12019
|
+
codex: (os31) => new CodexRuntimeStrategy(os31),
|
|
12020
|
+
coderabbit: (os31) => new CoderabbitRuntimeStrategy(os31),
|
|
12021
|
+
cursor: (os31) => new CursorRuntimeStrategy(os31),
|
|
12022
|
+
aider: (os31) => new AiderRuntimeStrategy(os31),
|
|
12023
|
+
gemini: (os31) => new GeminiRuntimeStrategy(os31)
|
|
12024
12024
|
};
|
|
12025
12025
|
var deployBuilders = {
|
|
12026
12026
|
claude: () => new ClaudeDeployStrategy(),
|
|
12027
12027
|
codex: () => new CodexDeployStrategy()
|
|
12028
12028
|
};
|
|
12029
|
-
function createAgentStrategy(agent,
|
|
12029
|
+
function createAgentStrategy(agent, os31 = createOsStrategy()) {
|
|
12030
12030
|
if (!AGENT_REGISTRY[agent]?.enabled) {
|
|
12031
12031
|
throw new Error(
|
|
12032
12032
|
`Agent "${agent}" is not supported in this codeam-cli version. Upgrade with 'npm i -g codeam-cli@latest'.`
|
|
@@ -12036,10 +12036,10 @@ function createAgentStrategy(agent, os30 = createOsStrategy()) {
|
|
|
12036
12036
|
if (!build) {
|
|
12037
12037
|
throw new Error(`No runtime strategy registered for agent "${agent}"`);
|
|
12038
12038
|
}
|
|
12039
|
-
return build(
|
|
12039
|
+
return build(os31);
|
|
12040
12040
|
}
|
|
12041
|
-
function createInteractiveAgentStrategy(agent,
|
|
12042
|
-
const s = createAgentStrategy(agent,
|
|
12041
|
+
function createInteractiveAgentStrategy(agent, os31 = createOsStrategy()) {
|
|
12042
|
+
const s = createAgentStrategy(agent, os31);
|
|
12043
12043
|
if (s.mode !== "interactive") {
|
|
12044
12044
|
throw new Error(
|
|
12045
12045
|
`Agent "${agent}" is a batch agent; use createAgentStrategy + .runOneShot for one-shot reviews.`
|
|
@@ -14601,9 +14601,49 @@ var RequestError = class _RequestError extends Error {
|
|
|
14601
14601
|
}
|
|
14602
14602
|
};
|
|
14603
14603
|
|
|
14604
|
+
// src/agents/acp/idleTimeout.ts
|
|
14605
|
+
function createIdleTimeout(idleMs, makeError) {
|
|
14606
|
+
let timer;
|
|
14607
|
+
let done = false;
|
|
14608
|
+
let reject;
|
|
14609
|
+
const promise = new Promise((_resolve, rej) => {
|
|
14610
|
+
reject = rej;
|
|
14611
|
+
});
|
|
14612
|
+
const stop = () => {
|
|
14613
|
+
if (timer !== void 0) {
|
|
14614
|
+
clearTimeout(timer);
|
|
14615
|
+
timer = void 0;
|
|
14616
|
+
}
|
|
14617
|
+
};
|
|
14618
|
+
const arm = () => {
|
|
14619
|
+
if (done) return;
|
|
14620
|
+
timer = setTimeout(() => {
|
|
14621
|
+
done = true;
|
|
14622
|
+
reject(makeError());
|
|
14623
|
+
}, idleMs);
|
|
14624
|
+
timer.unref?.();
|
|
14625
|
+
};
|
|
14626
|
+
arm();
|
|
14627
|
+
return {
|
|
14628
|
+
promise,
|
|
14629
|
+
bump: () => {
|
|
14630
|
+
if (done) return;
|
|
14631
|
+
stop();
|
|
14632
|
+
arm();
|
|
14633
|
+
},
|
|
14634
|
+
suspend: () => {
|
|
14635
|
+
stop();
|
|
14636
|
+
},
|
|
14637
|
+
clear: () => {
|
|
14638
|
+
done = true;
|
|
14639
|
+
stop();
|
|
14640
|
+
}
|
|
14641
|
+
};
|
|
14642
|
+
}
|
|
14643
|
+
|
|
14604
14644
|
// src/agents/acp/client.ts
|
|
14605
14645
|
var PROTOCOL_VERSION2 = 1;
|
|
14606
|
-
var
|
|
14646
|
+
var PROMPT_IDLE_TIMEOUT_MS = 9e4;
|
|
14607
14647
|
var CLIENT_CAPABILITIES = {
|
|
14608
14648
|
fs: { readTextFile: true, writeTextFile: true },
|
|
14609
14649
|
terminal: false
|
|
@@ -14617,6 +14657,11 @@ var AcpClient = class {
|
|
|
14617
14657
|
connection = null;
|
|
14618
14658
|
stopping = false;
|
|
14619
14659
|
sessionId = null;
|
|
14660
|
+
/** Idle watchdog for the in-flight prompt. The `Client` handlers
|
|
14661
|
+
* (`sessionUpdate` / `requestPermission`) reach for this to keep
|
|
14662
|
+
* the turn alive while the adapter is demonstrably working. Null
|
|
14663
|
+
* between prompts. */
|
|
14664
|
+
promptIdle = null;
|
|
14620
14665
|
/**
|
|
14621
14666
|
* Spawn the adapter + perform the initial handshake (initialize
|
|
14622
14667
|
* → newSession). Returns the ACP-assigned sessionId so the caller
|
|
@@ -14724,31 +14769,31 @@ var AcpClient = class {
|
|
|
14724
14769
|
sessionId: this.sessionId,
|
|
14725
14770
|
prompt: blocks
|
|
14726
14771
|
});
|
|
14727
|
-
|
|
14728
|
-
|
|
14729
|
-
|
|
14730
|
-
|
|
14731
|
-
|
|
14732
|
-
|
|
14733
|
-
|
|
14734
|
-
);
|
|
14735
|
-
}, PROMPT_TIMEOUT_MS);
|
|
14736
|
-
});
|
|
14772
|
+
const idle = createIdleTimeout(
|
|
14773
|
+
PROMPT_IDLE_TIMEOUT_MS,
|
|
14774
|
+
() => new Error(
|
|
14775
|
+
`ACP prompt idle for ${PROMPT_IDLE_TIMEOUT_MS / 1e3}s \u2014 adapter sent no updates. Likely the underlying agent's auth or network is misconfigured; check the adapter stderr lines above (acpAdapter tag) for the actual error.`
|
|
14776
|
+
)
|
|
14777
|
+
);
|
|
14778
|
+
this.promptIdle = idle;
|
|
14737
14779
|
try {
|
|
14738
|
-
const result = await Promise.race([send,
|
|
14780
|
+
const result = await Promise.race([send, idle.promise]);
|
|
14739
14781
|
log.info(
|
|
14740
14782
|
"acpClient",
|
|
14741
14783
|
`prompt \u2190 ok stopReason=${result.stopReason ?? "?"} elapsedMs=${Date.now() - t0}`
|
|
14742
14784
|
);
|
|
14743
14785
|
return result;
|
|
14744
14786
|
} catch (err) {
|
|
14787
|
+
void send.catch(() => {
|
|
14788
|
+
});
|
|
14745
14789
|
log.warn(
|
|
14746
14790
|
"acpClient",
|
|
14747
14791
|
`prompt \u2190 failed elapsedMs=${Date.now() - t0} err=${err instanceof Error ? err.message : String(err)}`
|
|
14748
14792
|
);
|
|
14749
14793
|
throw err;
|
|
14750
14794
|
} finally {
|
|
14751
|
-
|
|
14795
|
+
idle.clear();
|
|
14796
|
+
this.promptIdle = null;
|
|
14752
14797
|
}
|
|
14753
14798
|
}
|
|
14754
14799
|
/**
|
|
@@ -14837,10 +14882,16 @@ var AcpClient = class {
|
|
|
14837
14882
|
buildClient() {
|
|
14838
14883
|
return {
|
|
14839
14884
|
sessionUpdate: async (params) => {
|
|
14885
|
+
this.promptIdle?.bump();
|
|
14840
14886
|
this.opts.onSessionUpdate(params);
|
|
14841
14887
|
},
|
|
14842
|
-
requestPermission: (params) => {
|
|
14843
|
-
|
|
14888
|
+
requestPermission: async (params) => {
|
|
14889
|
+
this.promptIdle?.suspend();
|
|
14890
|
+
try {
|
|
14891
|
+
return await this.opts.onRequestPermission(params);
|
|
14892
|
+
} finally {
|
|
14893
|
+
this.promptIdle?.bump();
|
|
14894
|
+
}
|
|
14844
14895
|
},
|
|
14845
14896
|
readTextFile: async (params) => {
|
|
14846
14897
|
try {
|
|
@@ -15739,7 +15790,7 @@ function extractSelectPrompt(text) {
|
|
|
15739
15790
|
|
|
15740
15791
|
// src/commands/start/handlers.ts
|
|
15741
15792
|
var fs32 = __toESM(require("fs"));
|
|
15742
|
-
var
|
|
15793
|
+
var os26 = __toESM(require("os"));
|
|
15743
15794
|
var path39 = __toESM(require("path"));
|
|
15744
15795
|
var import_crypto3 = require("crypto");
|
|
15745
15796
|
var import_child_process17 = require("child_process");
|
|
@@ -17493,6 +17544,7 @@ function defaultBeadsHomeDir() {
|
|
|
17493
17544
|
// src/beads/provisioner.ts
|
|
17494
17545
|
var import_child_process15 = require("child_process");
|
|
17495
17546
|
var fs30 = __toESM(require("fs"));
|
|
17547
|
+
var os25 = __toESM(require("os"));
|
|
17496
17548
|
var path36 = __toESM(require("path"));
|
|
17497
17549
|
|
|
17498
17550
|
// src/beads/install-bd.ts
|
|
@@ -17576,26 +17628,47 @@ var _provisionSeam = {
|
|
|
17576
17628
|
};
|
|
17577
17629
|
var _linkSeam = {
|
|
17578
17630
|
platform: () => process.platform,
|
|
17631
|
+
homedir: () => os25.homedir(),
|
|
17632
|
+
isWritableDir: (dir) => {
|
|
17633
|
+
try {
|
|
17634
|
+
fs30.accessSync(dir, fs30.constants.W_OK);
|
|
17635
|
+
return true;
|
|
17636
|
+
} catch {
|
|
17637
|
+
return false;
|
|
17638
|
+
}
|
|
17639
|
+
},
|
|
17640
|
+
ensureDir: (dir) => {
|
|
17641
|
+
fs30.mkdirSync(dir, { recursive: true });
|
|
17642
|
+
},
|
|
17579
17643
|
/**
|
|
17580
|
-
* A directory
|
|
17581
|
-
* SessionStart `bd prime` hook resolve `bd` by name.
|
|
17644
|
+
* A directory to symlink `bd` into so the AGENT's shell + Claude Code's
|
|
17645
|
+
* SessionStart `bd prime` hook resolve `bd` by name. The dir MUST be on the
|
|
17646
|
+
* persistent shell PATH those processes use AND be writable.
|
|
17582
17647
|
*
|
|
17583
|
-
*
|
|
17584
|
-
*
|
|
17585
|
-
*
|
|
17586
|
-
*
|
|
17587
|
-
*
|
|
17588
|
-
*
|
|
17589
|
-
*
|
|
17590
|
-
*
|
|
17648
|
+
* History: v2.35.1 used `dirname(realpath(argv[1]))` (the package `dist/`,
|
|
17649
|
+
* not on PATH); v2.35.2 used `dirname(process.execPath)` — correct for a
|
|
17650
|
+
* normal global npm install, but in a GitHub Codespace `node` lives in a
|
|
17651
|
+
* TRANSIENT bootstrap prefix (`/tmp/codeam-node20/bin`) that is NOT on the
|
|
17652
|
+
* persistent shell PATH, so the hook still failed (validated live). The
|
|
17653
|
+
* dir that IS on PATH and writable in a codespace is `~/.local/bin`.
|
|
17654
|
+
*
|
|
17655
|
+
* Strategy: among [node's bin, ~/.local/bin, /usr/local/bin, entry dir],
|
|
17656
|
+
* pick the first that is BOTH on `$PATH` AND writable. If none qualifies
|
|
17657
|
+
* (codespace: node prefix off-PATH, /usr/local/bin read-only), fall back to
|
|
17658
|
+
* `~/.local/bin` — the standard user bin, on PATH for login shells —
|
|
17659
|
+
* which `linkBdOntoPath` creates if missing.
|
|
17591
17660
|
*/
|
|
17592
17661
|
cliBinDir: () => {
|
|
17593
17662
|
const pathDirs = (process.env.PATH ?? "").split(path36.delimiter).filter(Boolean);
|
|
17663
|
+
const home = _linkSeam.homedir();
|
|
17664
|
+
const localBin = home ? path36.join(home, ".local", "bin") : null;
|
|
17594
17665
|
const candidates = [];
|
|
17595
17666
|
try {
|
|
17596
17667
|
candidates.push(path36.dirname(process.execPath));
|
|
17597
17668
|
} catch {
|
|
17598
17669
|
}
|
|
17670
|
+
if (localBin) candidates.push(localBin);
|
|
17671
|
+
candidates.push("/usr/local/bin");
|
|
17599
17672
|
const entry = process.argv[1];
|
|
17600
17673
|
if (entry) {
|
|
17601
17674
|
try {
|
|
@@ -17604,8 +17677,11 @@ var _linkSeam = {
|
|
|
17604
17677
|
candidates.push(path36.dirname(entry));
|
|
17605
17678
|
}
|
|
17606
17679
|
}
|
|
17607
|
-
|
|
17608
|
-
|
|
17680
|
+
const onPathWritable = candidates.find(
|
|
17681
|
+
(d3) => pathDirs.includes(d3) && _linkSeam.isWritableDir(d3)
|
|
17682
|
+
);
|
|
17683
|
+
if (onPathWritable) return onPathWritable;
|
|
17684
|
+
return localBin ?? candidates[0] ?? null;
|
|
17609
17685
|
},
|
|
17610
17686
|
/** Current symlink target at `linkPath`, or null when absent / not a link. */
|
|
17611
17687
|
readlink: (linkPath) => {
|
|
@@ -17622,6 +17698,7 @@ function linkBdOntoPath(binaryPath) {
|
|
|
17622
17698
|
if (_linkSeam.platform() === "win32") return;
|
|
17623
17699
|
const binDir = _linkSeam.cliBinDir();
|
|
17624
17700
|
if (!binDir) return;
|
|
17701
|
+
_linkSeam.ensureDir(binDir);
|
|
17625
17702
|
const linkPath = path36.join(binDir, "bd");
|
|
17626
17703
|
if (linkPath === binaryPath) return;
|
|
17627
17704
|
const current = _linkSeam.readlink(linkPath);
|
|
@@ -18179,7 +18256,7 @@ function cleanupAttachmentTempFiles() {
|
|
|
18179
18256
|
function saveFilesTemp(files) {
|
|
18180
18257
|
return files.filter(({ base64 }) => base64 && base64.length > 0).map(({ filename, base64 }) => {
|
|
18181
18258
|
const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
|
18182
|
-
const tmpPath = path39.join(
|
|
18259
|
+
const tmpPath = path39.join(os26.tmpdir(), `codeam-${(0, import_crypto3.randomUUID)()}-${safeName}`);
|
|
18183
18260
|
fs32.writeFileSync(tmpPath, Buffer.from(base64, "base64"));
|
|
18184
18261
|
pendingAttachmentFiles.add(tmpPath);
|
|
18185
18262
|
return tmpPath;
|
|
@@ -19215,7 +19292,7 @@ async function dispatchCommand(ctx, cmd) {
|
|
|
19215
19292
|
// src/services/file-watcher.service.ts
|
|
19216
19293
|
var import_child_process18 = require("child_process");
|
|
19217
19294
|
var fs33 = __toESM(require("fs"));
|
|
19218
|
-
var
|
|
19295
|
+
var os27 = __toESM(require("os"));
|
|
19219
19296
|
var path40 = __toESM(require("path"));
|
|
19220
19297
|
var import_ignore = __toESM(require("ignore"));
|
|
19221
19298
|
|
|
@@ -19326,10 +19403,10 @@ var WINDOWS_LEGACY_JUNCTIONS = [
|
|
|
19326
19403
|
/[\\/]Start Menu([\\/]|$)/i,
|
|
19327
19404
|
/[\\/]Templates([\\/]|$)/i
|
|
19328
19405
|
];
|
|
19329
|
-
function isUnsafeWindowsWatchRoot(dir,
|
|
19406
|
+
function isUnsafeWindowsWatchRoot(dir, homedir23) {
|
|
19330
19407
|
const norm = (p2) => p2.replace(/\//g, "\\").replace(/\\+$/, "").toLowerCase();
|
|
19331
19408
|
const cwd = norm(dir);
|
|
19332
|
-
const home = norm(
|
|
19409
|
+
const home = norm(homedir23);
|
|
19333
19410
|
if (cwd === home) return true;
|
|
19334
19411
|
if (/^[a-z]:$/.test(cwd)) return true;
|
|
19335
19412
|
const sysRoots = [
|
|
@@ -19428,7 +19505,7 @@ var FileWatcherService = class {
|
|
|
19428
19505
|
throw new Error("FileWatcherService has already been stopped \u2014 re-instantiate to restart.");
|
|
19429
19506
|
}
|
|
19430
19507
|
const isWin = process.platform === "win32";
|
|
19431
|
-
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir,
|
|
19508
|
+
if (isWin && isUnsafeWindowsWatchRoot(this.opts.workingDir, os27.homedir())) {
|
|
19432
19509
|
log.warn(
|
|
19433
19510
|
"fileWatcher",
|
|
19434
19511
|
`refusing to watch ${this.opts.workingDir} \u2014 looks like a Windows user-profile or system path. Run codeam from your project folder to enable file change emission.`
|
|
@@ -22074,7 +22151,7 @@ var OutputService = class _OutputService {
|
|
|
22074
22151
|
// src/services/history.service.ts
|
|
22075
22152
|
var fs35 = __toESM(require("fs"));
|
|
22076
22153
|
var path43 = __toESM(require("path"));
|
|
22077
|
-
var
|
|
22154
|
+
var os28 = __toESM(require("os"));
|
|
22078
22155
|
var https7 = __toESM(require("https"));
|
|
22079
22156
|
var http7 = __toESM(require("http"));
|
|
22080
22157
|
var import_zod2 = require("zod");
|
|
@@ -22236,7 +22313,7 @@ var HistoryService = class _HistoryService {
|
|
|
22236
22313
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
22237
22314
|
}
|
|
22238
22315
|
get projectDir() {
|
|
22239
|
-
return this.runtime.resolveHistoryDir(this.cwd) ?? path43.join(
|
|
22316
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path43.join(os28.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
22240
22317
|
}
|
|
22241
22318
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
22242
22319
|
setCurrentConversationId(id) {
|
|
@@ -23442,7 +23519,7 @@ async function autoLinkAfterPair(opts) {
|
|
|
23442
23519
|
|
|
23443
23520
|
// src/commands/pair-auto.ts
|
|
23444
23521
|
var fs36 = __toESM(require("fs"));
|
|
23445
|
-
var
|
|
23522
|
+
var os29 = __toESM(require("os"));
|
|
23446
23523
|
var import_crypto7 = require("crypto");
|
|
23447
23524
|
|
|
23448
23525
|
// src/commands/start-infra-only.ts
|
|
@@ -23668,7 +23745,7 @@ async function claimOnce(token, pluginId) {
|
|
|
23668
23745
|
pluginId,
|
|
23669
23746
|
ideName: "codeam-cli (codespace)",
|
|
23670
23747
|
ideVersion: process.env.npm_package_version ?? "unknown",
|
|
23671
|
-
hostname:
|
|
23748
|
+
hostname: os29.hostname(),
|
|
23672
23749
|
codespaceName: process.env.CODESPACE_NAME ?? "",
|
|
23673
23750
|
// Current git branch of the codespace's working directory, so the
|
|
23674
23751
|
// backend can populate `PairedSession.branch` for the codespace pair.
|
|
@@ -25953,9 +26030,9 @@ function checkSessions() {
|
|
|
25953
26030
|
}
|
|
25954
26031
|
}
|
|
25955
26032
|
function checkAgentBinaries() {
|
|
25956
|
-
const
|
|
26033
|
+
const os31 = createOsStrategy();
|
|
25957
26034
|
return getEnabledAgents().map((meta) => {
|
|
25958
|
-
const found =
|
|
26035
|
+
const found = os31.findInPath(meta.binaryName);
|
|
25959
26036
|
return {
|
|
25960
26037
|
id: `agent-${meta.id}`,
|
|
25961
26038
|
label: `Agent binary: ${meta.displayName} (${meta.binaryName})`,
|
|
@@ -26019,7 +26096,7 @@ function checkChokidar() {
|
|
|
26019
26096
|
}
|
|
26020
26097
|
async function doctor(args2 = []) {
|
|
26021
26098
|
const json = args2.includes("--json");
|
|
26022
|
-
const cliVersion = true ? "2.35.
|
|
26099
|
+
const cliVersion = true ? "2.35.4" : "0.0.0-dev";
|
|
26023
26100
|
const apiBase = resolveApiBaseUrl();
|
|
26024
26101
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
26025
26102
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -26218,7 +26295,7 @@ async function completion(args2) {
|
|
|
26218
26295
|
// src/commands/version.ts
|
|
26219
26296
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
26220
26297
|
function version2() {
|
|
26221
|
-
const v = true ? "2.35.
|
|
26298
|
+
const v = true ? "2.35.4" : "unknown";
|
|
26222
26299
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
26223
26300
|
}
|
|
26224
26301
|
|
|
@@ -26347,7 +26424,7 @@ var _subcommandHelpKeys = Object.keys(HELPS);
|
|
|
26347
26424
|
|
|
26348
26425
|
// src/lib/updateNotifier.ts
|
|
26349
26426
|
var fs38 = __toESM(require("fs"));
|
|
26350
|
-
var
|
|
26427
|
+
var os30 = __toESM(require("os"));
|
|
26351
26428
|
var path49 = __toESM(require("path"));
|
|
26352
26429
|
var https8 = __toESM(require("https"));
|
|
26353
26430
|
var import_node_child_process12 = require("child_process");
|
|
@@ -26357,7 +26434,7 @@ var REGISTRY_URL = `https://registry.npmjs.org/${PKG_NAME}/latest`;
|
|
|
26357
26434
|
var TTL_MS = 24 * 60 * 60 * 1e3;
|
|
26358
26435
|
var REQUEST_TIMEOUT_MS = 1500;
|
|
26359
26436
|
function cachePath() {
|
|
26360
|
-
const dir = path49.join(
|
|
26437
|
+
const dir = path49.join(os30.homedir(), ".codeam");
|
|
26361
26438
|
return path49.join(dir, "update-check.json");
|
|
26362
26439
|
}
|
|
26363
26440
|
function readCache() {
|
|
@@ -26504,7 +26581,7 @@ function checkForUpdates() {
|
|
|
26504
26581
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
26505
26582
|
if (process.env.CI) return;
|
|
26506
26583
|
if (!process.stdout.isTTY) return;
|
|
26507
|
-
const current = true ? "2.35.
|
|
26584
|
+
const current = true ? "2.35.4" : null;
|
|
26508
26585
|
if (!current) return;
|
|
26509
26586
|
const cache = readCache();
|
|
26510
26587
|
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.35.
|
|
3
|
+
"version": "2.35.4",
|
|
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",
|