@indiekitai/pg-dash 0.4.5 → 0.5.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.js +283 -12
- package/dist/cli.js.map +1 -1
- package/dist/mcp.js +25 -11
- package/dist/mcp.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -300,30 +300,44 @@ SHOW shared_buffers;`,
|
|
|
300
300
|
}
|
|
301
301
|
try {
|
|
302
302
|
const r = await client.query(`
|
|
303
|
-
SELECT pid,
|
|
303
|
+
SELECT pid,
|
|
304
304
|
client_addr::text, application_name,
|
|
305
305
|
extract(epoch from now() - state_change)::int AS idle_seconds
|
|
306
306
|
FROM pg_stat_activity
|
|
307
|
-
WHERE state
|
|
307
|
+
WHERE state = 'idle in transaction'
|
|
308
308
|
AND now() - state_change > $1 * interval '1 minute'
|
|
309
309
|
AND pid != pg_backend_pid()
|
|
310
|
+
ORDER BY idle_seconds DESC
|
|
310
311
|
`, [longQueryThreshold]);
|
|
311
|
-
|
|
312
|
-
const
|
|
312
|
+
if (r.rows.length === 1) {
|
|
313
|
+
const row = r.rows[0];
|
|
313
314
|
issues.push({
|
|
314
|
-
id: `maint-idle-${row.pid}`,
|
|
315
|
-
severity:
|
|
315
|
+
id: `maint-idle-tx-${row.pid}`,
|
|
316
|
+
severity: "warning",
|
|
316
317
|
category: "maintenance",
|
|
317
|
-
title:
|
|
318
|
-
description: `PID ${row.pid} from ${row.client_addr || "local"} (${row.application_name || "unknown"}) has been
|
|
318
|
+
title: `Idle-in-transaction connection (PID ${row.pid})`,
|
|
319
|
+
description: `PID ${row.pid} from ${row.client_addr || "local"} (${row.application_name || "unknown"}) has been idle in transaction for ${Math.round(row.idle_seconds / 60)} minutes. This holds locks and blocks VACUUM.`,
|
|
319
320
|
fix: `SELECT pg_terminate_backend(${row.pid});`,
|
|
320
|
-
impact:
|
|
321
|
+
impact: "Idle-in-transaction connections hold locks and prevent VACUUM.",
|
|
322
|
+
effort: "quick"
|
|
323
|
+
});
|
|
324
|
+
} else if (r.rows.length > 1) {
|
|
325
|
+
const pids = r.rows.map((row) => row.pid);
|
|
326
|
+
const maxMin = Math.round(r.rows[0].idle_seconds / 60);
|
|
327
|
+
issues.push({
|
|
328
|
+
id: `maint-idle-tx-multi`,
|
|
329
|
+
severity: "warning",
|
|
330
|
+
category: "maintenance",
|
|
331
|
+
title: `${r.rows.length} idle-in-transaction connections (longest: ${maxMin}m)`,
|
|
332
|
+
description: `${r.rows.length} connections have been idle in transaction for over ${longQueryThreshold} minutes. These hold locks and prevent VACUUM from running.`,
|
|
333
|
+
fix: `SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle in transaction' AND now() - state_change > interval '${longQueryThreshold} minutes';`,
|
|
334
|
+
impact: "Idle-in-transaction connections hold locks and prevent VACUUM.",
|
|
321
335
|
effort: "quick"
|
|
322
336
|
});
|
|
323
337
|
}
|
|
324
338
|
} catch (err) {
|
|
325
|
-
console.error("[advisor] Error checking idle connections:", err.message);
|
|
326
|
-
skipped.push("idle
|
|
339
|
+
console.error("[advisor] Error checking idle-in-transaction connections:", err.message);
|
|
340
|
+
skipped.push("idle-in-transaction: " + err.message);
|
|
327
341
|
}
|
|
328
342
|
try {
|
|
329
343
|
const r = await client.query(`
|
|
@@ -2065,6 +2079,97 @@ var init_env_differ = __esm({
|
|
|
2065
2079
|
}
|
|
2066
2080
|
});
|
|
2067
2081
|
|
|
2082
|
+
// src/server/locks.ts
|
|
2083
|
+
var locks_exports = {};
|
|
2084
|
+
__export(locks_exports, {
|
|
2085
|
+
formatDurationSecs: () => formatDurationSecs,
|
|
2086
|
+
getLockReport: () => getLockReport
|
|
2087
|
+
});
|
|
2088
|
+
function formatDurationSecs(secs) {
|
|
2089
|
+
const h = Math.floor(secs / 3600);
|
|
2090
|
+
const m = Math.floor(secs % 3600 / 60);
|
|
2091
|
+
const s = secs % 60;
|
|
2092
|
+
return [
|
|
2093
|
+
String(h).padStart(2, "0"),
|
|
2094
|
+
String(m).padStart(2, "0"),
|
|
2095
|
+
String(s).padStart(2, "0")
|
|
2096
|
+
].join(":");
|
|
2097
|
+
}
|
|
2098
|
+
async function getLockReport(pool) {
|
|
2099
|
+
const [locksResult, longResult] = await Promise.all([
|
|
2100
|
+
pool.query(`
|
|
2101
|
+
SELECT
|
|
2102
|
+
blocked.pid AS blocked_pid,
|
|
2103
|
+
blocked.query AS blocked_query,
|
|
2104
|
+
EXTRACT(EPOCH FROM (NOW() - blocked.query_start))::int AS blocked_secs,
|
|
2105
|
+
blocking.pid AS blocking_pid,
|
|
2106
|
+
blocking.query AS blocking_query,
|
|
2107
|
+
EXTRACT(EPOCH FROM (NOW() - blocking.query_start))::int AS blocking_secs,
|
|
2108
|
+
blocked_locks.relation::regclass::text AS table_name,
|
|
2109
|
+
blocked_locks.locktype
|
|
2110
|
+
FROM pg_catalog.pg_locks blocked_locks
|
|
2111
|
+
JOIN pg_catalog.pg_stat_activity blocked ON blocked.pid = blocked_locks.pid
|
|
2112
|
+
JOIN pg_catalog.pg_locks blocking_locks
|
|
2113
|
+
ON blocking_locks.locktype = blocked_locks.locktype
|
|
2114
|
+
AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
|
|
2115
|
+
AND blocking_locks.pid != blocked_locks.pid
|
|
2116
|
+
AND blocking_locks.granted = true
|
|
2117
|
+
JOIN pg_catalog.pg_stat_activity blocking ON blocking.pid = blocking_locks.pid
|
|
2118
|
+
WHERE NOT blocked_locks.granted
|
|
2119
|
+
`),
|
|
2120
|
+
pool.query(`
|
|
2121
|
+
SELECT
|
|
2122
|
+
pid,
|
|
2123
|
+
EXTRACT(EPOCH FROM (NOW() - query_start))::int AS duration_secs,
|
|
2124
|
+
query,
|
|
2125
|
+
state,
|
|
2126
|
+
wait_event_type
|
|
2127
|
+
FROM pg_stat_activity
|
|
2128
|
+
WHERE state != 'idle'
|
|
2129
|
+
AND query_start IS NOT NULL
|
|
2130
|
+
AND EXTRACT(EPOCH FROM (NOW() - query_start)) > 5
|
|
2131
|
+
AND query NOT LIKE '%pg_stat_activity%'
|
|
2132
|
+
ORDER BY duration_secs DESC
|
|
2133
|
+
LIMIT 20
|
|
2134
|
+
`)
|
|
2135
|
+
]);
|
|
2136
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2137
|
+
const waitingLocks = [];
|
|
2138
|
+
for (const row of locksResult.rows) {
|
|
2139
|
+
const key = `${row.blocked_pid}:${row.blocking_pid}`;
|
|
2140
|
+
if (!seen.has(key)) {
|
|
2141
|
+
seen.add(key);
|
|
2142
|
+
waitingLocks.push({
|
|
2143
|
+
blockedPid: parseInt(row.blocked_pid, 10),
|
|
2144
|
+
blockedQuery: row.blocked_query,
|
|
2145
|
+
blockedDuration: formatDurationSecs(parseInt(row.blocked_secs, 10) || 0),
|
|
2146
|
+
blockingPid: parseInt(row.blocking_pid, 10),
|
|
2147
|
+
blockingQuery: row.blocking_query,
|
|
2148
|
+
blockingDuration: formatDurationSecs(parseInt(row.blocking_secs, 10) || 0),
|
|
2149
|
+
table: row.table_name ?? null,
|
|
2150
|
+
lockType: row.locktype
|
|
2151
|
+
});
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
const longRunningQueries = longResult.rows.map((row) => ({
|
|
2155
|
+
pid: parseInt(row.pid, 10),
|
|
2156
|
+
duration: formatDurationSecs(parseInt(row.duration_secs, 10) || 0),
|
|
2157
|
+
query: row.query,
|
|
2158
|
+
state: row.state,
|
|
2159
|
+
waitEventType: row.wait_event_type ?? null
|
|
2160
|
+
}));
|
|
2161
|
+
return {
|
|
2162
|
+
waitingLocks,
|
|
2163
|
+
longRunningQueries,
|
|
2164
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
var init_locks = __esm({
|
|
2168
|
+
"src/server/locks.ts"() {
|
|
2169
|
+
"use strict";
|
|
2170
|
+
}
|
|
2171
|
+
});
|
|
2172
|
+
|
|
2068
2173
|
// src/cli.ts
|
|
2069
2174
|
import { parseArgs } from "util";
|
|
2070
2175
|
|
|
@@ -4042,6 +4147,7 @@ var { values, positionals } = parseArgs({
|
|
|
4042
4147
|
"slack-webhook": { type: "string" },
|
|
4043
4148
|
"discord-webhook": { type: "string" },
|
|
4044
4149
|
"no-open": { type: "boolean", default: false },
|
|
4150
|
+
"no-analyze": { type: "boolean", default: false },
|
|
4045
4151
|
json: { type: "boolean", default: false },
|
|
4046
4152
|
host: { type: "string" },
|
|
4047
4153
|
user: { type: "string", short: "u" },
|
|
@@ -4085,6 +4191,8 @@ Usage:
|
|
|
4085
4191
|
pg-dash check <connection-string> Run health check and exit
|
|
4086
4192
|
pg-dash health <connection-string> Alias for check
|
|
4087
4193
|
pg-dash check-migration <file> [connection] Analyze migration SQL for risks
|
|
4194
|
+
pg-dash explain <query> <connection> EXPLAIN ANALYZE a query in the terminal
|
|
4195
|
+
pg-dash watch-locks <connection> Real-time lock + long-query monitor
|
|
4088
4196
|
pg-dash diff-env --source <url> --target <url> Compare two environments
|
|
4089
4197
|
pg-dash schema-diff <connection-string> Show latest schema changes
|
|
4090
4198
|
pg-dash --host localhost --user postgres --db mydb
|
|
@@ -4126,7 +4234,7 @@ Environment variables:
|
|
|
4126
4234
|
`);
|
|
4127
4235
|
process.exit(0);
|
|
4128
4236
|
}
|
|
4129
|
-
var KNOWN_SUBCOMMANDS = ["check", "health", "check-migration", "schema-diff", "diff-env"];
|
|
4237
|
+
var KNOWN_SUBCOMMANDS = ["check", "health", "check-migration", "schema-diff", "diff-env", "explain", "watch-locks"];
|
|
4130
4238
|
var subcommand = positionals[0];
|
|
4131
4239
|
function isValidConnectionString(s) {
|
|
4132
4240
|
return s.startsWith("postgresql://") || s.startsWith("postgres://") || s.includes("@") || // user@host shorthand
|
|
@@ -4483,6 +4591,166 @@ Migration check: ${filePath}`);
|
|
|
4483
4591
|
console.error(`Error: ${err.message}`);
|
|
4484
4592
|
process.exit(1);
|
|
4485
4593
|
}
|
|
4594
|
+
} else if (subcommand === "explain") {
|
|
4595
|
+
const query = positionals[1];
|
|
4596
|
+
if (!query) {
|
|
4597
|
+
console.error('Error: provide a SQL query.\n\nUsage: pg-dash explain "<query>" <connection>');
|
|
4598
|
+
process.exit(1);
|
|
4599
|
+
}
|
|
4600
|
+
const connStr = positionals[2] || resolveConnectionString(2);
|
|
4601
|
+
if (!connStr) {
|
|
4602
|
+
console.error("Error: provide a connection string.");
|
|
4603
|
+
process.exit(1);
|
|
4604
|
+
}
|
|
4605
|
+
const doAnalyze = !values["no-analyze"];
|
|
4606
|
+
const fmt = values.json ? "json" : "text";
|
|
4607
|
+
const { Pool: Pool3 } = await import("pg");
|
|
4608
|
+
const pool = new Pool3({ connectionString: connStr, max: 1, connectionTimeoutMillis: 1e4 });
|
|
4609
|
+
try {
|
|
4610
|
+
let nodeColor = function(type, rows, analyzed) {
|
|
4611
|
+
if (type.includes("Seq Scan")) return analyzed && rows >= 1e3 ? "\x1B[31m\x1B[1m" : "\x1B[31m";
|
|
4612
|
+
if (type.includes("Index")) return "\x1B[32m";
|
|
4613
|
+
if (type === "Hash Join" || type === "Hash") return "\x1B[33m";
|
|
4614
|
+
if (type === "Sort") return "\x1B[35m";
|
|
4615
|
+
return "\x1B[37m";
|
|
4616
|
+
}, renderNode = function(node, indent = 0, isLast = true) {
|
|
4617
|
+
const lines = [];
|
|
4618
|
+
const prefix = indent === 0 ? "" : " ".repeat(indent - 1) + (isLast ? "\u2514\u2500 " : "\u251C\u2500 ");
|
|
4619
|
+
const analyzed = node["Actual Total Time"] !== void 0;
|
|
4620
|
+
const rows = node["Actual Rows"] ?? node["Plan Rows"];
|
|
4621
|
+
const color = nodeColor(node["Node Type"], rows, analyzed);
|
|
4622
|
+
const rel = node["Relation Name"] ? ` on ${dim}${node["Alias"] || node["Relation Name"]}${reset}` : "";
|
|
4623
|
+
const cost = `${dim}cost=${node["Startup Cost"].toFixed(2)}..${node["Total Cost"].toFixed(2)}${reset}`;
|
|
4624
|
+
const timing = analyzed ? ` ${cyan}actual=${node["Actual Total Time"].toFixed(3)}ms${reset}` : "";
|
|
4625
|
+
const rowStr = analyzed ? ` ${dim}rows=${node["Actual Rows"]}/${node["Plan Rows"]}${reset}` : ` ${dim}rows=${node["Plan Rows"]}${reset}`;
|
|
4626
|
+
const idx = node["Index Name"] ? ` ${dim}idx=${node["Index Name"]}${reset}` : "";
|
|
4627
|
+
const filter = node["Filter"] ? ` ${dim}filter=${String(node["Filter"]).slice(0, 40)}${reset}` : "";
|
|
4628
|
+
lines.push(`${prefix}${color}${node["Node Type"]}${reset}${rel} ${cost}${timing}${rowStr}${idx}${filter}`);
|
|
4629
|
+
if (node.Plans?.length) {
|
|
4630
|
+
for (let i = 0; i < node.Plans.length; i++) {
|
|
4631
|
+
lines.push(renderNode(node.Plans[i], indent + 1, i === node.Plans.length - 1));
|
|
4632
|
+
}
|
|
4633
|
+
}
|
|
4634
|
+
return lines.join("\n");
|
|
4635
|
+
}, collectNodes2 = function(n) {
|
|
4636
|
+
return [n, ...n.Plans?.flatMap(collectNodes2) ?? []];
|
|
4637
|
+
};
|
|
4638
|
+
nodeColor2 = nodeColor, renderNode2 = renderNode, collectNodes3 = collectNodes2;
|
|
4639
|
+
const explainSql = doAnalyze ? `EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS, FORMAT JSON) ${query}` : `EXPLAIN (COSTS, VERBOSE, FORMAT JSON) ${query}`;
|
|
4640
|
+
const res = await pool.query(explainSql);
|
|
4641
|
+
await pool.end();
|
|
4642
|
+
const rawPlan = res.rows[0]["QUERY PLAN"];
|
|
4643
|
+
const planObj = Array.isArray(rawPlan) ? rawPlan[0] : rawPlan;
|
|
4644
|
+
const root = planObj.Plan;
|
|
4645
|
+
const planningTime = planObj["Planning Time"];
|
|
4646
|
+
const executionTime = planObj["Execution Time"];
|
|
4647
|
+
const reset = "\x1B[0m";
|
|
4648
|
+
const dim = "\x1B[2m";
|
|
4649
|
+
const cyan = "\x1B[36m";
|
|
4650
|
+
const allNodes = collectNodes2(root);
|
|
4651
|
+
const seqScans = allNodes.filter((n) => n["Node Type"] === "Seq Scan" && n["Relation Name"]).map((n) => n["Relation Name"]);
|
|
4652
|
+
const recs = [];
|
|
4653
|
+
for (const n of allNodes) {
|
|
4654
|
+
const rows = n["Actual Rows"] ?? n["Plan Rows"];
|
|
4655
|
+
if (n["Node Type"] === "Seq Scan" && n["Relation Name"] && rows >= 1e3) {
|
|
4656
|
+
recs.push(`\u26A0 Seq Scan on "${n["Relation Name"]}" (${rows} rows). Consider adding an index.`);
|
|
4657
|
+
}
|
|
4658
|
+
if (n["Node Type"] === "Sort") {
|
|
4659
|
+
recs.push(`\u2139 Sort on [${(n["Sort Key"] ?? []).join(", ")}]. An index might eliminate this.`);
|
|
4660
|
+
}
|
|
4661
|
+
if (n["Hash Batches"] && n["Hash Batches"] > 1) {
|
|
4662
|
+
recs.push(`\u26A0 Hash Join used ${n["Hash Batches"]} batches. Increase work_mem to avoid disk spilling.`);
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4665
|
+
if (fmt === "json") {
|
|
4666
|
+
console.log(JSON.stringify({ query, planningTime, executionTime, seqScans, recommendations: recs }, null, 2));
|
|
4667
|
+
} else {
|
|
4668
|
+
if (query) console.log(`
|
|
4669
|
+
\x1B[1mQuery:\x1B[0m ${dim}${query.slice(0, 120)}${reset}`);
|
|
4670
|
+
console.log("\n" + renderNode(root));
|
|
4671
|
+
console.log(`
|
|
4672
|
+
${dim}\u2500\u2500\u2500 Summary ${"\u2500".repeat(36)}${reset}`);
|
|
4673
|
+
if (executionTime !== void 0) console.log(` Execution time: ${cyan}${executionTime.toFixed(3)}ms${reset}`);
|
|
4674
|
+
if (planningTime !== void 0) console.log(` Planning time: ${dim}${planningTime.toFixed(3)}ms${reset}`);
|
|
4675
|
+
if (seqScans.length > 0) console.log(` Seq Scans: \x1B[31m${seqScans.join(", ")}${reset}`);
|
|
4676
|
+
if (recs.length > 0) {
|
|
4677
|
+
console.log(`
|
|
4678
|
+
${dim}\u2500\u2500\u2500 Recommendations ${"\u2500".repeat(28)}${reset}`);
|
|
4679
|
+
for (const r of recs) console.log(` ${r}`);
|
|
4680
|
+
}
|
|
4681
|
+
console.log();
|
|
4682
|
+
}
|
|
4683
|
+
} catch (err) {
|
|
4684
|
+
await pool.end().catch(() => {
|
|
4685
|
+
});
|
|
4686
|
+
console.error(`Error: ${err.message}`);
|
|
4687
|
+
process.exit(1);
|
|
4688
|
+
}
|
|
4689
|
+
process.exit(0);
|
|
4690
|
+
} else if (subcommand === "watch-locks") {
|
|
4691
|
+
const connStr = positionals[1] || resolveConnectionString(1);
|
|
4692
|
+
if (!connStr) {
|
|
4693
|
+
console.error("Error: provide a connection string.\n\nUsage: pg-dash watch-locks <connection>");
|
|
4694
|
+
process.exit(1);
|
|
4695
|
+
}
|
|
4696
|
+
const intervalSec = values.interval ? parseInt(values.interval, 10) : 3;
|
|
4697
|
+
const { Pool: Pool3 } = await import("pg");
|
|
4698
|
+
const pool = new Pool3({ connectionString: connStr, max: 2, connectionTimeoutMillis: 1e4 });
|
|
4699
|
+
const { getLockReport: getLockReport2 } = await Promise.resolve().then(() => (init_locks(), locks_exports));
|
|
4700
|
+
const reset = "\x1B[0m";
|
|
4701
|
+
const dim = "\x1B[2m";
|
|
4702
|
+
const red = "\x1B[31m";
|
|
4703
|
+
const yellow = "\x1B[33m";
|
|
4704
|
+
const cyan = "\x1B[36m";
|
|
4705
|
+
const bold = "\x1B[1m";
|
|
4706
|
+
process.stdout.write("\x1B[?25l");
|
|
4707
|
+
const cleanup = () => {
|
|
4708
|
+
process.stdout.write("\x1B[?25h");
|
|
4709
|
+
pool.end();
|
|
4710
|
+
process.exit(0);
|
|
4711
|
+
};
|
|
4712
|
+
process.on("SIGINT", cleanup);
|
|
4713
|
+
process.on("SIGTERM", cleanup);
|
|
4714
|
+
async function tick() {
|
|
4715
|
+
try {
|
|
4716
|
+
const report = await getLockReport2(pool);
|
|
4717
|
+
console.clear();
|
|
4718
|
+
const ts = (/* @__PURE__ */ new Date()).toLocaleTimeString();
|
|
4719
|
+
console.log(`${bold}pg-dash watch-locks${reset} ${dim}(Ctrl+C to exit \u2014 refresh every ${intervalSec}s \u2014 ${ts})${reset}
|
|
4720
|
+
`);
|
|
4721
|
+
if (report.waitingLocks.length === 0) {
|
|
4722
|
+
console.log(` ${dim}No lock waits detected.${reset}`);
|
|
4723
|
+
} else {
|
|
4724
|
+
console.log(`${bold}${red} Lock Waits (${report.waitingLocks.length})${reset}`);
|
|
4725
|
+
for (const lw of report.waitingLocks) {
|
|
4726
|
+
console.log(`
|
|
4727
|
+
${red}BLOCKED${reset} pid=${lw.blockedPid} waiting ${lw.blockedDuration}`);
|
|
4728
|
+
console.log(` Query: ${dim}${lw.blockedQuery.slice(0, 100)}${reset}`);
|
|
4729
|
+
console.log(` ${yellow}BLOCKING${reset} pid=${lw.blockingPid} running ${lw.blockingDuration}`);
|
|
4730
|
+
console.log(` Query: ${dim}${lw.blockingQuery.slice(0, 100)}${reset}`);
|
|
4731
|
+
if (lw.table) console.log(` Table: ${lw.table} Lock: ${lw.lockType}`);
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
if (report.longRunningQueries.length > 0) {
|
|
4735
|
+
console.log(`
|
|
4736
|
+
${bold}${yellow} Long-running Queries (${report.longRunningQueries.length})${reset}`);
|
|
4737
|
+
for (const q of report.longRunningQueries) {
|
|
4738
|
+
console.log(`
|
|
4739
|
+
pid=${q.pid} duration=${q.duration} state=${q.state}`);
|
|
4740
|
+
console.log(` ${dim}${q.query.slice(0, 120)}${reset}`);
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
if (report.waitingLocks.length === 0 && report.longRunningQueries.length === 0) {
|
|
4744
|
+
console.log(`
|
|
4745
|
+
${dim}No long-running queries.${reset}`);
|
|
4746
|
+
}
|
|
4747
|
+
} catch (err) {
|
|
4748
|
+
console.error(`Error: ${err.message}`);
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
await tick();
|
|
4752
|
+
const timer = setInterval(tick, intervalSec * 1e3);
|
|
4753
|
+
void timer;
|
|
4486
4754
|
} else {
|
|
4487
4755
|
if (subcommand && !isValidConnectionString(subcommand) && KNOWN_SUBCOMMANDS.indexOf(subcommand) === -1) {
|
|
4488
4756
|
console.error(
|
|
@@ -4524,4 +4792,7 @@ Run pg-dash --help for usage.`
|
|
|
4524
4792
|
webhook
|
|
4525
4793
|
});
|
|
4526
4794
|
}
|
|
4795
|
+
var nodeColor2;
|
|
4796
|
+
var renderNode2;
|
|
4797
|
+
var collectNodes3;
|
|
4527
4798
|
//# sourceMappingURL=cli.js.map
|