@nmakarov/cli-toolkit 0.79.0 → 0.81.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 +194 -57
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +194 -57
- package/dist/cli-runner.js.map +1 -1
- package/dist/db.cjs +105 -25
- package/dist/db.cjs.map +1 -1
- package/dist/db.js +105 -25
- package/dist/db.js.map +1 -1
- package/dist/index.cjs +179 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +175 -56
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +89 -32
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +89 -32
- package/dist/init.js.map +1 -1
- package/dist/logger.cjs +6 -5
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.js +6 -5
- package/dist/logger.js.map +1 -1
- package/dist/screen.cjs +59 -26
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +55 -26
- package/dist/screen.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -996,6 +996,30 @@ var init_ui_elements = __esm({
|
|
|
996
996
|
}
|
|
997
997
|
});
|
|
998
998
|
|
|
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
|
+
|
|
999
1023
|
// src/screen/scrollable-text.js
|
|
1000
1024
|
import { useState as useState3, useEffect as useEffect2, useMemo, useRef as useRef2, createElement as createElement2 } from "react";
|
|
1001
1025
|
import { Box as Box4, Text as Text5 } from "ink";
|
|
@@ -1030,9 +1054,11 @@ function ScrollableText({
|
|
|
1030
1054
|
showScrollbar = true,
|
|
1031
1055
|
showStatus = true,
|
|
1032
1056
|
bindKeys = true,
|
|
1033
|
-
header = null
|
|
1057
|
+
header = null,
|
|
1058
|
+
followBottom = false
|
|
1034
1059
|
}) {
|
|
1035
1060
|
const [scrollTop, setScrollTop] = useState3(0);
|
|
1061
|
+
const [following, setFollowing] = useState3(() => !!followBottom);
|
|
1036
1062
|
const [, bump] = useState3(0);
|
|
1037
1063
|
const termRows = process.stdout.rows || 24;
|
|
1038
1064
|
const viewportRows = Math.max(
|
|
@@ -1051,39 +1077,40 @@ function ScrollableText({
|
|
|
1051
1077
|
const clamped = Math.min(Math.max(0, scrollTop), maxScroll);
|
|
1052
1078
|
const visible = allLines.slice(clamped, clamped + viewportRows);
|
|
1053
1079
|
const bar = needsBar ? scrollbarGlyphs(viewportRows, allLines.length, clamped) : null;
|
|
1054
|
-
useEffect2(() => {
|
|
1055
|
-
setScrollTop((s) => Math.min(s, maxScroll));
|
|
1056
|
-
}, [maxScroll]);
|
|
1057
1080
|
const maxScrollRef = useRef2(maxScroll);
|
|
1058
1081
|
const pageSizeRef = useRef2(viewportRows);
|
|
1082
|
+
const scrollTopRef = useRef2(scrollTop);
|
|
1083
|
+
const followingRef = useRef2(following);
|
|
1059
1084
|
maxScrollRef.current = maxScroll;
|
|
1060
1085
|
pageSizeRef.current = viewportRows;
|
|
1086
|
+
scrollTopRef.current = scrollTop;
|
|
1087
|
+
followingRef.current = following;
|
|
1088
|
+
useEffect2(() => {
|
|
1089
|
+
const next = nextScrollAfterContentChange({
|
|
1090
|
+
following: followBottom && followingRef.current,
|
|
1091
|
+
scrollTop: scrollTopRef.current,
|
|
1092
|
+
maxScroll
|
|
1093
|
+
});
|
|
1094
|
+
if (next.scrollTop !== scrollTopRef.current) setScrollTop(next.scrollTop);
|
|
1095
|
+
if (followBottom && next.following !== followingRef.current) setFollowing(next.following);
|
|
1096
|
+
}, [maxScroll, followBottom]);
|
|
1097
|
+
const applyUserScroll = (delta) => {
|
|
1098
|
+
const next = nextScrollAfterUserMove(scrollTopRef.current, maxScrollRef.current, delta);
|
|
1099
|
+
setScrollTop(next.scrollTop);
|
|
1100
|
+
if (followBottom) setFollowing(next.following);
|
|
1101
|
+
bump((n) => n + 1);
|
|
1102
|
+
ctx?.update?.();
|
|
1103
|
+
};
|
|
1061
1104
|
useEffect2(() => {
|
|
1062
1105
|
if (!ctx || !bindKeys) return void 0;
|
|
1063
1106
|
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
|
-
});
|
|
1107
|
+
ctx.setAction("scrollUp", () => applyUserScroll(-1));
|
|
1108
|
+
ctx.setAction("scrollDown", () => applyUserScroll(1));
|
|
1109
|
+
ctx.setAction("pageUp", () => applyUserScroll(-pageSizeRef.current));
|
|
1110
|
+
ctx.setAction("pageDown", () => applyUserScroll(pageSizeRef.current));
|
|
1084
1111
|
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" : "");
|
|
1112
|
+
}, [ctx, bindKeys, followBottom]);
|
|
1113
|
+
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
1114
|
const rowNodes = visible.map((line, i) => {
|
|
1088
1115
|
const body = padEndVisible(line, textWidth);
|
|
1089
1116
|
const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
|
|
@@ -1121,6 +1148,7 @@ var init_scrollable_text = __esm({
|
|
|
1121
1148
|
"src/screen/scrollable-text.js"() {
|
|
1122
1149
|
init_components();
|
|
1123
1150
|
init_scrollbar();
|
|
1151
|
+
init_follow_scroll();
|
|
1124
1152
|
init_scrollbar();
|
|
1125
1153
|
h5 = createElement2;
|
|
1126
1154
|
SCROLL_KEYS = [
|
|
@@ -1279,6 +1307,7 @@ var init_screen = __esm({
|
|
|
1279
1307
|
init_components();
|
|
1280
1308
|
init_ui_elements();
|
|
1281
1309
|
init_scrollable_text();
|
|
1310
|
+
init_follow_scroll();
|
|
1282
1311
|
init_scrollbar();
|
|
1283
1312
|
init_key_bindings();
|
|
1284
1313
|
init_utils();
|
|
@@ -3760,7 +3789,7 @@ var CONNECTION_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
3760
3789
|
"57P02",
|
|
3761
3790
|
"57P03"
|
|
3762
3791
|
]);
|
|
3763
|
-
var CONNECTION_ERROR_MESSAGE_RE = /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection terminated unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;
|
|
3792
|
+
var CONNECTION_ERROR_MESSAGE_RE = /connection (terminated|ended|closed|destroyed|reset|refused|not open)|Connection (terminated|ended) unexpectedly|Client has encountered a connection error|server closed the connection|Cannot use a pool after calling end|This socket has been ended|connect ECONNRESET/i;
|
|
3764
3793
|
var Db = class _Db {
|
|
3765
3794
|
static async init(context, options = {}) {
|
|
3766
3795
|
const buildConfig = async () => {
|
|
@@ -4028,6 +4057,10 @@ var Db = class _Db {
|
|
|
4028
4057
|
this.isConnected = false;
|
|
4029
4058
|
this.queriesLog = [];
|
|
4030
4059
|
this._reconnectPromise = null;
|
|
4060
|
+
this._closed = false;
|
|
4061
|
+
this._liveKnex = /* @__PURE__ */ new Set();
|
|
4062
|
+
this._reconnectCooldownUntil = 0;
|
|
4063
|
+
this._reconnectAcquireTimeoutMs = null;
|
|
4031
4064
|
this.config = {
|
|
4032
4065
|
testConnection: true,
|
|
4033
4066
|
profile: false,
|
|
@@ -4112,6 +4145,9 @@ var Db = class _Db {
|
|
|
4112
4145
|
return null;
|
|
4113
4146
|
}
|
|
4114
4147
|
async connect() {
|
|
4148
|
+
if (this._closed) {
|
|
4149
|
+
throw new ParamError("Db: Connection closed");
|
|
4150
|
+
}
|
|
4115
4151
|
if (this.isConnected && this.knexInstance) {
|
|
4116
4152
|
this.logger.warn?.("[Db] Already connected");
|
|
4117
4153
|
return;
|
|
@@ -4127,22 +4163,46 @@ var Db = class _Db {
|
|
|
4127
4163
|
connectionString: this.config.connectionString,
|
|
4128
4164
|
family: 4
|
|
4129
4165
|
};
|
|
4166
|
+
const acquireTimeout = this._reconnectAcquireTimeoutMs ?? this.config.acquireConnectionTimeout;
|
|
4130
4167
|
this.knexInstance = knex({
|
|
4131
4168
|
client,
|
|
4132
4169
|
connection: connectionConfig,
|
|
4133
4170
|
pool: this.config.pool,
|
|
4134
|
-
acquireConnectionTimeout:
|
|
4171
|
+
acquireConnectionTimeout: acquireTimeout,
|
|
4135
4172
|
...this.config.ssl && { ssl: this.config.ssl }
|
|
4136
4173
|
});
|
|
4174
|
+
this._liveKnex.add(this.knexInstance);
|
|
4175
|
+
this.knexInstance.on?.("error", (err) => {
|
|
4176
|
+
if (this._closed) return;
|
|
4177
|
+
this.logger.warn?.(
|
|
4178
|
+
`[Db] Connection error (${this.getErrorMessage(err)})`
|
|
4179
|
+
);
|
|
4180
|
+
});
|
|
4181
|
+
if (this._closed) {
|
|
4182
|
+
await this._destroyKnex(this.knexInstance, "connect aborted (closed)");
|
|
4183
|
+
this.knexInstance = null;
|
|
4184
|
+
throw new ParamError("Db: Connection closed");
|
|
4185
|
+
}
|
|
4137
4186
|
if (this.config.profile) {
|
|
4138
4187
|
this.attachProfiler();
|
|
4139
4188
|
}
|
|
4140
4189
|
if (this.config.testConnection) {
|
|
4141
4190
|
await this.testConnection();
|
|
4142
4191
|
}
|
|
4192
|
+
if (this._closed) {
|
|
4193
|
+
await this._destroyKnex(this.knexInstance, "connect aborted (closed)");
|
|
4194
|
+
this.knexInstance = null;
|
|
4195
|
+
throw new ParamError("Db: Connection closed");
|
|
4196
|
+
}
|
|
4143
4197
|
this.isConnected = true;
|
|
4144
4198
|
this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));
|
|
4145
4199
|
} catch (error) {
|
|
4200
|
+
const failed = this.knexInstance;
|
|
4201
|
+
this.knexInstance = null;
|
|
4202
|
+
this.isConnected = false;
|
|
4203
|
+
if (failed) {
|
|
4204
|
+
await this._destroyKnex(failed, "connect failed");
|
|
4205
|
+
}
|
|
4146
4206
|
if (error instanceof ParamError) {
|
|
4147
4207
|
throw error;
|
|
4148
4208
|
}
|
|
@@ -4150,20 +4210,42 @@ var Db = class _Db {
|
|
|
4150
4210
|
throw new ParamError(`Db: Connection failed - ${errorMsg}`);
|
|
4151
4211
|
}
|
|
4152
4212
|
}
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4213
|
+
/**
|
|
4214
|
+
* Destroy a knex pool without hanging exit on stuck TCP sockets (ETIMEDOUT).
|
|
4215
|
+
* @param {import("knex").Knex | null | undefined} knexInst
|
|
4216
|
+
* @param {string} [reason]
|
|
4217
|
+
* @param {number} [timeoutMs]
|
|
4218
|
+
*/
|
|
4219
|
+
async _destroyKnex(knexInst, reason = "destroy", timeoutMs = 3e3) {
|
|
4220
|
+
if (!knexInst || typeof knexInst.destroy !== "function") return;
|
|
4221
|
+
this._liveKnex.delete(knexInst);
|
|
4157
4222
|
try {
|
|
4158
|
-
await
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4223
|
+
await Promise.race([
|
|
4224
|
+
knexInst.destroy(),
|
|
4225
|
+
new Promise((_, reject) => {
|
|
4226
|
+
const t = setTimeout(
|
|
4227
|
+
() => reject(new Error(`Db: ${reason} timed out after ${timeoutMs}ms`)),
|
|
4228
|
+
timeoutMs
|
|
4229
|
+
);
|
|
4230
|
+
t.unref?.();
|
|
4231
|
+
})
|
|
4232
|
+
]);
|
|
4163
4233
|
} catch (error) {
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4234
|
+
this.logger.debug?.(
|
|
4235
|
+
`[Db] ${reason}: ${this.getErrorMessage(error)}`
|
|
4236
|
+
);
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
async disconnect() {
|
|
4240
|
+
this._closed = true;
|
|
4241
|
+
this.isConnected = false;
|
|
4242
|
+
this.knexInstance = null;
|
|
4243
|
+
this.queriesLog = [];
|
|
4244
|
+
const all = [...this._liveKnex];
|
|
4245
|
+
this._liveKnex.clear();
|
|
4246
|
+
await Promise.all(all.map((inst) => this._destroyKnex(inst, "disconnect")));
|
|
4247
|
+
if (all.length > 0) {
|
|
4248
|
+
this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));
|
|
4167
4249
|
}
|
|
4168
4250
|
}
|
|
4169
4251
|
/**
|
|
@@ -4186,27 +4268,39 @@ var Db = class _Db {
|
|
|
4186
4268
|
}
|
|
4187
4269
|
/**
|
|
4188
4270
|
* Destroy the current knex pool and open a new one. Concurrent callers share one attempt.
|
|
4271
|
+
* No-ops once disconnect() has closed the handle.
|
|
4189
4272
|
*/
|
|
4190
4273
|
async reconnect() {
|
|
4274
|
+
if (this._closed) {
|
|
4275
|
+
return;
|
|
4276
|
+
}
|
|
4277
|
+
if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {
|
|
4278
|
+
return;
|
|
4279
|
+
}
|
|
4191
4280
|
if (this._reconnectPromise) {
|
|
4192
4281
|
await this._reconnectPromise;
|
|
4193
4282
|
return;
|
|
4194
4283
|
}
|
|
4195
4284
|
this._reconnectPromise = (async () => {
|
|
4285
|
+
if (this._closed) return;
|
|
4196
4286
|
const old = this.knexInstance;
|
|
4197
4287
|
this.isConnected = false;
|
|
4198
4288
|
this.knexInstance = null;
|
|
4199
4289
|
this.queriesLog = [];
|
|
4200
4290
|
if (old) {
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4291
|
+
await this._destroyKnex(old, "destroy during reconnect");
|
|
4292
|
+
}
|
|
4293
|
+
if (this._closed) return;
|
|
4294
|
+
this._reconnectAcquireTimeoutMs = 3e3;
|
|
4295
|
+
try {
|
|
4296
|
+
await this.connect();
|
|
4297
|
+
this._reconnectCooldownUntil = 0;
|
|
4298
|
+
} catch (error) {
|
|
4299
|
+
this._reconnectCooldownUntil = Date.now() + 5e3;
|
|
4300
|
+
throw error;
|
|
4301
|
+
} finally {
|
|
4302
|
+
this._reconnectAcquireTimeoutMs = null;
|
|
4208
4303
|
}
|
|
4209
|
-
await this.connect();
|
|
4210
4304
|
})();
|
|
4211
4305
|
try {
|
|
4212
4306
|
await this._reconnectPromise;
|
|
@@ -4215,10 +4309,19 @@ var Db = class _Db {
|
|
|
4215
4309
|
}
|
|
4216
4310
|
}
|
|
4217
4311
|
async reconnectAfterConnectionError(error) {
|
|
4312
|
+
if (this._closed) {
|
|
4313
|
+
return;
|
|
4314
|
+
}
|
|
4315
|
+
if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4218
4318
|
this.logger.warn?.(
|
|
4219
4319
|
`[Db] Connection lost (${this.getErrorMessage(error)}) \u2014 reconnecting\u2026`
|
|
4220
4320
|
);
|
|
4221
|
-
|
|
4321
|
+
try {
|
|
4322
|
+
await this.reconnect();
|
|
4323
|
+
} catch {
|
|
4324
|
+
}
|
|
4222
4325
|
}
|
|
4223
4326
|
/**
|
|
4224
4327
|
* Run `fn`; on a connection error, reconnect once (by default) and retry `fn`.
|
|
@@ -4231,10 +4334,13 @@ var Db = class _Db {
|
|
|
4231
4334
|
return await fn();
|
|
4232
4335
|
} catch (error) {
|
|
4233
4336
|
lastError = error;
|
|
4234
|
-
if (!this.isConnectionError(error) || attempt >= retries) {
|
|
4337
|
+
if (this._closed || !this.isConnectionError(error) || attempt >= retries) {
|
|
4235
4338
|
throw error;
|
|
4236
4339
|
}
|
|
4237
4340
|
await this.reconnectAfterConnectionError(error);
|
|
4341
|
+
if (this._closed) {
|
|
4342
|
+
throw error;
|
|
4343
|
+
}
|
|
4238
4344
|
}
|
|
4239
4345
|
}
|
|
4240
4346
|
throw lastError;
|
|
@@ -4258,10 +4364,13 @@ var Db = class _Db {
|
|
|
4258
4364
|
try {
|
|
4259
4365
|
return await protoThen.call(builder);
|
|
4260
4366
|
} catch (error) {
|
|
4261
|
-
if (!inst.isConnectionError(error)) {
|
|
4367
|
+
if (inst._closed || !inst.isConnectionError(error)) {
|
|
4262
4368
|
throw error;
|
|
4263
4369
|
}
|
|
4264
4370
|
await inst.reconnectAfterConnectionError(error);
|
|
4371
|
+
if (inst._closed || !inst.knexInstance) {
|
|
4372
|
+
throw error;
|
|
4373
|
+
}
|
|
4265
4374
|
if (typeof builder.clone === "function") {
|
|
4266
4375
|
const retry = builder.clone();
|
|
4267
4376
|
retry.client = inst.knexInstance.client;
|
|
@@ -5309,13 +5418,14 @@ var Logger = class _Logger {
|
|
|
5309
5418
|
*/
|
|
5310
5419
|
progress(message, opts) {
|
|
5311
5420
|
const { prefix, count, total } = opts;
|
|
5312
|
-
const
|
|
5421
|
+
const displayTotal = Math.max(Number(total) || 0, Number(count) || 0);
|
|
5422
|
+
const paddedTotal = String(displayTotal).length;
|
|
5313
5423
|
const paddedCount = String(count).padStart(paddedTotal, " ");
|
|
5314
5424
|
const payload = {
|
|
5315
5425
|
level: "progress",
|
|
5316
5426
|
message,
|
|
5317
5427
|
count: paddedCount,
|
|
5318
|
-
total,
|
|
5428
|
+
total: displayTotal,
|
|
5319
5429
|
prefix
|
|
5320
5430
|
};
|
|
5321
5431
|
const key = prefix ?? "";
|
|
@@ -5332,7 +5442,7 @@ var Logger = class _Logger {
|
|
|
5332
5442
|
if (wantTimes) {
|
|
5333
5443
|
let remaining = -1;
|
|
5334
5444
|
if (itemsPerSec > 0) {
|
|
5335
|
-
remaining = (
|
|
5445
|
+
remaining = Math.max(0, (displayTotal - count) / itemsPerSec);
|
|
5336
5446
|
}
|
|
5337
5447
|
payload.elapsed = this.round(elapsedSeconds, 2);
|
|
5338
5448
|
payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
|
|
@@ -5341,12 +5451,12 @@ var Logger = class _Logger {
|
|
|
5341
5451
|
payload.rate = itemsPerSec >= 0 ? this.round(itemsPerSec, 2) : itemsPerSec;
|
|
5342
5452
|
}
|
|
5343
5453
|
}
|
|
5344
|
-
if (count
|
|
5454
|
+
if (count === total) {
|
|
5345
5455
|
delete this.startTimes[key];
|
|
5346
5456
|
delete this.startCounts[key];
|
|
5347
5457
|
delete this.lastProgressTimes[key];
|
|
5348
5458
|
}
|
|
5349
|
-
if (this.shouldOutputProgress(prefix ?? "", count,
|
|
5459
|
+
if (this.shouldOutputProgress(prefix ?? "", count, displayTotal)) {
|
|
5350
5460
|
this.out(payload);
|
|
5351
5461
|
if (this.options.progressThrottle && prefix) {
|
|
5352
5462
|
this.lastProgressTimes[prefix] = Date.now();
|
|
@@ -5505,6 +5615,8 @@ function setup(opts = {}) {
|
|
|
5505
5615
|
// a quick "show me the figured params and quit" that skips the flow's
|
|
5506
5616
|
// actual work. Like --stopAfter=init, this is a hard exit(0) (registered
|
|
5507
5617
|
// cleanups are skipped); call it once components/params are resolved.
|
|
5618
|
+
_requestExitCode: null,
|
|
5619
|
+
requestExit: null,
|
|
5508
5620
|
showUsedParamsIfNeeded: () => {
|
|
5509
5621
|
const mode = params.getShowUsedParamsMode?.();
|
|
5510
5622
|
if (mode !== "top" && mode !== "stop") return;
|
|
@@ -5515,6 +5627,9 @@ function setup(opts = {}) {
|
|
|
5515
5627
|
}
|
|
5516
5628
|
}
|
|
5517
5629
|
};
|
|
5630
|
+
context.requestExit = (code = 0) => {
|
|
5631
|
+
context._requestExitCode = code;
|
|
5632
|
+
};
|
|
5518
5633
|
logger.debug("[setup] completed successfully");
|
|
5519
5634
|
return context;
|
|
5520
5635
|
}
|
|
@@ -10078,6 +10193,7 @@ export {
|
|
|
10078
10193
|
buildDetailBreadcrumb,
|
|
10079
10194
|
buildFooter,
|
|
10080
10195
|
bumpPatchVersion,
|
|
10196
|
+
clampScroll,
|
|
10081
10197
|
cloneRepo,
|
|
10082
10198
|
coerceRuntimeValue,
|
|
10083
10199
|
controlLaneTaskNames,
|
|
@@ -10115,6 +10231,7 @@ export {
|
|
|
10115
10231
|
ipcFileLogsTableNameForSourceResource,
|
|
10116
10232
|
isFreshOnline,
|
|
10117
10233
|
isPidAlive,
|
|
10234
|
+
isScrolledToBottom,
|
|
10118
10235
|
joiEdateType,
|
|
10119
10236
|
joiStringArrayType,
|
|
10120
10237
|
listServicesRegistry as listAliveRunnerHeartbeats,
|
|
@@ -10128,6 +10245,8 @@ export {
|
|
|
10128
10245
|
memo,
|
|
10129
10246
|
mergeAllowedTasksWithServiceTasks,
|
|
10130
10247
|
mergeRuntimeParamSpecs,
|
|
10248
|
+
nextScrollAfterContentChange,
|
|
10249
|
+
nextScrollAfterUserMove,
|
|
10131
10250
|
nextTimeMatch,
|
|
10132
10251
|
normalizeAllowedTasks,
|
|
10133
10252
|
npmEnv,
|