codeam-cli 2.61.4 → 2.61.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 +19 -0
- package/dist/index.js +209 -75
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,25 @@ 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.61.5] — 2026-07-16
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **cli:** ACP chrome-leak canary + detector (stability monitor, part 2)
|
|
12
|
+
- **ci:** Canary seeds onboarding + auths via in-house MiniMax backend
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **ci:** Canary auths by subscription (CLAUDE_CODE_OAUTH_TOKEN), not API key
|
|
17
|
+
- **cli:** Stop the changeset reporter from spamming install/SDK files
|
|
18
|
+
|
|
19
|
+
## [2.61.4] — 2026-07-16
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- **box:** Add unzip for CodeRabbit install (curl alone insufficient)
|
|
24
|
+
- **cli:** Bump ACP stack to latest + freeze claude binary (broken-chat fix)
|
|
25
|
+
|
|
7
26
|
## [2.61.3] — 2026-07-16
|
|
8
27
|
|
|
9
28
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -1073,11 +1073,11 @@ function quiet(fn) {
|
|
|
1073
1073
|
log.debug(TAG, "ignored sync error", err);
|
|
1074
1074
|
}
|
|
1075
1075
|
}
|
|
1076
|
-
function rmIfExistsQuiet(
|
|
1076
|
+
function rmIfExistsQuiet(path76) {
|
|
1077
1077
|
try {
|
|
1078
|
-
fs2.rmSync(
|
|
1078
|
+
fs2.rmSync(path76, { force: true });
|
|
1079
1079
|
} catch (err) {
|
|
1080
|
-
log.debug(TAG, `rmIfExists failed for ${
|
|
1080
|
+
log.debug(TAG, `rmIfExists failed for ${path76}`, err);
|
|
1081
1081
|
}
|
|
1082
1082
|
}
|
|
1083
1083
|
function killQuiet(target, signal = "SIGTERM") {
|
|
@@ -1261,8 +1261,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
1261
1261
|
return decodedFile;
|
|
1262
1262
|
};
|
|
1263
1263
|
}
|
|
1264
|
-
function normalizeWindowsPath(
|
|
1265
|
-
return
|
|
1264
|
+
function normalizeWindowsPath(path76) {
|
|
1265
|
+
return path76.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
1266
1266
|
}
|
|
1267
1267
|
|
|
1268
1268
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3742,9 +3742,9 @@ async function addSourceContext(frames) {
|
|
|
3742
3742
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3743
3743
|
return frames;
|
|
3744
3744
|
}
|
|
3745
|
-
function getContextLinesFromFile(
|
|
3745
|
+
function getContextLinesFromFile(path76, ranges, output) {
|
|
3746
3746
|
return new Promise((resolve8) => {
|
|
3747
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3747
|
+
const stream = (0, import_node_fs.createReadStream)(path76);
|
|
3748
3748
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3749
3749
|
input: stream
|
|
3750
3750
|
});
|
|
@@ -3759,7 +3759,7 @@ function getContextLinesFromFile(path75, ranges, output) {
|
|
|
3759
3759
|
let rangeStart = range[0];
|
|
3760
3760
|
let rangeEnd = range[1];
|
|
3761
3761
|
function onStreamError() {
|
|
3762
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3762
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path76, 1);
|
|
3763
3763
|
lineReaded.close();
|
|
3764
3764
|
lineReaded.removeAllListeners();
|
|
3765
3765
|
destroyStreamAndResolve();
|
|
@@ -3820,8 +3820,8 @@ function clearLineContext(frame) {
|
|
|
3820
3820
|
delete frame.context_line;
|
|
3821
3821
|
delete frame.post_context;
|
|
3822
3822
|
}
|
|
3823
|
-
function shouldSkipContextLinesForFile(
|
|
3824
|
-
return
|
|
3823
|
+
function shouldSkipContextLinesForFile(path76) {
|
|
3824
|
+
return path76.startsWith("node:") || path76.endsWith(".min.js") || path76.endsWith(".min.cjs") || path76.endsWith(".min.mjs") || path76.startsWith("data:");
|
|
3825
3825
|
}
|
|
3826
3826
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3827
3827
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -5975,7 +5975,7 @@ function readAnonId() {
|
|
|
5975
5975
|
}
|
|
5976
5976
|
function superProperties() {
|
|
5977
5977
|
return {
|
|
5978
|
-
cliVersion: true ? "2.61.
|
|
5978
|
+
cliVersion: true ? "2.61.7" : "0.0.0-dev",
|
|
5979
5979
|
nodeVersion: process.version,
|
|
5980
5980
|
platform: process.platform,
|
|
5981
5981
|
arch: process.arch,
|
|
@@ -6156,7 +6156,7 @@ var os4 = __toESM(require("os"));
|
|
|
6156
6156
|
// package.json
|
|
6157
6157
|
var package_default = {
|
|
6158
6158
|
name: "codeam-cli",
|
|
6159
|
-
version: "2.61.
|
|
6159
|
+
version: "2.61.7",
|
|
6160
6160
|
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.",
|
|
6161
6161
|
type: "commonjs",
|
|
6162
6162
|
main: "dist/index.js",
|
|
@@ -6225,7 +6225,7 @@ var package_default = {
|
|
|
6225
6225
|
url: "https://github.com/sponsors/edgar-durand"
|
|
6226
6226
|
},
|
|
6227
6227
|
engines: {
|
|
6228
|
-
node: ">=
|
|
6228
|
+
node: ">=22.0.0"
|
|
6229
6229
|
},
|
|
6230
6230
|
dependencies: {
|
|
6231
6231
|
"@agentclientprotocol/claude-agent-acp": "0.59.0",
|
|
@@ -7299,7 +7299,7 @@ var CommandRelayService = class _CommandRelayService {
|
|
|
7299
7299
|
// fresh + clear the "CLI update available" banner after a self-update
|
|
7300
7300
|
// (a codespace that reinstalls @latest reconnects via heartbeat, not
|
|
7301
7301
|
// pair/reconnect). Older backends ignore the extra field.
|
|
7302
|
-
..."2.61.
|
|
7302
|
+
..."2.61.7" ? { ideVersion: "2.61.7" } : {}
|
|
7303
7303
|
}).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
|
|
7304
7304
|
}
|
|
7305
7305
|
/**
|
|
@@ -13885,8 +13885,8 @@ function pickLine(obj) {
|
|
|
13885
13885
|
function toHunk(raw, groupSeverity) {
|
|
13886
13886
|
if (!raw || typeof raw !== "object") return null;
|
|
13887
13887
|
const o = raw;
|
|
13888
|
-
const
|
|
13889
|
-
if (!
|
|
13888
|
+
const path76 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
|
|
13889
|
+
if (!path76) return null;
|
|
13890
13890
|
const message = asString(
|
|
13891
13891
|
pick(o, [
|
|
13892
13892
|
"comment",
|
|
@@ -13903,7 +13903,7 @@ function toHunk(raw, groupSeverity) {
|
|
|
13903
13903
|
const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
|
|
13904
13904
|
const locObj = pick(o, ["location"]) ?? o;
|
|
13905
13905
|
return {
|
|
13906
|
-
path:
|
|
13906
|
+
path: path76.trim(),
|
|
13907
13907
|
line: pickLine(o) ?? pickLine(locObj),
|
|
13908
13908
|
severity,
|
|
13909
13909
|
message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
|
|
@@ -13986,10 +13986,10 @@ function parsePlain(stdout) {
|
|
|
13986
13986
|
for (const line of stdout.split(/\r?\n/)) {
|
|
13987
13987
|
const m = line.match(HUNK_LINE_RE);
|
|
13988
13988
|
if (!m) continue;
|
|
13989
|
-
const [,
|
|
13990
|
-
if (!
|
|
13989
|
+
const [, path76, lineNo, sevToken, message] = m;
|
|
13990
|
+
if (!path76 || !lineNo || !message) continue;
|
|
13991
13991
|
hunks.push({
|
|
13992
|
-
path:
|
|
13992
|
+
path: path76.trim(),
|
|
13993
13993
|
line: Number(lineNo),
|
|
13994
13994
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
13995
13995
|
message: message.trim().replace(/^[*-]\s+/, "")
|
|
@@ -17900,7 +17900,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
17900
17900
|
if (process.env.NODE_ENV === "test") return;
|
|
17901
17901
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17902
17902
|
if (process.env.CI) return;
|
|
17903
|
-
const current = true ? "2.61.
|
|
17903
|
+
const current = true ? "2.61.7" : null;
|
|
17904
17904
|
if (!current) return;
|
|
17905
17905
|
const cache = readCache();
|
|
17906
17906
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17917,7 +17917,7 @@ function checkForUpdates() {
|
|
|
17917
17917
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
17918
17918
|
if (process.env.CI) return;
|
|
17919
17919
|
if (!process.stdout.isTTY) return;
|
|
17920
|
-
const current = true ? "2.61.
|
|
17920
|
+
const current = true ? "2.61.7" : null;
|
|
17921
17921
|
if (!current) return;
|
|
17922
17922
|
const cache = readCache();
|
|
17923
17923
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -17937,7 +17937,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
|
17937
17937
|
var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
|
|
17938
17938
|
var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
|
|
17939
17939
|
function currentCliVersion() {
|
|
17940
|
-
return true ? "2.61.
|
|
17940
|
+
return true ? "2.61.7" : null;
|
|
17941
17941
|
}
|
|
17942
17942
|
function runCmd(cmd, args2, timeoutMs) {
|
|
17943
17943
|
return new Promise((resolve8) => {
|
|
@@ -18254,6 +18254,12 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process23.s
|
|
|
18254
18254
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18255
18255
|
detached: false
|
|
18256
18256
|
});
|
|
18257
|
+
var defaultResumeSpawner = (env, cwd) => (0, import_node_child_process23.spawn)(process.execPath, [process.argv[1]], {
|
|
18258
|
+
cwd,
|
|
18259
|
+
env: { ...process.env, ...env, CODEAM_AUTO_APPROVE: "1" },
|
|
18260
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
18261
|
+
detached: false
|
|
18262
|
+
});
|
|
18257
18263
|
var defaultOnIdentityRejected = () => {
|
|
18258
18264
|
deleteHostIdentity();
|
|
18259
18265
|
log.warn("host-agent", "host identity rejected by backend \u2014 wiped sealed identity, exiting");
|
|
@@ -18268,6 +18274,7 @@ var HostAgentSupervisor = class {
|
|
|
18268
18274
|
this.identity = identity;
|
|
18269
18275
|
this.deps = deps;
|
|
18270
18276
|
this.spawnChild = deps.spawnChild ?? defaultSpawner;
|
|
18277
|
+
this.resumeSpawner = deps.resumeSpawner ?? defaultResumeSpawner;
|
|
18271
18278
|
this.resolveAgentAuth = deps.resolveAgentAuth ?? unsealAgentAuth;
|
|
18272
18279
|
this.setupHeadroom = deps.setupHeadroom ?? setupHeadroomForSelfHosted;
|
|
18273
18280
|
this.isHeadroomInstalled = deps.isHeadroomInstalled ?? (() => defaultHeadroomRunner.which("headroom"));
|
|
@@ -18284,6 +18291,7 @@ var HostAgentSupervisor = class {
|
|
|
18284
18291
|
deps;
|
|
18285
18292
|
children = /* @__PURE__ */ new Map();
|
|
18286
18293
|
spawnChild;
|
|
18294
|
+
resumeSpawner;
|
|
18287
18295
|
resolveAgentAuth;
|
|
18288
18296
|
setupHeadroom;
|
|
18289
18297
|
/** Probe whether Headroom is already installed (defaults to `which headroom`). */
|
|
@@ -18344,6 +18352,7 @@ var HostAgentSupervisor = class {
|
|
|
18344
18352
|
void this.beat();
|
|
18345
18353
|
this.heartbeatTimer = setInterval(() => void this.beat(), HEARTBEAT_INTERVAL_MS);
|
|
18346
18354
|
this.heartbeatTimer.unref?.();
|
|
18355
|
+
this.resumePersistedSession();
|
|
18347
18356
|
void reportSessionEvent(
|
|
18348
18357
|
{ hostId: this.identity.hostId, hostToken: this.identity.hostToken },
|
|
18349
18358
|
{ event: "reconcile", activeDeployIds: this.activeSessions().map((s) => s.id) }
|
|
@@ -18933,6 +18942,60 @@ var HostAgentSupervisor = class {
|
|
|
18933
18942
|
spawnSessionChild(env, cwd, args2 = []) {
|
|
18934
18943
|
return this.spawnChild({ ...env, ...readHeadroomChildEnv() }, cwd, args2);
|
|
18935
18944
|
}
|
|
18945
|
+
/**
|
|
18946
|
+
* Auto-resume the user's last active session on supervisor boot (2026-07-16
|
|
18947
|
+
* churn fix). Before this, a restart / self-update killed the session child
|
|
18948
|
+
* and never re-spawned it — the session lost its heartbeat, went "CLI
|
|
18949
|
+
* disconnected", and the user had to reconnect by hand (churn right after an
|
|
18950
|
+
* update). Spawn bare `codeam` via the resume spawner (reconnects the SAME
|
|
18951
|
+
* pluginId via start(), then heartbeats) so the session comes back on its own
|
|
18952
|
+
* in its ORIGINAL ACP shape (self-hosted/codespace = ACP-only; the resume
|
|
18953
|
+
* spawner sets CODEAM_AUTO_APPROVE=1 to keep the local baton/native-TUI OFF).
|
|
18954
|
+
*
|
|
18955
|
+
* Best-effort + guarded: no-op when there's no persisted session, when the
|
|
18956
|
+
* persisted session lacks the reconnect material (pluginId + pollSecret +
|
|
18957
|
+
* agent), or when a fresh deploy already owns a child this boot.
|
|
18958
|
+
*/
|
|
18959
|
+
resumePersistedSession() {
|
|
18960
|
+
try {
|
|
18961
|
+
if (this.children.size > 0) return;
|
|
18962
|
+
const session = getActiveSession();
|
|
18963
|
+
if (!session || !session.pluginId || !session.pollSecret || !session.agent) return;
|
|
18964
|
+
const cwd = process.cwd();
|
|
18965
|
+
const proc = this.resumeSpawner({ ...readHeadroomChildEnv() }, cwd);
|
|
18966
|
+
const child = {
|
|
18967
|
+
deployId: session.id,
|
|
18968
|
+
proc,
|
|
18969
|
+
agent: session.agent,
|
|
18970
|
+
startedAt: Date.now()
|
|
18971
|
+
};
|
|
18972
|
+
this.children.set(session.id, child);
|
|
18973
|
+
let tail = "";
|
|
18974
|
+
const appendTail = (buf) => {
|
|
18975
|
+
tail = (tail + buf.toString("utf8")).slice(-2e3);
|
|
18976
|
+
};
|
|
18977
|
+
proc.stdout?.on("data", appendTail);
|
|
18978
|
+
proc.stderr?.on("data", appendTail);
|
|
18979
|
+
proc.once("exit", (code) => {
|
|
18980
|
+
if (this.children.get(session.id)?.proc === proc) this.children.delete(session.id);
|
|
18981
|
+
if (typeof code === "number" && code !== 0) {
|
|
18982
|
+
log.warn(
|
|
18983
|
+
"host-agent",
|
|
18984
|
+
`resumed session ${session.id.slice(0, 8)} exited (${code}): ${tail.trim().slice(-300)}`
|
|
18985
|
+
);
|
|
18986
|
+
}
|
|
18987
|
+
});
|
|
18988
|
+
log.info(
|
|
18989
|
+
"host-agent",
|
|
18990
|
+
`resumed session ${session.id.slice(0, 8)} pluginId=${session.pluginId.slice(0, 12)} (ACP)`
|
|
18991
|
+
);
|
|
18992
|
+
} catch (err) {
|
|
18993
|
+
log.warn(
|
|
18994
|
+
"host-agent",
|
|
18995
|
+
`resume persisted session failed (best-effort): ${err instanceof Error ? err.message : String(err)}`
|
|
18996
|
+
);
|
|
18997
|
+
}
|
|
18998
|
+
}
|
|
18936
18999
|
/**
|
|
18937
19000
|
* Run the backend-supplied per-agent CLI install script (e.g.
|
|
18938
19001
|
* `claude.ai/install.sh`, `npm i -g @openai/codex`). Best-effort + bounded:
|
|
@@ -23396,11 +23459,11 @@ function resolveTokenValue(args2) {
|
|
|
23396
23459
|
}
|
|
23397
23460
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
23398
23461
|
if (fileFlag) {
|
|
23399
|
-
const
|
|
23462
|
+
const path76 = fileFlag.slice("--token-file=".length);
|
|
23400
23463
|
try {
|
|
23401
|
-
const content = fs56.readFileSync(
|
|
23402
|
-
if (content.length === 0) fail(`--token-file ${
|
|
23403
|
-
rmIfExistsQuiet(
|
|
23464
|
+
const content = fs56.readFileSync(path76, "utf8").trim();
|
|
23465
|
+
if (content.length === 0) fail(`--token-file ${path76} is empty`);
|
|
23466
|
+
rmIfExistsQuiet(path76);
|
|
23404
23467
|
return content;
|
|
23405
23468
|
} catch (err) {
|
|
23406
23469
|
fail(`Could not read --token-file: ${err.message}`);
|
|
@@ -30442,8 +30505,67 @@ var import_crypto5 = require("crypto");
|
|
|
30442
30505
|
|
|
30443
30506
|
// src/services/turn-files/git-changeset.ts
|
|
30444
30507
|
var import_child_process28 = require("child_process");
|
|
30445
|
-
var
|
|
30508
|
+
var fs62 = __toESM(require("fs/promises"));
|
|
30509
|
+
var path67 = __toESM(require("path"));
|
|
30510
|
+
|
|
30511
|
+
// src/services/turn-files/review-ignore.ts
|
|
30512
|
+
var import_ignore2 = __toESM(require("ignore"));
|
|
30513
|
+
var fs61 = __toESM(require("fs"));
|
|
30446
30514
|
var path66 = __toESM(require("path"));
|
|
30515
|
+
var CURATED_REVIEW_IGNORE = [
|
|
30516
|
+
// Google Cloud SDK (the incident) — installs a huge python tree.
|
|
30517
|
+
"google-cloud-sdk/",
|
|
30518
|
+
"**/google-cloud-sdk/**",
|
|
30519
|
+
".config/gcloud/",
|
|
30520
|
+
// Python package installs that land outside a venv (which is already covered).
|
|
30521
|
+
"**/site-packages/**",
|
|
30522
|
+
"**/dist-packages/**",
|
|
30523
|
+
"__pypackages__/",
|
|
30524
|
+
".local/lib/",
|
|
30525
|
+
"**/.local/lib/**",
|
|
30526
|
+
"pip-wheel-metadata/",
|
|
30527
|
+
// JS package-manager stores/caches not already in isIgnoredFilePath's regex.
|
|
30528
|
+
".pnpm-store/",
|
|
30529
|
+
"**/.pnpm-store/**",
|
|
30530
|
+
".yarn/cache/",
|
|
30531
|
+
".yarn/unplugged/",
|
|
30532
|
+
".bun/",
|
|
30533
|
+
// Language toolchains dropped into $HOME/a project dir.
|
|
30534
|
+
".rustup/",
|
|
30535
|
+
".cargo/registry/",
|
|
30536
|
+
".cargo/git/",
|
|
30537
|
+
"go/pkg/",
|
|
30538
|
+
".nvm/",
|
|
30539
|
+
".rbenv/",
|
|
30540
|
+
".pyenv/",
|
|
30541
|
+
".sdkman/",
|
|
30542
|
+
// Cloud / infra CLIs with bundled trees.
|
|
30543
|
+
".azure/",
|
|
30544
|
+
".aws/cli/",
|
|
30545
|
+
"awscli/",
|
|
30546
|
+
// CodeAgent's own runtime prefixes (never a user change).
|
|
30547
|
+
".codeam/",
|
|
30548
|
+
"codeam-node20/"
|
|
30549
|
+
];
|
|
30550
|
+
function makeReviewIgnore(repoRoot) {
|
|
30551
|
+
const ig = (0, import_ignore2.default)().add(CURATED_REVIEW_IGNORE);
|
|
30552
|
+
try {
|
|
30553
|
+
const custom = fs61.readFileSync(path66.join(repoRoot, ".codeam", "reviewignore"), "utf8");
|
|
30554
|
+
ig.add(custom);
|
|
30555
|
+
} catch {
|
|
30556
|
+
}
|
|
30557
|
+
return (relPath) => {
|
|
30558
|
+
if (!relPath) return false;
|
|
30559
|
+
try {
|
|
30560
|
+
return ig.ignores(relPath);
|
|
30561
|
+
} catch (err) {
|
|
30562
|
+
log.trace("review-ignore", `ignores() threw for "${relPath}"`, err);
|
|
30563
|
+
return false;
|
|
30564
|
+
}
|
|
30565
|
+
};
|
|
30566
|
+
}
|
|
30567
|
+
|
|
30568
|
+
// src/services/turn-files/git-changeset.ts
|
|
30447
30569
|
async function collectRepoChangeset(opts) {
|
|
30448
30570
|
const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
|
|
30449
30571
|
if (status2 === null) return null;
|
|
@@ -30454,14 +30576,26 @@ async function collectRepoChangeset(opts) {
|
|
|
30454
30576
|
"HEAD"
|
|
30455
30577
|
]).catch(() => null);
|
|
30456
30578
|
const numstat = parseNumstat(numstatRaw ?? "");
|
|
30579
|
+
const reviewIgnore = makeReviewIgnore(opts.repoRoot);
|
|
30580
|
+
const rows = parseStatus(status2).filter(
|
|
30581
|
+
(row) => !isIgnoredFilePath(row.filePath) && !reviewIgnore(row.filePath)
|
|
30582
|
+
);
|
|
30583
|
+
const MAX_CHANGESET_FILES = Math.max(1, Number(process.env.CODEAM_MAX_CHANGESET_FILES ?? 500));
|
|
30584
|
+
const truncated = rows.length > MAX_CHANGESET_FILES;
|
|
30585
|
+
const bounded = truncated ? rows.slice(0, MAX_CHANGESET_FILES) : rows;
|
|
30586
|
+
if (truncated) {
|
|
30587
|
+
log.warn(
|
|
30588
|
+
"changeset",
|
|
30589
|
+
`${rows.length} changed files exceeds the ${MAX_CHANGESET_FILES}-file cap \u2014 reporting the first ${MAX_CHANGESET_FILES} only. This usually means a dependency/SDK/build install landed in the session's working directory; add it to .gitignore to remove it from reviews.`
|
|
30590
|
+
);
|
|
30591
|
+
}
|
|
30457
30592
|
const entries = [];
|
|
30458
|
-
for (const row of
|
|
30459
|
-
if (isIgnoredFilePath(row.filePath)) continue;
|
|
30593
|
+
for (const row of bounded) {
|
|
30460
30594
|
const numstatEntry = numstat.get(row.filePath);
|
|
30461
30595
|
let stats;
|
|
30462
|
-
if (row.fileStatus === "added" && numstatEntry === void 0) {
|
|
30596
|
+
if (!truncated && row.fileStatus === "added" && numstatEntry === void 0) {
|
|
30463
30597
|
const lineCount = await readUntrackedLineCount(
|
|
30464
|
-
|
|
30598
|
+
path67.join(opts.repoRoot, row.filePath)
|
|
30465
30599
|
);
|
|
30466
30600
|
stats = { added: lineCount, removed: 0 };
|
|
30467
30601
|
} else {
|
|
@@ -30492,7 +30626,7 @@ function readUntrackedLineCount(absPath) {
|
|
|
30492
30626
|
}
|
|
30493
30627
|
async function defaultReadUntrackedLineCount(absPath) {
|
|
30494
30628
|
try {
|
|
30495
|
-
const content = await
|
|
30629
|
+
const content = await fs62.readFile(absPath, "utf8");
|
|
30496
30630
|
let count = 0;
|
|
30497
30631
|
let pos = -1;
|
|
30498
30632
|
while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
|
|
@@ -30584,7 +30718,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
30584
30718
|
});
|
|
30585
30719
|
}
|
|
30586
30720
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
30587
|
-
const
|
|
30721
|
+
const fs67 = await import("fs/promises");
|
|
30588
30722
|
const out2 = [];
|
|
30589
30723
|
await walk(workingDir, 0);
|
|
30590
30724
|
return out2;
|
|
@@ -30592,7 +30726,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
30592
30726
|
if (depth > maxDepth) return;
|
|
30593
30727
|
let entries = [];
|
|
30594
30728
|
try {
|
|
30595
|
-
const dirents = await
|
|
30729
|
+
const dirents = await fs67.readdir(dir, { withFileTypes: true });
|
|
30596
30730
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
30597
30731
|
} catch {
|
|
30598
30732
|
return;
|
|
@@ -30603,8 +30737,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
30603
30737
|
if (hasGit) {
|
|
30604
30738
|
out2.push({
|
|
30605
30739
|
repoRoot: dir,
|
|
30606
|
-
repoPath:
|
|
30607
|
-
repoName:
|
|
30740
|
+
repoPath: path67.relative(workingDir, dir),
|
|
30741
|
+
repoName: path67.basename(dir)
|
|
30608
30742
|
});
|
|
30609
30743
|
return;
|
|
30610
30744
|
}
|
|
@@ -30612,14 +30746,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
30612
30746
|
if (!entry.isDirectory) continue;
|
|
30613
30747
|
if (entry.name === "node_modules") continue;
|
|
30614
30748
|
if (entry.name === "dist" || entry.name === "build") continue;
|
|
30615
|
-
await walk(
|
|
30749
|
+
await walk(path67.join(dir, entry.name), depth + 1);
|
|
30616
30750
|
}
|
|
30617
30751
|
}
|
|
30618
30752
|
}
|
|
30619
30753
|
|
|
30620
30754
|
// src/services/turn-files/files-outbox.ts
|
|
30621
|
-
var
|
|
30622
|
-
var
|
|
30755
|
+
var fs63 = __toESM(require("fs/promises"));
|
|
30756
|
+
var path68 = __toESM(require("path"));
|
|
30623
30757
|
var import_os11 = require("os");
|
|
30624
30758
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
30625
30759
|
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -30652,16 +30786,16 @@ var FilesOutbox = class {
|
|
|
30652
30786
|
backoffIndex = 0;
|
|
30653
30787
|
stopped = false;
|
|
30654
30788
|
constructor(opts) {
|
|
30655
|
-
const base = opts.baseDir ??
|
|
30656
|
-
this.filePath =
|
|
30789
|
+
const base = opts.baseDir ?? path68.join(homeDir(), HOME_OUTBOX_DIR);
|
|
30790
|
+
this.filePath = path68.join(base, `${opts.sessionId}.jsonl`);
|
|
30657
30791
|
this.post = opts.post;
|
|
30658
30792
|
this.autoSchedule = opts.autoSchedule !== false;
|
|
30659
30793
|
}
|
|
30660
30794
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
30661
30795
|
* line is durable on disk (not once the POST succeeds). */
|
|
30662
30796
|
async enqueue(entry) {
|
|
30663
|
-
await
|
|
30664
|
-
await
|
|
30797
|
+
await fs63.mkdir(path68.dirname(this.filePath), { recursive: true });
|
|
30798
|
+
await fs63.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
30665
30799
|
this.backoffIndex = 0;
|
|
30666
30800
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
30667
30801
|
}
|
|
@@ -30752,7 +30886,7 @@ var FilesOutbox = class {
|
|
|
30752
30886
|
async readAll() {
|
|
30753
30887
|
let raw = "";
|
|
30754
30888
|
try {
|
|
30755
|
-
raw = await
|
|
30889
|
+
raw = await fs63.readFile(this.filePath, "utf8");
|
|
30756
30890
|
} catch {
|
|
30757
30891
|
return [];
|
|
30758
30892
|
}
|
|
@@ -30776,12 +30910,12 @@ var FilesOutbox = class {
|
|
|
30776
30910
|
async rewrite(entries) {
|
|
30777
30911
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
30778
30912
|
if (entries.length === 0) {
|
|
30779
|
-
await
|
|
30913
|
+
await fs63.unlink(this.filePath).catch(() => void 0);
|
|
30780
30914
|
return;
|
|
30781
30915
|
}
|
|
30782
30916
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
30783
|
-
await
|
|
30784
|
-
await
|
|
30917
|
+
await fs63.writeFile(tmpPath, payload, "utf8");
|
|
30918
|
+
await fs63.rename(tmpPath, this.filePath);
|
|
30785
30919
|
}
|
|
30786
30920
|
};
|
|
30787
30921
|
function applyJitter(ms) {
|
|
@@ -33942,7 +34076,7 @@ var AcpDriver = class {
|
|
|
33942
34076
|
};
|
|
33943
34077
|
|
|
33944
34078
|
// src/baton/transcript-mirror.ts
|
|
33945
|
-
var
|
|
34079
|
+
var fs64 = __toESM(require("fs"));
|
|
33946
34080
|
var TranscriptMirror = class {
|
|
33947
34081
|
constructor(deps) {
|
|
33948
34082
|
this.deps = deps;
|
|
@@ -34009,7 +34143,7 @@ var TranscriptMirror = class {
|
|
|
34009
34143
|
}
|
|
34010
34144
|
};
|
|
34011
34145
|
function defaultWatch(file, onChange) {
|
|
34012
|
-
const w3 =
|
|
34146
|
+
const w3 = fs64.watch(file, { persistent: false }, () => onChange());
|
|
34013
34147
|
return () => w3.close();
|
|
34014
34148
|
}
|
|
34015
34149
|
|
|
@@ -34271,16 +34405,16 @@ function toEpochMs(ts) {
|
|
|
34271
34405
|
}
|
|
34272
34406
|
|
|
34273
34407
|
// src/agents/claude/onboarding.ts
|
|
34274
|
-
var
|
|
34408
|
+
var fs65 = __toESM(require("fs"));
|
|
34275
34409
|
var os50 = __toESM(require("os"));
|
|
34276
|
-
var
|
|
34410
|
+
var path69 = __toESM(require("path"));
|
|
34277
34411
|
var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
|
|
34278
34412
|
function ensureClaudeOnboarded(cwd) {
|
|
34279
34413
|
try {
|
|
34280
|
-
const file =
|
|
34414
|
+
const file = path69.join(os50.homedir(), ".claude.json");
|
|
34281
34415
|
let config = {};
|
|
34282
34416
|
try {
|
|
34283
|
-
config = JSON.parse(
|
|
34417
|
+
config = JSON.parse(fs65.readFileSync(file, "utf8"));
|
|
34284
34418
|
} catch {
|
|
34285
34419
|
}
|
|
34286
34420
|
let changed = false;
|
|
@@ -34305,8 +34439,8 @@ function ensureClaudeOnboarded(cwd) {
|
|
|
34305
34439
|
}
|
|
34306
34440
|
}
|
|
34307
34441
|
if (!changed) return;
|
|
34308
|
-
|
|
34309
|
-
|
|
34442
|
+
fs65.mkdirSync(path69.dirname(file), { recursive: true });
|
|
34443
|
+
fs65.writeFileSync(file, JSON.stringify(config, null, 2));
|
|
34310
34444
|
log.info(
|
|
34311
34445
|
"claude",
|
|
34312
34446
|
`pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
|
|
@@ -34992,7 +35126,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
|
|
|
34992
35126
|
var import_child_process29 = require("child_process");
|
|
34993
35127
|
var import_util4 = require("util");
|
|
34994
35128
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
34995
|
-
var
|
|
35129
|
+
var path70 = __toESM(require("path"));
|
|
34996
35130
|
var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
|
|
34997
35131
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
34998
35132
|
function resetStdinForChild() {
|
|
@@ -35481,7 +35615,7 @@ var GitHubCodespacesProvider = class {
|
|
|
35481
35615
|
});
|
|
35482
35616
|
}
|
|
35483
35617
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
35484
|
-
const remoteDir =
|
|
35618
|
+
const remoteDir = path70.posix.dirname(remotePath);
|
|
35485
35619
|
const parts = [
|
|
35486
35620
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
35487
35621
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -35551,7 +35685,7 @@ function shellQuote(s) {
|
|
|
35551
35685
|
// src/services/providers/gitpod.ts
|
|
35552
35686
|
var import_child_process30 = require("child_process");
|
|
35553
35687
|
var import_util5 = require("util");
|
|
35554
|
-
var
|
|
35688
|
+
var path71 = __toESM(require("path"));
|
|
35555
35689
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
35556
35690
|
var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
|
|
35557
35691
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -35791,7 +35925,7 @@ var GitpodProvider = class {
|
|
|
35791
35925
|
});
|
|
35792
35926
|
}
|
|
35793
35927
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
35794
|
-
const remoteDir =
|
|
35928
|
+
const remoteDir = path71.posix.dirname(remotePath);
|
|
35795
35929
|
const parts = [
|
|
35796
35930
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
35797
35931
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -35827,7 +35961,7 @@ function shellQuote2(s) {
|
|
|
35827
35961
|
// src/services/providers/gitlab-workspaces.ts
|
|
35828
35962
|
var import_child_process31 = require("child_process");
|
|
35829
35963
|
var import_util6 = require("util");
|
|
35830
|
-
var
|
|
35964
|
+
var path72 = __toESM(require("path"));
|
|
35831
35965
|
var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
|
|
35832
35966
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
35833
35967
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -36087,7 +36221,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
36087
36221
|
}
|
|
36088
36222
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
36089
36223
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
36090
|
-
const remoteDir =
|
|
36224
|
+
const remoteDir = path72.posix.dirname(remotePath);
|
|
36091
36225
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
36092
36226
|
if (options.mode != null) {
|
|
36093
36227
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -36155,7 +36289,7 @@ function shellQuote3(s) {
|
|
|
36155
36289
|
// src/services/providers/railway.ts
|
|
36156
36290
|
var import_child_process32 = require("child_process");
|
|
36157
36291
|
var import_util7 = require("util");
|
|
36158
|
-
var
|
|
36292
|
+
var path73 = __toESM(require("path"));
|
|
36159
36293
|
var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
|
|
36160
36294
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
36161
36295
|
function resetStdinForChild4() {
|
|
@@ -36391,7 +36525,7 @@ var RailwayProvider = class {
|
|
|
36391
36525
|
if (!projectId || !serviceId) {
|
|
36392
36526
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
36393
36527
|
}
|
|
36394
|
-
const remoteDir =
|
|
36528
|
+
const remoteDir = path73.posix.dirname(remotePath);
|
|
36395
36529
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
36396
36530
|
if (options.mode != null) {
|
|
36397
36531
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -37037,8 +37171,8 @@ async function invite() {
|
|
|
37037
37171
|
var import_node_dns = require("dns");
|
|
37038
37172
|
var import_node_util5 = require("util");
|
|
37039
37173
|
var import_node_crypto12 = require("crypto");
|
|
37040
|
-
var
|
|
37041
|
-
var
|
|
37174
|
+
var fs66 = __toESM(require("fs"));
|
|
37175
|
+
var path74 = __toESM(require("path"));
|
|
37042
37176
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
37043
37177
|
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
37044
37178
|
async function checkDns(apiBase2) {
|
|
@@ -37094,13 +37228,13 @@ async function checkHealth(apiBase2) {
|
|
|
37094
37228
|
}
|
|
37095
37229
|
}
|
|
37096
37230
|
function checkConfigDir() {
|
|
37097
|
-
const dir =
|
|
37231
|
+
const dir = path74.join(require("os").homedir(), ".codeam");
|
|
37098
37232
|
try {
|
|
37099
|
-
|
|
37100
|
-
const probe =
|
|
37101
|
-
|
|
37102
|
-
const read2 =
|
|
37103
|
-
|
|
37233
|
+
fs66.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
37234
|
+
const probe = path74.join(dir, ".doctor-probe");
|
|
37235
|
+
fs66.writeFileSync(probe, "ok", { mode: 384 });
|
|
37236
|
+
const read2 = fs66.readFileSync(probe, "utf8");
|
|
37237
|
+
fs66.unlinkSync(probe);
|
|
37104
37238
|
if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
|
|
37105
37239
|
return {
|
|
37106
37240
|
id: "config-dir",
|
|
@@ -37164,7 +37298,7 @@ function checkNodePty() {
|
|
|
37164
37298
|
detail: "not required on this platform"
|
|
37165
37299
|
};
|
|
37166
37300
|
}
|
|
37167
|
-
const vendoredPath =
|
|
37301
|
+
const vendoredPath = path74.join(__dirname, "vendor", "node-pty");
|
|
37168
37302
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
37169
37303
|
try {
|
|
37170
37304
|
require(target);
|
|
@@ -37206,7 +37340,7 @@ function checkChokidar() {
|
|
|
37206
37340
|
}
|
|
37207
37341
|
async function doctor(args2 = []) {
|
|
37208
37342
|
const json = args2.includes("--json");
|
|
37209
|
-
const cliVersion = true ? "2.61.
|
|
37343
|
+
const cliVersion = true ? "2.61.7" : "0.0.0-dev";
|
|
37210
37344
|
const apiBase2 = resolveApiBaseUrl();
|
|
37211
37345
|
const diagnosticId = (0, import_node_crypto12.randomUUID)();
|
|
37212
37346
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -37717,7 +37851,7 @@ async function mcpRun(args2) {
|
|
|
37717
37851
|
// src/commands/version.ts
|
|
37718
37852
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
37719
37853
|
function version2() {
|
|
37720
|
-
const v = true ? "2.61.
|
|
37854
|
+
const v = true ? "2.61.7" : "unknown";
|
|
37721
37855
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
37722
37856
|
}
|
|
37723
37857
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.61.
|
|
3
|
+
"version": "2.61.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",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"url": "https://github.com/sponsors/edgar-durand"
|
|
70
70
|
},
|
|
71
71
|
"engines": {
|
|
72
|
-
"node": ">=
|
|
72
|
+
"node": ">=22.0.0"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
75
|
"@agentclientprotocol/claude-agent-acp": "0.59.0",
|