@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.cjs
CHANGED
|
@@ -1018,6 +1018,30 @@ var init_ui_elements = __esm({
|
|
|
1018
1018
|
}
|
|
1019
1019
|
});
|
|
1020
1020
|
|
|
1021
|
+
// src/screen/follow-scroll.js
|
|
1022
|
+
function clampScroll(scrollTop, maxScroll) {
|
|
1023
|
+
const max = Math.max(0, Number(maxScroll) || 0);
|
|
1024
|
+
const top = Number(scrollTop) || 0;
|
|
1025
|
+
return Math.min(Math.max(0, top), max);
|
|
1026
|
+
}
|
|
1027
|
+
function isScrolledToBottom(scrollTop, maxScroll) {
|
|
1028
|
+
return clampScroll(scrollTop, maxScroll) >= Math.max(0, Number(maxScroll) || 0);
|
|
1029
|
+
}
|
|
1030
|
+
function nextScrollAfterUserMove(scrollTop, maxScroll, delta) {
|
|
1031
|
+
const next = clampScroll((Number(scrollTop) || 0) + (Number(delta) || 0), maxScroll);
|
|
1032
|
+
return { scrollTop: next, following: isScrolledToBottom(next, maxScroll) };
|
|
1033
|
+
}
|
|
1034
|
+
function nextScrollAfterContentChange({ following, scrollTop, maxScroll }) {
|
|
1035
|
+
const max = Math.max(0, Number(maxScroll) || 0);
|
|
1036
|
+
if (following) return { scrollTop: max, following: true };
|
|
1037
|
+
const next = clampScroll(scrollTop, max);
|
|
1038
|
+
return { scrollTop: next, following: isScrolledToBottom(next, max) };
|
|
1039
|
+
}
|
|
1040
|
+
var init_follow_scroll = __esm({
|
|
1041
|
+
"src/screen/follow-scroll.js"() {
|
|
1042
|
+
}
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1021
1045
|
// src/screen/scrollable-text.js
|
|
1022
1046
|
function wrapTextLines(text, cols) {
|
|
1023
1047
|
const w = Math.max(1, Math.floor(Number(cols) || 1));
|
|
@@ -1050,9 +1074,11 @@ function ScrollableText({
|
|
|
1050
1074
|
showScrollbar = true,
|
|
1051
1075
|
showStatus = true,
|
|
1052
1076
|
bindKeys = true,
|
|
1053
|
-
header = null
|
|
1077
|
+
header = null,
|
|
1078
|
+
followBottom = false
|
|
1054
1079
|
}) {
|
|
1055
1080
|
const [scrollTop, setScrollTop] = (0, import_react5.useState)(0);
|
|
1081
|
+
const [following, setFollowing] = (0, import_react5.useState)(() => !!followBottom);
|
|
1056
1082
|
const [, bump] = (0, import_react5.useState)(0);
|
|
1057
1083
|
const termRows = process.stdout.rows || 24;
|
|
1058
1084
|
const viewportRows = Math.max(
|
|
@@ -1071,39 +1097,40 @@ function ScrollableText({
|
|
|
1071
1097
|
const clamped = Math.min(Math.max(0, scrollTop), maxScroll);
|
|
1072
1098
|
const visible = allLines.slice(clamped, clamped + viewportRows);
|
|
1073
1099
|
const bar = needsBar ? scrollbarGlyphs(viewportRows, allLines.length, clamped) : null;
|
|
1074
|
-
(0, import_react5.useEffect)(() => {
|
|
1075
|
-
setScrollTop((s) => Math.min(s, maxScroll));
|
|
1076
|
-
}, [maxScroll]);
|
|
1077
1100
|
const maxScrollRef = (0, import_react5.useRef)(maxScroll);
|
|
1078
1101
|
const pageSizeRef = (0, import_react5.useRef)(viewportRows);
|
|
1102
|
+
const scrollTopRef = (0, import_react5.useRef)(scrollTop);
|
|
1103
|
+
const followingRef = (0, import_react5.useRef)(following);
|
|
1079
1104
|
maxScrollRef.current = maxScroll;
|
|
1080
1105
|
pageSizeRef.current = viewportRows;
|
|
1106
|
+
scrollTopRef.current = scrollTop;
|
|
1107
|
+
followingRef.current = following;
|
|
1108
|
+
(0, import_react5.useEffect)(() => {
|
|
1109
|
+
const next = nextScrollAfterContentChange({
|
|
1110
|
+
following: followBottom && followingRef.current,
|
|
1111
|
+
scrollTop: scrollTopRef.current,
|
|
1112
|
+
maxScroll
|
|
1113
|
+
});
|
|
1114
|
+
if (next.scrollTop !== scrollTopRef.current) setScrollTop(next.scrollTop);
|
|
1115
|
+
if (followBottom && next.following !== followingRef.current) setFollowing(next.following);
|
|
1116
|
+
}, [maxScroll, followBottom]);
|
|
1117
|
+
const applyUserScroll = (delta) => {
|
|
1118
|
+
const next = nextScrollAfterUserMove(scrollTopRef.current, maxScrollRef.current, delta);
|
|
1119
|
+
setScrollTop(next.scrollTop);
|
|
1120
|
+
if (followBottom) setFollowing(next.following);
|
|
1121
|
+
bump((n) => n + 1);
|
|
1122
|
+
ctx?.update?.();
|
|
1123
|
+
};
|
|
1081
1124
|
(0, import_react5.useEffect)(() => {
|
|
1082
1125
|
if (!ctx || !bindKeys) return void 0;
|
|
1083
1126
|
ctx.setKeyBinding(SCROLL_KEYS);
|
|
1084
|
-
ctx.setAction("scrollUp", () =>
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
});
|
|
1089
|
-
ctx.setAction("scrollDown", () => {
|
|
1090
|
-
setScrollTop((s) => Math.min(maxScrollRef.current, s + 1));
|
|
1091
|
-
bump((n) => n + 1);
|
|
1092
|
-
ctx.update?.();
|
|
1093
|
-
});
|
|
1094
|
-
ctx.setAction("pageUp", () => {
|
|
1095
|
-
setScrollTop((s) => Math.max(0, s - pageSizeRef.current));
|
|
1096
|
-
bump((n) => n + 1);
|
|
1097
|
-
ctx.update?.();
|
|
1098
|
-
});
|
|
1099
|
-
ctx.setAction("pageDown", () => {
|
|
1100
|
-
setScrollTop((s) => Math.min(maxScrollRef.current, s + pageSizeRef.current));
|
|
1101
|
-
bump((n) => n + 1);
|
|
1102
|
-
ctx.update?.();
|
|
1103
|
-
});
|
|
1127
|
+
ctx.setAction("scrollUp", () => applyUserScroll(-1));
|
|
1128
|
+
ctx.setAction("scrollDown", () => applyUserScroll(1));
|
|
1129
|
+
ctx.setAction("pageUp", () => applyUserScroll(-pageSizeRef.current));
|
|
1130
|
+
ctx.setAction("pageDown", () => applyUserScroll(pageSizeRef.current));
|
|
1104
1131
|
return void 0;
|
|
1105
|
-
}, [ctx, bindKeys]);
|
|
1106
|
-
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" : "");
|
|
1132
|
+
}, [ctx, bindKeys, followBottom]);
|
|
1133
|
+
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" : "");
|
|
1107
1134
|
const rowNodes = visible.map((line, i) => {
|
|
1108
1135
|
const body = padEndVisible(line, textWidth);
|
|
1109
1136
|
const glyph = bar ? bar[i] ?? BAR_TRACK : showScrollbar ? " " : "";
|
|
@@ -1143,6 +1170,7 @@ var init_scrollable_text = __esm({
|
|
|
1143
1170
|
import_ink5 = require("ink");
|
|
1144
1171
|
init_components();
|
|
1145
1172
|
init_scrollbar();
|
|
1173
|
+
init_follow_scroll();
|
|
1146
1174
|
init_scrollbar();
|
|
1147
1175
|
h5 = import_react5.createElement;
|
|
1148
1176
|
SCROLL_KEYS = [
|
|
@@ -1298,6 +1326,7 @@ var init_screen = __esm({
|
|
|
1298
1326
|
init_components();
|
|
1299
1327
|
init_ui_elements();
|
|
1300
1328
|
init_scrollable_text();
|
|
1329
|
+
init_follow_scroll();
|
|
1301
1330
|
init_scrollbar();
|
|
1302
1331
|
init_key_bindings();
|
|
1303
1332
|
init_utils();
|
|
@@ -1377,6 +1406,7 @@ __export(src_exports, {
|
|
|
1377
1406
|
buildDetailBreadcrumb: () => buildDetailBreadcrumb,
|
|
1378
1407
|
buildFooter: () => buildFooter,
|
|
1379
1408
|
bumpPatchVersion: () => bumpPatchVersion,
|
|
1409
|
+
clampScroll: () => clampScroll,
|
|
1380
1410
|
cloneRepo: () => cloneRepo,
|
|
1381
1411
|
coerceRuntimeValue: () => coerceRuntimeValue,
|
|
1382
1412
|
controlLaneTaskNames: () => controlLaneTaskNames,
|
|
@@ -1414,6 +1444,7 @@ __export(src_exports, {
|
|
|
1414
1444
|
ipcFileLogsTableNameForSourceResource: () => ipcFileLogsTableNameForSourceResource,
|
|
1415
1445
|
isFreshOnline: () => isFreshOnline,
|
|
1416
1446
|
isPidAlive: () => isPidAlive,
|
|
1447
|
+
isScrolledToBottom: () => isScrolledToBottom,
|
|
1417
1448
|
joiEdateType: () => joiEdateType,
|
|
1418
1449
|
joiStringArrayType: () => joiStringArrayType,
|
|
1419
1450
|
listAliveRunnerHeartbeats: () => listServicesRegistry,
|
|
@@ -1427,6 +1458,8 @@ __export(src_exports, {
|
|
|
1427
1458
|
memo: () => import_react6.memo,
|
|
1428
1459
|
mergeAllowedTasksWithServiceTasks: () => mergeAllowedTasksWithServiceTasks,
|
|
1429
1460
|
mergeRuntimeParamSpecs: () => mergeRuntimeParamSpecs,
|
|
1461
|
+
nextScrollAfterContentChange: () => nextScrollAfterContentChange,
|
|
1462
|
+
nextScrollAfterUserMove: () => nextScrollAfterUserMove,
|
|
1430
1463
|
nextTimeMatch: () => nextTimeMatch,
|
|
1431
1464
|
normalizeAllowedTasks: () => normalizeAllowedTasks,
|
|
1432
1465
|
npmEnv: () => npmEnv,
|
|
@@ -3972,7 +4005,7 @@ var CONNECTION_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
3972
4005
|
"57P02",
|
|
3973
4006
|
"57P03"
|
|
3974
4007
|
]);
|
|
3975
|
-
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;
|
|
4008
|
+
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;
|
|
3976
4009
|
var Db = class _Db {
|
|
3977
4010
|
static async init(context, options = {}) {
|
|
3978
4011
|
const buildConfig = async () => {
|
|
@@ -4240,6 +4273,10 @@ var Db = class _Db {
|
|
|
4240
4273
|
this.isConnected = false;
|
|
4241
4274
|
this.queriesLog = [];
|
|
4242
4275
|
this._reconnectPromise = null;
|
|
4276
|
+
this._closed = false;
|
|
4277
|
+
this._liveKnex = /* @__PURE__ */ new Set();
|
|
4278
|
+
this._reconnectCooldownUntil = 0;
|
|
4279
|
+
this._reconnectAcquireTimeoutMs = null;
|
|
4243
4280
|
this.config = {
|
|
4244
4281
|
testConnection: true,
|
|
4245
4282
|
profile: false,
|
|
@@ -4324,6 +4361,9 @@ var Db = class _Db {
|
|
|
4324
4361
|
return null;
|
|
4325
4362
|
}
|
|
4326
4363
|
async connect() {
|
|
4364
|
+
if (this._closed) {
|
|
4365
|
+
throw new ParamError("Db: Connection closed");
|
|
4366
|
+
}
|
|
4327
4367
|
if (this.isConnected && this.knexInstance) {
|
|
4328
4368
|
this.logger.warn?.("[Db] Already connected");
|
|
4329
4369
|
return;
|
|
@@ -4339,22 +4379,46 @@ var Db = class _Db {
|
|
|
4339
4379
|
connectionString: this.config.connectionString,
|
|
4340
4380
|
family: 4
|
|
4341
4381
|
};
|
|
4382
|
+
const acquireTimeout = this._reconnectAcquireTimeoutMs ?? this.config.acquireConnectionTimeout;
|
|
4342
4383
|
this.knexInstance = (0, import_knex.default)({
|
|
4343
4384
|
client,
|
|
4344
4385
|
connection: connectionConfig,
|
|
4345
4386
|
pool: this.config.pool,
|
|
4346
|
-
acquireConnectionTimeout:
|
|
4387
|
+
acquireConnectionTimeout: acquireTimeout,
|
|
4347
4388
|
...this.config.ssl && { ssl: this.config.ssl }
|
|
4348
4389
|
});
|
|
4390
|
+
this._liveKnex.add(this.knexInstance);
|
|
4391
|
+
this.knexInstance.on?.("error", (err) => {
|
|
4392
|
+
if (this._closed) return;
|
|
4393
|
+
this.logger.warn?.(
|
|
4394
|
+
`[Db] Connection error (${this.getErrorMessage(err)})`
|
|
4395
|
+
);
|
|
4396
|
+
});
|
|
4397
|
+
if (this._closed) {
|
|
4398
|
+
await this._destroyKnex(this.knexInstance, "connect aborted (closed)");
|
|
4399
|
+
this.knexInstance = null;
|
|
4400
|
+
throw new ParamError("Db: Connection closed");
|
|
4401
|
+
}
|
|
4349
4402
|
if (this.config.profile) {
|
|
4350
4403
|
this.attachProfiler();
|
|
4351
4404
|
}
|
|
4352
4405
|
if (this.config.testConnection) {
|
|
4353
4406
|
await this.testConnection();
|
|
4354
4407
|
}
|
|
4408
|
+
if (this._closed) {
|
|
4409
|
+
await this._destroyKnex(this.knexInstance, "connect aborted (closed)");
|
|
4410
|
+
this.knexInstance = null;
|
|
4411
|
+
throw new ParamError("Db: Connection closed");
|
|
4412
|
+
}
|
|
4355
4413
|
this.isConnected = true;
|
|
4356
4414
|
this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));
|
|
4357
4415
|
} catch (error) {
|
|
4416
|
+
const failed = this.knexInstance;
|
|
4417
|
+
this.knexInstance = null;
|
|
4418
|
+
this.isConnected = false;
|
|
4419
|
+
if (failed) {
|
|
4420
|
+
await this._destroyKnex(failed, "connect failed");
|
|
4421
|
+
}
|
|
4358
4422
|
if (error instanceof ParamError) {
|
|
4359
4423
|
throw error;
|
|
4360
4424
|
}
|
|
@@ -4362,20 +4426,42 @@ var Db = class _Db {
|
|
|
4362
4426
|
throw new ParamError(`Db: Connection failed - ${errorMsg}`);
|
|
4363
4427
|
}
|
|
4364
4428
|
}
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4429
|
+
/**
|
|
4430
|
+
* Destroy a knex pool without hanging exit on stuck TCP sockets (ETIMEDOUT).
|
|
4431
|
+
* @param {import("knex").Knex | null | undefined} knexInst
|
|
4432
|
+
* @param {string} [reason]
|
|
4433
|
+
* @param {number} [timeoutMs]
|
|
4434
|
+
*/
|
|
4435
|
+
async _destroyKnex(knexInst, reason = "destroy", timeoutMs = 3e3) {
|
|
4436
|
+
if (!knexInst || typeof knexInst.destroy !== "function") return;
|
|
4437
|
+
this._liveKnex.delete(knexInst);
|
|
4369
4438
|
try {
|
|
4370
|
-
await
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4439
|
+
await Promise.race([
|
|
4440
|
+
knexInst.destroy(),
|
|
4441
|
+
new Promise((_, reject) => {
|
|
4442
|
+
const t = setTimeout(
|
|
4443
|
+
() => reject(new Error(`Db: ${reason} timed out after ${timeoutMs}ms`)),
|
|
4444
|
+
timeoutMs
|
|
4445
|
+
);
|
|
4446
|
+
t.unref?.();
|
|
4447
|
+
})
|
|
4448
|
+
]);
|
|
4375
4449
|
} catch (error) {
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4450
|
+
this.logger.debug?.(
|
|
4451
|
+
`[Db] ${reason}: ${this.getErrorMessage(error)}`
|
|
4452
|
+
);
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
async disconnect() {
|
|
4456
|
+
this._closed = true;
|
|
4457
|
+
this.isConnected = false;
|
|
4458
|
+
this.knexInstance = null;
|
|
4459
|
+
this.queriesLog = [];
|
|
4460
|
+
const all = [...this._liveKnex];
|
|
4461
|
+
this._liveKnex.clear();
|
|
4462
|
+
await Promise.all(all.map((inst) => this._destroyKnex(inst, "disconnect")));
|
|
4463
|
+
if (all.length > 0) {
|
|
4464
|
+
this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));
|
|
4379
4465
|
}
|
|
4380
4466
|
}
|
|
4381
4467
|
/**
|
|
@@ -4398,27 +4484,39 @@ var Db = class _Db {
|
|
|
4398
4484
|
}
|
|
4399
4485
|
/**
|
|
4400
4486
|
* Destroy the current knex pool and open a new one. Concurrent callers share one attempt.
|
|
4487
|
+
* No-ops once disconnect() has closed the handle.
|
|
4401
4488
|
*/
|
|
4402
4489
|
async reconnect() {
|
|
4490
|
+
if (this._closed) {
|
|
4491
|
+
return;
|
|
4492
|
+
}
|
|
4493
|
+
if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {
|
|
4494
|
+
return;
|
|
4495
|
+
}
|
|
4403
4496
|
if (this._reconnectPromise) {
|
|
4404
4497
|
await this._reconnectPromise;
|
|
4405
4498
|
return;
|
|
4406
4499
|
}
|
|
4407
4500
|
this._reconnectPromise = (async () => {
|
|
4501
|
+
if (this._closed) return;
|
|
4408
4502
|
const old = this.knexInstance;
|
|
4409
4503
|
this.isConnected = false;
|
|
4410
4504
|
this.knexInstance = null;
|
|
4411
4505
|
this.queriesLog = [];
|
|
4412
4506
|
if (old) {
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4507
|
+
await this._destroyKnex(old, "destroy during reconnect");
|
|
4508
|
+
}
|
|
4509
|
+
if (this._closed) return;
|
|
4510
|
+
this._reconnectAcquireTimeoutMs = 3e3;
|
|
4511
|
+
try {
|
|
4512
|
+
await this.connect();
|
|
4513
|
+
this._reconnectCooldownUntil = 0;
|
|
4514
|
+
} catch (error) {
|
|
4515
|
+
this._reconnectCooldownUntil = Date.now() + 5e3;
|
|
4516
|
+
throw error;
|
|
4517
|
+
} finally {
|
|
4518
|
+
this._reconnectAcquireTimeoutMs = null;
|
|
4420
4519
|
}
|
|
4421
|
-
await this.connect();
|
|
4422
4520
|
})();
|
|
4423
4521
|
try {
|
|
4424
4522
|
await this._reconnectPromise;
|
|
@@ -4427,10 +4525,19 @@ var Db = class _Db {
|
|
|
4427
4525
|
}
|
|
4428
4526
|
}
|
|
4429
4527
|
async reconnectAfterConnectionError(error) {
|
|
4528
|
+
if (this._closed) {
|
|
4529
|
+
return;
|
|
4530
|
+
}
|
|
4531
|
+
if (this._reconnectCooldownUntil && Date.now() < this._reconnectCooldownUntil) {
|
|
4532
|
+
return;
|
|
4533
|
+
}
|
|
4430
4534
|
this.logger.warn?.(
|
|
4431
4535
|
`[Db] Connection lost (${this.getErrorMessage(error)}) \u2014 reconnecting\u2026`
|
|
4432
4536
|
);
|
|
4433
|
-
|
|
4537
|
+
try {
|
|
4538
|
+
await this.reconnect();
|
|
4539
|
+
} catch {
|
|
4540
|
+
}
|
|
4434
4541
|
}
|
|
4435
4542
|
/**
|
|
4436
4543
|
* Run `fn`; on a connection error, reconnect once (by default) and retry `fn`.
|
|
@@ -4443,10 +4550,13 @@ var Db = class _Db {
|
|
|
4443
4550
|
return await fn();
|
|
4444
4551
|
} catch (error) {
|
|
4445
4552
|
lastError = error;
|
|
4446
|
-
if (!this.isConnectionError(error) || attempt >= retries) {
|
|
4553
|
+
if (this._closed || !this.isConnectionError(error) || attempt >= retries) {
|
|
4447
4554
|
throw error;
|
|
4448
4555
|
}
|
|
4449
4556
|
await this.reconnectAfterConnectionError(error);
|
|
4557
|
+
if (this._closed) {
|
|
4558
|
+
throw error;
|
|
4559
|
+
}
|
|
4450
4560
|
}
|
|
4451
4561
|
}
|
|
4452
4562
|
throw lastError;
|
|
@@ -4470,10 +4580,13 @@ var Db = class _Db {
|
|
|
4470
4580
|
try {
|
|
4471
4581
|
return await protoThen.call(builder);
|
|
4472
4582
|
} catch (error) {
|
|
4473
|
-
if (!inst.isConnectionError(error)) {
|
|
4583
|
+
if (inst._closed || !inst.isConnectionError(error)) {
|
|
4474
4584
|
throw error;
|
|
4475
4585
|
}
|
|
4476
4586
|
await inst.reconnectAfterConnectionError(error);
|
|
4587
|
+
if (inst._closed || !inst.knexInstance) {
|
|
4588
|
+
throw error;
|
|
4589
|
+
}
|
|
4477
4590
|
if (typeof builder.clone === "function") {
|
|
4478
4591
|
const retry = builder.clone();
|
|
4479
4592
|
retry.client = inst.knexInstance.client;
|
|
@@ -5495,13 +5608,14 @@ var Logger = class _Logger {
|
|
|
5495
5608
|
*/
|
|
5496
5609
|
progress(message, opts) {
|
|
5497
5610
|
const { prefix, count, total } = opts;
|
|
5498
|
-
const
|
|
5611
|
+
const displayTotal = Math.max(Number(total) || 0, Number(count) || 0);
|
|
5612
|
+
const paddedTotal = String(displayTotal).length;
|
|
5499
5613
|
const paddedCount = String(count).padStart(paddedTotal, " ");
|
|
5500
5614
|
const payload = {
|
|
5501
5615
|
level: "progress",
|
|
5502
5616
|
message,
|
|
5503
5617
|
count: paddedCount,
|
|
5504
|
-
total,
|
|
5618
|
+
total: displayTotal,
|
|
5505
5619
|
prefix
|
|
5506
5620
|
};
|
|
5507
5621
|
const key = prefix ?? "";
|
|
@@ -5518,7 +5632,7 @@ var Logger = class _Logger {
|
|
|
5518
5632
|
if (wantTimes) {
|
|
5519
5633
|
let remaining = -1;
|
|
5520
5634
|
if (itemsPerSec > 0) {
|
|
5521
|
-
remaining = (
|
|
5635
|
+
remaining = Math.max(0, (displayTotal - count) / itemsPerSec);
|
|
5522
5636
|
}
|
|
5523
5637
|
payload.elapsed = this.round(elapsedSeconds, 2);
|
|
5524
5638
|
payload.remaining = remaining >= 0 ? this.round(remaining, 2) : remaining;
|
|
@@ -5527,12 +5641,12 @@ var Logger = class _Logger {
|
|
|
5527
5641
|
payload.rate = itemsPerSec >= 0 ? this.round(itemsPerSec, 2) : itemsPerSec;
|
|
5528
5642
|
}
|
|
5529
5643
|
}
|
|
5530
|
-
if (count
|
|
5644
|
+
if (count === total) {
|
|
5531
5645
|
delete this.startTimes[key];
|
|
5532
5646
|
delete this.startCounts[key];
|
|
5533
5647
|
delete this.lastProgressTimes[key];
|
|
5534
5648
|
}
|
|
5535
|
-
if (this.shouldOutputProgress(prefix ?? "", count,
|
|
5649
|
+
if (this.shouldOutputProgress(prefix ?? "", count, displayTotal)) {
|
|
5536
5650
|
this.out(payload);
|
|
5537
5651
|
if (this.options.progressThrottle && prefix) {
|
|
5538
5652
|
this.lastProgressTimes[prefix] = Date.now();
|
|
@@ -5691,6 +5805,8 @@ function setup(opts = {}) {
|
|
|
5691
5805
|
// a quick "show me the figured params and quit" that skips the flow's
|
|
5692
5806
|
// actual work. Like --stopAfter=init, this is a hard exit(0) (registered
|
|
5693
5807
|
// cleanups are skipped); call it once components/params are resolved.
|
|
5808
|
+
_requestExitCode: null,
|
|
5809
|
+
requestExit: null,
|
|
5694
5810
|
showUsedParamsIfNeeded: () => {
|
|
5695
5811
|
const mode = params.getShowUsedParamsMode?.();
|
|
5696
5812
|
if (mode !== "top" && mode !== "stop") return;
|
|
@@ -5701,6 +5817,9 @@ function setup(opts = {}) {
|
|
|
5701
5817
|
}
|
|
5702
5818
|
}
|
|
5703
5819
|
};
|
|
5820
|
+
context.requestExit = (code = 0) => {
|
|
5821
|
+
context._requestExitCode = code;
|
|
5822
|
+
};
|
|
5704
5823
|
logger.debug("[setup] completed successfully");
|
|
5705
5824
|
return context;
|
|
5706
5825
|
}
|
|
@@ -10265,6 +10384,7 @@ var TasksManager = class _TasksManager {
|
|
|
10265
10384
|
buildDetailBreadcrumb,
|
|
10266
10385
|
buildFooter,
|
|
10267
10386
|
bumpPatchVersion,
|
|
10387
|
+
clampScroll,
|
|
10268
10388
|
cloneRepo,
|
|
10269
10389
|
coerceRuntimeValue,
|
|
10270
10390
|
controlLaneTaskNames,
|
|
@@ -10302,6 +10422,7 @@ var TasksManager = class _TasksManager {
|
|
|
10302
10422
|
ipcFileLogsTableNameForSourceResource,
|
|
10303
10423
|
isFreshOnline,
|
|
10304
10424
|
isPidAlive,
|
|
10425
|
+
isScrolledToBottom,
|
|
10305
10426
|
joiEdateType,
|
|
10306
10427
|
joiStringArrayType,
|
|
10307
10428
|
listAliveRunnerHeartbeats,
|
|
@@ -10315,6 +10436,8 @@ var TasksManager = class _TasksManager {
|
|
|
10315
10436
|
memo,
|
|
10316
10437
|
mergeAllowedTasksWithServiceTasks,
|
|
10317
10438
|
mergeRuntimeParamSpecs,
|
|
10439
|
+
nextScrollAfterContentChange,
|
|
10440
|
+
nextScrollAfterUserMove,
|
|
10318
10441
|
nextTimeMatch,
|
|
10319
10442
|
normalizeAllowedTasks,
|
|
10320
10443
|
npmEnv,
|