@adobe/design-data-agent-mcp 1.4.1 → 1.6.0
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/LICENSE +1 -1
- package/README.md +6 -5
- package/package.json +4 -2
- package/skills/design-data/SKILL.md +76 -93
- package/src/tools/authoring.js +56 -77
- package/src/tools/diff.js +33 -7
- package/src/tools/read.js +117 -36
- package/src/tools/validate.js +17 -12
- package/src/tools/write.js +2 -7
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@ file or class name and description of purpose be included on the
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright 2026 Adobe
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `@adobe/design-data-agent-mcp`
|
|
2
2
|
|
|
3
|
-
MCP server and Claude Code skill for the [Spectrum Design Data](../../packages/design-data/) agent surface.
|
|
3
|
+
MCP server and Claude Code skill for the [Spectrum Design Data](../../packages/design-data/) agent surface. Read tools (`primer`, `resolve_token`, `query_tokens`, `describe_component`) run fully in-process via `@adobe/design-data-wasm` — no CLI binary required for those. Only `authoring_session_step_intent` still invokes the native binary (for NLP suggest ranking, not yet on the wasm surface).
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -29,7 +29,7 @@ https://github.com/adobe/spectrum-design-data/tree/main/tools/design-data-agent-
|
|
|
29
29
|
npx @adobe/design-data-agent-mcp
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
The `@adobe/design-data` CLI binary is **only** needed for `authoring_session_step_intent`. All other tools run in-process. Set `DESIGN_DATA_BIN` if the binary is not on `PATH`.
|
|
33
33
|
|
|
34
34
|
## MCP server
|
|
35
35
|
|
|
@@ -49,7 +49,7 @@ node tools/design-data-agent-mcp/src/index.js
|
|
|
49
49
|
|
|
50
50
|
| Variable | Default | Description |
|
|
51
51
|
| ------------------------ | ------------- | ------------------------------------------------- |
|
|
52
|
-
| `DESIGN_DATA_BIN` | `design-data` | Path to the `design-data` binary
|
|
52
|
+
| `DESIGN_DATA_BIN` | `design-data` | Path to the `design-data` binary (authoring only) |
|
|
53
53
|
| `DESIGN_DATA_ROOT` | — | Absolute root that relative paths are anchored to |
|
|
54
54
|
| `DESIGN_DATA_PATH` | `.` | Dataset root path |
|
|
55
55
|
| `DESIGN_DATA_COMPONENTS` | — | Override components directory |
|
|
@@ -74,8 +74,9 @@ node tools/design-data-agent-mcp/src/index.js
|
|
|
74
74
|
> `packages/design-data`; when published it uses the installed dependency. This
|
|
75
75
|
> is independent of the working directory.
|
|
76
76
|
> 3. **Fallback.** `dataPath` falls back to the (anchored) current directory; the
|
|
77
|
-
> component/field overrides fall back to
|
|
78
|
-
>
|
|
77
|
+
> component/field overrides fall back to `null` (not supplied), which means
|
|
78
|
+
> `describe_component` will throw an error if `@adobe/spectrum-design-data` is
|
|
79
|
+
> not resolvable.
|
|
79
80
|
>
|
|
80
81
|
> In a monorepo checkout you typically need no `DESIGN_DATA_*` env vars at all —
|
|
81
82
|
> resolution via the workspace package handles it.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/design-data-agent-mcp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "MCP server and Claude Code skill for the design-data agent surface —
|
|
3
|
+
"version": "1.6.0",
|
|
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",
|
|
7
7
|
"bin": {
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@modelcontextprotocol/sdk": "^1.27.1",
|
|
33
|
+
"@adobe/design-data": "2.0.0",
|
|
34
|
+
"@adobe/design-data-wasm": "0.1.0",
|
|
33
35
|
"@adobe/spectrum-design-data": "0.3.0"
|
|
34
36
|
},
|
|
35
37
|
"devDependencies": {
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
name: design-data-agent
|
|
3
3
|
description: >
|
|
4
4
|
Validate, query, resolve, diff, and author spec-conformant design tokens and components using the
|
|
5
|
-
design-data
|
|
5
|
+
design-data MCP tools against a local dataset. Use when the user asks about design tokens, a design
|
|
6
6
|
system, token lookup, spec-conformance, drift detection, or token authoring on custom data.
|
|
7
7
|
when_to_use: >
|
|
8
8
|
Trigger on: design system, design tokens, spec-conformant, drift, validate tokens, token
|
|
9
9
|
authoring, custom dataset, DESIGN_DATA_PATH, design-data validate, design-data diff,
|
|
10
10
|
design-data write, product-context.json.
|
|
11
|
-
allowed-tools:
|
|
11
|
+
allowed-tools: mcp__design-data-agent__primer, mcp__design-data-agent__query_tokens, mcp__design-data-agent__resolve_token, mcp__design-data-agent__describe_component, mcp__design-data-agent__validate_usage, mcp__design-data-agent__diff_datasets, mcp__design-data-agent__write, mcp__design-data-agent__start_authoring_session, mcp__design-data-agent__authoring_session_step_intent, mcp__design-data-agent__authoring_session_step_classification, mcp__design-data-agent__authoring_session_step_values, mcp__design-data-agent__authoring_session_commit, mcp__design-data-agent__authoring_session_cancel, mcp__design-data-agent__authoring_session_get, mcp__design-data-agent__authoring_session_list
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# design-data agent skill
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
`@adobe/design-data-agent-mcp` provides in-process wasm tools for validating, querying,
|
|
17
|
+
resolving, diffing, and authoring spec-conformant tokens and components from any dataset
|
|
18
|
+
on the local filesystem.
|
|
17
19
|
|
|
18
|
-
Set two path variables once and reference them throughout
|
|
20
|
+
Set two path variables once and reference them throughout:
|
|
19
21
|
|
|
20
22
|
```bash
|
|
21
23
|
export DESIGN_DATA_PATH=./packages/design-data/tokens
|
|
@@ -26,55 +28,50 @@ For Spectrum tokens with zero setup (embedded snapshot), use the `design-data` s
|
|
|
26
28
|
|
|
27
29
|
## Bootstrap
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
Add `@adobe/design-data-agent-mcp` to your `.cursor/mcp.json`:
|
|
30
32
|
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"design-data-agent": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["-y", "@adobe/design-data-agent-mcp"],
|
|
39
|
+
"env": {
|
|
40
|
+
"DESIGN_DATA_PATH": "./packages/tokens/src",
|
|
41
|
+
"DESIGN_DATA_COMPONENTS": "./packages/design-data/components",
|
|
42
|
+
"DESIGN_DATA_FIELDS": "./packages/design-data/fields"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
31
47
|
```
|
|
32
|
-
|
|
33
|
-
|
|
48
|
+
|
|
49
|
+
Adjust paths to match your dataset layout.
|
|
34
50
|
|
|
35
51
|
***
|
|
36
52
|
|
|
37
53
|
## Session start — call `primer` first
|
|
38
54
|
|
|
39
|
-
Call `primer` at the start of every session that touches design data. It returns the active
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
npx @adobe/design-data primer "$DESIGN_DATA_PATH" --format json \
|
|
43
|
-
--components-dir "$DESIGN_DATA_SPEC_PATH/components" \
|
|
44
|
-
--fields-dir "$DESIGN_DATA_SPEC_PATH/fields"
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
Always pass `--components-dir` and `--fields-dir` explicitly. These directories live under `packages/design-data/`, alongside the token dataset. The CLI defaults probe those paths relative to CWD, so omitting the flags when running from an arbitrary directory (or with an absolute `DESIGN_DATA_PATH`) produces empty `components` and `taxonomyFields`.
|
|
48
|
-
|
|
49
|
-
The payload includes `specVersion`, `manifest`, `components`, `taxonomyFields`, and `tokenCount`.
|
|
55
|
+
Call `primer` at the start of every session that touches design data. It returns the active
|
|
56
|
+
dimensions, component list, taxonomy fields, and token count — structural context that scopes
|
|
57
|
+
all subsequent lookups. No inputs required.
|
|
50
58
|
|
|
51
59
|
***
|
|
52
60
|
|
|
53
61
|
## Token lookup
|
|
54
62
|
|
|
55
|
-
### Resolve a token to its literal value
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
npx @adobe/design-data resolve <property> "$DESIGN_DATA_PATH" --format json \
|
|
59
|
-
[--color-scheme light|dark] \
|
|
60
|
-
[--scale desktop|mobile] \
|
|
61
|
-
[--contrast regular|high]
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Example:
|
|
63
|
+
### Resolve a token to its literal value — `resolve_token`
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```
|
|
65
|
+
Required: `property` (string) — e.g. `"accent-background-color-default"`
|
|
66
|
+
Optional: `colorScheme` (`"light"` or `"dark"`), `scale` (`"desktop"` or `"mobile"`),
|
|
67
|
+
`contrast` (`"regular"` or `"high"`)
|
|
70
68
|
|
|
71
|
-
### Query tokens by filter expression
|
|
69
|
+
### Query tokens by filter expression — `query_tokens`
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
npx @adobe/design-data query "$DESIGN_DATA_PATH" --filter "<expr>" --format json
|
|
75
|
-
```
|
|
71
|
+
Required: `filter` (string)
|
|
76
72
|
|
|
77
|
-
Valid filter keys: `property`, `component`, `variant`, `state`, `colorScheme`, `scale`,
|
|
73
|
+
Valid filter keys: `property`, `component`, `variant`, `state`, `colorScheme`, `scale`,
|
|
74
|
+
`contrast`, `uuid`, `$schema`.
|
|
78
75
|
|
|
79
76
|
Filter syntax examples:
|
|
80
77
|
|
|
@@ -87,64 +84,71 @@ property=background-color|property=border-color
|
|
|
87
84
|
$schema=https://spectrum.adobe.com/page/design-token/
|
|
88
85
|
```
|
|
89
86
|
|
|
90
|
-
> **Exit codes:** `0` = matches found;
|
|
87
|
+
> **Exit codes:** `0` = matches found; empty array = no matches (not an error).
|
|
91
88
|
|
|
92
89
|
***
|
|
93
90
|
|
|
94
|
-
## Component info
|
|
91
|
+
## Component info — `describe_component`
|
|
95
92
|
|
|
96
|
-
|
|
97
|
-
npx @adobe/design-data component <id> --components-dir "$DESIGN_DATA_SPEC_PATH/components"
|
|
98
|
-
```
|
|
93
|
+
Required: `id` (string) — kebab-case component ID, e.g. `button`, `action-button`
|
|
99
94
|
|
|
100
|
-
Returns the component contract: `name`, `displayName`, `options`, `anatomy`, `states`,
|
|
95
|
+
Returns the component contract: `name`, `displayName`, `options`, `anatomy`, `states`,
|
|
96
|
+
and `tokenBindings`.
|
|
101
97
|
|
|
102
|
-
|
|
98
|
+
***
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
## Validation — `validate_usage`
|
|
105
101
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
102
|
+
Optional inputs:
|
|
103
|
+
|
|
104
|
+
* `path` — dataset path (defaults to `DESIGN_DATA_PATH`)
|
|
105
|
+
* `strict` (boolean) — treat warnings as errors
|
|
106
|
+
* `schema_path` — override schemas directory (defaults to `@adobe/spectrum-tokens` schemas)
|
|
107
|
+
|
|
108
|
+
Runs Layer-1 JSON-Schema structural validation and Layer-2 relational rules.
|
|
109
|
+
Returns `{ valid, errors, warnings }`.
|
|
110
|
+
|
|
111
|
+
> **Note:** `--exceptions-path` (SPEC-007 naming allowlist) is not supported in the
|
|
112
|
+
> in-process path. Use the `design-data` CLI directly if you need exceptions support.
|
|
109
113
|
|
|
110
114
|
***
|
|
111
115
|
|
|
112
|
-
##
|
|
116
|
+
## Dataset diff — `diff_datasets`
|
|
113
117
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
[--schema-path <path>] \
|
|
117
|
-
[--exceptions-path <path>] \
|
|
118
|
-
[--strict]
|
|
119
|
-
```
|
|
118
|
+
Required: `oldPath`, `newPath`
|
|
119
|
+
Optional: `filter` (substring to narrow results by token name)
|
|
120
120
|
|
|
121
|
-
Returns
|
|
121
|
+
Returns `{ renamed, deprecated, reverted, added, deleted, updated }`.
|
|
122
122
|
|
|
123
123
|
***
|
|
124
124
|
|
|
125
|
-
##
|
|
125
|
+
## Product-layer authoring — `write`
|
|
126
126
|
|
|
127
|
-
|
|
128
|
-
npx @adobe/design-data diff <old-path> <new-path> --format json [--filter <expr>]
|
|
129
|
-
```
|
|
127
|
+
Write or update the product context document in the dataset.
|
|
130
128
|
|
|
131
|
-
|
|
129
|
+
Optional inputs: `output` (defaults to `$DESIGN_DATA_PATH/product-context.json`),
|
|
130
|
+
`rationale` (string)
|
|
132
131
|
|
|
133
132
|
***
|
|
134
133
|
|
|
135
|
-
##
|
|
134
|
+
## Token authoring session
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
Use the following tools in sequence to create a new token through the wizard:
|
|
138
137
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
1. **`start_authoring_session`** — start a session (returns `session_id`)
|
|
139
|
+
2. **`authoring_session_step_intent`** — provide natural-language intent; get token suggestions
|
|
140
|
+
3. **`authoring_session_step_classification`** — set layer, property, name fields
|
|
141
|
+
4. **`authoring_session_step_values`** — set mode-specific value rows
|
|
142
|
+
5. **`authoring_session_commit`** — validate and write the token to disk
|
|
143
|
+
6. **`authoring_session_cancel`** — cancel without writing
|
|
144
144
|
|
|
145
|
-
|
|
145
|
+
Helper tools: `authoring_session_get` (inspect state), `authoring_session_list` (all active sessions).
|
|
146
146
|
|
|
147
|
-
|
|
147
|
+
`authoring_session_commit` accepts an optional `schema_path` to override the schemas directory
|
|
148
|
+
for Layer-1 JSON-Schema validation before writing.
|
|
149
|
+
|
|
150
|
+
> **Note:** `authoring_session_step_intent` (NLP suggestion ranking) still delegates to the
|
|
151
|
+
> `design-data` CLI because the NLP `suggest` API is not yet on the wasm surface.
|
|
148
152
|
|
|
149
153
|
***
|
|
150
154
|
|
|
@@ -152,9 +156,8 @@ Generates a product-context scaffold at the output path (`specVersion`, `layer:
|
|
|
152
156
|
|
|
153
157
|
* **Scale values:** `desktop` and `mobile` — not `medium`/`large`.
|
|
154
158
|
* **Contrast values:** `regular` and `high` — not `standard`/`high`.
|
|
155
|
-
* **`
|
|
156
|
-
* **`
|
|
157
|
-
* **`--format json`** — always pass this in agent and script contexts; the CLI pretty-prints when stdout is a TTY.
|
|
159
|
+
* **`query_tokens` returns `[]`** when no tokens match — not an error.
|
|
160
|
+
* **`diff_datasets` filter** matches by token name substring (case-insensitive).
|
|
158
161
|
|
|
159
162
|
## When working in Cursor
|
|
160
163
|
|
|
@@ -163,23 +166,3 @@ Cursor Settings → Rules → **Add Rule** → **Remote Rule (GitHub)** → past
|
|
|
163
166
|
```
|
|
164
167
|
https://github.com/adobe/spectrum-design-data/tree/main/tools/design-data-agent-mcp/skills/design-data
|
|
165
168
|
```
|
|
166
|
-
|
|
167
|
-
For always-available tool access (higher context cost), add `@adobe/design-data-agent-mcp` to `.cursor/mcp.json`:
|
|
168
|
-
|
|
169
|
-
```json
|
|
170
|
-
{
|
|
171
|
-
"mcpServers": {
|
|
172
|
-
"design-data-agent": {
|
|
173
|
-
"command": "npx",
|
|
174
|
-
"args": ["-y", "@adobe/design-data-agent-mcp"],
|
|
175
|
-
"env": {
|
|
176
|
-
"DESIGN_DATA_PATH": "./packages/tokens/src",
|
|
177
|
-
"DESIGN_DATA_COMPONENTS": "./packages/design-data/components",
|
|
178
|
-
"DESIGN_DATA_FIELDS": "./packages/design-data/fields"
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
Adjust paths to match your dataset layout.
|
package/src/tools/authoring.js
CHANGED
|
@@ -8,21 +8,27 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Authoring-session tools for design-data-agent-mcp.
|
|
13
|
+
*
|
|
14
|
+
* Most operations use @adobe/design-data (on-disk session store) and run
|
|
15
|
+
* fully in-process. The exception is authoring_session_step_intent, which still
|
|
16
|
+
* delegates to the CLI because the NLP `suggest` ranking is not yet on the wasm
|
|
17
|
+
* surface. When that API is added, step_intent can be migrated here too.
|
|
18
|
+
*/
|
|
15
19
|
|
|
20
|
+
import {
|
|
21
|
+
startSession,
|
|
22
|
+
getSession,
|
|
23
|
+
listSessions,
|
|
24
|
+
stepClassification,
|
|
25
|
+
stepValues,
|
|
26
|
+
commitSession,
|
|
27
|
+
cancelSession,
|
|
28
|
+
} from "@adobe/design-data/session";
|
|
16
29
|
import { runCli } from "../cli.js";
|
|
17
30
|
import { config } from "../config.js";
|
|
18
31
|
|
|
19
|
-
async function callCli(args) {
|
|
20
|
-
const { exitCode, stdout, stderr } = await runCli(args, { timeout: 30_000 });
|
|
21
|
-
if (exitCode !== 0)
|
|
22
|
-
throw new Error(stderr || `authoring-session exited ${exitCode}`);
|
|
23
|
-
return JSON.parse(stdout);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
32
|
export function createAuthoringTools() {
|
|
27
33
|
return [
|
|
28
34
|
{
|
|
@@ -48,7 +54,7 @@ export function createAuthoringTools() {
|
|
|
48
54
|
"dataset_path is required (or set DESIGN_DATA_PATH in the environment)",
|
|
49
55
|
);
|
|
50
56
|
}
|
|
51
|
-
return
|
|
57
|
+
return startSession(path);
|
|
52
58
|
},
|
|
53
59
|
},
|
|
54
60
|
|
|
@@ -71,15 +77,25 @@ export function createAuthoringTools() {
|
|
|
71
77
|
additionalProperties: false,
|
|
72
78
|
},
|
|
73
79
|
async handler({ session_id, intent }) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
// step_intent requires NLP suggest ranking — still uses the CLI.
|
|
81
|
+
// Will be migrated when suggest is added to the wasm surface.
|
|
82
|
+
const { exitCode, stdout, stderr } = await runCli(
|
|
83
|
+
[
|
|
84
|
+
"authoring-session",
|
|
85
|
+
"step",
|
|
86
|
+
"intent",
|
|
87
|
+
"--session-id",
|
|
88
|
+
session_id,
|
|
89
|
+
"--intent",
|
|
90
|
+
intent,
|
|
91
|
+
],
|
|
92
|
+
{ timeout: 30_000 },
|
|
93
|
+
);
|
|
94
|
+
if (exitCode !== 0)
|
|
95
|
+
throw new Error(
|
|
96
|
+
stderr || `authoring-session step intent exited ${exitCode}`,
|
|
97
|
+
);
|
|
98
|
+
return JSON.parse(stdout);
|
|
83
99
|
},
|
|
84
100
|
},
|
|
85
101
|
|
|
@@ -118,21 +134,11 @@ export function createAuthoringTools() {
|
|
|
118
134
|
additionalProperties: false,
|
|
119
135
|
},
|
|
120
136
|
async handler({ session_id, layer, property, name_fields = [] }) {
|
|
121
|
-
|
|
122
|
-
"authoring-session",
|
|
123
|
-
"step",
|
|
124
|
-
"classification",
|
|
125
|
-
"--session-id",
|
|
126
|
-
session_id,
|
|
127
|
-
"--layer",
|
|
137
|
+
return stepClassification(session_id, {
|
|
128
138
|
layer,
|
|
129
|
-
"--property",
|
|
130
139
|
property,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
args.push("--name-field", `${key}=${value}`);
|
|
134
|
-
}
|
|
135
|
-
return callCli(args);
|
|
140
|
+
nameFields: name_fields,
|
|
141
|
+
});
|
|
136
142
|
},
|
|
137
143
|
},
|
|
138
144
|
|
|
@@ -174,15 +180,7 @@ export function createAuthoringTools() {
|
|
|
174
180
|
additionalProperties: false,
|
|
175
181
|
},
|
|
176
182
|
async handler({ session_id, rows }) {
|
|
177
|
-
return
|
|
178
|
-
"authoring-session",
|
|
179
|
-
"step",
|
|
180
|
-
"values",
|
|
181
|
-
"--session-id",
|
|
182
|
-
session_id,
|
|
183
|
-
"--rows",
|
|
184
|
-
JSON.stringify(rows),
|
|
185
|
-
]);
|
|
183
|
+
return stepValues(session_id, rows);
|
|
186
184
|
},
|
|
187
185
|
},
|
|
188
186
|
|
|
@@ -217,7 +215,9 @@ export function createAuthoringTools() {
|
|
|
217
215
|
schema_path: {
|
|
218
216
|
type: "string",
|
|
219
217
|
description:
|
|
220
|
-
"Path to schemas directory
|
|
218
|
+
"Path to schemas directory containing token-types/ and token-file.json. " +
|
|
219
|
+
"Used for Layer-1 JSON-Schema validation before writing. " +
|
|
220
|
+
"Defaults to @adobe/spectrum-tokens schemas when omitted.",
|
|
221
221
|
},
|
|
222
222
|
is_override: {
|
|
223
223
|
type: "boolean",
|
|
@@ -236,22 +236,15 @@ export function createAuthoringTools() {
|
|
|
236
236
|
schema_path,
|
|
237
237
|
is_override = false,
|
|
238
238
|
}) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
"--session-id",
|
|
243
|
-
session_id,
|
|
244
|
-
"--schema-url",
|
|
245
|
-
schema_url,
|
|
246
|
-
"--target",
|
|
239
|
+
return commitSession({
|
|
240
|
+
sessionId: session_id,
|
|
241
|
+
schemaUrl: schema_url,
|
|
247
242
|
target,
|
|
248
|
-
"--rationale",
|
|
249
243
|
rationale,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return callCli(args);
|
|
244
|
+
productContext: product_context,
|
|
245
|
+
schemaPath: schema_path ?? null,
|
|
246
|
+
isOverride: is_override,
|
|
247
|
+
});
|
|
255
248
|
},
|
|
256
249
|
},
|
|
257
250
|
|
|
@@ -261,18 +254,11 @@ export function createAuthoringTools() {
|
|
|
261
254
|
inputSchema: {
|
|
262
255
|
type: "object",
|
|
263
256
|
required: ["session_id"],
|
|
264
|
-
properties: {
|
|
265
|
-
session_id: { type: "string" },
|
|
266
|
-
},
|
|
257
|
+
properties: { session_id: { type: "string" } },
|
|
267
258
|
additionalProperties: false,
|
|
268
259
|
},
|
|
269
260
|
async handler({ session_id }) {
|
|
270
|
-
return
|
|
271
|
-
"authoring-session",
|
|
272
|
-
"cancel",
|
|
273
|
-
"--session-id",
|
|
274
|
-
session_id,
|
|
275
|
-
]);
|
|
261
|
+
return cancelSession(session_id);
|
|
276
262
|
},
|
|
277
263
|
},
|
|
278
264
|
|
|
@@ -282,18 +268,11 @@ export function createAuthoringTools() {
|
|
|
282
268
|
inputSchema: {
|
|
283
269
|
type: "object",
|
|
284
270
|
required: ["session_id"],
|
|
285
|
-
properties: {
|
|
286
|
-
session_id: { type: "string" },
|
|
287
|
-
},
|
|
271
|
+
properties: { session_id: { type: "string" } },
|
|
288
272
|
additionalProperties: false,
|
|
289
273
|
},
|
|
290
274
|
async handler({ session_id }) {
|
|
291
|
-
return
|
|
292
|
-
"authoring-session",
|
|
293
|
-
"get",
|
|
294
|
-
"--session-id",
|
|
295
|
-
session_id,
|
|
296
|
-
]);
|
|
275
|
+
return getSession(session_id);
|
|
297
276
|
},
|
|
298
277
|
},
|
|
299
278
|
|
|
@@ -306,7 +285,7 @@ export function createAuthoringTools() {
|
|
|
306
285
|
additionalProperties: false,
|
|
307
286
|
},
|
|
308
287
|
async handler() {
|
|
309
|
-
return
|
|
288
|
+
return listSessions();
|
|
310
289
|
},
|
|
311
290
|
},
|
|
312
291
|
];
|
package/src/tools/diff.js
CHANGED
|
@@ -8,7 +8,32 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { loadDataset } from "@adobe/design-data/load";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Filter a diff result by a substring match against token names.
|
|
15
|
+
*
|
|
16
|
+
* The diff() return shape uses camelCase (per wasm serde rename_all = "camelCase"):
|
|
17
|
+
* - renamed entries: { oldName, newName, ... }
|
|
18
|
+
* - all other entries: { name, ... }
|
|
19
|
+
*
|
|
20
|
+
* @param {object} diff - DiffResult from Dataset.diff().
|
|
21
|
+
* @param {string} filter - Substring to match (case-insensitive).
|
|
22
|
+
* @returns {object} Filtered diff with the same top-level keys.
|
|
23
|
+
*/
|
|
24
|
+
export function filterDiffByName(diff, filter) {
|
|
25
|
+
const f = filter.toLowerCase();
|
|
26
|
+
const matchName = (t) =>
|
|
27
|
+
[t.name, t.oldName, t.newName].some((n) => n?.toLowerCase().includes(f));
|
|
28
|
+
return {
|
|
29
|
+
renamed: diff.renamed.filter(matchName),
|
|
30
|
+
deprecated: diff.deprecated.filter(matchName),
|
|
31
|
+
reverted: diff.reverted.filter(matchName),
|
|
32
|
+
added: diff.added.filter(matchName),
|
|
33
|
+
deleted: diff.deleted.filter(matchName),
|
|
34
|
+
updated: diff.updated.filter(matchName),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
12
37
|
|
|
13
38
|
export function createDiffTools() {
|
|
14
39
|
return [
|
|
@@ -36,12 +61,13 @@ export function createDiffTools() {
|
|
|
36
61
|
additionalProperties: false,
|
|
37
62
|
},
|
|
38
63
|
async handler({ oldPath, newPath, filter }) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
64
|
+
const [oldDs, newDs] = await Promise.all([
|
|
65
|
+
loadDataset(oldPath),
|
|
66
|
+
loadDataset(newPath),
|
|
67
|
+
]);
|
|
68
|
+
const diff = oldDs.diff(newDs);
|
|
69
|
+
if (!filter) return diff;
|
|
70
|
+
return filterDiffByName(diff, filter);
|
|
45
71
|
},
|
|
46
72
|
},
|
|
47
73
|
];
|
package/src/tools/read.js
CHANGED
|
@@ -8,9 +8,57 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Read tools for design-data-agent-mcp.
|
|
13
|
+
*
|
|
14
|
+
* All read tools run fully in-process via @adobe/design-data-wasm — no CLI binary
|
|
15
|
+
* required. primer and describe_component were migrated in issue m1r.
|
|
16
|
+
*
|
|
17
|
+
* Note: authoring_session_step_intent in authoring.js still uses the CLI because
|
|
18
|
+
* the NLP suggest ranking is not yet on the wasm surface.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFileSync, existsSync, readdirSync } from "fs";
|
|
22
|
+
import { join } from "path";
|
|
23
|
+
import { loadDataset } from "@adobe/design-data/load";
|
|
12
24
|
import { config } from "../config.js";
|
|
13
25
|
|
|
26
|
+
let _wasm;
|
|
27
|
+
/** Lazy-load and cache the wasm module (nodejs target, no init() required). */
|
|
28
|
+
async function getWasm() {
|
|
29
|
+
if (!_wasm) _wasm = await import("@adobe/design-data-wasm");
|
|
30
|
+
return _wasm;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let _dataset;
|
|
34
|
+
/**
|
|
35
|
+
* Return the embedded Spectrum dataset, caching it after first access.
|
|
36
|
+
*
|
|
37
|
+
* Dataset.embedded() clones the in-memory graph on every call; caching here
|
|
38
|
+
* avoids that per-request cost.
|
|
39
|
+
*/
|
|
40
|
+
async function getDataset() {
|
|
41
|
+
if (!_dataset) {
|
|
42
|
+
const wasm = await getWasm();
|
|
43
|
+
_dataset = wasm.Dataset.embedded();
|
|
44
|
+
}
|
|
45
|
+
return _dataset;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Validate a component ID against the same rule as the Rust SDK.
|
|
50
|
+
* See sdk/core/src/component.rs:validate_id — prevents path traversal.
|
|
51
|
+
*/
|
|
52
|
+
const COMPONENT_ID_RE = /^[a-z][a-z0-9-]*$/;
|
|
53
|
+
function validateComponentId(id) {
|
|
54
|
+
if (!COMPONENT_ID_RE.test(id)) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
`Invalid component ID "${id}". IDs must be kebab-case: start with a lowercase ` +
|
|
57
|
+
`letter and contain only lowercase letters, digits, and hyphens.`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
14
62
|
export function createReadTools() {
|
|
15
63
|
return [
|
|
16
64
|
{
|
|
@@ -23,16 +71,34 @@ export function createReadTools() {
|
|
|
23
71
|
additionalProperties: false,
|
|
24
72
|
},
|
|
25
73
|
async handler() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
74
|
+
// Shape note: this response intentionally diverges from the CLI PrimerData
|
|
75
|
+
// struct (sdk/core/src/primer.rs). The CLI emits modeSets as an array of
|
|
76
|
+
// {name, values} objects and taxonomyFields as a flat array. This in-process
|
|
77
|
+
// shape uses keyed objects (matching the sibling design-data-mcp), which agents
|
|
78
|
+
// and the SKILL.md skill prompt consume by key name. Skill contract:
|
|
79
|
+
// tokenCount, modeSets.{colorScheme,scale,contrast}, components[],
|
|
80
|
+
// taxonomyFields.{indexed,advisory}. CLI-only fields (specVersion, manifest,
|
|
81
|
+
// provenance) are not present — no SKILL.md reference or consumer relies on them.
|
|
82
|
+
const wasm = await getWasm();
|
|
83
|
+
const ds = await getDataset();
|
|
84
|
+
return {
|
|
85
|
+
source: "embedded",
|
|
86
|
+
tokenCount: ds.tokenCount(),
|
|
87
|
+
modeSets: {
|
|
88
|
+
colorScheme: wasm.getFieldValues("colorScheme") ?? [],
|
|
89
|
+
scale: wasm.getFieldValues("scale") ?? [],
|
|
90
|
+
contrast: wasm.getFieldValues("contrast") ?? [],
|
|
91
|
+
},
|
|
92
|
+
taxonomyFields: {
|
|
93
|
+
indexed: wasm.getIndexedFields(),
|
|
94
|
+
advisory: wasm.getAdvisoryFields() ?? [],
|
|
95
|
+
},
|
|
96
|
+
components: wasm.getFieldValues("component") ?? [],
|
|
97
|
+
properties: wasm.getFieldValues("property") ?? [],
|
|
98
|
+
};
|
|
34
99
|
},
|
|
35
100
|
},
|
|
101
|
+
|
|
36
102
|
{
|
|
37
103
|
name: "resolve_token",
|
|
38
104
|
description:
|
|
@@ -64,16 +130,21 @@ export function createReadTools() {
|
|
|
64
130
|
additionalProperties: false,
|
|
65
131
|
},
|
|
66
132
|
async handler({ property, colorScheme, scale, contrast }) {
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
133
|
+
const ds = await loadDataset(config.dataPath);
|
|
134
|
+
const context = {};
|
|
135
|
+
if (colorScheme) context.colorScheme = colorScheme;
|
|
136
|
+
if (scale) context.scale = scale;
|
|
137
|
+
if (contrast) context.contrast = contrast;
|
|
138
|
+
const result = ds.resolve(property, context);
|
|
139
|
+
if (!result) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`No token found for property "${property}" in context ${JSON.stringify(context)}`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return result;
|
|
75
145
|
},
|
|
76
146
|
},
|
|
147
|
+
|
|
77
148
|
{
|
|
78
149
|
name: "query_tokens",
|
|
79
150
|
description:
|
|
@@ -90,20 +161,11 @@ export function createReadTools() {
|
|
|
90
161
|
additionalProperties: false,
|
|
91
162
|
},
|
|
92
163
|
async handler({ filter }) {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
config.dataPath,
|
|
96
|
-
"--filter",
|
|
97
|
-
filter,
|
|
98
|
-
"--format",
|
|
99
|
-
"json",
|
|
100
|
-
];
|
|
101
|
-
const { exitCode, stdout, stderr } = await runCli(args);
|
|
102
|
-
// exit code 1 means no matches — still valid JSON []
|
|
103
|
-
if (exitCode > 1) throw new Error(stderr || `query exited ${exitCode}`);
|
|
104
|
-
return JSON.parse(stdout);
|
|
164
|
+
const ds = await loadDataset(config.dataPath);
|
|
165
|
+
return ds.query(filter);
|
|
105
166
|
},
|
|
106
167
|
},
|
|
168
|
+
|
|
107
169
|
{
|
|
108
170
|
name: "describe_component",
|
|
109
171
|
description:
|
|
@@ -117,13 +179,32 @@ export function createReadTools() {
|
|
|
117
179
|
additionalProperties: false,
|
|
118
180
|
},
|
|
119
181
|
async handler({ id }) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
182
|
+
validateComponentId(id);
|
|
183
|
+
const componentsDir = config.componentsDir;
|
|
184
|
+
if (!componentsDir) {
|
|
185
|
+
throw new Error(
|
|
186
|
+
`@adobe/spectrum-design-data is not installed — cannot load component "${id}". ` +
|
|
187
|
+
`Install it with: pnpm add @adobe/spectrum-design-data`,
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
const componentFile = join(componentsDir, `${id}.json`);
|
|
191
|
+
if (!existsSync(componentFile)) {
|
|
192
|
+
let available;
|
|
193
|
+
try {
|
|
194
|
+
available = readdirSync(componentsDir)
|
|
195
|
+
.filter((f) => f.endsWith(".json"))
|
|
196
|
+
.map((f) => f.replace(/\.json$/, ""))
|
|
197
|
+
.sort()
|
|
198
|
+
.join(", ");
|
|
199
|
+
} catch {
|
|
200
|
+
available = null;
|
|
201
|
+
}
|
|
202
|
+
const hint = available
|
|
203
|
+
? `Available components: ${available}`
|
|
204
|
+
: `Call primer to see available component IDs.`;
|
|
205
|
+
throw new Error(`Component not found: "${id}". ${hint}`);
|
|
206
|
+
}
|
|
207
|
+
return JSON.parse(readFileSync(componentFile, "utf-8"));
|
|
127
208
|
},
|
|
128
209
|
},
|
|
129
210
|
];
|
package/src/tools/validate.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// OF ANY KIND, either express or implied. See the License for the specific language
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
|
-
import {
|
|
11
|
+
import { validateDataset } from "@adobe/design-data/validate";
|
|
12
12
|
import { config } from "../config.js";
|
|
13
13
|
|
|
14
14
|
export function createValidateTools() {
|
|
@@ -16,7 +16,8 @@ export function createValidateTools() {
|
|
|
16
16
|
{
|
|
17
17
|
name: "validate_usage",
|
|
18
18
|
description:
|
|
19
|
-
"Validate design token usage in a dataset.
|
|
19
|
+
"Validate design token usage in a dataset. Runs Layer-1 JSON-Schema structural " +
|
|
20
|
+
"validation and Layer-2 relational rules. Returns a JSON report of violations and warnings.",
|
|
20
21
|
inputSchema: {
|
|
21
22
|
type: "object",
|
|
22
23
|
properties: {
|
|
@@ -26,20 +27,24 @@ export function createValidateTools() {
|
|
|
26
27
|
"Path to dataset to validate (defaults to DESIGN_DATA_PATH)",
|
|
27
28
|
},
|
|
28
29
|
strict: { type: "boolean", description: "Treat warnings as errors" },
|
|
30
|
+
schema_path: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description:
|
|
33
|
+
"Path to schemas directory containing token-types/ and token-file.json. " +
|
|
34
|
+
"Defaults to @adobe/spectrum-tokens schemas. Set DESIGN_DATA_SCHEMAS env var or " +
|
|
35
|
+
"pass explicitly for custom schema sets.",
|
|
36
|
+
},
|
|
29
37
|
},
|
|
30
38
|
additionalProperties: false,
|
|
31
39
|
},
|
|
32
|
-
async handler({ path, strict } = {}) {
|
|
40
|
+
async handler({ path, strict, schema_path } = {}) {
|
|
33
41
|
const target = path ?? config.dataPath;
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (exitCode !== 0 && !stdout)
|
|
41
|
-
throw new Error(stderr || `validate exited ${exitCode}`);
|
|
42
|
-
return JSON.parse(stdout);
|
|
42
|
+
const schemaPath = schema_path ?? config.schemaPath ?? null;
|
|
43
|
+
// NOTE: exceptionsPath (DESIGN_DATA_EXCEPTIONS / --exceptions-path) applies to the
|
|
44
|
+
// SPEC-007 naming rule in the relational layer. The in-process wasm validate() does
|
|
45
|
+
// not consume it. Passing exceptionsPath here would throw an explicit error from
|
|
46
|
+
// validateDataset — omit it and document the limitation.
|
|
47
|
+
return validateDataset(target, { schemaPath, strict: strict ?? false });
|
|
43
48
|
},
|
|
44
49
|
},
|
|
45
50
|
];
|
package/src/tools/write.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// governing permissions and limitations under the License.
|
|
10
10
|
|
|
11
11
|
import { join } from "path";
|
|
12
|
-
import {
|
|
12
|
+
import { writeProductContext } from "@adobe/design-data/write";
|
|
13
13
|
import { config } from "../config.js";
|
|
14
14
|
|
|
15
15
|
export function createWriteTools() {
|
|
@@ -36,12 +36,7 @@ export function createWriteTools() {
|
|
|
36
36
|
async handler({ output, rationale } = {}) {
|
|
37
37
|
const resolvedOutput =
|
|
38
38
|
output ?? join(config.dataPath, "product-context.json");
|
|
39
|
-
|
|
40
|
-
if (rationale) args.push("--rationale", rationale);
|
|
41
|
-
const { exitCode, stdout, stderr } = await runCli(args);
|
|
42
|
-
if (exitCode !== 0)
|
|
43
|
-
throw new Error(stderr || `write exited ${exitCode}`);
|
|
44
|
-
return stdout;
|
|
39
|
+
return writeProductContext({ output: resolvedOutput, rationale });
|
|
45
40
|
},
|
|
46
41
|
},
|
|
47
42
|
];
|