numux 1.22.0 → 1.23.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/dist/numux.js +128 -87
- package/dist/types.d.ts +2 -1
- package/dist/utils/color.d.ts +40 -0
- package/package.json +1 -1
package/dist/numux.js
CHANGED
|
@@ -36,7 +36,7 @@ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports,
|
|
|
36
36
|
var require_package = __commonJS((exports, module) => {
|
|
37
37
|
module.exports = {
|
|
38
38
|
name: "numux",
|
|
39
|
-
version: "1.
|
|
39
|
+
version: "1.23.0",
|
|
40
40
|
description: "Terminal multiplexer with dependency orchestration",
|
|
41
41
|
type: "module",
|
|
42
42
|
license: "MIT",
|
|
@@ -915,12 +915,12 @@ function findCycle(remaining, config) {
|
|
|
915
915
|
// src/utils/color.ts
|
|
916
916
|
var BASIC_COLORS = {
|
|
917
917
|
black: "#000000",
|
|
918
|
-
red: "#
|
|
919
|
-
green: "#
|
|
920
|
-
yellow: "#
|
|
921
|
-
blue: "#
|
|
922
|
-
magenta: "#
|
|
923
|
-
cyan: "#
|
|
918
|
+
red: "#ff5555",
|
|
919
|
+
green: "#00cc00",
|
|
920
|
+
yellow: "#cccc00",
|
|
921
|
+
blue: "#0000cc",
|
|
922
|
+
magenta: "#cc00cc",
|
|
923
|
+
cyan: "#00cccc",
|
|
924
924
|
white: "#ffffff",
|
|
925
925
|
gray: "#808080",
|
|
926
926
|
grey: "#808080",
|
|
@@ -949,35 +949,35 @@ function hexToAnsi(hex) {
|
|
|
949
949
|
}
|
|
950
950
|
var HEX_COLOR_RE = /^#?[0-9a-fA-F]{6}$/;
|
|
951
951
|
var STATUS_ANSI = {
|
|
952
|
-
ready:
|
|
953
|
-
running:
|
|
954
|
-
finished:
|
|
955
|
-
failed:
|
|
956
|
-
stopped:
|
|
957
|
-
skipped:
|
|
952
|
+
ready: hexToAnsi(BASIC_COLORS.green),
|
|
953
|
+
running: hexToAnsi(BASIC_COLORS.cyan),
|
|
954
|
+
finished: hexToAnsi(BASIC_COLORS.green),
|
|
955
|
+
failed: hexToAnsi(BASIC_COLORS.red),
|
|
956
|
+
stopped: hexToAnsi(BASIC_COLORS.gray),
|
|
957
|
+
skipped: hexToAnsi(BASIC_COLORS.gray)
|
|
958
958
|
};
|
|
959
959
|
var ANSI_RESET = "\x1B[0m";
|
|
960
960
|
var ANSI_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b[()#][0-9A-Za-z]|\x1b[A-Za-z><=]/g;
|
|
961
961
|
function stripAnsi(str) {
|
|
962
962
|
return str.replace(ANSI_RE, "");
|
|
963
963
|
}
|
|
964
|
-
var
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
964
|
+
var DEFAULT_PALETTE = [
|
|
965
|
+
BASIC_COLORS.cyan,
|
|
966
|
+
BASIC_COLORS.yellow,
|
|
967
|
+
BASIC_COLORS.magenta,
|
|
968
|
+
BASIC_COLORS.blue,
|
|
969
|
+
BASIC_COLORS.green,
|
|
970
|
+
BASIC_COLORS.red,
|
|
971
|
+
BASIC_COLORS.orange,
|
|
972
|
+
BASIC_COLORS.purple
|
|
973
973
|
];
|
|
974
|
-
var
|
|
974
|
+
var DEFAULT_ANSI_COLORS = DEFAULT_PALETTE.map(hexToAnsi);
|
|
975
975
|
function colorFromName(name) {
|
|
976
976
|
let hash = 0;
|
|
977
977
|
for (let i = 0;i < name.length; i++) {
|
|
978
978
|
hash = (hash << 5) - hash + name.charCodeAt(i) | 0;
|
|
979
979
|
}
|
|
980
|
-
return
|
|
980
|
+
return DEFAULT_PALETTE[Math.abs(hash) % DEFAULT_PALETTE.length];
|
|
981
981
|
}
|
|
982
982
|
function resolveColor(color) {
|
|
983
983
|
if (typeof color === "string")
|
|
@@ -1018,9 +1018,9 @@ function buildProcessHexColorMap(names, config) {
|
|
|
1018
1018
|
if (hex)
|
|
1019
1019
|
map.set(name, hex);
|
|
1020
1020
|
else
|
|
1021
|
-
map.set(name,
|
|
1021
|
+
map.set(name, DEFAULT_PALETTE[paletteIndex++ % DEFAULT_PALETTE.length]);
|
|
1022
1022
|
} else {
|
|
1023
|
-
map.set(name,
|
|
1023
|
+
map.set(name, DEFAULT_PALETTE[paletteIndex % DEFAULT_PALETTE.length]);
|
|
1024
1024
|
paletteIndex++;
|
|
1025
1025
|
}
|
|
1026
1026
|
}
|
|
@@ -2180,8 +2180,6 @@ class Pane {
|
|
|
2180
2180
|
_onScroll = null;
|
|
2181
2181
|
_onCopy = null;
|
|
2182
2182
|
_onLinkClick = null;
|
|
2183
|
-
_textLines = null;
|
|
2184
|
-
_textLinesLower = null;
|
|
2185
2183
|
constructor(renderer, name, cols, rows, interactive = false) {
|
|
2186
2184
|
this.scrollBox = new ScrollBoxRenderable(renderer, {
|
|
2187
2185
|
id: `pane-${name}`,
|
|
@@ -2228,14 +2226,10 @@ class Pane {
|
|
|
2228
2226
|
feed(data) {
|
|
2229
2227
|
const text = this.decoder.decode(data, { stream: true });
|
|
2230
2228
|
this.terminal.feed(text);
|
|
2231
|
-
this._textLines = null;
|
|
2232
|
-
this._textLinesLower = null;
|
|
2233
2229
|
}
|
|
2234
2230
|
resize(cols, rows) {
|
|
2235
2231
|
this.terminal.cols = cols;
|
|
2236
2232
|
this.terminal.rows = rows;
|
|
2237
|
-
this._textLines = null;
|
|
2238
|
-
this._textLinesLower = null;
|
|
2239
2233
|
}
|
|
2240
2234
|
get isAtBottom() {
|
|
2241
2235
|
const { scrollTop, scrollHeight, viewport } = this.scrollBox;
|
|
@@ -2265,16 +2259,13 @@ class Pane {
|
|
|
2265
2259
|
this._onLinkClick = handler;
|
|
2266
2260
|
}
|
|
2267
2261
|
getLinkAtMouse(localX, localY) {
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
this._textLines = text.split(`
|
|
2262
|
+
const text = this.terminal.getText();
|
|
2263
|
+
const lines = text.split(`
|
|
2271
2264
|
`);
|
|
2272
|
-
this._textLinesLower = this._textLines.map((l) => l.toLowerCase());
|
|
2273
|
-
}
|
|
2274
2265
|
const lineIndex = Math.floor(this.scrollBox.scrollTop) + localY;
|
|
2275
|
-
if (lineIndex < 0 || lineIndex >=
|
|
2266
|
+
if (lineIndex < 0 || lineIndex >= lines.length)
|
|
2276
2267
|
return null;
|
|
2277
|
-
return findLinkAtPosition(
|
|
2268
|
+
return findLinkAtPosition(lines[lineIndex], localX);
|
|
2278
2269
|
}
|
|
2279
2270
|
show() {
|
|
2280
2271
|
this.scrollBox.visible = true;
|
|
@@ -2282,30 +2273,6 @@ class Pane {
|
|
|
2282
2273
|
hide() {
|
|
2283
2274
|
this.scrollBox.visible = false;
|
|
2284
2275
|
}
|
|
2285
|
-
search(query) {
|
|
2286
|
-
if (!query)
|
|
2287
|
-
return [];
|
|
2288
|
-
if (!this._textLines) {
|
|
2289
|
-
const text = this.terminal.getText();
|
|
2290
|
-
this._textLines = text.split(`
|
|
2291
|
-
`);
|
|
2292
|
-
this._textLinesLower = this._textLines.map((l) => l.toLowerCase());
|
|
2293
|
-
}
|
|
2294
|
-
const lines = this._textLinesLower;
|
|
2295
|
-
const matches = [];
|
|
2296
|
-
const lowerQuery = query.toLowerCase();
|
|
2297
|
-
for (let line = 0;line < lines.length; line++) {
|
|
2298
|
-
let pos = 0;
|
|
2299
|
-
while (true) {
|
|
2300
|
-
const idx = lines[line].indexOf(lowerQuery, pos);
|
|
2301
|
-
if (idx === -1)
|
|
2302
|
-
break;
|
|
2303
|
-
matches.push({ line, start: idx, end: idx + query.length });
|
|
2304
|
-
pos = idx + 1;
|
|
2305
|
-
}
|
|
2306
|
-
}
|
|
2307
|
-
return matches;
|
|
2308
|
-
}
|
|
2309
2276
|
setHighlights(matches, currentIndex) {
|
|
2310
2277
|
const firstVisible = Math.max(0, Math.floor(this.scrollBox.scrollTop) - 2);
|
|
2311
2278
|
const lastVisible = Math.ceil(this.scrollBox.scrollTop + this.scrollBox.viewport.height) + 2;
|
|
@@ -2334,8 +2301,6 @@ class Pane {
|
|
|
2334
2301
|
}
|
|
2335
2302
|
clear() {
|
|
2336
2303
|
this.terminal.reset();
|
|
2337
|
-
this._textLines = null;
|
|
2338
|
-
this._textLinesLower = null;
|
|
2339
2304
|
}
|
|
2340
2305
|
destroy() {
|
|
2341
2306
|
this.terminal.destroy();
|
|
@@ -2664,6 +2629,7 @@ class App {
|
|
|
2664
2629
|
termRows = 24;
|
|
2665
2630
|
sidebarWidth = 20;
|
|
2666
2631
|
config;
|
|
2632
|
+
logWriter;
|
|
2667
2633
|
resizeTimer = null;
|
|
2668
2634
|
searchTimer = null;
|
|
2669
2635
|
searchMode = false;
|
|
@@ -2672,9 +2638,10 @@ class App {
|
|
|
2672
2638
|
searchIndex = -1;
|
|
2673
2639
|
inputWaitTimers = new Map;
|
|
2674
2640
|
awaitingInput = new Set;
|
|
2675
|
-
constructor(manager, config) {
|
|
2641
|
+
constructor(manager, config, logWriter) {
|
|
2676
2642
|
this.manager = manager;
|
|
2677
2643
|
this.config = config;
|
|
2644
|
+
this.logWriter = logWriter;
|
|
2678
2645
|
this.names = manager.getProcessNames();
|
|
2679
2646
|
}
|
|
2680
2647
|
async start() {
|
|
@@ -2832,6 +2799,7 @@ class App {
|
|
|
2832
2799
|
}
|
|
2833
2800
|
if (name === SHORTCUTS.clear.key) {
|
|
2834
2801
|
this.panes.get(this.activePane)?.clear();
|
|
2802
|
+
this.logWriter.truncate(this.activePane);
|
|
2835
2803
|
return;
|
|
2836
2804
|
}
|
|
2837
2805
|
const num = Number.parseInt(name, 10);
|
|
@@ -3004,14 +2972,16 @@ class App {
|
|
|
3004
2972
|
this.runSearch();
|
|
3005
2973
|
}, 100);
|
|
3006
2974
|
}
|
|
3007
|
-
runSearch() {
|
|
2975
|
+
async runSearch() {
|
|
3008
2976
|
if (!this.activePane)
|
|
3009
2977
|
return;
|
|
3010
|
-
const
|
|
3011
|
-
|
|
2978
|
+
const query = this.searchQuery;
|
|
2979
|
+
const activeName = this.activePane;
|
|
2980
|
+
const matches = await this.logWriter.search(activeName, query);
|
|
2981
|
+
if (!this.searchMode || this.searchQuery !== query || this.activePane !== activeName)
|
|
3012
2982
|
return;
|
|
3013
|
-
this.searchMatches =
|
|
3014
|
-
this.searchIndex =
|
|
2983
|
+
this.searchMatches = matches;
|
|
2984
|
+
this.searchIndex = matches.length > 0 ? 0 : -1;
|
|
3015
2985
|
this.updateSearchHighlights();
|
|
3016
2986
|
if (this.searchIndex >= 0) {
|
|
3017
2987
|
this.scrollToCurrentMatch();
|
|
@@ -3179,7 +3149,7 @@ class PrefixDisplay {
|
|
|
3179
3149
|
const allDone = states.every((s) => s.status === "stopped" || s.status === "finished" || s.status === "failed" || s.status === "skipped");
|
|
3180
3150
|
if (allDone) {
|
|
3181
3151
|
this.printSummary();
|
|
3182
|
-
this.logWriter?.
|
|
3152
|
+
this.logWriter?.cleanup();
|
|
3183
3153
|
const anyFailed = states.some((s) => s.status === "failed");
|
|
3184
3154
|
process.exit(anyFailed ? 1 : 0);
|
|
3185
3155
|
}
|
|
@@ -3195,7 +3165,7 @@ class PrefixDisplay {
|
|
|
3195
3165
|
this.flushBuffer(name);
|
|
3196
3166
|
}
|
|
3197
3167
|
this.printSummary();
|
|
3198
|
-
this.logWriter?.
|
|
3168
|
+
this.logWriter?.cleanup();
|
|
3199
3169
|
process.exit(code === 0 ? 0 : 1);
|
|
3200
3170
|
});
|
|
3201
3171
|
}
|
|
@@ -3247,24 +3217,31 @@ ${DIM}Done in ${elapsed}${RESET}
|
|
|
3247
3217
|
for (const name of this.manager.getProcessNames()) {
|
|
3248
3218
|
this.flushBuffer(name);
|
|
3249
3219
|
}
|
|
3250
|
-
this.logWriter?.
|
|
3220
|
+
this.logWriter?.cleanup();
|
|
3251
3221
|
const anyFailed = this.manager.getAllStates().some((s) => s.status === "failed");
|
|
3252
3222
|
process.exit(anyFailed ? 1 : 0);
|
|
3253
3223
|
}
|
|
3254
3224
|
}
|
|
3255
3225
|
|
|
3256
3226
|
// src/utils/log-writer.ts
|
|
3257
|
-
import { closeSync, mkdirSync as mkdirSync2, openSync, writeSync } from "fs";
|
|
3227
|
+
import { closeSync, mkdirSync as mkdirSync2, openSync, rmSync, writeSync } from "fs";
|
|
3228
|
+
import { tmpdir } from "os";
|
|
3258
3229
|
import { join } from "path";
|
|
3259
3230
|
class LogWriter {
|
|
3260
3231
|
dir;
|
|
3232
|
+
isTemp;
|
|
3261
3233
|
files = new Map;
|
|
3262
3234
|
decoder = new TextDecoder;
|
|
3263
3235
|
encoder = new TextEncoder;
|
|
3264
|
-
constructor(dir) {
|
|
3236
|
+
constructor(dir, isTemp = false) {
|
|
3265
3237
|
this.dir = dir;
|
|
3238
|
+
this.isTemp = isTemp;
|
|
3266
3239
|
mkdirSync2(dir, { recursive: true });
|
|
3267
3240
|
}
|
|
3241
|
+
static createTemp() {
|
|
3242
|
+
const dir = join(tmpdir(), `numux-${process.pid}`);
|
|
3243
|
+
return new LogWriter(dir, true);
|
|
3244
|
+
}
|
|
3268
3245
|
errored = false;
|
|
3269
3246
|
handleEvent = (event) => {
|
|
3270
3247
|
if (event.type !== "output" || this.errored)
|
|
@@ -3285,12 +3262,81 @@ class LogWriter {
|
|
|
3285
3262
|
`);
|
|
3286
3263
|
}
|
|
3287
3264
|
};
|
|
3265
|
+
getLogPath(name) {
|
|
3266
|
+
if (this.files.has(name)) {
|
|
3267
|
+
return join(this.dir, `${name}.log`);
|
|
3268
|
+
}
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
async search(name, query) {
|
|
3272
|
+
if (!query)
|
|
3273
|
+
return [];
|
|
3274
|
+
const path = this.getLogPath(name);
|
|
3275
|
+
if (!path)
|
|
3276
|
+
return [];
|
|
3277
|
+
try {
|
|
3278
|
+
const proc = Bun.spawn(["grep", "-inF", query, path], {
|
|
3279
|
+
stdout: "pipe",
|
|
3280
|
+
stderr: "ignore"
|
|
3281
|
+
});
|
|
3282
|
+
const output = await new Response(proc.stdout).text();
|
|
3283
|
+
await proc.exited;
|
|
3284
|
+
const matches = [];
|
|
3285
|
+
const lowerQuery = query.toLowerCase();
|
|
3286
|
+
for (const line of output.split(`
|
|
3287
|
+
`)) {
|
|
3288
|
+
if (!line)
|
|
3289
|
+
continue;
|
|
3290
|
+
const colonIdx = line.indexOf(":");
|
|
3291
|
+
if (colonIdx === -1)
|
|
3292
|
+
continue;
|
|
3293
|
+
const lineNumber = Number.parseInt(line.slice(0, colonIdx), 10);
|
|
3294
|
+
if (Number.isNaN(lineNumber))
|
|
3295
|
+
continue;
|
|
3296
|
+
const lineText = line.slice(colonIdx + 1).toLowerCase();
|
|
3297
|
+
let pos = 0;
|
|
3298
|
+
while (true) {
|
|
3299
|
+
const idx = lineText.indexOf(lowerQuery, pos);
|
|
3300
|
+
if (idx === -1)
|
|
3301
|
+
break;
|
|
3302
|
+
matches.push({
|
|
3303
|
+
line: lineNumber - 1,
|
|
3304
|
+
start: idx,
|
|
3305
|
+
end: idx + query.length
|
|
3306
|
+
});
|
|
3307
|
+
pos = idx + 1;
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
return matches;
|
|
3311
|
+
} catch {
|
|
3312
|
+
return [];
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
truncate(name) {
|
|
3316
|
+
const fd = this.files.get(name);
|
|
3317
|
+
if (fd === undefined)
|
|
3318
|
+
return;
|
|
3319
|
+
try {
|
|
3320
|
+
closeSync(fd);
|
|
3321
|
+
const path = join(this.dir, `${name}.log`);
|
|
3322
|
+
const newFd = openSync(path, "w");
|
|
3323
|
+
this.files.set(name, newFd);
|
|
3324
|
+
} catch {}
|
|
3325
|
+
}
|
|
3288
3326
|
close() {
|
|
3289
3327
|
for (const fd of this.files.values()) {
|
|
3290
3328
|
closeSync(fd);
|
|
3291
3329
|
}
|
|
3292
3330
|
this.files.clear();
|
|
3293
3331
|
}
|
|
3332
|
+
cleanup() {
|
|
3333
|
+
this.close();
|
|
3334
|
+
if (this.isTemp) {
|
|
3335
|
+
try {
|
|
3336
|
+
rmSync(this.dir, { recursive: true });
|
|
3337
|
+
} catch {}
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3294
3340
|
}
|
|
3295
3341
|
|
|
3296
3342
|
// src/utils/shutdown.ts
|
|
@@ -3302,7 +3348,7 @@ function setupShutdownHandlers(app, logWriter) {
|
|
|
3302
3348
|
}
|
|
3303
3349
|
shuttingDown = true;
|
|
3304
3350
|
app.shutdown().finally(() => {
|
|
3305
|
-
logWriter?.
|
|
3351
|
+
logWriter?.cleanup();
|
|
3306
3352
|
process.exit(app.hasFailures() ? 1 : 0);
|
|
3307
3353
|
});
|
|
3308
3354
|
};
|
|
@@ -3313,7 +3359,7 @@ function setupShutdownHandlers(app, logWriter) {
|
|
|
3313
3359
|
process.stderr.write(`numux: unexpected error: ${err?.stack ?? err}
|
|
3314
3360
|
`);
|
|
3315
3361
|
app.shutdown().finally(() => {
|
|
3316
|
-
logWriter?.
|
|
3362
|
+
logWriter?.cleanup();
|
|
3317
3363
|
process.exit(1);
|
|
3318
3364
|
});
|
|
3319
3365
|
});
|
|
@@ -3323,7 +3369,7 @@ function setupShutdownHandlers(app, logWriter) {
|
|
|
3323
3369
|
process.stderr.write(`numux: unhandled rejection: ${message}
|
|
3324
3370
|
`);
|
|
3325
3371
|
app.shutdown().finally(() => {
|
|
3326
|
-
logWriter?.
|
|
3372
|
+
logWriter?.cleanup();
|
|
3327
3373
|
process.exit(1);
|
|
3328
3374
|
});
|
|
3329
3375
|
});
|
|
@@ -3530,10 +3576,7 @@ async function main() {
|
|
|
3530
3576
|
}
|
|
3531
3577
|
}
|
|
3532
3578
|
const manager = new ProcessManager(config);
|
|
3533
|
-
|
|
3534
|
-
if (parsed.logDir) {
|
|
3535
|
-
logWriter = new LogWriter(parsed.logDir);
|
|
3536
|
-
}
|
|
3579
|
+
const logWriter = parsed.logDir ? new LogWriter(parsed.logDir) : LogWriter.createTemp();
|
|
3537
3580
|
printWarnings(warnings);
|
|
3538
3581
|
if (parsed.prefix) {
|
|
3539
3582
|
if (!parsed.noRestart) {
|
|
@@ -3548,10 +3591,8 @@ async function main() {
|
|
|
3548
3591
|
});
|
|
3549
3592
|
await display.start();
|
|
3550
3593
|
} else {
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
}
|
|
3554
|
-
const app = new App(manager, config);
|
|
3594
|
+
manager.on(logWriter.handleEvent);
|
|
3595
|
+
const app = new App(manager, config, logWriter);
|
|
3555
3596
|
setupShutdownHandlers(app, logWriter);
|
|
3556
3597
|
await app.start();
|
|
3557
3598
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Color } from './utils/color';
|
|
1
2
|
export interface NumuxProcessConfig<K extends string = string> {
|
|
2
3
|
/** Shell command to run. Supports `$dep.group` references from dependency capture groups */
|
|
3
4
|
command: string;
|
|
@@ -39,7 +40,7 @@ export interface NumuxProcessConfig<K extends string = string> {
|
|
|
39
40
|
*/
|
|
40
41
|
stopSignal?: 'SIGTERM' | 'SIGINT' | 'SIGHUP';
|
|
41
42
|
/** Hex color (e.g. `"#ff6600"`) or color name. Array for round-robin in script patterns */
|
|
42
|
-
color?:
|
|
43
|
+
color?: Color | Color[];
|
|
43
44
|
/** Glob patterns — restart process when matching files change */
|
|
44
45
|
watch?: string | string[];
|
|
45
46
|
/**
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Basic color names mapped to muted hex tones (lowercase keys) */
|
|
2
|
+
export type BasicColor = keyof typeof BASIC_COLORS;
|
|
3
|
+
export type Color = `#${string}` | BasicColor;
|
|
4
|
+
export declare const BASIC_COLORS: {
|
|
5
|
+
readonly black: "#000000";
|
|
6
|
+
readonly red: "#ff5555";
|
|
7
|
+
readonly green: "#00cc00";
|
|
8
|
+
readonly yellow: "#cccc00";
|
|
9
|
+
readonly blue: "#0000cc";
|
|
10
|
+
readonly magenta: "#cc00cc";
|
|
11
|
+
readonly cyan: "#00cccc";
|
|
12
|
+
readonly white: "#ffffff";
|
|
13
|
+
readonly gray: "#808080";
|
|
14
|
+
readonly grey: "#808080";
|
|
15
|
+
readonly orange: "#ffa500";
|
|
16
|
+
readonly purple: "#800080";
|
|
17
|
+
};
|
|
18
|
+
/** Check if a string is a valid color (hex or basic name) */
|
|
19
|
+
export declare function isValidColor(color: string): boolean;
|
|
20
|
+
/** Resolve any color (hex or basic name) to normalized hex (#rrggbb) */
|
|
21
|
+
export declare function resolveToHex(color: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Convert a hex color string (e.g. "#ff8800") to an ANSI true-color escape sequence.
|
|
24
|
+
* Returns an empty string if the hex is malformed.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hexToAnsi(hex: string): string;
|
|
27
|
+
/** Regex matching a valid 6-digit hex color (with or without leading #) */
|
|
28
|
+
export declare const HEX_COLOR_RE: RegExp;
|
|
29
|
+
import type { ProcessStatus, ResolvedNumuxConfig } from '../types';
|
|
30
|
+
/** ANSI color codes for process statuses */
|
|
31
|
+
export declare const STATUS_ANSI: Partial<Record<ProcessStatus, string>>;
|
|
32
|
+
export declare const ANSI_RESET = "\u001B[0m";
|
|
33
|
+
/** Strip ANSI escape sequences from text */
|
|
34
|
+
export declare function stripAnsi(str: string): string;
|
|
35
|
+
/** Pick a deterministic color from the default palette based on the process name */
|
|
36
|
+
export declare function colorFromName(name: string): Color;
|
|
37
|
+
/** Build a map of process names to ANSI color codes, using explicit config colors or a default palette. */
|
|
38
|
+
export declare function buildProcessColorMap(names: string[], config: ResolvedNumuxConfig): Map<string, string>;
|
|
39
|
+
/** Build a map of process names to hex color strings (for StyledText rendering). */
|
|
40
|
+
export declare function buildProcessHexColorMap(names: string[], config: ResolvedNumuxConfig): Map<string, string>;
|