@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/mcp/index.js
CHANGED
|
@@ -9941,6 +9941,17 @@ INSERT OR IGNORE INTO _migrations (id) VALUES (6);
|
|
|
9941
9941
|
`
|
|
9942
9942
|
ALTER TABLE agents ADD COLUMN active_project_id TEXT REFERENCES projects(id) ON DELETE SET NULL;
|
|
9943
9943
|
INSERT OR IGNORE INTO _migrations (id) VALUES (7);
|
|
9944
|
+
`,
|
|
9945
|
+
`
|
|
9946
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_status_created ON sandboxes(status, created_at DESC);
|
|
9947
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_provider_created ON sandboxes(provider, created_at DESC);
|
|
9948
|
+
CREATE INDEX IF NOT EXISTS idx_sandboxes_project_created ON sandboxes(project_id, created_at DESC);
|
|
9949
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_started ON sandbox_sessions(sandbox_id, started_at DESC);
|
|
9950
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_status_started ON sandbox_sessions(status, started_at DESC);
|
|
9951
|
+
CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_status_started ON sandbox_sessions(sandbox_id, status, started_at DESC);
|
|
9952
|
+
CREATE INDEX IF NOT EXISTS idx_events_sandbox_created ON sandbox_events(sandbox_id, created_at ASC);
|
|
9953
|
+
CREATE INDEX IF NOT EXISTS idx_events_session_created ON sandbox_events(session_id, created_at ASC);
|
|
9954
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (8);
|
|
9944
9955
|
`
|
|
9945
9956
|
];
|
|
9946
9957
|
var db = null;
|
|
@@ -9971,16 +9982,26 @@ function uuid() {
|
|
|
9971
9982
|
function now() {
|
|
9972
9983
|
return new Date().toISOString().replace("T", " ").replace("Z", "");
|
|
9973
9984
|
}
|
|
9985
|
+
var PARTIAL_ID_TABLES = new Set([
|
|
9986
|
+
"agents",
|
|
9987
|
+
"projects",
|
|
9988
|
+
"sandbox_sessions",
|
|
9989
|
+
"sandboxes",
|
|
9990
|
+
"snapshots",
|
|
9991
|
+
"templates",
|
|
9992
|
+
"webhooks"
|
|
9993
|
+
]);
|
|
9974
9994
|
function resolvePartialId(table, partialId) {
|
|
9995
|
+
if (!PARTIAL_ID_TABLES.has(table)) {
|
|
9996
|
+
throw new Error(`Invalid partial-id table: ${table}`);
|
|
9997
|
+
}
|
|
9975
9998
|
const database = getDatabase();
|
|
9976
|
-
const
|
|
9977
|
-
if (rows.length === 1)
|
|
9978
|
-
return rows[0].id;
|
|
9979
|
-
if (rows.length === 0)
|
|
9980
|
-
return null;
|
|
9981
|
-
const exact = rows.find((r) => r.id === partialId);
|
|
9999
|
+
const exact = database.query(`SELECT id FROM ${table} WHERE id = ?`).get(partialId);
|
|
9982
10000
|
if (exact)
|
|
9983
10001
|
return exact.id;
|
|
10002
|
+
const rows = database.query(`SELECT id FROM ${table} WHERE id LIKE ? ORDER BY id LIMIT 2`).all(`${partialId}%`);
|
|
10003
|
+
if (rows.length === 1)
|
|
10004
|
+
return rows[0].id;
|
|
9984
10005
|
return null;
|
|
9985
10006
|
}
|
|
9986
10007
|
|
|
@@ -10189,7 +10210,7 @@ function listEvents(opts) {
|
|
|
10189
10210
|
const where = conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "";
|
|
10190
10211
|
const limit = opts?.limit ?? 100;
|
|
10191
10212
|
const offset = opts?.offset ?? 0;
|
|
10192
|
-
const rows = db2.query(`SELECT * FROM sandbox_events${where} ORDER BY created_at ASC LIMIT ? OFFSET ?`).all(...[...params, limit, offset]);
|
|
10213
|
+
const rows = db2.query(`SELECT * FROM sandbox_events${where} ORDER BY created_at ASC, rowid ASC LIMIT ? OFFSET ?`).all(...[...params, limit, offset]);
|
|
10193
10214
|
return rows.map(rowToEvent);
|
|
10194
10215
|
}
|
|
10195
10216
|
|
|
@@ -10861,55 +10882,80 @@ function getPackageVersion() {
|
|
|
10861
10882
|
return cachedVersion;
|
|
10862
10883
|
}
|
|
10863
10884
|
|
|
10864
|
-
// src/db/
|
|
10885
|
+
// src/db/storage-config.ts
|
|
10865
10886
|
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
10866
10887
|
import { homedir } from "os";
|
|
10867
10888
|
import { join as join4 } from "path";
|
|
10868
|
-
var
|
|
10869
|
-
|
|
10870
|
-
|
|
10889
|
+
var STORAGE_CONFIG_PATH = join4(homedir(), ".hasna", "sandboxes", "storage", "config.json");
|
|
10890
|
+
var SANDBOXES_STORAGE_ENV = "HASNA_SANDBOXES_DATABASE_URL";
|
|
10891
|
+
var SANDBOXES_STORAGE_FALLBACK_ENV = "SANDBOXES_DATABASE_URL";
|
|
10892
|
+
var SANDBOXES_STORAGE_MODE_ENV = "HASNA_SANDBOXES_STORAGE_MODE";
|
|
10893
|
+
var SANDBOXES_STORAGE_MODE_FALLBACK_ENV = "SANDBOXES_STORAGE_MODE";
|
|
10894
|
+
var STORAGE_DATABASE_ENV = [SANDBOXES_STORAGE_ENV, SANDBOXES_STORAGE_FALLBACK_ENV];
|
|
10895
|
+
function readEnv(name) {
|
|
10896
|
+
const value = process.env[name]?.trim();
|
|
10897
|
+
return value || undefined;
|
|
10898
|
+
}
|
|
10899
|
+
function normalizeStorageMode(value) {
|
|
10900
|
+
const normalized = value?.trim().toLowerCase();
|
|
10901
|
+
if (normalized === "local" || normalized === "hybrid" || normalized === "remote")
|
|
10902
|
+
return normalized;
|
|
10903
|
+
return;
|
|
10904
|
+
}
|
|
10905
|
+
function getStorageDatabaseEnvName() {
|
|
10906
|
+
for (const name of STORAGE_DATABASE_ENV) {
|
|
10907
|
+
if (readEnv(name))
|
|
10908
|
+
return name;
|
|
10909
|
+
}
|
|
10910
|
+
return null;
|
|
10911
|
+
}
|
|
10912
|
+
function getStorageDatabaseEnv() {
|
|
10913
|
+
const name = getStorageDatabaseEnvName();
|
|
10914
|
+
return name ? { name } : null;
|
|
10871
10915
|
}
|
|
10872
|
-
function
|
|
10873
|
-
|
|
10916
|
+
function getStorageDatabaseUrl() {
|
|
10917
|
+
const env = getStorageDatabaseEnv();
|
|
10918
|
+
return env ? readEnv(env.name) : undefined;
|
|
10874
10919
|
}
|
|
10875
|
-
function
|
|
10920
|
+
function getStorageConfig() {
|
|
10876
10921
|
const config = {
|
|
10877
10922
|
mode: "local",
|
|
10878
10923
|
rds: {
|
|
10879
10924
|
host: "",
|
|
10880
10925
|
port: 5432,
|
|
10881
10926
|
username: "",
|
|
10882
|
-
password_env: "
|
|
10927
|
+
password_env: "SANDBOXES_DATABASE_PASSWORD",
|
|
10883
10928
|
ssl: true
|
|
10884
10929
|
}
|
|
10885
10930
|
};
|
|
10886
|
-
if (existsSync4(
|
|
10931
|
+
if (existsSync4(STORAGE_CONFIG_PATH)) {
|
|
10887
10932
|
try {
|
|
10888
|
-
const raw = JSON.parse(readFileSync3(
|
|
10889
|
-
config.mode = raw.mode ?? config.mode;
|
|
10933
|
+
const raw = JSON.parse(readFileSync3(STORAGE_CONFIG_PATH, "utf-8"));
|
|
10934
|
+
config.mode = normalizeStorageMode(raw.mode) ?? config.mode;
|
|
10890
10935
|
config.rds = { ...config.rds, ...raw.rds ?? {} };
|
|
10891
10936
|
} catch {}
|
|
10892
10937
|
}
|
|
10893
|
-
const modeOverride =
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10938
|
+
const modeOverride = readEnv(SANDBOXES_STORAGE_MODE_ENV) ?? readEnv(SANDBOXES_STORAGE_MODE_FALLBACK_ENV);
|
|
10939
|
+
const mode = normalizeStorageMode(modeOverride);
|
|
10940
|
+
if (mode) {
|
|
10941
|
+
config.mode = mode;
|
|
10942
|
+
} else if (getStorageDatabaseUrl() && config.mode === "local") {
|
|
10897
10943
|
config.mode = "hybrid";
|
|
10898
10944
|
}
|
|
10899
10945
|
return config;
|
|
10900
10946
|
}
|
|
10901
|
-
function
|
|
10902
|
-
const direct =
|
|
10947
|
+
function getStorageConnectionString(dbName = "sandboxes") {
|
|
10948
|
+
const direct = getStorageDatabaseUrl();
|
|
10903
10949
|
if (direct)
|
|
10904
10950
|
return direct;
|
|
10905
|
-
const config =
|
|
10951
|
+
const config = getStorageConfig();
|
|
10906
10952
|
const { host, port, username, password_env, ssl } = config.rds;
|
|
10907
10953
|
if (!host || !username) {
|
|
10908
|
-
throw new Error("
|
|
10954
|
+
throw new Error("Storage database is not configured. Set HASNA_SANDBOXES_DATABASE_URL or configure ~/.hasna/sandboxes/storage/config.json.");
|
|
10909
10955
|
}
|
|
10910
10956
|
const password = process.env[password_env];
|
|
10911
10957
|
if (!password) {
|
|
10912
|
-
throw new Error(`
|
|
10958
|
+
throw new Error(`Storage database password is not set. Export ${password_env}.`);
|
|
10913
10959
|
}
|
|
10914
10960
|
const sslParam = ssl ? "?sslmode=require" : "";
|
|
10915
10961
|
return `postgres://${username}:${encodeURIComponent(password)}@${host}:${port}/${dbName}${sslParam}`;
|
|
@@ -11005,6 +11051,9 @@ var PG_MIGRATIONS = [
|
|
|
11005
11051
|
`CREATE INDEX IF NOT EXISTS idx_sandboxes_status ON sandboxes(status)`,
|
|
11006
11052
|
`CREATE INDEX IF NOT EXISTS idx_sandboxes_provider ON sandboxes(provider)`,
|
|
11007
11053
|
`CREATE INDEX IF NOT EXISTS idx_sandboxes_project ON sandboxes(project_id)`,
|
|
11054
|
+
`CREATE INDEX IF NOT EXISTS idx_sandboxes_status_created ON sandboxes(status, created_at DESC)`,
|
|
11055
|
+
`CREATE INDEX IF NOT EXISTS idx_sandboxes_provider_created ON sandboxes(provider, created_at DESC)`,
|
|
11056
|
+
`CREATE INDEX IF NOT EXISTS idx_sandboxes_project_created ON sandboxes(project_id, created_at DESC)`,
|
|
11008
11057
|
`CREATE TABLE IF NOT EXISTS sandbox_sessions (
|
|
11009
11058
|
id TEXT PRIMARY KEY,
|
|
11010
11059
|
sandbox_id TEXT NOT NULL REFERENCES sandboxes(id) ON DELETE CASCADE,
|
|
@@ -11018,6 +11067,9 @@ var PG_MIGRATIONS = [
|
|
|
11018
11067
|
)`,
|
|
11019
11068
|
`CREATE INDEX IF NOT EXISTS idx_sessions_sandbox ON sandbox_sessions(sandbox_id)`,
|
|
11020
11069
|
`CREATE INDEX IF NOT EXISTS idx_sessions_status ON sandbox_sessions(status)`,
|
|
11070
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_started ON sandbox_sessions(sandbox_id, started_at DESC)`,
|
|
11071
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_status_started ON sandbox_sessions(status, started_at DESC)`,
|
|
11072
|
+
`CREATE INDEX IF NOT EXISTS idx_sessions_sandbox_status_started ON sandbox_sessions(sandbox_id, status, started_at DESC)`,
|
|
11021
11073
|
`CREATE TABLE IF NOT EXISTS sandbox_events (
|
|
11022
11074
|
id TEXT PRIMARY KEY,
|
|
11023
11075
|
sandbox_id TEXT NOT NULL REFERENCES sandboxes(id) ON DELETE CASCADE,
|
|
@@ -11029,6 +11081,8 @@ var PG_MIGRATIONS = [
|
|
|
11029
11081
|
`CREATE INDEX IF NOT EXISTS idx_events_sandbox ON sandbox_events(sandbox_id)`,
|
|
11030
11082
|
`CREATE INDEX IF NOT EXISTS idx_events_session ON sandbox_events(session_id)`,
|
|
11031
11083
|
`CREATE INDEX IF NOT EXISTS idx_events_type ON sandbox_events(type)`,
|
|
11084
|
+
`CREATE INDEX IF NOT EXISTS idx_events_sandbox_created ON sandbox_events(sandbox_id, created_at ASC)`,
|
|
11085
|
+
`CREATE INDEX IF NOT EXISTS idx_events_session_created ON sandbox_events(session_id, created_at ASC)`,
|
|
11032
11086
|
`CREATE TABLE IF NOT EXISTS webhooks (
|
|
11033
11087
|
id TEXT PRIMARY KEY,
|
|
11034
11088
|
url TEXT NOT NULL,
|
|
@@ -11079,8 +11133,8 @@ var PG_MIGRATIONS = [
|
|
|
11079
11133
|
`ALTER TABLE agents ADD COLUMN IF NOT EXISTS active_project_id TEXT REFERENCES projects(id) ON DELETE SET NULL`
|
|
11080
11134
|
];
|
|
11081
11135
|
|
|
11082
|
-
// src/db/
|
|
11083
|
-
var
|
|
11136
|
+
// src/db/storage-sync.ts
|
|
11137
|
+
var STORAGE_TABLES = [
|
|
11084
11138
|
"projects",
|
|
11085
11139
|
"agents",
|
|
11086
11140
|
"sandboxes",
|
|
@@ -11174,21 +11228,26 @@ function upsertSqlite(db2, table, rows) {
|
|
|
11174
11228
|
}
|
|
11175
11229
|
return written;
|
|
11176
11230
|
}
|
|
11177
|
-
async function
|
|
11178
|
-
return new PgAdapterAsync(
|
|
11231
|
+
async function getStoragePg() {
|
|
11232
|
+
return new PgAdapterAsync(getStorageConnectionString("sandboxes"));
|
|
11179
11233
|
}
|
|
11180
|
-
async function
|
|
11234
|
+
async function runStorageMigrations(remote) {
|
|
11181
11235
|
for (const migration of PG_MIGRATIONS) {
|
|
11182
11236
|
await remote.exec(migration);
|
|
11183
11237
|
}
|
|
11184
11238
|
}
|
|
11185
|
-
function
|
|
11186
|
-
const config =
|
|
11239
|
+
function getStorageStatus(db2 = getDatabase()) {
|
|
11240
|
+
const config = getStorageConfig();
|
|
11241
|
+
const activeEnv = getStorageDatabaseEnv();
|
|
11187
11242
|
return {
|
|
11243
|
+
configured: Boolean(activeEnv),
|
|
11188
11244
|
mode: config.mode,
|
|
11189
|
-
enabled: config.mode === "hybrid" || config.mode === "
|
|
11245
|
+
enabled: config.mode === "hybrid" || config.mode === "remote",
|
|
11246
|
+
env: STORAGE_DATABASE_ENV,
|
|
11247
|
+
activeEnv: activeEnv?.name ?? null,
|
|
11248
|
+
service: "sandboxes",
|
|
11190
11249
|
db_path: getDbPath(),
|
|
11191
|
-
tables:
|
|
11250
|
+
tables: STORAGE_TABLES.map((table) => {
|
|
11192
11251
|
try {
|
|
11193
11252
|
const row = db2.query(`SELECT COUNT(*) as count FROM ${quoteId(table)}`).get();
|
|
11194
11253
|
return { table, rows: row.count };
|
|
@@ -11198,12 +11257,12 @@ function getCloudStatus(db2 = getDatabase()) {
|
|
|
11198
11257
|
})
|
|
11199
11258
|
};
|
|
11200
11259
|
}
|
|
11201
|
-
async function
|
|
11260
|
+
async function pushStorageChanges(tables = [...STORAGE_TABLES]) {
|
|
11202
11261
|
const db2 = getDatabase();
|
|
11203
|
-
const remote = await
|
|
11262
|
+
const remote = await getStoragePg();
|
|
11204
11263
|
const results = [];
|
|
11205
11264
|
try {
|
|
11206
|
-
await
|
|
11265
|
+
await runStorageMigrations(remote);
|
|
11207
11266
|
for (const table of tables) {
|
|
11208
11267
|
const result = { table, direction: "push", rowsRead: 0, rowsWritten: 0, errors: [] };
|
|
11209
11268
|
try {
|
|
@@ -11220,12 +11279,12 @@ async function pushCloudChanges(tables = [...CLOUD_TABLES]) {
|
|
|
11220
11279
|
}
|
|
11221
11280
|
return results;
|
|
11222
11281
|
}
|
|
11223
|
-
async function
|
|
11282
|
+
async function pullStorageChanges(tables = [...STORAGE_TABLES]) {
|
|
11224
11283
|
const db2 = getDatabase();
|
|
11225
|
-
const remote = await
|
|
11284
|
+
const remote = await getStoragePg();
|
|
11226
11285
|
const results = [];
|
|
11227
11286
|
try {
|
|
11228
|
-
await
|
|
11287
|
+
await runStorageMigrations(remote);
|
|
11229
11288
|
for (const table of tables) {
|
|
11230
11289
|
const result = { table, direction: "pull", rowsRead: 0, rowsWritten: 0, errors: [] };
|
|
11231
11290
|
try {
|
|
@@ -11242,20 +11301,26 @@ async function pullCloudChanges(tables = [...CLOUD_TABLES]) {
|
|
|
11242
11301
|
}
|
|
11243
11302
|
return results;
|
|
11244
11303
|
}
|
|
11245
|
-
async function
|
|
11304
|
+
async function syncStorageChanges(tables = [...STORAGE_TABLES]) {
|
|
11246
11305
|
return {
|
|
11247
|
-
push: await
|
|
11248
|
-
pull: await
|
|
11306
|
+
push: await pushStorageChanges(tables),
|
|
11307
|
+
pull: await pullStorageChanges(tables)
|
|
11249
11308
|
};
|
|
11250
11309
|
}
|
|
11251
|
-
function
|
|
11310
|
+
function parseStorageTables(raw) {
|
|
11252
11311
|
if (!raw)
|
|
11253
|
-
return [...
|
|
11312
|
+
return [...STORAGE_TABLES];
|
|
11254
11313
|
const requested = raw.split(",").map((table) => table.trim()).filter(Boolean);
|
|
11255
|
-
|
|
11314
|
+
if (requested.length === 0)
|
|
11315
|
+
return [...STORAGE_TABLES];
|
|
11316
|
+
const allowed = new Set(STORAGE_TABLES);
|
|
11317
|
+
const invalid = requested.filter((table) => !allowed.has(table));
|
|
11318
|
+
if (invalid.length > 0)
|
|
11319
|
+
throw new Error(`Unknown sandboxes sync table(s): ${invalid.join(", ")}`);
|
|
11320
|
+
return requested;
|
|
11256
11321
|
}
|
|
11257
11322
|
|
|
11258
|
-
// src/mcp/
|
|
11323
|
+
// src/mcp/storage-tools.ts
|
|
11259
11324
|
function ok(data) {
|
|
11260
11325
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
11261
11326
|
}
|
|
@@ -11265,42 +11330,42 @@ function err(error) {
|
|
|
11265
11330
|
isError: true
|
|
11266
11331
|
};
|
|
11267
11332
|
}
|
|
11268
|
-
function
|
|
11269
|
-
server.tool("
|
|
11333
|
+
function registerSandboxesStorageTools(server) {
|
|
11334
|
+
server.tool("sandboxes_storage_status", "Show sandboxes local database and storage sync status", {}, async () => {
|
|
11270
11335
|
try {
|
|
11271
|
-
return ok(
|
|
11336
|
+
return ok(getStorageStatus());
|
|
11272
11337
|
} catch (error) {
|
|
11273
11338
|
return err(error);
|
|
11274
11339
|
}
|
|
11275
11340
|
});
|
|
11276
|
-
server.tool("
|
|
11341
|
+
server.tool("sandboxes_storage_push", "Push local sandboxes data to PostgreSQL", {
|
|
11277
11342
|
tables: exports_external.string().optional().describe("Comma-separated table names")
|
|
11278
11343
|
}, async ({ tables }) => {
|
|
11279
11344
|
try {
|
|
11280
|
-
return ok(await
|
|
11345
|
+
return ok(await pushStorageChanges(parseStorageTables(tables)));
|
|
11281
11346
|
} catch (error) {
|
|
11282
11347
|
return err(error);
|
|
11283
11348
|
}
|
|
11284
11349
|
});
|
|
11285
|
-
server.tool("
|
|
11350
|
+
server.tool("sandboxes_storage_pull", "Pull PostgreSQL sandboxes data into the local database", {
|
|
11286
11351
|
tables: exports_external.string().optional().describe("Comma-separated table names")
|
|
11287
11352
|
}, async ({ tables }) => {
|
|
11288
11353
|
try {
|
|
11289
|
-
return ok(await
|
|
11354
|
+
return ok(await pullStorageChanges(parseStorageTables(tables)));
|
|
11290
11355
|
} catch (error) {
|
|
11291
11356
|
return err(error);
|
|
11292
11357
|
}
|
|
11293
11358
|
});
|
|
11294
|
-
server.tool("
|
|
11359
|
+
server.tool("sandboxes_storage_sync", "Push local changes, then pull remote changes", {
|
|
11295
11360
|
tables: exports_external.string().optional().describe("Comma-separated table names")
|
|
11296
11361
|
}, async ({ tables }) => {
|
|
11297
11362
|
try {
|
|
11298
|
-
return ok(await
|
|
11363
|
+
return ok(await syncStorageChanges(parseStorageTables(tables)));
|
|
11299
11364
|
} catch (error) {
|
|
11300
11365
|
return err(error);
|
|
11301
11366
|
}
|
|
11302
11367
|
});
|
|
11303
|
-
server.tool("
|
|
11368
|
+
server.tool("sandboxes_feedback", "Save feedback for sandboxes", {
|
|
11304
11369
|
message: exports_external.string(),
|
|
11305
11370
|
email: exports_external.string().optional(),
|
|
11306
11371
|
category: exports_external.enum(["bug", "feature", "general"]).optional()
|
|
@@ -12124,7 +12189,7 @@ function buildServer() {
|
|
|
12124
12189
|
return err2(e);
|
|
12125
12190
|
}
|
|
12126
12191
|
});
|
|
12127
|
-
|
|
12192
|
+
registerSandboxesStorageTools(server);
|
|
12128
12193
|
return server;
|
|
12129
12194
|
}
|
|
12130
12195
|
|