@indiekitai/pg-dash 0.3.3 → 0.3.4

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/README.md CHANGED
@@ -2,22 +2,45 @@
2
2
 
3
3
  # pg-dash
4
4
 
5
- **Lightweight PostgreSQL monitoring dashboard.** One command to start, built-in web UI, actionable fix suggestions.
5
+ **The AI-native PostgreSQL health checker.** One command to audit your database, 14 MCP tools for AI-assisted optimization, CI integration for automated checks.
6
6
 
7
- Think **pganalyze for indie devs** no Grafana, no Prometheus, no Docker. Just `npx` and go.
7
+ Not another monitoring dashboardpg-dash is built to fit into your **AI coding workflow**:
8
+
9
+ ```
10
+ Developer writes a migration → CI runs pg-dash check →
11
+ Finds missing indexes → MCP tool suggests fix → PR comment
12
+ ```
8
13
 
9
14
  ```bash
10
- npx @indiekitai/pg-dash postgres://user:pass@host/db
15
+ # One-shot health check
16
+ npx @indiekitai/pg-dash check postgres://user:pass@host/db
17
+
18
+ # AI assistant (Claude/Cursor) via MCP
19
+ pg-dash-mcp postgres://user:pass@host/db
20
+
21
+ # CI pipeline with diff
22
+ npx @indiekitai/pg-dash check $DATABASE_URL --ci --diff --format md
11
23
  ```
12
24
 
13
- ## Why?
25
+ ## Philosophy
14
26
 
