drafted 1.19.25 → 1.19.27

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 +52 -18
  2. package/package.json +1 -1
package/mcp/server.mjs CHANGED
@@ -633,6 +633,11 @@ registerAppResource(
633
633
 
634
634
  const AUTH_FILE = process.env.DRAFTED_AUTH_FILE || join(homedir(), '.drafted', 'auth.json');
635
635
  const PENDING_AUTH_FILE = process.env.DRAFTED_PENDING_AUTH_FILE || `${AUTH_FILE}.pending`;
636
+ // The DESKTOP app's own browser session (desktop/src-tauri/src/main.rs writes it beside
637
+ // auth.json). Never read for a credential here — only to answer "is the app signed in?",
638
+ // which is a different question from "is this MCP signed in?" and the one that decides
639
+ // whether an agent can reach the human at all.
640
+ const DESKTOP_SESSION_FILE = join(dirname(AUTH_FILE), 'desktop.json');
636
641
 
637
642
  // Active-project persistence (stdio only): see mcp/active-project-store.mjs.
638
643
  // Persisted so a `system restart mode=mcp` / skill-edit pass that re-spawns the
@@ -2101,6 +2106,51 @@ function desktopAppBinary() {
2101
2106
  return null; // e.g. Linux — no desktop app → device-code fallback
2102
2107
  }
2103
2108
 
2109
+ /**
2110
+ * The answer to "am I signed in?", which is a question about the MACHINE, not this
2111
+ * process. Two things went wrong before this existed, and they are the same mistake:
2112
+ *
2113
+ * - ~/.drafted/auth.json could be missing while the in-process session was fine. The
2114
+ * desktop's credential burn deletes it on purpose, so `login` answered
2115
+ * already_authenticated — truthfully, and uselessly — while every other reader on the
2116
+ * machine stayed signed out. Restore it from the live session.
2117
+ * - The DESKTOP app could be signed out, which is what actually decides whether an agent
2118
+ * asking for a human reaches anybody: its focus listener needs desktop.json. An agent
2119
+ * must never MINT that credential (origin='browser' is the class that may approve
2120
+ * actions), but opening the app's sign-in window is this tool's documented job — and it
2121
+ * usually completes with NO interaction, because the shared cookie store still holds a
2122
+ * valid login.
2123
+ */
2124
+ async function alreadyAuthenticated(me, sessionId) {
2125
+ const out = { status: 'already_authenticated', userId: me.userId, email: me.userEmail, org: me.currentOrg?.name };
2126
+ if (!getBootstrapSessionId()) {
2127
+ try {
2128
+ persistAuthSession({ sessionId, userId: me.userId, orgId: me.currentOrg?.id });
2129
+ out.restoredAuthFile = true;
2130
+ out.note = 'This session was signed in but ~/.drafted/auth.json was missing, so other readers on this machine (the desktop app, the CLI) were not. Rewrote it from the live session.';
2131
+ } catch { /* read-only home: report the truth rather than throwing */ }
2132
+ }
2133
+ const bin = desktopAppBinary();
2134
+ if (!bin) return out; // no app here: saying anything about it is noise
2135
+ if (!existsSync(DESKTOP_SESSION_FILE)) {
2136
+ if (await launchDesktopSignin()) {
2137
+ out.openedDesktopSignin = true;
2138
+ // Wait for the result rather than reporting an optimistic one — answering before it
2139
+ // lands is the same class of lie this whole helper exists to stop.
2140
+ for (let i = 0; i < 20 && !existsSync(DESKTOP_SESSION_FILE); i++) {
2141
+ await new Promise((r) => setTimeout(r, 500));
2142
+ }
2143
+ }
2144
+ }
2145
+ out.desktopSignedIn = existsSync(DESKTOP_SESSION_FILE);
2146
+ if (out.openedDesktopSignin) {
2147
+ out.desktopNote = out.desktopSignedIn
2148
+ ? 'The desktop app was signed out; opened its sign-in window and it completed on its own from the existing browser session.'
2149
+ : 'The desktop app is signed out and its sign-in window is open — it needs one approval there. Until then it holds no session, so an agent asking for attention cannot reach this machine.';
2150
+ }
2151
+ return out;
2152
+ }
2153
+
2104
2154
  async function launchDesktopSignin() {
2105
2155
  const bin = desktopAppBinary();
2106
2156
  if (!bin) return false;
@@ -2181,7 +2231,7 @@ if (!isRemote) tool('auth', 'Sign in to Drafted.\n\n`action=get_link` ALWAYS ret
2181
2231
  await cloneSession();
2182
2232
  connectAgentWs();
2183
2233
  }
2184
- return ok({ status: 'already_authenticated', userId: me.userId, email: me.userEmail, org: me.currentOrg?.name });
2234
+ return ok(await alreadyAuthenticated(me, existing));
2185
2235
  }
2186
2236
  } catch { /* stale session — continue to sign-in */ }
2187
2237
  }
@@ -2227,23 +2277,7 @@ if (!isRemote) tool('auth', 'Sign in to Drafted.\n\n`action=get_link` ALWAYS ret
2227
2277
  // The desktop's focus listener is one of those readers, so an agent asking
2228
2278
  // for a human reached nobody and the tool that exists to fix it reported
2229
2279
  // success.
2230
- let restoredAuthFile = false;
2231
- if (!getBootstrapSessionId()) {
2232
- try {
2233
- persistAuthSession({ sessionId: existing, userId: me.userId, orgId: me.currentOrg?.id });
2234
- restoredAuthFile = true;
2235
- } catch { /* read-only home: report the truth below rather than throwing */ }
2236
- }
2237
- return ok({
2238
- status: 'already_authenticated',
2239
- userId: me.userId,
2240
- email: me.userEmail,
2241
- org: me.currentOrg?.name,
2242
- ...(restoredAuthFile ? {
2243
- restoredAuthFile: true,
2244
- note: 'This session was signed in but ~/.drafted/auth.json was missing, so other readers on this machine (the desktop app, the CLI) were not. Rewrote it from the live session.',
2245
- } : {}),
2246
- });
2280
+ return ok(await alreadyAuthenticated(me, existing));
2247
2281
  }
2248
2282
  } catch { /* session invalid, proceed with login */ }
2249
2283
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafted",
3
- "version": "1.19.25",
3
+ "version": "1.19.27",
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": [