codeam-cli 2.12.10 → 2.12.11

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/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.12.9] — 2026-05-14
8
+
9
+ ### Fixed
10
+
11
+ - **shared:** Keep scrollback across alt-screen toggles + CSI 2J so multi-paragraph agent replies survive
12
+
13
+ ### Debug
14
+
15
+ - **cli:** Always-on filter-input dump so we can diagnose multi-line drops
16
+
17
+ ## [2.12.8] — 2026-05-14
18
+
19
+ ### Debug
20
+
21
+ - **cli:** Always-on filter-input dump so we can diagnose multi-line drops
22
+
7
23
  ## [2.12.7] — 2026-05-14
8
24
 
9
25
  ### Fixed
package/dist/index.js CHANGED
@@ -1682,7 +1682,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
1682
1682
  // package.json
1683
1683
  var package_default = {
1684
1684
  name: "codeam-cli",
1685
- version: "2.12.10",
1685
+ version: "2.12.11",
1686
1686
  description: "Remote control Claude Code (and other AI coding agents) from your mobile phone. Pair your device, send prompts, stream responses in real-time, and approve commands \u2014 from anywhere.",
1687
1687
  type: "commonjs",
1688
1688
  main: "dist/index.js",
@@ -5854,6 +5854,168 @@ function detectCodexSelector(_lines) {
5854
5854
  return null;
5855
5855
  }
5856
5856
 
5857
+ // src/agents/codex/renderer.ts
5858
+ function renderCodexBuffer(raw) {
5859
+ const scrollback = [];
5860
+ const screen = [""];
5861
+ let row = 0;
5862
+ let col = 0;
5863
+ let scrollTop = null;
5864
+ let scrollBottom = null;
5865
+ function ensureRow() {
5866
+ while (screen.length <= row) screen.push("");
5867
+ }
5868
+ function writeChar(ch) {
5869
+ ensureRow();
5870
+ if (col < screen[row].length) {
5871
+ screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);
5872
+ } else {
5873
+ while (screen[row].length < col) screen[row] += " ";
5874
+ screen[row] += ch;
5875
+ }
5876
+ col++;
5877
+ }
5878
+ function scrollRegionUp() {
5879
+ if (scrollTop === null || scrollBottom === null) {
5880
+ ensureRow();
5881
+ return;
5882
+ }
5883
+ while (screen.length <= scrollBottom) screen.push("");
5884
+ if (screen[scrollTop].trim() !== "") {
5885
+ scrollback.push(screen[scrollTop]);
5886
+ }
5887
+ for (let r = scrollTop; r < scrollBottom; r++) {
5888
+ screen[r] = screen[r + 1];
5889
+ }
5890
+ screen[scrollBottom] = "";
5891
+ }
5892
+ function scrollRegionDown() {
5893
+ if (scrollTop === null || scrollBottom === null) {
5894
+ return;
5895
+ }
5896
+ while (screen.length <= scrollBottom) screen.push("");
5897
+ if (screen[scrollBottom].trim() !== "") {
5898
+ scrollback.push(screen[scrollBottom]);
5899
+ }
5900
+ for (let r = scrollBottom; r > scrollTop; r--) {
5901
+ screen[r] = screen[r - 1];
5902
+ }
5903
+ screen[scrollTop] = "";
5904
+ }
5905
+ let i = 0;
5906
+ while (i < raw.length) {
5907
+ const ch = raw[i];
5908
+ if (ch === "\x1B") {
5909
+ i++;
5910
+ if (i >= raw.length) break;
5911
+ if (raw[i] === "[") {
5912
+ i++;
5913
+ let param = "";
5914
+ while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];
5915
+ const cmd = raw[i] ?? "";
5916
+ const n = parseInt(param) || 1;
5917
+ if (cmd === "A") {
5918
+ row = Math.max(0, row - n);
5919
+ } else if (cmd === "B") {
5920
+ row += n;
5921
+ ensureRow();
5922
+ } else if (cmd === "C") {
5923
+ col += n;
5924
+ } else if (cmd === "D") {
5925
+ col = Math.max(0, col - n);
5926
+ } else if (cmd === "G") {
5927
+ col = Math.max(0, n - 1);
5928
+ } else if (cmd === "H" || cmd === "f") {
5929
+ const p2 = param.split(";");
5930
+ row = Math.max(0, (parseInt(p2[0] ?? "1") || 1) - 1);
5931
+ col = Math.max(0, (parseInt(p2[1] ?? "1") || 1) - 1);
5932
+ ensureRow();
5933
+ } else if (cmd === "J") {
5934
+ if (param === "2" || param === "3") {
5935
+ for (let r = 0; r < screen.length; r++) {
5936
+ if (screen[r].trim() !== "") scrollback.push(screen[r]);
5937
+ }
5938
+ screen.length = 1;
5939
+ screen[0] = "";
5940
+ row = 0;
5941
+ col = 0;
5942
+ } else if (param === "1") {
5943
+ for (let r = 0; r < row; r++) screen[r] = "";
5944
+ screen[row] = " ".repeat(col) + screen[row].slice(col);
5945
+ } else {
5946
+ screen[row] = screen[row].slice(0, col);
5947
+ screen.splice(row + 1);
5948
+ }
5949
+ } else if (cmd === "K") {
5950
+ ensureRow();
5951
+ if (param === "" || param === "0") screen[row] = screen[row].slice(0, col);
5952
+ else if (param === "1") screen[row] = " ".repeat(col) + screen[row].slice(col);
5953
+ else if (param === "2") screen[row] = "";
5954
+ } else if (cmd === "r") {
5955
+ if (param === "" || param === ";") {
5956
+ scrollTop = null;
5957
+ scrollBottom = null;
5958
+ } else {
5959
+ const p2 = param.split(";");
5960
+ const top = parseInt(p2[0] ?? "1") || 1;
5961
+ const bot = parseInt(p2[1] ?? "1") || 1;
5962
+ scrollTop = Math.max(0, top - 1);
5963
+ scrollBottom = Math.max(scrollTop, bot - 1);
5964
+ }
5965
+ }
5966
+ } else if (raw[i] === "]") {
5967
+ i++;
5968
+ while (i < raw.length) {
5969
+ if (raw[i] === "\x07") break;
5970
+ if (raw[i] === "\x1B" && i + 1 < raw.length && raw[i + 1] === "\\") {
5971
+ i++;
5972
+ break;
5973
+ }
5974
+ i++;
5975
+ }
5976
+ } else if (raw[i] === "M") {
5977
+ if (scrollTop !== null && row === scrollTop) {
5978
+ scrollRegionDown();
5979
+ } else {
5980
+ row = Math.max(0, row - 1);
5981
+ }
5982
+ } else if (raw[i] === "D") {
5983
+ if (scrollBottom !== null && row === scrollBottom) {
5984
+ scrollRegionUp();
5985
+ } else {
5986
+ row++;
5987
+ ensureRow();
5988
+ }
5989
+ }
5990
+ } else if (ch === "\r") {
5991
+ if (i + 1 < raw.length && raw[i + 1] === "\n") {
5992
+ if (scrollBottom !== null && row === scrollBottom) {
5993
+ scrollRegionUp();
5994
+ } else {
5995
+ row++;
5996
+ ensureRow();
5997
+ }
5998
+ col = 0;
5999
+ i++;
6000
+ } else {
6001
+ col = 0;
6002
+ }
6003
+ } else if (ch === "\n") {
6004
+ if (scrollBottom !== null && row === scrollBottom) {
6005
+ scrollRegionUp();
6006
+ } else {
6007
+ row++;
6008
+ ensureRow();
6009
+ }
6010
+ col = 0;
6011
+ } else if (ch >= " " || ch === " ") {
6012
+ writeChar(ch);
6013
+ }
6014
+ i++;
6015
+ }
6016
+ return [...scrollback, ...screen];
6017
+ }
6018
+
5857
6019
  // src/agents/codex/runtime.ts
