@linktr.ee/arbor-mcp 0.4.0 → 0.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/dist/index.js +488 -63
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,7 +6,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
-
|
|
9
|
+
try {
|
|
10
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
11
|
+
} catch (e) {
|
|
12
|
+
throw mod = 0, e;
|
|
13
|
+
}
|
|
10
14
|
};
|
|
11
15
|
var __export = (target, all) => {
|
|
12
16
|
for (var name in all)
|
|
@@ -33,7 +37,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
33
37
|
var require_rules = __commonJS({
|
|
34
38
|
"../../docs/content/ux-writing/rules.json"(exports, module) {
|
|
35
39
|
module.exports = {
|
|
36
|
-
$schema: "./types.schema.json",
|
|
37
40
|
version: "1.0.0",
|
|
38
41
|
description: "Static lint rules for UX writing. Consumable by Lambda, Figma plugin, Claude skill, and CI scripts.",
|
|
39
42
|
rules: {
|
|
@@ -160,6 +163,86 @@ var require_rules = __commonJS({
|
|
|
160
163
|
pattern: "are you sure",
|
|
161
164
|
reason: "Patronizing. State consequences clearly instead.",
|
|
162
165
|
suggestion: "Replace with clear consequence statement: 'This will delete all data'"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
pattern: "\\btier\\b",
|
|
169
|
+
matchType: "regex",
|
|
170
|
+
label: "tier",
|
|
171
|
+
reason: 'Linktree plans are called "plans", not "tiers". "Tier" is internal language.',
|
|
172
|
+
suggestion: 'Use "plan" instead of "tier".'
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
pattern: "\\bPRO\\b",
|
|
176
|
+
matchType: "regex",
|
|
177
|
+
caseSensitive: true,
|
|
178
|
+
label: "PRO",
|
|
179
|
+
reason: 'Plan names use title case: "Pro", not "PRO".',
|
|
180
|
+
suggestion: 'Write the plan name as "Pro".'
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
pattern: "\\b(?:your|my|their|our|the|a|an|this|that)\\s+profiles?\\b(?!\\s+(?:photo|image|picture|avatar|url|link))",
|
|
184
|
+
matchType: "regex",
|
|
185
|
+
label: "profile",
|
|
186
|
+
reason: `Don't call a Linktree a generic "profile".`,
|
|
187
|
+
suggestion: 'Refer to it as your "Linktree" (the proper noun "Linktree Profile" is fine).'
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
pattern: "\\bpackage(s)?\\b",
|
|
191
|
+
matchType: "regex",
|
|
192
|
+
label: "package",
|
|
193
|
+
reason: 'Linktree plans are called "plans", not "packages".',
|
|
194
|
+
suggestion: 'Use "plan" instead of "package".'
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
pattern: "\\bbucket(s)?\\b",
|
|
198
|
+
matchType: "regex",
|
|
199
|
+
label: "bucket",
|
|
200
|
+
reason: 'Linktree plans are called "plans", not "buckets".',
|
|
201
|
+
suggestion: 'Use "plan" instead of "bucket".'
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
pattern: "\\busers?\\b(?!\\s*-?\\s*(?:friendly|name|names|generated|facing|flow|flows|journey|journeys|persona|personas|research|testing|experience|interface|story|stories))",
|
|
205
|
+
matchType: "regex",
|
|
206
|
+
label: "users",
|
|
207
|
+
reason: 'People who use Linktree are "Linkers", not "users".',
|
|
208
|
+
suggestion: 'Use "Linkers" \u2014 or just say "you".'
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
pattern: "\\bLink Tree\\b",
|
|
212
|
+
matchType: "regex",
|
|
213
|
+
label: "Link Tree",
|
|
214
|
+
reason: 'Linktree is one word: "Linktree", not "Link Tree".',
|
|
215
|
+
suggestion: 'Write it as "Linktree".'
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
pattern: "\\bLinkTree\\b",
|
|
219
|
+
matchType: "regex",
|
|
220
|
+
caseSensitive: true,
|
|
221
|
+
label: "LinkTree",
|
|
222
|
+
reason: 'Linktree capitalizes only the L: "Linktree", not "LinkTree".',
|
|
223
|
+
suggestion: 'Write it as "Linktree".'
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
pattern: "\\b(linkinbio|link-in-bio|bio link)\\b",
|
|
227
|
+
matchType: "regex",
|
|
228
|
+
label: "link-in-bio",
|
|
229
|
+
reason: `It's "link in bio" \u2014 three words, no hyphen.`,
|
|
230
|
+
suggestion: 'Use "link in bio" (not "linkinbio", "link-in-bio" or "bio link").'
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
pattern: "subscription",
|
|
234
|
+
reason: 'Linktree billing is a "plan", not a "subscription".',
|
|
235
|
+
suggestion: 'Use "plan". (Keep "subscribe"/"subscriber" for the visitor notification feature.)'
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
pattern: "utilize",
|
|
239
|
+
reason: "Formal and stiff. Plain language is friendlier.",
|
|
240
|
+
suggestion: 'Use "use" instead of "utilize".'
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
pattern: "facilitate",
|
|
244
|
+
reason: "Formal and stiff. Plain language is friendlier.",
|
|
245
|
+
suggestion: 'Use "help" instead of "facilitate".'
|
|
163
246
|
}
|
|
164
247
|
]
|
|
165
248
|
},
|
|
@@ -462,7 +545,7 @@ var require_patterns = __commonJS({
|
|
|
462
545
|
examples: {
|
|
463
546
|
do: [
|
|
464
547
|
"Update required. This version is no longer supported. Update now to continue.",
|
|
465
|
-
"
|
|
548
|
+
"Plan expired. Your account is paused. Renew your plan to restore access.",
|
|
466
549
|
"Verification needed. Confirm your email to access features. Check your inbox."
|
|
467
550
|
],
|
|
468
551
|
dont: [
|
|
@@ -511,7 +594,7 @@ var require_patterns = __commonJS({
|
|
|
511
594
|
do: [
|
|
512
595
|
"Changes saved",
|
|
513
596
|
"Email sent",
|
|
514
|
-
"
|
|
597
|
+
"Linktree updated",
|
|
515
598
|
"You're all set",
|
|
516
599
|
"You're officially a Pro!"
|
|
517
600
|
],
|
|
@@ -915,6 +998,7 @@ var require_engine = __commonJS({
|
|
|
915
998
|
var contentTypesData = require_content_types();
|
|
916
999
|
var rules = rulesData.rules;
|
|
917
1000
|
var scoring = rulesData.scoring;
|
|
1001
|
+
var MIN_CONTENT_TYPE_CONFIDENCE = 30;
|
|
918
1002
|
var passiveVoiceRegex = new RegExp(
|
|
919
1003
|
rules["passive-voice"].check.pattern,
|
|
920
1004
|
"gi"
|
|
@@ -931,6 +1015,15 @@ var require_engine = __commonJS({
|
|
|
931
1015
|
}
|
|
932
1016
|
compiledTextPatterns.set(typeId, regexes);
|
|
933
1017
|
}
|
|
1018
|
+
var compiledBannedPhrases = rules["banned-phrases"].phrases.map((phrase) => {
|
|
1019
|
+
if (phrase.matchType !== "regex") return phrase;
|
|
1020
|
+
try {
|
|
1021
|
+
const flags = phrase.caseSensitive ? "" : "i";
|
|
1022
|
+
return { ...phrase, _regex: new RegExp(phrase.pattern, flags) };
|
|
1023
|
+
} catch {
|
|
1024
|
+
return { ...phrase, _regex: null };
|
|
1025
|
+
}
|
|
1026
|
+
});
|
|
934
1027
|
function countSyllables(word) {
|
|
935
1028
|
const w = word.toLowerCase().replace(/[^a-z]/g, "");
|
|
936
1029
|
if (w.length <= 3) return 1;
|
|
@@ -946,34 +1039,42 @@ var require_engine = __commonJS({
|
|
|
946
1039
|
}
|
|
947
1040
|
function checkSentenceCase(text, issues) {
|
|
948
1041
|
const words = text.split(/\s+/);
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
if (
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1042
|
+
let sentenceStart = true;
|
|
1043
|
+
for (let i = 0; i < words.length; i++) {
|
|
1044
|
+
const raw = words[i];
|
|
1045
|
+
if (!raw) continue;
|
|
1046
|
+
const endsSentence = /[.!?][)\]"'\u2019\u201d]*$/.test(raw);
|
|
1047
|
+
if (!sentenceStart) {
|
|
1048
|
+
const word = raw.replace(/^[^a-zA-Z]+/, "").replace(/[^a-zA-Z]+$/, "");
|
|
1049
|
+
const isPronounI = word.replace(/[^a-zA-Z]/g, "") === "I" || /^[^a-zA-Z]*I['\u2019\u2018]/.test(raw);
|
|
1050
|
+
if (!isPronounI && word.length > 0 && word[0] === word[0].toUpperCase() && word[0] !== word[0].toLowerCase() && !properNounAllowlist.has(word)) {
|
|
1051
|
+
const sentenceCased = word === word.toUpperCase() ? word.toLowerCase() : word[0].toLowerCase() + word.slice(1);
|
|
1052
|
+
issues.push({
|
|
1053
|
+
ruleId: "sentence-case",
|
|
1054
|
+
ruleName: "Sentence case",
|
|
1055
|
+
severity: "warning",
|
|
1056
|
+
message: `"${word}" appears capitalized. Use sentence case for UI text.`,
|
|
1057
|
+
suggestion: `Change to "${sentenceCased}"`
|
|
1058
|
+
});
|
|
1059
|
+
break;
|
|
1060
|
+
}
|
|
961
1061
|
}
|
|
1062
|
+
sentenceStart = endsSentence;
|
|
962
1063
|
}
|
|
963
1064
|
}
|
|
964
1065
|
function checkBannedPhrases(text, contentType, issues) {
|
|
965
1066
|
const lower = text.toLowerCase();
|
|
966
|
-
for (const phrase of
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
}
|
|
1067
|
+
for (const phrase of compiledBannedPhrases) {
|
|
1068
|
+
const matched = phrase.matchType === "regex" ? phrase._regex !== null && phrase._regex.test(text) : lower.includes(phrase.pattern);
|
|
1069
|
+
if (!matched) continue;
|
|
1070
|
+
const severity = contentType === "button" ? rules["banned-phrases"].severityByContext.button : rules["banned-phrases"].severityByContext.other;
|
|
1071
|
+
issues.push({
|
|
1072
|
+
ruleId: "banned-phrases",
|
|
1073
|
+
ruleName: "Banned phrase",
|
|
1074
|
+
severity,
|
|
1075
|
+
message: `"${phrase.label || phrase.pattern}" \u2014 ${phrase.reason}`,
|
|
1076
|
+
suggestion: phrase.suggestion
|
|
1077
|
+
});
|
|
977
1078
|
}
|
|
978
1079
|
}
|
|
979
1080
|
function checkGenericButtons(text, issues) {
|
|
@@ -1113,6 +1214,9 @@ var require_engine = __commonJS({
|
|
|
1113
1214
|
bestMatch = { type: typeId, confidence: score };
|
|
1114
1215
|
}
|
|
1115
1216
|
}
|
|
1217
|
+
if (!bestMatch || bestMatch.confidence < MIN_CONTENT_TYPE_CONFIDENCE) {
|
|
1218
|
+
return null;
|
|
1219
|
+
}
|
|
1116
1220
|
return bestMatch;
|
|
1117
1221
|
}
|
|
1118
1222
|
function getPattern(contentType) {
|
|
@@ -5432,7 +5536,7 @@ ZodNaN.create = (params) => {
|
|
|
5432
5536
|
...processCreateParams(params)
|
|
5433
5537
|
});
|
|
5434
5538
|
};
|
|
5435
|
-
var BRAND = Symbol("zod_brand");
|
|
5539
|
+
var BRAND = /* @__PURE__ */ Symbol("zod_brand");
|
|
5436
5540
|
var ZodBranded = class extends ZodType {
|
|
5437
5541
|
_parse(input) {
|
|
5438
5542
|
const { ctx } = this._processInputParams(input);
|
|
@@ -5930,6 +6034,7 @@ async function querySupernova(resource, opts = {}) {
|
|
|
5930
6034
|
const {
|
|
5931
6035
|
designSystemId,
|
|
5932
6036
|
versionId,
|
|
6037
|
+
versionSelector,
|
|
5933
6038
|
proxyUrl = process.env.ARBOR_MCP_SUPERNOVA_PROXY_URL ?? "",
|
|
5934
6039
|
proxyToken = process.env.ARBOR_MCP_SUPERNOVA_PROXY_TOKEN ?? "",
|
|
5935
6040
|
fetchImpl = globalThis.fetch,
|
|
@@ -5948,12 +6053,13 @@ async function querySupernova(resource, opts = {}) {
|
|
|
5948
6053
|
if (parsed.protocol !== "https:") {
|
|
5949
6054
|
return { ok: false, reason: "not_configured", detail: `proxy URL must be https (got ${parsed.protocol})` };
|
|
5950
6055
|
}
|
|
5951
|
-
const cacheKey = `${resource}|${designSystemId ?? ""}|${versionId ?? ""}`;
|
|
6056
|
+
const cacheKey = `${resource}|${designSystemId ?? ""}|${versionId ?? ""}|${versionSelector ?? ""}`;
|
|
5952
6057
|
const cached = cache.get(cacheKey);
|
|
5953
6058
|
if (cached && now() - cached.fetchedAt < CACHE_TTL_MS2) return cached.value;
|
|
5954
6059
|
const body = { resource };
|
|
5955
6060
|
if (designSystemId) body.designSystemId = designSystemId;
|
|
5956
6061
|
if (versionId) body.versionId = versionId;
|
|
6062
|
+
if (versionSelector && !versionId) body.versionSelector = versionSelector;
|
|
5957
6063
|
const controller = new AbortController();
|
|
5958
6064
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
5959
6065
|
let res;
|
|
@@ -5998,15 +6104,124 @@ async function querySupernova(resource, opts = {}) {
|
|
|
5998
6104
|
return value;
|
|
5999
6105
|
}
|
|
6000
6106
|
|
|
6107
|
+
// src/lib/resolve-version.ts
|
|
6108
|
+
function extractVersionList(data) {
|
|
6109
|
+
const wrapped = data?.result?.designSystemVersions;
|
|
6110
|
+
const list = Array.isArray(wrapped) ? wrapped : Array.isArray(data) ? data : null;
|
|
6111
|
+
if (list === null) return null;
|
|
6112
|
+
return list.filter((x) => !!x && typeof x === "object");
|
|
6113
|
+
}
|
|
6114
|
+
async function resolveVersionId(version, deps = {}) {
|
|
6115
|
+
const query = deps.query ?? ((r) => querySupernova(r));
|
|
6116
|
+
const result = await query("versions");
|
|
6117
|
+
if (!result.ok) {
|
|
6118
|
+
return { ok: false, reason: "unavailable", detail: `could not load versions (${result.reason})` };
|
|
6119
|
+
}
|
|
6120
|
+
const list = extractVersionList(result.data);
|
|
6121
|
+
if (list === null) {
|
|
6122
|
+
return { ok: false, reason: "unavailable", detail: "proxy returned an unrecognized versions payload" };
|
|
6123
|
+
}
|
|
6124
|
+
const match = list.find((v) => v.isReadonly === true && v.version === version);
|
|
6125
|
+
if (!match) {
|
|
6126
|
+
return { ok: false, reason: "not_found", detail: `no frozen Supernova version "${version}" \u2014 it may not be cut yet (see arbor_list_versions)` };
|
|
6127
|
+
}
|
|
6128
|
+
const versionId = String(match.id ?? "");
|
|
6129
|
+
if (!versionId) {
|
|
6130
|
+
return { ok: false, reason: "unavailable", detail: `frozen version "${version}" has no id` };
|
|
6131
|
+
}
|
|
6132
|
+
const meta = match.meta;
|
|
6133
|
+
const versionName = meta && typeof meta === "object" && typeof meta.name === "string" && meta.name.length > 0 ? meta.name : version;
|
|
6134
|
+
return { ok: true, versionId, versionName };
|
|
6135
|
+
}
|
|
6136
|
+
|
|
6137
|
+
// src/lib/intentions.ts
|
|
6138
|
+
var INTENTIONS_ARTIFACT = "component-intentions.json";
|
|
6139
|
+
var INTENTION_STATUSES = [
|
|
6140
|
+
"shipped",
|
|
6141
|
+
"in-progress",
|
|
6142
|
+
"design-only",
|
|
6143
|
+
"deprecated",
|
|
6144
|
+
"researched-not-shipped"
|
|
6145
|
+
];
|
|
6146
|
+
var STATUS_SET = new Set(INTENTION_STATUSES);
|
|
6147
|
+
function normalizeComponentKey(name) {
|
|
6148
|
+
return name.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
6149
|
+
}
|
|
6150
|
+
function asStringArray(v) {
|
|
6151
|
+
return Array.isArray(v) ? v.filter((s) => typeof s === "string") : [];
|
|
6152
|
+
}
|
|
6153
|
+
function asDisambiguations(v) {
|
|
6154
|
+
if (!Array.isArray(v)) return [];
|
|
6155
|
+
const out = [];
|
|
6156
|
+
for (const d of v) {
|
|
6157
|
+
if (d && typeof d === "object") {
|
|
6158
|
+
const component = d.component;
|
|
6159
|
+
const distinction = d.distinction;
|
|
6160
|
+
if (typeof component === "string" && typeof distinction === "string") {
|
|
6161
|
+
out.push({ component, distinction });
|
|
6162
|
+
}
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
return out;
|
|
6166
|
+
}
|
|
6167
|
+
function coerceEntry(raw) {
|
|
6168
|
+
if (!raw || typeof raw !== "object") return null;
|
|
6169
|
+
const r = raw;
|
|
6170
|
+
const name = typeof r.name === "string" ? r.name.trim() : "";
|
|
6171
|
+
const status = typeof r.status === "string" ? r.status : "";
|
|
6172
|
+
if (!name || !STATUS_SET.has(status)) return null;
|
|
6173
|
+
return {
|
|
6174
|
+
name,
|
|
6175
|
+
status,
|
|
6176
|
+
shippedVersion: typeof r.shippedVersion === "string" ? r.shippedVersion : null,
|
|
6177
|
+
useWhen: asStringArray(r.useWhen),
|
|
6178
|
+
notWhen: asStringArray(r.notWhen),
|
|
6179
|
+
disambiguateFrom: asDisambiguations(r.disambiguateFrom),
|
|
6180
|
+
guideline: typeof r.guideline === "string" ? r.guideline : null,
|
|
6181
|
+
decisions: asStringArray(r.decisions)
|
|
6182
|
+
};
|
|
6183
|
+
}
|
|
6184
|
+
async function loadIntentions(load = loadPublishedJson) {
|
|
6185
|
+
const res = await load(INTENTIONS_ARTIFACT);
|
|
6186
|
+
if (!res.ok) return { ok: false, reason: res.reason };
|
|
6187
|
+
const data = res.data;
|
|
6188
|
+
if (data.degraded === true || !Array.isArray(data.components)) {
|
|
6189
|
+
return { ok: false, reason: "degraded" };
|
|
6190
|
+
}
|
|
6191
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
6192
|
+
for (const raw of data.components) {
|
|
6193
|
+
const entry = coerceEntry(raw);
|
|
6194
|
+
if (entry) byKey.set(normalizeComponentKey(entry.name), entry);
|
|
6195
|
+
}
|
|
6196
|
+
return { ok: true, byKey, generatedAt: typeof data.generatedAt === "string" ? data.generatedAt : null };
|
|
6197
|
+
}
|
|
6198
|
+
|
|
6001
6199
|
// src/tools/list-components.ts
|
|
6002
6200
|
var TOOL_NAME3 = "arbor_list_components";
|
|
6003
6201
|
var TOOL_TITLE3 = "List Arbor components";
|
|
6004
6202
|
var TOOL_DESCRIPTION3 = "List the components in the Arbor design system (name, id, short description) from Supernova via the Arbor federation proxy. Read-only metadata for discovery; returns top-level components, not Figma variants. Does NOT return token values, source code, or props \u2014 use arbor_get_component for one component, the shadcn registry/Storybook for source, arbor_open_in_playroom for a runnable snippet. Does NOT change anything.";
|
|
6005
|
-
var inputSchema3 = external_exports.object({
|
|
6203
|
+
var inputSchema3 = external_exports.object({
|
|
6204
|
+
query: external_exports.string().trim().min(1).max(100).optional().describe("Optional case-insensitive name/description filter"),
|
|
6205
|
+
versionSelector: external_exports.enum(["draft", "latest_released"]).optional().describe(
|
|
6206
|
+
"Which design system version to read: 'draft' (default \u2014 the editable working version) or 'latest_released' (the newest frozen release; available only once a release has been cut, otherwise unavailable)"
|
|
6207
|
+
),
|
|
6208
|
+
version: external_exports.string().trim().min(1).max(50).optional().describe(
|
|
6209
|
+
'List components as of a specific released version, e.g. "15.1.0" \u2014 resolves to that frozen Supernova version ("what shipped in 15.1.0"). Takes precedence over versionSelector. See arbor_list_versions for the versions that have been cut.'
|
|
6210
|
+
)
|
|
6211
|
+
}).strict();
|
|
6006
6212
|
var outputSchema3 = external_exports.object({
|
|
6007
6213
|
source: external_exports.enum(["remote", "unavailable"]),
|
|
6008
6214
|
total: external_exports.number(),
|
|
6009
|
-
components: external_exports.array(
|
|
6215
|
+
components: external_exports.array(
|
|
6216
|
+
external_exports.object({
|
|
6217
|
+
id: external_exports.string(),
|
|
6218
|
+
name: external_exports.string(),
|
|
6219
|
+
description: external_exports.string().nullable(),
|
|
6220
|
+
// Lifecycle status merged from the component-intentions manifest (DNG-726).
|
|
6221
|
+
// null when the manifest has no entry for this component or could not be loaded.
|
|
6222
|
+
status: external_exports.enum(INTENTION_STATUSES).nullable()
|
|
6223
|
+
})
|
|
6224
|
+
),
|
|
6010
6225
|
detail: external_exports.string().nullable()
|
|
6011
6226
|
});
|
|
6012
6227
|
var annotations3 = { readOnlyHint: true, idempotentHint: true, openWorldHint: true, destructiveHint: false };
|
|
@@ -6025,8 +6240,23 @@ function extractComponents(data) {
|
|
|
6025
6240
|
});
|
|
6026
6241
|
}
|
|
6027
6242
|
async function handleListComponents(args, deps = {}) {
|
|
6028
|
-
const query = deps.query ?? ((r) => querySupernova(r));
|
|
6029
|
-
|
|
6243
|
+
const query = deps.query ?? ((r, opts) => querySupernova(r, opts));
|
|
6244
|
+
let queryOpts;
|
|
6245
|
+
if (args.version) {
|
|
6246
|
+
const resolveVersion = deps.resolveVersion ?? ((v) => resolveVersionId(v));
|
|
6247
|
+
const resolved = await resolveVersion(args.version);
|
|
6248
|
+
if (!resolved.ok) {
|
|
6249
|
+
const out2 = { source: "unavailable", total: 0, components: [], detail: resolved.detail };
|
|
6250
|
+
return {
|
|
6251
|
+
content: [{ type: "text", text: `Could not read version ${args.version}: ${resolved.detail}. Treat as unavailable \u2014 do not assume there are none.` }],
|
|
6252
|
+
structuredContent: out2
|
|
6253
|
+
};
|
|
6254
|
+
}
|
|
6255
|
+
queryOpts = { versionId: resolved.versionId };
|
|
6256
|
+
} else {
|
|
6257
|
+
queryOpts = { versionSelector: args.versionSelector };
|
|
6258
|
+
}
|
|
6259
|
+
const result = await query("components", queryOpts);
|
|
6030
6260
|
let out;
|
|
6031
6261
|
const extracted = result.ok ? extractComponents(result.data) : null;
|
|
6032
6262
|
if (!result.ok) {
|
|
@@ -6041,7 +6271,13 @@ async function handleListComponents(args, deps = {}) {
|
|
|
6041
6271
|
(c) => c.name.toLowerCase().includes(q) || (c.description ? c.description.toLowerCase().includes(q) : false)
|
|
6042
6272
|
);
|
|
6043
6273
|
}
|
|
6044
|
-
|
|
6274
|
+
const intentionsRes = await (deps.loadIntentions ?? (() => loadIntentions()))();
|
|
6275
|
+
const byKey = intentionsRes.ok ? intentionsRes.byKey : null;
|
|
6276
|
+
const withStatus = components.map((c) => ({
|
|
6277
|
+
...c,
|
|
6278
|
+
status: byKey ? byKey.get(normalizeComponentKey(c.name))?.status ?? null : null
|
|
6279
|
+
}));
|
|
6280
|
+
out = { source: "remote", total: withStatus.length, components: withStatus, detail: null };
|
|
6045
6281
|
}
|
|
6046
6282
|
const summary = out.source === "unavailable" ? `Could not load components (${out.detail}). Treat as unavailable \u2014 do not assume there are none.` : `${out.total} component${out.total === 1 ? "" : "s"}${args.query ? ` matching "${args.query}"` : ""}.`;
|
|
6047
6283
|
return { content: [{ type: "text", text: summary }], structuredContent: out };
|
|
@@ -6055,43 +6291,125 @@ var listComponentsTool = {
|
|
|
6055
6291
|
// src/tools/get-component.ts
|
|
6056
6292
|
var TOOL_NAME4 = "arbor_get_component";
|
|
6057
6293
|
var TOOL_TITLE4 = "Get one Arbor component";
|
|
6058
|
-
var TOOL_DESCRIPTION4 = "Get a single Arbor component's metadata by name (case-insensitive) or id
|
|
6294
|
+
var TOOL_DESCRIPTION4 = "Get a single Arbor component's metadata by name (case-insensitive) or id (name, id, description) PLUS its intention overlay \u2014 lifecycle status (shipped | in-progress | design-only | deprecated | researched-not-shipped), when to use it, when NOT to (and what to use instead), and what it is commonly confused with. Intention comes from Arbor's source of truth, so a design-only component absent from the live design data still resolves. Read-only; matches top-level components, not Figma variants. Does NOT return token values or rendered source \u2014 use the shadcn registry / Storybook for implementation and arbor_open_in_playroom for a runnable snippet. Does NOT change anything.";
|
|
6059
6295
|
var inputSchema4 = external_exports.object({
|
|
6060
6296
|
name: external_exports.string().trim().min(1).max(100).optional().describe('Component name (case-insensitive), e.g. "Button"'),
|
|
6061
|
-
id: external_exports.string().trim().min(1).max(100).optional().describe("Supernova component id")
|
|
6297
|
+
id: external_exports.string().trim().min(1).max(100).optional().describe("Supernova component id"),
|
|
6298
|
+
versionSelector: external_exports.enum(["draft", "latest_released"]).optional().describe(
|
|
6299
|
+
"Which design system version to read: 'draft' (default \u2014 the editable working version) or 'latest_released' (the newest frozen release; available only once a release has been cut, otherwise unavailable)"
|
|
6300
|
+
),
|
|
6301
|
+
version: external_exports.string().trim().min(1).max(50).optional().describe(
|
|
6302
|
+
'Read a specific released version, e.g. "15.1.0" \u2014 resolves to that frozen Supernova version and reads the component there ("what shipped in 15.1.0"). Takes precedence over versionSelector. See arbor_list_versions for the versions that have been cut.'
|
|
6303
|
+
)
|
|
6062
6304
|
}).strict();
|
|
6305
|
+
var disambiguationSchema = external_exports.object({
|
|
6306
|
+
component: external_exports.string().describe("The thing to disambiguate from \u2014 an Arbor component or an external concept (chip, snackbar, \u2026)"),
|
|
6307
|
+
distinction: external_exports.string().describe("How they differ and which to pick when")
|
|
6308
|
+
});
|
|
6309
|
+
var intentionSchema = external_exports.object({
|
|
6310
|
+
status: external_exports.enum(["shipped", "in-progress", "design-only", "deprecated", "researched-not-shipped"]).describe("Lifecycle/availability in the @linktr.ee/arbor package"),
|
|
6311
|
+
shippedVersion: external_exports.string().nullable().describe("The arbor version where this became available, when known"),
|
|
6312
|
+
useWhen: external_exports.array(external_exports.string()).describe("Situations this is the right choice for"),
|
|
6313
|
+
notWhen: external_exports.array(external_exports.string()).describe("When NOT to reach for it, ideally naming the better alternative"),
|
|
6314
|
+
disambiguateFrom: external_exports.array(disambiguationSchema).describe("Things this is commonly confused with"),
|
|
6315
|
+
guideline: external_exports.string().nullable().describe("Repo-relative path to the long-form guideline, when one exists"),
|
|
6316
|
+
decisions: external_exports.array(external_exports.string()).describe("Decision-log ids (DL-NN) that explain this intention")
|
|
6317
|
+
});
|
|
6063
6318
|
var outputSchema4 = external_exports.object({
|
|
6064
|
-
source: external_exports.enum(["remote", "unavailable"]),
|
|
6065
|
-
found: external_exports.boolean(),
|
|
6319
|
+
source: external_exports.enum(["remote", "unavailable"]).describe("Live design-data (Supernova) availability"),
|
|
6320
|
+
found: external_exports.boolean().describe("True when a component OR an intention entry matched"),
|
|
6066
6321
|
component: external_exports.object({ id: external_exports.string(), name: external_exports.string(), description: external_exports.string().nullable() }).nullable(),
|
|
6322
|
+
intention: intentionSchema.nullable().describe("Intention overlay from the source-of-truth manifest; null when no entry matched or it could not be loaded"),
|
|
6323
|
+
intentionSource: external_exports.enum(["remote", "absent", "unavailable"]).describe("'remote' = matched, 'absent' = manifest loaded but no entry, 'unavailable' = manifest could not be loaded"),
|
|
6067
6324
|
detail: external_exports.string().nullable()
|
|
6068
6325
|
});
|
|
6069
6326
|
var annotations4 = { readOnlyHint: true, idempotentHint: true, openWorldHint: true, destructiveHint: false };
|
|
6327
|
+
async function resolveIntention(lookupName, load) {
|
|
6328
|
+
const res = await load();
|
|
6329
|
+
if (!res.ok) return { intention: null, intentionSource: "unavailable" };
|
|
6330
|
+
if (!lookupName) return { intention: null, intentionSource: "absent" };
|
|
6331
|
+
const match = res.byKey.get(normalizeComponentKey(lookupName));
|
|
6332
|
+
if (!match) return { intention: null, intentionSource: "absent" };
|
|
6333
|
+
const intention = {
|
|
6334
|
+
status: match.status,
|
|
6335
|
+
shippedVersion: match.shippedVersion,
|
|
6336
|
+
useWhen: match.useWhen,
|
|
6337
|
+
notWhen: match.notWhen,
|
|
6338
|
+
disambiguateFrom: match.disambiguateFrom.map((d) => ({ component: d.component, distinction: d.distinction })),
|
|
6339
|
+
guideline: match.guideline,
|
|
6340
|
+
decisions: match.decisions
|
|
6341
|
+
};
|
|
6342
|
+
return { intention, intentionSource: "remote" };
|
|
6343
|
+
}
|
|
6070
6344
|
async function handleGetComponent(args, deps = {}) {
|
|
6071
6345
|
const name = args.name?.trim();
|
|
6072
6346
|
const id = args.id?.trim();
|
|
6347
|
+
const loadIntentionsFn = deps.loadIntentions ?? (() => loadIntentions());
|
|
6073
6348
|
if (!name && !id) {
|
|
6074
|
-
const out2 = {
|
|
6349
|
+
const out2 = {
|
|
6350
|
+
source: "remote",
|
|
6351
|
+
found: false,
|
|
6352
|
+
component: null,
|
|
6353
|
+
intention: null,
|
|
6354
|
+
intentionSource: "absent",
|
|
6355
|
+
detail: "provide name or id"
|
|
6356
|
+
};
|
|
6075
6357
|
return {
|
|
6076
6358
|
content: [{ type: "text", text: 'Provide a component name or id \u2014 e.g. {"name":"Button"} or {"id":"35988997"}.' }],
|
|
6077
6359
|
structuredContent: out2
|
|
6078
6360
|
};
|
|
6079
6361
|
}
|
|
6080
|
-
const query = deps.query ?? ((r) => querySupernova(r));
|
|
6081
|
-
|
|
6082
|
-
let
|
|
6083
|
-
|
|
6084
|
-
|
|
6362
|
+
const query = deps.query ?? ((r, opts) => querySupernova(r, opts));
|
|
6363
|
+
let supernovaSource = "remote";
|
|
6364
|
+
let component = null;
|
|
6365
|
+
let supernovaDetail = null;
|
|
6366
|
+
let queryOpts = null;
|
|
6367
|
+
if (args.version) {
|
|
6368
|
+
const resolveVersion = deps.resolveVersion ?? ((v) => resolveVersionId(v));
|
|
6369
|
+
const resolved = await resolveVersion(args.version);
|
|
6370
|
+
if (resolved.ok) {
|
|
6371
|
+
queryOpts = { versionId: resolved.versionId };
|
|
6372
|
+
} else {
|
|
6373
|
+
supernovaSource = "unavailable";
|
|
6374
|
+
supernovaDetail = resolved.detail;
|
|
6375
|
+
}
|
|
6085
6376
|
} else {
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6377
|
+
queryOpts = { versionSelector: args.versionSelector };
|
|
6378
|
+
}
|
|
6379
|
+
if (queryOpts) {
|
|
6380
|
+
const result = await query("components", queryOpts);
|
|
6381
|
+
if (!result.ok) {
|
|
6382
|
+
supernovaSource = "unavailable";
|
|
6383
|
+
supernovaDetail = `could not load components (${result.reason})`;
|
|
6089
6384
|
} else {
|
|
6090
|
-
const
|
|
6091
|
-
|
|
6385
|
+
const components = extractComponents(result.data);
|
|
6386
|
+
if (components === null) {
|
|
6387
|
+
supernovaSource = "unavailable";
|
|
6388
|
+
supernovaDetail = "proxy returned an unrecognized components payload";
|
|
6389
|
+
} else {
|
|
6390
|
+
const target = name ? normalizeComponentKey(name) : null;
|
|
6391
|
+
const match = id ? components.find((c) => c.id === id) : components.find((c) => normalizeComponentKey(c.name) === target);
|
|
6392
|
+
if (match) component = match;
|
|
6393
|
+
else supernovaDetail = `no component ${id ? `with id ${id}` : `named "${name}"`}`;
|
|
6394
|
+
}
|
|
6092
6395
|
}
|
|
6093
6396
|
}
|
|
6094
|
-
const
|
|
6397
|
+
const lookupName = component?.name ?? name ?? null;
|
|
6398
|
+
const { intention, intentionSource } = await resolveIntention(lookupName, loadIntentionsFn);
|
|
6399
|
+
const found = component !== null || intention !== null;
|
|
6400
|
+
let detail = supernovaDetail;
|
|
6401
|
+
if (!component && intention) {
|
|
6402
|
+
detail = supernovaSource === "unavailable" ? `live design data unavailable (${supernovaDetail}); intention found \u2014 status "${intention.status}"` : `not in the live design data, but tracked as "${intention.status}" in Arbor's component intentions`;
|
|
6403
|
+
}
|
|
6404
|
+
const out = { source: supernovaSource, found, component, intention, intentionSource, detail };
|
|
6405
|
+
let summary;
|
|
6406
|
+
if (!found) {
|
|
6407
|
+
summary = supernovaSource === "unavailable" ? `Could not load components (${supernovaDetail}). Treat as unavailable.` : `No Arbor component ${id ? `with id ${id}` : `named "${name}"`} exists.`;
|
|
6408
|
+
} else {
|
|
6409
|
+
const head = component ? `${component.name}${component.description ? ` \u2014 ${component.description}` : " (no description)"}.` : `${lookupName} \u2014 ${detail}.`;
|
|
6410
|
+
const intentionLine = intention ? ` Status: ${intention.status}.${intention.useWhen.length ? ` Use when: ${intention.useWhen[0]}` : ""}` : intentionSource === "unavailable" ? " (intention overlay unavailable)" : "";
|
|
6411
|
+
summary = `${head}${intentionLine}`;
|
|
6412
|
+
}
|
|
6095
6413
|
return { content: [{ type: "text", text: summary }], structuredContent: out };
|
|
6096
6414
|
}
|
|
6097
6415
|
var getComponentTool = {
|
|
@@ -6103,15 +6421,38 @@ var getComponentTool = {
|
|
|
6103
6421
|
// src/tools/list-versions.ts
|
|
6104
6422
|
var TOOL_NAME5 = "arbor_list_versions";
|
|
6105
6423
|
var TOOL_TITLE5 = "List Arbor design system versions";
|
|
6106
|
-
var TOOL_DESCRIPTION5 = "List the version history of the Arbor design system (id, name, created date, read-only flag
|
|
6424
|
+
var TOOL_DESCRIPTION5 = "List the version history of the Arbor design system from Supernova (id, name, semver, created date, read-only flag, draft / latest-released markers) via the Arbor federation proxy, plus the committed release manifest (npm release \u2194 Supernova version). Read-only metadata. Does NOT return token values (use the compiled CSS / registry) and does NOT change anything.";
|
|
6107
6425
|
var inputSchema5 = external_exports.object({}).strict();
|
|
6426
|
+
var versionSchema = external_exports.object({
|
|
6427
|
+
id: external_exports.string(),
|
|
6428
|
+
name: external_exports.string(),
|
|
6429
|
+
semver: external_exports.string().nullable().describe('The version string when it parses as semver (X.Y.Z); null for the draft, whose version is a label like "Shared Draft"'),
|
|
6430
|
+
createdAt: external_exports.string().nullable(),
|
|
6431
|
+
readOnly: external_exports.boolean().nullable(),
|
|
6432
|
+
isDraft: external_exports.boolean().nullable().describe("The editable working version (readOnly === false). DNG-594: a draft's version is a label, not null \u2014 so readOnly is the signal."),
|
|
6433
|
+
isLatestReleased: external_exports.boolean().describe("True for the single newest read-only (frozen) version by createdAt")
|
|
6434
|
+
});
|
|
6435
|
+
var manifestReleaseSchema = external_exports.object({
|
|
6436
|
+
releaseId: external_exports.string(),
|
|
6437
|
+
date: external_exports.string().nullable(),
|
|
6438
|
+
frontDoorVersion: external_exports.string().nullable().describe("The @linktr.ee/arbor version for this release (DL-076 front-door number)"),
|
|
6439
|
+
supernovaVersionId: external_exports.string().nullable().describe("The frozen Supernova version id this release was cut as (null until the cutter + stamper run \u2014 later phases)"),
|
|
6440
|
+
supernovaStatus: external_exports.string().nullable()
|
|
6441
|
+
});
|
|
6108
6442
|
var outputSchema5 = external_exports.object({
|
|
6109
|
-
source: external_exports.enum(["remote", "unavailable"]).describe("'remote' = fetched; 'unavailable' = proxy fetch failed"),
|
|
6110
|
-
total: external_exports.number().describe("Number of versions returned"),
|
|
6111
|
-
versions: external_exports.array(
|
|
6443
|
+
source: external_exports.enum(["remote", "unavailable"]).describe("'remote' = Supernova versions fetched; 'unavailable' = proxy fetch failed"),
|
|
6444
|
+
total: external_exports.number().describe("Number of Supernova versions returned"),
|
|
6445
|
+
versions: external_exports.array(versionSchema).describe("Supernova versions, in the order returned"),
|
|
6446
|
+
manifest: external_exports.object({
|
|
6447
|
+
source: external_exports.enum(["local", "unavailable"]).describe("'local' = release manifest loaded; 'unavailable' = not published yet / degraded"),
|
|
6448
|
+
total: external_exports.number(),
|
|
6449
|
+
releases: external_exports.array(manifestReleaseSchema),
|
|
6450
|
+
detail: external_exports.string().nullable()
|
|
6451
|
+
}).describe("The committed release manifest (releases.json) mapping npm releases \u2194 Supernova versions"),
|
|
6112
6452
|
detail: external_exports.string().nullable().describe("Degraded reason when source is unavailable")
|
|
6113
6453
|
});
|
|
6114
6454
|
var annotations5 = { readOnlyHint: true, idempotentHint: true, openWorldHint: true, destructiveHint: false };
|
|
6455
|
+
var SEMVER_RE = /^\d+\.\d+\.\d+(?:[-+].*)?$/;
|
|
6115
6456
|
function extractList(data) {
|
|
6116
6457
|
const wrapped = data?.result?.designSystemVersions;
|
|
6117
6458
|
const list = Array.isArray(wrapped) ? wrapped : Array.isArray(data) ? data : null;
|
|
@@ -6119,26 +6460,86 @@ function extractList(data) {
|
|
|
6119
6460
|
return list.filter((x) => !!x && typeof x === "object");
|
|
6120
6461
|
}
|
|
6121
6462
|
var str2 = (v) => typeof v === "string" && v.length > 0 ? v : null;
|
|
6463
|
+
var semverOf = (v) => {
|
|
6464
|
+
const s = str2(v);
|
|
6465
|
+
return s && SEMVER_RE.test(s) ? s : null;
|
|
6466
|
+
};
|
|
6467
|
+
var createdAtEpoch = (s) => {
|
|
6468
|
+
const t = new Date(s ?? 0).getTime();
|
|
6469
|
+
return Number.isFinite(t) ? t : 0;
|
|
6470
|
+
};
|
|
6471
|
+
var metaName = (v) => {
|
|
6472
|
+
const meta = v.meta;
|
|
6473
|
+
return meta && typeof meta === "object" ? str2(meta.name) : null;
|
|
6474
|
+
};
|
|
6475
|
+
function latestReleasedId(versions) {
|
|
6476
|
+
const frozen = versions.filter((v) => v.readOnly === true);
|
|
6477
|
+
if (frozen.length === 0) return null;
|
|
6478
|
+
frozen.sort((a, b) => createdAtEpoch(b.createdAt) - createdAtEpoch(a.createdAt));
|
|
6479
|
+
return frozen[0].id || null;
|
|
6480
|
+
}
|
|
6481
|
+
async function buildManifestLane(load) {
|
|
6482
|
+
const res = await load("releases.json");
|
|
6483
|
+
if (!res.ok) {
|
|
6484
|
+
return { source: "unavailable", total: 0, releases: [], detail: `could not load release manifest (${res.reason})` };
|
|
6485
|
+
}
|
|
6486
|
+
const data = res.data;
|
|
6487
|
+
if (data?.degraded === true) {
|
|
6488
|
+
return { source: "unavailable", total: 0, releases: [], detail: "release manifest is a degraded fallback" };
|
|
6489
|
+
}
|
|
6490
|
+
if (!data || !Array.isArray(data.releases)) {
|
|
6491
|
+
return { source: "unavailable", total: 0, releases: [], detail: "unrecognized releases.json payload" };
|
|
6492
|
+
}
|
|
6493
|
+
const releases = data.releases.filter((r) => !!r && typeof r === "object").map((r) => {
|
|
6494
|
+
const sn = r.supernova ?? {};
|
|
6495
|
+
return {
|
|
6496
|
+
releaseId: String(r.releaseId ?? ""),
|
|
6497
|
+
date: str2(r.date),
|
|
6498
|
+
frontDoorVersion: str2(r.frontDoorVersion),
|
|
6499
|
+
supernovaVersionId: str2(sn.versionId),
|
|
6500
|
+
supernovaStatus: str2(sn.status)
|
|
6501
|
+
};
|
|
6502
|
+
});
|
|
6503
|
+
return { source: "local", total: releases.length, releases, detail: null };
|
|
6504
|
+
}
|
|
6122
6505
|
async function handleListVersions(_args, deps = {}) {
|
|
6123
6506
|
const query = deps.query ?? ((r) => querySupernova(r));
|
|
6507
|
+
const load = deps.load ?? ((f) => loadPublishedJson(f));
|
|
6124
6508
|
const result = await query("versions");
|
|
6125
|
-
let out;
|
|
6126
6509
|
const list = result.ok ? extractList(result.data) : null;
|
|
6510
|
+
let source;
|
|
6511
|
+
let versions;
|
|
6512
|
+
let detail;
|
|
6127
6513
|
if (!result.ok) {
|
|
6128
|
-
|
|
6514
|
+
source = "unavailable";
|
|
6515
|
+
versions = [];
|
|
6516
|
+
detail = `could not load versions (${result.reason})`;
|
|
6129
6517
|
} else if (list === null) {
|
|
6130
|
-
|
|
6518
|
+
source = "unavailable";
|
|
6519
|
+
versions = [];
|
|
6520
|
+
detail = "proxy returned an unrecognized versions payload";
|
|
6131
6521
|
} else {
|
|
6132
|
-
const
|
|
6522
|
+
const base = list.map((v) => ({
|
|
6133
6523
|
id: String(v.id ?? ""),
|
|
6134
|
-
name:
|
|
6524
|
+
name: metaName(v) ?? str2(v.version) ?? "(unnamed)",
|
|
6525
|
+
semver: semverOf(v.version),
|
|
6135
6526
|
createdAt: str2(v.createdAt),
|
|
6136
6527
|
readOnly: typeof v.isReadonly === "boolean" ? v.isReadonly : null
|
|
6137
6528
|
}));
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6529
|
+
const latest = latestReleasedId(base);
|
|
6530
|
+
versions = base.map((v) => ({
|
|
6531
|
+
...v,
|
|
6532
|
+
isDraft: v.readOnly === null ? null : v.readOnly === false,
|
|
6533
|
+
isLatestReleased: latest !== null && v.id === latest
|
|
6534
|
+
}));
|
|
6535
|
+
source = "remote";
|
|
6536
|
+
detail = null;
|
|
6537
|
+
}
|
|
6538
|
+
const manifest = await buildManifestLane(load);
|
|
6539
|
+
const out = { source, total: versions.length, versions, manifest, detail };
|
|
6540
|
+
const versionsLine = out.source === "unavailable" ? `Supernova versions unavailable (${out.detail}) \u2014 do not assume there are none.` : `${out.total} Supernova version${out.total === 1 ? "" : "s"}: ${out.versions.map((v) => v.name).join(", ") || "(none)"}.`;
|
|
6541
|
+
const manifestLine = manifest.source === "unavailable" ? `Release manifest unavailable (${manifest.detail}).` : `${manifest.total} manifest release${manifest.total === 1 ? "" : "s"} (front-door: ${manifest.releases.map((r) => r.frontDoorVersion).filter(Boolean).join(", ") || "n/a"}).`;
|
|
6542
|
+
return { content: [{ type: "text", text: `${versionsLine} ${manifestLine}` }], structuredContent: out };
|
|
6142
6543
|
}
|
|
6143
6544
|
var listVersionsTool = {
|
|
6144
6545
|
name: TOOL_NAME5,
|
|
@@ -6918,6 +7319,30 @@ var compositions_default = [
|
|
|
6918
7319
|
code: `<RadioGroup defaultValue="option-1">
|
|
6919
7320
|
<RadioButton value="option-1" variant="pill">Option 1</RadioButton>
|
|
6920
7321
|
<RadioButton value="option-2" variant="pill">Option 2</RadioButton>
|
|
7322
|
+
</RadioGroup>`
|
|
7323
|
+
},
|
|
7324
|
+
// ── Radio ──
|
|
7325
|
+
// Maps to figma-mappings `Radio` (canonical control, node 9232-27291). The bare
|
|
7326
|
+
// 20px control must render inside a RadioGroup; pair each with an accessible
|
|
7327
|
+
// name (aria-label here, or a sibling <label htmlFor> in real usage).
|
|
7328
|
+
{
|
|
7329
|
+
group: "Radio",
|
|
7330
|
+
name: "Radio",
|
|
7331
|
+
code: `<RadioGroup defaultValue="email" aria-label="Notifications">
|
|
7332
|
+
<Radio value="email" aria-label="Email" />
|
|
7333
|
+
<Radio value="sms" aria-label="SMS" />
|
|
7334
|
+
<Radio value="push" aria-label="Push notification" />
|
|
7335
|
+
</RadioGroup>`
|
|
7336
|
+
},
|
|
7337
|
+
// ── RadioItem ──
|
|
7338
|
+
// Maps to figma-mappings `RadioItem` (canonical control + label, node 12360-58265).
|
|
7339
|
+
{
|
|
7340
|
+
group: "RadioItem",
|
|
7341
|
+
name: "RadioItem",
|
|
7342
|
+
code: `<RadioGroup defaultValue="email" aria-label="Notifications">
|
|
7343
|
+
<RadioItem value="email" description="We'll send a confirmation">Email</RadioItem>
|
|
7344
|
+
<RadioItem value="sms">SMS</RadioItem>
|
|
7345
|
+
<RadioItem value="push" disabled>Push notification</RadioItem>
|
|
6921
7346
|
</RadioGroup>`
|
|
6922
7347
|
},
|
|
6923
7348
|
// ── SearchInput ──
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linktr.ee/arbor-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Model Context Protocol server exposing Arbor design system tools: Playroom snippets, Figma→code sync health, UX-writing checks, decision-log lookup, and federated component/version metadata.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arbor",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"esbuild": "^0.
|
|
48
|
+
"esbuild": "^0.28.1",
|
|
49
49
|
"tsx": "^4.7.0",
|
|
50
50
|
"typescript": "^5.7.0",
|
|
51
51
|
"zod": "3.25.76"
|