drafted 1.14.13 → 1.14.14

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/mcp/server.mjs +16 -7
  2. package/package.json +1 -1
package/mcp/server.mjs CHANGED
@@ -1460,11 +1460,12 @@ async function requireBoundOrgForProjectlessMutation(explicitOrg) {
1460
1460
  `Which org? A project-less wiki/skill write needs one, and you belong to ${orgs.length}: ` +
1461
1461
  `${names.join(', ')}. Don't guess — an unaddressed write lands in whichever org this ` +
1462
1462
  `session inherited, which is how a page meant for one org ends up in another.\n` +
1463
- `Recover in ONE call:\n` +
1464
- ` get_org(action="use", org="<name>")binds this session's working org; every ` +
1465
- `later project-less wiki/skill write then just works, no project needed.\n` +
1466
- ` or pass org="<name>" on this single call.\n` +
1467
- ` or project(action="open") if the work belongs to a project — the org derives from it.\n` +
1463
+ `Recover with ONE call: get_org(action="use", org="<name>"). That binds this session's ` +
1464
+ `working org — every later project-less wiki/skill write then just works, with no project ` +
1465
+ `and no org= to repeat. Prefer it over passing org= per call, which pays this toll on ` +
1466
+ `every write.\n` +
1467
+ `(Alternatives: org="<name>" on this single call; or project(action="open") if the work ` +
1468
+ `belongs to a project — the org derives from it.)\n` +
1468
1469
  `Pick from the conversation if the org is clear from context; ask the user only if it isn't.`
1469
1470
  );
1470
1471
  }
@@ -1863,6 +1864,12 @@ async function sessionSurfaceBlock() {
1863
1864
  color: agentSurface.color,
1864
1865
  surfaced: true,
1865
1866
  alive: !!agentSurface.alive,
1867
+ // `alive` was ambiguous: agents couldn't tell whether it meant "your writes are
1868
+ // no-ops" (act differently) or "the user's canvas tab is closed" (ignore). It's the
1869
+ // latter — say so, so nobody changes behavior over it.
1870
+ aliveMeaning: agentSurface.alive
1871
+ ? 'A canvas/desktop surface is live for this session — focus and presence calls will be seen.'
1872
+ : 'No canvas surface is currently open for this session. Frame, wiki, and skill writes all persist normally — only focus/presence have nothing to draw on. Do not change what you write because of this.',
1866
1873
  };
1867
1874
  }
1868
1875
  // No WS ack yet — best-effort identity from /auth/me so callers still get a userId/org.
@@ -2671,7 +2678,7 @@ tool('frame', 'Frame CRUD in the ACTIVE PROJECT. Dispatch by `action`: read (by
2671
2678
  path: z.string().optional().describe('[read] /{layer}/{lane}/{filename}, frame URL, or UUID. [write|edit|anchor] /{layer}/{lane}/{filename}.'),
2672
2679
  lines: z.string().optional().describe('[read] line range (e.g. "1-50"). Omit to read all.'),
2673
2680
  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.'),
2674
- excalidraw_data: z.any().optional().describe('[write_excalidraw] Excalidraw scene JSON object or JSON string. Defaults to an empty scene.'),
2681
+ excalidraw_data: z.any().optional().describe('[write_excalidraw] Excalidraw scene JSON object or JSON string. Defaults to an empty scene. WRITE LEAN SCENES: your MCP client caps tool-call arguments (a big scene is rejected before Drafted ever sees it), so emit only the fields that carry meaning — id, type, x, y, width, height, angle, text/label, strokeColor, backgroundColor, fillStyle, strokeWidth, and the binding ids for arrows. Omit every field the editor can default (version, versionNonce, seed, updated, groupIds, boundElements when empty, roundness, opacity at 100, frameId when null). The editor fills them on open; shipping them can triple the payload for no gain. For a big diagram, write it in passes: create the scene, then frame(action="write_excalidraw") again with the next batch of elements.'),
2675
2682
  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.'),
2676
2683
  file_path: z.string().optional().describe('[write] absolute path to a local file to upload. Mutually exclusive with content/base64/googleType.'),
2677
2684
  base64: z.string().optional().describe('[write] base64-encoded binary content. Mutually exclusive with content/file_path/googleType. Use with content_type when known.'),
@@ -3178,8 +3185,9 @@ tool('ls', 'List contents of the ACTIVE PROJECT. Use ls / after project(action="
3178
3185
  recursive: z.boolean().optional().describe('List contents of subdirectories. When true, forces summary mode (metadata only, no full content) to keep results under the 25k token cap.'),
3179
3186
  summary: z.boolean().optional().describe('Include size, updatedAt, title for frames'),
3180
3187
  pattern: z.string().optional().describe('Glob pattern to filter filenames (e.g. "*.html")'),
3188
+ head: z.number().optional().describe('Include the first N lines of EACH frame inline (max 50). Survey a whole lane in one call instead of one frame(action="read") per frame — read only the frames the heads show you actually need.'),
3181
3189
  limit: z.number().optional().default(500).describe('Max entries to return (default 500, max 2000). Use pattern or path to scope further.'),
3182
- }, async ({ path, recursive, summary, pattern, limit }) => {
3190
+ }, async ({ path, recursive, summary, pattern, head, limit }) => {
3183
3191
  try {
3184
3192
  const params = new URLSearchParams();
3185
3193
  params.set('path', path);
@@ -3194,6 +3202,7 @@ tool('ls', 'List contents of the ACTIVE PROJECT. Use ls / after project(action="
3194
3202
  } else if (summary) {
3195
3203
  params.set('summary', 'true');
3196
3204
  }
3205
+ if (head) params.set('head', String(head));
3197
3206
  if (pattern) params.set('pattern', pattern);
3198
3207
  const result = await api('GET', `/api/fs/?${params.toString()}`);
3199
3208
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafted",
3
- "version": "1.14.13",
3
+ "version": "1.14.14",
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": [