drafted 1.11.36 → 1.11.37
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/mcp/server.mjs +5 -8
- package/package.json +1 -3
- package/src/shared/excalidraw.mjs +0 -61
package/mcp/server.mjs
CHANGED
|
@@ -19,7 +19,7 @@ import { z } from 'zod';
|
|
|
19
19
|
import { registerAppResource, RESOURCE_MIME_TYPE } from '@modelcontextprotocol/ext-apps/server';
|
|
20
20
|
import WebSocket from 'ws';
|
|
21
21
|
import { LAYERS } from '../src/shared/constants.mjs';
|
|
22
|
-
import { emptyExcalidrawScene,
|
|
22
|
+
import { emptyExcalidrawScene, stringifyExcalidrawScene } from '../src/shared/excalidraw.mjs';
|
|
23
23
|
import { createGateState, markSearched, g1Block, g2Block, g3Block, selectWithinBudget, wouldExceedBudget, budgetError, formatWikiIndex, PROJECT_CONTEXT_BUDGET_CHARS } from './gates.mjs';
|
|
24
24
|
import { loadPersistedProject, savePersistedProject } from './active-project-store.mjs';
|
|
25
25
|
|
|
@@ -2046,7 +2046,6 @@ tool('frame', 'Frame CRUD in the ACTIVE PROJECT. Dispatch by `action`: read (by
|
|
|
2046
2046
|
content: z.string().optional().describe('[write] HTML/markdown/text for Drafted inline frames. [write_doc_content|append_doc_content] native Google Doc body text. Do not use action=write content to populate Google Doc/Slide frames.'),
|
|
2047
2047
|
excalidraw_data: z.any().optional().describe('[write_excalidraw] Excalidraw scene JSON object or JSON string. Defaults to an empty scene.'),
|
|
2048
2048
|
state: z.any().optional().describe('[set_state] App-frame state object (JSON) to persist for a deployed windowType:"app" frame — e.g. {specText:"..."} for the AS/NZS electrical app. The canvas hydrates the app from this on load (the host posts a "hydrate" message with it when the frame mounts), so you can deploy a generic app frame once and drive it with data afterwards. Max 64KB. Frame must be an app frame.'),
|
|
2049
|
-
mermaid: z.string().optional().describe('[write_excalidraw] Mermaid source to convert into an editable Excalidraw scene.'),
|
|
2050
2049
|
file_path: z.string().optional().describe('[write] absolute path to a local file to upload. Mutually exclusive with content/base64/googleType.'),
|
|
2051
2050
|
base64: z.string().optional().describe('[write] base64-encoded binary content. Mutually exclusive with content/file_path/googleType. Use with content_type when known.'),
|
|
2052
2051
|
content_type: z.string().optional().describe('[write + base64] MIME type for base64 binary content, e.g. image/png, application/pdf. Defaults from the path extension or application/octet-stream.'),
|
|
@@ -2438,13 +2437,12 @@ tool('frame', 'Frame CRUD in the ACTIVE PROJECT. Dispatch by `action`: read (by
|
|
|
2438
2437
|
});
|
|
2439
2438
|
}
|
|
2440
2439
|
case 'write_excalidraw': {
|
|
2441
|
-
const { path, excalidraw_data,
|
|
2440
|
+
const { path, excalidraw_data, width, height, color } = args;
|
|
2442
2441
|
if (!path) throw new Error('path required for action=write_excalidraw');
|
|
2443
|
-
if (excalidraw_data != null && mermaid) throw new Error('Provide only one of excalidraw_data or mermaid');
|
|
2444
2442
|
const parts = path.replace(/^\/+/, '').split('/');
|
|
2445
2443
|
if (parts.length !== 3) throw new Error('Path must be /{layer}/{lane}/{filename}');
|
|
2446
2444
|
const filename = parts[2].toLowerCase().endsWith('.excalidraw') ? parts[2] : parts[2] + '.excalidraw';
|
|
2447
|
-
const scene =
|
|
2445
|
+
const scene = excalidraw_data ?? emptyExcalidrawScene();
|
|
2448
2446
|
const body = { content: stringifyExcalidrawScene(scene) };
|
|
2449
2447
|
if (width) body.width = width;
|
|
2450
2448
|
if (height) body.height = height;
|
|
@@ -3462,13 +3460,12 @@ tool('wiki', 'Per-org wiki. Markdown pages with paths as hierarchy. You and othe
|
|
|
3462
3460
|
// `LINE+ID|content`). The server applies the ops via the same
|
|
3463
3461
|
// hashline algorithm — no client-side re-hashing, no algorithm drift.
|
|
3464
3462
|
case 'write_excalidraw': {
|
|
3465
|
-
const { path, excalidraw_data,
|
|
3463
|
+
const { path, excalidraw_data, width, height, color } = args;
|
|
3466
3464
|
if (!path) throw new Error('path required for action=write_excalidraw');
|
|
3467
|
-
if (excalidraw_data != null && mermaid) throw new Error('Provide only one of excalidraw_data or mermaid');
|
|
3468
3465
|
const parts = path.replace(/^\/+/, '').split('/');
|
|
3469
3466
|
if (parts.length !== 3) throw new Error('Path must be /{layer}/{lane}/{filename}');
|
|
3470
3467
|
const filename = parts[2].toLowerCase().endsWith('.excalidraw') ? parts[2] : parts[2] + '.excalidraw';
|
|
3471
|
-
const scene =
|
|
3468
|
+
const scene = excalidraw_data ?? emptyExcalidrawScene();
|
|
3472
3469
|
const body = { content: stringifyExcalidrawScene(scene) };
|
|
3473
3470
|
if (width) body.width = width;
|
|
3474
3471
|
if (height) body.height = height;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drafted",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.37",
|
|
4
4
|
"description": "Drafted — visual thinking surface for humans and AI agents. Renders HTML, markdown, images, and code as frames on a zoomable canvas, with MCP tools for AI agents and real-time sync for humans.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -45,7 +45,6 @@
|
|
|
45
45
|
"@clerk/express": "^2.1.4",
|
|
46
46
|
"@clerk/mcp-tools": "^0.3.1",
|
|
47
47
|
"@excalidraw/excalidraw": "^0.18.1",
|
|
48
|
-
"@excalidraw/mermaid-to-excalidraw": "^2.2.2",
|
|
49
48
|
"@modelcontextprotocol/ext-apps": "^1.6.0",
|
|
50
49
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
51
50
|
"@sentry/browser": "^10.53.1",
|
|
@@ -59,7 +58,6 @@
|
|
|
59
58
|
"esbuild": "^0.28.0",
|
|
60
59
|
"exceljs": "^4.4.0",
|
|
61
60
|
"express": "^4.18.2",
|
|
62
|
-
"jsdom": "^27.0.1",
|
|
63
61
|
"jszip": "^3.10.1",
|
|
64
62
|
"lucide": "^1.16.0",
|
|
65
63
|
"mdast-util-from-markdown": "^2.0.3",
|
|
@@ -38,64 +38,3 @@ export function normalizeExcalidrawScene(input) {
|
|
|
38
38
|
export function stringifyExcalidrawScene(input) {
|
|
39
39
|
return JSON.stringify(normalizeExcalidrawScene(input), null, 2);
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
function restoreMermaidDom(previous, dom) {
|
|
43
|
-
for (const [key, value] of Object.entries(previous)) {
|
|
44
|
-
if (value === undefined) {
|
|
45
|
-
try { delete globalThis[key]; } catch {}
|
|
46
|
-
} else if (key === 'navigator') {
|
|
47
|
-
Object.defineProperty(globalThis, 'navigator', { value, configurable: true });
|
|
48
|
-
} else {
|
|
49
|
-
globalThis[key] = value;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (dom) dom.window.close();
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export async function excalidrawSceneFromMermaid(mermaid) {
|
|
56
|
-
let dom;
|
|
57
|
-
const previous = {
|
|
58
|
-
window: globalThis.window,
|
|
59
|
-
document: globalThis.document,
|
|
60
|
-
DOMParser: globalThis.DOMParser,
|
|
61
|
-
XMLSerializer: globalThis.XMLSerializer,
|
|
62
|
-
Element: globalThis.Element,
|
|
63
|
-
SVGElement: globalThis.SVGElement,
|
|
64
|
-
navigator: globalThis.navigator,
|
|
65
|
-
CSSStyleSheet: globalThis.CSSStyleSheet,
|
|
66
|
-
};
|
|
67
|
-
try {
|
|
68
|
-
if (typeof document === 'undefined') {
|
|
69
|
-
const { JSDOM } = await import('jsdom');
|
|
70
|
-
dom = new JSDOM('<!doctype html><html><body></body></html>');
|
|
71
|
-
globalThis.window = dom.window;
|
|
72
|
-
globalThis.document = dom.window.document;
|
|
73
|
-
globalThis.DOMParser = dom.window.DOMParser;
|
|
74
|
-
globalThis.XMLSerializer = dom.window.XMLSerializer;
|
|
75
|
-
globalThis.Element = dom.window.Element;
|
|
76
|
-
globalThis.SVGElement = dom.window.SVGElement;
|
|
77
|
-
if (globalThis.SVGElement && !globalThis.SVGElement.prototype.getBBox) {
|
|
78
|
-
globalThis.SVGElement.prototype.getBBox = function () {
|
|
79
|
-
const text = this.textContent || '';
|
|
80
|
-
return { x: 0, y: 0, width: Math.max(24, text.length * 8), height: 20 };
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
Object.defineProperty(globalThis, 'navigator', { value: dom.window.navigator, configurable: true });
|
|
84
|
-
globalThis.CSSStyleSheet = class {
|
|
85
|
-
constructor() { this.cssRules = []; }
|
|
86
|
-
replaceSync() { this.cssRules = []; }
|
|
87
|
-
insertRule(rule) { this.cssRules.push({ cssText: rule }); }
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
const { parseMermaidToExcalidraw } = await import('@excalidraw/mermaid-to-excalidraw');
|
|
91
|
-
const result = await parseMermaidToExcalidraw(mermaid);
|
|
92
|
-
return {
|
|
93
|
-
...emptyExcalidrawScene(),
|
|
94
|
-
elements: result.elements || [],
|
|
95
|
-
files: result.files || {},
|
|
96
|
-
appState: { viewBackgroundColor: '#ffffff' },
|
|
97
|
-
};
|
|
98
|
-
} finally {
|
|
99
|
-
if (dom) restoreMermaidDom(previous, dom);
|
|
100
|
-
}
|
|
101
|
-
}
|