@cydm/pie 1.0.42 → 1.0.43
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/cli.js +386 -90
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -46314,6 +46314,24 @@ var SettingsManager = class {
|
|
|
46314
46314
|
getBellNotificationsEnabled() {
|
|
46315
46315
|
return this.settings.notifications?.bell !== false;
|
|
46316
46316
|
}
|
|
46317
|
+
setBellNotificationsEnabled(enabled) {
|
|
46318
|
+
this.settings.notifications = { ...this.settings.notifications, bell: enabled };
|
|
46319
|
+
this.writeSettings();
|
|
46320
|
+
}
|
|
46321
|
+
getDesktopNotificationsEnabled() {
|
|
46322
|
+
return this.settings.notifications?.desktop !== false;
|
|
46323
|
+
}
|
|
46324
|
+
setDesktopNotificationsEnabled(enabled) {
|
|
46325
|
+
this.settings.notifications = { ...this.settings.notifications, desktop: enabled };
|
|
46326
|
+
this.writeSettings();
|
|
46327
|
+
}
|
|
46328
|
+
getCalmModeEnabled() {
|
|
46329
|
+
return this.settings.calmMode === true;
|
|
46330
|
+
}
|
|
46331
|
+
setCalmModeEnabled(enabled) {
|
|
46332
|
+
this.settings.calmMode = enabled;
|
|
46333
|
+
this.writeSettings();
|
|
46334
|
+
}
|
|
46317
46335
|
// ==========================================================================
|
|
46318
46336
|
// Extension enablement (user ~/.pie/settings.json + project ./.pie/settings.json)
|
|
46319
46337
|
// ==========================================================================
|
|
@@ -49807,10 +49825,15 @@ var Text = class {
|
|
|
49807
49825
|
for (const line of wrappedLines) {
|
|
49808
49826
|
const lineWithMargins = leftMargin + line + rightMargin;
|
|
49809
49827
|
if (this.customBgFn) {
|
|
49810
|
-
|
|
49828
|
+
const clamped = visibleWidth(lineWithMargins) > width ? truncateToWidth(lineWithMargins, width, "") : lineWithMargins;
|
|
49829
|
+
contentLines.push(applyBackgroundToLine(clamped, width, this.customBgFn));
|
|
49811
49830
|
} else {
|
|
49812
49831
|
const visibleLen = visibleWidth(lineWithMargins);
|
|
49813
|
-
|
|
49832
|
+
if (visibleLen > width) {
|
|
49833
|
+
contentLines.push(truncateToWidth(lineWithMargins, width, ""));
|
|
49834
|
+
continue;
|
|
49835
|
+
}
|
|
49836
|
+
const paddingNeeded = width - visibleLen;
|
|
49814
49837
|
contentLines.push(lineWithMargins + " ".repeat(paddingNeeded));
|
|
49815
49838
|
}
|
|
49816
49839
|
}
|
|
@@ -50369,6 +50392,8 @@ var TUI = class extends Container {
|
|
|
50369
50392
|
// Track previous viewport top for resize-aware cursor moves
|
|
50370
50393
|
fullRedrawCount = 0;
|
|
50371
50394
|
stopped = false;
|
|
50395
|
+
/** Guard: never paint before terminal.start() has run (modes like DECAWM-off are set there). */
|
|
50396
|
+
started = false;
|
|
50372
50397
|
constructor(terminal, showHardwareCursor) {
|
|
50373
50398
|
super();
|
|
50374
50399
|
this.terminal = terminal;
|
|
@@ -50431,6 +50456,7 @@ var TUI = class extends Container {
|
|
|
50431
50456
|
}
|
|
50432
50457
|
start() {
|
|
50433
50458
|
this.stopped = false;
|
|
50459
|
+
this.started = true;
|
|
50434
50460
|
this.terminal.start(
|
|
50435
50461
|
(data) => this.handleInput(data),
|
|
50436
50462
|
() => this.requestRender()
|
|
@@ -50470,6 +50496,7 @@ var TUI = class extends Container {
|
|
|
50470
50496
|
this.previousViewportTop = 0;
|
|
50471
50497
|
}
|
|
50472
50498
|
if (this.renderRequested) return;
|
|
50499
|
+
if (!this.started || this.stopped) return;
|
|
50473
50500
|
this.renderRequested = true;
|
|
50474
50501
|
process.nextTick(() => {
|
|
50475
50502
|
this.renderRequested = false;
|
|
@@ -50809,7 +50836,7 @@ var SelectList = class {
|
|
|
50809
50836
|
render(width) {
|
|
50810
50837
|
const lines = [];
|
|
50811
50838
|
if (this.filteredItems.length === 0) {
|
|
50812
|
-
lines.push(this.theme.noMatch(" No matching commands"));
|
|
50839
|
+
lines.push(truncateToWidth(this.theme.noMatch(" No matching commands"), width));
|
|
50813
50840
|
return lines;
|
|
50814
50841
|
}
|
|
50815
50842
|
const { startIndex, endIndex } = this.getVisibleRange();
|
|
@@ -51133,8 +51160,8 @@ var Editor = class {
|
|
|
51133
51160
|
const rightPadding = leftPadding;
|
|
51134
51161
|
if (this.scrollOffset > 0) {
|
|
51135
51162
|
const indicator = `\u2500\u2500\u2500 \u2191 ${this.scrollOffset} more `;
|
|
51136
|
-
const
|
|
51137
|
-
result.push(this.borderColor(indicator + "
|
|
51163
|
+
const fill = "\u2500".repeat(Math.max(0, width - visibleWidth(indicator)));
|
|
51164
|
+
result.push(this.borderColor(truncateToWidth(indicator + fill, width, "")));
|
|
51138
51165
|
} else {
|
|
51139
51166
|
result.push(horizontal.repeat(width));
|
|
51140
51167
|
}
|
|
@@ -51164,13 +51191,13 @@ var Editor = class {
|
|
|
51164
51191
|
}
|
|
51165
51192
|
const padding = " ".repeat(Math.max(0, contentWidth - lineVisibleWidth));
|
|
51166
51193
|
const lineRightPadding = cursorInPadding ? rightPadding.slice(1) : rightPadding;
|
|
51167
|
-
result.push(`${leftPadding}${displayText}${padding}${lineRightPadding}
|
|
51194
|
+
result.push(truncateToWidth(`${leftPadding}${displayText}${padding}${lineRightPadding}`, width, ""));
|
|
51168
51195
|
}
|
|
51169
51196
|
const linesBelow = layoutLines.length - (this.scrollOffset + visibleLines.length);
|
|
51170
51197
|
if (linesBelow > 0) {
|
|
51171
51198
|
const indicator = `\u2500\u2500\u2500 \u2193 ${linesBelow} more `;
|
|
51172
|
-
const
|
|
51173
|
-
result.push(this.borderColor(indicator + "
|
|
51199
|
+
const fill = "\u2500".repeat(Math.max(0, width - visibleWidth(indicator)));
|
|
51200
|
+
result.push(this.borderColor(truncateToWidth(indicator + fill, width, "")));
|
|
51174
51201
|
} else {
|
|
51175
51202
|
result.push(horizontal.repeat(width));
|
|
51176
51203
|
}
|
|
@@ -51728,26 +51755,55 @@ var Editor = class {
|
|
|
51728
51755
|
/**
|
|
51729
51756
|
* Move cursor to a target visual line, applying sticky column logic.
|
|
51730
51757
|
* Shared by moveCursor() and pageScroll().
|
|
51758
|
+
*
|
|
51759
|
+
* Column math is done in terminal columns (visibleWidth), not UTF-16 code
|
|
51760
|
+
* units, so CJK/emoji text keeps the cursor visually aligned when moving
|
|
51761
|
+
* up/down across wrapped segments.
|
|
51731
51762
|
*/
|
|
51732
51763
|
moveToVisualLine(visualLines, currentVisualLine, targetVisualLine) {
|
|
51733
51764
|
const currentVL = visualLines[currentVisualLine];
|
|
51734
51765
|
const targetVL = visualLines[targetVisualLine];
|
|
51735
51766
|
if (currentVL && targetVL) {
|
|
51736
|
-
const
|
|
51767
|
+
const sourceLine = this.state.lines[currentVL.logicalLine] || "";
|
|
51768
|
+
const sourceText = sourceLine.slice(currentVL.startUnit, currentVL.startUnit + currentVL.lengthUnits);
|
|
51769
|
+
const currentVisualCol = visibleWidth(sourceLine.slice(currentVL.startUnit, this.state.cursorCol));
|
|
51737
51770
|
const isLastSourceSegment = currentVisualLine === visualLines.length - 1 || visualLines[currentVisualLine + 1]?.logicalLine !== currentVL.logicalLine;
|
|
51738
|
-
const sourceMaxVisualCol = isLastSourceSegment ? currentVL.
|
|
51771
|
+
const sourceMaxVisualCol = isLastSourceSegment ? currentVL.widthCols : Math.max(0, currentVL.widthCols - this.lastGraphemeColumns(sourceText));
|
|
51772
|
+
const targetLine = this.state.lines[targetVL.logicalLine] || "";
|
|
51773
|
+
const targetText = targetLine.slice(targetVL.startUnit, targetVL.startUnit + targetVL.lengthUnits);
|
|
51739
51774
|
const isLastTargetSegment = targetVisualLine === visualLines.length - 1 || visualLines[targetVisualLine + 1]?.logicalLine !== targetVL.logicalLine;
|
|
51740
|
-
const targetMaxVisualCol = isLastTargetSegment ? targetVL.
|
|
51775
|
+
const targetMaxVisualCol = isLastTargetSegment ? targetVL.widthCols : Math.max(0, targetVL.widthCols - this.lastGraphemeColumns(targetText));
|
|
51741
51776
|
const moveToVisualCol = this.computeVerticalMoveColumn(
|
|
51742
51777
|
currentVisualCol,
|
|
51743
51778
|
sourceMaxVisualCol,
|
|
51744
51779
|
targetMaxVisualCol
|
|
51745
51780
|
);
|
|
51746
51781
|
this.state.cursorLine = targetVL.logicalLine;
|
|
51747
|
-
const targetCol = targetVL.
|
|
51748
|
-
|
|
51749
|
-
|
|
51782
|
+
const targetCol = targetVL.startUnit + this.columnToUnit(targetText, moveToVisualCol);
|
|
51783
|
+
this.state.cursorCol = Math.min(targetCol, targetLine.length);
|
|
51784
|
+
}
|
|
51785
|
+
}
|
|
51786
|
+
/** Map a terminal-column offset to the closest code-unit offset at or before it. */
|
|
51787
|
+
columnToUnit(text, col) {
|
|
51788
|
+
if (col <= 0) return 0;
|
|
51789
|
+
let units = 0;
|
|
51790
|
+
let cols = 0;
|
|
51791
|
+
for (const seg of segmenter2.segment(text)) {
|
|
51792
|
+
const width = visibleWidth(seg.segment);
|
|
51793
|
+
if (cols + width > col) break;
|
|
51794
|
+
cols += width;
|
|
51795
|
+
units += seg.segment.length;
|
|
51796
|
+
}
|
|
51797
|
+
return units;
|
|
51798
|
+
}
|
|
51799
|
+
/** Visible width (columns) of the last grapheme of a non-empty string. */
|
|
51800
|
+
lastGraphemeColumns(text) {
|
|
51801
|
+
if (!text) return 0;
|
|
51802
|
+
let width = 0;
|
|
51803
|
+
for (const seg of segmenter2.segment(text)) {
|
|
51804
|
+
width = visibleWidth(seg.segment);
|
|
51750
51805
|
}
|
|
51806
|
+
return width;
|
|
51751
51807
|
}
|
|
51752
51808
|
/**
|
|
51753
51809
|
* Compute the target visual column for vertical cursor movement.
|
|
@@ -51937,11 +51993,8 @@ var Editor = class {
|
|
|
51937
51993
|
}
|
|
51938
51994
|
}
|
|
51939
51995
|
/**
|
|
51940
|
-
*
|
|
51941
|
-
*
|
|
51942
|
-
* - logicalLine: index into this.state.lines
|
|
51943
|
-
* - startCol: starting column in the logical line
|
|
51944
|
-
* - length: length of this visual line segment
|
|
51996
|
+
* A wrapped segment of a logical line: both UTF-16 offsets (for editing)
|
|
51997
|
+
* and terminal columns (for visual cursor movement) are tracked.
|
|
51945
51998
|
*/
|
|
51946
51999
|
buildVisualLineMap(width) {
|
|
51947
52000
|
const visualLines = [];
|
|
@@ -51949,17 +52002,22 @@ var Editor = class {
|
|
|
51949
52002
|
const line = this.state.lines[i] || "";
|
|
51950
52003
|
const lineVisWidth = visibleWidth(line);
|
|
51951
52004
|
if (line.length === 0) {
|
|
51952
|
-
visualLines.push({ logicalLine: i, startCol: 0,
|
|
52005
|
+
visualLines.push({ logicalLine: i, startUnit: 0, lengthUnits: 0, startCol: 0, widthCols: 0 });
|
|
51953
52006
|
} else if (lineVisWidth <= width) {
|
|
51954
|
-
visualLines.push({ logicalLine: i,
|
|
52007
|
+
visualLines.push({ logicalLine: i, startUnit: 0, lengthUnits: line.length, startCol: 0, widthCols: lineVisWidth });
|
|
51955
52008
|
} else {
|
|
51956
52009
|
const chunks = wordWrapLine(line, width);
|
|
52010
|
+
let col = 0;
|
|
51957
52011
|
for (const chunk of chunks) {
|
|
52012
|
+
const chunkWidth = visibleWidth(chunk.text);
|
|
51958
52013
|
visualLines.push({
|
|
51959
52014
|
logicalLine: i,
|
|
51960
|
-
|
|
51961
|
-
|
|
52015
|
+
startUnit: chunk.startIndex,
|
|
52016
|
+
lengthUnits: chunk.endIndex - chunk.startIndex,
|
|
52017
|
+
startCol: col,
|
|
52018
|
+
widthCols: chunkWidth
|
|
51962
52019
|
});
|
|
52020
|
+
col += chunkWidth;
|
|
51963
52021
|
}
|
|
51964
52022
|
}
|
|
51965
52023
|
}
|
|
@@ -51973,9 +52031,9 @@ var Editor = class {
|
|
|
51973
52031
|
const vl = visualLines[i];
|
|
51974
52032
|
if (!vl) continue;
|
|
51975
52033
|
if (vl.logicalLine === this.state.cursorLine) {
|
|
51976
|
-
const
|
|
52034
|
+
const unitInSegment = this.state.cursorCol - vl.startUnit;
|
|
51977
52035
|
const isLastSegmentOfLine = i === visualLines.length - 1 || visualLines[i + 1]?.logicalLine !== vl.logicalLine;
|
|
51978
|
-
if (
|
|
52036
|
+
if (unitInSegment >= 0 && (unitInSegment < vl.lengthUnits || isLastSegmentOfLine && unitInSegment <= vl.lengthUnits)) {
|
|
51979
52037
|
return i;
|
|
51980
52038
|
}
|
|
51981
52039
|
}
|
|
@@ -52361,7 +52419,14 @@ var Input = class {
|
|
|
52361
52419
|
}
|
|
52362
52420
|
setValue(value) {
|
|
52363
52421
|
this.value = value;
|
|
52364
|
-
|
|
52422
|
+
const clamped = Math.min(this.cursor, value.length);
|
|
52423
|
+
let units = 0;
|
|
52424
|
+
for (const seg of segmenter3.segment(value)) {
|
|
52425
|
+
const segLength = seg.segment.length;
|
|
52426
|
+
if (units + segLength > clamped) break;
|
|
52427
|
+
units += segLength;
|
|
52428
|
+
}
|
|
52429
|
+
this.cursor = units;
|
|
52365
52430
|
}
|
|
52366
52431
|
handleInput(data) {
|
|
52367
52432
|
if (data.includes("\x1B[200~")) {
|
|
@@ -52646,47 +52711,53 @@ var Input = class {
|
|
|
52646
52711
|
if (availableWidth <= 0) {
|
|
52647
52712
|
return [prompt];
|
|
52648
52713
|
}
|
|
52649
|
-
|
|
52650
|
-
|
|
52651
|
-
|
|
52652
|
-
|
|
52653
|
-
|
|
52654
|
-
const
|
|
52714
|
+
const cursorAtEnd = this.cursor >= this.value.length;
|
|
52715
|
+
const scrollWidth = cursorAtEnd ? Math.max(0, availableWidth - 1) : availableWidth;
|
|
52716
|
+
const valueGraphemes = [];
|
|
52717
|
+
let totalWidth = 0;
|
|
52718
|
+
for (const seg of segmenter3.segment(this.value)) {
|
|
52719
|
+
const text = seg.segment;
|
|
52720
|
+
const gWidth = visibleWidth(text);
|
|
52721
|
+
valueGraphemes.push({ text, startUnit: seg.index, startCol: totalWidth, width: gWidth });
|
|
52722
|
+
totalWidth += gWidth;
|
|
52723
|
+
}
|
|
52724
|
+
let cursorCol = 0;
|
|
52725
|
+
let cursorGraphemeIndex = valueGraphemes.length;
|
|
52726
|
+
for (let i = 0; i < valueGraphemes.length; i++) {
|
|
52727
|
+
const g2 = valueGraphemes[i];
|
|
52728
|
+
if (g2.startUnit >= this.cursor) break;
|
|
52729
|
+
cursorCol = g2.startCol + g2.width;
|
|
52730
|
+
cursorGraphemeIndex = i + 1;
|
|
52731
|
+
}
|
|
52732
|
+
const cursorCellWidth = valueGraphemes[cursorGraphemeIndex]?.width ?? 1;
|
|
52733
|
+
const cursorEndCol = cursorAtEnd ? cursorCol + 1 : cursorCol + cursorCellWidth;
|
|
52734
|
+
let startCol = 0;
|
|
52735
|
+
if (cursorEndCol > availableWidth) {
|
|
52655
52736
|
const halfWidth = Math.floor(scrollWidth / 2);
|
|
52656
|
-
|
|
52657
|
-
|
|
52658
|
-
|
|
52659
|
-
|
|
52660
|
-
start++;
|
|
52661
|
-
continue;
|
|
52662
|
-
}
|
|
52663
|
-
break;
|
|
52664
|
-
}
|
|
52665
|
-
return start;
|
|
52666
|
-
};
|
|
52667
|
-
const findValidEnd = (end) => {
|
|
52668
|
-
while (end > 0) {
|
|
52669
|
-
const charCode = this.value.charCodeAt(end - 1);
|
|
52670
|
-
if (charCode >= 55296 && charCode < 56320) {
|
|
52671
|
-
end--;
|
|
52672
|
-
continue;
|
|
52673
|
-
}
|
|
52674
|
-
break;
|
|
52675
|
-
}
|
|
52676
|
-
return end;
|
|
52677
|
-
};
|
|
52678
|
-
if (this.cursor < halfWidth) {
|
|
52679
|
-
visibleText = this.value.slice(0, findValidEnd(scrollWidth));
|
|
52680
|
-
cursorDisplay = this.cursor;
|
|
52681
|
-
} else if (this.cursor > this.value.length - halfWidth) {
|
|
52682
|
-
const start = findValidStart(this.value.length - scrollWidth);
|
|
52683
|
-
visibleText = this.value.slice(start);
|
|
52684
|
-
cursorDisplay = this.cursor - start;
|
|
52737
|
+
if (cursorCol < halfWidth) {
|
|
52738
|
+
startCol = 0;
|
|
52739
|
+
} else if (cursorEndCol > totalWidth - halfWidth) {
|
|
52740
|
+
startCol = Math.max(0, totalWidth - scrollWidth);
|
|
52685
52741
|
} else {
|
|
52686
|
-
|
|
52687
|
-
visibleText = this.value.slice(start, findValidEnd(start + scrollWidth));
|
|
52688
|
-
cursorDisplay = halfWidth;
|
|
52742
|
+
startCol = cursorCol - halfWidth;
|
|
52689
52743
|
}
|
|
52744
|
+
startCol = Math.max(0, Math.min(startCol, cursorEndCol - scrollWidth));
|
|
52745
|
+
}
|
|
52746
|
+
const windowEnd = startCol + scrollWidth;
|
|
52747
|
+
let visibleText = "";
|
|
52748
|
+
let cursorDisplay = 0;
|
|
52749
|
+
let cursorPlaced = false;
|
|
52750
|
+
for (const g2 of valueGraphemes) {
|
|
52751
|
+
if (g2.startCol >= startCol && g2.startCol + g2.width <= windowEnd) {
|
|
52752
|
+
if (!cursorPlaced && this.cursor <= g2.startUnit) {
|
|
52753
|
+
cursorDisplay = visibleText.length;
|
|
52754
|
+
cursorPlaced = true;
|
|
52755
|
+
}
|
|
52756
|
+
visibleText += g2.text;
|
|
52757
|
+
}
|
|
52758
|
+
}
|
|
52759
|
+
if (!cursorPlaced) {
|
|
52760
|
+
cursorDisplay = visibleText.length;
|
|
52690
52761
|
}
|
|
52691
52762
|
const graphemes = [...segmenter3.segment(visibleText.slice(cursorDisplay))];
|
|
52692
52763
|
const cursorGrapheme = graphemes[0];
|
|
@@ -53981,10 +54052,15 @@ var Markdown = class {
|
|
|
53981
54052
|
}
|
|
53982
54053
|
const lineWithMargins = leftMargin + line + rightMargin;
|
|
53983
54054
|
if (bgFn) {
|
|
53984
|
-
|
|
54055
|
+
const clamped = visibleWidth(lineWithMargins) > width ? truncateToWidth(lineWithMargins, width, "") : lineWithMargins;
|
|
54056
|
+
contentLines.push(applyBackgroundToLine(clamped, width, bgFn));
|
|
53985
54057
|
} else {
|
|
53986
54058
|
const visibleLen = visibleWidth(lineWithMargins);
|
|
53987
|
-
|
|
54059
|
+
if (visibleLen > width) {
|
|
54060
|
+
contentLines.push(truncateToWidth(lineWithMargins, width, ""));
|
|
54061
|
+
continue;
|
|
54062
|
+
}
|
|
54063
|
+
const paddingNeeded = width - visibleLen;
|
|
53988
54064
|
contentLines.push(lineWithMargins + " ".repeat(paddingNeeded));
|
|
53989
54065
|
}
|
|
53990
54066
|
}
|
|
@@ -54513,7 +54589,7 @@ var SettingsList = class {
|
|
|
54513
54589
|
lines.push("");
|
|
54514
54590
|
}
|
|
54515
54591
|
if (this.items.length === 0) {
|
|
54516
|
-
lines.push(this.theme.hint(" No settings available"));
|
|
54592
|
+
lines.push(truncateToWidth(this.theme.hint(" No settings available"), width));
|
|
54517
54593
|
if (this.searchEnabled) {
|
|
54518
54594
|
this.addHintLine(lines, width);
|
|
54519
54595
|
}
|
|
@@ -54554,7 +54630,7 @@ var SettingsList = class {
|
|
|
54554
54630
|
lines.push("");
|
|
54555
54631
|
const wrappedDesc = wrapTextWithAnsi(selectedItem.description, width - 4);
|
|
54556
54632
|
for (const line of wrappedDesc) {
|
|
54557
|
-
lines.push(this.theme.description(` ${line}`));
|
|
54633
|
+
lines.push(truncateToWidth(this.theme.description(` ${line}`), width));
|
|
54558
54634
|
}
|
|
54559
54635
|
}
|
|
54560
54636
|
this.addHintLine(lines, width);
|
|
@@ -54919,6 +54995,7 @@ var ProcessTerminal = class {
|
|
|
54919
54995
|
process.stdin.setEncoding("utf8");
|
|
54920
54996
|
process.stdin.resume();
|
|
54921
54997
|
process.stdout.write("\x1B[?2004h");
|
|
54998
|
+
process.stdout.write("\x1B[?7l");
|
|
54922
54999
|
process.stdout.on("resize", this.resizeHandler);
|
|
54923
55000
|
if (process.platform !== "win32") {
|
|
54924
55001
|
process.kill(process.pid, "SIGWINCH");
|
|
@@ -55030,6 +55107,7 @@ var ProcessTerminal = class {
|
|
|
55030
55107
|
}
|
|
55031
55108
|
stop() {
|
|
55032
55109
|
process.stdout.write("\x1B[?2004l");
|
|
55110
|
+
process.stdout.write("\x1B[?7h");
|
|
55033
55111
|
if (this._kittyProtocolActive && !process.env.PIE_DISABLE_KITTY_PROTOCOL) {
|
|
55034
55112
|
process.stdout.write("\x1B[<u");
|
|
55035
55113
|
this._kittyProtocolActive = false;
|
|
@@ -55093,7 +55171,26 @@ var ProcessTerminal = class {
|
|
|
55093
55171
|
setTitle(title) {
|
|
55094
55172
|
process.stdout.write(`\x1B]0;${title}\x07`);
|
|
55095
55173
|
}
|
|
55174
|
+
notify(title, body) {
|
|
55175
|
+
if (!process.stdout.isTTY) return;
|
|
55176
|
+
for (const sequence of buildDesktopNotificationSequences(title, body)) {
|
|
55177
|
+
process.stdout.write(sequence);
|
|
55178
|
+
}
|
|
55179
|
+
}
|
|
55096
55180
|
};
|
|
55181
|
+
var NOTIFICATION_UNSAFE_CHARS = /[\x00-\x1f\x7f-\x9f;]/g;
|
|
55182
|
+
function sanitizeNotificationText(text) {
|
|
55183
|
+
return text.replace(NOTIFICATION_UNSAFE_CHARS, "");
|
|
55184
|
+
}
|
|
55185
|
+
function buildDesktopNotificationSequences(title, body) {
|
|
55186
|
+
const sanitizedTitle = sanitizeNotificationText(title);
|
|
55187
|
+
const sanitizedBody = sanitizeNotificationText(body);
|
|
55188
|
+
return [
|
|
55189
|
+
`\x1B]9;${sanitizedTitle}: ${sanitizedBody}\x07`,
|
|
55190
|
+
`\x1B]777;notify;${sanitizedTitle};${sanitizedBody}\x07`,
|
|
55191
|
+
`\x1B]99;i=1:d=0;${sanitizedBody}\x07`
|
|
55192
|
+
];
|
|
55193
|
+
}
|
|
55097
55194
|
|
|
55098
55195
|
// src/extensions/runner.ts
|
|
55099
55196
|
function createLoggedProxy(obj, contextPrefix) {
|
|
@@ -61079,6 +61176,27 @@ var SettingsSelectorComponent = class extends Container {
|
|
|
61079
61176
|
}
|
|
61080
61177
|
)
|
|
61081
61178
|
},
|
|
61179
|
+
{
|
|
61180
|
+
id: "calm",
|
|
61181
|
+
label: "Calm Mode",
|
|
61182
|
+
description: "Show only questions and answers; hide tool runs and thinking",
|
|
61183
|
+
currentValue: config.calmMode ? "on" : "off",
|
|
61184
|
+
values: ["on", "off"]
|
|
61185
|
+
},
|
|
61186
|
+
{
|
|
61187
|
+
id: "notificationsBell",
|
|
61188
|
+
label: "Bell",
|
|
61189
|
+
description: "Ring the terminal bell when a turn needs you",
|
|
61190
|
+
currentValue: config.notificationsBell ? "on" : "off",
|
|
61191
|
+
values: ["on", "off"]
|
|
61192
|
+
},
|
|
61193
|
+
{
|
|
61194
|
+
id: "notificationsDesktop",
|
|
61195
|
+
label: "Desktop Notify",
|
|
61196
|
+
description: "Desktop notification (banner / dock badge) via terminal OSC",
|
|
61197
|
+
currentValue: config.notificationsDesktop ? "on" : "off",
|
|
61198
|
+
values: ["on", "off"]
|
|
61199
|
+
},
|
|
61082
61200
|
{
|
|
61083
61201
|
id: "extensions",
|
|
61084
61202
|
label: "Extensions",
|
|
@@ -61126,6 +61244,15 @@ var SettingsSelectorComponent = class extends Container {
|
|
|
61126
61244
|
case "thinking":
|
|
61127
61245
|
callbacks.onThinkingLevelChange(newValue);
|
|
61128
61246
|
break;
|
|
61247
|
+
case "calm":
|
|
61248
|
+
callbacks.onCalmToggle(newValue === "on");
|
|
61249
|
+
break;
|
|
61250
|
+
case "notificationsBell":
|
|
61251
|
+
callbacks.onBellNotificationsChange(newValue === "on");
|
|
61252
|
+
break;
|
|
61253
|
+
case "notificationsDesktop":
|
|
61254
|
+
callbacks.onDesktopNotificationsChange(newValue === "on");
|
|
61255
|
+
break;
|
|
61129
61256
|
}
|
|
61130
61257
|
},
|
|
61131
61258
|
callbacks.onCancel,
|
|
@@ -61698,6 +61825,7 @@ function handleExtensionsCommand(host, args) {
|
|
|
61698
61825
|
|
|
61699
61826
|
// src/slash-commands.ts
|
|
61700
61827
|
var BUILTIN_SLASH_COMMANDS = [
|
|
61828
|
+
{ name: "sessions", description: "Pick a saved session to switch to" },
|
|
61701
61829
|
{ name: "sessions/compact", description: "Summarize history and add a compact checkpoint to the session" },
|
|
61702
61830
|
{ name: "sessions/new", description: "Start a new session" },
|
|
61703
61831
|
{ name: "sessions/resume", description: "Resume a different session" },
|
|
@@ -61711,6 +61839,7 @@ var BUILTIN_SLASH_COMMANDS = [
|
|
|
61711
61839
|
{ name: "settings/model", description: "Select AI model" },
|
|
61712
61840
|
{ name: "settings/theme", description: "Change theme" },
|
|
61713
61841
|
{ name: "settings/thinking", description: "Set thinking level" },
|
|
61842
|
+
{ name: "settings/calm", description: "Toggle calm mode: show only questions and answers" },
|
|
61714
61843
|
{ name: "settings/yolo", description: "Toggle or set YOLO mode" },
|
|
61715
61844
|
{ name: "settings/debugs/cache-test", description: "Run provider cache diagnostics with a dedicated 2-request probe" },
|
|
61716
61845
|
{ name: "settings/debugs/context", description: "Append a context summary to ~/.pie/logs/pie-cli.log" },
|
|
@@ -62181,11 +62310,8 @@ var SessionSelectorComponent = class extends Container {
|
|
|
62181
62310
|
var RESET = "\x1B[0m";
|
|
62182
62311
|
var INVERSE = "\x1B[7m";
|
|
62183
62312
|
var DIM = "\x1B[2m";
|
|
62184
|
-
function stripAnsi(str2) {
|
|
62185
|
-
return str2.replace(/\x1b\[[0-9;]*m/g, "");
|
|
62186
|
-
}
|
|
62187
62313
|
function visibleLength(str2) {
|
|
62188
|
-
return
|
|
62314
|
+
return visibleWidth(str2);
|
|
62189
62315
|
}
|
|
62190
62316
|
var TREE_CHARS = {
|
|
62191
62317
|
branch: "\u251C\u2500\u2500 ",
|
|
@@ -62625,6 +62751,7 @@ var TreeSelectorComponent = class {
|
|
|
62625
62751
|
var AssistantMessageComponent = class extends Container {
|
|
62626
62752
|
contentContainer;
|
|
62627
62753
|
hideThinkingBlock;
|
|
62754
|
+
calmMode = false;
|
|
62628
62755
|
markdownTheme;
|
|
62629
62756
|
lastMessage;
|
|
62630
62757
|
constructor(message, hideThinkingBlock = false, markdownTheme = getMarkdownTheme()) {
|
|
@@ -62646,12 +62773,26 @@ var AssistantMessageComponent = class extends Container {
|
|
|
62646
62773
|
setHideThinkingBlock(hide) {
|
|
62647
62774
|
this.hideThinkingBlock = hide;
|
|
62648
62775
|
}
|
|
62776
|
+
/**
|
|
62777
|
+
* Calm mode: suppress thinking traces entirely (no "Thinking..." label,
|
|
62778
|
+
* no surrounding spacers). Errors and text still render.
|
|
62779
|
+
*/
|
|
62780
|
+
setCalmMode(calm) {
|
|
62781
|
+
if (this.calmMode === calm) return;
|
|
62782
|
+
this.calmMode = calm;
|
|
62783
|
+
if (this.lastMessage) {
|
|
62784
|
+
this.updateContent(this.lastMessage);
|
|
62785
|
+
}
|
|
62786
|
+
}
|
|
62787
|
+
isCalmMode() {
|
|
62788
|
+
return this.calmMode;
|
|
62789
|
+
}
|
|
62649
62790
|
updateContent(message) {
|
|
62650
62791
|
this.lastMessage = message;
|
|
62651
62792
|
this.contentContainer.clear();
|
|
62652
|
-
const
|
|
62653
|
-
|
|
62654
|
-
|
|
62793
|
+
const hasTextContent = message.content.some((c) => c.type === "text" && c.text.trim());
|
|
62794
|
+
const hasThinkingContent = message.content.some((c) => c.type === "thinking" && c.thinking.trim());
|
|
62795
|
+
const hasVisibleContent = this.calmMode ? hasTextContent : hasTextContent || hasThinkingContent;
|
|
62655
62796
|
if (hasVisibleContent) {
|
|
62656
62797
|
this.contentContainer.addChild(new Spacer(1));
|
|
62657
62798
|
}
|
|
@@ -62660,6 +62801,9 @@ var AssistantMessageComponent = class extends Container {
|
|
|
62660
62801
|
if (content.type === "text" && content.text.trim()) {
|
|
62661
62802
|
this.contentContainer.addChild(new Markdown(content.text.trim(), 1, 0, this.markdownTheme));
|
|
62662
62803
|
} else if (content.type === "thinking" && content.thinking.trim()) {
|
|
62804
|
+
if (this.calmMode) {
|
|
62805
|
+
continue;
|
|
62806
|
+
}
|
|
62663
62807
|
const hasVisibleContentAfter = message.content.slice(i + 1).some((c) => c.type === "text" && c.text.trim() || c.type === "thinking" && c.thinking.trim());
|
|
62664
62808
|
if (this.hideThinkingBlock) {
|
|
62665
62809
|
this.contentContainer.addChild(new Text(theme.italic(theme.fg("thinkingText", "Thinking...")), 1, 0));
|
|
@@ -63912,13 +64056,14 @@ async function loadSession(host, sessionId) {
|
|
|
63912
64056
|
}
|
|
63913
64057
|
if (contentBlocks.length > 0) {
|
|
63914
64058
|
const msgComponent = new AssistantMessageComponent(void 0, host.thinkingLevel === "off");
|
|
64059
|
+
msgComponent.setCalmMode(host.calmMode);
|
|
63915
64060
|
msgComponent.updateContent({
|
|
63916
64061
|
role: "assistant",
|
|
63917
64062
|
content: contentBlocks
|
|
63918
64063
|
});
|
|
63919
64064
|
host.chatContainer.addChild(msgComponent);
|
|
63920
64065
|
}
|
|
63921
|
-
if (Array.isArray(assistantMsg.content)) {
|
|
64066
|
+
if (Array.isArray(assistantMsg.content) && !host.calmMode) {
|
|
63922
64067
|
for (const c of assistantMsg.content) {
|
|
63923
64068
|
if (typeof c === "object" && c && "type" in c && c.type === "toolCall") {
|
|
63924
64069
|
const toolCall = c;
|
|
@@ -64196,7 +64341,9 @@ function renderMessageHistory(host, messages) {
|
|
|
64196
64341
|
stopReason: msg.stopReason,
|
|
64197
64342
|
errorMessage: msg.errorMessage
|
|
64198
64343
|
};
|
|
64199
|
-
|
|
64344
|
+
const msgComponent = new AssistantMessageComponent(assistantMsg, host.thinkingLevel === "off");
|
|
64345
|
+
msgComponent.setCalmMode(host.calmMode);
|
|
64346
|
+
host.chatContainer.addChild(msgComponent);
|
|
64200
64347
|
}
|
|
64201
64348
|
}
|
|
64202
64349
|
host.ui.requestRender();
|
|
@@ -64565,7 +64712,10 @@ function showSettingsSelector(host) {
|
|
|
64565
64712
|
availableThemes: getAvailableThemes(),
|
|
64566
64713
|
currentModel: currentFullId,
|
|
64567
64714
|
availableModels,
|
|
64568
|
-
yoloMode: host.yoloMode
|
|
64715
|
+
yoloMode: host.yoloMode,
|
|
64716
|
+
calmMode: host.calmMode,
|
|
64717
|
+
notificationsBell: host.options.settingsManager.getBellNotificationsEnabled(),
|
|
64718
|
+
notificationsDesktop: host.options.settingsManager.getDesktopNotificationsEnabled()
|
|
64569
64719
|
},
|
|
64570
64720
|
{
|
|
64571
64721
|
onThinkingLevelChange: (level) => {
|
|
@@ -64598,6 +64748,17 @@ function showSettingsSelector(host) {
|
|
|
64598
64748
|
await host.handleYoloCommand();
|
|
64599
64749
|
done();
|
|
64600
64750
|
},
|
|
64751
|
+
onCalmToggle: (enabled) => {
|
|
64752
|
+
host.setCalmMode(enabled);
|
|
64753
|
+
},
|
|
64754
|
+
onBellNotificationsChange: (enabled) => {
|
|
64755
|
+
host.options.settingsManager.setBellNotificationsEnabled(enabled);
|
|
64756
|
+
host.showStatus(`Bell notifications ${enabled ? "on" : "off"}`);
|
|
64757
|
+
},
|
|
64758
|
+
onDesktopNotificationsChange: (enabled) => {
|
|
64759
|
+
host.options.settingsManager.setDesktopNotificationsEnabled(enabled);
|
|
64760
|
+
host.showStatus(`Desktop notifications ${enabled ? "on" : "off"}`);
|
|
64761
|
+
},
|
|
64601
64762
|
createExtensionsSubmenu: (onCancel) => createExtensionSelector(host, "user", onCancel),
|
|
64602
64763
|
onHelp: () => {
|
|
64603
64764
|
host.handleHotkeysCommand();
|
|
@@ -64791,6 +64952,23 @@ function handleThinkingCommand(host, level) {
|
|
|
64791
64952
|
}
|
|
64792
64953
|
host.setThinkingLevel(level);
|
|
64793
64954
|
}
|
|
64955
|
+
async function handleCalmCommand(host, args) {
|
|
64956
|
+
const mode = (args || "").trim().toLowerCase();
|
|
64957
|
+
if (mode === "status") {
|
|
64958
|
+
host.showStatus(`Calm mode is ${host.calmMode ? "on" : "off"}`);
|
|
64959
|
+
return;
|
|
64960
|
+
}
|
|
64961
|
+
if (mode && !["on", "off", "enable", "enabled", "disable", "disabled", "true", "false", "1", "0"].includes(mode)) {
|
|
64962
|
+
host.showStatus("Usage: /settings/calm [on|off|status]");
|
|
64963
|
+
return;
|
|
64964
|
+
}
|
|
64965
|
+
const nextCalmMode = mode ? ["on", "enable", "enabled", "true", "1"].includes(mode) : !host.calmMode;
|
|
64966
|
+
if (host.calmMode === nextCalmMode) {
|
|
64967
|
+
host.showStatus(`Calm mode already ${host.calmMode ? "on" : "off"}`);
|
|
64968
|
+
return;
|
|
64969
|
+
}
|
|
64970
|
+
host.setCalmMode(nextCalmMode);
|
|
64971
|
+
}
|
|
64794
64972
|
async function handleYoloCommand(host, args) {
|
|
64795
64973
|
const mode = (args || "").trim().toLowerCase();
|
|
64796
64974
|
if (mode === "status") {
|
|
@@ -65060,6 +65238,10 @@ function createExtensionContextForCommands(host) {
|
|
|
65060
65238
|
};
|
|
65061
65239
|
}
|
|
65062
65240
|
function registerBuiltinCommands(host) {
|
|
65241
|
+
commandTree.register(["sessions"], {
|
|
65242
|
+
description: "Pick a saved session to switch to (tree/fork/new below)",
|
|
65243
|
+
handler: () => host.handleResumeCommand()
|
|
65244
|
+
});
|
|
65063
65245
|
commandTree.register(["sessions", "compact"], {
|
|
65064
65246
|
description: "Summarize history and replace it with a compact checkpoint",
|
|
65065
65247
|
handler: () => host.handleCompactCommand()
|
|
@@ -65112,6 +65294,10 @@ function registerBuiltinCommands(host) {
|
|
|
65112
65294
|
description: "Toggle or set YOLO mode (on/off/status)",
|
|
65113
65295
|
handler: (_2, args) => host.handleYoloCommand(args)
|
|
65114
65296
|
});
|
|
65297
|
+
commandTree.register(["settings", "calm"], {
|
|
65298
|
+
description: "Toggle calm mode: show only questions and answers (on/off/status)",
|
|
65299
|
+
handler: (_2, args) => host.handleCalmCommand(args)
|
|
65300
|
+
});
|
|
65115
65301
|
commandTree.register(["settings", "extensions"], {
|
|
65116
65302
|
description: "List extensions and manage enable/disable toggles",
|
|
65117
65303
|
handler: (_2, args) => host.handleExtensionsCommand(args)
|
|
@@ -65307,7 +65493,37 @@ function ringTerminalBell(options = {}) {
|
|
|
65307
65493
|
function ringTurnSettledBell(host) {
|
|
65308
65494
|
if ((host.agentSessionController?.pendingMessageCount ?? 0) > 0) return;
|
|
65309
65495
|
if (host.executionState.read().awaitingContinuation) return;
|
|
65310
|
-
host.ringAttentionBell?.();
|
|
65496
|
+
host.ringAttentionBell?.("turn-settled");
|
|
65497
|
+
}
|
|
65498
|
+
function attentionMessage(reason) {
|
|
65499
|
+
switch (reason) {
|
|
65500
|
+
case "interaction":
|
|
65501
|
+
return { title: "Pie", body: "Waiting for your input" };
|
|
65502
|
+
case "turn-settled":
|
|
65503
|
+
return { title: "Pie", body: "Response ready" };
|
|
65504
|
+
case "turn-failed":
|
|
65505
|
+
return { title: "Pie", body: "Turn failed" };
|
|
65506
|
+
case "stall-recovery":
|
|
65507
|
+
return { title: "Pie", body: "Recovered from a stalled turn" };
|
|
65508
|
+
}
|
|
65509
|
+
}
|
|
65510
|
+
var DEFAULT_NOTIFICATION_MIN_INTERVAL_MS = 1e3;
|
|
65511
|
+
var lastNotificationAtMs = 0;
|
|
65512
|
+
function sendDesktopNotification(reason, options = {}) {
|
|
65513
|
+
const {
|
|
65514
|
+
enabled = true,
|
|
65515
|
+
terminal,
|
|
65516
|
+
now = Date.now,
|
|
65517
|
+
minIntervalMs = DEFAULT_NOTIFICATION_MIN_INTERVAL_MS
|
|
65518
|
+
} = options;
|
|
65519
|
+
if (!enabled) return false;
|
|
65520
|
+
if (!terminal || typeof terminal.notify !== "function") return false;
|
|
65521
|
+
const atMs = now();
|
|
65522
|
+
if (atMs - lastNotificationAtMs < minIntervalMs) return false;
|
|
65523
|
+
lastNotificationAtMs = atMs;
|
|
65524
|
+
const { title, body } = attentionMessage(reason);
|
|
65525
|
+
terminal.notify(title, body);
|
|
65526
|
+
return true;
|
|
65311
65527
|
}
|
|
65312
65528
|
|
|
65313
65529
|
// src/runtime/interactive-runtime-events.ts
|
|
@@ -65515,7 +65731,7 @@ function handleSemanticAgentEvent(host, event) {
|
|
|
65515
65731
|
host.appendWarningSummary(outcome.terminalSummary);
|
|
65516
65732
|
}
|
|
65517
65733
|
host.sessionTrace.completeTurn(event.message, true);
|
|
65518
|
-
host.ringAttentionBell?.();
|
|
65734
|
+
host.ringAttentionBell?.("turn-failed");
|
|
65519
65735
|
host._semanticTurnIndex++;
|
|
65520
65736
|
break;
|
|
65521
65737
|
}
|
|
@@ -65556,6 +65772,7 @@ function handleMessageStart(host, event) {
|
|
|
65556
65772
|
if (event.message?.role === "assistant") {
|
|
65557
65773
|
host.clearContinuationTimeout("assistant_message_start");
|
|
65558
65774
|
host.streamingComponent = new AssistantMessageComponent(void 0, host.thinkingLevel === "off");
|
|
65775
|
+
host.streamingComponent.setCalmMode(host.calmMode);
|
|
65559
65776
|
host.chatContainer.addChild(host.streamingComponent);
|
|
65560
65777
|
host.sessionTrace.updateAssistantMessage(event.message);
|
|
65561
65778
|
}
|
|
@@ -65584,6 +65801,9 @@ function handleMessageUpdate(host, event) {
|
|
|
65584
65801
|
thinkingContent += content2.thinking || "";
|
|
65585
65802
|
} else if (content2.type === "toolCall") {
|
|
65586
65803
|
toolCallCount += 1;
|
|
65804
|
+
if (host.calmMode) {
|
|
65805
|
+
continue;
|
|
65806
|
+
}
|
|
65587
65807
|
const toolCall = content2;
|
|
65588
65808
|
const contentIndex = message.content.indexOf(content2);
|
|
65589
65809
|
const partialToolId = `__partial_tool__:${contentIndex}`;
|
|
@@ -65649,7 +65869,7 @@ function findToolRenderHint(host, toolName) {
|
|
|
65649
65869
|
function handleToolStart(host, event) {
|
|
65650
65870
|
host.logDebug("tool:start", { toolName: event.toolName, toolCallId: event.toolCallId });
|
|
65651
65871
|
host.sessionTrace.startTool(event.toolCallId, event.toolName, event.args);
|
|
65652
|
-
if (event.toolCallId) {
|
|
65872
|
+
if (event.toolCallId && !host.calmMode) {
|
|
65653
65873
|
const toolComponent = host.pendingTools.get(event.toolCallId);
|
|
65654
65874
|
if (toolComponent) {
|
|
65655
65875
|
toolComponent.updateArgs(event.args);
|
|
@@ -65740,6 +65960,22 @@ function handleMessageEnd(host, event) {
|
|
|
65740
65960
|
host.safeRequestRender();
|
|
65741
65961
|
}
|
|
65742
65962
|
|
|
65963
|
+
// src/runtime/interactive-calm.ts
|
|
65964
|
+
function applyCalmMode(host, enabled) {
|
|
65965
|
+
const streaming = host.streamingComponent;
|
|
65966
|
+
if (streaming) {
|
|
65967
|
+
streaming.setCalmMode(enabled);
|
|
65968
|
+
}
|
|
65969
|
+
host.chatContainer.clear();
|
|
65970
|
+
host.pendingTools.clear();
|
|
65971
|
+
host.lastStatusSpacer = void 0;
|
|
65972
|
+
host.lastStatusText = void 0;
|
|
65973
|
+
host.renderMessageHistory(host.sessionManager.getMessages());
|
|
65974
|
+
if (streaming) {
|
|
65975
|
+
host.chatContainer.addChild(streaming);
|
|
65976
|
+
}
|
|
65977
|
+
}
|
|
65978
|
+
|
|
65743
65979
|
// src/input/interactive-input-pipeline.ts
|
|
65744
65980
|
function shouldQueueUserInput(host) {
|
|
65745
65981
|
return host.submitLock || (host.agentSessionController?.hasQueuedMessages ?? false);
|
|
@@ -67880,6 +68116,13 @@ function isCommandLikeInput(text) {
|
|
|
67880
68116
|
// src/components/extension-widgets.ts
|
|
67881
68117
|
var ExtensionWidgetsComponent = class extends Container {
|
|
67882
68118
|
slots = /* @__PURE__ */ new Map();
|
|
68119
|
+
calmMode = false;
|
|
68120
|
+
/** Calm mode hides ambient extension widgets (slots keep their data). */
|
|
68121
|
+
setCalmMode(calm) {
|
|
68122
|
+
if (this.calmMode === calm) return;
|
|
68123
|
+
this.calmMode = calm;
|
|
68124
|
+
this.rebuild();
|
|
68125
|
+
}
|
|
67883
68126
|
setWidget(key, lines) {
|
|
67884
68127
|
const normalized = (lines ?? []).map((line) => String(line ?? "")).filter((line) => line.trim().length > 0);
|
|
67885
68128
|
if (normalized.length === 0) {
|
|
@@ -67896,6 +68139,9 @@ var ExtensionWidgetsComponent = class extends Container {
|
|
|
67896
68139
|
}
|
|
67897
68140
|
rebuild() {
|
|
67898
68141
|
this.clear();
|
|
68142
|
+
if (this.calmMode) {
|
|
68143
|
+
return;
|
|
68144
|
+
}
|
|
67899
68145
|
for (const lines of this.slots.values()) {
|
|
67900
68146
|
for (const line of lines) {
|
|
67901
68147
|
this.addChild(new Text(theme.fg("dim", `\xB7 ${line}`), 1, 0));
|
|
@@ -68007,9 +68253,10 @@ var FooterComponent = class {
|
|
|
68007
68253
|
if (visibleWidth(pwd) > width) {
|
|
68008
68254
|
const half = Math.floor(width / 2) - 2;
|
|
68009
68255
|
if (half > 1) {
|
|
68010
|
-
const
|
|
68011
|
-
const
|
|
68012
|
-
|
|
68256
|
+
const total = visibleWidth(pwd);
|
|
68257
|
+
const head = sliceByColumn(pwd, 0, half);
|
|
68258
|
+
const tail = sliceByColumn(pwd, Math.max(0, total - (half - 1)), half - 1);
|
|
68259
|
+
pwd = `${head}...${tail}`;
|
|
68013
68260
|
} else {
|
|
68014
68261
|
pwd = truncateToWidth(pwd, width);
|
|
68015
68262
|
}
|
|
@@ -68035,6 +68282,9 @@ var FooterComponent = class {
|
|
|
68035
68282
|
if (state.planMode) {
|
|
68036
68283
|
statsParts.push(theme.fg("accent", "[PLAN]"));
|
|
68037
68284
|
}
|
|
68285
|
+
if (state.calmMode) {
|
|
68286
|
+
statsParts.push(theme.fg("dim", "[CALM]"));
|
|
68287
|
+
}
|
|
68038
68288
|
if (state.yoloMode) {
|
|
68039
68289
|
statsParts.push(theme.fg("warning", "[YOLO]"));
|
|
68040
68290
|
}
|
|
@@ -68078,8 +68328,8 @@ var FooterComponent = class {
|
|
|
68078
68328
|
const availableForRight = width - statsLeftWidth - minPadding;
|
|
68079
68329
|
if (availableForRight > 3) {
|
|
68080
68330
|
const plainRight = rightSide.replace(/\x1b\[[0-9;]*m/g, "");
|
|
68081
|
-
const truncated = plainRight
|
|
68082
|
-
const padding = " ".repeat(width - statsLeftWidth - truncated
|
|
68331
|
+
const truncated = truncateToWidth(plainRight, availableForRight, "");
|
|
68332
|
+
const padding = " ".repeat(Math.max(0, width - statsLeftWidth - visibleWidth(truncated)));
|
|
68083
68333
|
statsLine = statsLeft + padding + truncated;
|
|
68084
68334
|
} else {
|
|
68085
68335
|
statsLine = truncateToWidth(statsLeft, width);
|
|
@@ -68096,13 +68346,27 @@ var FooterComponent = class {
|
|
|
68096
68346
|
// src/components/todo-widget.ts
|
|
68097
68347
|
var TodoWidgetComponent = class extends Container {
|
|
68098
68348
|
state;
|
|
68349
|
+
calmMode = false;
|
|
68099
68350
|
constructor(state) {
|
|
68100
68351
|
super();
|
|
68101
68352
|
this.state = state;
|
|
68102
68353
|
void this.refresh();
|
|
68103
68354
|
}
|
|
68355
|
+
/** Calm mode hides the progress widget (questions/answers only). */
|
|
68356
|
+
setCalmMode(calm) {
|
|
68357
|
+
if (this.calmMode === calm) return;
|
|
68358
|
+
this.calmMode = calm;
|
|
68359
|
+
if (calm) {
|
|
68360
|
+
this.clear();
|
|
68361
|
+
} else {
|
|
68362
|
+
void this.refresh();
|
|
68363
|
+
}
|
|
68364
|
+
}
|
|
68104
68365
|
async refresh() {
|
|
68105
68366
|
this.clear();
|
|
68367
|
+
if (this.calmMode) {
|
|
68368
|
+
return;
|
|
68369
|
+
}
|
|
68106
68370
|
const lines = renderExecutionWidgetLines(this.state.getWidgetSteps());
|
|
68107
68371
|
if (lines.length === 0) {
|
|
68108
68372
|
return;
|
|
@@ -68390,6 +68654,7 @@ function setupUI(host) {
|
|
|
68390
68654
|
modelName: host.options.model ? `${host.options.model.provider}/${host.options.model.id}` : "unknown",
|
|
68391
68655
|
status: "ready",
|
|
68392
68656
|
planMode: host.planModeEnabled,
|
|
68657
|
+
calmMode: host.calmMode,
|
|
68393
68658
|
yoloMode: Boolean(host.yoloMode),
|
|
68394
68659
|
thinkingLevel: host.thinkingLevel,
|
|
68395
68660
|
contextWindow: host.options.model?.contextWindow ?? 0
|
|
@@ -68918,7 +69183,7 @@ async function recoverHardStalledTurn(host, stalledMs) {
|
|
|
68918
69183
|
void host.refreshTodoWidget();
|
|
68919
69184
|
host.footer.setState({ status: "ready" });
|
|
68920
69185
|
host.safeRequestRender();
|
|
68921
|
-
host.ringAttentionBell?.();
|
|
69186
|
+
host.ringAttentionBell?.("stall-recovery");
|
|
68922
69187
|
appendWarningSummary(host, "Recovered from a stalled turn (no progress for " + Math.round(stalledMs / 1e3) + "s). The previous turn was interrupted; review its partial output before continuing.");
|
|
68923
69188
|
if (abortOutcome.terminalSummary) {
|
|
68924
69189
|
appendWarningSummary(host, abortOutcome.terminalSummary);
|
|
@@ -69175,7 +69440,7 @@ function createInteractiveAgentSessionController(host) {
|
|
|
69175
69440
|
host.showStatus("Todo list preserved. Send 'continue' when you want to resume it.");
|
|
69176
69441
|
}
|
|
69177
69442
|
host.showError(event.failure.message);
|
|
69178
|
-
host.ringAttentionBell?.();
|
|
69443
|
+
host.ringAttentionBell?.("turn-failed");
|
|
69179
69444
|
host.setControllerBusy(false);
|
|
69180
69445
|
} else if (event.type === "turn_cancelled") {
|
|
69181
69446
|
const outcome = host.executionState.abort();
|
|
@@ -69554,7 +69819,7 @@ function installInteractiveInteractionHandler(host) {
|
|
|
69554
69819
|
host.activeInteractionCount++;
|
|
69555
69820
|
host.setWaitingForUser(true);
|
|
69556
69821
|
host.footer.setState({ lifecycleEvent: "waiting_for_user_input" });
|
|
69557
|
-
host.ringAttentionBell?.();
|
|
69822
|
+
host.ringAttentionBell?.("interaction");
|
|
69558
69823
|
host.safeRequestRender();
|
|
69559
69824
|
};
|
|
69560
69825
|
const endWaitingForUser = () => {
|
|
@@ -70164,6 +70429,8 @@ var InteractiveMode = class {
|
|
|
70164
70429
|
mentionPickerOptions = [];
|
|
70165
70430
|
attachmentResolver;
|
|
70166
70431
|
yoloMode = false;
|
|
70432
|
+
/** Calm mode: render only questions and answers (display-only; persisted). */
|
|
70433
|
+
calmMode = false;
|
|
70167
70434
|
originalTools = [];
|
|
70168
70435
|
isInterrupting = false;
|
|
70169
70436
|
isCompacting = false;
|
|
@@ -70214,9 +70481,17 @@ var InteractiveMode = class {
|
|
|
70214
70481
|
* interaction prompts, turn completion/failure, and stall recovery. The
|
|
70215
70482
|
* bell itself enforces a cross-call-site cooldown; the settings gate here
|
|
70216
70483
|
* is the single opt-out point (settings.json `notifications.bell`).
|
|
70484
|
+
*
|
|
70485
|
+
* A desktop notification (OSC 9/777/99, gated by `notifications.desktop`)
|
|
70486
|
+
* rides along so the host terminal app can badge its dock icon / post a
|
|
70487
|
+
* notification-center banner — the persistent marker the bell can't give.
|
|
70217
70488
|
*/
|
|
70218
|
-
ringAttentionBell() {
|
|
70489
|
+
ringAttentionBell(reason) {
|
|
70219
70490
|
ringTerminalBell({ enabled: this.options.settingsManager.getBellNotificationsEnabled() });
|
|
70491
|
+
sendDesktopNotification(reason ?? "turn-settled", {
|
|
70492
|
+
enabled: this.options.settingsManager.getDesktopNotificationsEnabled(),
|
|
70493
|
+
terminal: this.ui.terminal
|
|
70494
|
+
});
|
|
70220
70495
|
}
|
|
70221
70496
|
getContinuationTimeoutMs() {
|
|
70222
70497
|
return getContinuationTimeoutMs();
|
|
@@ -70266,6 +70541,7 @@ var InteractiveMode = class {
|
|
|
70266
70541
|
this.originalTools = [...options.allTools];
|
|
70267
70542
|
this.skillsSection = formatSkillsForPrompt(options.skills);
|
|
70268
70543
|
this.knowledgeSection = buildCliProjectContextSection(options.cwd);
|
|
70544
|
+
this.calmMode = options.settingsManager.getCalmModeEnabled();
|
|
70269
70545
|
}
|
|
70270
70546
|
options;
|
|
70271
70547
|
get runtimeEventHost() {
|
|
@@ -70664,6 +70940,25 @@ var InteractiveMode = class {
|
|
|
70664
70940
|
async handleYoloCommand(args) {
|
|
70665
70941
|
return handleYoloCommand(this, args);
|
|
70666
70942
|
}
|
|
70943
|
+
/**
|
|
70944
|
+
* Toggle calm mode and rebuild the chat so already-rendered rows follow
|
|
70945
|
+
* the new mode. Delivery, tool execution, and session storage are
|
|
70946
|
+
* unaffected — this is purely a presentation change.
|
|
70947
|
+
*/
|
|
70948
|
+
setCalmMode(enabled) {
|
|
70949
|
+
if (this.calmMode === enabled) return;
|
|
70950
|
+
this.calmMode = enabled;
|
|
70951
|
+
this.options.settingsManager.setCalmModeEnabled(enabled);
|
|
70952
|
+
this.footer.setState({ calmMode: enabled });
|
|
70953
|
+
applyCalmMode(this, enabled);
|
|
70954
|
+
this.todoWidget.setCalmMode(enabled);
|
|
70955
|
+
this.extensionWidgets.setCalmMode(enabled);
|
|
70956
|
+
this.showStatus(`Calm mode ${enabled ? "on \u2014 showing questions and answers only" : "off"}`);
|
|
70957
|
+
this.safeRequestRender();
|
|
70958
|
+
}
|
|
70959
|
+
async handleCalmCommand(args) {
|
|
70960
|
+
return handleCalmCommand(this, args);
|
|
70961
|
+
}
|
|
70667
70962
|
setThinkingLevel(level) {
|
|
70668
70963
|
return setThinkingLevel(this, level);
|
|
70669
70964
|
}
|
|
@@ -72925,6 +73220,7 @@ async function startChat(initialPrompt, testCommand) {
|
|
|
72925
73220
|
}
|
|
72926
73221
|
flushEarlyLogs();
|
|
72927
73222
|
if (testCommand) {
|
|
73223
|
+
await interactive.run();
|
|
72928
73224
|
console.log(`[TEST] Auto-executing command: ${testCommand}`);
|
|
72929
73225
|
await new Promise((resolve7) => setTimeout(resolve7, 500));
|
|
72930
73226
|
await interactive.executeCommand(testCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cydm/pie",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.43",
|
|
4
4
|
"description": "Pie AI Agent CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
"test": "npm run test:offline",
|
|
19
19
|
"pretest:offline": "npm run build --workspace @pie/agent-framework && npm run build --workspace @pie/shared-headless-capabilities && npm run build",
|
|
20
20
|
"posttest:offline": "node --test --import tsx test/remote-model-catalog.test.ts",
|
|
21
|
-
"test:offline": "node --test --import tsx test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-extension.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/hierarchical-command-system.test.ts test/extensions-enablement.test.ts test/message-queue-unit.test.ts test/evals-harness.test.ts test/session-trace.test.ts test/runtime-mode-context.test.ts test/tool-policy.test.ts test/retry-policy.test.ts test/yolo-command.test.ts test/footer-lifecycle.test.ts test/files-utils.test.ts test/source-size-guard.test.ts test/runtime-logger.test.ts test/release-readiness.test.ts test/package-artifacts.test.ts test/code-intel-typescript-provider.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/skills-agents-discovery.test.ts test/skills-symlink.test.ts test/model-overrides.test.ts test/auth-storage.test.ts test/extension-register-provider.test.ts test/extension-reload.test.ts test/extension-terminal-input.test.ts test/extension-session-before-events.test.ts test/extension-widgets.test.ts test/extension-render-hint.test.ts test/extension-oauth-restore.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/session-selector.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/plan-mode-extension.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/direct-bash.test.ts test/terminal-bell.test.ts test/daily-agent-smoke.terminal.test.ts",
|
|
21
|
+
"test:offline": "node --test --import tsx test/core-services.test.ts test/cli.test.ts test/cli-auto-compaction.test.ts test/execution-state-manager.test.ts test/queued-steer-execution-state.test.ts test/architecture-boundaries.test.ts test/attachment-resolver.test.ts test/kimi-attachment-extension.test.ts test/document-attachment-extension.test.ts test/auto-compact-overflow.test.ts test/hierarchical-command-system.test.ts test/extensions-enablement.test.ts test/message-queue-unit.test.ts test/evals-harness.test.ts test/session-trace.test.ts test/runtime-mode-context.test.ts test/tool-policy.test.ts test/retry-policy.test.ts test/yolo-command.test.ts test/footer-lifecycle.test.ts test/files-utils.test.ts test/source-size-guard.test.ts test/runtime-logger.test.ts test/release-readiness.test.ts test/package-artifacts.test.ts test/code-intel-typescript-provider.test.ts test/init-extension-contract.test.ts test/skills-runtime.test.ts test/skills-agents-discovery.test.ts test/skills-symlink.test.ts test/model-overrides.test.ts test/auth-storage.test.ts test/extension-register-provider.test.ts test/extension-reload.test.ts test/extension-terminal-input.test.ts test/extension-session-before-events.test.ts test/extension-widgets.test.ts test/extension-render-hint.test.ts test/extension-oauth-restore.test.ts test/cross-host-parity.test.ts test/tool-name-rendering.test.ts test/session-selector.test.ts test/terminal-title.test.ts test/interactive-controller-title.test.ts test/todo-title.terminal.test.ts test/plan-mode-extension.test.ts test/tools-registry.test.ts test/system-prompt-contract.test.ts test/direct-bash.test.ts test/terminal-bell.test.ts test/calm-mode.test.ts test/daily-agent-smoke.terminal.test.ts",
|
|
22
22
|
"test:all": "npm run test:offline && npm run test:terminal:vitest",
|
|
23
|
-
"test:terminal:vitest": "vitest run test/mention-file-select.terminal.test.ts test/tool-partial-display.terminal.test.ts test/viewport-position-final.test.ts --no-file-parallelism",
|
|
23
|
+
"test:terminal:vitest": "vitest run test/mention-file-select.terminal.test.ts test/tool-partial-display.terminal.test.ts test/viewport-position-final.test.ts test/resume-header.terminal.test.ts --no-file-parallelism",
|
|
24
24
|
"test:todo-tui": "PIE_REAL_TODO_TUI=1 node --test --import tsx test/todo-closure.terminal.test.ts",
|
|
25
25
|
"test:daily-tui": "npm run test:daily-tui:quick",
|
|
26
26
|
"test:daily-tui:quick": "PIE_REAL_DAILY_TUI=1 PIE_DAILY_TUI_LEVEL=quick node --test --import tsx test/daily-agent-smoke.terminal.test.ts",
|