numux 2.9.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
 
@@ -256,6 +256,7 @@ Each process accepts:
256
256
  | `readyTimeout` | `number` | — | Milliseconds to wait for `readyPattern` before failing |
257
257
  | `maxRestarts` | `number` | `0` | Max auto-restart attempts on non-zero exit (0 = no restarts) |
258
258
  | `delay` | `number` | — | Milliseconds to wait before starting the process |
259
+ | `optional` | `boolean` | `false` | Process is visible as a tab but not started automatically. Use Alt+S to start manually |
259
260
  | `condition` | `string` | — | Env var name; process skipped if falsy. Prefix with `!` to negate |
260
261
  | `platform` | `string \| string[]` | — | OS(es) this process runs on (e.g. `'darwin'`, `'linux'`). Non-matching processes are removed; dependents still start |
261
262
  | `stopSignal` | `string` | `SIGTERM` | Signal for graceful stop (`SIGTERM`, `SIGINT`, or `SIGHUP`) |
@@ -360,6 +361,24 @@ export default defineConfig({
360
361
 
361
362
  Falsy values: unset, empty string, `"0"`, `"false"`, `"no"`, `"off"` (case-insensitive). If a conditional process is skipped, its dependents are also skipped.
362
363
 
364
+ ### Optional processes
365
+
366
+ Use `optional` for tools you want visible in tabs but not auto-started (e.g. Prisma Studio, debug servers):
367
+
368
+ ```ts
369
+ export default defineConfig({
370
+ processes: {
371
+ app: { command: 'bun run dev' },
372
+ studio: {
373
+ command: 'bunx prisma studio',
374
+ optional: true, // shows as stopped tab, start with Alt+S
375
+ },
376
+ },
377
+ })
378
+ ```
379
+
380
+ Unlike `condition`, optional processes don't cascade — their dependents still start normally.
381
+
363
382
  ### Dependency orchestration
364
383
 
365
384
  Each process starts as soon as its declared `dependsOn` dependencies are ready — it does not wait for unrelated processes. If a process fails, its dependents are skipped.
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.9.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",
@@ -1237,6 +1237,7 @@ function validateConfig(raw, _warnings) {
1237
1237
  const processWatch = validateStringOrStringArray(p.watch);
1238
1238
  validated[name] = {
1239
1239
  command: p.command,
1240
+ ...p.optional === true ? { optional: true } : {},
1240
1241
  cwd: processCwd ?? globalCwd,
1241
1242
  env: globalEnv || processEnv ? { ...globalEnv, ...processEnv } : undefined,
1242
1243
  envFile: processEnvFile ?? globalEnvFile,
@@ -1967,6 +1968,12 @@ class ProcessManager {
1967
1968
  const launches = this.tiers.flat().map(async (name) => {
1968
1969
  const proc = this.config.processes[name];
1969
1970
  const resolve8 = readyResolvers.get(name);
1971
+ if (proc.optional) {
1972
+ this.updateStatus(name, "stopped");
1973
+ this.createRunner(name);
1974
+ resolve8();
1975
+ return;
1976
+ }
1970
1977
  const deps = proc.dependsOn ?? [];
1971
1978
  if (deps.length > 0) {
1972
1979
  await Promise.all(deps.map((d) => readyPromises.get(d)));
@@ -2313,7 +2320,407 @@ import {
2313
2320
  LineNumberRenderable,
2314
2321
  ScrollBoxRenderable
2315
2322
  } from "@opentui/core";
2316
- 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
+ }
2317
2724
 
2318
2725
  // src/utils/timestamp.ts
2319
2726
  var DEFAULT_TIMESTAMP_FORMAT = "HH:mm:ss";
@@ -2789,7 +3196,7 @@ class SearchController {
2789
3196
  }
2790
3197
 
2791
3198
  // src/ui/status-bar.ts
2792
- import { cyan, red, reverse, StyledText, TextRenderable, yellow } from "@opentui/core";
3199
+ import { cyan, red, reverse, StyledText as StyledText2, TextRenderable, yellow } from "@opentui/core";
2793
3200
  function plain(text) {
2794
3201
  return { __isChunk: true, text };
2795
3202
  }
@@ -2835,12 +3242,12 @@ class StatusBar {
2835
3242
  }
2836
3243
  buildContent() {
2837
3244
  if (this._tempMessage) {
2838
- return new StyledText([cyan(this._tempMessage)]);
3245
+ return new StyledText2([cyan(this._tempMessage)]);
2839
3246
  }
2840
3247
  if (this._searchMode) {
2841
3248
  return this.buildSearchContent();
2842
3249
  }
2843
- return new StyledText([plain(STATUS_BAR_TEXT)]);
3250
+ return new StyledText2([plain(STATUS_BAR_TEXT)]);
2844
3251
  }
2845
3252
  buildSearchContent() {
2846
3253
  const chunks = [];
@@ -2866,7 +3273,7 @@ class StatusBar {
2866
3273
  chunks.push(plain(" Enter: next"));
2867
3274
  }
2868
3275
  chunks.push(plain(` Tab: ${isAllMode ? "single" : "all"} Esc: close`));
2869
- return new StyledText(chunks);
3276
+ return new StyledText2(chunks);
2870
3277
  }
2871
3278
  }
2872
3279
 
@@ -3529,8 +3936,8 @@ class PrefixDisplay {
3529
3936
  this.shutdown();
3530
3937
  });
3531
3938
  process.on("unhandledRejection", (reason) => {
3532
- const message = reason instanceof Error ? reason.message : String(reason);
3533
- process.stderr.write(`numux: unhandled rejection: ${message}
3939
+ const stack = reason instanceof Error ? reason.stack : String(reason);
3940
+ process.stderr.write(`numux: unhandled rejection: ${stack}
3534
3941
  `);
3535
3942
  this.shutdown();
3536
3943
  });
@@ -3941,10 +4348,10 @@ function setupShutdownHandlers(app, logWriter) {
3941
4348
  });
3942
4349
  });
3943
4350
  process.on("unhandledRejection", (reason) => {
3944
- const message = reason instanceof Error ? reason.message : String(reason);
3945
- log("Unhandled rejection:", message);
4351
+ const stack = reason instanceof Error ? reason.stack : String(reason);
4352
+ log("Unhandled rejection:", stack);
3946
4353
  app.shutdown().finally(() => {
3947
- process.stderr.write(`numux: unhandled rejection: ${message}
4354
+ process.stderr.write(`numux: unhandled rejection: ${stack}
3948
4355
  `);
3949
4356
  logWriter?.cleanup();
3950
4357
  process.exit(1);
package/dist/types.d.ts CHANGED
@@ -43,6 +43,8 @@ export interface NumuxProcessConfig<K extends string = string> {
43
43
  * @default false
44
44
  */
45
45
  interactive?: boolean;
46
+ /** Process is visible but not started automatically. Use Alt+S to start manually */
47
+ optional?: boolean;
46
48
  /** `true` = detect ANSI red output, string = regex pattern */
47
49
  errorMatcher?: boolean | string;
48
50
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numux",
3
- "version": "2.9.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",