@hasna/cloud 0.1.38 → 0.1.40
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 +102 -63
- package/dist/config.d.ts.map +1 -1
- package/dist/index.js +10 -3
- package/dist/mcp/bin.js +44 -12
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +57 -18
- package/dist/scheduled-sync.js +10 -3
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +2 -3
package/dist/cli/index.js
CHANGED
|
@@ -8956,7 +8956,7 @@ var require_dist = __commonJS((exports) => {
|
|
|
8956
8956
|
function parse(stream, callback) {
|
|
8957
8957
|
const parser = new parser_1.Parser;
|
|
8958
8958
|
stream.on("data", (buffer) => parser.parse(buffer, callback));
|
|
8959
|
-
return new Promise((
|
|
8959
|
+
return new Promise((resolve2) => stream.on("end", () => resolve2()));
|
|
8960
8960
|
}
|
|
8961
8961
|
exports.parse = parse;
|
|
8962
8962
|
});
|
|
@@ -9635,12 +9635,12 @@ var require_client = __commonJS((exports, module) => {
|
|
|
9635
9635
|
this._connect(callback);
|
|
9636
9636
|
return;
|
|
9637
9637
|
}
|
|
9638
|
-
return new this._Promise((
|
|
9638
|
+
return new this._Promise((resolve2, reject) => {
|
|
9639
9639
|
this._connect((error) => {
|
|
9640
9640
|
if (error) {
|
|
9641
9641
|
reject(error);
|
|
9642
9642
|
} else {
|
|
9643
|
-
|
|
9643
|
+
resolve2(this);
|
|
9644
9644
|
}
|
|
9645
9645
|
});
|
|
9646
9646
|
});
|
|
@@ -9972,8 +9972,8 @@ var require_client = __commonJS((exports, module) => {
|
|
|
9972
9972
|
readTimeout = config.query_timeout || this.connectionParameters.query_timeout;
|
|
9973
9973
|
query = new Query(config, values, callback);
|
|
9974
9974
|
if (!query.callback) {
|
|
9975
|
-
result = new this._Promise((
|
|
9976
|
-
query.callback = (err, res) => err ? reject(err) :
|
|
9975
|
+
result = new this._Promise((resolve2, reject) => {
|
|
9976
|
+
query.callback = (err, res) => err ? reject(err) : resolve2(res);
|
|
9977
9977
|
}).catch((err) => {
|
|
9978
9978
|
Error.captureStackTrace(err);
|
|
9979
9979
|
throw err;
|
|
@@ -10048,8 +10048,8 @@ var require_client = __commonJS((exports, module) => {
|
|
|
10048
10048
|
if (cb) {
|
|
10049
10049
|
this.connection.once("end", cb);
|
|
10050
10050
|
} else {
|
|
10051
|
-
return new this._Promise((
|
|
10052
|
-
this.connection.once("end",
|
|
10051
|
+
return new this._Promise((resolve2) => {
|
|
10052
|
+
this.connection.once("end", resolve2);
|
|
10053
10053
|
});
|
|
10054
10054
|
}
|
|
10055
10055
|
}
|
|
@@ -10096,8 +10096,8 @@ var require_pg_pool = __commonJS((exports, module) => {
|
|
|
10096
10096
|
const cb = function(err, client) {
|
|
10097
10097
|
err ? rej(err) : res(client);
|
|
10098
10098
|
};
|
|
10099
|
-
const result = new Promise2(function(
|
|
10100
|
-
res =
|
|
10099
|
+
const result = new Promise2(function(resolve2, reject) {
|
|
10100
|
+
res = resolve2;
|
|
10101
10101
|
rej = reject;
|
|
10102
10102
|
}).catch((err) => {
|
|
10103
10103
|
Error.captureStackTrace(err);
|
|
@@ -10158,7 +10158,7 @@ var require_pg_pool = __commonJS((exports, module) => {
|
|
|
10158
10158
|
if (typeof Promise2.try === "function") {
|
|
10159
10159
|
return Promise2.try(f);
|
|
10160
10160
|
}
|
|
10161
|
-
return new Promise2((
|
|
10161
|
+
return new Promise2((resolve2) => resolve2(f()));
|
|
10162
10162
|
}
|
|
10163
10163
|
_isFull() {
|
|
10164
10164
|
return this._clients.length >= this.options.max;
|
|
@@ -10534,8 +10534,8 @@ var require_query2 = __commonJS((exports, module) => {
|
|
|
10534
10534
|
NativeQuery.prototype._getPromise = function() {
|
|
10535
10535
|
if (this._promise)
|
|
10536
10536
|
return this._promise;
|
|
10537
|
-
this._promise = new Promise(function(
|
|
10538
|
-
this._once("end",
|
|
10537
|
+
this._promise = new Promise(function(resolve2, reject) {
|
|
10538
|
+
this._once("end", resolve2);
|
|
10539
10539
|
this._once("error", reject);
|
|
10540
10540
|
}.bind(this));
|
|
10541
10541
|
return this._promise;
|
|
@@ -10709,12 +10709,12 @@ var require_client2 = __commonJS((exports, module) => {
|
|
|
10709
10709
|
this._connect(callback);
|
|
10710
10710
|
return;
|
|
10711
10711
|
}
|
|
10712
|
-
return new this._Promise((
|
|
10712
|
+
return new this._Promise((resolve2, reject) => {
|
|
10713
10713
|
this._connect((error) => {
|
|
10714
10714
|
if (error) {
|
|
10715
10715
|
reject(error);
|
|
10716
10716
|
} else {
|
|
10717
|
-
|
|
10717
|
+
resolve2(this);
|
|
10718
10718
|
}
|
|
10719
10719
|
});
|
|
10720
10720
|
});
|
|
@@ -10738,8 +10738,8 @@ var require_client2 = __commonJS((exports, module) => {
|
|
|
10738
10738
|
query = new NativeQuery(config, values, callback);
|
|
10739
10739
|
if (!query.callback) {
|
|
10740
10740
|
let resolveOut, rejectOut;
|
|
10741
|
-
result = new this._Promise((
|
|
10742
|
-
resolveOut =
|
|
10741
|
+
result = new this._Promise((resolve2, reject) => {
|
|
10742
|
+
resolveOut = resolve2;
|
|
10743
10743
|
rejectOut = reject;
|
|
10744
10744
|
}).catch((err) => {
|
|
10745
10745
|
Error.captureStackTrace(err);
|
|
@@ -10797,8 +10797,8 @@ var require_client2 = __commonJS((exports, module) => {
|
|
|
10797
10797
|
}
|
|
10798
10798
|
let result;
|
|
10799
10799
|
if (!cb) {
|
|
10800
|
-
result = new this._Promise(function(
|
|
10801
|
-
cb = (err) => err ? reject(err) :
|
|
10800
|
+
result = new this._Promise(function(resolve2, reject) {
|
|
10801
|
+
cb = (err) => err ? reject(err) : resolve2();
|
|
10802
10802
|
});
|
|
10803
10803
|
}
|
|
10804
10804
|
this.native.end(function() {
|
|
@@ -11238,7 +11238,7 @@ var init_adapter = __esm(() => {
|
|
|
11238
11238
|
|
|
11239
11239
|
// src/dotfile.ts
|
|
11240
11240
|
import {
|
|
11241
|
-
existsSync as
|
|
11241
|
+
existsSync as existsSync3,
|
|
11242
11242
|
mkdirSync,
|
|
11243
11243
|
readdirSync,
|
|
11244
11244
|
copyFileSync
|
|
@@ -11257,9 +11257,9 @@ function getDbPath(serviceName) {
|
|
|
11257
11257
|
function migrateDotfile(serviceName) {
|
|
11258
11258
|
const legacyDir = join2(homedir2(), `.${serviceName}`);
|
|
11259
11259
|
const newDir = join2(HASNA_DIR, serviceName);
|
|
11260
|
-
if (!
|
|
11260
|
+
if (!existsSync3(legacyDir))
|
|
11261
11261
|
return [];
|
|
11262
|
-
if (
|
|
11262
|
+
if (existsSync3(newDir))
|
|
11263
11263
|
return [];
|
|
11264
11264
|
mkdirSync(newDir, { recursive: true });
|
|
11265
11265
|
const migrated = [];
|
|
@@ -11299,7 +11299,7 @@ __export(exports_discover, {
|
|
|
11299
11299
|
SYNC_EXCLUDED_TABLE_PATTERNS: () => SYNC_EXCLUDED_TABLE_PATTERNS,
|
|
11300
11300
|
KNOWN_PG_SERVICES: () => KNOWN_PG_SERVICES
|
|
11301
11301
|
});
|
|
11302
|
-
import { readdirSync as readdirSync2, existsSync as
|
|
11302
|
+
import { readdirSync as readdirSync2, existsSync as existsSync4 } from "fs";
|
|
11303
11303
|
import { join as join3 } from "path";
|
|
11304
11304
|
import { homedir as homedir3 } from "os";
|
|
11305
11305
|
function isSyncExcludedTable(table) {
|
|
@@ -11307,7 +11307,7 @@ function isSyncExcludedTable(table) {
|
|
|
11307
11307
|
}
|
|
11308
11308
|
function discoverServices() {
|
|
11309
11309
|
const dataDir = join3(homedir3(), ".hasna");
|
|
11310
|
-
if (!
|
|
11310
|
+
if (!existsSync4(dataDir))
|
|
11311
11311
|
return [];
|
|
11312
11312
|
try {
|
|
11313
11313
|
const entries = readdirSync2(dataDir, { withFileTypes: true });
|
|
@@ -11329,7 +11329,7 @@ function discoverSyncableServices() {
|
|
|
11329
11329
|
}
|
|
11330
11330
|
function getServiceDbPath(service) {
|
|
11331
11331
|
const dataDir = join3(homedir3(), ".hasna", service);
|
|
11332
|
-
if (!
|
|
11332
|
+
if (!existsSync4(dataDir))
|
|
11333
11333
|
return null;
|
|
11334
11334
|
const candidates = [
|
|
11335
11335
|
join3(dataDir, `${service}.db`),
|
|
@@ -11345,7 +11345,7 @@ function getServiceDbPath(service) {
|
|
|
11345
11345
|
}
|
|
11346
11346
|
} catch {}
|
|
11347
11347
|
for (const p of candidates) {
|
|
11348
|
-
if (
|
|
11348
|
+
if (existsSync4(p))
|
|
11349
11349
|
return p;
|
|
11350
11350
|
}
|
|
11351
11351
|
return null;
|
|
@@ -11400,9 +11400,9 @@ var init_discover = __esm(() => {
|
|
|
11400
11400
|
|
|
11401
11401
|
// src/machines.ts
|
|
11402
11402
|
import { spawnSync } from "child_process";
|
|
11403
|
-
import { existsSync as
|
|
11403
|
+
import { existsSync as existsSync5 } from "fs";
|
|
11404
11404
|
import { homedir as homedir4, hostname, platform, arch, userInfo } from "os";
|
|
11405
|
-
import { dirname, join as join4 } from "path";
|
|
11405
|
+
import { dirname as dirname2, join as join4 } from "path";
|
|
11406
11406
|
function quoteSqlString(value) {
|
|
11407
11407
|
return `'${value.replace(/'/g, "''")}'`;
|
|
11408
11408
|
}
|
|
@@ -11417,7 +11417,7 @@ function detectWorkspacePath() {
|
|
|
11417
11417
|
const home = homedir4();
|
|
11418
11418
|
const candidates = [join4(home, "workspace"), join4(home, "Workspace")];
|
|
11419
11419
|
for (const candidate of candidates) {
|
|
11420
|
-
if (
|
|
11420
|
+
if (existsSync5(candidate))
|
|
11421
11421
|
return candidate;
|
|
11422
11422
|
}
|
|
11423
11423
|
const cwd = process.cwd();
|
|
@@ -11432,7 +11432,7 @@ function detectWorkspacePath() {
|
|
|
11432
11432
|
return cwd;
|
|
11433
11433
|
}
|
|
11434
11434
|
function detectBunPath() {
|
|
11435
|
-
return
|
|
11435
|
+
return dirname2(process.execPath);
|
|
11436
11436
|
}
|
|
11437
11437
|
function toFlag(value, fallback = 0) {
|
|
11438
11438
|
if (value === undefined)
|
|
@@ -11814,7 +11814,7 @@ __export(exports_config, {
|
|
|
11814
11814
|
createDatabase: () => createDatabase,
|
|
11815
11815
|
CloudConfigSchema: () => CloudConfigSchema
|
|
11816
11816
|
});
|
|
11817
|
-
import { existsSync as
|
|
11817
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
11818
11818
|
import { homedir as homedir5 } from "os";
|
|
11819
11819
|
import { join as join5 } from "path";
|
|
11820
11820
|
function getConfigDir() {
|
|
@@ -11824,11 +11824,11 @@ function getConfigPath() {
|
|
|
11824
11824
|
return CONFIG_PATH;
|
|
11825
11825
|
}
|
|
11826
11826
|
function getCloudConfig() {
|
|
11827
|
-
if (!
|
|
11827
|
+
if (!existsSync6(CONFIG_PATH)) {
|
|
11828
11828
|
return CloudConfigSchema.parse({});
|
|
11829
11829
|
}
|
|
11830
11830
|
try {
|
|
11831
|
-
const raw =
|
|
11831
|
+
const raw = readFileSync2(CONFIG_PATH, "utf-8");
|
|
11832
11832
|
return CloudConfigSchema.parse(JSON.parse(raw));
|
|
11833
11833
|
} catch {
|
|
11834
11834
|
return CloudConfigSchema.parse({});
|
|
@@ -11849,8 +11849,15 @@ function getConnectionString(dbName) {
|
|
|
11849
11849
|
if (password === undefined || password === "") {
|
|
11850
11850
|
throw new Error(`RDS password not set. Export ${password_env} in your shell or add it to ~/.secrets/hasna/rds/live.env`);
|
|
11851
11851
|
}
|
|
11852
|
-
const
|
|
11853
|
-
|
|
11852
|
+
const url = new URL("postgres:" + "//placeholder");
|
|
11853
|
+
url.hostname = host;
|
|
11854
|
+
url.port = String(port);
|
|
11855
|
+
url.username = username;
|
|
11856
|
+
url.password = password;
|
|
11857
|
+
url.pathname = `/${dbName}`;
|
|
11858
|
+
if (ssl)
|
|
11859
|
+
url.searchParams.set("sslmode", "require");
|
|
11860
|
+
return url.toString();
|
|
11854
11861
|
}
|
|
11855
11862
|
function createDatabase(options) {
|
|
11856
11863
|
const config = getCloudConfig();
|
|
@@ -11891,7 +11898,7 @@ var init_config = __esm(() => {
|
|
|
11891
11898
|
password_env: exports_external.string().default("HASNA_RDS_PASSWORD"),
|
|
11892
11899
|
ssl: exports_external.boolean().default(true)
|
|
11893
11900
|
}).default({}),
|
|
11894
|
-
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("
|
|
11901
|
+
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("local"),
|
|
11895
11902
|
auto_sync_interval_minutes: exports_external.number().default(0),
|
|
11896
11903
|
feedback_endpoint: exports_external.string().default("https://feedback.hasna.com/api/v1/feedback"),
|
|
11897
11904
|
sync: exports_external.object({
|
|
@@ -12603,6 +12610,31 @@ function collectValues(value, previous) {
|
|
|
12603
12610
|
return previous;
|
|
12604
12611
|
}
|
|
12605
12612
|
|
|
12613
|
+
// src/version.ts
|
|
12614
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
12615
|
+
import { dirname, resolve } from "node:path";
|
|
12616
|
+
import { fileURLToPath } from "node:url";
|
|
12617
|
+
var cachedPackageVersion;
|
|
12618
|
+
function getPackageVersion() {
|
|
12619
|
+
if (cachedPackageVersion)
|
|
12620
|
+
return cachedPackageVersion;
|
|
12621
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
12622
|
+
const candidates = [
|
|
12623
|
+
resolve(here, "../package.json"),
|
|
12624
|
+
resolve(here, "../../package.json")
|
|
12625
|
+
];
|
|
12626
|
+
for (const path of candidates) {
|
|
12627
|
+
if (!existsSync2(path))
|
|
12628
|
+
continue;
|
|
12629
|
+
const pkg = JSON.parse(readFileSync(path, "utf8"));
|
|
12630
|
+
if (typeof pkg.version === "string" && pkg.version.length > 0) {
|
|
12631
|
+
cachedPackageVersion = pkg.version;
|
|
12632
|
+
return cachedPackageVersion;
|
|
12633
|
+
}
|
|
12634
|
+
}
|
|
12635
|
+
throw new Error("Unable to resolve @hasna/cloud package version");
|
|
12636
|
+
}
|
|
12637
|
+
|
|
12606
12638
|
// src/cli/cmd-setup.ts
|
|
12607
12639
|
init_config();
|
|
12608
12640
|
|
|
@@ -13194,8 +13226,8 @@ async function ensureAllPgDatabases() {
|
|
|
13194
13226
|
|
|
13195
13227
|
// src/sync-schedule.ts
|
|
13196
13228
|
init_config();
|
|
13197
|
-
import { join as join6, dirname as
|
|
13198
|
-
import { existsSync as
|
|
13229
|
+
import { join as join6, dirname as dirname3 } from "path";
|
|
13230
|
+
import { existsSync as existsSync7, writeFileSync as writeFileSync2, unlinkSync, mkdirSync as mkdirSync3 } from "fs";
|
|
13199
13231
|
import { homedir as homedir6, platform as platform2 } from "os";
|
|
13200
13232
|
var SERVICE_NAME = "hasna-cloud-sync";
|
|
13201
13233
|
var CONFIG_DIR2 = join6(homedir6(), ".hasna", "cloud");
|
|
@@ -13238,11 +13270,11 @@ function minutesToCron(minutes) {
|
|
|
13238
13270
|
return `*/${minutes} * * * *`;
|
|
13239
13271
|
}
|
|
13240
13272
|
function getWorkerPath() {
|
|
13241
|
-
const dir = typeof import.meta.dir === "string" ? import.meta.dir :
|
|
13273
|
+
const dir = typeof import.meta.dir === "string" ? import.meta.dir : dirname3(import.meta.url.replace("file://", ""));
|
|
13242
13274
|
const tsPath = join6(dir, "scheduled-sync.ts");
|
|
13243
13275
|
const jsPath = join6(dir, "scheduled-sync.js");
|
|
13244
13276
|
try {
|
|
13245
|
-
if (
|
|
13277
|
+
if (existsSync7(tsPath))
|
|
13246
13278
|
return tsPath;
|
|
13247
13279
|
} catch {}
|
|
13248
13280
|
return jsPath;
|
|
@@ -13254,7 +13286,7 @@ function getBunPath() {
|
|
|
13254
13286
|
"/usr/bin/bun"
|
|
13255
13287
|
];
|
|
13256
13288
|
for (const p of candidates) {
|
|
13257
|
-
if (
|
|
13289
|
+
if (existsSync7(p))
|
|
13258
13290
|
return p;
|
|
13259
13291
|
}
|
|
13260
13292
|
return "bun";
|
|
@@ -13299,7 +13331,7 @@ function createLaunchdPlist(intervalMinutes) {
|
|
|
13299
13331
|
}
|
|
13300
13332
|
async function registerLaunchd(intervalMinutes) {
|
|
13301
13333
|
const plistPath = getLaunchdPlistPath();
|
|
13302
|
-
const plistDir =
|
|
13334
|
+
const plistDir = dirname3(plistPath);
|
|
13303
13335
|
mkdirSync3(plistDir, { recursive: true });
|
|
13304
13336
|
try {
|
|
13305
13337
|
await Bun.spawn(["launchctl", "unload", plistPath]).exited;
|
|
@@ -13403,9 +13435,9 @@ function getSyncScheduleStatus() {
|
|
|
13403
13435
|
let mechanism = "none";
|
|
13404
13436
|
if (registered) {
|
|
13405
13437
|
if (platform2() === "darwin") {
|
|
13406
|
-
mechanism =
|
|
13438
|
+
mechanism = existsSync7(getLaunchdPlistPath()) ? "launchd" : "none";
|
|
13407
13439
|
} else {
|
|
13408
|
-
mechanism =
|
|
13440
|
+
mechanism = existsSync7(join6(getSystemdDir(), `${SERVICE_NAME}.timer`)) ? "systemd" : "none";
|
|
13409
13441
|
}
|
|
13410
13442
|
}
|
|
13411
13443
|
return {
|
|
@@ -13597,7 +13629,7 @@ function purgeResolvedConflicts(db) {
|
|
|
13597
13629
|
// src/scheduled-sync.ts
|
|
13598
13630
|
init_config();
|
|
13599
13631
|
init_adapter();
|
|
13600
|
-
import { existsSync as
|
|
13632
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
13601
13633
|
import { join as join7 } from "path";
|
|
13602
13634
|
|
|
13603
13635
|
// src/sync-incremental.ts
|
|
@@ -13806,7 +13838,7 @@ function discoverSyncableServices2() {
|
|
|
13806
13838
|
if (!entry.isDirectory())
|
|
13807
13839
|
continue;
|
|
13808
13840
|
const dbPath = join7(hasnaDir, entry.name, `${entry.name}.db`);
|
|
13809
|
-
if (
|
|
13841
|
+
if (existsSync8(dbPath)) {
|
|
13810
13842
|
services.push(entry.name);
|
|
13811
13843
|
}
|
|
13812
13844
|
}
|
|
@@ -13829,7 +13861,7 @@ async function runScheduledSync() {
|
|
|
13829
13861
|
};
|
|
13830
13862
|
try {
|
|
13831
13863
|
const dbPath = join7(getDataDir(service), `${service}.db`);
|
|
13832
|
-
if (!
|
|
13864
|
+
if (!existsSync8(dbPath)) {
|
|
13833
13865
|
continue;
|
|
13834
13866
|
}
|
|
13835
13867
|
const local = new SqliteAdapter(dbPath);
|
|
@@ -13872,7 +13904,7 @@ async function runScheduledSync() {
|
|
|
13872
13904
|
}
|
|
13873
13905
|
|
|
13874
13906
|
// src/cli/cmd-sync.ts
|
|
13875
|
-
import { existsSync as
|
|
13907
|
+
import { existsSync as existsSync10, statSync as statSync5 } from "fs";
|
|
13876
13908
|
import { join as join9 } from "path";
|
|
13877
13909
|
import { homedir as homedir8 } from "os";
|
|
13878
13910
|
|
|
@@ -13883,9 +13915,9 @@ init_discover();
|
|
|
13883
13915
|
init_dotfile();
|
|
13884
13916
|
import { spawn as spawn2 } from "child_process";
|
|
13885
13917
|
import {
|
|
13886
|
-
existsSync as
|
|
13918
|
+
existsSync as existsSync9,
|
|
13887
13919
|
mkdirSync as mkdirSync4,
|
|
13888
|
-
readFileSync as
|
|
13920
|
+
readFileSync as readFileSync4,
|
|
13889
13921
|
statSync as statSync4,
|
|
13890
13922
|
writeFileSync as writeFileSync3
|
|
13891
13923
|
} from "fs";
|
|
@@ -13959,11 +13991,11 @@ function createDefaultDaemonState() {
|
|
|
13959
13991
|
};
|
|
13960
13992
|
}
|
|
13961
13993
|
function readDaemonState() {
|
|
13962
|
-
if (!
|
|
13994
|
+
if (!existsSync9(DAEMON_STATE_PATH)) {
|
|
13963
13995
|
return createDefaultDaemonState();
|
|
13964
13996
|
}
|
|
13965
13997
|
try {
|
|
13966
|
-
const raw = JSON.parse(
|
|
13998
|
+
const raw = JSON.parse(readFileSync4(DAEMON_STATE_PATH, "utf-8"));
|
|
13967
13999
|
const defaults2 = createDefaultDaemonState();
|
|
13968
14000
|
return {
|
|
13969
14001
|
...defaults2,
|
|
@@ -14132,7 +14164,7 @@ function runDaemonPass(config, state = createDefaultDaemonState(), options = {})
|
|
|
14132
14164
|
}
|
|
14133
14165
|
for (const service of services) {
|
|
14134
14166
|
const dbPath = adapterFactory.getLocalDbPath(service);
|
|
14135
|
-
if (!
|
|
14167
|
+
if (!existsSync9(dbPath))
|
|
14136
14168
|
continue;
|
|
14137
14169
|
const serviceState = getServiceState(nextState, service);
|
|
14138
14170
|
let local = null;
|
|
@@ -14632,7 +14664,7 @@ function registerStatusCommand(syncCmd) {
|
|
|
14632
14664
|
const statuses = [];
|
|
14633
14665
|
for (const service of services) {
|
|
14634
14666
|
const dbPath = getDbPath(service);
|
|
14635
|
-
const localExists =
|
|
14667
|
+
const localExists = existsSync10(dbPath);
|
|
14636
14668
|
let localSize = "—";
|
|
14637
14669
|
let tableCount = 0;
|
|
14638
14670
|
if (localExists) {
|
|
@@ -15124,14 +15156,14 @@ function registerFeedbackCommand(program3) {
|
|
|
15124
15156
|
init_config();
|
|
15125
15157
|
init_adapter();
|
|
15126
15158
|
init_discover();
|
|
15127
|
-
import { existsSync as
|
|
15159
|
+
import { existsSync as existsSync11 } from "fs";
|
|
15128
15160
|
import { join as join10 } from "path";
|
|
15129
15161
|
import { homedir as homedir9 } from "os";
|
|
15130
15162
|
function registerDoctorCommand(program3) {
|
|
15131
15163
|
program3.command("doctor").description("Comprehensive health check for cloud sync setup").action(async () => {
|
|
15132
15164
|
const checks = [];
|
|
15133
15165
|
const configPath = join10(homedir9(), ".hasna", "cloud", "config.json");
|
|
15134
|
-
checks.push(
|
|
15166
|
+
checks.push(existsSync11(configPath) ? { name: "Config file", status: "pass", detail: configPath } : { name: "Config file", status: "fail", detail: "Missing. Run `cloud setup`." });
|
|
15135
15167
|
const config = getCloudConfig();
|
|
15136
15168
|
checks.push(config.mode === "hybrid" || config.mode === "cloud" ? { name: "Sync mode", status: "pass", detail: config.mode } : { name: "Sync mode", status: "fail", detail: `"${config.mode}" — sync disabled. Run \`cloud setup --mode hybrid\`.` });
|
|
15137
15169
|
checks.push(config.rds.host ? { name: "RDS host", status: "pass", detail: config.rds.host } : { name: "RDS host", status: "fail", detail: "Not configured. Run `cloud setup`." });
|
|
@@ -15150,7 +15182,7 @@ function registerDoctorCommand(program3) {
|
|
|
15150
15182
|
checks.push({ name: "PG connection", status: "fail", detail: "Skipped — missing host or password" });
|
|
15151
15183
|
}
|
|
15152
15184
|
const caPath = process.env.NODE_EXTRA_CA_CERTS;
|
|
15153
|
-
if (caPath &&
|
|
15185
|
+
if (caPath && existsSync11(caPath)) {
|
|
15154
15186
|
checks.push({ name: "SSL CA cert", status: "pass", detail: caPath });
|
|
15155
15187
|
} else if (caPath) {
|
|
15156
15188
|
checks.push({ name: "SSL CA cert", status: "warn", detail: `NODE_EXTRA_CA_CERTS set but file missing: ${caPath}` });
|
|
@@ -15191,7 +15223,7 @@ init_zod();
|
|
|
15191
15223
|
init_adapter();
|
|
15192
15224
|
init_dotfile();
|
|
15193
15225
|
init_machines();
|
|
15194
|
-
import { existsSync as
|
|
15226
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
15195
15227
|
import { homedir as homedir10 } from "os";
|
|
15196
15228
|
import { join as join11 } from "path";
|
|
15197
15229
|
var DaemonConfigSchema2 = exports_external.object({
|
|
@@ -15217,7 +15249,7 @@ var CloudConfigSchema2 = exports_external.object({
|
|
|
15217
15249
|
password_env: exports_external.string().default("HASNA_RDS_PASSWORD"),
|
|
15218
15250
|
ssl: exports_external.boolean().default(true)
|
|
15219
15251
|
}).default({}),
|
|
15220
|
-
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("
|
|
15252
|
+
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("local"),
|
|
15221
15253
|
auto_sync_interval_minutes: exports_external.number().default(0),
|
|
15222
15254
|
feedback_endpoint: exports_external.string().default("https://feedback.hasna.com/api/v1/feedback"),
|
|
15223
15255
|
sync: exports_external.object({
|
|
@@ -15228,11 +15260,11 @@ var CloudConfigSchema2 = exports_external.object({
|
|
|
15228
15260
|
var CONFIG_DIR3 = join11(homedir10(), ".hasna", "cloud");
|
|
15229
15261
|
var CONFIG_PATH2 = join11(CONFIG_DIR3, "config.json");
|
|
15230
15262
|
function getCloudConfig2() {
|
|
15231
|
-
if (!
|
|
15263
|
+
if (!existsSync12(CONFIG_PATH2)) {
|
|
15232
15264
|
return CloudConfigSchema2.parse({});
|
|
15233
15265
|
}
|
|
15234
15266
|
try {
|
|
15235
|
-
const raw =
|
|
15267
|
+
const raw = readFileSync5(CONFIG_PATH2, "utf-8");
|
|
15236
15268
|
return CloudConfigSchema2.parse(JSON.parse(raw));
|
|
15237
15269
|
} catch {
|
|
15238
15270
|
return CloudConfigSchema2.parse({});
|
|
@@ -15248,8 +15280,15 @@ function getConnectionString2(dbName) {
|
|
|
15248
15280
|
if (password === undefined || password === "") {
|
|
15249
15281
|
throw new Error(`RDS password not set. Export ${password_env} in your shell or add it to ~/.secrets/hasna/rds/live.env`);
|
|
15250
15282
|
}
|
|
15251
|
-
const
|
|
15252
|
-
|
|
15283
|
+
const url = new URL("postgres:" + "//placeholder");
|
|
15284
|
+
url.hostname = host;
|
|
15285
|
+
url.port = String(port);
|
|
15286
|
+
url.username = username;
|
|
15287
|
+
url.password = password;
|
|
15288
|
+
url.pathname = `/${dbName}`;
|
|
15289
|
+
if (ssl)
|
|
15290
|
+
url.searchParams.set("sslmode", "require");
|
|
15291
|
+
return url.toString();
|
|
15253
15292
|
}
|
|
15254
15293
|
|
|
15255
15294
|
// src/adapter.ts
|
|
@@ -15313,7 +15352,7 @@ class PgAdapterAsync2 {
|
|
|
15313
15352
|
|
|
15314
15353
|
// src/cli/index.ts
|
|
15315
15354
|
var program3 = new Command;
|
|
15316
|
-
program3.name("cloud").description("Shared cloud infrastructure \u2014 database adapter, sync engine, feedback, dotfile migration").version(
|
|
15355
|
+
program3.name("cloud").description("Shared cloud infrastructure \u2014 database adapter, sync engine, feedback, dotfile migration").version(getPackageVersion());
|
|
15317
15356
|
registerEventsCommands(program3, { source: "cloud" });
|
|
15318
15357
|
registerSetupCommand(program3);
|
|
15319
15358
|
program3.command("status").description("Show current cloud configuration and connection health").action(async () => {
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwBV,CAAC;AAMf,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AASnE,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAMD,wBAAgB,cAAc,IAAI,WAAW,CAU5C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGzD;AAMD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwBV,CAAC;AAMf,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqB5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAC5D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AASnE,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAMD,wBAAgB,cAAc,IAAI,WAAW,CAU5C;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,CAGzD;AAMD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CA0B1D;AAQD,OAAO,EAEL,KAAK,qBAAqB,EAC3B,MAAM,eAAe,CAAC;AAEvB,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,iCAAiC;IACjC,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpC,qCAAqC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yCAAyC;IACzC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,qBAAqB,GAC7B,qBAAqB,CAavB"}
|
package/dist/index.js
CHANGED
|
@@ -9827,8 +9827,15 @@ function getConnectionString(dbName) {
|
|
|
9827
9827
|
if (password === undefined || password === "") {
|
|
9828
9828
|
throw new Error(`RDS password not set. Export ${password_env} in your shell or add it to ~/.secrets/hasna/rds/live.env`);
|
|
9829
9829
|
}
|
|
9830
|
-
const
|
|
9831
|
-
|
|
9830
|
+
const url = new URL("postgres:" + "//placeholder");
|
|
9831
|
+
url.hostname = host;
|
|
9832
|
+
url.port = String(port);
|
|
9833
|
+
url.username = username;
|
|
9834
|
+
url.password = password;
|
|
9835
|
+
url.pathname = `/${dbName}`;
|
|
9836
|
+
if (ssl)
|
|
9837
|
+
url.searchParams.set("sslmode", "require");
|
|
9838
|
+
return url.toString();
|
|
9832
9839
|
}
|
|
9833
9840
|
function createDatabase(options) {
|
|
9834
9841
|
const config = getCloudConfig();
|
|
@@ -9869,7 +9876,7 @@ var init_config = __esm(() => {
|
|
|
9869
9876
|
password_env: exports_external.string().default("HASNA_RDS_PASSWORD"),
|
|
9870
9877
|
ssl: exports_external.boolean().default(true)
|
|
9871
9878
|
}).default({}),
|
|
9872
|
-
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("
|
|
9879
|
+
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("local"),
|
|
9873
9880
|
auto_sync_interval_minutes: exports_external.number().default(0),
|
|
9874
9881
|
feedback_endpoint: exports_external.string().default("https://feedback.hasna.com/api/v1/feedback"),
|
|
9875
9882
|
sync: exports_external.object({
|
package/dist/mcp/bin.js
CHANGED
|
@@ -16257,8 +16257,15 @@ function getConnectionString(dbName) {
|
|
|
16257
16257
|
if (password === undefined || password === "") {
|
|
16258
16258
|
throw new Error(`RDS password not set. Export ${password_env} in your shell or add it to ~/.secrets/hasna/rds/live.env`);
|
|
16259
16259
|
}
|
|
16260
|
-
const
|
|
16261
|
-
|
|
16260
|
+
const url = new URL("postgres:" + "//placeholder");
|
|
16261
|
+
url.hostname = host;
|
|
16262
|
+
url.port = String(port);
|
|
16263
|
+
url.username = username;
|
|
16264
|
+
url.password = password;
|
|
16265
|
+
url.pathname = `/${dbName}`;
|
|
16266
|
+
if (ssl)
|
|
16267
|
+
url.searchParams.set("sslmode", "require");
|
|
16268
|
+
return url.toString();
|
|
16262
16269
|
}
|
|
16263
16270
|
function createDatabase(options) {
|
|
16264
16271
|
const config2 = getCloudConfig();
|
|
@@ -16299,7 +16306,7 @@ var init_config = __esm(() => {
|
|
|
16299
16306
|
password_env: exports_external.string().default("HASNA_RDS_PASSWORD"),
|
|
16300
16307
|
ssl: exports_external.boolean().default(true)
|
|
16301
16308
|
}).default({}),
|
|
16302
|
-
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("
|
|
16309
|
+
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("local"),
|
|
16303
16310
|
auto_sync_interval_minutes: exports_external.number().default(0),
|
|
16304
16311
|
feedback_endpoint: exports_external.string().default("https://feedback.hasna.com/api/v1/feedback"),
|
|
16305
16312
|
sync: exports_external.object({
|
|
@@ -25964,6 +25971,31 @@ async function sendFeedback(feedback, db) {
|
|
|
25964
25971
|
init_dotfile();
|
|
25965
25972
|
init_adapter();
|
|
25966
25973
|
|
|
25974
|
+
// src/version.ts
|
|
25975
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
|
|
25976
|
+
import { dirname as dirname2, resolve } from "node:path";
|
|
25977
|
+
import { fileURLToPath } from "node:url";
|
|
25978
|
+
var cachedPackageVersion;
|
|
25979
|
+
function getPackageVersion() {
|
|
25980
|
+
if (cachedPackageVersion)
|
|
25981
|
+
return cachedPackageVersion;
|
|
25982
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
25983
|
+
const candidates = [
|
|
25984
|
+
resolve(here, "../package.json"),
|
|
25985
|
+
resolve(here, "../../package.json")
|
|
25986
|
+
];
|
|
25987
|
+
for (const path of candidates) {
|
|
25988
|
+
if (!existsSync5(path))
|
|
25989
|
+
continue;
|
|
25990
|
+
const pkg = JSON.parse(readFileSync2(path, "utf8"));
|
|
25991
|
+
if (typeof pkg.version === "string" && pkg.version.length > 0) {
|
|
25992
|
+
cachedPackageVersion = pkg.version;
|
|
25993
|
+
return cachedPackageVersion;
|
|
25994
|
+
}
|
|
25995
|
+
}
|
|
25996
|
+
throw new Error("Unable to resolve @hasna/cloud package version");
|
|
25997
|
+
}
|
|
25998
|
+
|
|
25967
25999
|
// src/mcp/http.ts
|
|
25968
26000
|
import { createServer } from "node:http";
|
|
25969
26001
|
|
|
@@ -26378,7 +26410,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
26378
26410
|
});
|
|
26379
26411
|
if (!chunk) {
|
|
26380
26412
|
if (i === 1) {
|
|
26381
|
-
await new Promise((
|
|
26413
|
+
await new Promise((resolve2) => setTimeout(resolve2));
|
|
26382
26414
|
maxReadCount = 3;
|
|
26383
26415
|
continue;
|
|
26384
26416
|
}
|
|
@@ -26829,9 +26861,9 @@ data:
|
|
|
26829
26861
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
26830
26862
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
26831
26863
|
if (this._enableJsonResponse) {
|
|
26832
|
-
return new Promise((
|
|
26864
|
+
return new Promise((resolve2) => {
|
|
26833
26865
|
this._streamMapping.set(streamId, {
|
|
26834
|
-
resolveJson:
|
|
26866
|
+
resolveJson: resolve2,
|
|
26835
26867
|
cleanup: () => {
|
|
26836
26868
|
this._streamMapping.delete(streamId);
|
|
26837
26869
|
}
|
|
@@ -27098,7 +27130,7 @@ init_adapter();
|
|
|
27098
27130
|
function buildServer() {
|
|
27099
27131
|
const server = new McpServer({
|
|
27100
27132
|
name: "cloud",
|
|
27101
|
-
version:
|
|
27133
|
+
version: getPackageVersion()
|
|
27102
27134
|
});
|
|
27103
27135
|
server.tool("cloud_status", "Show cloud configuration and connection health", {}, async () => {
|
|
27104
27136
|
const config2 = getCloudConfig();
|
|
@@ -27466,16 +27498,16 @@ async function startMcpHttpServer(options = {}) {
|
|
|
27466
27498
|
res.writeHead(404);
|
|
27467
27499
|
res.end("Not found");
|
|
27468
27500
|
});
|
|
27469
|
-
await new Promise((
|
|
27501
|
+
await new Promise((resolve2, reject) => {
|
|
27470
27502
|
httpServer.once("error", reject);
|
|
27471
|
-
httpServer.listen(port, host, () =>
|
|
27503
|
+
httpServer.listen(port, host, () => resolve2());
|
|
27472
27504
|
});
|
|
27473
27505
|
const address = httpServer.address();
|
|
27474
27506
|
const boundPort = typeof address === "object" && address ? address.port : port;
|
|
27475
27507
|
return {
|
|
27476
27508
|
port: boundPort,
|
|
27477
|
-
close: () => new Promise((
|
|
27478
|
-
httpServer.close((err) => err ? reject(err) :
|
|
27509
|
+
close: () => new Promise((resolve2, reject) => {
|
|
27510
|
+
httpServer.close((err) => err ? reject(err) : resolve2());
|
|
27479
27511
|
})
|
|
27480
27512
|
};
|
|
27481
27513
|
}
|
|
@@ -27489,7 +27521,7 @@ async function runMcpHttpServer(options = {}) {
|
|
|
27489
27521
|
function buildServer2() {
|
|
27490
27522
|
const server = new McpServer({
|
|
27491
27523
|
name: "cloud",
|
|
27492
|
-
version:
|
|
27524
|
+
version: getPackageVersion()
|
|
27493
27525
|
});
|
|
27494
27526
|
server.tool("cloud_status", "Show cloud configuration and connection health", {}, async () => {
|
|
27495
27527
|
const config2 = getCloudConfig();
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAepE,wBAAgB,WAAW,IAAI,SAAS,CAwVvC;AAED,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAW1C"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -16257,8 +16257,15 @@ function getConnectionString2(dbName) {
|
|
|
16257
16257
|
if (password === undefined || password === "") {
|
|
16258
16258
|
throw new Error(`RDS password not set. Export ${password_env} in your shell or add it to ~/.secrets/hasna/rds/live.env`);
|
|
16259
16259
|
}
|
|
16260
|
-
const
|
|
16261
|
-
|
|
16260
|
+
const url = new URL("postgres:" + "//placeholder");
|
|
16261
|
+
url.hostname = host;
|
|
16262
|
+
url.port = String(port);
|
|
16263
|
+
url.username = username;
|
|
16264
|
+
url.password = password;
|
|
16265
|
+
url.pathname = `/${dbName}`;
|
|
16266
|
+
if (ssl)
|
|
16267
|
+
url.searchParams.set("sslmode", "require");
|
|
16268
|
+
return url.toString();
|
|
16262
16269
|
}
|
|
16263
16270
|
function createDatabase2(options) {
|
|
16264
16271
|
const config2 = getCloudConfig2();
|
|
@@ -16299,7 +16306,7 @@ var init_config = __esm(() => {
|
|
|
16299
16306
|
password_env: exports_external.string().default("HASNA_RDS_PASSWORD"),
|
|
16300
16307
|
ssl: exports_external.boolean().default(true)
|
|
16301
16308
|
}).default({}),
|
|
16302
|
-
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("
|
|
16309
|
+
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("local"),
|
|
16303
16310
|
auto_sync_interval_minutes: exports_external.number().default(0),
|
|
16304
16311
|
feedback_endpoint: exports_external.string().default("https://feedback.hasna.com/api/v1/feedback"),
|
|
16305
16312
|
sync: exports_external.object({
|
|
@@ -16321,7 +16328,7 @@ __export(exports_discover2, {
|
|
|
16321
16328
|
SYNC_EXCLUDED_TABLE_PATTERNS: () => SYNC_EXCLUDED_TABLE_PATTERNS2,
|
|
16322
16329
|
KNOWN_PG_SERVICES: () => KNOWN_PG_SERVICES2
|
|
16323
16330
|
});
|
|
16324
|
-
import { readdirSync as readdirSync4, existsSync as
|
|
16331
|
+
import { readdirSync as readdirSync4, existsSync as existsSync8 } from "fs";
|
|
16325
16332
|
import { join as join7 } from "path";
|
|
16326
16333
|
import { homedir as homedir7 } from "os";
|
|
16327
16334
|
function isSyncExcludedTable2(table) {
|
|
@@ -16329,7 +16336,7 @@ function isSyncExcludedTable2(table) {
|
|
|
16329
16336
|
}
|
|
16330
16337
|
function discoverServices2() {
|
|
16331
16338
|
const dataDir = join7(homedir7(), ".hasna");
|
|
16332
|
-
if (!
|
|
16339
|
+
if (!existsSync8(dataDir))
|
|
16333
16340
|
return [];
|
|
16334
16341
|
try {
|
|
16335
16342
|
const entries = readdirSync4(dataDir, { withFileTypes: true });
|
|
@@ -16351,7 +16358,7 @@ function discoverSyncableServices2() {
|
|
|
16351
16358
|
}
|
|
16352
16359
|
function getServiceDbPath2(service) {
|
|
16353
16360
|
const dataDir = join7(homedir7(), ".hasna", service);
|
|
16354
|
-
if (!
|
|
16361
|
+
if (!existsSync8(dataDir))
|
|
16355
16362
|
return null;
|
|
16356
16363
|
const candidates = [
|
|
16357
16364
|
join7(dataDir, `${service}.db`),
|
|
@@ -16367,7 +16374,7 @@ function getServiceDbPath2(service) {
|
|
|
16367
16374
|
}
|
|
16368
16375
|
} catch {}
|
|
16369
16376
|
for (const p of candidates) {
|
|
16370
|
-
if (
|
|
16377
|
+
if (existsSync8(p))
|
|
16371
16378
|
return p;
|
|
16372
16379
|
}
|
|
16373
16380
|
return null;
|
|
@@ -25584,7 +25591,7 @@ var CloudConfigSchema = exports_external.object({
|
|
|
25584
25591
|
password_env: exports_external.string().default("HASNA_RDS_PASSWORD"),
|
|
25585
25592
|
ssl: exports_external.boolean().default(true)
|
|
25586
25593
|
}).default({}),
|
|
25587
|
-
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("
|
|
25594
|
+
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("local"),
|
|
25588
25595
|
auto_sync_interval_minutes: exports_external.number().default(0),
|
|
25589
25596
|
feedback_endpoint: exports_external.string().default("https://feedback.hasna.com/api/v1/feedback"),
|
|
25590
25597
|
sync: exports_external.object({
|
|
@@ -25615,8 +25622,15 @@ function getConnectionString(dbName) {
|
|
|
25615
25622
|
if (password === undefined || password === "") {
|
|
25616
25623
|
throw new Error(`RDS password not set. Export ${password_env} in your shell or add it to ~/.secrets/hasna/rds/live.env`);
|
|
25617
25624
|
}
|
|
25618
|
-
const
|
|
25619
|
-
|
|
25625
|
+
const url = new URL("postgres:" + "//placeholder");
|
|
25626
|
+
url.hostname = host;
|
|
25627
|
+
url.port = String(port);
|
|
25628
|
+
url.username = username;
|
|
25629
|
+
url.password = password;
|
|
25630
|
+
url.pathname = `/${dbName}`;
|
|
25631
|
+
if (ssl)
|
|
25632
|
+
url.searchParams.set("sslmode", "require");
|
|
25633
|
+
return url.toString();
|
|
25620
25634
|
}
|
|
25621
25635
|
function createDatabase(options) {
|
|
25622
25636
|
const config2 = getCloudConfig();
|
|
@@ -26284,6 +26298,31 @@ class PgAdapterAsync2 {
|
|
|
26284
26298
|
}
|
|
26285
26299
|
}
|
|
26286
26300
|
|
|
26301
|
+
// src/version.ts
|
|
26302
|
+
import { existsSync as existsSync7, readFileSync as readFileSync3 } from "node:fs";
|
|
26303
|
+
import { dirname as dirname2, resolve } from "node:path";
|
|
26304
|
+
import { fileURLToPath } from "node:url";
|
|
26305
|
+
var cachedPackageVersion;
|
|
26306
|
+
function getPackageVersion() {
|
|
26307
|
+
if (cachedPackageVersion)
|
|
26308
|
+
return cachedPackageVersion;
|
|
26309
|
+
const here = dirname2(fileURLToPath(import.meta.url));
|
|
26310
|
+
const candidates = [
|
|
26311
|
+
resolve(here, "../package.json"),
|
|
26312
|
+
resolve(here, "../../package.json")
|
|
26313
|
+
];
|
|
26314
|
+
for (const path of candidates) {
|
|
26315
|
+
if (!existsSync7(path))
|
|
26316
|
+
continue;
|
|
26317
|
+
const pkg = JSON.parse(readFileSync3(path, "utf8"));
|
|
26318
|
+
if (typeof pkg.version === "string" && pkg.version.length > 0) {
|
|
26319
|
+
cachedPackageVersion = pkg.version;
|
|
26320
|
+
return cachedPackageVersion;
|
|
26321
|
+
}
|
|
26322
|
+
}
|
|
26323
|
+
throw new Error("Unable to resolve @hasna/cloud package version");
|
|
26324
|
+
}
|
|
26325
|
+
|
|
26287
26326
|
// src/mcp/http.ts
|
|
26288
26327
|
import { createServer } from "node:http";
|
|
26289
26328
|
|
|
@@ -26698,7 +26737,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
26698
26737
|
});
|
|
26699
26738
|
if (!chunk) {
|
|
26700
26739
|
if (i === 1) {
|
|
26701
|
-
await new Promise((
|
|
26740
|
+
await new Promise((resolve2) => setTimeout(resolve2));
|
|
26702
26741
|
maxReadCount = 3;
|
|
26703
26742
|
continue;
|
|
26704
26743
|
}
|
|
@@ -27149,9 +27188,9 @@ data:
|
|
|
27149
27188
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
27150
27189
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
27151
27190
|
if (this._enableJsonResponse) {
|
|
27152
|
-
return new Promise((
|
|
27191
|
+
return new Promise((resolve2) => {
|
|
27153
27192
|
this._streamMapping.set(streamId, {
|
|
27154
|
-
resolveJson:
|
|
27193
|
+
resolveJson: resolve2,
|
|
27155
27194
|
cleanup: () => {
|
|
27156
27195
|
this._streamMapping.delete(streamId);
|
|
27157
27196
|
}
|
|
@@ -27505,16 +27544,16 @@ async function startMcpHttpServer(options = {}) {
|
|
|
27505
27544
|
res.writeHead(404);
|
|
27506
27545
|
res.end("Not found");
|
|
27507
27546
|
});
|
|
27508
|
-
await new Promise((
|
|
27547
|
+
await new Promise((resolve2, reject) => {
|
|
27509
27548
|
httpServer.once("error", reject);
|
|
27510
|
-
httpServer.listen(port, host, () =>
|
|
27549
|
+
httpServer.listen(port, host, () => resolve2());
|
|
27511
27550
|
});
|
|
27512
27551
|
const address = httpServer.address();
|
|
27513
27552
|
const boundPort = typeof address === "object" && address ? address.port : port;
|
|
27514
27553
|
return {
|
|
27515
27554
|
port: boundPort,
|
|
27516
|
-
close: () => new Promise((
|
|
27517
|
-
httpServer.close((err) => err ? reject(err) :
|
|
27555
|
+
close: () => new Promise((resolve2, reject) => {
|
|
27556
|
+
httpServer.close((err) => err ? reject(err) : resolve2());
|
|
27518
27557
|
})
|
|
27519
27558
|
};
|
|
27520
27559
|
}
|
|
@@ -27528,7 +27567,7 @@ async function runMcpHttpServer(options = {}) {
|
|
|
27528
27567
|
function buildServer() {
|
|
27529
27568
|
const server = new McpServer({
|
|
27530
27569
|
name: "cloud",
|
|
27531
|
-
version:
|
|
27570
|
+
version: getPackageVersion()
|
|
27532
27571
|
});
|
|
27533
27572
|
server.tool("cloud_status", "Show cloud configuration and connection health", {}, async () => {
|
|
27534
27573
|
const config2 = getCloudConfig();
|
package/dist/scheduled-sync.js
CHANGED
|
@@ -9252,7 +9252,7 @@ var CloudConfigSchema = exports_external.object({
|
|
|
9252
9252
|
password_env: exports_external.string().default("HASNA_RDS_PASSWORD"),
|
|
9253
9253
|
ssl: exports_external.boolean().default(true)
|
|
9254
9254
|
}).default({}),
|
|
9255
|
-
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("
|
|
9255
|
+
mode: exports_external.enum(["local", "cloud", "hybrid"]).default("local"),
|
|
9256
9256
|
auto_sync_interval_minutes: exports_external.number().default(0),
|
|
9257
9257
|
feedback_endpoint: exports_external.string().default("https://feedback.hasna.com/api/v1/feedback"),
|
|
9258
9258
|
sync: exports_external.object({
|
|
@@ -9283,8 +9283,15 @@ function getConnectionString(dbName) {
|
|
|
9283
9283
|
if (password === undefined || password === "") {
|
|
9284
9284
|
throw new Error(`RDS password not set. Export ${password_env} in your shell or add it to ~/.secrets/hasna/rds/live.env`);
|
|
9285
9285
|
}
|
|
9286
|
-
const
|
|
9287
|
-
|
|
9286
|
+
const url = new URL("postgres:" + "//placeholder");
|
|
9287
|
+
url.hostname = host;
|
|
9288
|
+
url.port = String(port);
|
|
9289
|
+
url.username = username;
|
|
9290
|
+
url.password = password;
|
|
9291
|
+
url.pathname = `/${dbName}`;
|
|
9292
|
+
if (ssl)
|
|
9293
|
+
url.searchParams.set("sslmode", "require");
|
|
9294
|
+
return url.toString();
|
|
9288
9295
|
}
|
|
9289
9296
|
|
|
9290
9297
|
// src/sync-incremental.ts
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAMA,wBAAgB,iBAAiB,IAAI,MAAM,CAmB1C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/cloud",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
4
4
|
"description": "Shared cloud infrastructure — database adapter (SQLite + PostgreSQL), sync engine, feedback system, unified dotfile config",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -24,8 +24,7 @@
|
|
|
24
24
|
"build": "bun build src/index.ts --outdir dist --target node && bun build src/cli/index.ts --outdir dist/cli --target node && bun build src/mcp/index.ts --outdir dist/mcp --target node && bun build src/mcp/bin.ts --outfile dist/mcp/bin.js --target node && chmod +x dist/mcp/bin.js && bun build src/scheduled-sync.ts --outdir dist --target node && bun run build:types",
|
|
25
25
|
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
26
26
|
"test": "bun test",
|
|
27
|
-
"prepublishOnly": "bun run build"
|
|
28
|
-
"postinstall": "mkdir -p $HOME/.hasna/cloud 2>/dev/null || true; test -f $HOME/.hasna/cloud/config.json || printf '{\"rds\":{\"host\":\"hasnaxyz-prod-opensource.c4limg0qgqvk.us-east-1.rds.amazonaws.com\",\"port\":5432,\"username\":\"\",\"password_env\":\"HASNA_RDS_PASSWORD\",\"ssl\":true},\"mode\":\"local\",\"feedback_endpoint\":\"https://feedback.hasna.com/api/v1/feedback\",\"auto_sync_interval_minutes\":0,\"sync\":{\"schedule_minutes\":0}}\\n' > $HOME/.hasna/cloud/config.json 2>/dev/null || true"
|
|
27
|
+
"prepublishOnly": "bun run build"
|
|
29
28
|
},
|
|
30
29
|
"publishConfig": {
|
|
31
30
|
"registry": "https://registry.npmjs.org",
|