codeam-cli 1.4.37 → 1.4.39
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 +66 -47
- 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.39",
|
|
120
120
|
description: "Remote control Claude Code from your mobile device",
|
|
121
121
|
main: "dist/index.js",
|
|
122
122
|
bin: {
|
|
@@ -815,9 +815,22 @@ var ClaudeService = class {
|
|
|
815
815
|
const claudeCmd = findInPath("claude") ? "claude" : "claude-code";
|
|
816
816
|
this.strategy.spawn(claudeCmd, this.opts.cwd);
|
|
817
817
|
}
|
|
818
|
-
/**
|
|
818
|
+
/**
|
|
819
|
+
* Send a command to Claude's stdin (remote control from mobile).
|
|
820
|
+
*
|
|
821
|
+
* Why two separate writes with a delay?
|
|
822
|
+
* Same batching problem as selectOption: all bytes arriving in one write()
|
|
823
|
+
* call are processed by readline in one synchronous run. React Ink batches
|
|
824
|
+
* the resulting state updates, so when '\r' fires the input's value is still
|
|
825
|
+
* the pre-batch (empty/previous) state → Enter submits nothing and the text
|
|
826
|
+
* stays visible-but-unsubmitted in the input field.
|
|
827
|
+
*
|
|
828
|
+
* Sending '\r' in a separate write() 50 ms later guarantees it arrives on
|
|
829
|
+
* a fresh event-loop tick, after React has flushed the text into input state.
|
|
830
|
+
*/
|
|
819
831
|
sendCommand(text) {
|
|
820
|
-
this.strategy.write(text
|
|
832
|
+
this.strategy.write(text);
|
|
833
|
+
setTimeout(() => this.strategy.write("\r"), 50);
|
|
821
834
|
}
|
|
822
835
|
/**
|
|
823
836
|
* Navigate a React Ink selector to the given 0-based target index and confirm.
|
|
@@ -1116,7 +1129,11 @@ function filterChrome(lines) {
|
|
|
1116
1129
|
if (/^\?\s.*shortcut/i.test(t)) continue;
|
|
1117
1130
|
if (/spending limit|usage limit/i.test(t) && t.length < 80) continue;
|
|
1118
1131
|
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t)) continue;
|
|
1119
|
-
if (
|
|
1132
|
+
if (t.replace(/\s/g, "").length === 1) continue;
|
|
1133
|
+
if ((t.match(/─/g)?.length ?? 0) >= 6) continue;
|
|
1134
|
+
if (/ctrl\+?o\s+to\s+expand/i.test(t)) continue;
|
|
1135
|
+
const stripped = t.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "");
|
|
1136
|
+
if (/^[❯>]\s+\S/.test(stripped) && !/^[❯>]\s*\d+\./.test(stripped)) {
|
|
1120
1137
|
skipEchoContinuation = true;
|
|
1121
1138
|
continue;
|
|
1122
1139
|
}
|
|
@@ -1148,7 +1165,15 @@ var OutputService = class _OutputService {
|
|
|
1148
1165
|
static IDLE_MS = 3e3;
|
|
1149
1166
|
/** Shorter idle threshold for selector detection (UI is ready immediately). */
|
|
1150
1167
|
static SELECTOR_IDLE_MS = 1500;
|
|
1151
|
-
|
|
1168
|
+
/**
|
|
1169
|
+
* Grace period before the first tick processes output.
|
|
1170
|
+
* Prevents the raw PTY input echo from being captured before Claude Code
|
|
1171
|
+
* clears and re-renders its TUI (which happens within ~100-200 ms of
|
|
1172
|
+
* receiving the input, but we give a 1.5 s margin for loaded machines).
|
|
1173
|
+
*/
|
|
1174
|
+
static WARMUP_MS = 1500;
|
|
1175
|
+
/** Max idle with no visible content (spinner only) before finalizing. */
|
|
1176
|
+
static EMPTY_TIMEOUT_MS = 6e4;
|
|
1152
1177
|
static MAX_MS = 12e4;
|
|
1153
1178
|
newTurn() {
|
|
1154
1179
|
this.stopPoll();
|
|
@@ -1222,6 +1247,7 @@ var OutputService = class _OutputService {
|
|
|
1222
1247
|
this.finalize();
|
|
1223
1248
|
return;
|
|
1224
1249
|
}
|
|
1250
|
+
if (elapsed < _OutputService.WARMUP_MS) return;
|
|
1225
1251
|
const lines = renderToLines(this.rawBuffer);
|
|
1226
1252
|
const selector = detectSelector(lines) ?? detectListSelector(lines);
|
|
1227
1253
|
if (selector) {
|
|
@@ -1559,61 +1585,54 @@ var HistoryService = class {
|
|
|
1559
1585
|
return { used: inputTokens, total, percent, model: lastModel, outputTokens, cacheReadTokens: lastUsage["cache_read_input_tokens"] ?? 0 };
|
|
1560
1586
|
}
|
|
1561
1587
|
/**
|
|
1562
|
-
* Estimate the
|
|
1563
|
-
* Scans
|
|
1588
|
+
* Estimate the API cost for the current month in the current project directory.
|
|
1589
|
+
* Scans only the JSONL files for this project (cwd), so the value reflects
|
|
1590
|
+
* usage from the active Claude Code session rather than the entire machine.
|
|
1564
1591
|
*/
|
|
1565
1592
|
getMonthlyEstimatedCost() {
|
|
1566
|
-
const
|
|
1567
|
-
let projectDirs;
|
|
1568
|
-
try {
|
|
1569
|
-
projectDirs = fs4.readdirSync(claudeDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path4.join(claudeDir, e.name));
|
|
1570
|
-
} catch {
|
|
1571
|
-
return 0;
|
|
1572
|
-
}
|
|
1593
|
+
const projectDir = this.projectDir;
|
|
1573
1594
|
const now = /* @__PURE__ */ new Date();
|
|
1574
1595
|
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
1575
1596
|
const monthStartIso = monthStart.toISOString();
|
|
1576
1597
|
const monthStartMs = monthStart.getTime();
|
|
1577
1598
|
let totalCost = 0;
|
|
1578
|
-
|
|
1579
|
-
|
|
1599
|
+
let files;
|
|
1600
|
+
try {
|
|
1601
|
+
files = fs4.readdirSync(projectDir).filter((f) => f.endsWith(".jsonl")).filter((f) => {
|
|
1602
|
+
try {
|
|
1603
|
+
return fs4.statSync(path4.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
1604
|
+
} catch {
|
|
1605
|
+
return false;
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
1608
|
+
} catch {
|
|
1609
|
+
return 0;
|
|
1610
|
+
}
|
|
1611
|
+
for (const file of files) {
|
|
1612
|
+
let raw;
|
|
1580
1613
|
try {
|
|
1581
|
-
|
|
1582
|
-
try {
|
|
1583
|
-
return fs4.statSync(path4.join(projectDir, f)).mtimeMs >= monthStartMs;
|
|
1584
|
-
} catch {
|
|
1585
|
-
return false;
|
|
1586
|
-
}
|
|
1587
|
-
});
|
|
1614
|
+
raw = fs4.readFileSync(path4.join(projectDir, file), "utf8");
|
|
1588
1615
|
} catch {
|
|
1589
1616
|
continue;
|
|
1590
1617
|
}
|
|
1591
|
-
for (const
|
|
1592
|
-
let raw;
|
|
1618
|
+
for (const line of raw.split("\n").filter(Boolean)) {
|
|
1593
1619
|
try {
|
|
1594
|
-
|
|
1620
|
+
const record = JSON.parse(line);
|
|
1621
|
+
if (record["type"] !== "assistant") continue;
|
|
1622
|
+
const timestamp = record["timestamp"];
|
|
1623
|
+
if (timestamp && timestamp < monthStartIso) continue;
|
|
1624
|
+
const msg = record["message"];
|
|
1625
|
+
if (!msg || msg["model"] === "<synthetic>") continue;
|
|
1626
|
+
const model = msg["model"] || "";
|
|
1627
|
+
const usage = msg["usage"];
|
|
1628
|
+
if (!usage) continue;
|
|
1629
|
+
const pricing = getPricing(model);
|
|
1630
|
+
const input = usage["input_tokens"] ?? 0;
|
|
1631
|
+
const output = usage["output_tokens"] ?? 0;
|
|
1632
|
+
const cacheRead = usage["cache_read_input_tokens"] ?? 0;
|
|
1633
|
+
const cacheWrite = usage["cache_creation_input_tokens"] ?? 0;
|
|
1634
|
+
totalCost += input / 1e6 * pricing.input + output / 1e6 * pricing.output + cacheRead / 1e6 * pricing.cacheRead + cacheWrite / 1e6 * pricing.cacheWrite;
|
|
1595
1635
|
} catch {
|
|
1596
|
-
continue;
|
|
1597
|
-
}
|
|
1598
|
-
for (const line of raw.split("\n").filter(Boolean)) {
|
|
1599
|
-
try {
|
|
1600
|
-
const record = JSON.parse(line);
|
|
1601
|
-
if (record["type"] !== "assistant") continue;
|
|
1602
|
-
const timestamp = record["timestamp"];
|
|
1603
|
-
if (timestamp && timestamp < monthStartIso) continue;
|
|
1604
|
-
const msg = record["message"];
|
|
1605
|
-
if (!msg || msg["model"] === "<synthetic>") continue;
|
|
1606
|
-
const model = msg["model"] || "";
|
|
1607
|
-
const usage = msg["usage"];
|
|
1608
|
-
if (!usage) continue;
|
|
1609
|
-
const pricing = getPricing(model);
|
|
1610
|
-
const input = usage["input_tokens"] ?? 0;
|
|
1611
|
-
const output = usage["output_tokens"] ?? 0;
|
|
1612
|
-
const cacheRead = usage["cache_read_input_tokens"] ?? 0;
|
|
1613
|
-
const cacheWrite = usage["cache_creation_input_tokens"] ?? 0;
|
|
1614
|
-
totalCost += input / 1e6 * pricing.input + output / 1e6 * pricing.output + cacheRead / 1e6 * pricing.cacheRead + cacheWrite / 1e6 * pricing.cacheWrite;
|
|
1615
|
-
} catch {
|
|
1616
|
-
}
|
|
1617
1636
|
}
|
|
1618
1637
|
}
|
|
1619
1638
|
}
|