@nmakarov/cli-toolkit 0.68.0 → 0.70.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/cli-runner.cjs +328 -193
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +328 -193
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +366 -209
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +360 -209
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +145 -103
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +145 -103
- package/dist/init.js.map +1 -1
- package/dist/screen.cjs +140 -103
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +137 -103
- package/dist/screen.js.map +1 -1
- package/dist/tasks.cjs +218 -106
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +215 -106
- package/dist/tasks.js.map +1 -1
- package/package.json +2 -2
package/dist/cli-runner.js
CHANGED
|
@@ -94,9 +94,48 @@ var init_components = __esm({
|
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
96
|
|
|
97
|
+
// src/screen/scrollbar.js
|
|
98
|
+
function scrollbarGlyphs(viewportRows, totalLines, scrollTop) {
|
|
99
|
+
const view = Math.max(1, Math.floor(viewportRows));
|
|
100
|
+
const total = Math.max(0, Math.floor(totalLines));
|
|
101
|
+
if (total <= view) return null;
|
|
102
|
+
const maxScroll = total - view;
|
|
103
|
+
const thumbSize = Math.max(1, Math.round(view / total * view));
|
|
104
|
+
const travel = Math.max(0, view - thumbSize);
|
|
105
|
+
const s = Math.min(Math.max(0, Math.floor(scrollTop)), maxScroll);
|
|
106
|
+
const thumbStart = maxScroll === 0 ? 0 : Math.round(s / maxScroll * travel);
|
|
107
|
+
const glyphs = [];
|
|
108
|
+
for (let i = 0; i < view; i++) {
|
|
109
|
+
glyphs.push(i >= thumbStart && i < thumbStart + thumbSize ? BAR_THUMB : BAR_TRACK);
|
|
110
|
+
}
|
|
111
|
+
return glyphs;
|
|
112
|
+
}
|
|
113
|
+
var BAR_THUMB, BAR_TRACK, PAGE_SCROLL_KEY_BINDINGS;
|
|
114
|
+
var init_scrollbar = __esm({
|
|
115
|
+
"src/screen/scrollbar.js"() {
|
|
116
|
+
BAR_THUMB = "#";
|
|
117
|
+
BAR_TRACK = "|";
|
|
118
|
+
PAGE_SCROLL_KEY_BINDINGS = [
|
|
119
|
+
{ key: "upArrow", meta: true, caption: "page", action: "pageUp", order: 0 },
|
|
120
|
+
{ key: "downArrow", meta: true, caption: "page", action: "pageDown", order: 0 },
|
|
121
|
+
{ key: "upArrow", ctrl: true, caption: "page", action: "pageUp", order: 0 },
|
|
122
|
+
{ key: "downArrow", ctrl: true, caption: "page", action: "pageDown", order: 0 },
|
|
123
|
+
{ key: "pageUp", caption: "page", action: "pageUp", order: 0 },
|
|
124
|
+
{ key: "pageDown", caption: "page", action: "pageDown", order: 0 }
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
|
|
97
129
|
// src/screen/list-components.js
|
|
98
130
|
import React, { useState, useEffect, useRef, createElement } from "react";
|
|
99
131
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
132
|
+
function clipNameForScrollbar(name, needsBar) {
|
|
133
|
+
if (!needsBar || name == null) return name;
|
|
134
|
+
const s = String(name);
|
|
135
|
+
if (s.length <= 1) return s;
|
|
136
|
+
if (/\s$/.test(s)) return s.slice(0, -1);
|
|
137
|
+
return s;
|
|
138
|
+
}
|
|
100
139
|
function MultiColumnListComponent({ items, ctx, selectedIndexRef }) {
|
|
101
140
|
const [, forceUpdate] = useState({});
|
|
102
141
|
const termWidth = (process.stdout.columns || 80) - 8;
|
|
@@ -310,17 +349,42 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
310
349
|
});
|
|
311
350
|
ctx.setAction("scrollUp", () => {
|
|
312
351
|
const { scrollOffset: currentScrollOffset } = scrollStateRef.current;
|
|
313
|
-
|
|
314
|
-
setScrollOffset(newScrollOffset);
|
|
352
|
+
setScrollOffset(Math.max(0, currentScrollOffset - 1));
|
|
315
353
|
forceUpdate({});
|
|
316
354
|
});
|
|
317
355
|
ctx.setAction("scrollDown", () => {
|
|
318
356
|
const { scrollOffset: currentScrollOffset, maxHeight: currentMaxHeight, totalItems } = scrollStateRef.current;
|
|
319
357
|
const currentMaxScrollOffset = Math.max(0, totalItems - currentMaxHeight);
|
|
320
|
-
|
|
321
|
-
|
|
358
|
+
setScrollOffset(Math.min(currentMaxScrollOffset, currentScrollOffset + 1));
|
|
359
|
+
forceUpdate({});
|
|
360
|
+
});
|
|
361
|
+
ctx.setAction("pageUp", () => {
|
|
362
|
+
const { maxHeight: vh } = scrollStateRef.current;
|
|
363
|
+
const page = Math.max(1, vh || 1);
|
|
364
|
+
const newIndex = Math.max(0, selectedIndexRef.current - page);
|
|
365
|
+
selectedIndexRef.current = newIndex;
|
|
366
|
+
const list = displayItemsRef.current;
|
|
367
|
+
onSelectionChangeRef.current?.(newIndex, list[newIndex]);
|
|
368
|
+
setScrollOffset(newIndex);
|
|
322
369
|
forceUpdate({});
|
|
323
370
|
});
|
|
371
|
+
ctx.setAction("pageDown", () => {
|
|
372
|
+
const { maxHeight: vh, totalItems } = scrollStateRef.current;
|
|
373
|
+
const page = Math.max(1, vh || 1);
|
|
374
|
+
const maxIndex = Math.max(0, totalItems - 1);
|
|
375
|
+
const newIndex = Math.min(maxIndex, selectedIndexRef.current + page);
|
|
376
|
+
selectedIndexRef.current = newIndex;
|
|
377
|
+
const list = displayItemsRef.current;
|
|
378
|
+
onSelectionChangeRef.current?.(newIndex, list[newIndex]);
|
|
379
|
+
const maxScroll = Math.max(0, totalItems - page);
|
|
380
|
+
setScrollOffset(Math.min(maxScroll, Math.max(0, newIndex - page + 1)));
|
|
381
|
+
forceUpdate({});
|
|
382
|
+
});
|
|
383
|
+
const navBindings = [
|
|
384
|
+
{ key: "upArrow", caption: "navigate", action: "moveUp", order: 0 },
|
|
385
|
+
{ key: "downArrow", caption: "navigate", action: "moveDown", order: 0 },
|
|
386
|
+
...PAGE_SCROLL_KEY_BINDINGS
|
|
387
|
+
];
|
|
324
388
|
if (sortable) {
|
|
325
389
|
ctx.setAction("toggleSort", () => {
|
|
326
390
|
const nextSort = sortOrder === "none" ? "asc" : sortOrder === "asc" ? "desc" : "none";
|
|
@@ -367,8 +431,7 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
367
431
|
}
|
|
368
432
|
};
|
|
369
433
|
ctx.setKeyBinding([
|
|
370
|
-
|
|
371
|
-
{ key: "downArrow", caption: "navigate", action: "moveDown", order: 0 },
|
|
434
|
+
...navBindings,
|
|
372
435
|
{
|
|
373
436
|
key: "s",
|
|
374
437
|
caption: sortCaption,
|
|
@@ -378,47 +441,47 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
378
441
|
]);
|
|
379
442
|
ctx.update();
|
|
380
443
|
} else {
|
|
381
|
-
ctx.setKeyBinding(
|
|
382
|
-
{ key: "upArrow", caption: "navigate", action: "moveUp", order: 0 },
|
|
383
|
-
{ key: "downArrow", caption: "navigate", action: "moveDown", order: 0 }
|
|
384
|
-
]);
|
|
444
|
+
ctx.setKeyBinding(navBindings);
|
|
385
445
|
}
|
|
386
446
|
}, [sortOrder, sortable]);
|
|
387
447
|
const selectedIndex = selectedIndexRef.current;
|
|
448
|
+
const needsBar = displayItems.length > effectiveMaxHeight;
|
|
449
|
+
const barGlyphs = needsBar ? scrollbarGlyphs(effectiveMaxHeight, displayItems.length, clampedScrollOffset) : null;
|
|
450
|
+
const appendBar = (rowContent, displayIndex) => {
|
|
451
|
+
if (!barGlyphs) return rowContent;
|
|
452
|
+
const glyph = barGlyphs[displayIndex] ?? BAR_TRACK;
|
|
453
|
+
return h2(
|
|
454
|
+
Box2,
|
|
455
|
+
{ flexDirection: "row" },
|
|
456
|
+
rowContent,
|
|
457
|
+
h2(Text2, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
|
|
458
|
+
);
|
|
459
|
+
};
|
|
388
460
|
const defaultRenderItem = (item, isSelected, displayIndex, actualIndex) => {
|
|
389
461
|
const isFirstVisible = displayIndex === 0;
|
|
390
462
|
const isLastVisible = displayIndex === visibleItems.length - 1;
|
|
391
|
-
let arrowPrefix = "";
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
arrowPrefix = "\
|
|
395
|
-
} else if (isLastVisible && canScrollDown) {
|
|
396
|
-
arrowPrefix = "\u2193 ";
|
|
397
|
-
} else {
|
|
398
|
-
arrowPrefix = " ";
|
|
399
|
-
}
|
|
400
|
-
if (isSelected) {
|
|
401
|
-
selectionPrefix = selectionMarker;
|
|
402
|
-
} else {
|
|
403
|
-
selectionPrefix = " ".repeat(selectionMarker.length);
|
|
463
|
+
let arrowPrefix = " ";
|
|
464
|
+
if (!needsBar) {
|
|
465
|
+
if (isFirstVisible && canScrollUp) arrowPrefix = "\u2191 ";
|
|
466
|
+
else if (isLastVisible && canScrollDown) arrowPrefix = "\u2193 ";
|
|
404
467
|
}
|
|
468
|
+
const selectionPrefix = isSelected ? selectionMarker : " ".repeat(selectionMarker.length);
|
|
469
|
+
const label = clipNameForScrollbar(item.name, needsBar);
|
|
405
470
|
return h2(
|
|
406
471
|
Box2,
|
|
407
472
|
{ flexDirection: "row" },
|
|
408
|
-
|
|
409
|
-
h2(Text2, {
|
|
410
|
-
key: `arrow-${actualIndex}`,
|
|
411
|
-
color: "white"
|
|
412
|
-
}, arrowPrefix),
|
|
413
|
-
// Selection marker space (always same width, not highlighted)
|
|
473
|
+
h2(Text2, { key: `arrow-${actualIndex}`, color: "white" }, arrowPrefix),
|
|
414
474
|
h2(Text2, { key: `marker-${actualIndex}`, color: "white" }, selectionPrefix),
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
475
|
+
h2(
|
|
476
|
+
Text2,
|
|
477
|
+
{
|
|
478
|
+
key: `name-${actualIndex}`,
|
|
479
|
+
color: isSelected ? "black" : "white",
|
|
480
|
+
backgroundColor: isSelected ? "cyan" : void 0,
|
|
481
|
+
bold: isSelected
|
|
482
|
+
},
|
|
483
|
+
label
|
|
484
|
+
)
|
|
422
485
|
);
|
|
423
486
|
};
|
|
424
487
|
const itemRenderer = renderItem || defaultRenderItem;
|
|
@@ -431,42 +494,32 @@ function ListComponent({ items, ctx, selectedIndexRef, renderItem, getTitle, sor
|
|
|
431
494
|
if (renderItem) {
|
|
432
495
|
const isFirstVisible = displayIndex === 0;
|
|
433
496
|
const isLastVisible = displayIndex === visibleItems.length - 1;
|
|
434
|
-
let arrowPrefix = "";
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
arrowPrefix = "\
|
|
438
|
-
} else if (isLastVisible && canScrollDown) {
|
|
439
|
-
arrowPrefix = "\u2193 ";
|
|
440
|
-
} else {
|
|
441
|
-
arrowPrefix = " ";
|
|
442
|
-
}
|
|
443
|
-
if (isSelected) {
|
|
444
|
-
selectionPrefix = selectionMarker;
|
|
445
|
-
} else {
|
|
446
|
-
selectionPrefix = " ".repeat(selectionMarker.length);
|
|
497
|
+
let arrowPrefix = " ";
|
|
498
|
+
if (!needsBar) {
|
|
499
|
+
if (isFirstVisible && canScrollUp) arrowPrefix = "\u2191 ";
|
|
500
|
+
else if (isLastVisible && canScrollDown) arrowPrefix = "\u2193 ";
|
|
447
501
|
}
|
|
502
|
+
const selectionPrefix = isSelected ? selectionMarker : " ".repeat(selectionMarker.length);
|
|
503
|
+
const clipped = needsBar ? { ...item, name: clipNameForScrollbar(item.name, true) } : item;
|
|
504
|
+
const row = h2(
|
|
505
|
+
Box2,
|
|
506
|
+
{ flexDirection: "row" },
|
|
507
|
+
h2(Text2, { key: `arrow-${actualIndex}`, color: "white" }, arrowPrefix),
|
|
508
|
+
h2(Text2, { key: `marker-${actualIndex}`, color: "white" }, selectionPrefix),
|
|
509
|
+
renderItem(clipped, isSelected, displayIndex)
|
|
510
|
+
);
|
|
448
511
|
return h2(ScreenRow, {
|
|
449
512
|
key: `item-${actualIndex}`,
|
|
450
|
-
children:
|
|
451
|
-
Box2,
|
|
452
|
-
{ flexDirection: "row" },
|
|
453
|
-
// Arrow (clickable if functional, not highlighted)
|
|
454
|
-
h2(Text2, {
|
|
455
|
-
key: `arrow-${actualIndex}`,
|
|
456
|
-
color: "white"
|
|
457
|
-
}, arrowPrefix),
|
|
458
|
-
// Selection marker space (always same width, not highlighted)
|
|
459
|
-
h2(Text2, { key: `marker-${actualIndex}`, color: "white" }, selectionPrefix),
|
|
460
|
-
// Custom rendered content
|
|
461
|
-
renderItem(item, isSelected, displayIndex)
|
|
462
|
-
)
|
|
463
|
-
});
|
|
464
|
-
} else {
|
|
465
|
-
return h2(ScreenRow, {
|
|
466
|
-
key: `item-${actualIndex}`,
|
|
467
|
-
children: itemRenderer(item, isSelected, displayIndex, actualIndex)
|
|
513
|
+
children: appendBar(row, displayIndex)
|
|
468
514
|
});
|
|
469
515
|
}
|
|
516
|
+
return h2(ScreenRow, {
|
|
517
|
+
key: `item-${actualIndex}`,
|
|
518
|
+
children: appendBar(
|
|
519
|
+
itemRenderer(item, isSelected, displayIndex, actualIndex),
|
|
520
|
+
displayIndex
|
|
521
|
+
)
|
|
522
|
+
});
|
|
470
523
|
})
|
|
471
524
|
);
|
|
472
525
|
}
|
|
@@ -474,6 +527,7 @@ var h2;
|
|
|
474
527
|
var init_list_components = __esm({
|
|
475
528
|
"src/screen/list-components.js"() {
|
|
476
529
|
init_components();
|
|
530
|
+
init_scrollbar();
|
|
477
531
|
h2 = createElement;
|
|
478
532
|
}
|
|
479
533
|
});
|
|
@@ -968,21 +1022,6 @@ function wrapTextLines(text, cols) {
|
|
|
968
1022
|
}
|
|
969
1023
|
return out;
|
|
970
1024
|
}
|
|
971
|
-
function scrollbarGlyphs(viewportRows, totalLines, scrollTop) {
|
|
972
|
-
const view = Math.max(1, Math.floor(viewportRows));
|
|
973
|
-
const total = Math.max(0, Math.floor(totalLines));
|
|
974
|
-
if (total <= view) return null;
|
|
975
|
-
const maxScroll = total - view;
|
|
976
|
-
const thumbSize = Math.max(1, Math.round(view / total * view));
|
|
977
|
-
const travel = Math.max(0, view - thumbSize);
|
|
978
|
-
const s = Math.min(Math.max(0, Math.floor(scrollTop)), maxScroll);
|
|
979
|
-
const thumbStart = maxScroll === 0 ? 0 : Math.round(s / maxScroll * travel);
|
|
980
|
-
const glyphs = [];
|
|
981
|
-
for (let i = 0; i < view; i++) {
|
|
982
|
-
glyphs.push(i >= thumbStart && i < thumbStart + thumbSize ? "\u2588" : "\u2502");
|
|
983
|
-
}
|
|
984
|
-
return glyphs;
|
|
985
|
-
}
|
|
986
1025
|
function padEndVisible(s, w) {
|
|
987
1026
|
const t = String(s ?? "");
|
|
988
1027
|
if (t.length >= w) return t.slice(0, w);
|
|
@@ -1001,20 +1040,19 @@ function ScrollableText({
|
|
|
1001
1040
|
}) {
|
|
1002
1041
|
const [scrollTop, setScrollTop] = useState3(0);
|
|
1003
1042
|
const [, bump] = useState3(0);
|
|
1004
|
-
const termCols = process.stdout.columns || 80;
|
|
1005
1043
|
const termRows = process.stdout.rows || 24;
|
|
1006
1044
|
const viewportRows = Math.max(
|
|
1007
1045
|
4,
|
|
1008
1046
|
maxHeight != null ? Math.floor(maxHeight) : Math.max(8, termRows - 8)
|
|
1009
1047
|
);
|
|
1010
|
-
const
|
|
1011
|
-
const
|
|
1048
|
+
const contentCols = Math.max(20, getScreenWidth() - 4);
|
|
1049
|
+
const barCols = showScrollbar ? 1 : 0;
|
|
1050
|
+
const textWidth = Math.max(8, contentCols - barCols);
|
|
1012
1051
|
const allLines = useMemo(() => {
|
|
1013
1052
|
if (Array.isArray(linesProp)) return linesProp.map((l) => String(l ?? ""));
|
|
1014
|
-
return wrap ? wrapTextLines(text,
|
|
1015
|
-
}, [linesProp, text, wrap,
|
|
1053
|
+
return wrap ? wrapTextLines(text, textWidth) : String(text ?? "").split("\n");
|
|
1054
|
+
}, [linesProp, text, wrap, textWidth]);
|
|
1016
1055
|
const needsBar = showScrollbar && allLines.length > viewportRows;
|
|
1017
|
-
const textWidth = Math.max(8, termCols - (needsBar ? 1 : 0));
|
|
1018
1056
|
const maxScroll = Math.max(0, allLines.length - viewportRows);
|
|
1019
1057
|
const clamped = Math.min(Math.max(0, scrollTop), maxScroll);
|
|
1020
1058
|
const visible = allLines.slice(clamped, clamped + viewportRows);
|
|
@@ -1054,22 +1092,24 @@ function ScrollableText({
|
|
|
1054
1092
|
const status = allLines.length === 0 ? "empty" : `lines ${clamped + 1}-${Math.min(clamped + visible.length, allLines.length)} of ${allLines.length}` + (needsBar ? " \xB7 \u2325\u2191/\u2193 or PgUp/Dn page" : "");
|
|
1055
1093
|
const rowNodes = visible.map((line, i) => {
|
|
1056
1094
|
const body = padEndVisible(line, textWidth);
|
|
1057
|
-
const glyph = bar ? bar[i] ?? "
|
|
1095
|
+
const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
|
|
1096
|
+
const isThumb = glyph === BAR_THUMB;
|
|
1058
1097
|
return h5(
|
|
1059
|
-
|
|
1060
|
-
{ key: `L${clamped + i}
|
|
1061
|
-
|
|
1062
|
-
glyph ? h5(Text5, { color:
|
|
1098
|
+
Text5,
|
|
1099
|
+
{ key: `L${clamped + i}` },
|
|
1100
|
+
body,
|
|
1101
|
+
glyph ? h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph) : null
|
|
1063
1102
|
);
|
|
1064
1103
|
});
|
|
1065
1104
|
if (bar && visible.length < viewportRows) {
|
|
1066
1105
|
for (let i = visible.length; i < viewportRows; i++) {
|
|
1106
|
+
const glyph = bar[i] ?? BAR_TRACK;
|
|
1067
1107
|
rowNodes.push(
|
|
1068
1108
|
h5(
|
|
1069
|
-
|
|
1070
|
-
{ key: `pad${i}
|
|
1071
|
-
|
|
1072
|
-
h5(Text5, { color:
|
|
1109
|
+
Text5,
|
|
1110
|
+
{ key: `pad${i}` },
|
|
1111
|
+
padEndVisible("", textWidth),
|
|
1112
|
+
h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
|
|
1073
1113
|
)
|
|
1074
1114
|
);
|
|
1075
1115
|
}
|
|
@@ -1085,16 +1125,14 @@ function ScrollableText({
|
|
|
1085
1125
|
var h5, SCROLL_KEYS;
|
|
1086
1126
|
var init_scrollable_text = __esm({
|
|
1087
1127
|
"src/screen/scrollable-text.js"() {
|
|
1128
|
+
init_components();
|
|
1129
|
+
init_scrollbar();
|
|
1130
|
+
init_scrollbar();
|
|
1088
1131
|
h5 = createElement2;
|
|
1089
1132
|
SCROLL_KEYS = [
|
|
1090
1133
|
{ key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
|
|
1091
1134
|
{ key: "downArrow", caption: "scroll", action: "scrollDown", order: 0 },
|
|
1092
|
-
|
|
1093
|
-
{ key: "downArrow", meta: true, caption: "page", action: "pageDown", order: 0 },
|
|
1094
|
-
{ key: "upArrow", ctrl: true, caption: "page", action: "pageUp", order: 0 },
|
|
1095
|
-
{ key: "downArrow", ctrl: true, caption: "page", action: "pageDown", order: 0 },
|
|
1096
|
-
{ key: "pageUp", caption: "page", action: "pageUp", order: 0 },
|
|
1097
|
-
{ key: "pageDown", caption: "page", action: "pageDown", order: 0 }
|
|
1135
|
+
...PAGE_SCROLL_KEY_BINDINGS
|
|
1098
1136
|
];
|
|
1099
1137
|
}
|
|
1100
1138
|
});
|
|
@@ -1230,6 +1268,8 @@ var init_footer_builder = __esm({
|
|
|
1230
1268
|
// src/screen/index.js
|
|
1231
1269
|
var screen_exports = {};
|
|
1232
1270
|
__export(screen_exports, {
|
|
1271
|
+
BAR_THUMB: () => BAR_THUMB,
|
|
1272
|
+
BAR_TRACK: () => BAR_TRACK,
|
|
1233
1273
|
Box: () => Box5,
|
|
1234
1274
|
Divider: () => Divider,
|
|
1235
1275
|
FooterPresets: () => FooterPresets,
|
|
@@ -1239,6 +1279,7 @@ __export(screen_exports, {
|
|
|
1239
1279
|
ListItem: () => ListItem,
|
|
1240
1280
|
MultiColumnListComponent: () => MultiColumnListComponent,
|
|
1241
1281
|
MultiColumnListWithPreviewComponent: () => MultiColumnListWithPreviewComponent,
|
|
1282
|
+
PAGE_SCROLL_KEY_BINDINGS: () => PAGE_SCROLL_KEY_BINDINGS,
|
|
1242
1283
|
React: () => React2,
|
|
1243
1284
|
ScreenBody: () => ScreenBody,
|
|
1244
1285
|
ScreenContainer: () => ScreenContainer,
|
|
@@ -1294,6 +1335,7 @@ var init_screen = __esm({
|
|
|
1294
1335
|
init_components();
|
|
1295
1336
|
init_ui_elements();
|
|
1296
1337
|
init_scrollable_text();
|
|
1338
|
+
init_scrollbar();
|
|
1297
1339
|
init_key_bindings();
|
|
1298
1340
|
init_utils();
|
|
1299
1341
|
init_footer_builder();
|
|
@@ -4146,12 +4188,13 @@ function tasksSchemaSpec(queueName = "tasks") {
|
|
|
4146
4188
|
}
|
|
4147
4189
|
};
|
|
4148
4190
|
}
|
|
4149
|
-
function taskHistoryInsertFromQueueRow(row, overrides) {
|
|
4191
|
+
function taskHistoryInsertFromQueueRow(row, overrides = {}) {
|
|
4150
4192
|
const { id, ...snapshot } = row;
|
|
4151
|
-
void id;
|
|
4193
|
+
const opid = overrides.opid !== void 0 ? overrides.opid : snapshot.opid != null && String(snapshot.opid).trim() !== "" ? snapshot.opid : id;
|
|
4152
4194
|
return {
|
|
4153
4195
|
...snapshot,
|
|
4154
|
-
...overrides
|
|
4196
|
+
...overrides,
|
|
4197
|
+
opid
|
|
4155
4198
|
};
|
|
4156
4199
|
}
|
|
4157
4200
|
async function ensureTaskTables(context, options = {}) {
|
|
@@ -6451,69 +6494,6 @@ var TaskStopRunner = class extends AbstractTask {
|
|
|
6451
6494
|
}
|
|
6452
6495
|
};
|
|
6453
6496
|
|
|
6454
|
-
// src/tasks/coreTasks/TaskGetLogs.js
|
|
6455
|
-
var TaskGetLogs = class extends AbstractTask {
|
|
6456
|
-
/**
|
|
6457
|
-
* @param {object} context
|
|
6458
|
-
* @param {Record<string, unknown>} [overrides]
|
|
6459
|
-
* @returns {Promise<{ source: string, resource: string, tail: number, afterTs?: string }>}
|
|
6460
|
-
*/
|
|
6461
|
-
static async resolveCustomParams(context, overrides = {}) {
|
|
6462
|
-
const merged = AbstractTask._mergeTypedParams(context, "task-get-logs", {
|
|
6463
|
-
source: "string",
|
|
6464
|
-
resource: "string",
|
|
6465
|
-
tail: "number default 100",
|
|
6466
|
-
afterTs: "string"
|
|
6467
|
-
}, overrides);
|
|
6468
|
-
const source = typeof merged.source === "string" ? merged.source.trim() : "";
|
|
6469
|
-
const resource = typeof merged.resource === "string" ? merged.resource.trim() : "";
|
|
6470
|
-
if (!source) throw new ParamError('getLogs: param "source" is required');
|
|
6471
|
-
if (!resource) throw new ParamError('getLogs: param "resource" is required');
|
|
6472
|
-
let tail = Number(merged.tail);
|
|
6473
|
-
if (!Number.isFinite(tail) || tail < 1) tail = 100;
|
|
6474
|
-
tail = Math.min(1e4, Math.max(1, Math.floor(tail)));
|
|
6475
|
-
const out = { source, resource, tail };
|
|
6476
|
-
if (typeof merged.afterTs === "string" && merged.afterTs.trim()) {
|
|
6477
|
-
out.afterTs = merged.afterTs.trim();
|
|
6478
|
-
}
|
|
6479
|
-
return out;
|
|
6480
|
-
}
|
|
6481
|
-
/**
|
|
6482
|
-
* @param {unknown} _reportProgress Unused (single-shot read, no progress events).
|
|
6483
|
-
* @returns {Promise<{ success: boolean, results: unknown }>}
|
|
6484
|
-
*/
|
|
6485
|
-
async run(_reportProgress) {
|
|
6486
|
-
const p = this.task.params ?? {};
|
|
6487
|
-
const source = String(p.source ?? "").trim();
|
|
6488
|
-
const resource = String(p.resource ?? "").trim();
|
|
6489
|
-
const tail = Math.max(1, Math.min(1e4, Number(p.tail) > 0 ? Number(p.tail) : 100));
|
|
6490
|
-
const afterTs = p.afterTs != null && String(p.afterTs).trim() ? String(p.afterTs).trim() : null;
|
|
6491
|
-
if (!source || !resource) {
|
|
6492
|
-
return {
|
|
6493
|
-
success: false,
|
|
6494
|
-
results: { error: 'getLogs requires params "source" and "resource"' }
|
|
6495
|
-
};
|
|
6496
|
-
}
|
|
6497
|
-
try {
|
|
6498
|
-
const { records, latestTs } = await readTaskIpcLogsSnapshot(this.context, {
|
|
6499
|
-
source,
|
|
6500
|
-
resource,
|
|
6501
|
-
tail,
|
|
6502
|
-
afterTs
|
|
6503
|
-
});
|
|
6504
|
-
return {
|
|
6505
|
-
success: true,
|
|
6506
|
-
results: { records, latestTs, source, resource }
|
|
6507
|
-
};
|
|
6508
|
-
} catch (e) {
|
|
6509
|
-
return {
|
|
6510
|
-
success: false,
|
|
6511
|
-
results: { error: e?.message ?? String(e) }
|
|
6512
|
-
};
|
|
6513
|
-
}
|
|
6514
|
-
}
|
|
6515
|
-
};
|
|
6516
|
-
|
|
6517
6497
|
// src/tasks/runtimeParams.js
|
|
6518
6498
|
var LOOP_RUNTIME_KEYS = ["maxParallel", "pollMs", "claimJitterMs", "scanLimit"];
|
|
6519
6499
|
var LOGGER_RUNTIME_KEYS = [
|
|
@@ -6527,7 +6507,16 @@ var LOGGER_RUNTIME_KEYS = [
|
|
|
6527
6507
|
"progressWithTimes",
|
|
6528
6508
|
"progressThrottleMs"
|
|
6529
6509
|
];
|
|
6530
|
-
var CONTROL_LANE_TASK_NAMES = [
|
|
6510
|
+
var CONTROL_LANE_TASK_NAMES = [
|
|
6511
|
+
"stopRunner",
|
|
6512
|
+
"stop",
|
|
6513
|
+
"pauseRunner",
|
|
6514
|
+
"pause",
|
|
6515
|
+
"unpauseRunner",
|
|
6516
|
+
"unpause",
|
|
6517
|
+
"setRuntimeParam",
|
|
6518
|
+
"setRunnerParam"
|
|
6519
|
+
];
|
|
6531
6520
|
function controlLaneTaskNames(extra) {
|
|
6532
6521
|
const names = [...CONTROL_LANE_TASK_NAMES];
|
|
6533
6522
|
if (extra == null || extra === "") return names;
|
|
@@ -6590,6 +6579,7 @@ function ensureTasksRuntime(context, seed = {}) {
|
|
|
6590
6579
|
if (rt.pollMs === void 0) rt.pollMs = seed.pollMs ?? 1e3;
|
|
6591
6580
|
if (rt.claimJitterMs === void 0) rt.claimJitterMs = seed.claimJitterMs ?? 0;
|
|
6592
6581
|
if (rt.scanLimit === void 0) rt.scanLimit = seed.scanLimit ?? 100;
|
|
6582
|
+
if (rt.paused === void 0) rt.paused = seed.paused === true;
|
|
6593
6583
|
return rt;
|
|
6594
6584
|
}
|
|
6595
6585
|
async function applyRuntimeParam(context, key, value) {
|
|
@@ -6654,6 +6644,140 @@ function readLoopRuntime(context) {
|
|
|
6654
6644
|
};
|
|
6655
6645
|
}
|
|
6656
6646
|
|
|
6647
|
+
// src/tasks/coreTasks/TaskPauseRunner.js
|
|
6648
|
+
async function applyRunnerPaused(context, paused) {
|
|
6649
|
+
const runtime = ensureTasksRuntime(context);
|
|
6650
|
+
const was = runtime.paused === true;
|
|
6651
|
+
runtime.paused = paused === true;
|
|
6652
|
+
const registry = context.servicesRegistry;
|
|
6653
|
+
if (registry && typeof registry === "object") {
|
|
6654
|
+
await updateServicesRegistryMetadata(context, registry, {
|
|
6655
|
+
paused: runtime.paused,
|
|
6656
|
+
pausedAt: runtime.paused ? (/* @__PURE__ */ new Date()).toISOString() : null
|
|
6657
|
+
});
|
|
6658
|
+
}
|
|
6659
|
+
const message = runtime.paused ? was ? "Runner already paused (no new worker tasks)." : "Runner paused: finishing in-flight work; no new worker tasks until unpause." : was ? "Runner unpaused: claiming worker tasks again." : "Runner already running (not paused).";
|
|
6660
|
+
context.logger?.warn?.(
|
|
6661
|
+
runtime.paused ? `[TaskPauseRunner] ${message}` : `[TaskUnpauseRunner] ${message}`
|
|
6662
|
+
);
|
|
6663
|
+
return {
|
|
6664
|
+
success: true,
|
|
6665
|
+
results: {
|
|
6666
|
+
paused: runtime.paused,
|
|
6667
|
+
message
|
|
6668
|
+
}
|
|
6669
|
+
};
|
|
6670
|
+
}
|
|
6671
|
+
var TaskPauseRunner = class extends AbstractTask {
|
|
6672
|
+
static taskName = "pauseRunner";
|
|
6673
|
+
static description = "Pause a runner: finish in-flight tasks, claim no new worker tasks until unpaused";
|
|
6674
|
+
static aliases = ["pause"];
|
|
6675
|
+
static defaultWaitForResult = true;
|
|
6676
|
+
/**
|
|
6677
|
+
* @param {object} context
|
|
6678
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6679
|
+
* @returns {Promise<object>}
|
|
6680
|
+
*/
|
|
6681
|
+
static async resolveParams(context, overrides = {}) {
|
|
6682
|
+
const main = await super.resolveParams(context, overrides);
|
|
6683
|
+
if (!main.serviceName) {
|
|
6684
|
+
throw new ParamError(
|
|
6685
|
+
"pause/pauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)"
|
|
6686
|
+
);
|
|
6687
|
+
}
|
|
6688
|
+
return main;
|
|
6689
|
+
}
|
|
6690
|
+
async run() {
|
|
6691
|
+
return applyRunnerPaused(this.context, true);
|
|
6692
|
+
}
|
|
6693
|
+
};
|
|
6694
|
+
var TaskUnpauseRunner = class extends AbstractTask {
|
|
6695
|
+
static taskName = "unpauseRunner";
|
|
6696
|
+
static description = "Unpause a runner: resume claiming worker tasks";
|
|
6697
|
+
static aliases = ["unpause"];
|
|
6698
|
+
static defaultWaitForResult = true;
|
|
6699
|
+
/**
|
|
6700
|
+
* @param {object} context
|
|
6701
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6702
|
+
* @returns {Promise<object>}
|
|
6703
|
+
*/
|
|
6704
|
+
static async resolveParams(context, overrides = {}) {
|
|
6705
|
+
const main = await super.resolveParams(context, overrides);
|
|
6706
|
+
if (!main.serviceName) {
|
|
6707
|
+
throw new ParamError(
|
|
6708
|
+
"unpause/unpauseRunner requires --serviceName (registry instance name; optional --serviceGroup, --instanceNumber, --serverName to narrow targeting)"
|
|
6709
|
+
);
|
|
6710
|
+
}
|
|
6711
|
+
return main;
|
|
6712
|
+
}
|
|
6713
|
+
async run() {
|
|
6714
|
+
return applyRunnerPaused(this.context, false);
|
|
6715
|
+
}
|
|
6716
|
+
};
|
|
6717
|
+
|
|
6718
|
+
// src/tasks/coreTasks/TaskGetLogs.js
|
|
6719
|
+
var TaskGetLogs = class extends AbstractTask {
|
|
6720
|
+
/**
|
|
6721
|
+
* @param {object} context
|
|
6722
|
+
* @param {Record<string, unknown>} [overrides]
|
|
6723
|
+
* @returns {Promise<{ source: string, resource: string, tail: number, afterTs?: string }>}
|
|
6724
|
+
*/
|
|
6725
|
+
static async resolveCustomParams(context, overrides = {}) {
|
|
6726
|
+
const merged = AbstractTask._mergeTypedParams(context, "task-get-logs", {
|
|
6727
|
+
source: "string",
|
|
6728
|
+
resource: "string",
|
|
6729
|
+
tail: "number default 100",
|
|
6730
|
+
afterTs: "string"
|
|
6731
|
+
}, overrides);
|
|
6732
|
+
const source = typeof merged.source === "string" ? merged.source.trim() : "";
|
|
6733
|
+
const resource = typeof merged.resource === "string" ? merged.resource.trim() : "";
|
|
6734
|
+
if (!source) throw new ParamError('getLogs: param "source" is required');
|
|
6735
|
+
if (!resource) throw new ParamError('getLogs: param "resource" is required');
|
|
6736
|
+
let tail = Number(merged.tail);
|
|
6737
|
+
if (!Number.isFinite(tail) || tail < 1) tail = 100;
|
|
6738
|
+
tail = Math.min(1e4, Math.max(1, Math.floor(tail)));
|
|
6739
|
+
const out = { source, resource, tail };
|
|
6740
|
+
if (typeof merged.afterTs === "string" && merged.afterTs.trim()) {
|
|
6741
|
+
out.afterTs = merged.afterTs.trim();
|
|
6742
|
+
}
|
|
6743
|
+
return out;
|
|
6744
|
+
}
|
|
6745
|
+
/**
|
|
6746
|
+
* @param {unknown} _reportProgress Unused (single-shot read, no progress events).
|
|
6747
|
+
* @returns {Promise<{ success: boolean, results: unknown }>}
|
|
6748
|
+
*/
|
|
6749
|
+
async run(_reportProgress) {
|
|
6750
|
+
const p = this.task.params ?? {};
|
|
6751
|
+
const source = String(p.source ?? "").trim();
|
|
6752
|
+
const resource = String(p.resource ?? "").trim();
|
|
6753
|
+
const tail = Math.max(1, Math.min(1e4, Number(p.tail) > 0 ? Number(p.tail) : 100));
|
|
6754
|
+
const afterTs = p.afterTs != null && String(p.afterTs).trim() ? String(p.afterTs).trim() : null;
|
|
6755
|
+
if (!source || !resource) {
|
|
6756
|
+
return {
|
|
6757
|
+
success: false,
|
|
6758
|
+
results: { error: 'getLogs requires params "source" and "resource"' }
|
|
6759
|
+
};
|
|
6760
|
+
}
|
|
6761
|
+
try {
|
|
6762
|
+
const { records, latestTs } = await readTaskIpcLogsSnapshot(this.context, {
|
|
6763
|
+
source,
|
|
6764
|
+
resource,
|
|
6765
|
+
tail,
|
|
6766
|
+
afterTs
|
|
6767
|
+
});
|
|
6768
|
+
return {
|
|
6769
|
+
success: true,
|
|
6770
|
+
results: { records, latestTs, source, resource }
|
|
6771
|
+
};
|
|
6772
|
+
} catch (e) {
|
|
6773
|
+
return {
|
|
6774
|
+
success: false,
|
|
6775
|
+
results: { error: e?.message ?? String(e) }
|
|
6776
|
+
};
|
|
6777
|
+
}
|
|
6778
|
+
}
|
|
6779
|
+
};
|
|
6780
|
+
|
|
6657
6781
|
// src/tasks/coreTasks/TaskSetRuntimeParam.js
|
|
6658
6782
|
var TaskSetRuntimeParam = class extends AbstractTask {
|
|
6659
6783
|
static defaultWaitForResult = true;
|
|
@@ -6809,7 +6933,7 @@ var TasksRegistry = class _TasksRegistry {
|
|
|
6809
6933
|
* @returns {TasksRegistry}
|
|
6810
6934
|
*/
|
|
6811
6935
|
static withCoreTasks() {
|
|
6812
|
-
return new _TasksRegistry().add("ping", TaskPing).add("sampleProcess", TaskSampleProcess).add("shellCommand", TaskShellCommand).add("systemInfo", TaskSystemInfo).add("info", TaskSystemInfo).add("taskSumAB", TaskSumAB).add("stopRunner", TaskStopRunner).add("stop", TaskStopRunner).add("getLogs", TaskGetLogs).add("setRuntimeParam", TaskSetRuntimeParam).add("setRunnerParam", TaskSetRuntimeParam);
|
|
6936
|
+
return new _TasksRegistry().add("ping", TaskPing).add("sampleProcess", TaskSampleProcess).add("shellCommand", TaskShellCommand).add("systemInfo", TaskSystemInfo).add("info", TaskSystemInfo).add("taskSumAB", TaskSumAB).add("stopRunner", TaskStopRunner).add("stop", TaskStopRunner).add("pauseRunner", TaskPauseRunner).add("pause", TaskPauseRunner).add("unpauseRunner", TaskUnpauseRunner).add("unpause", TaskUnpauseRunner).add("getLogs", TaskGetLogs).add("setRuntimeParam", TaskSetRuntimeParam).add("setRunnerParam", TaskSetRuntimeParam);
|
|
6813
6937
|
}
|
|
6814
6938
|
/**
|
|
6815
6939
|
* Register a single task class under a name. Overwrites any previous entry.
|
|
@@ -7171,6 +7295,7 @@ async function runTasksLoop(context, options) {
|
|
|
7171
7295
|
const defaultMeta = {
|
|
7172
7296
|
component: "tasks-runner",
|
|
7173
7297
|
allowedTasks: allowedTasks?.length ? allowedTasks.join(",") : "all",
|
|
7298
|
+
paused: false,
|
|
7174
7299
|
runtime: {
|
|
7175
7300
|
maxParallel: loop0.maxParallel,
|
|
7176
7301
|
pollMs: loop0.pollMs,
|
|
@@ -7237,28 +7362,38 @@ async function runTasksLoop(context, options) {
|
|
|
7237
7362
|
if (claimJitterMs > 0) {
|
|
7238
7363
|
await sleepMs(Math.floor(Math.random() * (claimJitterMs + 1)));
|
|
7239
7364
|
}
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
|
|
7247
|
-
|
|
7248
|
-
|
|
7249
|
-
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
if (
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
|
|
7257
|
-
|
|
7258
|
-
|
|
7259
|
-
|
|
7260
|
-
|
|
7261
|
-
|
|
7365
|
+
const paused = context.tasksRuntime?.paused === true;
|
|
7366
|
+
if (!paused) {
|
|
7367
|
+
while (runningPromises.size < maxParallel) {
|
|
7368
|
+
const claimed = await claimNextRunnableTask(
|
|
7369
|
+
context,
|
|
7370
|
+
tasksTable,
|
|
7371
|
+
target,
|
|
7372
|
+
registry,
|
|
7373
|
+
scanLimit,
|
|
7374
|
+
allowedTasks,
|
|
7375
|
+
runnerIdentity
|
|
7376
|
+
);
|
|
7377
|
+
if (!claimed) break;
|
|
7378
|
+
const p = executeClaimedTask(
|
|
7379
|
+
context,
|
|
7380
|
+
tasksTable,
|
|
7381
|
+
historyTable,
|
|
7382
|
+
claimed,
|
|
7383
|
+
registry,
|
|
7384
|
+
runningTaskInstances
|
|
7385
|
+
).then(async (outcome) => {
|
|
7386
|
+
if (outcome.stopRunnerRequested && !stopRequested) {
|
|
7387
|
+
stopRequested = true;
|
|
7388
|
+
stopAllowanceMs = outcome.stopAllowanceMs || stopAllowanceMs;
|
|
7389
|
+
context.tasksRunnerStop = true;
|
|
7390
|
+
await signalRunningTasksStop(context, runningTaskInstances, stopAllowanceMs);
|
|
7391
|
+
}
|
|
7392
|
+
}).finally(() => {
|
|
7393
|
+
runningPromises.delete(p);
|
|
7394
|
+
});
|
|
7395
|
+
runningPromises.add(p);
|
|
7396
|
+
}
|
|
7262
7397
|
}
|
|
7263
7398
|
const wakePromises = [...runningPromises];
|
|
7264
7399
|
if (runningControlPromise) {
|