15
- | Tool | Price | Setup | For |
16
- |------|-------|-------|-----|
17
- | pganalyze | $149+/mo | SaaS signup | Enterprises |
18
- | Grafana+Prometheus | Free | 3 services to configure | DevOps teams |
19
- | pgAdmin | Free | Complex UI | DBAs |
20
- | **pg-dash** | **Free** | **One command** | **Developers** |
27
+ **Developer tools are use-and-go.** You don't stare at a PostgreSQL dashboard all day. You run a check, fix the issues, and move on. pg-dash embraces this:
28
+
29
+ - **Health check** Find problems, get actionable SQL fixes, done
30
+ - **MCP tools** Let your AI assistant query and fix your database directly (unique — pganalyze/pgwatch don't have this)
31
+ - **CI integration** Catch issues automatically on every migration, not when production is on fire
32
+ - **Smart diff** See what changed since last run, track your progress
33
+
34
+ The Dashboard is there when you need it. But the real power is in the CLI, MCP, and CI.
35
+
36
+ ## Why pg-dash?
37
+
38
+ | Tool | Price | Setup | AI-native | CI-ready |
39
+ |------|-------|-------|-----------|----------|
40
+ | pganalyze | $149+/mo | SaaS signup | ❌ | ❌ |
41
+ | Grafana+Prometheus | Free | 3 services | ❌ | ❌ |
42
+ | pgAdmin | Free | Complex UI | ❌ | ❌ |
43
+ | **pg-dash** | **Free** | **One command** | **14 MCP tools** | **`--ci --diff`** |
21
44
 
22
45
  ## Features
23
46
 
@@ -144,7 +167,61 @@ pg-dash-mcp postgres://user:pass@host/db
144
167
  PG_DASH_CONNECTION_STRING=postgres://... pg-dash-mcp
145
168
  ```
146
169
 
147
- Available tools: `pg_dash_overview`, `pg_dash_health`, `pg_dash_tables`, `pg_dash_table_detail`, `pg_dash_activity`, `pg_dash_schema_changes`, `pg_dash_fix`, `pg_dash_alerts`
170
+ ### Available Tools (14)
171
+
172
+ | Tool | Description |
173
+ |------|-------------|
174
+ | `pg_dash_overview` | Database overview (version, uptime, size, connections) |
175
+ | `pg_dash_health` | Health advisor report with score, grade, and issues |
176
+ | `pg_dash_tables` | List all tables with sizes and row counts |
177
+ | `pg_dash_table_detail` | Detailed info about a specific table |
178
+ | `pg_dash_activity` | Current database activity (active queries, connections) |
179
+ | `pg_dash_schema_changes` | Recent schema changes |
180
+ | `pg_dash_fix` | Execute a safe fix (VACUUM, ANALYZE, REINDEX, etc.) |
181
+ | `pg_dash_alerts` | Alert history |
182
+ | `pg_dash_explain` | Run EXPLAIN ANALYZE on a SELECT query (read-only) |
183
+ | `pg_dash_batch_fix` | Get batch fix SQL for issues, optionally filtered by category |
184
+ | `pg_dash_slow_queries` | Top slow queries from pg_stat_statements |
185
+ | `pg_dash_table_sizes` | Table sizes with data/index breakdown (top 30) |
186
+ | `pg_dash_export` | Export full health report (JSON or Markdown) |
187
+ | `pg_dash_diff` | Compare current health with last saved snapshot |
188
+
189
+ ## CI Integration
190
+
191
+ ### GitHub Actions
192
+
193
+ Add `--ci` and `--diff` flags to integrate with CI pipelines:
194
+
195
+ ```bash
196
+ # GitHub Actions annotations (::error::, ::warning::)
197
+ pg-dash check postgres://... --ci
198
+
199
+ # Markdown report for PR comments
200
+ pg-dash check postgres://... --ci --format md
201
+
202
+ # Compare with previous run
203
+ pg-dash check postgres://... --diff
204
+
205
+ # All together
206
+ pg-dash check postgres://... --ci --diff --format md
207
+ ```
208
+
209
+ Sample workflow (`.github/workflows/pg-check.yml`):
210
+
211
+ ```yaml
212
+ name: Database Health Check
213
+ on:
214
+ push:
215
+ paths: ['migrations/**', 'prisma/**', 'drizzle/**']
216
+ schedule:
217
+ - cron: '0 8 * * 1' # Weekly Monday 8am
218
+ jobs:
219
+ check:
220
+ runs-on: ubuntu-latest
221
+ steps:
222
+ - uses: actions/checkout@v4
223
+ - run: npx @indiekitai/pg-dash check ${{ secrets.DATABASE_URL }} --ci --diff --format md
224
+ ```
148
225
 
149
226
  ## Health Checks
150
227
 
package/README.zh-CN.md CHANGED
@@ -2,22 +2,45 @@
2
2
 
3
3
  # pg-dash
4
4
 
5
- **轻量级 PostgreSQL 监控面板。** 一条命令启动,内置 Web UI,提供可操作的修复建议。
5
+ **AI 原生的 PostgreSQL 健康检查工具。** 一条命令审计数据库,14 MCP 工具让 AI 帮你优化,CI 集成自动检查。
6
6
 
7
- 可以理解为**给独立开发者的 pganalyze** —— 不需要 Grafana,不需要 Prometheus,不需要 Docker。只需 `npx` 即可运行。
7
+ 不是又一个监控面板 —— pg-dash 是为 **AI 编程工作流** 设计的:
8
+
9
+ ```
10
+ 开发者写了一个 migration → CI 跑 pg-dash check →
11
+ 发现缺失索引 → MCP 工具建议修复 → PR comment
12
+ ```
8
13
 
9
14
  ```bash
10
- npx @indiekitai/pg-dash postgres://user:pass@host/db
15
+ # 一次性健康检查
16
+ npx @indiekitai/pg-dash check postgres://user:pass@host/db
17
+
18
+ # AI 助手(Claude/Cursor)通过 MCP 调用
19
+ pg-dash-mcp postgres://user:pass@host/db
20
+
21
+ # CI 流水线 + 差异对比
22
+ npx @indiekitai/pg-dash check $DATABASE_URL --ci --diff --format md
11
23
  ```
12
24
 
25
+ ## 设计理念
26
+
27
+ **开发者工具就是用完即走的。** 你不会整天盯着 PostgreSQL 监控面板。你跑一次检查,修掉问题,然后继续干活。pg-dash 就是为此设计的:
28
+
29
+ - **健康检查** → 发现问题,拿到可执行的 SQL 修复建议,搞定
30
+ - **MCP 工具** → 让 AI 助手直接查询和修复你的数据库(独一份 —— pganalyze/pgwatch 都没有)
31
+ - **CI 集成** → 每次 migration 自动检查,不要等到生产环境出事
32
+ - **智能 diff** → 看到上次以来的变化,追踪改进进度
33
+
34
+ Dashboard 需要时可以用。但真正的核心能力在 CLI、MCP 和 CI。
35
+
13
36
  ## 为什么选 pg-dash?
14
37
 
15
- | 工具 | 价格 | 部署 | 适合 |
16
- |------|------|------|------|
17
- | pganalyze | $149+/月 | SaaS 注册 | 企业 |
18
- | Grafana+Prometheus | 免费 | 配置 3 个服务 | DevOps 团队 |
19
- | pgAdmin | 免费 | 界面复杂 | DBA |
20
- | **pg-dash** | **免费** | **一条命令** | **开发者** |
38
+ | 工具 | 价格 | 部署 | AI 原生 | CI 就绪 |
39
+ |------|------|------|---------|---------|
40
+ | pganalyze | $149+/月 | SaaS 注册 | | ❌ |
41
+ | Grafana+Prometheus | 免费 | 配置 3 个服务 | | |
42
+ | pgAdmin | 免费 | 界面复杂 | | ❌ |
43
+ | **pg-dash** | **免费** | **一条命令** | **14 个 MCP 工具** | **`--ci --diff`** |
21
44
 
22
45
  ## 功能
23
46
 
@@ -144,7 +167,61 @@ pg-dash-mcp postgres://user:pass@host/db
144
167
  PG_DASH_CONNECTION_STRING=postgres://... pg-dash-mcp
145
168
  ```
146
169
 
147
- 可用工具:`pg_dash_overview`、`pg_dash_health`、`pg_dash_tables`、`pg_dash_table_detail`、`pg_dash_activity`、`pg_dash_schema_changes`、`pg_dash_fix`、`pg_dash_alerts`
170
+ ### 可用工具(14 个)
171
+
172
+ | 工具 | 描述 |
173
+ |------|------|
174
+ | `pg_dash_overview` | 数据库概览(版本、运行时间、大小、连接数) |
175
+ | `pg_dash_health` | 健康报告(评分、等级、问题列表) |
176
+ | `pg_dash_tables` | 所有表的大小和行数 |
177
+ | `pg_dash_table_detail` | 单个表的详细信息 |
178
+ | `pg_dash_activity` | 当前活动(查询、连接) |
179
+ | `pg_dash_schema_changes` | 最近的 schema 变更 |
180
+ | `pg_dash_fix` | 执行安全修复(VACUUM、ANALYZE、REINDEX 等) |
181
+ | `pg_dash_alerts` | 告警历史 |
182
+ | `pg_dash_explain` | 对 SELECT 查询运行 EXPLAIN ANALYZE(只读) |
183
+ | `pg_dash_batch_fix` | 获取批量修复 SQL,可按类别过滤 |
184
+ | `pg_dash_slow_queries` | pg_stat_statements 中的慢查询 |
185
+ | `pg_dash_table_sizes` | 表大小(数据/索引拆分,前 30) |
186
+ | `pg_dash_export` | 导出完整健康报告(JSON 或 Markdown) |
187
+ | `pg_dash_diff` | 与上次快照对比当前健康状态 |
188
+
189
+ ## CI 集成
190
+
191
+ ### GitHub Actions
192
+
193
+ 使用 `--ci` 和 `--diff` 标志集成到 CI 流水线:
194
+
195
+ ```bash
196
+ # GitHub Actions 注解(::error::、::warning::)
197
+ pg-dash check postgres://... --ci
198
+
199
+ # 适合 PR 评论的 Markdown 报告
200
+ pg-dash check postgres://... --ci --format md
201
+
202
+ # 与上次运行对比
203
+ pg-dash check postgres://... --diff
204
+
205
+ # 全部组合
206
+ pg-dash check postgres://... --ci --diff --format md
207
+ ```
208
+
209
+ 示例工作流(`.github/workflows/pg-check.yml`):
210
+
211
+ ```yaml
212
+ name: Database Health Check
213
+ on:
214
+ push:
215
+ paths: ['migrations/**', 'prisma/**', 'drizzle/**']
216
+ schedule:
217
+ - cron: '0 8 * * 1' # 每周一早 8 点
218
+ jobs:
219
+ check:
220
+ runs-on: ubuntu-latest
221
+ steps:
222
+ - uses: actions/checkout@v4
223
+ - run: npx @indiekitai/pg-dash check ${{ secrets.DATABASE_URL }} --ci --diff --format md
224
+ ```
148
225
 
149
226
  ## 健康检查
150
227
 
package/dist/cli.js CHANGED
@@ -754,6 +754,54 @@ var init_advisor = __esm({
754
754
  }
755
755
  });
