@hasna/sandboxes 0.1.29 → 0.1.30
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 +8 -8
- package/dist/cli/index.js +130 -65
- package/dist/cli/storage.d.ts +2 -0
- package/dist/db/pg-migrations.d.ts +1 -1
- package/dist/db/storage-config.d.ts +26 -0
- package/dist/db/storage-sync.d.ts +35 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +136 -57
- package/dist/mcp/index.js +125 -60
- package/dist/mcp/storage-tools.d.ts +2 -0
- package/dist/server/index.js +126 -61
- package/dist/storage.d.ts +6 -0
- package/dist/storage.js +5654 -0
- package/package.json +6 -2
- package/dist/cli/cloud.d.ts +0 -2
- package/dist/db/cloud-config.d.ts +0 -13
- package/dist/db/cloud-sync.d.ts +0 -29
- package/dist/mcp/cloud-tools.d.ts +0 -2
package/dist/server/index.js
CHANGED
|
@@ -12443,6 +12443,17 @@ INSERT OR IGNORE INTO _migrations (id) VALUES (6);
|
|
|
12443
12443
|
`
|
|
12444
12444
|
ALTER TABLE agents ADD COLUMN active_project_id TEXT REFERENCES projects(id) ON DELETE SET NULL;
|
|
12445
12445
|
INSERT OR IGNORE INTO _migrations (id) VALUES (7);
|
|
12446
|
+
`,
|
|
12447
|
+
`
|
|
12448
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_status_created ON sandboxes(status, created_at DESC);
|
|
12449
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_provider_created ON sandboxes(provider, created_at DESC);
|
|
12450
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_project_created ON sandboxes(project_id, created_at DESC);
|
|
12451
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_started ON sandbox_sessions(sandbox_id, started_at DESC);
|
|
12452
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_started ON sandbox_sessions(status, started_at DESC);
|
|
12453
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_status_started ON sandbox_sessions(sandbox_id, status, started_at DESC);
|
|
12454
|
+
CREATE INDEX IF NOT EXISTS idx_events_sandbox_created ON sandbox_events(sandbox_id, created_at ASC);
|
|
12455
|
+
CREATE INDEX IF NOT EXISTS idx_events_session_created ON sandbox_events(session_id, created_at ASC);
|
|
12456
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (8);
|
|
12446
12457
|
`
|
|
12447
12458
|
];
|
|
12448
12459
|
var db = null;
|
|
@@ -12473,16 +12484,26 @@ function uuid() {
|
|
|
12473
12484
|
function now() {
|
|
12474
12485
|
return new Date().toISOString().replace("T", " ").replace("Z", "");
|
|
12475
12486
|
}
|
|
12487
|
+
var PARTIAL_ID_TABLES = new Set([
|
|
12488
|
+
"agents",
|
|
12489
|
+
"projects",
|
|
12490
|
+
"sandbox_sessions",
|
|
12491
|
+
"sandboxes",
|
|
12492
|
+
"snapshots",
|
|
12493
|
+
"templates",
|
|
12494
|
+
"webhooks"
|
|
12495
|
+
]);
|
|
12476
12496
|
function resolvePartialId(table, partialId) {
|
|
12497
|
+
if (!PARTIAL_ID_TABLES.has(table)) {
|
|
12498
|
+
throw new Error(`Invalid partial-id table: ${table}`);
|
|
12499
|
+
}
|
|
12477
12500
|
const database = getDatabase();
|
|
12478
|
-
const
|
|
12479
|
-
if (rows.length === 1)
|
|
12480
|
-
return rows[0].id;
|
|
12481
|
-
if (rows.length === 0)
|
|
12482
|
-
return null;
|
|
12483
|
-
const exact = rows.find((r) => r.id === partialId);
|
|
12501
|
+
const exact = database.query(`SELECT id FROM ${table} WHERE id = ?`).get(partialId);
|
|
12484
12502
|
if (exact)
|
|
12485
12503
|
return exact.id;
|
|
12504
|
+
const rows = database.query(`SELECT id FROM ${table} WHERE id LIKE ? ORDER BY id LIMIT 2`).all(`${partialId}%`);
|
|
12505
|
+
if (rows.length === 1)
|
|
12506
|
+
return rows[0].id;
|
|
12486
12507
|
return null;
|
|
12487
12508
|
}
|
|
12488
12509
|
|
|
@@ -12707,7 +12728,7 @@ function listEvents(opts) {
|
|
|
12707
12728
|
const where = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
12708
12729
|
const limit = opts?.limit ?? 100;
|
|
12709
12730
|
const offset = opts?.offset ?? 0;
|
|
12710
|
-
const rows = db2.query(`SELECT * FROM sandbox_events${where} ORDER BY created_at ASC LIMIT ? OFFSET ?`).all(...[...params, limit, offset]);
|
|
12731
|
+
const rows = db2.query(`SELECT * FROM sandbox_events${where} ORDER BY created_at ASC, rowid ASC LIMIT ? OFFSET ?`).all(...[...params, limit, offset]);
|
|
12711
12732
|
return rows.map(rowToEvent);
|
|
12712
12733
|
}
|
|
12713
12734
|
|
|
@@ -16586,7 +16607,7 @@ class JSONSchemaGenerator {
|
|
|
16586
16607
|
if (val === undefined) {
|
|
16587
16608
|
if (this.unrepresentable === "throw") {
|
|
16588
16609
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
16589
|
-
}
|
|
16610
|
+
}
|
|
16590
16611
|
} else if (typeof val === "bigint") {
|
|
16591
16612
|
if (this.unrepresentable === "throw") {
|
|
16592
16613
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|
|
@@ -27035,55 +27056,80 @@ function getBuiltinImageSetupScript(image) {
|
|
|
27035
27056
|
return BUILTIN_IMAGES[image]?.setup_script;
|
|
27036
27057
|
}
|
|
27037
27058
|
|
|
27038
|
-
// src/db/
|
|
27059
|
+
// src/db/storage-config.ts
|
|
27039
27060
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
27040
27061
|
import { homedir } from "os";
|
|
27041
27062
|
import { join as join4 } from "path";
|
|
27042
|
-
var
|
|
27043
|
-
|
|
27044
|
-
|
|
27063
|
+
var STORAGE_CONFIG_PATH = join4(homedir(), ".hasna", "sandboxes", "storage", "config.json");
|
|
27064
|
+
var SANDBOXES_STORAGE_ENV = "HASNA_SANDBOXES_DATABASE_URL";
|
|
27065
|
+
var SANDBOXES_STORAGE_FALLBACK_ENV = "SANDBOXES_DATABASE_URL";
|
|
27066
|
+
var SANDBOXES_STORAGE_MODE_ENV = "HASNA_SANDBOXES_STORAGE_MODE";
|
|
27067
|
+
var SANDBOXES_STORAGE_MODE_FALLBACK_ENV = "SANDBOXES_STORAGE_MODE";
|
|
27068
|
+
var STORAGE_DATABASE_ENV = [SANDBOXES_STORAGE_ENV, SANDBOXES_STORAGE_FALLBACK_ENV];
|
|
27069
|
+
function readEnv(name) {
|
|
27070
|
+
const value = process.env[name]?.trim();
|
|
27071
|
+
return value || undefined;
|
|
27072
|
+
}
|
|
27073
|
+
function normalizeStorageMode(value) {
|
|
27074
|
+
const normalized = value?.trim().toLowerCase();
|
|
27075
|
+
if (normalized === "local" || normalized === "hybrid" || normalized === "remote")
|
|
27076
|
+
return normalized;
|
|
27077
|
+
return;
|
|
27078
|
+
}
|
|
27079
|
+
function getStorageDatabaseEnvName() {
|
|
27080
|
+
for (const name of STORAGE_DATABASE_ENV) {
|
|
27081
|
+
if (readEnv(name))
|
|
27082
|
+
return name;
|
|
27083
|
+
}
|
|
27084
|
+
return null;
|
|
27085
|
+
}
|
|
27086
|
+
function getStorageDatabaseEnv() {
|
|
27087
|
+
const name = getStorageDatabaseEnvName();
|
|
27088
|
+
return name ? { name } : null;
|
|
27045
27089
|
}
|
|
27046
|
-
function
|
|
27047
|
-
|
|
27090
|
+
function getStorageDatabaseUrl() {
|
|
27091
|
+
const env = getStorageDatabaseEnv();
|
|
27092
|
+
return env ? readEnv(env.name) : undefined;
|
|
27048
27093
|
}
|
|
27049
|
-
function
|
|
27094
|
+
function getStorageConfig() {
|
|
27050
27095
|
const config2 = {
|
|
27051
27096
|
mode: "local",
|
|
27052
27097
|
rds: {
|
|
27053
27098
|
host: "",
|
|
27054
27099
|
port: 5432,
|
|
27055
27100
|
username: "",
|
|
27056
|
-
password_env: "
|
|
27101
|
+
password_env: "SANDBOXES_DATABASE_PASSWORD",
|
|
27057
27102
|
ssl: true
|
|
27058
27103
|
}
|
|
27059
27104
|
};
|
|
27060
|
-
if (existsSync4(
|
|
27105
|
+
if (existsSync4(STORAGE_CONFIG_PATH)) {
|
|
27061
27106
|
try {
|
|
27062
|
-
const raw = JSON.parse(readFileSync3(
|
|
27063
|
-
config2.mode = raw.mode ?? config2.mode;
|
|
27107
|
+
const raw = JSON.parse(readFileSync3(STORAGE_CONFIG_PATH, "utf-8"));
|
|
27108
|
+
config2.mode = normalizeStorageMode(raw.mode) ?? config2.mode;
|
|
27064
27109
|
config2.rds = { ...config2.rds, ...raw.rds ?? {} };
|
|
27065
27110
|
} catch {}
|
|
27066
27111
|
}
|
|
27067
|
-
const modeOverride =
|
|
27068
|
-
|
|
27069
|
-
|
|
27070
|
-
|
|
27112
|
+
const modeOverride = readEnv(SANDBOXES_STORAGE_MODE_ENV) ?? readEnv(SANDBOXES_STORAGE_MODE_FALLBACK_ENV);
|
|
27113
|
+
const mode = normalizeStorageMode(modeOverride);
|
|
27114
|
+
if (mode) {
|
|
27115
|
+
config2.mode = mode;
|
|
27116
|
+
} else if (getStorageDatabaseUrl() && config2.mode === "local") {
|
|
27071
27117
|
config2.mode = "hybrid";
|
|
27072
27118
|
}
|
|
27073
27119
|
return config2;
|
|
27074
27120
|
}
|
|
27075
|
-
function
|
|
27076
|
-
const direct =
|
|
27121
|
+
function getStorageConnectionString(dbName = "sandboxes") {
|
|
27122
|
+
const direct = getStorageDatabaseUrl();
|
|
27077
27123
|
if (direct)
|
|
27078
27124
|
return direct;
|
|
27079
|
-
const config2 =
|
|
27125
|
+
const config2 = getStorageConfig();
|
|
27080
27126
|
const { host, port, username, password_env, ssl } = config2.rds;
|
|
27081
27127
|
if (!host || !username) {
|
|
27082
|
-
throw new Error("
|
|
27128
|
+
throw new Error("Storage database is not configured. Set HASNA_SANDBOXES_DATABASE_URL or configure ~/.hasna/sandboxes/storage/config.json.");
|
|
27083
27129
|
}
|
|
27084
27130
|
const password = process.env[password_env];
|
|
27085
27131
|
if (!password) {
|
|
27086
|
-
throw new Error(`
|
|
27132
|
+
throw new Error(`Storage database password is not set. Export ${password_env}.`);
|
|
27087
27133
|
}
|
|
27088
27134
|
const sslParam = ssl ? "?sslmode=require" : "";
|
|
27089
27135
|
return `postgres://${username}:${encodeURIComponent(password)}@${host}:${port}/${dbName}${sslParam}`;
|
|
@@ -27179,6 +27225,9 @@ var PG_MIGRATIONS = [
|
|
|
27179
27225
|
`CREATE INDEX IF NOT EXISTS idx_sandboxes_status ON sandboxes(status)`,
|
|
27180
27226
|
`CREATE INDEX IF NOT EXISTS idx_sandboxes_provider ON sandboxes(provider)`,
|
|
27181
27227
|
`CREATE INDEX IF NOT EXISTS idx_sandboxes_project ON sandboxes(project_id)`,
|
|
27228
|
+
`CREATE INDEX IF NOT EXISTS idx_sandboxes_status_created ON sandboxes(status, created_at DESC)`,
|
|
27229
|
+
`CREATE INDEX IF NOT EXISTS idx_sandboxes_provider_created ON sandboxes(provider, created_at DESC)`,
|
|
27230
|
+
`CREATE INDEX IF NOT EXISTS idx_sandboxes_project_created ON sandboxes(project_id, created_at DESC)`,
|
|
27182
27231
|
`CREATE TABLE IF NOT EXISTS sandbox_sessions (
|
|
27183
27232
|
id TEXT PRIMARY KEY,
|
|
27184
27233
|
sandbox_id TEXT NOT NULL REFERENCES sandboxes(id) ON DELETE CASCADE,
|
|
@@ -27192,6 +27241,9 @@ var PG_MIGRATIONS = [
|
|
|
27192
27241
|
)`,
|
|
27193
27242
|
`CREATE INDEX IF NOT EXISTS idx_sessions_sandbox ON sandbox_sessions(sandbox_id)`,
|
|
27194
27243
|
`CREATE INDEX IF NOT EXISTS idx_sessions_status ON sandbox_sessions(status)`,
|
|
27244
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_started ON sandbox_sessions(sandbox_id, started_at DESC)`,
|
|
27245
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_status_started ON sandbox_sessions(status, started_at DESC)`,
|
|
27246
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_status_started ON sandbox_sessions(sandbox_id, status, started_at DESC)`,
|
|
27195
27247
|
`CREATE TABLE IF NOT EXISTS sandbox_events (
|
|
27196
27248
|
id TEXT PRIMARY KEY,
|
|
27197
27249
|
sandbox_id TEXT NOT NULL REFERENCES sandboxes(id) ON DELETE CASCADE,
|
|
@@ -27203,6 +27255,8 @@ var PG_MIGRATIONS = [
|
|
|
27203
27255
|
`CREATE INDEX IF NOT EXISTS idx_events_sandbox ON sandbox_events(sandbox_id)`,
|
|
27204
27256
|
`CREATE INDEX IF NOT EXISTS idx_events_session ON sandbox_events(session_id)`,
|
|
27205
27257
|
`CREATE INDEX IF NOT EXISTS idx_events_type ON sandbox_events(type)`,
|
|
27258
|
+
`CREATE INDEX IF NOT EXISTS idx_events_sandbox_created ON sandbox_events(sandbox_id, created_at ASC)`,
|
|
27259
|
+
`CREATE INDEX IF NOT EXISTS idx_events_session_created ON sandbox_events(session_id, created_at ASC)`,
|
|
27206
27260
|
`CREATE TABLE IF NOT EXISTS webhooks (
|
|
27207
27261
|
id TEXT PRIMARY KEY,
|
|
27208
27262
|
url TEXT NOT NULL,
|
|
@@ -27253,8 +27307,8 @@ var PG_MIGRATIONS = [
|
|
|
27253
27307
|
`ALTER TABLE agents ADD COLUMN IF NOT EXISTS active_project_id TEXT REFERENCES projects(id) ON DELETE SET NULL`
|
|
27254
27308
|
];
|
|
27255
27309
|
|
|
27256
|
-
// src/db/
|
|
27257
|
-
var
|
|
27310
|
+
// src/db/storage-sync.ts
|
|
27311
|
+
var STORAGE_TABLES = [
|
|
27258
27312
|
"projects",
|
|
27259
27313
|
"agents",
|
|
27260
27314
|
"sandboxes",
|
|
@@ -27348,21 +27402,26 @@ function upsertSqlite(db2, table, rows) {
|
|
|
27348
27402
|
}
|
|
27349
27403
|
return written;
|
|
27350
27404
|
}
|
|
27351
|
-
async function
|
|
27352
|
-
return new PgAdapterAsync(
|
|
27405
|
+
async function getStoragePg() {
|
|
27406
|
+
return new PgAdapterAsync(getStorageConnectionString("sandboxes"));
|
|
27353
27407
|
}
|
|
27354
|
-
async function
|
|
27408
|
+
async function runStorageMigrations(remote) {
|
|
27355
27409
|
for (const migration of PG_MIGRATIONS) {
|
|
27356
27410
|
await remote.exec(migration);
|
|
27357
27411
|
}
|
|
27358
27412
|
}
|
|
27359
|
-
function
|
|
27360
|
-
const config2 =
|
|
27413
|
+
function getStorageStatus(db2 = getDatabase()) {
|
|
27414
|
+
const config2 = getStorageConfig();
|
|
27415
|
+
const activeEnv = getStorageDatabaseEnv();
|
|
27361
27416
|
return {
|
|
27417
|
+
configured: Boolean(activeEnv),
|
|
27362
27418
|
mode: config2.mode,
|
|
27363
|
-
enabled: config2.mode === "hybrid" || config2.mode === "
|
|
27419
|
+
enabled: config2.mode === "hybrid" || config2.mode === "remote",
|
|
27420
|
+
env: STORAGE_DATABASE_ENV,
|
|
27421
|
+
activeEnv: activeEnv?.name ?? null,
|
|
27422
|
+
service: "sandboxes",
|
|
27364
27423
|
db_path: getDbPath(),
|
|
27365
|
-
tables:
|
|
27424
|
+
tables: STORAGE_TABLES.map((table) => {
|
|
27366
27425
|
try {
|
|
27367
27426
|
const row = db2.query(`SELECT COUNT(*) as count FROM ${quoteId(table)}`).get();
|
|
27368
27427
|
return { table, rows: row.count };
|
|
@@ -27372,12 +27431,12 @@ function getCloudStatus(db2 = getDatabase()) {
|
|
|
27372
27431
|
})
|
|
27373
27432
|
};
|
|
27374
27433
|
}
|
|
27375
|
-
async function
|
|
27434
|
+
async function pushStorageChanges(tables = [...STORAGE_TABLES]) {
|
|
27376
27435
|
const db2 = getDatabase();
|
|
27377
|
-
const remote = await
|
|
27436
|
+
const remote = await getStoragePg();
|
|
27378
27437
|
const results = [];
|
|
27379
27438
|
try {
|
|
27380
|
-
await
|
|
27439
|
+
await runStorageMigrations(remote);
|
|
27381
27440
|
for (const table of tables) {
|
|
27382
27441
|
const result = { table, direction: "push", rowsRead: 0, rowsWritten: 0, errors: [] };
|
|
27383
27442
|
try {
|
|
@@ -27394,12 +27453,12 @@ async function pushCloudChanges(tables = [...CLOUD_TABLES]) {
|
|
|
27394
27453
|
}
|
|
27395
27454
|
return results;
|
|
27396
27455
|
}
|
|
27397
|
-
async function
|
|
27456
|
+
async function pullStorageChanges(tables = [...STORAGE_TABLES]) {
|
|
27398
27457
|
const db2 = getDatabase();
|
|
27399
|
-
const remote = await
|
|
27458
|
+
const remote = await getStoragePg();
|
|
27400
27459
|
const results = [];
|
|
27401
27460
|
try {
|
|
27402
|
-
await
|
|
27461
|
+
await runStorageMigrations(remote);
|
|
27403
27462
|
for (const table of tables) {
|
|
27404
27463
|
const result = { table, direction: "pull", rowsRead: 0, rowsWritten: 0, errors: [] };
|
|
27405
27464
|
try {
|
|
@@ -27416,20 +27475,26 @@ async function pullCloudChanges(tables = [...CLOUD_TABLES]) {
|
|
|
27416
27475
|
}
|
|
27417
27476
|
return results;
|
|
27418
27477
|
}
|
|
27419
|
-
async function
|
|
27478
|
+
async function syncStorageChanges(tables = [...STORAGE_TABLES]) {
|
|
27420
27479
|
return {
|
|
27421
|
-
push: await
|
|
27422
|
-
pull: await
|
|
27480
|
+
push: await pushStorageChanges(tables),
|
|
27481
|
+
pull: await pullStorageChanges(tables)
|
|
27423
27482
|
};
|
|
27424
27483
|
}
|
|
27425
|
-
function
|
|
27484
|
+
function parseStorageTables(raw) {
|
|
27426
27485
|
if (!raw)
|
|
27427
|
-
return [...
|
|
27486
|
+
return [...STORAGE_TABLES];
|
|
27428
27487
|
const requested = raw.split(",").map((table) => table.trim()).filter(Boolean);
|
|
27429
|
-
|
|
27488
|
+
if (requested.length === 0)
|
|
27489
|
+
return [...STORAGE_TABLES];
|
|
27490
|
+
const allowed = new Set(STORAGE_TABLES);
|
|
27491
|
+
const invalid = requested.filter((table) => !allowed.has(table));
|
|
27492
|
+
if (invalid.length > 0)
|
|
27493
|
+
throw new Error(`Unknown sandboxes sync table(s): ${invalid.join(", ")}`);
|
|
27494
|
+
return requested;
|
|
27430
27495
|
}
|
|
27431
27496
|
|
|
27432
|
-
// src/mcp/
|
|
27497
|
+
// src/mcp/storage-tools.ts
|
|
27433
27498
|
function ok(data) {
|
|
27434
27499
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
27435
27500
|
}
|
|
@@ -27439,42 +27504,42 @@ function err(error2) {
|
|
|
27439
27504
|
isError: true
|
|
27440
27505
|
};
|
|
27441
27506
|
}
|
|
27442
|
-
function
|
|
27443
|
-
server.tool("
|
|
27507
|
+
function registerSandboxesStorageTools(server) {
|
|
27508
|
+
server.tool("sandboxes_storage_status", "Show sandboxes local database and storage sync status", {}, async () => {
|
|
27444
27509
|
try {
|
|
27445
|
-
return ok(
|
|
27510
|
+
return ok(getStorageStatus());
|
|
27446
27511
|
} catch (error2) {
|
|
27447
27512
|
return err(error2);
|
|
27448
27513
|
}
|
|
27449
27514
|
});
|
|
27450
|
-
server.tool("
|
|
27515
|
+
server.tool("sandboxes_storage_push", "Push local sandboxes data to PostgreSQL", {
|
|
27451
27516
|
tables: exports_external.string().optional().describe("Comma-separated table names")
|
|
27452
27517
|
}, async ({ tables }) => {
|
|
27453
27518
|
try {
|
|
27454
|
-
return ok(await
|
|
27519
|
+
return ok(await pushStorageChanges(parseStorageTables(tables)));
|
|
27455
27520
|
} catch (error2) {
|
|
27456
27521
|
return err(error2);
|
|
27457
27522
|
}
|
|
27458
27523
|
});
|
|
27459
|
-
server.tool("
|
|
27524
|
+
server.tool("sandboxes_storage_pull", "Pull PostgreSQL sandboxes data into the local database", {
|
|
27460
27525
|
tables: exports_external.string().optional().describe("Comma-separated table names")
|
|
27461
27526
|
}, async ({ tables }) => {
|
|
27462
27527
|
try {
|
|
27463
|
-
return ok(await
|
|
27528
|
+
return ok(await pullStorageChanges(parseStorageTables(tables)));
|
|
27464
27529
|
} catch (error2) {
|
|
27465
27530
|
return err(error2);
|
|
27466
27531
|
}
|
|
27467
27532
|
});
|
|
27468
|
-
server.tool("
|
|
27533
|
+
server.tool("sandboxes_storage_sync", "Push local changes, then pull remote changes", {
|
|
27469
27534
|
tables: exports_external.string().optional().describe("Comma-separated table names")
|
|
27470
27535
|
}, async ({ tables }) => {
|
|
27471
27536
|
try {
|
|
27472
|
-
return ok(await
|
|
27537
|
+
return ok(await syncStorageChanges(parseStorageTables(tables)));
|
|
27473
27538
|
} catch (error2) {
|
|
27474
27539
|
return err(error2);
|
|
27475
27540
|
}
|
|
27476
27541
|
});
|
|
27477
|
-
server.tool("
|
|
27542
|
+
server.tool("sandboxes_feedback", "Save feedback for sandboxes", {
|
|
27478
27543
|
message: exports_external.string(),
|
|
27479
27544
|
email: exports_external.string().optional(),
|
|
27480
27545
|
category: exports_external.enum(["bug", "feature", "general"]).optional()
|
|
@@ -28298,7 +28363,7 @@ function buildServer() {
|
|
|
28298
28363
|
return err2(e);
|
|
28299
28364
|
}
|
|
28300
28365
|
});
|
|
28301
|
-
|
|
28366
|
+
registerSandboxesStorageTools(server);
|
|
28302
28367
|
return server;
|
|
28303
28368
|
}
|
|
28304
28369
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { SANDBOXES_STORAGE_ENV, SANDBOXES_STORAGE_FALLBACK_ENV, SANDBOXES_STORAGE_MODE_ENV, SANDBOXES_STORAGE_MODE_FALLBACK_ENV, STORAGE_DATABASE_ENV, STORAGE_MODE_ENV, getConnectionString, getStorageConfig, getStorageConnectionString, getStorageDatabaseEnv, getStorageDatabaseEnvName, getStorageDatabaseUrl, } from "./db/storage-config.js";
|
|
2
|
+
export type { StorageConfig, StorageEnv, StorageMode } from "./db/storage-config.js";
|
|
3
|
+
export { SANDBOXES_STORAGE_TABLES, STORAGE_TABLES, getStoragePg, getStorageStatus, parseStorageTables, pullStorageChanges, pushStorageChanges, runStorageMigrations, syncStorageChanges, } from "./db/storage-sync.js";
|
|
4
|
+
export type { StorageStatus, SyncResult } from "./db/storage-sync.js";
|
|
5
|
+
export { PgAdapterAsync } from "./db/remote-storage.js";
|
|
6
|
+
export { PG_MIGRATIONS } from "./db/pg-migrations.js";
|