codeam-cli 2.23.25 → 2.23.27

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.23.26] — 2026-05-30
8
+
9
+ ### Chore
10
+
11
+ - **meta:** No-polling rule + PreToolUse hook to enforce it
12
+
13
+ ### Fixed
14
+
15
+ - **cli:** Event-driven input_suggestion via PTY data event
16
+
17
+ ## [2.23.25] — 2026-05-30
18
+
19
+ ### Fixed
20
+
21
+ - **cli:** Poll for input_suggestion after turn finalises
22
+
7
23
  ## [2.23.24] — 2026-05-30
8
24
 
9
25
  ### Added
package/dist/index.js CHANGED
@@ -441,7 +441,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
441
441
  // package.json
442
442
  var package_default = {
443
443
  name: "codeam-cli",
444
- version: "2.23.25",
444
+ version: "2.23.27",
445
445
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
446
446
  type: "commonjs",
447
447
  main: "dist/index.js",
@@ -5774,7 +5774,7 @@ function readAnonId() {
5774
5774
  }
5775
5775
  function superProperties() {
5776
5776
  return {
5777
- cliVersion: true ? "2.23.25" : "0.0.0-dev",
5777
+ cliVersion: true ? "2.23.27" : "0.0.0-dev",
5778
5778
  nodeVersion: process.version,
5779
5779
  platform: process.platform,
5780
5780
  arch: process.arch,
@@ -11915,7 +11915,7 @@ var OutputService = class _OutputService {
11915
11915
  this.terminalTurnPending = true;
11916
11916
  this.onTerminalTurnDetected?.();
11917
11917
  }
11918
- log.trace("outputSvc", `push dropped (inactive, ${raw.length}B)`);
11918
+ this.detectIdleSuggestion(raw);
11919
11919
  return;
11920
11920
  }
11921
11921
  log.trace(
@@ -11925,6 +11925,42 @@ var OutputService = class _OutputService {
11925
11925
  this.tryExtractSessionId(raw);
11926
11926
  this.tryDetectRateLimit(raw);
11927
11927
  }
11928
+ /**
11929
+ * Idle-window accumulator. Seeded at finalize() with the current
11930
+ * established screen (`pty.content` BEFORE deactivate wipes it),
11931
+ * then appended-to by every post-finalize push. The seed is
11932
+ * mandatory: Claude paints the ghost-text completion via cursor
11933
+ * positioning ANSI on top of the existing frame, so the virtual
11934
+ * terminal needs the baseline to resolve the target cells.
11935
+ *
11936
+ * Capped at the same size as PtyBuffer's own MAX — head-truncated
11937
+ * on overflow so the most-recent visible state survives.
11938
+ */
11939
+ idleBuffer = "";
11940
+ static IDLE_BUFFER_MAX = 2 * 1024 * 1024;
11941
+ static IDLE_BUFFER_KEEP = 1.5 * 1024 * 1024;
11942
+ detectIdleSuggestion(raw) {
11943
+ if (!this.runtime.detectInputSuggestion) return;
11944
+ this.idleBuffer += raw;
11945
+ if (this.idleBuffer.length > _OutputService.IDLE_BUFFER_MAX) {
11946
+ this.idleBuffer = this.idleBuffer.slice(
11947
+ this.idleBuffer.length - _OutputService.IDLE_BUFFER_KEEP
11948
+ );
11949
+ }
11950
+ const rendered = this.runtime.renderToLines?.(this.idleBuffer) ?? renderLines(this.idleBuffer);
11951
+ const suggestion = this.runtime.detectInputSuggestion(rendered);
11952
+ if (suggestion === this.lastSentSuggestion) return;
11953
+ this.lastSentSuggestion = suggestion;
11954
+ this.send(
11955
+ {
11956
+ type: "input_suggestion",
11957
+ content: suggestion ?? "",
11958
+ done: true
11959
+ },
11960
+ { critical: false }
11961
+ ).catch(() => {
11962
+ });
11963
+ }
11928
11964
  dispose() {
11929
11965
  this.stopPoll();
11930
11966
  this.pty.deactivate();
@@ -11936,6 +11972,7 @@ var OutputService = class _OutputService {
11936
11972
  this.steps.reset();
11937
11973
  this.lastSentContent = "";
11938
11974
  this.lastContentChangeAt = 0;
11975
+ this.idleBuffer = "";
11939
11976
  this.startTime = Date.now();
11940
11977
  this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
11941
11978
  }
@@ -12116,6 +12153,7 @@ var OutputService = class _OutputService {
12116
12153
  }
12117
12154
  const selector = this.runtime.detectInteractivePrompt(lines);
12118
12155
  this.stopPoll();
12156
+ this.idleBuffer = this.pty.content;
12119
12157
  this.pty.deactivate();
12120
12158
  if (selector) {
12121
12159
  this.send(
@@ -12138,40 +12176,8 @@ var OutputService = class _OutputService {
12138
12176
  ).catch(() => {
12139
12177
  });
12140
12178
  this.onTurnComplete?.();
12141
- this.scheduleSuggestionPoll();
12142
12179
  }
12143
12180
  }
12144
- /**
12145
- * Poll for an `input_suggestion` chunk a few times after a
12146
- * turn finalises. The TUI takes a beat to render the ghost
12147
- * completion, so a single check at finalize-time would miss
12148
- * it. Three checks at 400/800/1500 ms cover the window
12149
- * without burning CPU when there's no suggestion (each tick
12150
- * is cheap — a regex over the rendered lines).
12151
- */
12152
- scheduleSuggestionPoll() {
12153
- if (!this.runtime.detectInputSuggestion) return;
12154
- const tryDetect = () => {
12155
- if (!this.runtime.detectInputSuggestion) return;
12156
- const rendered = this.runtime.renderToLines?.(this.pty.content) ?? renderLines(this.pty.content);
12157
- const suggestion = this.runtime.detectInputSuggestion(rendered);
12158
- if (suggestion !== this.lastSentSuggestion) {
12159
- this.lastSentSuggestion = suggestion;
12160
- this.send(
12161
- {
12162
- type: "input_suggestion",
12163
- content: suggestion ?? "",
12164
- done: true
12165
- },
12166
- { critical: false }
12167
- ).catch(() => {
12168
- });
12169
- }
12170
- };
12171
- setTimeout(tryDetect, 400);
12172
- setTimeout(tryDetect, 800);
12173
- setTimeout(tryDetect, 1500);
12174
- }
12175
12181
  // ─── Side-channel observation (session id + rate limit) ──────────
12176
12182
  tryExtractSessionId(text) {
12177
12183
  if (!this.onSessionIdDetected) return;
@@ -18908,7 +18914,7 @@ function checkChokidar() {
18908
18914
  }
18909
18915
  async function doctor(args2 = []) {
18910
18916
  const json = args2.includes("--json");
18911
- const cliVersion = true ? "2.23.25" : "0.0.0-dev";
18917
+ const cliVersion = true ? "2.23.27" : "0.0.0-dev";
18912
18918
  const apiBase = resolveApiBaseUrl();
18913
18919
  const diagnosticId = (0, import_node_crypto6.randomUUID)();
18914
18920
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -19107,7 +19113,7 @@ async function completion(args2) {
19107
19113
  // src/commands/version.ts
19108
19114
  var import_picocolors13 = __toESM(require("picocolors"));
19109
19115
  function version2() {
19110
- const v = true ? "2.23.25" : "unknown";
19116
+ const v = true ? "2.23.27" : "unknown";
19111
19117
  console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
19112
19118
  }
19113
19119
 
@@ -19335,7 +19341,7 @@ function checkForUpdates() {
19335
19341
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
19336
19342
  if (process.env.CI) return;
19337
19343
  if (!process.stdout.isTTY) return;
19338
- const current = true ? "2.23.25" : null;
19344
+ const current = true ? "2.23.27" : null;
19339
19345
  if (!current) return;
19340
19346
  const cache = readCache();
19341
19347
  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.23.25",
3
+ "version": "2.23.27",
4
4
  "description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",