dsh-code 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +4 -2
- package/README.md +4 -2
- package/bin/deepseek.mjs +38 -3
- package/lib/index.mjs +1485 -906
- package/lib/startup.mjs +21 -9
- package/lib/theme-BEi4i_aN.mjs +624 -0
- package/lib/types/app.d.ts +31 -3
- package/lib/types/index.d.ts +1 -0
- package/lib/types/kernel-panels.d.ts +21 -0
- package/lib/types/mentions.d.ts +29 -12
- package/lib/types/models.d.ts +66 -0
- package/lib/types/render/animations.d.ts +175 -2
- package/lib/types/render/projection.d.ts +38 -7
- package/lib/types/render/status.d.ts +34 -13
- package/lib/types/startup.d.ts +12 -4
- package/lib/types/theme-panel.d.ts +24 -0
- package/lib/types/theme.d.ts +158 -2
- package/package.json +1 -1
- package/src/app.ts +510 -130
- package/src/index.ts +964 -900
- package/src/kernel-panels.ts +481 -419
- package/src/mentions.ts +57 -27
- package/src/models.ts +200 -66
- package/src/render/animations.ts +359 -2
- package/src/render/projection.ts +764 -655
- package/src/render/status.ts +744 -603
- package/src/startup.ts +119 -109
- package/src/theme-panel.ts +72 -0
- package/src/theme.ts +206 -70
package/lib/startup.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { t as THEME_NAMES } from "./theme-BEi4i_aN.mjs";
|
|
1
2
|
import { Command } from "commander";
|
|
2
3
|
import { parseCmdline } from "@deepseek-ai/dsh-cmdline";
|
|
3
4
|
//#region src/startup.ts
|
|
4
5
|
/**
|
|
5
6
|
* The interactive terminal app's command-line provider: parses `--resume`,
|
|
6
|
-
* `--continue`, `--session`, `--mode`, and `--help`, then
|
|
7
|
-
* {@link TUI_STARTUP_SERVICE} for the runner to consume lazily.
|
|
8
|
-
* headless bundle's startup shape (a commander action publishing
|
|
9
|
-
* through {@link parseCmdline}).
|
|
7
|
+
* `--continue`, `--session`, `--mode`, `--theme`, and `--help`, then
|
|
8
|
+
* publishes {@link TUI_STARTUP_SERVICE} for the runner to consume lazily.
|
|
9
|
+
* Follows the headless bundle's startup shape (a commander action publishing
|
|
10
|
+
* a service through {@link parseCmdline}).
|
|
10
11
|
*
|
|
11
12
|
* Semantics:
|
|
12
13
|
* - `--resume <id|prefix>` — continue the persisted session whose id or unique
|
|
@@ -16,6 +17,8 @@ import { parseCmdline } from "@deepseek-ai/dsh-cmdline";
|
|
|
16
17
|
* whose project directory matches the current working directory.
|
|
17
18
|
* - `--session <id>` — create a new session under an explicit identity (the
|
|
18
19
|
* id must not exist yet).
|
|
20
|
+
* - `--theme <dark|light|auto>` — the color palette; auto follows the
|
|
21
|
+
* terminal (dark fallback until OSC-11 detection lands).
|
|
19
22
|
* - no flags — a fresh session with a minted id.
|
|
20
23
|
*
|
|
21
24
|
* @module @deepseek-ai/dsh-tui/startup
|
|
@@ -37,16 +40,24 @@ function resolveTuiStartup(options) {
|
|
|
37
40
|
if (options.resume === "") throw new Error("--resume needs a session id or id prefix");
|
|
38
41
|
if (options.mode === "") throw new Error("--mode needs a preset id");
|
|
39
42
|
if (options.mode !== void 0 && (options.resume !== void 0 || options.continue === true)) throw new Error("--mode applies only to a new session; it cannot be combined with --resume or --continue");
|
|
43
|
+
if (options.theme !== void 0 && !THEME_NAMES.includes(options.theme)) throw new Error("--theme must be dark, light, or auto");
|
|
44
|
+
const theme = options.theme === void 0 ? {} : { theme: options.theme };
|
|
40
45
|
return options.resume !== void 0 ? {
|
|
41
46
|
kind: "resume",
|
|
42
|
-
sessionId: options.resume
|
|
43
|
-
|
|
47
|
+
sessionId: options.resume,
|
|
48
|
+
...theme
|
|
49
|
+
} : options.continue === true ? {
|
|
50
|
+
kind: "latest",
|
|
51
|
+
...theme
|
|
52
|
+
} : options.session !== void 0 ? {
|
|
44
53
|
kind: "named",
|
|
45
54
|
sessionId: options.session,
|
|
46
|
-
...options.mode === void 0 ? {} : { mode: options.mode }
|
|
55
|
+
...options.mode === void 0 ? {} : { mode: options.mode },
|
|
56
|
+
...theme
|
|
47
57
|
} : {
|
|
48
58
|
kind: "fresh",
|
|
49
|
-
...options.mode === void 0 ? {} : { mode: options.mode }
|
|
59
|
+
...options.mode === void 0 ? {} : { mode: options.mode },
|
|
60
|
+
...theme
|
|
50
61
|
};
|
|
51
62
|
}
|
|
52
63
|
/**
|
|
@@ -55,12 +66,13 @@ function resolveTuiStartup(options) {
|
|
|
55
66
|
* @returns a fresh program, so one process can parse more than once (tests).
|
|
56
67
|
*/
|
|
57
68
|
function tuiCommand() {
|
|
58
|
-
return new Command().name("dsh --profile cli").description("Claude-Code-style interactive terminal for DeepSeek Harness.").helpOption("-h, --help", "show this help").option("-r, --resume <session>", "resume the persisted session with this id (or unique id prefix)").option("-c, --continue", "resume the most recent persisted session for this working directory").option("--session <id>", "create a new session under this explicit id").option("--mode <preset>", "agent preset for a newly created session").addHelpText("after", `
|
|
69
|
+
return new Command().name("dsh --profile cli").description("Claude-Code-style interactive terminal for DeepSeek Harness.").helpOption("-h, --help", "show this help").option("-r, --resume <session>", "resume the persisted session with this id (or unique id prefix)").option("-c, --continue", "resume the most recent persisted session for this working directory").option("--session <id>", "create a new session under this explicit id").option("--mode <preset>", "agent preset for a newly created session").option("--theme <name>", "color theme: dark (default), light, or auto").addHelpText("after", `
|
|
59
70
|
Examples:
|
|
60
71
|
dsh --profile cli fresh session, minted id
|
|
61
72
|
dsh --profile cli --resume abc123 resume session by id prefix
|
|
62
73
|
dsh --profile cli --continue resume the latest local session
|
|
63
74
|
dsh --profile cli --mode minimal fresh session using the minimal preset
|
|
75
|
+
dsh --profile cli --theme light light palette for bright terminals
|
|
64
76
|
`);
|
|
65
77
|
}
|
|
66
78
|
/**
|
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
import tty from "node:tty";
|
|
4
|
+
//#region node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
|
|
5
|
+
const ANSI_BACKGROUND_OFFSET = 10;
|
|
6
|
+
const wrapAnsi16 = (offset = 0) => (code) => `\u001B[${code + offset}m`;
|
|
7
|
+
const wrapAnsi256 = (offset = 0) => (code) => `\u001B[${38 + offset};5;${code}m`;
|
|
8
|
+
const wrapAnsi16m = (offset = 0) => (red, green, blue) => `\u001B[${38 + offset};2;${red};${green};${blue}m`;
|
|
9
|
+
const styles$1 = {
|
|
10
|
+
modifier: {
|
|
11
|
+
reset: [0, 0],
|
|
12
|
+
bold: [1, 22],
|
|
13
|
+
dim: [2, 22],
|
|
14
|
+
italic: [3, 23],
|
|
15
|
+
underline: [4, 24],
|
|
16
|
+
overline: [53, 55],
|
|
17
|
+
inverse: [7, 27],
|
|
18
|
+
hidden: [8, 28],
|
|
19
|
+
strikethrough: [9, 29]
|
|
20
|
+
},
|
|
21
|
+
color: {
|
|
22
|
+
black: [30, 39],
|
|
23
|
+
red: [31, 39],
|
|
24
|
+
green: [32, 39],
|
|
25
|
+
yellow: [33, 39],
|
|
26
|
+
blue: [34, 39],
|
|
27
|
+
magenta: [35, 39],
|
|
28
|
+
cyan: [36, 39],
|
|
29
|
+
white: [37, 39],
|
|
30
|
+
blackBright: [90, 39],
|
|
31
|
+
gray: [90, 39],
|
|
32
|
+
grey: [90, 39],
|
|
33
|
+
redBright: [91, 39],
|
|
34
|
+
greenBright: [92, 39],
|
|
35
|
+
yellowBright: [93, 39],
|
|
36
|
+
blueBright: [94, 39],
|
|
37
|
+
magentaBright: [95, 39],
|
|
38
|
+
cyanBright: [96, 39],
|
|
39
|
+
whiteBright: [97, 39]
|
|
40
|
+
},
|
|
41
|
+
bgColor: {
|
|
42
|
+
bgBlack: [40, 49],
|
|
43
|
+
bgRed: [41, 49],
|
|
44
|
+
bgGreen: [42, 49],
|
|
45
|
+
bgYellow: [43, 49],
|
|
46
|
+
bgBlue: [44, 49],
|
|
47
|
+
bgMagenta: [45, 49],
|
|
48
|
+
bgCyan: [46, 49],
|
|
49
|
+
bgWhite: [47, 49],
|
|
50
|
+
bgBlackBright: [100, 49],
|
|
51
|
+
bgGray: [100, 49],
|
|
52
|
+
bgGrey: [100, 49],
|
|
53
|
+
bgRedBright: [101, 49],
|
|
54
|
+
bgGreenBright: [102, 49],
|
|
55
|
+
bgYellowBright: [103, 49],
|
|
56
|
+
bgBlueBright: [104, 49],
|
|
57
|
+
bgMagentaBright: [105, 49],
|
|
58
|
+
bgCyanBright: [106, 49],
|
|
59
|
+
bgWhiteBright: [107, 49]
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
Object.keys(styles$1.modifier);
|
|
63
|
+
const foregroundColorNames = Object.keys(styles$1.color);
|
|
64
|
+
const backgroundColorNames = Object.keys(styles$1.bgColor);
|
|
65
|
+
[...foregroundColorNames, ...backgroundColorNames];
|
|
66
|
+
function assembleStyles() {
|
|
67
|
+
const codes = /* @__PURE__ */ new Map();
|
|
68
|
+
for (const [groupName, group] of Object.entries(styles$1)) {
|
|
69
|
+
for (const [styleName, style] of Object.entries(group)) {
|
|
70
|
+
styles$1[styleName] = {
|
|
71
|
+
open: `\u001B[${style[0]}m`,
|
|
72
|
+
close: `\u001B[${style[1]}m`
|
|
73
|
+
};
|
|
74
|
+
group[styleName] = styles$1[styleName];
|
|
75
|
+
codes.set(style[0], style[1]);
|
|
76
|
+
}
|
|
77
|
+
Object.defineProperty(styles$1, groupName, {
|
|
78
|
+
value: group,
|
|
79
|
+
enumerable: false
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
Object.defineProperty(styles$1, "codes", {
|
|
83
|
+
value: codes,
|
|
84
|
+
enumerable: false
|
|
85
|
+
});
|
|
86
|
+
styles$1.color.close = "\x1B[39m";
|
|
87
|
+
styles$1.bgColor.close = "\x1B[49m";
|
|
88
|
+
styles$1.color.ansi = wrapAnsi16();
|
|
89
|
+
styles$1.color.ansi256 = wrapAnsi256();
|
|
90
|
+
styles$1.color.ansi16m = wrapAnsi16m();
|
|
91
|
+
styles$1.bgColor.ansi = wrapAnsi16(ANSI_BACKGROUND_OFFSET);
|
|
92
|
+
styles$1.bgColor.ansi256 = wrapAnsi256(ANSI_BACKGROUND_OFFSET);
|
|
93
|
+
styles$1.bgColor.ansi16m = wrapAnsi16m(ANSI_BACKGROUND_OFFSET);
|
|
94
|
+
Object.defineProperties(styles$1, {
|
|
95
|
+
rgbToAnsi256: {
|
|
96
|
+
value(red, green, blue) {
|
|
97
|
+
if (red === green && green === blue) {
|
|
98
|
+
if (red < 8) return 16;
|
|
99
|
+
if (red > 248) return 231;
|
|
100
|
+
return Math.round((red - 8) / 247 * 24) + 232;
|
|
101
|
+
}
|
|
102
|
+
return 16 + 36 * Math.round(red / 255 * 5) + 6 * Math.round(green / 255 * 5) + Math.round(blue / 255 * 5);
|
|
103
|
+
},
|
|
104
|
+
enumerable: false
|
|
105
|
+
},
|
|
106
|
+
hexToRgb: {
|
|
107
|
+
value(hex) {
|
|
108
|
+
const matches = /[a-f\d]{6}|[a-f\d]{3}/i.exec(hex.toString(16));
|
|
109
|
+
if (!matches) return [
|
|
110
|
+
0,
|
|
111
|
+
0,
|
|
112
|
+
0
|
|
113
|
+
];
|
|
114
|
+
let [colorString] = matches;
|
|
115
|
+
if (colorString.length === 3) colorString = [...colorString].map((character) => character + character).join("");
|
|
116
|
+
const integer = Number.parseInt(colorString, 16);
|
|
117
|
+
return [
|
|
118
|
+
integer >> 16 & 255,
|
|
119
|
+
integer >> 8 & 255,
|
|
120
|
+
integer & 255
|
|
121
|
+
];
|
|
122
|
+
},
|
|
123
|
+
enumerable: false
|
|
124
|
+
},
|
|
125
|
+
hexToAnsi256: {
|
|
126
|
+
value: (hex) => styles$1.rgbToAnsi256(...styles$1.hexToRgb(hex)),
|
|
127
|
+
enumerable: false
|
|
128
|
+
},
|
|
129
|
+
ansi256ToAnsi: {
|
|
130
|
+
value(code) {
|
|
131
|
+
if (code < 8) return 30 + code;
|
|
132
|
+
if (code < 16) return 90 + (code - 8);
|
|
133
|
+
let red;
|
|
134
|
+
let green;
|
|
135
|
+
let blue;
|
|
136
|
+
if (code >= 232) {
|
|
137
|
+
red = ((code - 232) * 10 + 8) / 255;
|
|
138
|
+
green = red;
|
|
139
|
+
blue = red;
|
|
140
|
+
} else {
|
|
141
|
+
code -= 16;
|
|
142
|
+
const remainder = code % 36;
|
|
143
|
+
red = Math.floor(code / 36) / 5;
|
|
144
|
+
green = Math.floor(remainder / 6) / 5;
|
|
145
|
+
blue = remainder % 6 / 5;
|
|
146
|
+
}
|
|
147
|
+
const value = Math.max(red, green, blue) * 2;
|
|
148
|
+
if (value === 0) return 30;
|
|
149
|
+
let result = 30 + (Math.round(blue) << 2 | Math.round(green) << 1 | Math.round(red));
|
|
150
|
+
if (value === 2) result += 60;
|
|
151
|
+
return result;
|
|
152
|
+
},
|
|
153
|
+
enumerable: false
|
|
154
|
+
},
|
|
155
|
+
rgbToAnsi: {
|
|
156
|
+
value: (red, green, blue) => styles$1.ansi256ToAnsi(styles$1.rgbToAnsi256(red, green, blue)),
|
|
157
|
+
enumerable: false
|
|
158
|
+
},
|
|
159
|
+
hexToAnsi: {
|
|
160
|
+
value: (hex) => styles$1.ansi256ToAnsi(styles$1.hexToAnsi256(hex)),
|
|
161
|
+
enumerable: false
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
return styles$1;
|
|
165
|
+
}
|
|
166
|
+
const ansiStyles = assembleStyles();
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/vendor/supports-color/index.js
|
|
169
|
+
function hasFlag(flag, argv = globalThis.Deno ? globalThis.Deno.args : process.argv) {
|
|
170
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
171
|
+
const position = argv.indexOf(prefix + flag);
|
|
172
|
+
const terminatorPosition = argv.indexOf("--");
|
|
173
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
174
|
+
}
|
|
175
|
+
const { env: env$1 } = process;
|
|
176
|
+
let flagForceColor;
|
|
177
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) flagForceColor = 0;
|
|
178
|
+
else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) flagForceColor = 1;
|
|
179
|
+
function envForceColor() {
|
|
180
|
+
if ("FORCE_COLOR" in env$1) {
|
|
181
|
+
if (env$1.FORCE_COLOR === "true") return 1;
|
|
182
|
+
if (env$1.FORCE_COLOR === "false") return 0;
|
|
183
|
+
return env$1.FORCE_COLOR.length === 0 ? 1 : Math.min(Number.parseInt(env$1.FORCE_COLOR, 10), 3);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function translateLevel(level) {
|
|
187
|
+
if (level === 0) return false;
|
|
188
|
+
return {
|
|
189
|
+
level,
|
|
190
|
+
hasBasic: true,
|
|
191
|
+
has256: level >= 2,
|
|
192
|
+
has16m: level >= 3
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function _supportsColor(haveStream, { streamIsTTY, sniffFlags = true } = {}) {
|
|
196
|
+
const noFlagForceColor = envForceColor();
|
|
197
|
+
if (noFlagForceColor !== void 0) flagForceColor = noFlagForceColor;
|
|
198
|
+
const forceColor = sniffFlags ? flagForceColor : noFlagForceColor;
|
|
199
|
+
if (forceColor === 0) return 0;
|
|
200
|
+
if (sniffFlags) {
|
|
201
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) return 3;
|
|
202
|
+
if (hasFlag("color=256")) return 2;
|
|
203
|
+
}
|
|
204
|
+
if ("TF_BUILD" in env$1 && "AGENT_NAME" in env$1) return 1;
|
|
205
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) return 0;
|
|
206
|
+
const min = forceColor || 0;
|
|
207
|
+
if (env$1.TERM === "dumb") return min;
|
|
208
|
+
if (process.platform === "win32") {
|
|
209
|
+
const osRelease = os.release().split(".");
|
|
210
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
if ("CI" in env$1) {
|
|
214
|
+
if ([
|
|
215
|
+
"GITHUB_ACTIONS",
|
|
216
|
+
"GITEA_ACTIONS",
|
|
217
|
+
"CIRCLECI"
|
|
218
|
+
].some((key) => key in env$1)) return 3;
|
|
219
|
+
if ([
|
|
220
|
+
"TRAVIS",
|
|
221
|
+
"APPVEYOR",
|
|
222
|
+
"GITLAB_CI",
|
|
223
|
+
"BUILDKITE",
|
|
224
|
+
"DRONE"
|
|
225
|
+
].some((sign) => sign in env$1) || env$1.CI_NAME === "codeship") return 1;
|
|
226
|
+
return min;
|
|
227
|
+
}
|
|
228
|
+
if ("TEAMCITY_VERSION" in env$1) return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env$1.TEAMCITY_VERSION) ? 1 : 0;
|
|
229
|
+
if (env$1.COLORTERM === "truecolor") return 3;
|
|
230
|
+
if (env$1.TERM === "xterm-kitty") return 3;
|
|
231
|
+
if (env$1.TERM === "xterm-ghostty") return 3;
|
|
232
|
+
if (env$1.TERM === "wezterm") return 3;
|
|
233
|
+
if ("TERM_PROGRAM" in env$1) {
|
|
234
|
+
const version = Number.parseInt((env$1.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
235
|
+
switch (env$1.TERM_PROGRAM) {
|
|
236
|
+
case "iTerm.app": return version >= 3 ? 3 : 2;
|
|
237
|
+
case "Apple_Terminal": return 2;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (/-256(color)?$/i.test(env$1.TERM)) return 2;
|
|
241
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env$1.TERM)) return 1;
|
|
242
|
+
if ("COLORTERM" in env$1) return 1;
|
|
243
|
+
return min;
|
|
244
|
+
}
|
|
245
|
+
function createSupportsColor(stream, options = {}) {
|
|
246
|
+
return translateLevel(_supportsColor(stream, {
|
|
247
|
+
streamIsTTY: stream && stream.isTTY,
|
|
248
|
+
...options
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
const supportsColor = {
|
|
252
|
+
stdout: createSupportsColor({ isTTY: tty.isatty(1) }),
|
|
253
|
+
stderr: createSupportsColor({ isTTY: tty.isatty(2) })
|
|
254
|
+
};
|
|
255
|
+
//#endregion
|
|
256
|
+
//#region node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/utilities.js
|
|
257
|
+
function stringReplaceAll(string, substring, replacer) {
|
|
258
|
+
let index = string.indexOf(substring);
|
|
259
|
+
if (index === -1) return string;
|
|
260
|
+
const substringLength = substring.length;
|
|
261
|
+
let endIndex = 0;
|
|
262
|
+
let returnValue = "";
|
|
263
|
+
do {
|
|
264
|
+
returnValue += string.slice(endIndex, index) + substring + replacer;
|
|
265
|
+
endIndex = index + substringLength;
|
|
266
|
+
index = string.indexOf(substring, endIndex);
|
|
267
|
+
} while (index !== -1);
|
|
268
|
+
returnValue += string.slice(endIndex);
|
|
269
|
+
return returnValue;
|
|
270
|
+
}
|
|
271
|
+
function stringEncaseCRLFWithFirstIndex(string, prefix, postfix, index) {
|
|
272
|
+
let endIndex = 0;
|
|
273
|
+
let returnValue = "";
|
|
274
|
+
do {
|
|
275
|
+
const gotCR = string[index - 1] === "\r";
|
|
276
|
+
returnValue += string.slice(endIndex, gotCR ? index - 1 : index) + prefix + (gotCR ? "\r\n" : "\n") + postfix;
|
|
277
|
+
endIndex = index + 1;
|
|
278
|
+
index = string.indexOf("\n", endIndex);
|
|
279
|
+
} while (index !== -1);
|
|
280
|
+
returnValue += string.slice(endIndex);
|
|
281
|
+
return returnValue;
|
|
282
|
+
}
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region node_modules/.pnpm/chalk@5.6.2/node_modules/chalk/source/index.js
|
|
285
|
+
const { stdout: stdoutColor, stderr: stderrColor } = supportsColor;
|
|
286
|
+
const GENERATOR = Symbol("GENERATOR");
|
|
287
|
+
const STYLER = Symbol("STYLER");
|
|
288
|
+
const IS_EMPTY = Symbol("IS_EMPTY");
|
|
289
|
+
const levelMapping = [
|
|
290
|
+
"ansi",
|
|
291
|
+
"ansi",
|
|
292
|
+
"ansi256",
|
|
293
|
+
"ansi16m"
|
|
294
|
+
];
|
|
295
|
+
const styles = Object.create(null);
|
|
296
|
+
const applyOptions = (object, options = {}) => {
|
|
297
|
+
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");
|
|
298
|
+
const colorLevel = stdoutColor ? stdoutColor.level : 0;
|
|
299
|
+
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
300
|
+
};
|
|
301
|
+
const chalkFactory = (options) => {
|
|
302
|
+
const chalk = (...strings) => strings.join(" ");
|
|
303
|
+
applyOptions(chalk, options);
|
|
304
|
+
Object.setPrototypeOf(chalk, createChalk.prototype);
|
|
305
|
+
return chalk;
|
|
306
|
+
};
|
|
307
|
+
function createChalk(options) {
|
|
308
|
+
return chalkFactory(options);
|
|
309
|
+
}
|
|
310
|
+
Object.setPrototypeOf(createChalk.prototype, Function.prototype);
|
|
311
|
+
for (const [styleName, style] of Object.entries(ansiStyles)) styles[styleName] = { get() {
|
|
312
|
+
const builder = createBuilder(this, createStyler(style.open, style.close, this[STYLER]), this[IS_EMPTY]);
|
|
313
|
+
Object.defineProperty(this, styleName, { value: builder });
|
|
314
|
+
return builder;
|
|
315
|
+
} };
|
|
316
|
+
styles.visible = { get() {
|
|
317
|
+
const builder = createBuilder(this, this[STYLER], true);
|
|
318
|
+
Object.defineProperty(this, "visible", { value: builder });
|
|
319
|
+
return builder;
|
|
320
|
+
} };
|
|
321
|
+
const getModelAnsi = (model, level, type, ...arguments_) => {
|
|
322
|
+
if (model === "rgb") {
|
|
323
|
+
if (level === "ansi16m") return ansiStyles[type].ansi16m(...arguments_);
|
|
324
|
+
if (level === "ansi256") return ansiStyles[type].ansi256(ansiStyles.rgbToAnsi256(...arguments_));
|
|
325
|
+
return ansiStyles[type].ansi(ansiStyles.rgbToAnsi(...arguments_));
|
|
326
|
+
}
|
|
327
|
+
if (model === "hex") return getModelAnsi("rgb", level, type, ...ansiStyles.hexToRgb(...arguments_));
|
|
328
|
+
return ansiStyles[type][model](...arguments_);
|
|
329
|
+
};
|
|
330
|
+
for (const model of [
|
|
331
|
+
"rgb",
|
|
332
|
+
"hex",
|
|
333
|
+
"ansi256"
|
|
334
|
+
]) {
|
|
335
|
+
styles[model] = { get() {
|
|
336
|
+
const { level } = this;
|
|
337
|
+
return function(...arguments_) {
|
|
338
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "color", ...arguments_), ansiStyles.color.close, this[STYLER]);
|
|
339
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
340
|
+
};
|
|
341
|
+
} };
|
|
342
|
+
const bgModel = "bg" + model[0].toUpperCase() + model.slice(1);
|
|
343
|
+
styles[bgModel] = { get() {
|
|
344
|
+
const { level } = this;
|
|
345
|
+
return function(...arguments_) {
|
|
346
|
+
const styler = createStyler(getModelAnsi(model, levelMapping[level], "bgColor", ...arguments_), ansiStyles.bgColor.close, this[STYLER]);
|
|
347
|
+
return createBuilder(this, styler, this[IS_EMPTY]);
|
|
348
|
+
};
|
|
349
|
+
} };
|
|
350
|
+
}
|
|
351
|
+
const proto = Object.defineProperties(() => {}, {
|
|
352
|
+
...styles,
|
|
353
|
+
level: {
|
|
354
|
+
enumerable: true,
|
|
355
|
+
get() {
|
|
356
|
+
return this[GENERATOR].level;
|
|
357
|
+
},
|
|
358
|
+
set(level) {
|
|
359
|
+
this[GENERATOR].level = level;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
const createStyler = (open, close, parent) => {
|
|
364
|
+
let openAll;
|
|
365
|
+
let closeAll;
|
|
366
|
+
if (parent === void 0) {
|
|
367
|
+
openAll = open;
|
|
368
|
+
closeAll = close;
|
|
369
|
+
} else {
|
|
370
|
+
openAll = parent.openAll + open;
|
|
371
|
+
closeAll = close + parent.closeAll;
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
open,
|
|
375
|
+
close,
|
|
376
|
+
openAll,
|
|
377
|
+
closeAll,
|
|
378
|
+
parent
|
|
379
|
+
};
|
|
380
|
+
};
|
|
381
|
+
const createBuilder = (self, _styler, _isEmpty) => {
|
|
382
|
+
const builder = (...arguments_) => applyStyle(builder, arguments_.length === 1 ? "" + arguments_[0] : arguments_.join(" "));
|
|
383
|
+
Object.setPrototypeOf(builder, proto);
|
|
384
|
+
builder[GENERATOR] = self;
|
|
385
|
+
builder[STYLER] = _styler;
|
|
386
|
+
builder[IS_EMPTY] = _isEmpty;
|
|
387
|
+
return builder;
|
|
388
|
+
};
|
|
389
|
+
const applyStyle = (self, string) => {
|
|
390
|
+
if (self.level <= 0 || !string) return self[IS_EMPTY] ? "" : string;
|
|
391
|
+
let styler = self[STYLER];
|
|
392
|
+
if (styler === void 0) return string;
|
|
393
|
+
const { openAll, closeAll } = styler;
|
|
394
|
+
if (string.includes("\x1B")) while (styler !== void 0) {
|
|
395
|
+
string = stringReplaceAll(string, styler.close, styler.open);
|
|
396
|
+
styler = styler.parent;
|
|
397
|
+
}
|
|
398
|
+
const lfIndex = string.indexOf("\n");
|
|
399
|
+
if (lfIndex !== -1) string = stringEncaseCRLFWithFirstIndex(string, closeAll, openAll, lfIndex);
|
|
400
|
+
return openAll + string + closeAll;
|
|
401
|
+
};
|
|
402
|
+
Object.defineProperties(createChalk.prototype, styles);
|
|
403
|
+
const chalk = createChalk();
|
|
404
|
+
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region src/theme.ts
|
|
407
|
+
/**
|
|
408
|
+
* Terminal color tokens for the dsh TUI, mapped from the product design
|
|
409
|
+
* platform's DeepSeek palette
|
|
410
|
+
* (`packages/client/ui-theme/src/styles/design-platform.css`). Truecolor RGB
|
|
411
|
+
* rides chalk, which degrades automatically on terminals without truecolor.
|
|
412
|
+
*
|
|
413
|
+
* Two palettes — `dark` (the default) and `light` — share the same token keys
|
|
414
|
+
* with different values. Painters and the palette accessor read the ACTIVE
|
|
415
|
+
* palette selected through {@link setTheme}, so a theme switch recolors every
|
|
416
|
+
* painted surface on the next render without touching call sites. Raw token
|
|
417
|
+
* consumers keep reading {@link TUI_RGB} (the dark values) until the
|
|
418
|
+
* theme-aware integration replaces those call sites with
|
|
419
|
+
* `inkColor(getPalette().token)`.
|
|
420
|
+
*
|
|
421
|
+
* @module @deepseek-ai/dsh-tui/theme
|
|
422
|
+
*/
|
|
423
|
+
/** Valid theme names in canonical picker order. */
|
|
424
|
+
const THEME_NAMES = [
|
|
425
|
+
"dark",
|
|
426
|
+
"light",
|
|
427
|
+
"auto"
|
|
428
|
+
];
|
|
429
|
+
/**
|
|
430
|
+
* DeepSeek dark palette: the original TUI colors, one entry per
|
|
431
|
+
* design-platform token in use. Keep names and values in sync with the CSS
|
|
432
|
+
* custom properties cited inline.
|
|
433
|
+
*/
|
|
434
|
+
const DARK_PALETTE = {
|
|
435
|
+
/** Primary brand blue — `--dsw-static-deepseek-500`. */
|
|
436
|
+
brand: [
|
|
437
|
+
65,
|
|
438
|
+
118,
|
|
439
|
+
230
|
|
440
|
+
],
|
|
441
|
+
/** Brighter brand blue for live/streaming emphasis — `--dsw-static-deepseek-400`. */
|
|
442
|
+
brandBright: [
|
|
443
|
+
103,
|
|
444
|
+
158,
|
|
445
|
+
254
|
|
446
|
+
],
|
|
447
|
+
/** Intermediate brand blue between brand and brandBright — `--dsw-static-deepseek-450`. */
|
|
448
|
+
brandMid: [
|
|
449
|
+
86,
|
|
450
|
+
134,
|
|
451
|
+
254
|
|
452
|
+
],
|
|
453
|
+
/** Deep brand blue for secondary chrome — `--dsw-static-deepseek-600`. */
|
|
454
|
+
brandDeep: [
|
|
455
|
+
72,
|
|
456
|
+
104,
|
|
457
|
+
178
|
|
458
|
+
],
|
|
459
|
+
/** Muted caption gray — `--dsw-static-neutral-bluish-600`. */
|
|
460
|
+
dim: [
|
|
461
|
+
129,
|
|
462
|
+
133,
|
|
463
|
+
140
|
|
464
|
+
],
|
|
465
|
+
/** Success green — `--dsw-static-green-500`. */
|
|
466
|
+
success: [
|
|
467
|
+
34,
|
|
468
|
+
197,
|
|
469
|
+
94
|
|
470
|
+
],
|
|
471
|
+
/** Error red — `--dsw-static-red-500`. */
|
|
472
|
+
error: [
|
|
473
|
+
239,
|
|
474
|
+
68,
|
|
475
|
+
68
|
|
476
|
+
],
|
|
477
|
+
/** Warning amber — `--dsw-static-amber-500`. */
|
|
478
|
+
warn: [
|
|
479
|
+
245,
|
|
480
|
+
158,
|
|
481
|
+
11
|
|
482
|
+
],
|
|
483
|
+
/** Default foreground text — `--dsw-static-neutral-50`. */
|
|
484
|
+
text: [
|
|
485
|
+
236,
|
|
486
|
+
240,
|
|
487
|
+
246
|
|
488
|
+
],
|
|
489
|
+
/** Inline/fenced code — soft sky blue, distinct from brand accents. */
|
|
490
|
+
code: [
|
|
491
|
+
125,
|
|
492
|
+
211,
|
|
493
|
+
252
|
|
494
|
+
]
|
|
495
|
+
};
|
|
496
|
+
/** Every palette by theme name; auto resolves through {@link resolveTheme}. */
|
|
497
|
+
const PALETTES = {
|
|
498
|
+
dark: DARK_PALETTE,
|
|
499
|
+
light: {
|
|
500
|
+
/** Primary brand blue — unchanged, ≈4.9:1 AA on white. */
|
|
501
|
+
brand: [
|
|
502
|
+
65,
|
|
503
|
+
118,
|
|
504
|
+
230
|
|
505
|
+
],
|
|
506
|
+
/** Brighter brand blue deepened for white backgrounds (was 2.7:1). */
|
|
507
|
+
brandBright: [
|
|
508
|
+
72,
|
|
509
|
+
104,
|
|
510
|
+
178
|
|
511
|
+
],
|
|
512
|
+
/** Intermediate brand blue — Tailwind blue-500. */
|
|
513
|
+
brandMid: [
|
|
514
|
+
59,
|
|
515
|
+
130,
|
|
516
|
+
246
|
|
517
|
+
],
|
|
518
|
+
/** Deep brand blue for secondary chrome — `--dsw-static-deepseek-700`. */
|
|
519
|
+
brandDeep: [
|
|
520
|
+
47,
|
|
521
|
+
76,
|
|
522
|
+
143
|
|
523
|
+
],
|
|
524
|
+
/** Muted caption gray deepened for white backgrounds. */
|
|
525
|
+
dim: [
|
|
526
|
+
101,
|
|
527
|
+
103,
|
|
528
|
+
107
|
|
529
|
+
],
|
|
530
|
+
/** Success green — Tailwind green-700. */
|
|
531
|
+
success: [
|
|
532
|
+
21,
|
|
533
|
+
128,
|
|
534
|
+
61
|
|
535
|
+
],
|
|
536
|
+
/** Error red — Tailwind red-600. */
|
|
537
|
+
error: [
|
|
538
|
+
236,
|
|
539
|
+
19,
|
|
540
|
+
19
|
|
541
|
+
],
|
|
542
|
+
/** Warning amber — Tailwind amber-700. */
|
|
543
|
+
warn: [
|
|
544
|
+
180,
|
|
545
|
+
83,
|
|
546
|
+
9
|
|
547
|
+
],
|
|
548
|
+
/** Default foreground text — near-black. */
|
|
549
|
+
text: [
|
|
550
|
+
21,
|
|
551
|
+
21,
|
|
552
|
+
23
|
|
553
|
+
],
|
|
554
|
+
/** Inline/fenced code — Tailwind cyan-700, distinct from brand accents. */
|
|
555
|
+
code: [
|
|
556
|
+
14,
|
|
557
|
+
116,
|
|
558
|
+
144
|
|
559
|
+
]
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
/** The theme name in force (the requested name; 'auto' included). */
|
|
563
|
+
let activeName = "dark";
|
|
564
|
+
/** The palette painters and {@link getPalette} read for the active theme. */
|
|
565
|
+
let activePalette = DARK_PALETTE;
|
|
566
|
+
/**
|
|
567
|
+
* Resolve a theme name to the palette actually in use. `auto` detection
|
|
568
|
+
* (OSC 11 terminal background query) is a later enhancement; until it lands,
|
|
569
|
+
* auto falls back to the dark palette.
|
|
570
|
+
* @param name - the requested theme name.
|
|
571
|
+
* @returns 'dark' or 'light' — the palette key to paint with.
|
|
572
|
+
*/
|
|
573
|
+
function resolveTheme(name) {
|
|
574
|
+
return name === "light" ? "light" : "dark";
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Switch the active theme: painters and {@link getPalette} reflect the new
|
|
578
|
+
* palette from the next render onward. The default is dark, so a process
|
|
579
|
+
* that never calls this paints exactly as before.
|
|
580
|
+
* @param name - the theme to activate ('auto' resolves to dark for now).
|
|
581
|
+
*/
|
|
582
|
+
function setTheme(name) {
|
|
583
|
+
activeName = name;
|
|
584
|
+
activePalette = PALETTES[resolveTheme(name)];
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* The theme name in force. Returns the requested name ('auto' included) so
|
|
588
|
+
* the /theme picker and persistence can round-trip the user's choice; the
|
|
589
|
+
* palette actually used is {@link getPalette}.
|
|
590
|
+
*/
|
|
591
|
+
function getTheme() {
|
|
592
|
+
return activeName;
|
|
593
|
+
}
|
|
594
|
+
/** The palette in force; theme-aware call sites read colors through it. */
|
|
595
|
+
function getPalette() {
|
|
596
|
+
return activePalette;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Parse a persisted theme name: only 'light' and 'auto' survive; anything
|
|
600
|
+
* else (missing, corrupt, or unknown) falls back to the dark default.
|
|
601
|
+
* @param value - the raw parsed JSON value (expected string).
|
|
602
|
+
* @returns a valid theme name.
|
|
603
|
+
*/
|
|
604
|
+
function parseThemeName(value) {
|
|
605
|
+
return value === "light" || value === "auto" ? value : "dark";
|
|
606
|
+
}
|
|
607
|
+
/** Ink `color` string for one RGB triple. */
|
|
608
|
+
function inkColor(triple) {
|
|
609
|
+
return `rgb(${triple[0]}, ${triple[1]}, ${triple[2]})`;
|
|
610
|
+
}
|
|
611
|
+
/** Paint with the primary brand blue: whale, wordmark, tool names, accents. */
|
|
612
|
+
function brand(text) {
|
|
613
|
+
return chalk.rgb(...activePalette.brand)(text);
|
|
614
|
+
}
|
|
615
|
+
/** Paint muted captions, hints, and meta lines. */
|
|
616
|
+
function dim(text) {
|
|
617
|
+
return chalk.rgb(...activePalette.dim)(text);
|
|
618
|
+
}
|
|
619
|
+
/** Paint failures and error entries. */
|
|
620
|
+
function error(text) {
|
|
621
|
+
return chalk.rgb(...activePalette.error)(text);
|
|
622
|
+
}
|
|
623
|
+
//#endregion
|
|
624
|
+
export { getPalette as a, parseThemeName as c, error as i, setTheme as l, brand as n, getTheme as o, dim as r, inkColor as s, THEME_NAMES as t, chalk as u };
|