codeam-cli 1.4.44 → 1.4.46
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 +100 -12
- 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.46",
|
|
120
120
|
description: "Remote control Claude Code from your mobile device",
|
|
121
121
|
main: "dist/index.js",
|
|
122
122
|
bin: {
|
|
@@ -896,6 +896,67 @@ var ClaudeService = class {
|
|
|
896
896
|
// src/services/output.service.ts
|
|
897
897
|
var https2 = __toESM(require("https"));
|
|
898
898
|
var http2 = __toESM(require("http"));
|
|
899
|
+
|
|
900
|
+
// src/services/parseChrome.ts
|
|
901
|
+
var SPINNER_RE = /^[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]\s/;
|
|
902
|
+
function isChromeLine(line) {
|
|
903
|
+
const t = line.trim();
|
|
904
|
+
if (!t) return false;
|
|
905
|
+
if (/^[─━—═─\-]{3,}$/.test(t)) return true;
|
|
906
|
+
if (SPINNER_RE.test(t)) return true;
|
|
907
|
+
if (/esc.{0,5}to.{0,5}interrupt/i.test(t)) return true;
|
|
908
|
+
if (/high\s*[·•]\s*\/effort/i.test(t)) return true;
|
|
909
|
+
if (/^[❯>]\s*$/.test(t)) return true;
|
|
910
|
+
if (/^\(thinking\)\s*$/.test(t)) return true;
|
|
911
|
+
if (/^\?\s.*shortcut/i.test(t)) return true;
|
|
912
|
+
if (/spending limit|usage limit/i.test(t) && t.length < 80) return true;
|
|
913
|
+
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t)) return true;
|
|
914
|
+
if (t.replace(/\s/g, "").length === 1) return true;
|
|
915
|
+
if ((t.match(/─/g)?.length ?? 0) >= 6) return true;
|
|
916
|
+
if (/ctrl\+?o\s+to\s+expand/i.test(t)) return true;
|
|
917
|
+
const stripped = t.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "");
|
|
918
|
+
if (/^[❯>]\s+\S/.test(stripped) && !/^[❯>]\s*\d+\./.test(stripped)) return true;
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
function parseChromeLine(line) {
|
|
922
|
+
const t = line.trim();
|
|
923
|
+
if (!t) return null;
|
|
924
|
+
if (/^[─━—═─\-]{3,}$/.test(t)) return null;
|
|
925
|
+
if (/^[❯>]\s*$/.test(t)) return null;
|
|
926
|
+
if (t.replace(/\s/g, "").length === 1) return null;
|
|
927
|
+
if ((t.match(/─/g)?.length ?? 0) >= 6) return null;
|
|
928
|
+
if (/^\(thinking\)\s*$/.test(t)) {
|
|
929
|
+
return { tool: "thinking", label: "Thinking\u2026", status: "running" };
|
|
930
|
+
}
|
|
931
|
+
let text = t;
|
|
932
|
+
if (SPINNER_RE.test(t)) {
|
|
933
|
+
text = t.slice(2).trim();
|
|
934
|
+
}
|
|
935
|
+
if (!text) return null;
|
|
936
|
+
return classifyStep(text);
|
|
937
|
+
}
|
|
938
|
+
function classifyStep(text) {
|
|
939
|
+
if (/^Read(?:ing)?\s+/i.test(text)) {
|
|
940
|
+
const label2 = text.replace(/^Read(?:ing)?\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
941
|
+
return { tool: "read", label: label2, status: "running" };
|
|
942
|
+
}
|
|
943
|
+
if (/^Edit(?:ing)?\s+|^Writ(?:e|ing|ing to)\s+|^Creat(?:e|ing)\s+/i.test(text)) {
|
|
944
|
+
const label2 = text.replace(/^(?:Edit(?:ing)?|Writ(?:e|ing(?: to)?)|Creat(?:e|ing))\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
945
|
+
return { tool: "edit", label: label2, status: "running" };
|
|
946
|
+
}
|
|
947
|
+
if (/^Runn(?:ing)?\s+|^Execut(?:e|ing)\s+|^Bash(?:ing)?\s*:|^\$\s+/i.test(text)) {
|
|
948
|
+
const label2 = text.replace(/^(?:Runn(?:ing)?|Execut(?:e|ing)|Bash(?:ing)?:|\$)\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
949
|
+
return { tool: "bash", label: label2, status: "running" };
|
|
950
|
+
}
|
|
951
|
+
if (/^Search(?:ing)?\s+for\s+|^Grep(?:ping)?\s*:/i.test(text)) {
|
|
952
|
+
const label2 = text.replace(/^(?:Search(?:ing)?\s+for|Grep(?:ping)?:)\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
953
|
+
return { tool: "search", label: label2, status: "running" };
|
|
954
|
+
}
|
|
955
|
+
const label = text.replace(/\.\.\.$/, "").trim();
|
|
956
|
+
return { tool: "other", label, status: "running" };
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
// src/services/output.service.ts
|
|
899
960
|
var API_BASE4 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
|
|
900
961
|
function renderToLines(raw) {
|
|
901
962
|
const screen = [""];
|
|
@@ -1155,6 +1216,7 @@ var OutputService = class _OutputService {
|
|
|
1155
1216
|
pluginId;
|
|
1156
1217
|
rawBuffer = "";
|
|
1157
1218
|
lastSentContent = "";
|
|
1219
|
+
lastSentChromeStepsJson = "";
|
|
1158
1220
|
pollTimer = null;
|
|
1159
1221
|
startTime = 0;
|
|
1160
1222
|
active = false;
|
|
@@ -1189,6 +1251,7 @@ var OutputService = class _OutputService {
|
|
|
1189
1251
|
this.stopPoll();
|
|
1190
1252
|
this.rawBuffer = "";
|
|
1191
1253
|
this.lastSentContent = "";
|
|
1254
|
+
this.lastSentChromeStepsJson = "";
|
|
1192
1255
|
this.lastPushTime = 0;
|
|
1193
1256
|
this.active = true;
|
|
1194
1257
|
this.startTime = Date.now();
|
|
@@ -1203,6 +1266,7 @@ var OutputService = class _OutputService {
|
|
|
1203
1266
|
this.stopPoll();
|
|
1204
1267
|
this.rawBuffer = "";
|
|
1205
1268
|
this.lastSentContent = "";
|
|
1269
|
+
this.lastSentChromeStepsJson = "";
|
|
1206
1270
|
this.lastPushTime = 0;
|
|
1207
1271
|
this.active = true;
|
|
1208
1272
|
this.terminalTurnPending = false;
|
|
@@ -1220,6 +1284,7 @@ var OutputService = class _OutputService {
|
|
|
1220
1284
|
this.stopPoll();
|
|
1221
1285
|
this.rawBuffer = "";
|
|
1222
1286
|
this.lastSentContent = "";
|
|
1287
|
+
this.lastSentChromeStepsJson = "";
|
|
1223
1288
|
this.lastPushTime = 0;
|
|
1224
1289
|
this.active = true;
|
|
1225
1290
|
this.startTime = Date.now();
|
|
@@ -1283,6 +1348,7 @@ var OutputService = class _OutputService {
|
|
|
1283
1348
|
}
|
|
1284
1349
|
if (elapsed < _OutputService.WARMUP_MS) return;
|
|
1285
1350
|
const lines = renderToLines(this.rawBuffer);
|
|
1351
|
+
this.postChromeSteps(lines);
|
|
1286
1352
|
const selector = detectSelector(lines) ?? detectListSelector(lines);
|
|
1287
1353
|
if (selector) {
|
|
1288
1354
|
const idleMs2 = this.lastPushTime > 0 ? now - this.lastPushTime : elapsed;
|
|
@@ -1312,6 +1378,7 @@ var OutputService = class _OutputService {
|
|
|
1312
1378
|
}
|
|
1313
1379
|
finalize() {
|
|
1314
1380
|
const lines = renderToLines(this.rawBuffer);
|
|
1381
|
+
this.postChromeSteps(lines);
|
|
1315
1382
|
const selector = detectSelector(lines) ?? detectListSelector(lines);
|
|
1316
1383
|
this.stopPoll();
|
|
1317
1384
|
this.active = false;
|
|
@@ -1331,6 +1398,15 @@ var OutputService = class _OutputService {
|
|
|
1331
1398
|
this.pollTimer = null;
|
|
1332
1399
|
}
|
|
1333
1400
|
}
|
|
1401
|
+
postChromeSteps(lines) {
|
|
1402
|
+
const steps = lines.filter((l) => isChromeLine(l)).map((l) => parseChromeLine(l)).filter((s) => s !== null);
|
|
1403
|
+
if (steps.length === 0) return;
|
|
1404
|
+
const json = JSON.stringify(steps);
|
|
1405
|
+
if (json === this.lastSentChromeStepsJson) return;
|
|
1406
|
+
this.lastSentChromeStepsJson = json;
|
|
1407
|
+
this.postChunk({ type: "chrome_steps", content: "", steps }).catch(() => {
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1334
1410
|
postChunk(body) {
|
|
1335
1411
|
return new Promise((resolve) => {
|
|
1336
1412
|
const payload = JSON.stringify({
|
|
@@ -1527,13 +1603,28 @@ var HistoryService = class {
|
|
|
1527
1603
|
getCurrentConversationId() {
|
|
1528
1604
|
return this.currentConversationId;
|
|
1529
1605
|
}
|
|
1530
|
-
/** Return the
|
|
1531
|
-
|
|
1532
|
-
if (!this.currentConversationId) return
|
|
1606
|
+
/** Return the current message count in the active conversation. */
|
|
1607
|
+
getCurrentMessageCount() {
|
|
1608
|
+
if (!this.currentConversationId) return 0;
|
|
1533
1609
|
const filePath = path4.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1610
|
+
return parseJsonl(filePath).length;
|
|
1611
|
+
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Poll the JSONL until a new user message appears after previousCount entries.
|
|
1614
|
+
* Returns the text of the new user message, or null if not found within timeoutMs.
|
|
1615
|
+
*/
|
|
1616
|
+
async waitForNewUserMessage(previousCount, timeoutMs = 4e3) {
|
|
1617
|
+
const deadline = Date.now() + timeoutMs;
|
|
1618
|
+
while (Date.now() < deadline) {
|
|
1619
|
+
if (!this.currentConversationId) return null;
|
|
1620
|
+
const filePath = path4.join(this.projectDir, `${this.currentConversationId}.jsonl`);
|
|
1621
|
+
const messages = parseJsonl(filePath);
|
|
1622
|
+
if (messages.length > previousCount) {
|
|
1623
|
+
for (let i = messages.length - 1; i >= previousCount; i--) {
|
|
1624
|
+
if (messages[i].role === "user") return messages[i].text;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
1537
1628
|
}
|
|
1538
1629
|
return null;
|
|
1539
1630
|
}
|
|
@@ -1898,11 +1989,8 @@ except Exception:sys.exit(0)
|
|
|
1898
1989
|
fetchQuotaUsage();
|
|
1899
1990
|
}
|
|
1900
1991
|
}, () => {
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
outputSvc.startTerminalTurn(userText).catch(() => {
|
|
1904
|
-
});
|
|
1905
|
-
}, 300);
|
|
1992
|
+
const prevCount = historySvc.getCurrentMessageCount();
|
|
1993
|
+
historySvc.waitForNewUserMessage(prevCount).then((userText) => outputSvc.startTerminalTurn(userText ?? void 0)).catch(() => outputSvc.startTerminalTurn(void 0));
|
|
1906
1994
|
});
|
|
1907
1995
|
function sendPrompt(prompt) {
|
|
1908
1996
|
outputSvc.newTurn();
|