drafted 1.17.12 → 1.17.13
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 +27 -3
- package/package.json +1 -1
package/mcp/server.mjs
CHANGED
|
@@ -309,6 +309,7 @@ const TOOL_ANNOTATIONS = {
|
|
|
309
309
|
|
|
310
310
|
// Canvas / view
|
|
311
311
|
focus: { title: 'Focus on target', readOnlyHint: false, destructiveHint: false, openWorldHint: false, description: 'Pan the canvas viewport for connected clients to a frame, lane, or layer.' },
|
|
312
|
+
tour: { title: 'Guided tours', readOnlyHint: false, destructiveHint: false, openWorldHint: false, description: 'Play or stop an agent-authored guided tour (driver.js) on the project surface for all connected clients. Tours live on a frame\'s metadata.tour — author them with fs(write, metadata={tour: {title, steps}}). Dispatch by `action`: play (frameId) starts the walkthrough, stop (projectId) ends it. Use for presentations and collaborative walkthroughs.' },
|
|
312
313
|
screenshot: { title: 'Screenshot', readOnlyHint: true, destructiveHint: false, openWorldHint: false, description: 'Render a PNG via headless browser. `scope=frame` for a single frame, `scope=canvas` for a region of the project surface.' },
|
|
313
314
|
|
|
314
315
|
// Minions — checklist-driven intake surfaces bound to a project
|
|
@@ -418,7 +419,7 @@ function tool(name, descOrSchema, schemaOrHandler, handler) {
|
|
|
418
419
|
const v = args[0][k];
|
|
419
420
|
if (typeof v === 'string' && v.trim()) {
|
|
420
421
|
try { args[0][k] = JSON.parse(v); }
|
|
421
|
-
catch { return err(new Error(`Param "${k}" must be a JSON-encoded ${['excalidraw_data', 'frontmatter', 'target', 'output', 'state'].includes(k) ? 'object' : 'array'} string; JSON.parse failed.`)); }
|
|
422
|
+
catch { return err(new Error(`Param "${k}" must be a JSON-encoded ${['excalidraw_data', 'frontmatter', 'target', 'output', 'state', 'metadata'].includes(k) ? 'object' : 'array'} string; JSON.parse failed.`)); }
|
|
422
423
|
}
|
|
423
424
|
}
|
|
424
425
|
}
|
|
@@ -2299,6 +2300,27 @@ tool('trigger', {
|
|
|
2299
2300
|
} catch (error) { return err(error); }
|
|
2300
2301
|
});
|
|
2301
2302
|
|
|
2303
|
+
tool('tour', {
|
|
2304
|
+
action: z.enum(['play', 'stop']).describe('play: start a guided tour on the project surface for all connected clients. stop: end the currently playing tour.'),
|
|
2305
|
+
frameId: z.string().optional().describe('[play] Tour frame: a frame path (/projects/<project>/<layer>/<lane>/<file>), frame URL, or frame UUID. The frame must carry metadata.tour (steps: [{target, title?, body?, side?, advanceOnClick?}]).'),
|
|
2306
|
+
projectId: z.string().optional().describe('[stop] Project UUID or slug owning the tour.'),
|
|
2307
|
+
}, async ({ action, frameId, projectId }) => {
|
|
2308
|
+
try {
|
|
2309
|
+
if (action === 'play') {
|
|
2310
|
+
if (!frameId) throw new Error('frameId is required for tour play');
|
|
2311
|
+
const { frameId: fid } = await resolveFsFramePath(frameId);
|
|
2312
|
+
const result = await api('POST', '/api/tour/play', { frameId: fid });
|
|
2313
|
+
return ok(result);
|
|
2314
|
+
}
|
|
2315
|
+
if (action === 'stop') {
|
|
2316
|
+
if (!projectId) throw new Error('projectId is required for tour stop');
|
|
2317
|
+
const result = await api('POST', '/api/tour/stop', { projectId });
|
|
2318
|
+
return ok(result);
|
|
2319
|
+
}
|
|
2320
|
+
throw new Error(`Unknown tour action: ${action}`);
|
|
2321
|
+
} catch (error) { return err(error); }
|
|
2322
|
+
});
|
|
2323
|
+
|
|
2302
2324
|
tool('focus', {
|
|
2303
2325
|
target: z.string().describe('What to pan the canvas to: a frame path (/projects/<project>/<layer>/<lane>/<file>), a frame URL (any URL containing /f/{uuid} or /o/<org>/projects/...), or a frame ID (UUID). When a user shares a Drafted link, pass it directly here.'),
|
|
2304
2326
|
}, async ({ target }) => {
|
|
@@ -2565,7 +2587,7 @@ server.resource('info', 'drafted://info', {
|
|
|
2565
2587
|
skills: '/o/<org>/skills/<slug>',
|
|
2566
2588
|
projects: '/o/<org>/projects/<folder?>/<project>/<layer>/<lane>/<file>',
|
|
2567
2589
|
},
|
|
2568
|
-
tools: ['fs (ls/read/write/edit/mv/rm/mkdir/search)', 'whoami', 'auth', 'session', 'trigger', 'focus', 'screenshot', 'minion'],
|
|
2590
|
+
tools: ['fs (ls/read/write/edit/mv/rm/mkdir/search)', 'whoami', 'auth', 'session', 'trigger', 'focus', 'tour', 'screenshot', 'minion'],
|
|
2569
2591
|
}, null, 2),
|
|
2570
2592
|
}],
|
|
2571
2593
|
};
|
|
@@ -2583,13 +2605,14 @@ tool('fs', 'Navigate Drafted like a local filesystem. An org is the top folder:
|
|
|
2583
2605
|
title: z.string().optional().describe('[write + googleType] title for a new native file'),
|
|
2584
2606
|
ops: z.array(z.any()).optional().describe('[edit] hashline ops for text frames. Apply ONLY against a fresh fs(read) of the frame: each op = {type, lineHash, newContent} where type is one of replace | delete | insertAfter | insertBefore, and lineHash is the FULL anchor from the read output (line number + hash, e.g. the token left of the |, like 42srt) — NOT a bare hash. delete/replace consume the target line; at most one replace/delete per line per edit (combine into one replace). If an op targets a line that changed since read it is rejected — re-read and retry. Element ops for excalidraw ({id,x,y,...}), or structured ops for office'),
|
|
2585
2607
|
state: z.any().optional().describe('[write] app-frame state (JSON) to persist for a deployed windowType:"app" frame; the canvas hydrates the app from it on load. Max 64KB.'),
|
|
2608
|
+
metadata: z.any().optional().describe('[write] JSON metadata to attach to the written frame (e.g. {"tour": {title, auto?, steps}} to define a guided tour on this frame). Max 64KB.'),
|
|
2586
2609
|
recursive: z.boolean().optional().describe('[ls] recurse into subdirectories'),
|
|
2587
2610
|
lines: z.string().optional().describe('[read] line range (e.g. "1-50") — partial read; content is hashline-annotated so a later edit stays surgical'),
|
|
2588
2611
|
pattern: z.string().optional().describe('[ls] filter filenames (e.g. "*.html")'),
|
|
2589
2612
|
org: z.string().optional().describe('Org (id or name) for bare /wiki and /skills paths (org-scoped /o/<org>/... paths don\'t need it). Per-request only; project paths self-derive org from the project row.'),
|
|
2590
2613
|
projectId: PROJECT_OVERRIDE_PARAM,
|
|
2591
2614
|
}, async (args) => {
|
|
2592
|
-
const { action, path: rawPath, to: rawTo, query, content, file_path, base64, googleType, title, ops, state, recursive, pattern, lines, org } = args;
|
|
2615
|
+
const { action, path: rawPath, to: rawTo, query, content, file_path, base64, googleType, title, ops, state, metadata, recursive, pattern, lines, org } = args;
|
|
2593
2616
|
// Org-scoped path (Shape A): /o/<org>/<root>/... — strip the org segment here,
|
|
2594
2617
|
// carry it as the per-request org scope (orgHeader), validate per-root below.
|
|
2595
2618
|
// The PATH is the address; the org= param is legacy for bare roots only, and a
|
|
@@ -2969,6 +2992,7 @@ tool('fs', 'Navigate Drafted like a local filesystem. An org is the top folder:
|
|
|
2969
2992
|
}
|
|
2970
2993
|
else if (base64) body.base64 = base64;
|
|
2971
2994
|
else return err(new Error('write requires one of content / file_path / base64 / googleType / state'));
|
|
2995
|
+
if (metadata !== undefined) body.metadata = metadata;
|
|
2972
2996
|
const result = await api('PUT', `/api/fs/${filePath}`, body, orgHeader);
|
|
2973
2997
|
if (state !== undefined && result?.id) {
|
|
2974
2998
|
try { await api('POST', `/api/file/${result.id}/state`, { state }); } catch { /* state best-effort */ }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drafted",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.13",
|
|
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": [
|