numux 2.10.0 → 2.10.1

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.md CHANGED
@@ -130,7 +130,7 @@ numux -w dev -n redis="redis-server" --colors
130
130
  # Unnamed (name derived from command)
131
131
  numux "bun dev:api" "bun dev:web"
132
132
 
133
- # Named
133
+ # Named process
134
134
  numux -n api="bun dev:api" -n web="bun dev:web"
135
135
  ```
136
136
 
package/dist/config.js CHANGED
@@ -1,3 +1,4 @@
1
+ // @bun
1
2
  // src/config.ts
2
3
  function defineConfig(config) {
3
4
  return config;
package/dist/numux.js CHANGED
@@ -37,7 +37,7 @@ var __require = import.meta.require;
37
37
  var require_package = __commonJS((exports, module) => {
38
38
  module.exports = {
39
39
  name: "numux",
40
- version: "2.10.0",
40
+ version: "2.10.1",
41
41
  description: "Terminal multiplexer with dependency orchestration",
42
42
  type: "module",
43
43
  license: "MIT",
@@ -67,7 +67,7 @@ var require_package = __commonJS((exports, module) => {
67
67
  }
68
68
  },
69
69
  scripts: {
70
- build: "bun build src/index.ts --outfile dist/numux.js --target bun --packages external && bun build src/config.ts --outfile dist/config.js --packages external && bunx tsc src/config.ts src/types.ts --emitDeclarationOnly --declaration --outDir dist --target ESNext --module ESNext --moduleResolution bundler && cp src/bin-wrapper.js dist/bin.js",
70
+ build: "bun run build.ts",
71
71
  prepublishOnly: "bun run build",
72
72
  dev: "cd example && bun run dev --debug",
73
73
  test: "bun test",
@@ -2320,7 +2320,407 @@ import {
2320
2320
  LineNumberRenderable,
2321
2321
  ScrollBoxRenderable
2322
2322
  } from "@opentui/core";
2323
- import { GhosttyTerminalRenderable } from "ghostty-opentui/terminal-buffer";
2323
+
2324
+ // node_modules/ghostty-opentui/src/terminal-buffer.ts
2325
+ import {
2326
+ TextBufferRenderable,
2327
+ StyledText,
2328
+ RGBA
2329
+ } from "@opentui/core";
2330
+ import { ptyToJson, PersistentTerminal, hasPersistentTerminalSupport, StyleFlags } from "ghostty-opentui";
2331
+ var DEFAULT_FG = RGBA.fromHex("#d4d4d4");
2332
+ var DEFAULT_BG = RGBA.fromHex("#1e1e1e");
2333
+ var TextAttributes = {
2334
+ BOLD: 1 << 0,
2335
+ DIM: 1 << 1,
2336
+ ITALIC: 1 << 2,
2337
+ UNDERLINE: 1 << 3,
2338
+ BLINK: 1 << 4,
2339
+ REVERSE: 1 << 5,
2340
+ HIDDEN: 1 << 6,
2341
+ STRIKETHROUGH: 1 << 7
2342
+ };
2343
+ function convertSpanToChunk(span) {
2344
+ const { text, fg, bg, flags } = span;
2345
+ let fgColor = fg ? RGBA.fromHex(fg) : DEFAULT_FG;
2346
+ let bgColor = bg ? RGBA.fromHex(bg) : undefined;
2347
+ if (flags & StyleFlags.INVERSE) {
2348
+ const temp = fgColor;
2349
+ fgColor = bgColor || DEFAULT_BG;
2350
+ bgColor = temp;
2351
+ }
2352
+ let attributes = 0;
2353
+ if (flags & StyleFlags.BOLD)
2354
+ attributes |= TextAttributes.BOLD;
2355
+ if (flags & StyleFlags.ITALIC)
2356
+ attributes |= TextAttributes.ITALIC;
2357
+ if (flags & StyleFlags.UNDERLINE)
2358
+ attributes |= TextAttributes.UNDERLINE;
2359
+ if (flags & StyleFlags.STRIKETHROUGH)
2360
+ attributes |= TextAttributes.STRIKETHROUGH;
2361
+ if (flags & StyleFlags.FAINT)
2362
+ attributes |= TextAttributes.DIM;
2363
+ return { __isChunk: true, text, fg: fgColor, bg: bgColor, attributes };
2364
+ }
2365
+ function applyHighlightsToLine(chunks, highlights) {
2366
+ if (highlights.length === 0)
2367
+ return chunks;
2368
+ const result = [];
2369
+ let col = 0;
2370
+ for (const chunk of chunks) {
2371
+ const chunkStart = col;
2372
+ const chunkEnd = col + chunk.text.length;
2373
+ const overlappingHighlights = highlights.filter((hl) => hl.start < chunkEnd && hl.end > chunkStart);
2374
+ if (overlappingHighlights.length === 0) {
2375
+ result.push(chunk);
2376
+ col = chunkEnd;
2377
+ continue;
2378
+ }
2379
+ let pos = 0;
2380
+ const text = chunk.text;
2381
+ const sortedHighlights = [...overlappingHighlights].sort((a, b) => a.start - b.start);
2382
+ for (const hl of sortedHighlights) {
2383
+ const hlStartInChunk = Math.max(0, hl.start - chunkStart);
2384
+ const hlEndInChunk = Math.min(text.length, hl.end - chunkStart);
2385
+ if (pos < hlStartInChunk) {
2386
+ result.push({
2387
+ __isChunk: true,
2388
+ text: text.slice(pos, hlStartInChunk),
2389
+ fg: chunk.fg,
2390
+ bg: chunk.bg,
2391
+ attributes: chunk.attributes
2392
+ });
2393
+ }
2394
+ if (hlStartInChunk < hlEndInChunk) {
2395
+ const highlightedText = text.slice(hlStartInChunk, hlEndInChunk);
2396
+ const displayText = hl.replaceWithX ? "x".repeat(highlightedText.length) : highlightedText;
2397
+ result.push({
2398
+ __isChunk: true,
2399
+ text: displayText,
2400
+ fg: chunk.fg,
2401
+ bg: RGBA.fromHex(hl.backgroundColor),
2402
+ attributes: chunk.attributes
2403
+ });
2404
+ }
2405
+ pos = hlEndInChunk;
2406
+ }
2407
+ if (pos < text.length) {
2408
+ result.push({
2409
+ __isChunk: true,
2410
+ text: text.slice(pos),
2411
+ fg: chunk.fg,
2412
+ bg: chunk.bg,
2413
+ attributes: chunk.attributes
2414
+ });
2415
+ }
2416
+ col = chunkEnd;
2417
+ }
2418
+ return result;
2419
+ }
2420
+ function makeCursorChunk(char, style, original) {
2421
+ if (style === "block") {
2422
+ return {
2423
+ __isChunk: true,
2424
+ text: char,
2425
+ fg: original?.bg || RGBA.fromHex("#1e1e1e"),
2426
+ bg: original?.fg || DEFAULT_FG,
2427
+ attributes: original?.attributes ?? 0
2428
+ };
2429
+ }
2430
+ return {
2431
+ __isChunk: true,
2432
+ text: char,
2433
+ fg: original?.fg || DEFAULT_FG,
2434
+ bg: original?.bg,
2435
+ attributes: (original?.attributes ?? 0) | TextAttributes.UNDERLINE
2436
+ };
2437
+ }
2438
+ function applyCursorToLine(chunks, cursorX, cursorStyle) {
2439
+ const totalLen = chunks.reduce((sum, c) => sum + c.text.length, 0);
2440
+ if (cursorX >= totalLen) {
2441
+ const gap = cursorX - totalLen;
2442
+ if (gap > 0) {
2443
+ return [...chunks, { __isChunk: true, text: " ".repeat(gap), attributes: 0 }, makeCursorChunk(" ", cursorStyle)];
2444
+ }
2445
+ return [...chunks, makeCursorChunk(" ", cursorStyle)];
2446
+ }
2447
+ const result = [];
2448
+ let col = 0;
2449
+ for (const chunk of chunks) {
2450
+ const chunkEnd = col + chunk.text.length;
2451
+ if (cursorX >= col && cursorX < chunkEnd) {
2452
+ const pos = cursorX - col;
2453
+ if (pos > 0) {
2454
+ result.push({ ...chunk, text: chunk.text.slice(0, pos) });
2455
+ }
2456
+ result.push(makeCursorChunk(chunk.text[pos], cursorStyle, chunk));
2457
+ if (pos + 1 < chunk.text.length) {
2458
+ result.push({ ...chunk, text: chunk.text.slice(pos + 1) });
2459
+ }
2460
+ } else {
2461
+ result.push(chunk);
2462
+ }
2463
+ col = chunkEnd;
2464
+ }
2465
+ return result;
2466
+ }
2467
+ function terminalDataToStyledText(data, highlights, cursor) {
2468
+ const chunks = [];
2469
+ const highlightsByLine = new Map;
2470
+ if (highlights) {
2471
+ for (const hl of highlights) {
2472
+ const lineHighlights = highlightsByLine.get(hl.line) ?? [];
2473
+ lineHighlights.push(hl);
2474
+ highlightsByLine.set(hl.line, lineHighlights);
2475
+ }
2476
+ }
2477
+ for (let i = 0;i < data.lines.length; i++) {
2478
+ const line = data.lines[i];
2479
+ let lineChunks = [];
2480
+ if (line.spans.length === 0) {
2481
+ lineChunks.push({ __isChunk: true, text: " ", attributes: 0 });
2482
+ } else {
2483
+ for (const span of line.spans) {
2484
+ lineChunks.push(convertSpanToChunk(span));
2485
+ }
2486
+ }
2487
+ const lineHighlights = highlightsByLine.get(i);
2488
+ if (lineHighlights) {
2489
+ lineChunks = applyHighlightsToLine(lineChunks, lineHighlights);
2490
+ }
2491
+ if (cursor && i === cursor.y) {
2492
+ lineChunks = applyCursorToLine(lineChunks, cursor.x, cursor.style);
2493
+ }
2494
+ chunks.push(...lineChunks);
2495
+ if (i < data.lines.length - 1) {
2496
+ chunks.push({ __isChunk: true, text: `
2497
+ `, attributes: 0 });
2498
+ }
2499
+ }
2500
+ return new StyledText(chunks);
2501
+ }
2502
+
2503
+ class GhosttyTerminalRenderable extends TextBufferRenderable {
2504
+ _ansi;
2505
+ _cols;
2506
+ _rows;
2507
+ _limit;
2508
+ _trimEnd;
2509
+ _highlights;
2510
+ _ansiDirty = false;
2511
+ _lineCount = 0;
2512
+ _showCursor = false;
2513
+ _cursorStyle = "block";
2514
+ _persistent = false;
2515
+ _persistentTerminal = null;
2516
+ constructor(ctx, options) {
2517
+ super(ctx, {
2518
+ ...options,
2519
+ fg: DEFAULT_FG,
2520
+ wrapMode: "none"
2521
+ });
2522
+ this._ansi = options.ansi ?? "";
2523
+ this._cols = options.cols ?? 120;
2524
+ this._rows = options.rows ?? 40;
2525
+ this._limit = options.limit;
2526
+ this._trimEnd = options.trimEnd;
2527
+ this._highlights = options.highlights;
2528
+ this._persistent = options.persistent ?? false;
2529
+ this._showCursor = options.showCursor ?? false;
2530
+ this._cursorStyle = options.cursorStyle ?? "block";
2531
+ if (this._persistent && hasPersistentTerminalSupport()) {
2532
+ this._persistentTerminal = new PersistentTerminal({
2533
+ cols: this._cols,
2534
+ rows: this._rows
2535
+ });
2536
+ if (this._ansi && (typeof this._ansi === "string" ? this._ansi.length > 0 : this._ansi.length > 0)) {
2537
+ this._persistentTerminal.feed(this._ansi);
2538
+ }
2539
+ }
2540
+ this._ansiDirty = true;
2541
+ }
2542
+ get lineCount() {
2543
+ return this._lineCount;
2544
+ }
2545
+ get limit() {
2546
+ return this._limit;
2547
+ }
2548
+ set limit(value) {
2549
+ if (this._limit !== value) {
2550
+ this._limit = value;
2551
+ this._ansiDirty = true;
2552
+ this.requestRender();
2553
+ }
2554
+ }
2555
+ get trimEnd() {
2556
+ return this._trimEnd;
2557
+ }
2558
+ set trimEnd(value) {
2559
+ if (this._trimEnd !== value) {
2560
+ this._trimEnd = value;
2561
+ this._ansiDirty = true;
2562
+ this.requestRender();
2563
+ }
2564
+ }
2565
+ get highlights() {
2566
+ return this._highlights;
2567
+ }
2568
+ set highlights(value) {
2569
+ this._highlights = value;
2570
+ this._ansiDirty = true;
2571
+ this.requestRender();
2572
+ }
2573
+ get showCursor() {
2574
+ return this._showCursor;
2575
+ }
2576
+ set showCursor(value) {
2577
+ if (this._showCursor !== value) {
2578
+ this._showCursor = value;
2579
+ this._ansiDirty = true;
2580
+ this.requestRender();
2581
+ }
2582
+ }
2583
+ get cursorStyle() {
2584
+ return this._cursorStyle;
2585
+ }
2586
+ set cursorStyle(value) {
2587
+ if (this._cursorStyle !== value) {
2588
+ this._cursorStyle = value;
2589
+ this._ansiDirty = true;
2590
+ this.requestRender();
2591
+ }
2592
+ }
2593
+ get ansi() {
2594
+ return this._ansi;
2595
+ }
2596
+ set ansi(value) {
2597
+ if (this._ansi !== value) {
2598
+ this._ansi = value;
2599
+ if (this._persistentTerminal) {
2600
+ this._persistentTerminal.reset();
2601
+ if (value && (typeof value === "string" ? value.length > 0 : value.length > 0)) {
2602
+ this._persistentTerminal.feed(value);
2603
+ }
2604
+ }
2605
+ this._ansiDirty = true;
2606
+ this.requestRender();
2607
+ }
2608
+ }
2609
+ get cols() {
2610
+ return this._cols;
2611
+ }
2612
+ set cols(value) {
2613
+ if (this._cols !== value) {
2614
+ this._cols = value;
2615
+ if (this._persistentTerminal) {
2616
+ this._persistentTerminal.resize(value, this._rows);
2617
+ }
2618
+ this._ansiDirty = true;
2619
+ this.requestRender();
2620
+ }
2621
+ }
2622
+ get rows() {
2623
+ return this._rows;
2624
+ }
2625
+ set rows(value) {
2626
+ if (this._rows !== value) {
2627
+ this._rows = value;
2628
+ if (this._persistentTerminal) {
2629
+ this._persistentTerminal.resize(this._cols, value);
2630
+ }
2631
+ this._ansiDirty = true;
2632
+ this.requestRender();
2633
+ }
2634
+ }
2635
+ get persistent() {
2636
+ return this._persistent;
2637
+ }
2638
+ set persistent(_value) {}
2639
+ feed(data) {
2640
+ if (!this._persistentTerminal) {
2641
+ throw new Error("feed() is only available in persistent mode. Set persistent=true in options.");
2642
+ }
2643
+ this._persistentTerminal.feed(data);
2644
+ this._ansiDirty = true;
2645
+ this.requestRender();
2646
+ }
2647
+ reset() {
2648
+ if (!this._persistentTerminal) {
2649
+ throw new Error("reset() is only available in persistent mode. Set persistent=true in options.");
2650
+ }
2651
+ this._persistentTerminal.reset();
2652
+ this._ansiDirty = true;
2653
+ this.requestRender();
2654
+ }
2655
+ getCursor() {
2656
+ if (!this._persistentTerminal) {
2657
+ throw new Error("getCursor() is only available in persistent mode. Set persistent=true in options.");
2658
+ }
2659
+ return this._persistentTerminal.getCursor();
2660
+ }
2661
+ getText() {
2662
+ if (this._persistentTerminal) {
2663
+ return this._persistentTerminal.getText();
2664
+ }
2665
+ throw new Error("getText() in stateless mode is not implemented. Use persistent=true.");
2666
+ }
2667
+ destroy() {
2668
+ if (this._persistentTerminal) {
2669
+ this._persistentTerminal.destroy();
2670
+ this._persistentTerminal = null;
2671
+ }
2672
+ super.destroy();
2673
+ }
2674
+ renderSelf(buffer) {
2675
+ if (this._ansiDirty) {
2676
+ let data;
2677
+ if (this._persistentTerminal) {
2678
+ data = this._persistentTerminal.getJson({
2679
+ limit: this._limit
2680
+ });
2681
+ } else {
2682
+ data = ptyToJson(this._ansi, {
2683
+ cols: this._cols,
2684
+ rows: this._rows,
2685
+ limit: this._limit
2686
+ });
2687
+ }
2688
+ if (this._trimEnd) {
2689
+ while (data.lines.length > 0) {
2690
+ const lastLine = data.lines[data.lines.length - 1];
2691
+ const hasText = lastLine.spans.some((span) => span.text.trim().length > 0);
2692
+ if (hasText)
2693
+ break;
2694
+ data.lines.pop();
2695
+ }
2696
+ }
2697
+ const cursor = this._showCursor ? {
2698
+ x: data.cursor[0],
2699
+ y: Math.max(0, data.totalLines - data.rows + data.cursor[1] - data.offset),
2700
+ style: this._cursorStyle
2701
+ } : undefined;
2702
+ const styledText = terminalDataToStyledText(data, this._highlights, cursor);
2703
+ this.textBuffer.setStyledText(styledText);
2704
+ this.updateTextInfo();
2705
+ const lineInfo = this.textBufferView.logicalLineInfo;
2706
+ if (lineInfo) {
2707
+ this._lineCount = lineInfo.lineStarts.length;
2708
+ }
2709
+ this._ansiDirty = false;
2710
+ }
2711
+ super.renderSelf(buffer);
2712
+ }
2713
+ getScrollPositionForLine(lineNumber) {
2714
+ const clampedLine = Math.max(0, Math.min(lineNumber, this._lineCount - 1));
2715
+ const lineInfo = this.textBufferView.logicalLineInfo;
2716
+ const lineStarts = lineInfo?.lineStarts;
2717
+ let lineYOffset = clampedLine;
2718
+ if (lineStarts && lineStarts.length > clampedLine) {
2719
+ lineYOffset = lineStarts[clampedLine];
2720
+ }
2721
+ return this.y + lineYOffset;
2722
+ }
2723
+ }
2324
2724
 
2325
2725
  // src/utils/timestamp.ts
2326
2726
  var DEFAULT_TIMESTAMP_FORMAT = "HH:mm:ss";
@@ -2796,7 +3196,7 @@ class SearchController {
2796
3196
  }
2797
3197
 
2798
3198
  // src/ui/status-bar.ts
2799
- import { cyan, red, reverse, StyledText, TextRenderable, yellow } from "@opentui/core";
3199
+ import { cyan, red, reverse, StyledText as StyledText2, TextRenderable, yellow } from "@opentui/core";
2800
3200
  function plain(text) {
2801
3201
  return { __isChunk: true, text };
2802
3202
  }
@@ -2842,12 +3242,12 @@ class StatusBar {
2842
3242
  }
2843
3243
  buildContent() {
2844
3244
  if (this._tempMessage) {
2845
- return new StyledText([cyan(this._tempMessage)]);
3245
+ return new StyledText2([cyan(this._tempMessage)]);
2846
3246
  }
2847
3247
  if (this._searchMode) {
2848
3248
  return this.buildSearchContent();
2849
3249
  }
2850
- return new StyledText([plain(STATUS_BAR_TEXT)]);
3250
+ return new StyledText2([plain(STATUS_BAR_TEXT)]);
2851
3251
  }
2852
3252
  buildSearchContent() {
2853
3253
  const chunks = [];
@@ -2873,7 +3273,7 @@ class StatusBar {
2873
3273
  chunks.push(plain(" Enter: next"));
2874
3274
  }
2875
3275
  chunks.push(plain(` Tab: ${isAllMode ? "single" : "all"} Esc: close`));
2876
- return new StyledText(chunks);
3276
+ return new StyledText2(chunks);
2877
3277
  }
2878
3278
  }
2879
3279
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numux",
3
- "version": "2.10.0",
3
+ "version": "2.10.1",
4
4
  "description": "Terminal multiplexer with dependency orchestration",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,7 +30,7 @@
30
30
  }
31
31
  },
32
32
  "scripts": {
33
- "build": "bun build src/index.ts --outfile dist/numux.js --target bun --packages external && bun build src/config.ts --outfile dist/config.js --packages external && bunx tsc src/config.ts src/types.ts --emitDeclarationOnly --declaration --outDir dist --target ESNext --module ESNext --moduleResolution bundler && cp src/bin-wrapper.js dist/bin.js",
33
+ "build": "bun run build.ts",
34
34
  "prepublishOnly": "bun run build",
35
35
  "dev": "cd example && bun run dev --debug",
36
36
  "test": "bun test",