drafted 1.17.1 → 1.17.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/mcp/server.mjs +25 -3
  2. package/package.json +1 -1
package/mcp/server.mjs CHANGED
@@ -1940,12 +1940,19 @@ if (!isRemote) tool('auth', 'Sign in to Drafted. On a local install the DESKTOP
1940
1940
  // Local install → open the desktop app's sign-in window (no link). Falls through to the
1941
1941
  // device-code flow below only when no desktop app is installed on this platform.
1942
1942
  {
1943
- const existing = getState().sessionId || getBootstrapSessionId();
1944
- if (existing) {
1943
+ const activeSession = getState().sessionId;
1944
+ const bootstrapSession = getBootstrapSessionId();
1945
+ for (const existing of [...new Set([activeSession, bootstrapSession].filter(Boolean))]) {
1945
1946
  try {
1946
1947
  const meRes = await serverFetch(`${getServerUrl()}/auth/me`, { headers: { Cookie: `gc_session=${existing}` } });
1947
1948
  if (meRes.ok) {
1948
1949
  const me = await meRes.json();
1950
+ // A stale cloned agent session must never hide a valid desktop login.
1951
+ if (existing === bootstrapSession && existing !== activeSession) {
1952
+ getState().sessionId = null;
1953
+ await cloneSession();
1954
+ connectAgentWs();
1955
+ }
1949
1956
  return ok({ status: 'already_authenticated', userId: me.userId, email: me.userEmail, org: me.currentOrg?.name });
1950
1957
  }
1951
1958
  } catch { /* stale session — continue to sign-in */ }
@@ -2886,7 +2893,22 @@ tool('fs', 'Navigate Drafted like a local filesystem. An org is the top folder:
2886
2893
  return ok({ ...result, path: `/${layer}/${lane}/${filename}`, sourceType: gw });
2887
2894
  }
2888
2895
  else if (content) body.content = content;
2889
- else if (file_path) body.file_path = file_path;
2896
+ else if (file_path) {
2897
+ // Local-file upload (stdio only): read the file here and send base64.
2898
+ // The HTTP API only accepts content/base64 — forwarding the raw path
2899
+ // makes the server reply 'content or base64 is required' (regression
2900
+ // from the fs consolidation; pre-fs write read the file locally).
2901
+ let resolved = file_path;
2902
+ try { resolved = resolve(file_path); } catch { /* keep as-is */ }
2903
+ if (!existsSync(resolved)) {
2904
+ return err(new Error(`file not found: ${file_path}`));
2905
+ }
2906
+ const buffer = readFileSync(resolved);
2907
+ const ext = extname(resolved).toLowerCase();
2908
+ const MIME = { '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp', '.svg': 'image/svg+xml', '.pdf': 'application/pdf' };
2909
+ body.base64 = buffer.toString('base64');
2910
+ body.contentType = MIME[ext] || 'application/octet-stream';
2911
+ }
2890
2912
  else if (base64) body.base64 = base64;
2891
2913
  else return err(new Error('write requires one of content / file_path / base64 / googleType / state'));
2892
2914
  const result = await api('PUT', `/api/fs/${filePath}`, body, orgHeader);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafted",
3
- "version": "1.17.1",
3
+ "version": "1.17.3",
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": [