codeam-cli 1.4.8 → 1.4.9
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 +105 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -115,7 +115,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
115
115
|
// package.json
|
|
116
116
|
var package_default = {
|
|
117
117
|
name: "codeam-cli",
|
|
118
|
-
version: "1.4.
|
|
118
|
+
version: "1.4.9",
|
|
119
119
|
description: "Remote control Claude Code from your mobile device",
|
|
120
120
|
main: "dist/index.js",
|
|
121
121
|
bin: {
|
|
@@ -1121,9 +1121,10 @@ function filterChrome(lines) {
|
|
|
1121
1121
|
return result;
|
|
1122
1122
|
}
|
|
1123
1123
|
var OutputService = class _OutputService {
|
|
1124
|
-
constructor(sessionId, pluginId) {
|
|
1124
|
+
constructor(sessionId, pluginId, onSessionIdDetected) {
|
|
1125
1125
|
this.sessionId = sessionId;
|
|
1126
1126
|
this.pluginId = pluginId;
|
|
1127
|
+
this.onSessionIdDetected = onSessionIdDetected;
|
|
1127
1128
|
}
|
|
1128
1129
|
sessionId;
|
|
1129
1130
|
pluginId;
|
|
@@ -1133,6 +1134,7 @@ var OutputService = class _OutputService {
|
|
|
1133
1134
|
startTime = 0;
|
|
1134
1135
|
active = false;
|
|
1135
1136
|
lastPushTime = 0;
|
|
1137
|
+
onSessionIdDetected;
|
|
1136
1138
|
static POLL_MS = 1e3;
|
|
1137
1139
|
static IDLE_MS = 3e3;
|
|
1138
1140
|
/** Shorter idle threshold for selector detection (UI is ready immediately). */
|
|
@@ -1170,7 +1172,26 @@ var OutputService = class _OutputService {
|
|
|
1170
1172
|
if (!this.active) return;
|
|
1171
1173
|
this.rawBuffer += raw;
|
|
1172
1174
|
const printable = raw.replace(/\x1B\[[^@-~]*[@-~]/g, "").replace(/[\x00-\x1F\x7F]/g, "");
|
|
1173
|
-
if (printable.trim())
|
|
1175
|
+
if (printable.trim()) {
|
|
1176
|
+
this.lastPushTime = Date.now();
|
|
1177
|
+
this.tryExtractSessionId(printable);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
/** Extract Claude conversation ID from output text (e.g., from /cost command or session resume) */
|
|
1181
|
+
tryExtractSessionId(text) {
|
|
1182
|
+
const patterns = [
|
|
1183
|
+
/Resuming session[:\s]+([a-f0-9-]{36})/i,
|
|
1184
|
+
/Session[:\s]+([a-f0-9-]{36})/i,
|
|
1185
|
+
/Conversation[:\s]+([a-f0-9-]{36})/i,
|
|
1186
|
+
/Session\s+ID[:\s]+([a-f0-9-]{36})/i
|
|
1187
|
+
];
|
|
1188
|
+
for (const pattern of patterns) {
|
|
1189
|
+
const match = text.match(pattern);
|
|
1190
|
+
if (match && this.onSessionIdDetected) {
|
|
1191
|
+
this.onSessionIdDetected(match[1]);
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1174
1195
|
}
|
|
1175
1196
|
dispose() {
|
|
1176
1197
|
this.stopPoll();
|
|
@@ -1366,9 +1387,29 @@ var HistoryService = class {
|
|
|
1366
1387
|
}
|
|
1367
1388
|
pluginId;
|
|
1368
1389
|
cwd;
|
|
1390
|
+
currentConversationId = null;
|
|
1369
1391
|
get projectDir() {
|
|
1370
1392
|
return path4.join(os4.homedir(), ".claude", "projects", encodeCwd(this.cwd));
|
|
1371
1393
|
}
|
|
1394
|
+
/** Set the current Claude conversation ID (extracted from /cost command or session start) */
|
|
1395
|
+
setCurrentConversationId(id) {
|
|
1396
|
+
this.currentConversationId = id;
|
|
1397
|
+
}
|
|
1398
|
+
/** Extract conversation ID from Claude output (e.g., from session resume messages) */
|
|
1399
|
+
tryExtractConversationIdFromOutput(output) {
|
|
1400
|
+
const patterns = [
|
|
1401
|
+
/Resuming session[:\s]+([a-f0-9-]{36})/i,
|
|
1402
|
+
/session[:\s]+([a-f0-9-]{36})/i,
|
|
1403
|
+
/conversation[:\s]+([a-f0-9-]{36})/i
|
|
1404
|
+
];
|
|
1405
|
+
for (const pattern of patterns) {
|
|
1406
|
+
const match = output.match(pattern);
|
|
1407
|
+
if (match) {
|
|
1408
|
+
this.currentConversationId = match[1];
|
|
1409
|
+
return;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1372
1413
|
/**
|
|
1373
1414
|
* Read the most recently modified JSONL session file and extract the
|
|
1374
1415
|
* context window usage from the last assistant message's usage field.
|
|
@@ -1379,10 +1420,13 @@ var HistoryService = class {
|
|
|
1379
1420
|
*/
|
|
1380
1421
|
getCurrentUsage() {
|
|
1381
1422
|
const dir = this.projectDir;
|
|
1423
|
+
console.log(`[HistoryService] Looking for sessions in: ${dir}`);
|
|
1424
|
+
console.log(`[HistoryService] Current conversation ID: ${this.currentConversationId ?? "not set"}`);
|
|
1382
1425
|
let entries;
|
|
1383
1426
|
try {
|
|
1384
1427
|
entries = fs4.readdirSync(dir, { withFileTypes: true });
|
|
1385
|
-
} catch {
|
|
1428
|
+
} catch (err) {
|
|
1429
|
+
console.log(`[HistoryService] Failed to read directory: ${err}`);
|
|
1386
1430
|
return null;
|
|
1387
1431
|
}
|
|
1388
1432
|
const files = entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
@@ -1392,29 +1436,66 @@ var HistoryService = class {
|
|
|
1392
1436
|
return { name: e.name, mtime: 0 };
|
|
1393
1437
|
}
|
|
1394
1438
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
1395
|
-
if (files.length === 0)
|
|
1439
|
+
if (files.length === 0) {
|
|
1440
|
+
console.log(`[HistoryService] No .jsonl files found in directory`);
|
|
1441
|
+
return null;
|
|
1442
|
+
}
|
|
1443
|
+
let targetFile = files[0].name;
|
|
1444
|
+
if (this.currentConversationId) {
|
|
1445
|
+
const conversationFile = `${this.currentConversationId}.jsonl`;
|
|
1446
|
+
const exists = files.some((f) => f.name === conversationFile);
|
|
1447
|
+
if (exists) {
|
|
1448
|
+
targetFile = conversationFile;
|
|
1449
|
+
console.log(`[HistoryService] Using tracked conversation file: ${targetFile}`);
|
|
1450
|
+
} else {
|
|
1451
|
+
console.log(`[HistoryService] Tracked conversation file not found, using most recent: ${targetFile}`);
|
|
1452
|
+
}
|
|
1453
|
+
} else {
|
|
1454
|
+
console.log(`[HistoryService] No tracked conversation, using most recent: ${targetFile}`);
|
|
1455
|
+
}
|
|
1396
1456
|
let raw;
|
|
1397
1457
|
try {
|
|
1398
|
-
raw = fs4.readFileSync(path4.join(dir,
|
|
1399
|
-
} catch {
|
|
1458
|
+
raw = fs4.readFileSync(path4.join(dir, targetFile), "utf8");
|
|
1459
|
+
} catch (err) {
|
|
1460
|
+
console.log(`[HistoryService] Failed to read file: ${err}`);
|
|
1400
1461
|
return null;
|
|
1401
1462
|
}
|
|
1402
1463
|
let lastUsage = null;
|
|
1403
1464
|
let lastModel = null;
|
|
1404
|
-
|
|
1465
|
+
let assistantMessageCount = 0;
|
|
1466
|
+
let hasAnyMessages = false;
|
|
1467
|
+
const lines = raw.split("\n").filter(Boolean);
|
|
1468
|
+
console.log(`[HistoryService] File has ${lines.length} lines`);
|
|
1469
|
+
for (const line of lines) {
|
|
1405
1470
|
try {
|
|
1406
1471
|
const record = JSON.parse(line);
|
|
1472
|
+
if (record["type"] === "user" || record["type"] === "assistant") {
|
|
1473
|
+
hasAnyMessages = true;
|
|
1474
|
+
}
|
|
1407
1475
|
if (record["type"] === "assistant") {
|
|
1476
|
+
assistantMessageCount++;
|
|
1408
1477
|
const msg = record["message"];
|
|
1409
|
-
|
|
1478
|
+
const usage = msg?.["usage"];
|
|
1479
|
+
if (usage && (usage["input_tokens"] !== void 0 || usage["prompt_tokens"] !== void 0)) {
|
|
1480
|
+
lastUsage = usage;
|
|
1481
|
+
console.log(`[HistoryService] Found usage data: ${JSON.stringify(lastUsage)}`);
|
|
1482
|
+
}
|
|
1410
1483
|
if (msg?.["model"]) lastModel = msg["model"];
|
|
1411
1484
|
}
|
|
1412
1485
|
} catch {
|
|
1413
1486
|
}
|
|
1414
1487
|
}
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1488
|
+
console.log(`[HistoryService] Processed ${assistantMessageCount} assistant messages, hasAnyMessages: ${hasAnyMessages}, lastUsage: ${lastUsage ? "found" : "not found"}, lastModel: ${lastModel}`);
|
|
1489
|
+
if (!lastUsage) {
|
|
1490
|
+
if (hasAnyMessages) {
|
|
1491
|
+
console.log(`[HistoryService] File has messages but no usage data (Claude Code may not have recorded usage yet)`);
|
|
1492
|
+
return { used: 0, total: 2e5, percent: 0, model: lastModel, outputTokens: 0, cacheReadTokens: 0 };
|
|
1493
|
+
}
|
|
1494
|
+
console.log(`[HistoryService] No messages or usage data found in session file`);
|
|
1495
|
+
return null;
|
|
1496
|
+
}
|
|
1497
|
+
const inputTokens = (lastUsage["input_tokens"] ?? lastUsage["prompt_tokens"] ?? 0) + (lastUsage["cache_read_input_tokens"] ?? 0) + (lastUsage["cache_creation_input_tokens"] ?? 0);
|
|
1498
|
+
const outputTokens = lastUsage["output_tokens"] ?? lastUsage["completion_tokens"] ?? 0;
|
|
1418
1499
|
const total = 2e5;
|
|
1419
1500
|
const percent = Math.min(100, Math.round(inputTokens / total * 100));
|
|
1420
1501
|
return { used: inputTokens, total, percent, model: lastModel, outputTokens, cacheReadTokens: lastUsage["cache_read_input_tokens"] ?? 0 };
|
|
@@ -1503,9 +1584,15 @@ async function start() {
|
|
|
1503
1584
|
const pluginId = session.pluginId ?? ensurePluginId();
|
|
1504
1585
|
showInfo(`${session.userName} \xB7 ${import_picocolors2.default.cyan(session.plan)}`);
|
|
1505
1586
|
showInfo("Launching Claude Code...\n");
|
|
1587
|
+
const cwd = process.cwd();
|
|
1588
|
+
console.log(`[CLI] Starting with cwd: ${cwd}`);
|
|
1589
|
+
console.log(`[CLI] Session: ${session.id}, Plugin: ${pluginId}`);
|
|
1506
1590
|
const ws = new WebSocketService(session.id, pluginId);
|
|
1507
|
-
const
|
|
1508
|
-
const
|
|
1591
|
+
const historySvc = new HistoryService(pluginId, cwd);
|
|
1592
|
+
const outputSvc = new OutputService(session.id, pluginId, (conversationId) => {
|
|
1593
|
+
console.log(`[CLI] Detected Claude conversation ID: ${conversationId}`);
|
|
1594
|
+
historySvc.setCurrentConversationId(conversationId);
|
|
1595
|
+
});
|
|
1509
1596
|
function sendPrompt(prompt) {
|
|
1510
1597
|
outputSvc.newTurn();
|
|
1511
1598
|
claude.sendCommand(prompt);
|
|
@@ -1554,8 +1641,11 @@ async function start() {
|
|
|
1554
1641
|
claude.interrupt();
|
|
1555
1642
|
break;
|
|
1556
1643
|
case "get_context": {
|
|
1644
|
+
console.log(`[CLI] Received get_context command, fetching usage...`);
|
|
1557
1645
|
const usage = historySvc.getCurrentUsage();
|
|
1558
|
-
|
|
1646
|
+
const result = usage ?? { used: 0, total: 2e5, percent: 0, model: null, outputTokens: 0, cacheReadTokens: 0, error: "No usage data found" };
|
|
1647
|
+
console.log(`[CLI] Sending context result: ${JSON.stringify(result)}`);
|
|
1648
|
+
await relay.sendResult(cmd.id, "completed", result);
|
|
1559
1649
|
break;
|
|
1560
1650
|
}
|
|
1561
1651
|
case "resume_session": {
|