@spooky-sync/cli 0.0.1-canary.290 → 0.0.1-canary.291

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.
@@ -9166,7 +9166,8 @@ const BRIDGE_METHODS = {
9166
9166
  GET_QUERY_ROWS: "getQueryRows",
9167
9167
  UPDATE_TABLE_ROW: "updateTableRow",
9168
9168
  DELETE_TABLE_ROW: "deleteTableRow",
9169
- CLEAR_HISTORY: "clearHistory"
9169
+ /** `{ method: 'mutationOp' | 'logOp', op, args }`: the Mutations / Logs dispatchers. */
9170
+ PAGE_OP: "pageOp"
9170
9171
  };
9171
9172
  const BRIDGE_PORT = 9315;
9172
9173
  function isBridgeResponse(msg) {
@@ -12962,6 +12963,7 @@ var ZodFirstPartyTypeKind;
12962
12963
  })(ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {}));
12963
12964
  const stringType = ZodString.create;
12964
12965
  const numberType = ZodNumber.create;
12966
+ const booleanType = ZodBoolean.create;
12965
12967
  const unknownType = ZodUnknown.create;
12966
12968
  ZodNever.create;
12967
12969
  ZodArray.create;
@@ -23593,6 +23595,22 @@ const EMPTY_COMPLETION_RESULT = {
23593
23595
  function json(data) {
23594
23596
  return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
23595
23597
  }
23598
+ const LOG_LEVELS = { trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60 };
23599
+ const LEVEL_NAMES = Object.keys(LOG_LEVELS);
23600
+ const levelName = (level) => Object.entries(LOG_LEVELS).reduce(
23601
+ (name, [n, v]) => level >= v ? n : name,
23602
+ "trace"
23603
+ );
23604
+ function readableLog(e) {
23605
+ let data;
23606
+ try {
23607
+ const { time: _time, level: _level, msg: _msg, ...rest } = JSON.parse(e.line);
23608
+ data = Object.keys(rest).length ? rest : void 0;
23609
+ } catch {
23610
+ data = { truncated: e.line };
23611
+ }
23612
+ return { seq: e.seq, time: new Date(e.time).toISOString(), level: levelName(e.level), msg: e.msg, data };
23613
+ }
23596
23614
  function createServer(bridge, surreal) {
23597
23615
  const server = new McpServer({
23598
23616
  name: "sp00ky-devtools",
@@ -23608,7 +23626,7 @@ function createServer(bridge, surreal) {
23608
23626
  );
23609
23627
  server.tool(
23610
23628
  "get_state",
23611
- "Get the full Sp00ky DevTools state (events, queries, auth, database)",
23629
+ "Get the full Sp00ky DevTools state (queries, mutations, auth, database, versions)",
23612
23630
  { tabId: numberType().optional().describe("Browser tab ID (uses first connected tab if omitted)") },
23613
23631
  async ({ tabId }) => {
23614
23632
  if (!bridge.isConnected) {
@@ -23787,32 +23805,70 @@ function createServer(bridge, surreal) {
23787
23805
  }
23788
23806
  );
23789
23807
  server.tool(
23790
- "get_events",
23791
- "Get event history, optionally filtered by type",
23808
+ "get_mutations",
23809
+ `The client's writes: the outbox (pending / retrying with attempt counts), what left it since DevTools attached (synced with the server latency, or rolled back with the server error), debounced updates, the tab role and connection (a follower tab never drains), and the rows of the persistent failed-writes tray with their payload and before image. Answers "did my write reach the server?" and "why was it rolled back?".`,
23792
23810
  {
23793
- eventType: stringType().optional().describe("Filter by event type"),
23794
- limit: numberType().optional().default(50).describe("Max number of events to return"),
23811
+ status: enumType(["pending", "retrying", "synced", "rolled-back", "dropped"]).optional().describe("Only entries with this status"),
23812
+ includeTray: booleanType().optional().default(true).describe("Also read the failed-writes tray rows"),
23795
23813
  tabId: numberType().optional().describe("Browser tab ID")
23796
23814
  },
23797
- async ({ eventType, limit: limit2, tabId }) => {
23798
- if (bridge.isConnected) {
23799
- const state = await bridge.request(BRIDGE_METHODS.GET_STATE, {}, tabId);
23800
- let events = state?.eventsHistory ?? [];
23801
- if (eventType) {
23802
- events = events.filter((e) => e.eventType === eventType);
23803
- }
23804
- if (limit2) {
23805
- events = events.slice(-limit2);
23806
- }
23807
- return json(events);
23815
+ async ({ status, includeTray, tabId }) => {
23816
+ if (!bridge.isConnected) {
23817
+ throw new Error("No extension connected. get_mutations requires the Sp00ky DevTools browser extension.");
23808
23818
  }
23809
- if (surreal) {
23810
- const result = await surreal.query(
23811
- `SELECT * FROM _00_events ORDER BY timestamp DESC LIMIT ${limit2};`
23819
+ const state = await bridge.request(BRIDGE_METHODS.GET_STATE, {}, tabId);
23820
+ const mutations = state?.mutations;
23821
+ if (!mutations) {
23822
+ throw new Error("This client does not report its mutations; update @spooky-sync/core.");
23823
+ }
23824
+ const entries = status ? (mutations.entries ?? []).filter((e) => e.status === status) : mutations.entries;
23825
+ const failed = includeTray ? (await bridge.request(
23826
+ BRIDGE_METHODS.PAGE_OP,
23827
+ { method: "mutationOp", op: "listFailed", args: {} },
23828
+ tabId
23829
+ ))?.failed : void 0;
23830
+ return json({ ...mutations, entries, failed });
23831
+ }
23832
+ );
23833
+ server.tool(
23834
+ "get_logs",
23835
+ "Recent lines from the client's own logger (the page keeps its last 500), oldest first, each with its structured fields. Pass `after` = a previous call's `head` to read only what is new. `captureLevel` changes what the page records (e.g. 'debug') without printing more to the console; it holds for the tab's session, so a reload records its boot at that level.",
23836
+ {
23837
+ minLevel: enumType(LEVEL_NAMES).optional().describe("Only lines at or above this level"),
23838
+ contains: stringType().optional().describe("Only lines whose JSON contains this text (case-insensitive)"),
23839
+ after: numberType().optional().describe("Only lines after this seq (a previous `head`)"),
23840
+ limit: numberType().optional().default(100).describe("Max lines, newest kept"),
23841
+ captureLevel: enumType(LEVEL_NAMES).optional().describe("Set what the page records from now on"),
23842
+ tabId: numberType().optional().describe("Browser tab ID")
23843
+ },
23844
+ async ({ minLevel, contains: contains2, after, limit: limit2, captureLevel, tabId }) => {
23845
+ if (!bridge.isConnected) {
23846
+ throw new Error("No extension connected. get_logs requires the Sp00ky DevTools browser extension.");
23847
+ }
23848
+ if (captureLevel) {
23849
+ await bridge.request(
23850
+ BRIDGE_METHODS.PAGE_OP,
23851
+ { method: "logOp", op: "setCaptureLevel", args: { level: captureLevel } },
23852
+ tabId
23812
23853
  );
23813
- return json(result);
23814
23854
  }
23815
- throw new Error("No extension connected and no direct database configured.");
23855
+ const read = await bridge.request(
23856
+ BRIDGE_METHODS.PAGE_OP,
23857
+ { method: "logOp", op: "read", args: { after: after ?? 0 } },
23858
+ tabId
23859
+ );
23860
+ const floor = minLevel ? LOG_LEVELS[minLevel] : 0;
23861
+ const term = contains2?.toLowerCase();
23862
+ const entries = (read?.entries ?? []).filter(
23863
+ (e) => e.level >= floor && (!term || String(e.line).toLowerCase().includes(term))
23864
+ );
23865
+ return json({
23866
+ head: read?.head,
23867
+ dropped: read?.dropped,
23868
+ consoleLevel: read?.consoleLevel,
23869
+ captureLevel: read?.captureLevel,
23870
+ entries: entries.slice(Math.max(0, entries.length - (limit2 ?? 100))).map(readableLog)
23871
+ });
23816
23872
  }
23817
23873
  );
23818
23874
  server.tool(
@@ -23827,18 +23883,6 @@ function createServer(bridge, surreal) {
23827
23883
  return json(state?.auth ?? null);
23828
23884
  }
23829
23885
  );
23830
- server.tool(
23831
- "clear_history",
23832
- "Clear the event history",
23833
- { tabId: numberType().optional().describe("Browser tab ID") },
23834
- async ({ tabId }) => {
23835
- if (!bridge.isConnected) {
23836
- throw new Error("No extension connected. clear_history requires the Sp00ky DevTools browser extension.");
23837
- }
23838
- await bridge.request(BRIDGE_METHODS.CLEAR_HISTORY, {}, tabId);
23839
- return { content: [{ type: "text", text: "History cleared." }] };
23840
- }
23841
- );
23842
23886
  server.tool(
23843
23887
  "describe_schema",
23844
23888
  "Describe all tables with columns, types, and sp00ky annotations (@crdt, @parent). Stitches INFO FOR DB with parsed schema metadata. With the browser extension this returns @crdt/@parent semantics; direct-DB mode returns raw column info only.",
@@ -23983,18 +24027,6 @@ function createServer(bridge, surreal) {
23983
24027
  }
23984
24028
  throw new Error("No extension connected and no direct database configured.");
23985
24029
  });
23986
- server.resource("events", "sp00ky://events", { description: "Event history" }, async (uri2) => {
23987
- if (bridge.isConnected) {
23988
- const state = await bridge.request(BRIDGE_METHODS.GET_STATE);
23989
- const events = state?.eventsHistory ?? [];
23990
- return { contents: [{ uri: uri2.href, mimeType: "application/json", text: JSON.stringify(events, null, 2) }] };
23991
- }
23992
- if (surreal) {
23993
- const result = await surreal.query("SELECT * FROM _00_events ORDER BY timestamp DESC LIMIT 50;");
23994
- return { contents: [{ uri: uri2.href, mimeType: "application/json", text: JSON.stringify(result, null, 2) }] };
23995
- }
23996
- throw new Error("No extension connected and no direct database configured.");
23997
- });
23998
24030
  return server;
23999
24031
  }
24000
24032
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spooky-sync/cli",
3
- "version": "0.0.1-canary.290",
3
+ "version": "0.0.1-canary.291",
4
4
  "description": "Generate TypeScript/Dart types from SurrealDB schema files",
5
5
  "type": "module",
6
6
  "main": "./dist/syncgen.cjs",
@@ -62,10 +62,10 @@
62
62
  "vitest": "^1.0.0"
63
63
  },
64
64
  "optionalDependencies": {
65
- "@spooky-sync/cli-darwin-arm64": "0.0.1-canary.290",
66
- "@spooky-sync/cli-darwin-x64": "0.0.1-canary.290",
67
- "@spooky-sync/cli-linux-arm64": "0.0.1-canary.290",
68
- "@spooky-sync/cli-linux-x64": "0.0.1-canary.290",
69
- "@spooky-sync/cli-win32-x64": "0.0.1-canary.290"
65
+ "@spooky-sync/cli-darwin-arm64": "0.0.1-canary.291",
66
+ "@spooky-sync/cli-darwin-x64": "0.0.1-canary.291",
67
+ "@spooky-sync/cli-linux-arm64": "0.0.1-canary.291",
68
+ "@spooky-sync/cli-linux-x64": "0.0.1-canary.291",
69
+ "@spooky-sync/cli-win32-x64": "0.0.1-canary.291"
70
70
  }
71
71
  }