codeam-cli 1.0.9 → 1.1.1

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 +78 -49
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -110,7 +110,7 @@ var import_picocolors = __toESM(require("picocolors"));
110
110
  // package.json
111
111
  var package_default = {
112
112
  name: "codeam-cli",
113
- version: "1.0.9",
113
+ version: "1.1.1",
114
114
  description: "Remote control Claude Code from your mobile device",
115
115
  main: "dist/index.js",
116
116
  bin: {
@@ -746,67 +746,84 @@ var OutputService = class _OutputService {
746
746
  sessionId;
747
747
  pluginId;
748
748
  buffer = "";
749
- flushTimer = null;
750
- streamTimer = null;
749
+ lastSentBuffer = "";
750
+ pollTimer = null;
751
+ startTime = 0;
751
752
  active = false;
752
- static STREAM_INTERVAL_MS = 1e3;
753
- static DONE_DEBOUNCE_MS = 2500;
753
+ /** Time since last meaningful push() — when this exceeds IDLE_MS, response is done. */
754
+ lastPushTime = 0;
755
+ static POLL_MS = 500;
756
+ /** No new content for 3 s = Claude finished responding. */
757
+ static IDLE_MS = 3e3;
758
+ /** No content at all for 30 s = give up (connection issue, etc.). */
759
+ static EMPTY_TIMEOUT_MS = 3e4;
760
+ /** Hard cap — always clear typing state after 2 minutes. */
761
+ static MAX_MS = 12e4;
754
762
  /**
755
763
  * Call before sending a command from mobile.
756
- * Clears previous output and pushes a new_turn event so the mobile app
757
- * shows the typing indicator.
764
+ * Clears previous output, sends new_turn event, starts polling.
758
765
  */
759
- async newTurn() {
760
- this.stopTimers();
766
+ newTurn() {
767
+ this.stopPoll();
761
768
  this.buffer = "";
769
+ this.lastSentBuffer = "";
770
+ this.lastPushTime = 0;
762
771
  this.active = true;
763
- await this.postChunk({ clear: true });
764
- await this.postChunk({ type: "new_turn", content: "", done: false });
765
- this.startStreamTimer();
772
+ this.startTime = Date.now();
773
+ this.postChunk({ clear: true }).then(() => this.postChunk({ type: "new_turn", content: "", done: false })).catch(() => {
774
+ });
775
+ this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
766
776
  }
767
777
  /** Feed raw terminal output from Claude (called on every stdout chunk). */
768
778
  push(raw) {
769
779
  if (!this.active) return;
770
780
  const text = stripAnsi(raw).replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n");
771
- if (!text.trim()) return;
772
- this.buffer += text;
773
- this.resetDoneDebounce();
781
+ if (text.trim()) {
782
+ this.buffer += text;
783
+ this.lastPushTime = Date.now();
784
+ }
774
785
  }
775
786
  dispose() {
776
- this.stopTimers();
787
+ this.stopPoll();
777
788
  this.active = false;
778
789
  }
779
- startStreamTimer() {
780
- this.streamTimer = setInterval(() => {
781
- const text = this.buffer;
782
- if (text.trim()) {
783
- this.postChunk({ type: "text", content: text, done: false }).catch(() => {
784
- });
790
+ tick() {
791
+ if (!this.active) return;
792
+ const now = Date.now();
793
+ const elapsed = now - this.startTime;
794
+ if (elapsed >= _OutputService.MAX_MS) {
795
+ this.finalize();
796
+ return;
797
+ }
798
+ const hasContent = this.buffer.trim().length > 0;
799
+ if (!hasContent) {
800
+ if (elapsed >= _OutputService.EMPTY_TIMEOUT_MS) {
801
+ this.finalize();
785
802
  }
786
- }, _OutputService.STREAM_INTERVAL_MS);
803
+ return;
804
+ }
805
+ const idleMs = this.lastPushTime > 0 ? now - this.lastPushTime : elapsed;
806
+ if (idleMs >= _OutputService.IDLE_MS) {
807
+ this.finalize();
808
+ return;
809
+ }
810
+ if (this.buffer !== this.lastSentBuffer) {
811
+ this.lastSentBuffer = this.buffer;
812
+ this.postChunk({ type: "text", content: this.buffer, done: false }).catch(() => {
813
+ });
814
+ }
787
815
  }
788
- resetDoneDebounce() {
789
- if (this.flushTimer) clearTimeout(this.flushTimer);
790
- this.flushTimer = setTimeout(() => {
791
- this.flushTimer = null;
792
- this.stopTimers();
793
- const text = this.buffer;
794
- this.buffer = "";
795
- this.active = false;
796
- if (text.trim()) {
797
- this.postChunk({ type: "text", content: text, done: true }).catch(() => {
798
- });
799
- }
800
- }, _OutputService.DONE_DEBOUNCE_MS);
816
+ finalize() {
817
+ const text = this.buffer;
818
+ this.stopPoll();
819
+ this.active = false;
820
+ this.postChunk({ type: "text", content: text, done: true }).catch(() => {
821
+ });
801
822
  }
802
- stopTimers() {
803
- if (this.flushTimer) {
804
- clearTimeout(this.flushTimer);
805
- this.flushTimer = null;
806
- }
807
- if (this.streamTimer) {
808
- clearInterval(this.streamTimer);
809
- this.streamTimer = null;
823
+ stopPoll() {
824
+ if (this.pollTimer) {
825
+ clearInterval(this.pollTimer);
826
+ this.pollTimer = null;
810
827
  }
811
828
  }
812
829
  postChunk(body) {
@@ -831,11 +848,24 @@ var OutputService = class _OutputService {
831
848
  timeout: 8e3
832
849
  },
833
850
  (res) => {
834
- res.resume();
835
- resolve();
851
+ let body2 = "";
852
+ res.on("data", (c) => {
853
+ body2 += c.toString();
854
+ });
855
+ res.on("end", () => {
856
+ if (res.statusCode && res.statusCode >= 400) {
857
+ process.stderr.write(`[codeam] output API error ${res.statusCode}: ${body2}
858
+ `);
859
+ }
860
+ resolve();
861
+ });
836
862
  }
837
863
  );
838
- req.on("error", () => resolve());
864
+ req.on("error", (err) => {
865
+ process.stderr.write(`[codeam] output POST failed: ${err.message}
866
+ `);
867
+ resolve();
868
+ });
839
869
  req.on("timeout", () => {
840
870
  req.destroy();
841
871
  resolve();
@@ -862,8 +892,7 @@ async function start() {
862
892
  const ws = new WebSocketService(session.id, pluginId);
863
893
  const outputSvc = new OutputService(session.id, pluginId);
864
894
  function sendPrompt(prompt) {
865
- outputSvc.newTurn().catch(() => {
866
- });
895
+ outputSvc.newTurn();
867
896
  claude.sendCommand(prompt);
868
897
  }
869
898
  const relay = new CommandRelayService(pluginId, (cmd) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
4
4
  "description": "Remote control Claude Code from your mobile device",
5
5
  "main": "dist/index.js",
6
6
  "bin": {