numux 2.10.0 → 2.10.2

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.2",
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,414 @@ 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
+ }
2724
+ var EMPTY_LINE_INFO = { lineStarts: [], lineStartCols: [], lineWidthColsMax: 0, lineSources: [] };
2725
+ Object.defineProperty(GhosttyTerminalRenderable.prototype, "lineInfo", {
2726
+ get() {
2727
+ return this.textBufferView.logicalLineInfo ?? EMPTY_LINE_INFO;
2728
+ },
2729
+ configurable: true
2730
+ });
2324
2731
 
2325
2732
  // src/utils/timestamp.ts
2326
2733
  var DEFAULT_TIMESTAMP_FORMAT = "HH:mm:ss";
@@ -2796,7 +3203,7 @@ class SearchController {
2796
3203
  }
2797
3204
 
2798
3205
  // src/ui/status-bar.ts
2799
- import { cyan, red, reverse, StyledText, TextRenderable, yellow } from "@opentui/core";
3206
+ import { cyan, red, reverse, StyledText as StyledText2, TextRenderable, yellow } from "@opentui/core";
2800
3207
  function plain(text) {
2801
3208
  return { __isChunk: true, text };
2802
3209
  }
@@ -2842,12 +3249,12 @@ class StatusBar {
2842
3249
  }
2843
3250
  buildContent() {
2844
3251
  if (this._tempMessage) {
2845
- return new StyledText([cyan(this._tempMessage)]);
3252
+ return new StyledText2([cyan(this._tempMessage)]);
2846
3253
  }
2847
3254
  if (this._searchMode) {
2848
3255
  return this.buildSearchContent();
2849
3256
  }
2850
- return new StyledText([plain(STATUS_BAR_TEXT)]);
3257
+ return new StyledText2([plain(STATUS_BAR_TEXT)]);
2851
3258
  }
2852
3259
  buildSearchContent() {
2853
3260
  const chunks = [];
@@ -2873,7 +3280,7 @@ class StatusBar {
2873
3280
  chunks.push(plain(" Enter: next"));
2874
3281
  }
2875
3282
  chunks.push(plain(` Tab: ${isAllMode ? "single" : "all"} Esc: close`));
2876
- return new StyledText(chunks);
3283
+ return new StyledText2(chunks);
2877
3284
  }
2878
3285
  }
2879
3286
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numux",
3
- "version": "2.10.0",
3
+ "version": "2.10.2",
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",