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.
Files changed (2) hide show
  1. package/dist/index.js +100 -12
  2. 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.44",
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 text of the last user message in the current conversation, or null. */
1531
- getLastUserMessage() {
1532
- if (!this.currentConversationId) return null;
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
- const messages = parseJsonl(filePath);
1535
- for (let i = messages.length - 1; i >= 0; i--) {
1536
- if (messages[i].role === "user") return messages[i].text;
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
- setTimeout(() => {
1902
- const userText = historySvc.getLastUserMessage() ?? void 0;
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "1.4.44",
3
+ "version": "1.4.46",
4
4
  "description": "Remote control Claude Code from your mobile device",
5
5
  "main": "dist/index.js",
6
6
  "bin": {