codeam-cli 2.39.43 → 2.39.45
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 +142 -97
- 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.44] — 2026-06-19
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Surface untracked new files with real line counts in changeset
|
|
12
|
+
|
|
13
|
+
## [2.39.43] — 2026-06-19
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- **cli:** Extract macOS cloudflared .tgz + self-heal gzip-corrupt cache
|
|
18
|
+
|
|
7
19
|
## [2.39.42] — 2026-06-19
|
|
8
20
|
|
|
9
21
|
### Added
|
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.45",
|
|
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.45" : "0.0.0-dev",
|
|
5912
5912
|
nodeVersion: process.version,
|
|
5913
5913
|
platform: process.platform,
|
|
5914
5914
|
arch: process.arch,
|
|
@@ -16173,9 +16173,11 @@ async function link(args2 = []) {
|
|
|
16173
16173
|
return;
|
|
16174
16174
|
}
|
|
16175
16175
|
const pluginId = (0, import_node_crypto6.randomUUID)();
|
|
16176
|
+
const pollSecret = (0, import_node_crypto6.randomBytes)(32).toString("base64url");
|
|
16177
|
+
const pluginSecretHash = (0, import_node_crypto6.createHash)("sha256").update(pollSecret).digest("hex");
|
|
16176
16178
|
const spin = dist_exports.spinner();
|
|
16177
16179
|
spin.start("Requesting pairing code...");
|
|
16178
|
-
const pairing = await requestCode(pluginId);
|
|
16180
|
+
const pairing = await requestCode(pluginId, pluginSecretHash);
|
|
16179
16181
|
if (!pairing.ok) {
|
|
16180
16182
|
spin.stop("Failed");
|
|
16181
16183
|
if (pairing.reason === "rate-limited") {
|
|
@@ -16219,15 +16221,30 @@ async function link(args2 = []) {
|
|
|
16219
16221
|
clearInterval(countdown);
|
|
16220
16222
|
waitSpin.stop("Timed out");
|
|
16221
16223
|
reject(new Error("Pairing timed out after 5 minutes. Run codeam link again."));
|
|
16222
|
-
}
|
|
16224
|
+
},
|
|
16225
|
+
// SEC: replay the PoP secret so the pending-stream gate passes
|
|
16226
|
+
// under PoP enforcement.
|
|
16227
|
+
pollSecret
|
|
16223
16228
|
);
|
|
16224
16229
|
process.once("SIGINT", sigint);
|
|
16225
16230
|
});
|
|
16226
|
-
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
);
|
|
16230
|
-
|
|
16231
|
+
let pluginAuthToken = paired.pluginAuthToken;
|
|
16232
|
+
if (!pluginAuthToken) {
|
|
16233
|
+
const fetchSpin = dist_exports.spinner();
|
|
16234
|
+
fetchSpin.start("Fetching plugin auth token via secure reconnect...");
|
|
16235
|
+
pluginAuthToken = await fetchCurrentPluginAuthToken(
|
|
16236
|
+
paired.sessionId,
|
|
16237
|
+
pluginId,
|
|
16238
|
+
pollSecret
|
|
16239
|
+
) ?? void 0;
|
|
16240
|
+
if (!pluginAuthToken) {
|
|
16241
|
+
fetchSpin.stop("Failed");
|
|
16242
|
+
showError(
|
|
16243
|
+
"Could not obtain a pluginAuthToken \u2014 the pairing did not supply one and the /api/pairing/reconnect fallback also failed. Ensure api-v2 is deployed and try running codeam link again."
|
|
16244
|
+
);
|
|
16245
|
+
process.exit(1);
|
|
16246
|
+
}
|
|
16247
|
+
fetchSpin.stop("Token retrieved");
|
|
16231
16248
|
}
|
|
16232
16249
|
addSession({
|
|
16233
16250
|
id: paired.sessionId,
|
|
@@ -16236,12 +16253,15 @@ async function link(args2 = []) {
|
|
|
16236
16253
|
userEmail: paired.userEmail,
|
|
16237
16254
|
plan: paired.plan,
|
|
16238
16255
|
pairedAt: Date.now(),
|
|
16239
|
-
pluginAuthToken
|
|
16256
|
+
pluginAuthToken,
|
|
16257
|
+
// SEC: persist so command-relay and future reconnects can prove
|
|
16258
|
+
// possession on the gated endpoint.
|
|
16259
|
+
pollSecret,
|
|
16240
16260
|
agent: ctx.runtime.id
|
|
16241
16261
|
});
|
|
16242
16262
|
saveCliConfig({ ...loadCliConfig(), preferredAgent: ctx.runtime.id });
|
|
16243
16263
|
if (parsed.apiKey) {
|
|
16244
|
-
await uploadAndSucceed(ctx, paired, pluginId, {
|
|
16264
|
+
await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, {
|
|
16245
16265
|
method: "api_key",
|
|
16246
16266
|
credential: parsed.apiKey.trim(),
|
|
16247
16267
|
source: "manual"
|
|
@@ -16254,7 +16274,7 @@ async function link(args2 = []) {
|
|
|
16254
16274
|
showError(`--token-file ${parsed.tokenFile} is empty.`);
|
|
16255
16275
|
process.exit(1);
|
|
16256
16276
|
}
|
|
16257
|
-
await uploadAndSucceed(ctx, paired, pluginId, {
|
|
16277
|
+
await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, {
|
|
16258
16278
|
method: "oauth",
|
|
16259
16279
|
credential,
|
|
16260
16280
|
source: "manual"
|
|
@@ -16272,9 +16292,9 @@ async function link(args2 = []) {
|
|
|
16272
16292
|
installSpin.stop(`${ctx.displayName} is installed`);
|
|
16273
16293
|
const existing = await ctx.locator.extract();
|
|
16274
16294
|
if (existing) {
|
|
16275
|
-
if (await refuseIfStale(ctx, paired, pluginId, existing)) return;
|
|
16295
|
+
if (await refuseIfStale(ctx, paired, pluginId, pluginAuthToken, existing)) return;
|
|
16276
16296
|
showInfo(`Found existing ${ctx.displayName} credentials at ${import_picocolors2.default.bold(existing.source)}.`);
|
|
16277
|
-
await uploadAndSucceed(ctx, paired, pluginId, existing);
|
|
16297
|
+
await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, existing);
|
|
16278
16298
|
return;
|
|
16279
16299
|
}
|
|
16280
16300
|
if (parsed.reuseExisting) {
|
|
@@ -16289,23 +16309,21 @@ async function link(args2 = []) {
|
|
|
16289
16309
|
console.log("");
|
|
16290
16310
|
const captured = await captureFreshCredentials(ctx);
|
|
16291
16311
|
console.log("");
|
|
16292
|
-
if (await refuseIfStale(ctx, paired, pluginId, captured)) return;
|
|
16293
|
-
await uploadAndSucceed(ctx, paired, pluginId, captured);
|
|
16312
|
+
if (await refuseIfStale(ctx, paired, pluginId, pluginAuthToken, captured)) return;
|
|
16313
|
+
await uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, captured);
|
|
16294
16314
|
}
|
|
16295
|
-
async function refuseIfStale(ctx, paired, pluginId, token) {
|
|
16315
|
+
async function refuseIfStale(ctx, paired, pluginId, pluginAuthToken, token) {
|
|
16296
16316
|
const verdict = ctx.locator.validate?.(token);
|
|
16297
16317
|
if (!verdict || verdict.status !== "expired") return false;
|
|
16298
16318
|
const reason = verdict.reason ?? "Token expired";
|
|
16299
|
-
|
|
16300
|
-
|
|
16301
|
-
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
|
|
16306
|
-
|
|
16307
|
-
});
|
|
16308
|
-
}
|
|
16319
|
+
await postLinkErrorSignal({
|
|
16320
|
+
agentId: ctx.locator.publicId,
|
|
16321
|
+
sessionId: paired.sessionId,
|
|
16322
|
+
pluginId,
|
|
16323
|
+
pluginAuthToken,
|
|
16324
|
+
code: "credentials_expired",
|
|
16325
|
+
reason
|
|
16326
|
+
});
|
|
16309
16327
|
showError(
|
|
16310
16328
|
`Your local ${ctx.displayName} credentials at ${import_picocolors2.default.bold(ctx.locator.hint)} are already expired:
|
|
16311
16329
|
${reason}
|
|
@@ -16394,18 +16412,14 @@ async function captureFreshCredentials(ctx) {
|
|
|
16394
16412
|
throw err;
|
|
16395
16413
|
}
|
|
16396
16414
|
}
|
|
16397
|
-
async function uploadAndSucceed(ctx, paired, pluginId, token) {
|
|
16398
|
-
if (!paired.pluginAuthToken) {
|
|
16399
|
-
showError("Missing pluginAuthToken; re-run codeam link.");
|
|
16400
|
-
process.exit(1);
|
|
16401
|
-
}
|
|
16415
|
+
async function uploadAndSucceed(ctx, paired, pluginId, pluginAuthToken, token) {
|
|
16402
16416
|
const uploadSpin = dist_exports.spinner();
|
|
16403
16417
|
uploadSpin.start("Sealing credential in your vault...");
|
|
16404
16418
|
const result = await postLinkCredential({
|
|
16405
16419
|
agentId: ctx.locator.publicId,
|
|
16406
16420
|
sessionId: paired.sessionId,
|
|
16407
16421
|
pluginId,
|
|
16408
|
-
pluginAuthToken
|
|
16422
|
+
pluginAuthToken,
|
|
16409
16423
|
method: token.method,
|
|
16410
16424
|
credential: token.credential,
|
|
16411
16425
|
agentState: token.agentState
|
|
@@ -20253,6 +20267,7 @@ var import_crypto4 = require("crypto");
|
|
|
20253
20267
|
|
|
20254
20268
|
// src/services/turn-files/git-changeset.ts
|
|
20255
20269
|
var import_child_process21 = require("child_process");
|
|
20270
|
+
var fs37 = __toESM(require("fs/promises"));
|
|
20256
20271
|
var path44 = __toESM(require("path"));
|
|
20257
20272
|
async function collectRepoChangeset(opts) {
|
|
20258
20273
|
const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
|
|
@@ -20267,7 +20282,16 @@ async function collectRepoChangeset(opts) {
|
|
|
20267
20282
|
const entries = [];
|
|
20268
20283
|
for (const row of parseStatus(status2)) {
|
|
20269
20284
|
if (isIgnoredFilePath(row.filePath)) continue;
|
|
20270
|
-
const
|
|
20285
|
+
const numstatEntry = numstat.get(row.filePath);
|
|
20286
|
+
let stats;
|
|
20287
|
+
if (row.fileStatus === "added" && numstatEntry === void 0) {
|
|
20288
|
+
const lineCount = await readUntrackedLineCount(
|
|
20289
|
+
path44.join(opts.repoRoot, row.filePath)
|
|
20290
|
+
);
|
|
20291
|
+
stats = { added: lineCount, removed: 0 };
|
|
20292
|
+
} else {
|
|
20293
|
+
stats = numstatEntry ?? { added: 0, removed: 0 };
|
|
20294
|
+
}
|
|
20271
20295
|
entries.push({
|
|
20272
20296
|
filePath: row.filePath,
|
|
20273
20297
|
fileStatus: row.fileStatus,
|
|
@@ -20284,6 +20308,27 @@ async function collectRepoChangeset(opts) {
|
|
|
20284
20308
|
}
|
|
20285
20309
|
return entries;
|
|
20286
20310
|
}
|
|
20311
|
+
var MAX_UNTRACKED_LINE_SCAN = 1e5;
|
|
20312
|
+
var _readUntrackedLineCountImpl = {
|
|
20313
|
+
read: defaultReadUntrackedLineCount
|
|
20314
|
+
};
|
|
20315
|
+
function readUntrackedLineCount(absPath) {
|
|
20316
|
+
return _readUntrackedLineCountImpl.read(absPath);
|
|
20317
|
+
}
|
|
20318
|
+
async function defaultReadUntrackedLineCount(absPath) {
|
|
20319
|
+
try {
|
|
20320
|
+
const content = await fs37.readFile(absPath, "utf8");
|
|
20321
|
+
let count = 0;
|
|
20322
|
+
let pos = -1;
|
|
20323
|
+
while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
|
|
20324
|
+
count += 1;
|
|
20325
|
+
if (count >= MAX_UNTRACKED_LINE_SCAN) return count;
|
|
20326
|
+
}
|
|
20327
|
+
return content.length > 0 ? Math.max(count, 1) : 0;
|
|
20328
|
+
} catch {
|
|
20329
|
+
return 0;
|
|
20330
|
+
}
|
|
20331
|
+
}
|
|
20287
20332
|
function parseStatus(raw) {
|
|
20288
20333
|
const tokens = raw.split("\0");
|
|
20289
20334
|
const rows = [];
|
|
@@ -20364,7 +20409,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
20364
20409
|
});
|
|
20365
20410
|
}
|
|
20366
20411
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
20367
|
-
const
|
|
20412
|
+
const fs47 = await import("fs/promises");
|
|
20368
20413
|
const out2 = [];
|
|
20369
20414
|
await walk(workingDir, 0);
|
|
20370
20415
|
return out2;
|
|
@@ -20372,7 +20417,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
20372
20417
|
if (depth > maxDepth) return;
|
|
20373
20418
|
let entries = [];
|
|
20374
20419
|
try {
|
|
20375
|
-
const dirents = await
|
|
20420
|
+
const dirents = await fs47.readdir(dir, { withFileTypes: true });
|
|
20376
20421
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
20377
20422
|
} catch {
|
|
20378
20423
|
return;
|
|
@@ -20398,7 +20443,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
20398
20443
|
}
|
|
20399
20444
|
|
|
20400
20445
|
// src/services/turn-files/files-outbox.ts
|
|
20401
|
-
var
|
|
20446
|
+
var fs38 = __toESM(require("fs/promises"));
|
|
20402
20447
|
var path45 = __toESM(require("path"));
|
|
20403
20448
|
var import_os7 = require("os");
|
|
20404
20449
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
@@ -20440,8 +20485,8 @@ var FilesOutbox = class {
|
|
|
20440
20485
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
20441
20486
|
* line is durable on disk (not once the POST succeeds). */
|
|
20442
20487
|
async enqueue(entry) {
|
|
20443
|
-
await
|
|
20444
|
-
await
|
|
20488
|
+
await fs38.mkdir(path45.dirname(this.filePath), { recursive: true });
|
|
20489
|
+
await fs38.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
20445
20490
|
this.backoffIndex = 0;
|
|
20446
20491
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
20447
20492
|
}
|
|
@@ -20530,7 +20575,7 @@ var FilesOutbox = class {
|
|
|
20530
20575
|
async readAll() {
|
|
20531
20576
|
let raw = "";
|
|
20532
20577
|
try {
|
|
20533
|
-
raw = await
|
|
20578
|
+
raw = await fs38.readFile(this.filePath, "utf8");
|
|
20534
20579
|
} catch {
|
|
20535
20580
|
return [];
|
|
20536
20581
|
}
|
|
@@ -20554,12 +20599,12 @@ var FilesOutbox = class {
|
|
|
20554
20599
|
async rewrite(entries) {
|
|
20555
20600
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
20556
20601
|
if (entries.length === 0) {
|
|
20557
|
-
await
|
|
20602
|
+
await fs38.unlink(this.filePath).catch(() => void 0);
|
|
20558
20603
|
return;
|
|
20559
20604
|
}
|
|
20560
20605
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
20561
|
-
await
|
|
20562
|
-
await
|
|
20606
|
+
await fs38.writeFile(tmpPath, payload, "utf8");
|
|
20607
|
+
await fs38.rename(tmpPath, this.filePath);
|
|
20563
20608
|
}
|
|
20564
20609
|
};
|
|
20565
20610
|
function applyJitter(ms) {
|
|
@@ -22457,7 +22502,7 @@ var OutputService = class _OutputService {
|
|
|
22457
22502
|
};
|
|
22458
22503
|
|
|
22459
22504
|
// src/services/history.service.ts
|
|
22460
|
-
var
|
|
22505
|
+
var fs39 = __toESM(require("fs"));
|
|
22461
22506
|
var path46 = __toESM(require("path"));
|
|
22462
22507
|
var os30 = __toESM(require("os"));
|
|
22463
22508
|
var https7 = __toESM(require("https"));
|
|
@@ -22486,7 +22531,7 @@ function parseJsonl(filePath) {
|
|
|
22486
22531
|
const messages = [];
|
|
22487
22532
|
let raw;
|
|
22488
22533
|
try {
|
|
22489
|
-
raw =
|
|
22534
|
+
raw = fs39.readFileSync(filePath, "utf8");
|
|
22490
22535
|
} catch (err) {
|
|
22491
22536
|
if (err.code !== "ENOENT") {
|
|
22492
22537
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -22676,9 +22721,9 @@ var HistoryService = class _HistoryService {
|
|
|
22676
22721
|
const dir = this.projectDir;
|
|
22677
22722
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
22678
22723
|
try {
|
|
22679
|
-
const files =
|
|
22724
|
+
const files = fs39.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
22680
22725
|
try {
|
|
22681
|
-
const stat3 =
|
|
22726
|
+
const stat3 = fs39.statSync(path46.join(dir, e.name));
|
|
22682
22727
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
22683
22728
|
} catch {
|
|
22684
22729
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -22719,13 +22764,13 @@ var HistoryService = class _HistoryService {
|
|
|
22719
22764
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
22720
22765
|
let entries;
|
|
22721
22766
|
try {
|
|
22722
|
-
entries =
|
|
22767
|
+
entries = fs39.readdirSync(dir, { withFileTypes: true });
|
|
22723
22768
|
} catch {
|
|
22724
22769
|
return null;
|
|
22725
22770
|
}
|
|
22726
22771
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
22727
22772
|
try {
|
|
22728
|
-
const stat3 =
|
|
22773
|
+
const stat3 = fs39.statSync(path46.join(dir, e.name));
|
|
22729
22774
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
22730
22775
|
} catch {
|
|
22731
22776
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -22739,7 +22784,7 @@ var HistoryService = class _HistoryService {
|
|
|
22739
22784
|
extractUsageFromFile(filePath) {
|
|
22740
22785
|
let raw;
|
|
22741
22786
|
try {
|
|
22742
|
-
raw =
|
|
22787
|
+
raw = fs39.readFileSync(filePath, "utf8");
|
|
22743
22788
|
} catch {
|
|
22744
22789
|
return null;
|
|
22745
22790
|
}
|
|
@@ -22784,9 +22829,9 @@ var HistoryService = class _HistoryService {
|
|
|
22784
22829
|
let totalCost = 0;
|
|
22785
22830
|
let files;
|
|
22786
22831
|
try {
|
|
22787
|
-
files =
|
|
22832
|
+
files = fs39.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
22788
22833
|
try {
|
|
22789
|
-
return
|
|
22834
|
+
return fs39.statSync(path46.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
22790
22835
|
} catch {
|
|
22791
22836
|
return false;
|
|
22792
22837
|
}
|
|
@@ -22797,7 +22842,7 @@ var HistoryService = class _HistoryService {
|
|
|
22797
22842
|
for (const file of files) {
|
|
22798
22843
|
let raw;
|
|
22799
22844
|
try {
|
|
22800
|
-
raw =
|
|
22845
|
+
raw = fs39.readFileSync(path46.join(projectDir, file), "utf8");
|
|
22801
22846
|
} catch {
|
|
22802
22847
|
continue;
|
|
22803
22848
|
}
|
|
@@ -23388,7 +23433,7 @@ function buildKeepAlive(ctx) {
|
|
|
23388
23433
|
}
|
|
23389
23434
|
|
|
23390
23435
|
// src/agents/claude/onboarding.ts
|
|
23391
|
-
var
|
|
23436
|
+
var fs40 = __toESM(require("fs"));
|
|
23392
23437
|
var os31 = __toESM(require("os"));
|
|
23393
23438
|
var path47 = __toESM(require("path"));
|
|
23394
23439
|
function ensureClaudeOnboarded() {
|
|
@@ -23396,7 +23441,7 @@ function ensureClaudeOnboarded() {
|
|
|
23396
23441
|
const file = path47.join(os31.homedir(), ".claude.json");
|
|
23397
23442
|
let config = {};
|
|
23398
23443
|
try {
|
|
23399
|
-
config = JSON.parse(
|
|
23444
|
+
config = JSON.parse(fs40.readFileSync(file, "utf8"));
|
|
23400
23445
|
} catch {
|
|
23401
23446
|
}
|
|
23402
23447
|
if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
|
|
@@ -23407,8 +23452,8 @@ function ensureClaudeOnboarded() {
|
|
|
23407
23452
|
if (typeof config.lastOnboardingVersion !== "string") {
|
|
23408
23453
|
config.lastOnboardingVersion = "2.1.177";
|
|
23409
23454
|
}
|
|
23410
|
-
|
|
23411
|
-
|
|
23455
|
+
fs40.mkdirSync(path47.dirname(file), { recursive: true });
|
|
23456
|
+
fs40.writeFileSync(file, JSON.stringify(config, null, 2));
|
|
23412
23457
|
log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
|
|
23413
23458
|
} catch (err) {
|
|
23414
23459
|
log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
|
|
@@ -23899,7 +23944,7 @@ async function autoLinkAfterPair(opts) {
|
|
|
23899
23944
|
}
|
|
23900
23945
|
|
|
23901
23946
|
// src/commands/pair-auto.ts
|
|
23902
|
-
var
|
|
23947
|
+
var fs41 = __toESM(require("fs"));
|
|
23903
23948
|
var os32 = __toESM(require("os"));
|
|
23904
23949
|
var path48 = __toESM(require("path"));
|
|
23905
23950
|
var import_crypto7 = require("crypto");
|
|
@@ -24098,10 +24143,10 @@ function readTokenFromArgs(args2) {
|
|
|
24098
24143
|
if (fileFlag) {
|
|
24099
24144
|
const path58 = fileFlag.slice("--token-file=".length);
|
|
24100
24145
|
try {
|
|
24101
|
-
const content =
|
|
24146
|
+
const content = fs41.readFileSync(path58, "utf8").trim();
|
|
24102
24147
|
if (content.length === 0) fail(`--token-file ${path58} is empty`);
|
|
24103
24148
|
try {
|
|
24104
|
-
|
|
24149
|
+
fs41.unlinkSync(path58);
|
|
24105
24150
|
} catch {
|
|
24106
24151
|
}
|
|
24107
24152
|
return content;
|
|
@@ -24198,7 +24243,7 @@ function isLivePairAuto(pid) {
|
|
|
24198
24243
|
if (e.code !== "EPERM") return false;
|
|
24199
24244
|
}
|
|
24200
24245
|
try {
|
|
24201
|
-
return
|
|
24246
|
+
return fs41.readFileSync(`/proc/${pid}/cmdline`, "utf8").includes("codeam");
|
|
24202
24247
|
} catch {
|
|
24203
24248
|
return true;
|
|
24204
24249
|
}
|
|
@@ -24206,19 +24251,19 @@ function isLivePairAuto(pid) {
|
|
|
24206
24251
|
function acquireSingletonLock() {
|
|
24207
24252
|
const lockPath = pairAutoLockPath();
|
|
24208
24253
|
try {
|
|
24209
|
-
|
|
24254
|
+
fs41.mkdirSync(path48.dirname(lockPath), { recursive: true });
|
|
24210
24255
|
try {
|
|
24211
|
-
|
|
24256
|
+
fs41.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
24212
24257
|
} catch (e) {
|
|
24213
24258
|
if (e.code !== "EEXIST") throw e;
|
|
24214
|
-
const holder = Number(
|
|
24259
|
+
const holder = Number(fs41.readFileSync(lockPath, "utf8").trim());
|
|
24215
24260
|
if (isLivePairAuto(holder)) return false;
|
|
24216
|
-
|
|
24261
|
+
fs41.writeFileSync(lockPath, String(process.pid));
|
|
24217
24262
|
}
|
|
24218
24263
|
process.once("exit", () => {
|
|
24219
24264
|
try {
|
|
24220
|
-
if (
|
|
24221
|
-
|
|
24265
|
+
if (fs41.existsSync(lockPath) && Number(fs41.readFileSync(lockPath, "utf8").trim()) === process.pid) {
|
|
24266
|
+
fs41.unlinkSync(lockPath);
|
|
24222
24267
|
}
|
|
24223
24268
|
} catch {
|
|
24224
24269
|
}
|
|
@@ -26360,7 +26405,7 @@ async function stopWorkspaceFromLocal(target) {
|
|
|
26360
26405
|
}
|
|
26361
26406
|
|
|
26362
26407
|
// src/commands/host/host-client.ts
|
|
26363
|
-
var
|
|
26408
|
+
var fs42 = __toESM(require("fs"));
|
|
26364
26409
|
var os33 = __toESM(require("os"));
|
|
26365
26410
|
var path53 = __toESM(require("path"));
|
|
26366
26411
|
function sampleCpuTimes() {
|
|
@@ -26421,7 +26466,7 @@ function collectOsInfo() {
|
|
|
26421
26466
|
}
|
|
26422
26467
|
function loadHostIdentity() {
|
|
26423
26468
|
try {
|
|
26424
|
-
const raw =
|
|
26469
|
+
const raw = fs42.readFileSync(hostIdentityPath(), "utf8");
|
|
26425
26470
|
const parsed = JSON.parse(raw);
|
|
26426
26471
|
if (typeof parsed === "object" && parsed !== null && typeof parsed.hostId === "string" && typeof parsed.hostToken === "string" && typeof parsed.controlPluginId === "string") {
|
|
26427
26472
|
const p2 = parsed;
|
|
@@ -26434,12 +26479,12 @@ function loadHostIdentity() {
|
|
|
26434
26479
|
}
|
|
26435
26480
|
function saveHostIdentity(identity) {
|
|
26436
26481
|
const file = hostIdentityPath();
|
|
26437
|
-
|
|
26438
|
-
|
|
26482
|
+
fs42.mkdirSync(path53.dirname(file), { recursive: true, mode: 448 });
|
|
26483
|
+
fs42.writeFileSync(file, JSON.stringify(identity, null, 2), {
|
|
26439
26484
|
encoding: "utf8",
|
|
26440
26485
|
mode: 384
|
|
26441
26486
|
});
|
|
26442
|
-
|
|
26487
|
+
fs42.chmodSync(file, 384);
|
|
26443
26488
|
}
|
|
26444
26489
|
var HostHttpError = class extends Error {
|
|
26445
26490
|
constructor(message, status2) {
|
|
@@ -26462,7 +26507,7 @@ function isHostAuthRejection(err) {
|
|
|
26462
26507
|
}
|
|
26463
26508
|
function deleteHostIdentity() {
|
|
26464
26509
|
try {
|
|
26465
|
-
|
|
26510
|
+
fs42.rmSync(hostIdentityPath(), { force: true });
|
|
26466
26511
|
} catch {
|
|
26467
26512
|
}
|
|
26468
26513
|
}
|
|
@@ -26626,7 +26671,7 @@ var import_node_child_process13 = require("child_process");
|
|
|
26626
26671
|
var os36 = __toESM(require("os"));
|
|
26627
26672
|
|
|
26628
26673
|
// src/commands/host/workspace.ts
|
|
26629
|
-
var
|
|
26674
|
+
var fs43 = __toESM(require("fs"));
|
|
26630
26675
|
var os34 = __toESM(require("os"));
|
|
26631
26676
|
var path54 = __toESM(require("path"));
|
|
26632
26677
|
var import_node_child_process12 = require("child_process");
|
|
@@ -26679,16 +26724,16 @@ function maskToken(text, cloneToken) {
|
|
|
26679
26724
|
}
|
|
26680
26725
|
async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
|
|
26681
26726
|
if (isAbsolutePathTarget(repoOrPath)) {
|
|
26682
|
-
if (!
|
|
26727
|
+
if (!fs43.existsSync(repoOrPath)) {
|
|
26683
26728
|
throw new Error(`deploy target path does not exist: ${repoOrPath}`);
|
|
26684
26729
|
}
|
|
26685
26730
|
return repoOrPath;
|
|
26686
26731
|
}
|
|
26687
26732
|
const dest = path54.join(selfHostedWorkspaceRoot(), deployId);
|
|
26688
|
-
if (
|
|
26733
|
+
if (fs43.existsSync(path54.join(dest, ".git"))) {
|
|
26689
26734
|
return dest;
|
|
26690
26735
|
}
|
|
26691
|
-
|
|
26736
|
+
fs43.mkdirSync(selfHostedWorkspaceRoot(), { recursive: true, mode: 448 });
|
|
26692
26737
|
const cloneUrl = repoCloneUrl(repoOrPath, cloneToken);
|
|
26693
26738
|
try {
|
|
26694
26739
|
await execFileP9("git", ["clone", "--depth", "1", cloneUrl, dest], {
|
|
@@ -26704,7 +26749,7 @@ async function prepareWorkspace(repoOrPath, deployId, cloneToken) {
|
|
|
26704
26749
|
}
|
|
26705
26750
|
|
|
26706
26751
|
// src/commands/host/agent-provisioning.ts
|
|
26707
|
-
var
|
|
26752
|
+
var fs44 = __toESM(require("fs"));
|
|
26708
26753
|
var os35 = __toESM(require("os"));
|
|
26709
26754
|
var path55 = __toESM(require("path"));
|
|
26710
26755
|
var PUBLIC_TO_INTERNAL_AGENT = {
|
|
@@ -26721,12 +26766,12 @@ function toInternalAgentId(publicAgentId) {
|
|
|
26721
26766
|
return PUBLIC_TO_INTERNAL_AGENT[publicAgentId] ?? null;
|
|
26722
26767
|
}
|
|
26723
26768
|
function ensureDir(dir) {
|
|
26724
|
-
|
|
26769
|
+
fs44.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
26725
26770
|
}
|
|
26726
26771
|
function writeFile0600(filePath, contents) {
|
|
26727
26772
|
ensureDir(path55.dirname(filePath));
|
|
26728
|
-
|
|
26729
|
-
|
|
26773
|
+
fs44.writeFileSync(filePath, contents, { encoding: "utf8", mode: 384 });
|
|
26774
|
+
fs44.chmodSync(filePath, 384);
|
|
26730
26775
|
}
|
|
26731
26776
|
var claudeProvisioner = {
|
|
26732
26777
|
write(auth, home) {
|
|
@@ -26735,7 +26780,7 @@ var claudeProvisioner = {
|
|
|
26735
26780
|
}
|
|
26736
26781
|
writeFile0600(path55.join(home, ".claude", ".credentials.json"), auth.value);
|
|
26737
26782
|
const claudeJson = path55.join(home, ".claude.json");
|
|
26738
|
-
if (!
|
|
26783
|
+
if (!fs44.existsSync(claudeJson)) {
|
|
26739
26784
|
writeFile0600(
|
|
26740
26785
|
claudeJson,
|
|
26741
26786
|
JSON.stringify({ hasCompletedOnboarding: true, customApiKeyResponses: { approved: [] } })
|
|
@@ -27165,7 +27210,7 @@ async function hostAgent(args2 = []) {
|
|
|
27165
27210
|
var import_node_dns = require("dns");
|
|
27166
27211
|
var import_node_util5 = require("util");
|
|
27167
27212
|
var import_node_crypto8 = require("crypto");
|
|
27168
|
-
var
|
|
27213
|
+
var fs45 = __toESM(require("fs"));
|
|
27169
27214
|
var path56 = __toESM(require("path"));
|
|
27170
27215
|
var import_picocolors12 = __toESM(require("picocolors"));
|
|
27171
27216
|
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
@@ -27224,11 +27269,11 @@ async function checkHealth(apiBase2) {
|
|
|
27224
27269
|
function checkConfigDir() {
|
|
27225
27270
|
const dir = path56.join(require("os").homedir(), ".codeam");
|
|
27226
27271
|
try {
|
|
27227
|
-
|
|
27272
|
+
fs45.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
27228
27273
|
const probe = path56.join(dir, ".doctor-probe");
|
|
27229
|
-
|
|
27230
|
-
const read =
|
|
27231
|
-
|
|
27274
|
+
fs45.writeFileSync(probe, "ok", { mode: 384 });
|
|
27275
|
+
const read = fs45.readFileSync(probe, "utf8");
|
|
27276
|
+
fs45.unlinkSync(probe);
|
|
27232
27277
|
if (read !== "ok") throw new Error("write/read round-trip mismatch");
|
|
27233
27278
|
return {
|
|
27234
27279
|
id: "config-dir",
|
|
@@ -27334,7 +27379,7 @@ function checkChokidar() {
|
|
|
27334
27379
|
}
|
|
27335
27380
|
async function doctor(args2 = []) {
|
|
27336
27381
|
const json = args2.includes("--json");
|
|
27337
|
-
const cliVersion = true ? "2.39.
|
|
27382
|
+
const cliVersion = true ? "2.39.45" : "0.0.0-dev";
|
|
27338
27383
|
const apiBase2 = resolveApiBaseUrl();
|
|
27339
27384
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
27340
27385
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -27533,7 +27578,7 @@ async function completion(args2) {
|
|
|
27533
27578
|
// src/commands/version.ts
|
|
27534
27579
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
27535
27580
|
function version2() {
|
|
27536
|
-
const v = true ? "2.39.
|
|
27581
|
+
const v = true ? "2.39.45" : "unknown";
|
|
27537
27582
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
27538
27583
|
}
|
|
27539
27584
|
|
|
@@ -27661,7 +27706,7 @@ function tryShowSubcommandHelp(cmd, args2) {
|
|
|
27661
27706
|
var _subcommandHelpKeys = Object.keys(HELPS);
|
|
27662
27707
|
|
|
27663
27708
|
// src/lib/updateNotifier.ts
|
|
27664
|
-
var
|
|
27709
|
+
var fs46 = __toESM(require("fs"));
|
|
27665
27710
|
var os37 = __toESM(require("os"));
|
|
27666
27711
|
var path57 = __toESM(require("path"));
|
|
27667
27712
|
var https8 = __toESM(require("https"));
|
|
@@ -27677,7 +27722,7 @@ function cachePath() {
|
|
|
27677
27722
|
}
|
|
27678
27723
|
function readCache() {
|
|
27679
27724
|
try {
|
|
27680
|
-
const raw =
|
|
27725
|
+
const raw = fs46.readFileSync(cachePath(), "utf8");
|
|
27681
27726
|
const parsed = JSON.parse(raw);
|
|
27682
27727
|
if (typeof parsed.fetchedAt !== "number" || typeof parsed.latest !== "string") return null;
|
|
27683
27728
|
return parsed;
|
|
@@ -27688,10 +27733,10 @@ function readCache() {
|
|
|
27688
27733
|
function writeCache(cache) {
|
|
27689
27734
|
try {
|
|
27690
27735
|
const file = cachePath();
|
|
27691
|
-
|
|
27736
|
+
fs46.mkdirSync(path57.dirname(file), { recursive: true });
|
|
27692
27737
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
27693
|
-
|
|
27694
|
-
|
|
27738
|
+
fs46.writeFileSync(tmp, JSON.stringify(cache));
|
|
27739
|
+
fs46.renameSync(tmp, file);
|
|
27695
27740
|
} catch {
|
|
27696
27741
|
}
|
|
27697
27742
|
}
|
|
@@ -27766,7 +27811,7 @@ function isLinkedInstall() {
|
|
|
27766
27811
|
}).trim();
|
|
27767
27812
|
if (!root) return false;
|
|
27768
27813
|
const pkgPath = path57.join(root, PKG_NAME);
|
|
27769
|
-
return
|
|
27814
|
+
return fs46.lstatSync(pkgPath).isSymbolicLink();
|
|
27770
27815
|
} catch {
|
|
27771
27816
|
return false;
|
|
27772
27817
|
}
|
|
@@ -27802,7 +27847,7 @@ function maybeAutoUpdate(currentVersion, latest) {
|
|
|
27802
27847
|
return;
|
|
27803
27848
|
}
|
|
27804
27849
|
try {
|
|
27805
|
-
|
|
27850
|
+
fs46.unlinkSync(cachePath());
|
|
27806
27851
|
} catch {
|
|
27807
27852
|
}
|
|
27808
27853
|
process.stderr.write(` ${import_picocolors16.default.green("\u2713")} Updated. Resuming session...
|
|
@@ -27819,7 +27864,7 @@ function checkForUpdates() {
|
|
|
27819
27864
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
27820
27865
|
if (process.env.CI) return;
|
|
27821
27866
|
if (!process.stdout.isTTY) return;
|
|
27822
|
-
const current = true ? "2.39.
|
|
27867
|
+
const current = true ? "2.39.45" : null;
|
|
27823
27868
|
if (!current) return;
|
|
27824
27869
|
const cache = readCache();
|
|
27825
27870
|
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.39.
|
|
3
|
+
"version": "2.39.45",
|
|
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",
|