drafted 1.7.2 → 1.7.4

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 +51 -4
  2. package/package.json +5 -2
package/mcp/server.mjs CHANGED
@@ -350,7 +350,28 @@ async function api(method, path, body, _retried) {
350
350
  data = { text };
351
351
  }
352
352
 
353
- if (!res.ok) throw new Error(data.error || `HTTP ${res.status}`);
353
+ if (!res.ok) {
354
+ const msg = data.error || `HTTP ${res.status}`;
355
+ // The active project no longer resolves in the current org context.
356
+ // This is the silent-drift bug: project.open set a project, then
357
+ // something switched the active org (parallel agent, browser tab, or
358
+ // a get_org switch), and now the project is invisible. Clear our
359
+ // sticky reference so the next tool call doesn't append a stale
360
+ // projectId to its URL — and tell the agent what happened.
361
+ if ((res.status === 404 || /project not found/i.test(msg)) && pid && getState().projectId === pid) {
362
+ const meta = getState().projectMeta;
363
+ getState().projectId = null;
364
+ getState().projectMeta = null;
365
+ const sess = getSessionState();
366
+ sess.activeProjectId = null;
367
+ sess.activeProjectMeta = null;
368
+ throw new Error(
369
+ `${msg} — the active project (${meta?.slug || pid}) is no longer in the current org. ` +
370
+ `Active project cleared. Call project(action="open") to set a new one, or proceed without one for org-scoped tools (wiki, skill).`
371
+ );
372
+ }
373
+ throw new Error(msg);
374
+ }
354
375
  return data;
355
376
  }
356
377
 
@@ -436,6 +457,25 @@ function setMcpActiveProject(projectId, meta = null) {
436
457
  sess.activeProjectMeta = meta;
437
458
  }
438
459
 
460
+ // Clear the active project if its orgId no longer matches the current org.
461
+ // Catches the silent drift where org switches (via get_org switch, browser
462
+ // tab, parallel agent, etc.) leave the MCP session pointing at a project
463
+ // the API can no longer see — which surfaces as confusing "Project not
464
+ // found" errors on otherwise-valid tool calls.
465
+ async function ensureProjectMatchesOrg() {
466
+ const s = getState();
467
+ const meta = s.projectMeta;
468
+ if (!s.projectId || !meta?.orgId) return;
469
+ const currentOrgId = await getCurrentOrgId();
470
+ if (currentOrgId && currentOrgId !== meta.orgId) {
471
+ s.projectId = null;
472
+ s.projectMeta = null;
473
+ const sess = getSessionState();
474
+ sess.activeProjectId = null;
475
+ sess.activeProjectMeta = null;
476
+ }
477
+ }
478
+
439
479
  // Returns { id, slug, name, orgId } for the project this MCP session most
440
480
  // recently opened — what frame mutations will actually target. Echoed on
441
481
  // every mutation so silent cross-project drift is visible.
@@ -1808,9 +1848,16 @@ tool('skill', 'Manage the Drafted skill library. Skills are reusable prompts/gui
1808
1848
  // empty-org / wiki-only sessions where there's no project to bind to.
1809
1849
  const explicit = args.projectId;
1810
1850
  const active = getState().projectId;
1811
- if (explicit || active) {
1812
- const pid = explicit || active;
1813
- return ok(await api('GET', `/api/projects/${pid}/skills`));
1851
+ const pid = explicit || active;
1852
+ if (pid) {
1853
+ try {
1854
+ return ok(await api('GET', `/api/projects/${pid}/skills`));
1855
+ } catch (e) {
1856
+ // 404 / "not found" means the project isn't visible in the
1857
+ // current org (typical after an org switch). Fall through to
1858
+ // org-attached skills rather than bubbling a useless error.
1859
+ if (!/not found/i.test(e.message)) throw e;
1860
+ }
1814
1861
  }
1815
1862
  const orgId = await getCurrentOrgId();
1816
1863
  if (!orgId) throw new Error('No active org. Call get_org first or pass projectId.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafted",
3
- "version": "1.7.2",
3
+ "version": "1.7.4",
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": [
@@ -25,7 +25,10 @@
25
25
  "db:clean-sessions": "tsx src/auth/cleanup.ts",
26
26
  "import:legacy": "tsx scripts/import-legacy.mts",
27
27
  "test": "vitest run",
28
- "test:watch": "vitest"
28
+ "test:watch": "vitest",
29
+ "version": "node scripts/sync-versions.mjs && git add plugin/.claude-plugin/plugin.json .claude-plugin/marketplace.json",
30
+ "version:check": "node scripts/sync-versions.mjs",
31
+ "postpublish": "bash scripts/sync-plugin.sh \"chore: sync plugin to v$npm_package_version\""
29
32
  },
30
33
  "dependencies": {
31
34
  "@aws-sdk/client-s3": "^3.1007.0",