@abraca/mcp 2.16.0 → 2.17.1

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.
@@ -10,7 +10,7 @@ import * as os from "node:os";
10
10
  import { homedir } from "node:os";
11
11
  import * as path from "node:path";
12
12
  import { dirname, join } from "node:path";
13
- import { AbracadabraClient, AbracadabraProvider, Kind, SERVER_ROOT_ID, WebSocketStatus, awarenessStatesToArray, foldRecords, isEncryptedContent, makeEntryMap, patchEntry, recordFromYAny, toPlain } from "@abraca/dabra";
13
+ import { AbracadabraClient, AbracadabraProvider, Kind, SERVER_ROOT_ID, WebSocketStatus, awarenessStatesToArray, foldRecords, isEncryptedContent, makeEntryMap, patchEntry, reconcileDocCover, recordFromYAny, toPlain } from "@abraca/dabra";
14
14
  import * as Y from "yjs";
15
15
  import { mkdir, readFile, writeFile } from "node:fs/promises";
16
16
  import { parseFrontmatter, populateYDocFromMarkdown, yjsToMarkdown } from "@abraca/convert";
@@ -21461,6 +21461,7 @@ var AbracadabraMCPServer = class AbracadabraMCPServer {
21461
21461
  this._spaceConnections = /* @__PURE__ */ new Map();
21462
21462
  this.childCache = /* @__PURE__ */ new Map();
21463
21463
  this.evictionTimer = null;
21464
+ this.heartbeatTimer = null;
21464
21465
  this._mcpServerRef = null;
21465
21466
  this._serverRef = null;
21466
21467
  this._handledTaskIds = /* @__PURE__ */ new Set();
@@ -21558,6 +21559,9 @@ var AbracadabraMCPServer = class AbracadabraMCPServer {
21558
21559
  await this._connectToSpace(initialDocId);
21559
21560
  console.error("[abracadabra-mcp] Space doc synced");
21560
21561
  this.evictionTimer = setInterval(() => this.evictIdle(), 6e4);
21562
+ this.heartbeatTimer = setInterval(() => {
21563
+ this.ensureConnected();
21564
+ }, 3e4);
21561
21565
  }
21562
21566
  /** Connect to a space's root doc and cache it. Sets it as the active connection. */
21563
21567
  async _connectToSpace(docId) {
@@ -21666,34 +21670,37 @@ var AbracadabraMCPServer = class AbracadabraMCPServer {
21666
21670
  console.error("[abracadabra-mcp] Re-auth during heal failed:", e);
21667
21671
  }
21668
21672
  const conn = this._activeConnection;
21669
- if (!conn) return;
21670
- if (this._wsConnected(conn.provider)) return;
21671
- try {
21672
- await waitForSync(conn.provider, 6e3);
21673
- } catch {}
21674
- if (this._wsConnected(conn.provider)) return;
21675
- console.error("[abracadabra-mcp] Active connection dead — rebuilding space provider…");
21676
- const docId = conn.docId;
21677
- this._spaceConnections.delete(docId);
21678
- try {
21679
- conn.provider.destroy();
21680
- } catch {}
21681
- for (const [, cached] of this.childCache) try {
21682
- cached.provider.destroy();
21683
- } catch {}
21684
- this.childCache.clear();
21685
- try {
21686
- await this._connectToSpace(docId);
21687
- console.error("[abracadabra-mcp] Space provider rebuilt + synced");
21688
- } catch (e) {
21689
- console.error("[abracadabra-mcp] Connection rebuild failed:", e);
21690
- }
21673
+ if (conn) await this._healProvider(conn.provider, "space");
21674
+ if (this._inboxProvider) await this._healProvider(this._inboxProvider, "inbox");
21691
21675
  } finally {
21692
21676
  this._reconnecting = null;
21693
21677
  }
21694
21678
  })();
21695
21679
  return this._reconnecting;
21696
21680
  }
21681
+ /**
21682
+ * Bring one provider's socket back to a synced state WITHOUT swapping its
21683
+ * Y.Doc. First let the SDK's own auto-reconnect finish if it's mid-flight;
21684
+ * if the socket is still dead, force a reconnect on the same doc. Because the
21685
+ * document is never replaced, every observer attached to it (root awareness,
21686
+ * tree reads, the inbox `entries` array, the stateless chat listener) keeps
21687
+ * firing — no re-attach needed. Best-effort: logs but never throws.
21688
+ */
21689
+ async _healProvider(provider, label) {
21690
+ if (this._wsConnected(provider)) return;
21691
+ try {
21692
+ await waitForSync(provider, 6e3);
21693
+ } catch {}
21694
+ if (this._wsConnected(provider)) return;
21695
+ console.error(`[abracadabra-mcp] ${label} socket dead — forcing reconnect on the same doc…`);
21696
+ provider.reconnect();
21697
+ try {
21698
+ await waitForSync(provider, 1e4);
21699
+ console.error(`[abracadabra-mcp] ${label} reconnected + re-synced`);
21700
+ } catch (e) {
21701
+ console.error(`[abracadabra-mcp] ${label} reconnect did not re-sync in time:`, e);
21702
+ }
21703
+ }
21697
21704
  async ensureSpaceActive(targetId) {
21698
21705
  await this.ensureConnected();
21699
21706
  if (!targetId || targetId === this._rootDocId) return true;
@@ -22300,6 +22307,10 @@ var AbracadabraMCPServer = class AbracadabraMCPServer {
22300
22307
  clearInterval(this.evictionTimer);
22301
22308
  this.evictionTimer = null;
22302
22309
  }
22310
+ if (this.heartbeatTimer) {
22311
+ clearInterval(this.heartbeatTimer);
22312
+ this.heartbeatTimer = null;
22313
+ }
22303
22314
  for (const dispose of this._inboxDisposers) try {
22304
22315
  dispose();
22305
22316
  } catch {}
@@ -22767,6 +22778,8 @@ function registerContentTools(mcp, server) {
22767
22778
  const contentToWrite = body || markdown;
22768
22779
  const existingLabel = server.getDocSummary(docId)?.label;
22769
22780
  populateYDocFromMarkdown(fragment, contentToWrite, title || existingLabel || "Untitled");
22781
+ const coverTree = server.getTreeMap();
22782
+ if (coverTree) reconcileDocCover(coverTree, docId, fragment);
22770
22783
  server.setFocusedDoc(docId);
22771
22784
  server.setDocCursor(docId, fragment.length);
22772
22785
  return { content: [{