drafted 1.17.9 → 1.17.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 +33 -2
  2. package/package.json +1 -1
package/mcp/server.mjs CHANGED
@@ -2729,9 +2729,16 @@ tool('fs', 'Navigate Drafted like a local filesystem. An org is the top folder:
2729
2729
  return ok({ archived: true, from: canonPath, to: result?.path || archivePath, ...(result?.referrersUpdated ? { referrersUpdated: result.referrersUpdated } : {}) });
2730
2730
  }
2731
2731
  case 'search': {
2732
+ // The gate means "consult the wiki before project writes". Only an
2733
+ // actual search with a real query counts — not the call itself.
2734
+ const q = String(query || '').trim();
2735
+ if (!q) return ok('(provide a query — e.g. fs(search, path="/wiki", query="<terms>"))');
2736
+ const pages = await api('GET', `/api/wiki/search?q=${encodeURIComponent(q)}`, undefined, orgHeader);
2737
+ // Server responds { hits: [...] } — earlier code read .pages/.results,
2738
+ // which are never present, so every MCP wiki search reported empty.
2739
+ const hits = pages?.hits || pages?.pages || pages?.results || [];
2732
2740
  markSearched(gs, 'wiki');
2733
- const pages = await api('GET', `/api/wiki/search?q=${encodeURIComponent(query || '')}`, undefined, orgHeader);
2734
- return ok(formatWikiIndex(pages?.pages || pages?.results || []));
2741
+ return ok(formatWikiIndex(hits));
2735
2742
  }
2736
2743
  default:
2737
2744
  return err(new Error(`fs ${action} not supported for /wiki`));
@@ -2746,6 +2753,11 @@ tool('fs', 'Navigate Drafted like a local filesystem. An org is the top folder:
2746
2753
  }
2747
2754
  switch (action) {
2748
2755
  case 'ls': {
2756
+ // A specific slug is a targeted ls: just that skill, not the whole root.
2757
+ if (slug) {
2758
+ const s = await api('GET', `/api/skills/slug/${slug}`, undefined, orgHeader).catch(() => null);
2759
+ return ok(s ? [{ slug: s.slug, name: s.name, description: s.description }] : []);
2760
+ }
2749
2761
  const list = await api('GET', '/api/skills', undefined, orgHeader);
2750
2762
  const skills = Array.isArray(list) ? list : (list?.skills || []);
2751
2763
  return ok(skills.map(s => ({ slug: s.slug, name: s.name, description: s.description })));
@@ -2842,6 +2854,25 @@ tool('fs', 'Navigate Drafted like a local filesystem. An org is the top folder:
2842
2854
  projectRef = parts[0]; // /projects/<project>
2843
2855
  }
2844
2856
 
2857
+ // fs grammar: the project comes from the PATH, not the shared session
2858
+ // binding — scope the whole call to the path's project (request-local, per
2859
+ // the DRAFT-36 addressing invariant). Without this, /api/fs falls back to
2860
+ // the session's active project (the user's shared row any browser tab or
2861
+ // parallel agent can rewrite), so ls/read/write silently touched the wrong
2862
+ // project and "fixed itself" when something re-bound — the under-reporting
2863
+ // churn reported from the MJ Directive org.
2864
+ if (projectRef) {
2865
+ const pathProject = await resolveProjectRef(projectRef).catch(() => null);
2866
+ if (!pathProject?.id) return err(new Error(`project not found: ${projectRef}`));
2867
+ // An org-scoped path must name a project of that org — never a same-named
2868
+ // project from another org (the path is both address and guardrail).
2869
+ if (orgFromPath && !(await pathOrgMatches(orgFromPath, pathProject))) {
2870
+ return err(new Error(`project ${projectRef} is not in org ${orgFromPath}`));
2871
+ }
2872
+ getState().projectId = pathProject.id;
2873
+ getState().projectMeta = pathProject;
2874
+ }
2875
+
2845
2876
  const run = async () => {
2846
2877
  const hasFile = layer && filename;
2847
2878
  // Layer-root file (lane null) hits the server's 2-segment route.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "drafted",
3
- "version": "1.17.9",
3
+ "version": "1.17.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": [