@nmakarov/cli-toolkit 0.80.0 → 0.82.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 +132 -44
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +134 -46
- package/dist/cli-runner.js.map +1 -1
- package/dist/index.cjs +140 -44
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +134 -46
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +132 -44
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +134 -46
- package/dist/init.js.map +1 -1
- package/dist/screen.cjs +128 -44
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +120 -44
- package/dist/screen.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -996,9 +996,68 @@ var init_ui_elements = __esm({
|
|
|
996
996
|
}
|
|
997
997
|
});
|
|
998
998
|
|
|
999
|
-
// src/screen/
|
|
1000
|
-
|
|
1001
|
-
|
|
999
|
+
// src/screen/follow-scroll.js
|
|
1000
|
+
function clampScroll(scrollTop, maxScroll) {
|
|
1001
|
+
const max = Math.max(0, Number(maxScroll) || 0);
|
|
1002
|
+
const top = Number(scrollTop) || 0;
|
|
1003
|
+
return Math.min(Math.max(0, top), max);
|
|
1004
|
+
}
|
|
1005
|
+
function isScrolledToBottom(scrollTop, maxScroll) {
|
|
1006
|
+
return clampScroll(scrollTop, maxScroll) >= Math.max(0, Number(maxScroll) || 0);
|
|
1007
|
+
}
|
|
1008
|
+
function nextScrollAfterUserMove(scrollTop, maxScroll, delta) {
|
|
1009
|
+
const next = clampScroll((Number(scrollTop) || 0) + (Number(delta) || 0), maxScroll);
|
|
1010
|
+
return { scrollTop: next, following: isScrolledToBottom(next, maxScroll) };
|
|
1011
|
+
}
|
|
1012
|
+
function nextScrollAfterContentChange({ following, scrollTop, maxScroll }) {
|
|
1013
|
+
const max = Math.max(0, Number(maxScroll) || 0);
|
|
1014
|
+
if (following) return { scrollTop: max, following: true };
|
|
1015
|
+
const next = clampScroll(scrollTop, max);
|
|
1016
|
+
return { scrollTop: next, following: isScrolledToBottom(next, max) };
|
|
1017
|
+
}
|
|
1018
|
+
var init_follow_scroll = __esm({
|
|
1019
|
+
"src/screen/follow-scroll.js"() {
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// src/screen/visible-text.js
|
|
1024
|
+
function stripAnsi(text) {
|
|
1025
|
+
return String(text ?? "").replace(ANSI_RE, "");
|
|
1026
|
+
}
|
|
1027
|
+
function visibleWidth(text) {
|
|
1028
|
+
return [...stripAnsi(text)].length;
|
|
1029
|
+
}
|
|
1030
|
+
function sliceVisible(text, cols) {
|
|
1031
|
+
const w = Math.max(0, Math.floor(Number(cols) || 0));
|
|
1032
|
+
const s = String(text ?? "");
|
|
1033
|
+
if (w === 0) return "";
|
|
1034
|
+
let vis = 0;
|
|
1035
|
+
let out = "";
|
|
1036
|
+
let i = 0;
|
|
1037
|
+
while (i < s.length && vis < w) {
|
|
1038
|
+
ANSI_RE.lastIndex = i;
|
|
1039
|
+
const m = ANSI_RE.exec(s);
|
|
1040
|
+
if (m && m.index === i) {
|
|
1041
|
+
out += m[0];
|
|
1042
|
+
i += m[0].length;
|
|
1043
|
+
continue;
|
|
1044
|
+
}
|
|
1045
|
+
const cp3 = s.codePointAt(i);
|
|
1046
|
+
const ch = String.fromCodePoint(cp3);
|
|
1047
|
+
out += ch;
|
|
1048
|
+
i += ch.length;
|
|
1049
|
+
vis += 1;
|
|
1050
|
+
}
|
|
1051
|
+
return out;
|
|
1052
|
+
}
|
|
1053
|
+
function padEndVisible(text, cols) {
|
|
1054
|
+
const w = Math.max(0, Math.floor(Number(cols) || 0));
|
|
1055
|
+
const s = String(text ?? "");
|
|
1056
|
+
const vis = visibleWidth(s);
|
|
1057
|
+
if (vis === w) return s;
|
|
1058
|
+
if (vis > w) return sliceVisible(s, w);
|
|
1059
|
+
return s + " ".repeat(w - vis);
|
|
1060
|
+
}
|
|
1002
1061
|
function wrapTextLines(text, cols) {
|
|
1003
1062
|
const w = Math.max(1, Math.floor(Number(cols) || 1));
|
|
1004
1063
|
const out = [];
|
|
@@ -1007,20 +1066,30 @@ function wrapTextLines(text, cols) {
|
|
|
1007
1066
|
out.push("");
|
|
1008
1067
|
continue;
|
|
1009
1068
|
}
|
|
1069
|
+
if (visibleWidth(raw) <= w) {
|
|
1070
|
+
out.push(raw);
|
|
1071
|
+
continue;
|
|
1072
|
+
}
|
|
1010
1073
|
let rest = raw;
|
|
1011
|
-
while (rest
|
|
1012
|
-
|
|
1013
|
-
|
|
1074
|
+
while (visibleWidth(rest) > w) {
|
|
1075
|
+
const head = sliceVisible(rest, w);
|
|
1076
|
+
out.push(head);
|
|
1077
|
+
rest = rest.slice(head.length);
|
|
1014
1078
|
}
|
|
1015
1079
|
if (rest.length > 0) out.push(rest);
|
|
1016
1080
|
}
|
|
1017
1081
|
return out;
|
|
1018
1082
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
}
|
|
1083
|
+
var ANSI_RE;
|
|
1084
|
+
var init_visible_text = __esm({
|
|
1085
|
+
"src/screen/visible-text.js"() {
|
|
1086
|
+
ANSI_RE = /\u001b(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
1087
|
+
}
|
|
1088
|
+
});
|
|
1089
|
+
|
|
1090
|
+
// src/screen/scrollable-text.js
|
|
1091
|
+
import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
|
|
1092
|
+
import { Box as Box4, Text as Text5 } from "ink";
|
|
1024
1093
|
function ScrollableText({
|
|
1025
1094
|
ctx,
|
|
1026
1095
|
text = "",
|
|
@@ -1030,9 +1099,11 @@ function ScrollableText({
|
|
|
1030
1099
|
showScrollbar = true,
|
|
1031
1100
|
showStatus = true,
|
|
1032
1101
|
bindKeys = true,
|
|
1033
|
-
header = null
|
|
1102
|
+
header = null,
|
|
1103
|
+
followBottom = false
|
|
1034
1104
|
}) {
|
|
1035
1105
|
const [scrollTop, setScrollTop] = useState3(0);
|
|
1106
|
+
const [following, setFollowing] = useState3(() => !!followBottom);
|
|
1036
1107
|
const [, bump] = useState3(0);
|
|
1037
1108
|
const termRows = process.stdout.rows || 24;
|
|
1038
1109
|
const viewportRows = Math.max(
|
|
@@ -1051,48 +1122,52 @@ function ScrollableText({
|
|
|
1051
1122
|
const clamped = Math.min(Math.max(0, scrollTop), maxScroll);
|
|
1052
1123
|
const visible = allLines.slice(clamped, clamped + viewportRows);
|
|
1053
1124
|
const bar = needsBar ? scrollbarGlyphs(viewportRows, allLines.length, clamped) : null;
|
|
1054
|
-
useEffect2(() => {
|
|
1055
|
-
setScrollTop((s) => Math.min(s, maxScroll));
|
|
1056
|
-
}, [maxScroll]);
|
|
1057
1125
|
const maxScrollRef = useRef2(maxScroll);
|
|
1058
1126
|
const pageSizeRef = useRef2(viewportRows);
|
|
1127
|
+
const scrollTopRef = useRef2(scrollTop);
|
|
1128
|
+
const followingRef = useRef2(following);
|
|
1059
1129
|
maxScrollRef.current = maxScroll;
|
|
1060
1130
|
pageSizeRef.current = viewportRows;
|
|
1131
|
+
scrollTopRef.current = scrollTop;
|
|
1132
|
+
followingRef.current = following;
|
|
1133
|
+
useEffect2(() => {
|
|
1134
|
+
const next = nextScrollAfterContentChange({
|
|
1135
|
+
following: followBottom && followingRef.current,
|
|
1136
|
+
scrollTop: scrollTopRef.current,
|
|
1137
|
+
maxScroll
|
|
1138
|
+
});
|
|
1139
|
+
if (next.scrollTop !== scrollTopRef.current) setScrollTop(next.scrollTop);
|
|
1140
|
+
if (followBottom && next.following !== followingRef.current) setFollowing(next.following);
|
|
1141
|
+
}, [maxScroll, followBottom]);
|
|
1142
|
+
const applyUserScroll = (delta) => {
|
|
1143
|
+
const next = nextScrollAfterUserMove(scrollTopRef.current, maxScrollRef.current, delta);
|
|
1144
|
+
setScrollTop(next.scrollTop);
|
|
1145
|
+
if (followBottom) setFollowing(next.following);
|
|
1146
|
+
bump((n) => n + 1);
|
|
1147
|
+
ctx?.update?.();
|
|
1148
|
+
};
|
|
1061
1149
|
useEffect2(() => {
|
|
1062
1150
|
if (!ctx || !bindKeys) return void 0;
|
|
1063
1151
|
ctx.setKeyBinding(SCROLL_KEYS);
|
|
1064
|
-
ctx.setAction("scrollUp", () =>
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
});
|
|
1069
|
-
ctx.setAction("scrollDown", () => {
|
|
1070
|
-
setScrollTop((s) => Math.min(maxScrollRef.current, s + 1));
|
|
1071
|
-
bump((n) => n + 1);
|
|
1072
|
-
ctx.update?.();
|
|
1073
|
-
});
|
|
1074
|
-
ctx.setAction("pageUp", () => {
|
|
1075
|
-
setScrollTop((s) => Math.max(0, s - pageSizeRef.current));
|
|
1076
|
-
bump((n) => n + 1);
|
|
1077
|
-
ctx.update?.();
|
|
1078
|
-
});
|
|
1079
|
-
ctx.setAction("pageDown", () => {
|
|
1080
|
-
setScrollTop((s) => Math.min(maxScrollRef.current, s + pageSizeRef.current));
|
|
1081
|
-
bump((n) => n + 1);
|
|
1082
|
-
ctx.update?.();
|
|
1083
|
-
});
|
|
1152
|
+
ctx.setAction("scrollUp", () => applyUserScroll(-1));
|
|
1153
|
+
ctx.setAction("scrollDown", () => applyUserScroll(1));
|
|
1154
|
+
ctx.setAction("pageUp", () => applyUserScroll(-pageSizeRef.current));
|
|
1155
|
+
ctx.setAction("pageDown", () => applyUserScroll(pageSizeRef.current));
|
|
1084
1156
|
return void 0;
|
|
1085
|
-
}, [ctx, bindKeys]);
|
|
1086
|
-
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" : "");
|
|
1157
|
+
}, [ctx, bindKeys, followBottom]);
|
|
1158
|
+
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" : "") + (followBottom && following ? " \xB7 follow" : followBottom ? " \xB7 follow off" : "");
|
|
1087
1159
|
const rowNodes = visible.map((line, i) => {
|
|
1088
|
-
const body = padEndVisible(line, textWidth);
|
|
1089
1160
|
const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
|
|
1090
1161
|
const isThumb = glyph === BAR_THUMB;
|
|
1091
1162
|
return h5(
|
|
1092
|
-
|
|
1093
|
-
{ key: `L${clamped + i}
|
|
1094
|
-
|
|
1095
|
-
|
|
1163
|
+
Box4,
|
|
1164
|
+
{ key: `L${clamped + i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
|
|
1165
|
+
h5(
|
|
1166
|
+
Box4,
|
|
1167
|
+
{ width: textWidth, flexShrink: 0 },
|
|
1168
|
+
h5(Text5, { wrap: "truncate" }, padEndVisible(line, textWidth))
|
|
1169
|
+
),
|
|
1170
|
+
showScrollbar ? h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: isThumb ? "cyan" : "gray" }, glyph)) : null
|
|
1096
1171
|
);
|
|
1097
1172
|
});
|
|
1098
1173
|
if (bar && visible.length < viewportRows) {
|
|
@@ -1100,10 +1175,10 @@ function ScrollableText({
|
|
|
1100
1175
|
const glyph = bar[i] ?? BAR_TRACK;
|
|
1101
1176
|
rowNodes.push(
|
|
1102
1177
|
h5(
|
|
1103
|
-
|
|
1104
|
-
{ key: `pad${i}
|
|
1105
|
-
padEndVisible("", textWidth),
|
|
1106
|
-
h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph)
|
|
1178
|
+
Box4,
|
|
1179
|
+
{ key: `pad${i}`, flexDirection: "row", width: contentCols, flexShrink: 0 },
|
|
1180
|
+
h5(Box4, { width: textWidth, flexShrink: 0 }, h5(Text5, {}, padEndVisible("", textWidth))),
|
|
1181
|
+
h5(Box4, { width: 1, flexShrink: 0 }, h5(Text5, { color: glyph === BAR_THUMB ? "cyan" : "gray" }, glyph))
|
|
1107
1182
|
)
|
|
1108
1183
|
);
|
|
1109
1184
|
}
|
|
@@ -1121,7 +1196,10 @@ var init_scrollable_text = __esm({
|
|
|
1121
1196
|
"src/screen/scrollable-text.js"() {
|
|
1122
1197
|
init_components();
|
|
1123
1198
|
init_scrollbar();
|
|
1199
|
+
init_follow_scroll();
|
|
1200
|
+
init_visible_text();
|
|
1124
1201
|
init_scrollbar();
|
|
1202
|
+
init_visible_text();
|
|
1125
1203
|
h5 = createElement2;
|
|
1126
1204
|
SCROLL_KEYS = [
|
|
1127
1205
|
{ key: "upArrow", caption: "scroll", action: "scrollUp", order: 0 },
|
|
@@ -1279,6 +1357,8 @@ var init_screen = __esm({
|
|
|
1279
1357
|
init_components();
|
|
1280
1358
|
init_ui_elements();
|
|
1281
1359
|
init_scrollable_text();
|
|
1360
|
+
init_visible_text();
|
|
1361
|
+
init_follow_scroll();
|
|
1282
1362
|
init_scrollbar();
|
|
1283
1363
|
init_key_bindings();
|
|
1284
1364
|
init_utils();
|
|
@@ -10164,6 +10244,7 @@ export {
|
|
|
10164
10244
|
buildDetailBreadcrumb,
|
|
10165
10245
|
buildFooter,
|
|
10166
10246
|
bumpPatchVersion,
|
|
10247
|
+
clampScroll,
|
|
10167
10248
|
cloneRepo,
|
|
10168
10249
|
coerceRuntimeValue,
|
|
10169
10250
|
controlLaneTaskNames,
|
|
@@ -10201,6 +10282,7 @@ export {
|
|
|
10201
10282
|
ipcFileLogsTableNameForSourceResource,
|
|
10202
10283
|
isFreshOnline,
|
|
10203
10284
|
isPidAlive,
|
|
10285
|
+
isScrolledToBottom,
|
|
10204
10286
|
joiEdateType,
|
|
10205
10287
|
joiStringArrayType,
|
|
10206
10288
|
listServicesRegistry as listAliveRunnerHeartbeats,
|
|
@@ -10214,11 +10296,14 @@ export {
|
|
|
10214
10296
|
memo,
|
|
10215
10297
|
mergeAllowedTasksWithServiceTasks,
|
|
10216
10298
|
mergeRuntimeParamSpecs,
|
|
10299
|
+
nextScrollAfterContentChange,
|
|
10300
|
+
nextScrollAfterUserMove,
|
|
10217
10301
|
nextTimeMatch,
|
|
10218
10302
|
normalizeAllowedTasks,
|
|
10219
10303
|
npmEnv,
|
|
10220
10304
|
npmInstallEnv,
|
|
10221
10305
|
organizeFooterMessages,
|
|
10306
|
+
padEndVisible,
|
|
10222
10307
|
parseGitHost,
|
|
10223
10308
|
parsePm2Jlist,
|
|
10224
10309
|
prepareGitHost,
|
|
@@ -10264,9 +10349,11 @@ export {
|
|
|
10264
10349
|
showMultiColumnListWithPreviewScreen,
|
|
10265
10350
|
showScreen,
|
|
10266
10351
|
showWordGridScreen,
|
|
10352
|
+
sliceVisible,
|
|
10267
10353
|
sshRun,
|
|
10268
10354
|
startPm2,
|
|
10269
10355
|
stopPm2,
|
|
10356
|
+
stripAnsi,
|
|
10270
10357
|
syncEnv,
|
|
10271
10358
|
taskHistoryInsertFromQueueRow,
|
|
10272
10359
|
timeMatcher,
|
|
@@ -10283,6 +10370,7 @@ export {
|
|
|
10283
10370
|
useMemo2 as useMemo,
|
|
10284
10371
|
useRef3 as useRef,
|
|
10285
10372
|
useState4 as useState,
|
|
10373
|
+
visibleWidth,
|
|
10286
10374
|
waitForTaskResult,
|
|
10287
10375
|
waitPm2,
|
|
10288
10376
|
wrapTextLines,
|