@hasna/cloud 0.1.21 → 0.1.23
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/index.js +70 -1
- package/dist/mcp/index.js +15199 -14638
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -12794,6 +12794,9 @@ async function ensureAllPgDatabases() {
|
|
|
12794
12794
|
}
|
|
12795
12795
|
|
|
12796
12796
|
// src/cli/index.ts
|
|
12797
|
+
import { existsSync as existsSync9, statSync as statSync6 } from "fs";
|
|
12798
|
+
import { join as join9 } from "path";
|
|
12799
|
+
import { homedir as homedir8 } from "os";
|
|
12797
12800
|
var program2 = new Command;
|
|
12798
12801
|
program2.name("cloud").description("Shared cloud infrastructure \u2014 database adapter, sync engine, feedback, dotfile migration").version("0.1.8");
|
|
12799
12802
|
program2.command("setup").description("Configure cloud settings").option("--host <host>", "RDS hostname").option("--port <port>", "RDS port", "5432").option("--username <user>", "RDS username").option("--password-env <env>", "Env var for RDS password", "HASNA_RDS_PASSWORD").option("--ssl", "Enable SSL", true).option("--no-ssl", "Disable SSL").option("--mode <mode>", "Mode: local, cloud, or hybrid", "local").option("--sync-interval <minutes>", "Auto-sync interval in minutes", "0").action((opts) => {
|
|
@@ -13068,7 +13071,6 @@ Done. ${results.length} services, ${totalApplied} migrations applied, ${totalErr
|
|
|
13068
13071
|
syncCmd.command("status").description("Show sync status for all discovered services").option("--service <name>", "Show status for a single service").option("--json", "Output as JSON").action(async (opts) => {
|
|
13069
13072
|
const services = opts.service ? [opts.service] : discoverServices();
|
|
13070
13073
|
const statuses = [];
|
|
13071
|
-
const { existsSync: existsSync9, statSync: statSync6 } = __require("fs");
|
|
13072
13074
|
for (const service of services) {
|
|
13073
13075
|
const dbPath = getDbPath2(service);
|
|
13074
13076
|
const localExists = existsSync9(dbPath);
|
|
@@ -13218,4 +13220,71 @@ program2.command("migrate").description("Migrate legacy dotfiles to ~/.hasna/").
|
|
|
13218
13220
|
}
|
|
13219
13221
|
}
|
|
13220
13222
|
});
|
|
13223
|
+
program2.command("doctor").description("Comprehensive health check for cloud sync setup").action(async () => {
|
|
13224
|
+
const checks = [];
|
|
13225
|
+
const configPath = join9(homedir8(), ".hasna", "cloud", "config.json");
|
|
13226
|
+
if (existsSync9(configPath)) {
|
|
13227
|
+
checks.push({ name: "Config file", status: "pass", detail: configPath });
|
|
13228
|
+
} else {
|
|
13229
|
+
checks.push({ name: "Config file", status: "fail", detail: "Missing. Run `cloud setup`." });
|
|
13230
|
+
}
|
|
13231
|
+
const config = getCloudConfig();
|
|
13232
|
+
if (config.mode === "hybrid" || config.mode === "cloud") {
|
|
13233
|
+
checks.push({ name: "Sync mode", status: "pass", detail: config.mode });
|
|
13234
|
+
} else {
|
|
13235
|
+
checks.push({ name: "Sync mode", status: "fail", detail: `"${config.mode}" \u2014 sync disabled. Run \`cloud setup --mode hybrid\`.` });
|
|
13236
|
+
}
|
|
13237
|
+
if (config.rds.host) {
|
|
13238
|
+
checks.push({ name: "RDS host", status: "pass", detail: config.rds.host });
|
|
13239
|
+
} else {
|
|
13240
|
+
checks.push({ name: "RDS host", status: "fail", detail: "Not configured. Run `cloud setup`." });
|
|
13241
|
+
}
|
|
13242
|
+
const password = process.env[config.rds.password_env];
|
|
13243
|
+
if (password) {
|
|
13244
|
+
checks.push({ name: "RDS password", status: "pass", detail: `${config.rds.password_env} is set` });
|
|
13245
|
+
} else {
|
|
13246
|
+
checks.push({ name: "RDS password", status: "fail", detail: `${config.rds.password_env} not in environment. Add to ~/.secrets/hasna/rds/live.env` });
|
|
13247
|
+
}
|
|
13248
|
+
if (config.rds.host && password) {
|
|
13249
|
+
try {
|
|
13250
|
+
const connStr = getConnectionString("postgres");
|
|
13251
|
+
const pg2 = new PgAdapterAsync2(connStr);
|
|
13252
|
+
await pg2.all("SELECT 1");
|
|
13253
|
+
await pg2.close();
|
|
13254
|
+
checks.push({ name: "PG connection", status: "pass", detail: "Connected" });
|
|
13255
|
+
} catch (err) {
|
|
13256
|
+
checks.push({ name: "PG connection", status: "fail", detail: err?.message ?? String(err) });
|
|
13257
|
+
}
|
|
13258
|
+
} else {
|
|
13259
|
+
checks.push({ name: "PG connection", status: "fail", detail: "Skipped \u2014 missing host or password" });
|
|
13260
|
+
}
|
|
13261
|
+
const caPath = process.env.NODE_EXTRA_CA_CERTS;
|
|
13262
|
+
if (caPath && existsSync9(caPath)) {
|
|
13263
|
+
checks.push({ name: "SSL CA cert", status: "pass", detail: caPath });
|
|
13264
|
+
} else if (caPath) {
|
|
13265
|
+
checks.push({ name: "SSL CA cert", status: "warn", detail: `NODE_EXTRA_CA_CERTS set but file missing: ${caPath}` });
|
|
13266
|
+
} else {
|
|
13267
|
+
checks.push({ name: "SSL CA cert", status: "warn", detail: "NODE_EXTRA_CA_CERTS not set. May cause SSL errors on some systems." });
|
|
13268
|
+
}
|
|
13269
|
+
const services = discoverServices();
|
|
13270
|
+
checks.push({ name: "Local services", status: services.length > 0 ? "pass" : "warn", detail: `${services.length} found in ~/.hasna/` });
|
|
13271
|
+
const schedule = getSyncScheduleStatus();
|
|
13272
|
+
if (schedule.registered) {
|
|
13273
|
+
checks.push({ name: "Sync schedule", status: "pass", detail: `Every ${schedule.schedule_minutes}m (${schedule.mechanism})` });
|
|
13274
|
+
} else {
|
|
13275
|
+
checks.push({ name: "Sync schedule", status: "warn", detail: "Not configured. Run `cloud sync schedule --every 30m`." });
|
|
13276
|
+
}
|
|
13277
|
+
console.log(`Cloud Doctor
|
|
13278
|
+
`);
|
|
13279
|
+
for (const c of checks) {
|
|
13280
|
+
const icon = c.status === "pass" ? "\u2713" : c.status === "fail" ? "\u2717" : "\u26A0";
|
|
13281
|
+
console.log(` ${icon} ${c.name.padEnd(20)} ${c.detail}`);
|
|
13282
|
+
}
|
|
13283
|
+
const fails = checks.filter((c) => c.status === "fail").length;
|
|
13284
|
+
const warns = checks.filter((c) => c.status === "warn").length;
|
|
13285
|
+
console.log(`
|
|
13286
|
+
${checks.length} checks: ${checks.length - fails - warns} passed, ${warns} warnings, ${fails} failed`);
|
|
13287
|
+
if (fails > 0)
|
|
13288
|
+
process.exit(1);
|
|
13289
|
+
});
|
|
13221
13290
|
program2.parse();
|