codeam-cli 2.39.23 → 2.39.24
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 +10 -0
- package/dist/index.js +53 -766
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,16 @@ 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.39.23] — 2026-06-17
|
|
8
|
+
|
|
9
|
+
### Chore
|
|
10
|
+
|
|
11
|
+
- **cli:** Raise engines.node floor to >=20, bump which to ^6 (#345)
|
|
12
|
+
|
|
13
|
+
### Agent
|
|
14
|
+
|
|
15
|
+
- Waiting for your CLI... (#348)
|
|
16
|
+
|
|
7
17
|
## [2.39.22] — 2026-06-16
|
|
8
18
|
|
|
9
19
|
### Fixed
|
package/dist/index.js
CHANGED
|
@@ -498,7 +498,7 @@ var import_qrcode_terminal = __toESM(require("qrcode-terminal"));
|
|
|
498
498
|
// package.json
|
|
499
499
|
var package_default = {
|
|
500
500
|
name: "codeam-cli",
|
|
501
|
-
version: "2.39.
|
|
501
|
+
version: "2.39.24",
|
|
502
502
|
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.",
|
|
503
503
|
type: "commonjs",
|
|
504
504
|
main: "dist/index.js",
|
|
@@ -5908,7 +5908,7 @@ function readAnonId() {
|
|
|
5908
5908
|
}
|
|
5909
5909
|
function superProperties() {
|
|
5910
5910
|
return {
|
|
5911
|
-
cliVersion: true ? "2.39.
|
|
5911
|
+
cliVersion: true ? "2.39.24" : "0.0.0-dev",
|
|
5912
5912
|
nodeVersion: process.version,
|
|
5913
5913
|
platform: process.platform,
|
|
5914
5914
|
arch: process.arch,
|
|
@@ -9748,300 +9748,6 @@ function listResumableSessions(cwd) {
|
|
|
9748
9748
|
return out2;
|
|
9749
9749
|
}
|
|
9750
9750
|
|
|
9751
|
-
// src/agents/claude/parsing.ts
|
|
9752
|
-
function filterChrome(lines) {
|
|
9753
|
-
const result = [];
|
|
9754
|
-
let skipEchoContinuation = false;
|
|
9755
|
-
for (const line of lines) {
|
|
9756
|
-
const t2 = line.trim();
|
|
9757
|
-
if (!t2) {
|
|
9758
|
-
skipEchoContinuation = false;
|
|
9759
|
-
continue;
|
|
9760
|
-
}
|
|
9761
|
-
if (/^[─━—═─\-]{3,}$/.test(t2)) {
|
|
9762
|
-
skipEchoContinuation = false;
|
|
9763
|
-
continue;
|
|
9764
|
-
}
|
|
9765
|
-
if (/^[●⏺]\s/.test(t2)) skipEchoContinuation = false;
|
|
9766
|
-
if (/^[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]\s/.test(t2)) continue;
|
|
9767
|
-
if (/esc.{0,5}to.{0,5}interrupt/i.test(t2)) continue;
|
|
9768
|
-
if (/high\s*[·•]\s*\/effort/i.test(t2)) continue;
|
|
9769
|
-
if (/^[❯>]\s*$/.test(t2)) continue;
|
|
9770
|
-
if (/^\(thinking\)\s*$/.test(t2)) continue;
|
|
9771
|
-
if (/^\?\s.*shortcut/i.test(t2)) continue;
|
|
9772
|
-
if (/spending limit|usage limit/i.test(t2) && t2.length < 80) continue;
|
|
9773
|
-
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t2)) continue;
|
|
9774
|
-
if (t2.replace(/\s/g, "").length === 1) continue;
|
|
9775
|
-
if ((t2.match(/─/g)?.length ?? 0) >= 6) continue;
|
|
9776
|
-
if (/ctrl\+?o\s+to\s+expand/i.test(t2)) continue;
|
|
9777
|
-
if (/^•\s+(?:Read(?:ing)?|Edit(?:ing)?|Writ(?:e|ing)|Bash|Runn(?:ing)?|Search(?:ing)?|Glob(?:bing)?|Grep(?:ping)?|Creat(?:e|ing)|Execut(?:e|ing)|Task|Agent|NotebookEdit)\b/i.test(
|
|
9778
|
-
t2
|
|
9779
|
-
))
|
|
9780
|
-
continue;
|
|
9781
|
-
if (/^└\s/.test(t2)) continue;
|
|
9782
|
-
if (/^\+\s/.test(t2) && /\d+\s*s\s*[·•]|\bthought\s+for\b|\d+\s*tokens|\(thinking\)/i.test(t2)) continue;
|
|
9783
|
-
if (/^↓\s*\d+\s*tokens/i.test(t2)) continue;
|
|
9784
|
-
if (/^\bthought\s+for\s+\d+/i.test(t2)) continue;
|
|
9785
|
-
const stripped = t2.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "");
|
|
9786
|
-
if (/^[❯>]\s+\S/.test(stripped) && !/^[❯>]\s*\d+\./.test(stripped)) {
|
|
9787
|
-
skipEchoContinuation = true;
|
|
9788
|
-
continue;
|
|
9789
|
-
}
|
|
9790
|
-
if (skipEchoContinuation) continue;
|
|
9791
|
-
result.push(line);
|
|
9792
|
-
}
|
|
9793
|
-
return result;
|
|
9794
|
-
}
|
|
9795
|
-
var SPINNER_RE = /^(?:[✳✢✶✻✽✴✷✸✹⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏◐◑◒◓▁▂▃▄▅▆▇█]|🔴|🟠|🟡|🟢|🔵|🟣|🟤|⚫|⚪|🌀|💭|✨)\s/u;
|
|
9796
|
-
var BULLET_TOOL_RE = /^•\s+(?:Read(?:ing)?|Edit(?:ing)?|Writ(?:e|ing)|Bash|Runn(?:ing)?|Search(?:ing)?|Glob(?:bing)?|Grep(?:ping)?|Creat(?:e|ing)|Execut(?:e|ing)|Task|Agent|NotebookEdit)\b/i;
|
|
9797
|
-
var TREE_LINE_RE = /^└\s/;
|
|
9798
|
-
var STATUS_LINE_RE = /^(?:\+|[🔴🟠🟡🟢🔵🟣🟤⚫⚪🌀💭✨])\s/u;
|
|
9799
|
-
function isChromeLine(line) {
|
|
9800
|
-
const t2 = line.replace(/️/g, "").trim();
|
|
9801
|
-
if (!t2) return false;
|
|
9802
|
-
if (/^[─━—═─\-]{3,}$/.test(t2)) return true;
|
|
9803
|
-
if (SPINNER_RE.test(t2)) return true;
|
|
9804
|
-
if (BULLET_TOOL_RE.test(t2)) return true;
|
|
9805
|
-
if (TREE_LINE_RE.test(t2)) return true;
|
|
9806
|
-
if (STATUS_LINE_RE.test(t2) && /\d+\s*s\s*[·•]|\bthought\s+for\b|\d+\s*tokens|\(thinking\)/i.test(t2)) return true;
|
|
9807
|
-
if (/^↓\s*\d+\s*tokens/i.test(t2)) return true;
|
|
9808
|
-
if (/^\bthought\s+for\s+\d+/i.test(t2)) return true;
|
|
9809
|
-
if (/esc.{0,5}to.{0,5}interrupt/i.test(t2)) return true;
|
|
9810
|
-
if (/high\s*[·•]\s*\/effort/i.test(t2)) return true;
|
|
9811
|
-
if (/^[❯>]\s*$/.test(t2)) return true;
|
|
9812
|
-
if (/^\(thinking\)\s*$/.test(t2)) return true;
|
|
9813
|
-
if (/^\?\s.*shortcut/i.test(t2)) return true;
|
|
9814
|
-
if (/spending limit|usage limit/i.test(t2) && t2.length < 80) return true;
|
|
9815
|
-
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t2)) return true;
|
|
9816
|
-
if (t2.replace(/\s/g, "").length === 1) return true;
|
|
9817
|
-
if ((t2.match(/─/g)?.length ?? 0) >= 6) return true;
|
|
9818
|
-
if (/ctrl\+?o\s+to\s+expand/i.test(t2)) return true;
|
|
9819
|
-
const hasBoxPrefix = /^[│╭╰╮╯┌└┐┘├┤┬┴┼]/.test(t2);
|
|
9820
|
-
const stripped = t2.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "");
|
|
9821
|
-
if (hasBoxPrefix && /^[❯>]\s+\S/.test(stripped) && !/^[❯>]\s*\d+\./.test(stripped)) return true;
|
|
9822
|
-
return false;
|
|
9823
|
-
}
|
|
9824
|
-
function parseChromeLine(line) {
|
|
9825
|
-
const t2 = line.replace(/️/g, "").trim();
|
|
9826
|
-
if (!t2) return null;
|
|
9827
|
-
if (/^[─━—═─\-]{3,}$/.test(t2)) return null;
|
|
9828
|
-
if (/^[❯>]\s*$/.test(t2)) return null;
|
|
9829
|
-
if (t2.replace(/\s/g, "").length === 1) return null;
|
|
9830
|
-
if ((t2.match(/─/g)?.length ?? 0) >= 6) return null;
|
|
9831
|
-
if (/esc.{0,5}to.{0,5}interrupt/i.test(t2)) return null;
|
|
9832
|
-
if (/high\s*[·•]\s*\/effort/i.test(t2)) return null;
|
|
9833
|
-
if (/↑\s*\/?\s*↓\s*to\s*navigate/i.test(t2)) return null;
|
|
9834
|
-
if (/ctrl\+?o\s+to\s+expand/i.test(t2)) return null;
|
|
9835
|
-
if (/spending limit|usage limit/i.test(t2)) return null;
|
|
9836
|
-
if (/^\(thinking\)\s*$/.test(t2)) {
|
|
9837
|
-
return { tool: "thinking", label: "Thinking\u2026", status: "running" };
|
|
9838
|
-
}
|
|
9839
|
-
if (TREE_LINE_RE.test(t2)) return null;
|
|
9840
|
-
if (STATUS_LINE_RE.test(t2)) {
|
|
9841
|
-
const label = t2.slice(2).replace(/….*/s, "").trim() || "Thinking\u2026";
|
|
9842
|
-
return { tool: "thinking", label, status: "running" };
|
|
9843
|
-
}
|
|
9844
|
-
let text = t2;
|
|
9845
|
-
if (SPINNER_RE.test(t2)) {
|
|
9846
|
-
text = t2.slice(2).trim().replace(/….*/s, "").trim();
|
|
9847
|
-
} else if (BULLET_TOOL_RE.test(t2)) {
|
|
9848
|
-
text = t2.slice(2).trim();
|
|
9849
|
-
text = text.replace(/\s*\(ctrl\+?o[^)]*\)/gi, "").replace(/,\s*reading\s+\d+\s+files?\s*…?/gi, "").replace(/,\s*\d+\s+files?\s*…?/gi, "").replace(/…$/, "").trim();
|
|
9850
|
-
}
|
|
9851
|
-
if (!text) return null;
|
|
9852
|
-
return classifyStep(text);
|
|
9853
|
-
}
|
|
9854
|
-
function classifyStep(text) {
|
|
9855
|
-
if (/^Read(?:ing)?\s+/i.test(text)) {
|
|
9856
|
-
const label2 = text.replace(/^Read(?:ing)?\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9857
|
-
return { tool: "read", label: label2, status: "running" };
|
|
9858
|
-
}
|
|
9859
|
-
if (/^Edit(?:ing)?\s+|^Writ(?:e|ing|ing to)\s+|^Creat(?:e|ing)\s+/i.test(text)) {
|
|
9860
|
-
const label2 = text.replace(/^(?:Edit(?:ing)?|Writ(?:e|ing(?: to)?)|Creat(?:e|ing))\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9861
|
-
return { tool: "edit", label: label2, status: "running" };
|
|
9862
|
-
}
|
|
9863
|
-
if (/^Runn(?:ing)?\s+|^Execut(?:e|ing)\s+|^Bash(?:ing)?\s*:|^\$\s+/i.test(text)) {
|
|
9864
|
-
const label2 = text.replace(/^(?:Runn(?:ing)?|Execut(?:e|ing)|Bash(?:ing)?:|\$)\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9865
|
-
return { tool: "bash", label: label2, status: "running" };
|
|
9866
|
-
}
|
|
9867
|
-
if (/^Search(?:ing)?\s+for\s+|^Grep(?:ping)?\s*:/i.test(text)) {
|
|
9868
|
-
const label2 = text.replace(/^(?:Search(?:ing)?\s+for|Grep(?:ping)?:)\s+/i, "").replace(/\.\.\.$/, "").trim();
|
|
9869
|
-
return { tool: "search", label: label2, status: "running" };
|
|
9870
|
-
}
|
|
9871
|
-
const label = text.replace(/\.\.\.$/, "").trim();
|
|
9872
|
-
return { tool: "other", label, status: "running" };
|
|
9873
|
-
}
|
|
9874
|
-
function detectSelector(lines) {
|
|
9875
|
-
if (lines.some((l) => /\?\s+for\s+shortcuts/i.test(l.trim()))) return null;
|
|
9876
|
-
const clean = lines.map(
|
|
9877
|
-
(l) => l.replace(/^[│╭╰╮╯┌└┐┘├┤┬┴┼]\s?/, "").replace(/\s*[│╭╰╮╯┌└┐┘├┤┬┴┼─━═]+\s*$/, "")
|
|
9878
|
-
);
|
|
9879
|
-
const hasCursor = clean.some((l) => /^[❯>]\s*\d+\./.test(l.trim()));
|
|
9880
|
-
const looksLikeTrust = clean.some(
|
|
9881
|
-
(l) => /\b(?:trust\s+the\s+files|trust\s+this\s+folder|safety\s+check)\b/i.test(l)
|
|
9882
|
-
);
|
|
9883
|
-
if (!hasCursor && !looksLikeTrust) return null;
|
|
9884
|
-
const OPTION_RE = /^(?:[❯>]\s*)?(\d+)\.(\s+|(?=\D))(.+)/;
|
|
9885
|
-
let optionStartIdx = -1;
|
|
9886
|
-
for (let i = 0; i < clean.length; i++) {
|
|
9887
|
-
if (OPTION_RE.test(clean[i].trim())) {
|
|
9888
|
-
optionStartIdx = i;
|
|
9889
|
-
break;
|
|
9890
|
-
}
|
|
9891
|
-
}
|
|
9892
|
-
if (optionStartIdx === -1) return null;
|
|
9893
|
-
const questionParts = [];
|
|
9894
|
-
for (let i = 0; i < optionStartIdx; i++) {
|
|
9895
|
-
const t2 = clean[i].trim();
|
|
9896
|
-
if (!t2) continue;
|
|
9897
|
-
if (/^[─━—═\-]{3,}$/.test(t2)) continue;
|
|
9898
|
-
if (/^\[.*\]$/.test(t2)) continue;
|
|
9899
|
-
if (/^[>❯]\s/.test(t2)) continue;
|
|
9900
|
-
if (!t2.includes(" ") && t2.length > 15) continue;
|
|
9901
|
-
questionParts.push(t2);
|
|
9902
|
-
}
|
|
9903
|
-
const question = questionParts.filter((line, i, arr) => !arr.some((other, j2) => j2 !== i && other.includes(line))).join("\n").trim();
|
|
9904
|
-
const optionLabels = /* @__PURE__ */ new Map();
|
|
9905
|
-
const optionDescs = /* @__PURE__ */ new Map();
|
|
9906
|
-
let currentNum = -1;
|
|
9907
|
-
for (let i = optionStartIdx; i < clean.length; i++) {
|
|
9908
|
-
const t2 = clean[i].trim();
|
|
9909
|
-
if (!t2) continue;
|
|
9910
|
-
const m = t2.match(OPTION_RE);
|
|
9911
|
-
if (m) {
|
|
9912
|
-
const num = parseInt(m[1], 10);
|
|
9913
|
-
if (!optionLabels.has(num)) {
|
|
9914
|
-
optionLabels.set(num, m[3].trim());
|
|
9915
|
-
optionDescs.set(num, []);
|
|
9916
|
-
}
|
|
9917
|
-
currentNum = num;
|
|
9918
|
-
} else if (currentNum !== -1 && !/^Enter to/i.test(t2) && !/^[─━—═\-]{3,}$/.test(t2) && !/↑.*↓.*navigate/i.test(t2) && !/Esc to/i.test(t2)) {
|
|
9919
|
-
optionDescs.get(currentNum)?.push(t2);
|
|
9920
|
-
}
|
|
9921
|
-
}
|
|
9922
|
-
const keys = [...optionLabels.keys()].sort((a, b) => a - b);
|
|
9923
|
-
if (keys.length < 2 || keys[0] !== 1) return null;
|
|
9924
|
-
return {
|
|
9925
|
-
question,
|
|
9926
|
-
options: keys.map((k2) => optionLabels.get(k2)),
|
|
9927
|
-
optionDescriptions: keys.map((k2) => (optionDescs.get(k2) ?? []).join(" ").trim()),
|
|
9928
|
-
currentIndex: 0
|
|
9929
|
-
};
|
|
9930
|
-
}
|
|
9931
|
-
function detectInputSuggestion(lines) {
|
|
9932
|
-
let hintIdx = -1;
|
|
9933
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
9934
|
-
if (/\?\s+for\s+shortcuts/i.test(lines[i].trim())) {
|
|
9935
|
-
hintIdx = i;
|
|
9936
|
-
break;
|
|
9937
|
-
}
|
|
9938
|
-
}
|
|
9939
|
-
if (hintIdx === -1) return null;
|
|
9940
|
-
if (lines.some((l) => /^[❯>]\s*\d+\./.test(l.trim()))) return null;
|
|
9941
|
-
const windowStart = Math.max(0, hintIdx - 5);
|
|
9942
|
-
for (let i = hintIdx - 1; i >= windowStart; i--) {
|
|
9943
|
-
const t2 = lines[i].trim();
|
|
9944
|
-
if (!t2) continue;
|
|
9945
|
-
if (/^[─━═│┌┐└┘├┤┬┴┼]+$/u.test(t2)) continue;
|
|
9946
|
-
const m = t2.match(/^[❯>]\s+(\S.*)$/);
|
|
9947
|
-
if (!m) return null;
|
|
9948
|
-
if (/^\d+\.\s/.test(m[1])) return null;
|
|
9949
|
-
if (/^for\s/i.test(m[1])) return null;
|
|
9950
|
-
const text = m[1].trim();
|
|
9951
|
-
if (text.length === 0) return null;
|
|
9952
|
-
return text;
|
|
9953
|
-
}
|
|
9954
|
-
return null;
|
|
9955
|
-
}
|
|
9956
|
-
function detectListSelector(lines) {
|
|
9957
|
-
if (!lines.some((l) => /[↑↓].*navigate/i.test(l.trim()))) return null;
|
|
9958
|
-
if (lines.some((l) => /^❯\s*\d+\./.test(l.trim()))) return null;
|
|
9959
|
-
if (!lines.some((l) => /^\s+❯\s+\S/.test(l))) return null;
|
|
9960
|
-
const isSelected = (line) => /^\s+❯\s+\S/.test(line);
|
|
9961
|
-
const isUnselected = (line) => /^ \S/.test(line);
|
|
9962
|
-
const isItem = (line) => isSelected(line) || isUnselected(line);
|
|
9963
|
-
let optionStartIdx = -1;
|
|
9964
|
-
for (let i = 0; i < lines.length; i++) {
|
|
9965
|
-
if (isItem(lines[i])) {
|
|
9966
|
-
optionStartIdx = i;
|
|
9967
|
-
break;
|
|
9968
|
-
}
|
|
9969
|
-
}
|
|
9970
|
-
if (optionStartIdx === -1) return null;
|
|
9971
|
-
const questionParts = [];
|
|
9972
|
-
for (let i = 0; i < optionStartIdx; i++) {
|
|
9973
|
-
const t2 = lines[i].trim();
|
|
9974
|
-
if (!t2) continue;
|
|
9975
|
-
if (/^[─━—═\-]{3,}$/.test(t2)) continue;
|
|
9976
|
-
if (/[┌└│┐┘├┤┬┴┼]/.test(t2)) {
|
|
9977
|
-
const inner = t2.replace(/[│┌└┐┘├┤┬┴┼─]/g, "").trim();
|
|
9978
|
-
if (inner) questionParts.push(inner);
|
|
9979
|
-
continue;
|
|
9980
|
-
}
|
|
9981
|
-
if (/^[>❯]\s/.test(t2)) continue;
|
|
9982
|
-
if (/[↑↓].*navigate/i.test(t2)) continue;
|
|
9983
|
-
if (!t2.includes(" ") && t2.length > 15) continue;
|
|
9984
|
-
questionParts.push(t2);
|
|
9985
|
-
}
|
|
9986
|
-
const question = questionParts.filter((line, i, arr) => !arr.some((other, j2) => j2 !== i && other.includes(line))).join("\n").trim();
|
|
9987
|
-
const options = [];
|
|
9988
|
-
let currentIndex = 0;
|
|
9989
|
-
for (const line of lines.slice(optionStartIdx)) {
|
|
9990
|
-
const t2 = line.trim();
|
|
9991
|
-
if (!t2) continue;
|
|
9992
|
-
if (/[↑↓].*navigate/i.test(t2)) break;
|
|
9993
|
-
if (/^[─━—═\-]{3,}$/.test(t2)) continue;
|
|
9994
|
-
if (isSelected(line)) {
|
|
9995
|
-
currentIndex = options.length;
|
|
9996
|
-
options.push(t2.replace(/^❯\s+/, "").trim());
|
|
9997
|
-
} else if (isUnselected(line)) {
|
|
9998
|
-
options.push(t2);
|
|
9999
|
-
}
|
|
10000
|
-
}
|
|
10001
|
-
if (options.length < 2) return null;
|
|
10002
|
-
return {
|
|
10003
|
-
question,
|
|
10004
|
-
options,
|
|
10005
|
-
optionDescriptions: options.map(() => ""),
|
|
10006
|
-
currentIndex
|
|
10007
|
-
};
|
|
10008
|
-
}
|
|
10009
|
-
var BANNER_ART_RE = /[█▀▄▌▐▝▘▛▜▙▟▖▗▔▕▮▯▰▱▓▒░◆◇]/;
|
|
10010
|
-
var BANNER_META_RE = /(?:Sonnet|Opus|Haiku|Claude)(?:\s|·|-|\(|$)/i;
|
|
10011
|
-
function detectStartupBanner(lines) {
|
|
10012
|
-
for (let i = 0; i + 2 < lines.length; i++) {
|
|
10013
|
-
if (!/▐▛[█]+▜▌/.test(lines[i])) continue;
|
|
10014
|
-
if (!/▝▜[█]+▛▘/.test(lines[i + 1])) continue;
|
|
10015
|
-
if (!lines[i + 2].includes("\u2598\u2598")) continue;
|
|
10016
|
-
const inArtTitle = lines[i].replace(/^▐▛[█]+▜▌\s*/, "").trim();
|
|
10017
|
-
const inArtSubtitle = lines[i + 1].replace(/^▝▜[█]+▛▘\s*/, "").trim();
|
|
10018
|
-
const inArtPath = lines[i + 2].replace(/.*▝▝\s*/, "").trim();
|
|
10019
|
-
return {
|
|
10020
|
-
title: inArtTitle === lines[i].trim() ? "" : inArtTitle,
|
|
10021
|
-
subtitle: inArtSubtitle === lines[i + 1].trim() ? "" : inArtSubtitle,
|
|
10022
|
-
path: inArtPath === lines[i + 2].trim() ? "" : inArtPath,
|
|
10023
|
-
startIdx: i,
|
|
10024
|
-
endIdx: i + 2
|
|
10025
|
-
};
|
|
10026
|
-
}
|
|
10027
|
-
const metaIdx = lines.findIndex(
|
|
10028
|
-
(l) => BANNER_META_RE.test(l) && /(?:Claude|API|Console)/i.test(l) && !BANNER_ART_RE.test(l)
|
|
10029
|
-
);
|
|
10030
|
-
if (metaIdx === -1) return null;
|
|
10031
|
-
let artStart = metaIdx;
|
|
10032
|
-
while (artStart > 0 && BANNER_ART_RE.test(lines[artStart - 1])) artStart--;
|
|
10033
|
-
if (metaIdx - artStart < 2) return null;
|
|
10034
|
-
const pathLine = (lines[metaIdx + 1] ?? "").trim();
|
|
10035
|
-
const path55 = pathLine && !BANNER_ART_RE.test(pathLine) ? pathLine : "";
|
|
10036
|
-
return {
|
|
10037
|
-
title: "",
|
|
10038
|
-
subtitle: lines[metaIdx].trim(),
|
|
10039
|
-
path: path55,
|
|
10040
|
-
startIdx: artStart,
|
|
10041
|
-
endIdx: metaIdx + (path55 ? 1 : 0)
|
|
10042
|
-
};
|
|
10043
|
-
}
|
|
10044
|
-
|
|
10045
9751
|
// src/agents/claude/runtime.ts
|
|
10046
9752
|
var ClaudeRuntimeStrategy = class {
|
|
10047
9753
|
id = "claude";
|
|
@@ -10152,24 +9858,17 @@ var ClaudeRuntimeStrategy = class {
|
|
|
10152
9858
|
return { ptyInput: "/compact\r" };
|
|
10153
9859
|
}
|
|
10154
9860
|
// ─── TUI parser strategy methods ─────────────────────────────────
|
|
10155
|
-
|
|
10156
|
-
|
|
10157
|
-
|
|
10158
|
-
|
|
9861
|
+
// Claude runs ACP-only (see the `requiresAcp` dispatch in start.ts),
|
|
9862
|
+
// so the legacy PTY-spawn pipeline never reaches these. They remain
|
|
9863
|
+
// as inert stubs purely to satisfy the InteractiveAgentStrategy
|
|
9864
|
+
// contract; the React-Ink TUI parsers were removed with the PTY path.
|
|
9865
|
+
// The optional TUI hooks (parseTuiChrome / detectReadyPrompt /
|
|
9866
|
+
// detectStartupBanner / detectInputSuggestion) are dropped entirely.
|
|
10159
9867
|
filterTuiOutput(lines) {
|
|
10160
|
-
return
|
|
10161
|
-
}
|
|
10162
|
-
detectInteractivePrompt(lines) {
|
|
10163
|
-
return detectSelector(lines) ?? detectListSelector(lines);
|
|
10164
|
-
}
|
|
10165
|
-
detectReadyPrompt(lines) {
|
|
10166
|
-
return lines.some((l) => /^\?\s.*shortcut/i.test(l.trim()));
|
|
10167
|
-
}
|
|
10168
|
-
detectStartupBanner(lines) {
|
|
10169
|
-
return detectStartupBanner(lines);
|
|
9868
|
+
return lines;
|
|
10170
9869
|
}
|
|
10171
|
-
|
|
10172
|
-
return
|
|
9870
|
+
detectInteractivePrompt(_lines) {
|
|
9871
|
+
return null;
|
|
10173
9872
|
}
|
|
10174
9873
|
credentialLocator() {
|
|
10175
9874
|
return claudeCredentialLocator();
|
|
@@ -10603,410 +10302,6 @@ function getCurrentUsage2(historyDir) {
|
|
|
10603
10302
|
};
|
|
10604
10303
|
}
|
|
10605
10304
|
|
|
10606
|
-
// src/agents/codex/parsing.ts
|
|
10607
|
-
var BOX_DRAW_RE = /^[╭─╮│╰╯]/u;
|
|
10608
|
-
var BULLET_CHARS = "\u2022\xB7\u2027\u2219\u22C5";
|
|
10609
|
-
var CODEX_AGENT_REPLY_RE = new RegExp(`^[${BULLET_CHARS}]\\s`, "u");
|
|
10610
|
-
var STRIP_BULLET_RE = new RegExp(`^(\\s*)[${BULLET_CHARS}]\\s`, "u");
|
|
10611
|
-
var CODEX_USER_ECHO_RE = /^[›>]\s+(?!\d+\.\s)\S/u;
|
|
10612
|
-
var TIP_RE = /^\s*Tip:\s/i;
|
|
10613
|
-
var LEARN_MORE_RE = /^\s*Learn more:\s/i;
|
|
10614
|
-
var CODEX_STATUS_FOOTER_RE = /\bdefault\s+[·•]\s+\S+/i;
|
|
10615
|
-
var CODEAM_BANNER_RES = [
|
|
10616
|
-
// Bullet-prefixed banner entries (any role / launch label).
|
|
10617
|
-
new RegExp(`^[${BULLET_CHARS}]\\s+(Launching|Edgar|PRO|FREE|ENTERPRISE)\\b`, "i"),
|
|
10618
|
-
/^Paired\b/,
|
|
10619
|
-
/^codeam\b\s+v\d/,
|
|
10620
|
-
/^✓\s+Paired/,
|
|
10621
|
-
/^◇\s+Paired/
|
|
10622
|
-
];
|
|
10623
|
-
function filterCodexChrome(lines) {
|
|
10624
|
-
const out2 = [];
|
|
10625
|
-
for (const line of lines) {
|
|
10626
|
-
const t2 = line.trimEnd();
|
|
10627
|
-
const trimmed = t2.trimStart();
|
|
10628
|
-
if (!trimmed) continue;
|
|
10629
|
-
if (BOX_DRAW_RE.test(trimmed)) continue;
|
|
10630
|
-
if (/^OpenAI Codex\b/i.test(trimmed) || /^>_\s+OpenAI Codex\b/i.test(trimmed) || /^model:\s/i.test(trimmed) || /^directory:\s/i.test(trimmed)) continue;
|
|
10631
|
-
if (TIP_RE.test(t2) || LEARN_MORE_RE.test(t2)) continue;
|
|
10632
|
-
if (CODEX_STATUS_FOOTER_RE.test(trimmed)) continue;
|
|
10633
|
-
if (CODEAM_BANNER_RES.some((re2) => re2.test(trimmed))) continue;
|
|
10634
|
-
if (CODEX_USER_ECHO_RE.test(trimmed)) continue;
|
|
10635
|
-
if (CODEX_AGENT_REPLY_RE.test(trimmed)) {
|
|
10636
|
-
out2.push(t2.replace(STRIP_BULLET_RE, "$1"));
|
|
10637
|
-
continue;
|
|
10638
|
-
}
|
|
10639
|
-
out2.push(t2);
|
|
10640
|
-
}
|
|
10641
|
-
const dedented = dedentCodexStructuredLines(out2);
|
|
10642
|
-
const wrapped = wrapCodexCodeBlocks(dedented);
|
|
10643
|
-
const hasRealInput = lines.some((l) => /\w/.test(l));
|
|
10644
|
-
if (out2.length > 0 || hasRealInput) {
|
|
10645
|
-
const sampleIn = lines.slice(-50).map((l, i) => ` in[${i}] ${JSON.stringify(l)}`).join("\n");
|
|
10646
|
-
const sampleOut = dedented.map((l, i) => ` out[${i}] ${JSON.stringify(l)}`).join("\n");
|
|
10647
|
-
log.info("codex-parse", `in=${lines.length} out=${dedented.length}
|
|
10648
|
-
${sampleIn}
|
|
10649
|
-
---
|
|
10650
|
-
${sampleOut}`);
|
|
10651
|
-
} else {
|
|
10652
|
-
log.trace("codex-parse", `filterCodexChrome in=${lines.length} out=${out2.length}`);
|
|
10653
|
-
}
|
|
10654
|
-
return wrapped;
|
|
10655
|
-
}
|
|
10656
|
-
var CODE_CHAR_RE = /[;{}]|=>|^\s*(?:import|public|private|static|class|function|interface|type|const|let|var|def|return|if|else|for|while)\b/;
|
|
10657
|
-
var DIFF_HUNK_RE = /^@@\s+-\d+(?:,\d+)?\s+\+\d+(?:,\d+)?\s+@@/;
|
|
10658
|
-
var DIFF_GIT_RE = /^diff\s+--git\s+/;
|
|
10659
|
-
var DIFF_OLD_RE = /^---\s+(?:a\/)?\S/;
|
|
10660
|
-
var DIFF_NEW_RE = /^\+\+\+\s+(?:b\/)?\S/;
|
|
10661
|
-
var COMMIT_HEAD_RE = /^\[[\w./@-]+\s+[0-9a-f]{7,40}\]\s+/;
|
|
10662
|
-
var COMMIT_STATS_RE = /\d+\s+files?\s+changed/;
|
|
10663
|
-
var PUSH_TO_RE = /^To\s+(?:https?:\/\/|git@)/;
|
|
10664
|
-
var PUSH_NEW_RE = /\[new branch\]\s+\S+\s*->\s*\S+/;
|
|
10665
|
-
var PUSH_UPDATE_RE = /^\s*[0-9a-f]{7,40}\.\.[0-9a-f]{7,40}\s+\S+\s*->\s*\S+/;
|
|
10666
|
-
var MERGE_UPD_RE = /^Updating\s+[0-9a-f]{7,40}\.\.[0-9a-f]{7,40}/;
|
|
10667
|
-
var MERGE_FF_RE = /^Fast-forward\s*$/;
|
|
10668
|
-
var PR_TITLE_RE = /^title:\s+\S/;
|
|
10669
|
-
var PR_STATE_RE = /^state:\s+(?:OPEN|CLOSED|MERGED|DRAFT)/i;
|
|
10670
|
-
var PR_URL_RE = /https?:\/\/github\.com\/[\w.-]+\/[\w.-]+\/pull\/\d+/;
|
|
10671
|
-
var PR_BANNER_RE = /^\s*[✓✔]?\s*Pull request created\s*$/i;
|
|
10672
|
-
function dedentCodexStructuredLines(lines) {
|
|
10673
|
-
const MARKER_RE = /^( +)(?:diff --git |@@ |--- |\+\+\+ |Updating [0-9a-f]|Fast-forward|Merge made by |To (?:https?:\/\/|git@|github\.com|[\w.-]+[:/])|From (?:https?:\/\/|git@|github\.com|[\w.-]+[:/])|\[[\w./@-]+\s+[0-9a-f]{7,40}\])/;
|
|
10674
|
-
let margin = -1;
|
|
10675
|
-
for (const line of lines) {
|
|
10676
|
-
const m = line.match(MARKER_RE);
|
|
10677
|
-
if (m) {
|
|
10678
|
-
const w3 = m[1].length;
|
|
10679
|
-
if (margin === -1 || w3 < margin) margin = w3;
|
|
10680
|
-
}
|
|
10681
|
-
}
|
|
10682
|
-
if (margin <= 0) return lines;
|
|
10683
|
-
return lines.map((line) => {
|
|
10684
|
-
if (line.length === 0) return line;
|
|
10685
|
-
const lead = line.match(/^ */)?.[0].length ?? 0;
|
|
10686
|
-
const strip = Math.min(margin, lead);
|
|
10687
|
-
return strip > 0 ? line.slice(strip) : line;
|
|
10688
|
-
});
|
|
10689
|
-
}
|
|
10690
|
-
function isStructuredBlock(block) {
|
|
10691
|
-
if (block.some((l) => DIFF_HUNK_RE.test(l))) return true;
|
|
10692
|
-
if (block.some((l) => DIFF_GIT_RE.test(l))) return true;
|
|
10693
|
-
if (block.some((l) => DIFF_OLD_RE.test(l)) && block.some((l) => DIFF_NEW_RE.test(l))) return true;
|
|
10694
|
-
if (block.some((l) => COMMIT_HEAD_RE.test(l))) return true;
|
|
10695
|
-
if (block.some((l) => COMMIT_STATS_RE.test(l))) return true;
|
|
10696
|
-
if (block.some((l) => PUSH_TO_RE.test(l))) return true;
|
|
10697
|
-
if (block.some((l) => PUSH_NEW_RE.test(l))) return true;
|
|
10698
|
-
if (block.some((l) => PUSH_UPDATE_RE.test(l))) return true;
|
|
10699
|
-
if (block.some((l) => MERGE_UPD_RE.test(l))) return true;
|
|
10700
|
-
if (block.some((l) => MERGE_FF_RE.test(l))) return true;
|
|
10701
|
-
if (block.some((l) => PR_TITLE_RE.test(l)) && block.some((l) => PR_STATE_RE.test(l))) return true;
|
|
10702
|
-
if (block.some((l) => PR_URL_RE.test(l))) return true;
|
|
10703
|
-
if (block.some((l) => PR_BANNER_RE.test(l))) return true;
|
|
10704
|
-
return false;
|
|
10705
|
-
}
|
|
10706
|
-
function inferLanguage(block) {
|
|
10707
|
-
const head = block.slice(0, 10).join("\n");
|
|
10708
|
-
if (/\bpublic\s+(?:static\s+)?(?:class|void|int|String)\b|System\.out\.println|\bjava\.util/.test(head)) return "java";
|
|
10709
|
-
if (/\b(?:interface|type)\s+\w+\s*=?\s*[{<]|\bas\s+(?:string|number|boolean)\b|\b(?:string|number|boolean)\s*[;,)\]]/.test(head)) return "typescript";
|
|
10710
|
-
if (/\bimport\s+\w+\s+from\s+['"]|=>\s*[{(]|\bconst\s+\w+\s*=\s*(?:async\s+)?\(/.test(head)) return "javascript";
|
|
10711
|
-
if (/^\s*def\s+\w+\(|^\s*from\s+\w+\s+import|print\(/m.test(head)) return "python";
|
|
10712
|
-
if (/^\s*package\s+\w+|^\s*func\s+\w+\(|\binterface\s*{/m.test(head)) return "go";
|
|
10713
|
-
if (/^\s*fn\s+\w+\(|^\s*use\s+\w+::|^\s*impl\s+/m.test(head)) return "rust";
|
|
10714
|
-
if (/#include\s*<|int\s+main\s*\(/.test(head)) return "cpp";
|
|
10715
|
-
return "";
|
|
10716
|
-
}
|
|
10717
|
-
function wrapCodexCodeBlocks(lines) {
|
|
10718
|
-
if (isStructuredBlock(lines)) {
|
|
10719
|
-
return lines;
|
|
10720
|
-
}
|
|
10721
|
-
const result = [];
|
|
10722
|
-
let i = 0;
|
|
10723
|
-
while (i < lines.length) {
|
|
10724
|
-
const line = lines[i];
|
|
10725
|
-
if (!CODE_CHAR_RE.test(line)) {
|
|
10726
|
-
result.push(line);
|
|
10727
|
-
i++;
|
|
10728
|
-
continue;
|
|
10729
|
-
}
|
|
10730
|
-
const start2 = i;
|
|
10731
|
-
let end = i;
|
|
10732
|
-
let j2 = i + 1;
|
|
10733
|
-
while (j2 < lines.length) {
|
|
10734
|
-
const l = lines[j2];
|
|
10735
|
-
if (CODE_CHAR_RE.test(l)) {
|
|
10736
|
-
end = j2;
|
|
10737
|
-
j2++;
|
|
10738
|
-
continue;
|
|
10739
|
-
}
|
|
10740
|
-
if (l.trim() === "") {
|
|
10741
|
-
let k2 = j2 + 1;
|
|
10742
|
-
while (k2 < lines.length && lines[k2].trim() === "") k2++;
|
|
10743
|
-
if (k2 < lines.length && CODE_CHAR_RE.test(lines[k2])) {
|
|
10744
|
-
end = k2;
|
|
10745
|
-
j2 = k2 + 1;
|
|
10746
|
-
continue;
|
|
10747
|
-
}
|
|
10748
|
-
break;
|
|
10749
|
-
}
|
|
10750
|
-
if (/^\s{2,}\S/.test(l)) {
|
|
10751
|
-
end = j2;
|
|
10752
|
-
j2++;
|
|
10753
|
-
continue;
|
|
10754
|
-
}
|
|
10755
|
-
break;
|
|
10756
|
-
}
|
|
10757
|
-
const runLen = end - start2 + 1;
|
|
10758
|
-
const body = lines.slice(start2, end + 1);
|
|
10759
|
-
if (isStructuredBlock(body)) {
|
|
10760
|
-
for (const l of body) result.push(l);
|
|
10761
|
-
i = end + 1;
|
|
10762
|
-
continue;
|
|
10763
|
-
}
|
|
10764
|
-
const codeShapedCount = body.filter((l) => CODE_CHAR_RE.test(l)).length;
|
|
10765
|
-
if (codeShapedCount >= 3) {
|
|
10766
|
-
const lang = inferLanguage(body);
|
|
10767
|
-
result.push("```" + lang);
|
|
10768
|
-
for (const l of body) result.push(l);
|
|
10769
|
-
while (result.length > 0 && result[result.length - 1].trim() === "") {
|
|
10770
|
-
result.pop();
|
|
10771
|
-
}
|
|
10772
|
-
result.push("```");
|
|
10773
|
-
i = end + 1;
|
|
10774
|
-
} else {
|
|
10775
|
-
for (let k2 = start2; k2 <= end && k2 < lines.length; k2++) result.push(lines[k2]);
|
|
10776
|
-
i = end + 1;
|
|
10777
|
-
if (i === start2) i++;
|
|
10778
|
-
}
|
|
10779
|
-
void runLen;
|
|
10780
|
-
}
|
|
10781
|
-
return result;
|
|
10782
|
-
}
|
|
10783
|
-
function parseCodexChrome(_line) {
|
|
10784
|
-
return null;
|
|
10785
|
-
}
|
|
10786
|
-
var CODEX_OPTION_RE = /^\s*([>›]\s+)?(\d+)\.\s+(.+)/;
|
|
10787
|
-
var CODEX_OPTION_START_RE = /^\s*(?:[>›]\s+)?\d+\.\s/;
|
|
10788
|
-
var CODEX_FOOTER_RE = /\bpress\s+enter\s+to\s+(?:confirm|continue|select)\b/i;
|
|
10789
|
-
function detectCodexSelector(lines) {
|
|
10790
|
-
let optionStartIdx = -1;
|
|
10791
|
-
for (let i = 0; i < lines.length; i++) {
|
|
10792
|
-
if (CODEX_OPTION_START_RE.test(lines[i])) {
|
|
10793
|
-
optionStartIdx = i;
|
|
10794
|
-
break;
|
|
10795
|
-
}
|
|
10796
|
-
}
|
|
10797
|
-
if (optionStartIdx === -1) return null;
|
|
10798
|
-
const optionLabels = /* @__PURE__ */ new Map();
|
|
10799
|
-
let cursorIndex = 0;
|
|
10800
|
-
let hasCursor = false;
|
|
10801
|
-
let footerAfterOptions = false;
|
|
10802
|
-
let lastOptionLineIdx = optionStartIdx;
|
|
10803
|
-
for (let i = optionStartIdx; i < lines.length; i++) {
|
|
10804
|
-
const raw = lines[i];
|
|
10805
|
-
const t2 = raw.trim();
|
|
10806
|
-
if (!t2) continue;
|
|
10807
|
-
if (CODEX_FOOTER_RE.test(t2)) {
|
|
10808
|
-
footerAfterOptions = true;
|
|
10809
|
-
break;
|
|
10810
|
-
}
|
|
10811
|
-
const m = t2.match(CODEX_OPTION_RE);
|
|
10812
|
-
if (!m) {
|
|
10813
|
-
if (i - lastOptionLineIdx > 2) break;
|
|
10814
|
-
continue;
|
|
10815
|
-
}
|
|
10816
|
-
const num = parseInt(m[2], 10);
|
|
10817
|
-
if (!optionLabels.has(num)) {
|
|
10818
|
-
optionLabels.set(num, m[3].trim());
|
|
10819
|
-
if (m[1]) {
|
|
10820
|
-
cursorIndex = optionLabels.size - 1;
|
|
10821
|
-
hasCursor = true;
|
|
10822
|
-
}
|
|
10823
|
-
}
|
|
10824
|
-
lastOptionLineIdx = i;
|
|
10825
|
-
}
|
|
10826
|
-
const keys = [...optionLabels.keys()].sort((a, b) => a - b);
|
|
10827
|
-
if (keys.length < 2 || keys[0] !== 1) return null;
|
|
10828
|
-
const questionParts = [];
|
|
10829
|
-
for (let i = 0; i < optionStartIdx; i++) {
|
|
10830
|
-
const t2 = lines[i].trim();
|
|
10831
|
-
if (!t2) continue;
|
|
10832
|
-
if (/^[>›]\s*$/.test(t2)) continue;
|
|
10833
|
-
questionParts.push(t2);
|
|
10834
|
-
}
|
|
10835
|
-
const question = questionParts.join("\n").trim();
|
|
10836
|
-
const questionEndsWithQuery = /\?\s*$/.test(question);
|
|
10837
|
-
if (!hasCursor && !(questionEndsWithQuery && footerAfterOptions)) {
|
|
10838
|
-
return null;
|
|
10839
|
-
}
|
|
10840
|
-
return {
|
|
10841
|
-
question,
|
|
10842
|
-
options: keys.map((k2) => optionLabels.get(k2)),
|
|
10843
|
-
optionDescriptions: keys.map(() => ""),
|
|
10844
|
-
currentIndex: hasCursor ? cursorIndex : 0
|
|
10845
|
-
};
|
|
10846
|
-
}
|
|
10847
|
-
|
|
10848
|
-
// src/agents/codex/renderer.ts
|
|
10849
|
-
function renderCodexBuffer(raw) {
|
|
10850
|
-
const scrollback = [];
|
|
10851
|
-
const screen = [""];
|
|
10852
|
-
let row = 0;
|
|
10853
|
-
let col = 0;
|
|
10854
|
-
let scrollTop = null;
|
|
10855
|
-
let scrollBottom = null;
|
|
10856
|
-
function ensureRow() {
|
|
10857
|
-
while (screen.length <= row) screen.push("");
|
|
10858
|
-
}
|
|
10859
|
-
function writeChar(ch) {
|
|
10860
|
-
ensureRow();
|
|
10861
|
-
if (col < screen[row].length) {
|
|
10862
|
-
screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);
|
|
10863
|
-
} else {
|
|
10864
|
-
while (screen[row].length < col) screen[row] += " ";
|
|
10865
|
-
screen[row] += ch;
|
|
10866
|
-
}
|
|
10867
|
-
col++;
|
|
10868
|
-
}
|
|
10869
|
-
function scrollRegionUp() {
|
|
10870
|
-
if (scrollTop === null || scrollBottom === null) {
|
|
10871
|
-
ensureRow();
|
|
10872
|
-
return;
|
|
10873
|
-
}
|
|
10874
|
-
while (screen.length <= scrollBottom) screen.push("");
|
|
10875
|
-
if (screen[scrollTop].trim() !== "") {
|
|
10876
|
-
scrollback.push(screen[scrollTop]);
|
|
10877
|
-
}
|
|
10878
|
-
for (let r = scrollTop; r < scrollBottom; r++) {
|
|
10879
|
-
screen[r] = screen[r + 1];
|
|
10880
|
-
}
|
|
10881
|
-
screen[scrollBottom] = "";
|
|
10882
|
-
}
|
|
10883
|
-
function scrollRegionDown() {
|
|
10884
|
-
if (scrollTop === null || scrollBottom === null) {
|
|
10885
|
-
return;
|
|
10886
|
-
}
|
|
10887
|
-
while (screen.length <= scrollBottom) screen.push("");
|
|
10888
|
-
if (screen[scrollBottom].trim() !== "") {
|
|
10889
|
-
scrollback.push(screen[scrollBottom]);
|
|
10890
|
-
}
|
|
10891
|
-
for (let r = scrollBottom; r > scrollTop; r--) {
|
|
10892
|
-
screen[r] = screen[r - 1];
|
|
10893
|
-
}
|
|
10894
|
-
screen[scrollTop] = "";
|
|
10895
|
-
}
|
|
10896
|
-
let i = 0;
|
|
10897
|
-
while (i < raw.length) {
|
|
10898
|
-
const ch = raw[i];
|
|
10899
|
-
if (ch === "\x1B") {
|
|
10900
|
-
i++;
|
|
10901
|
-
if (i >= raw.length) break;
|
|
10902
|
-
if (raw[i] === "[") {
|
|
10903
|
-
i++;
|
|
10904
|
-
let param = "";
|
|
10905
|
-
while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];
|
|
10906
|
-
const cmd = raw[i] ?? "";
|
|
10907
|
-
const n = parseInt(param) || 1;
|
|
10908
|
-
if (cmd === "A") {
|
|
10909
|
-
row = Math.max(0, row - n);
|
|
10910
|
-
} else if (cmd === "B") {
|
|
10911
|
-
row += n;
|
|
10912
|
-
ensureRow();
|
|
10913
|
-
} else if (cmd === "C") {
|
|
10914
|
-
col += n;
|
|
10915
|
-
} else if (cmd === "D") {
|
|
10916
|
-
col = Math.max(0, col - n);
|
|
10917
|
-
} else if (cmd === "G") {
|
|
10918
|
-
col = Math.max(0, n - 1);
|
|
10919
|
-
} else if (cmd === "H" || cmd === "f") {
|
|
10920
|
-
const p2 = param.split(";");
|
|
10921
|
-
row = Math.max(0, (parseInt(p2[0] ?? "1") || 1) - 1);
|
|
10922
|
-
col = Math.max(0, (parseInt(p2[1] ?? "1") || 1) - 1);
|
|
10923
|
-
ensureRow();
|
|
10924
|
-
} else if (cmd === "J") {
|
|
10925
|
-
if (param === "2" || param === "3") {
|
|
10926
|
-
for (let r = 0; r < screen.length; r++) {
|
|
10927
|
-
if (screen[r].trim() !== "") scrollback.push(screen[r]);
|
|
10928
|
-
}
|
|
10929
|
-
screen.length = 1;
|
|
10930
|
-
screen[0] = "";
|
|
10931
|
-
row = 0;
|
|
10932
|
-
col = 0;
|
|
10933
|
-
} else if (param === "1") {
|
|
10934
|
-
for (let r = 0; r < row; r++) screen[r] = "";
|
|
10935
|
-
screen[row] = " ".repeat(col) + screen[row].slice(col);
|
|
10936
|
-
} else {
|
|
10937
|
-
screen[row] = screen[row].slice(0, col);
|
|
10938
|
-
screen.splice(row + 1);
|
|
10939
|
-
}
|
|
10940
|
-
} else if (cmd === "K") {
|
|
10941
|
-
ensureRow();
|
|
10942
|
-
if (param === "" || param === "0") screen[row] = screen[row].slice(0, col);
|
|
10943
|
-
else if (param === "1") screen[row] = " ".repeat(col) + screen[row].slice(col);
|
|
10944
|
-
else if (param === "2") screen[row] = "";
|
|
10945
|
-
} else if (cmd === "r") {
|
|
10946
|
-
if (param === "" || param === ";") {
|
|
10947
|
-
scrollTop = null;
|
|
10948
|
-
scrollBottom = null;
|
|
10949
|
-
} else {
|
|
10950
|
-
const p2 = param.split(";");
|
|
10951
|
-
const top = parseInt(p2[0] ?? "1") || 1;
|
|
10952
|
-
const bot = parseInt(p2[1] ?? "1") || 1;
|
|
10953
|
-
scrollTop = Math.max(0, top - 1);
|
|
10954
|
-
scrollBottom = Math.max(scrollTop, bot - 1);
|
|
10955
|
-
}
|
|
10956
|
-
}
|
|
10957
|
-
} else if (raw[i] === "]") {
|
|
10958
|
-
i++;
|
|
10959
|
-
while (i < raw.length) {
|
|
10960
|
-
if (raw[i] === "\x07") break;
|
|
10961
|
-
if (raw[i] === "\x1B" && i + 1 < raw.length && raw[i + 1] === "\\") {
|
|
10962
|
-
i++;
|
|
10963
|
-
break;
|
|
10964
|
-
}
|
|
10965
|
-
i++;
|
|
10966
|
-
}
|
|
10967
|
-
} else if (raw[i] === "M") {
|
|
10968
|
-
if (scrollTop !== null && row === scrollTop) {
|
|
10969
|
-
scrollRegionDown();
|
|
10970
|
-
} else {
|
|
10971
|
-
row = Math.max(0, row - 1);
|
|
10972
|
-
}
|
|
10973
|
-
} else if (raw[i] === "D") {
|
|
10974
|
-
if (scrollBottom !== null && row === scrollBottom) {
|
|
10975
|
-
scrollRegionUp();
|
|
10976
|
-
} else {
|
|
10977
|
-
row++;
|
|
10978
|
-
ensureRow();
|
|
10979
|
-
}
|
|
10980
|
-
}
|
|
10981
|
-
} else if (ch === "\r") {
|
|
10982
|
-
if (i + 1 < raw.length && raw[i + 1] === "\n") {
|
|
10983
|
-
if (scrollBottom !== null && row === scrollBottom) {
|
|
10984
|
-
scrollRegionUp();
|
|
10985
|
-
} else {
|
|
10986
|
-
row++;
|
|
10987
|
-
ensureRow();
|
|
10988
|
-
}
|
|
10989
|
-
col = 0;
|
|
10990
|
-
i++;
|
|
10991
|
-
} else {
|
|
10992
|
-
col = 0;
|
|
10993
|
-
}
|
|
10994
|
-
} else if (ch === "\n") {
|
|
10995
|
-
if (scrollBottom !== null && row === scrollBottom) {
|
|
10996
|
-
scrollRegionUp();
|
|
10997
|
-
} else {
|
|
10998
|
-
row++;
|
|
10999
|
-
ensureRow();
|
|
11000
|
-
}
|
|
11001
|
-
col = 0;
|
|
11002
|
-
} else if (ch >= " " || ch === " ") {
|
|
11003
|
-
writeChar(ch);
|
|
11004
|
-
}
|
|
11005
|
-
i++;
|
|
11006
|
-
}
|
|
11007
|
-
return [...scrollback, ...screen];
|
|
11008
|
-
}
|
|
11009
|
-
|
|
11010
10305
|
// src/agents/codex/link.ts
|
|
11011
10306
|
var import_node_child_process3 = require("child_process");
|
|
11012
10307
|
|
|
@@ -11172,27 +10467,17 @@ var CodexRuntimeStrategy = class {
|
|
|
11172
10467
|
return { ptyInput: "/compact\r" };
|
|
11173
10468
|
}
|
|
11174
10469
|
// ─── TUI parser strategy methods ─────────────────────────────────
|
|
11175
|
-
|
|
11176
|
-
|
|
11177
|
-
|
|
11178
|
-
|
|
11179
|
-
|
|
11180
|
-
|
|
11181
|
-
*/
|
|
11182
|
-
renderToLines(buffer) {
|
|
11183
|
-
return renderCodexBuffer(buffer);
|
|
11184
|
-
}
|
|
11185
|
-
parseTuiChrome(line) {
|
|
11186
|
-
return parseCodexChrome(line);
|
|
11187
|
-
}
|
|
10470
|
+
// Codex runs ACP-only (see the `requiresAcp` dispatch in start.ts);
|
|
10471
|
+
// the legacy PTY-spawn pipeline never reaches these. Inert stubs to
|
|
10472
|
+
// satisfy the InteractiveAgentStrategy contract — the Codex ratatui
|
|
10473
|
+
// parsers + scroll-region renderer were removed with the PTY path.
|
|
10474
|
+
// The optional TUI hooks (renderToLines / parseTuiChrome /
|
|
10475
|
+
// detectReadyPrompt) are dropped entirely.
|
|
11188
10476
|
filterTuiOutput(lines) {
|
|
11189
|
-
return
|
|
11190
|
-
}
|
|
11191
|
-
detectInteractivePrompt(lines) {
|
|
11192
|
-
return detectCodexSelector(lines);
|
|
10477
|
+
return lines;
|
|
11193
10478
|
}
|
|
11194
|
-
|
|
11195
|
-
return
|
|
10479
|
+
detectInteractivePrompt(_lines) {
|
|
10480
|
+
return null;
|
|
11196
10481
|
}
|
|
11197
10482
|
credentialLocator() {
|
|
11198
10483
|
return codexCredentialLocator();
|
|
@@ -11977,7 +11262,7 @@ var GeminiRuntimeStrategy = class {
|
|
|
11977
11262
|
const binary = this.os.findInPath("gemini");
|
|
11978
11263
|
if (!binary) {
|
|
11979
11264
|
throw new Error(
|
|
11980
|
-
"Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again
|
|
11265
|
+
"Gemini CLI is not on PATH. Install it with:\n npm install -g @google/gemini-cli\n Then run `codeam pair` again."
|
|
11981
11266
|
);
|
|
11982
11267
|
}
|
|
11983
11268
|
return this.os.buildLaunch(binary);
|
|
@@ -12018,11 +11303,10 @@ var GeminiRuntimeStrategy = class {
|
|
|
12018
11303
|
return { ptyInput: "/compress\r" };
|
|
12019
11304
|
}
|
|
12020
11305
|
/**
|
|
12021
|
-
* Pass-through filter. Gemini
|
|
12022
|
-
*
|
|
12023
|
-
*
|
|
12024
|
-
*
|
|
12025
|
-
* showing whatever the REPL prints.
|
|
11306
|
+
* Pass-through filter. Gemini runs over ACP, so this is never hit
|
|
11307
|
+
* in production — it exists only to satisfy the contract's
|
|
11308
|
+
* idempotency assertion. Returning the input verbatim keeps the
|
|
11309
|
+
* stub trivially idempotent.
|
|
12026
11310
|
*/
|
|
12027
11311
|
filterTuiOutput(lines) {
|
|
12028
11312
|
return lines;
|
|
@@ -12172,8 +11456,8 @@ var REGISTRY = {
|
|
|
12172
11456
|
// },
|
|
12173
11457
|
//
|
|
12174
11458
|
// Until then `getAcpAdapter('cursor')` returns null and the dispatch
|
|
12175
|
-
// in start.ts
|
|
12176
|
-
// cursor users had before ACP was added.
|
|
11459
|
+
// in start.ts runs cursor over the legacy PTY runtime — same
|
|
11460
|
+
// behaviour cursor users had before ACP was added.
|
|
12177
11461
|
// Gemini speaks ACP natively via `gemini --acp` — no npm adapter
|
|
12178
11462
|
// package, just the user-installed `gemini` binary on PATH. Same
|
|
12179
11463
|
// {@link AdapterSpec} shape; the only difference is `command` is
|
|
@@ -12196,6 +11480,9 @@ function getAcpAdapter(agent) {
|
|
|
12196
11480
|
const factory = REGISTRY[agent];
|
|
12197
11481
|
return factory ? factory() : null;
|
|
12198
11482
|
}
|
|
11483
|
+
function requiresAcp(agent) {
|
|
11484
|
+
return getAcpAdapter(agent) !== null;
|
|
11485
|
+
}
|
|
12199
11486
|
|
|
12200
11487
|
// src/agents/acp/runner.ts
|
|
12201
11488
|
var import_node_crypto7 = require("crypto");
|
|
@@ -24041,28 +23328,28 @@ async function start(requestedAgent) {
|
|
|
24041
23328
|
`agent-spawn gate released \u2014 beads ${beads ? "ready" : "pending"}; project deps provisioned`
|
|
24042
23329
|
);
|
|
24043
23330
|
}
|
|
24044
|
-
|
|
24045
|
-
if (!acpDisabled && session.pluginAuthToken) {
|
|
23331
|
+
if (requiresAcp(session.agent)) {
|
|
24046
23332
|
const adapter = getAcpAdapter(session.agent);
|
|
24047
|
-
if (adapter) {
|
|
24048
|
-
|
|
24049
|
-
agent
|
|
24050
|
-
|
|
24051
|
-
|
|
24052
|
-
pluginAuthToken: session.pluginAuthToken,
|
|
24053
|
-
adapter,
|
|
24054
|
-
cwd,
|
|
24055
|
-
getBeads,
|
|
24056
|
-
// AUTO mode in a headless GitHub Codespace: no human at the phone to
|
|
24057
|
-
// answer permission prompts, so auto-approve them rather than stall the
|
|
24058
|
-
// turn (the agent-agnostic equivalent of --dangerously-skip-permissions).
|
|
24059
|
-
autoApprovePermissions: process.env.CODESPACES === "true"
|
|
24060
|
-
});
|
|
24061
|
-
return;
|
|
23333
|
+
if (!adapter || !session.pluginAuthToken) {
|
|
23334
|
+
showError(
|
|
23335
|
+
`${AGENT_REGISTRY[session.agent].displayName} requires a paired session with an auth token. Re-pair with \`codeam pair\` to continue.`
|
|
23336
|
+
);
|
|
23337
|
+
process.exit(1);
|
|
24062
23338
|
}
|
|
24063
|
-
|
|
24064
|
-
|
|
24065
|
-
|
|
23339
|
+
await runAcpSession({
|
|
23340
|
+
agent: session.agent,
|
|
23341
|
+
sessionId: session.id,
|
|
23342
|
+
pluginId,
|
|
23343
|
+
pluginAuthToken: session.pluginAuthToken,
|
|
23344
|
+
adapter,
|
|
23345
|
+
cwd,
|
|
23346
|
+
getBeads,
|
|
23347
|
+
// AUTO mode in a headless GitHub Codespace: no human at the phone to
|
|
23348
|
+
// answer permission prompts, so auto-approve them rather than stall the
|
|
23349
|
+
// turn (the agent-agnostic equivalent of --dangerously-skip-permissions).
|
|
23350
|
+
autoApprovePermissions: process.env.CODESPACES === "true"
|
|
23351
|
+
});
|
|
23352
|
+
return;
|
|
24066
23353
|
}
|
|
24067
23354
|
const runtime = createRuntimeStrategy(session.agent);
|
|
24068
23355
|
const historySvc = new HistoryService(runtime, pluginId, cwd, {
|
|
@@ -27069,7 +26356,7 @@ function checkChokidar() {
|
|
|
27069
26356
|
}
|
|
27070
26357
|
async function doctor(args2 = []) {
|
|
27071
26358
|
const json = args2.includes("--json");
|
|
27072
|
-
const cliVersion = true ? "2.39.
|
|
26359
|
+
const cliVersion = true ? "2.39.24" : "0.0.0-dev";
|
|
27073
26360
|
const apiBase = resolveApiBaseUrl();
|
|
27074
26361
|
const diagnosticId = (0, import_node_crypto8.randomUUID)();
|
|
27075
26362
|
log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
|
|
@@ -27268,7 +26555,7 @@ async function completion(args2) {
|
|
|
27268
26555
|
// src/commands/version.ts
|
|
27269
26556
|
var import_picocolors13 = __toESM(require("picocolors"));
|
|
27270
26557
|
function version2() {
|
|
27271
|
-
const v = true ? "2.39.
|
|
26558
|
+
const v = true ? "2.39.24" : "unknown";
|
|
27272
26559
|
console.log(`${import_picocolors13.default.bold("codeam-cli")} ${import_picocolors13.default.cyan(v)}`);
|
|
27273
26560
|
}
|
|
27274
26561
|
|
|
@@ -27554,7 +26841,7 @@ function checkForUpdates() {
|
|
|
27554
26841
|
if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
|
|
27555
26842
|
if (process.env.CI) return;
|
|
27556
26843
|
if (!process.stdout.isTTY) return;
|
|
27557
|
-
const current = true ? "2.39.
|
|
26844
|
+
const current = true ? "2.39.24" : null;
|
|
27558
26845
|
if (!current) return;
|
|
27559
26846
|
const cache = readCache();
|
|
27560
26847
|
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.39.
|
|
3
|
+
"version": "2.39.24",
|
|
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",
|