codeam-cli 1.4.36 → 1.4.38
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/dist/index.js +49 -45
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -116,7 +116,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
116
116
|
// package.json
|
|
117
117
|
var package_default = {
|
|
118
118
|
name: "codeam-cli",
|
|
119
|
-
version: "1.4.
|
|
119
|
+
version: "1.4.38",
|
|
120
120
|
description: "Remote control Claude Code from your mobile device",
|
|
121
121
|
main: "dist/index.js",
|
|
122
122
|
bin: {
|
|
@@ -1116,7 +1116,8 @@ function filterChrome(lines) {
|
|
|
1116
1116
|
if (/^\?\s.*shortcut/i.test(t)) continue;
|
|
1117
1117
|
if (/spending limit|usage limit/i.test(t) && t.length < 80) continue;
|
|
1118
1118
|
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t)) continue;
|
|
1119
|
-
|
|
1119
|
+
const stripped = t.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "");
|
|
1120
|
+
if (/^[❯>]\s+\S/.test(stripped) && !/^[❯>]\s*\d+\./.test(stripped)) {
|
|
1120
1121
|
skipEchoContinuation = true;
|
|
1121
1122
|
continue;
|
|
1122
1123
|
}
|
|
@@ -1148,7 +1149,15 @@ var OutputService = class _OutputService {
|
|
|
1148
1149
|
static IDLE_MS = 3e3;
|
|
1149
1150
|
/** Shorter idle threshold for selector detection (UI is ready immediately). */
|
|
1150
1151
|
static SELECTOR_IDLE_MS = 1500;
|
|
1151
|
-
|
|
1152
|
+
/**
|
|
1153
|
+
* Grace period before the first tick processes output.
|
|
1154
|
+
* Prevents the raw PTY input echo from being captured before Claude Code
|
|
1155
|
+
* clears and re-renders its TUI (which happens within ~100-200 ms of
|
|
1156
|
+
* receiving the input, but we give a 1.5 s margin for loaded machines).
|
|
1157
|
+
*/
|
|
1158
|
+
static WARMUP_MS = 1500;
|
|
1159
|
+
/** Max idle with no visible content (spinner only) before finalizing. */
|
|
1160
|
+
static EMPTY_TIMEOUT_MS = 6e4;
|
|
1152
1161
|
static MAX_MS = 12e4;
|
|
1153
1162
|
newTurn() {
|
|
1154
1163
|
this.stopPoll();
|
|
@@ -1222,6 +1231,7 @@ var OutputService = class _OutputService {
|
|
|
1222
1231
|
this.finalize();
|
|
1223
1232
|
return;
|
|
1224
1233
|
}
|
|
1234
|
+
if (elapsed < _OutputService.WARMUP_MS) return;
|
|
1225
1235
|
const lines = renderToLines(this.rawBuffer);
|
|
1226
1236
|
const selector = detectSelector(lines) ?? detectListSelector(lines);
|
|
1227
1237
|
if (selector) {
|
|
@@ -1356,6 +1366,7 @@ function parseJsonl(filePath) {
|
|
|
1356
1366
|
const ts = record["timestamp"];
|
|
1357
1367
|
const timestamp = typeof ts === "string" ? new Date(ts).getTime() : typeof ts === "number" ? ts : Date.now();
|
|
1358
1368
|
const uuid = record["uuid"] ?? `${Date.now()}-${Math.random()}`;
|
|
1369
|
+
if (record["isMeta"]) continue;
|
|
1359
1370
|
if (type === "user" && msg) {
|
|
1360
1371
|
const text = extractText(msg["content"]).trim();
|
|
1361
1372
|
if (text) messages.push({ id: uuid, role: "user", text, timestamp });
|
|
@@ -1558,61 +1569,54 @@ var HistoryService = class {
|
|
|
1558
1569
|
return { used: inputTokens, total, percent, model: lastModel, outputTokens, cacheReadTokens: lastUsage["cache_read_input_tokens"] ?? 0 };
|
|
1559
1570
|
}
|
|
1560
1571
|
/**
|
|
1561
|
-
* Estimate the
|
|
1562
|
-
* Scans
|
|
1572
|
+
* Estimate the API cost for the current month in the current project directory.
|
|
1573
|
+
* Scans only the JSONL files for this project (cwd), so the value reflects
|
|
1574
|
+
* usage from the active Claude Code session rather than the entire machine.
|
|
1563
1575
|
*/
|
|
1564
1576
|
getMonthlyEstimatedCost() {
|
|
1565
|
-
const
|
|
1566
|
-
let projectDirs;
|
|
1567
|
-
try {
|
|
1568
|
-
projectDirs = fs4.readdirSync(claudeDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path4.join(claudeDir, e.name));
|
|
1569
|
-
} catch {
|
|
1570
|
-
return 0;
|
|
1571
|
-
}
|
|
1577
|
+
const projectDir = this.projectDir;
|
|
1572
1578
|
const now = /* @__PURE__ */ new Date();
|
|
1573
1579
|
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
1574
1580
|
const monthStartIso = monthStart.toISOString();
|
|
1575
1581
|
const monthStartMs = monthStart.getTime();
|
|
1576
1582
|
let totalCost = 0;
|
|
1577
|
-
|
|
1578
|
-
|
|
1583
|
+
let files;
|
|
1584
|
+
try {
|
|
1585
|
+
files = fs4.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
1586
|
+
try {
|
|
1587
|
+
return fs4.statSync(path4.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
1588
|
+
} catch {
|
|
1589
|
+
return false;
|
|
1590
|
+
}
|
|
1591
|
+
});
|
|
1592
|
+
} catch {
|
|
1593
|
+
return 0;
|
|
1594
|
+
}
|
|
1595
|
+
for (const file of files) {
|
|
1596
|
+
let raw;
|
|
1579
1597
|
try {
|
|
1580
|
-
|
|
1581
|
-
try {
|
|
1582
|
-
return fs4.statSync(path4.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
1583
|
-
} catch {
|
|
1584
|
-
return false;
|
|
1585
|
-
}
|
|
1586
|
-
});
|
|
1598
|
+
raw = fs4.readFileSync(path4.join(projectDir, file), "utf8");
|
|
1587
1599
|
} catch {
|
|
1588
1600
|
continue;
|
|
1589
1601
|
}
|
|
1590
|
-
for (const
|
|
1591
|
-
let raw;
|
|
1602
|
+
for (const line of raw.split("\n").filter(Boolean)) {
|
|
1592
1603
|
try {
|
|
1593
|
-
|
|
1604
|
+
const record = JSON.parse(line);
|
|
1605
|
+
if (record["type"] !== "assistant") continue;
|
|
1606
|
+
const timestamp = record["timestamp"];
|
|
1607
|
+
if (timestamp && timestamp < monthStartIso) continue;
|
|
1608
|
+
const msg = record["message"];
|
|
1609
|
+
if (!msg || msg["model"] === "<synthetic>") continue;
|
|
1610
|
+
const model = msg["model"] || "";
|
|
1611
|
+
const usage = msg["usage"];
|
|
1612
|
+
if (!usage) continue;
|
|
1613
|
+
const pricing = getPricing(model);
|
|
1614
|
+
const input = usage["input_tokens"] ?? 0;
|
|
1615
|
+
const output = usage["output_tokens"] ?? 0;
|
|
1616
|
+
const cacheRead = usage["cache_read_input_tokens"] ?? 0;
|
|
1617
|
+
const cacheWrite = usage["cache_creation_input_tokens"] ?? 0;
|
|
1618
|
+
totalCost += input / 1e6 * pricing.input + output / 1e6 * pricing.output + cacheRead / 1e6 * pricing.cacheRead + cacheWrite / 1e6 * pricing.cacheWrite;
|
|
1594
1619
|
} catch {
|
|
1595
|
-
continue;
|
|
1596
|
-
}
|
|
1597
|
-
for (const line of raw.split("\n").filter(Boolean)) {
|
|
1598
|
-
try {
|
|
1599
|
-
const record = JSON.parse(line);
|
|
1600
|
-
if (record["type"] !== "assistant") continue;
|
|
1601
|
-
const timestamp = record["timestamp"];
|
|
1602
|
-
if (timestamp && timestamp < monthStartIso) continue;
|
|
1603
|
-
const msg = record["message"];
|
|
1604
|
-
if (!msg || msg["model"] === "<synthetic>") continue;
|
|
1605
|
-
const model = msg["model"] || "";
|
|
1606
|
-
const usage = msg["usage"];
|
|
1607
|
-
if (!usage) continue;
|
|
1608
|
-
const pricing = getPricing(model);
|
|
1609
|
-
const input = usage["input_tokens"] ?? 0;
|
|
1610
|
-
const output = usage["output_tokens"] ?? 0;
|
|
1611
|
-
const cacheRead = usage["cache_read_input_tokens"] ?? 0;
|
|
1612
|
-
const cacheWrite = usage["cache_creation_input_tokens"] ?? 0;
|
|
1613
|
-
totalCost += input / 1e6 * pricing.input + output / 1e6 * pricing.output + cacheRead / 1e6 * pricing.cacheRead + cacheWrite / 1e6 * pricing.cacheWrite;
|
|
1614
|
-
} catch {
|
|
1615
|
-
}
|
|
1616
1620
|
}
|
|
1617
1621
|
}
|
|
1618
1622
|
}
|