@adobe/design-data-agent-mcp 1.13.0 → 1.14.1

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/README.md CHANGED
@@ -71,11 +71,14 @@ node tools/design-data-agent-mcp/src/index.js
71
71
  | `DESIGN_DATA_SCHEMAS` | — | Override schema path (for `validate`) |
72
72
  | `DESIGN_DATA_EXCEPTIONS` | — | Override exceptions path (for `validate`) |
73
73
  | `DESIGN_DATA_CONFIG` | — | Path to a `.design-data.toml` (or its directory) to resolve a platform cascade |
74
+ | `DESIGN_DATA_PLATFORM` | — | Select a named `[platforms.<id>]` entry (needs `DESIGN_DATA_CONFIG`) |
74
75
 
75
76
  > **Platform cascade.** If `DESIGN_DATA_CONFIG` is set, the server shells out to
76
77
  > the `design-data` CLI once at startup (`design-data query --filter "" --format
77
78
  > json`, run from the config's directory) to resolve its `.design-data.toml`
78
- > source (path/npm/github/git) and any top-level `manifest` cascade, then
79
+ > source (path/npm/github/git) and either its top-level `manifest` cascade or,
80
+ > if `DESIGN_DATA_PLATFORM` is also set, that named `[platforms.<id>]` entry's
81
+ > manifest — mirroring the CLI's own `--platform`/`DESIGN_DATA_PLATFORM`, then
79
82
  > materializes the result to a temp dir and points `primer` / `resolve_token` /
80
83
  > `query_tokens` / `validate_usage` / `describe_component` /
81
84
  > `describe_guideline` / `list_guidelines` at it instead of the embedded
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/design-data-agent-mcp",
3
- "version": "1.13.0",
3
+ "version": "1.14.1",
4
4
  "description": "MCP server and Claude Code skill for the design-data agent surface — read tools run in-process via wasm",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@modelcontextprotocol/sdk": "^1.27.1",
33
- "@adobe/design-data": "3.2.1",
34
- "@adobe/design-data-wasm": "0.10.0",
35
- "@adobe/spectrum-design-data": "3.2.5"
33
+ "@adobe/design-data": "3.2.3",
34
+ "@adobe/design-data-wasm": "0.10.2",
35
+ "@adobe/spectrum-design-data": "3.3.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "ava": "^6.0.1"
@@ -6,7 +6,7 @@ description: >
6
6
  system, token lookup, spec-conformance, drift detection, or token authoring on custom data.
7
7
  metadata:
8
8
  author: adobe
9
- version: "1.13.0"
9
+ version: "1.14.1"
10
10
  when_to_use: >
11
11
  Trigger on: design system, design tokens, spec-conformant, drift, validate tokens, token
12
12
  authoring, custom dataset, DESIGN_DATA_PATH, design-data validate, design-data diff,
@@ -43,18 +43,64 @@ function resolveConfigDir(configPath) {
43
43
  return statSync(configPath).isDirectory() ? configPath : dirname(configPath);
44
44
  }
45
45
 
46
- function resolveManifestPath(configDir) {
46
+ function resolveManifestPath(configDir, platformId) {
47
47
  const configPath = join(configDir, ".design-data.toml");
48
48
  if (!existsSync(configPath)) return null;
49
49
 
50
50
  const configText = readFileSync(configPath, "utf-8");
51
+
52
+ if (platformId) {
53
+ // Named `[platforms.<id>]` entries (spectrum-design-data-h890.27.3) are
54
+ // either a bare local path (`id = "platforms/id/manifest.json"`, matched
55
+ // here) or a remote `github`-sourced table. This regex only resolves the
56
+ // local-path shape — a remote platform entry's extensions/ catalogs still
57
+ // need fetching, which the CLI's `query` shell-out below does not surface
58
+ // to this file; local-path is the shape every platform incubating in this
59
+ // monorepo uses today (see platforms/README.md).
60
+ const idPattern = platformId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
61
+ const match = configText.match(
62
+ new RegExp(`^\\s*${idPattern}\\s*=\\s*["']([^"']+)["']\\s*$`, "m"),
63
+ );
64
+ if (!match) return null;
65
+ const manifestPath = join(configDir, match[1]);
66
+ return existsSync(manifestPath) ? manifestPath : null;
67
+ }
68
+
51
69
  const match = configText.match(/^\s*manifest\s*=\s*["']([^"']+)["']\s*$/m);
52
70
  const manifestPath = join(configDir, match?.[1] ?? "manifest.json");
53
71
  return existsSync(manifestPath) ? manifestPath : null;
54
72
  }
55
73
 
56
- function materializeCatalogs(config, cascadeDir, configDir) {
57
- const manifestPath = resolveManifestPath(configDir);
74
+ /**
75
+ * Determine which named `[platforms.<id>]` entry, if any, the CLI would pick
76
+ * for the *tokens* cascade so catalog materialization can match it exactly.
77
+ * `config.platformId` (from `DESIGN_DATA_PLATFORM`) always wins; otherwise
78
+ * this asks the CLI which id `default_platform` resolves to, via
79
+ * `platform list --format json`, rather than re-implementing the CLI's own
80
+ * precedence rules (`--manifest` > `--platform` > `DESIGN_DATA_PLATFORM` >
81
+ * `default_platform` > legacy `manifest` key) in a second, drifting regex.
82
+ * Returns `null` on any failure (no platforms configured, CLI error,
83
+ * unparsable output) so callers fall back to the legacy `manifest` key.
84
+ */
85
+ async function resolveActivePlatformId(configDir, config, run) {
86
+ if (config.platformId) return config.platformId;
87
+ try {
88
+ const { exitCode, stdout } = await run(
89
+ ["platform", "list", "--format", "json"],
90
+ { timeout: 10_000, cwd: configDir },
91
+ );
92
+ if (exitCode !== 0) return null;
93
+ const rows = JSON.parse(stdout);
94
+ const defaultRow = rows.find((row) => row.default);
95
+ if (!defaultRow || defaultRow.id === "(default)") return null;
96
+ return defaultRow.id;
97
+ } catch {
98
+ return null;
99
+ }
100
+ }
101
+
102
+ function materializeCatalogs(config, cascadeDir, configDir, activePlatformId) {
103
+ const manifestPath = resolveManifestPath(configDir, activePlatformId);
58
104
  let extensionsDir = null;
59
105
  if (manifestPath) {
60
106
  const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
@@ -119,7 +165,13 @@ function mergeGuidelineManifest(targetDir, extensionDir) {
119
165
 
120
166
  /**
121
167
  * Resolve `config.designDataConfig`'s cascade and populate
122
- * `config.cascadeDataPath` / `config.cascadeActive` with the result.
168
+ * `config.cascadeDataPath` / `config.cascadeActive` with the result. If
169
+ * `config.platformId` is set, selects that named `[platforms.<id>]` entry
170
+ * (spectrum-design-data-h890.27.14) — both for the CLI query shell-out and
171
+ * for materializing that platform's `extensions/` catalogs, instead of the
172
+ * legacy top-level `manifest` key. If `platformId` is unset but the config
173
+ * has a `default_platform`, `resolveActivePlatformId` discovers that id from
174
+ * the CLI itself so both halves still agree on the same platform.
123
175
  * Deliberately does not touch `config.dataPath`/`config.dataRoot` — those
124
176
  * remain the fallback anchors for unrelated write/authoring/data tools,
125
177
  * which must keep targeting the real dataset root, not the cascade's
@@ -144,10 +196,25 @@ export async function bootstrapCascade(config, { run = runCli } = {}) {
144
196
  }
145
197
 
146
198
  try {
147
- const { exitCode, stdout, stderr } = await run(
148
- ["query", "--filter", "", "--format", "json"],
149
- { timeout: 60_000, cwd: configDir },
199
+ const activePlatformId = await resolveActivePlatformId(
200
+ configDir,
201
+ config,
202
+ run,
150
203
  );
204
+ const queryArgs = ["query", "--filter", "", "--format", "json"];
205
+ if (activePlatformId) {
206
+ // Must follow the subcommand — see the CLI's own --platform help text
207
+ // on this ordering limitation. Passing this explicitly (even when it
208
+ // only came from `default_platform`, not an explicit selection) keeps
209
+ // the token query and the catalog materialization below looking at
210
+ // the exact same platform, instead of letting the CLI's own default
211
+ // resolution and this file's manifest-path regex potentially disagree.
212
+ queryArgs.push("--platform", activePlatformId);
213
+ }
214
+ const { exitCode, stdout, stderr } = await run(queryArgs, {
215
+ timeout: 60_000,
216
+ cwd: configDir,
217
+ });
151
218
  if (exitCode !== 0) {
152
219
  throw new Error(stderr || `design-data exited with code ${exitCode}`);
153
220
  }
@@ -159,7 +226,7 @@ export async function bootstrapCascade(config, { run = runCli } = {}) {
159
226
  JSON.stringify(tokens),
160
227
  "utf-8",
161
228
  );
162
- materializeCatalogs(config, dir, configDir);
229
+ materializeCatalogs(config, dir, configDir, activePlatformId);
163
230
 
164
231
  config.cascadeDataPath = dir;
165
232
  config.cascadeActive = true;
package/src/config.js CHANGED
@@ -89,6 +89,12 @@ export const config = {
89
89
  // cascadeDataPath/cascadeActive below. Unset by default so an in-repo run's
90
90
  // ambient .design-data.toml (if any) doesn't surprise it.
91
91
  designDataConfig: anchorPath(process.env.DESIGN_DATA_CONFIG ?? null),
92
+ // Selects a named `[platforms.<id>]` entry from designDataConfig's
93
+ // `.design-data.toml` (spectrum-design-data-h890.27.14), mirroring the CLI's
94
+ // own `--platform`/`DESIGN_DATA_PLATFORM`. Has no effect unless
95
+ // designDataConfig is also set. Unset by default: falls back to the config's
96
+ // legacy top-level `manifest` key or `default_platform`, same as the CLI.
97
+ platformId: process.env.DESIGN_DATA_PLATFORM ?? null,
92
98
  // Set by cascade-bootstrap.js on a successful resolve: the temp dir holding
93
99
  // the materialized cascade dataset. Deliberately separate from dataPath —
94
100
  // dataPath/dataRoot are also the fallback anchors for unrelated