drafted 1.14.9 → 1.14.10

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 -6
  2. package/package.json +1 -1
package/mcp/server.mjs CHANGED
@@ -1078,6 +1078,15 @@ function shapeSkillCatalog(result, { limit, offset = 0, compact = false } = {})
1078
1078
  return result;
1079
1079
  }
1080
1080
 
1081
+ // Semantic frame URL (/o/<org>/<project>/<layer>/<lane>/<label>) from a row that
1082
+ // carries slugs (e.g. /api/search hits). Returns null when a slug is missing so the
1083
+ // caller can fall back to the /f/<uuid> resolver.
1084
+ function semanticFrameUrl({ orgSlug, projectSlug, layer, lane, label }) {
1085
+ if (!orgSlug || !projectSlug || !label) return null;
1086
+ const e = encodeURIComponent;
1087
+ return `${getServerUrl()}/o/${e(orgSlug)}/${e(projectSlug)}/${e(layer || 'designs')}/${e(lane || 'default')}/${e(label)}`;
1088
+ }
1089
+
1081
1090
  // Build the structuredContent shape that the frame-preview widget reads.
1082
1091
  // Tools that produce or return a frame (read/write/edit) call this so the
1083
1092
  // model and widget see the same metadata view.
@@ -1093,7 +1102,9 @@ function frameStructuredContent(result, project = null) {
1093
1102
  lane: result.lane,
1094
1103
  width: result.width,
1095
1104
  height: result.height,
1096
- frameUrl: result.id ? `${getServerUrl()}/f/${result.id}` : undefined,
1105
+ // Server emits the semantic /o/<org>/<project>/<layer>/... URL; /f/<uuid> is the
1106
+ // fallback (still resolved + redirected server-side).
1107
+ frameUrl: result.frameUrl || (result.id ? `${getServerUrl()}/f/${result.id}` : undefined),
1097
1108
  project, // {id, slug, name, orgId} of the active project — visible in client UI
1098
1109
  };
1099
1110
  }
@@ -1880,17 +1891,21 @@ tool('project', 'START HERE for project management. Dispatch by `action`: list (
1880
1891
  joinAgentWsRoom(projectId);
1881
1892
  const base = getServerUrl();
1882
1893
  let projectSlug = projectId;
1883
- let projectMeta = { id: projectId, slug: null, name: null, orgId: null };
1894
+ let orgSlug = null;
1895
+ let projectMeta = { id: projectId, slug: null, name: null, orgId: null, orgSlug: null };
1884
1896
  try {
1885
1897
  const data = await api('GET', '/api/projects');
1886
1898
  const proj = (data.projects || []).find(p => p.id === projectId);
1887
1899
  if (proj) {
1888
1900
  projectSlug = proj.slug || projectId;
1889
- projectMeta = { id: proj.id, slug: proj.slug || null, name: proj.name || null, orgId: proj.orgId || null };
1901
+ orgSlug = proj.orgSlug || null;
1902
+ projectMeta = { id: proj.id, slug: proj.slug || null, name: proj.name || null, orgId: proj.orgId || null, orgSlug };
1890
1903
  }
1891
1904
  } catch { /* fall back to projectId */ }
1892
1905
  setMcpActiveProject(projectId, projectMeta);
1893
- const url = `${base}/project/${projectSlug}`;
1906
+ // Semantic /o/<org-slug>/<project-slug> when the org slug is known; otherwise
1907
+ // the /project/<slug> resolver redirects to it.
1908
+ const url = orgSlug ? `${base}/o/${encodeURIComponent(orgSlug)}/${encodeURIComponent(projectSlug)}` : `${base}/project/${projectSlug}`;
1894
1909
  // Surfacing to the user is the focus mechanism's job now (agent-active ping ->
1895
1910
  // desktop window / notification+glow for browser tabs) — this used to also force
1896
1911
  // `exec('open <url>')` on the MCP host machine, an unsolicited GUI action that both
@@ -3039,7 +3054,7 @@ tool('frame', 'Frame CRUD in the ACTIVE PROJECT. Dispatch by `action`: read (by
3039
3054
  path: `/${r.layer}/${r.lane}/${r.label}`,
3040
3055
  project: r.projectName,
3041
3056
  projectId: r.projectId,
3042
- frameUrl: `${getServerUrl()}/f/${r.id}`,
3057
+ frameUrl: semanticFrameUrl(r) || `${getServerUrl()}/f/${r.id}`,
3043
3058
  contentType: r.contentType,
3044
3059
  updatedAt: r.updatedAt,
3045
3060
  })),
@@ -3112,7 +3127,11 @@ tool('ls', 'List contents of the ACTIVE PROJECT. Use ls / after project(action="
3112
3127
  const projectId = getState().projectId;
3113
3128
  const structuredContent = {
3114
3129
  project: result?.project || result?.projectName,
3115
- canvasUrl: result?.projectSlug ? `${getServerUrl()}/project/${result.projectSlug}` : undefined,
3130
+ canvasUrl: result?.project?.slug
3131
+ ? (result.project.orgSlug
3132
+ ? `${getServerUrl()}/o/${encodeURIComponent(result.project.orgSlug)}/${encodeURIComponent(result.project.slug)}`
3133
+ : `${getServerUrl()}/project/${encodeURIComponent(result.project.slug)}`)
3134
+ : undefined,
3116
3135
  byLayer,
3117
3136
  truncated: result?.truncated || false,
3118
3137
  totalAvailable: result?.totalAvailable,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafted",
3
- "version": "1.14.9",
3
+ "version": "1.14.10",
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": [