@vibegrid/mcp 0.2.1 → 0.3.0-beta.0

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.
Files changed (2) hide show
  1. package/dist/index.js +83 -7
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ var DEFAULT_AGENT_COMMANDS = {
35
35
  };
36
36
 
37
37
  // ../server/src/database.ts
38
- import Database from "better-sqlite3";
38
+ import Database from "libsql";
39
39
  import path from "path";
40
40
  import os from "os";
41
41
  import fs from "fs";
@@ -120,6 +120,13 @@ function recoverCorruptDatabase() {
120
120
  }
121
121
  logger_default.warn(`[database] Database was corrupted and has been reset. Backup saved to: ${backupPath}`);
122
122
  }
123
+ function dbSignalChange() {
124
+ try {
125
+ const signalPath = path.join(CONFIG_DIR, ".db-signal");
126
+ fs.writeFileSync(signalPath, Date.now().toString());
127
+ } catch {
128
+ }
129
+ }
123
130
  function closeDatabase() {
124
131
  if (db) {
125
132
  db.close();
@@ -180,10 +187,23 @@ function createSchema() {
180
187
  hostname TEXT NOT NULL,
181
188
  user TEXT NOT NULL,
182
189
  port INTEGER NOT NULL DEFAULT 22,
190
+ auth_method TEXT DEFAULT 'agent',
183
191
  ssh_key_path TEXT,
192
+ credential_id TEXT,
193
+ encrypted_password TEXT,
184
194
  ssh_options TEXT
185
195
  );
186
196
 
197
+ CREATE TABLE IF NOT EXISTS ssh_keys (
198
+ id TEXT PRIMARY KEY,
199
+ label TEXT NOT NULL,
200
+ encrypted_private_key TEXT NOT NULL,
201
+ public_key TEXT,
202
+ certificate TEXT,
203
+ key_type TEXT,
204
+ created_at TEXT NOT NULL
205
+ );
206
+
187
207
  CREATE TABLE IF NOT EXISTS tasks (
188
208
  id TEXT PRIMARY KEY,
189
209
  project_name TEXT NOT NULL,
@@ -311,6 +331,34 @@ function migrateSchema(d) {
311
331
  })();
312
332
  logger_default.info("[database] migrated schema to version 1 (workspaces)");
313
333
  }
334
+ if (version < 2) {
335
+ d.transaction(() => {
336
+ const hostCols = d.prepare("PRAGMA table_info(remote_hosts)").all();
337
+ if (!hostCols.some((c) => c.name === "auth_method")) {
338
+ d.exec("ALTER TABLE remote_hosts ADD COLUMN auth_method TEXT");
339
+ d.exec("ALTER TABLE remote_hosts ADD COLUMN credential_id TEXT");
340
+ d.exec("ALTER TABLE remote_hosts ADD COLUMN encrypted_password TEXT");
341
+ d.exec(
342
+ "UPDATE remote_hosts SET auth_method = CASE WHEN ssh_key_path IS NOT NULL AND ssh_key_path != '' THEN 'key-file' ELSE 'agent' END"
343
+ );
344
+ }
345
+ d.exec(`
346
+ CREATE TABLE IF NOT EXISTS ssh_keys (
347
+ id TEXT PRIMARY KEY,
348
+ label TEXT NOT NULL,
349
+ encrypted_private_key TEXT NOT NULL,
350
+ public_key TEXT,
351
+ certificate TEXT,
352
+ key_type TEXT,
353
+ created_at TEXT NOT NULL
354
+ )
355
+ `);
356
+ d.prepare(
357
+ "INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('schema_version', '2')"
358
+ ).run();
359
+ })();
360
+ logger_default.info("[database] migrated schema to version 2 (ssh credential vault)");
361
+ }
314
362
  }
315
363
  function loadConfig() {
316
364
  const d = getDb();
@@ -366,6 +414,15 @@ function loadDefaults(d) {
366
414
  },
367
415
  ...map.updateChannel !== void 0 && {
368
416
  updateChannel: map.updateChannel
417
+ },
418
+ ...map.webAccessEnabled !== void 0 && {
419
+ webAccessEnabled: map.webAccessEnabled
420
+ },
421
+ ...map.mobileAccessEnabled !== void 0 && {
422
+ mobileAccessEnabled: map.mobileAccessEnabled
423
+ },
424
+ ...map.networkAccessEnabled !== void 0 && {
425
+ networkAccessEnabled: map.networkAccessEnabled
369
426
  }
370
427
  };
371
428
  }