756
756
 
757
+ // src/server/snapshot.ts
758
+ var snapshot_exports = {};
759
+ __export(snapshot_exports, {
760
+ diffSnapshots: () => diffSnapshots2,
761
+ loadSnapshot: () => loadSnapshot,
762
+ saveSnapshot: () => saveSnapshot
763
+ });
764
+ import fs4 from "fs";
765
+ import path4 from "path";
766
+ function saveSnapshot(dataDir, result) {
767
+ fs4.mkdirSync(dataDir, { recursive: true });
768
+ const snapshot = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), result };
769
+ fs4.writeFileSync(path4.join(dataDir, SNAPSHOT_FILE), JSON.stringify(snapshot, null, 2));
770
+ }
771
+ function loadSnapshot(dataDir) {
772
+ const filePath = path4.join(dataDir, SNAPSHOT_FILE);
773
+ if (!fs4.existsSync(filePath)) return null;
774
+ try {
775
+ return JSON.parse(fs4.readFileSync(filePath, "utf-8"));
776
+ } catch {
777
+ return null;
778
+ }
779
+ }
780
+ function diffSnapshots2(prev, current) {
781
+ const prevIds = new Set(prev.issues.map((i) => i.id));
782
+ const currIds = new Set(current.issues.map((i) => i.id));
783
+ const newIssues = current.issues.filter((i) => !prevIds.has(i.id));
784
+ const resolvedIssues = prev.issues.filter((i) => !currIds.has(i.id));
785
+ const unchanged = current.issues.filter((i) => prevIds.has(i.id));
786
+ return {
787
+ scoreDelta: current.score - prev.score,
788
+ previousScore: prev.score,
789
+ currentScore: current.score,
790
+ previousGrade: prev.grade,
791
+ currentGrade: current.grade,
792
+ newIssues,
793
+ resolvedIssues,
794
+ unchanged
795
+ };
796
+ }
797
+ var SNAPSHOT_FILE;
798
+ var init_snapshot = __esm({
799
+ "src/server/snapshot.ts"() {
800
+ "use strict";
801
+ SNAPSHOT_FILE = "last-check.json";
802
+ }
803
+ });
804
+
757
805
  // src/cli.ts
