postgresai 0.14.0-dev.59 → 0.14.0-dev.61
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/bin/postgres-ai.ts
CHANGED
|
@@ -1104,7 +1104,7 @@ function checkRunningContainers(): { running: boolean; containers: string[] } {
|
|
|
1104
1104
|
/**
|
|
1105
1105
|
* Run docker compose command
|
|
1106
1106
|
*/
|
|
1107
|
-
async function runCompose(args: string[]): Promise<number> {
|
|
1107
|
+
async function runCompose(args: string[], grafanaPassword?: string): Promise<number> {
|
|
1108
1108
|
let composeFile: string;
|
|
1109
1109
|
let projectDir: string;
|
|
1110
1110
|
try {
|
|
@@ -1130,21 +1130,28 @@ async function runCompose(args: string[]): Promise<number> {
|
|
|
1130
1130
|
return 1;
|
|
1131
1131
|
}
|
|
1132
1132
|
|
|
1133
|
-
//
|
|
1133
|
+
// Set Grafana password from parameter or .pgwatch-config
|
|
1134
1134
|
const env = { ...process.env };
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
const
|
|
1142
|
-
if (
|
|
1143
|
-
|
|
1135
|
+
if (grafanaPassword) {
|
|
1136
|
+
env.GF_SECURITY_ADMIN_PASSWORD = grafanaPassword;
|
|
1137
|
+
} else {
|
|
1138
|
+
const cfgPath = path.resolve(projectDir, ".pgwatch-config");
|
|
1139
|
+
if (fs.existsSync(cfgPath)) {
|
|
1140
|
+
try {
|
|
1141
|
+
const stats = fs.statSync(cfgPath);
|
|
1142
|
+
if (!stats.isDirectory()) {
|
|
1143
|
+
const content = fs.readFileSync(cfgPath, "utf8");
|
|
1144
|
+
const match = content.match(/^grafana_password=([^\r\n]+)/m);
|
|
1145
|
+
if (match) {
|
|
1146
|
+
env.GF_SECURITY_ADMIN_PASSWORD = match[1].trim();
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
} catch (err) {
|
|
1150
|
+
// If we can't read the config, log warning and continue without setting the password
|
|
1151
|
+
if (process.env.DEBUG) {
|
|
1152
|
+
console.warn(`Warning: Could not read Grafana password from config: ${err instanceof Error ? err.message : String(err)}`);
|
|
1144
1153
|
}
|
|
1145
1154
|
}
|
|
1146
|
-
} catch (err) {
|
|
1147
|
-
// If we can't read the config, continue without setting the password
|
|
1148
1155
|
}
|
|
1149
1156
|
}
|
|
1150
1157
|
|
|
@@ -1461,8 +1468,8 @@ mon
|
|
|
1461
1468
|
}
|
|
1462
1469
|
|
|
1463
1470
|
// Step 5: Start services
|
|
1464
|
-
console.log(
|
|
1465
|
-
const code2 = await runCompose(["up", "-d", "--force-recreate"]);
|
|
1471
|
+
console.log("Step 5: Starting monitoring services...");
|
|
1472
|
+
const code2 = await runCompose(["up", "-d", "--force-recreate"], grafanaPassword);
|
|
1466
1473
|
if (code2 !== 0) {
|
|
1467
1474
|
process.exitCode = code2;
|
|
1468
1475
|
return;
|
|
@@ -1758,34 +1765,64 @@ mon
|
|
|
1758
1765
|
});
|
|
1759
1766
|
mon
|
|
1760
1767
|
.command("clean")
|
|
1761
|
-
.description("cleanup monitoring services artifacts")
|
|
1762
|
-
.
|
|
1763
|
-
|
|
1768
|
+
.description("cleanup monitoring services artifacts (stops services and removes volumes)")
|
|
1769
|
+
.option("--keep-volumes", "keep data volumes (only stop and remove containers)")
|
|
1770
|
+
.action(async (options: { keepVolumes?: boolean }) => {
|
|
1771
|
+
console.log("Cleaning up monitoring services...\n");
|
|
1764
1772
|
|
|
1765
1773
|
try {
|
|
1766
|
-
//
|
|
1767
|
-
const
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1774
|
+
// First, use docker-compose down to properly stop and remove containers/volumes
|
|
1775
|
+
const downArgs = options.keepVolumes ? ["down"] : ["down", "-v"];
|
|
1776
|
+
console.log(options.keepVolumes
|
|
1777
|
+
? "Stopping and removing containers (keeping volumes)..."
|
|
1778
|
+
: "Stopping and removing containers and volumes...");
|
|
1779
|
+
|
|
1780
|
+
const downCode = await runCompose(downArgs);
|
|
1781
|
+
if (downCode === 0) {
|
|
1782
|
+
console.log("✓ Monitoring services stopped and removed");
|
|
1772
1783
|
} else {
|
|
1773
|
-
console.log("
|
|
1784
|
+
console.log("⚠ Could not stop services (may not be running)");
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
// Remove orphaned volumes from previous installs with different project names
|
|
1788
|
+
if (!options.keepVolumes) {
|
|
1789
|
+
const volumePatterns = [
|
|
1790
|
+
"monitoring_grafana_data",
|
|
1791
|
+
"monitoring_postgres_ai_configs",
|
|
1792
|
+
"monitoring_sink_postgres_data",
|
|
1793
|
+
"monitoring_target_db_data",
|
|
1794
|
+
"monitoring_victoria_metrics_data",
|
|
1795
|
+
"postgres_ai_configs_grafana_data",
|
|
1796
|
+
"postgres_ai_configs_sink_postgres_data",
|
|
1797
|
+
"postgres_ai_configs_target_db_data",
|
|
1798
|
+
"postgres_ai_configs_victoria_metrics_data",
|
|
1799
|
+
"postgres_ai_configs_postgres_ai_configs",
|
|
1800
|
+
];
|
|
1801
|
+
|
|
1802
|
+
const { stdout: existingVolumes } = await execFilePromise("docker", ["volume", "ls", "-q"]);
|
|
1803
|
+
const volumeList = existingVolumes.trim().split('\n').filter(Boolean);
|
|
1804
|
+
const orphanedVolumes = volumeList.filter(v => volumePatterns.includes(v));
|
|
1805
|
+
|
|
1806
|
+
if (orphanedVolumes.length > 0) {
|
|
1807
|
+
for (const vol of orphanedVolumes) {
|
|
1808
|
+
try {
|
|
1809
|
+
await execFilePromise("docker", ["volume", "rm", vol]);
|
|
1810
|
+
} catch {
|
|
1811
|
+
// Volume might be in use, skip
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
console.log(`✓ Removed ${orphanedVolumes.length} orphaned volume(s) from previous installs`);
|
|
1815
|
+
}
|
|
1774
1816
|
}
|
|
1775
1817
|
|
|
1776
|
-
// Remove
|
|
1777
|
-
await execFilePromise("docker", ["volume", "prune", "-f"]);
|
|
1778
|
-
console.log("✓ Removed unused volumes");
|
|
1779
|
-
|
|
1780
|
-
// Remove unused networks
|
|
1818
|
+
// Remove any dangling resources
|
|
1781
1819
|
await execFilePromise("docker", ["network", "prune", "-f"]);
|
|
1782
1820
|
console.log("✓ Removed unused networks");
|
|
1783
1821
|
|
|
1784
|
-
// Remove dangling images
|
|
1785
1822
|
await execFilePromise("docker", ["image", "prune", "-f"]);
|
|
1786
1823
|
console.log("✓ Removed dangling images");
|
|
1787
1824
|
|
|
1788
|
-
console.log("\
|
|
1825
|
+
console.log("\n✓ Cleanup completed - ready for fresh install");
|
|
1789
1826
|
} catch (error) {
|
|
1790
1827
|
const message = error instanceof Error ? error.message : String(error);
|
|
1791
1828
|
console.error(`Error during cleanup: ${message}`);
|
package/dist/bin/postgres-ai.js
CHANGED
|
@@ -13064,7 +13064,7 @@ var {
|
|
|
13064
13064
|
// package.json
|
|
13065
13065
|
var package_default = {
|
|
13066
13066
|
name: "postgresai",
|
|
13067
|
-
version: "0.14.0-dev.
|
|
13067
|
+
version: "0.14.0-dev.61",
|
|
13068
13068
|
description: "postgres_ai CLI",
|
|
13069
13069
|
license: "Apache-2.0",
|
|
13070
13070
|
private: false,
|
|
@@ -15887,7 +15887,7 @@ var Result = import_lib.default.Result;
|
|
|
15887
15887
|
var TypeOverrides = import_lib.default.TypeOverrides;
|
|
15888
15888
|
var defaults = import_lib.default.defaults;
|
|
15889
15889
|
// package.json
|
|
15890
|
-
var version = "0.14.0-dev.
|
|
15890
|
+
var version = "0.14.0-dev.61";
|
|
15891
15891
|
var package_default2 = {
|
|
15892
15892
|
name: "postgresai",
|
|
15893
15893
|
version,
|
|
@@ -27138,7 +27138,7 @@ function checkRunningContainers() {
|
|
|
27138
27138
|
return { running: false, containers: [] };
|
|
27139
27139
|
}
|
|
27140
27140
|
}
|
|
27141
|
-
async function runCompose(args) {
|
|
27141
|
+
async function runCompose(args, grafanaPassword) {
|
|
27142
27142
|
let composeFile;
|
|
27143
27143
|
let projectDir;
|
|
27144
27144
|
try {
|
|
@@ -27161,18 +27161,26 @@ async function runCompose(args) {
|
|
|
27161
27161
|
return 1;
|
|
27162
27162
|
}
|
|
27163
27163
|
const env = { ...process.env };
|
|
27164
|
-
|
|
27165
|
-
|
|
27166
|
-
|
|
27167
|
-
|
|
27168
|
-
|
|
27169
|
-
|
|
27170
|
-
const
|
|
27171
|
-
if (
|
|
27172
|
-
|
|
27164
|
+
if (grafanaPassword) {
|
|
27165
|
+
env.GF_SECURITY_ADMIN_PASSWORD = grafanaPassword;
|
|
27166
|
+
} else {
|
|
27167
|
+
const cfgPath = path5.resolve(projectDir, ".pgwatch-config");
|
|
27168
|
+
if (fs5.existsSync(cfgPath)) {
|
|
27169
|
+
try {
|
|
27170
|
+
const stats = fs5.statSync(cfgPath);
|
|
27171
|
+
if (!stats.isDirectory()) {
|
|
27172
|
+
const content = fs5.readFileSync(cfgPath, "utf8");
|
|
27173
|
+
const match = content.match(/^grafana_password=([^\r\n]+)/m);
|
|
27174
|
+
if (match) {
|
|
27175
|
+
env.GF_SECURITY_ADMIN_PASSWORD = match[1].trim();
|
|
27176
|
+
}
|
|
27177
|
+
}
|
|
27178
|
+
} catch (err) {
|
|
27179
|
+
if (process.env.DEBUG) {
|
|
27180
|
+
console.warn(`Warning: Could not read Grafana password from config: ${err instanceof Error ? err.message : String(err)}`);
|
|
27173
27181
|
}
|
|
27174
27182
|
}
|
|
27175
|
-
}
|
|
27183
|
+
}
|
|
27176
27184
|
}
|
|
27177
27185
|
return new Promise((resolve6) => {
|
|
27178
27186
|
const child = spawn2(cmd[0], [...cmd.slice(1), "-f", composeFile, ...args], {
|
|
@@ -27484,8 +27492,8 @@ You can provide either:`);
|
|
|
27484
27492
|
`);
|
|
27485
27493
|
grafanaPassword = "demo";
|
|
27486
27494
|
}
|
|
27487
|
-
console.log(
|
|
27488
|
-
const code2 = await runCompose(["up", "-d", "--force-recreate"]);
|
|
27495
|
+
console.log("Step 5: Starting monitoring services...");
|
|
27496
|
+
const code2 = await runCompose(["up", "-d", "--force-recreate"], grafanaPassword);
|
|
27489
27497
|
if (code2 !== 0) {
|
|
27490
27498
|
process.exitCode = code2;
|
|
27491
27499
|
return;
|
|
@@ -27740,27 +27748,50 @@ Stopping services and removing data...`);
|
|
|
27740
27748
|
process.exitCode = 1;
|
|
27741
27749
|
}
|
|
27742
27750
|
});
|
|
27743
|
-
mon.command("clean").description("cleanup monitoring services artifacts").action(async () => {
|
|
27744
|
-
console.log(`Cleaning up
|
|
27751
|
+
mon.command("clean").description("cleanup monitoring services artifacts (stops services and removes volumes)").option("--keep-volumes", "keep data volumes (only stop and remove containers)").action(async (options) => {
|
|
27752
|
+
console.log(`Cleaning up monitoring services...
|
|
27745
27753
|
`);
|
|
27746
27754
|
try {
|
|
27747
|
-
const
|
|
27748
|
-
|
|
27749
|
-
|
|
27750
|
-
|
|
27751
|
-
|
|
27752
|
-
console.log("\u2713 Removed stopped containers");
|
|
27755
|
+
const downArgs = options.keepVolumes ? ["down"] : ["down", "-v"];
|
|
27756
|
+
console.log(options.keepVolumes ? "Stopping and removing containers (keeping volumes)..." : "Stopping and removing containers and volumes...");
|
|
27757
|
+
const downCode = await runCompose(downArgs);
|
|
27758
|
+
if (downCode === 0) {
|
|
27759
|
+
console.log("\u2713 Monitoring services stopped and removed");
|
|
27753
27760
|
} else {
|
|
27754
|
-
console.log("\
|
|
27761
|
+
console.log("\u26A0 Could not stop services (may not be running)");
|
|
27762
|
+
}
|
|
27763
|
+
if (!options.keepVolumes) {
|
|
27764
|
+
const volumePatterns = [
|
|
27765
|
+
"monitoring_grafana_data",
|
|
27766
|
+
"monitoring_postgres_ai_configs",
|
|
27767
|
+
"monitoring_sink_postgres_data",
|
|
27768
|
+
"monitoring_target_db_data",
|
|
27769
|
+
"monitoring_victoria_metrics_data",
|
|
27770
|
+
"postgres_ai_configs_grafana_data",
|
|
27771
|
+
"postgres_ai_configs_sink_postgres_data",
|
|
27772
|
+
"postgres_ai_configs_target_db_data",
|
|
27773
|
+
"postgres_ai_configs_victoria_metrics_data",
|
|
27774
|
+
"postgres_ai_configs_postgres_ai_configs"
|
|
27775
|
+
];
|
|
27776
|
+
const { stdout: existingVolumes } = await execFilePromise("docker", ["volume", "ls", "-q"]);
|
|
27777
|
+
const volumeList = existingVolumes.trim().split(`
|
|
27778
|
+
`).filter(Boolean);
|
|
27779
|
+
const orphanedVolumes = volumeList.filter((v) => volumePatterns.includes(v));
|
|
27780
|
+
if (orphanedVolumes.length > 0) {
|
|
27781
|
+
for (const vol of orphanedVolumes) {
|
|
27782
|
+
try {
|
|
27783
|
+
await execFilePromise("docker", ["volume", "rm", vol]);
|
|
27784
|
+
} catch {}
|
|
27785
|
+
}
|
|
27786
|
+
console.log(`\u2713 Removed ${orphanedVolumes.length} orphaned volume(s) from previous installs`);
|
|
27787
|
+
}
|
|
27755
27788
|
}
|
|
27756
|
-
await execFilePromise("docker", ["volume", "prune", "-f"]);
|
|
27757
|
-
console.log("\u2713 Removed unused volumes");
|
|
27758
27789
|
await execFilePromise("docker", ["network", "prune", "-f"]);
|
|
27759
27790
|
console.log("\u2713 Removed unused networks");
|
|
27760
27791
|
await execFilePromise("docker", ["image", "prune", "-f"]);
|
|
27761
27792
|
console.log("\u2713 Removed dangling images");
|
|
27762
27793
|
console.log(`
|
|
27763
|
-
Cleanup completed`);
|
|
27794
|
+
\u2713 Cleanup completed - ready for fresh install`);
|
|
27764
27795
|
} catch (error2) {
|
|
27765
27796
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
27766
27797
|
console.error(`Error during cleanup: ${message}`);
|
package/lib/metrics-embedded.ts
CHANGED
package/package.json
CHANGED
|
@@ -112,11 +112,12 @@ async function createTempPostgres(): Promise<TempPostgres> {
|
|
|
112
112
|
const cleanup = async () => {
|
|
113
113
|
postgresProc.kill("SIGTERM");
|
|
114
114
|
try {
|
|
115
|
+
// 30s timeout to handle slower CI environments gracefully
|
|
115
116
|
await waitFor(
|
|
116
117
|
async () => {
|
|
117
118
|
if (postgresProc.exitCode === null) throw new Error("still running");
|
|
118
119
|
},
|
|
119
|
-
{ timeoutMs:
|
|
120
|
+
{ timeoutMs: 30000, intervalMs: 100 }
|
|
120
121
|
);
|
|
121
122
|
} catch {
|
|
122
123
|
postgresProc.kill("SIGKILL");
|
|
@@ -118,11 +118,12 @@ async function createTempPostgres(): Promise<TempPostgres> {
|
|
|
118
118
|
const cleanup = async () => {
|
|
119
119
|
postgresProc.kill("SIGTERM");
|
|
120
120
|
try {
|
|
121
|
+
// 30s timeout to handle slower CI environments gracefully
|
|
121
122
|
await waitFor(
|
|
122
123
|
async () => {
|
|
123
124
|
if (postgresProc.exitCode === null) throw new Error("still running");
|
|
124
125
|
},
|
|
125
|
-
{ timeoutMs:
|
|
126
|
+
{ timeoutMs: 30000, intervalMs: 100 }
|
|
126
127
|
);
|
|
127
128
|
} catch {
|
|
128
129
|
postgresProc.kill("SIGKILL");
|