5858
6020
  var CODEX_CONTEXT_WINDOW = 272e3;
5859
6021
  var CODEX_MODELS = [
@@ -5917,6 +6079,16 @@ var CodexRuntimeStrategy = class {
5917
6079
  return { ptyInput: "/compact\r" };
5918
6080
  }
5919
6081
  // ─── TUI parser strategy methods ─────────────────────────────────
6082
+ /**
6083
+ * Codex needs its own virtual terminal because the Codex CLI uses
6084
+ * DECSTBM scroll regions (`\x1B[1;31r`) and Reverse Index (`\x1BM`)
6085
+ * to scroll chat history within a fixed top zone — bytes the shared
6086
+ * renderer drops, leaving the mobile feed with only the most recent
6087
+ * frame instead of the full reply. See ./renderer.ts.
6088
+ */
6089
+ renderToLines(buffer) {
6090
+ return renderCodexBuffer(buffer);
6091
+ }
5920
6092
  parseTuiChrome(line) {
5921
6093
  return parseCodexChrome(line);
5922
6094
  }
@@ -6431,7 +6603,7 @@ var OutputService = class _OutputService {
6431
6603
  return;
6432
6604
  }
6433
6605
  if (elapsed < _OutputService.WARMUP_MS) return;
6434
- const lines = renderLines(this.pty.content);
6606
+ const lines = this.runtime.renderToLines?.(this.pty.content) ?? renderLines(this.pty.content);
6435
6607
  const parseLine2 = this.runtime.parseTuiChrome?.bind(this.runtime) ?? (() => null);
6436
6608
  this.steps.ingest(lines, parseLine2);
6437
6609
  const stepsDelta = this.steps.consumeDelta();
@@ -6489,7 +6661,7 @@ var OutputService = class _OutputService {
6489
6661
  }
6490
6662
  }
6491
6663
  finalize() {
6492
- const lines = renderLines(this.pty.content);
6664
+ const lines = this.runtime.renderToLines?.(this.pty.content) ?? renderLines(this.pty.content);
6493
6665
  const parseLine2 = this.runtime.parseTuiChrome?.bind(this.runtime) ?? (() => null);
6494
6666
  this.steps.ingest(lines, parseLine2);
6495
6667
  const stepsDelta = this.steps.consumeDelta();
@@ -10142,7 +10314,7 @@ async function stopWorkspaceFromLocal(target) {
10142
10314
  // src/commands/version.ts
10143
10315
  var import_picocolors11 = __toESM(require("picocolors"));
10144
10316
  function version() {
10145
- const v = true ? "2.12.10" : "unknown";
10317
+ const v = true ? "2.12.11" : "unknown";
10146
10318
  console.log(`${import_picocolors11.default.bold("codeam-cli")} ${import_picocolors11.default.cyan(v)}`);
10147
10319
  }
10148
10320
 
@@ -10277,7 +10449,7 @@ function checkForUpdates() {
10277
10449
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
10278
10450
  if (process.env.CI) return;
10279
10451
  if (!process.stdout.isTTY) return;
10280
- const current = true ? "2.12.10" : null;
10452
+ const current = true ? "2.12.11" : null;
10281
10453
  if (!current) return;
10282
10454
  const cache = readCache();
10283
10455
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.12.10",
3
+ "version": "2.12.11",
4
4
  "description": "Remote control Claude Code (and other AI coding agents) from your mobile phone. Pair your device, send prompts, stream responses in real-time, and approve commands — from anywhere.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",