codeam-cli 1.1.1 → 1.1.2
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 +147 -32
- 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.1.
|
|
113
|
+
version: "1.1.2",
|
|
114
114
|
description: "Remote control Claude Code from your mobile device",
|
|
115
115
|
main: "dist/index.js",
|
|
116
116
|
bin: {
|
|
@@ -735,8 +735,131 @@ function findInPath(name) {
|
|
|
735
735
|
var https2 = __toESM(require("https"));
|
|
736
736
|
var http2 = __toESM(require("http"));
|
|
737
737
|
var API_BASE4 = process.env.CODEAM_API_URL ?? "https://codeagent-mobile-api.vercel.app";
|
|
738
|
-
function
|
|
739
|
-
|
|
738
|
+
function renderToLines(raw) {
|
|
739
|
+
const screen = [""];
|
|
740
|
+
let row = 0;
|
|
741
|
+
let col = 0;
|
|
742
|
+
function ensureRow() {
|
|
743
|
+
while (screen.length <= row) screen.push("");
|
|
744
|
+
}
|
|
745
|
+
function writeChar(ch) {
|
|
746
|
+
ensureRow();
|
|
747
|
+
if (col < screen[row].length) {
|
|
748
|
+
screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);
|
|
749
|
+
} else {
|
|
750
|
+
while (screen[row].length < col) screen[row] += " ";
|
|
751
|
+
screen[row] += ch;
|
|
752
|
+
}
|
|
753
|
+
col++;
|
|
754
|
+
}
|
|
755
|
+
let i = 0;
|
|
756
|
+
while (i < raw.length) {
|
|
757
|
+
const ch = raw[i];
|
|
758
|
+
if (ch === "\x1B") {
|
|
759
|
+
i++;
|
|
760
|
+
if (i >= raw.length) break;
|
|
761
|
+
if (raw[i] === "[") {
|
|
762
|
+
i++;
|
|
763
|
+
let param = "";
|
|
764
|
+
while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];
|
|
765
|
+
const cmd = raw[i] ?? "";
|
|
766
|
+
const n = parseInt(param) || 1;
|
|
767
|
+
if (cmd === "A") {
|
|
768
|
+
row = Math.max(0, row - n);
|
|
769
|
+
} else if (cmd === "B") {
|
|
770
|
+
row += n;
|
|
771
|
+
ensureRow();
|
|
772
|
+
} else if (cmd === "C") {
|
|
773
|
+
col += n;
|
|
774
|
+
} else if (cmd === "D") {
|
|
775
|
+
col = Math.max(0, col - n);
|
|
776
|
+
} else if (cmd === "G") {
|
|
777
|
+
col = Math.max(0, n - 1);
|
|
778
|
+
} else if (cmd === "H" || cmd === "f") {
|
|
779
|
+
const p2 = param.split(";");
|
|
780
|
+
row = Math.max(0, (parseInt(p2[0] ?? "1") || 1) - 1);
|
|
781
|
+
col = Math.max(0, (parseInt(p2[1] ?? "1") || 1) - 1);
|
|
782
|
+
ensureRow();
|
|
783
|
+
} else if (cmd === "J") {
|
|
784
|
+
if (param === "2" || param === "3") {
|
|
785
|
+
screen.length = 1;
|
|
786
|
+
screen[0] = "";
|
|
787
|
+
row = 0;
|
|
788
|
+
col = 0;
|
|
789
|
+
} else if (param === "1") {
|
|
790
|
+
for (let r = 0; r < row; r++) screen[r] = "";
|
|
791
|
+
screen[row] = " ".repeat(col) + screen[row].slice(col);
|
|
792
|
+
} else {
|
|
793
|
+
screen[row] = screen[row].slice(0, col);
|
|
794
|
+
screen.splice(row + 1);
|
|
795
|
+
}
|
|
796
|
+
} else if (cmd === "K") {
|
|
797
|
+
ensureRow();
|
|
798
|
+
if (param === "" || param === "0") screen[row] = screen[row].slice(0, col);
|
|
799
|
+
else if (param === "1") screen[row] = " ".repeat(col) + screen[row].slice(col);
|
|
800
|
+
else if (param === "2") screen[row] = "";
|
|
801
|
+
} else if (cmd === "h" && (param === "?1049" || param === "?47")) {
|
|
802
|
+
screen.length = 1;
|
|
803
|
+
screen[0] = "";
|
|
804
|
+
row = 0;
|
|
805
|
+
col = 0;
|
|
806
|
+
} else if (cmd === "l" && (param === "?1049" || param === "?47")) {
|
|
807
|
+
screen.length = 1;
|
|
808
|
+
screen[0] = "";
|
|
809
|
+
row = 0;
|
|
810
|
+
col = 0;
|
|
811
|
+
}
|
|
812
|
+
} else if (raw[i] === "]") {
|
|
813
|
+
i++;
|
|
814
|
+
while (i < raw.length) {
|
|
815
|
+
if (raw[i] === "\x07") break;
|
|
816
|
+
if (raw[i] === "\x1B" && i + 1 < raw.length && raw[i + 1] === "\\") {
|
|
817
|
+
i++;
|
|
818
|
+
break;
|
|
819
|
+
}
|
|
820
|
+
i++;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
} else if (ch === "\r") {
|
|
824
|
+
if (i + 1 < raw.length && raw[i + 1] === "\n") {
|
|
825
|
+
row++;
|
|
826
|
+
col = 0;
|
|
827
|
+
ensureRow();
|
|
828
|
+
i++;
|
|
829
|
+
} else {
|
|
830
|
+
col = 0;
|
|
831
|
+
}
|
|
832
|
+
} else if (ch === "\n") {
|
|
833
|
+
row++;
|
|
834
|
+
col = 0;
|
|
835
|
+
ensureRow();
|
|
836
|
+
} else if (ch >= " " || ch === " ") {
|
|
837
|
+
writeChar(ch);
|
|
838
|
+
}
|
|
839
|
+
i++;
|
|
840
|
+
}
|
|
841
|
+
return screen;
|
|
842
|
+
}
|
|
843
|
+
function filterChrome(lines) {
|
|
844
|
+
return lines.filter((line) => {
|
|
845
|
+
const t = line.trim();
|
|
846
|
+
if (!t) return false;
|
|
847
|
+
if (/^[─━—═\-─]{3,}$/.test(t)) return false;
|
|
848
|
+
if (/^[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]\s/.test(t)) return false;
|
|
849
|
+
if (/esc.{0,5}to.{0,5}interrupt/i.test(t)) return false;
|
|
850
|
+
if (/high\s*[·•]\s*\/effort/i.test(t)) return false;
|
|
851
|
+
if (/^[❯>]\s*$/.test(t)) return false;
|
|
852
|
+
if (/^[❯>]\s+\S/.test(t)) return false;
|
|
853
|
+
if (/^\(thinking\)\s*$/.test(t)) return false;
|
|
854
|
+
if (/^\?\s.*shortcut/i.test(t)) return false;
|
|
855
|
+
if (/spending limit|usage limit/i.test(t) && t.length < 80) return false;
|
|
856
|
+
return true;
|
|
857
|
+
});
|
|
858
|
+
}
|
|
859
|
+
function extractContent(raw) {
|
|
860
|
+
const lines = renderToLines(raw);
|
|
861
|
+
const filtered = filterChrome(lines);
|
|
862
|
+
return filtered.join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
740
863
|
}
|
|
741
864
|
var OutputService = class _OutputService {
|
|
742
865
|
constructor(sessionId, pluginId) {
|
|
@@ -745,28 +868,25 @@ var OutputService = class _OutputService {
|
|
|
745
868
|
}
|
|
746
869
|
sessionId;
|
|
747
870
|
pluginId;
|
|
748
|
-
|
|
749
|
-
|
|
871
|
+
/** Raw PTY bytes — processed only when we need to send content. */
|
|
872
|
+
rawBuffer = "";
|
|
873
|
+
lastSentContent = "";
|
|
750
874
|
pollTimer = null;
|
|
751
875
|
startTime = 0;
|
|
752
876
|
active = false;
|
|
753
|
-
/**
|
|
877
|
+
/** When the last chunk of printable raw content arrived. */
|
|
754
878
|
lastPushTime = 0;
|
|
755
|
-
static POLL_MS =
|
|
756
|
-
/** No new content for 3 s
|
|
879
|
+
static POLL_MS = 1e3;
|
|
880
|
+
/** No new printable content for 3 s → Claude finished responding. */
|
|
757
881
|
static IDLE_MS = 3e3;
|
|
758
|
-
/** No content at all for 30 s
|
|
882
|
+
/** No content at all for 30 s → give up. */
|
|
759
883
|
static EMPTY_TIMEOUT_MS = 3e4;
|
|
760
|
-
/** Hard cap —
|
|
884
|
+
/** Hard cap — clear typing state after 2 min no matter what. */
|
|
761
885
|
static MAX_MS = 12e4;
|
|
762
|
-
/**
|
|
763
|
-
* Call before sending a command from mobile.
|
|
764
|
-
* Clears previous output, sends new_turn event, starts polling.
|
|
765
|
-
*/
|
|
766
886
|
newTurn() {
|
|
767
887
|
this.stopPoll();
|
|
768
|
-
this.
|
|
769
|
-
this.
|
|
888
|
+
this.rawBuffer = "";
|
|
889
|
+
this.lastSentContent = "";
|
|
770
890
|
this.lastPushTime = 0;
|
|
771
891
|
this.active = true;
|
|
772
892
|
this.startTime = Date.now();
|
|
@@ -774,14 +894,11 @@ var OutputService = class _OutputService {
|
|
|
774
894
|
});
|
|
775
895
|
this.pollTimer = setInterval(() => this.tick(), _OutputService.POLL_MS);
|
|
776
896
|
}
|
|
777
|
-
/** Feed raw terminal output from Claude (called on every stdout chunk). */
|
|
778
897
|
push(raw) {
|
|
779
898
|
if (!this.active) return;
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
this.lastPushTime = Date.now();
|
|
784
|
-
}
|
|
899
|
+
this.rawBuffer += raw;
|
|
900
|
+
const printable = raw.replace(/\x1B\[[^@-~]*[@-~]/g, "").replace(/[\x00-\x1F\x7F]/g, "");
|
|
901
|
+
if (printable.trim()) this.lastPushTime = Date.now();
|
|
785
902
|
}
|
|
786
903
|
dispose() {
|
|
787
904
|
this.stopPoll();
|
|
@@ -795,11 +912,9 @@ var OutputService = class _OutputService {
|
|
|
795
912
|
this.finalize();
|
|
796
913
|
return;
|
|
797
914
|
}
|
|
798
|
-
const
|
|
799
|
-
if (!
|
|
800
|
-
if (elapsed >= _OutputService.EMPTY_TIMEOUT_MS)
|
|
801
|
-
this.finalize();
|
|
802
|
-
}
|
|
915
|
+
const content = extractContent(this.rawBuffer);
|
|
916
|
+
if (!content) {
|
|
917
|
+
if (elapsed >= _OutputService.EMPTY_TIMEOUT_MS) this.finalize();
|
|
803
918
|
return;
|
|
804
919
|
}
|
|
805
920
|
const idleMs = this.lastPushTime > 0 ? now - this.lastPushTime : elapsed;
|
|
@@ -807,17 +922,17 @@ var OutputService = class _OutputService {
|
|
|
807
922
|
this.finalize();
|
|
808
923
|
return;
|
|
809
924
|
}
|
|
810
|
-
if (
|
|
811
|
-
this.
|
|
812
|
-
this.postChunk({ type: "text", content
|
|
925
|
+
if (content !== this.lastSentContent) {
|
|
926
|
+
this.lastSentContent = content;
|
|
927
|
+
this.postChunk({ type: "text", content, done: false }).catch(() => {
|
|
813
928
|
});
|
|
814
929
|
}
|
|
815
930
|
}
|
|
816
931
|
finalize() {
|
|
817
|
-
const
|
|
932
|
+
const content = extractContent(this.rawBuffer);
|
|
818
933
|
this.stopPoll();
|
|
819
934
|
this.active = false;
|
|
820
|
-
this.postChunk({ type: "text", content
|
|
935
|
+
this.postChunk({ type: "text", content, done: true }).catch(() => {
|
|
821
936
|
});
|
|
822
937
|
}
|
|
823
938
|
stopPoll() {
|