open-agents-ai 0.29.0 → 0.30.0
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 +235 -75
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -18728,7 +18728,7 @@ function themeForTool(toolName) {
|
|
|
18728
18728
|
return THEME_DEFAULT;
|
|
18729
18729
|
}
|
|
18730
18730
|
}
|
|
18731
|
-
var DENSITY, WAVE, THEME_DEFAULT, THEME_FILE, THEME_SHELL, THEME_WEB, THEME_SEARCH, THEME_MEMORY, THEME_SKILL, THEME_TOOL_CREATE, BrailleSpinner;
|
|
18731
|
+
var DENSITY, WAVE, THEME_DEFAULT, THEME_FILE, THEME_SHELL, THEME_WEB, THEME_SEARCH, THEME_MEMORY, THEME_SKILL, THEME_TOOL_CREATE, DEFAULT_METRICS, BrailleSpinner;
|
|
18732
18732
|
var init_braille_spinner = __esm({
|
|
18733
18733
|
"packages/cli/dist/tui/braille-spinner.js"() {
|
|
18734
18734
|
"use strict";
|
|
@@ -18785,11 +18785,17 @@ var init_braille_spinner = __esm({
|
|
|
18785
18785
|
ramp: [237, 173, 174, 179, 180, 215, 216, 222, 229],
|
|
18786
18786
|
speed: 2
|
|
18787
18787
|
};
|
|
18788
|
+
DEFAULT_METRICS = {
|
|
18789
|
+
contextPct: 0,
|
|
18790
|
+
tokenRate: 0,
|
|
18791
|
+
isStreaming: false
|
|
18792
|
+
};
|
|
18788
18793
|
BrailleSpinner = class {
|
|
18789
18794
|
frame = 0;
|
|
18790
18795
|
timer = null;
|
|
18791
18796
|
theme = THEME_DEFAULT;
|
|
18792
18797
|
colorRamp = buildColorRamp(THEME_DEFAULT.ramp);
|
|
18798
|
+
_metrics = { ...DEFAULT_METRICS };
|
|
18793
18799
|
/** Start the animation, calling `onFrame` every tick (~80 ms). */
|
|
18794
18800
|
start(onFrame) {
|
|
18795
18801
|
this.frame = 0;
|
|
@@ -18806,14 +18812,15 @@ var init_braille_spinner = __esm({
|
|
|
18806
18812
|
}
|
|
18807
18813
|
this.frame = 0;
|
|
18808
18814
|
this.setTool(null);
|
|
18815
|
+
this._metrics = { ...DEFAULT_METRICS };
|
|
18809
18816
|
}
|
|
18810
18817
|
/** Whether the animation timer is active. */
|
|
18811
18818
|
get isRunning() {
|
|
18812
18819
|
return this.timer !== null;
|
|
18813
18820
|
}
|
|
18814
18821
|
/**
|
|
18815
|
-
* Set the active tool, changing the animation color theme
|
|
18816
|
-
* Pass null to return to the default idle theme.
|
|
18822
|
+
* Set the active tool, changing the animation color theme.
|
|
18823
|
+
* Pass null to return to the default idle theme (e.g. on tool_result).
|
|
18817
18824
|
*/
|
|
18818
18825
|
setTool(toolName) {
|
|
18819
18826
|
const next = themeForTool(toolName);
|
|
@@ -18822,21 +18829,68 @@ var init_braille_spinner = __esm({
|
|
|
18822
18829
|
this.colorRamp = buildColorRamp(next.ramp);
|
|
18823
18830
|
}
|
|
18824
18831
|
}
|
|
18832
|
+
/**
|
|
18833
|
+
* Update real-time metrics that drive animation dynamics.
|
|
18834
|
+
* Call frequently (e.g. on each metrics update / stream tick).
|
|
18835
|
+
*/
|
|
18836
|
+
setMetrics(metrics) {
|
|
18837
|
+
if (metrics.contextPct !== void 0)
|
|
18838
|
+
this._metrics.contextPct = metrics.contextPct;
|
|
18839
|
+
if (metrics.tokenRate !== void 0)
|
|
18840
|
+
this._metrics.tokenRate = metrics.tokenRate;
|
|
18841
|
+
if (metrics.isStreaming !== void 0)
|
|
18842
|
+
this._metrics.isStreaming = metrics.isStreaming;
|
|
18843
|
+
}
|
|
18825
18844
|
/**
|
|
18826
18845
|
* Render the current animation frame as an ANSI-colored string.
|
|
18827
|
-
*
|
|
18828
|
-
*
|
|
18829
|
-
*
|
|
18846
|
+
*
|
|
18847
|
+
* State-driven dynamics:
|
|
18848
|
+
* - Speed: base from tool theme, boosted by token rate when streaming,
|
|
18849
|
+
* modulated by a slow breathing oscillation when idle.
|
|
18850
|
+
* - Amplitude: context pressure scales how much of the density range is
|
|
18851
|
+
* used — gentle ripples at low usage, full waves at high usage.
|
|
18852
|
+
* - Slinky: a secondary slow sine wave creates organic compression and
|
|
18853
|
+
* expansion across columns, making the wave feel elastic and alive.
|
|
18830
18854
|
*/
|
|
18831
18855
|
render(width) {
|
|
18832
18856
|
const cycleLen = WAVE.length;
|
|
18833
|
-
const
|
|
18857
|
+
const baseSpeed = this.theme.speed;
|
|
18858
|
+
const m = this._metrics;
|
|
18859
|
+
const breathPhase = Math.sin(this.frame * 0.08);
|
|
18860
|
+
let speed;
|
|
18861
|
+
if (m.isStreaming && m.tokenRate > 0) {
|
|
18862
|
+
const rateBoost = Math.min(4, m.tokenRate / 8);
|
|
18863
|
+
speed = baseSpeed + rateBoost + breathPhase * 0.3;
|
|
18864
|
+
} else {
|
|
18865
|
+
speed = baseSpeed + breathPhase * 0.8;
|
|
18866
|
+
}
|
|
18867
|
+
const pressure = Math.max(0, Math.min(100, m.contextPct)) / 100;
|
|
18868
|
+
const densityScale = 0.3 + pressure * 0.7;
|
|
18869
|
+
const slinkyFreq = 0.02 + (m.isStreaming ? 0.01 : 0);
|
|
18870
|
+
const slinkyAmp = 1.5 + pressure * 2;
|
|
18834
18871
|
let buf = "";
|
|
18835
18872
|
let lastColor = -1;
|
|
18836
18873
|
for (let col = 0; col < width; col++) {
|
|
18837
|
-
const
|
|
18838
|
-
const
|
|
18839
|
-
const
|
|
18874
|
+
const slinkyOffset = Math.sin(col * 0.1 + this.frame * slinkyFreq) * slinkyAmp;
|
|
18875
|
+
const rawPhase = col * speed + this.frame + slinkyOffset;
|
|
18876
|
+
const normalizedPhase = (rawPhase % cycleLen + cycleLen) % cycleLen;
|
|
18877
|
+
const waveIdx = Math.round(normalizedPhase) % cycleLen;
|
|
18878
|
+
let amplitude;
|
|
18879
|
+
if (waveIdx <= 8) {
|
|
18880
|
+
amplitude = waveIdx;
|
|
18881
|
+
} else {
|
|
18882
|
+
amplitude = 16 - waveIdx;
|
|
18883
|
+
}
|
|
18884
|
+
const scaledAmplitude = Math.round(amplitude * densityScale);
|
|
18885
|
+
let scaledIdx;
|
|
18886
|
+
if (waveIdx <= 8) {
|
|
18887
|
+
scaledIdx = scaledAmplitude;
|
|
18888
|
+
} else {
|
|
18889
|
+
scaledIdx = 16 - scaledAmplitude;
|
|
18890
|
+
}
|
|
18891
|
+
scaledIdx = Math.max(0, Math.min(cycleLen - 1, scaledIdx));
|
|
18892
|
+
const ch = WAVE[scaledIdx];
|
|
18893
|
+
const color = this.colorRamp[scaledIdx];
|
|
18840
18894
|
if (color !== lastColor) {
|
|
18841
18895
|
buf += `\x1B[38;5;${color}m`;
|
|
18842
18896
|
lastColor = color;
|
|
@@ -18851,13 +18905,12 @@ var init_braille_spinner = __esm({
|
|
|
18851
18905
|
});
|
|
18852
18906
|
|
|
18853
18907
|
// packages/cli/dist/tui/status-bar.js
|
|
18854
|
-
var
|
|
18908
|
+
var StatusBar;
|
|
18855
18909
|
var init_status_bar = __esm({
|
|
18856
18910
|
"packages/cli/dist/tui/status-bar.js"() {
|
|
18857
18911
|
"use strict";
|
|
18858
18912
|
init_render();
|
|
18859
18913
|
init_braille_spinner();
|
|
18860
|
-
FOOTER_ROWS = 5;
|
|
18861
18914
|
StatusBar = class {
|
|
18862
18915
|
metrics = {
|
|
18863
18916
|
promptTokens: 0,
|
|
@@ -18898,6 +18951,10 @@ var init_status_bar = __esm({
|
|
|
18898
18951
|
/** Whether agent is actively processing (braille animation) */
|
|
18899
18952
|
_processing = false;
|
|
18900
18953
|
_brailleSpinner = new BrailleSpinner();
|
|
18954
|
+
/** Current dynamic footer height (min 5: buffer + topSep + 1 input line + bottomSep + metrics) */
|
|
18955
|
+
_currentFooterHeight = 5;
|
|
18956
|
+
/** Timestamp when streaming started (for token rate calculation) */
|
|
18957
|
+
_streamStartTime = 0;
|
|
18901
18958
|
/**
|
|
18902
18959
|
* Provide a callback that returns readline's current input state.
|
|
18903
18960
|
* StatusBar uses this to render typed text and position the cursor
|
|
@@ -18939,11 +18996,13 @@ var init_status_bar = __esm({
|
|
|
18939
18996
|
return;
|
|
18940
18997
|
this._processing = active;
|
|
18941
18998
|
if (active) {
|
|
18999
|
+
this._brailleSpinner.setMetrics({ isStreaming: true });
|
|
18942
19000
|
this._brailleSpinner.start(() => {
|
|
18943
19001
|
if (this.active)
|
|
18944
19002
|
this.renderBufferLine();
|
|
18945
19003
|
});
|
|
18946
19004
|
} else {
|
|
19005
|
+
this._brailleSpinner.setMetrics({ isStreaming: false, tokenRate: 0 });
|
|
18947
19006
|
this._brailleSpinner.stop();
|
|
18948
19007
|
if (this.active)
|
|
18949
19008
|
this.renderBufferLine();
|
|
@@ -18984,6 +19043,9 @@ var init_status_bar = __esm({
|
|
|
18984
19043
|
if (update.estimatedContextTokens !== void 0)
|
|
18985
19044
|
this.metrics.estimatedContextTokens = update.estimatedContextTokens;
|
|
18986
19045
|
this._streamingTokens = 0;
|
|
19046
|
+
this._streamStartTime = 0;
|
|
19047
|
+
this.pushSpinnerContextMetrics();
|
|
19048
|
+
this._brailleSpinner.setMetrics({ tokenRate: 0, isStreaming: false });
|
|
18987
19049
|
if (this.active)
|
|
18988
19050
|
this.renderFooterPreserveCursor();
|
|
18989
19051
|
}
|
|
@@ -18993,6 +19055,11 @@ var init_status_bar = __esm({
|
|
|
18993
19055
|
/** Increment the live streaming token counter (throttled re-render at 100ms) */
|
|
18994
19056
|
incrementStreamingTokens(count) {
|
|
18995
19057
|
this._streamingTokens += count;
|
|
19058
|
+
if (this._streamStartTime === 0)
|
|
19059
|
+
this._streamStartTime = Date.now();
|
|
19060
|
+
const elapsedSec = (Date.now() - this._streamStartTime) / 1e3;
|
|
19061
|
+
const tokenRate = elapsedSec > 0.1 ? this._streamingTokens / elapsedSec : 0;
|
|
19062
|
+
this._brailleSpinner.setMetrics({ tokenRate, isStreaming: true });
|
|
18996
19063
|
if (!this._streamThrottleTimer && this.active) {
|
|
18997
19064
|
this._streamThrottleTimer = setTimeout(() => {
|
|
18998
19065
|
this._streamThrottleTimer = null;
|
|
@@ -19011,6 +19078,7 @@ var init_status_bar = __esm({
|
|
|
19011
19078
|
this.metrics.completionTokens = 0;
|
|
19012
19079
|
this.metrics.totalTokens = 0;
|
|
19013
19080
|
this.metrics.estimatedContextTokens = 0;
|
|
19081
|
+
this.pushSpinnerContextMetrics();
|
|
19014
19082
|
if (this.active)
|
|
19015
19083
|
this.renderFooterPreserveCursor();
|
|
19016
19084
|
}
|
|
@@ -19038,7 +19106,7 @@ var init_status_bar = __esm({
|
|
|
19038
19106
|
}
|
|
19039
19107
|
/**
|
|
19040
19108
|
* Set the prompt text that StatusBar draws on the input row.
|
|
19041
|
-
* Called by the REPL whenever the prompt changes (idle
|
|
19109
|
+
* Called by the REPL whenever the prompt changes (idle <-> active).
|
|
19042
19110
|
* The prompt is rendered as part of the atomic footer write so cursor
|
|
19043
19111
|
* positioning never depends on readline's internal tracking.
|
|
19044
19112
|
* @param text The ANSI-colored prompt string (e.g. "> " or "+ ")
|
|
@@ -19051,21 +19119,29 @@ var init_status_bar = __esm({
|
|
|
19051
19119
|
this.renderFooterAndPositionInput();
|
|
19052
19120
|
}
|
|
19053
19121
|
}
|
|
19054
|
-
/** Number of rows reserved at the bottom */
|
|
19122
|
+
/** Number of rows reserved at the bottom (dynamic based on input wrapping) */
|
|
19055
19123
|
get reservedRows() {
|
|
19056
|
-
return
|
|
19124
|
+
return this._currentFooterHeight;
|
|
19057
19125
|
}
|
|
19058
19126
|
/** Handle terminal resize — reapply scroll region and redraw footer */
|
|
19059
19127
|
handleResize() {
|
|
19060
19128
|
if (!this.active)
|
|
19061
19129
|
return;
|
|
19130
|
+
this.updateFooterHeight();
|
|
19131
|
+
const rows = process.stdout.rows ?? 24;
|
|
19132
|
+
const pos = this.rowPositions(rows);
|
|
19133
|
+
const w = getTermWidth();
|
|
19134
|
+
const sep = c2.dim("\u2500".repeat(w));
|
|
19062
19135
|
if (this.writeDepth > 0) {
|
|
19063
|
-
const
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19067
|
-
|
|
19068
|
-
|
|
19136
|
+
const inputWrap = this.wrapInput(w);
|
|
19137
|
+
let buf = `\x1B[${this.scrollRegionTop};${pos.scrollEnd}r\x1B[?25l\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
|
|
19138
|
+
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
19139
|
+
const row = pos.inputStartRow + i;
|
|
19140
|
+
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
19141
|
+
buf += `\x1B[${row};1H\x1B[2K${prefix}${inputWrap.lines[i]}`;
|
|
19142
|
+
}
|
|
19143
|
+
buf += `\x1B[${pos.bottomSepRow};1H\x1B[2K${sep}\x1B[${pos.metricsRow};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B[${pos.scrollEnd};1H`;
|
|
19144
|
+
process.stdout.write(buf);
|
|
19069
19145
|
} else {
|
|
19070
19146
|
this.applyScrollRegion();
|
|
19071
19147
|
this.renderFooterAndPositionInput();
|
|
@@ -19093,8 +19169,9 @@ var init_status_bar = __esm({
|
|
|
19093
19169
|
if (!this.active)
|
|
19094
19170
|
return;
|
|
19095
19171
|
this.writeDepth++;
|
|
19172
|
+
this._brailleSpinner.setMetrics({ isStreaming: true });
|
|
19096
19173
|
const rows = process.stdout.rows ?? 24;
|
|
19097
|
-
const scrollEnd = Math.max(rows -
|
|
19174
|
+
const scrollEnd = Math.max(rows - this._currentFooterHeight, this.scrollRegionTop + 1);
|
|
19098
19175
|
process.stdout.write(`\x1B[?25l\x1B[${this.scrollRegionTop};${scrollEnd}r\x1B[${scrollEnd};1H`);
|
|
19099
19176
|
}
|
|
19100
19177
|
/**
|
|
@@ -19109,6 +19186,7 @@ var init_status_bar = __esm({
|
|
|
19109
19186
|
return;
|
|
19110
19187
|
this.writeDepth = Math.max(0, this.writeDepth - 1);
|
|
19111
19188
|
if (this.writeDepth === 0) {
|
|
19189
|
+
this._brailleSpinner.setMetrics({ isStreaming: false });
|
|
19112
19190
|
this.renderFooterAndPositionInput();
|
|
19113
19191
|
}
|
|
19114
19192
|
}
|
|
@@ -19120,8 +19198,8 @@ var init_status_bar = __esm({
|
|
|
19120
19198
|
if (!this.active)
|
|
19121
19199
|
return;
|
|
19122
19200
|
const rows = process.stdout.rows ?? 24;
|
|
19123
|
-
const
|
|
19124
|
-
process.stdout.write(`\x1B[${
|
|
19201
|
+
const pos = this.rowPositions(rows);
|
|
19202
|
+
process.stdout.write(`\x1B[${pos.inputStartRow};1H\x1B[2K`);
|
|
19125
19203
|
}
|
|
19126
19204
|
/** Build the metrics line string */
|
|
19127
19205
|
buildMetricsLine() {
|
|
@@ -19162,18 +19240,88 @@ var init_status_bar = __esm({
|
|
|
19162
19240
|
// -------------------------------------------------------------------------
|
|
19163
19241
|
// Private
|
|
19164
19242
|
// -------------------------------------------------------------------------
|
|
19165
|
-
/**
|
|
19243
|
+
/** Push current context window usage to the braille spinner */
|
|
19244
|
+
pushSpinnerContextMetrics() {
|
|
19245
|
+
const ctxUsed = this.metrics.estimatedContextTokens;
|
|
19246
|
+
const ctxTotal = this.metrics.contextWindowSize;
|
|
19247
|
+
const contextPct = ctxTotal > 0 ? Math.round(ctxUsed / ctxTotal * 100) : 0;
|
|
19248
|
+
this._brailleSpinner.setMetrics({ contextPct });
|
|
19249
|
+
}
|
|
19250
|
+
/** Compute how many visual lines the current input text occupies */
|
|
19251
|
+
computeInputLineCount(termWidth) {
|
|
19252
|
+
if (!this.inputStateProvider)
|
|
19253
|
+
return 1;
|
|
19254
|
+
const w = termWidth ?? getTermWidth();
|
|
19255
|
+
const availWidth = Math.max(1, w - this.promptWidth);
|
|
19256
|
+
const { line } = this.inputStateProvider();
|
|
19257
|
+
if (line.length <= availWidth)
|
|
19258
|
+
return 1;
|
|
19259
|
+
return Math.ceil(line.length / availWidth);
|
|
19260
|
+
}
|
|
19261
|
+
/** Update _currentFooterHeight based on current input. Returns true if height changed. */
|
|
19262
|
+
updateFooterHeight(termWidth) {
|
|
19263
|
+
const inputLines = this.computeInputLineCount(termWidth);
|
|
19264
|
+
const newHeight = 4 + inputLines;
|
|
19265
|
+
if (newHeight !== this._currentFooterHeight) {
|
|
19266
|
+
this._currentFooterHeight = newHeight;
|
|
19267
|
+
return true;
|
|
19268
|
+
}
|
|
19269
|
+
return false;
|
|
19270
|
+
}
|
|
19271
|
+
/** Compute absolute row positions for all footer elements */
|
|
19272
|
+
rowPositions(rows) {
|
|
19273
|
+
const fh = this._currentFooterHeight;
|
|
19274
|
+
return {
|
|
19275
|
+
scrollEnd: Math.max(rows - fh, this.scrollRegionTop + 1),
|
|
19276
|
+
bufferRow: rows - fh + 1,
|
|
19277
|
+
topSepRow: rows - fh + 2,
|
|
19278
|
+
inputStartRow: rows - fh + 3,
|
|
19279
|
+
bottomSepRow: rows - 1,
|
|
19280
|
+
metricsRow: rows
|
|
19281
|
+
};
|
|
19282
|
+
}
|
|
19283
|
+
/**
|
|
19284
|
+
* Wrap input text into lines of availWidth characters.
|
|
19285
|
+
* Returns the lines, plus cursor position within the wrapped layout.
|
|
19286
|
+
*/
|
|
19287
|
+
wrapInput(termWidth) {
|
|
19288
|
+
const availWidth = Math.max(1, termWidth - this.promptWidth);
|
|
19289
|
+
const inputState = this.inputStateProvider?.();
|
|
19290
|
+
const fullLine = inputState?.line ?? "";
|
|
19291
|
+
const cursorPos = inputState?.cursor ?? 0;
|
|
19292
|
+
if (fullLine.length <= availWidth) {
|
|
19293
|
+
return {
|
|
19294
|
+
lines: [fullLine],
|
|
19295
|
+
cursorRow: 0,
|
|
19296
|
+
cursorCol: this.promptWidth + cursorPos + 1
|
|
19297
|
+
};
|
|
19298
|
+
}
|
|
19299
|
+
const lines = [];
|
|
19300
|
+
for (let i = 0; i < fullLine.length; i += availWidth) {
|
|
19301
|
+
lines.push(fullLine.slice(i, i + availWidth));
|
|
19302
|
+
}
|
|
19303
|
+
if (lines.length === 0)
|
|
19304
|
+
lines.push("");
|
|
19305
|
+
const cursorLineIdx = Math.min(Math.floor(cursorPos / availWidth), lines.length - 1);
|
|
19306
|
+
const cursorColInLine = cursorPos - cursorLineIdx * availWidth;
|
|
19307
|
+
return {
|
|
19308
|
+
lines,
|
|
19309
|
+
cursorRow: cursorLineIdx,
|
|
19310
|
+
cursorCol: this.promptWidth + cursorColInLine + 1
|
|
19311
|
+
};
|
|
19312
|
+
}
|
|
19313
|
+
/** Set the DECSTBM scroll region to exclude the dynamic footer rows */
|
|
19166
19314
|
applyScrollRegion() {
|
|
19315
|
+
this.updateFooterHeight();
|
|
19167
19316
|
const rows = process.stdout.rows ?? 24;
|
|
19168
|
-
const
|
|
19169
|
-
process.stdout.write(`\x1B[${this.scrollRegionTop};${scrollEnd}r\x1B[${scrollEnd};1H`);
|
|
19317
|
+
const pos = this.rowPositions(rows);
|
|
19318
|
+
process.stdout.write(`\x1B[${this.scrollRegionTop};${pos.scrollEnd}r\x1B[${pos.scrollEnd};1H`);
|
|
19170
19319
|
}
|
|
19171
19320
|
/**
|
|
19172
19321
|
* Draw the COMPLETE footer — separators, prompt, metrics — in a single
|
|
19173
|
-
* atomic process.stdout.write() call.
|
|
19174
|
-
*
|
|
19175
|
-
*
|
|
19176
|
-
* movements that conflict with our absolute ANSI positioning).
|
|
19322
|
+
* atomic process.stdout.write() call. Input text wraps across multiple
|
|
19323
|
+
* rows when it exceeds the available width, and the footer dynamically
|
|
19324
|
+
* grows/shrinks to accommodate.
|
|
19177
19325
|
*
|
|
19178
19326
|
* Does NOT set DECSTBM — the scroll region is maintained by
|
|
19179
19327
|
* applyScrollRegion() and beginContentWrite().
|
|
@@ -19183,25 +19331,21 @@ var init_status_bar = __esm({
|
|
|
19183
19331
|
return;
|
|
19184
19332
|
const rows = process.stdout.rows ?? 24;
|
|
19185
19333
|
const w = getTermWidth();
|
|
19186
|
-
const
|
|
19187
|
-
const
|
|
19188
|
-
|
|
19189
|
-
|
|
19190
|
-
const cursorPos = inputState?.cursor ?? 0;
|
|
19191
|
-
const availWidth = Math.max(1, w - this.promptWidth);
|
|
19192
|
-
let visibleText;
|
|
19193
|
-
let cursorCol;
|
|
19194
|
-
if (fullLine.length <= availWidth) {
|
|
19195
|
-
visibleText = fullLine;
|
|
19196
|
-
cursorCol = this.promptWidth + cursorPos + 1;
|
|
19197
|
-
} else {
|
|
19198
|
-
const lookAhead = Math.min(8, Math.floor(availWidth / 4));
|
|
19199
|
-
let scrollOffset = cursorPos - (availWidth - lookAhead);
|
|
19200
|
-
scrollOffset = Math.max(0, Math.min(scrollOffset, fullLine.length - availWidth));
|
|
19201
|
-
visibleText = fullLine.slice(scrollOffset, scrollOffset + availWidth);
|
|
19202
|
-
cursorCol = this.promptWidth + (cursorPos - scrollOffset) + 1;
|
|
19334
|
+
const heightChanged = this.updateFooterHeight(w);
|
|
19335
|
+
const pos = this.rowPositions(rows);
|
|
19336
|
+
if (heightChanged) {
|
|
19337
|
+
process.stdout.write(`\x1B[${this.scrollRegionTop};${pos.scrollEnd}r`);
|
|
19203
19338
|
}
|
|
19204
|
-
const
|
|
19339
|
+
const sep = c2.dim("\u2500".repeat(w));
|
|
19340
|
+
const inputWrap = this.wrapInput(w);
|
|
19341
|
+
let buf = `\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
|
|
19342
|
+
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
19343
|
+
const row = pos.inputStartRow + i;
|
|
19344
|
+
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
19345
|
+
buf += `\x1B[${row};1H\x1B[2K${prefix}${inputWrap.lines[i]}`;
|
|
19346
|
+
}
|
|
19347
|
+
const cursorTermRow = pos.inputStartRow + inputWrap.cursorRow;
|
|
19348
|
+
buf += `\x1B[${pos.bottomSepRow};1H\x1B[2K${sep}\x1B[${pos.metricsRow};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B[?25h\x1B[${cursorTermRow};${inputWrap.cursorCol}H`;
|
|
19205
19349
|
process.stdout.write(buf);
|
|
19206
19350
|
}
|
|
19207
19351
|
/**
|
|
@@ -19210,50 +19354,66 @@ var init_status_bar = __esm({
|
|
|
19210
19354
|
* move the cursor away from where readline left it.
|
|
19211
19355
|
* Uses DEC DECSC/DECRC (\x1B7/\x1B8) for save/restore in a single write.
|
|
19212
19356
|
*
|
|
19357
|
+
* If the footer height has changed (due to input wrapping), falls back
|
|
19358
|
+
* to a full renderFooterAndPositionInput() instead.
|
|
19359
|
+
*
|
|
19213
19360
|
* IMPORTANT: Does NOT set DECSTBM here — setting the scroll region between
|
|
19214
19361
|
* cursor save/restore corrupts the restore position on many terminals.
|
|
19215
|
-
* The scroll region is enforced by beginContentWrite() and renderFooterAndPositionInput().
|
|
19216
19362
|
*/
|
|
19217
19363
|
renderFooterPreserveCursor() {
|
|
19218
19364
|
if (!this.active)
|
|
19219
19365
|
return;
|
|
19366
|
+
if (this.updateFooterHeight()) {
|
|
19367
|
+
if (this.writeDepth === 0) {
|
|
19368
|
+
this.renderFooterAndPositionInput();
|
|
19369
|
+
}
|
|
19370
|
+
return;
|
|
19371
|
+
}
|
|
19220
19372
|
const rows = process.stdout.rows ?? 24;
|
|
19221
19373
|
const w = getTermWidth();
|
|
19374
|
+
const pos = this.rowPositions(rows);
|
|
19222
19375
|
const sep = c2.dim("\u2500".repeat(w));
|
|
19223
|
-
const buf = `\x1B7\x1B[?7l\x1B[${
|
|
19376
|
+
const buf = `\x1B7\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}\x1B[${pos.topSepRow};1H\x1B[2K${sep}\x1B[${pos.bottomSepRow};1H\x1B[2K${sep}\x1B[${pos.metricsRow};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B8`;
|
|
19224
19377
|
process.stdout.write(buf);
|
|
19225
19378
|
}
|
|
19226
19379
|
/**
|
|
19227
|
-
* Render
|
|
19380
|
+
* Render the input rows during an active content write (streaming).
|
|
19228
19381
|
* Uses DEC save/restore cursor so the streaming cursor position is preserved.
|
|
19229
|
-
*
|
|
19382
|
+
* If footer height changed, also updates DECSTBM and redraws full footer.
|
|
19230
19383
|
*/
|
|
19231
19384
|
renderInputRowDuringStream() {
|
|
19232
19385
|
if (!this.active || !this.inputStateProvider)
|
|
19233
19386
|
return;
|
|
19234
19387
|
const rows = process.stdout.rows ?? 24;
|
|
19235
19388
|
const w = getTermWidth();
|
|
19236
|
-
const
|
|
19237
|
-
const
|
|
19238
|
-
const
|
|
19239
|
-
|
|
19240
|
-
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19389
|
+
const heightChanged = this.updateFooterHeight(w);
|
|
19390
|
+
const pos = this.rowPositions(rows);
|
|
19391
|
+
const inputWrap = this.wrapInput(w);
|
|
19392
|
+
let buf = "\x1B7\x1B[?7l";
|
|
19393
|
+
if (heightChanged) {
|
|
19394
|
+
buf += `\x1B[${this.scrollRegionTop};${pos.scrollEnd}r`;
|
|
19395
|
+
const sep = c2.dim("\u2500".repeat(w));
|
|
19396
|
+
buf += `\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}`;
|
|
19397
|
+
buf += `\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
|
|
19398
|
+
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
19399
|
+
const row = pos.inputStartRow + i;
|
|
19400
|
+
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
19401
|
+
buf += `\x1B[${row};1H\x1B[2K${prefix}${inputWrap.lines[i]}`;
|
|
19402
|
+
}
|
|
19403
|
+
buf += `\x1B[${pos.bottomSepRow};1H\x1B[2K${sep}`;
|
|
19404
|
+
buf += `\x1B[${pos.metricsRow};1H\x1B[2K${this.buildMetricsLine()}`;
|
|
19246
19405
|
} else {
|
|
19247
|
-
|
|
19248
|
-
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
|
|
19406
|
+
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
19407
|
+
const row = pos.inputStartRow + i;
|
|
19408
|
+
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
19409
|
+
buf += `\x1B[${row};1H\x1B[2K${prefix}${inputWrap.lines[i]}`;
|
|
19410
|
+
}
|
|
19252
19411
|
}
|
|
19253
|
-
|
|
19412
|
+
buf += "\x1B[?7h\x1B8";
|
|
19413
|
+
process.stdout.write(buf);
|
|
19254
19414
|
}
|
|
19255
19415
|
/**
|
|
19256
|
-
* Build the content for the buffer line
|
|
19416
|
+
* Build the content for the buffer line.
|
|
19257
19417
|
* Returns braille animation when processing, empty string when idle.
|
|
19258
19418
|
*/
|
|
19259
19419
|
buildBufferContent(width) {
|
|
@@ -19263,7 +19423,7 @@ var init_status_bar = __esm({
|
|
|
19263
19423
|
return "";
|
|
19264
19424
|
}
|
|
19265
19425
|
/**
|
|
19266
|
-
* Render ONLY the buffer line
|
|
19426
|
+
* Render ONLY the buffer line using DEC save/restore cursor.
|
|
19267
19427
|
* Called by the braille spinner timer without disrupting scroll or input.
|
|
19268
19428
|
*/
|
|
19269
19429
|
renderBufferLine() {
|
|
@@ -19271,15 +19431,15 @@ var init_status_bar = __esm({
|
|
|
19271
19431
|
return;
|
|
19272
19432
|
const rows = process.stdout.rows ?? 24;
|
|
19273
19433
|
const w = getTermWidth();
|
|
19274
|
-
const
|
|
19434
|
+
const pos = this.rowPositions(rows);
|
|
19275
19435
|
const content = this.buildBufferContent(w);
|
|
19276
|
-
process.stdout.write(`\x1B7\x1B[?7l\x1B[${bufferRow};1H\x1B[2K${content}\x1B[?7h\x1B8`);
|
|
19436
|
+
process.stdout.write(`\x1B7\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${content}\x1B[?7h\x1B8`);
|
|
19277
19437
|
}
|
|
19278
19438
|
/**
|
|
19279
19439
|
* Hook into process.stdin to redraw footer after every keystroke.
|
|
19280
19440
|
* Since readline's output is suppressed (redirected to a no-op stream),
|
|
19281
19441
|
* this hook is responsible for rendering typed text on the input row.
|
|
19282
|
-
* During streaming (writeDepth > 0), only the input
|
|
19442
|
+
* During streaming (writeDepth > 0), only the input rows are updated using
|
|
19283
19443
|
* cursor save/restore so the streaming position isn't disrupted.
|
|
19284
19444
|
* When idle (writeDepth === 0), the full footer is redrawn.
|
|
19285
19445
|
*/
|
|
@@ -19899,7 +20059,7 @@ async function startInteractive(config, repoPath) {
|
|
|
19899
20059
|
let sessionToolCallCount = 0;
|
|
19900
20060
|
let sessionSudoPassword = null;
|
|
19901
20061
|
let sudoPromptPending = false;
|
|
19902
|
-
const idlePrompt = `${c2.bold(c2.white("\
|
|
20062
|
+
const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
|
|
19903
20063
|
const activePrompt = `${c2.bold(c2.white("+ "))}`;
|
|
19904
20064
|
const rl = readline2.createInterface({
|
|
19905
20065
|
input: process.stdin,
|
package/package.json
CHANGED