dsh-code 0.6.0 → 0.7.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/README.en.md +4 -2
- package/README.md +4 -2
- package/bin/deepseek.mjs +38 -3
- package/lib/index.mjs +1485 -906
- package/lib/startup.mjs +21 -9
- package/lib/theme-BEi4i_aN.mjs +624 -0
- package/lib/types/app.d.ts +31 -3
- package/lib/types/index.d.ts +1 -0
- package/lib/types/kernel-panels.d.ts +21 -0
- package/lib/types/mentions.d.ts +29 -12
- package/lib/types/models.d.ts +66 -0
- package/lib/types/render/animations.d.ts +175 -2
- package/lib/types/render/projection.d.ts +38 -7
- package/lib/types/render/status.d.ts +34 -13
- package/lib/types/startup.d.ts +12 -4
- package/lib/types/theme-panel.d.ts +24 -0
- package/lib/types/theme.d.ts +158 -2
- package/package.json +1 -1
- package/src/app.ts +510 -130
- package/src/index.ts +964 -900
- package/src/kernel-panels.ts +481 -419
- package/src/mentions.ts +57 -27
- package/src/models.ts +200 -66
- package/src/render/animations.ts +359 -2
- package/src/render/projection.ts +764 -655
- package/src/render/status.ts +744 -603
- package/src/startup.ts +119 -109
- package/src/theme-panel.ts +72 -0
- package/src/theme.ts +206 -70
package/lib/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { n as __require, r as __toESM, t as __commonJSMin } from "./rolldown-runtime-CMFfr-1z.mjs";
|
|
2
|
+
import { a as getPalette, c as parseThemeName, i as error, l as setTheme, n as brand, o as getTheme, r as dim, s as inkColor, u as chalk } from "./theme-BEi4i_aN.mjs";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
import * as fs from "node:fs";
|
|
4
5
|
import { readFileSync } from "node:fs";
|
|
@@ -7,11 +8,10 @@ import { mkdir, readdir, writeFile } from "node:fs/promises";
|
|
|
7
8
|
import { basename, dirname, join, resolve } from "node:path";
|
|
8
9
|
import z from "@deepseek-ai/schemastery";
|
|
9
10
|
import { installModelSelection } from "@deepseek-ai/dsh-agent";
|
|
10
|
-
import { MessageId, assertNever, boundContextSummary, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
11
|
+
import { MessageId, ReasoningEffortId, assertNever, boundContextSummary, createUserMessage } from "@deepseek-ai/dsh-llm";
|
|
11
12
|
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
12
13
|
import { PassThrough, Stream } from "node:stream";
|
|
13
14
|
import process$1, { cwd, env } from "node:process";
|
|
14
|
-
import tty from "node:tty";
|
|
15
15
|
import { EventEmitter } from "node:events";
|
|
16
16
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
17
17
|
import { formatSessionReferenceMention, parseSessionReferenceText } from "@deepseek-ai/dsh-session-reference";
|
|
@@ -21707,11 +21707,11 @@ const measureText = (text) => {
|
|
|
21707
21707
|
};
|
|
21708
21708
|
//#endregion
|
|
21709
21709
|
//#region node_modules/.pnpm/ansi-styles@6.2.3/node_modules/ansi-styles/index.js
|
|
21710
|
-
const ANSI_BACKGROUND_OFFSET
|
|
21711
|
-
const wrapAnsi16
|
|
21712
|
-
const wrapAnsi256
|
|
21713
|
-
const wrapAnsi16m
|
|
21714
|
-
const styles$
|
|
21710
|
+
const ANSI_BACKGROUND_OFFSET = 10;
|
|
21711
|
+
const wrapAnsi16 = (offset = 0) => (code) => `\u001B[${code + offset}m`;
|
|
21712
|
+
const wrapAnsi256 = (offset = 0) => (code) => `\u001B[${38 + offset};5;${code}m`;
|
|
21713
|
+
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
|
|
21714
|
+
const styles$1 = {
|
|
21715
21715
|
modifier: {
|
|
21716
21716
|
reset: [0, 0],
|
|
21717
21717
|
bold: [1, 22],
|
|
@@ -21764,39 +21764,39 @@ const styles$3 = {
|
|
|
21764
21764
|
bgWhiteBright: [107, 49]
|
|
21765
21765
|
}
|
|
21766
21766
|
};
|
|
21767
|
-
Object.keys(styles$
|
|
21768
|
-
const foregroundColorNames
|
|
21769
|
-
const backgroundColorNames
|
|
21770
|
-
[...foregroundColorNames
|
|
21771
|
-
function assembleStyles
|
|
21767
|
+
Object.keys(styles$1.modifier);
|
|
21768
|
+
const foregroundColorNames = Object.keys(styles$1.color);
|
|
21769
|
+
const backgroundColorNames = Object.keys(styles$1.bgColor);
|
|
21770
|
+
[...foregroundColorNames, ...backgroundColorNames];
|
|
21771
|
+
function assembleStyles() {
|
|
21772
21772
|
const codes = /* @__PURE__ */ new Map();
|
|
21773
|
-
for (const [groupName, group] of Object.entries(styles$
|
|
21773
|
+
for (const [groupName, group] of Object.entries(styles$1)) {
|
|
21774
21774
|
for (const [styleName, style] of Object.entries(group)) {
|
|
21775
|
-
styles$
|
|
21775
|
+
styles$1[styleName] = {
|
|
21776
21776
|
open: `\u001B[${style[0]}m`,
|
|
21777
21777
|
close: `\u001B[${style[1]}m`
|
|
21778
21778
|
};
|
|
21779
|
-
group[styleName] = styles$
|
|
21779
|
+
group[styleName] = styles$1[styleName];
|
|
21780
21780
|
codes.set(style[0], style[1]);
|
|
21781
21781
|
}
|
|
21782
|
-
Object.defineProperty(styles$
|
|
21782
|
+
Object.defineProperty(styles$1, groupName, {
|
|
21783
21783
|
value: group,
|
|
21784
21784
|
enumerable: false
|
|
21785
21785
|
});
|
|
21786
21786
|
}
|
|
21787
|
-
Object.defineProperty(styles$
|
|
21787
|
+
Object.defineProperty(styles$1, "codes", {
|
|
21788
21788
|
value: codes,
|
|
21789
21789
|
enumerable: false
|
|
21790
21790
|
});
|
|
21791
|
-
styles$
|
|
21792
|
-
styles$
|
|
21793
|
-
styles$
|
|
21794
|
-
styles$
|
|
21795
|
-
styles$
|
|
21796
|
-
styles$
|
|
21797
|
-
styles$
|
|
21798
|
-
styles$
|
|
21799
|
-
Object.defineProperties(styles$
|
|
21791
|
+
styles$1.color.close = "\x1B[39m";
|
|
21792
|
+
styles$1.bgColor.close = "\x1B[49m";
|
|
21793
|
+
styles$1.color.ansi = wrapAnsi16();
|
|
21794
|
+
styles$1.color.ansi256 = wrapAnsi256();
|
|
21795
|
+
styles$1.color.ansi16m = wrapAnsi16m();
|
|
21796
|
+
styles$1.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
21797
|
+
styles$1.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
21798
|
+
styles$1.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
21799
|
+
Object.defineProperties(styles$1, {
|
|
21800
21800
|
rgbToAnsi256: {
|
|
21801
21801
|
value(red, green, blue) {
|
|
21802
21802
|
if (red === green && green === blue) {
|
|
@@ -21828,7 +21828,7 @@ function assembleStyles$1() {
|
|
|
21828
21828
|
enumerable: false
|
|
21829
21829
|
},
|
|
21830
21830
|
hexToAnsi256: {
|
|
21831
|
-
value: (hex) => styles$
|
|
21831
|
+
value: (hex) => styles$1.rgbToAnsi256(...styles$1.hexToRgb(hex)),
|
|
21832
21832
|
enumerable: false
|
|
21833
21833
|
},
|
|
21834
21834
|
ansi256ToAnsi: {
|
|
@@ -21858,17 +21858,17 @@ function assembleStyles$1() {
|
|
|
21858
21858
|
enumerable: false
|
|
21859
21859
|
},
|
|
21860
21860
|
rgbToAnsi: {
|
|
21861
|
-
value: (red, green, blue) => styles$
|
|
21861
|
+
value: (red, green, blue) => styles$1.ansi256ToAnsi(styles$1.rgbToAnsi256(red, green, blue)),
|
|
21862
21862
|
enumerable: false
|
|
21863
21863
|
},
|
|
21864
21864
|
hexToAnsi: {
|
|
21865
|
-
value: (hex) => styles$
|
|
21865
|
+
value: (hex) => styles$1.ansi256ToAnsi(styles$1.hexToAnsi256(hex)),
|
|
21866
21866
|
enumerable: false
|
|
21867
21867
|
}
|
|
21868
21868
|
});
|
|
21869
|
-
return styles$
|
|
21869
|
+
return styles$1;
|
|
21870
21870
|
}
|
|
21871
|
-
const ansiStyles
|
|
21871
|
+
const ansiStyles = assembleStyles();
|
|
21872
21872
|
//#endregion
|
|
21873
21873
|
//#region node_modules/.pnpm/wrap-ansi@9.0.2/node_modules/wrap-ansi/index.js
|
|
21874
21874
|
const ESCAPES$3 = /* @__PURE__ */ new Set(["\x1B", ""]);
|
|
@@ -21977,7 +21977,7 @@ const exec = (string, columns, options = {}) => {
|
|
|
21977
21977
|
escapeCode = code === END_CODE ? void 0 : code;
|
|
21978
21978
|
} else if (groups.uri !== void 0) escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
|
|
21979
21979
|
}
|
|
21980
|
-
const code = ansiStyles
|
|
21980
|
+
const code = ansiStyles.codes.get(Number(escapeCode));
|
|
21981
21981
|
if (pre[index + 1] === "\n") {
|
|
21982
21982
|
if (escapeUrl) returnValue += wrapAnsiHyperlink("");
|
|
21983
21983
|
if (escapeCode && code) returnValue += wrapAnsiCode(code);
|
|
@@ -22009,7 +22009,7 @@ const checkAnsi = (ansiCodes, isEscapes, endAnsiCode) => {
|
|
|
22009
22009
|
for (let ansiCode of ansiCodes) {
|
|
22010
22010
|
const ansiCodeOrigin = ansiCode;
|
|
22011
22011
|
if (ansiCode.includes(";")) ansiCode = ansiCode.split(";")[0][0] + "0";
|
|
22012
|
-
const item = ansiStyles
|
|
22012
|
+
const item = ansiStyles.codes.get(Number.parseInt(ansiCode, 10));
|
|
22013
22013
|
if (item) {
|
|
22014
22014
|
const indexEscape = ansiCodes.indexOf(item.toString());
|
|
22015
22015
|
if (indexEscape === -1) output.push(wrapAnsi(isEscapes ? item : ansiCodeOrigin));
|
|
@@ -22022,7 +22022,7 @@ const checkAnsi = (ansiCodes, isEscapes, endAnsiCode) => {
|
|
|
22022
22022
|
if (isEscapes) {
|
|
22023
22023
|
output = output.filter((element, index) => output.indexOf(element) === index);
|
|
22024
22024
|
if (endAnsiCode !== void 0) {
|
|
22025
|
-
const fistEscapeCode = wrapAnsi(ansiStyles
|
|
22025
|
+
const fistEscapeCode = wrapAnsi(ansiStyles.codes.get(Number.parseInt(endAnsiCode, 10)));
|
|
22026
22026
|
output = output.reduce((current, next) => next === fistEscapeCode ? [next, ...current] : [...current, next], []);
|
|
22027
22027
|
}
|
|
22028
22028
|
}
|
|
@@ -22325,7 +22325,7 @@ const applyGapStyles = (node, style) => {
|
|
|
22325
22325
|
if ("columnGap" in style) node.setGap(Yoga.GUTTER_COLUMN, style.columnGap ?? 0);
|
|
22326
22326
|
if ("rowGap" in style) node.setGap(Yoga.GUTTER_ROW, style.rowGap ?? 0);
|
|
22327
22327
|
};
|
|
22328
|
-
const styles
|
|
22328
|
+
const styles = (node, style = {}) => {
|
|
22329
22329
|
applyPositionStyles(node, style);
|
|
22330
22330
|
applyMarginStyles(node, style);
|
|
22331
22331
|
applyPaddingStyles(node, style);
|
|
@@ -22400,7 +22400,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
|
|
|
22400
22400
|
if (key === "children") continue;
|
|
22401
22401
|
if (key === "style") {
|
|
22402
22402
|
setStyle(node, value);
|
|
22403
|
-
if (node.yogaNode) styles
|
|
22403
|
+
if (node.yogaNode) styles(node.yogaNode, value);
|
|
22404
22404
|
continue;
|
|
22405
22405
|
}
|
|
22406
22406
|
if (key === "internal_transform") {
|
|
@@ -22489,7 +22489,7 @@ var reconciler_default = (0, import_react_reconciler.default)({
|
|
|
22489
22489
|
}
|
|
22490
22490
|
setAttribute(node, key, value);
|
|
22491
22491
|
}
|
|
22492
|
-
if (style && node.yogaNode) styles
|
|
22492
|
+
if (style && node.yogaNode) styles(node.yogaNode, style);
|
|
22493
22493
|
},
|
|
22494
22494
|
commitTextUpdate(node, _oldText, newText) {
|
|
22495
22495
|
setTextNodeValue(node, newText);
|
|
@@ -22603,414 +22603,12 @@ var require_boxes = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
22603
22603
|
};
|
|
22604
22604
|
}));
|
|
22605
22605
|
//#endregion
|
|
22606
|
-
//#region node_modules/.pnpm/
|
|
22606
|
+
//#region node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/colorize.js
|
|
22607
22607
|
var import_cli_boxes = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
22608
22608
|
const cliBoxes = require_boxes();
|
|
22609
22609
|
module.exports = cliBoxes;
|
|
22610
22610
|
module.exports.default = cliBoxes;
|
|
22611
22611
|
})))(), 1);
|
|
22612
|
-
const ANSI_BACKGROUND_OFFSET = 10;
|
|
22613
|
-
const wrapAnsi16 = (offset = 0) => (code) => `\u001B[${code + offset}m`;
|
|
22614
|
-
const wrapAnsi256 = (offset = 0) => (code) => `\u001B[${38 + offset};5;${code}m`;
|
|
22615
|
-
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
|
|
22616
|
-
const styles$1 = {
|
|
22617
|
-
modifier: {
|
|
22618
|
-
reset: [0, 0],
|
|
22619
|
-
bold: [1, 22],
|
|
22620
|
-
dim: [2, 22],
|
|
22621
|
-
italic: [3, 23],
|
|
22622
|
-
underline: [4, 24],
|
|
22623
|
-
overline: [53, 55],
|
|
22624
|
-
inverse: [7, 27],
|
|
22625
|
-
hidden: [8, 28],
|
|
22626
|
-
strikethrough: [9, 29]
|
|
22627
|
-
},
|
|
22628
|
-
color: {
|
|
22629
|
-
black: [30, 39],
|
|
22630
|
-
red: [31, 39],
|
|
22631
|
-
green: [32, 39],
|
|
22632
|
-
yellow: [33, 39],
|
|
22633
|
-
blue: [34, 39],
|
|
22634
|
-
magenta: [35, 39],
|
|
22635
|
-
cyan: [36, 39],
|
|
22636
|
-
white: [37, 39],
|
|
22637
|
-
blackBright: [90, 39],
|
|
22638
|
-
gray: [90, 39],
|
|
22639
|
-
grey: [90, 39],
|
|
22640
|
-
redBright: [91, 39],
|
|
22641
|
-
greenBright: [92, 39],
|
|
22642
|
-
yellowBright: [93, 39],
|
|
22643
|
-
blueBright: [94, 39],
|
|
22644
|
-
magentaBright: [95, 39],
|
|
22645
|
-
cyanBright: [96, 39],
|
|
22646
|
-
whiteBright: [97, 39]
|
|
22647
|
-
},
|
|
22648
|
-
bgColor: {
|
|
22649
|
-
bgBlack: [40, 49],
|
|
22650
|
-
bgRed: [41, 49],
|
|
22651
|
-
bgGreen: [42, 49],
|
|
22652
|
-
bgYellow: [43, 49],
|
|
22653
|
-
bgBlue: [44, 49],
|
|
22654
|
-
bgMagenta: [45, 49],
|
|
22655
|
-
bgCyan: [46, 49],
|
|
22656
|
-
bgWhite: [47, 49],
|
|
22657
|
-
bgBlackBright: [100, 49],
|
|
22658
|
-
bgGray: [100, 49],
|
|
22659
|
-
bgGrey: [100, 49],
|
|
22660
|
-
bgRedBright: [101, 49],
|
|
22661
|
-
bgGreenBright: [102, 49],
|
|
22662
|
-
bgYellowBright: [103, 49],
|
|
22663
|
-
bgBlueBright: [104, 49],
|
|
22664
|
-
bgMagentaBright: [105, 49],
|
|
22665
|
-
bgCyanBright: [106, 49],
|
|
22666
|
-
bgWhiteBright: [107, 49]
|
|
22667
|
-
}
|
|
22668
|
-
};
|
|
22669
|
-
Object.keys(styles$1.modifier);
|
|
22670
|
-
const foregroundColorNames = Object.keys(styles$1.color);
|
|
22671
|
-
const backgroundColorNames = Object.keys(styles$1.bgColor);
|
|
22672
|
-
[...foregroundColorNames, ...backgroundColorNames];
|
|
22673
|
-
function assembleStyles() {
|
|
22674
|
-
const codes = /* @__PURE__ */ new Map();
|
|
22675
|
-
for (const [groupName, group] of Object.entries(styles$1)) {
|
|
22676
|
-
for (const [styleName, style] of Object.entries(group)) {
|
|
22677
|
-
styles$1[styleName] = {
|
|
22678
|
-
open: `\u001B[${style[0]}m`,
|
|
22679
|
-
close: `\u001B[${style[1]}m`
|
|
22680
|
-
};
|
|
22681
|
-
group[styleName] = styles$1[styleName];
|
|
22682
|
-
codes.set(style[0], style[1]);
|
|
22683
|
-
}
|
|
22684
|
-
Object.defineProperty(styles$1, groupName, {
|
|
22685
|
-
value: group,
|
|
22686
|
-
enumerable: false
|
|
22687
|
-
});
|
|
22688
|
-
}
|
|
22689
|
-
Object.defineProperty(styles$1, "codes", {
|
|
22690
|
-
value: codes,
|
|
22691
|
-
enumerable: false
|
|
22692
|
-
});
|
|
22693
|
-
styles$1.color.close = "\x1B[39m";
|
|
22694
|
-
styles$1.bgColor.close = "\x1B[49m";
|
|
22695
|
-
styles$1.color.ansi = wrapAnsi16();
|
|
22696
|
-
styles$1.color.ansi256 = wrapAnsi256();
|
|
22697
|
-
styles$1.color.ansi16m = wrapAnsi16m();
|
|
22698
|
-
styles$1.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
22699
|
-
styles$1.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
22700
|
-
styles$1.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
22701
|
-
Object.defineProperties(styles$1, {
|
|
22702
|
-
rgbToAnsi256: {
|
|
22703
|
-
value(red, green, blue) {
|
|
22704
|
-
if (red === green && green === blue) {
|
|
22705
|
-
if (red < 8) return 16;
|
|
22706
|
-
if (red > 248) return 231;
|
|
22707
|
-
return Math.round((red - 8) / 247 * 24) + 232;
|
|
22708
|
-
}
|
|
22709
|
-
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
22710
|
-
},
|
|
22711
|
-
enumerable: false
|
|
22712
|
-
},
|
|
22713
|
-
hexToRgb: {
|
|
22714
|
-
value(hex) {
|
|
22715
|
-
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
22716
|
-
if (!matches) return [
|
|
22717
|
-
0,
|
|
22718
|
-
0,
|
|
22719
|
-
0
|
|
22720
|
-
];
|
|
22721
|
-
let [colorString] = matches;
|
|
22722
|
-
if (colorString.length === 3) colorString = [...colorString].map((character) => character + character).join("");
|
|
22723
|
-
const integer = Number.parseInt(colorString, 16);
|
|
22724
|
-
return [
|
|
22725
|
-
integer >> 16 & 255,
|
|
22726
|
-
integer >> 8 & 255,
|
|
22727
|
-
integer & 255
|
|
22728
|
-
];
|
|
22729
|
-
},
|
|
22730
|
-
enumerable: false
|
|
22731
|
-
},
|
|
22732
|
-
hexToAnsi256: {
|
|
22733
|
-
value: (hex) => styles$1.rgbToAnsi256(...styles$1.hexToRgb(hex)),
|
|
22734
|
-
enumerable: false
|
|
22735
|
-
},
|
|
22736
|
-
ansi256ToAnsi: {
|
|
22737
|
-
value(code) {
|
|
22738
|
-
if (code < 8) return 30 + code;
|
|
22739
|
-
if (code < 16) return 90 + (code - 8);
|
|
22740
|
-
let red;
|
|
22741
|
-
let green;
|
|
22742
|
-
let blue;
|
|
22743
|
-
if (code >= 232) {
|
|
22744
|
-
red = ((code - 232) * 10 + 8) / 255;
|
|
22745
|
-
green = red;
|
|
22746
|
-
blue = red;
|
|
22747
|
-
} else {
|
|
22748
|
-
code -= 16;
|
|
22749
|
-
const remainder = code % 36;
|
|
22750
|
-
red = Math.floor(code / 36) / 5;
|
|
22751
|
-
green = Math.floor(remainder / 6) / 5;
|
|
22752
|
-
blue = remainder % 6 / 5;
|
|
22753
|
-
}
|
|
22754
|
-
const value = Math.max(red, green, blue) * 2;
|
|
22755
|
-
if (value === 0) return 30;
|
|
22756
|
-
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
22757
|
-
if (value === 2) result += 60;
|
|
22758
|
-
return result;
|
|
22759
|
-
},
|
|
22760
|
-
enumerable: false
|
|
22761
|
-
},
|
|
22762
|
-
rgbToAnsi: {
|
|
22763
|
-
value: (red, green, blue) => styles$1.ansi256ToAnsi(styles$1.rgbToAnsi256(red, green, blue)),
|
|
22764
|
-
enumerable: false
|
|
22765
|
-
},
|
|
22766
|
-
hexToAnsi: {
|
|
22767
|
-
value: (hex) => styles$1.ansi256ToAnsi(styles$1.hexToAnsi256(hex)),
|
|
22768
|
-
enumerable: false
|
|
22769
|
-
}
|
|
22770
|
-
});
|
|
22771
|
-
return styles$1;
|
|
22772
|
-
}
|
|
22773
|
-
const ansiStyles = assembleStyles();
|
|
22774
|
-
//#endregion
|
|
22775
|
-
//#region node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
22776
|
-
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process$1.argv) {
|
|
22777
|
-
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
22778
|
-
const position = argv.indexOf(prefix + flag);
|
|
22779
|
-
const terminatorPosition = argv.indexOf("--");
|
|
22780
|
-
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
22781
|
-
}
|
|
22782
|
-
const { env: env$1 } = process$1;
|
|
22783
|
-
let flagForceColor;
|
|
22784
|
-
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) flagForceColor = 0;
|
|
22785
|
-
else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) flagForceColor = 1;
|
|
22786
|
-
function envForceColor() {
|
|
22787
|
-
if ("FORCE_COLOR" in env$1) {
|
|
22788
|
-
if (env$1.FORCE_COLOR === "true") return 1;
|
|
22789
|
-
if (env$1.FORCE_COLOR === "false") return 0;
|
|
22790
|
-
return env$1.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env$1.FORCE_COLOR, 10), 3);
|
|
22791
|
-
}
|
|
22792
|
-
}
|
|
22793
|
-
function translateLevel(level) {
|
|
22794
|
-
if (level === 0) return false;
|
|
22795
|
-
return {
|
|
22796
|
-
level,
|
|
22797
|
-
hasBasic: true,
|
|
22798
|
-
has256: level >= 2,
|
|
22799
|
-
has16m: level >= 3
|
|
22800
|
-
};
|
|
22801
|
-
}
|
|
22802
|
-
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
22803
|
-
const noFlagForceColor = envForceColor();
|
|
22804
|
-
if (noFlagForceColor !== void 0) flagForceColor = noFlagForceColor;
|
|
22805
|
-
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
22806
|
-
if (forceColor === 0) return 0;
|
|
22807
|
-
if (sniffFlags) {
|
|
22808
|
-
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) return 3;
|
|
22809
|
-
if (hasFlag("color=256")) return 2;
|
|
22810
|
-
}
|
|
22811
|
-
if ("TF_BUILD" in env$1 && "AGENT_NAME" in env$1) return 1;
|
|
22812
|
-
if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
|
|
22813
|
-
const min = forceColor || 0;
|
|
22814
|
-
if (env$1.TERM === "dumb") return min;
|
|
22815
|
-
if (process$1.platform === "win32") {
|
|
22816
|
-
const osRelease = os.release().split(".");
|
|
22817
|
-
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
22818
|
-
return 1;
|
|
22819
|
-
}
|
|
22820
|
-
if ("CI" in env$1) {
|
|
22821
|
-
if ([
|
|
22822
|
-
"GITHUB_ACTIONS",
|
|
22823
|
-
"GITEA_ACTIONS",
|
|
22824
|
-
"CIRCLECI"
|
|
22825
|
-
].some((key) => key in env$1)) return 3;
|
|
22826
|
-
if ([
|
|
22827
|
-
"TRAVIS",
|
|
22828
|
-
"APPVEYOR",
|
|
22829
|
-
"GITLAB_CI",
|
|
22830
|
-
"BUILDKITE",
|
|
22831
|
-
"DRONE"
|
|
22832
|
-
].some((sign) => sign in env$1) || env$1.CI_NAME === "codeship") return 1;
|
|
22833
|
-
return min;
|
|
22834
|
-
}
|
|
22835
|
-
if ("TEAMCITY_VERSION" in env$1) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env$1.TEAMCITY_VERSION) ? 1 : 0;
|
|
22836
|
-
if (env$1.COLORTERM === "truecolor") return 3;
|
|
22837
|
-
if (env$1.TERM === "xterm-kitty") return 3;
|
|
22838
|
-
if (env$1.TERM === "xterm-ghostty") return 3;
|
|
22839
|
-
if (env$1.TERM === "wezterm") return 3;
|
|
22840
|
-
if ("TERM_PROGRAM" in env$1) {
|
|
22841
|
-
const version = Number.parseInt((env$1.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
22842
|
-
switch (env$1.TERM_PROGRAM) {
|
|
22843
|
-
case "iTerm.app": return version >= 3 ? 3 : 2;
|
|
22844
|
-
case "Apple_Terminal": return 2;
|
|
22845
|
-
}
|
|
22846
|
-
}
|
|
22847
|
-
if (/-256(color)?$/i.test(env$1.TERM)) return 2;
|
|
22848
|
-
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env$1.TERM)) return 1;
|
|
22849
|
-
if ("COLORTERM" in env$1) return 1;
|
|
22850
|
-
return min;
|
|
22851
|
-
}
|
|
22852
|
-
function createSupportsColor(stream, options = {}) {
|
|
22853
|
-
return translateLevel(_supportsColor(stream, {
|
|
22854
|
-
streamIsTTY: stream && stream.isTTY,
|
|
22855
|
-
...options
|
|
22856
|
-
}));
|
|
22857
|
-
}
|
|
22858
|
-
const supportsColor = {
|
|
22859
|
-
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
22860
|
-
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
22861
|
-
};
|
|
22862
|
-
//#endregion
|
|
22863
|
-
//#region node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js
|
|
22864
|
-
function stringReplaceAll(string, substring, replacer) {
|
|
22865
|
-
let index = string.indexOf(substring);
|
|
22866
|
-
if (index === -1) return string;
|
|
22867
|
-
const substringLength = substring.length;
|
|
22868
|
-
let endIndex = 0;
|
|
22869
|
-
let returnValue = "";
|
|
22870
|
-
do {
|
|
22871
|
-
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
22872
|
-
endIndex = index + substringLength;
|
|
22873
|
-
index = string.indexOf(substring, endIndex);
|
|
22874
|
-
} while (index !== -1);
|
|
22875
|
-
returnValue += string.slice(endIndex);
|
|
22876
|
-
return returnValue;
|
|
22877
|
-
}
|
|
22878
|
-
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
22879
|
-
let endIndex = 0;
|
|
22880
|
-
let returnValue = "";
|
|
22881
|
-
do {
|
|
22882
|
-
const gotCR = string[index - 1] === "\r";
|
|
22883
|
-
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
22884
|
-
endIndex = index + 1;
|
|
22885
|
-
index = string.indexOf("\n", endIndex);
|
|
22886
|
-
} while (index !== -1);
|
|
22887
|
-
returnValue += string.slice(endIndex);
|
|
22888
|
-
return returnValue;
|
|
22889
|
-
}
|
|
22890
|
-
//#endregion
|
|
22891
|
-
//#region node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js
|
|
22892
|
-
const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
|
|
22893
|
-
const GENERATOR = Symbol("GENERATOR");
|
|
22894
|
-
const STYLER = Symbol("STYLER");
|
|
22895
|
-
const IS_EMPTY = Symbol("IS_EMPTY");
|
|
22896
|
-
const levelMapping = [
|
|
22897
|
-
"ansi",
|
|
22898
|
-
"ansi",
|
|
22899
|
-
"ansi256",
|
|
22900
|
-
"ansi16m"
|
|
22901
|
-
];
|
|
22902
|
-
const styles = Object.create(null);
|
|
22903
|
-
const applyOptions = (object, options = {}) => {
|
|
22904
|
-
if (options.level && !(Number.isInteger(options.level) && options.level >= 0 && options.level <= 3)) throw new Error("The `level` option should be an integer from 0 to 3");
|
|
22905
|
-
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
22906
|
-
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
22907
|
-
};
|
|
22908
|
-
const chalkFactory = (options) => {
|
|
22909
|
-
const chalk = (...strings) => strings.join(" ");
|
|
22910
|
-
applyOptions(chalk, options);
|
|
22911
|
-
Object.setPrototypeOf(chalk, createChalk.prototype);
|
|
22912
|
-
return chalk;
|
|
22913
|
-
};
|
|
22914
|
-
function createChalk(options) {
|
|
22915
|
-
return chalkFactory(options);
|
|
22916
|
-
}
|
|
22917
|
-
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
22918
|
-
for (const [styleName, style] of Object.entries(ansiStyles)) styles[styleName] = { get() {
|
|
22919
|
-
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
22920
|
-
Object.defineProperty(this, styleName, { value: builder });
|
|
22921
|
-
return builder;
|
|
22922
|
-
} };
|
|
22923
|
-
styles.visible = { get() {
|
|
22924
|
-
const builder = createBuilder(this, this[STYLER], true);
|
|
22925
|
-
Object.defineProperty(this, "visible", { value: builder });
|
|
22926
|
-
return builder;
|
|
22927
|
-
} };
|
|
22928
|
-
const getModelAnsi = (model, level, type, ...arguments_) => {
|
|
22929
|
-
if (model === "rgb") {
|
|
22930
|
-
if (level === "ansi16m") return ansiStyles[type].ansi16m(...arguments_);
|
|
22931
|
-
if (level === "ansi256") return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));
|
|
22932
|
-
return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));
|
|
22933
|
-
}
|
|
22934
|
-
if (model === "hex") return getModelAnsi("rgb", level, type, ...ansiStyles.hexToRgb(...arguments_));
|
|
22935
|
-
return ansiStyles[type][model](...arguments_);
|
|
22936
|
-
};
|
|
22937
|
-
for (const model of [
|
|
22938
|
-
"rgb",
|
|
22939
|
-
"hex",
|
|
22940
|
-
"ansi256"
|
|
22941
|
-
]) {
|
|
22942
|
-
styles[model] = { get() {
|
|
22943
|
-
const { level } = this;
|
|
22944
|
-
return function(...arguments_) {
|
|
22945
|
-
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansiStyles.color.close, this[STYLER]);
|
|
22946
|
-
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
22947
|
-
};
|
|
22948
|
-
} };
|
|
22949
|
-
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
22950
|
-
styles[bgModel] = { get() {
|
|
22951
|
-
const { level } = this;
|
|
22952
|
-
return function(...arguments_) {
|
|
22953
|
-
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansiStyles.bgColor.close, this[STYLER]);
|
|
22954
|
-
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
22955
|
-
};
|
|
22956
|
-
} };
|
|
22957
|
-
}
|
|
22958
|
-
const proto = Object.defineProperties(() => {}, {
|
|
22959
|
-
...styles,
|
|
22960
|
-
level: {
|
|
22961
|
-
enumerable: true,
|
|
22962
|
-
get() {
|
|
22963
|
-
return this[GENERATOR].level;
|
|
22964
|
-
},
|
|
22965
|
-
set(level) {
|
|
22966
|
-
this[GENERATOR].level = level;
|
|
22967
|
-
}
|
|
22968
|
-
}
|
|
22969
|
-
});
|
|
22970
|
-
const createStyler = (open, close, parent) => {
|
|
22971
|
-
let openAll;
|
|
22972
|
-
let closeAll;
|
|
22973
|
-
if (parent === void 0) {
|
|
22974
|
-
openAll = open;
|
|
22975
|
-
closeAll = close;
|
|
22976
|
-
} else {
|
|
22977
|
-
openAll = parent.openAll + open;
|
|
22978
|
-
closeAll = close + parent.closeAll;
|
|
22979
|
-
}
|
|
22980
|
-
return {
|
|
22981
|
-
open,
|
|
22982
|
-
close,
|
|
22983
|
-
openAll,
|
|
22984
|
-
closeAll,
|
|
22985
|
-
parent
|
|
22986
|
-
};
|
|
22987
|
-
};
|
|
22988
|
-
const createBuilder = (self, _styler, _isEmpty) => {
|
|
22989
|
-
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
22990
|
-
Object.setPrototypeOf(builder, proto);
|
|
22991
|
-
builder[GENERATOR] = self;
|
|
22992
|
-
builder[STYLER] = _styler;
|
|
22993
|
-
builder[IS_EMPTY] = _isEmpty;
|
|
22994
|
-
return builder;
|
|
22995
|
-
};
|
|
22996
|
-
const applyStyle = (self, string) => {
|
|
22997
|
-
if (self.level <= 0 || !string) return self[IS_EMPTY] ? "" : string;
|
|
22998
|
-
let styler = self[STYLER];
|
|
22999
|
-
if (styler === void 0) return string;
|
|
23000
|
-
const { openAll, closeAll } = styler;
|
|
23001
|
-
if (string.includes("\x1B")) while (styler !== void 0) {
|
|
23002
|
-
string = stringReplaceAll(string, styler.close, styler.open);
|
|
23003
|
-
styler = styler.parent;
|
|
23004
|
-
}
|
|
23005
|
-
const lfIndex = string.indexOf("\n");
|
|
23006
|
-
if (lfIndex !== -1) string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
23007
|
-
return openAll + string + closeAll;
|
|
23008
|
-
};
|
|
23009
|
-
Object.defineProperties(createChalk.prototype, styles);
|
|
23010
|
-
const chalk = createChalk();
|
|
23011
|
-
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
23012
|
-
//#endregion
|
|
23013
|
-
//#region node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/colorize.js
|
|
23014
22612
|
const rgbRegex = /^rgb\(\s?(\d+),\s?(\d+),\s?(\d+)\s?\)$/;
|
|
23015
22613
|
const ansiRegex = /^ansi256\(\s?(\d+)\s?\)$/;
|
|
23016
22614
|
const isNamedColor = (color) => {
|
|
@@ -23157,18 +22755,18 @@ const CODE_POINT_9 = "9".codePointAt(0);
|
|
|
23157
22755
|
const MAX_ANSI_SEQUENCE_LENGTH = 19;
|
|
23158
22756
|
const endCodesSet$1 = /* @__PURE__ */ new Set();
|
|
23159
22757
|
const endCodesMap$1 = /* @__PURE__ */ new Map();
|
|
23160
|
-
for (const [start, end] of ansiStyles
|
|
23161
|
-
endCodesSet$1.add(ansiStyles
|
|
23162
|
-
endCodesMap$1.set(ansiStyles
|
|
22758
|
+
for (const [start, end] of ansiStyles.codes) {
|
|
22759
|
+
endCodesSet$1.add(ansiStyles.color.ansi(end));
|
|
22760
|
+
endCodesMap$1.set(ansiStyles.color.ansi(start), ansiStyles.color.ansi(end));
|
|
23163
22761
|
}
|
|
23164
22762
|
function getEndCode$1(code) {
|
|
23165
22763
|
if (endCodesSet$1.has(code)) return code;
|
|
23166
22764
|
if (endCodesMap$1.has(code)) return endCodesMap$1.get(code);
|
|
23167
22765
|
code = code.slice(2);
|
|
23168
22766
|
if (code.includes(";")) code = code[0] + "0";
|
|
23169
|
-
const returnValue = ansiStyles
|
|
23170
|
-
if (returnValue) return ansiStyles
|
|
23171
|
-
return ansiStyles
|
|
22767
|
+
const returnValue = ansiStyles.codes.get(Number.parseInt(code, 10));
|
|
22768
|
+
if (returnValue) return ansiStyles.color.ansi(returnValue);
|
|
22769
|
+
return ansiStyles.reset.open;
|
|
23172
22770
|
}
|
|
23173
22771
|
function findNumberIndex$1(string) {
|
|
23174
22772
|
for (let index = 0; index < string.length; index++) {
|
|
@@ -23219,7 +22817,7 @@ function tokenize$1(string, endCharacter = Number.POSITIVE_INFINITY) {
|
|
|
23219
22817
|
}
|
|
23220
22818
|
function reduceAnsiCodes$1(codes) {
|
|
23221
22819
|
let returnValue = [];
|
|
23222
|
-
for (const code of codes) if (code.code === ansiStyles
|
|
22820
|
+
for (const code of codes) if (code.code === ansiStyles.reset.open) returnValue = [];
|
|
23223
22821
|
else if (endCodesSet$1.has(code.code)) returnValue = returnValue.filter((returnValueCode) => returnValueCode.endCode !== code.code);
|
|
23224
22822
|
else {
|
|
23225
22823
|
returnValue = returnValue.filter((returnValueCode) => returnValueCode.endCode !== code.endCode);
|
|
@@ -23259,9 +22857,9 @@ function sliceAnsi(string, start, end) {
|
|
|
23259
22857
|
const ESCAPES = /* @__PURE__ */ new Set([27, 155]);
|
|
23260
22858
|
const endCodesSet = /* @__PURE__ */ new Set();
|
|
23261
22859
|
const endCodesMap = /* @__PURE__ */ new Map();
|
|
23262
|
-
for (const [start, end] of ansiStyles
|
|
23263
|
-
endCodesSet.add(ansiStyles
|
|
23264
|
-
endCodesMap.set(ansiStyles
|
|
22860
|
+
for (const [start, end] of ansiStyles.codes) {
|
|
22861
|
+
endCodesSet.add(ansiStyles.color.ansi(end));
|
|
22862
|
+
endCodesMap.set(ansiStyles.color.ansi(start), ansiStyles.color.ansi(end));
|
|
23265
22863
|
}
|
|
23266
22864
|
const linkStartCodePrefixCharCodes = "\x1B]8;;".split("").map((char) => char.charCodeAt(0));
|
|
23267
22865
|
"\x07".charCodeAt(0);
|
|
@@ -23272,9 +22870,9 @@ function getEndCode(code) {
|
|
|
23272
22870
|
if (code.startsWith("\x1B]8;;")) return linkEndCode;
|
|
23273
22871
|
code = code.slice(2);
|
|
23274
22872
|
if (code.includes(";")) code = code[0] + "0";
|
|
23275
|
-
const ret = ansiStyles
|
|
23276
|
-
if (ret) return ansiStyles
|
|
23277
|
-
else return ansiStyles
|
|
22873
|
+
const ret = ansiStyles.codes.get(parseInt(code, 10));
|
|
22874
|
+
if (ret) return ansiStyles.color.ansi(ret);
|
|
22875
|
+
else return ansiStyles.reset.open;
|
|
23278
22876
|
}
|
|
23279
22877
|
function ansiCodesToString(codes) {
|
|
23280
22878
|
return codes.map((code) => code.code).join("");
|
|
@@ -23288,7 +22886,7 @@ function reduceAnsiCodes(codes) {
|
|
|
23288
22886
|
/** Like {@link reduceAnsiCodes}, but assumes that `codes` is already reduced. Further reductions are only done for the items in `newCodes`. */
|
|
23289
22887
|
function reduceAnsiCodesIncremental(codes, newCodes) {
|
|
23290
22888
|
let ret = [...codes];
|
|
23291
|
-
for (const code of newCodes) if (code.code === ansiStyles
|
|
22889
|
+
for (const code of newCodes) if (code.code === ansiStyles.reset.open) ret = [];
|
|
23292
22890
|
else if (endCodesSet.has(code.code)) ret = ret.filter((retCode) => retCode.endCode !== code.code);
|
|
23293
22891
|
else {
|
|
23294
22892
|
ret = ret.filter((retCode) => retCode.endCode !== code.endCode);
|
|
@@ -24692,87 +24290,253 @@ const useInput = (inputHandler, options = {}) => {
|
|
|
24692
24290
|
*/
|
|
24693
24291
|
const useStdout = () => (0, import_react.useContext)(StdoutContext);
|
|
24694
24292
|
//#endregion
|
|
24695
|
-
//#region src/
|
|
24696
|
-
/**
|
|
24697
|
-
|
|
24698
|
-
|
|
24699
|
-
|
|
24700
|
-
|
|
24701
|
-
|
|
24702
|
-
* @module @deepseek-ai/dsh-tui/theme
|
|
24703
|
-
*/
|
|
24293
|
+
//#region src/render/inspector.ts
|
|
24294
|
+
/** Composer (3) + two-row status chrome, plus one optional fixed-height local notice row. */
|
|
24295
|
+
const INSPECTOR_CHROME_ROWS = 6;
|
|
24296
|
+
/** One transcript-to-composer gutter, collapsed on short terminals. */
|
|
24297
|
+
function layoutGutterRows(rows) {
|
|
24298
|
+
return Math.max(1, Math.floor(rows)) >= 14 ? 1 : 0;
|
|
24299
|
+
}
|
|
24704
24300
|
/**
|
|
24705
|
-
*
|
|
24706
|
-
*
|
|
24301
|
+
* Keep the inspector plus its persistent status/composer chrome below
|
|
24302
|
+
* `stdout.rows`: at equality Ink clears the terminal and rewrites all
|
|
24303
|
+
* accumulated `<Static>` output on every frame.
|
|
24707
24304
|
*/
|
|
24708
|
-
|
|
24709
|
-
|
|
24710
|
-
|
|
24711
|
-
|
|
24712
|
-
|
|
24713
|
-
|
|
24714
|
-
|
|
24715
|
-
|
|
24716
|
-
|
|
24717
|
-
|
|
24718
|
-
|
|
24719
|
-
|
|
24720
|
-
|
|
24721
|
-
|
|
24722
|
-
|
|
24723
|
-
|
|
24724
|
-
|
|
24725
|
-
|
|
24726
|
-
|
|
24727
|
-
|
|
24728
|
-
|
|
24729
|
-
|
|
24730
|
-
|
|
24731
|
-
|
|
24732
|
-
|
|
24733
|
-
|
|
24734
|
-
|
|
24735
|
-
|
|
24736
|
-
|
|
24737
|
-
|
|
24738
|
-
|
|
24739
|
-
|
|
24740
|
-
|
|
24741
|
-
|
|
24742
|
-
|
|
24743
|
-
|
|
24744
|
-
|
|
24745
|
-
|
|
24746
|
-
|
|
24747
|
-
|
|
24748
|
-
|
|
24749
|
-
|
|
24750
|
-
|
|
24751
|
-
|
|
24752
|
-
|
|
24753
|
-
|
|
24754
|
-
|
|
24755
|
-
|
|
24756
|
-
|
|
24757
|
-
|
|
24758
|
-
|
|
24759
|
-
|
|
24760
|
-
|
|
24761
|
-
|
|
24762
|
-
|
|
24763
|
-
|
|
24764
|
-
|
|
24765
|
-
|
|
24766
|
-
|
|
24767
|
-
|
|
24768
|
-
|
|
24769
|
-
|
|
24770
|
-
|
|
24771
|
-
|
|
24772
|
-
|
|
24773
|
-
|
|
24774
|
-
|
|
24775
|
-
|
|
24305
|
+
function panelViewport(columns, rows) {
|
|
24306
|
+
const safeColumns = Math.max(1, Math.floor(columns));
|
|
24307
|
+
const safeRows = Math.max(1, Math.floor(rows));
|
|
24308
|
+
const maxHeight = Math.max(0, Math.min(safeRows - 2 - INSPECTOR_CHROME_ROWS - layoutGutterRows(safeRows), Math.floor(safeRows / 2)));
|
|
24309
|
+
const compact = maxHeight < 5 || safeColumns < 8;
|
|
24310
|
+
const gapRows = !compact && maxHeight >= 7 ? 2 : 0;
|
|
24311
|
+
const outerColumns = compact ? safeColumns : Math.max(1, safeColumns - 1);
|
|
24312
|
+
return {
|
|
24313
|
+
maxHeight,
|
|
24314
|
+
bodyRows: compact ? 0 : maxHeight - 4 - gapRows,
|
|
24315
|
+
gapRows,
|
|
24316
|
+
contentColumns: compact ? Math.max(1, safeColumns - 1) : Math.max(1, outerColumns - 4),
|
|
24317
|
+
outerColumns,
|
|
24318
|
+
compact
|
|
24319
|
+
};
|
|
24320
|
+
}
|
|
24321
|
+
/** Backward-compatible name for the Ctrl+O-specific caller and tests. */
|
|
24322
|
+
function inspectorViewport(columns, rows) {
|
|
24323
|
+
return panelViewport(columns, rows);
|
|
24324
|
+
}
|
|
24325
|
+
/** Clamp a first-visible row to the range representable by one viewport. */
|
|
24326
|
+
function clampScroll(offset, totalRows, visibleRows) {
|
|
24327
|
+
const last = Math.max(0, Math.max(0, Math.floor(totalRows)) - Math.max(0, Math.floor(visibleRows)));
|
|
24328
|
+
return Math.max(0, Math.min(Math.floor(offset), last));
|
|
24329
|
+
}
|
|
24330
|
+
/** Move a viewport by a signed row delta without escaping its content. */
|
|
24331
|
+
function moveScroll(offset, delta, totalRows, visibleRows) {
|
|
24332
|
+
return clampScroll(offset + delta, totalRows, visibleRows);
|
|
24333
|
+
}
|
|
24334
|
+
/** Keep one focused row visible while preserving the current window when possible. */
|
|
24335
|
+
function revealRow(offset, row, totalRows, visibleRows) {
|
|
24336
|
+
const size = Math.max(1, Math.floor(visibleRows));
|
|
24337
|
+
const target = Math.max(0, Math.min(Math.floor(row), Math.max(0, totalRows - 1)));
|
|
24338
|
+
if (target < offset) return clampScroll(target, totalRows, size);
|
|
24339
|
+
if (target >= offset + size) return clampScroll(target - size + 1, totalRows, size);
|
|
24340
|
+
return clampScroll(offset, totalRows, size);
|
|
24341
|
+
}
|
|
24342
|
+
/** Center a selected list row where possible, clamped at both ends. */
|
|
24343
|
+
function selectionWindow(cursor, totalRows, visibleRows) {
|
|
24344
|
+
return clampScroll(cursor - Math.floor(Math.max(1, visibleRows) / 2), totalRows, visibleRows);
|
|
24345
|
+
}
|
|
24346
|
+
/** Follow appended history only while the inspector cursor was at the tail. */
|
|
24347
|
+
function followInspectorCursor(cursor, previousLength, nextLength) {
|
|
24348
|
+
const nextLast = Math.max(0, nextLength - 1);
|
|
24349
|
+
if (cursor >= Math.max(0, previousLength - 1)) return nextLast;
|
|
24350
|
+
return Math.min(cursor, nextLast);
|
|
24351
|
+
}
|
|
24352
|
+
//#endregion
|
|
24353
|
+
//#region src/render/text.ts
|
|
24354
|
+
/**
|
|
24355
|
+
* Display-boundary sanitization for externally sourced text (model output,
|
|
24356
|
+
* tool payloads, skill descriptions). Control characters — including ANSI
|
|
24357
|
+
* CSI/OSC escape sequences — would otherwise pass through Ink into the
|
|
24358
|
+
* terminal, letting output rewrite the screen or inject prompts. Newlines
|
|
24359
|
+
* and tabs survive; everything else in C0/C1 plus DEL becomes a visible
|
|
24360
|
+
* `\xNN` escape.
|
|
24361
|
+
*
|
|
24362
|
+
* @module @deepseek-ai/dsh-code/render/text
|
|
24363
|
+
*/
|
|
24364
|
+
/** C0 controls except tab (0x09) and newline (0x0a), plus DEL and C1. */
|
|
24365
|
+
const CONTROL_ESCAPE = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/gu;
|
|
24366
|
+
/**
|
|
24367
|
+
* Escape control characters so externally sourced text cannot drive the
|
|
24368
|
+
* terminal.
|
|
24369
|
+
* @param text - raw text from a session event, tool payload, or catalog.
|
|
24370
|
+
* @returns text with every control character (except `\n`, `\t`) rendered
|
|
24371
|
+
* as a literal `\xNN` escape.
|
|
24372
|
+
*/
|
|
24373
|
+
function displayText(text) {
|
|
24374
|
+
return text.replace(CONTROL_ESCAPE, (char) => `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`);
|
|
24375
|
+
}
|
|
24376
|
+
/** Collapse external text to one terminal-safe logical row. */
|
|
24377
|
+
function singleLineText(text) {
|
|
24378
|
+
return displayText(text).replace(/\r?\n/gu, " ↵ ").replace(/\t/gu, " ");
|
|
24379
|
+
}
|
|
24380
|
+
/** Terminal-cell width matching the TUI's existing CJK-aware wrapping rule. */
|
|
24381
|
+
function cellWidth(text) {
|
|
24382
|
+
let columns = 0;
|
|
24383
|
+
for (const char of text) columns += (char.codePointAt(0) ?? 0) > 11903 ? 2 : 1;
|
|
24384
|
+
return columns;
|
|
24385
|
+
}
|
|
24386
|
+
/**
|
|
24387
|
+
* Truncate one display-safe row without ever exceeding its physical-column
|
|
24388
|
+
* budget. The ellipsis is included inside the budget, matching Codex's popup
|
|
24389
|
+
* truncation contract; the previous app-local helper appended it after the
|
|
24390
|
+
* row was already full and could force an extra terminal wrap.
|
|
24391
|
+
*/
|
|
24392
|
+
function truncateColumns(text, columns) {
|
|
24393
|
+
const limit = Math.max(0, Math.floor(columns));
|
|
24394
|
+
if (limit === 0) return "";
|
|
24395
|
+
if (cellWidth(text) <= limit) return text;
|
|
24396
|
+
const contentLimit = limit - 1;
|
|
24397
|
+
let used = 0;
|
|
24398
|
+
let result = "";
|
|
24399
|
+
for (const char of text) {
|
|
24400
|
+
const width = cellWidth(char);
|
|
24401
|
+
if (used + width > contentLimit) break;
|
|
24402
|
+
result += char;
|
|
24403
|
+
used += width;
|
|
24404
|
+
}
|
|
24405
|
+
return `${result}…`;
|
|
24406
|
+
}
|
|
24407
|
+
/** Read one Unicode character immediately before `end`. */
|
|
24408
|
+
function previousCharacter(text, end) {
|
|
24409
|
+
const last = text.charCodeAt(end - 1);
|
|
24410
|
+
if (last >= 56320 && last <= 57343 && end >= 2) {
|
|
24411
|
+
const first = text.charCodeAt(end - 2);
|
|
24412
|
+
if (first >= 55296 && first <= 56319) return {
|
|
24413
|
+
char: text.slice(end - 2, end),
|
|
24414
|
+
start: end - 2
|
|
24415
|
+
};
|
|
24416
|
+
}
|
|
24417
|
+
return {
|
|
24418
|
+
char: text.slice(end - 1, end),
|
|
24419
|
+
start: end - 1
|
|
24420
|
+
};
|
|
24421
|
+
}
|
|
24422
|
+
/**
|
|
24423
|
+
* Keep only the newest display-safe text that fits a terminal rectangle.
|
|
24424
|
+
* The scan walks backward and stops as soon as the suffix is full, so a long
|
|
24425
|
+
* reasoning stream does not rescan its entire accumulated prefix per chunk.
|
|
24426
|
+
* Explicit newlines and terminal wrapping both consume rows.
|
|
24427
|
+
* @param text - raw externally sourced text.
|
|
24428
|
+
* @param columns - available terminal columns.
|
|
24429
|
+
* @param rows - available terminal rows.
|
|
24430
|
+
* @returns a sanitized bounded suffix and whether an earlier prefix was cut.
|
|
24431
|
+
*/
|
|
24432
|
+
function displayTail(text, columns, rows) {
|
|
24433
|
+
const columnLimit = Math.max(1, Math.floor(columns));
|
|
24434
|
+
const rowLimit = Math.max(1, Math.floor(rows));
|
|
24435
|
+
const reversed = [];
|
|
24436
|
+
let row = 1;
|
|
24437
|
+
let used = 0;
|
|
24438
|
+
let end = text.length;
|
|
24439
|
+
while (end > 0) {
|
|
24440
|
+
const previous = previousCharacter(text, end);
|
|
24441
|
+
if (previous.char === "\n") {
|
|
24442
|
+
if (row >= rowLimit) break;
|
|
24443
|
+
reversed.push("\n");
|
|
24444
|
+
row += 1;
|
|
24445
|
+
used = 0;
|
|
24446
|
+
end = previous.start;
|
|
24447
|
+
continue;
|
|
24448
|
+
}
|
|
24449
|
+
const safe = displayText(previous.char);
|
|
24450
|
+
const width = cellWidth(safe);
|
|
24451
|
+
if (used > 0 && used + width > columnLimit) {
|
|
24452
|
+
if (row >= rowLimit) break;
|
|
24453
|
+
reversed.push("\n");
|
|
24454
|
+
row += 1;
|
|
24455
|
+
used = 0;
|
|
24456
|
+
}
|
|
24457
|
+
const extraRows = Math.floor(Math.max(0, width - 1) / columnLimit);
|
|
24458
|
+
if (row + extraRows > rowLimit) break;
|
|
24459
|
+
row += extraRows;
|
|
24460
|
+
reversed.push(safe);
|
|
24461
|
+
used = extraRows === 0 ? used + width : width - extraRows * columnLimit;
|
|
24462
|
+
end = previous.start;
|
|
24463
|
+
}
|
|
24464
|
+
return {
|
|
24465
|
+
text: reversed.reverse().join(""),
|
|
24466
|
+
truncated: end > 0
|
|
24467
|
+
};
|
|
24468
|
+
}
|
|
24469
|
+
//#endregion
|
|
24470
|
+
//#region src/theme-panel.ts
|
|
24471
|
+
/**
|
|
24472
|
+
* The `/theme` picker (the Codex `/theme` contract): one bounded list over
|
|
24473
|
+
* the three color themes — dark, light, and auto (terminal-sensed; auto
|
|
24474
|
+
* falls back to dark until OSC-11 detection lands). Enter applies the row
|
|
24475
|
+
* and the runner persists it; Esc closes without changing the theme.
|
|
24476
|
+
*
|
|
24477
|
+
* @module @deepseek-ai/dsh-tui/theme-panel
|
|
24478
|
+
*/
|
|
24479
|
+
/** The three theme rows in canonical order (the /theme selection surface). */
|
|
24480
|
+
const THEME_ROWS = [
|
|
24481
|
+
{
|
|
24482
|
+
id: "dark",
|
|
24483
|
+
label: "dark",
|
|
24484
|
+
description: "DeepSeek dark palette (default)"
|
|
24485
|
+
},
|
|
24486
|
+
{
|
|
24487
|
+
id: "light",
|
|
24488
|
+
label: "light",
|
|
24489
|
+
description: "light palette for bright terminals"
|
|
24490
|
+
},
|
|
24491
|
+
{
|
|
24492
|
+
id: "auto",
|
|
24493
|
+
label: "auto",
|
|
24494
|
+
description: "follow the terminal; dark until detection lands"
|
|
24495
|
+
}
|
|
24496
|
+
];
|
|
24497
|
+
/**
|
|
24498
|
+
* The /theme list: one row per theme, the current one marked with ●, the
|
|
24499
|
+
* focused one with ›. Enter applies the focused theme (the runner persists
|
|
24500
|
+
* it), Esc/q closes without changing anything. Colors read the ACTIVE
|
|
24501
|
+
* palette, so the panel itself adapts to a light theme once applied.
|
|
24502
|
+
*/
|
|
24503
|
+
function ThemePanel({ current, select, close }) {
|
|
24504
|
+
const [cursor, setCursor] = (0, import_react.useState)(() => {
|
|
24505
|
+
const index = THEME_ROWS.findIndex((theme) => theme.id === current);
|
|
24506
|
+
return index < 0 ? 0 : index;
|
|
24507
|
+
});
|
|
24508
|
+
const stdout = useStdout().stdout;
|
|
24509
|
+
const viewport = panelViewport(stdout?.columns ?? 80, stdout?.rows ?? 30);
|
|
24510
|
+
useInput((input, key) => {
|
|
24511
|
+
if (key.escape || input === "q") return close();
|
|
24512
|
+
if (key.upArrow) return setCursor((value) => (value + THEME_ROWS.length - 1) % THEME_ROWS.length);
|
|
24513
|
+
if (key.downArrow) return setCursor((value) => (value + 1) % THEME_ROWS.length);
|
|
24514
|
+
if (key.return) return select(THEME_ROWS[cursor].id);
|
|
24515
|
+
});
|
|
24516
|
+
if (viewport.maxHeight === 0) return (0, import_react.createElement)(Box, { display: "none" });
|
|
24517
|
+
if (viewport.compact) return (0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns("/theme · esc close", viewport.contentColumns));
|
|
24518
|
+
return (0, import_react.createElement)(Box, {
|
|
24519
|
+
width: viewport.outerColumns,
|
|
24520
|
+
borderStyle: "round",
|
|
24521
|
+
borderColor: inkColor(getPalette().dim),
|
|
24522
|
+
flexDirection: "column",
|
|
24523
|
+
paddingX: 1
|
|
24524
|
+
}, (0, import_react.createElement)(Text, {
|
|
24525
|
+
color: inkColor(getPalette().brandBright),
|
|
24526
|
+
wrap: "truncate-end"
|
|
24527
|
+
}, truncateColumns("/theme — color palette", viewport.contentColumns)), ...THEME_ROWS.map((theme, index) => {
|
|
24528
|
+
const selected = index === cursor;
|
|
24529
|
+
const active = theme.id === current;
|
|
24530
|
+
return (0, import_react.createElement)(Text, {
|
|
24531
|
+
key: theme.id,
|
|
24532
|
+
color: selected ? inkColor(getPalette().brandBright) : void 0,
|
|
24533
|
+
wrap: "truncate-end"
|
|
24534
|
+
}, truncateColumns(`${selected ? "› " : " "}${active ? "● " : "○ "}${theme.label}${active ? " · current" : ""} · ${theme.description}`, viewport.contentColumns));
|
|
24535
|
+
}), (0, import_react.createElement)(Text, {
|
|
24536
|
+
dimColor: true,
|
|
24537
|
+
wrap: "truncate-end"
|
|
24538
|
+
}, truncateColumns("↑↓ choose · enter apply · esc/q close", viewport.contentColumns)));
|
|
24539
|
+
}
|
|
24776
24540
|
//#endregion
|
|
24777
24541
|
//#region src/whale-glyph.ts
|
|
24778
24542
|
/** Half-block whale glyph rows; render with the brand color. */
|
|
@@ -24999,6 +24763,21 @@ function textOf(content) {
|
|
|
24999
24763
|
function reasoningOf(content) {
|
|
25000
24764
|
return content.filter((block) => block.type === "reasoning").map((block) => block.text).join("");
|
|
25001
24765
|
}
|
|
24766
|
+
/**
|
|
24767
|
+
* Rough token estimate for the segmented context bar (pi-nano-context's ~4
|
|
24768
|
+
* chars/token heuristic, CJK-aware so a Chinese prompt is not quartered):
|
|
24769
|
+
* CJK/wide chars cost ~1 token each, ASCII ~4 chars per token. Estimates
|
|
24770
|
+
* drive bar PROPORTIONS, never billing, so precision is not required.
|
|
24771
|
+
* @param text - the text to estimate.
|
|
24772
|
+
* @returns an integer token estimate, 0 for empty text.
|
|
24773
|
+
*/
|
|
24774
|
+
function estimateTokens(text) {
|
|
24775
|
+
let wide = 0;
|
|
24776
|
+
let narrow = 0;
|
|
24777
|
+
for (const char of text) if ((char.codePointAt(0) ?? 0) > 11903) wide += 1;
|
|
24778
|
+
else narrow += 1;
|
|
24779
|
+
return wide + Math.ceil(narrow / 4);
|
|
24780
|
+
}
|
|
25002
24781
|
/** A fresh, empty transcript view. */
|
|
25003
24782
|
function createTranscriptView() {
|
|
25004
24783
|
return {
|
|
@@ -25030,10 +24809,18 @@ function createTranscriptView() {
|
|
|
25030
24809
|
},
|
|
25031
24810
|
lastPromptTokens: 0,
|
|
25032
24811
|
contextWindow: 0,
|
|
24812
|
+
contextSegments: {
|
|
24813
|
+
system: 0,
|
|
24814
|
+
prompt: 0,
|
|
24815
|
+
assistant: 0,
|
|
24816
|
+
thinking: 0,
|
|
24817
|
+
tools: 0
|
|
24818
|
+
},
|
|
25033
24819
|
ttftMs: 0,
|
|
25034
24820
|
ttftSteps: 0,
|
|
25035
24821
|
decodeMs: 0,
|
|
25036
|
-
decodeTokens: 0
|
|
24822
|
+
decodeTokens: 0,
|
|
24823
|
+
reasoningEffort: ""
|
|
25037
24824
|
},
|
|
25038
24825
|
anchors: {
|
|
25039
24826
|
stepStart: /* @__PURE__ */ new Map(),
|
|
@@ -25070,24 +24857,40 @@ function projectEvent(view, event) {
|
|
|
25070
24857
|
};
|
|
25071
24858
|
entries = entries.filter((entry) => !(entry.kind === "pending" && entry.messageId === message.id));
|
|
25072
24859
|
}
|
|
24860
|
+
const text = textOf(message.content);
|
|
25073
24861
|
if (message.source.kind === "user") return {
|
|
25074
24862
|
...view,
|
|
25075
24863
|
pending,
|
|
25076
24864
|
entries: [...entries, {
|
|
25077
24865
|
kind: "user",
|
|
25078
|
-
text
|
|
24866
|
+
text,
|
|
25079
24867
|
notice: false
|
|
25080
|
-
}]
|
|
24868
|
+
}],
|
|
24869
|
+
stats: {
|
|
24870
|
+
...view.stats,
|
|
24871
|
+
contextSegments: {
|
|
24872
|
+
...view.stats.contextSegments,
|
|
24873
|
+
prompt: view.stats.contextSegments.prompt + estimateTokens(text)
|
|
24874
|
+
}
|
|
24875
|
+
}
|
|
25081
24876
|
};
|
|
25082
24877
|
const notice = message.source.kind === "plugin" && message.source.form === "notice" ? message.source.summary : message.source.kind;
|
|
24878
|
+
const summary = boundContextSummary(notice);
|
|
25083
24879
|
return {
|
|
25084
24880
|
...view,
|
|
25085
24881
|
pending,
|
|
25086
24882
|
entries: [...entries, {
|
|
25087
24883
|
kind: "user",
|
|
25088
|
-
text:
|
|
24884
|
+
text: summary,
|
|
25089
24885
|
notice: true
|
|
25090
|
-
}]
|
|
24886
|
+
}],
|
|
24887
|
+
stats: {
|
|
24888
|
+
...view.stats,
|
|
24889
|
+
contextSegments: {
|
|
24890
|
+
...view.stats.contextSegments,
|
|
24891
|
+
system: view.stats.contextSegments.system + estimateTokens(summary)
|
|
24892
|
+
}
|
|
24893
|
+
}
|
|
25091
24894
|
};
|
|
25092
24895
|
}
|
|
25093
24896
|
case "agent/inbox/spliced": {
|
|
@@ -25153,14 +24956,16 @@ function projectEvent(view, event) {
|
|
|
25153
24956
|
view.anchors.firstChunkAt.delete(key);
|
|
25154
24957
|
const usage = event.data.usage;
|
|
25155
24958
|
const totals = view.stats.usage;
|
|
24959
|
+
const text = textOf(event.data.message.content);
|
|
24960
|
+
const reasoning = reasoningOf(event.data.message.content);
|
|
25156
24961
|
return {
|
|
25157
24962
|
...view,
|
|
25158
24963
|
streaming: "",
|
|
25159
24964
|
streamingReasoning: "",
|
|
25160
24965
|
entries: [...view.entries, {
|
|
25161
24966
|
kind: "assistant",
|
|
25162
|
-
text
|
|
25163
|
-
reasoning
|
|
24967
|
+
text,
|
|
24968
|
+
reasoning
|
|
25164
24969
|
}],
|
|
25165
24970
|
stats: {
|
|
25166
24971
|
...view.stats,
|
|
@@ -25172,7 +24977,12 @@ function projectEvent(view, event) {
|
|
|
25172
24977
|
},
|
|
25173
24978
|
lastPromptTokens: usage === void 0 ? view.stats.lastPromptTokens : usage.inputTokens + (usage.cacheReadTokens ?? 0) + (usage.cacheWriteTokens ?? 0),
|
|
25174
24979
|
decodeMs: view.stats.decodeMs + (firstChunk === void 0 ? 0 : Math.max(0, event.time - firstChunk)),
|
|
25175
|
-
decodeTokens: view.stats.decodeTokens + (firstChunk === void 0 || usage === void 0 ? 0 : usage.outputTokens)
|
|
24980
|
+
decodeTokens: view.stats.decodeTokens + (firstChunk === void 0 || usage === void 0 ? 0 : usage.outputTokens),
|
|
24981
|
+
contextSegments: {
|
|
24982
|
+
...view.stats.contextSegments,
|
|
24983
|
+
thinking: view.stats.contextSegments.thinking + estimateTokens(reasoning),
|
|
24984
|
+
assistant: view.stats.contextSegments.assistant + estimateTokens(text)
|
|
24985
|
+
}
|
|
25176
24986
|
}
|
|
25177
24987
|
};
|
|
25178
24988
|
}
|
|
@@ -25190,7 +25000,14 @@ function projectEvent(view, event) {
|
|
|
25190
25000
|
state: "running",
|
|
25191
25001
|
summary: "",
|
|
25192
25002
|
detail: void 0
|
|
25193
|
-
}]
|
|
25003
|
+
}],
|
|
25004
|
+
stats: {
|
|
25005
|
+
...view.stats,
|
|
25006
|
+
contextSegments: {
|
|
25007
|
+
...view.stats.contextSegments,
|
|
25008
|
+
tools: view.stats.contextSegments.tools + (typeof data.arguments === "string" ? estimateTokens(data.arguments) : 0)
|
|
25009
|
+
}
|
|
25010
|
+
}
|
|
25194
25011
|
};
|
|
25195
25012
|
}
|
|
25196
25013
|
case "tool/result": {
|
|
@@ -25219,7 +25036,11 @@ function projectEvent(view, event) {
|
|
|
25219
25036
|
entries,
|
|
25220
25037
|
stats: {
|
|
25221
25038
|
...view.stats,
|
|
25222
|
-
toolMs: view.stats.toolMs + (started === void 0 ? 0 : Math.max(0, event.time - started))
|
|
25039
|
+
toolMs: view.stats.toolMs + (started === void 0 ? 0 : Math.max(0, event.time - started)),
|
|
25040
|
+
contextSegments: {
|
|
25041
|
+
...view.stats.contextSegments,
|
|
25042
|
+
tools: view.stats.contextSegments.tools + estimateTokens(rawText)
|
|
25043
|
+
}
|
|
25223
25044
|
}
|
|
25224
25045
|
};
|
|
25225
25046
|
}
|
|
@@ -25378,7 +25199,15 @@ function projectEvent(view, event) {
|
|
|
25378
25199
|
const config = event.data.header.config;
|
|
25379
25200
|
return {
|
|
25380
25201
|
...view,
|
|
25381
|
-
model: `${config.provider}/${config.model}
|
|
25202
|
+
model: `${config.provider}/${config.model}`,
|
|
25203
|
+
stats: {
|
|
25204
|
+
...view.stats,
|
|
25205
|
+
reasoningEffort: config.reasoningEffort === void 0 ? "" : String(config.reasoningEffort),
|
|
25206
|
+
contextSegments: {
|
|
25207
|
+
...view.stats.contextSegments,
|
|
25208
|
+
system: estimateTokens(event.data.header.system ?? "")
|
|
25209
|
+
}
|
|
25210
|
+
}
|
|
25382
25211
|
};
|
|
25383
25212
|
}
|
|
25384
25213
|
case "plan/mode": return {
|
|
@@ -25430,19 +25259,23 @@ function projectEvents(events) {
|
|
|
25430
25259
|
return events.reduce(projectEvent, createTranscriptView());
|
|
25431
25260
|
}
|
|
25432
25261
|
/**
|
|
25433
|
-
*
|
|
25434
|
-
*
|
|
25435
|
-
*
|
|
25436
|
-
*
|
|
25437
|
-
*
|
|
25438
|
-
*
|
|
25439
|
-
*
|
|
25262
|
+
* The append-only flush boundary for a transcript view: the count of entries
|
|
25263
|
+
* no later event can remove. Entries at or beyond this index are mutable and
|
|
25264
|
+
* must stay in the live tree.
|
|
25265
|
+
*
|
|
25266
|
+
* `pending` rows are excluded even though they are not a running tool/retry:
|
|
25267
|
+
* the inbox claims or cancels them durably (`agent/inbox/spliced` removals,
|
|
25268
|
+
* `user/message` retirement), and an append-only `<Static>` flush cannot
|
|
25269
|
+
* erase a row that vanishes from the view — the retired row would ghost on
|
|
25270
|
+
* screen until the next source-backed replay. Everything else (including a
|
|
25271
|
+
* completed tail) is final: later events only APPEND new rows.
|
|
25440
25272
|
* @param entries - the view's transcript entries in order.
|
|
25441
25273
|
* @returns the count of entries safe to flush (0 for an empty transcript).
|
|
25442
25274
|
*/
|
|
25443
25275
|
function settledEntryCount(entries) {
|
|
25444
25276
|
for (let index = 0; index < entries.length; index++) {
|
|
25445
25277
|
const entry = entries[index];
|
|
25278
|
+
if (entry.kind === "pending") return index;
|
|
25446
25279
|
if (entry.kind === "tool" && entry.state === "running") return index;
|
|
25447
25280
|
if (entry.kind === "retry" && entry.state === "running") return index;
|
|
25448
25281
|
}
|
|
@@ -25681,16 +25514,6 @@ function renderMarkdown(text, width) {
|
|
|
25681
25514
|
}
|
|
25682
25515
|
//#endregion
|
|
25683
25516
|
//#region src/render/animations.ts
|
|
25684
|
-
/**
|
|
25685
|
-
* Terminal animation frame tables derived from the web design language:
|
|
25686
|
-
* the StateDot "ongoing" pixel chase (3×3 ring, 125ms flat-hold brightness
|
|
25687
|
-
* steps, 1s cycle) becomes the single-cell stepped pulse below and the
|
|
25688
|
-
* full-ring clockwise braille chase in {@link BUSY_CHASE_FRAMES}, and the
|
|
25689
|
-
* streaming caret blink is the Claude-Code convention. Pure functions only —
|
|
25690
|
-
* the Ink layer owns timers and colors.
|
|
25691
|
-
*
|
|
25692
|
-
* @module @deepseek-ai/dsh-code/render/animations
|
|
25693
|
-
*/
|
|
25694
25517
|
/** Single-cell stepped pulse: flat holds mirroring the web's 125ms keyframes. */
|
|
25695
25518
|
const PULSE_FRAMES = [
|
|
25696
25519
|
"█",
|
|
@@ -25729,182 +25552,329 @@ function busyChaseFrame(tick) {
|
|
|
25729
25552
|
function caretVisible(tick) {
|
|
25730
25553
|
return tick % 2 === 0;
|
|
25731
25554
|
}
|
|
25732
|
-
|
|
25733
|
-
|
|
25734
|
-
|
|
25735
|
-
|
|
25736
|
-
|
|
25737
|
-
|
|
25738
|
-
|
|
25739
|
-
|
|
25555
|
+
/** All styles in canonical order, for random selection and tests. */
|
|
25556
|
+
const DEEPSEEK_WAVE_STYLES = [
|
|
25557
|
+
"wave",
|
|
25558
|
+
"aurora",
|
|
25559
|
+
"pulse"
|
|
25560
|
+
];
|
|
25561
|
+
/** Pulse ring half-width in columns — Codex PULSE_HALF_WIDTH (4.5). */
|
|
25562
|
+
const PULSE_HALF_WIDTH = 4.5;
|
|
25563
|
+
/** Sparkle glyphs in frame order — Codex SPARK_GLYPHS (`· ✦ ✧`). */
|
|
25564
|
+
const SPARK_GLYPHS = [
|
|
25565
|
+
"·",
|
|
25566
|
+
"✦",
|
|
25567
|
+
"✧"
|
|
25568
|
+
];
|
|
25569
|
+
const DEEPSEEK_WAVE_BANDS = {
|
|
25570
|
+
wave: {
|
|
25571
|
+
flash: [[
|
|
25572
|
+
.1,
|
|
25573
|
+
.75,
|
|
25574
|
+
1
|
|
25575
|
+
]],
|
|
25576
|
+
deepseek: [[
|
|
25577
|
+
.1,
|
|
25578
|
+
.7,
|
|
25579
|
+
1
|
|
25580
|
+
], [
|
|
25581
|
+
.35,
|
|
25582
|
+
.55,
|
|
25583
|
+
1
|
|
25584
|
+
]]
|
|
25585
|
+
},
|
|
25586
|
+
aurora: {
|
|
25587
|
+
flash: [[
|
|
25588
|
+
.35,
|
|
25589
|
+
.15,
|
|
25590
|
+
0
|
|
25591
|
+
], [
|
|
25592
|
+
-.5,
|
|
25593
|
+
.6,
|
|
25594
|
+
1
|
|
25595
|
+
]],
|
|
25596
|
+
deepseek: [
|
|
25597
|
+
[
|
|
25598
|
+
.35,
|
|
25599
|
+
.15,
|
|
25600
|
+
0
|
|
25601
|
+
],
|
|
25602
|
+
[
|
|
25603
|
+
-.5,
|
|
25604
|
+
.6,
|
|
25605
|
+
1
|
|
25606
|
+
],
|
|
25607
|
+
[
|
|
25608
|
+
.75,
|
|
25609
|
+
.35,
|
|
25610
|
+
2
|
|
25611
|
+
]
|
|
25612
|
+
]
|
|
25613
|
+
},
|
|
25614
|
+
pulse: {
|
|
25615
|
+
flash: [[
|
|
25616
|
+
.1,
|
|
25617
|
+
.6,
|
|
25618
|
+
1
|
|
25619
|
+
]],
|
|
25620
|
+
deepseek: [[
|
|
25621
|
+
.1,
|
|
25622
|
+
.55,
|
|
25623
|
+
.8
|
|
25624
|
+
], [
|
|
25625
|
+
.45,
|
|
25626
|
+
.55,
|
|
25627
|
+
1.1
|
|
25628
|
+
]]
|
|
25629
|
+
}
|
|
25630
|
+
};
|
|
25740
25631
|
/**
|
|
25741
|
-
*
|
|
25742
|
-
*
|
|
25743
|
-
*
|
|
25632
|
+
* Total animation duration — Codex `IgnitionStyle::total_duration`: three
|
|
25633
|
+
* styles × two tiers.
|
|
25634
|
+
* @param tier - the active wave tier.
|
|
25635
|
+
* @param style - the active ignition style.
|
|
25636
|
+
* @returns the duration in milliseconds.
|
|
25744
25637
|
*/
|
|
25745
|
-
function
|
|
25746
|
-
|
|
25747
|
-
|
|
25748
|
-
|
|
25749
|
-
|
|
25750
|
-
|
|
25751
|
-
const outerColumns = compact ? safeColumns : Math.max(1, safeColumns - 1);
|
|
25752
|
-
return {
|
|
25753
|
-
maxHeight,
|
|
25754
|
-
bodyRows: compact ? 0 : maxHeight - 4 - gapRows,
|
|
25755
|
-
gapRows,
|
|
25756
|
-
contentColumns: compact ? Math.max(1, safeColumns - 1) : Math.max(1, outerColumns - 4),
|
|
25757
|
-
outerColumns,
|
|
25758
|
-
compact
|
|
25759
|
-
};
|
|
25760
|
-
}
|
|
25761
|
-
/** Backward-compatible name for the Ctrl+O-specific caller and tests. */
|
|
25762
|
-
function inspectorViewport(columns, rows) {
|
|
25763
|
-
return panelViewport(columns, rows);
|
|
25764
|
-
}
|
|
25765
|
-
/** Clamp a first-visible row to the range representable by one viewport. */
|
|
25766
|
-
function clampScroll(offset, totalRows, visibleRows) {
|
|
25767
|
-
const last = Math.max(0, Math.max(0, Math.floor(totalRows)) - Math.max(0, Math.floor(visibleRows)));
|
|
25768
|
-
return Math.max(0, Math.min(Math.floor(offset), last));
|
|
25769
|
-
}
|
|
25770
|
-
/** Move a viewport by a signed row delta without escaping its content. */
|
|
25771
|
-
function moveScroll(offset, delta, totalRows, visibleRows) {
|
|
25772
|
-
return clampScroll(offset + delta, totalRows, visibleRows);
|
|
25638
|
+
function deepseekWaveDuration(tier, style = "wave") {
|
|
25639
|
+
switch (style) {
|
|
25640
|
+
case "aurora": return tier === "flash" ? 1300 : 1600;
|
|
25641
|
+
case "pulse": return tier === "flash" ? 900 : 1250;
|
|
25642
|
+
case "wave": return tier === "flash" ? 1e3 : 1300;
|
|
25643
|
+
}
|
|
25773
25644
|
}
|
|
25774
|
-
/**
|
|
25775
|
-
|
|
25776
|
-
|
|
25777
|
-
|
|
25778
|
-
|
|
25779
|
-
|
|
25780
|
-
|
|
25645
|
+
/**
|
|
25646
|
+
* Pick one ignition style at random, never repeating the previous one —
|
|
25647
|
+
* Codex `IgnitionStyle::random`. Falls back to the remaining styles.
|
|
25648
|
+
* @param previous - the style of the last trigger, if any.
|
|
25649
|
+
* @returns a style different from `previous`.
|
|
25650
|
+
*/
|
|
25651
|
+
function deepseekWaveStyleRandom(previous) {
|
|
25652
|
+
const candidates = DEEPSEEK_WAVE_STYLES.filter((style) => style !== previous);
|
|
25653
|
+
return candidates[Math.floor(Math.random() * candidates.length)] ?? "wave";
|
|
25781
25654
|
}
|
|
25782
|
-
/**
|
|
25783
|
-
|
|
25784
|
-
|
|
25655
|
+
/**
|
|
25656
|
+
* Blank-cell background the wave tint blends toward — fixed approximations
|
|
25657
|
+
* of the terminal's default background, mirroring Codex's
|
|
25658
|
+
* `user_message_bg_rgb` (which derives a near-black / near-white bubble tint
|
|
25659
|
+
* from the terminal background). The Ink layer picks the active theme's one.
|
|
25660
|
+
*/
|
|
25661
|
+
const WAVE_BASE_DARK = [
|
|
25662
|
+
16,
|
|
25663
|
+
18,
|
|
25664
|
+
24
|
|
25665
|
+
];
|
|
25666
|
+
const WAVE_BASE_LIGHT = [
|
|
25667
|
+
242,
|
|
25668
|
+
244,
|
|
25669
|
+
248
|
|
25670
|
+
];
|
|
25671
|
+
/**
|
|
25672
|
+
* Tier for a `provider/model` label: a model id containing `flash` runs the
|
|
25673
|
+
* single-band flash tier; everything else (pro/reasoner/chat) runs the
|
|
25674
|
+
* dual-band deepseek tier. Mirrors Codex's Max→Ultra mapping.
|
|
25675
|
+
* @param model - the `provider/model` label of the applied model.
|
|
25676
|
+
* @returns the wave tier for that model.
|
|
25677
|
+
*/
|
|
25678
|
+
function deepseekWaveTier(model) {
|
|
25679
|
+
return model.toLowerCase().includes("flash") ? "flash" : "deepseek";
|
|
25785
25680
|
}
|
|
25786
|
-
/**
|
|
25787
|
-
|
|
25788
|
-
|
|
25789
|
-
|
|
25790
|
-
|
|
25681
|
+
/**
|
|
25682
|
+
* Cosine window — Codex `crest`: 1 exactly under the wave center, 0 from
|
|
25683
|
+
* one half-width away.
|
|
25684
|
+
* @param distance - distance from the crest center in half-widths.
|
|
25685
|
+
* @returns the crest strength in 0..1.
|
|
25686
|
+
*/
|
|
25687
|
+
function crest(distance) {
|
|
25688
|
+
if (distance >= 1) return 0;
|
|
25689
|
+
return .5 * (1 + Math.cos(Math.PI * distance));
|
|
25791
25690
|
}
|
|
25792
|
-
//#endregion
|
|
25793
|
-
//#region src/render/text.ts
|
|
25794
25691
|
/**
|
|
25795
|
-
*
|
|
25796
|
-
*
|
|
25797
|
-
*
|
|
25798
|
-
*
|
|
25799
|
-
* and tabs survive; everything else in C0/C1 plus DEL becomes a visible
|
|
25800
|
-
* `\xNN` escape.
|
|
25801
|
-
*
|
|
25802
|
-
* @module @deepseek-ai/dsh-code/render/text
|
|
25692
|
+
* Cubic ease-in-out — Codex `ease_in_out`: flat at both ends, steepest in
|
|
25693
|
+
* the middle, so the crest accelerates and eases instead of sliding linearly.
|
|
25694
|
+
* @param progress - raw progress (clamped to 0..1).
|
|
25695
|
+
* @returns the eased progress in 0..1.
|
|
25803
25696
|
*/
|
|
25804
|
-
|
|
25805
|
-
const
|
|
25697
|
+
function easeInOut(progress) {
|
|
25698
|
+
const p = Math.min(1, Math.max(0, progress));
|
|
25699
|
+
if (p < .5) return 4 * p * p * p;
|
|
25700
|
+
const inverse = -2 * p + 2;
|
|
25701
|
+
return 1 - inverse * inverse * inverse / 2;
|
|
25702
|
+
}
|
|
25806
25703
|
/**
|
|
25807
|
-
*
|
|
25808
|
-
*
|
|
25809
|
-
*
|
|
25810
|
-
*
|
|
25811
|
-
*
|
|
25704
|
+
* Fade-in/fade-out envelope — Codex `envelope`: linear ramp over `fadeIn`
|
|
25705
|
+
* at the start and `fadeOut` at the end, plateau at 1 between, 0 outside the
|
|
25706
|
+
* total. The Wave style keeps the envelope at 1 (Codex paints Wave without
|
|
25707
|
+
* an envelope); exported for the Aurora-style fades and for tests.
|
|
25708
|
+
* @param elapsed - seconds since the animation started.
|
|
25709
|
+
* @param total - total duration in seconds.
|
|
25710
|
+
* @param fadeIn - seconds of fade-in.
|
|
25711
|
+
* @param fadeOut - seconds of fade-out.
|
|
25712
|
+
* @returns the envelope value in 0..1.
|
|
25812
25713
|
*/
|
|
25813
|
-
function
|
|
25814
|
-
|
|
25714
|
+
function envelope(elapsed, total, fadeIn, fadeOut) {
|
|
25715
|
+
if (elapsed <= 0 || elapsed >= total) return 0;
|
|
25716
|
+
const rise = elapsed / Math.max(fadeIn, Number.EPSILON);
|
|
25717
|
+
const fall = (total - elapsed) / Math.max(fadeOut, Number.EPSILON);
|
|
25718
|
+
return Math.min(Math.max(Math.min(rise, fall), 0), 1);
|
|
25815
25719
|
}
|
|
25816
|
-
/**
|
|
25817
|
-
|
|
25818
|
-
|
|
25720
|
+
/**
|
|
25721
|
+
* One band's contribution at a column — Codex `band_sample`, all three
|
|
25722
|
+
* branches: Wave sweeps an eased crest across the row; Aurora drifts a
|
|
25723
|
+
* sinusoidal center carrying a hue index; Pulse expands a ring from the row
|
|
25724
|
+
* center with cubic ease and decaying strength.
|
|
25725
|
+
* @param style - the ignition style.
|
|
25726
|
+
* @param band - the band triple (meaning depends on the style).
|
|
25727
|
+
* @param elapsed - seconds since the animation started.
|
|
25728
|
+
* @param column - column index in the content row (0..width-1).
|
|
25729
|
+
* @param width - content-row width in columns.
|
|
25730
|
+
* @returns `[hueIndex, strength]`.
|
|
25731
|
+
*/
|
|
25732
|
+
function bandSample(style, band, elapsed, column, width) {
|
|
25733
|
+
const [first, second, third] = band;
|
|
25734
|
+
switch (style) {
|
|
25735
|
+
case "wave": {
|
|
25736
|
+
const progress = (elapsed - first) / second;
|
|
25737
|
+
if (progress < 0 || progress > 1) return [0, 0];
|
|
25738
|
+
const center = easeInOut(progress) * (width + 18) - 9;
|
|
25739
|
+
return [0, crest(Math.abs(column - center) / 9)];
|
|
25740
|
+
}
|
|
25741
|
+
case "aurora": {
|
|
25742
|
+
const center = (.5 + .38 * Math.sin(Math.PI * 2 * (first * elapsed + second))) * width;
|
|
25743
|
+
const halfWidth = Math.max(width * .22, 4);
|
|
25744
|
+
return [Math.trunc(third), crest(Math.abs(column - center) / halfWidth)];
|
|
25745
|
+
}
|
|
25746
|
+
case "pulse": {
|
|
25747
|
+
const progress = (elapsed - first) / second;
|
|
25748
|
+
if (progress < 0 || progress > 1) return [0, 0];
|
|
25749
|
+
const inverse = 1 - progress;
|
|
25750
|
+
const radius = (1 - inverse * inverse * inverse) * (width / 2 + 2 * PULSE_HALF_WIDTH);
|
|
25751
|
+
const distance = Math.abs(column - width / 2);
|
|
25752
|
+
return [0, crest(Math.abs(distance - radius) / PULSE_HALF_WIDTH) * third * (1 - .6 * progress)];
|
|
25753
|
+
}
|
|
25754
|
+
}
|
|
25819
25755
|
}
|
|
25820
|
-
/**
|
|
25821
|
-
function
|
|
25822
|
-
|
|
25823
|
-
|
|
25824
|
-
|
|
25756
|
+
/** Linear RGB blend — Codex `blend`: `fg * alpha + bg * (1 - alpha)`. */
|
|
25757
|
+
function blendRgb(fg, bg, alpha) {
|
|
25758
|
+
return [
|
|
25759
|
+
Math.round(fg[0] * alpha + bg[0] * (1 - alpha)),
|
|
25760
|
+
Math.round(fg[1] * alpha + bg[1] * (1 - alpha)),
|
|
25761
|
+
Math.round(fg[2] * alpha + bg[2] * (1 - alpha))
|
|
25762
|
+
];
|
|
25825
25763
|
}
|
|
25826
25764
|
/**
|
|
25827
|
-
*
|
|
25828
|
-
*
|
|
25829
|
-
*
|
|
25830
|
-
*
|
|
25765
|
+
* The background color for one composer-row column at a tick — Codex
|
|
25766
|
+
* `paint_bands` + `Canvas::tint` for all three styles. Bands overlap with a
|
|
25767
|
+
* max for Wave/Pulse and a SUM for Aurora (Codex differs by style), the
|
|
25768
|
+
* weighted hues mix per column (Wave/Pulse always end on hue 0), the tint
|
|
25769
|
+
* blends the mixed hue toward the blank-cell base at the style's alpha cap,
|
|
25770
|
+
* and Aurora applies its own fade envelope. Returns `null` when the column
|
|
25771
|
+
* should stay transparent, so the row returns to no `backgroundColor` on
|
|
25772
|
+
* both ends.
|
|
25773
|
+
* @param tick - wave frame (0, 1, … at DEEPSEEK_WAVE_TICK_MS).
|
|
25774
|
+
* @param column - column index in the content row (0..width-1).
|
|
25775
|
+
* @param width - content-row width in columns.
|
|
25776
|
+
* @param tier - the wave tier (flash = Max, deepseek = Ultra parameters).
|
|
25777
|
+
* @param style - the ignition style.
|
|
25778
|
+
* @param hues - the tier's three hues.
|
|
25779
|
+
* @param base - the blank-cell base color the tint blends toward.
|
|
25780
|
+
* @returns the blended RGB background, or null for transparent.
|
|
25831
25781
|
*/
|
|
25832
|
-
function
|
|
25833
|
-
const
|
|
25834
|
-
|
|
25835
|
-
|
|
25836
|
-
const
|
|
25837
|
-
|
|
25838
|
-
|
|
25839
|
-
|
|
25840
|
-
|
|
25841
|
-
|
|
25842
|
-
|
|
25843
|
-
|
|
25782
|
+
function deepseekWaveColumnBg(tick, column, width, tier, style, hues, base) {
|
|
25783
|
+
const total = deepseekWaveDuration(tier, style) / 1e3;
|
|
25784
|
+
const elapsed = tick * 33 / 1e3;
|
|
25785
|
+
const fade = style === "aurora" ? envelope(elapsed, total, .25, .4) : 1;
|
|
25786
|
+
const weights = [
|
|
25787
|
+
0,
|
|
25788
|
+
0,
|
|
25789
|
+
0
|
|
25790
|
+
];
|
|
25791
|
+
for (const band of DEEPSEEK_WAVE_BANDS[style][tier]) {
|
|
25792
|
+
const [hue, strength] = bandSample(style, band, elapsed, column, width);
|
|
25793
|
+
weights[hue] = style === "aurora" ? weights[hue] + strength : Math.max(weights[hue], strength);
|
|
25844
25794
|
}
|
|
25845
|
-
|
|
25846
|
-
|
|
25847
|
-
|
|
25848
|
-
|
|
25849
|
-
|
|
25850
|
-
|
|
25851
|
-
|
|
25852
|
-
|
|
25853
|
-
|
|
25854
|
-
start: end - 2
|
|
25855
|
-
};
|
|
25795
|
+
const weight = weights[0] + weights[1] + weights[2];
|
|
25796
|
+
if (weight <= .01) return null;
|
|
25797
|
+
let red = 0;
|
|
25798
|
+
let green = 0;
|
|
25799
|
+
let blue = 0;
|
|
25800
|
+
for (let index = 0; index < 3; index += 1) {
|
|
25801
|
+
red += weights[index] * hues[index][0];
|
|
25802
|
+
green += weights[index] * hues[index][1];
|
|
25803
|
+
blue += weights[index] * hues[index][2];
|
|
25856
25804
|
}
|
|
25857
|
-
|
|
25858
|
-
|
|
25859
|
-
|
|
25860
|
-
|
|
25805
|
+
const mixed = [
|
|
25806
|
+
Math.round(red / weight),
|
|
25807
|
+
Math.round(green / weight),
|
|
25808
|
+
Math.round(blue / weight)
|
|
25809
|
+
];
|
|
25810
|
+
const alpha = style === "aurora" ? Math.min(weight * .4, .5) * fade : weight * .55;
|
|
25811
|
+
if (alpha < .02) return null;
|
|
25812
|
+
return blendRgb(mixed, base, alpha);
|
|
25813
|
+
}
|
|
25814
|
+
/**
|
|
25815
|
+
* The sparkle glyph for a tick — Codex `spark_frame`: from 900ms on, one
|
|
25816
|
+
* glyph every 100ms through `· ✦ ✧`, then silent. The deepseek (Ultra) tier
|
|
25817
|
+
* only; the Ink layer still must skip occupied cells.
|
|
25818
|
+
* @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS.
|
|
25819
|
+
* @returns the sparkle glyph, or null outside the 900..1200ms window.
|
|
25820
|
+
*/
|
|
25821
|
+
function deepseekWaveSpark(tick) {
|
|
25822
|
+
const elapsed = tick * 33;
|
|
25823
|
+
if (elapsed < 900) return null;
|
|
25824
|
+
const frame = Math.floor((elapsed - 900) / 100);
|
|
25825
|
+
return SPARK_GLYPHS[frame] ?? null;
|
|
25826
|
+
}
|
|
25827
|
+
/**
|
|
25828
|
+
* The composer BORDER color at a tick: the frame breathes with the wave —
|
|
25829
|
+
* the palette's static dim blends toward the tier accent as the crest is
|
|
25830
|
+
* alive and back, so the frame glows up while the wave sweeps and settles to
|
|
25831
|
+
* dim on both ends (first==last frame==dim, no hard jump).
|
|
25832
|
+
* @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS.
|
|
25833
|
+
* @param tier - the wave tier.
|
|
25834
|
+
* @param hues - the tier's three hues; the border blends toward hues[0].
|
|
25835
|
+
* @param dim - the palette's static dim RGB (the resting border color).
|
|
25836
|
+
* @returns the blended border RGB.
|
|
25837
|
+
*/
|
|
25838
|
+
function deepseekWaveBorderColor(tick, tier, style, hues, dim) {
|
|
25839
|
+
const total = deepseekWaveDuration(tier, style) / 1e3;
|
|
25840
|
+
const glow = envelope(tick * 33 / 1e3, total, total * .25, total * .4);
|
|
25841
|
+
return blendRgb(hues[0], dim, .25 + glow * .6);
|
|
25861
25842
|
}
|
|
25862
25843
|
/**
|
|
25863
|
-
*
|
|
25864
|
-
*
|
|
25865
|
-
*
|
|
25866
|
-
*
|
|
25867
|
-
* @param
|
|
25868
|
-
* @param
|
|
25869
|
-
* @
|
|
25870
|
-
* @returns a sanitized bounded suffix and whether an earlier prefix was cut.
|
|
25844
|
+
* Whether the `deepseek` wordmark rides the wave at this tick: it fades in
|
|
25845
|
+
* shortly after the first crest launches and out before the wave settles,
|
|
25846
|
+
* so the brand name surfaces through the sweep's middle. The Ink layer
|
|
25847
|
+
* places it in the row's blank mid-section (never over real draft text).
|
|
25848
|
+
* @param tick - wave frame at DEEPSEEK_WAVE_TICK_MS.
|
|
25849
|
+
* @param tier - the wave tier.
|
|
25850
|
+
* @returns true while the wordmark should be visible.
|
|
25871
25851
|
*/
|
|
25872
|
-
function
|
|
25873
|
-
const
|
|
25874
|
-
|
|
25875
|
-
|
|
25876
|
-
|
|
25877
|
-
|
|
25878
|
-
|
|
25879
|
-
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
25885
|
-
|
|
25886
|
-
|
|
25887
|
-
|
|
25888
|
-
|
|
25889
|
-
|
|
25890
|
-
|
|
25891
|
-
|
|
25892
|
-
|
|
25893
|
-
|
|
25894
|
-
|
|
25895
|
-
|
|
25896
|
-
|
|
25897
|
-
|
|
25898
|
-
if (row + extraRows > rowLimit) break;
|
|
25899
|
-
row += extraRows;
|
|
25900
|
-
reversed.push(safe);
|
|
25901
|
-
used = extraRows === 0 ? used + width : width - extraRows * columnLimit;
|
|
25902
|
-
end = previous.start;
|
|
25903
|
-
}
|
|
25904
|
-
return {
|
|
25905
|
-
text: reversed.reverse().join(""),
|
|
25906
|
-
truncated: end > 0
|
|
25907
|
-
};
|
|
25852
|
+
function deepseekWaveWordVisible(tick, tier, style = "wave") {
|
|
25853
|
+
const total = deepseekWaveDuration(tier, style) / 1e3;
|
|
25854
|
+
return envelope(tick * 33 / 1e3, total, total * .2, total * .35) > .25;
|
|
25855
|
+
}
|
|
25856
|
+
/**
|
|
25857
|
+
* The per-character color for the `deepseek` wordmark: the tier's hues
|
|
25858
|
+
* cycled per character (d→hue0, e→hue1, e→hue2, …), a brand-gradient text.
|
|
25859
|
+
* @param index - character index in the wordmark.
|
|
25860
|
+
* @param hues - the tier's three hues.
|
|
25861
|
+
* @returns the hue for that character.
|
|
25862
|
+
*/
|
|
25863
|
+
function deepseekWaveWordHue(index, hues) {
|
|
25864
|
+
return hues[index % hues.length];
|
|
25865
|
+
}
|
|
25866
|
+
/**
|
|
25867
|
+
* True when a `provider/model` status label addresses the official DeepSeek
|
|
25868
|
+
* route: either segment contains `deepseek` (case-insensitive), covering the
|
|
25869
|
+
* `deepseek-official` provider route and its `deepseek-*` model ids.
|
|
25870
|
+
* @param label - the status bar model label (`provider/model`).
|
|
25871
|
+
* @returns whether the label names an official DeepSeek model.
|
|
25872
|
+
*/
|
|
25873
|
+
function isOfficialDeepSeekLabel(label) {
|
|
25874
|
+
const slash = label.indexOf("/");
|
|
25875
|
+
const provider = slash < 0 ? label : label.slice(0, slash);
|
|
25876
|
+
const model = slash < 0 ? "" : label.slice(slash + 1);
|
|
25877
|
+
return provider.toLowerCase().includes("deepseek") || model.toLowerCase().includes("deepseek");
|
|
25908
25878
|
}
|
|
25909
25879
|
//#endregion
|
|
25910
25880
|
//#region src/render/status.ts
|
|
@@ -25965,39 +25935,152 @@ function cacheHitPercent(usage) {
|
|
|
25965
25935
|
const STATUS_ITEM_SEPARATOR = " · ";
|
|
25966
25936
|
/** The Codex-style mode cycle hint appended to the permission badge. */
|
|
25967
25937
|
const STATUS_CYCLE_HINT = " (shift+tab to cycle)";
|
|
25938
|
+
/** Free-tail floor in columns: wide enough for the bare percent readout, so
|
|
25939
|
+
* the warning stays visible even at 100%+ occupancy. */
|
|
25940
|
+
const CONTEXT_MIN_FREE = 5;
|
|
25941
|
+
/** The five content types in conversation order, dark → light blue. */
|
|
25942
|
+
const CONTEXT_SEGMENTS = [
|
|
25943
|
+
{
|
|
25944
|
+
key: "system",
|
|
25945
|
+
tone: "ctxSystem",
|
|
25946
|
+
labels: [
|
|
25947
|
+
"system",
|
|
25948
|
+
"sys",
|
|
25949
|
+
"s"
|
|
25950
|
+
]
|
|
25951
|
+
},
|
|
25952
|
+
{
|
|
25953
|
+
key: "prompt",
|
|
25954
|
+
tone: "ctxPrompt",
|
|
25955
|
+
labels: [
|
|
25956
|
+
"prompt",
|
|
25957
|
+
"pr",
|
|
25958
|
+
"p"
|
|
25959
|
+
]
|
|
25960
|
+
},
|
|
25961
|
+
{
|
|
25962
|
+
key: "assistant",
|
|
25963
|
+
tone: "ctxAssistant",
|
|
25964
|
+
labels: [
|
|
25965
|
+
"assistant",
|
|
25966
|
+
"ast",
|
|
25967
|
+
"a"
|
|
25968
|
+
]
|
|
25969
|
+
},
|
|
25970
|
+
{
|
|
25971
|
+
key: "thinking",
|
|
25972
|
+
tone: "ctxThinking",
|
|
25973
|
+
labels: [
|
|
25974
|
+
"think",
|
|
25975
|
+
"th",
|
|
25976
|
+
"t"
|
|
25977
|
+
]
|
|
25978
|
+
},
|
|
25979
|
+
{
|
|
25980
|
+
key: "tools",
|
|
25981
|
+
tone: "ctxTools",
|
|
25982
|
+
labels: [
|
|
25983
|
+
"tools",
|
|
25984
|
+
"tl",
|
|
25985
|
+
"x"
|
|
25986
|
+
]
|
|
25987
|
+
}
|
|
25988
|
+
];
|
|
25989
|
+
/** First label whose visible width fits the segment; empty only when none do. */
|
|
25990
|
+
function chooseContextLabel(labels, width) {
|
|
25991
|
+
for (const label of labels) if (visibleColumns(label) <= width) return label;
|
|
25992
|
+
return "";
|
|
25993
|
+
}
|
|
25994
|
+
/** Center a label inside its segment width; the padding spaces carry the tone. */
|
|
25995
|
+
function centerInSegment(text, width) {
|
|
25996
|
+
const textWidth = visibleColumns(text);
|
|
25997
|
+
const left = Math.floor((width - textWidth) / 2);
|
|
25998
|
+
return " ".repeat(Math.max(0, left)) + text + " ".repeat(Math.max(0, width - textWidth - left));
|
|
25999
|
+
}
|
|
26000
|
+
/**
|
|
26001
|
+
* Largest-remainder allocation: distribute `columns` across `values`
|
|
26002
|
+
* proportionally, handing each leftover column to the largest remainder.
|
|
26003
|
+
*/
|
|
26004
|
+
function allocateProportionally(values, columns) {
|
|
26005
|
+
if (columns <= 0) return values.map(() => 0);
|
|
26006
|
+
const total = values.reduce((sum, value) => sum + value, 0);
|
|
26007
|
+
if (total <= 0) return values.map(() => 0);
|
|
26008
|
+
const raw = values.map((value) => value / total * columns);
|
|
26009
|
+
const allocated = raw.map(Math.floor);
|
|
26010
|
+
let remaining = columns - allocated.reduce((sum, value) => sum + value, 0);
|
|
26011
|
+
const remainders = raw.map((value, index) => ({
|
|
26012
|
+
index,
|
|
26013
|
+
remainder: value - Math.floor(value)
|
|
26014
|
+
})).sort((left, right) => right.remainder - left.remainder);
|
|
26015
|
+
for (const slot of remainders) {
|
|
26016
|
+
if (remaining <= 0) break;
|
|
26017
|
+
allocated[slot.index] = (allocated[slot.index] ?? 0) + 1;
|
|
26018
|
+
remaining -= 1;
|
|
26019
|
+
}
|
|
26020
|
+
return allocated;
|
|
26021
|
+
}
|
|
26022
|
+
/** Bar column widths: every non-zero segment keeps at least one column before
|
|
26023
|
+
* the remaining columns share by token proportion. */
|
|
26024
|
+
function allocateBarColumns(values, width) {
|
|
26025
|
+
const visible = values.map((value, index) => value > 0 ? index : -1).filter((index) => index >= 0);
|
|
26026
|
+
if (visible.length === 0 || visible.length >= width) return allocateProportionally(values, width);
|
|
26027
|
+
const minimum = values.map(() => 0);
|
|
26028
|
+
for (const index of visible) minimum[index] = 1;
|
|
26029
|
+
const remaining = allocateProportionally(values, width - visible.length);
|
|
26030
|
+
return minimum.map((min, index) => min + (remaining[index] ?? 0));
|
|
26031
|
+
}
|
|
25968
26032
|
/**
|
|
25969
|
-
* Render
|
|
25970
|
-
*
|
|
25971
|
-
*
|
|
25972
|
-
*
|
|
25973
|
-
*
|
|
25974
|
-
*
|
|
25975
|
-
*
|
|
26033
|
+
* Render context occupancy as a segmented bar: one DeepSeek-blue run per
|
|
26034
|
+
* content type (system/prompt/assistant/thinking/tools), column widths
|
|
26035
|
+
* proportional to their estimated token share, each with a centered label
|
|
26036
|
+
* that shortens to fit (system→sys→s). The remaining free tail is a dim
|
|
26037
|
+
* track whose right edge carries the usage readout (`12.3K/1.0M 25%`,
|
|
26038
|
+
* shrinking to the bare percent as the tail narrows). The readout flips to
|
|
26039
|
+
* amber once occupancy reaches the warning threshold; the segment blues stay
|
|
26040
|
+
* untouched so the composition remains readable at full context. The used
|
|
26041
|
+
* total comes from the reported `lastPromptTokens`, never from the estimates.
|
|
26042
|
+
* @param segments - estimated used tokens per content type.
|
|
26043
|
+
* @param usedTokens - reported used tokens (drives the readout and percent).
|
|
26044
|
+
* @param contextWindow - route capacity.
|
|
26045
|
+
* @param width - total bar interior columns.
|
|
25976
26046
|
* @returns tone-split spans for the footer to paint.
|
|
25977
26047
|
*/
|
|
25978
|
-
function contextBar(
|
|
25979
|
-
|
|
25980
|
-
const
|
|
25981
|
-
const
|
|
25982
|
-
const
|
|
25983
|
-
const
|
|
25984
|
-
|
|
25985
|
-
|
|
25986
|
-
}
|
|
25987
|
-
|
|
25988
|
-
|
|
25989
|
-
|
|
25990
|
-
|
|
25991
|
-
|
|
25992
|
-
|
|
26048
|
+
function contextBar(segments, usedTokens, contextWindow, width) {
|
|
26049
|
+
if (width <= 0 || contextWindow <= 0) return [];
|
|
26050
|
+
const used = Math.max(0, usedTokens);
|
|
26051
|
+
const percent = Math.round(used / contextWindow * 100);
|
|
26052
|
+
const readoutTone = percent >= 90 ? "warn" : "value";
|
|
26053
|
+
const freeShare = Math.round(Math.max(0, contextWindow - used) / contextWindow * width);
|
|
26054
|
+
const freeColumns = Math.min(width, Math.max(freeShare, CONTEXT_MIN_FREE));
|
|
26055
|
+
const usedColumns = Math.max(0, width - freeColumns);
|
|
26056
|
+
const total = `${formatTokens(used)}/${formatTokens(contextWindow)}`;
|
|
26057
|
+
const percentText = `${percent}%`;
|
|
26058
|
+
const readout = freeColumns >= visibleColumns(`${total} ${percentText}`) ? `${total} ${percentText}` : freeColumns >= visibleColumns(percentText) ? percentText : "";
|
|
26059
|
+
const values = CONTEXT_SEGMENTS.map((segment) => segments[segment.key]);
|
|
26060
|
+
const allocation = allocateBarColumns(values.reduce((sum, value) => sum + value, 0) > 0 ? values : [
|
|
26061
|
+
0,
|
|
26062
|
+
used,
|
|
26063
|
+
0,
|
|
26064
|
+
0,
|
|
26065
|
+
0
|
|
26066
|
+
], usedColumns);
|
|
26067
|
+
const spans = [];
|
|
26068
|
+
for (let index = 0; index < CONTEXT_SEGMENTS.length; index += 1) {
|
|
26069
|
+
const columns = allocation[index] ?? 0;
|
|
26070
|
+
if (columns <= 0) continue;
|
|
26071
|
+
spans.push({
|
|
26072
|
+
text: centerInSegment(chooseContextLabel(CONTEXT_SEGMENTS[index].labels, columns), columns),
|
|
26073
|
+
tone: CONTEXT_SEGMENTS[index].tone
|
|
26074
|
+
});
|
|
26075
|
+
}
|
|
26076
|
+
const pad = freeColumns - visibleColumns(readout);
|
|
26077
|
+
if (pad > 0) spans.push({
|
|
26078
|
+
text: "▱".repeat(pad),
|
|
25993
26079
|
tone: "label"
|
|
25994
26080
|
});
|
|
25995
|
-
spans.push({
|
|
25996
|
-
text:
|
|
25997
|
-
tone:
|
|
25998
|
-
}, {
|
|
25999
|
-
text: percentText,
|
|
26000
|
-
tone
|
|
26081
|
+
if (readout !== "") spans.push({
|
|
26082
|
+
text: readout,
|
|
26083
|
+
tone: readoutTone
|
|
26001
26084
|
});
|
|
26002
26085
|
return spans;
|
|
26003
26086
|
}
|
|
@@ -26181,10 +26264,13 @@ function buildCandidates(facts, stats, busy, enabled) {
|
|
|
26181
26264
|
identity.push(span);
|
|
26182
26265
|
};
|
|
26183
26266
|
const model = safe(facts.model);
|
|
26184
|
-
if (model !== "" && enabled.has("model"))
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
|
|
26267
|
+
if (model !== "" && enabled.has("model")) {
|
|
26268
|
+
const effort = safe(stats.reasoningEffort);
|
|
26269
|
+
push({
|
|
26270
|
+
text: effort === "" ? model : `${model}@${effort}`,
|
|
26271
|
+
tone: "model"
|
|
26272
|
+
});
|
|
26273
|
+
}
|
|
26188
26274
|
const cwd = safe(facts.cwd);
|
|
26189
26275
|
if (cwd !== "" && enabled.has("cwd")) push({
|
|
26190
26276
|
text: cwd,
|
|
@@ -26287,7 +26373,7 @@ function buildCandidates(facts, stats, busy, enabled) {
|
|
|
26287
26373
|
group: { spans: [{
|
|
26288
26374
|
text: "context ",
|
|
26289
26375
|
tone: "label"
|
|
26290
|
-
}, ...contextBar(stats.lastPromptTokens
|
|
26376
|
+
}, ...contextBar(stats.contextSegments, stats.lastPromptTokens, stats.contextWindow, 24)] },
|
|
26291
26377
|
rank: RANK2_CONTEXT,
|
|
26292
26378
|
id: "context"
|
|
26293
26379
|
});
|
|
@@ -26591,9 +26677,6 @@ function transcriptEntryLines(entry, columns) {
|
|
|
26591
26677
|
//#endregion
|
|
26592
26678
|
//#region src/kernel-panels.ts
|
|
26593
26679
|
/** Bounded, composer-safe panels for preset, session, and plugin kernel views. */
|
|
26594
|
-
function color(rgb) {
|
|
26595
|
-
return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
|
|
26596
|
-
}
|
|
26597
26680
|
function ListFrame(props) {
|
|
26598
26681
|
const stdout = useStdout().stdout;
|
|
26599
26682
|
const viewport = panelViewport(stdout?.columns ?? 80, stdout?.rows ?? 30);
|
|
@@ -26615,11 +26698,11 @@ function ListFrame(props) {
|
|
|
26615
26698
|
return (0, import_react.createElement)(Box, {
|
|
26616
26699
|
width: viewport.outerColumns,
|
|
26617
26700
|
borderStyle: "round",
|
|
26618
|
-
borderColor:
|
|
26701
|
+
borderColor: inkColor(getPalette().dim),
|
|
26619
26702
|
flexDirection: "column",
|
|
26620
26703
|
paddingX: 1
|
|
26621
26704
|
}, (0, import_react.createElement)(Text, {
|
|
26622
|
-
color:
|
|
26705
|
+
color: inkColor(getPalette().brandBright),
|
|
26623
26706
|
wrap: "truncate-end"
|
|
26624
26707
|
}, truncateColumns(props.title, viewport.contentColumns)), (0, import_react.createElement)(Text, {
|
|
26625
26708
|
dimColor: true,
|
|
@@ -26629,7 +26712,7 @@ function ListFrame(props) {
|
|
|
26629
26712
|
const selected = !props.loading && props.error === void 0 && props.rows.length > 0 && absolute === props.cursor;
|
|
26630
26713
|
return (0, import_react.createElement)(Text, {
|
|
26631
26714
|
key: row.key,
|
|
26632
|
-
color: selected ?
|
|
26715
|
+
color: selected ? inkColor(getPalette().brandBright) : row.disabled ? inkColor(getPalette().dim) : void 0,
|
|
26633
26716
|
dimColor: row.disabled,
|
|
26634
26717
|
wrap: "truncate-end"
|
|
26635
26718
|
}, truncateColumns(`${selected ? "› " : " "}${row.text}`, viewport.contentColumns));
|
|
@@ -26861,11 +26944,11 @@ function DocumentPanel({ title, text, error, close }) {
|
|
|
26861
26944
|
return (0, import_react.createElement)(Box, {
|
|
26862
26945
|
width: viewport.outerColumns,
|
|
26863
26946
|
borderStyle: "round",
|
|
26864
|
-
borderColor:
|
|
26947
|
+
borderColor: inkColor(getPalette().dim),
|
|
26865
26948
|
flexDirection: "column",
|
|
26866
26949
|
paddingX: 1
|
|
26867
26950
|
}, (0, import_react.createElement)(Text, {
|
|
26868
|
-
color:
|
|
26951
|
+
color: inkColor(getPalette().brandBright),
|
|
26869
26952
|
wrap: "truncate-end"
|
|
26870
26953
|
}, truncateColumns(title, viewport.contentColumns)), ...body.map((line, index) => (0, import_react.createElement)(Text, {
|
|
26871
26954
|
key: `${scroll}-${index}`,
|
|
@@ -26917,11 +27000,11 @@ function HistoryPanel({ entries, fill, close }) {
|
|
|
26917
27000
|
return (0, import_react.createElement)(Box, {
|
|
26918
27001
|
width: viewport.outerColumns,
|
|
26919
27002
|
borderStyle: "round",
|
|
26920
|
-
borderColor:
|
|
27003
|
+
borderColor: inkColor(getPalette().dim),
|
|
26921
27004
|
flexDirection: "column",
|
|
26922
27005
|
paddingX: 1
|
|
26923
27006
|
}, (0, import_react.createElement)(Text, {
|
|
26924
|
-
color:
|
|
27007
|
+
color: inkColor(getPalette().brandBright),
|
|
26925
27008
|
wrap: "truncate-end"
|
|
26926
27009
|
}, truncateColumns(header, viewport.contentColumns)), (0, import_react.createElement)(Text, {
|
|
26927
27010
|
dimColor: true,
|
|
@@ -26935,7 +27018,7 @@ function HistoryPanel({ entries, fill, close }) {
|
|
|
26935
27018
|
const selected = absolute === cursor;
|
|
26936
27019
|
return (0, import_react.createElement)(Text, {
|
|
26937
27020
|
key: `history-${absolute}`,
|
|
26938
|
-
color: selected ?
|
|
27021
|
+
color: selected ? inkColor(getPalette().brandBright) : void 0,
|
|
26939
27022
|
wrap: "truncate-end"
|
|
26940
27023
|
}, truncateColumns((selected ? "› " : " ") + displayText(entry), viewport.contentColumns));
|
|
26941
27024
|
}), (0, import_react.createElement)(Text, {
|
|
@@ -27003,18 +27086,18 @@ function StatuslinePanel({ enabled, change, close }) {
|
|
|
27003
27086
|
return (0, import_react.createElement)(Box, {
|
|
27004
27087
|
width: viewport.outerColumns,
|
|
27005
27088
|
borderStyle: "round",
|
|
27006
|
-
borderColor:
|
|
27089
|
+
borderColor: inkColor(getPalette().dim),
|
|
27007
27090
|
flexDirection: "column",
|
|
27008
27091
|
paddingX: 1
|
|
27009
27092
|
}, (0, import_react.createElement)(Text, {
|
|
27010
|
-
color:
|
|
27093
|
+
color: inkColor(getPalette().brandBright),
|
|
27011
27094
|
wrap: "truncate-end"
|
|
27012
27095
|
}, truncateColumns("/statusline · items apply to the live status line below", viewport.contentColumns)), ...visible.map((id, index) => {
|
|
27013
27096
|
const selected = offset + index === cursor;
|
|
27014
27097
|
const info = meta.get(id);
|
|
27015
27098
|
return (0, import_react.createElement)(Text, {
|
|
27016
27099
|
key: id,
|
|
27017
|
-
color: selected ?
|
|
27100
|
+
color: selected ? inkColor(getPalette().brandBright) : void 0,
|
|
27018
27101
|
dimColor: !on.has(id) || void 0,
|
|
27019
27102
|
wrap: "truncate-end"
|
|
27020
27103
|
}, truncateColumns((selected ? "› " : " ") + (on.has(id) ? "● " : "○ ") + (info?.label ?? id) + (info === void 0 ? "" : " · " + info.description + " · " + info.side), viewport.contentColumns));
|
|
@@ -27023,6 +27106,56 @@ function StatuslinePanel({ enabled, change, close }) {
|
|
|
27023
27106
|
wrap: "truncate-end"
|
|
27024
27107
|
}, truncateColumns("↑↓ move · space toggle · ←→ reorder · d default · esc close", viewport.contentColumns)));
|
|
27025
27108
|
}
|
|
27109
|
+
/**
|
|
27110
|
+
* The `/model` reasoning-effort stage (the Codex model → reasoning popup
|
|
27111
|
+
* contract): one bounded list over the selected model's adapter-advertised
|
|
27112
|
+
* effort levels, with the effective effort and the model default marked.
|
|
27113
|
+
* A model WITHOUT an adapter-declared default leads with a "Default"
|
|
27114
|
+
* (provider-default) row — the web effort pane's first entry — so the user
|
|
27115
|
+
* can clear a picked level back to provider behavior instead of being forced
|
|
27116
|
+
* to choose an advertised one. Enter applies one level; Esc returns to the
|
|
27117
|
+
* model list without applying.
|
|
27118
|
+
*/
|
|
27119
|
+
function EffortPanel({ row, current, select, back }) {
|
|
27120
|
+
const [cursor, setCursor] = (0, import_react.useState)(0);
|
|
27121
|
+
const efforts = row.reasoning?.efforts ?? [];
|
|
27122
|
+
const rows = row.reasoning !== void 0 && row.reasoning.defaultEffort === void 0 ? [{
|
|
27123
|
+
id: "",
|
|
27124
|
+
name: "Default"
|
|
27125
|
+
}, ...efforts] : efforts;
|
|
27126
|
+
const effective = current === void 0 || current === "" ? "" : current;
|
|
27127
|
+
(0, import_react.useEffect)(() => {
|
|
27128
|
+
if (rows.length === 0) {
|
|
27129
|
+
if (cursor !== 0) setCursor(0);
|
|
27130
|
+
return;
|
|
27131
|
+
}
|
|
27132
|
+
if (cursor >= rows.length) setCursor(rows.length - 1);
|
|
27133
|
+
}, [rows.length, cursor]);
|
|
27134
|
+
useInput((input, key) => {
|
|
27135
|
+
if (key.escape || input === "q") return back();
|
|
27136
|
+
if (rows.length === 0) return;
|
|
27137
|
+
if (key.upArrow) {
|
|
27138
|
+
setCursor(cursor > 0 ? cursor - 1 : rows.length - 1);
|
|
27139
|
+
return;
|
|
27140
|
+
}
|
|
27141
|
+
if (key.downArrow) {
|
|
27142
|
+
setCursor(cursor < rows.length - 1 ? cursor + 1 : 0);
|
|
27143
|
+
return;
|
|
27144
|
+
}
|
|
27145
|
+
if (key.return && rows[cursor] !== void 0) select(rows[cursor].id);
|
|
27146
|
+
});
|
|
27147
|
+
return (0, import_react.createElement)(ListFrame, {
|
|
27148
|
+
title: `/model — effort for ${row.providerName} · ${row.modelName}`,
|
|
27149
|
+
rows: rows.map((effort) => ({
|
|
27150
|
+
key: effort.id,
|
|
27151
|
+
text: `${effort.id === effective ? "●" : "○"} ${effort.name}${effort.id === row.reasoning?.defaultEffort ? " · default" : ""}${effort.description === void 0 ? "" : ` · ${effort.description}`}`
|
|
27152
|
+
})),
|
|
27153
|
+
cursor,
|
|
27154
|
+
loading: false,
|
|
27155
|
+
query: "",
|
|
27156
|
+
footer: "↑↓ choose · enter apply · esc/q back"
|
|
27157
|
+
});
|
|
27158
|
+
}
|
|
27026
27159
|
/** Encode one entry for the history file (JSON keeps multi-line drafts intact). */
|
|
27027
27160
|
function serializeHistoryEntry(text) {
|
|
27028
27161
|
return JSON.stringify(text);
|
|
@@ -27172,10 +27305,6 @@ function recallNewer(state) {
|
|
|
27172
27305
|
const RESIZE_REFLOW_DELAY_MS = 75;
|
|
27173
27306
|
/** Reset region/style, clear the visible screen and scrollback, then home. */
|
|
27174
27307
|
const RESIZE_REFLOW_CLEAR = "\x1B[r\x1B[0m\x1B[H\x1B[2J\x1B[3J\x1B[H";
|
|
27175
|
-
/** Ink `color` string for one palette triple. */
|
|
27176
|
-
function inkColor(triple) {
|
|
27177
|
-
return `rgb(${triple[0]}, ${triple[1]}, ${triple[2]})`;
|
|
27178
|
-
}
|
|
27179
27308
|
/** Pad text with spaces to a visible-column target (menu name column). */
|
|
27180
27309
|
function padColumns(text, width) {
|
|
27181
27310
|
const clipped = truncateColumns(singleLineText(text), width);
|
|
@@ -27209,7 +27338,7 @@ function useStableInput(handler, active) {
|
|
|
27209
27338
|
/** Single-cell stepped pulse: the web's 125ms flat-hold brightness steps over 1s. */
|
|
27210
27339
|
function Pulse() {
|
|
27211
27340
|
const tick = useFrames(125);
|
|
27212
|
-
return (0, import_react.createElement)(Text, { color: inkColor(
|
|
27341
|
+
return (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, pulseFrame(tick));
|
|
27213
27342
|
}
|
|
27214
27343
|
/**
|
|
27215
27344
|
* The web StateDot "ongoing" chase in terminal form: three cells of the 3×3
|
|
@@ -27219,7 +27348,7 @@ function Pulse() {
|
|
|
27219
27348
|
*/
|
|
27220
27349
|
function BusyChase() {
|
|
27221
27350
|
const tick = useFrames(125);
|
|
27222
|
-
return (0, import_react.createElement)(Text, { color: inkColor(
|
|
27351
|
+
return (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, busyChaseFrame(tick) + " ");
|
|
27223
27352
|
}
|
|
27224
27353
|
/** Blinking block caret appended to streaming text. */
|
|
27225
27354
|
function Caret() {
|
|
@@ -27269,19 +27398,19 @@ function StreamTail({ text, dim, maxRows, prefix, children }) {
|
|
|
27269
27398
|
function segmentProps(style) {
|
|
27270
27399
|
switch (style) {
|
|
27271
27400
|
case "accent": return {
|
|
27272
|
-
color: inkColor(
|
|
27401
|
+
color: inkColor(getPalette().brandBright),
|
|
27273
27402
|
bold: void 0,
|
|
27274
27403
|
italic: void 0,
|
|
27275
27404
|
strikethrough: void 0
|
|
27276
27405
|
};
|
|
27277
27406
|
case "code": return {
|
|
27278
|
-
color: inkColor(
|
|
27407
|
+
color: inkColor(getPalette().code),
|
|
27279
27408
|
bold: void 0,
|
|
27280
27409
|
italic: void 0,
|
|
27281
27410
|
strikethrough: void 0
|
|
27282
27411
|
};
|
|
27283
27412
|
case "dim": return {
|
|
27284
|
-
color: inkColor(
|
|
27413
|
+
color: inkColor(getPalette().dim),
|
|
27285
27414
|
bold: void 0,
|
|
27286
27415
|
italic: void 0,
|
|
27287
27416
|
strikethrough: void 0
|
|
@@ -27305,7 +27434,7 @@ function segmentProps(style) {
|
|
|
27305
27434
|
strikethrough: void 0
|
|
27306
27435
|
};
|
|
27307
27436
|
case "strike": return {
|
|
27308
|
-
color: inkColor(
|
|
27437
|
+
color: inkColor(getPalette().dim),
|
|
27309
27438
|
bold: void 0,
|
|
27310
27439
|
italic: void 0,
|
|
27311
27440
|
strikethrough: true
|
|
@@ -27322,28 +27451,28 @@ function segmentProps(style) {
|
|
|
27322
27451
|
function lineStyleProps(style) {
|
|
27323
27452
|
switch (style) {
|
|
27324
27453
|
case "brand": return {
|
|
27325
|
-
color: inkColor(
|
|
27454
|
+
color: inkColor(getPalette().brandBright),
|
|
27326
27455
|
bold: void 0,
|
|
27327
27456
|
italic: void 0,
|
|
27328
27457
|
strikethrough: void 0,
|
|
27329
27458
|
dimColor: void 0
|
|
27330
27459
|
};
|
|
27331
27460
|
case "success": return {
|
|
27332
|
-
color: inkColor(
|
|
27461
|
+
color: inkColor(getPalette().success),
|
|
27333
27462
|
bold: void 0,
|
|
27334
27463
|
italic: void 0,
|
|
27335
27464
|
strikethrough: void 0,
|
|
27336
27465
|
dimColor: void 0
|
|
27337
27466
|
};
|
|
27338
27467
|
case "error": return {
|
|
27339
|
-
color: inkColor(
|
|
27468
|
+
color: inkColor(getPalette().error),
|
|
27340
27469
|
bold: void 0,
|
|
27341
27470
|
italic: void 0,
|
|
27342
27471
|
strikethrough: void 0,
|
|
27343
27472
|
dimColor: void 0
|
|
27344
27473
|
};
|
|
27345
27474
|
case "warn": return {
|
|
27346
|
-
color: inkColor(
|
|
27475
|
+
color: inkColor(getPalette().warn),
|
|
27347
27476
|
bold: void 0,
|
|
27348
27477
|
italic: void 0,
|
|
27349
27478
|
strikethrough: void 0,
|
|
@@ -27408,7 +27537,7 @@ function ToolDetailBody({ detail }) {
|
|
|
27408
27537
|
wrap: "truncate-end"
|
|
27409
27538
|
}, ` ── ${displayText(diff.path)}${diff.truncated ? " (diff truncated)" : ""}`), ...diff.lines.map((line, at) => (0, import_react.createElement)(Text, {
|
|
27410
27539
|
key: at,
|
|
27411
|
-
color: line.mark === "+" ? inkColor(
|
|
27540
|
+
color: line.mark === "+" ? inkColor(getPalette().success) : line.mark === "-" ? inkColor(getPalette().error) : inkColor(getPalette().dim),
|
|
27412
27541
|
wrap: "truncate-end"
|
|
27413
27542
|
}, ` ${line.mark}${displayText(line.text)}`)))));
|
|
27414
27543
|
case "read": return (0, import_react.createElement)(Box, { flexDirection: "column" }, (0, import_react.createElement)(Text, {
|
|
@@ -27447,16 +27576,16 @@ function EntryLine({ entry, showReasoning, verbose }) {
|
|
|
27447
27576
|
indent: 2
|
|
27448
27577
|
}));
|
|
27449
27578
|
case "tool": {
|
|
27450
|
-
const mark = entry.state === "running" ? (0, import_react.createElement)(Pulse) : entry.state === "error" ? (0, import_react.createElement)(Text, { color: inkColor(
|
|
27579
|
+
const mark = entry.state === "running" ? (0, import_react.createElement)(Pulse) : entry.state === "error" ? (0, import_react.createElement)(Text, { color: inkColor(getPalette().error) }, "⨯") : (0, import_react.createElement)(Text, { color: inkColor(getPalette().success) }, "⏺");
|
|
27451
27580
|
return (0, import_react.createElement)(Box, { flexDirection: "column" }, (0, import_react.createElement)(Text, { wrap: verbose ? "truncate-end" : void 0 }, mark, " ", brand(entry.name), entry.preview === "" ? "" : ` ${dim(displayText(entry.preview))}`), entry.summary === "" ? void 0 : (0, import_react.createElement)(Text, {
|
|
27452
|
-
color: entry.state === "error" ? inkColor(
|
|
27581
|
+
color: entry.state === "error" ? inkColor(getPalette().error) : inkColor(getPalette().dim),
|
|
27453
27582
|
wrap: verbose ? "truncate-end" : void 0
|
|
27454
27583
|
}, ` ⎿ ${displayText(entry.summary)}`), verbose && entry.detail !== void 0 ? (0, import_react.createElement)(ToolDetailBody, { detail: entry.detail }) : void 0);
|
|
27455
27584
|
}
|
|
27456
27585
|
case "command": {
|
|
27457
|
-
const mark = entry.state === "running" ? (0, import_react.createElement)(Pulse) : entry.state === "error" ? (0, import_react.createElement)(Text, { color: inkColor(
|
|
27586
|
+
const mark = entry.state === "running" ? (0, import_react.createElement)(Pulse) : entry.state === "error" ? (0, import_react.createElement)(Text, { color: inkColor(getPalette().error) }, "⨯") : (0, import_react.createElement)(Text, { color: inkColor(getPalette().success) }, "⏺");
|
|
27458
27587
|
return (0, import_react.createElement)(Box, { flexDirection: "column" }, (0, import_react.createElement)(Text, { wrap: verbose ? "truncate-end" : void 0 }, mark, " ", brand(`/${entry.name}`), entry.args === "" ? "" : ` ${dim(displayText(entry.args))}`), entry.summary === "" ? void 0 : (0, import_react.createElement)(Text, {
|
|
27459
|
-
color: inkColor(
|
|
27588
|
+
color: inkColor(getPalette().dim),
|
|
27460
27589
|
wrap: verbose ? "truncate-end" : void 0
|
|
27461
27590
|
}, ` ⎿ ${displayText(entry.summary)}`));
|
|
27462
27591
|
}
|
|
@@ -27469,7 +27598,7 @@ function EntryLine({ entry, showReasoning, verbose }) {
|
|
|
27469
27598
|
wrap: verbose ? "truncate-end" : void 0
|
|
27470
27599
|
}, entry.ok ? ` ⧉ compacted ~${formatTokens(entry.tokens)} tokens` : ` ⧉ compaction failed: ${displayText(entry.error)}`);
|
|
27471
27600
|
case "retry": return (0, import_react.createElement)(Text, {
|
|
27472
|
-
color: entry.state === "running" ? inkColor(
|
|
27601
|
+
color: entry.state === "running" ? inkColor(getPalette().warn) : inkColor(getPalette().dim),
|
|
27473
27602
|
wrap: verbose ? "truncate-end" : void 0
|
|
27474
27603
|
}, ` ↻ retry ${entry.attempt}/${entry.max} · ${displayText(entry.code)} · ${Math.round(entry.delayMs / 100) / 10}s`);
|
|
27475
27604
|
case "files": {
|
|
@@ -27499,18 +27628,18 @@ function Header({ resumed }) {
|
|
|
27499
27628
|
flexDirection: "row",
|
|
27500
27629
|
gap: 1,
|
|
27501
27630
|
borderStyle: "round",
|
|
27502
|
-
borderColor: inkColor(
|
|
27631
|
+
borderColor: inkColor(getPalette().brand),
|
|
27503
27632
|
paddingX: 1,
|
|
27504
27633
|
alignSelf: "flex-start"
|
|
27505
27634
|
}, (0, import_react.createElement)(Text, {
|
|
27506
|
-
color: inkColor(
|
|
27635
|
+
color: inkColor(getPalette().brandBright),
|
|
27507
27636
|
bold: true
|
|
27508
27637
|
}, "DeepSeek Harness"), (0, import_react.createElement)(Text, { dimColor: true }, hint));
|
|
27509
27638
|
return (0, import_react.createElement)(Box, {
|
|
27510
27639
|
flexDirection: "row",
|
|
27511
27640
|
gap: 2,
|
|
27512
27641
|
borderStyle: "round",
|
|
27513
|
-
borderColor: inkColor(
|
|
27642
|
+
borderColor: inkColor(getPalette().brand),
|
|
27514
27643
|
paddingX: 1,
|
|
27515
27644
|
alignSelf: "flex-start"
|
|
27516
27645
|
}, (0, import_react.createElement)(Box, {
|
|
@@ -27519,12 +27648,12 @@ function Header({ resumed }) {
|
|
|
27519
27648
|
justifyContent: "center"
|
|
27520
27649
|
}, ...WHALE_GLYPH.map((row, index) => (0, import_react.createElement)(Text, {
|
|
27521
27650
|
key: index,
|
|
27522
|
-
color: inkColor(
|
|
27651
|
+
color: inkColor(getPalette().brand)
|
|
27523
27652
|
}, row))), (0, import_react.createElement)(Box, {
|
|
27524
27653
|
flexDirection: "column",
|
|
27525
27654
|
justifyContent: "center"
|
|
27526
27655
|
}, (0, import_react.createElement)(Text, {
|
|
27527
|
-
color: inkColor(
|
|
27656
|
+
color: inkColor(getPalette().brandBright),
|
|
27528
27657
|
bold: true
|
|
27529
27658
|
}, "DeepSeek Harness"), (0, import_react.createElement)(Text, { dimColor: true }, hint)));
|
|
27530
27659
|
}
|
|
@@ -27540,74 +27669,99 @@ function TodoPanel({ todos }) {
|
|
|
27540
27669
|
const pending = todos.length - completed - inProgress;
|
|
27541
27670
|
const current = todos.find((todo) => todo.status === "in_progress");
|
|
27542
27671
|
return (0, import_react.createElement)(Box, { paddingX: 1 }, (0, import_react.createElement)(Text, {
|
|
27543
|
-
color: inkColor(
|
|
27672
|
+
color: inkColor(getPalette().brand),
|
|
27544
27673
|
bold: true,
|
|
27545
27674
|
wrap: "truncate-end"
|
|
27546
|
-
}, `todos ${completed}/${todos.length}`, (0, import_react.createElement)(Text, { dimColor: true }, ` · ${inProgress} active · ${pending} pending`), current === void 0 ? "" : (0, import_react.createElement)(Text, { color: inkColor(
|
|
27675
|
+
}, `todos ${completed}/${todos.length}`, (0, import_react.createElement)(Text, { dimColor: true }, ` · ${inProgress} active · ${pending} pending`), current === void 0 ? "" : (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, ` · ${todoMark(current.status)} ${displayText(current.content)}`)));
|
|
27547
27676
|
}
|
|
27548
27677
|
/**
|
|
27549
27678
|
* Ink props for one status tone: the Codex status-line accent mapping over
|
|
27550
27679
|
* the DeepSeek palette, all blue by design — the status bar speaks only in
|
|
27551
|
-
* degrees of blue (deep accent, primary figures,
|
|
27680
|
+
* degrees of blue (deep accent, primary figures, model identity, sky
|
|
27552
27681
|
* paths and done states), with amber/red reserved for warnings and errors.
|
|
27553
27682
|
*/
|
|
27554
27683
|
function statusToneProps(tone) {
|
|
27555
27684
|
switch (tone) {
|
|
27556
27685
|
case "model": return {
|
|
27557
|
-
color: inkColor(
|
|
27686
|
+
color: inkColor(getPalette().code),
|
|
27558
27687
|
bold: true,
|
|
27559
27688
|
dimColor: void 0
|
|
27560
27689
|
};
|
|
27561
27690
|
case "live": return {
|
|
27562
|
-
color: inkColor(
|
|
27691
|
+
color: inkColor(getPalette().brandBright),
|
|
27563
27692
|
bold: void 0,
|
|
27564
27693
|
dimColor: void 0
|
|
27565
27694
|
};
|
|
27566
27695
|
case "path": return {
|
|
27567
|
-
color: inkColor(
|
|
27696
|
+
color: inkColor(getPalette().code),
|
|
27568
27697
|
bold: void 0,
|
|
27569
27698
|
dimColor: void 0
|
|
27570
27699
|
};
|
|
27571
27700
|
case "branch": return {
|
|
27572
|
-
color: inkColor(
|
|
27701
|
+
color: inkColor(getPalette().text),
|
|
27573
27702
|
bold: void 0,
|
|
27574
27703
|
dimColor: void 0
|
|
27575
27704
|
};
|
|
27576
27705
|
case "value": return {
|
|
27577
|
-
color: inkColor(
|
|
27706
|
+
color: inkColor(getPalette().brand),
|
|
27578
27707
|
bold: void 0,
|
|
27579
27708
|
dimColor: void 0
|
|
27580
27709
|
};
|
|
27581
27710
|
case "label":
|
|
27582
27711
|
case "meta": return {
|
|
27583
|
-
color:
|
|
27712
|
+
color: inkColor(getPalette().dim),
|
|
27584
27713
|
bold: void 0,
|
|
27585
|
-
dimColor:
|
|
27714
|
+
dimColor: void 0
|
|
27586
27715
|
};
|
|
27587
27716
|
case "accent": return {
|
|
27588
|
-
color: inkColor(
|
|
27717
|
+
color: inkColor(getPalette().brandDeep),
|
|
27718
|
+
bold: void 0,
|
|
27719
|
+
dimColor: void 0
|
|
27720
|
+
};
|
|
27721
|
+
case "ctxSystem": return {
|
|
27722
|
+
color: inkColor(getPalette().brandDeep),
|
|
27723
|
+
bold: void 0,
|
|
27724
|
+
dimColor: void 0
|
|
27725
|
+
};
|
|
27726
|
+
case "ctxPrompt": return {
|
|
27727
|
+
color: inkColor(getPalette().brand),
|
|
27728
|
+
bold: void 0,
|
|
27729
|
+
dimColor: void 0
|
|
27730
|
+
};
|
|
27731
|
+
case "ctxAssistant": return {
|
|
27732
|
+
color: inkColor(getPalette().brandMid),
|
|
27733
|
+
bold: void 0,
|
|
27734
|
+
dimColor: void 0
|
|
27735
|
+
};
|
|
27736
|
+
case "ctxThinking": return {
|
|
27737
|
+
color: inkColor(getPalette().brandBright),
|
|
27738
|
+
bold: void 0,
|
|
27739
|
+
dimColor: void 0
|
|
27740
|
+
};
|
|
27741
|
+
case "ctxTools": return {
|
|
27742
|
+
color: inkColor(getPalette().code),
|
|
27589
27743
|
bold: void 0,
|
|
27590
27744
|
dimColor: void 0
|
|
27591
27745
|
};
|
|
27592
27746
|
case "success": return {
|
|
27593
|
-
color: inkColor(
|
|
27747
|
+
color: inkColor(getPalette().code),
|
|
27594
27748
|
bold: true,
|
|
27595
27749
|
dimColor: void 0
|
|
27596
27750
|
};
|
|
27597
27751
|
case "warn": return {
|
|
27598
|
-
color: inkColor(
|
|
27752
|
+
color: inkColor(getPalette().warn),
|
|
27599
27753
|
bold: true,
|
|
27600
27754
|
dimColor: void 0
|
|
27601
27755
|
};
|
|
27602
27756
|
case "error": return {
|
|
27603
|
-
color: inkColor(
|
|
27757
|
+
color: inkColor(getPalette().error),
|
|
27604
27758
|
bold: true,
|
|
27605
27759
|
dimColor: void 0
|
|
27606
27760
|
};
|
|
27607
27761
|
default: return {
|
|
27608
|
-
color:
|
|
27762
|
+
color: inkColor(getPalette().dim),
|
|
27609
27763
|
bold: void 0,
|
|
27610
|
-
dimColor:
|
|
27764
|
+
dimColor: void 0
|
|
27611
27765
|
};
|
|
27612
27766
|
}
|
|
27613
27767
|
}
|
|
@@ -27620,7 +27774,32 @@ function statusToneProps(tone) {
|
|
|
27620
27774
|
* content, so the footer degrades to a single row on narrow terminals. Both
|
|
27621
27775
|
* layouts arrive pre-measured from the pure reducer, so Ink only paints;
|
|
27622
27776
|
* truncation degrades groups, it never wraps a row.
|
|
27777
|
+
*
|
|
27778
|
+
* The DeepSeek easter egg: when the model label *switches* to an official
|
|
27779
|
+
* DeepSeek route, the composer's INPUT ROW (not the frame) plays Codex's
|
|
27780
|
+
* effort-ignition "Wave" — a blue crest sweeping the content row column by
|
|
27781
|
+
* column, with the `· ✦ ✧` sparkles on the deepseek tier — and the prompt
|
|
27782
|
+
* marker keeps the tier accent afterwards. The border stays a constant
|
|
27783
|
+
* static dim; only the row's per-column background tints during the wave,
|
|
27784
|
+
* so the row and column budget is untouched throughout.
|
|
27623
27785
|
*/
|
|
27786
|
+
/** Theme anchors for the one-shot composer wave, read from the active palette
|
|
27787
|
+
* so the wave stays coordinated in both themes. The flash tier runs the
|
|
27788
|
+
* brand blues; the deepseek tier swaps in the code sky-blue for a brighter,
|
|
27789
|
+
* richer mix. Codex's Wave bands carry no hue index (only hues[0] tints the
|
|
27790
|
+
* row), so the accent the prompt keeps is always hues[0]. */
|
|
27791
|
+
function deepseekWaveHues(tier) {
|
|
27792
|
+
const palette = getPalette();
|
|
27793
|
+
return tier === "flash" ? [
|
|
27794
|
+
palette.brandBright,
|
|
27795
|
+
palette.brand,
|
|
27796
|
+
palette.brandMid
|
|
27797
|
+
] : [
|
|
27798
|
+
palette.brandBright,
|
|
27799
|
+
palette.code,
|
|
27800
|
+
palette.brandMid
|
|
27801
|
+
];
|
|
27802
|
+
}
|
|
27624
27803
|
function StatusLine({ facts, stats, busy, columns, items }) {
|
|
27625
27804
|
const layout = layoutStatusBar(facts, stats, Math.max(8, columns - 2), {
|
|
27626
27805
|
busy,
|
|
@@ -27631,7 +27810,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27631
27810
|
row.left.forEach((group, groupIndex) => {
|
|
27632
27811
|
if (groupIndex > 0) leftParts.push((0, import_react.createElement)(Text, {
|
|
27633
27812
|
key: key + "gs" + groupIndex,
|
|
27634
|
-
|
|
27813
|
+
color: inkColor(getPalette().dim)
|
|
27635
27814
|
}, " | "));
|
|
27636
27815
|
group.spans.forEach((span, spanIndex) => {
|
|
27637
27816
|
leftParts.push((0, import_react.createElement)(Text, {
|
|
@@ -27645,7 +27824,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27645
27824
|
row.right.forEach((span, index) => {
|
|
27646
27825
|
if (index > 0) rightParts.push((0, import_react.createElement)(Text, {
|
|
27647
27826
|
key: key + "rs" + index,
|
|
27648
|
-
|
|
27827
|
+
color: inkColor(getPalette().dim)
|
|
27649
27828
|
}, STATUS_ITEM_SEPARATOR));
|
|
27650
27829
|
rightParts.push((0, import_react.createElement)(Text, {
|
|
27651
27830
|
key: key + "r" + index,
|
|
@@ -27655,7 +27834,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27655
27834
|
});
|
|
27656
27835
|
if (row.hint) rightParts.push((0, import_react.createElement)(Text, {
|
|
27657
27836
|
key: key + "hint",
|
|
27658
|
-
|
|
27837
|
+
color: inkColor(getPalette().dim)
|
|
27659
27838
|
}, STATUS_CYCLE_HINT));
|
|
27660
27839
|
return (0, import_react.createElement)(Box, {
|
|
27661
27840
|
paddingLeft: 2,
|
|
@@ -27671,7 +27850,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27671
27850
|
* above the composer.
|
|
27672
27851
|
*/
|
|
27673
27852
|
function NoticeLine({ text, tone, columns }) {
|
|
27674
|
-
const color = tone === "error" ?
|
|
27853
|
+
const color = tone === "error" ? getPalette().error : tone === "warning" ? getPalette().warn : getPalette().brandBright;
|
|
27675
27854
|
const mark = tone === "error" ? "⨯" : tone === "warning" ? "!" : "•";
|
|
27676
27855
|
return (0, import_react.createElement)(Box, { paddingLeft: 2 }, (0, import_react.createElement)(Text, {
|
|
27677
27856
|
color: inkColor(color),
|
|
@@ -27727,9 +27906,9 @@ function ApprovalBar({ snapshot, locked }) {
|
|
|
27727
27906
|
width: viewport.outerColumns,
|
|
27728
27907
|
paddingX: 1,
|
|
27729
27908
|
borderStyle: "round",
|
|
27730
|
-
borderColor: inkColor(
|
|
27909
|
+
borderColor: inkColor(getPalette().warn)
|
|
27731
27910
|
}, (0, import_react.createElement)(Text, {
|
|
27732
|
-
color: inkColor(
|
|
27911
|
+
color: inkColor(getPalette().warn),
|
|
27733
27912
|
bold: true,
|
|
27734
27913
|
wrap: "truncate-end"
|
|
27735
27914
|
}, truncateColumns(`⏸ waiting for approval · lines ${content.length === 0 ? 0 : visibleScroll + 1}-${Math.min(content.length, visibleScroll + viewport.bodyRows)}/${content.length}`, viewport.contentColumns)), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(StyledRows, { lines: content.slice(visibleScroll, visibleScroll + viewport.bodyRows) }), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(Text, {
|
|
@@ -27970,9 +28149,9 @@ function QuestionBar({ store, snapshot, locked }) {
|
|
|
27970
28149
|
width: viewport.outerColumns,
|
|
27971
28150
|
paddingX: 1,
|
|
27972
28151
|
borderStyle: "round",
|
|
27973
|
-
borderColor: inkColor(isPlan ?
|
|
28152
|
+
borderColor: inkColor(isPlan ? getPalette().brand : getPalette().brandDeep)
|
|
27974
28153
|
}, (0, import_react.createElement)(Text, {
|
|
27975
|
-
color: inkColor(isPlan ?
|
|
28154
|
+
color: inkColor(isPlan ? getPalette().brand : getPalette().brandDeep),
|
|
27976
28155
|
bold: true,
|
|
27977
28156
|
wrap: "truncate-end"
|
|
27978
28157
|
}, truncateColumns(`${isPlan ? "📋 plan review" : "❓ question"} ${index + 1}/${pending.request.questions.length} · lines ${rendered.lines.length === 0 ? 0 : visibleScroll + 1}-${Math.min(rendered.lines.length, visibleScroll + viewport.bodyRows)}/${rendered.lines.length}`, viewport.contentColumns)), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(StyledRows, { lines: rendered.lines.slice(visibleScroll, visibleScroll + viewport.bodyRows) }), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(Text, {
|
|
@@ -28037,11 +28216,11 @@ function ModelPanel({ directory, error, onSelect, onRetry, onClose }) {
|
|
|
28037
28216
|
wrap: "truncate-end"
|
|
28038
28217
|
}, " loading models…")] : error !== void 0 ? [(0, import_react.createElement)(Text, {
|
|
28039
28218
|
key: "error",
|
|
28040
|
-
color: inkColor(
|
|
28219
|
+
color: inkColor(getPalette().error),
|
|
28041
28220
|
wrap: "truncate-end"
|
|
28042
28221
|
}, truncateColumns(` ${singleLineText(error)}`, viewport.contentColumns))] : [...directory?.failures.length === 0 ? [] : [(0, import_react.createElement)(Text, {
|
|
28043
28222
|
key: "failures",
|
|
28044
|
-
color: inkColor(
|
|
28223
|
+
color: inkColor(getPalette().warn),
|
|
28045
28224
|
wrap: "truncate-end"
|
|
28046
28225
|
}, truncateColumns(` unavailable providers: ${directory?.failures.join(", ")}`, viewport.contentColumns))], ...rows.length === 0 ? [(0, import_react.createElement)(Text, {
|
|
28047
28226
|
key: "empty",
|
|
@@ -28056,9 +28235,9 @@ function ModelPanel({ directory, error, onSelect, onRetry, onClose }) {
|
|
|
28056
28235
|
width: viewport.outerColumns,
|
|
28057
28236
|
paddingX: 1,
|
|
28058
28237
|
borderStyle: "round",
|
|
28059
|
-
borderColor: inkColor(
|
|
28238
|
+
borderColor: inkColor(getPalette().brand)
|
|
28060
28239
|
}, (0, import_react.createElement)(Text, {
|
|
28061
|
-
color: inkColor(
|
|
28240
|
+
color: inkColor(getPalette().brand),
|
|
28062
28241
|
bold: true,
|
|
28063
28242
|
wrap: "truncate-end"
|
|
28064
28243
|
}, truncateColumns(`/model — select model${rows.length === 0 ? "" : ` · ${cursor + 1}/${rows.length}`}`, viewport.contentColumns)), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), ...stateRows, ...visible.map((row) => {
|
|
@@ -28066,7 +28245,7 @@ function ModelPanel({ directory, error, onSelect, onRetry, onClose }) {
|
|
|
28066
28245
|
const label = displayText(`${row.providerName} · ${row.modelName}`);
|
|
28067
28246
|
return (0, import_react.createElement)(Text, {
|
|
28068
28247
|
key: `${row.provider}/${row.model}`,
|
|
28069
|
-
color: index === cursor ? inkColor(
|
|
28248
|
+
color: index === cursor ? inkColor(getPalette().brandBright) : inkColor(getPalette().dim),
|
|
28070
28249
|
wrap: "truncate-end"
|
|
28071
28250
|
}, truncateColumns(`${index === cursor ? "❯ " : " "}${label}`, viewport.contentColumns));
|
|
28072
28251
|
}), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(Text, {
|
|
@@ -28133,16 +28312,18 @@ function HelpPanel({ descriptors, skills, commandError, skillError, onClose }) {
|
|
|
28133
28312
|
}, " commands"),
|
|
28134
28313
|
...commandError === void 0 ? [] : [(0, import_react.createElement)(Text, {
|
|
28135
28314
|
key: "commands-error",
|
|
28136
|
-
color: inkColor(
|
|
28315
|
+
color: inkColor(getPalette().error),
|
|
28137
28316
|
wrap: "truncate-end"
|
|
28138
28317
|
}, truncateColumns(` command catalog unavailable: ${singleLineText(commandError)}`, viewport.contentColumns))],
|
|
28139
28318
|
(0, import_react.createElement)(Box, { key: "local-help" }, row("/help", "show this overlay")),
|
|
28140
28319
|
(0, import_react.createElement)(Box, { key: "local-model" }, row("/model", "switch the model")),
|
|
28320
|
+
(0, import_react.createElement)(Box, { key: "local-effort" }, row("/effort", "adjust reasoning effort for the current model")),
|
|
28141
28321
|
(0, import_react.createElement)(Box, { key: "local-mode" }, row("/mode", "inspect or select the agent preset (/mode [preset])")),
|
|
28142
28322
|
(0, import_react.createElement)(Box, { key: "local-new" }, row("/new", "create and switch to a fresh session (/new [preset])")),
|
|
28143
28323
|
(0, import_react.createElement)(Box, { key: "local-resume" }, row("/resume", "browse or switch root sessions (/resume [id|prefix])")),
|
|
28144
28324
|
(0, import_react.createElement)(Box, { key: "local-plugin" }, row("/plugin", "inspect the live plugin composition")),
|
|
28145
28325
|
(0, import_react.createElement)(Box, { key: "local-statusline" }, row("/statusline", "customize the status line items")),
|
|
28326
|
+
(0, import_react.createElement)(Box, { key: "local-theme" }, row("/theme", "switch the color theme")),
|
|
28146
28327
|
(0, import_react.createElement)(Box, { key: "local-history" }, row("/history", "search and recall past prompts")),
|
|
28147
28328
|
(0, import_react.createElement)(Box, { key: "local-clear" }, row("/clear", "clear the screen")),
|
|
28148
28329
|
(0, import_react.createElement)(Box, { key: "local-export" }, row("/export", "export the transcript to markdown (/export [path])")),
|
|
@@ -28160,7 +28341,7 @@ function HelpPanel({ descriptors, skills, commandError, skillError, onClose }) {
|
|
|
28160
28341
|
}, " skills")],
|
|
28161
28342
|
...skillError === void 0 ? [] : [(0, import_react.createElement)(Text, {
|
|
28162
28343
|
key: "skills-error",
|
|
28163
|
-
color: inkColor(
|
|
28344
|
+
color: inkColor(getPalette().error),
|
|
28164
28345
|
wrap: "truncate-end"
|
|
28165
28346
|
}, truncateColumns(` skill catalog unavailable: ${singleLineText(skillError)}`, viewport.contentColumns))],
|
|
28166
28347
|
...skills.map((skill) => (0, import_react.createElement)(Text, {
|
|
@@ -28195,9 +28376,9 @@ function HelpPanel({ descriptors, skills, commandError, skillError, onClose }) {
|
|
|
28195
28376
|
width: viewport.outerColumns,
|
|
28196
28377
|
paddingX: 1,
|
|
28197
28378
|
borderStyle: "round",
|
|
28198
|
-
borderColor: inkColor(
|
|
28379
|
+
borderColor: inkColor(getPalette().brand)
|
|
28199
28380
|
}, (0, import_react.createElement)(Text, {
|
|
28200
|
-
color: inkColor(
|
|
28381
|
+
color: inkColor(getPalette().brand),
|
|
28201
28382
|
bold: true,
|
|
28202
28383
|
wrap: "truncate-end"
|
|
28203
28384
|
}, truncateColumns(`/help — keys and commands · rows ${content.length === 0 ? 0 : visibleScroll + 1}-${Math.min(content.length, visibleScroll + viewport.bodyRows)}/${content.length}`, viewport.contentColumns)), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), ...content.slice(visibleScroll, visibleScroll + viewport.bodyRows), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(Text, {
|
|
@@ -28224,6 +28405,38 @@ function editorWindow(value, cursor, columns) {
|
|
|
28224
28405
|
after: afterBudget === 0 ? "" : truncateColumns(normalize(value.slice(cursor + 1)), afterBudget)
|
|
28225
28406
|
};
|
|
28226
28407
|
}
|
|
28408
|
+
/** The empty-composer placeholder text (shared by the static and wave paths). */
|
|
28409
|
+
const COMPOSER_PLACEHOLDER = "type a message · / commands · @ mentions";
|
|
28410
|
+
/** Adjacent cells with identical styling merge into one styled Text span. */
|
|
28411
|
+
function sameCellStyle(a, b) {
|
|
28412
|
+
return a.color === b.color && a.backgroundColor === b.backgroundColor && a.bold === b.bold && a.inverse === b.inverse && a.dim === b.dim;
|
|
28413
|
+
}
|
|
28414
|
+
/**
|
|
28415
|
+
* Render the wave row as one Text whose cells carry per-column
|
|
28416
|
+
* `backgroundColor` runs: the Codex Wave crest paints a smooth gradient
|
|
28417
|
+
* (one SGR run per sampled column) over the prompt, draft, cursor,
|
|
28418
|
+
* placeholder, and the trailing blank fill — the draft stays readable
|
|
28419
|
+
* because the tint blends at ≤ 0.55 toward the theme's blank-cell base.
|
|
28420
|
+
*/
|
|
28421
|
+
function waveRowSpans(cells) {
|
|
28422
|
+
const spans = [];
|
|
28423
|
+
let start = 0;
|
|
28424
|
+
while (start < cells.length) {
|
|
28425
|
+
const cell = cells[start];
|
|
28426
|
+
let end = start + 1;
|
|
28427
|
+
while (end < cells.length && sameCellStyle(cells[end], cell)) end += 1;
|
|
28428
|
+
spans.push((0, import_react.createElement)(Text, {
|
|
28429
|
+
key: start,
|
|
28430
|
+
color: cell.color,
|
|
28431
|
+
backgroundColor: cell.backgroundColor,
|
|
28432
|
+
bold: cell.bold,
|
|
28433
|
+
inverse: cell.inverse,
|
|
28434
|
+
dimColor: cell.dim
|
|
28435
|
+
}, cells.slice(start, end).map((c) => c.char).join("")));
|
|
28436
|
+
start = end;
|
|
28437
|
+
}
|
|
28438
|
+
return spans;
|
|
28439
|
+
}
|
|
28227
28440
|
/**
|
|
28228
28441
|
* The Ctrl+O transcript inspector: one selected durable entry at a time,
|
|
28229
28442
|
* with independent history selection and content scrolling. The complete
|
|
@@ -28320,9 +28533,9 @@ function VerbosePanel({ entries, onClose }) {
|
|
|
28320
28533
|
width: viewport.outerColumns,
|
|
28321
28534
|
paddingX: 1,
|
|
28322
28535
|
borderStyle: "round",
|
|
28323
|
-
borderColor: inkColor(
|
|
28536
|
+
borderColor: inkColor(getPalette().brand)
|
|
28324
28537
|
}, (0, import_react.createElement)(Text, {
|
|
28325
|
-
color: inkColor(
|
|
28538
|
+
color: inkColor(getPalette().brand),
|
|
28326
28539
|
bold: true,
|
|
28327
28540
|
wrap: "truncate-end"
|
|
28328
28541
|
}, truncateColumns(title, viewport.contentColumns)), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(Box, { flexDirection: "column" }, entry === void 0 ? (0, import_react.createElement)(Text, { dimColor: true }, " no durable entries yet") : (0, import_react.createElement)(StyledRows, { lines: visible })), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(Text, {
|
|
@@ -28347,7 +28560,12 @@ const MemoStaticTranscript = (0, import_react.memo)(StaticTranscript);
|
|
|
28347
28560
|
* Resolve completion candidates for the current input: TUI-local commands,
|
|
28348
28561
|
* the live registry descriptors, and user-invocable skills, filtered by the
|
|
28349
28562
|
* typed prefix. Command names win collisions (the dispatch tries the
|
|
28350
|
-
* registry first and only then falls through to the skill gesture)
|
|
28563
|
+
* registry first and only then falls through to the skill gesture), and a
|
|
28564
|
+
* later duplicate name never renders twice.
|
|
28565
|
+
*
|
|
28566
|
+
* A bare `/` returns the FULL merged list — Codex's command popup shows every
|
|
28567
|
+
* command inside a scroll window on an empty filter, and the menu's own
|
|
28568
|
+
* selection window bounds the visible rows, so no slice cap is needed.
|
|
28351
28569
|
*/
|
|
28352
28570
|
function completionCandidates(value, descriptors, skills) {
|
|
28353
28571
|
if (!value.startsWith("/")) return [];
|
|
@@ -28363,6 +28581,11 @@ function completionCandidates(value, descriptors, skills) {
|
|
|
28363
28581
|
description: "switch the model",
|
|
28364
28582
|
origin: "command"
|
|
28365
28583
|
},
|
|
28584
|
+
{
|
|
28585
|
+
label: "/effort",
|
|
28586
|
+
description: "adjust reasoning effort for the current model",
|
|
28587
|
+
origin: "command"
|
|
28588
|
+
},
|
|
28366
28589
|
{
|
|
28367
28590
|
label: "/mode",
|
|
28368
28591
|
description: "select the agent preset",
|
|
@@ -28388,6 +28611,11 @@ function completionCandidates(value, descriptors, skills) {
|
|
|
28388
28611
|
description: "customize the status line",
|
|
28389
28612
|
origin: "command"
|
|
28390
28613
|
},
|
|
28614
|
+
{
|
|
28615
|
+
label: "/theme",
|
|
28616
|
+
description: "switch the color theme",
|
|
28617
|
+
origin: "command"
|
|
28618
|
+
},
|
|
28391
28619
|
{
|
|
28392
28620
|
label: "/history",
|
|
28393
28621
|
description: "search and recall past prompts",
|
|
@@ -28426,13 +28654,20 @@ function completionCandidates(value, descriptors, skills) {
|
|
|
28426
28654
|
description: skill.modelInvocable ? `skill · ${skill.description}` : `skill (user only) · ${skill.description}`,
|
|
28427
28655
|
origin: "skill"
|
|
28428
28656
|
}));
|
|
28429
|
-
const
|
|
28657
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28658
|
+
const all = [];
|
|
28659
|
+
for (const candidate of [
|
|
28430
28660
|
...local,
|
|
28431
28661
|
...registry,
|
|
28432
28662
|
...skillRows
|
|
28433
|
-
]
|
|
28434
|
-
|
|
28435
|
-
|
|
28663
|
+
]) {
|
|
28664
|
+
const name = candidate.label.slice(1);
|
|
28665
|
+
if (seen.has(name)) continue;
|
|
28666
|
+
seen.add(name);
|
|
28667
|
+
all.push(candidate);
|
|
28668
|
+
}
|
|
28669
|
+
if (prefix === "") return all;
|
|
28670
|
+
return all.filter((candidate) => candidate.label.slice(1).startsWith(prefix));
|
|
28436
28671
|
}
|
|
28437
28672
|
/**
|
|
28438
28673
|
* The completion menu, rendered inside the composer's subtree directly above
|
|
@@ -28457,6 +28692,7 @@ function CompletionMenu({ active, mention, index, rows }) {
|
|
|
28457
28692
|
const selected = rows.length === 0 ? 0 : index % rows.length;
|
|
28458
28693
|
const first = selectionWindow(selected, rows.length, limit);
|
|
28459
28694
|
const visible = rows.slice(first, first + limit);
|
|
28695
|
+
const hidden = rows.length - visible.length;
|
|
28460
28696
|
return (0, import_react.createElement)(Box, {
|
|
28461
28697
|
flexDirection: "column",
|
|
28462
28698
|
marginLeft: 2,
|
|
@@ -28468,13 +28704,17 @@ function CompletionMenu({ active, mention, index, rows }) {
|
|
|
28468
28704
|
const absolute = first + at;
|
|
28469
28705
|
return (0, import_react.createElement)(Text, {
|
|
28470
28706
|
key: candidate.label,
|
|
28471
|
-
color: absolute === selected ? inkColor(
|
|
28707
|
+
color: absolute === selected ? inkColor(getPalette().brandBright) : inkColor(getPalette().dim),
|
|
28472
28708
|
wrap: "truncate-end"
|
|
28473
28709
|
}, `${absolute === selected ? "❯ " : " "}${padColumns(candidate.label, nameWidth)}${dim(truncateColumns(displayText(candidate.description), descBudget))}`);
|
|
28474
|
-
}),
|
|
28475
|
-
|
|
28710
|
+
}), hidden > 0 ? (0, import_react.createElement)(Text, {
|
|
28711
|
+
key: "more",
|
|
28712
|
+
color: inkColor(getPalette().dim),
|
|
28476
28713
|
wrap: "truncate-end"
|
|
28477
|
-
}, dim(
|
|
28714
|
+
}, dim(` … +${hidden} more`)) : void 0, showFooter ? (0, import_react.createElement)(Text, {
|
|
28715
|
+
color: inkColor(getPalette().dim),
|
|
28716
|
+
wrap: "truncate-end"
|
|
28717
|
+
}, dim(mention ? `↑↓ choose · ${rows.length} items · tab insert` : `↑↓ choose · ${rows.length} items · tab complete`)) : void 0);
|
|
28478
28718
|
}
|
|
28479
28719
|
/**
|
|
28480
28720
|
* The prompt box: TUI-local slash commands handled locally, other lines
|
|
@@ -28482,7 +28722,7 @@ function CompletionMenu({ active, mention, index, rows }) {
|
|
|
28482
28722
|
* While a modal (approval / question / model panel) owns the keys, the
|
|
28483
28723
|
* box passes every key through untouched.
|
|
28484
28724
|
*/
|
|
28485
|
-
function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, interrupt, quit, openModel, openHelp, openMode, openResume, openPlugin, openStatusline, openHistory, createSession, cancelSessionSwitch, notify, hasNotice, dismissNotice, toggleReasoning, openVerbose, clearView, refresh, loadMentions, cyclePermission, exportTranscript, renameTitle, recallSpace, recordLocal, recordHistory, queued, cancelQueued, historyFill, historyConsumed }) {
|
|
28725
|
+
function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, interrupt, quit, openModel, openEffort, openHelp, openMode, openResume, openPlugin, openStatusline, openTheme, openHistory, createSession, cancelSessionSwitch, notify, hasNotice, dismissNotice, toggleReasoning, openVerbose, clearView, refresh, loadMentions, cyclePermission, exportTranscript, renameTitle, recallSpace, recordLocal, recordHistory, queued, cancelQueued, historyFill, historyConsumed, waveTick, waveTier, waveStyle }) {
|
|
28486
28726
|
const columns = useStdout().stdout?.columns ?? 80;
|
|
28487
28727
|
const [value, setValue] = (0, import_react.useState)("");
|
|
28488
28728
|
const [cursor, setCursor] = (0, import_react.useState)(0);
|
|
@@ -28678,6 +28918,10 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
28678
28918
|
openModel();
|
|
28679
28919
|
return;
|
|
28680
28920
|
}
|
|
28921
|
+
if (text === "/effort" || text.startsWith("/effort ")) {
|
|
28922
|
+
openEffort();
|
|
28923
|
+
return;
|
|
28924
|
+
}
|
|
28681
28925
|
if (text === "/mode" || text.startsWith("/mode ")) {
|
|
28682
28926
|
if (text.slice(5).trim() === "") openMode();
|
|
28683
28927
|
else dispatch(text);
|
|
@@ -28704,6 +28948,10 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
28704
28948
|
openStatusline();
|
|
28705
28949
|
return;
|
|
28706
28950
|
}
|
|
28951
|
+
if (text === "/theme") {
|
|
28952
|
+
openTheme();
|
|
28953
|
+
return;
|
|
28954
|
+
}
|
|
28707
28955
|
if (text === "/history") {
|
|
28708
28956
|
openHistory();
|
|
28709
28957
|
return;
|
|
@@ -28818,27 +29066,118 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
28818
29066
|
setDismissedMenuValue(void 0);
|
|
28819
29067
|
}
|
|
28820
29068
|
});
|
|
29069
|
+
const tierActive = waveTier !== null;
|
|
29070
|
+
const tierHues = waveTier === null ? null : deepseekWaveHues(waveTier);
|
|
29071
|
+
const promptColor = tierHues === null ? inkColor(getPalette().brand) : inkColor(tierHues[0]);
|
|
29072
|
+
const promptGlyph = waveTier === "flash" ? "›" : waveTier === "deepseek" ? "»" : "❯";
|
|
28821
29073
|
if (frozen) {
|
|
28822
29074
|
const frozen = value === "" ? "type a message" : verboseLine(value, Math.max(1, columns - 6));
|
|
28823
29075
|
return (0, import_react.createElement)(Box, {
|
|
28824
29076
|
width: Math.max(1, columns - 1),
|
|
28825
29077
|
borderStyle: "round",
|
|
28826
|
-
borderColor: inkColor(
|
|
29078
|
+
borderColor: inkColor(getPalette().dim),
|
|
28827
29079
|
paddingX: 1
|
|
28828
|
-
}, (0, import_react.createElement)(Text, { wrap: "truncate-end" }, (0, import_react.createElement)(Text, {
|
|
29080
|
+
}, (0, import_react.createElement)(Text, { wrap: "truncate-end" }, (0, import_react.createElement)(Text, {
|
|
29081
|
+
color: promptColor,
|
|
29082
|
+
bold: tierActive ? true : void 0
|
|
29083
|
+
}, busy ? "… " : `${promptGlyph} `), frozen));
|
|
28829
29084
|
}
|
|
28830
|
-
const
|
|
28831
|
-
|
|
29085
|
+
const frame = (row, borderRgb) => (0, import_react.createElement)(Box, {
|
|
29086
|
+
width: Math.max(1, columns - 1),
|
|
29087
|
+
borderStyle: "round",
|
|
29088
|
+
borderColor: inkColor(borderRgb ?? getPalette().dim),
|
|
29089
|
+
paddingX: 1
|
|
29090
|
+
}, row);
|
|
29091
|
+
const menu = (0, import_react.createElement)(CompletionMenu, {
|
|
28832
29092
|
active: menuActive,
|
|
28833
29093
|
mention: mentionActive,
|
|
28834
29094
|
index: completionIndex,
|
|
28835
29095
|
rows: menuRows
|
|
28836
|
-
})
|
|
28837
|
-
|
|
28838
|
-
|
|
28839
|
-
|
|
28840
|
-
|
|
28841
|
-
},
|
|
29096
|
+
});
|
|
29097
|
+
const editor = editorWindow(value, cursor, Math.max(1, columns - 6));
|
|
29098
|
+
const staticRow = (0, import_react.createElement)(Text, { wrap: "truncate-end" }, busy ? (0, import_react.createElement)(BusyChase) : (0, import_react.createElement)(Text, {
|
|
29099
|
+
color: promptColor,
|
|
29100
|
+
bold: tierActive ? true : void 0
|
|
29101
|
+
}, `${promptGlyph} `), value === "" ? void 0 : editor.before, (0, import_react.createElement)(CursorBlock, { char: editor.caret }), value === "" && !busy ? (0, import_react.createElement)(Text, { dimColor: true }, COMPOSER_PLACEHOLDER) : editor.after);
|
|
29102
|
+
const waveRow = () => {
|
|
29103
|
+
const contentWidth = Math.max(1, columns - 5);
|
|
29104
|
+
const waveEditor = editorWindow(value, cursor, Math.max(1, contentWidth - 2));
|
|
29105
|
+
const hues = deepseekWaveHues(waveTier);
|
|
29106
|
+
const style = waveStyle;
|
|
29107
|
+
const base = getTheme() === "light" ? WAVE_BASE_LIGHT : WAVE_BASE_DARK;
|
|
29108
|
+
const waveBg = (column) => {
|
|
29109
|
+
const rgb = deepseekWaveColumnBg(waveTick, column, contentWidth, waveTier, style, hues, base);
|
|
29110
|
+
return rgb === null ? void 0 : inkColor(rgb);
|
|
29111
|
+
};
|
|
29112
|
+
const cells = [];
|
|
29113
|
+
cells.push({
|
|
29114
|
+
char: promptGlyph,
|
|
29115
|
+
color: promptColor,
|
|
29116
|
+
bold: true,
|
|
29117
|
+
backgroundColor: waveBg(0)
|
|
29118
|
+
});
|
|
29119
|
+
cells.push({
|
|
29120
|
+
char: " ",
|
|
29121
|
+
color: promptColor,
|
|
29122
|
+
backgroundColor: waveBg(1)
|
|
29123
|
+
});
|
|
29124
|
+
for (const char of waveEditor.before) cells.push({
|
|
29125
|
+
char,
|
|
29126
|
+
backgroundColor: waveBg(cells.length)
|
|
29127
|
+
});
|
|
29128
|
+
cells.push({
|
|
29129
|
+
char: waveEditor.caret,
|
|
29130
|
+
inverse: true,
|
|
29131
|
+
backgroundColor: waveBg(cells.length)
|
|
29132
|
+
});
|
|
29133
|
+
if (value === "" && !busy) for (let at = 0; at < 40; at += 1) cells.push({
|
|
29134
|
+
char: COMPOSER_PLACEHOLDER[at],
|
|
29135
|
+
dim: true,
|
|
29136
|
+
backgroundColor: waveBg(cells.length)
|
|
29137
|
+
});
|
|
29138
|
+
else for (const char of waveEditor.after) cells.push({
|
|
29139
|
+
char,
|
|
29140
|
+
backgroundColor: waveBg(cells.length)
|
|
29141
|
+
});
|
|
29142
|
+
while (cells.length < contentWidth) cells.push({
|
|
29143
|
+
char: " ",
|
|
29144
|
+
backgroundColor: waveBg(cells.length)
|
|
29145
|
+
});
|
|
29146
|
+
if (deepseekWaveWordVisible(waveTick, waveTier, style)) {
|
|
29147
|
+
const word = "deepseek";
|
|
29148
|
+
const start = Math.max(2, Math.floor((contentWidth - 8) / 2));
|
|
29149
|
+
let clear = true;
|
|
29150
|
+
for (let at = 0; at < 8; at += 1) {
|
|
29151
|
+
const cell = cells[start + at];
|
|
29152
|
+
if (cell === void 0 || cell.char !== " " && cell.dim !== true) {
|
|
29153
|
+
clear = false;
|
|
29154
|
+
break;
|
|
29155
|
+
}
|
|
29156
|
+
}
|
|
29157
|
+
if (clear) for (let at = 0; at < 8; at += 1) {
|
|
29158
|
+
const cell = cells[start + at];
|
|
29159
|
+
cell.char = word[at];
|
|
29160
|
+
cell.color = inkColor(deepseekWaveWordHue(at, hues));
|
|
29161
|
+
cell.bold = true;
|
|
29162
|
+
cell.dim = false;
|
|
29163
|
+
}
|
|
29164
|
+
}
|
|
29165
|
+
if (waveTier === "deepseek" && style === "wave") {
|
|
29166
|
+
const spark = deepseekWaveSpark(waveTick);
|
|
29167
|
+
if (spark !== null) {
|
|
29168
|
+
const last = cells[cells.length - 1];
|
|
29169
|
+
if (last !== void 0 && last.char === " ") {
|
|
29170
|
+
last.char = spark;
|
|
29171
|
+
last.color = promptColor;
|
|
29172
|
+
last.bold = true;
|
|
29173
|
+
last.dim = false;
|
|
29174
|
+
}
|
|
29175
|
+
}
|
|
29176
|
+
}
|
|
29177
|
+
const borderRgb = deepseekWaveBorderColor(waveTick, waveTier, style, hues, getPalette().dim);
|
|
29178
|
+
return frame((0, import_react.createElement)(Text, { wrap: "truncate-end" }, ...waveRowSpans(cells)), borderRgb);
|
|
29179
|
+
};
|
|
29180
|
+
return (0, import_react.createElement)(Box, { flexDirection: "column" }, menu, waveTick !== null && waveTier !== null && !busy ? waveRow() : frame(staticRow));
|
|
28842
29181
|
}
|
|
28843
29182
|
/** The whole terminal app; state arrives via the store, output via Ink. */
|
|
28844
29183
|
function App(props) {
|
|
@@ -28847,6 +29186,60 @@ function App(props) {
|
|
|
28847
29186
|
const skills = (0, import_react.useSyncExternalStore)(props.skills.subscribe, () => props.skills.rows);
|
|
28848
29187
|
const [modelLabel, setModelLabel] = (0, import_react.useState)(props.model);
|
|
28849
29188
|
const [modelOpen, setModelOpen] = (0, import_react.useState)(false);
|
|
29189
|
+
/** The model row whose effort levels the /model stage lists; undefined shows the model list. */
|
|
29190
|
+
const [effortFor, setEffortFor] = (0, import_react.useState)(void 0);
|
|
29191
|
+
/** Effective reasoning effort, shown in the /model picker and switch notice. */
|
|
29192
|
+
const [effortLabel, setEffortLabel] = (0, import_react.useState)(props.effort);
|
|
29193
|
+
/** DeepSeek easter egg: switching INTO an official DeepSeek route plays
|
|
29194
|
+
* one of Codex's three ignition styles (Wave / Aurora / Pulse, picked at
|
|
29195
|
+
* random without repeating) across the composer's padded band (33ms tick,
|
|
29196
|
+
* per-style durations), then the band returns to static while the prompt
|
|
29197
|
+
* marker keeps the tier accent. The trigger follows the applied model
|
|
29198
|
+
* label (what the status bar actually shows), never the initial paint,
|
|
29199
|
+
* and the tier is derived from the label and cached at the switch. */
|
|
29200
|
+
const [waveTick, setWaveTick] = (0, import_react.useState)(null);
|
|
29201
|
+
const [waveTier, setWaveTier] = (0, import_react.useState)(null);
|
|
29202
|
+
const [waveStyle, setWaveStyle] = (0, import_react.useState)(null);
|
|
29203
|
+
const previousModel = (0, import_react.useRef)(void 0);
|
|
29204
|
+
const previousEffort = (0, import_react.useRef)(props.effort);
|
|
29205
|
+
const previousStyle = (0, import_react.useRef)(void 0);
|
|
29206
|
+
(0, import_react.useEffect)(() => {
|
|
29207
|
+
const previous = previousModel.current;
|
|
29208
|
+
previousModel.current = modelLabel;
|
|
29209
|
+
const effortChanged = previousEffort.current !== effortLabel;
|
|
29210
|
+
previousEffort.current = effortLabel;
|
|
29211
|
+
const modelChanged = previous !== void 0 && previous !== modelLabel;
|
|
29212
|
+
if (!isOfficialDeepSeekLabel(modelLabel)) {
|
|
29213
|
+
setWaveTier(null);
|
|
29214
|
+
setWaveStyle(null);
|
|
29215
|
+
setWaveTick(null);
|
|
29216
|
+
return;
|
|
29217
|
+
}
|
|
29218
|
+
if (modelChanged || effortChanged) {
|
|
29219
|
+
setWaveTier(deepseekWaveTier(modelLabel));
|
|
29220
|
+
const nextStyle = deepseekWaveStyleRandom(previousStyle.current);
|
|
29221
|
+
previousStyle.current = nextStyle;
|
|
29222
|
+
setWaveStyle(nextStyle);
|
|
29223
|
+
setWaveTick(0);
|
|
29224
|
+
}
|
|
29225
|
+
}, [modelLabel, effortLabel]);
|
|
29226
|
+
const waveActive = waveTick !== null && waveTier !== null && waveStyle !== null && waveTick * 33 < deepseekWaveDuration(waveTier, waveStyle);
|
|
29227
|
+
(0, import_react.useEffect)(() => {
|
|
29228
|
+
if (!waveActive) return;
|
|
29229
|
+
const id = setInterval(() => {
|
|
29230
|
+
setWaveTick((current) => current === null ? 0 : current + 1);
|
|
29231
|
+
}, 33);
|
|
29232
|
+
return () => {
|
|
29233
|
+
clearInterval(id);
|
|
29234
|
+
};
|
|
29235
|
+
}, [waveActive]);
|
|
29236
|
+
(0, import_react.useEffect)(() => {
|
|
29237
|
+
if (waveTick !== null && waveTier !== null && waveStyle !== null && waveTick * 33 >= deepseekWaveDuration(waveTier, waveStyle)) setWaveTick(null);
|
|
29238
|
+
}, [
|
|
29239
|
+
waveTick,
|
|
29240
|
+
waveTier,
|
|
29241
|
+
waveStyle
|
|
29242
|
+
]);
|
|
28850
29243
|
const [directory, setDirectory] = (0, import_react.useState)(void 0);
|
|
28851
29244
|
const [modelError, setModelError] = (0, import_react.useState)(void 0);
|
|
28852
29245
|
const [modelLoadEpoch, setModelLoadEpoch] = (0, import_react.useState)(0);
|
|
@@ -28888,6 +29281,7 @@ function App(props) {
|
|
|
28888
29281
|
const [pluginQuery, setPluginQuery] = (0, import_react.useState)("");
|
|
28889
29282
|
const [statuslineOpen, setStatuslineOpen] = (0, import_react.useState)(false);
|
|
28890
29283
|
const [statuslineItems, setStatuslineItems] = (0, import_react.useState)(() => parseStatuslineItems(props.statusline));
|
|
29284
|
+
const [themeOpen, setThemeOpen] = (0, import_react.useState)(false);
|
|
28891
29285
|
const [historyOpen, setHistoryOpen] = (0, import_react.useState)(false);
|
|
28892
29286
|
/** The /history panel's accepted entry: text plus its recall-space index. */
|
|
28893
29287
|
const [historyFill, setHistoryFill] = (0, import_react.useState)(void 0);
|
|
@@ -28908,15 +29302,17 @@ function App(props) {
|
|
|
28908
29302
|
const questionSnapshot = (0, import_react.useSyncExternalStore)(props.questions.subscribe, props.questions.getSnapshot);
|
|
28909
29303
|
const approvalPending = approvalSnapshot.pending !== void 0;
|
|
28910
29304
|
const questionPending = questionSnapshot.pending !== void 0;
|
|
28911
|
-
const inputActive = !modelOpen && !helpOpen && !modeOpen && !resumeOpen && !pluginOpen && !statuslineOpen && !historyOpen && !verboseOpen && !approvalPending && !questionPending;
|
|
29305
|
+
const inputActive = !modelOpen && !helpOpen && !modeOpen && !resumeOpen && !pluginOpen && !statuslineOpen && !themeOpen && !historyOpen && !verboseOpen && !approvalPending && !questionPending;
|
|
28912
29306
|
(0, import_react.useEffect)(() => {
|
|
28913
29307
|
if (!approvalPending && !questionPending) return;
|
|
28914
29308
|
setModelOpen(false);
|
|
29309
|
+
setEffortFor(void 0);
|
|
28915
29310
|
setHelpOpen(false);
|
|
28916
29311
|
setModeOpen(false);
|
|
28917
29312
|
setResumeOpen(false);
|
|
28918
29313
|
setPluginOpen(false);
|
|
28919
29314
|
setStatuslineOpen(false);
|
|
29315
|
+
setThemeOpen(false);
|
|
28920
29316
|
setHistoryOpen(false);
|
|
28921
29317
|
setVerboseOpen(false);
|
|
28922
29318
|
}, [approvalPending, questionPending]);
|
|
@@ -28998,8 +29394,8 @@ function App(props) {
|
|
|
28998
29394
|
const streamRows = Math.max(1, dynamicRows - visibleLiveLines.length);
|
|
28999
29395
|
const reasoningRows = view.streamingReasoning === "" ? 0 : view.streaming === "" ? streamRows : streamRows <= 1 ? 0 : showReasoning ? Math.max(1, Math.floor(streamRows / 3)) : 1;
|
|
29000
29396
|
const answerRows = view.streaming === "" ? 0 : Math.max(1, streamRows - reasoningRows);
|
|
29001
|
-
const transcriptVisible = !modelOpen && !helpOpen && !modeOpen && !resumeOpen && !pluginOpen && !statuslineOpen && !historyOpen && !verboseOpen && !approvalPending && !questionPending;
|
|
29002
|
-
const modalVisible = modelOpen || helpOpen || modeOpen || resumeOpen || pluginOpen || statuslineOpen || historyOpen || verboseOpen && !approvalPending && !questionPending || approvalPending || questionPending;
|
|
29397
|
+
const transcriptVisible = !modelOpen && !helpOpen && !modeOpen && !resumeOpen && !pluginOpen && !statuslineOpen && !themeOpen && !historyOpen && !verboseOpen && !approvalPending && !questionPending;
|
|
29398
|
+
const modalVisible = modelOpen || helpOpen || modeOpen || resumeOpen || pluginOpen || statuslineOpen || themeOpen || historyOpen || verboseOpen && !approvalPending && !questionPending || approvalPending || questionPending;
|
|
29003
29399
|
const closeInspector = (0, import_react.useCallback)(() => {
|
|
29004
29400
|
setVerboseOpen(false);
|
|
29005
29401
|
}, []);
|
|
@@ -29007,6 +29403,19 @@ function App(props) {
|
|
|
29007
29403
|
if (appStdout !== void 0) appStdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
29008
29404
|
setRefreshEpoch((epoch) => epoch + 1);
|
|
29009
29405
|
};
|
|
29406
|
+
/** Apply one /model pick: record the selection, close the panel, report via notice. */
|
|
29407
|
+
const applyModel = (row, effortId) => {
|
|
29408
|
+
try {
|
|
29409
|
+
const label = props.selectModel(row, effortId);
|
|
29410
|
+
setModelLabel(label);
|
|
29411
|
+
setEffortLabel(effortId);
|
|
29412
|
+
notify(`model → next step uses ${label}${effortId === void 0 || effortId === "" ? "" : `@${effortId}`}`);
|
|
29413
|
+
setModelOpen(false);
|
|
29414
|
+
setEffortFor(void 0);
|
|
29415
|
+
} catch (error) {
|
|
29416
|
+
notify(`model switch failed: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
29417
|
+
}
|
|
29418
|
+
};
|
|
29010
29419
|
return (0, import_react.createElement)(Box, { flexDirection: "column" }, (0, import_react.createElement)(MemoStaticTranscript, {
|
|
29011
29420
|
key: refreshEpoch,
|
|
29012
29421
|
items: settledRows
|
|
@@ -29030,24 +29439,29 @@ function App(props) {
|
|
|
29030
29439
|
}), (0, import_react.createElement)(ApprovalBar, {
|
|
29031
29440
|
snapshot: approvalSnapshot,
|
|
29032
29441
|
locked: questionPending
|
|
29033
|
-
}), modelOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(ModelPanel, {
|
|
29442
|
+
}), modelOpen && !approvalPending && !questionPending ? effortFor === void 0 ? (0, import_react.createElement)(ModelPanel, {
|
|
29034
29443
|
directory,
|
|
29035
29444
|
error: modelError,
|
|
29036
29445
|
onSelect: (row) => {
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
setModelOpen(false);
|
|
29041
|
-
} catch (error) {
|
|
29042
|
-
notify(`model switch failed: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
29446
|
+
if (row.reasoning !== void 0 && row.reasoning.efforts.length > 1) {
|
|
29447
|
+
setEffortFor(row);
|
|
29448
|
+
return;
|
|
29043
29449
|
}
|
|
29450
|
+
const effortId = row.reasoning?.efforts.length === 1 ? row.reasoning.efforts[0].id : void 0;
|
|
29451
|
+
applyModel(row, effortId);
|
|
29044
29452
|
},
|
|
29045
29453
|
onRetry: () => {
|
|
29046
29454
|
setModelLoadEpoch((epoch) => epoch + 1);
|
|
29047
29455
|
},
|
|
29048
29456
|
onClose: () => {
|
|
29049
29457
|
setModelOpen(false);
|
|
29458
|
+
setEffortFor(void 0);
|
|
29050
29459
|
}
|
|
29460
|
+
}) : (0, import_react.createElement)(EffortPanel, {
|
|
29461
|
+
row: effortFor,
|
|
29462
|
+
current: effortLabel,
|
|
29463
|
+
select: (effortId) => applyModel(effortFor, effortId),
|
|
29464
|
+
back: () => setEffortFor(void 0)
|
|
29051
29465
|
}) : void 0, helpOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(HelpPanel, {
|
|
29052
29466
|
descriptors,
|
|
29053
29467
|
skills,
|
|
@@ -29089,6 +29503,15 @@ function App(props) {
|
|
|
29089
29503
|
props.saveStatusline(items);
|
|
29090
29504
|
},
|
|
29091
29505
|
close: () => setStatuslineOpen(false)
|
|
29506
|
+
}) : void 0, themeOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(ThemePanel, {
|
|
29507
|
+
current: getTheme(),
|
|
29508
|
+
select: (name) => {
|
|
29509
|
+
setTheme(name);
|
|
29510
|
+
props.saveTheme?.(name);
|
|
29511
|
+
notify(`theme → ${name}`);
|
|
29512
|
+
setThemeOpen(false);
|
|
29513
|
+
},
|
|
29514
|
+
close: () => setThemeOpen(false)
|
|
29092
29515
|
}) : void 0, historyOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(HistoryPanel, {
|
|
29093
29516
|
entries: recallSpace,
|
|
29094
29517
|
fill: (text, index) => {
|
|
@@ -29119,8 +29542,32 @@ function App(props) {
|
|
|
29119
29542
|
openModel: () => {
|
|
29120
29543
|
setDirectory(void 0);
|
|
29121
29544
|
setModelError(void 0);
|
|
29545
|
+
setEffortFor(void 0);
|
|
29122
29546
|
setModelOpen(true);
|
|
29123
29547
|
},
|
|
29548
|
+
openEffort: () => {
|
|
29549
|
+
props.loadModels().then((loaded) => {
|
|
29550
|
+
const [provider, model] = modelLabel.split("/");
|
|
29551
|
+
const row = loaded.rows.find((candidate) => candidate.provider === provider && candidate.model === model) ?? loaded.rows.find((candidate) => candidate.model === model && candidate.reasoning !== void 0) ?? loaded.rows.find((candidate) => candidate.model === model);
|
|
29552
|
+
if (row === void 0) {
|
|
29553
|
+
notify("current model is not in the catalog", "warning");
|
|
29554
|
+
return;
|
|
29555
|
+
}
|
|
29556
|
+
const rowTag = `${row.provider}/${row.model}`;
|
|
29557
|
+
if (loaded.reasoningFailures?.includes(rowTag) === true) {
|
|
29558
|
+
notify("reasoning levels temporarily unavailable (capability lookup failed) — try again", "warning");
|
|
29559
|
+
return;
|
|
29560
|
+
}
|
|
29561
|
+
if (row.reasoning === void 0 || row.reasoning.efforts.length === 0) {
|
|
29562
|
+
notify("current model does not expose reasoning efforts", "warning");
|
|
29563
|
+
return;
|
|
29564
|
+
}
|
|
29565
|
+
setEffortFor(row);
|
|
29566
|
+
setModelOpen(true);
|
|
29567
|
+
}, (error) => {
|
|
29568
|
+
notify(`model lookup failed: ${error instanceof Error ? error.message : String(error)}`, "error");
|
|
29569
|
+
});
|
|
29570
|
+
},
|
|
29124
29571
|
openHelp: () => {
|
|
29125
29572
|
setHelpOpen(true);
|
|
29126
29573
|
},
|
|
@@ -29131,6 +29578,7 @@ function App(props) {
|
|
|
29131
29578
|
setPluginOpen(true);
|
|
29132
29579
|
},
|
|
29133
29580
|
openStatusline: () => setStatuslineOpen(true),
|
|
29581
|
+
openTheme: () => setThemeOpen(true),
|
|
29134
29582
|
openHistory: () => setHistoryOpen(true),
|
|
29135
29583
|
createSession: props.createSession,
|
|
29136
29584
|
cancelSessionSwitch: props.cancelSessionSwitch,
|
|
@@ -29160,7 +29608,10 @@ function App(props) {
|
|
|
29160
29608
|
queued: queuedRows,
|
|
29161
29609
|
cancelQueued: props.cancelQueued,
|
|
29162
29610
|
historyFill,
|
|
29163
|
-
historyConsumed
|
|
29611
|
+
historyConsumed,
|
|
29612
|
+
waveTick,
|
|
29613
|
+
waveTier,
|
|
29614
|
+
waveStyle
|
|
29164
29615
|
}), (0, import_react.createElement)(StatusLine, {
|
|
29165
29616
|
facts: {
|
|
29166
29617
|
model: modelLabel,
|
|
@@ -29346,11 +29797,66 @@ const internals = {
|
|
|
29346
29797
|
};
|
|
29347
29798
|
//#endregion
|
|
29348
29799
|
//#region src/models.ts
|
|
29800
|
+
/** Map an adapter's reasoning capability onto the panel's plain-id shape. */
|
|
29801
|
+
function mapReasoning(reasoning) {
|
|
29802
|
+
return {
|
|
29803
|
+
efforts: reasoning.efforts.map((effort) => ({
|
|
29804
|
+
id: effort.id,
|
|
29805
|
+
name: effort.name,
|
|
29806
|
+
...effort.description === void 0 ? {} : { description: effort.description }
|
|
29807
|
+
})),
|
|
29808
|
+
...reasoning.defaultEffort === void 0 ? {} : { defaultEffort: reasoning.defaultEffort }
|
|
29809
|
+
};
|
|
29810
|
+
}
|
|
29811
|
+
/**
|
|
29812
|
+
* Resolve the effective model selection for one live session, in the
|
|
29813
|
+
* documented precedence: the in-process explicit pick, then the session's
|
|
29814
|
+
* last `request/header` config, then the deployment default.
|
|
29815
|
+
* @param picked - the explicit selection made in this process, when any.
|
|
29816
|
+
* @param logged - the last logged request header config, when any.
|
|
29817
|
+
* @param defaults - the deployment default selection.
|
|
29818
|
+
* @returns the effective selection, carrying a reasoning effort when one is in force.
|
|
29819
|
+
*/
|
|
29820
|
+
function resolveEffectiveSelection(picked, logged, defaults) {
|
|
29821
|
+
if (picked !== void 0) return picked;
|
|
29822
|
+
if (logged !== void 0) return {
|
|
29823
|
+
provider: logged.provider,
|
|
29824
|
+
model: logged.model,
|
|
29825
|
+
...logged.reasoningEffort === void 0 ? {} : { reasoningEffort: ReasoningEffortId(logged.reasoningEffort) }
|
|
29826
|
+
};
|
|
29827
|
+
return defaults;
|
|
29828
|
+
}
|
|
29829
|
+
/**
|
|
29830
|
+
* Build the selection one `/model` pick applies, rejecting an effort the
|
|
29831
|
+
* row does not advertise. The row is the picker's source of truth, so a
|
|
29832
|
+
* stale directory cannot smuggle an unsupported effort into the next step
|
|
29833
|
+
* (the request pipeline would reject it before network I/O regardless). The
|
|
29834
|
+
* empty string is the picker's "provider default" sentinel — an explicit
|
|
29835
|
+
* choice to leave the effort to the model's own default, exactly like an
|
|
29836
|
+
* absent effort.
|
|
29837
|
+
* @param row - the picked model row.
|
|
29838
|
+
* @param effortId - the chosen advertised effort, '' or undefined for the model default.
|
|
29839
|
+
* @returns the selection the runner records for the next assembled step.
|
|
29840
|
+
*/
|
|
29841
|
+
function buildModelSelection(row, effortId) {
|
|
29842
|
+
const selected = effortId === void 0 || effortId === "" ? void 0 : effortId;
|
|
29843
|
+
if (selected !== void 0 && (row.reasoning === void 0 || !row.reasoning.efforts.some((effort) => effort.id === selected))) throw new Error(`model ${row.provider}/${row.model} does not support reasoning effort "${selected}"`);
|
|
29844
|
+
return {
|
|
29845
|
+
provider: row.provider,
|
|
29846
|
+
model: row.model,
|
|
29847
|
+
...selected === void 0 ? {} : { reasoningEffort: ReasoningEffortId(selected) }
|
|
29848
|
+
};
|
|
29849
|
+
}
|
|
29349
29850
|
/**
|
|
29350
29851
|
* Load the selectable model directory from the live `ctx.llm` registry.
|
|
29351
29852
|
* Providers are listed synchronously; each provider's models are discovered
|
|
29352
29853
|
* with a bounded parallel fan-out whose failures degrade to that provider
|
|
29353
29854
|
* contributing no rows (mirrors the web catalog's per-provider failures).
|
|
29855
|
+
* Each row's reasoning levels are resolved per exact model like the web
|
|
29856
|
+
* catalog (`buildModelCatalog`); a single model's capability lookup failure
|
|
29857
|
+
* degrades to that row having no effort picker rather than hiding the model,
|
|
29858
|
+
* and the failure rides `reasoningFailures` so the caller can tell "no
|
|
29859
|
+
* advertised reasoning" from "capability lookup failed".
|
|
29354
29860
|
* @param ctx - context carrying the `llm` service.
|
|
29355
29861
|
* @returns the resolved directory; empty rows when `llm` is unavailable.
|
|
29356
29862
|
*/
|
|
@@ -29358,21 +29864,39 @@ async function loadModelDirectory(ctx) {
|
|
|
29358
29864
|
const llm = ctx.get("llm");
|
|
29359
29865
|
if (llm === void 0) return {
|
|
29360
29866
|
rows: [],
|
|
29361
|
-
failures: []
|
|
29867
|
+
failures: [],
|
|
29868
|
+
reasoningFailures: []
|
|
29362
29869
|
};
|
|
29870
|
+
const llmResolve = llm;
|
|
29363
29871
|
const providers = llm.listProviders();
|
|
29364
29872
|
const listed = await Promise.all(providers.map(async (provider) => {
|
|
29365
29873
|
try {
|
|
29366
29874
|
const models = await llm.listModels(provider.id);
|
|
29367
|
-
|
|
29368
|
-
|
|
29369
|
-
|
|
29370
|
-
models: models.map((model) => ({
|
|
29875
|
+
const reasoningFailures = [];
|
|
29876
|
+
const rows = await Promise.all(models.map(async (model) => {
|
|
29877
|
+
const row = {
|
|
29371
29878
|
provider: provider.id,
|
|
29372
29879
|
providerName: provider.name,
|
|
29373
29880
|
model: model.id,
|
|
29374
29881
|
modelName: model.name
|
|
29375
|
-
}
|
|
29882
|
+
};
|
|
29883
|
+
if (llmResolve.resolveModelInfo === void 0) return row;
|
|
29884
|
+
try {
|
|
29885
|
+
const resolved = await llmResolve.resolveModelInfo(provider.id, model.id);
|
|
29886
|
+
return resolved.reasoning === void 0 ? row : {
|
|
29887
|
+
...row,
|
|
29888
|
+
reasoning: mapReasoning(resolved.reasoning)
|
|
29889
|
+
};
|
|
29890
|
+
} catch {
|
|
29891
|
+
reasoningFailures.push(`${provider.id}/${model.id}`);
|
|
29892
|
+
return row;
|
|
29893
|
+
}
|
|
29894
|
+
}));
|
|
29895
|
+
return {
|
|
29896
|
+
provider: provider.id,
|
|
29897
|
+
providerName: provider.name,
|
|
29898
|
+
models: rows,
|
|
29899
|
+
reasoningFailures
|
|
29376
29900
|
};
|
|
29377
29901
|
} catch {
|
|
29378
29902
|
return {
|
|
@@ -29385,20 +29909,26 @@ async function loadModelDirectory(ctx) {
|
|
|
29385
29909
|
}));
|
|
29386
29910
|
return {
|
|
29387
29911
|
rows: listed.flatMap((entry) => entry.models),
|
|
29388
|
-
failures: listed.filter((entry) => "failed" in entry && entry.failed === true).map((entry) => entry.provider)
|
|
29912
|
+
failures: listed.filter((entry) => "failed" in entry && entry.failed === true).map((entry) => entry.provider),
|
|
29913
|
+
reasoningFailures: listed.flatMap((entry) => "failed" in entry ? [] : entry.reasoningFailures)
|
|
29389
29914
|
};
|
|
29390
29915
|
}
|
|
29391
29916
|
//#endregion
|
|
29392
29917
|
//#region src/mentions.ts
|
|
29393
29918
|
/**
|
|
29394
|
-
* Workspace @mention support: file candidates from a bounded
|
|
29395
|
-
* the session cwd, session candidates from the opt-in
|
|
29396
|
-
* service, and submission preparation through its
|
|
29397
|
-
* session mentions land as canonical
|
|
29398
|
-
* submit the text is parsed back into
|
|
29399
|
-
* references, snapshots are injected
|
|
29400
|
-
*
|
|
29401
|
-
* upstream README's wiring.
|
|
29919
|
+
* Workspace @mention support: file and directory candidates from a bounded
|
|
29920
|
+
* async scan of the session cwd, session candidates from the opt-in
|
|
29921
|
+
* `sessionReferenceResolver` service, and submission preparation through its
|
|
29922
|
+
* `prepare()` API. Picked session mentions land as canonical
|
|
29923
|
+
* `@[label](dsh-session:…)` tokens; on submit the text is parsed back into
|
|
29924
|
+
* readable `@label` text plus structured references, snapshots are injected
|
|
29925
|
+
* via `agent.inject()` before the readable message wakes the driver
|
|
29926
|
+
* (`followup` idle, `steer` running) — exactly the upstream README's wiring.
|
|
29927
|
+
*
|
|
29928
|
+
* Harness exposes no workspace-file mention service (only session references
|
|
29929
|
+
* plus a post-hoc produced-file linker), so the file index is the lightweight
|
|
29930
|
+
* bounded scan below, kept deliberately smaller than Codex's streaming
|
|
29931
|
+
* gitignore-aware walker.
|
|
29402
29932
|
*
|
|
29403
29933
|
* @module @deepseek-ai/dsh-code/mentions
|
|
29404
29934
|
*/
|
|
@@ -29414,7 +29944,16 @@ const SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
29414
29944
|
]);
|
|
29415
29945
|
const MAX_FILES = 4e3;
|
|
29416
29946
|
const MAX_DEPTH = 12;
|
|
29417
|
-
/**
|
|
29947
|
+
/** Empty-query default rows: proves the index exists without typing (Codex's
|
|
29948
|
+
* popups show something on a bare sigil too). */
|
|
29949
|
+
const EMPTY_QUERY_ROWS = 20;
|
|
29950
|
+
/**
|
|
29951
|
+
* Bounded async BFS scan of a workspace; unreadable entries are skipped.
|
|
29952
|
+
* Both files and directories are indexed (directories insert with a trailing
|
|
29953
|
+
* slash), mirroring Codex's `MatchType::{File,Directory}` index. Dotfiles and
|
|
29954
|
+
* the {@link SKIP_DIRS} list are excluded, which is a coarser filter than
|
|
29955
|
+
* Codex's gitignore-aware walker but stays dependency-free and bounded.
|
|
29956
|
+
*/
|
|
29418
29957
|
async function scanWorkspaceFiles(root, signal) {
|
|
29419
29958
|
const found = [];
|
|
29420
29959
|
const pending = [{
|
|
@@ -29438,6 +29977,10 @@ async function scanWorkspaceFiles(root, signal) {
|
|
|
29438
29977
|
const relative = current.relative === "" ? entry.name : `${current.relative}/${entry.name}`;
|
|
29439
29978
|
if (entry.isDirectory()) {
|
|
29440
29979
|
if (SKIP_DIRS.has(entry.name) || current.depth + 1 > MAX_DEPTH) continue;
|
|
29980
|
+
found.push({
|
|
29981
|
+
path: relative,
|
|
29982
|
+
kind: "directory"
|
|
29983
|
+
});
|
|
29441
29984
|
pending.push({
|
|
29442
29985
|
absolute: join(current.absolute, entry.name),
|
|
29443
29986
|
relative,
|
|
@@ -29474,38 +30017,47 @@ function scoreFile(path, query) {
|
|
|
29474
30017
|
/**
|
|
29475
30018
|
* Create the mention API for one agent's workspace. A missing
|
|
29476
30019
|
* session-reference service degrades to file mentions only (the scan still
|
|
29477
|
-
* works); `prepare` then passes text through untouched.
|
|
30020
|
+
* works); `prepare` then passes text through untouched. An undefined agent
|
|
30021
|
+
* (a bare launch before any session exists) also degrades to file-only
|
|
30022
|
+
* mentions, so `@` file completion works before the first message.
|
|
30023
|
+
*
|
|
30024
|
+
* `files` is hoisted into the closure so `candidates` never reaches for
|
|
30025
|
+
* `this` — the runner hands `mentions.candidates` to the input editor as a
|
|
30026
|
+
* detached callback, and a `this`-bound method would throw on every `@` key.
|
|
29478
30027
|
* @param ctx - context carrying the optional `sessionReferenceResolver`.
|
|
29479
30028
|
* @param agent - the session owner; excluded from its own candidates.
|
|
29480
30029
|
* @param cwd - workspace root to scan.
|
|
29481
30030
|
*/
|
|
29482
30031
|
function createMentions(ctx, agent, cwd) {
|
|
29483
30032
|
const resolver = ctx.get("sessionReferenceResolver");
|
|
30033
|
+
const sessionCapable = agent !== void 0 && resolver !== void 0;
|
|
29484
30034
|
let filesPromise;
|
|
30035
|
+
const files = () => {
|
|
30036
|
+
filesPromise ??= scanWorkspaceFiles(cwd);
|
|
30037
|
+
return filesPromise;
|
|
30038
|
+
};
|
|
29485
30039
|
return {
|
|
29486
|
-
files
|
|
29487
|
-
filesPromise ??= scanWorkspaceFiles(cwd);
|
|
29488
|
-
return filesPromise;
|
|
29489
|
-
},
|
|
30040
|
+
files,
|
|
29490
30041
|
async candidates(query, signal) {
|
|
29491
30042
|
const needle = query.trim();
|
|
29492
|
-
const [
|
|
29493
|
-
const fileRows =
|
|
30043
|
+
const [scanned, sessions] = await Promise.all([files(), sessionCapable && needle !== "" && agent !== void 0 ? resolver.listCandidates(agent, needle, 10, signal).catch(() => []) : Promise.resolve([])]);
|
|
30044
|
+
const fileRows = (needle === "" ? scanned.slice(0, EMPTY_QUERY_ROWS) : scanned.filter((candidate) => scoreFile(candidate.path, needle) > 0).sort((left, right) => scoreFile(right.path, needle) - scoreFile(left.path, needle)).slice(0, 20)).map((candidate) => ({
|
|
29494
30045
|
label: candidate.path,
|
|
29495
30046
|
description: candidate.kind === "directory" ? "Folder" : "File",
|
|
29496
30047
|
kind: candidate.kind
|
|
29497
30048
|
}));
|
|
29498
|
-
|
|
30049
|
+
const sessionRows = sessions.map((candidate) => ({
|
|
29499
30050
|
label: formatSessionReferenceMention(candidate),
|
|
29500
30051
|
description: `Session · ${candidate.cwd ?? "(no cwd)"}`,
|
|
29501
30052
|
kind: "session"
|
|
29502
|
-
}))
|
|
30053
|
+
}));
|
|
30054
|
+
return [...fileRows, ...sessionRows];
|
|
29503
30055
|
},
|
|
29504
30056
|
parse(text) {
|
|
29505
30057
|
return parseSessionReferenceText(text);
|
|
29506
30058
|
},
|
|
29507
30059
|
async prepare(parsed, signal) {
|
|
29508
|
-
if (parsed.references.length === 0 || resolver === void 0) return {
|
|
30060
|
+
if (parsed.references.length === 0 || resolver === void 0 || agent === void 0) return {
|
|
29509
30061
|
text: parsed.text,
|
|
29510
30062
|
references: parsed.references
|
|
29511
30063
|
};
|
|
@@ -29937,7 +30489,8 @@ const inject = [
|
|
|
29937
30489
|
const Config = z.object({ startup: z.object({
|
|
29938
30490
|
kind: z.string().required(),
|
|
29939
30491
|
sessionId: z.string(),
|
|
29940
|
-
mode: z.string()
|
|
30492
|
+
mode: z.string(),
|
|
30493
|
+
theme: z.string()
|
|
29941
30494
|
}) });
|
|
29942
30495
|
/** Report an unexpected direct-driver failure and request a failing exit. */
|
|
29943
30496
|
function fail(io, error) {
|
|
@@ -30034,7 +30587,7 @@ async function run(ctx, startup, io) {
|
|
|
30034
30587
|
/** Prepare a complete next session before disturbing the currently visible one. */
|
|
30035
30588
|
const prepare = async (next) => {
|
|
30036
30589
|
const nextCwd = next.cwd ?? cwd;
|
|
30037
|
-
const selectionState = {};
|
|
30590
|
+
const selectionState = pendingSelection === void 0 ? {} : { picked: pendingSelection };
|
|
30038
30591
|
let mode = next.mode;
|
|
30039
30592
|
if (!next.resume) mode = (await presets.resolve(mode)).id;
|
|
30040
30593
|
const setup = async (agentCtx) => {
|
|
@@ -30042,14 +30595,7 @@ async function run(ctx, startup, io) {
|
|
|
30042
30595
|
mode = (await presets.mount(agentCtx, sessionPreset)).id;
|
|
30043
30596
|
installModelSelection(agentCtx, {
|
|
30044
30597
|
get current() {
|
|
30045
|
-
|
|
30046
|
-
const logged = agentCtx.agent?.session.requestHeader()?.config;
|
|
30047
|
-
if (logged !== void 0) return {
|
|
30048
|
-
provider: logged.provider,
|
|
30049
|
-
model: logged.model,
|
|
30050
|
-
...logged.reasoningEffort === void 0 ? {} : { reasoningEffort: logged.reasoningEffort }
|
|
30051
|
-
};
|
|
30052
|
-
return defaults;
|
|
30598
|
+
return resolveEffectiveSelection(selectionState.picked, agentCtx.agent?.session.requestHeader()?.config, defaults);
|
|
30053
30599
|
},
|
|
30054
30600
|
set current(value) {
|
|
30055
30601
|
selectionState.picked = value;
|
|
@@ -30093,7 +30639,9 @@ async function run(ctx, startup, io) {
|
|
|
30093
30639
|
let agent;
|
|
30094
30640
|
let session;
|
|
30095
30641
|
let store = createTranscriptStore();
|
|
30096
|
-
let mentions;
|
|
30642
|
+
let mentions = createMentions(ctx, void 0, cwd);
|
|
30643
|
+
/** Explicit model pick made before any session exists (a bare launch). */
|
|
30644
|
+
let pendingSelection;
|
|
30097
30645
|
if (!lazy) {
|
|
30098
30646
|
const prepared = await prepare(await resolveTarget(startup, persistence, cwd));
|
|
30099
30647
|
active = prepared;
|
|
@@ -30127,6 +30675,20 @@ async function run(ctx, startup, io) {
|
|
|
30127
30675
|
bridge.notify("statusline save failed: " + (writeError instanceof Error ? writeError.message : String(writeError)), "error");
|
|
30128
30676
|
});
|
|
30129
30677
|
};
|
|
30678
|
+
const themePath = join(homedir(), ".dsh", "dsh-code", "theme.json");
|
|
30679
|
+
let themeWarning;
|
|
30680
|
+
if (startup.theme === void 0) try {
|
|
30681
|
+
setTheme(parseThemeName(JSON.parse(readFileSync(themePath, "utf8")).theme));
|
|
30682
|
+
} catch (error) {
|
|
30683
|
+
if (error.code !== "ENOENT") themeWarning = error instanceof Error ? error.message : String(error);
|
|
30684
|
+
}
|
|
30685
|
+
else setTheme(startup.theme);
|
|
30686
|
+
const saveTheme = (name) => {
|
|
30687
|
+
setTheme(name);
|
|
30688
|
+
mkdir(dirname(themePath), { recursive: true }).then(() => writeFile(themePath, JSON.stringify({ theme: name }, null, 2) + "\n", "utf8")).catch((writeError) => {
|
|
30689
|
+
bridge.notify("theme save failed: " + (writeError instanceof Error ? writeError.message : String(writeError)), "error");
|
|
30690
|
+
});
|
|
30691
|
+
};
|
|
30130
30692
|
const historyPath = join(homedir(), ".dsh", "dsh-code", "history.jsonl");
|
|
30131
30693
|
let inputHistory = [];
|
|
30132
30694
|
try {
|
|
@@ -30276,6 +30838,7 @@ async function run(ctx, startup, io) {
|
|
|
30276
30838
|
mentions = next.mentions;
|
|
30277
30839
|
commands.setAgent(agent);
|
|
30278
30840
|
skills.setAgent(agent);
|
|
30841
|
+
process.stdout.write("\x1B[r\x1B[0m\x1B[H\x1B[2J\x1B[3J\x1B[H");
|
|
30279
30842
|
renderCurrent();
|
|
30280
30843
|
const queued = pendingInputs.splice(0);
|
|
30281
30844
|
for (const item of queued) deliverLine(item.text, item.mode);
|
|
@@ -30347,13 +30910,16 @@ async function run(ctx, startup, io) {
|
|
|
30347
30910
|
return "";
|
|
30348
30911
|
}
|
|
30349
30912
|
};
|
|
30350
|
-
/**
|
|
30351
|
-
|
|
30352
|
-
|
|
30353
|
-
|
|
30354
|
-
|
|
30355
|
-
|
|
30356
|
-
|
|
30913
|
+
/**
|
|
30914
|
+
* Apply one /model selection: takes effect from the next assembled step.
|
|
30915
|
+
* The optional reasoning effort must be one the row advertises (the picker
|
|
30916
|
+
* only offers those), so an unsupported value cannot reach the request
|
|
30917
|
+
* pipeline; an absent effort restores the model's own default.
|
|
30918
|
+
*/
|
|
30919
|
+
const selectModel = (row, effortId) => {
|
|
30920
|
+
const selection = buildModelSelection(row, effortId);
|
|
30921
|
+
if (active === void 0) pendingSelection = selection;
|
|
30922
|
+
else active.selection.picked = selection;
|
|
30357
30923
|
return `${row.provider}/${row.model}`;
|
|
30358
30924
|
};
|
|
30359
30925
|
/**
|
|
@@ -30438,7 +31004,7 @@ async function run(ctx, startup, io) {
|
|
|
30438
31004
|
agent = previous?.agent;
|
|
30439
31005
|
session = previous?.session;
|
|
30440
31006
|
store = previous === void 0 ? createTranscriptStore() : previous.store;
|
|
30441
|
-
mentions = previous
|
|
31007
|
+
mentions = previous === void 0 ? createMentions(ctx, void 0, cwd) : previous.mentions;
|
|
30442
31008
|
if (agent !== void 0) commands.setAgent(agent);
|
|
30443
31009
|
if (agent !== void 0) skills.setAgent(agent);
|
|
30444
31010
|
await next.handle.dispose();
|
|
@@ -30536,7 +31102,8 @@ async function run(ctx, startup, io) {
|
|
|
30536
31102
|
};
|
|
30537
31103
|
const appElement = () => {
|
|
30538
31104
|
const sessionCwd = session?.header.cwd ?? cwd;
|
|
30539
|
-
const model = store.getView().model !== "" ? store.getView().model : `${defaults.provider}/${defaults.model}`;
|
|
31105
|
+
const model = store.getView().model !== "" ? store.getView().model : pendingSelection !== void 0 ? `${pendingSelection.provider}/${pendingSelection.model}` : `${defaults.provider}/${defaults.model}`;
|
|
31106
|
+
const effort = resolveEffectiveSelection(active?.selection.picked ?? pendingSelection, session?.requestHeader()?.config, defaults).reasoningEffort;
|
|
30540
31107
|
return (0, import_react.createElement)(App, {
|
|
30541
31108
|
key: session?.id ?? "pending",
|
|
30542
31109
|
store,
|
|
@@ -30545,6 +31112,7 @@ async function run(ctx, startup, io) {
|
|
|
30545
31112
|
commands,
|
|
30546
31113
|
skills,
|
|
30547
31114
|
model,
|
|
31115
|
+
effort,
|
|
30548
31116
|
cwd: basename(sessionCwd),
|
|
30549
31117
|
workspaceRoot: sessionCwd,
|
|
30550
31118
|
branch: gitBranch(sessionCwd),
|
|
@@ -30556,7 +31124,7 @@ async function run(ctx, startup, io) {
|
|
|
30556
31124
|
interrupt,
|
|
30557
31125
|
quit,
|
|
30558
31126
|
loadModels: () => loadModelDirectory(ctx),
|
|
30559
|
-
loadMentions:
|
|
31127
|
+
loadMentions: (query, signal) => mentions.candidates(query, signal),
|
|
30560
31128
|
cyclePermission,
|
|
30561
31129
|
selectModel,
|
|
30562
31130
|
exportTranscript,
|
|
@@ -30571,6 +31139,7 @@ async function run(ctx, startup, io) {
|
|
|
30571
31139
|
loadPlugins: () => listPluginRows(ctx),
|
|
30572
31140
|
statusline: statuslineItems,
|
|
30573
31141
|
saveStatusline,
|
|
31142
|
+
saveTheme,
|
|
30574
31143
|
history: inputHistory,
|
|
30575
31144
|
recordHistory,
|
|
30576
31145
|
cancelQueued,
|
|
@@ -30586,6 +31155,9 @@ async function run(ctx, startup, io) {
|
|
|
30586
31155
|
if (statuslineWarning !== void 0) setTimeout(() => {
|
|
30587
31156
|
bridge.notify("statusline config unreadable, using defaults: " + statuslineWarning, "warning");
|
|
30588
31157
|
}, 50);
|
|
31158
|
+
if (themeWarning !== void 0) setTimeout(() => {
|
|
31159
|
+
bridge.notify("theme config unreadable, using dark: " + themeWarning, "warning");
|
|
31160
|
+
}, 50);
|
|
30589
31161
|
}
|
|
30590
31162
|
/**
|
|
30591
31163
|
* Mount the interactive terminal driver.
|
|
@@ -30593,16 +31165,23 @@ async function run(ctx, startup, io) {
|
|
|
30593
31165
|
* @param config - validated startup config resolved from the tuiStartup provider.
|
|
30594
31166
|
*/
|
|
30595
31167
|
function apply(ctx, config) {
|
|
31168
|
+
const theme = config.startup.theme === void 0 ? void 0 : parseThemeName(config.startup.theme);
|
|
30596
31169
|
const startup = config.startup.kind === "resume" && config.startup.sessionId !== void 0 ? {
|
|
30597
31170
|
kind: "resume",
|
|
30598
|
-
sessionId: config.startup.sessionId
|
|
30599
|
-
|
|
31171
|
+
sessionId: config.startup.sessionId,
|
|
31172
|
+
...theme === void 0 ? {} : { theme }
|
|
31173
|
+
} : config.startup.kind === "latest" ? {
|
|
31174
|
+
kind: "latest",
|
|
31175
|
+
...theme === void 0 ? {} : { theme }
|
|
31176
|
+
} : config.startup.kind === "named" && config.startup.sessionId !== void 0 ? {
|
|
30600
31177
|
kind: "named",
|
|
30601
31178
|
sessionId: config.startup.sessionId,
|
|
30602
|
-
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode }
|
|
31179
|
+
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode },
|
|
31180
|
+
...theme === void 0 ? {} : { theme }
|
|
30603
31181
|
} : {
|
|
30604
31182
|
kind: "fresh",
|
|
30605
|
-
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode }
|
|
31183
|
+
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode },
|
|
31184
|
+
...theme === void 0 ? {} : { theme }
|
|
30606
31185
|
};
|
|
30607
31186
|
const exit = ctx.get("appExit");
|
|
30608
31187
|
if (exit === void 0) throw new Error("tui-runner: the launcher must provide ctx.appExit before the tree mounts");
|