@@ -398,7 +455,10 @@ function loadRemoteHosts(d) {
398
455
  hostname: r.hostname,
399
456
  user: r.user,
400
457
  port: r.port,
458
+ ...r.auth_method != null && { authMethod: r.auth_method },
401
459
  ...r.ssh_key_path != null && { sshKeyPath: r.ssh_key_path },
460
+ ...r.credential_id != null && { credentialId: r.credential_id },
461
+ ...r.encrypted_password != null && { encryptedPassword: r.encrypted_password },
402
462
  ...r.ssh_options != null && { sshOptions: r.ssh_options }
403
463
  }));
404
464
  }
@@ -474,7 +534,7 @@ function saveConfig(config) {
474
534
  }
475
535
  d.prepare("DELETE FROM remote_hosts").run();
476
536
  const insertHost = d.prepare(
477
- "INSERT INTO remote_hosts (id, label, hostname, user, port, ssh_key_path, ssh_options) VALUES (?, ?, ?, ?, ?, ?, ?)"
537
+ "INSERT INTO remote_hosts (id, label, hostname, user, port, auth_method, ssh_key_path, credential_id, encrypted_password, ssh_options) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
478
538
  );
479
539
  for (const h of config.remoteHosts ?? []) {
480
540
  insertHost.run(
@@ -483,7 +543,10 @@ function saveConfig(config) {
483
543
  h.hostname,
484
544
  h.user,
485
545
  h.port,
546
+ h.authMethod ?? "agent",
486
547
  h.sshKeyPath ?? null,
548
+ h.credentialId ?? null,
549
+ h.encryptedPassword ?? null,
487
550
  h.sshOptions ?? null
488
551
  );
489
552
  }
@@ -955,18 +1018,19 @@ var ConfigManager = class {
955
1018
  }
956
1019
  }
957
1020
  /**
958
- * Watch the SQLite WAL file for external writes (e.g. MCP stdio process).
959
- * On change, debounce and notify callbacks so the GUI picks up fresh data.
1021
+ * Watch for external DB writes (e.g. MCP stdio process).
1022
+ * Detects: .db-signal (explicit), .db-wal changes, and .db changes (post-checkpoint).
960
1023
  */
961
1024
  watchDb() {
962
1025
  if (this.dbWatcher) return;
1026
+ const WATCH_SUFFIXES = [".db-signal", ".db-wal", ".db"];
963
1027
  try {
964
1028
  this.dbWatcher = fs2.watch(DB_DIR, (eventType, filename) => {
965
- if (!filename || !filename.endsWith(".db-wal")) return;
1029
+ if (!filename || !WATCH_SUFFIXES.some((s) => filename.endsWith(s))) return;
966
1030
  if (this.debounceTimer) clearTimeout(this.debounceTimer);
967
1031
  this.debounceTimer = setTimeout(() => {
968
1032
  this.notifyChanged();
969
- }, 1e3);
1033
+ }, 300);
970
1034
  });
971
1035
  } catch {
972
1036
  }
@@ -1092,6 +1156,7 @@ function registerTaskTools(server) {
1092
1156
  ...(status === "done" || status === "cancelled") && { completedAt: now }
1093
1157
  };
1094
1158
  dbInsertTask(task);
1159
+ dbSignalChange();
1095
1160
  return { content: [{ type: "text", text: JSON.stringify(task, null, 2) }] };
1096
1161
  }
1097
1162
  );
@@ -1143,6 +1208,7 @@ function registerTaskTools(server) {
1143
1208
  if (!isDone && wasDone) updates.completedAt = void 0;
1144
1209
  }
1145
1210
  dbUpdateTask(args.id, updates);
1211
+ dbSignalChange();
1146
1212
  const updated = dbGetTask(args.id);
1147
1213
  return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
1148
1214
  }
@@ -1160,6 +1226,7 @@ function registerTaskTools(server) {
1160
1226
  };
1161
1227
  }
1162
1228
  dbDeleteTask(args.id);
1229
+ dbSignalChange();
1163
1230
  return { content: [{ type: "text", text: `Deleted task: ${task.title}` }] };
1164
1231
  }
1165
1232
  );
@@ -1323,6 +1390,7 @@ function registerProjectTools(server) {
1323
1390
  ...args.icon_color && { iconColor: args.icon_color }
1324
1391
  };
1325
1392
  dbInsertProject(project);
1393
+ dbSignalChange();
1326
1394
  return { content: [{ type: "text", text: JSON.stringify(project, null, 2) }] };
1327
1395
  }
1328
1396
  );
