codeam-cli 2.52.5 → 2.52.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/index.js +253 -125
- 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.52.6] — 2026-07-03
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** An invalid pairing latches the output pipeline — no more silent dead-token spam
|
|
12
|
+
|
|
13
|
+
## [2.52.5] — 2026-07-02
|
|
14
|
+
|
|
15
|
+
### CI
|
|
16
|
+
|
|
17
|
+
- **workflow:** Free runner disk before the JetBrains publish job
|
|
18
|
+
|
|
7
19
|
## [2.52.3] — 2026-06-30
|
|
8
20
|
|
|
9
21
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -560,8 +560,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
|
|
|
560
560
|
return decodedFile;
|
|
561
561
|
};
|
|
562
562
|
}
|
|
563
|
-
function normalizeWindowsPath(
|
|
564
|
-
return
|
|
563
|
+
function normalizeWindowsPath(path63) {
|
|
564
|
+
return path63.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
|
|
565
565
|
}
|
|
566
566
|
|
|
567
567
|
// ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
|
|
@@ -3041,9 +3041,9 @@ async function addSourceContext(frames) {
|
|
|
3041
3041
|
LRU_FILE_CONTENTS_CACHE.reduce();
|
|
3042
3042
|
return frames;
|
|
3043
3043
|
}
|
|
3044
|
-
function getContextLinesFromFile(
|
|
3044
|
+
function getContextLinesFromFile(path63, ranges, output) {
|
|
3045
3045
|
return new Promise((resolve7) => {
|
|
3046
|
-
const stream = (0, import_node_fs.createReadStream)(
|
|
3046
|
+
const stream = (0, import_node_fs.createReadStream)(path63);
|
|
3047
3047
|
const lineReaded = (0, import_node_readline.createInterface)({
|
|
3048
3048
|
input: stream
|
|
3049
3049
|
});
|
|
@@ -3058,7 +3058,7 @@ function getContextLinesFromFile(path62, ranges, output) {
|
|
|
3058
3058
|
let rangeStart = range[0];
|
|
3059
3059
|
let rangeEnd = range[1];
|
|
3060
3060
|
function onStreamError() {
|
|
3061
|
-
LRU_FILE_CONTENTS_FS_READ_FAILED.set(
|
|
3061
|
+
LRU_FILE_CONTENTS_FS_READ_FAILED.set(path63, 1);
|
|
3062
3062
|
lineReaded.close();
|
|
3063
3063
|
lineReaded.removeAllListeners();
|
|
3064
3064
|
destroyStreamAndResolve();
|
|
@@ -3119,8 +3119,8 @@ function clearLineContext(frame) {
|
|
|
3119
3119
|
delete frame.context_line;
|
|
3120
3120
|
delete frame.post_context;
|
|
3121
3121
|
}
|
|
3122
|
-
function shouldSkipContextLinesForFile(
|
|
3123
|
-
return
|
|
3122
|
+
function shouldSkipContextLinesForFile(path63) {
|
|
3123
|
+
return path63.startsWith("node:") || path63.endsWith(".min.js") || path63.endsWith(".min.cjs") || path63.endsWith(".min.mjs") || path63.startsWith("data:");
|
|
3124
3124
|
}
|
|
3125
3125
|
function shouldSkipContextLinesForFrame(frame) {
|
|
3126
3126
|
if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
|
|
@@ -5397,7 +5397,7 @@ function readAnonId() {
|
|
|
5397
5397
|
}
|
|
5398
5398
|
function superProperties() {
|
|
5399
5399
|
return {
|
|
5400
|
-
cliVersion: true ? "2.52.
|
|
5400
|
+
cliVersion: true ? "2.52.7" : "0.0.0-dev",
|
|
5401
5401
|
nodeVersion: process.version,
|
|
5402
5402
|
platform: process.platform,
|
|
5403
5403
|
arch: process.arch,
|
|
@@ -5578,7 +5578,7 @@ var os4 = __toESM(require("os"));
|
|
|
5578
5578
|
// package.json
|
|
5579
5579
|
var package_default = {
|
|
5580
5580
|
name: "codeam-cli",
|
|
5581
|
-
version: "2.52.
|
|
5581
|
+
version: "2.52.7",
|
|
5582
5582
|
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.",
|
|
5583
5583
|
type: "commonjs",
|
|
5584
5584
|
main: "dist/index.js",
|
|
@@ -6105,6 +6105,13 @@ function computePollDelay({ baseMs, failures }) {
|
|
|
6105
6105
|
}
|
|
6106
6106
|
|
|
6107
6107
|
// src/services/command-relay.service.ts
|
|
6108
|
+
function httpStatusOf(err) {
|
|
6109
|
+
if (typeof err === "object" && err !== null && "statusCode" in err) {
|
|
6110
|
+
const status2 = err.statusCode;
|
|
6111
|
+
if (typeof status2 === "number") return status2;
|
|
6112
|
+
}
|
|
6113
|
+
return null;
|
|
6114
|
+
}
|
|
6108
6115
|
var API_BASE2 = resolveApiBaseUrl();
|
|
6109
6116
|
var SSE_LIVENESS_TIMEOUT_MS = 45e3;
|
|
6110
6117
|
var SSE_WATCHDOG_INTERVAL_MS = 1e4;
|
|
@@ -6120,6 +6127,7 @@ var CommandRelayService = class {
|
|
|
6120
6127
|
agentMeta;
|
|
6121
6128
|
agentsOverride;
|
|
6122
6129
|
_running = false;
|
|
6130
|
+
pairingInvalid = false;
|
|
6123
6131
|
heartbeatTimer = null;
|
|
6124
6132
|
agentsTimer = null;
|
|
6125
6133
|
/** True once `/api/plugin/agents` has accepted at least one report. */
|
|
@@ -6197,7 +6205,22 @@ var CommandRelayService = class {
|
|
|
6197
6205
|
});
|
|
6198
6206
|
}
|
|
6199
6207
|
async sendResult(commandId, status2, result) {
|
|
6200
|
-
|
|
6208
|
+
if (this.pairingInvalid) return;
|
|
6209
|
+
try {
|
|
6210
|
+
await _postJson(`${API_BASE2}/api/commands/result`, { commandId, status: status2, result });
|
|
6211
|
+
} catch (err) {
|
|
6212
|
+
const statusCode = httpStatusOf(err);
|
|
6213
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
6214
|
+
this.pairingInvalid = true;
|
|
6215
|
+
process.stderr.write(
|
|
6216
|
+
"[codeam] This pairing is no longer valid \u2014 run `codeam pair` again to reconnect this session.\n"
|
|
6217
|
+
);
|
|
6218
|
+
log.warn("relay", `pairing invalid (status=${statusCode}) \u2014 relay stopped`);
|
|
6219
|
+
this.stop();
|
|
6220
|
+
return;
|
|
6221
|
+
}
|
|
6222
|
+
throw err;
|
|
6223
|
+
}
|
|
6201
6224
|
}
|
|
6202
6225
|
// ─── SSE pull (primary) ──────────────────────────────────────────
|
|
6203
6226
|
connectSSE() {
|
|
@@ -7340,24 +7363,24 @@ async function refreshAuthToken(sessionId, pluginId) {
|
|
|
7340
7363
|
},
|
|
7341
7364
|
JSON.stringify({ sessionId, pluginId })
|
|
7342
7365
|
);
|
|
7343
|
-
if (statusCode === 404) {
|
|
7344
|
-
log.warn("chunkEmitter",
|
|
7345
|
-
return
|
|
7366
|
+
if (statusCode === 404 || statusCode === 401 || statusCode === 403) {
|
|
7367
|
+
log.warn("chunkEmitter", `[auth] reconnect ${statusCode} \u2014 session gone server-side`);
|
|
7368
|
+
return { kind: "gone" };
|
|
7346
7369
|
}
|
|
7347
7370
|
if (statusCode >= 400) {
|
|
7348
7371
|
log.warn("chunkEmitter", `[auth] reconnect failed status=${statusCode}`);
|
|
7349
|
-
return
|
|
7372
|
+
return { kind: "transient" };
|
|
7350
7373
|
}
|
|
7351
7374
|
const parsed = JSON.parse(body);
|
|
7352
7375
|
const fresh = parsed.data?.pluginAuthToken;
|
|
7353
7376
|
if (typeof fresh !== "string" || fresh.length === 0) {
|
|
7354
7377
|
log.warn("chunkEmitter", "[auth] reconnect response missing pluginAuthToken");
|
|
7355
|
-
return
|
|
7378
|
+
return { kind: "transient" };
|
|
7356
7379
|
}
|
|
7357
|
-
return fresh;
|
|
7380
|
+
return { kind: "fresh", token: fresh };
|
|
7358
7381
|
} catch (err) {
|
|
7359
7382
|
log.warn("chunkEmitter", `[auth] reconnect threw: ${String(err)}`);
|
|
7360
|
-
return
|
|
7383
|
+
return { kind: "transient" };
|
|
7361
7384
|
}
|
|
7362
7385
|
}
|
|
7363
7386
|
var ChunkEmitter = class {
|
|
@@ -7375,6 +7398,11 @@ var ChunkEmitter = class {
|
|
|
7375
7398
|
opts;
|
|
7376
7399
|
url = `${API_BASE4}/api/commands/output`;
|
|
7377
7400
|
headers;
|
|
7401
|
+
/** Latched when the pairing is unrecoverable (401/403 whose refresh
|
|
7402
|
+
* says the session is gone, or a fresh token still rejected) —
|
|
7403
|
+
* every later send short-circuits (2026-06-28 incident: 401 ×34
|
|
7404
|
+
* with a dead token while the user saw nothing). */
|
|
7405
|
+
pairingInvalid = false;
|
|
7378
7406
|
/**
|
|
7379
7407
|
* Send a chunk. `body` is the chunk fields minus `sessionId` /
|
|
7380
7408
|
* `pluginId` — the emitter splices those in. `critical = true`
|
|
@@ -7394,7 +7422,11 @@ var ChunkEmitter = class {
|
|
|
7394
7422
|
"chunkEmitter",
|
|
7395
7423
|
`send type=${body.type ?? "(clear)"} bytes=${payload.length} done=${body.done === true}`
|
|
7396
7424
|
);
|
|
7425
|
+
if (this.pairingInvalid) {
|
|
7426
|
+
return Promise.resolve({ dead: true });
|
|
7427
|
+
}
|
|
7397
7428
|
return new Promise((resolve7) => {
|
|
7429
|
+
let refreshedOnce = false;
|
|
7398
7430
|
const attempt = (attemptsLeft) => {
|
|
7399
7431
|
_transport3.post(this.url, this.headers, payload).then(({ statusCode, body: resBody }) => {
|
|
7400
7432
|
const tookMs = Date.now() - t0;
|
|
@@ -7404,18 +7436,27 @@ var ChunkEmitter = class {
|
|
|
7404
7436
|
resolve7({ dead: true });
|
|
7405
7437
|
return;
|
|
7406
7438
|
}
|
|
7407
|
-
if (statusCode === 401) {
|
|
7408
|
-
|
|
7439
|
+
if (statusCode === 401 || statusCode === 403) {
|
|
7440
|
+
if (refreshedOnce) {
|
|
7441
|
+
this.markPairingInvalid(statusCode, tookMs);
|
|
7442
|
+
resolve7({ dead: true });
|
|
7443
|
+
return;
|
|
7444
|
+
}
|
|
7445
|
+
log.warn("chunkEmitter", `auth ${statusCode} took=${tookMs}ms \u2014 attempting silent refresh`);
|
|
7409
7446
|
void (async () => {
|
|
7410
|
-
const
|
|
7411
|
-
if (fresh) {
|
|
7412
|
-
this.headers["X-Plugin-Auth-Token"] =
|
|
7413
|
-
this.opts.pluginAuthToken =
|
|
7447
|
+
const refresh = await refreshAuthToken(this.opts.sessionId, this.opts.pluginId);
|
|
7448
|
+
if (refresh.kind === "fresh") {
|
|
7449
|
+
this.headers["X-Plugin-Auth-Token"] = refresh.token;
|
|
7450
|
+
this.opts.pluginAuthToken = refresh.token;
|
|
7451
|
+
refreshedOnce = true;
|
|
7414
7452
|
log.info("chunkEmitter", "auth refreshed silently");
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7453
|
+
attempt(Math.max(attemptsLeft, 1));
|
|
7454
|
+
return;
|
|
7455
|
+
}
|
|
7456
|
+
if (refresh.kind === "gone") {
|
|
7457
|
+
this.markPairingInvalid(statusCode, tookMs);
|
|
7458
|
+
resolve7({ dead: true });
|
|
7459
|
+
return;
|
|
7419
7460
|
}
|
|
7420
7461
|
resolve7({ dead: false });
|
|
7421
7462
|
})();
|
|
@@ -7446,6 +7487,17 @@ var ChunkEmitter = class {
|
|
|
7446
7487
|
attempt(maxRetries);
|
|
7447
7488
|
});
|
|
7448
7489
|
}
|
|
7490
|
+
markPairingInvalid(statusCode, tookMs) {
|
|
7491
|
+
if (this.pairingInvalid) return;
|
|
7492
|
+
this.pairingInvalid = true;
|
|
7493
|
+
process.stderr.write(
|
|
7494
|
+
"[codeam] This pairing is no longer valid \u2014 run `codeam pair` again to reconnect this session.\n"
|
|
7495
|
+
);
|
|
7496
|
+
log.warn(
|
|
7497
|
+
"chunkEmitter",
|
|
7498
|
+
`pairing invalid (status=${statusCode}) took=${tookMs}ms \u2014 emitter latched, no further posts`
|
|
7499
|
+
);
|
|
7500
|
+
}
|
|
7449
7501
|
};
|
|
7450
7502
|
var _transport3 = {
|
|
7451
7503
|
post: _post2
|
|
@@ -12790,11 +12842,11 @@ function parseReview(stdout) {
|
|
|
12790
12842
|
for (const line of lines) {
|
|
12791
12843
|
const m = line.match(HUNK_LINE_RE);
|
|
12792
12844
|
if (!m) continue;
|
|
12793
|
-
const [,
|
|
12794
|
-
if (!
|
|
12845
|
+
const [, path63, lineNo, sevToken, message] = m;
|
|
12846
|
+
if (!path63 || !lineNo || !message) continue;
|
|
12795
12847
|
const cleanedMessage = message.trim().replace(/^[*-]\s+/, "");
|
|
12796
12848
|
hunks.push({
|
|
12797
|
-
path:
|
|
12849
|
+
path: path63.trim(),
|
|
12798
12850
|
line: Number(lineNo),
|
|
12799
12851
|
severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
|
|
12800
12852
|
message: cleanedMessage
|
|
@@ -14876,7 +14928,7 @@ async function autoUpgradeBeforeCriticalCommand() {
|
|
|
14876
14928
|
if (process.env.NODE_ENV === "test") return;
|
|
14877
14929
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
14878
14930
|
if (process.env.CI) return;
|
|
14879
|
-
const current = true ? "2.52.
|
|
14931
|
+
const current = true ? "2.52.7" : null;
|
|
14880
14932
|
if (!current) return;
|
|
14881
14933
|
const cache = readCache();
|
|
14882
14934
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -14893,7 +14945,7 @@ function checkForUpdates() {
|
|
|
14893
14945
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
14894
14946
|
if (process.env.CI) return;
|
|
14895
14947
|
if (!process.stdout.isTTY) return;
|
|
14896
|
-
const current = true ? "2.52.
|
|
14948
|
+
const current = true ? "2.52.7" : null;
|
|
14897
14949
|
if (!current) return;
|
|
14898
14950
|
const cache = readCache();
|
|
14899
14951
|
const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
|
|
@@ -15595,7 +15647,7 @@ var defaultSpawner = (env, cwd, args2 = []) => (0, import_node_child_process15.s
|
|
|
15595
15647
|
detached: false
|
|
15596
15648
|
});
|
|
15597
15649
|
function currentCliVersion() {
|
|
15598
|
-
return true ? "2.52.
|
|
15650
|
+
return true ? "2.52.7" : null;
|
|
15599
15651
|
}
|
|
15600
15652
|
function runCmd(cmd, args2, timeoutMs) {
|
|
15601
15653
|
return new Promise((resolve7) => {
|
|
@@ -20337,12 +20389,12 @@ function readTokenFromArgs(args2) {
|
|
|
20337
20389
|
}
|
|
20338
20390
|
const fileFlag = args2.find((a) => a.startsWith("--token-file="));
|
|
20339
20391
|
if (fileFlag) {
|
|
20340
|
-
const
|
|
20392
|
+
const path63 = fileFlag.slice("--token-file=".length);
|
|
20341
20393
|
try {
|
|
20342
|
-
const content = fs44.readFileSync(
|
|
20343
|
-
if (content.length === 0) fail(`--token-file ${
|
|
20394
|
+
const content = fs44.readFileSync(path63, "utf8").trim();
|
|
20395
|
+
if (content.length === 0) fail(`--token-file ${path63} is empty`);
|
|
20344
20396
|
try {
|
|
20345
|
-
fs44.unlinkSync(
|
|
20397
|
+
fs44.unlinkSync(path63);
|
|
20346
20398
|
} catch {
|
|
20347
20399
|
}
|
|
20348
20400
|
return content;
|
|
@@ -21023,12 +21075,58 @@ function requiresAcp(agent) {
|
|
|
21023
21075
|
return getAcpAdapter(agent) !== null;
|
|
21024
21076
|
}
|
|
21025
21077
|
|
|
21078
|
+
// src/agents/acp/claude-binary.ts
|
|
21079
|
+
var import_fs4 = __toESM(require("fs"));
|
|
21080
|
+
var import_path8 = __toESM(require("path"));
|
|
21081
|
+
function currentPlatformKey() {
|
|
21082
|
+
return `${process.platform}-${process.arch}`;
|
|
21083
|
+
}
|
|
21084
|
+
function defaultSdkDir() {
|
|
21085
|
+
try {
|
|
21086
|
+
const manifest = require.resolve("@anthropic-ai/claude-agent-sdk/package.json");
|
|
21087
|
+
return import_path8.default.dirname(manifest);
|
|
21088
|
+
} catch {
|
|
21089
|
+
return null;
|
|
21090
|
+
}
|
|
21091
|
+
}
|
|
21092
|
+
function resolveClaudeNativeBinary(deps = {}) {
|
|
21093
|
+
const existsSync21 = deps.existsSync ?? import_fs4.default.existsSync;
|
|
21094
|
+
const platformKey = deps.platformKey ?? currentPlatformKey();
|
|
21095
|
+
const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
|
|
21096
|
+
if (!sdkDir) return null;
|
|
21097
|
+
const scopeDir = import_path8.default.dirname(sdkDir);
|
|
21098
|
+
const binName = process.platform === "win32" ? "claude.exe" : "claude";
|
|
21099
|
+
const candidate = import_path8.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
|
|
21100
|
+
return existsSync21(candidate) ? candidate : null;
|
|
21101
|
+
}
|
|
21102
|
+
var realSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
21103
|
+
async function waitForClaudeNativeBinary(opts = {}) {
|
|
21104
|
+
const timeoutMs = opts.timeoutMs ?? 18e4;
|
|
21105
|
+
const pollMs = opts.pollMs ?? 500;
|
|
21106
|
+
const now = opts.now ?? Date.now;
|
|
21107
|
+
const sleep3 = opts.sleep ?? realSleep;
|
|
21108
|
+
const deps = {
|
|
21109
|
+
sdkDir: opts.sdkDir,
|
|
21110
|
+
platformKey: opts.platformKey,
|
|
21111
|
+
existsSync: opts.existsSync
|
|
21112
|
+
};
|
|
21113
|
+
const deadline = now() + timeoutMs;
|
|
21114
|
+
let found = resolveClaudeNativeBinary(deps);
|
|
21115
|
+
if (found) return found;
|
|
21116
|
+
while (now() < deadline) {
|
|
21117
|
+
await sleep3(pollMs);
|
|
21118
|
+
found = resolveClaudeNativeBinary(deps);
|
|
21119
|
+
if (found) return found;
|
|
21120
|
+
}
|
|
21121
|
+
return resolveClaudeNativeBinary(deps);
|
|
21122
|
+
}
|
|
21123
|
+
|
|
21026
21124
|
// src/agents/acp/runner.ts
|
|
21027
21125
|
var import_node_crypto7 = require("crypto");
|
|
21028
21126
|
|
|
21029
21127
|
// src/services/history.service.ts
|
|
21030
|
-
var
|
|
21031
|
-
var
|
|
21128
|
+
var fs46 = __toESM(require("fs"));
|
|
21129
|
+
var path52 = __toESM(require("path"));
|
|
21032
21130
|
var os38 = __toESM(require("os"));
|
|
21033
21131
|
var https7 = __toESM(require("https"));
|
|
21034
21132
|
var http6 = __toESM(require("http"));
|
|
@@ -21056,7 +21154,7 @@ function parseJsonl(filePath) {
|
|
|
21056
21154
|
const messages = [];
|
|
21057
21155
|
let raw;
|
|
21058
21156
|
try {
|
|
21059
|
-
raw =
|
|
21157
|
+
raw = fs46.readFileSync(filePath, "utf8");
|
|
21060
21158
|
} catch (err) {
|
|
21061
21159
|
if (err.code !== "ENOENT") {
|
|
21062
21160
|
log.warn("history:parseJsonl", `read failed for ${filePath}`, err);
|
|
@@ -21197,7 +21295,7 @@ var HistoryService = class _HistoryService {
|
|
|
21197
21295
|
return this._quotaPercent === null || Date.now() - this._quotaFetchedAt > ttlMs;
|
|
21198
21296
|
}
|
|
21199
21297
|
get projectDir() {
|
|
21200
|
-
return this.runtime.resolveHistoryDir(this.cwd) ??
|
|
21298
|
+
return this.runtime.resolveHistoryDir(this.cwd) ?? path52.join(os38.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
21201
21299
|
}
|
|
21202
21300
|
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
21203
21301
|
setCurrentConversationId(id) {
|
|
@@ -21209,7 +21307,7 @@ var HistoryService = class _HistoryService {
|
|
|
21209
21307
|
/** Return the current message count in the active conversation. */
|
|
21210
21308
|
getCurrentMessageCount() {
|
|
21211
21309
|
if (!this.currentConversationId) return 0;
|
|
21212
|
-
const filePath =
|
|
21310
|
+
const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
21213
21311
|
return parseJsonl(filePath).length;
|
|
21214
21312
|
}
|
|
21215
21313
|
/**
|
|
@@ -21220,7 +21318,7 @@ var HistoryService = class _HistoryService {
|
|
|
21220
21318
|
const deadline = Date.now() + timeoutMs;
|
|
21221
21319
|
while (Date.now() < deadline) {
|
|
21222
21320
|
if (!this.currentConversationId) return null;
|
|
21223
|
-
const filePath =
|
|
21321
|
+
const filePath = path52.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
21224
21322
|
const messages = parseJsonl(filePath);
|
|
21225
21323
|
if (messages.length > previousCount) {
|
|
21226
21324
|
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
@@ -21246,16 +21344,16 @@ var HistoryService = class _HistoryService {
|
|
|
21246
21344
|
const dir = this.projectDir;
|
|
21247
21345
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
21248
21346
|
try {
|
|
21249
|
-
const files =
|
|
21347
|
+
const files = fs46.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
21250
21348
|
try {
|
|
21251
|
-
const stat3 =
|
|
21349
|
+
const stat3 = fs46.statSync(path52.join(dir, e.name));
|
|
21252
21350
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
21253
21351
|
} catch {
|
|
21254
21352
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
21255
21353
|
}
|
|
21256
21354
|
}).filter((f) => f.birthtime >= cutoff).sort((a, b) => b.mtime - a.mtime);
|
|
21257
21355
|
if (files.length > 0) {
|
|
21258
|
-
this.currentConversationId =
|
|
21356
|
+
this.currentConversationId = path52.basename(files[0].name, ".jsonl");
|
|
21259
21357
|
}
|
|
21260
21358
|
} catch {
|
|
21261
21359
|
}
|
|
@@ -21289,13 +21387,13 @@ var HistoryService = class _HistoryService {
|
|
|
21289
21387
|
const cutoff = this.bootTimeMs - _HistoryService.BIRTHTIME_GRACE_MS;
|
|
21290
21388
|
let entries;
|
|
21291
21389
|
try {
|
|
21292
|
-
entries =
|
|
21390
|
+
entries = fs46.readdirSync(dir, { withFileTypes: true });
|
|
21293
21391
|
} catch {
|
|
21294
21392
|
return null;
|
|
21295
21393
|
}
|
|
21296
21394
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
21297
21395
|
try {
|
|
21298
|
-
const stat3 =
|
|
21396
|
+
const stat3 = fs46.statSync(path52.join(dir, e.name));
|
|
21299
21397
|
return { name: e.name, mtime: stat3.mtimeMs, birthtime: stat3.birthtimeMs };
|
|
21300
21398
|
} catch {
|
|
21301
21399
|
return { name: e.name, mtime: 0, birthtime: 0 };
|
|
@@ -21304,12 +21402,12 @@ var HistoryService = class _HistoryService {
|
|
|
21304
21402
|
if (files.length === 0) return null;
|
|
21305
21403
|
const targetFile = this.currentConversationId ? `${this.currentConversationId}.jsonl` : files[0].name;
|
|
21306
21404
|
if (!files.some((f) => f.name === targetFile)) return null;
|
|
21307
|
-
return this.extractUsageFromFile(
|
|
21405
|
+
return this.extractUsageFromFile(path52.join(dir, targetFile));
|
|
21308
21406
|
}
|
|
21309
21407
|
extractUsageFromFile(filePath) {
|
|
21310
21408
|
let raw;
|
|
21311
21409
|
try {
|
|
21312
|
-
raw =
|
|
21410
|
+
raw = fs46.readFileSync(filePath, "utf8");
|
|
21313
21411
|
} catch {
|
|
21314
21412
|
return null;
|
|
21315
21413
|
}
|
|
@@ -21354,9 +21452,9 @@ var HistoryService = class _HistoryService {
|
|
|
21354
21452
|
let totalCost = 0;
|
|
21355
21453
|
let files;
|
|
21356
21454
|
try {
|
|
21357
|
-
files =
|
|
21455
|
+
files = fs46.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
21358
21456
|
try {
|
|
21359
|
-
return
|
|
21457
|
+
return fs46.statSync(path52.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
21360
21458
|
} catch {
|
|
21361
21459
|
return false;
|
|
21362
21460
|
}
|
|
@@ -21367,7 +21465,7 @@ var HistoryService = class _HistoryService {
|
|
|
21367
21465
|
for (const file of files) {
|
|
21368
21466
|
let raw;
|
|
21369
21467
|
try {
|
|
21370
|
-
raw =
|
|
21468
|
+
raw = fs46.readFileSync(path52.join(projectDir, file), "utf8");
|
|
21371
21469
|
} catch {
|
|
21372
21470
|
continue;
|
|
21373
21471
|
}
|
|
@@ -21446,7 +21544,7 @@ var HistoryService = class _HistoryService {
|
|
|
21446
21544
|
if (this.runtime.resolveHistoryFile) {
|
|
21447
21545
|
return this.runtime.resolveHistoryFile(this.cwd, sessionId);
|
|
21448
21546
|
}
|
|
21449
|
-
return
|
|
21547
|
+
return path52.join(this.projectDir, `${sessionId}.jsonl`);
|
|
21450
21548
|
}
|
|
21451
21549
|
/**
|
|
21452
21550
|
* Parse a conversation's messages from disk, agent-aware. Claude uses the
|
|
@@ -21480,7 +21578,7 @@ var HistoryService = class _HistoryService {
|
|
|
21480
21578
|
};
|
|
21481
21579
|
});
|
|
21482
21580
|
}
|
|
21483
|
-
return parseJsonl(
|
|
21581
|
+
return parseJsonl(path52.join(this.projectDir, `${sessionId}.jsonl`));
|
|
21484
21582
|
}
|
|
21485
21583
|
async loadConversation(sessionId) {
|
|
21486
21584
|
const messages = this.readConversation(sessionId);
|
|
@@ -21536,7 +21634,7 @@ var HistoryService = class _HistoryService {
|
|
|
21536
21634
|
if (!filePath) return false;
|
|
21537
21635
|
let mtimeMs;
|
|
21538
21636
|
try {
|
|
21539
|
-
mtimeMs =
|
|
21637
|
+
mtimeMs = fs46.statSync(filePath).mtimeMs;
|
|
21540
21638
|
} catch {
|
|
21541
21639
|
return false;
|
|
21542
21640
|
}
|
|
@@ -21605,10 +21703,10 @@ var HistoryService = class _HistoryService {
|
|
|
21605
21703
|
|
|
21606
21704
|
// src/agents/acp/client.ts
|
|
21607
21705
|
var import_node_child_process17 = require("child_process");
|
|
21608
|
-
var
|
|
21706
|
+
var fs47 = __toESM(require("fs/promises"));
|
|
21609
21707
|
var fsSync = __toESM(require("fs"));
|
|
21610
21708
|
var os39 = __toESM(require("os"));
|
|
21611
|
-
var
|
|
21709
|
+
var path53 = __toESM(require("path"));
|
|
21612
21710
|
var import_node_stream = require("stream");
|
|
21613
21711
|
|
|
21614
21712
|
// ../../node_modules/@agentclientprotocol/sdk/dist/acp.js
|
|
@@ -24441,7 +24539,7 @@ var AcpClient = class {
|
|
|
24441
24539
|
},
|
|
24442
24540
|
readTextFile: async (params) => {
|
|
24443
24541
|
try {
|
|
24444
|
-
const content = await
|
|
24542
|
+
const content = await fs47.readFile(params.path, "utf8");
|
|
24445
24543
|
return applyLineRange(content, params.line ?? null, params.limit ?? null);
|
|
24446
24544
|
} catch (err) {
|
|
24447
24545
|
const code = err.code;
|
|
@@ -24461,7 +24559,7 @@ var AcpClient = class {
|
|
|
24461
24559
|
},
|
|
24462
24560
|
writeTextFile: async (params) => {
|
|
24463
24561
|
try {
|
|
24464
|
-
await
|
|
24562
|
+
await fs47.writeFile(params.path, params.content, "utf8");
|
|
24465
24563
|
return {};
|
|
24466
24564
|
} catch (err) {
|
|
24467
24565
|
const code = err.code;
|
|
@@ -24515,20 +24613,20 @@ function knownAgentBinaryDirs() {
|
|
|
24515
24613
|
out2.push("/tmp/codeam-node20/bin");
|
|
24516
24614
|
for (const root of [
|
|
24517
24615
|
"/usr/local/share/nvm/versions/node",
|
|
24518
|
-
|
|
24616
|
+
path53.join(home, ".nvm/versions/node")
|
|
24519
24617
|
]) {
|
|
24520
24618
|
try {
|
|
24521
24619
|
for (const child of fsSync.readdirSync(root)) {
|
|
24522
|
-
out2.push(
|
|
24620
|
+
out2.push(path53.join(root, child, "bin"));
|
|
24523
24621
|
}
|
|
24524
24622
|
} catch {
|
|
24525
24623
|
}
|
|
24526
24624
|
}
|
|
24527
|
-
out2.push(
|
|
24625
|
+
out2.push(path53.join(home, ".volta/bin"));
|
|
24528
24626
|
out2.push("/usr/local/bin");
|
|
24529
24627
|
out2.push("/usr/bin");
|
|
24530
|
-
out2.push(
|
|
24531
|
-
out2.push(
|
|
24628
|
+
out2.push(path53.join(home, ".local/bin"));
|
|
24629
|
+
out2.push(path53.join(home, "bin"));
|
|
24532
24630
|
return out2.filter((p2) => {
|
|
24533
24631
|
try {
|
|
24534
24632
|
return fsSync.statSync(p2).isDirectory();
|
|
@@ -24539,7 +24637,7 @@ function knownAgentBinaryDirs() {
|
|
|
24539
24637
|
}
|
|
24540
24638
|
function expandPathForAgentBinaries(existingPath) {
|
|
24541
24639
|
const existing = new Set(
|
|
24542
|
-
existingPath.split(
|
|
24640
|
+
existingPath.split(path53.delimiter).filter((p2) => p2.length > 0)
|
|
24543
24641
|
);
|
|
24544
24642
|
const additions = [];
|
|
24545
24643
|
for (const dir of knownAgentBinaryDirs()) {
|
|
@@ -24549,7 +24647,7 @@ function expandPathForAgentBinaries(existingPath) {
|
|
|
24549
24647
|
}
|
|
24550
24648
|
}
|
|
24551
24649
|
if (additions.length === 0) return existingPath;
|
|
24552
|
-
return [...additions, existingPath].filter((p2) => p2.length > 0).join(
|
|
24650
|
+
return [...additions, existingPath].filter((p2) => p2.length > 0).join(path53.delimiter);
|
|
24553
24651
|
}
|
|
24554
24652
|
|
|
24555
24653
|
// src/services/streaming/transport.ts
|
|
@@ -24652,6 +24750,10 @@ var AcpPublisher = class {
|
|
|
24652
24750
|
opts;
|
|
24653
24751
|
apiBase;
|
|
24654
24752
|
token;
|
|
24753
|
+
/** Latched on an unrecoverable 401/403 — every surface stops posting
|
|
24754
|
+
* (2026-06-28 incident: a dead-token publisher spammed 401 ×34 while
|
|
24755
|
+
* the agent's replies silently never reached the phone). */
|
|
24756
|
+
pairingInvalid = false;
|
|
24655
24757
|
authHeaders() {
|
|
24656
24758
|
return {
|
|
24657
24759
|
"Content-Type": "application/json",
|
|
@@ -24667,14 +24769,39 @@ var AcpPublisher = class {
|
|
|
24667
24769
|
* response unchanged — callers log non-2xx but never throw.
|
|
24668
24770
|
*/
|
|
24669
24771
|
async postWithReauth(url, payload) {
|
|
24772
|
+
if (this.pairingInvalid) {
|
|
24773
|
+
return { statusCode: 401, body: "PAIRING_INVALID" };
|
|
24774
|
+
}
|
|
24670
24775
|
const first = await _transport4.post(url, this.authHeaders(), payload);
|
|
24671
24776
|
if (first.statusCode !== 401 && first.statusCode !== 403) return first;
|
|
24672
|
-
if (
|
|
24673
|
-
|
|
24674
|
-
|
|
24675
|
-
|
|
24676
|
-
|
|
24677
|
-
|
|
24777
|
+
if (this.opts.refreshAuthToken) {
|
|
24778
|
+
const fresh = await this.opts.refreshAuthToken();
|
|
24779
|
+
if (fresh) {
|
|
24780
|
+
this.token = fresh;
|
|
24781
|
+
log.info("acpPublisher", `plugin-auth token refreshed after ${first.statusCode}; retrying POST`);
|
|
24782
|
+
const second = await _transport4.post(url, this.authHeaders(), payload);
|
|
24783
|
+
if (second.statusCode !== 401 && second.statusCode !== 403) return second;
|
|
24784
|
+
this.markPairingInvalid(second.statusCode);
|
|
24785
|
+
return second;
|
|
24786
|
+
}
|
|
24787
|
+
}
|
|
24788
|
+
this.markPairingInvalid(first.statusCode);
|
|
24789
|
+
return first;
|
|
24790
|
+
}
|
|
24791
|
+
markPairingInvalid(statusCode) {
|
|
24792
|
+
if (this.pairingInvalid) return;
|
|
24793
|
+
this.pairingInvalid = true;
|
|
24794
|
+
process.stderr.write(
|
|
24795
|
+
"[codeam] This pairing is no longer valid \u2014 run `codeam pair` again to reconnect this session.\n"
|
|
24796
|
+
);
|
|
24797
|
+
log.warn(
|
|
24798
|
+
"acpPublisher",
|
|
24799
|
+
`pairing invalid (status=${statusCode}) \u2014 publisher latched, no further posts`
|
|
24800
|
+
);
|
|
24801
|
+
try {
|
|
24802
|
+
this.opts.onPairingInvalid?.();
|
|
24803
|
+
} catch {
|
|
24804
|
+
}
|
|
24678
24805
|
}
|
|
24679
24806
|
/**
|
|
24680
24807
|
* Wrap the body with `sessionId` + `pluginId` at the top level.
|
|
@@ -25034,15 +25161,15 @@ function commonPrefixLength(a, b) {
|
|
|
25034
25161
|
|
|
25035
25162
|
// src/agents/acp/onboarding.ts
|
|
25036
25163
|
var import_child_process23 = require("child_process");
|
|
25037
|
-
var
|
|
25164
|
+
var fs48 = __toESM(require("fs"));
|
|
25038
25165
|
var os40 = __toESM(require("os"));
|
|
25039
|
-
var
|
|
25166
|
+
var path54 = __toESM(require("path"));
|
|
25040
25167
|
var _onboardingSeam = {
|
|
25041
|
-
markerPath: (sessionId) =>
|
|
25042
|
-
exists: (p2) =>
|
|
25168
|
+
markerPath: (sessionId) => path54.join(os40.homedir(), ".codeam", "welcomed", `${sessionId}.done`),
|
|
25169
|
+
exists: (p2) => fs48.existsSync(p2),
|
|
25043
25170
|
write: (p2) => {
|
|
25044
|
-
|
|
25045
|
-
|
|
25171
|
+
fs48.mkdirSync(path54.dirname(p2), { recursive: true });
|
|
25172
|
+
fs48.writeFileSync(p2, "");
|
|
25046
25173
|
},
|
|
25047
25174
|
disabled: () => {
|
|
25048
25175
|
const v = process.env.CODEAM_ONBOARDING_DISABLED;
|
|
@@ -25079,7 +25206,7 @@ function resolveRepoName(cwd) {
|
|
|
25079
25206
|
if (name) return name;
|
|
25080
25207
|
}
|
|
25081
25208
|
}
|
|
25082
|
-
const base =
|
|
25209
|
+
const base = path54.basename(cwd || "");
|
|
25083
25210
|
if (base && !isUuid(base)) return base;
|
|
25084
25211
|
return "this project";
|
|
25085
25212
|
}
|
|
@@ -25357,8 +25484,8 @@ var import_crypto5 = require("crypto");
|
|
|
25357
25484
|
|
|
25358
25485
|
// src/services/turn-files/git-changeset.ts
|
|
25359
25486
|
var import_child_process24 = require("child_process");
|
|
25360
|
-
var
|
|
25361
|
-
var
|
|
25487
|
+
var fs49 = __toESM(require("fs/promises"));
|
|
25488
|
+
var path55 = __toESM(require("path"));
|
|
25362
25489
|
async function collectRepoChangeset(opts) {
|
|
25363
25490
|
const status2 = await runGit3(opts.repoRoot, ["status", "--porcelain=v1", "-z"]);
|
|
25364
25491
|
if (status2 === null) return null;
|
|
@@ -25376,7 +25503,7 @@ async function collectRepoChangeset(opts) {
|
|
|
25376
25503
|
let stats;
|
|
25377
25504
|
if (row.fileStatus === "added" && numstatEntry === void 0) {
|
|
25378
25505
|
const lineCount = await readUntrackedLineCount(
|
|
25379
|
-
|
|
25506
|
+
path55.join(opts.repoRoot, row.filePath)
|
|
25380
25507
|
);
|
|
25381
25508
|
stats = { added: lineCount, removed: 0 };
|
|
25382
25509
|
} else {
|
|
@@ -25407,7 +25534,7 @@ function readUntrackedLineCount(absPath) {
|
|
|
25407
25534
|
}
|
|
25408
25535
|
async function defaultReadUntrackedLineCount(absPath) {
|
|
25409
25536
|
try {
|
|
25410
|
-
const content = await
|
|
25537
|
+
const content = await fs49.readFile(absPath, "utf8");
|
|
25411
25538
|
let count = 0;
|
|
25412
25539
|
let pos = -1;
|
|
25413
25540
|
while ((pos = content.indexOf("\n", pos + 1)) !== -1) {
|
|
@@ -25499,7 +25626,7 @@ function defaultRunGit(cwd, args2) {
|
|
|
25499
25626
|
});
|
|
25500
25627
|
}
|
|
25501
25628
|
async function discoverRepos(workingDir, maxDepth = 4) {
|
|
25502
|
-
const
|
|
25629
|
+
const fs53 = await import("fs/promises");
|
|
25503
25630
|
const out2 = [];
|
|
25504
25631
|
await walk(workingDir, 0);
|
|
25505
25632
|
return out2;
|
|
@@ -25507,7 +25634,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
25507
25634
|
if (depth > maxDepth) return;
|
|
25508
25635
|
let entries = [];
|
|
25509
25636
|
try {
|
|
25510
|
-
const dirents = await
|
|
25637
|
+
const dirents = await fs53.readdir(dir, { withFileTypes: true });
|
|
25511
25638
|
entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
|
|
25512
25639
|
} catch {
|
|
25513
25640
|
return;
|
|
@@ -25518,8 +25645,8 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
25518
25645
|
if (hasGit) {
|
|
25519
25646
|
out2.push({
|
|
25520
25647
|
repoRoot: dir,
|
|
25521
|
-
repoPath:
|
|
25522
|
-
repoName:
|
|
25648
|
+
repoPath: path55.relative(workingDir, dir),
|
|
25649
|
+
repoName: path55.basename(dir)
|
|
25523
25650
|
});
|
|
25524
25651
|
return;
|
|
25525
25652
|
}
|
|
@@ -25527,14 +25654,14 @@ async function discoverRepos(workingDir, maxDepth = 4) {
|
|
|
25527
25654
|
if (!entry.isDirectory) continue;
|
|
25528
25655
|
if (entry.name === "node_modules") continue;
|
|
25529
25656
|
if (entry.name === "dist" || entry.name === "build") continue;
|
|
25530
|
-
await walk(
|
|
25657
|
+
await walk(path55.join(dir, entry.name), depth + 1);
|
|
25531
25658
|
}
|
|
25532
25659
|
}
|
|
25533
25660
|
}
|
|
25534
25661
|
|
|
25535
25662
|
// src/services/turn-files/files-outbox.ts
|
|
25536
|
-
var
|
|
25537
|
-
var
|
|
25663
|
+
var fs50 = __toESM(require("fs/promises"));
|
|
25664
|
+
var path56 = __toESM(require("path"));
|
|
25538
25665
|
var import_os7 = require("os");
|
|
25539
25666
|
var HOME_OUTBOX_DIR = ".codeam/outbox";
|
|
25540
25667
|
var MAX_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -25567,16 +25694,16 @@ var FilesOutbox = class {
|
|
|
25567
25694
|
backoffIndex = 0;
|
|
25568
25695
|
stopped = false;
|
|
25569
25696
|
constructor(opts) {
|
|
25570
|
-
const base = opts.baseDir ??
|
|
25571
|
-
this.filePath =
|
|
25697
|
+
const base = opts.baseDir ?? path56.join(homeDir(), HOME_OUTBOX_DIR);
|
|
25698
|
+
this.filePath = path56.join(base, `${opts.sessionId}.jsonl`);
|
|
25572
25699
|
this.post = opts.post;
|
|
25573
25700
|
this.autoSchedule = opts.autoSchedule !== false;
|
|
25574
25701
|
}
|
|
25575
25702
|
/** Persist the entry to disk and trigger a flush. Returns once the
|
|
25576
25703
|
* line is durable on disk (not once the POST succeeds). */
|
|
25577
25704
|
async enqueue(entry) {
|
|
25578
|
-
await
|
|
25579
|
-
await
|
|
25705
|
+
await fs50.mkdir(path56.dirname(this.filePath), { recursive: true });
|
|
25706
|
+
await fs50.appendFile(this.filePath, JSON.stringify(entry) + "\n", "utf8");
|
|
25580
25707
|
this.backoffIndex = 0;
|
|
25581
25708
|
if (this.autoSchedule) this.scheduleFlush(0);
|
|
25582
25709
|
}
|
|
@@ -25665,7 +25792,7 @@ var FilesOutbox = class {
|
|
|
25665
25792
|
async readAll() {
|
|
25666
25793
|
let raw = "";
|
|
25667
25794
|
try {
|
|
25668
|
-
raw = await
|
|
25795
|
+
raw = await fs50.readFile(this.filePath, "utf8");
|
|
25669
25796
|
} catch {
|
|
25670
25797
|
return [];
|
|
25671
25798
|
}
|
|
@@ -25689,12 +25816,12 @@ var FilesOutbox = class {
|
|
|
25689
25816
|
async rewrite(entries) {
|
|
25690
25817
|
const tmpPath = `${this.filePath}.${process.pid}.tmp`;
|
|
25691
25818
|
if (entries.length === 0) {
|
|
25692
|
-
await
|
|
25819
|
+
await fs50.unlink(this.filePath).catch(() => void 0);
|
|
25693
25820
|
return;
|
|
25694
25821
|
}
|
|
25695
25822
|
const payload = entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
25696
|
-
await
|
|
25697
|
-
await
|
|
25823
|
+
await fs50.writeFile(tmpPath, payload, "utf8");
|
|
25824
|
+
await fs50.rename(tmpPath, this.filePath);
|
|
25698
25825
|
}
|
|
25699
25826
|
};
|
|
25700
25827
|
function applyJitter(ms) {
|
|
@@ -28323,15 +28450,15 @@ function fetchQuotaUsage(runtime, historySvc) {
|
|
|
28323
28450
|
}
|
|
28324
28451
|
|
|
28325
28452
|
// src/agents/claude/onboarding.ts
|
|
28326
|
-
var
|
|
28453
|
+
var fs51 = __toESM(require("fs"));
|
|
28327
28454
|
var os41 = __toESM(require("os"));
|
|
28328
|
-
var
|
|
28455
|
+
var path57 = __toESM(require("path"));
|
|
28329
28456
|
function ensureClaudeOnboarded() {
|
|
28330
28457
|
try {
|
|
28331
|
-
const file =
|
|
28458
|
+
const file = path57.join(os41.homedir(), ".claude.json");
|
|
28332
28459
|
let config = {};
|
|
28333
28460
|
try {
|
|
28334
|
-
config = JSON.parse(
|
|
28461
|
+
config = JSON.parse(fs51.readFileSync(file, "utf8"));
|
|
28335
28462
|
} catch {
|
|
28336
28463
|
}
|
|
28337
28464
|
if (config.hasCompletedOnboarding === true && typeof config.theme === "string") {
|
|
@@ -28342,8 +28469,8 @@ function ensureClaudeOnboarded() {
|
|
|
28342
28469
|
if (typeof config.lastOnboardingVersion !== "string") {
|
|
28343
28470
|
config.lastOnboardingVersion = "2.1.177";
|
|
28344
28471
|
}
|
|
28345
|
-
|
|
28346
|
-
|
|
28472
|
+
fs51.mkdirSync(path57.dirname(file), { recursive: true });
|
|
28473
|
+
fs51.writeFileSync(file, JSON.stringify(config, null, 2));
|
|
28347
28474
|
log.info("claude", "pre-completed Claude onboarding (skip first-run theme picker)");
|
|
28348
28475
|
} catch (err) {
|
|
28349
28476
|
log.warn("claude", `ensureClaudeOnboarded failed (non-fatal): ${err.message}`);
|
|
@@ -28447,9 +28574,10 @@ async function start(requestedAgent) {
|
|
|
28447
28574
|
const depsReady = process.env.CODESPACES === "true" ? provisionProjectDependencies(cwd).catch(() => void 0) : Promise.resolve();
|
|
28448
28575
|
if (process.env.CODESPACES === "true") {
|
|
28449
28576
|
const GATE_TIMEOUT_MS = 24e4;
|
|
28577
|
+
const claudeBinaryReady = session.agent === "claude" ? waitForClaudeNativeBinary({ timeoutMs: GATE_TIMEOUT_MS }).catch(() => null) : Promise.resolve();
|
|
28450
28578
|
let gateTimer;
|
|
28451
28579
|
await Promise.race([
|
|
28452
|
-
Promise.all([beadsReady.catch(() => null), depsReady]),
|
|
28580
|
+
Promise.all([beadsReady.catch(() => null), depsReady, claudeBinaryReady]),
|
|
28453
28581
|
new Promise((resolve7) => {
|
|
28454
28582
|
gateTimer = setTimeout(resolve7, GATE_TIMEOUT_MS);
|
|
28455
28583
|
})
|
|
@@ -28993,7 +29121,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
|
|
|
28993
29121
|
var import_child_process25 = require("child_process");
|
|
28994
29122
|
var import_util4 = require("util");
|
|
28995
29123
|
var import_picocolors9 = __toESM(require("picocolors"));
|
|
28996
|
-
var
|
|
29124
|
+
var path58 = __toESM(require("path"));
|
|
28997
29125
|
var execFileP6 = (0, import_util4.promisify)(import_child_process25.execFile);
|
|
28998
29126
|
var MAX_BUFFER = 8 * 1024 * 1024;
|
|
28999
29127
|
function resetStdinForChild() {
|
|
@@ -29482,7 +29610,7 @@ var GitHubCodespacesProvider = class {
|
|
|
29482
29610
|
});
|
|
29483
29611
|
}
|
|
29484
29612
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
29485
|
-
const remoteDir =
|
|
29613
|
+
const remoteDir = path58.posix.dirname(remotePath);
|
|
29486
29614
|
const parts = [
|
|
29487
29615
|
`mkdir -p ${shellQuote(remoteDir)}`,
|
|
29488
29616
|
`cat > ${shellQuote(remotePath)}`
|
|
@@ -29552,7 +29680,7 @@ function shellQuote(s) {
|
|
|
29552
29680
|
// src/services/providers/gitpod.ts
|
|
29553
29681
|
var import_child_process26 = require("child_process");
|
|
29554
29682
|
var import_util5 = require("util");
|
|
29555
|
-
var
|
|
29683
|
+
var path59 = __toESM(require("path"));
|
|
29556
29684
|
var import_picocolors10 = __toESM(require("picocolors"));
|
|
29557
29685
|
var execFileP7 = (0, import_util5.promisify)(import_child_process26.execFile);
|
|
29558
29686
|
var MAX_BUFFER2 = 8 * 1024 * 1024;
|
|
@@ -29792,7 +29920,7 @@ var GitpodProvider = class {
|
|
|
29792
29920
|
});
|
|
29793
29921
|
}
|
|
29794
29922
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
29795
|
-
const remoteDir =
|
|
29923
|
+
const remoteDir = path59.posix.dirname(remotePath);
|
|
29796
29924
|
const parts = [
|
|
29797
29925
|
`mkdir -p ${shellQuote2(remoteDir)}`,
|
|
29798
29926
|
`cat > ${shellQuote2(remotePath)}`
|
|
@@ -29828,7 +29956,7 @@ function shellQuote2(s) {
|
|
|
29828
29956
|
// src/services/providers/gitlab-workspaces.ts
|
|
29829
29957
|
var import_child_process27 = require("child_process");
|
|
29830
29958
|
var import_util6 = require("util");
|
|
29831
|
-
var
|
|
29959
|
+
var path60 = __toESM(require("path"));
|
|
29832
29960
|
var execFileP8 = (0, import_util6.promisify)(import_child_process27.execFile);
|
|
29833
29961
|
var MAX_BUFFER3 = 8 * 1024 * 1024;
|
|
29834
29962
|
var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
|
|
@@ -30088,7 +30216,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
|
|
|
30088
30216
|
}
|
|
30089
30217
|
async uploadFile(workspaceId, remotePath, contents, options = {}) {
|
|
30090
30218
|
const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
|
|
30091
|
-
const remoteDir =
|
|
30219
|
+
const remoteDir = path60.posix.dirname(remotePath);
|
|
30092
30220
|
const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
|
|
30093
30221
|
if (options.mode != null) {
|
|
30094
30222
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
|
|
@@ -30156,7 +30284,7 @@ function shellQuote3(s) {
|
|
|
30156
30284
|
// src/services/providers/railway.ts
|
|
30157
30285
|
var import_child_process28 = require("child_process");
|
|
30158
30286
|
var import_util7 = require("util");
|
|
30159
|
-
var
|
|
30287
|
+
var path61 = __toESM(require("path"));
|
|
30160
30288
|
var execFileP9 = (0, import_util7.promisify)(import_child_process28.execFile);
|
|
30161
30289
|
var MAX_BUFFER4 = 8 * 1024 * 1024;
|
|
30162
30290
|
function resetStdinForChild4() {
|
|
@@ -30392,7 +30520,7 @@ var RailwayProvider = class {
|
|
|
30392
30520
|
if (!projectId || !serviceId) {
|
|
30393
30521
|
throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
|
|
30394
30522
|
}
|
|
30395
|
-
const remoteDir =
|
|
30523
|
+
const remoteDir = path61.posix.dirname(remotePath);
|
|
30396
30524
|
const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
|
|
30397
30525
|
if (options.mode != null) {
|
|
30398
30526
|
parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
|
|
@@ -31038,8 +31166,8 @@ async function invite() {
|
|
|
31038
31166
|
var import_node_dns = require("dns");
|
|
31039
31167
|
var import_node_util5 = require("util");
|
|
31040
31168
|
var import_node_crypto8 = require("crypto");
|
|
31041
|
-
var
|
|
31042
|
-
var
|
|
31169
|
+
var fs52 = __toESM(require("fs"));
|
|
31170
|
+
var path62 = __toESM(require("path"));
|
|
31043
31171
|
var import_picocolors14 = __toESM(require("picocolors"));
|
|
31044
31172
|
var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
|
|
31045
31173
|
async function checkDns(apiBase2) {
|
|
@@ -31095,13 +31223,13 @@ async function checkHealth(apiBase2) {
|
|
|
31095
31223
|
}
|
|
31096
31224
|
}
|
|
31097
31225
|
function checkConfigDir() {
|
|
31098
|
-
const dir =
|
|
31226
|
+
const dir = path62.join(require("os").homedir(), ".codeam");
|
|
31099
31227
|
try {
|
|
31100
|
-
|
|
31101
|
-
const probe =
|
|
31102
|
-
|
|
31103
|
-
const read2 =
|
|
31104
|
-
|
|
31228
|
+
fs52.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
31229
|
+
const probe = path62.join(dir, ".doctor-probe");
|
|
31230
|
+
fs52.writeFileSync(probe, "ok", { mode: 384 });
|
|
31231
|
+
const read2 = fs52.readFileSync(probe, "utf8");
|
|
31232
|
+
fs52.unlinkSync(probe);
|
|
31105
31233
|
if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
|
|
31106
31234
|
return {
|
|
31107
31235
|
id: "config-dir",
|
|
@@ -31165,7 +31293,7 @@ function checkNodePty() {
|
|
|
31165
31293
|
detail: "not required on this platform"
|
|
31166
31294
|
};
|
|
31167
31295
|
}
|
|
31168
|
-
const vendoredPath =
|
|
31296
|
+
const vendoredPath = path62.join(__dirname, "vendor", "node-pty");
|
|
31169
31297
|
for (const target of [vendoredPath, "node-pty"]) {
|
|
31170
31298
|
try {
|
|
31171
31299
|
require(target);
|
|
@@ -31207,7 +31335,7 @@ function checkChokidar() {
|
|
|
31207
31335
|
}
|
|
31208
31336
|
async function doctor(args2 = []) {
|
|
31209
31337
|
const json = args2.includes("--json");
|
|
31210
|
-
const cliVersion = true ? "2.52.
|
|
31338
|
+
const cliVersion = true ? "2.52.7" : "0.0.0-dev";
|
|
31211
31339
|
const apiBase2 = resolveApiBaseUrl();
|
|
31212
31340
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
31213
31341
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -31406,7 +31534,7 @@ async function completion(args2) {
|
|
|
31406
31534
|
// src/commands/version.ts
|
|
31407
31535
|
var import_picocolors15 = __toESM(require("picocolors"));
|
|
31408
31536
|
function version2() {
|
|
31409
|
-
const v = true ? "2.52.
|
|
31537
|
+
const v = true ? "2.52.7" : "unknown";
|
|
31410
31538
|
console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
|
|
31411
31539
|
}
|
|
31412
31540
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codeam-cli",
|
|
3
|
-
"version": "2.52.
|
|
3
|
+
"version": "2.52.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",
|