dsh-code 0.6.1 → 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 +2 -2
- package/README.md +2 -2
- package/lib/index.mjs +1473 -899
- 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 +28 -0
- 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 -905
- 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 -659
- 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 {
|
|
@@ -25685,16 +25514,6 @@ function renderMarkdown(text, width) {
|
|
|
25685
25514
|
}
|
|
25686
25515
|
//#endregion
|
|
25687
25516
|
//#region src/render/animations.ts
|
|
25688
|
-
/**
|
|
25689
|
-
* Terminal animation frame tables derived from the web design language:
|
|
25690
|
-
* the StateDot "ongoing" pixel chase (3×3 ring, 125ms flat-hold brightness
|
|
25691
|
-
* steps, 1s cycle) becomes the single-cell stepped pulse below and the
|
|
25692
|
-
* full-ring clockwise braille chase in {@link BUSY_CHASE_FRAMES}, and the
|
|
25693
|
-
* streaming caret blink is the Claude-Code convention. Pure functions only —
|
|
25694
|
-
* the Ink layer owns timers and colors.
|
|
25695
|
-
*
|
|
25696
|
-
* @module @deepseek-ai/dsh-code/render/animations
|
|
25697
|
-
*/
|
|
25698
25517
|
/** Single-cell stepped pulse: flat holds mirroring the web's 125ms keyframes. */
|
|
25699
25518
|
const PULSE_FRAMES = [
|
|
25700
25519
|
"█",
|
|
@@ -25733,182 +25552,329 @@ function busyChaseFrame(tick) {
|
|
|
25733
25552
|
function caretVisible(tick) {
|
|
25734
25553
|
return tick % 2 === 0;
|
|
25735
25554
|
}
|
|
25736
|
-
|
|
25737
|
-
|
|
25738
|
-
|
|
25739
|
-
|
|
25740
|
-
|
|
25741
|
-
|
|
25742
|
-
|
|
25743
|
-
|
|
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
|
+
};
|
|
25744
25631
|
/**
|
|
25745
|
-
*
|
|
25746
|
-
*
|
|
25747
|
-
*
|
|
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.
|
|
25748
25637
|
*/
|
|
25749
|
-
function
|
|
25750
|
-
|
|
25751
|
-
|
|
25752
|
-
|
|
25753
|
-
|
|
25754
|
-
|
|
25755
|
-
const outerColumns = compact ? safeColumns : Math.max(1, safeColumns - 1);
|
|
25756
|
-
return {
|
|
25757
|
-
maxHeight,
|
|
25758
|
-
bodyRows: compact ? 0 : maxHeight - 4 - gapRows,
|
|
25759
|
-
gapRows,
|
|
25760
|
-
contentColumns: compact ? Math.max(1, safeColumns - 1) : Math.max(1, outerColumns - 4),
|
|
25761
|
-
outerColumns,
|
|
25762
|
-
compact
|
|
25763
|
-
};
|
|
25764
|
-
}
|
|
25765
|
-
/** Backward-compatible name for the Ctrl+O-specific caller and tests. */
|
|
25766
|
-
function inspectorViewport(columns, rows) {
|
|
25767
|
-
return panelViewport(columns, rows);
|
|
25768
|
-
}
|
|
25769
|
-
/** Clamp a first-visible row to the range representable by one viewport. */
|
|
25770
|
-
function clampScroll(offset, totalRows, visibleRows) {
|
|
25771
|
-
const last = Math.max(0, Math.max(0, Math.floor(totalRows)) - Math.max(0, Math.floor(visibleRows)));
|
|
25772
|
-
return Math.max(0, Math.min(Math.floor(offset), last));
|
|
25773
|
-
}
|
|
25774
|
-
/** Move a viewport by a signed row delta without escaping its content. */
|
|
25775
|
-
function moveScroll(offset, delta, totalRows, visibleRows) {
|
|
25776
|
-
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
|
+
}
|
|
25777
25644
|
}
|
|
25778
|
-
/**
|
|
25779
|
-
|
|
25780
|
-
|
|
25781
|
-
|
|
25782
|
-
|
|
25783
|
-
|
|
25784
|
-
|
|
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";
|
|
25785
25654
|
}
|
|
25786
|
-
/**
|
|
25787
|
-
|
|
25788
|
-
|
|
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";
|
|
25789
25680
|
}
|
|
25790
|
-
/**
|
|
25791
|
-
|
|
25792
|
-
|
|
25793
|
-
|
|
25794
|
-
|
|
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));
|
|
25795
25690
|
}
|
|
25796
|
-
//#endregion
|
|
25797
|
-
//#region src/render/text.ts
|
|
25798
25691
|
/**
|
|
25799
|
-
*
|
|
25800
|
-
*
|
|
25801
|
-
*
|
|
25802
|
-
*
|
|
25803
|
-
* and tabs survive; everything else in C0/C1 plus DEL becomes a visible
|
|
25804
|
-
* `\xNN` escape.
|
|
25805
|
-
*
|
|
25806
|
-
* @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.
|
|
25807
25696
|
*/
|
|
25808
|
-
|
|
25809
|
-
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
|
+
}
|
|
25810
25703
|
/**
|
|
25811
|
-
*
|
|
25812
|
-
*
|
|
25813
|
-
*
|
|
25814
|
-
*
|
|
25815
|
-
*
|
|
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.
|
|
25816
25713
|
*/
|
|
25817
|
-
function
|
|
25818
|
-
|
|
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);
|
|
25819
25719
|
}
|
|
25820
|
-
/**
|
|
25821
|
-
|
|
25822
|
-
|
|
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
|
+
}
|
|
25823
25755
|
}
|
|
25824
|
-
/**
|
|
25825
|
-
function
|
|
25826
|
-
|
|
25827
|
-
|
|
25828
|
-
|
|
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
|
+
];
|
|
25829
25763
|
}
|
|
25830
25764
|
/**
|
|
25831
|
-
*
|
|
25832
|
-
*
|
|
25833
|
-
*
|
|
25834
|
-
*
|
|
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.
|
|
25835
25781
|
*/
|
|
25836
|
-
function
|
|
25837
|
-
const
|
|
25838
|
-
|
|
25839
|
-
|
|
25840
|
-
const
|
|
25841
|
-
|
|
25842
|
-
|
|
25843
|
-
|
|
25844
|
-
|
|
25845
|
-
|
|
25846
|
-
|
|
25847
|
-
|
|
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);
|
|
25848
25794
|
}
|
|
25849
|
-
|
|
25850
|
-
|
|
25851
|
-
|
|
25852
|
-
|
|
25853
|
-
|
|
25854
|
-
|
|
25855
|
-
|
|
25856
|
-
|
|
25857
|
-
|
|
25858
|
-
start: end - 2
|
|
25859
|
-
};
|
|
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];
|
|
25860
25804
|
}
|
|
25861
|
-
|
|
25862
|
-
|
|
25863
|
-
|
|
25864
|
-
|
|
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;
|
|
25865
25826
|
}
|
|
25866
25827
|
/**
|
|
25867
|
-
*
|
|
25868
|
-
*
|
|
25869
|
-
*
|
|
25870
|
-
*
|
|
25871
|
-
* @param
|
|
25872
|
-
* @param
|
|
25873
|
-
* @param
|
|
25874
|
-
* @
|
|
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.
|
|
25875
25837
|
*/
|
|
25876
|
-
function
|
|
25877
|
-
const
|
|
25878
|
-
const
|
|
25879
|
-
|
|
25880
|
-
|
|
25881
|
-
|
|
25882
|
-
|
|
25883
|
-
|
|
25884
|
-
|
|
25885
|
-
|
|
25886
|
-
|
|
25887
|
-
|
|
25888
|
-
|
|
25889
|
-
|
|
25890
|
-
|
|
25891
|
-
|
|
25892
|
-
|
|
25893
|
-
|
|
25894
|
-
|
|
25895
|
-
|
|
25896
|
-
|
|
25897
|
-
|
|
25898
|
-
|
|
25899
|
-
|
|
25900
|
-
|
|
25901
|
-
|
|
25902
|
-
|
|
25903
|
-
|
|
25904
|
-
|
|
25905
|
-
|
|
25906
|
-
|
|
25907
|
-
|
|
25908
|
-
|
|
25909
|
-
|
|
25910
|
-
|
|
25911
|
-
|
|
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);
|
|
25842
|
+
}
|
|
25843
|
+
/**
|
|
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.
|
|
25851
|
+
*/
|
|
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");
|
|
25912
25878
|
}
|
|
25913
25879
|
//#endregion
|
|
25914
25880
|
//#region src/render/status.ts
|
|
@@ -25969,39 +25935,152 @@ function cacheHitPercent(usage) {
|
|
|
25969
25935
|
const STATUS_ITEM_SEPARATOR = " · ";
|
|
25970
25936
|
/** The Codex-style mode cycle hint appended to the permission badge. */
|
|
25971
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
|
+
}
|
|
25972
26032
|
/**
|
|
25973
|
-
* Render
|
|
25974
|
-
*
|
|
25975
|
-
*
|
|
25976
|
-
*
|
|
25977
|
-
*
|
|
25978
|
-
*
|
|
25979
|
-
*
|
|
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.
|
|
25980
26046
|
* @returns tone-split spans for the footer to paint.
|
|
25981
26047
|
*/
|
|
25982
|
-
function contextBar(
|
|
25983
|
-
|
|
25984
|
-
const
|
|
25985
|
-
const
|
|
25986
|
-
const
|
|
25987
|
-
const
|
|
25988
|
-
|
|
25989
|
-
|
|
25990
|
-
}
|
|
25991
|
-
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
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),
|
|
25997
26079
|
tone: "label"
|
|
25998
26080
|
});
|
|
25999
|
-
spans.push({
|
|
26000
|
-
text:
|
|
26001
|
-
tone:
|
|
26002
|
-
}, {
|
|
26003
|
-
text: percentText,
|
|
26004
|
-
tone
|
|
26081
|
+
if (readout !== "") spans.push({
|
|
26082
|
+
text: readout,
|
|
26083
|
+
tone: readoutTone
|
|
26005
26084
|
});
|
|
26006
26085
|
return spans;
|
|
26007
26086
|
}
|
|
@@ -26185,10 +26264,13 @@ function buildCandidates(facts, stats, busy, enabled) {
|
|
|
26185
26264
|
identity.push(span);
|
|
26186
26265
|
};
|
|
26187
26266
|
const model = safe(facts.model);
|
|
26188
|
-
if (model !== "" && enabled.has("model"))
|
|
26189
|
-
|
|
26190
|
-
|
|
26191
|
-
|
|
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
|
+
}
|
|
26192
26274
|
const cwd = safe(facts.cwd);
|
|
26193
26275
|
if (cwd !== "" && enabled.has("cwd")) push({
|
|
26194
26276
|
text: cwd,
|
|
@@ -26291,7 +26373,7 @@ function buildCandidates(facts, stats, busy, enabled) {
|
|
|
26291
26373
|
group: { spans: [{
|
|
26292
26374
|
text: "context ",
|
|
26293
26375
|
tone: "label"
|
|
26294
|
-
}, ...contextBar(stats.lastPromptTokens
|
|
26376
|
+
}, ...contextBar(stats.contextSegments, stats.lastPromptTokens, stats.contextWindow, 24)] },
|
|
26295
26377
|
rank: RANK2_CONTEXT,
|
|
26296
26378
|
id: "context"
|
|
26297
26379
|
});
|
|
@@ -26595,9 +26677,6 @@ function transcriptEntryLines(entry, columns) {
|
|
|
26595
26677
|
//#endregion
|
|
26596
26678
|
//#region src/kernel-panels.ts
|
|
26597
26679
|
/** Bounded, composer-safe panels for preset, session, and plugin kernel views. */
|
|
26598
|
-
function color(rgb) {
|
|
26599
|
-
return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`;
|
|
26600
|
-
}
|
|
26601
26680
|
function ListFrame(props) {
|
|
26602
26681
|
const stdout = useStdout().stdout;
|
|
26603
26682
|
const viewport = panelViewport(stdout?.columns ?? 80, stdout?.rows ?? 30);
|
|
@@ -26619,11 +26698,11 @@ function ListFrame(props) {
|
|
|
26619
26698
|
return (0, import_react.createElement)(Box, {
|
|
26620
26699
|
width: viewport.outerColumns,
|
|
26621
26700
|
borderStyle: "round",
|
|
26622
|
-
borderColor:
|
|
26701
|
+
borderColor: inkColor(getPalette().dim),
|
|
26623
26702
|
flexDirection: "column",
|
|
26624
26703
|
paddingX: 1
|
|
26625
26704
|
}, (0, import_react.createElement)(Text, {
|
|
26626
|
-
color:
|
|
26705
|
+
color: inkColor(getPalette().brandBright),
|
|
26627
26706
|
wrap: "truncate-end"
|
|
26628
26707
|
}, truncateColumns(props.title, viewport.contentColumns)), (0, import_react.createElement)(Text, {
|
|
26629
26708
|
dimColor: true,
|
|
@@ -26633,7 +26712,7 @@ function ListFrame(props) {
|
|
|
26633
26712
|
const selected = !props.loading && props.error === void 0 && props.rows.length > 0 && absolute === props.cursor;
|
|
26634
26713
|
return (0, import_react.createElement)(Text, {
|
|
26635
26714
|
key: row.key,
|
|
26636
|
-
color: selected ?
|
|
26715
|
+
color: selected ? inkColor(getPalette().brandBright) : row.disabled ? inkColor(getPalette().dim) : void 0,
|
|
26637
26716
|
dimColor: row.disabled,
|
|
26638
26717
|
wrap: "truncate-end"
|
|
26639
26718
|
}, truncateColumns(`${selected ? "› " : " "}${row.text}`, viewport.contentColumns));
|
|
@@ -26865,11 +26944,11 @@ function DocumentPanel({ title, text, error, close }) {
|
|
|
26865
26944
|
return (0, import_react.createElement)(Box, {
|
|
26866
26945
|
width: viewport.outerColumns,
|
|
26867
26946
|
borderStyle: "round",
|
|
26868
|
-
borderColor:
|
|
26947
|
+
borderColor: inkColor(getPalette().dim),
|
|
26869
26948
|
flexDirection: "column",
|
|
26870
26949
|
paddingX: 1
|
|
26871
26950
|
}, (0, import_react.createElement)(Text, {
|
|
26872
|
-
color:
|
|
26951
|
+
color: inkColor(getPalette().brandBright),
|
|
26873
26952
|
wrap: "truncate-end"
|
|
26874
26953
|
}, truncateColumns(title, viewport.contentColumns)), ...body.map((line, index) => (0, import_react.createElement)(Text, {
|
|
26875
26954
|
key: `${scroll}-${index}`,
|
|
@@ -26921,11 +27000,11 @@ function HistoryPanel({ entries, fill, close }) {
|
|
|
26921
27000
|
return (0, import_react.createElement)(Box, {
|
|
26922
27001
|
width: viewport.outerColumns,
|
|
26923
27002
|
borderStyle: "round",
|
|
26924
|
-
borderColor:
|
|
27003
|
+
borderColor: inkColor(getPalette().dim),
|
|
26925
27004
|
flexDirection: "column",
|
|
26926
27005
|
paddingX: 1
|
|
26927
27006
|
}, (0, import_react.createElement)(Text, {
|
|
26928
|
-
color:
|
|
27007
|
+
color: inkColor(getPalette().brandBright),
|
|
26929
27008
|
wrap: "truncate-end"
|
|
26930
27009
|
}, truncateColumns(header, viewport.contentColumns)), (0, import_react.createElement)(Text, {
|
|
26931
27010
|
dimColor: true,
|
|
@@ -26939,7 +27018,7 @@ function HistoryPanel({ entries, fill, close }) {
|
|
|
26939
27018
|
const selected = absolute === cursor;
|
|
26940
27019
|
return (0, import_react.createElement)(Text, {
|
|
26941
27020
|
key: `history-${absolute}`,
|
|
26942
|
-
color: selected ?
|
|
27021
|
+
color: selected ? inkColor(getPalette().brandBright) : void 0,
|
|
26943
27022
|
wrap: "truncate-end"
|
|
26944
27023
|
}, truncateColumns((selected ? "› " : " ") + displayText(entry), viewport.contentColumns));
|
|
26945
27024
|
}), (0, import_react.createElement)(Text, {
|
|
@@ -27007,18 +27086,18 @@ function StatuslinePanel({ enabled, change, close }) {
|
|
|
27007
27086
|
return (0, import_react.createElement)(Box, {
|
|
27008
27087
|
width: viewport.outerColumns,
|
|
27009
27088
|
borderStyle: "round",
|
|
27010
|
-
borderColor:
|
|
27089
|
+
borderColor: inkColor(getPalette().dim),
|
|
27011
27090
|
flexDirection: "column",
|
|
27012
27091
|
paddingX: 1
|
|
27013
27092
|
}, (0, import_react.createElement)(Text, {
|
|
27014
|
-
color:
|
|
27093
|
+
color: inkColor(getPalette().brandBright),
|
|
27015
27094
|
wrap: "truncate-end"
|
|
27016
27095
|
}, truncateColumns("/statusline · items apply to the live status line below", viewport.contentColumns)), ...visible.map((id, index) => {
|
|
27017
27096
|
const selected = offset + index === cursor;
|
|
27018
27097
|
const info = meta.get(id);
|
|
27019
27098
|
return (0, import_react.createElement)(Text, {
|
|
27020
27099
|
key: id,
|
|
27021
|
-
color: selected ?
|
|
27100
|
+
color: selected ? inkColor(getPalette().brandBright) : void 0,
|
|
27022
27101
|
dimColor: !on.has(id) || void 0,
|
|
27023
27102
|
wrap: "truncate-end"
|
|
27024
27103
|
}, truncateColumns((selected ? "› " : " ") + (on.has(id) ? "● " : "○ ") + (info?.label ?? id) + (info === void 0 ? "" : " · " + info.description + " · " + info.side), viewport.contentColumns));
|
|
@@ -27027,6 +27106,56 @@ function StatuslinePanel({ enabled, change, close }) {
|
|
|
27027
27106
|
wrap: "truncate-end"
|
|
27028
27107
|
}, truncateColumns("↑↓ move · space toggle · ←→ reorder · d default · esc close", viewport.contentColumns)));
|
|
27029
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
|
+
}
|
|
27030
27159
|
/** Encode one entry for the history file (JSON keeps multi-line drafts intact). */
|
|
27031
27160
|
function serializeHistoryEntry(text) {
|
|
27032
27161
|
return JSON.stringify(text);
|
|
@@ -27176,10 +27305,6 @@ function recallNewer(state) {
|
|
|
27176
27305
|
const RESIZE_REFLOW_DELAY_MS = 75;
|
|
27177
27306
|
/** Reset region/style, clear the visible screen and scrollback, then home. */
|
|
27178
27307
|
const RESIZE_REFLOW_CLEAR = "\x1B[r\x1B[0m\x1B[H\x1B[2J\x1B[3J\x1B[H";
|
|
27179
|
-
/** Ink `color` string for one palette triple. */
|
|
27180
|
-
function inkColor(triple) {
|
|
27181
|
-
return `rgb(${triple[0]}, ${triple[1]}, ${triple[2]})`;
|
|
27182
|
-
}
|
|
27183
27308
|
/** Pad text with spaces to a visible-column target (menu name column). */
|
|
27184
27309
|
function padColumns(text, width) {
|
|
27185
27310
|
const clipped = truncateColumns(singleLineText(text), width);
|
|
@@ -27213,7 +27338,7 @@ function useStableInput(handler, active) {
|
|
|
27213
27338
|
/** Single-cell stepped pulse: the web's 125ms flat-hold brightness steps over 1s. */
|
|
27214
27339
|
function Pulse() {
|
|
27215
27340
|
const tick = useFrames(125);
|
|
27216
|
-
return (0, import_react.createElement)(Text, { color: inkColor(
|
|
27341
|
+
return (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, pulseFrame(tick));
|
|
27217
27342
|
}
|
|
27218
27343
|
/**
|
|
27219
27344
|
* The web StateDot "ongoing" chase in terminal form: three cells of the 3×3
|
|
@@ -27223,7 +27348,7 @@ function Pulse() {
|
|
|
27223
27348
|
*/
|
|
27224
27349
|
function BusyChase() {
|
|
27225
27350
|
const tick = useFrames(125);
|
|
27226
|
-
return (0, import_react.createElement)(Text, { color: inkColor(
|
|
27351
|
+
return (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, busyChaseFrame(tick) + " ");
|
|
27227
27352
|
}
|
|
27228
27353
|
/** Blinking block caret appended to streaming text. */
|
|
27229
27354
|
function Caret() {
|
|
@@ -27273,19 +27398,19 @@ function StreamTail({ text, dim, maxRows, prefix, children }) {
|
|
|
27273
27398
|
function segmentProps(style) {
|
|
27274
27399
|
switch (style) {
|
|
27275
27400
|
case "accent": return {
|
|
27276
|
-
color: inkColor(
|
|
27401
|
+
color: inkColor(getPalette().brandBright),
|
|
27277
27402
|
bold: void 0,
|
|
27278
27403
|
italic: void 0,
|
|
27279
27404
|
strikethrough: void 0
|
|
27280
27405
|
};
|
|
27281
27406
|
case "code": return {
|
|
27282
|
-
color: inkColor(
|
|
27407
|
+
color: inkColor(getPalette().code),
|
|
27283
27408
|
bold: void 0,
|
|
27284
27409
|
italic: void 0,
|
|
27285
27410
|
strikethrough: void 0
|
|
27286
27411
|
};
|
|
27287
27412
|
case "dim": return {
|
|
27288
|
-
color: inkColor(
|
|
27413
|
+
color: inkColor(getPalette().dim),
|
|
27289
27414
|
bold: void 0,
|
|
27290
27415
|
italic: void 0,
|
|
27291
27416
|
strikethrough: void 0
|
|
@@ -27309,7 +27434,7 @@ function segmentProps(style) {
|
|
|
27309
27434
|
strikethrough: void 0
|
|
27310
27435
|
};
|
|
27311
27436
|
case "strike": return {
|
|
27312
|
-
color: inkColor(
|
|
27437
|
+
color: inkColor(getPalette().dim),
|
|
27313
27438
|
bold: void 0,
|
|
27314
27439
|
italic: void 0,
|
|
27315
27440
|
strikethrough: true
|
|
@@ -27326,28 +27451,28 @@ function segmentProps(style) {
|
|
|
27326
27451
|
function lineStyleProps(style) {
|
|
27327
27452
|
switch (style) {
|
|
27328
27453
|
case "brand": return {
|
|
27329
|
-
color: inkColor(
|
|
27454
|
+
color: inkColor(getPalette().brandBright),
|
|
27330
27455
|
bold: void 0,
|
|
27331
27456
|
italic: void 0,
|
|
27332
27457
|
strikethrough: void 0,
|
|
27333
27458
|
dimColor: void 0
|
|
27334
27459
|
};
|
|
27335
27460
|
case "success": return {
|
|
27336
|
-
color: inkColor(
|
|
27461
|
+
color: inkColor(getPalette().success),
|
|
27337
27462
|
bold: void 0,
|
|
27338
27463
|
italic: void 0,
|
|
27339
27464
|
strikethrough: void 0,
|
|
27340
27465
|
dimColor: void 0
|
|
27341
27466
|
};
|
|
27342
27467
|
case "error": return {
|
|
27343
|
-
color: inkColor(
|
|
27468
|
+
color: inkColor(getPalette().error),
|
|
27344
27469
|
bold: void 0,
|
|
27345
27470
|
italic: void 0,
|
|
27346
27471
|
strikethrough: void 0,
|
|
27347
27472
|
dimColor: void 0
|
|
27348
27473
|
};
|
|
27349
27474
|
case "warn": return {
|
|
27350
|
-
color: inkColor(
|
|
27475
|
+
color: inkColor(getPalette().warn),
|
|
27351
27476
|
bold: void 0,
|
|
27352
27477
|
italic: void 0,
|
|
27353
27478
|
strikethrough: void 0,
|
|
@@ -27412,7 +27537,7 @@ function ToolDetailBody({ detail }) {
|
|
|
27412
27537
|
wrap: "truncate-end"
|
|
27413
27538
|
}, ` ── ${displayText(diff.path)}${diff.truncated ? " (diff truncated)" : ""}`), ...diff.lines.map((line, at) => (0, import_react.createElement)(Text, {
|
|
27414
27539
|
key: at,
|
|
27415
|
-
color: line.mark === "+" ? inkColor(
|
|
27540
|
+
color: line.mark === "+" ? inkColor(getPalette().success) : line.mark === "-" ? inkColor(getPalette().error) : inkColor(getPalette().dim),
|
|
27416
27541
|
wrap: "truncate-end"
|
|
27417
27542
|
}, ` ${line.mark}${displayText(line.text)}`)))));
|
|
27418
27543
|
case "read": return (0, import_react.createElement)(Box, { flexDirection: "column" }, (0, import_react.createElement)(Text, {
|
|
@@ -27451,16 +27576,16 @@ function EntryLine({ entry, showReasoning, verbose }) {
|
|
|
27451
27576
|
indent: 2
|
|
27452
27577
|
}));
|
|
27453
27578
|
case "tool": {
|
|
27454
|
-
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) }, "⏺");
|
|
27455
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, {
|
|
27456
|
-
color: entry.state === "error" ? inkColor(
|
|
27581
|
+
color: entry.state === "error" ? inkColor(getPalette().error) : inkColor(getPalette().dim),
|
|
27457
27582
|
wrap: verbose ? "truncate-end" : void 0
|
|
27458
27583
|
}, ` ⎿ ${displayText(entry.summary)}`), verbose && entry.detail !== void 0 ? (0, import_react.createElement)(ToolDetailBody, { detail: entry.detail }) : void 0);
|
|
27459
27584
|
}
|
|
27460
27585
|
case "command": {
|
|
27461
|
-
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) }, "⏺");
|
|
27462
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, {
|
|
27463
|
-
color: inkColor(
|
|
27588
|
+
color: inkColor(getPalette().dim),
|
|
27464
27589
|
wrap: verbose ? "truncate-end" : void 0
|
|
27465
27590
|
}, ` ⎿ ${displayText(entry.summary)}`));
|
|
27466
27591
|
}
|
|
@@ -27473,7 +27598,7 @@ function EntryLine({ entry, showReasoning, verbose }) {
|
|
|
27473
27598
|
wrap: verbose ? "truncate-end" : void 0
|
|
27474
27599
|
}, entry.ok ? ` ⧉ compacted ~${formatTokens(entry.tokens)} tokens` : ` ⧉ compaction failed: ${displayText(entry.error)}`);
|
|
27475
27600
|
case "retry": return (0, import_react.createElement)(Text, {
|
|
27476
|
-
color: entry.state === "running" ? inkColor(
|
|
27601
|
+
color: entry.state === "running" ? inkColor(getPalette().warn) : inkColor(getPalette().dim),
|
|
27477
27602
|
wrap: verbose ? "truncate-end" : void 0
|
|
27478
27603
|
}, ` ↻ retry ${entry.attempt}/${entry.max} · ${displayText(entry.code)} · ${Math.round(entry.delayMs / 100) / 10}s`);
|
|
27479
27604
|
case "files": {
|
|
@@ -27503,18 +27628,18 @@ function Header({ resumed }) {
|
|
|
27503
27628
|
flexDirection: "row",
|
|
27504
27629
|
gap: 1,
|
|
27505
27630
|
borderStyle: "round",
|
|
27506
|
-
borderColor: inkColor(
|
|
27631
|
+
borderColor: inkColor(getPalette().brand),
|
|
27507
27632
|
paddingX: 1,
|
|
27508
27633
|
alignSelf: "flex-start"
|
|
27509
27634
|
}, (0, import_react.createElement)(Text, {
|
|
27510
|
-
color: inkColor(
|
|
27635
|
+
color: inkColor(getPalette().brandBright),
|
|
27511
27636
|
bold: true
|
|
27512
27637
|
}, "DeepSeek Harness"), (0, import_react.createElement)(Text, { dimColor: true }, hint));
|
|
27513
27638
|
return (0, import_react.createElement)(Box, {
|
|
27514
27639
|
flexDirection: "row",
|
|
27515
27640
|
gap: 2,
|
|
27516
27641
|
borderStyle: "round",
|
|
27517
|
-
borderColor: inkColor(
|
|
27642
|
+
borderColor: inkColor(getPalette().brand),
|
|
27518
27643
|
paddingX: 1,
|
|
27519
27644
|
alignSelf: "flex-start"
|
|
27520
27645
|
}, (0, import_react.createElement)(Box, {
|
|
@@ -27523,12 +27648,12 @@ function Header({ resumed }) {
|
|
|
27523
27648
|
justifyContent: "center"
|
|
27524
27649
|
}, ...WHALE_GLYPH.map((row, index) => (0, import_react.createElement)(Text, {
|
|
27525
27650
|
key: index,
|
|
27526
|
-
color: inkColor(
|
|
27651
|
+
color: inkColor(getPalette().brand)
|
|
27527
27652
|
}, row))), (0, import_react.createElement)(Box, {
|
|
27528
27653
|
flexDirection: "column",
|
|
27529
27654
|
justifyContent: "center"
|
|
27530
27655
|
}, (0, import_react.createElement)(Text, {
|
|
27531
|
-
color: inkColor(
|
|
27656
|
+
color: inkColor(getPalette().brandBright),
|
|
27532
27657
|
bold: true
|
|
27533
27658
|
}, "DeepSeek Harness"), (0, import_react.createElement)(Text, { dimColor: true }, hint)));
|
|
27534
27659
|
}
|
|
@@ -27544,74 +27669,99 @@ function TodoPanel({ todos }) {
|
|
|
27544
27669
|
const pending = todos.length - completed - inProgress;
|
|
27545
27670
|
const current = todos.find((todo) => todo.status === "in_progress");
|
|
27546
27671
|
return (0, import_react.createElement)(Box, { paddingX: 1 }, (0, import_react.createElement)(Text, {
|
|
27547
|
-
color: inkColor(
|
|
27672
|
+
color: inkColor(getPalette().brand),
|
|
27548
27673
|
bold: true,
|
|
27549
27674
|
wrap: "truncate-end"
|
|
27550
|
-
}, `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)}`)));
|
|
27551
27676
|
}
|
|
27552
27677
|
/**
|
|
27553
27678
|
* Ink props for one status tone: the Codex status-line accent mapping over
|
|
27554
27679
|
* the DeepSeek palette, all blue by design — the status bar speaks only in
|
|
27555
|
-
* degrees of blue (deep accent, primary figures,
|
|
27680
|
+
* degrees of blue (deep accent, primary figures, model identity, sky
|
|
27556
27681
|
* paths and done states), with amber/red reserved for warnings and errors.
|
|
27557
27682
|
*/
|
|
27558
27683
|
function statusToneProps(tone) {
|
|
27559
27684
|
switch (tone) {
|
|
27560
27685
|
case "model": return {
|
|
27561
|
-
color: inkColor(
|
|
27686
|
+
color: inkColor(getPalette().code),
|
|
27562
27687
|
bold: true,
|
|
27563
27688
|
dimColor: void 0
|
|
27564
27689
|
};
|
|
27565
27690
|
case "live": return {
|
|
27566
|
-
color: inkColor(
|
|
27691
|
+
color: inkColor(getPalette().brandBright),
|
|
27567
27692
|
bold: void 0,
|
|
27568
27693
|
dimColor: void 0
|
|
27569
27694
|
};
|
|
27570
27695
|
case "path": return {
|
|
27571
|
-
color: inkColor(
|
|
27696
|
+
color: inkColor(getPalette().code),
|
|
27572
27697
|
bold: void 0,
|
|
27573
27698
|
dimColor: void 0
|
|
27574
27699
|
};
|
|
27575
27700
|
case "branch": return {
|
|
27576
|
-
color: inkColor(
|
|
27701
|
+
color: inkColor(getPalette().text),
|
|
27577
27702
|
bold: void 0,
|
|
27578
27703
|
dimColor: void 0
|
|
27579
27704
|
};
|
|
27580
27705
|
case "value": return {
|
|
27581
|
-
color: inkColor(
|
|
27706
|
+
color: inkColor(getPalette().brand),
|
|
27582
27707
|
bold: void 0,
|
|
27583
27708
|
dimColor: void 0
|
|
27584
27709
|
};
|
|
27585
27710
|
case "label":
|
|
27586
27711
|
case "meta": return {
|
|
27587
|
-
color:
|
|
27712
|
+
color: inkColor(getPalette().dim),
|
|
27588
27713
|
bold: void 0,
|
|
27589
|
-
dimColor:
|
|
27714
|
+
dimColor: void 0
|
|
27590
27715
|
};
|
|
27591
27716
|
case "accent": return {
|
|
27592
|
-
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),
|
|
27593
27743
|
bold: void 0,
|
|
27594
27744
|
dimColor: void 0
|
|
27595
27745
|
};
|
|
27596
27746
|
case "success": return {
|
|
27597
|
-
color: inkColor(
|
|
27747
|
+
color: inkColor(getPalette().code),
|
|
27598
27748
|
bold: true,
|
|
27599
27749
|
dimColor: void 0
|
|
27600
27750
|
};
|
|
27601
27751
|
case "warn": return {
|
|
27602
|
-
color: inkColor(
|
|
27752
|
+
color: inkColor(getPalette().warn),
|
|
27603
27753
|
bold: true,
|
|
27604
27754
|
dimColor: void 0
|
|
27605
27755
|
};
|
|
27606
27756
|
case "error": return {
|
|
27607
|
-
color: inkColor(
|
|
27757
|
+
color: inkColor(getPalette().error),
|
|
27608
27758
|
bold: true,
|
|
27609
27759
|
dimColor: void 0
|
|
27610
27760
|
};
|
|
27611
27761
|
default: return {
|
|
27612
|
-
color:
|
|
27762
|
+
color: inkColor(getPalette().dim),
|
|
27613
27763
|
bold: void 0,
|
|
27614
|
-
dimColor:
|
|
27764
|
+
dimColor: void 0
|
|
27615
27765
|
};
|
|
27616
27766
|
}
|
|
27617
27767
|
}
|
|
@@ -27624,7 +27774,32 @@ function statusToneProps(tone) {
|
|
|
27624
27774
|
* content, so the footer degrades to a single row on narrow terminals. Both
|
|
27625
27775
|
* layouts arrive pre-measured from the pure reducer, so Ink only paints;
|
|
27626
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.
|
|
27627
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
|
+
}
|
|
27628
27803
|
function StatusLine({ facts, stats, busy, columns, items }) {
|
|
27629
27804
|
const layout = layoutStatusBar(facts, stats, Math.max(8, columns - 2), {
|
|
27630
27805
|
busy,
|
|
@@ -27635,7 +27810,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27635
27810
|
row.left.forEach((group, groupIndex) => {
|
|
27636
27811
|
if (groupIndex > 0) leftParts.push((0, import_react.createElement)(Text, {
|
|
27637
27812
|
key: key + "gs" + groupIndex,
|
|
27638
|
-
|
|
27813
|
+
color: inkColor(getPalette().dim)
|
|
27639
27814
|
}, " | "));
|
|
27640
27815
|
group.spans.forEach((span, spanIndex) => {
|
|
27641
27816
|
leftParts.push((0, import_react.createElement)(Text, {
|
|
@@ -27649,7 +27824,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27649
27824
|
row.right.forEach((span, index) => {
|
|
27650
27825
|
if (index > 0) rightParts.push((0, import_react.createElement)(Text, {
|
|
27651
27826
|
key: key + "rs" + index,
|
|
27652
|
-
|
|
27827
|
+
color: inkColor(getPalette().dim)
|
|
27653
27828
|
}, STATUS_ITEM_SEPARATOR));
|
|
27654
27829
|
rightParts.push((0, import_react.createElement)(Text, {
|
|
27655
27830
|
key: key + "r" + index,
|
|
@@ -27659,7 +27834,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27659
27834
|
});
|
|
27660
27835
|
if (row.hint) rightParts.push((0, import_react.createElement)(Text, {
|
|
27661
27836
|
key: key + "hint",
|
|
27662
|
-
|
|
27837
|
+
color: inkColor(getPalette().dim)
|
|
27663
27838
|
}, STATUS_CYCLE_HINT));
|
|
27664
27839
|
return (0, import_react.createElement)(Box, {
|
|
27665
27840
|
paddingLeft: 2,
|
|
@@ -27675,7 +27850,7 @@ function StatusLine({ facts, stats, busy, columns, items }) {
|
|
|
27675
27850
|
* above the composer.
|
|
27676
27851
|
*/
|
|
27677
27852
|
function NoticeLine({ text, tone, columns }) {
|
|
27678
|
-
const color = tone === "error" ?
|
|
27853
|
+
const color = tone === "error" ? getPalette().error : tone === "warning" ? getPalette().warn : getPalette().brandBright;
|
|
27679
27854
|
const mark = tone === "error" ? "⨯" : tone === "warning" ? "!" : "•";
|
|
27680
27855
|
return (0, import_react.createElement)(Box, { paddingLeft: 2 }, (0, import_react.createElement)(Text, {
|
|
27681
27856
|
color: inkColor(color),
|
|
@@ -27731,9 +27906,9 @@ function ApprovalBar({ snapshot, locked }) {
|
|
|
27731
27906
|
width: viewport.outerColumns,
|
|
27732
27907
|
paddingX: 1,
|
|
27733
27908
|
borderStyle: "round",
|
|
27734
|
-
borderColor: inkColor(
|
|
27909
|
+
borderColor: inkColor(getPalette().warn)
|
|
27735
27910
|
}, (0, import_react.createElement)(Text, {
|
|
27736
|
-
color: inkColor(
|
|
27911
|
+
color: inkColor(getPalette().warn),
|
|
27737
27912
|
bold: true,
|
|
27738
27913
|
wrap: "truncate-end"
|
|
27739
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, {
|
|
@@ -27974,9 +28149,9 @@ function QuestionBar({ store, snapshot, locked }) {
|
|
|
27974
28149
|
width: viewport.outerColumns,
|
|
27975
28150
|
paddingX: 1,
|
|
27976
28151
|
borderStyle: "round",
|
|
27977
|
-
borderColor: inkColor(isPlan ?
|
|
28152
|
+
borderColor: inkColor(isPlan ? getPalette().brand : getPalette().brandDeep)
|
|
27978
28153
|
}, (0, import_react.createElement)(Text, {
|
|
27979
|
-
color: inkColor(isPlan ?
|
|
28154
|
+
color: inkColor(isPlan ? getPalette().brand : getPalette().brandDeep),
|
|
27980
28155
|
bold: true,
|
|
27981
28156
|
wrap: "truncate-end"
|
|
27982
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, {
|
|
@@ -28041,11 +28216,11 @@ function ModelPanel({ directory, error, onSelect, onRetry, onClose }) {
|
|
|
28041
28216
|
wrap: "truncate-end"
|
|
28042
28217
|
}, " loading models…")] : error !== void 0 ? [(0, import_react.createElement)(Text, {
|
|
28043
28218
|
key: "error",
|
|
28044
|
-
color: inkColor(
|
|
28219
|
+
color: inkColor(getPalette().error),
|
|
28045
28220
|
wrap: "truncate-end"
|
|
28046
28221
|
}, truncateColumns(` ${singleLineText(error)}`, viewport.contentColumns))] : [...directory?.failures.length === 0 ? [] : [(0, import_react.createElement)(Text, {
|
|
28047
28222
|
key: "failures",
|
|
28048
|
-
color: inkColor(
|
|
28223
|
+
color: inkColor(getPalette().warn),
|
|
28049
28224
|
wrap: "truncate-end"
|
|
28050
28225
|
}, truncateColumns(` unavailable providers: ${directory?.failures.join(", ")}`, viewport.contentColumns))], ...rows.length === 0 ? [(0, import_react.createElement)(Text, {
|
|
28051
28226
|
key: "empty",
|
|
@@ -28060,9 +28235,9 @@ function ModelPanel({ directory, error, onSelect, onRetry, onClose }) {
|
|
|
28060
28235
|
width: viewport.outerColumns,
|
|
28061
28236
|
paddingX: 1,
|
|
28062
28237
|
borderStyle: "round",
|
|
28063
|
-
borderColor: inkColor(
|
|
28238
|
+
borderColor: inkColor(getPalette().brand)
|
|
28064
28239
|
}, (0, import_react.createElement)(Text, {
|
|
28065
|
-
color: inkColor(
|
|
28240
|
+
color: inkColor(getPalette().brand),
|
|
28066
28241
|
bold: true,
|
|
28067
28242
|
wrap: "truncate-end"
|
|
28068
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) => {
|
|
@@ -28070,7 +28245,7 @@ function ModelPanel({ directory, error, onSelect, onRetry, onClose }) {
|
|
|
28070
28245
|
const label = displayText(`${row.providerName} · ${row.modelName}`);
|
|
28071
28246
|
return (0, import_react.createElement)(Text, {
|
|
28072
28247
|
key: `${row.provider}/${row.model}`,
|
|
28073
|
-
color: index === cursor ? inkColor(
|
|
28248
|
+
color: index === cursor ? inkColor(getPalette().brandBright) : inkColor(getPalette().dim),
|
|
28074
28249
|
wrap: "truncate-end"
|
|
28075
28250
|
}, truncateColumns(`${index === cursor ? "❯ " : " "}${label}`, viewport.contentColumns));
|
|
28076
28251
|
}), (0, import_react.createElement)(PanelGap, { visible: viewport.gapRows > 0 }), (0, import_react.createElement)(Text, {
|
|
@@ -28137,16 +28312,18 @@ function HelpPanel({ descriptors, skills, commandError, skillError, onClose }) {
|
|
|
28137
28312
|
}, " commands"),
|
|
28138
28313
|
...commandError === void 0 ? [] : [(0, import_react.createElement)(Text, {
|
|
28139
28314
|
key: "commands-error",
|
|
28140
|
-
color: inkColor(
|
|
28315
|
+
color: inkColor(getPalette().error),
|
|
28141
28316
|
wrap: "truncate-end"
|
|
28142
28317
|
}, truncateColumns(` command catalog unavailable: ${singleLineText(commandError)}`, viewport.contentColumns))],
|
|
28143
28318
|
(0, import_react.createElement)(Box, { key: "local-help" }, row("/help", "show this overlay")),
|
|
28144
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")),
|
|
28145
28321
|
(0, import_react.createElement)(Box, { key: "local-mode" }, row("/mode", "inspect or select the agent preset (/mode [preset])")),
|
|
28146
28322
|
(0, import_react.createElement)(Box, { key: "local-new" }, row("/new", "create and switch to a fresh session (/new [preset])")),
|
|
28147
28323
|
(0, import_react.createElement)(Box, { key: "local-resume" }, row("/resume", "browse or switch root sessions (/resume [id|prefix])")),
|
|
28148
28324
|
(0, import_react.createElement)(Box, { key: "local-plugin" }, row("/plugin", "inspect the live plugin composition")),
|
|
28149
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")),
|
|
28150
28327
|
(0, import_react.createElement)(Box, { key: "local-history" }, row("/history", "search and recall past prompts")),
|
|
28151
28328
|
(0, import_react.createElement)(Box, { key: "local-clear" }, row("/clear", "clear the screen")),
|
|
28152
28329
|
(0, import_react.createElement)(Box, { key: "local-export" }, row("/export", "export the transcript to markdown (/export [path])")),
|
|
@@ -28164,7 +28341,7 @@ function HelpPanel({ descriptors, skills, commandError, skillError, onClose }) {
|
|
|
28164
28341
|
}, " skills")],
|
|
28165
28342
|
...skillError === void 0 ? [] : [(0, import_react.createElement)(Text, {
|
|
28166
28343
|
key: "skills-error",
|
|
28167
|
-
color: inkColor(
|
|
28344
|
+
color: inkColor(getPalette().error),
|
|
28168
28345
|
wrap: "truncate-end"
|
|
28169
28346
|
}, truncateColumns(` skill catalog unavailable: ${singleLineText(skillError)}`, viewport.contentColumns))],
|
|
28170
28347
|
...skills.map((skill) => (0, import_react.createElement)(Text, {
|
|
@@ -28199,9 +28376,9 @@ function HelpPanel({ descriptors, skills, commandError, skillError, onClose }) {
|
|
|
28199
28376
|
width: viewport.outerColumns,
|
|
28200
28377
|
paddingX: 1,
|
|
28201
28378
|
borderStyle: "round",
|
|
28202
|
-
borderColor: inkColor(
|
|
28379
|
+
borderColor: inkColor(getPalette().brand)
|
|
28203
28380
|
}, (0, import_react.createElement)(Text, {
|
|
28204
|
-
color: inkColor(
|
|
28381
|
+
color: inkColor(getPalette().brand),
|
|
28205
28382
|
bold: true,
|
|
28206
28383
|
wrap: "truncate-end"
|
|
28207
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, {
|
|
@@ -28228,6 +28405,38 @@ function editorWindow(value, cursor, columns) {
|
|
|
28228
28405
|
after: afterBudget === 0 ? "" : truncateColumns(normalize(value.slice(cursor + 1)), afterBudget)
|
|
28229
28406
|
};
|
|
28230
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
|
+
}
|
|
28231
28440
|
/**
|
|
28232
28441
|
* The Ctrl+O transcript inspector: one selected durable entry at a time,
|
|
28233
28442
|
* with independent history selection and content scrolling. The complete
|
|
@@ -28324,9 +28533,9 @@ function VerbosePanel({ entries, onClose }) {
|
|
|
28324
28533
|
width: viewport.outerColumns,
|
|
28325
28534
|
paddingX: 1,
|
|
28326
28535
|
borderStyle: "round",
|
|
28327
|
-
borderColor: inkColor(
|
|
28536
|
+
borderColor: inkColor(getPalette().brand)
|
|
28328
28537
|
}, (0, import_react.createElement)(Text, {
|
|
28329
|
-
color: inkColor(
|
|
28538
|
+
color: inkColor(getPalette().brand),
|
|
28330
28539
|
bold: true,
|
|
28331
28540
|
wrap: "truncate-end"
|
|
28332
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, {
|
|
@@ -28351,7 +28560,12 @@ const MemoStaticTranscript = (0, import_react.memo)(StaticTranscript);
|
|
|
28351
28560
|
* Resolve completion candidates for the current input: TUI-local commands,
|
|
28352
28561
|
* the live registry descriptors, and user-invocable skills, filtered by the
|
|
28353
28562
|
* typed prefix. Command names win collisions (the dispatch tries the
|
|
28354
|
-
* 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.
|
|
28355
28569
|
*/
|
|
28356
28570
|
function completionCandidates(value, descriptors, skills) {
|
|
28357
28571
|
if (!value.startsWith("/")) return [];
|
|
@@ -28367,6 +28581,11 @@ function completionCandidates(value, descriptors, skills) {
|
|
|
28367
28581
|
description: "switch the model",
|
|
28368
28582
|
origin: "command"
|
|
28369
28583
|
},
|
|
28584
|
+
{
|
|
28585
|
+
label: "/effort",
|
|
28586
|
+
description: "adjust reasoning effort for the current model",
|
|
28587
|
+
origin: "command"
|
|
28588
|
+
},
|
|
28370
28589
|
{
|
|
28371
28590
|
label: "/mode",
|
|
28372
28591
|
description: "select the agent preset",
|
|
@@ -28392,6 +28611,11 @@ function completionCandidates(value, descriptors, skills) {
|
|
|
28392
28611
|
description: "customize the status line",
|
|
28393
28612
|
origin: "command"
|
|
28394
28613
|
},
|
|
28614
|
+
{
|
|
28615
|
+
label: "/theme",
|
|
28616
|
+
description: "switch the color theme",
|
|
28617
|
+
origin: "command"
|
|
28618
|
+
},
|
|
28395
28619
|
{
|
|
28396
28620
|
label: "/history",
|
|
28397
28621
|
description: "search and recall past prompts",
|
|
@@ -28430,13 +28654,20 @@ function completionCandidates(value, descriptors, skills) {
|
|
|
28430
28654
|
description: skill.modelInvocable ? `skill · ${skill.description}` : `skill (user only) · ${skill.description}`,
|
|
28431
28655
|
origin: "skill"
|
|
28432
28656
|
}));
|
|
28433
|
-
const
|
|
28657
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28658
|
+
const all = [];
|
|
28659
|
+
for (const candidate of [
|
|
28434
28660
|
...local,
|
|
28435
28661
|
...registry,
|
|
28436
28662
|
...skillRows
|
|
28437
|
-
]
|
|
28438
|
-
|
|
28439
|
-
|
|
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));
|
|
28440
28671
|
}
|
|
28441
28672
|
/**
|
|
28442
28673
|
* The completion menu, rendered inside the composer's subtree directly above
|
|
@@ -28461,6 +28692,7 @@ function CompletionMenu({ active, mention, index, rows }) {
|
|
|
28461
28692
|
const selected = rows.length === 0 ? 0 : index % rows.length;
|
|
28462
28693
|
const first = selectionWindow(selected, rows.length, limit);
|
|
28463
28694
|
const visible = rows.slice(first, first + limit);
|
|
28695
|
+
const hidden = rows.length - visible.length;
|
|
28464
28696
|
return (0, import_react.createElement)(Box, {
|
|
28465
28697
|
flexDirection: "column",
|
|
28466
28698
|
marginLeft: 2,
|
|
@@ -28472,13 +28704,17 @@ function CompletionMenu({ active, mention, index, rows }) {
|
|
|
28472
28704
|
const absolute = first + at;
|
|
28473
28705
|
return (0, import_react.createElement)(Text, {
|
|
28474
28706
|
key: candidate.label,
|
|
28475
|
-
color: absolute === selected ? inkColor(
|
|
28707
|
+
color: absolute === selected ? inkColor(getPalette().brandBright) : inkColor(getPalette().dim),
|
|
28476
28708
|
wrap: "truncate-end"
|
|
28477
28709
|
}, `${absolute === selected ? "❯ " : " "}${padColumns(candidate.label, nameWidth)}${dim(truncateColumns(displayText(candidate.description), descBudget))}`);
|
|
28478
|
-
}),
|
|
28479
|
-
|
|
28710
|
+
}), hidden > 0 ? (0, import_react.createElement)(Text, {
|
|
28711
|
+
key: "more",
|
|
28712
|
+
color: inkColor(getPalette().dim),
|
|
28713
|
+
wrap: "truncate-end"
|
|
28714
|
+
}, dim(` … +${hidden} more`)) : void 0, showFooter ? (0, import_react.createElement)(Text, {
|
|
28715
|
+
color: inkColor(getPalette().dim),
|
|
28480
28716
|
wrap: "truncate-end"
|
|
28481
|
-
}, dim(mention ?
|
|
28717
|
+
}, dim(mention ? `↑↓ choose · ${rows.length} items · tab insert` : `↑↓ choose · ${rows.length} items · tab complete`)) : void 0);
|
|
28482
28718
|
}
|
|
28483
28719
|
/**
|
|
28484
28720
|
* The prompt box: TUI-local slash commands handled locally, other lines
|
|
@@ -28486,7 +28722,7 @@ function CompletionMenu({ active, mention, index, rows }) {
|
|
|
28486
28722
|
* While a modal (approval / question / model panel) owns the keys, the
|
|
28487
28723
|
* box passes every key through untouched.
|
|
28488
28724
|
*/
|
|
28489
|
-
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 }) {
|
|
28490
28726
|
const columns = useStdout().stdout?.columns ?? 80;
|
|
28491
28727
|
const [value, setValue] = (0, import_react.useState)("");
|
|
28492
28728
|
const [cursor, setCursor] = (0, import_react.useState)(0);
|
|
@@ -28682,6 +28918,10 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
28682
28918
|
openModel();
|
|
28683
28919
|
return;
|
|
28684
28920
|
}
|
|
28921
|
+
if (text === "/effort" || text.startsWith("/effort ")) {
|
|
28922
|
+
openEffort();
|
|
28923
|
+
return;
|
|
28924
|
+
}
|
|
28685
28925
|
if (text === "/mode" || text.startsWith("/mode ")) {
|
|
28686
28926
|
if (text.slice(5).trim() === "") openMode();
|
|
28687
28927
|
else dispatch(text);
|
|
@@ -28708,6 +28948,10 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
28708
28948
|
openStatusline();
|
|
28709
28949
|
return;
|
|
28710
28950
|
}
|
|
28951
|
+
if (text === "/theme") {
|
|
28952
|
+
openTheme();
|
|
28953
|
+
return;
|
|
28954
|
+
}
|
|
28711
28955
|
if (text === "/history") {
|
|
28712
28956
|
openHistory();
|
|
28713
28957
|
return;
|
|
@@ -28822,27 +29066,118 @@ function Input({ active, frozen, busy, descriptors, skills, dispatch, steer, int
|
|
|
28822
29066
|
setDismissedMenuValue(void 0);
|
|
28823
29067
|
}
|
|
28824
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" ? "»" : "❯";
|
|
28825
29073
|
if (frozen) {
|
|
28826
29074
|
const frozen = value === "" ? "type a message" : verboseLine(value, Math.max(1, columns - 6));
|
|
28827
29075
|
return (0, import_react.createElement)(Box, {
|
|
28828
29076
|
width: Math.max(1, columns - 1),
|
|
28829
29077
|
borderStyle: "round",
|
|
28830
|
-
borderColor: inkColor(
|
|
29078
|
+
borderColor: inkColor(getPalette().dim),
|
|
28831
29079
|
paddingX: 1
|
|
28832
|
-
}, (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));
|
|
28833
29084
|
}
|
|
28834
|
-
const
|
|
28835
|
-
|
|
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, {
|
|
28836
29092
|
active: menuActive,
|
|
28837
29093
|
mention: mentionActive,
|
|
28838
29094
|
index: completionIndex,
|
|
28839
29095
|
rows: menuRows
|
|
28840
|
-
})
|
|
28841
|
-
|
|
28842
|
-
|
|
28843
|
-
|
|
28844
|
-
|
|
28845
|
-
},
|
|
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));
|
|
28846
29181
|
}
|
|
28847
29182
|
/** The whole terminal app; state arrives via the store, output via Ink. */
|
|
28848
29183
|
function App(props) {
|
|
@@ -28851,6 +29186,60 @@ function App(props) {
|
|
|
28851
29186
|
const skills = (0, import_react.useSyncExternalStore)(props.skills.subscribe, () => props.skills.rows);
|
|
28852
29187
|
const [modelLabel, setModelLabel] = (0, import_react.useState)(props.model);
|
|
28853
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
|
+
]);
|
|
28854
29243
|
const [directory, setDirectory] = (0, import_react.useState)(void 0);
|
|
28855
29244
|
const [modelError, setModelError] = (0, import_react.useState)(void 0);
|
|
28856
29245
|
const [modelLoadEpoch, setModelLoadEpoch] = (0, import_react.useState)(0);
|
|
@@ -28892,6 +29281,7 @@ function App(props) {
|
|
|
28892
29281
|
const [pluginQuery, setPluginQuery] = (0, import_react.useState)("");
|
|
28893
29282
|
const [statuslineOpen, setStatuslineOpen] = (0, import_react.useState)(false);
|
|
28894
29283
|
const [statuslineItems, setStatuslineItems] = (0, import_react.useState)(() => parseStatuslineItems(props.statusline));
|
|
29284
|
+
const [themeOpen, setThemeOpen] = (0, import_react.useState)(false);
|
|
28895
29285
|
const [historyOpen, setHistoryOpen] = (0, import_react.useState)(false);
|
|
28896
29286
|
/** The /history panel's accepted entry: text plus its recall-space index. */
|
|
28897
29287
|
const [historyFill, setHistoryFill] = (0, import_react.useState)(void 0);
|
|
@@ -28912,15 +29302,17 @@ function App(props) {
|
|
|
28912
29302
|
const questionSnapshot = (0, import_react.useSyncExternalStore)(props.questions.subscribe, props.questions.getSnapshot);
|
|
28913
29303
|
const approvalPending = approvalSnapshot.pending !== void 0;
|
|
28914
29304
|
const questionPending = questionSnapshot.pending !== void 0;
|
|
28915
|
-
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;
|
|
28916
29306
|
(0, import_react.useEffect)(() => {
|
|
28917
29307
|
if (!approvalPending && !questionPending) return;
|
|
28918
29308
|
setModelOpen(false);
|
|
29309
|
+
setEffortFor(void 0);
|
|
28919
29310
|
setHelpOpen(false);
|
|
28920
29311
|
setModeOpen(false);
|
|
28921
29312
|
setResumeOpen(false);
|
|
28922
29313
|
setPluginOpen(false);
|
|
28923
29314
|
setStatuslineOpen(false);
|
|
29315
|
+
setThemeOpen(false);
|
|
28924
29316
|
setHistoryOpen(false);
|
|
28925
29317
|
setVerboseOpen(false);
|
|
28926
29318
|
}, [approvalPending, questionPending]);
|
|
@@ -29002,8 +29394,8 @@ function App(props) {
|
|
|
29002
29394
|
const streamRows = Math.max(1, dynamicRows - visibleLiveLines.length);
|
|
29003
29395
|
const reasoningRows = view.streamingReasoning === "" ? 0 : view.streaming === "" ? streamRows : streamRows <= 1 ? 0 : showReasoning ? Math.max(1, Math.floor(streamRows / 3)) : 1;
|
|
29004
29396
|
const answerRows = view.streaming === "" ? 0 : Math.max(1, streamRows - reasoningRows);
|
|
29005
|
-
const transcriptVisible = !modelOpen && !helpOpen && !modeOpen && !resumeOpen && !pluginOpen && !statuslineOpen && !historyOpen && !verboseOpen && !approvalPending && !questionPending;
|
|
29006
|
-
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;
|
|
29007
29399
|
const closeInspector = (0, import_react.useCallback)(() => {
|
|
29008
29400
|
setVerboseOpen(false);
|
|
29009
29401
|
}, []);
|
|
@@ -29011,6 +29403,19 @@ function App(props) {
|
|
|
29011
29403
|
if (appStdout !== void 0) appStdout.write("\x1B[2J\x1B[3J\x1B[H");
|
|
29012
29404
|
setRefreshEpoch((epoch) => epoch + 1);
|
|
29013
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
|
+
};
|
|
29014
29419
|
return (0, import_react.createElement)(Box, { flexDirection: "column" }, (0, import_react.createElement)(MemoStaticTranscript, {
|
|
29015
29420
|
key: refreshEpoch,
|
|
29016
29421
|
items: settledRows
|
|
@@ -29034,24 +29439,29 @@ function App(props) {
|
|
|
29034
29439
|
}), (0, import_react.createElement)(ApprovalBar, {
|
|
29035
29440
|
snapshot: approvalSnapshot,
|
|
29036
29441
|
locked: questionPending
|
|
29037
|
-
}), modelOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(ModelPanel, {
|
|
29442
|
+
}), modelOpen && !approvalPending && !questionPending ? effortFor === void 0 ? (0, import_react.createElement)(ModelPanel, {
|
|
29038
29443
|
directory,
|
|
29039
29444
|
error: modelError,
|
|
29040
29445
|
onSelect: (row) => {
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
setModelOpen(false);
|
|
29045
|
-
} catch (error) {
|
|
29046
|
-
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;
|
|
29047
29449
|
}
|
|
29450
|
+
const effortId = row.reasoning?.efforts.length === 1 ? row.reasoning.efforts[0].id : void 0;
|
|
29451
|
+
applyModel(row, effortId);
|
|
29048
29452
|
},
|
|
29049
29453
|
onRetry: () => {
|
|
29050
29454
|
setModelLoadEpoch((epoch) => epoch + 1);
|
|
29051
29455
|
},
|
|
29052
29456
|
onClose: () => {
|
|
29053
29457
|
setModelOpen(false);
|
|
29458
|
+
setEffortFor(void 0);
|
|
29054
29459
|
}
|
|
29460
|
+
}) : (0, import_react.createElement)(EffortPanel, {
|
|
29461
|
+
row: effortFor,
|
|
29462
|
+
current: effortLabel,
|
|
29463
|
+
select: (effortId) => applyModel(effortFor, effortId),
|
|
29464
|
+
back: () => setEffortFor(void 0)
|
|
29055
29465
|
}) : void 0, helpOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(HelpPanel, {
|
|
29056
29466
|
descriptors,
|
|
29057
29467
|
skills,
|
|
@@ -29093,6 +29503,15 @@ function App(props) {
|
|
|
29093
29503
|
props.saveStatusline(items);
|
|
29094
29504
|
},
|
|
29095
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)
|
|
29096
29515
|
}) : void 0, historyOpen && !approvalPending && !questionPending ? (0, import_react.createElement)(HistoryPanel, {
|
|
29097
29516
|
entries: recallSpace,
|
|
29098
29517
|
fill: (text, index) => {
|
|
@@ -29123,8 +29542,32 @@ function App(props) {
|
|
|
29123
29542
|
openModel: () => {
|
|
29124
29543
|
setDirectory(void 0);
|
|
29125
29544
|
setModelError(void 0);
|
|
29545
|
+
setEffortFor(void 0);
|
|
29126
29546
|
setModelOpen(true);
|
|
29127
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
|
+
},
|
|
29128
29571
|
openHelp: () => {
|
|
29129
29572
|
setHelpOpen(true);
|
|
29130
29573
|
},
|
|
@@ -29135,6 +29578,7 @@ function App(props) {
|
|
|
29135
29578
|
setPluginOpen(true);
|
|
29136
29579
|
},
|
|
29137
29580
|
openStatusline: () => setStatuslineOpen(true),
|
|
29581
|
+
openTheme: () => setThemeOpen(true),
|
|
29138
29582
|
openHistory: () => setHistoryOpen(true),
|
|
29139
29583
|
createSession: props.createSession,
|
|
29140
29584
|
cancelSessionSwitch: props.cancelSessionSwitch,
|
|
@@ -29164,7 +29608,10 @@ function App(props) {
|
|
|
29164
29608
|
queued: queuedRows,
|
|
29165
29609
|
cancelQueued: props.cancelQueued,
|
|
29166
29610
|
historyFill,
|
|
29167
|
-
historyConsumed
|
|
29611
|
+
historyConsumed,
|
|
29612
|
+
waveTick,
|
|
29613
|
+
waveTier,
|
|
29614
|
+
waveStyle
|
|
29168
29615
|
}), (0, import_react.createElement)(StatusLine, {
|
|
29169
29616
|
facts: {
|
|
29170
29617
|
model: modelLabel,
|
|
@@ -29350,11 +29797,66 @@ const internals = {
|
|
|
29350
29797
|
};
|
|
29351
29798
|
//#endregion
|
|
29352
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
|
+
}
|
|
29353
29850
|
/**
|
|
29354
29851
|
* Load the selectable model directory from the live `ctx.llm` registry.
|
|
29355
29852
|
* Providers are listed synchronously; each provider's models are discovered
|
|
29356
29853
|
* with a bounded parallel fan-out whose failures degrade to that provider
|
|
29357
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".
|
|
29358
29860
|
* @param ctx - context carrying the `llm` service.
|
|
29359
29861
|
* @returns the resolved directory; empty rows when `llm` is unavailable.
|
|
29360
29862
|
*/
|
|
@@ -29362,21 +29864,39 @@ async function loadModelDirectory(ctx) {
|
|
|
29362
29864
|
const llm = ctx.get("llm");
|
|
29363
29865
|
if (llm === void 0) return {
|
|
29364
29866
|
rows: [],
|
|
29365
|
-
failures: []
|
|
29867
|
+
failures: [],
|
|
29868
|
+
reasoningFailures: []
|
|
29366
29869
|
};
|
|
29870
|
+
const llmResolve = llm;
|
|
29367
29871
|
const providers = llm.listProviders();
|
|
29368
29872
|
const listed = await Promise.all(providers.map(async (provider) => {
|
|
29369
29873
|
try {
|
|
29370
29874
|
const models = await llm.listModels(provider.id);
|
|
29371
|
-
|
|
29372
|
-
|
|
29373
|
-
|
|
29374
|
-
models: models.map((model) => ({
|
|
29875
|
+
const reasoningFailures = [];
|
|
29876
|
+
const rows = await Promise.all(models.map(async (model) => {
|
|
29877
|
+
const row = {
|
|
29375
29878
|
provider: provider.id,
|
|
29376
29879
|
providerName: provider.name,
|
|
29377
29880
|
model: model.id,
|
|
29378
29881
|
modelName: model.name
|
|
29379
|
-
}
|
|
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
|
|
29380
29900
|
};
|
|
29381
29901
|
} catch {
|
|
29382
29902
|
return {
|
|
@@ -29389,20 +29909,26 @@ async function loadModelDirectory(ctx) {
|
|
|
29389
29909
|
}));
|
|
29390
29910
|
return {
|
|
29391
29911
|
rows: listed.flatMap((entry) => entry.models),
|
|
29392
|
-
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)
|
|
29393
29914
|
};
|
|
29394
29915
|
}
|
|
29395
29916
|
//#endregion
|
|
29396
29917
|
//#region src/mentions.ts
|
|
29397
29918
|
/**
|
|
29398
|
-
* Workspace @mention support: file candidates from a bounded
|
|
29399
|
-
* the session cwd, session candidates from the opt-in
|
|
29400
|
-
* service, and submission preparation through its
|
|
29401
|
-
* session mentions land as canonical
|
|
29402
|
-
* submit the text is parsed back into
|
|
29403
|
-
* references, snapshots are injected
|
|
29404
|
-
*
|
|
29405
|
-
* 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.
|
|
29406
29932
|
*
|
|
29407
29933
|
* @module @deepseek-ai/dsh-code/mentions
|
|
29408
29934
|
*/
|
|
@@ -29418,7 +29944,16 @@ const SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
29418
29944
|
]);
|
|
29419
29945
|
const MAX_FILES = 4e3;
|
|
29420
29946
|
const MAX_DEPTH = 12;
|
|
29421
|
-
/**
|
|
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
|
+
*/
|
|
29422
29957
|
async function scanWorkspaceFiles(root, signal) {
|
|
29423
29958
|
const found = [];
|
|
29424
29959
|
const pending = [{
|
|
@@ -29442,6 +29977,10 @@ async function scanWorkspaceFiles(root, signal) {
|
|
|
29442
29977
|
const relative = current.relative === "" ? entry.name : `${current.relative}/${entry.name}`;
|
|
29443
29978
|
if (entry.isDirectory()) {
|
|
29444
29979
|
if (SKIP_DIRS.has(entry.name) || current.depth + 1 > MAX_DEPTH) continue;
|
|
29980
|
+
found.push({
|
|
29981
|
+
path: relative,
|
|
29982
|
+
kind: "directory"
|
|
29983
|
+
});
|
|
29445
29984
|
pending.push({
|
|
29446
29985
|
absolute: join(current.absolute, entry.name),
|
|
29447
29986
|
relative,
|
|
@@ -29478,38 +30017,47 @@ function scoreFile(path, query) {
|
|
|
29478
30017
|
/**
|
|
29479
30018
|
* Create the mention API for one agent's workspace. A missing
|
|
29480
30019
|
* session-reference service degrades to file mentions only (the scan still
|
|
29481
|
-
* 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.
|
|
29482
30027
|
* @param ctx - context carrying the optional `sessionReferenceResolver`.
|
|
29483
30028
|
* @param agent - the session owner; excluded from its own candidates.
|
|
29484
30029
|
* @param cwd - workspace root to scan.
|
|
29485
30030
|
*/
|
|
29486
30031
|
function createMentions(ctx, agent, cwd) {
|
|
29487
30032
|
const resolver = ctx.get("sessionReferenceResolver");
|
|
30033
|
+
const sessionCapable = agent !== void 0 && resolver !== void 0;
|
|
29488
30034
|
let filesPromise;
|
|
30035
|
+
const files = () => {
|
|
30036
|
+
filesPromise ??= scanWorkspaceFiles(cwd);
|
|
30037
|
+
return filesPromise;
|
|
30038
|
+
};
|
|
29489
30039
|
return {
|
|
29490
|
-
files
|
|
29491
|
-
filesPromise ??= scanWorkspaceFiles(cwd);
|
|
29492
|
-
return filesPromise;
|
|
29493
|
-
},
|
|
30040
|
+
files,
|
|
29494
30041
|
async candidates(query, signal) {
|
|
29495
30042
|
const needle = query.trim();
|
|
29496
|
-
const [
|
|
29497
|
-
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) => ({
|
|
29498
30045
|
label: candidate.path,
|
|
29499
30046
|
description: candidate.kind === "directory" ? "Folder" : "File",
|
|
29500
30047
|
kind: candidate.kind
|
|
29501
30048
|
}));
|
|
29502
|
-
|
|
30049
|
+
const sessionRows = sessions.map((candidate) => ({
|
|
29503
30050
|
label: formatSessionReferenceMention(candidate),
|
|
29504
30051
|
description: `Session · ${candidate.cwd ?? "(no cwd)"}`,
|
|
29505
30052
|
kind: "session"
|
|
29506
|
-
}))
|
|
30053
|
+
}));
|
|
30054
|
+
return [...fileRows, ...sessionRows];
|
|
29507
30055
|
},
|
|
29508
30056
|
parse(text) {
|
|
29509
30057
|
return parseSessionReferenceText(text);
|
|
29510
30058
|
},
|
|
29511
30059
|
async prepare(parsed, signal) {
|
|
29512
|
-
if (parsed.references.length === 0 || resolver === void 0) return {
|
|
30060
|
+
if (parsed.references.length === 0 || resolver === void 0 || agent === void 0) return {
|
|
29513
30061
|
text: parsed.text,
|
|
29514
30062
|
references: parsed.references
|
|
29515
30063
|
};
|
|
@@ -29941,7 +30489,8 @@ const inject = [
|
|
|
29941
30489
|
const Config = z.object({ startup: z.object({
|
|
29942
30490
|
kind: z.string().required(),
|
|
29943
30491
|
sessionId: z.string(),
|
|
29944
|
-
mode: z.string()
|
|
30492
|
+
mode: z.string(),
|
|
30493
|
+
theme: z.string()
|
|
29945
30494
|
}) });
|
|
29946
30495
|
/** Report an unexpected direct-driver failure and request a failing exit. */
|
|
29947
30496
|
function fail(io, error) {
|
|
@@ -30038,7 +30587,7 @@ async function run(ctx, startup, io) {
|
|
|
30038
30587
|
/** Prepare a complete next session before disturbing the currently visible one. */
|
|
30039
30588
|
const prepare = async (next) => {
|
|
30040
30589
|
const nextCwd = next.cwd ?? cwd;
|
|
30041
|
-
const selectionState = {};
|
|
30590
|
+
const selectionState = pendingSelection === void 0 ? {} : { picked: pendingSelection };
|
|
30042
30591
|
let mode = next.mode;
|
|
30043
30592
|
if (!next.resume) mode = (await presets.resolve(mode)).id;
|
|
30044
30593
|
const setup = async (agentCtx) => {
|
|
@@ -30046,14 +30595,7 @@ async function run(ctx, startup, io) {
|
|
|
30046
30595
|
mode = (await presets.mount(agentCtx, sessionPreset)).id;
|
|
30047
30596
|
installModelSelection(agentCtx, {
|
|
30048
30597
|
get current() {
|
|
30049
|
-
|
|
30050
|
-
const logged = agentCtx.agent?.session.requestHeader()?.config;
|
|
30051
|
-
if (logged !== void 0) return {
|
|
30052
|
-
provider: logged.provider,
|
|
30053
|
-
model: logged.model,
|
|
30054
|
-
...logged.reasoningEffort === void 0 ? {} : { reasoningEffort: logged.reasoningEffort }
|
|
30055
|
-
};
|
|
30056
|
-
return defaults;
|
|
30598
|
+
return resolveEffectiveSelection(selectionState.picked, agentCtx.agent?.session.requestHeader()?.config, defaults);
|
|
30057
30599
|
},
|
|
30058
30600
|
set current(value) {
|
|
30059
30601
|
selectionState.picked = value;
|
|
@@ -30097,7 +30639,9 @@ async function run(ctx, startup, io) {
|
|
|
30097
30639
|
let agent;
|
|
30098
30640
|
let session;
|
|
30099
30641
|
let store = createTranscriptStore();
|
|
30100
|
-
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;
|
|
30101
30645
|
if (!lazy) {
|
|
30102
30646
|
const prepared = await prepare(await resolveTarget(startup, persistence, cwd));
|
|
30103
30647
|
active = prepared;
|
|
@@ -30131,6 +30675,20 @@ async function run(ctx, startup, io) {
|
|
|
30131
30675
|
bridge.notify("statusline save failed: " + (writeError instanceof Error ? writeError.message : String(writeError)), "error");
|
|
30132
30676
|
});
|
|
30133
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
|
+
};
|
|
30134
30692
|
const historyPath = join(homedir(), ".dsh", "dsh-code", "history.jsonl");
|
|
30135
30693
|
let inputHistory = [];
|
|
30136
30694
|
try {
|
|
@@ -30352,13 +30910,16 @@ async function run(ctx, startup, io) {
|
|
|
30352
30910
|
return "";
|
|
30353
30911
|
}
|
|
30354
30912
|
};
|
|
30355
|
-
/**
|
|
30356
|
-
|
|
30357
|
-
|
|
30358
|
-
|
|
30359
|
-
|
|
30360
|
-
|
|
30361
|
-
|
|
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;
|
|
30362
30923
|
return `${row.provider}/${row.model}`;
|
|
30363
30924
|
};
|
|
30364
30925
|
/**
|
|
@@ -30443,7 +31004,7 @@ async function run(ctx, startup, io) {
|
|
|
30443
31004
|
agent = previous?.agent;
|
|
30444
31005
|
session = previous?.session;
|
|
30445
31006
|
store = previous === void 0 ? createTranscriptStore() : previous.store;
|
|
30446
|
-
mentions = previous
|
|
31007
|
+
mentions = previous === void 0 ? createMentions(ctx, void 0, cwd) : previous.mentions;
|
|
30447
31008
|
if (agent !== void 0) commands.setAgent(agent);
|
|
30448
31009
|
if (agent !== void 0) skills.setAgent(agent);
|
|
30449
31010
|
await next.handle.dispose();
|
|
@@ -30541,7 +31102,8 @@ async function run(ctx, startup, io) {
|
|
|
30541
31102
|
};
|
|
30542
31103
|
const appElement = () => {
|
|
30543
31104
|
const sessionCwd = session?.header.cwd ?? cwd;
|
|
30544
|
-
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;
|
|
30545
31107
|
return (0, import_react.createElement)(App, {
|
|
30546
31108
|
key: session?.id ?? "pending",
|
|
30547
31109
|
store,
|
|
@@ -30550,6 +31112,7 @@ async function run(ctx, startup, io) {
|
|
|
30550
31112
|
commands,
|
|
30551
31113
|
skills,
|
|
30552
31114
|
model,
|
|
31115
|
+
effort,
|
|
30553
31116
|
cwd: basename(sessionCwd),
|
|
30554
31117
|
workspaceRoot: sessionCwd,
|
|
30555
31118
|
branch: gitBranch(sessionCwd),
|
|
@@ -30561,7 +31124,7 @@ async function run(ctx, startup, io) {
|
|
|
30561
31124
|
interrupt,
|
|
30562
31125
|
quit,
|
|
30563
31126
|
loadModels: () => loadModelDirectory(ctx),
|
|
30564
|
-
loadMentions:
|
|
31127
|
+
loadMentions: (query, signal) => mentions.candidates(query, signal),
|
|
30565
31128
|
cyclePermission,
|
|
30566
31129
|
selectModel,
|
|
30567
31130
|
exportTranscript,
|
|
@@ -30576,6 +31139,7 @@ async function run(ctx, startup, io) {
|
|
|
30576
31139
|
loadPlugins: () => listPluginRows(ctx),
|
|
30577
31140
|
statusline: statuslineItems,
|
|
30578
31141
|
saveStatusline,
|
|
31142
|
+
saveTheme,
|
|
30579
31143
|
history: inputHistory,
|
|
30580
31144
|
recordHistory,
|
|
30581
31145
|
cancelQueued,
|
|
@@ -30591,6 +31155,9 @@ async function run(ctx, startup, io) {
|
|
|
30591
31155
|
if (statuslineWarning !== void 0) setTimeout(() => {
|
|
30592
31156
|
bridge.notify("statusline config unreadable, using defaults: " + statuslineWarning, "warning");
|
|
30593
31157
|
}, 50);
|
|
31158
|
+
if (themeWarning !== void 0) setTimeout(() => {
|
|
31159
|
+
bridge.notify("theme config unreadable, using dark: " + themeWarning, "warning");
|
|
31160
|
+
}, 50);
|
|
30594
31161
|
}
|
|
30595
31162
|
/**
|
|
30596
31163
|
* Mount the interactive terminal driver.
|
|
@@ -30598,16 +31165,23 @@ async function run(ctx, startup, io) {
|
|
|
30598
31165
|
* @param config - validated startup config resolved from the tuiStartup provider.
|
|
30599
31166
|
*/
|
|
30600
31167
|
function apply(ctx, config) {
|
|
31168
|
+
const theme = config.startup.theme === void 0 ? void 0 : parseThemeName(config.startup.theme);
|
|
30601
31169
|
const startup = config.startup.kind === "resume" && config.startup.sessionId !== void 0 ? {
|
|
30602
31170
|
kind: "resume",
|
|
30603
|
-
sessionId: config.startup.sessionId
|
|
30604
|
-
|
|
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 ? {
|
|
30605
31177
|
kind: "named",
|
|
30606
31178
|
sessionId: config.startup.sessionId,
|
|
30607
|
-
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode }
|
|
31179
|
+
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode },
|
|
31180
|
+
...theme === void 0 ? {} : { theme }
|
|
30608
31181
|
} : {
|
|
30609
31182
|
kind: "fresh",
|
|
30610
|
-
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode }
|
|
31183
|
+
...config.startup.mode === void 0 ? {} : { mode: config.startup.mode },
|
|
31184
|
+
...theme === void 0 ? {} : { theme }
|
|
30611
31185
|
};
|
|
30612
31186
|
const exit = ctx.get("appExit");
|
|
30613
31187
|
if (exit === void 0) throw new Error("tui-runner: the launcher must provide ctx.appExit before the tree mounts");
|