758
806
  import { parseArgs } from "util";
759
807
 
@@ -2983,8 +3031,8 @@ async function startServer(opts) {
2983
3031
  }
2984
3032
 
2985
3033
  // src/cli.ts
2986
- import fs4 from "fs";
2987
- import path4 from "path";
3034
+ import fs5 from "fs";
3035
+ import path5 from "path";
2988
3036
  import { fileURLToPath as fileURLToPath2 } from "url";
2989
3037
  process.on("uncaughtException", (err) => {
2990
3038
  console.error("Uncaught exception:", err);
@@ -3018,13 +3066,15 @@ var { values, positionals } = parseArgs({
3018
3066
  help: { type: "boolean", short: "h" },
3019
3067
  version: { type: "boolean", short: "v" },
3020
3068
  threshold: { type: "string" },
3021
- format: { type: "string", short: "f" }
3069
+ format: { type: "string", short: "f" },
3070
+ ci: { type: "boolean", default: false },
3071
+ diff: { type: "boolean", default: false }
3022
3072
  }
3023
3073
  });
3024
3074
  if (values.version) {
3025
3075
  try {
3026
- const __dirname2 = path4.dirname(fileURLToPath2(import.meta.url));
3027
- const pkg = JSON.parse(fs4.readFileSync(path4.resolve(__dirname2, "../package.json"), "utf-8"));
3076
+ const __dirname2 = path5.dirname(fileURLToPath2(import.meta.url));
3077
+ const pkg = JSON.parse(fs5.readFileSync(path5.resolve(__dirname2, "../package.json"), "utf-8"));
3028
3078
  console.log(`pg-dash v${pkg.version}`);
3029
3079
  } catch {
3030
3080
  console.log("pg-dash v0.1.0");
@@ -3064,6 +3114,8 @@ Options:
3064
3114
  --long-query-threshold <min> Long query threshold in minutes (default: 5)
3065
3115
  --threshold <score> Health score threshold for check command (default: 70)
3066
3116
  -f, --format <fmt> Output format: text|json|md (default: text)
3117
+ --ci Output GitHub Actions compatible annotations
3118
+ --diff Compare with previous run (saves to ~/.pg-dash/last-check.json)
3067
3119
  -v, --version Show version
3068
3120
  -h, --help Show this help
3069
3121
 
@@ -3094,50 +3146,120 @@ if (subcommand === "check") {
3094
3146
  const connectionString = resolveConnectionString(1);
3095
3147
  const threshold = parseInt(values.threshold || "70", 10);
3096
3148
  const format = values.format || "text";
3149
+ const ci = values.ci || false;
3150
+ const useDiff = values.diff || false;
3097
3151
  const { Pool: Pool2 } = await import("pg");
3098
3152
  const { getAdvisorReport: getAdvisorReport2 } = await Promise.resolve().then(() => (init_advisor(), advisor_exports));
3153
+ const { saveSnapshot: saveSnapshot2, loadSnapshot: loadSnapshot2, diffSnapshots: diffSnapshots3 } = await Promise.resolve().then(() => (init_snapshot(), snapshot_exports));
3154
+ const os4 = await import("os");
3099
3155
  const pool = new Pool2({ connectionString });
3156
+ const checkDataDir = values["data-dir"] || path5.join(os4.homedir(), ".pg-dash");
3100
3157
  try {
3101
3158
  const lqt = parseInt(values["long-query-threshold"] || process.env.PG_DASH_LONG_QUERY_THRESHOLD || "5", 10);
3102
3159
  const report = await getAdvisorReport2(pool, lqt);
3160
+ let diff = null;
3161
+ if (useDiff) {
3162
+ const prev = loadSnapshot2(checkDataDir);
3163
+ if (prev) {
3164
+ diff = diffSnapshots3(prev.result, report);
3165
+ }
3166
+ saveSnapshot2(checkDataDir, report);
3167
+ }
3103
3168
  if (format === "json") {
3104
- console.log(JSON.stringify(report, null, 2));
3105
- } else if (format === "md") {
3106
- console.log(`# pg-dash Health Report
3169
+ const output = { ...report };
3170
+ if (diff) output.diff = diff;
3171
+ console.log(JSON.stringify(output, null, 2));
3172
+ } else if (format === "md" || ci && format !== "text") {
3173
+ console.log(`## \u{1F3E5} pg-dash Health Report
3107
3174
  `);
3108
- console.log(`Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
3175
+ if (diff) {
3176
+ const sign = diff.scoreDelta >= 0 ? "+" : "";
3177
+ console.log(`**Score: ${diff.previousScore} \u2192 ${report.score} (${sign}${diff.scoreDelta})**
3109
3178
  `);
3110
- console.log(`## Health Score: ${report.score}/100 (Grade: ${report.grade})
3179
+ } else {
3180
+ console.log(`**Score: ${report.score}/100 (${report.grade})**
3111
3181
  `);
3112
- console.log(`| Category | Grade | Score | Issues |`);
3182
+ }
3183
+ console.log(`| Category | Score | Grade | Issues |`);
3113
3184
  console.log(`|----------|-------|-------|--------|`);
3114
3185
  for (const [cat, b] of Object.entries(report.breakdown)) {
3115
- console.log(`| ${cat} | ${b.grade} | ${b.score}/100 | ${b.count} |`);
3186
+ console.log(`| ${cat} | ${b.score} | ${b.grade} | ${b.count} |`);
3187
+ }
3188
+ if (diff) {
3189
+ if (diff.resolvedIssues.length > 0) {
3190
+ console.log(`
3191
+ ### \u2705 Resolved (${diff.resolvedIssues.length})`);
3192
+ for (const i of diff.resolvedIssues) console.log(`- ~~${i.title}~~`);
3193
+ }
3194
+ if (diff.newIssues.length > 0) {
3195
+ console.log(`
3196
+ ### \u{1F195} New Issues (${diff.newIssues.length})`);
3197
+ for (const i of diff.newIssues) {
3198
+ const icon = i.severity === "critical" ? "\u{1F534}" : i.severity === "warning" ? "\u{1F7E1}" : "\u{1F535}";
3199
+ console.log(`- ${icon} [${i.severity}] ${i.title}`);
3200
+ }
3201
+ }
3116
3202
  }
3117
3203
  if (report.issues.length > 0) {
3118
3204
  console.log(`
3119
- ### Issues (${report.issues.length})
3205
+ ### \u26A0\uFE0F Issues (${report.issues.length})
3120
3206
  `);
3121
3207
  for (const issue of report.issues) {
3122
- const icon = issue.severity === "critical" ? "\u{1F534}" : issue.severity === "warning" ? "\u{1F7E1}" : "\u{1F535}";
3123
- console.log(`#### ${icon} [${issue.severity}] ${issue.title}
3124
- `);
3125
- console.log(`${issue.description}
3126
- `);
3127
- console.log(`**Fix**:
3128
- \`\`\`sql
3129
- ${issue.fix}
3130
- \`\`\`
3131
- `);
3208
+ const sev = issue.severity === "critical" ? "error" : issue.severity === "warning" ? "warning" : "notice";
3209
+ console.log(`- [${sev}] ${issue.title}`);
3132
3210
  }
3133
3211
  } else {
3134
3212
  console.log(`
3135
3213
  \u2705 No issues found!`);
3136
3214
  }
3137
- } else {
3215
+ if (report.batchFixes.length > 0) {
3216
+ console.log(`
3217
+ ### \u{1F527} Batch Fixes
3218
+ `);
3219
+ console.log("```sql");
3220
+ for (const fix of report.batchFixes) {
3221
+ console.log(`-- ${fix.title}`);
3222
+ console.log(fix.sql);
3223
+ }
3224
+ console.log("```");
3225
+ }
3226
+ } else if (ci) {
3227
+ for (const issue of report.issues) {
3228
+ const level = issue.severity === "critical" ? "error" : issue.severity === "warning" ? "warning" : "notice";
3229
+ console.log(`::${level}::${issue.title}: ${issue.description}`);
3230
+ }
3138
3231
  console.log(`
3232
+ Health Score: ${report.score}/100 (${report.grade})`);
3233
+ for (const [cat, b] of Object.entries(report.breakdown)) {
3234
+ console.log(` ${cat.padEnd(14)} ${b.grade} (${b.score}/100) \u2014 ${b.count} issue${b.count !== 1 ? "s" : ""}`);
3235
+ }
3236
+ if (diff) {
3237
+ const sign = diff.scoreDelta >= 0 ? "+" : "";
3238
+ console.log(`
3239
+ Score: ${diff.previousScore} \u2192 ${report.score} (${sign}${diff.scoreDelta})`);
3240
+ console.log(`Resolved: ${diff.resolvedIssues.length} issues`);
3241
+ console.log(`New: ${diff.newIssues.length} issues`);
3242
+ }
3243
+ } else {
3244
+ if (diff) {
3245
+ const sign = diff.scoreDelta >= 0 ? "+" : "";
3246
+ console.log(`
3247
+ Score: ${diff.previousScore} \u2192 ${report.score} (${sign}${diff.scoreDelta})
3248
+ `);
3249
+ if (diff.resolvedIssues.length > 0) {
3250
+ console.log(` \u2705 Resolved: ${diff.resolvedIssues.length} issues`);
3251
+ for (const i of diff.resolvedIssues) console.log(` - ${i.title}`);
3252
+ }
3253
+ if (diff.newIssues.length > 0) {
3254
+ console.log(` \u{1F195} New: ${diff.newIssues.length} issues`);
3255
+ for (const i of diff.newIssues) console.log(` - ${i.title}`);
3256
+ }
3257
+ console.log();
3258
+ } else {
3259
+ console.log(`
3139
3260
  Health Score: ${report.score}/100 (Grade: ${report.grade})
3140
3261
  `);
3262
+ }
3141
3263
  for (const [cat, b] of Object.entries(report.breakdown)) {
3142
3264
  console.log(` ${cat.padEnd(14)} ${b.grade} (${b.score}/100) \u2014 ${b.count} issue${b.count !== 1 ? "s" : ""}`);
3143
3265
  }
@@ -3161,9 +3283,9 @@ ${issue.fix}
3161
3283
  }
3162
3284
  } else if (subcommand === "schema-diff") {
3163
3285
  const connectionString = resolveConnectionString(1);
3164
- const dataDir = values["data-dir"] || path4.join((await import("os")).homedir(), ".pg-dash");
3165
- const schemaDbPath = path4.join(dataDir, "schema.db");
3166
- if (!fs4.existsSync(schemaDbPath)) {
3286
+ const dataDir = values["data-dir"] || path5.join((await import("os")).homedir(), ".pg-dash");
3287
+ const schemaDbPath = path5.join(dataDir, "schema.db");
3288
+ if (!fs5.existsSync(schemaDbPath)) {
3167
3289
  console.error("No schema tracking data found. Run pg-dash server first to collect schema snapshots.");
3168
3290
  process.exit(1);
3169
3291
  }