codeam-cli 2.26.7 → 2.26.8
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 +6 -0
- package/dist/index.js +154 -46
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,12 @@ 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.26.7] — 2026-06-03
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **cli:** Preview no longer pollutes the host terminal + waits for tunnel DNS (#240)
|
|
12
|
+
|
|
7
13
|
## [2.26.6] — 2026-06-03
|
|
8
14
|
|
|
9
15
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -472,7 +472,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
472
472
|
// package.json
|
|
473
473
|
var package_default = {
|
|
474
474
|
name: "codeam-cli",
|
|
475
|
-
version: "2.26.
|
|
475
|
+
version: "2.26.8",
|
|
476
476
|
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.",
|
|
477
477
|
type: "commonjs",
|
|
478
478
|
main: "dist/index.js",
|
|
@@ -5829,7 +5829,7 @@ function readAnonId() {
|
|
|
5829
5829
|
}
|
|
5830
5830
|
function superProperties() {
|
|
5831
5831
|
return {
|
|
5832
|
-
cliVersion: true ? "2.26.
|
|
5832
|
+
cliVersion: true ? "2.26.8" : "0.0.0-dev",
|
|
5833
5833
|
nodeVersion: process.version,
|
|
5834
5834
|
platform: process.platform,
|
|
5835
5835
|
arch: process.arch,
|
|
@@ -9572,6 +9572,50 @@ function parseHistoryFile(filePath) {
|
|
|
9572
9572
|
}
|
|
9573
9573
|
return out2;
|
|
9574
9574
|
}
|
|
9575
|
+
function listResumableSessions(cwd) {
|
|
9576
|
+
const dir = resolveHistoryDir(cwd);
|
|
9577
|
+
if (!dir) return [];
|
|
9578
|
+
let entries;
|
|
9579
|
+
try {
|
|
9580
|
+
entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
9581
|
+
} catch {
|
|
9582
|
+
return [];
|
|
9583
|
+
}
|
|
9584
|
+
const out2 = [];
|
|
9585
|
+
for (const entry of entries) {
|
|
9586
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
9587
|
+
const id = entry.name.slice(0, -".jsonl".length);
|
|
9588
|
+
const filePath = path12.join(dir, entry.name);
|
|
9589
|
+
let timestamp = Date.now();
|
|
9590
|
+
try {
|
|
9591
|
+
timestamp = fs9.statSync(filePath).mtimeMs;
|
|
9592
|
+
} catch {
|
|
9593
|
+
}
|
|
9594
|
+
let summary = "";
|
|
9595
|
+
try {
|
|
9596
|
+
const raw = fs9.readFileSync(filePath, "utf8");
|
|
9597
|
+
for (const line of raw.split("\n")) {
|
|
9598
|
+
if (!line.trim()) continue;
|
|
9599
|
+
try {
|
|
9600
|
+
const record = JSON.parse(line);
|
|
9601
|
+
if (record["type"] === "user") {
|
|
9602
|
+
const msg = record["message"];
|
|
9603
|
+
const text = extractText(msg?.["content"]).trim();
|
|
9604
|
+
if (text) {
|
|
9605
|
+
summary = text.slice(0, 120);
|
|
9606
|
+
break;
|
|
9607
|
+
}
|
|
9608
|
+
}
|
|
9609
|
+
} catch {
|
|
9610
|
+
}
|
|
9611
|
+
}
|
|
9612
|
+
} catch {
|
|
9613
|
+
}
|
|
9614
|
+
if (summary) out2.push({ id, summary, timestamp });
|
|
9615
|
+
}
|
|
9616
|
+
out2.sort((a, b) => b.timestamp - a.timestamp);
|
|
9617
|
+
return out2;
|
|
9618
|
+
}
|
|
9575
9619
|
|
|
9576
9620
|
// src/agents/claude/parsing.ts
|
|
9577
9621
|
function filterChrome(lines) {
|
|
@@ -9933,6 +9977,9 @@ var ClaudeRuntimeStrategy = class {
|
|
|
9933
9977
|
getCurrentUsage(historyDir) {
|
|
9934
9978
|
return getCurrentUsage(historyDir);
|
|
9935
9979
|
}
|
|
9980
|
+
listResumableSessions(cwd) {
|
|
9981
|
+
return listResumableSessions(cwd);
|
|
9982
|
+
}
|
|
9936
9983
|
async fetchWeeklyUsage() {
|
|
9937
9984
|
return fetchClaudeQuota();
|
|
9938
9985
|
}
|
|
@@ -10297,6 +10344,84 @@ function parseHistoryFile2(filePath) {
|
|
|
10297
10344
|
}
|
|
10298
10345
|
return out2;
|
|
10299
10346
|
}
|
|
10347
|
+
function listResumableSessions2(cwd, homeOverride) {
|
|
10348
|
+
const home = homeOverride ?? import_node_os.default.homedir();
|
|
10349
|
+
const sessionsRoot = import_node_path2.default.join(home, ".codex", "sessions");
|
|
10350
|
+
if (!import_node_fs3.default.existsSync(sessionsRoot)) return [];
|
|
10351
|
+
let resolvedCurrent;
|
|
10352
|
+
try {
|
|
10353
|
+
resolvedCurrent = import_node_fs3.default.realpathSync(cwd);
|
|
10354
|
+
} catch {
|
|
10355
|
+
resolvedCurrent = import_node_path2.default.resolve(cwd);
|
|
10356
|
+
}
|
|
10357
|
+
const out2 = [];
|
|
10358
|
+
const now = /* @__PURE__ */ new Date();
|
|
10359
|
+
for (let dayOffset = 0; dayOffset < 7; dayOffset += 1) {
|
|
10360
|
+
const d3 = new Date(now.getTime() - dayOffset * 24 * 60 * 60 * 1e3);
|
|
10361
|
+
const yyyy = String(d3.getUTCFullYear());
|
|
10362
|
+
const mm = String(d3.getUTCMonth() + 1).padStart(2, "0");
|
|
10363
|
+
const dd = String(d3.getUTCDate()).padStart(2, "0");
|
|
10364
|
+
const dayDir = import_node_path2.default.join(sessionsRoot, yyyy, mm, dd);
|
|
10365
|
+
if (!import_node_fs3.default.existsSync(dayDir)) continue;
|
|
10366
|
+
let dayFiles;
|
|
10367
|
+
try {
|
|
10368
|
+
dayFiles = import_node_fs3.default.readdirSync(dayDir, { withFileTypes: true });
|
|
10369
|
+
} catch {
|
|
10370
|
+
continue;
|
|
10371
|
+
}
|
|
10372
|
+
for (const entry of dayFiles) {
|
|
10373
|
+
if (!entry.isFile()) continue;
|
|
10374
|
+
if (!entry.name.startsWith("rollout-") || !entry.name.endsWith(".jsonl")) {
|
|
10375
|
+
continue;
|
|
10376
|
+
}
|
|
10377
|
+
const filePath = import_node_path2.default.join(dayDir, entry.name);
|
|
10378
|
+
let timestamp = Date.now();
|
|
10379
|
+
try {
|
|
10380
|
+
timestamp = import_node_fs3.default.statSync(filePath).mtimeMs;
|
|
10381
|
+
} catch {
|
|
10382
|
+
}
|
|
10383
|
+
let metaCwd;
|
|
10384
|
+
let metaId;
|
|
10385
|
+
let summary = "";
|
|
10386
|
+
try {
|
|
10387
|
+
const raw = import_node_fs3.default.readFileSync(filePath, "utf8");
|
|
10388
|
+
for (const line of raw.split("\n")) {
|
|
10389
|
+
if (!line.trim()) continue;
|
|
10390
|
+
const rec = parseLine(line);
|
|
10391
|
+
if (!rec) continue;
|
|
10392
|
+
if (rec.type === "session_meta") {
|
|
10393
|
+
const meta = rec.payload;
|
|
10394
|
+
metaCwd = typeof meta?.cwd === "string" ? meta.cwd : void 0;
|
|
10395
|
+
metaId = typeof meta?.id === "string" ? meta.id : void 0;
|
|
10396
|
+
continue;
|
|
10397
|
+
}
|
|
10398
|
+
if (!summary && rec.type === "response_item") {
|
|
10399
|
+
const payload = rec.payload;
|
|
10400
|
+
const msg = payload?.Message;
|
|
10401
|
+
if (msg && msg.role === "user") {
|
|
10402
|
+
const text = extractMessageText(msg.content).trim();
|
|
10403
|
+
if (text) summary = text.slice(0, 120);
|
|
10404
|
+
}
|
|
10405
|
+
}
|
|
10406
|
+
if (metaCwd !== void 0 && summary) break;
|
|
10407
|
+
}
|
|
10408
|
+
} catch {
|
|
10409
|
+
continue;
|
|
10410
|
+
}
|
|
10411
|
+
if (!metaCwd || !metaId || !summary) continue;
|
|
10412
|
+
let resolvedMeta;
|
|
10413
|
+
try {
|
|
10414
|
+
resolvedMeta = import_node_fs3.default.realpathSync(metaCwd);
|
|
10415
|
+
} catch {
|
|
10416
|
+
resolvedMeta = import_node_path2.default.resolve(metaCwd);
|
|
10417
|
+
}
|
|
10418
|
+
if (resolvedMeta !== resolvedCurrent) continue;
|
|
10419
|
+
out2.push({ id: metaId, summary, timestamp });
|
|
10420
|
+
}
|
|
10421
|
+
}
|
|
10422
|
+
out2.sort((a, b) => b.timestamp - a.timestamp);
|
|
10423
|
+
return out2;
|
|
10424
|
+
}
|
|
10300
10425
|
function getCurrentUsage2(historyDir) {
|
|
10301
10426
|
if (!import_node_fs3.default.existsSync(historyDir)) return null;
|
|
10302
10427
|
const files = import_node_fs3.default.readdirSync(historyDir).filter((f) => f.startsWith("rollout-") && f.endsWith(".jsonl")).map((f) => ({ name: f, full: import_node_path2.default.join(historyDir, f) })).map((e) => ({ ...e, mtime: import_node_fs3.default.statSync(e.full).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
@@ -10830,6 +10955,9 @@ var CodexRuntimeStrategy = class {
|
|
|
10830
10955
|
getCurrentUsage(historyDir) {
|
|
10831
10956
|
return getCurrentUsage2(historyDir);
|
|
10832
10957
|
}
|
|
10958
|
+
listResumableSessions(cwd) {
|
|
10959
|
+
return listResumableSessions2(cwd);
|
|
10960
|
+
}
|
|
10833
10961
|
/**
|
|
10834
10962
|
* Codex's quota lives behind the `account/get_account_rate_limits` RPC,
|
|
10835
10963
|
* not a TUI slash command. Phase 2 ships with this stubbed to null so the
|
|
@@ -12731,52 +12859,32 @@ var HistoryService = class _HistoryService {
|
|
|
12731
12859
|
return Math.round(totalCost * 100) / 100;
|
|
12732
12860
|
}
|
|
12733
12861
|
/**
|
|
12734
|
-
*
|
|
12735
|
-
*
|
|
12862
|
+
* Push the active agent's resumable-sessions list to the backend.
|
|
12863
|
+
* Delegates the per-agent JSONL/rollout walk to
|
|
12864
|
+
* `runtime.listResumableSessions(cwd)` so each agent reads its own
|
|
12865
|
+
* on-disk format (Claude's JSONL files vs Codex's date-bucketed
|
|
12866
|
+
* rollouts). Strategies that don't yet expose the helper (Cursor,
|
|
12867
|
+
* Aider) cause this to no-op — the Conversations sheet on mobile
|
|
12868
|
+
* just shows the empty state for those agents until each one's
|
|
12869
|
+
* `listResumableSessions` lands.
|
|
12870
|
+
*
|
|
12871
|
+
* The push body now includes `agentId` so the backend keys by
|
|
12872
|
+
* (pluginId, agentId). Old CLI clients that omit `agentId` continue
|
|
12873
|
+
* to land in the `claude-code` slot via the backend's default.
|
|
12874
|
+
*
|
|
12875
|
+
* Called once ~2 s after the agent spawns (non-blocking).
|
|
12736
12876
|
*/
|
|
12737
12877
|
async load() {
|
|
12738
|
-
|
|
12739
|
-
let entries;
|
|
12740
|
-
try {
|
|
12741
|
-
entries = fs20.readdirSync(dir, { withFileTypes: true });
|
|
12742
|
-
} catch {
|
|
12878
|
+
if (!this.runtime.listResumableSessions) {
|
|
12743
12879
|
return;
|
|
12744
12880
|
}
|
|
12745
|
-
const sessions3 =
|
|
12746
|
-
for (const entry of entries) {
|
|
12747
|
-
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
12748
|
-
const id = path24.basename(entry.name, ".jsonl");
|
|
12749
|
-
const filePath = path24.join(dir, entry.name);
|
|
12750
|
-
let mtime = Date.now();
|
|
12751
|
-
try {
|
|
12752
|
-
mtime = fs20.statSync(filePath).mtimeMs;
|
|
12753
|
-
} catch {
|
|
12754
|
-
}
|
|
12755
|
-
let summary = "";
|
|
12756
|
-
try {
|
|
12757
|
-
const raw = fs20.readFileSync(filePath, "utf8");
|
|
12758
|
-
for (const line of raw.split("\n")) {
|
|
12759
|
-
if (!line.trim()) continue;
|
|
12760
|
-
try {
|
|
12761
|
-
const record = JSON.parse(line);
|
|
12762
|
-
if (record["type"] === "user") {
|
|
12763
|
-
const msg = record["message"];
|
|
12764
|
-
const text = extractText2(msg?.["content"]).trim();
|
|
12765
|
-
if (text) {
|
|
12766
|
-
summary = text.slice(0, 120);
|
|
12767
|
-
break;
|
|
12768
|
-
}
|
|
12769
|
-
}
|
|
12770
|
-
} catch {
|
|
12771
|
-
}
|
|
12772
|
-
}
|
|
12773
|
-
} catch {
|
|
12774
|
-
}
|
|
12775
|
-
if (summary) sessions3.push({ id, summary, timestamp: mtime });
|
|
12776
|
-
}
|
|
12881
|
+
const sessions3 = this.runtime.listResumableSessions(this.cwd);
|
|
12777
12882
|
if (sessions3.length === 0) return;
|
|
12778
|
-
|
|
12779
|
-
|
|
12883
|
+
await post("/api/sessions/list", {
|
|
12884
|
+
pluginId: this.pluginId,
|
|
12885
|
+
agentId: this.runtime.id,
|
|
12886
|
+
sessions: sessions3
|
|
12887
|
+
});
|
|
12780
12888
|
}
|
|
12781
12889
|
/**
|
|
12782
12890
|
* Read a specific session's full conversation and POST it to the API in batches.
|
|
@@ -20036,7 +20144,7 @@ function checkChokidar() {
|
|
|
20036
20144
|
}
|
|
20037
20145
|
async function doctor(args2 = []) {
|
|
20038
20146
|
const json = args2.includes("--json");
|
|
20039
|
-
const cliVersion = true ? "2.26.
|
|
20147
|
+
const cliVersion = true ? "2.26.8" : "0.0.0-dev";
|
|
20040
20148
|
const apiBase = resolveApiBaseUrl();
|
|
20041
20149
|
const diagnosticId = (0, import_node_crypto6.randomUUID)();
|
|
20042
20150
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -20235,7 +20343,7 @@ async function completion(args2) {
|
|
|
20235
20343
|
// src/commands/version.ts
|
|
20236
20344
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
20237
20345
|
function version2() {
|
|
20238
|
-
const v = true ? "2.26.
|
|
20346
|
+
const v = true ? "2.26.8" : "unknown";
|
|
20239
20347
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
20240
20348
|
}
|
|
20241
20349
|
|
|
@@ -20463,7 +20571,7 @@ function checkForUpdates() {
|
|
|
20463
20571
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
20464
20572
|
if (process.env.CI) return;
|
|
20465
20573
|
if (!process.stdout.isTTY) return;
|
|
20466
|
-
const current = true ? "2.26.
|
|
20574
|
+
const current = true ? "2.26.8" : null;
|
|
20467
20575
|
if (!current) return;
|
|
20468
20576
|
const cache = readCache();
|
|
20469
20577
|
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.26.
|
|
3
|
+
"version": "2.26.8",
|
|
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",
|