@@ -1350,6 +1418,7 @@ function registerProjectTools(server) {
1350
1418
  if (args.icon !== void 0) updates.icon = args.icon;
1351
1419
  if (args.icon_color !== void 0) updates.iconColor = args.icon_color;
1352
1420
  dbUpdateProject(args.name, updates);
1421
+ dbSignalChange();
1353
1422
  const updated = dbGetProject(args.name);
1354
1423
  return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
1355
1424
  }
@@ -1366,6 +1435,7 @@ function registerProjectTools(server) {
1366
1435
  };
1367
1436
  }
1368
1437
  dbDeleteProject(args.name);
1438
+ dbSignalChange();
1369
1439
  return { content: [{ type: "text", text: `Deleted project: ${args.name}` }] };
1370
1440
  }
1371
1441
  );
@@ -1824,6 +1894,7 @@ function registerWorkflowTools(server) {
1824
1894
  ...args.stagger_delay_ms && { staggerDelayMs: args.stagger_delay_ms }
1825
1895
  };
1826
1896
  dbInsertWorkflow(workflow);
1897
+ dbSignalChange();
1827
1898
  return { content: [{ type: "text", text: JSON.stringify(workflow, null, 2) }] };
1828
1899
  }
1829
1900
  );
@@ -1858,6 +1929,7 @@ function registerWorkflowTools(server) {
1858
1929
  if (args.enabled !== void 0) updates.enabled = args.enabled;
1859
1930
  if (args.stagger_delay_ms !== void 0) updates.staggerDelayMs = args.stagger_delay_ms;
1860
1931
  dbUpdateWorkflow(args.id, updates);
1932
+ dbSignalChange();
1861
1933
  return {
1862
1934
  content: [{ type: "text", text: JSON.stringify({ ...workflow, ...updates }, null, 2) }]
1863
1935
  };
@@ -1877,6 +1949,7 @@ function registerWorkflowTools(server) {
1877
1949
  };
1878
1950
  }
1879
1951
  dbDeleteWorkflow(args.id);
1952
+ dbSignalChange();
1880
1953
  return { content: [{ type: "text", text: `Deleted workflow: ${workflow.name}` }] };
1881
1954
  }
1882
1955
  );
@@ -2382,6 +2455,7 @@ function registerWorkspaceTools(server) {
2382
2455
  ...args.icon_color && { iconColor: args.icon_color }
2383
2456
  };
2384
2457
  dbInsertWorkspace(workspace);
2458
+ dbSignalChange();
2385
2459
  return { content: [{ type: "text", text: JSON.stringify(workspace, null, 2) }] };
2386
2460
  }
2387
2461
  );
@@ -2409,6 +2483,7 @@ function registerWorkspaceTools(server) {
2409
2483
  if (args.icon_color !== void 0) updates.iconColor = args.icon_color;
2410
2484
  if (args.order !== void 0) updates.order = args.order;
2411
2485
  dbUpdateWorkspace(args.id, updates);
2486
+ dbSignalChange();
2412
2487
  const updated = dbListWorkspaces().find((w) => w.id === args.id);
2413
2488
  return { content: [{ type: "text", text: JSON.stringify(updated, null, 2) }] };
2414
2489
  }
@@ -2433,6 +2508,7 @@ function registerWorkspaceTools(server) {
2433
2508
  };
2434
2509
  }
2435
2510
  dbDeleteWorkspace(args.id);
2511
+ dbSignalChange();
2436
2512
  return { content: [{ type: "text", text: `Deleted workspace: ${workspace.name}` }] };
2437
2513
  }
2438
2514
  );
@@ -2460,7 +2536,7 @@ console.warn = (...args) => _origError("[mcp:warn]", ...args);
2460
2536
  console.error = (...args) => _origError("[mcp:error]", ...args);
2461
2537
  async function main() {
2462
2538
  configManager.init();
2463
- const version = true ? "0.2.1" : createRequire(import.meta.url)("../package.json").version;
2539
+ const version = true ? "0.3.0-beta.0" : createRequire(import.meta.url)("../package.json").version;
2464
2540
  const server = createMcpServer(version);
2465
2541
  const transport = new StdioServerTransport();
2466
2542
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibegrid/mcp",
3
- "version": "0.2.1",
3
+ "version": "0.3.0-beta.0",
4
4
  "description": "VibeGrid MCP server — task management, git, and workflow tools for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@modelcontextprotocol/sdk": "^1.27.1",
34
- "better-sqlite3": "^12.8.0",
34
+ "libsql": "^0.5.22",
35
35
  "pino": "^9.6.0",
36
36
  "ws": "^8.18.0",
37
37
  "zod": "^4.3.6"