drafted 1.7.25 → 1.7.26
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 +35 -13
- package/package.json +1 -1
package/mcp/server.mjs
CHANGED
|
@@ -614,34 +614,50 @@ function schedulePendingAuthPoll(delayMs = 2000) {
|
|
|
614
614
|
if (typeof pendingAuthPollTimer.unref === 'function') pendingAuthPollTimer.unref();
|
|
615
615
|
}
|
|
616
616
|
|
|
617
|
+
// Cookie for normal tool operations. Deliberately uses ONLY this instance's
|
|
618
|
+
// per-process session (getState().sessionId) and never the shared root login in
|
|
619
|
+
// ~/.drafted/auth.json. The root is a *credential for minting child sessions*
|
|
620
|
+
// (see cloneSession): every agent process on the machine reads the same root, so
|
|
621
|
+
// operating on it directly is exactly what let one agent's get_org switch move
|
|
622
|
+
// every other agent's active org. ensureSession() guarantees a per-instance
|
|
623
|
+
// session before any operation runs.
|
|
617
624
|
function getAuthHeaders() {
|
|
618
|
-
const sid = getState().sessionId
|
|
625
|
+
const sid = getState().sessionId;
|
|
619
626
|
if (sid) return { Cookie: `gc_session=${sid}` };
|
|
620
627
|
return {};
|
|
621
628
|
}
|
|
622
629
|
|
|
630
|
+
// Mint a fresh per-instance child session from the shared root login and bind it
|
|
631
|
+
// to this process. The root session id (getBootstrapSessionId) is shared by every
|
|
632
|
+
// agent on this machine via ~/.drafted/auth.json; the clone gives THIS process its
|
|
633
|
+
// own server-side session so its active org/project stay isolated from other
|
|
634
|
+
// agents. Returns true once a per-instance session is set.
|
|
623
635
|
async function cloneSession() {
|
|
636
|
+
if (getState().sessionId) return true;
|
|
624
637
|
const bootstrapId = getBootstrapSessionId();
|
|
625
|
-
if (!bootstrapId) return;
|
|
638
|
+
if (!bootstrapId) return false;
|
|
626
639
|
|
|
627
640
|
try {
|
|
628
|
-
const
|
|
629
|
-
const res = await fetch(url, {
|
|
641
|
+
const res = await fetch(`${getServerUrl()}/auth/session/clone`, {
|
|
630
642
|
method: 'POST',
|
|
631
643
|
headers: { Cookie: `gc_session=${bootstrapId}` },
|
|
632
644
|
});
|
|
633
|
-
if (
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
645
|
+
if (res.ok) {
|
|
646
|
+
const data = await res.json();
|
|
647
|
+
if (data.sessionId) {
|
|
648
|
+
getState().sessionId = data.sessionId;
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
637
651
|
}
|
|
638
|
-
} catch { /* server may not be ready yet
|
|
652
|
+
} catch { /* server may not be ready yet; caller retries on next API call */ }
|
|
653
|
+
return false;
|
|
639
654
|
}
|
|
640
655
|
|
|
641
656
|
async function ensureSession() {
|
|
642
657
|
if (getState().sessionId) return;
|
|
643
|
-
|
|
644
|
-
|
|
658
|
+
// A pending device-code login (from `auth get_link`) takes priority; consuming
|
|
659
|
+
// it mints this instance's own session. Otherwise clone the saved root login.
|
|
660
|
+
if (await consumePendingDeviceCode()) return;
|
|
645
661
|
await cloneSession();
|
|
646
662
|
}
|
|
647
663
|
|
|
@@ -1130,10 +1146,14 @@ async function consumePendingDeviceCode() {
|
|
|
1130
1146
|
if (!res.ok) return false;
|
|
1131
1147
|
const data = await res.json();
|
|
1132
1148
|
if (data.status === 'approved' && data.sessionId) {
|
|
1149
|
+
// data.sessionId is the shared ROOT login. Persist it as the machine-level
|
|
1150
|
+
// credential, then mint our OWN per-instance child session from it (mirrors
|
|
1151
|
+
// the `auth login` tool) so this process never operates on the shared root.
|
|
1133
1152
|
persistAuthSession(data);
|
|
1134
|
-
getState().sessionId = data.sessionId;
|
|
1135
1153
|
clearPendingDeviceCode();
|
|
1136
|
-
|
|
1154
|
+
getState().sessionId = null;
|
|
1155
|
+
await cloneSession();
|
|
1156
|
+
return !!getState().sessionId;
|
|
1137
1157
|
}
|
|
1138
1158
|
if (data.status === 'expired') {
|
|
1139
1159
|
clearPendingDeviceCode();
|
|
@@ -1468,6 +1488,7 @@ tool('screenshot', 'Render a PNG via headless browser. `scope=frame` captures a
|
|
|
1468
1488
|
frameId = frame.id;
|
|
1469
1489
|
}
|
|
1470
1490
|
const url = `${getServerUrl()}/api/screenshot/${frameId}?width=${width}&height=${height}&fullPage=${fullPage}`;
|
|
1491
|
+
await ensureSession();
|
|
1471
1492
|
const res = await fetch(url, { headers: getAuthHeaders() });
|
|
1472
1493
|
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
|
|
1473
1494
|
const buffer = await res.arrayBuffer();
|
|
@@ -1486,6 +1507,7 @@ tool('screenshot', 'Render a PNG via headless browser. `scope=frame` captures a
|
|
|
1486
1507
|
targetSlug = active.slug;
|
|
1487
1508
|
}
|
|
1488
1509
|
const url = `${getServerUrl()}/api/canvas-screenshot/${encodeURIComponent(targetSlug)}?layer=${encodeURIComponent(layer)}&width=${width}&height=${height}`;
|
|
1510
|
+
await ensureSession();
|
|
1489
1511
|
const res = await fetch(url, { headers: getAuthHeaders() });
|
|
1490
1512
|
if (!res.ok) throw new Error(`Canvas screenshot failed: ${res.status} ${await res.text()}`);
|
|
1491
1513
|
const buffer = await res.arrayBuffer();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drafted",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.26",
|
|
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": [
|