@drawpro/mcp 0.6.1 → 0.6.3

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/server.js +80 -16
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -1411,7 +1411,7 @@ function api() {
1411
1411
  return clientInstance;
1412
1412
  }
1413
1413
  var SESSION_ID = Math.random().toString(36).slice(2, 10);
1414
- var VERSION = "0.6.1";
1414
+ var VERSION = "0.6.3";
1415
1415
  var inFlight = [];
1416
1416
  var cachedUser = null;
1417
1417
  async function currentUser() {
@@ -1622,11 +1622,11 @@ tool(
1622
1622
  );
1623
1623
  function buildOrExplain(spec) {
1624
1624
  const { scene, issues } = buildDiagram(spec);
1625
- const errors = issues.filter((i) => i.level === "error");
1626
- if (errors.length > 0) {
1625
+ const errors2 = issues.filter((i) => i.level === "error");
1626
+ if (errors2.length > 0) {
1627
1627
  return {
1628
1628
  ok: false,
1629
- error: "The diagram was not created. Fix the spec and try again:\n" + errors.map((i) => ` error: ${i.message}`).join("\n")
1629
+ error: "The diagram was not created. Fix the spec and try again:\n" + errors2.map((i) => ` error: ${i.message}`).join("\n")
1630
1630
  };
1631
1631
  }
1632
1632
  const warnings = issues.filter((i) => i.level === "warning");
@@ -1726,7 +1726,9 @@ tool(
1726
1726
  sheet_id: import_zod.z.string(),
1727
1727
  edits: import_zod.z.array(
1728
1728
  import_zod.z.object({
1729
- find: import_zod.z.string().describe("The element's exact current text, as read_sheet reports it"),
1729
+ find: import_zod.z.string().describe(
1730
+ "The element's current text, as read_sheet reports it. Whitespace is matched loosely, so the flattened single-line form read_sheet prints works even when the element itself contains line breaks."
1731
+ ),
1730
1732
  replace: import_zod.z.string()
1731
1733
  })
1732
1734
  ).describe("Applied all-or-nothing: if any find has no match, nothing is written.")
@@ -1736,13 +1738,14 @@ tool(
1736
1738
  if ("error" in unlocked) return text(unlocked.error);
1737
1739
  const scene = await api().readSheet(workspace_id, sheet_id, unlocked.key);
1738
1740
  const elements = scene.elements;
1741
+ const collapse = (t) => t.replace(/\s+/g, " ").trim();
1739
1742
  const counts = /* @__PURE__ */ new Map();
1740
1743
  const changedTextIds = /* @__PURE__ */ new Set();
1741
1744
  for (const el of elements) {
1742
1745
  if (el.type !== "text") continue;
1743
1746
  const current = (el.originalText ?? el.text)?.trim();
1744
1747
  if (current === void 0) continue;
1745
- const edit = edits.find((e) => e.find.trim() === current);
1748
+ const edit = edits.find((e) => e.find.trim() === current) ?? edits.find((e) => collapse(e.find) === collapse(current));
1746
1749
  if (!edit) continue;
1747
1750
  el.text = edit.replace;
1748
1751
  el.originalText = edit.replace;
@@ -1761,7 +1764,7 @@ tool(
1761
1764
  const missed = edits.filter((e) => !counts.has(e.find));
1762
1765
  if (missed.length > 0) {
1763
1766
  return text(
1764
- "Nothing was written. These strings matched no text element:\n" + missed.map((e) => ` ${JSON.stringify(e.find)}`).join("\n") + "\n\nRun read_sheet and copy the text exactly as it appears there."
1767
+ "Nothing was written. These strings matched no text element:\n" + missed.map((e) => ` ${JSON.stringify(e.find)}`).join("\n") + "\n\nRun read_sheet and copy the text as it appears there. Line breaks and repeated spaces do not need to match \u2014 only the words do."
1765
1768
  );
1766
1769
  }
1767
1770
  const user = await currentUser();
@@ -1861,6 +1864,44 @@ function summariseLog(file) {
1861
1864
  }))
1862
1865
  };
1863
1866
  }
1867
+ function errors(file) {
1868
+ let rows;
1869
+ try {
1870
+ rows = (0, import_node_fs3.readFileSync)(file, "utf8").split("\n").filter(Boolean).flatMap((line) => {
1871
+ try {
1872
+ return [JSON.parse(line)];
1873
+ } catch {
1874
+ return [];
1875
+ }
1876
+ });
1877
+ } catch {
1878
+ console.error(`Could not read ${file}`);
1879
+ process.exit(2);
1880
+ }
1881
+ const failures = rows.filter((r) => r.ok === false || r.refused);
1882
+ if (failures.length === 0) {
1883
+ console.log("No failures or refusals recorded.");
1884
+ return;
1885
+ }
1886
+ const grouped = /* @__PURE__ */ new Map();
1887
+ for (const r of failures) {
1888
+ const reason = String(r.error ?? "refused (the tool declined, see its message)").slice(0, 120);
1889
+ const acc = grouped.get(reason) ?? { n: 0, tools: /* @__PURE__ */ new Set(), last: "" };
1890
+ acc.n++;
1891
+ acc.tools.add(String(r.tool));
1892
+ acc.last = String(r.ts);
1893
+ grouped.set(reason, acc);
1894
+ }
1895
+ console.log(`${failures.length} of ${rows.length} calls failed or were refused
1896
+ `);
1897
+ for (const [reason, a] of [...grouped.entries()].sort((x, y) => y[1].n - x[1].n)) {
1898
+ console.log(` ${a.n}x ${[...a.tools].join(", ")}`);
1899
+ console.log(` ${reason}`);
1900
+ console.log(` last seen ${a.last}
1901
+ `);
1902
+ }
1903
+ console.log(" This reads your local log and sends nothing.");
1904
+ }
1864
1905
  function stats(path, asJson) {
1865
1906
  const file = path ?? logPath();
1866
1907
  if (!file) {
@@ -1892,7 +1933,7 @@ function stats(path, asJson) {
1892
1933
  console.log(
1893
1934
  "\n No ids, account details, or diagram content above \u2014 safe to paste into a bug report."
1894
1935
  );
1895
- console.log(" Add --json for a machine-readable copy.");
1936
+ console.log(" Add --json for a machine-readable copy, or --errors to see why calls failed.");
1896
1937
  }
1897
1938
  function buildReport() {
1898
1939
  const file = logPath();
@@ -1929,15 +1970,29 @@ async function telemetry(action) {
1929
1970
  if (action === "on") {
1930
1971
  writeConfig({ telemetry: "on" });
1931
1972
  console.log(`Telemetry on. Usage is recorded to ${logPath()}`);
1932
- console.log("Roughly once a day, an aggregate of it is sent:\n");
1933
- console.log(
1934
- report ? JSON.stringify(report, null, 2) : " (no calls recorded yet \u2014 the first report goes out once you have used the tools)"
1935
- );
1936
- console.log("\nTurn it off any time with: drawpro-mcp telemetry off");
1973
+ const built = buildReport();
1974
+ if (!built) {
1975
+ console.log("\nNothing recorded yet. The first report goes out once you have used the tools.");
1976
+ console.log("Turn it off any time with: drawpro-mcp telemetry off");
1977
+ return;
1978
+ }
1979
+ console.log("\nSending this now, and roughly once a day after:\n");
1980
+ console.log(JSON.stringify(built, null, 2));
1981
+ const { ok, detail } = await sendReport(built);
1982
+ if (ok) {
1983
+ writeConfig({ lastReportAt: (/* @__PURE__ */ new Date()).toISOString() });
1984
+ console.log("\nSent.");
1985
+ } else {
1986
+ console.log(`
1987
+ Could not send it (${detail}). Telemetry is still on and it will retry.`);
1988
+ }
1989
+ console.log("Turn it off any time with: drawpro-mcp telemetry off");
1937
1990
  return;
1938
1991
  }
1939
- console.log(`Telemetry is ${telemetryEnabled() ? "ON" : "OFF"}.
1940
- `);
1992
+ const last = readConfig().lastReportAt;
1993
+ console.log(`Telemetry is ${telemetryEnabled() ? "ON" : "OFF"}.`);
1994
+ console.log(last ? `Last report sent ${last}.
1995
+ ` : "No report has been sent yet.\n");
1941
1996
  console.log("If enabled, this is the entire payload \u2014 tool counts and timings,");
1942
1997
  console.log("no account, no token, no workspace or sheet ids, nothing drawn:\n");
1943
1998
  console.log(
@@ -2101,7 +2156,16 @@ async function main() {
2101
2156
  }
2102
2157
  if (command === "stats") {
2103
2158
  const rest = process.argv.slice(3);
2104
- stats(rest.find((a) => !a.startsWith("--")), rest.includes("--json"));
2159
+ const file = rest.find((a) => !a.startsWith("--")) ?? logPath();
2160
+ if (rest.includes("--errors")) {
2161
+ if (!file) {
2162
+ console.error("No usage is being recorded, so there is nothing to explain.");
2163
+ process.exit(2);
2164
+ }
2165
+ errors(file);
2166
+ return;
2167
+ }
2168
+ stats(file, rest.includes("--json"));
2105
2169
  return;
2106
2170
  }
2107
2171
  if (command && command !== "serve") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drawpro/mcp",
3
- "version": "0.6.1",
3
+ "version": "0.6.3",
4
4
  "description": "MCP server for DrawPro \u2014 read and create end-to-end encrypted Excalidraw diagrams from Claude",
5
5
  "license": "MIT",
6
6
  "repository": {