numux 1.10.2 → 1.10.4

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.
Files changed (2) hide show
  1. package/dist/numux.js +94 -53
  2. package/package.json +1 -1
package/dist/numux.js CHANGED
@@ -22,7 +22,7 @@ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports,
22
22
  var require_package = __commonJS((exports, module) => {
23
23
  module.exports = {
24
24
  name: "numux",
25
- version: "1.10.2",
25
+ version: "1.10.4",
26
26
  description: "Terminal multiplexer with dependency orchestration",
27
27
  type: "module",
28
28
  license: "MIT",
@@ -608,6 +608,24 @@ function detectPackageManager(pkgJson, cwd) {
608
608
  function isGlobPattern(name) {
609
609
  return /[*?[]/.test(name);
610
610
  }
611
+ function deriveShortName(pattern, scriptName) {
612
+ let prefixEnd = 0;
613
+ while (prefixEnd < pattern.length && !"*?[".includes(pattern[prefixEnd])) {
614
+ prefixEnd++;
615
+ }
616
+ let suffixStart = pattern.length;
617
+ while (suffixStart > 0 && !"*?[".includes(pattern[suffixStart - 1])) {
618
+ suffixStart--;
619
+ }
620
+ const prefix = pattern.slice(0, prefixEnd);
621
+ const suffix = pattern.slice(suffixStart);
622
+ let short = scriptName;
623
+ if (prefix && short.startsWith(prefix))
624
+ short = short.slice(prefix.length);
625
+ if (suffix && short.endsWith(suffix))
626
+ short = short.slice(0, short.length - suffix.length);
627
+ return short || scriptName;
628
+ }
611
629
  function splitPatternArgs(raw) {
612
630
  const i = raw.indexOf(" ");
613
631
  if (i === -1)
@@ -652,12 +670,13 @@ function expandScriptPatterns(config, cwd) {
652
670
  const singleColor = typeof template.color === "string" ? template.color : undefined;
653
671
  for (let i = 0;i < matches.length; i++) {
654
672
  const scriptName = matches[i];
655
- if (expanded[scriptName]) {
673
+ const displayName = deriveShortName(globPattern, scriptName);
674
+ if (expanded[displayName]) {
656
675
  throw new Error(`"${name}": expanded script "${scriptName}" collides with an existing process name`);
657
676
  }
658
677
  const color = colors ? colors[i % colors.length] : singleColor;
659
678
  const { color: _color, ...rest } = template;
660
- expanded[scriptName] = {
679
+ expanded[displayName] = {
661
680
  ...rest,
662
681
  command: `${pm} run ${scriptName}${extraArgs}`,
663
682
  ...color ? { color } : {}
@@ -2100,6 +2119,37 @@ var STATUS_ICON_HEX = {
2100
2119
  skipped: "#888888"
2101
2120
  };
2102
2121
  var TERMINAL_STATUSES = new Set(["finished", "stopped", "failed", "skipped"]);
2122
+ function formatTab(name, status) {
2123
+ return `${STATUS_ICONS[status]} ${name}`;
2124
+ }
2125
+ function formatDescription(status, exitCode, restartCount) {
2126
+ let desc = status;
2127
+ if ((status === "failed" || status === "stopped") && exitCode != null && exitCode !== 0) {
2128
+ desc = `exit ${exitCode}`;
2129
+ }
2130
+ if (restartCount && restartCount > 0) {
2131
+ desc += ` \xD7${restartCount}`;
2132
+ }
2133
+ return desc;
2134
+ }
2135
+ function getDisplayOrder(originalNames, statuses) {
2136
+ const active = originalNames.filter((n) => !TERMINAL_STATUSES.has(statuses.get(n)));
2137
+ const terminal = originalNames.filter((n) => TERMINAL_STATUSES.has(statuses.get(n)));
2138
+ return [...active, ...terminal];
2139
+ }
2140
+ function resolveOptionColors(names, statuses, processColors, inputWaiting, erroredProcesses) {
2141
+ return names.map((name) => {
2142
+ const status = statuses.get(name);
2143
+ const waiting = inputWaiting.has(name);
2144
+ const errored = erroredProcesses.has(name);
2145
+ const statusHex = waiting ? "#ffaa00" : errored ? "#ff5555" : STATUS_ICON_HEX[status];
2146
+ const processHex = processColors.get(name);
2147
+ return {
2148
+ iconHex: statusHex ?? processHex ?? "#888888",
2149
+ nameHex: processHex ?? null
2150
+ };
2151
+ });
2152
+ }
2103
2153
 
2104
2154
  class ColoredSelectRenderable extends SelectRenderable {
2105
2155
  _optionColors = [];
@@ -2107,12 +2157,11 @@ class ColoredSelectRenderable extends SelectRenderable {
2107
2157
  this._optionColors = colors;
2108
2158
  this.requestRender();
2109
2159
  }
2110
- renderSelf(buffer, deltaTime) {
2111
- const wasDirty = this.isDirty;
2112
- super.renderSelf(buffer, deltaTime);
2113
- if (wasDirty && this.frameBuffer && this._optionColors.length > 0) {
2114
- this.colorizeOptions();
2115
- }
2160
+ renderSelf(_buffer, _deltaTime) {
2161
+ if (!(this.visible && this.frameBuffer))
2162
+ return;
2163
+ if (this.isDirty)
2164
+ this.renderOptions();
2116
2165
  }
2117
2166
  onMouseEvent(event) {
2118
2167
  if (event.type === "down") {
@@ -2125,28 +2174,45 @@ class ColoredSelectRenderable extends SelectRenderable {
2125
2174
  }
2126
2175
  }
2127
2176
  }
2128
- colorizeOptions() {
2177
+ renderOptions() {
2178
+ if (!this.frameBuffer || this.options.length === 0)
2179
+ return;
2129
2180
  const fb = this.frameBuffer;
2181
+ const bgColor = this._focused ? this._focusedBackgroundColor : this._backgroundColor;
2182
+ fb.clear(bgColor);
2130
2183
  const scrollOffset = this.scrollOffset;
2131
2184
  const maxVisibleItems = this.maxVisibleItems;
2132
2185
  const linesPerItem = this.linesPerItem;
2186
+ const fontHeight = this.fontHeight;
2133
2187
  const selectedIndex = this.getSelectedIndex();
2134
- const options = this.options;
2135
- const visibleCount = Math.min(maxVisibleItems, options.length - scrollOffset);
2188
+ const showDescription = this._showDescription;
2136
2189
  const baseTextColor = this._focused ? this._focusedTextColor : this._textColor;
2137
2190
  const selectedTextColor = this._selectedTextColor;
2138
- const lineWidth = fb.width;
2191
+ const descColor = this._descriptionColor;
2192
+ const selectedDescColor = this._selectedDescriptionColor;
2193
+ const selectedBgColor = this._selectedBackgroundColor;
2194
+ const itemSpacing = this._itemSpacing;
2195
+ const visibleCount = Math.min(maxVisibleItems, this.options.length - scrollOffset);
2139
2196
  for (let i = 0;i < visibleCount; i++) {
2140
2197
  const actualIndex = scrollOffset + i;
2141
- const itemY = i * linesPerItem;
2142
- const optName = options[actualIndex].name;
2198
+ const option = this.options[actualIndex];
2143
2199
  const isSelected = actualIndex === selectedIndex;
2144
- const defaultColor = isSelected ? selectedTextColor : baseTextColor;
2200
+ const itemY = i * linesPerItem;
2201
+ if (itemY + linesPerItem - 1 >= this.height)
2202
+ break;
2203
+ if (isSelected) {
2204
+ fb.fillRect(0, itemY, this.width, linesPerItem - itemSpacing, selectedBgColor);
2205
+ }
2145
2206
  const colors = this._optionColors[actualIndex];
2146
- const textColor = colors?.name ?? defaultColor;
2147
- fb.drawText(optName.padEnd(lineWidth), 1, itemY, textColor);
2207
+ const defaultColor = isSelected ? selectedTextColor : baseTextColor;
2208
+ const nameColor = colors?.name ?? defaultColor;
2209
+ fb.drawText(option.name, 1, itemY, nameColor);
2148
2210
  if (colors?.icon) {
2149
- fb.drawText(optName.charAt(0), 1, itemY, colors.icon);
2211
+ fb.drawText(option.name.charAt(0), 1, itemY, colors.icon);
2212
+ }
2213
+ if (showDescription && itemY + fontHeight < this.height) {
2214
+ const dc = isSelected ? selectedDescColor : descColor;
2215
+ fb.drawText(option.description, 3, itemY + fontHeight, dc);
2150
2216
  }
2151
2217
  }
2152
2218
  }
@@ -2172,7 +2238,7 @@ class TabBar {
2172
2238
  width: "100%",
2173
2239
  height: "100%",
2174
2240
  options: names.map((n) => ({
2175
- name: this.formatTab(n, "pending"),
2241
+ name: formatTab(n, "pending"),
2176
2242
  description: "pending"
2177
2243
  })),
2178
2244
  selectedBackgroundColor: "#334455",
@@ -2195,7 +2261,7 @@ class TabBar {
2195
2261
  }
2196
2262
  updateStatus(name, status, exitCode, restartCount) {
2197
2263
  this.statuses.set(name, status);
2198
- this.baseDescriptions.set(name, this.formatDescription(status, exitCode, restartCount));
2264
+ this.baseDescriptions.set(name, formatDescription(status, exitCode, restartCount));
2199
2265
  if (TERMINAL_STATUSES.has(status) || status === "stopping") {
2200
2266
  this.inputWaiting.delete(name);
2201
2267
  }
@@ -2227,9 +2293,9 @@ class TabBar {
2227
2293
  refreshOptions() {
2228
2294
  const currentIdx = this.renderable.getSelectedIndex();
2229
2295
  const currentName = this.names[currentIdx];
2230
- this.names = this.getDisplayOrder();
2296
+ this.names = getDisplayOrder(this.originalNames, this.statuses);
2231
2297
  this.renderable.options = this.names.map((n) => ({
2232
- name: this.formatTab(n, this.statuses.get(n)),
2298
+ name: formatTab(n, this.statuses.get(n)),
2233
2299
  description: this.getDescription(n)
2234
2300
  }));
2235
2301
  const newIdx = this.names.indexOf(currentName);
@@ -2238,11 +2304,6 @@ class TabBar {
2238
2304
  }
2239
2305
  this.updateOptionColors();
2240
2306
  }
2241
- getDisplayOrder() {
2242
- const active = this.originalNames.filter((n) => !TERMINAL_STATUSES.has(this.statuses.get(n)));
2243
- const terminal = this.originalNames.filter((n) => TERMINAL_STATUSES.has(this.statuses.get(n)));
2244
- return [...active, ...terminal];
2245
- }
2246
2307
  getDescription(name) {
2247
2308
  if (this.inputWaiting.has(name))
2248
2309
  return "awaiting input";
@@ -2251,33 +2312,13 @@ class TabBar {
2251
2312
  return this.baseDescriptions.get(name) ?? "pending";
2252
2313
  }
2253
2314
  updateOptionColors() {
2254
- const colors = this.names.map((name) => {
2255
- const status = this.statuses.get(name);
2256
- const waiting = this.inputWaiting.has(name);
2257
- const errored = this.erroredProcesses.has(name);
2258
- const statusHex = waiting ? "#ffaa00" : errored ? "#ff5555" : STATUS_ICON_HEX[status];
2259
- const processHex = this.processColors.get(name);
2260
- return {
2261
- icon: parseColor(statusHex ?? processHex ?? "#888888"),
2262
- name: processHex ? parseColor(processHex) : null
2263
- };
2264
- });
2315
+ const resolved = resolveOptionColors(this.names, this.statuses, this.processColors, this.inputWaiting, this.erroredProcesses);
2316
+ const colors = resolved.map((c) => ({
2317
+ icon: parseColor(c.iconHex),
2318
+ name: c.nameHex ? parseColor(c.nameHex) : null
2319
+ }));
2265
2320
  this.renderable.setOptionColors(colors);
2266
2321
  }
2267
- formatDescription(status, exitCode, restartCount) {
2268
- let desc = status;
2269
- if ((status === "failed" || status === "stopped") && exitCode != null && exitCode !== 0) {
2270
- desc = `exit ${exitCode}`;
2271
- }
2272
- if (restartCount && restartCount > 0) {
2273
- desc += ` \xD7${restartCount}`;
2274
- }
2275
- return desc;
2276
- }
2277
- formatTab(name, status) {
2278
- const icon = STATUS_ICONS[status];
2279
- return `${icon} ${name}`;
2280
- }
2281
2322
  getSelectedIndex() {
2282
2323
  return this.renderable.getSelectedIndex();
2283
2324
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "numux",
3
- "version": "1.10.2",
3
+ "version": "1.10.4",
4
4
  "description": "Terminal multiplexer with dependency orchestration",
5
5
  "type": "module",
6
6
  "license": "MIT",