open-agents-ai 0.29.0 → 0.30.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.
- package/dist/index.js +278 -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,93 @@ 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
|
+
/** Check if footer height would change, WITHOUT actually updating it */
|
|
19272
|
+
footerHeightChanged(termWidth) {
|
|
19273
|
+
const inputLines = this.computeInputLineCount(termWidth);
|
|
19274
|
+
return 4 + inputLines !== this._currentFooterHeight;
|
|
19275
|
+
}
|
|
19276
|
+
/** Compute absolute row positions for all footer elements */
|
|
19277
|
+
rowPositions(rows) {
|
|
19278
|
+
const fh = this._currentFooterHeight;
|
|
19279
|
+
return {
|
|
19280
|
+
scrollEnd: Math.max(rows - fh, this.scrollRegionTop + 1),
|
|
19281
|
+
bufferRow: rows - fh + 1,
|
|
19282
|
+
topSepRow: rows - fh + 2,
|
|
19283
|
+
inputStartRow: rows - fh + 3,
|
|
19284
|
+
bottomSepRow: rows - 1,
|
|
19285
|
+
metricsRow: rows
|
|
19286
|
+
};
|
|
19287
|
+
}
|
|
19288
|
+
/**
|
|
19289
|
+
* Wrap input text into lines of availWidth characters.
|
|
19290
|
+
* Returns the lines, plus cursor position within the wrapped layout.
|
|
19291
|
+
*/
|
|
19292
|
+
wrapInput(termWidth) {
|
|
19293
|
+
const availWidth = Math.max(1, termWidth - this.promptWidth);
|
|
19294
|
+
const inputState = this.inputStateProvider?.();
|
|
19295
|
+
const fullLine = inputState?.line ?? "";
|
|
19296
|
+
const cursorPos = inputState?.cursor ?? 0;
|
|
19297
|
+
if (fullLine.length <= availWidth) {
|
|
19298
|
+
return {
|
|
19299
|
+
lines: [fullLine],
|
|
19300
|
+
cursorRow: 0,
|
|
19301
|
+
cursorCol: this.promptWidth + cursorPos + 1
|
|
19302
|
+
};
|
|
19303
|
+
}
|
|
19304
|
+
const lines = [];
|
|
19305
|
+
for (let i = 0; i < fullLine.length; i += availWidth) {
|
|
19306
|
+
lines.push(fullLine.slice(i, i + availWidth));
|
|
19307
|
+
}
|
|
19308
|
+
if (lines.length === 0)
|
|
19309
|
+
lines.push("");
|
|
19310
|
+
const cursorLineIdx = Math.min(Math.floor(cursorPos / availWidth), lines.length - 1);
|
|
19311
|
+
const cursorColInLine = cursorPos - cursorLineIdx * availWidth;
|
|
19312
|
+
return {
|
|
19313
|
+
lines,
|
|
19314
|
+
cursorRow: cursorLineIdx,
|
|
19315
|
+
cursorCol: this.promptWidth + cursorColInLine + 1
|
|
19316
|
+
};
|
|
19317
|
+
}
|
|
19318
|
+
/** Set the DECSTBM scroll region to exclude the dynamic footer rows */
|
|
19166
19319
|
applyScrollRegion() {
|
|
19320
|
+
this.updateFooterHeight();
|
|
19167
19321
|
const rows = process.stdout.rows ?? 24;
|
|
19168
|
-
const
|
|
19169
|
-
process.stdout.write(`\x1B[${this.scrollRegionTop};${scrollEnd}r\x1B[${scrollEnd};1H`);
|
|
19322
|
+
const pos = this.rowPositions(rows);
|
|
19323
|
+
process.stdout.write(`\x1B[${this.scrollRegionTop};${pos.scrollEnd}r\x1B[${pos.scrollEnd};1H`);
|
|
19170
19324
|
}
|
|
19171
19325
|
/**
|
|
19172
19326
|
* 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).
|
|
19327
|
+
* atomic process.stdout.write() call. Input text wraps across multiple
|
|
19328
|
+
* rows when it exceeds the available width, and the footer dynamically
|
|
19329
|
+
* grows/shrinks to accommodate.
|
|
19177
19330
|
*
|
|
19178
19331
|
* Does NOT set DECSTBM — the scroll region is maintained by
|
|
19179
19332
|
* applyScrollRegion() and beginContentWrite().
|
|
@@ -19183,25 +19336,38 @@ var init_status_bar = __esm({
|
|
|
19183
19336
|
return;
|
|
19184
19337
|
const rows = process.stdout.rows ?? 24;
|
|
19185
19338
|
const w = getTermWidth();
|
|
19186
|
-
const
|
|
19187
|
-
const
|
|
19188
|
-
const
|
|
19189
|
-
|
|
19190
|
-
|
|
19191
|
-
|
|
19192
|
-
|
|
19193
|
-
|
|
19194
|
-
|
|
19195
|
-
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
|
|
19199
|
-
|
|
19200
|
-
|
|
19201
|
-
|
|
19202
|
-
|
|
19339
|
+
const oldFooterHeight = this._currentFooterHeight;
|
|
19340
|
+
const heightChanged = this.updateFooterHeight(w);
|
|
19341
|
+
const pos = this.rowPositions(rows);
|
|
19342
|
+
if (heightChanged) {
|
|
19343
|
+
const heightDelta = this._currentFooterHeight - oldFooterHeight;
|
|
19344
|
+
if (heightDelta > 0) {
|
|
19345
|
+
const oldScrollEnd = Math.max(rows - oldFooterHeight, this.scrollRegionTop + 1);
|
|
19346
|
+
let scrollUp = `\x1B[${oldScrollEnd};1H`;
|
|
19347
|
+
for (let i = 0; i < heightDelta; i++)
|
|
19348
|
+
scrollUp += "\n";
|
|
19349
|
+
process.stdout.write(scrollUp);
|
|
19350
|
+
} else {
|
|
19351
|
+
const oldScrollEnd = Math.max(rows - oldFooterHeight, this.scrollRegionTop + 1);
|
|
19352
|
+
let clear = "";
|
|
19353
|
+
for (let row = oldScrollEnd + 1; row <= pos.scrollEnd; row++) {
|
|
19354
|
+
clear += `\x1B[${row};1H\x1B[2K`;
|
|
19355
|
+
}
|
|
19356
|
+
if (clear)
|
|
19357
|
+
process.stdout.write(clear);
|
|
19358
|
+
}
|
|
19359
|
+
process.stdout.write(`\x1B[${this.scrollRegionTop};${pos.scrollEnd}r`);
|
|
19203
19360
|
}
|
|
19204
|
-
const
|
|
19361
|
+
const sep = c2.dim("\u2500".repeat(w));
|
|
19362
|
+
const inputWrap = this.wrapInput(w);
|
|
19363
|
+
let buf = `\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
|
|
19364
|
+
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
19365
|
+
const row = pos.inputStartRow + i;
|
|
19366
|
+
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
19367
|
+
buf += `\x1B[${row};1H\x1B[2K${prefix}${inputWrap.lines[i]}`;
|
|
19368
|
+
}
|
|
19369
|
+
const cursorTermRow = pos.inputStartRow + inputWrap.cursorRow;
|
|
19370
|
+
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
19371
|
process.stdout.write(buf);
|
|
19206
19372
|
}
|
|
19207
19373
|
/**
|
|
@@ -19210,50 +19376,87 @@ var init_status_bar = __esm({
|
|
|
19210
19376
|
* move the cursor away from where readline left it.
|
|
19211
19377
|
* Uses DEC DECSC/DECRC (\x1B7/\x1B8) for save/restore in a single write.
|
|
19212
19378
|
*
|
|
19379
|
+
* If the footer height has changed (due to input wrapping), falls back
|
|
19380
|
+
* to a full renderFooterAndPositionInput() instead.
|
|
19381
|
+
*
|
|
19213
19382
|
* IMPORTANT: Does NOT set DECSTBM here — setting the scroll region between
|
|
19214
19383
|
* cursor save/restore corrupts the restore position on many terminals.
|
|
19215
|
-
* The scroll region is enforced by beginContentWrite() and renderFooterAndPositionInput().
|
|
19216
19384
|
*/
|
|
19217
19385
|
renderFooterPreserveCursor() {
|
|
19218
19386
|
if (!this.active)
|
|
19219
19387
|
return;
|
|
19388
|
+
if (this.footerHeightChanged()) {
|
|
19389
|
+
if (this.writeDepth === 0) {
|
|
19390
|
+
this.renderFooterAndPositionInput();
|
|
19391
|
+
}
|
|
19392
|
+
return;
|
|
19393
|
+
}
|
|
19220
19394
|
const rows = process.stdout.rows ?? 24;
|
|
19221
19395
|
const w = getTermWidth();
|
|
19396
|
+
const pos = this.rowPositions(rows);
|
|
19222
19397
|
const sep = c2.dim("\u2500".repeat(w));
|
|
19223
|
-
const buf = `\x1B7\x1B[?7l\x1B[${
|
|
19398
|
+
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
19399
|
process.stdout.write(buf);
|
|
19225
19400
|
}
|
|
19226
19401
|
/**
|
|
19227
|
-
* Render
|
|
19402
|
+
* Render the input rows during an active content write (streaming).
|
|
19228
19403
|
* Uses DEC save/restore cursor so the streaming cursor position is preserved.
|
|
19229
|
-
*
|
|
19404
|
+
* If footer height changed, also updates DECSTBM and redraws full footer.
|
|
19230
19405
|
*/
|
|
19231
19406
|
renderInputRowDuringStream() {
|
|
19232
19407
|
if (!this.active || !this.inputStateProvider)
|
|
19233
19408
|
return;
|
|
19234
19409
|
const rows = process.stdout.rows ?? 24;
|
|
19235
19410
|
const w = getTermWidth();
|
|
19236
|
-
const
|
|
19237
|
-
const
|
|
19238
|
-
const
|
|
19239
|
-
const
|
|
19240
|
-
|
|
19241
|
-
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19245
|
-
|
|
19411
|
+
const oldFooterHeight = this._currentFooterHeight;
|
|
19412
|
+
const heightChanged = this.updateFooterHeight(w);
|
|
19413
|
+
const pos = this.rowPositions(rows);
|
|
19414
|
+
const inputWrap = this.wrapInput(w);
|
|
19415
|
+
if (heightChanged) {
|
|
19416
|
+
const heightDelta = this._currentFooterHeight - oldFooterHeight;
|
|
19417
|
+
let buf = "\x1B7";
|
|
19418
|
+
if (heightDelta > 0) {
|
|
19419
|
+
const oldScrollEnd = Math.max(rows - oldFooterHeight, this.scrollRegionTop + 1);
|
|
19420
|
+
buf += `\x1B[${oldScrollEnd};1H`;
|
|
19421
|
+
for (let i = 0; i < heightDelta; i++)
|
|
19422
|
+
buf += "\n";
|
|
19423
|
+
} else {
|
|
19424
|
+
const oldScrollEnd = Math.max(rows - oldFooterHeight, this.scrollRegionTop + 1);
|
|
19425
|
+
for (let row = oldScrollEnd + 1; row <= pos.scrollEnd; row++) {
|
|
19426
|
+
buf += `\x1B[${row};1H\x1B[2K`;
|
|
19427
|
+
}
|
|
19428
|
+
}
|
|
19429
|
+
buf += `\x1B[${this.scrollRegionTop};${pos.scrollEnd}r`;
|
|
19430
|
+
buf += "\x1B[?7l";
|
|
19431
|
+
const sep = c2.dim("\u2500".repeat(w));
|
|
19432
|
+
buf += `\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}`;
|
|
19433
|
+
buf += `\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
|
|
19434
|
+
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
19435
|
+
const row = pos.inputStartRow + i;
|
|
19436
|
+
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
19437
|
+
buf += `\x1B[${row};1H\x1B[2K${prefix}${inputWrap.lines[i]}`;
|
|
19438
|
+
}
|
|
19439
|
+
buf += `\x1B[${pos.bottomSepRow};1H\x1B[2K${sep}`;
|
|
19440
|
+
buf += `\x1B[${pos.metricsRow};1H\x1B[2K${this.buildMetricsLine()}`;
|
|
19441
|
+
buf += "\x1B[?7h";
|
|
19442
|
+
buf += "\x1B8";
|
|
19443
|
+
if (heightDelta > 0) {
|
|
19444
|
+
buf += `\x1B[${heightDelta}A`;
|
|
19445
|
+
}
|
|
19446
|
+
process.stdout.write(buf);
|
|
19246
19447
|
} else {
|
|
19247
|
-
|
|
19248
|
-
let
|
|
19249
|
-
|
|
19250
|
-
|
|
19251
|
-
|
|
19448
|
+
let buf = "\x1B7\x1B[?7l";
|
|
19449
|
+
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
19450
|
+
const row = pos.inputStartRow + i;
|
|
19451
|
+
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
19452
|
+
buf += `\x1B[${row};1H\x1B[2K${prefix}${inputWrap.lines[i]}`;
|
|
19453
|
+
}
|
|
19454
|
+
buf += "\x1B[?7h\x1B8";
|
|
19455
|
+
process.stdout.write(buf);
|
|
19252
19456
|
}
|
|
19253
|
-
process.stdout.write(`\x1B7\x1B[?7l\x1B[${inputRow};1H\x1B[2K${this.promptText}${visibleText}\x1B[?7h\x1B8`);
|
|
19254
19457
|
}
|
|
19255
19458
|
/**
|
|
19256
|
-
* Build the content for the buffer line
|
|
19459
|
+
* Build the content for the buffer line.
|
|
19257
19460
|
* Returns braille animation when processing, empty string when idle.
|
|
19258
19461
|
*/
|
|
19259
19462
|
buildBufferContent(width) {
|
|
@@ -19263,7 +19466,7 @@ var init_status_bar = __esm({
|
|
|
19263
19466
|
return "";
|
|
19264
19467
|
}
|
|
19265
19468
|
/**
|
|
19266
|
-
* Render ONLY the buffer line
|
|
19469
|
+
* Render ONLY the buffer line using DEC save/restore cursor.
|
|
19267
19470
|
* Called by the braille spinner timer without disrupting scroll or input.
|
|
19268
19471
|
*/
|
|
19269
19472
|
renderBufferLine() {
|
|
@@ -19271,15 +19474,15 @@ var init_status_bar = __esm({
|
|
|
19271
19474
|
return;
|
|
19272
19475
|
const rows = process.stdout.rows ?? 24;
|
|
19273
19476
|
const w = getTermWidth();
|
|
19274
|
-
const
|
|
19477
|
+
const pos = this.rowPositions(rows);
|
|
19275
19478
|
const content = this.buildBufferContent(w);
|
|
19276
|
-
process.stdout.write(`\x1B7\x1B[?7l\x1B[${bufferRow};1H\x1B[2K${content}\x1B[?7h\x1B8`);
|
|
19479
|
+
process.stdout.write(`\x1B7\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${content}\x1B[?7h\x1B8`);
|
|
19277
19480
|
}
|
|
19278
19481
|
/**
|
|
19279
19482
|
* Hook into process.stdin to redraw footer after every keystroke.
|
|
19280
19483
|
* Since readline's output is suppressed (redirected to a no-op stream),
|
|
19281
19484
|
* this hook is responsible for rendering typed text on the input row.
|
|
19282
|
-
* During streaming (writeDepth > 0), only the input
|
|
19485
|
+
* During streaming (writeDepth > 0), only the input rows are updated using
|
|
19283
19486
|
* cursor save/restore so the streaming position isn't disrupted.
|
|
19284
19487
|
* When idle (writeDepth === 0), the full footer is redrawn.
|
|
19285
19488
|
*/
|
|
@@ -19899,7 +20102,7 @@ async function startInteractive(config, repoPath) {
|
|
|
19899
20102
|
let sessionToolCallCount = 0;
|
|
19900
20103
|
let sessionSudoPassword = null;
|
|
19901
20104
|
let sudoPromptPending = false;
|
|
19902
|
-
const idlePrompt = `${c2.bold(c2.white("\
|
|
20105
|
+
const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
|
|
19903
20106
|
const activePrompt = `${c2.bold(c2.white("+ "))}`;
|
|
19904
20107
|
const rl = readline2.createInterface({
|
|
19905
20108
|
input: process.stdin,
|
package/package.json
CHANGED